assimp-4.1.0/0000755002537200234200000000000013213503245013254 5ustar zmoelnigiemusersassimp-4.1.0/CREDITS0000644002537200234200000001036013213503245014274 0ustar zmoelnigiemusers=============================================================== Open Asset Import Library (Assimp) Developers and Contributors =============================================================== The following is a non-exhaustive list of all constributors over the years. If you think your name should be listed here, drop us a line and we'll add you. - Alexander Gessler, 3DS-, BLEND-, ASE-, DXF-, HMP-, MDL-, MD2-, MD3-, MD5-, MDC-, NFF-, PLY-, STL-, RAW-, OFF-, MS3D-, Q3D- and LWO-Loader, Assimp-Viewer, assimp-cmd, -noboost, Website (Design). - Thomas Schulze, X-, Collada-, BVH-Loader, Postprocessing framework. Data structure & Interface design, documentation. - Kim Kulling, Obj-, Q3BSD-, OpenGEX-Loader, Logging system, CMake-build-environment, Linux-build, Website ( Admin ), Coverity ( Admin ), Glitter ( Admin ). - R.Schmidt, Linux build, eclipse support. - Matthias Gubisch, Assimp.net Visual Studio 9 support, bugfixes. - Mark Sibly B3D-Loader, Assimp testing - Jonathan Klein Ogre Loader, VC2010 fixes and CMake fixes. - Sebastian Hempel, PyAssimp (first version) Compile-Bugfixes for mingw, add environment for static library support in make. - Jonathan Pokrass Supplied a bugfix concerning the scaling in the md3 loader. - Andrew Galante, Submitted patches to make Assimp compile with GCC-4, a makefile and the xcode3 workspace. - Andreas Nagel First Assimp testing & verification under Windows Vista 64 Bit. - Marius Schr�der Allowed us to use many of his models for screenshots and testing. - Christian Schubert Supplied various XFiles for testing purposes. - Tizian Wieland Searched the web for hundreds of test models for internal use - John Connors Supplied patches for linux and SCons. - T. R. The GUY who performed some of the CSM mocaps. - Andy Maloney Contributed fixes for the documentation and the doxygen markup - Zhao Lei Contributed several bugfixes fixing memory leaks and improving float parsing - sueastside Updated PyAssimp to the latest Assimp data structures and provided a script to keep the Python binding up-to-date. - Tobias Rittig Collada testing with Cinema 4D - Brad Grantham Improvements in OpenGL-Sample. - Robert Ramirez Add group loading feature to Obj-Loader. - Chris Maiwald Many bugreports, improving Assimp's portability, regular testing & feedback. - Stepan Hrbek Bugreport and fix for a obj-materialloader crash. - David Nadlinger D bindings, CMake install support. - Dario Accornero Contributed several patches regarding Mac OS/XCode targets, bug reports. - Martin Walser (Samhayne) Contributed the 'SimpleTexturedOpenGl' sample. - Matthias Fauconneau Contributed a fix for the Q3-BSP loader. - Jørgen P. Tjernø Contributed updated and improved xcode workspaces - drparallax Contributed the /samples/SimpleAssimpViewX sample - Carsten Fuchs Contributed a fix for the Normalize method in aiQuaternion. - dbburgess Contributes a Android-specific build issue: log the hardware architecture for ARM. - alfiereinre7 Contributes a obj-fileparser fix: missing tokens in the obj-token list. - Roman Kharitonov Contributes a fix for the configure script environment. - Ed Diana Contributed AssimpDelphi (/port/AssimpDelphi). - rdb Contributes a bundle of fixes and improvements for the bsp-importer. - Mick P For contributing the De-bone postprocessing step and filing various bug reports. - Rosen Diankov Contributed patches to build assimp debian packages using cmake. - Mark Page Contributed a patch to fix the VertexTriangleAdjacency postprocessing step. - IOhannes Contributed the Debian build fixes ( architecture macro ). - gellule Several LWO and LWS fixes (pivoting). - Marcel Metz GCC/Linux fixes for the SimpleOpenGL sample. - Brian Miller Bugfix for a compiler fix for iOS on arm. - Séverin Lemaignan Rewrite of PyAssimp, distutils and Python3 support - albert-wang Bugfixes for the collada parser - Ya ping Jin Bugfixes for uv-tanget calculation. - Jonne Nauha Ogre Binary format support - Filip Wasil, Tieto Poland Sp. z o.o. Android JNI asset extraction support - Richard Steffen Contributed ExportProperties interface Contributed X File exporter Contributed Step (stp) exporter For a more detailed list just check: https://github.com/assimp/assimp/network/members Patreons: - migenius - Marcus - Cort - elect - Steffen assimp-4.1.0/README0000644002537200234200000000001613213503245014131 0ustar zmoelnigiemusersSee Readme.md assimp-4.1.0/samples/0000755002537200234200000000000013213503245014720 5ustar zmoelnigiemusersassimp-4.1.0/samples/bin/0000755002537200234200000000000013213503245015470 5ustar zmoelnigiemusersassimp-4.1.0/samples/bin/ShowWuson.bat0000644002537200234200000000006013213503245020130 0ustar zmoelnigiemusersSimpleOpenGL.exe ..\..\test\models\X\Testwuson.Xassimp-4.1.0/samples/bin/ShowDwarf.bat0000644002537200234200000000006313213503245020063 0ustar zmoelnigiemusersSimpleOpenGL.exe ..\..\test\models-nonbsd\X\dwarf.Xassimp-4.1.0/samples/SimpleTexturedDirectx11/0000755002537200234200000000000013213503245021363 5ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/0000755002537200234200000000000013213503245026026 5ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.h0000644002537200234200000000365113213503245030773 0ustar zmoelnigiemusers//-------------------------------------------------------------------------------------- // File: WICTextureLoader.h // // Function for loading a WIC image and creating a Direct3D 11 runtime texture for it // (auto-generating mipmaps if possible) // // Note: Assumes application has already called CoInitializeEx // // Warning: CreateWICTexture* functions are not thread-safe if given a d3dContext instance for // auto-gen mipmap support. // // Note these functions are useful for images created as simple 2D textures. For // more complex resources, DDSTextureLoader is an excellent light-weight runtime loader. // For a full-featured DDS file reader, writer, and texture processing pipeline see // the 'Texconv' sample and the 'DirectXTex' library. // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved. // // http://go.microsoft.com/fwlink/?LinkId=248926 // http://go.microsoft.com/fwlink/?LinkId=248929 //-------------------------------------------------------------------------------------- #ifdef _MSC_VER #pragma once #endif #include #pragma warning(push) #pragma warning(disable : 4005) #include #pragma warning(pop) HRESULT CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice, _In_opt_ ID3D11DeviceContext* d3dContext, _In_bytecount_(wicDataSize) const uint8_t* wicData, _In_ size_t wicDataSize, _Out_opt_ ID3D11Resource** texture, _Out_opt_ ID3D11ShaderResourceView** textureView, _In_ size_t maxsize = 0 ); HRESULT CreateWICTextureFromFile(_In_ ID3D11Device* d3dDevice, _In_opt_ ID3D11DeviceContext* d3dContext, _In_z_ const wchar_t* szFileName, _Out_opt_ ID3D11Resource** texture, _Out_opt_ ID3D11ShaderResourceView** textureView, _In_ size_t maxsize = 0 ); assimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/TextureLoader.cpp0000644002537200234200000005245113213503245031330 0ustar zmoelnigiemusers//-------------------------------------------------------------------------------------- // File: WICTextureLoader.cpp // // Function for loading a WIC image and creating a Direct3D 11 runtime texture for it // (auto-generating mipmaps if possible) // // Note: Assumes application has already called CoInitializeEx // // Warning: CreateWICTexture* functions are not thread-safe if given a d3dContext instance for // auto-gen mipmap support. // // Note these functions are useful for images created as simple 2D textures. For // more complex resources, DDSTextureLoader is an excellent light-weight runtime loader. // For a full-featured DDS file reader, writer, and texture processing pipeline see // the 'Texconv' sample and the 'DirectXTex' library. // // THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF // ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A // PARTICULAR PURPOSE. // // Copyright (c) Microsoft Corporation. All rights reserved. // // http://go.microsoft.com/fwlink/?LinkId=248926 // http://go.microsoft.com/fwlink/?LinkId=248929 //-------------------------------------------------------------------------------------- // We could load multi-frame images (TIFF/GIF) into a texture array. // For now, we just load the first frame (note: DirectXTex supports multi-frame images) #include #include #pragma warning(push) #pragma warning(disable : 4005) #include #pragma warning(pop) #include #include "TextureLoader.h" #if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) && !defined(DXGI_1_2_FORMATS) #define DXGI_1_2_FORMATS #endif //--------------------------------------------------------------------------------- template class ScopedObject { public: explicit ScopedObject(T *p = 0) : _pointer(p) {} ~ScopedObject() { if (_pointer) { _pointer->Release(); _pointer = nullptr; } } bool IsNull() const { return (!_pointer); } T& operator*() { return *_pointer; } T* operator->() { return _pointer; } T** operator&() { return &_pointer; } void Reset(T *p = 0) { if (_pointer) { _pointer->Release(); } _pointer = p; } T* Get() const { return _pointer; } private: ScopedObject(const ScopedObject&); ScopedObject& operator=(const ScopedObject&); T* _pointer; }; //------------------------------------------------------------------------------------- // WIC Pixel Format Translation Data //------------------------------------------------------------------------------------- struct WICTranslate { GUID wic; DXGI_FORMAT format; }; static WICTranslate g_WICFormats[] = { { GUID_WICPixelFormat128bppRGBAFloat, DXGI_FORMAT_R32G32B32A32_FLOAT }, { GUID_WICPixelFormat64bppRGBAHalf, DXGI_FORMAT_R16G16B16A16_FLOAT }, { GUID_WICPixelFormat64bppRGBA, DXGI_FORMAT_R16G16B16A16_UNORM }, { GUID_WICPixelFormat32bppRGBA, DXGI_FORMAT_R8G8B8A8_UNORM }, { GUID_WICPixelFormat32bppBGRA, DXGI_FORMAT_B8G8R8A8_UNORM }, // DXGI 1.1 { GUID_WICPixelFormat32bppBGR, DXGI_FORMAT_B8G8R8X8_UNORM }, // DXGI 1.1 { GUID_WICPixelFormat32bppRGBA1010102XR, DXGI_FORMAT_R10G10B10_XR_BIAS_A2_UNORM }, // DXGI 1.1 { GUID_WICPixelFormat32bppRGBA1010102, DXGI_FORMAT_R10G10B10A2_UNORM }, { GUID_WICPixelFormat32bppRGBE, DXGI_FORMAT_R9G9B9E5_SHAREDEXP }, #ifdef DXGI_1_2_FORMATS { GUID_WICPixelFormat16bppBGRA5551, DXGI_FORMAT_B5G5R5A1_UNORM }, { GUID_WICPixelFormat16bppBGR565, DXGI_FORMAT_B5G6R5_UNORM }, #endif // DXGI_1_2_FORMATS { GUID_WICPixelFormat32bppGrayFloat, DXGI_FORMAT_R32_FLOAT }, { GUID_WICPixelFormat16bppGrayHalf, DXGI_FORMAT_R16_FLOAT }, { GUID_WICPixelFormat16bppGray, DXGI_FORMAT_R16_UNORM }, { GUID_WICPixelFormat8bppGray, DXGI_FORMAT_R8_UNORM }, { GUID_WICPixelFormat8bppAlpha, DXGI_FORMAT_A8_UNORM }, #if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) { GUID_WICPixelFormat96bppRGBFloat, DXGI_FORMAT_R32G32B32_FLOAT }, #endif }; //------------------------------------------------------------------------------------- // WIC Pixel Format nearest conversion table //------------------------------------------------------------------------------------- struct WICConvert { GUID source; GUID target; }; static WICConvert g_WICConvert[] = { // Note target GUID in this conversion table must be one of those directly supported formats (above). { GUID_WICPixelFormatBlackWhite, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM { GUID_WICPixelFormat1bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM { GUID_WICPixelFormat2bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM { GUID_WICPixelFormat4bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM { GUID_WICPixelFormat8bppIndexed, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM { GUID_WICPixelFormat2bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM { GUID_WICPixelFormat4bppGray, GUID_WICPixelFormat8bppGray }, // DXGI_FORMAT_R8_UNORM { GUID_WICPixelFormat16bppGrayFixedPoint, GUID_WICPixelFormat16bppGrayHalf }, // DXGI_FORMAT_R16_FLOAT { GUID_WICPixelFormat32bppGrayFixedPoint, GUID_WICPixelFormat32bppGrayFloat }, // DXGI_FORMAT_R32_FLOAT #ifdef DXGI_1_2_FORMATS { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat16bppBGRA5551 }, // DXGI_FORMAT_B5G5R5A1_UNORM #else { GUID_WICPixelFormat16bppBGR555, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM { GUID_WICPixelFormat16bppBGRA5551, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM { GUID_WICPixelFormat16bppBGR565, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM #endif // DXGI_1_2_FORMATS { GUID_WICPixelFormat32bppBGR101010, GUID_WICPixelFormat32bppRGBA1010102 }, // DXGI_FORMAT_R10G10B10A2_UNORM { GUID_WICPixelFormat24bppBGR, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM { GUID_WICPixelFormat24bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM { GUID_WICPixelFormat32bppPBGRA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM { GUID_WICPixelFormat32bppPRGBA, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM { GUID_WICPixelFormat48bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM { GUID_WICPixelFormat48bppBGR, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM { GUID_WICPixelFormat64bppBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM { GUID_WICPixelFormat64bppPRGBA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM { GUID_WICPixelFormat64bppPBGRA, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM { GUID_WICPixelFormat48bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT { GUID_WICPixelFormat48bppBGRFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT { GUID_WICPixelFormat64bppRGBAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT { GUID_WICPixelFormat64bppBGRAFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT { GUID_WICPixelFormat64bppRGBFixedPoint, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT { GUID_WICPixelFormat64bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT { GUID_WICPixelFormat48bppRGBHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT { GUID_WICPixelFormat96bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT { GUID_WICPixelFormat128bppPRGBAFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT { GUID_WICPixelFormat128bppRGBFloat, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT { GUID_WICPixelFormat128bppRGBAFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT { GUID_WICPixelFormat128bppRGBFixedPoint, GUID_WICPixelFormat128bppRGBAFloat }, // DXGI_FORMAT_R32G32B32A32_FLOAT { GUID_WICPixelFormat32bppCMYK, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM { GUID_WICPixelFormat64bppCMYK, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM { GUID_WICPixelFormat40bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM { GUID_WICPixelFormat80bppCMYKAlpha, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM #if (_WIN32_WINNT >= 0x0602 /*_WIN32_WINNT_WIN8*/) { GUID_WICPixelFormat32bppRGB, GUID_WICPixelFormat32bppRGBA }, // DXGI_FORMAT_R8G8B8A8_UNORM { GUID_WICPixelFormat64bppRGB, GUID_WICPixelFormat64bppRGBA }, // DXGI_FORMAT_R16G16B16A16_UNORM { GUID_WICPixelFormat64bppPRGBAHalf, GUID_WICPixelFormat64bppRGBAHalf }, // DXGI_FORMAT_R16G16B16A16_FLOAT #endif // We don't support n-channel formats }; //-------------------------------------------------------------------------------------- static IWICImagingFactory* _GetWIC() { static IWICImagingFactory* s_Factory = nullptr; if (s_Factory) return s_Factory; HRESULT hr = CoCreateInstance( CLSID_WICImagingFactory, nullptr, CLSCTX_INPROC_SERVER, __uuidof(IWICImagingFactory), (LPVOID*)&s_Factory ); if (FAILED(hr)) { s_Factory = nullptr; return nullptr; } return s_Factory; } //--------------------------------------------------------------------------------- static DXGI_FORMAT _WICToDXGI(const GUID& guid) { for (size_t i = 0; i < _countof(g_WICFormats); ++i) { if (memcmp(&g_WICFormats[i].wic, &guid, sizeof(GUID)) == 0) return g_WICFormats[i].format; } return DXGI_FORMAT_UNKNOWN; } //--------------------------------------------------------------------------------- static size_t _WICBitsPerPixel(REFGUID targetGuid) { IWICImagingFactory* pWIC = _GetWIC(); if (!pWIC) return 0; ScopedObject cinfo; if (FAILED(pWIC->CreateComponentInfo(targetGuid, &cinfo))) return 0; WICComponentType type; if (FAILED(cinfo->GetComponentType(&type))) return 0; if (type != WICPixelFormat) return 0; ScopedObject pfinfo; if (FAILED(cinfo->QueryInterface(__uuidof(IWICPixelFormatInfo), reinterpret_cast(&pfinfo)))) return 0; UINT bpp; if (FAILED(pfinfo->GetBitsPerPixel(&bpp))) return 0; return bpp; } //--------------------------------------------------------------------------------- static HRESULT CreateTextureFromWIC(_In_ ID3D11Device* d3dDevice, _In_opt_ ID3D11DeviceContext* d3dContext, _In_ IWICBitmapFrameDecode *frame, _Out_opt_ ID3D11Resource** texture, _Out_opt_ ID3D11ShaderResourceView** textureView, _In_ size_t maxsize) { UINT width, height; HRESULT hr = frame->GetSize(&width, &height); if (FAILED(hr)) return hr; assert(width > 0 && height > 0); if (!maxsize) { // This is a bit conservative because the hardware could support larger textures than // the Feature Level defined minimums, but doing it this way is much easier and more // performant for WIC than the 'fail and retry' model used by DDSTextureLoader switch (d3dDevice->GetFeatureLevel()) { case D3D_FEATURE_LEVEL_9_1: case D3D_FEATURE_LEVEL_9_2: maxsize = 2048 /*D3D_FL9_1_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; break; case D3D_FEATURE_LEVEL_9_3: maxsize = 4096 /*D3D_FL9_3_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; break; case D3D_FEATURE_LEVEL_10_0: case D3D_FEATURE_LEVEL_10_1: maxsize = 8192 /*D3D10_REQ_TEXTURE2D_U_OR_V_DIMENSION*/; break; default: maxsize = D3D11_REQ_TEXTURE2D_U_OR_V_DIMENSION; break; } } assert(maxsize > 0); UINT twidth, theight; if (width > maxsize || height > maxsize) { float ar = static_cast(height) / static_cast(width); if (width > height) { twidth = static_cast(maxsize); theight = static_cast(static_cast(maxsize) * ar); } else { theight = static_cast(maxsize); twidth = static_cast(static_cast(maxsize) / ar); } assert(twidth <= maxsize && theight <= maxsize); } else { twidth = width; theight = height; } // Determine format WICPixelFormatGUID pixelFormat; hr = frame->GetPixelFormat(&pixelFormat); if (FAILED(hr)) return hr; WICPixelFormatGUID convertGUID; memcpy(&convertGUID, &pixelFormat, sizeof(WICPixelFormatGUID)); size_t bpp = 0; DXGI_FORMAT format = _WICToDXGI(pixelFormat); if (format == DXGI_FORMAT_UNKNOWN) { for (size_t i = 0; i < _countof(g_WICConvert); ++i) { if (memcmp(&g_WICConvert[i].source, &pixelFormat, sizeof(WICPixelFormatGUID)) == 0) { memcpy(&convertGUID, &g_WICConvert[i].target, sizeof(WICPixelFormatGUID)); format = _WICToDXGI(g_WICConvert[i].target); assert(format != DXGI_FORMAT_UNKNOWN); bpp = _WICBitsPerPixel(convertGUID); break; } } if (format == DXGI_FORMAT_UNKNOWN) return HRESULT_FROM_WIN32(ERROR_NOT_SUPPORTED); } else { bpp = _WICBitsPerPixel(pixelFormat); } if (!bpp) return E_FAIL; // Verify our target format is supported by the current device // (handles WDDM 1.0 or WDDM 1.1 device driver cases as well as DirectX 11.0 Runtime without 16bpp format support) UINT support = 0; hr = d3dDevice->CheckFormatSupport(format, &support); if (FAILED(hr) || !(support & D3D11_FORMAT_SUPPORT_TEXTURE2D)) { // Fallback to RGBA 32-bit format which is supported by all devices memcpy(&convertGUID, &GUID_WICPixelFormat32bppRGBA, sizeof(WICPixelFormatGUID)); format = DXGI_FORMAT_R8G8B8A8_UNORM; bpp = 32; } // Allocate temporary memory for image size_t rowPitch = (twidth * bpp + 7) / 8; size_t imageSize = rowPitch * theight; std::unique_ptr temp(new uint8_t[imageSize]); // Load image data if (memcmp(&convertGUID, &pixelFormat, sizeof(GUID)) == 0 && twidth == width && theight == height) { // No format conversion or resize needed hr = frame->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); if (FAILED(hr)) return hr; } else if (twidth != width || theight != height) { // Resize IWICImagingFactory* pWIC = _GetWIC(); if (!pWIC) return E_NOINTERFACE; ScopedObject scaler; hr = pWIC->CreateBitmapScaler(&scaler); if (FAILED(hr)) return hr; hr = scaler->Initialize(frame, twidth, theight, WICBitmapInterpolationModeFant); if (FAILED(hr)) return hr; WICPixelFormatGUID pfScaler; hr = scaler->GetPixelFormat(&pfScaler); if (FAILED(hr)) return hr; if (memcmp(&convertGUID, &pfScaler, sizeof(GUID)) == 0) { // No format conversion needed hr = scaler->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); if (FAILED(hr)) return hr; } else { ScopedObject FC; hr = pWIC->CreateFormatConverter(&FC); if (FAILED(hr)) return hr; hr = FC->Initialize(scaler.Get(), convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom); if (FAILED(hr)) return hr; hr = FC->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); if (FAILED(hr)) return hr; } } else { // Format conversion but no resize IWICImagingFactory* pWIC = _GetWIC(); if (!pWIC) return E_NOINTERFACE; ScopedObject FC; hr = pWIC->CreateFormatConverter(&FC); if (FAILED(hr)) return hr; hr = FC->Initialize(frame, convertGUID, WICBitmapDitherTypeErrorDiffusion, 0, 0, WICBitmapPaletteTypeCustom); if (FAILED(hr)) return hr; hr = FC->CopyPixels(0, static_cast(rowPitch), static_cast(imageSize), temp.get()); if (FAILED(hr)) return hr; } // See if format is supported for auto-gen mipmaps (varies by feature level) bool autogen = false; if (d3dContext != 0 && textureView != 0) // Must have context and shader-view to auto generate mipmaps { UINT fmtSupport = 0; hr = d3dDevice->CheckFormatSupport(format, &fmtSupport); if (SUCCEEDED(hr) && (fmtSupport & D3D11_FORMAT_SUPPORT_MIP_AUTOGEN)) { autogen = true; } } // Create texture D3D11_TEXTURE2D_DESC desc; desc.Width = twidth; desc.Height = theight; desc.MipLevels = (autogen) ? 0 : 1; desc.ArraySize = 1; desc.Format = format; desc.SampleDesc.Count = 1; desc.SampleDesc.Quality = 0; desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = (autogen) ? (D3D11_BIND_SHADER_RESOURCE | D3D11_BIND_RENDER_TARGET) : (D3D11_BIND_SHADER_RESOURCE); desc.CPUAccessFlags = 0; desc.MiscFlags = (autogen) ? D3D11_RESOURCE_MISC_GENERATE_MIPS : 0; D3D11_SUBRESOURCE_DATA initData; initData.pSysMem = temp.get(); initData.SysMemPitch = static_cast(rowPitch); initData.SysMemSlicePitch = static_cast(imageSize); ID3D11Texture2D* tex = nullptr; hr = d3dDevice->CreateTexture2D(&desc, (autogen) ? nullptr : &initData, &tex); if (SUCCEEDED(hr) && tex != 0) { if (textureView != 0) { D3D11_SHADER_RESOURCE_VIEW_DESC SRVDesc; memset(&SRVDesc, 0, sizeof(SRVDesc)); SRVDesc.Format = format; SRVDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D; SRVDesc.Texture2D.MipLevels = (autogen) ? -1 : 1; hr = d3dDevice->CreateShaderResourceView(tex, &SRVDesc, textureView); if (FAILED(hr)) { tex->Release(); return hr; } if (autogen) { assert(d3dContext != 0); d3dContext->UpdateSubresource(tex, 0, nullptr, temp.get(), static_cast(rowPitch), static_cast(imageSize)); d3dContext->GenerateMips(*textureView); } } if (texture != 0) { *texture = tex; } else { #if defined(_DEBUG) || defined(PROFILE) tex->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof("WICTextureLoader") - 1, "WICTextureLoader" ); #endif tex->Release(); } } return hr; } //-------------------------------------------------------------------------------------- HRESULT CreateWICTextureFromMemory(_In_ ID3D11Device* d3dDevice, _In_opt_ ID3D11DeviceContext* d3dContext, _In_bytecount_(wicDataSize) const uint8_t* wicData, _In_ size_t wicDataSize, _Out_opt_ ID3D11Resource** texture, _Out_opt_ ID3D11ShaderResourceView** textureView, _In_ size_t maxsize ) { if (!d3dDevice || !wicData || (!texture && !textureView)) { return E_INVALIDARG; } if (!wicDataSize) { return E_FAIL; } #ifdef _M_AMD64 if (wicDataSize > 0xFFFFFFFF) return HRESULT_FROM_WIN32(ERROR_FILE_TOO_LARGE); #endif IWICImagingFactory* pWIC = _GetWIC(); if (!pWIC) return E_NOINTERFACE; // Create input stream for memory ScopedObject stream; HRESULT hr = pWIC->CreateStream(&stream); if (FAILED(hr)) return hr; hr = stream->InitializeFromMemory(const_cast(wicData), static_cast(wicDataSize)); if (FAILED(hr)) return hr; // Initialize WIC ScopedObject decoder; hr = pWIC->CreateDecoderFromStream(stream.Get(), 0, WICDecodeMetadataCacheOnDemand, &decoder); if (FAILED(hr)) return hr; ScopedObject frame; hr = decoder->GetFrame(0, &frame); if (FAILED(hr)) return hr; hr = CreateTextureFromWIC(d3dDevice, d3dContext, frame.Get(), texture, textureView, maxsize); if (FAILED(hr)) return hr; #if defined(_DEBUG) || defined(PROFILE) if (texture != 0 && *texture != 0) { (*texture)->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof("WICTextureLoader") - 1, "WICTextureLoader" ); } if (textureView != 0 && *textureView != 0) { (*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName, sizeof("WICTextureLoader") - 1, "WICTextureLoader" ); } #endif return hr; } //-------------------------------------------------------------------------------------- HRESULT CreateWICTextureFromFile(_In_ ID3D11Device* d3dDevice, _In_opt_ ID3D11DeviceContext* d3dContext, _In_z_ const wchar_t* fileName, _Out_opt_ ID3D11Resource** texture, _Out_opt_ ID3D11ShaderResourceView** textureView, _In_ size_t maxsize) { if (!d3dDevice || !fileName || (!texture && !textureView)) { return E_INVALIDARG; } IWICImagingFactory* pWIC = _GetWIC(); if (!pWIC) return E_NOINTERFACE; // Initialize WIC ScopedObject decoder; HRESULT hr = pWIC->CreateDecoderFromFilename(fileName, 0, GENERIC_READ, WICDecodeMetadataCacheOnDemand, &decoder); if (FAILED(hr)) return hr; ScopedObject frame; hr = decoder->GetFrame(0, &frame); if (FAILED(hr)) return hr; hr = CreateTextureFromWIC(d3dDevice, d3dContext, frame.Get(), texture, textureView, maxsize); if (FAILED(hr)) return hr; #if defined(_DEBUG) || defined(PROFILE) if (texture != 0 || textureView != 0) { CHAR strFileA[MAX_PATH]; WideCharToMultiByte(CP_ACP, WC_NO_BEST_FIT_CHARS, fileName, -1, strFileA, MAX_PATH, nullptr, FALSE ); const CHAR* pstrName = strrchr(strFileA, '\\'); if (!pstrName) { pstrName = strFileA; } else { pstrName++; } if (texture != 0 && *texture != 0) { (*texture)->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast(strnlen_s(pstrName, MAX_PATH)), pstrName ); } if (textureView != 0 && *textureView != 0) { (*textureView)->SetPrivateData(WKPDID_D3DDebugObjectName, static_cast(strnlen_s(pstrName, MAX_PATH)), pstrName ); } } #endif return hr; } assimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/VertexShader.hlsl0000644002537200234200000000065013213503245031317 0ustar zmoelnigiemuserscbuffer ConstantBuffer : register(b0) { matrix World; matrix View; matrix Projection; } struct VOut { float4 pos : SV_POSITION; float2 texcoord : TEXCOORD; }; VOut main(float4 pos : POSITION, float2 texcoord : TEXCOORD) { VOut output; output.pos = mul(pos, World); output.pos = mul(output.pos, View); output.pos = mul(output.pos, Projection); output.texcoord = texcoord; return output; }assimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/PixelShader.hlsl0000644002537200234200000000034213213503245031121 0ustar zmoelnigiemusersTexture2D diffTexture; SamplerState SampleType; float4 main(float4 pos : SV_POSITION, float2 texcoord : TEXCOORD) : SV_TARGET { float4 textureColor = diffTexture.Sample(SampleType, texcoord); return textureColor; }assimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.cpp0000644002537200234200000001224713213503245030727 0ustar zmoelnigiemusers#include "ModelLoader.h" ModelLoader::ModelLoader() { } ModelLoader::~ModelLoader() { } bool ModelLoader::Load(HWND hwnd, ID3D11Device * dev, ID3D11DeviceContext * devcon, std::string filename) { Assimp::Importer importer; const aiScene* pScene = importer.ReadFile(filename, aiProcess_Triangulate | aiProcess_ConvertToLeftHanded); if (pScene == NULL) return false; this->directory = filename.substr(0, filename.find_last_of('/')); this->dev = dev; this->hwnd = hwnd; processNode(pScene->mRootNode, pScene); return true; } void ModelLoader::Draw(ID3D11DeviceContext * devcon) { for (int i = 0; i < meshes.size(); i++) { meshes[i].Draw(devcon); } } string textype; Mesh ModelLoader::processMesh(aiMesh * mesh, const aiScene * scene) { // Data to fill vector vertices; vector indices; vector textures; if (mesh->mMaterialIndex >= 0) { aiMaterial* mat = scene->mMaterials[mesh->mMaterialIndex]; if (textype.empty()) textype = determineTextureType(scene, mat); } // Walk through each of the mesh's vertices for (UINT i = 0; i < mesh->mNumVertices; i++) { VERTEX vertex; vertex.X = mesh->mVertices[i].x; vertex.Y = mesh->mVertices[i].y; vertex.Z = mesh->mVertices[i].z; if (mesh->mTextureCoords[0]) { vertex.texcoord.x = (float)mesh->mTextureCoords[0][i].x; vertex.texcoord.y = (float)mesh->mTextureCoords[0][i].y; } vertices.push_back(vertex); } for (UINT i = 0; i < mesh->mNumFaces; i++) { aiFace face = mesh->mFaces[i]; for (UINT j = 0; j < face.mNumIndices; j++) indices.push_back(face.mIndices[j]); } if (mesh->mMaterialIndex >= 0) { aiMaterial* material = scene->mMaterials[mesh->mMaterialIndex]; vector diffuseMaps = this->loadMaterialTextures(material, aiTextureType_DIFFUSE, "texture_diffuse", scene); textures.insert(textures.end(), diffuseMaps.begin(), diffuseMaps.end()); } return Mesh(dev, vertices, indices, textures); } vector ModelLoader::loadMaterialTextures(aiMaterial * mat, aiTextureType type, string typeName, const aiScene * scene) { vector textures; for (UINT i = 0; i < mat->GetTextureCount(type); i++) { aiString str; mat->GetTexture(type, i, &str); // Check if texture was loaded before and if so, continue to next iteration: skip loading a new texture bool skip = false; for (UINT j = 0; j < textures_loaded.size(); j++) { if (std::strcmp(textures_loaded[j].path.c_str(), str.C_Str()) == 0) { textures.push_back(textures_loaded[j]); skip = true; // A texture with the same filepath has already been loaded, continue to next one. (optimization) break; } } if (!skip) { // If texture hasn't been loaded already, load it HRESULT hr; Texture texture; if (textype == "embedded compressed texture") { int textureindex = getTextureIndex(&str); texture.texture = getTextureFromModel(scene, textureindex); } else { string filename = string(str.C_Str()); filename = directory + '/' + filename; wstring filenamews = wstring(filename.begin(), filename.end()); hr = CreateWICTextureFromFile(dev, devcon, filenamews.c_str(), nullptr, &texture.texture); if (FAILED(hr)) MessageBox(hwnd, "Texture couldn't be loaded", "Error!", MB_ICONERROR | MB_OK); } texture.type = typeName; texture.path = str.C_Str(); textures.push_back(texture); this->textures_loaded.push_back(texture); // Store it as texture loaded for entire model, to ensure we won't unnecesery load duplicate textures. } } return textures; } void ModelLoader::Close() { for (int i = 0; i < meshes.size(); i++) { meshes[i].Close(); } dev->Release(); } void ModelLoader::processNode(aiNode * node, const aiScene * scene) { for (UINT i = 0; i < node->mNumMeshes; i++) { aiMesh* mesh = scene->mMeshes[node->mMeshes[i]]; meshes.push_back(this->processMesh(mesh, scene)); } for (UINT i = 0; i < node->mNumChildren; i++) { this->processNode(node->mChildren[i], scene); } } string ModelLoader::determineTextureType(const aiScene * scene, aiMaterial * mat) { aiString textypeStr; mat->GetTexture(aiTextureType_DIFFUSE, 0, &textypeStr); string textypeteststr = textypeStr.C_Str(); if (textypeteststr == "*0" || textypeteststr == "*1" || textypeteststr == "*2" || textypeteststr == "*3" || textypeteststr == "*4" || textypeteststr == "*5") { if (scene->mTextures[0]->mHeight == 0) { return "embedded compressed texture"; } else { return "embedded non-compressed texture"; } } if (textypeteststr.find('.') != string::npos) { return "textures are on disk"; } } int ModelLoader::getTextureIndex(aiString * str) { string tistr; tistr = str->C_Str(); tistr = tistr.substr(1); return stoi(tistr); } ID3D11ShaderResourceView * ModelLoader::getTextureFromModel(const aiScene * scene, int textureindex) { HRESULT hr; ID3D11ShaderResourceView *texture; int* size = reinterpret_cast(&scene->mTextures[textureindex]->mWidth); hr = CreateWICTextureFromMemory(dev, devcon, reinterpret_cast(scene->mTextures[textureindex]->pcData), *size, nullptr, &texture); if (FAILED(hr)) MessageBox(hwnd, "Texture couldn't be created from memory!", "Error!", MB_ICONERROR | MB_OK); return texture; } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootassimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj.filtersassimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj0000644002537200234200000000343213213503245034110 0ustar zmoelnigiemusers {4FC737F1-C7A5-4376-A066-2A32D752A2FF} cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;hm;inl;inc;xsd {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms {b6a86d3e-70a5-4d1e-ba05-c20902300206} Source Files Source Files Source Files Shaders Shaders Header Files Header Files Header Files assimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/ModelLoader.h0000644002537200234200000000210013213503245030357 0ustar zmoelnigiemusers#ifndef MODEL_LOADER_H #define MODEL_LOADER_H #include #include #include #include #include #include #include "Mesh.h" #include "TextureLoader.h" using namespace DirectX; class ModelLoader { public: ModelLoader(); ~ModelLoader(); bool Load(HWND hwnd, ID3D11Device* dev, ID3D11DeviceContext* devcon, std::string filename); void Draw(ID3D11DeviceContext* devcon); void Close(); private: ID3D11Device *dev; ID3D11DeviceContext *devcon; std::vector meshes; string directory; vector textures_loaded; HWND hwnd; void processNode(aiNode* node, const aiScene* scene); Mesh processMesh(aiMesh* mesh, const aiScene* scene); vector loadMaterialTextures(aiMaterial* mat, aiTextureType type, string typeName, const aiScene* scene); string determineTextureType(const aiScene* scene, aiMaterial* mat); int getTextureIndex(aiString* str); ID3D11ShaderResourceView* getTextureFromModel(const aiScene* scene, int textureindex); }; #endif // !MODEL_LOADER_H assimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/SimpleTexturedDirectx11.vcxproj0000644002537200234200000001620213213503245034107 0ustar zmoelnigiemusers Debug Win32 Release Win32 Debug x64 Release x64 15.0 {E3B160B5-E71F-4F3F-9310-B8F156F736D8} SimpleTexturedDirectx11 10.0.14393.0 Application true v141 MultiByte Application false v141 true MultiByte Application true v141 MultiByte Application false v141 true MultiByte $(IncludePath);E:\OpenGL VS Files\include $(LibraryPath);E:\OpenGL VS Files\lib Level3 Disabled true assimp-vc140-mt.lib;%(AdditionalDependencies) Level3 Disabled true Level3 MaxSpeed true true true true true Level3 MaxSpeed true true true true true Pixel Pixel Pixel Pixel Vertex Vertex Vertex Vertex assimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/Mesh.h0000644002537200234200000000400513213503245027072 0ustar zmoelnigiemusers#ifndef MESH_H #define MESH_H #include #include #include #include #include using namespace std; #include #include #include using namespace DirectX; struct VERTEX { FLOAT X, Y, Z; XMFLOAT2 texcoord; }; struct Texture { string type; string path; ID3D11ShaderResourceView *texture; }; class Mesh { public: vector vertices; vector indices; vector textures; ID3D11Device *dev; Mesh(ID3D11Device *dev, vector vertices, vector indices, vector textures) { this->vertices = vertices; this->indices = indices; this->textures = textures; this->dev = dev; this->setupMesh(dev); } void Draw(ID3D11DeviceContext *devcon) { UINT stride = sizeof(VERTEX); UINT offset = 0; devcon->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset); devcon->IASetIndexBuffer(IndexBuffer, DXGI_FORMAT_R32_UINT, 0); devcon->PSSetShaderResources(0, 1, &textures[0].texture); devcon->DrawIndexed(indices.size(), 0, 0); } void Close() { VertexBuffer->Release(); IndexBuffer->Release(); } private: /* Render data */ ID3D11Buffer *VertexBuffer, *IndexBuffer; /* Functions */ // Initializes all the buffer objects/arrays bool setupMesh(ID3D11Device *dev) { HRESULT hr; D3D11_BUFFER_DESC vbd; vbd.Usage = D3D11_USAGE_IMMUTABLE; vbd.ByteWidth = sizeof(VERTEX) * vertices.size(); vbd.BindFlags = D3D11_BIND_VERTEX_BUFFER; vbd.CPUAccessFlags = 0; vbd.MiscFlags = 0; D3D11_SUBRESOURCE_DATA initData; initData.pSysMem = &vertices[0]; hr = dev->CreateBuffer(&vbd, &initData, &VertexBuffer); if (FAILED(hr)) return false; D3D11_BUFFER_DESC ibd; ibd.Usage = D3D11_USAGE_IMMUTABLE; ibd.ByteWidth = sizeof(UINT) * indices.size(); ibd.BindFlags = D3D11_BIND_INDEX_BUFFER; ibd.CPUAccessFlags = 0; ibd.MiscFlags = 0; initData.pSysMem = &indices[0]; hr = dev->CreateBuffer(&ibd, &initData, &IndexBuffer); if (FAILED(hr)) return false; } }; #endif assimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11/main.cpp0000644002537200234200000003460713213503245027470 0ustar zmoelnigiemusers// --------------------------------------------------------------------------- // Simple Assimp Directx11 Sample // This is a very basic sample and only reads diffuse texture // but this can load both embedded textures in fbx and non-embedded textures // // // Replace ourModel->Load(hwnd, dev, devcon, "Models/myModel.fbx") this with your // model name (line 480) // If your model isn't a fbx with embedded textures make sure your model's // textures are in same directory as your model // // // Written by IAS. :) // --------------------------------------------------------------------------- #include #include #include #include #include #include #include "ModelLoader.h" #pragma comment (lib, "d3d11.lib") #pragma comment (lib, "Dxgi.lib") #pragma comment(lib,"d3dcompiler.lib") #pragma comment (lib, "dxguid.lib") using namespace DirectX; // ------------------------------------------------------------ // Structs // ------------------------------------------------------------ struct ConstantBuffer { XMMATRIX mWorld; XMMATRIX mView; XMMATRIX mProjection; }; // ------------------------------------------------------------ // Window Variables // ------------------------------------------------------------ #define SCREEN_WIDTH 800 #define SCREEN_HEIGHT 600 const char g_szClassName[] = "directxWindowClass"; UINT width, height; HWND hwnd; // ------------------------------------------------------------ // DirectX Variables // ------------------------------------------------------------ D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL; D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0; ID3D11Device *dev; ID3D11Device1 *dev1; ID3D11DeviceContext *devcon; ID3D11DeviceContext1 *devcon1; IDXGISwapChain *swapchain; IDXGISwapChain1 *swapchain1; ID3D11RenderTargetView *backbuffer; ID3D11VertexShader *pVS; ID3D11PixelShader *pPS; ID3D11InputLayout *pLayout; ID3D11Buffer *pConstantBuffer; ID3D11Texture2D *g_pDepthStencil; ID3D11DepthStencilView *g_pDepthStencilView; ID3D11SamplerState *TexSamplerState; XMMATRIX m_World; XMMATRIX m_View; XMMATRIX m_Projection; // ------------------------------------------------------------ // Function identifiers // ------------------------------------------------------------ void InitD3D(HINSTANCE hinstance, HWND hWnd); void CleanD3D(void); void RenderFrame(void); void InitPipeline(); void InitGraphics(); HRESULT CompileShaderFromFile(LPCWSTR pFileName, const D3D_SHADER_MACRO* pDefines, LPCSTR pEntryPoint, LPCSTR pShaderModel, ID3DBlob** ppBytecodeBlob); void Throwanerror(LPCSTR errormessage); // ------------------------------------------------------------ // Our Model // ------------------------------------------------------------ ModelLoader *ourModel; LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) { case WM_CLOSE: DestroyWindow(hwnd); break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { WNDCLASSEX wc; MSG msg; wc.cbSize = sizeof(WNDCLASSEX); wc.style = 0; wc.lpfnWndProc = WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = g_szClassName; wc.hIconSm = LoadIcon(NULL, IDI_APPLICATION); if (!RegisterClassEx(&wc)) { MessageBox(NULL, "Window Registration Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } RECT wr = { 0,0, SCREEN_WIDTH, SCREEN_HEIGHT }; AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); hwnd = CreateWindowEx( WS_EX_CLIENTEDGE, g_szClassName, " Simple Textured Directx11 Sample ", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, wr.right - wr.left, wr.bottom - wr.top, NULL, NULL, hInstance, NULL ); if (hwnd == NULL) { MessageBox(NULL, "Window Creation Failed!", "Error!", MB_ICONEXCLAMATION | MB_OK); return 0; } ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); width = wr.right - wr.left; height = wr.bottom - wr.top; InitD3D(hInstance, hwnd); while (true) { if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); if (msg.message == WM_QUIT) break; } RenderFrame(); } CleanD3D(); return msg.wParam; } void InitD3D(HINSTANCE hinstance, HWND hWnd) { HRESULT hr; UINT createDeviceFlags = 0; #ifdef _DEBUG createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG; #endif D3D_DRIVER_TYPE driverTypes[] = { D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP, D3D_DRIVER_TYPE_REFERENCE, }; UINT numDriverTypes = ARRAYSIZE(driverTypes); D3D_FEATURE_LEVEL featureLevels[] = { D3D_FEATURE_LEVEL_11_1, D3D_FEATURE_LEVEL_11_0, D3D_FEATURE_LEVEL_10_1, D3D_FEATURE_LEVEL_10_0, }; UINT numFeatureLevels = ARRAYSIZE(featureLevels); for (UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++) { g_driverType = driverTypes[driverTypeIndex]; hr = D3D11CreateDevice(nullptr, g_driverType, nullptr, createDeviceFlags, featureLevels, numFeatureLevels, D3D11_SDK_VERSION, &dev, &g_featureLevel, &devcon); if (hr == E_INVALIDARG) { // DirectX 11.0 platforms will not recognize D3D_FEATURE_LEVEL_11_1 so we need to retry without it hr = D3D11CreateDevice(nullptr, g_driverType, nullptr, createDeviceFlags, &featureLevels[1], numFeatureLevels - 1, D3D11_SDK_VERSION, &dev, &g_featureLevel, &devcon); } if (SUCCEEDED(hr)) break; } if (FAILED(hr)) Throwanerror("Directx Device Creation Failed!"); UINT m4xMsaaQuality; dev->CheckMultisampleQualityLevels( DXGI_FORMAT_R8G8B8A8_UNORM, 4, &m4xMsaaQuality); // Obtain DXGI factory from device (since we used nullptr for pAdapter above) IDXGIFactory1* dxgiFactory = nullptr; { IDXGIDevice* dxgiDevice = nullptr; hr = dev->QueryInterface(__uuidof(IDXGIDevice), reinterpret_cast(&dxgiDevice)); if (SUCCEEDED(hr)) { IDXGIAdapter* adapter = nullptr; hr = dxgiDevice->GetAdapter(&adapter); if (SUCCEEDED(hr)) { hr = adapter->GetParent(__uuidof(IDXGIFactory1), reinterpret_cast(&dxgiFactory)); adapter->Release(); } dxgiDevice->Release(); } } if (FAILED(hr)) Throwanerror("DXGI Factory couldn't be obtained!"); // Create swap chain IDXGIFactory2* dxgiFactory2 = nullptr; hr = dxgiFactory->QueryInterface(__uuidof(IDXGIFactory2), reinterpret_cast(&dxgiFactory2)); if (dxgiFactory2) { // DirectX 11.1 or later hr = dev->QueryInterface(__uuidof(ID3D11Device1), reinterpret_cast(&dev1)); if (SUCCEEDED(hr)) { (void)devcon->QueryInterface(__uuidof(ID3D11DeviceContext1), reinterpret_cast(&devcon1)); } DXGI_SWAP_CHAIN_DESC1 sd; ZeroMemory(&sd, sizeof(sd)); sd.Width = SCREEN_WIDTH; sd.Height = SCREEN_HEIGHT; sd.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.SampleDesc.Count = 4; sd.SampleDesc.Quality = m4xMsaaQuality - 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.BufferCount = 1; hr = dxgiFactory2->CreateSwapChainForHwnd(dev, hWnd, &sd, nullptr, nullptr, &swapchain1); if (SUCCEEDED(hr)) { hr = swapchain1->QueryInterface(__uuidof(IDXGISwapChain), reinterpret_cast(&swapchain)); } dxgiFactory2->Release(); } else { // DirectX 11.0 systems DXGI_SWAP_CHAIN_DESC sd; ZeroMemory(&sd, sizeof(sd)); sd.BufferCount = 1; sd.BufferDesc.Width = SCREEN_WIDTH; sd.BufferDesc.Height = SCREEN_HEIGHT; sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; sd.BufferDesc.RefreshRate.Numerator = 60; sd.BufferDesc.RefreshRate.Denominator = 1; sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; sd.OutputWindow = hWnd; sd.SampleDesc.Count = 1; sd.SampleDesc.Quality = m4xMsaaQuality - 1; sd.Windowed = TRUE; hr = dxgiFactory->CreateSwapChain(dev, &sd, &swapchain); } // Note this tutorial doesn't handle full-screen swapchains so we block the ALT+ENTER shortcut dxgiFactory->MakeWindowAssociation(hwnd, DXGI_MWA_NO_ALT_ENTER); dxgiFactory->Release(); if (FAILED(hr)) Throwanerror("Swapchain Creation Failed!"); ID3D11Texture2D *pBackBuffer; swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer); dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer); pBackBuffer->Release(); D3D11_TEXTURE2D_DESC descDepth; ZeroMemory(&descDepth, sizeof(descDepth)); descDepth.Width = SCREEN_WIDTH; descDepth.Height = SCREEN_HEIGHT; descDepth.MipLevels = 1; descDepth.ArraySize = 1; descDepth.Format = DXGI_FORMAT_D24_UNORM_S8_UINT; descDepth.SampleDesc.Count = 4; descDepth.SampleDesc.Quality = m4xMsaaQuality - 1; descDepth.Usage = D3D11_USAGE_DEFAULT; descDepth.BindFlags = D3D11_BIND_DEPTH_STENCIL; descDepth.CPUAccessFlags = 0; descDepth.MiscFlags = 0; hr = dev->CreateTexture2D(&descDepth, nullptr, &g_pDepthStencil); if (FAILED(hr)) Throwanerror("Depth Stencil Texture couldn't be created!"); // Create the depth stencil view D3D11_DEPTH_STENCIL_VIEW_DESC descDSV; ZeroMemory(&descDSV, sizeof(descDSV)); descDSV.Format = descDepth.Format; descDSV.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2D; descDSV.Texture2D.MipSlice = 0; hr = dev->CreateDepthStencilView(g_pDepthStencil, 0, &g_pDepthStencilView); if (FAILED(hr)) { Throwanerror("Depth Stencil View couldn't be created!"); } devcon->OMSetRenderTargets(1, &backbuffer, g_pDepthStencilView); D3D11_RASTERIZER_DESC rasterDesc; ID3D11RasterizerState *rasterState; rasterDesc.AntialiasedLineEnable = false; rasterDesc.CullMode = D3D11_CULL_BACK; rasterDesc.DepthBias = 0; rasterDesc.DepthBiasClamp = 0.0f; rasterDesc.DepthClipEnable = true; rasterDesc.FillMode = D3D11_FILL_SOLID; rasterDesc.FrontCounterClockwise = false; rasterDesc.MultisampleEnable = false; rasterDesc.ScissorEnable = false; rasterDesc.SlopeScaledDepthBias = 0.0f; dev->CreateRasterizerState(&rasterDesc, &rasterState); devcon->RSSetState(rasterState); D3D11_VIEWPORT viewport; ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT)); viewport.TopLeftX = 0; viewport.TopLeftY = 0; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; viewport.Width = SCREEN_WIDTH; viewport.Height = SCREEN_HEIGHT; devcon->RSSetViewports(1, &viewport); InitPipeline(); InitGraphics(); } void CleanD3D(void) { swapchain->SetFullscreenState(FALSE, NULL); ourModel->Close(); g_pDepthStencil->Release(); g_pDepthStencilView->Release(); pLayout->Release(); pVS->Release(); pPS->Release(); pConstantBuffer->Release(); swapchain->Release(); backbuffer->Release(); dev->Release(); devcon->Release(); } void RenderFrame(void) { static float t = 0.0f; static ULONGLONG timeStart = 0; ULONGLONG timeCur = GetTickCount64(); if (timeStart == 0) timeStart = timeCur; t = (timeCur - timeStart) / 1000.0f; float clearColor[4] = { 0.0f, 0.2f, 0.4f, 1.0f }; devcon->ClearRenderTargetView(backbuffer, clearColor); devcon->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0); devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); m_World = XMMatrixRotationY(-t); ConstantBuffer cb; cb.mWorld = XMMatrixTranspose(m_World); cb.mView = XMMatrixTranspose(m_View); cb.mProjection = XMMatrixTranspose(m_Projection); devcon->UpdateSubresource(pConstantBuffer, 0, nullptr, &cb, 0, 0); devcon->VSSetShader(pVS, 0, 0); devcon->VSSetConstantBuffers(0, 1, &pConstantBuffer); devcon->PSSetShader(pPS, 0, 0); devcon->PSSetSamplers(0, 1, &TexSamplerState); ourModel->Draw(devcon); swapchain->Present(0, 0); } void InitPipeline() { ID3DBlob *VS, *PS; CompileShaderFromFile(L"VertexShader.hlsl", 0, "main", "vs_4_0", &VS); CompileShaderFromFile(L"PixelShader.hlsl", 0, "main", "ps_4_0", &PS); dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS); dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS); D3D11_INPUT_ELEMENT_DESC ied[] = { { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }, { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0 } }; dev->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout); devcon->IASetInputLayout(pLayout); } void InitGraphics() { HRESULT hr; m_Projection = XMMatrixPerspectiveFovLH(XM_PIDIV4, SCREEN_WIDTH / (float)SCREEN_HEIGHT, 0.01f, 1000.0f); D3D11_BUFFER_DESC bd; ZeroMemory(&bd, sizeof(bd)); bd.Usage = D3D11_USAGE_DEFAULT; bd.ByteWidth = sizeof(ConstantBuffer); bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER; bd.CPUAccessFlags = 0; hr = dev->CreateBuffer(&bd, nullptr, &pConstantBuffer); if (FAILED(hr)) Throwanerror("Constant buffer couldn't be created"); D3D11_SAMPLER_DESC sampDesc; ZeroMemory(&sampDesc, sizeof(sampDesc)); sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR; sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP; sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP; sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP; sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER; sampDesc.MinLOD = 0; sampDesc.MaxLOD = D3D11_FLOAT32_MAX; hr = dev->CreateSamplerState(&sampDesc, &TexSamplerState); if (FAILED(hr)) Throwanerror("Texture sampler state couldn't be created"); XMVECTOR Eye = XMVectorSet(0.0f, 5.0f, -300.0f, 0.0f); XMVECTOR At = XMVectorSet(0.0f, 100.0f, 0.0f, 0.0f); XMVECTOR Up = XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f); m_View = XMMatrixLookAtLH(Eye, At, Up); ourModel = new ModelLoader; if (!ourModel->Load(hwnd, dev, devcon, "Models/myModel.fbx")) Throwanerror("Model couldn't be loaded"); } HRESULT CompileShaderFromFile(LPCWSTR pFileName, const D3D_SHADER_MACRO* pDefines, LPCSTR pEntryPoint, LPCSTR pShaderModel, ID3DBlob** ppBytecodeBlob) { UINT compileFlags = D3DCOMPILE_ENABLE_STRICTNESS | D3DCOMPILE_PACK_MATRIX_COLUMN_MAJOR; #ifdef _DEBUG compileFlags |= D3DCOMPILE_DEBUG; #endif ID3DBlob* pErrorBlob = NULL; HRESULT result = D3DCompileFromFile(pFileName, pDefines, D3D_COMPILE_STANDARD_FILE_INCLUDE, pEntryPoint, pShaderModel, compileFlags, 0, ppBytecodeBlob, &pErrorBlob); if (FAILED(result)) { if (pErrorBlob != NULL) OutputDebugStringA((LPCSTR)pErrorBlob->GetBufferPointer()); } if (pErrorBlob != NULL) pErrorBlob->Release(); return result; } void Throwanerror(LPCSTR errormessage) { MessageBox(hwnd, errormessage, "Error!", MB_ICONERROR | MB_OK); }assimp-4.1.0/samples/SimpleTexturedDirectx11/SimpleTexturedDirectx11.sln0000644002537200234200000000250713213503245026550 0ustar zmoelnigiemusers Microsoft Visual Studio Solution File, Format Version 12.00 # Visual Studio 15 VisualStudioVersion = 15.0.26228.9 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleTexturedDirectx11", "SimpleTexturedDirectx11\SimpleTexturedDirectx11.vcxproj", "{E3B160B5-E71F-4F3F-9310-B8F156F736D8}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 Debug|x86 = Debug|x86 Release|x64 = Release|x64 Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.ActiveCfg = Debug|x64 {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x64.Build.0 = Debug|x64 {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.ActiveCfg = Debug|Win32 {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Debug|x86.Build.0 = Debug|Win32 {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.ActiveCfg = Release|x64 {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x64.Build.0 = Release|x64 {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.ActiveCfg = Release|Win32 {E3B160B5-E71F-4F3F-9310-B8F156F736D8}.Release|x86.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal assimp-4.1.0/samples/README0000644002537200234200000000356013213503245015604 0ustar zmoelnigiemusers ASSIMP SAMPLES README ===================== 1. General ---------- This directory contains various samples to illustrate Assimp's use in various real-world environments. Workspaces to build the samples can be found in the respective directories. The VC workspaces copy the created executables to the ./bin directory. All GL-based samples depend on GLUT, some on DevIL. For convenience, these libraries are included in the repository in their respective Windows/x86 prebuilt versions. To build on linux, install the required packages using the package manager of your choice. Also note that the VS workspaces link against the DLL version of the Assimp library, thus you need to build it in the first place ( assimp-release-dll build configuration). The Assimp DLL needs to be copied to ./bin as well (the VS workspaces will try to do this automatically). 2. List of samples ------------------ SimpleOpenGL A very simple and straightforward OpenGL sample. It loads a model (gets the path to it on the command line, default is dwarf.x) and displays the model as wireframe. Animations and materials are not evaluated at all. This samples uses the C interface to Assimp. Basic materials are displayed, but no textures. This sample should work virtually everywhere, provided glut is available. SimpleTexturedOpenGL An extended OpenGL sample, featuring texturing using the DevIL library. Based on SimpleOpenGL and the NeHe GL tutorial style. This is a Windows-only sample. This sample was kindly provided by SamHayne (http://sf.net/users/samhayne/) See http://sourceforge.net/projects/assimp/forums/forum/817654/topic/3736373 SimpleAssimpViewX A Mac OSX-based viewer app. This sample was kindly provided by drparallax. See http://sourceforge.net/projects/assimp/forums/forum/817654/topic/3917829 assimp-4.1.0/samples/DevIL/0000755002537200234200000000000013213503245015663 5ustar zmoelnigiemusersassimp-4.1.0/samples/DevIL/CREDITS0000644002537200234200000002206613213503245016711 0ustar zmoelnigiemusersCredits as of 02/06/2009 ------------------------ If I inadvertently omitted anyone's name from this list, please e-mail me at doomwiz@users.sourceforge.net to remedy the problem. James Joplin, alias jayjay (rjoplin@webzone.net) for all his invaluable help and encouragement with DevIL. Edouard Gomez for his invaluable help. All the #flipCode gang for their support. All my friends at uni for their support. SoftImage .pic support based off of code obtained from http://www.swin.edu.au/astronomy/pbourke/dataformats/ TestPic, used in TestIL http://www.paintlib.de/paintlib/testpic.zip Png Test Images http://www.schaik.com/pngsuite/pngsuite.html John Villar (john.villar@eliaschev.com) for making the suggestion of not letting the user use ILimage structs but instead binding images like OpenGL. He also made a suggestion on how to load luminance .jpg images, along with other suggestions. http://www.opengl.org/Coding/KilgardTechniques/oglpitfall/oglpitfall.html section 6 for the values the NTSC uses, so I could convert from coloured images to luminance values. Kodak Photo CD code from the .pcd link on http://www.wotsit.org. Foper (foper@hotmail.com) from #flipCode for supplying the excellent flipcode.jpg in testil\in. The original can be found at http://webpatterns.com/flip/flipshow.htm Lightman (cdthompson@home.net) from #flipCode for restructuring the project into /bin, /obj, etc. Alexander Blach (alexander@abee.de) from #flipCode for creating the Delphi headers and test app. He figured out that we needed to use .def files to prevent name decoration of the dlls. He has contributed multiple ideas and found flaws. Alexander also created a lovely documentation database to help with documenting DevIL. Randy Heit for finding problems in my Doom texture code. Oliver Kurowski (oliver.kurowski@gmx.de) for locating a bug in ilut's DllMain() and another very harmful bug with ilDeleteImages(). Ender Wiggin's article on "Elementary Digital Filtering", found at http://www.gamedev.net/reference/programming/features/edf/ for many filters in DevIL. SGI's "Graphica Obscura" site at http://www.sgi.com/grafica/matrix/index.html for several filters in DevIL. The http://bae.fse.missouri.edu/luw/course/image/project1/project1.html page for help in determining filter code for Graphica Obscura's interpolation article at http://www.sgi.com/grafica/interp/index.html. Matt Denham for suggesting optimizations in ilNegativeImage(), iluEdgeDetectS() and iluEdgeDetectP(). Timo Heister (Timo-Heister@gmx.de) from #flipCode for creating the original Visual Basic headers and test apps for VB. The OpenGL SuperBible for code for ilutGetHPal(). DJ Luminescent (luminescent@uswest.net) for finding a couple of bugs in the .bmp-loading code and diligently beta testing. Lionel Brits, alias Zaewo from #flipCode for slapping me around and telling me how Microsoft does their .bmp padding. He then wrote most of the iluEqualize() code from the base code on http://www.manning.com/Kabir/Files.html . Joel Wilsson, alias Siigron (siigron@hotmail.com) for pointing-out several design flaws that I (Denton) had introduced and posing very useful suggestions. Sean Montgomery, alias Vapor (sean@astralfx.com) for patiently listening to my endless drivel about DevIL. Perlin Noise site http://freespace.virgin.net/hugo.elias/models/m_perlin.htm for information on interpolation used in iluScale(). Shimon Shvartsbroit, alias MasterBoy (cobra11@netvision.net.il) from #flipCode for explaining bilinear interpolation to me. Lbm source from http://www.wotsit.org Eran Kampf, alias ttentacle (ekampf@internet-zahav.net) for giving me resource-loading code for ilutLoadResource and helping with the Windows clipboard functions. Strumpf from #flipCode for writing a really good DirectDraw class for me to use in the DDraw test, which is based off of his test, too. NullSoft (http://www.nullsoft.com), for their SuperPiMP installer. It is extremely easy to learn to use and very powerful. Serun from #flipCode for noticing that Quake2 .pcx files sometimes don't have the checksum byte for palette'd .pcx files. Conor Stokes, aka DirtyPunk from #flipCode for helping explain several things to me. Half-Life model viewer sources (at http://www.swissquake.ch/chumbalum-soft/) for specs for the Half-Life model format. Rich Schwab, alias endura (endura29@hotmail.com) for contributing girlfriend.cpp. The Djgpp libc sources (http://www.delorie.com/djgpp), from where I copied several functions. Roman Podobedov (romka@ut.ee) of Romka Graphics (http://romka.demonews.com) for his colour quantization sources, which he was kind enough to let me use. Pcx document on http://www.wotsit.org for .pcx saving code. http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue2.html#Insight for iluWave(). .lif specs from http://www.infinite-mass.com/bob/files/lifed.zip and http://www.infinite-mass.com/bob/files/lif.zip Rune Kock (rune@vupti.com) for writing the new Visual Basic headers and for finding a return bug in iluScaleAdvanced. Julien Verchere and Xavier Decoret for suggesting that I use const char*'s instead of char*'s as function parameters. Jason Reeve (jason@retribution-entertainment.com) for finding a bug in iluCrop, several origin-related problems, and helping me bring my targa-loading code up to spec. Darren Adams for telling me the #pragmas to use in MSVC++ to disable the console window in a "console app". David Gould for getting onto me about my crappy Linux support. David Galeano for his DX8 Surface to TGA code, modified to save to any texture. The original can be found at http://rt000s2p.eresmas.net/downloads.htm RLE code from TrueVision's TGA sample code available as Tgautils.zip at ftp://ftp.truevision.com/pub/TGA.File.Format.Spec/PC.Version/ Jeroen Janssen for creating a Mandrake RPM patch for DevIL. Greg Priem for his help with supporting libungif and some various other things. Nelson Rush for SDL surface support and finding several bugs with DevIL. George McBay for his wonderful help finding bugs in my mipmapping code. Marco Kgler for finding bugs in my .jpg and .png code. Falco Kleinschmidt for fixing problems with the Linux makefiles. Olivier Bucher for finding a bug in saving 8-bit .bmp files. Derek Wills for noticing a problem with ilutGLScreenie when the screen width is not a multiple of 4. Dale Schumacher's "Filtered Image Rescaling" code in Graphic Gems III for some scaling algorithms in ILU. Kevin Park for making some suggestions on the ilImage C++ wrapper. Alessandro Pedretti for finding a bug in my TIFF code and making suggestions about portability issues. boostrlns from #flipCode for finding the ilutGLLoadImage bug in the 1.1.5 release. Ismo Krkkinen (iak@cs.joensuu.fi) for making some really nice new makefiles for Linux. Kishan (http://www.hackorama.com) for the nice directions on how to compile the external libraries under Linux. Wojciech Sobczuk for creating FreeBSD versions of the makefiles. nVidia for code to load .DDS files available at http://www.nvidia.com/view.asp?IO=dxtc_decompression_code PixiGreg for noticing that many viewers don't like .bmp files with negative heights (flipped), even though the specs say that it is valid. Matthias Stiller and Andre Normann for their invaluable help with getting DevIL to work on Big Endian machines. Jean-Francois Richard for the Python bindings of DevIL. Nick Marley for post-build information in MSVC++. Kenneth Hurley for his help in expanding and fixing my DDS code. Mark Callow for EXIF-loading and saving code, along with il[Load/Save]FromJpegStruct Sam for several fixes to my .bmp and .jpg loaders. chris79 for his help debugging my .psp and .gif code in several versions. Nick Marley for his MSVC++ post-build fixes. Marc Gregoire for sending images that DevIL would not load. Alberto Barbati for noticing that the IL_NEU_QUANT_SAMPLE mode wasn't being used properly. Ryan Butterfoss for his contributions to the DDS saving code. Computer Graphics (C Version) book by Hearn and Baker for the arbitrary polygon filling code. Nicolas Weber Meloni Dario Erick Tryzelaar Matej Tyc for completely redoing the Linux makefile system and rewriting the documentation. Matevz Tadel for fixing makefile for Scientific Linux. Richard Sim for contributing several fixes, especially for .psd loading robin_charlton for contributing a patch for Windows BMP support in ILUT. Vincent Richomme for DirectX Mobile support Antibyte for DDS save bugfix Stefan Cornelius, Secunia Research, for finding some buffer overflow vulnerabilities. Nico Golde for finding that my fix for the above vulnerability was not totally complete. GAIA (Group for Artificial Intelligence Applications) for contributions including .iff-loading and redoing the ilutConvertToHBitmap code. Their changes are at http://gaia.fdi.ucm.es/grupo/projects/javy/devzone.html#DevILNotes. Jesse Maurais for support of X11 component Translations: ------------- Carlos Aragons, for Spanish translation Bart De Lathouwer, for Danish translation Osamu Ohara, for English translation Abdullah Alshammari, for Arabic translation Osamu Ohara, for Japanese translation Andreas Stckel, for German translation assimp-4.1.0/samples/DevIL/README0000644002537200234200000001160513213503245016546 0ustar zmoelnigiemusersDeveloper's Image Library version 1.7.8 Readme, Notes and Quick Use ------------------------------------------------------------------- DevIL song: "la la la, a cross-platform image library utilizing a simple syntax to load, save, convert, manipulate, filter and display a variety of images with ease, la la la" What is it? ----------- DevIL is an Open Source image library whose distribution is done under the terms of the GNU LGPL license. See the COPYING file for more details. DevIL offers you a simple way to implement loading, manipulating, filtering, converting, displaying, saving from/to several different image formats in your own project. Where can I find it? -------------------- DevIL can be found at http://openil.sourceforge.net How do I build and install the 3 libraries ? ----------------------------------------- *nix users should read README.unix VisualC users should read README.win Cygwin users should read README.cygwin MacOSX users should read README.macosx PS: *nix stands for GNU/Linux, *BSD, SunOS/Solaris and perhaps some more. More Extensive Documentation ---------------------------- This file is only a quick guide to point you to more detailed information on how to use DevIL. More extensive documentation can currently be found on the DevIL site at http://openil.sf.net and in the /Docs directory in a normal install. Why the hell another image library? ----------------------------------- I have never seen an image library that can do everything DevIL does. Sure, various different libraries can do part of what DevIL can do as well or even better, but I wanted a simple to use library that encompassed all of these features. I also wanted an extremely portable image library that could be used from a variety of languages and utilized the OpenGL syntax. Basic Readme ------------ Most anything stated in this document applies to DevIL as well as DevILU and DevILUT, unless otherwise stated. (This file is best viewed with word wrap on.) Errors: ------- All errors generated inside DevIL, along with illegal parameters passed to DevIL functions are caught and passed to ilSetError(), an internal library function. The calling program can call ilGetError() to get the value of the error generated. Error types are defined in il.h, using the 0x501 - 0x5FF range. ilGetError() will return 0 (IL_NO_ERROR) if no error has occurred. Basic Usage: ------ This demonstrates loading an image through DevIL for OpenGL. Don't forget to call ilInit before you before you do anything: #include #include #include ... ILuint devilError; ilInit(); devilError = ilGetError(); if (devilError != IL_NO_ERROR) { printf ("Devil Error (ilInit: %s\n", iluGetErrorString (devilError)); exit (2); } .... ILuint devilID; ilGenImages(1, &devilID); ilBindImage(devilID); ilLoadImage("default1.tga"); // Loads into the current bound image devilError = ilGetError(); if (devilError != IL_NO_ERROR) { printf ("Devil Error (ilLoadImage: %s\n", iluGetErrorString (devilError)); exit (2); } .... ilutRenderer(IL_OPENGL); // Switch the renderer .... GLuint openglID, openglError; openglID = ilutGLBindTexImage(); // This generates the texture for you devilError = ilGetError(); if (devilError != IL_NO_ERROR) { printf ("Error: %s\n", iluGetErrorString (devilError)); exit (2); } if (openglError != GL_NO_ERROR) { printf ("Opengl Error (ilutGLBindTexImage): %s\n", gluGetErrorString (openglError)); exit (2); } // Make sure to close the image when you are done with it (though DevIL // automatically deletes them when the program exits): glDeleteTextures(1, &openglID); ilDeleteImages (1, &devilID); More Examples: --------- The TestIL project is included to test features of DevIL. DevIL includes a project called GLTest. This is a simple test of DevIL's capabilities. All it does it load any image and displays it in a window created by FreeGlut, which is available on http://freeglut.sourceforge.net. It is also included to let the user have an idea of what the library can really be used for. Several other test projects are included to test support with various display APIs. The WindowsTest project is a basic image program that only runs in Windows right now but showcases several of DevIL's features through various menus. If you want more in-depth tutorials, you can find them on http://openil.sf.net, or they may be in your installation under the /examples directory. Documents are also available in the /docs directory. Additional Reading ------------------ All image formats used in DevIL have corresponding documents on http://www.wotsit.org, under the Graphics Files section. These documents proved invaluable for the creation of this library when there was no library already available for that image format. Legalese -------- All contents of this file are intellectual property of Denton Woods, copyright 2001-2008. assimp-4.1.0/samples/DevIL/Libraries.txt0000644002537200234200000000364613213503245020351 0ustar zmoelnigiemusersLibraries needed to compile DevIL* : ---------------------------------- (Most of these are optional) Libpng for .png (and some .ico) support available at http://www.libpng.org/pub/png/libpng.html ZLib for .png (and some .ico) support available at http://www.gzip.org/zlib/ Libjpeg for .jpg (and some .blp) support from http://www.ijg.org/ Libtiff for .tif support from http://www.libtiff.org/ Libmng for .mng and .jng support from http://www.libmng.com/ JasPer for .jp2 (and some .icns) support available at http://www.ece.uvic.ca/~mdadams/jasper/ HD Photo Device Porting Kit for .wdp/.hdp support from http://www.microsoft.com/Downloads/details.aspx?FamilyID=285eeffd-d86c-48c3-ab93-3abd5ee7f1ce&displaylang=en. Little CMS for color profiles (ILU) from http://www.littlecms.com/ Colour Picker lib for WindowsTest from http://www.fluidstudios.com/freeware.html Freeglut (or glut) for GLTest from http://freeglut.sourceforge.net glext.h from http://oss.sgi.com/projects/ogl-sample/ABI/glext.h (as if using OpenGL) libsquish for DXT compression from http://code.google.com/p/libsquish/ nVidia Texture Tools for DXT compression from http://developer.nvidia.com/object/nv_texture_tools.html. MSVC++ precompiled versions of libpng, zlib, libjpeg, libtiff, lcms and JasPer can be found at http://openil.sourceforge.net/libs/LibCompiled-vc8.zip or http://openil.sourceforge.net/libs/LibCompiled-vc9.zip. Sources of libpng, zlib, libjpeg, libmng, libungif, libtiff, lcms and JasPer can be found at http://openil.sourceforge.net/libs/LibSrc.zip Intel Jpeg Library from http://developer.intel.com/software/products/perflib/ijl/index.htm MAC OS X These library are not still uploaded! To learn how to install these libraries, read README.macosx Source of external framework, downloaded from the previous sites http://openil.sourceforge.net/libs/ExternFrameworksSrc.sitx Complete Compiled Library http://openil.sourceforge.net/libs/OpenILBin.sitxassimp-4.1.0/samples/DevIL/include/0000755002537200234200000000000013213503245017306 5ustar zmoelnigiemusersassimp-4.1.0/samples/DevIL/include/IL/0000755002537200234200000000000013213503245017612 5ustar zmoelnigiemusersassimp-4.1.0/samples/DevIL/include/IL/ilu.h0000644002537200234200000001531513213503245020561 0ustar zmoelnigiemusers//----------------------------------------------------------------------------- // // ImageLib Utility Sources // Copyright (C) 2000-2009 by Denton Woods // Last modified: 03/07/2009 // // Filename: IL/ilu.h // // Description: The main include file for ILU // //----------------------------------------------------------------------------- // Doxygen comment /*! \file ilu.h The main include file for ILU */ #ifndef __ilu_h_ #ifndef __ILU_H__ #define __ilu_h_ #define __ILU_H__ #include #ifdef __cplusplus extern "C" { #endif #ifdef _WIN32 #if (defined(IL_USE_PRAGMA_LIBS)) && (!defined(_IL_BUILD_LIBRARY)) #if defined(_MSC_VER) || defined(__BORLANDC__) #pragma comment(lib, "ILU.lib") #endif #endif #endif #define ILU_VERSION_1_7_8 1 #define ILU_VERSION 178 #define ILU_FILTER 0x2600 #define ILU_NEAREST 0x2601 #define ILU_LINEAR 0x2602 #define ILU_BILINEAR 0x2603 #define ILU_SCALE_BOX 0x2604 #define ILU_SCALE_TRIANGLE 0x2605 #define ILU_SCALE_BELL 0x2606 #define ILU_SCALE_BSPLINE 0x2607 #define ILU_SCALE_LANCZOS3 0x2608 #define ILU_SCALE_MITCHELL 0x2609 // Error types #define ILU_INVALID_ENUM 0x0501 #define ILU_OUT_OF_MEMORY 0x0502 #define ILU_INTERNAL_ERROR 0x0504 #define ILU_INVALID_VALUE 0x0505 #define ILU_ILLEGAL_OPERATION 0x0506 #define ILU_INVALID_PARAM 0x0509 // Values #define ILU_PLACEMENT 0x0700 #define ILU_LOWER_LEFT 0x0701 #define ILU_LOWER_RIGHT 0x0702 #define ILU_UPPER_LEFT 0x0703 #define ILU_UPPER_RIGHT 0x0704 #define ILU_CENTER 0x0705 #define ILU_CONVOLUTION_MATRIX 0x0710 #define ILU_VERSION_NUM IL_VERSION_NUM #define ILU_VENDOR IL_VENDOR // Languages #define ILU_ENGLISH 0x0800 #define ILU_ARABIC 0x0801 #define ILU_DUTCH 0x0802 #define ILU_JAPANESE 0x0803 #define ILU_SPANISH 0x0804 #define ILU_GERMAN 0x0805 #define ILU_FRENCH 0x0806 // Filters /* #define ILU_FILTER_BLUR 0x0803 #define ILU_FILTER_GAUSSIAN_3x3 0x0804 #define ILU_FILTER_GAUSSIAN_5X5 0x0805 #define ILU_FILTER_EMBOSS1 0x0807 #define ILU_FILTER_EMBOSS2 0x0808 #define ILU_FILTER_LAPLACIAN1 0x080A #define ILU_FILTER_LAPLACIAN2 0x080B #define ILU_FILTER_LAPLACIAN3 0x080C #define ILU_FILTER_LAPLACIAN4 0x080D #define ILU_FILTER_SHARPEN1 0x080E #define ILU_FILTER_SHARPEN2 0x080F #define ILU_FILTER_SHARPEN3 0x0810 */ typedef struct ILinfo { ILuint Id; // the image's id ILubyte *Data; // the image's data ILuint Width; // the image's width ILuint Height; // the image's height ILuint Depth; // the image's depth ILubyte Bpp; // bytes per pixel (not bits) of the image ILuint SizeOfData; // the total size of the data (in bytes) ILenum Format; // image format (in IL enum style) ILenum Type; // image type (in IL enum style) ILenum Origin; // origin of the image ILubyte *Palette; // the image's palette ILenum PalType; // palette type ILuint PalSize; // palette size ILenum CubeFlags; // flags for what cube map sides are present ILuint NumNext; // number of images following ILuint NumMips; // number of mipmaps ILuint NumLayers; // number of layers } ILinfo; typedef struct ILpointf { ILfloat x; ILfloat y; } ILpointf; typedef struct ILpointi { ILint x; ILint y; } ILpointi; ILAPI ILboolean ILAPIENTRY iluAlienify(void); ILAPI ILboolean ILAPIENTRY iluBlurAvg(ILuint Iter); ILAPI ILboolean ILAPIENTRY iluBlurGaussian(ILuint Iter); ILAPI ILboolean ILAPIENTRY iluBuildMipmaps(void); ILAPI ILuint ILAPIENTRY iluColoursUsed(void); ILAPI ILboolean ILAPIENTRY iluCompareImage(ILuint Comp); ILAPI ILboolean ILAPIENTRY iluContrast(ILfloat Contrast); ILAPI ILboolean ILAPIENTRY iluCrop(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth); ILAPI void ILAPIENTRY iluDeleteImage(ILuint Id); // Deprecated ILAPI ILboolean ILAPIENTRY iluEdgeDetectE(void); ILAPI ILboolean ILAPIENTRY iluEdgeDetectP(void); ILAPI ILboolean ILAPIENTRY iluEdgeDetectS(void); ILAPI ILboolean ILAPIENTRY iluEmboss(void); ILAPI ILboolean ILAPIENTRY iluEnlargeCanvas(ILuint Width, ILuint Height, ILuint Depth); ILAPI ILboolean ILAPIENTRY iluEnlargeImage(ILfloat XDim, ILfloat YDim, ILfloat ZDim); ILAPI ILboolean ILAPIENTRY iluEqualize(void); ILAPI ILconst_string ILAPIENTRY iluErrorString(ILenum Error); ILAPI ILboolean ILAPIENTRY iluConvolution(ILint *matrix, ILint scale, ILint bias); ILAPI ILboolean ILAPIENTRY iluFlipImage(void); ILAPI ILboolean ILAPIENTRY iluGammaCorrect(ILfloat Gamma); ILAPI ILuint ILAPIENTRY iluGenImage(void); // Deprecated ILAPI void ILAPIENTRY iluGetImageInfo(ILinfo *Info); ILAPI ILint ILAPIENTRY iluGetInteger(ILenum Mode); ILAPI void ILAPIENTRY iluGetIntegerv(ILenum Mode, ILint *Param); ILAPI ILstring ILAPIENTRY iluGetString(ILenum StringName); ILAPI void ILAPIENTRY iluImageParameter(ILenum PName, ILenum Param); ILAPI void ILAPIENTRY iluInit(void); ILAPI ILboolean ILAPIENTRY iluInvertAlpha(void); ILAPI ILuint ILAPIENTRY iluLoadImage(ILconst_string FileName); ILAPI ILboolean ILAPIENTRY iluMirror(void); ILAPI ILboolean ILAPIENTRY iluNegative(void); ILAPI ILboolean ILAPIENTRY iluNoisify(ILclampf Tolerance); ILAPI ILboolean ILAPIENTRY iluPixelize(ILuint PixSize); ILAPI void ILAPIENTRY iluRegionfv(ILpointf *Points, ILuint n); ILAPI void ILAPIENTRY iluRegioniv(ILpointi *Points, ILuint n); ILAPI ILboolean ILAPIENTRY iluReplaceColour(ILubyte Red, ILubyte Green, ILubyte Blue, ILfloat Tolerance); ILAPI ILboolean ILAPIENTRY iluRotate(ILfloat Angle); ILAPI ILboolean ILAPIENTRY iluRotate3D(ILfloat x, ILfloat y, ILfloat z, ILfloat Angle); ILAPI ILboolean ILAPIENTRY iluSaturate1f(ILfloat Saturation); ILAPI ILboolean ILAPIENTRY iluSaturate4f(ILfloat r, ILfloat g, ILfloat b, ILfloat Saturation); ILAPI ILboolean ILAPIENTRY iluScale(ILuint Width, ILuint Height, ILuint Depth); ILAPI ILboolean ILAPIENTRY iluScaleAlpha(ILfloat scale); ILAPI ILboolean ILAPIENTRY iluScaleColours(ILfloat r, ILfloat g, ILfloat b); ILAPI ILboolean ILAPIENTRY iluSetLanguage(ILenum Language); ILAPI ILboolean ILAPIENTRY iluSharpen(ILfloat Factor, ILuint Iter); ILAPI ILboolean ILAPIENTRY iluSwapColours(void); ILAPI ILboolean ILAPIENTRY iluWave(ILfloat Angle); #define iluColorsUsed iluColoursUsed #define iluSwapColors iluSwapColours #define iluReplaceColor iluReplaceColour #define iluScaleColor iluScaleColour #ifdef __cplusplus } #endif #endif // __ILU_H__ #endif // __ilu_h_ assimp-4.1.0/samples/DevIL/include/IL/il_wrap.h0000644002537200234200000001067013213503245021424 0ustar zmoelnigiemusers#ifndef WRAPPER_H #define WRAPPER_H /*#include #include */ #include // Probably only have to #include this one #ifdef _MSC_VER #ifndef _IL_WRAP_BUILD_LIB #pragma comment(lib, "il_wrap.lib") #endif #endif class ilImage { public: ilImage(); ilImage(char *); ilImage(const ilImage &); virtual ~ilImage(); ILboolean Load(char *); ILboolean Load(char *, ILenum); ILboolean Save(char *); ILboolean Save(char *, ILenum); // ImageLib functions ILboolean ActiveImage(ILuint); ILboolean ActiveLayer(ILuint); ILboolean ActiveMipmap(ILuint); ILboolean Clear(void); ILvoid ClearColour(ILclampf, ILclampf, ILclampf, ILclampf); ILboolean Convert(ILenum); ILboolean Copy(ILuint); ILboolean Default(void); ILboolean Flip(void); ILboolean SwapColours(void); ILboolean Resize(ILuint, ILuint, ILuint); ILboolean TexImage(ILuint, ILuint, ILuint, ILubyte, ILenum, ILenum, ILvoid*); // Image handling ILvoid Bind(void) const; ILvoid Bind(ILuint); ILvoid Close(void) { this->Delete(); } ILvoid Delete(void); ILvoid iGenBind(); ILenum PaletteAlphaIndex(); // Image characteristics ILuint Width(void); ILuint Height(void); ILuint Depth(void); ILubyte Bpp(void); ILubyte Bitpp(void); ILenum PaletteType(void); ILenum Format(void); ILenum Type(void); ILuint NumImages(void); ILuint NumMipmaps(void); ILuint GetId(void) const; ILenum GetOrigin(void); ILubyte *GetData(void); ILubyte *GetPalette(void); // Rendering ILuint BindImage(void); ILuint BindImage(ILenum); // Operators ilImage& operator = (ILuint); ilImage& operator = (const ilImage &); protected: ILuint Id; private: ILvoid iStartUp(); }; class ilFilters { public: static ILboolean Alienify(ilImage &); static ILboolean BlurAvg(ilImage &, ILuint Iter); static ILboolean BlurGaussian(ilImage &, ILuint Iter); static ILboolean Contrast(ilImage &, ILfloat Contrast); static ILboolean EdgeDetectE(ilImage &); static ILboolean EdgeDetectP(ilImage &); static ILboolean EdgeDetectS(ilImage &); static ILboolean Emboss(ilImage &); static ILboolean Gamma(ilImage &, ILfloat Gamma); static ILboolean Negative(ilImage &); static ILboolean Noisify(ilImage &, ILubyte Factor); static ILboolean Pixelize(ilImage &, ILuint PixSize); static ILboolean Saturate(ilImage &, ILfloat Saturation); static ILboolean Saturate(ilImage &, ILfloat r, ILfloat g, ILfloat b, ILfloat Saturation); static ILboolean ScaleColours(ilImage &, ILfloat r, ILfloat g, ILfloat b); static ILboolean Sharpen(ilImage &, ILfloat Factor, ILuint Iter); }; #ifdef ILUT_USE_OPENGL class ilOgl { public: static ILvoid Init(void); static GLuint BindTex(ilImage &); static ILboolean Upload(ilImage &, ILuint); static GLuint Mipmap(ilImage &); static ILboolean Screen(void); static ILboolean Screenie(void); }; #endif//ILUT_USE_OPENGL #ifdef ILUT_USE_ALLEGRO class ilAlleg { public: static ILvoid Init(void); static BITMAP *Convert(ilImage &); }; #endif//ILUT_USE_ALLEGRO #ifdef ILUT_USE_WIN32 class ilWin32 { public: static ILvoid Init(void); static HBITMAP Convert(ilImage &); static ILboolean GetClipboard(ilImage &); static ILvoid GetInfo(ilImage &, BITMAPINFO *Info); static ILubyte *GetPadData(ilImage &); static HPALETTE GetPal(ilImage &); static ILboolean GetResource(ilImage &, HINSTANCE hInst, ILint ID, char *ResourceType); static ILboolean GetResource(ilImage &, HINSTANCE hInst, ILint ID, char *ResourceType, ILenum Type); static ILboolean SetClipboard(ilImage &); }; #endif//ILUT_USE_WIN32 class ilValidate { public: static ILboolean Valid(ILenum, char *); static ILboolean Valid(ILenum, FILE *); static ILboolean Valid(ILenum, ILvoid *, ILuint); protected: private: }; class ilState { public: static ILboolean Disable(ILenum); static ILboolean Enable(ILenum); static ILvoid Get(ILenum, ILboolean &); static ILvoid Get(ILenum, ILint &); static ILboolean GetBool(ILenum); static ILint GetInt(ILenum); static const char *GetString(ILenum); static ILboolean IsDisabled(ILenum); static ILboolean IsEnabled(ILenum); static ILboolean Origin(ILenum); static ILvoid Pop(void); static ILvoid Push(ILuint); protected: private: }; class ilError { public: static ILvoid Check(ILvoid (*Callback)(const char*)); static ILvoid Check(ILvoid (*Callback)(ILenum)); static ILenum Get(void); static const char *String(void); static const char *String(ILenum); protected: private: }; #endif//WRAPPER_H assimp-4.1.0/samples/DevIL/include/IL/il.h0000644002537200234200000006021613213503245020374 0ustar zmoelnigiemusers//----------------------------------------------------------------------------- // // ImageLib Sources // Copyright (C) 2000-2009 by Denton Woods // Last modified: 03/07/2009 // // Filename: IL/il.h // // Description: The main include file for DevIL // //----------------------------------------------------------------------------- // Doxygen comment /*! \file il.h The main include file for DevIL */ #ifndef __il_h_ #ifndef __IL_H__ #define __il_h_ #define __IL_H__ #ifdef __cplusplus extern "C" { #endif //this define controls if floats and doubles are clampled to [0..1] //during conversion. It takes a little more time, but it is the correct //way of doing this. If you are sure your floats are always valid, //you can undefine this value... #define CLAMP_HALF 1 #define CLAMP_FLOATS 1 #define CLAMP_DOUBLES 1 /*#ifdef _WIN32_WCE #define IL_NO_EXR #define IL_NO_GIF #define IL_NO_JP2 #define IL_NO_JPG #define IL_NO_MNG #define IL_NO_PNG #define IL_NO_TIF #define IL_NO_LCMS #endif //_WIN32_WCE #ifdef DJGPP #define IL_NO_EXR #define IL_NO_GIF #define IL_NO_JP2 #define IL_NO_JPG #define IL_NO_MNG #define IL_NO_PNG #define IL_NO_TIF #define IL_NO_LCMS #endif //DJGPP*/ #ifdef _WIN32 #if (defined(IL_USE_PRAGMA_LIBS)) && (!defined(_IL_BUILD_LIBRARY)) #if defined(_MSC_VER) || defined(__BORLANDC__) #pragma comment(lib, "DevIL.lib") #endif #endif #endif #ifdef RESTRICT_KEYWORD #define RESTRICT restrict #define CONST_RESTRICT const restrict #else #define RESTRICT #define CONST_RESTRICT const #endif #include typedef unsigned int ILenum; typedef unsigned char ILboolean; typedef unsigned int ILbitfield; typedef signed char ILbyte; typedef signed short ILshort; typedef int ILint; typedef size_t ILsizei; typedef unsigned char ILubyte; typedef unsigned short ILushort; typedef unsigned int ILuint; typedef float ILfloat; typedef float ILclampf; typedef double ILdouble; typedef double ILclampd; #ifdef _MSC_VER typedef __int64 ILint64; typedef unsigned __int64 ILuint64; #else typedef long long int ILint64; typedef long long unsigned int ILuint64; #endif #include #ifdef _UNICODE #ifndef _WIN32_WCE #include #endif //if we use a define instead of a typedef, //ILconst_string works as intended #define ILchar wchar_t #define ILstring wchar_t* #define ILconst_string wchar_t const * #else //if we use a define instead of a typedef, //ILconst_string works as intended #define ILchar char #define ILstring char* #define ILconst_string char const * #endif //_UNICODE #define IL_FALSE 0 #define IL_TRUE 1 // Matches OpenGL's right now. //! Data formats \link Formats Formats\endlink #define IL_COLOUR_INDEX 0x1900 #define IL_COLOR_INDEX 0x1900 #define IL_ALPHA 0x1906 #define IL_RGB 0x1907 #define IL_RGBA 0x1908 #define IL_BGR 0x80E0 #define IL_BGRA 0x80E1 #define IL_LUMINANCE 0x1909 #define IL_LUMINANCE_ALPHA 0x190A //! Data types \link Types Types\endlink #define IL_BYTE 0x1400 #define IL_UNSIGNED_BYTE 0x1401 #define IL_SHORT 0x1402 #define IL_UNSIGNED_SHORT 0x1403 #define IL_INT 0x1404 #define IL_UNSIGNED_INT 0x1405 #define IL_FLOAT 0x1406 #define IL_DOUBLE 0x140A #define IL_HALF 0x140B #define IL_MAX_BYTE SCHAR_MAX #define IL_MAX_UNSIGNED_BYTE UCHAR_MAX #define IL_MAX_SHORT SHRT_MAX #define IL_MAX_UNSIGNED_SHORT USHRT_MAX #define IL_MAX_INT INT_MAX #define IL_MAX_UNSIGNED_INT UINT_MAX #define IL_LIMIT(x,m,M) (xM?M:x)) #define IL_CLAMP(x) IL_LIMIT(x,0,1) #define IL_VENDOR 0x1F00 #define IL_LOAD_EXT 0x1F01 #define IL_SAVE_EXT 0x1F02 // // IL-specific #define's // #define IL_VERSION_1_7_8 1 #define IL_VERSION 178 // Attribute Bits #define IL_ORIGIN_BIT 0x00000001 #define IL_FILE_BIT 0x00000002 #define IL_PAL_BIT 0x00000004 #define IL_FORMAT_BIT 0x00000008 #define IL_TYPE_BIT 0x00000010 #define IL_COMPRESS_BIT 0x00000020 #define IL_LOADFAIL_BIT 0x00000040 #define IL_FORMAT_SPECIFIC_BIT 0x00000080 #define IL_ALL_ATTRIB_BITS 0x000FFFFF // Palette types #define IL_PAL_NONE 0x0400 #define IL_PAL_RGB24 0x0401 #define IL_PAL_RGB32 0x0402 #define IL_PAL_RGBA32 0x0403 #define IL_PAL_BGR24 0x0404 #define IL_PAL_BGR32 0x0405 #define IL_PAL_BGRA32 0x0406 // Image types #define IL_TYPE_UNKNOWN 0x0000 #define IL_BMP 0x0420 //!< Microsoft Windows Bitmap - .bmp extension #define IL_CUT 0x0421 //!< Dr. Halo - .cut extension #define IL_DOOM 0x0422 //!< DooM walls - no specific extension #define IL_DOOM_FLAT 0x0423 //!< DooM flats - no specific extension #define IL_ICO 0x0424 //!< Microsoft Windows Icons and Cursors - .ico and .cur extensions #define IL_JPG 0x0425 //!< JPEG - .jpg, .jpe and .jpeg extensions #define IL_JFIF 0x0425 //!< #define IL_ILBM 0x0426 //!< Amiga IFF (FORM ILBM) - .iff, .ilbm, .lbm extensions #define IL_PCD 0x0427 //!< Kodak PhotoCD - .pcd extension #define IL_PCX 0x0428 //!< ZSoft PCX - .pcx extension #define IL_PIC 0x0429 //!< PIC - .pic extension #define IL_PNG 0x042A //!< Portable Network Graphics - .png extension #define IL_PNM 0x042B //!< Portable Any Map - .pbm, .pgm, .ppm and .pnm extensions #define IL_SGI 0x042C //!< Silicon Graphics - .sgi, .bw, .rgb and .rgba extensions #define IL_TGA 0x042D //!< TrueVision Targa File - .tga, .vda, .icb and .vst extensions #define IL_TIF 0x042E //!< Tagged Image File Format - .tif and .tiff extensions #define IL_CHEAD 0x042F //!< C-Style Header - .h extension #define IL_RAW 0x0430 //!< Raw Image Data - any extension #define IL_MDL 0x0431 //!< Half-Life Model Texture - .mdl extension #define IL_WAL 0x0432 //!< Quake 2 Texture - .wal extension #define IL_LIF 0x0434 //!< Homeworld Texture - .lif extension #define IL_MNG 0x0435 //!< Multiple-image Network Graphics - .mng extension #define IL_JNG 0x0435 //!< #define IL_GIF 0x0436 //!< Graphics Interchange Format - .gif extension #define IL_DDS 0x0437 //!< DirectDraw Surface - .dds extension #define IL_DCX 0x0438 //!< ZSoft Multi-PCX - .dcx extension #define IL_PSD 0x0439 //!< Adobe PhotoShop - .psd extension #define IL_EXIF 0x043A //!< #define IL_PSP 0x043B //!< PaintShop Pro - .psp extension #define IL_PIX 0x043C //!< PIX - .pix extension #define IL_PXR 0x043D //!< Pixar - .pxr extension #define IL_XPM 0x043E //!< X Pixel Map - .xpm extension #define IL_HDR 0x043F //!< Radiance High Dynamic Range - .hdr extension #define IL_ICNS 0x0440 //!< Macintosh Icon - .icns extension #define IL_JP2 0x0441 //!< Jpeg 2000 - .jp2 extension #define IL_EXR 0x0442 //!< OpenEXR - .exr extension #define IL_WDP 0x0443 //!< Microsoft HD Photo - .wdp and .hdp extension #define IL_VTF 0x0444 //!< Valve Texture Format - .vtf extension #define IL_WBMP 0x0445 //!< Wireless Bitmap - .wbmp extension #define IL_SUN 0x0446 //!< Sun Raster - .sun, .ras, .rs, .im1, .im8, .im24 and .im32 extensions #define IL_IFF 0x0447 //!< Interchange File Format - .iff extension #define IL_TPL 0x0448 //!< Gamecube Texture - .tpl extension #define IL_FITS 0x0449 //!< Flexible Image Transport System - .fit and .fits extensions #define IL_DICOM 0x044A //!< Digital Imaging and Communications in Medicine (DICOM) - .dcm and .dicom extensions #define IL_IWI 0x044B //!< Call of Duty Infinity Ward Image - .iwi extension #define IL_BLP 0x044C //!< Blizzard Texture Format - .blp extension #define IL_FTX 0x044D //!< Heavy Metal: FAKK2 Texture - .ftx extension #define IL_ROT 0x044E //!< Homeworld 2 - Relic Texture - .rot extension #define IL_TEXTURE 0x044F //!< Medieval II: Total War Texture - .texture extension #define IL_DPX 0x0450 //!< Digital Picture Exchange - .dpx extension #define IL_UTX 0x0451 //!< Unreal (and Unreal Tournament) Texture - .utx extension #define IL_MP3 0x0452 //!< MPEG-1 Audio Layer 3 - .mp3 extension #define IL_JASC_PAL 0x0475 //!< PaintShop Pro Palette // Error Types #define IL_NO_ERROR 0x0000 #define IL_INVALID_ENUM 0x0501 #define IL_OUT_OF_MEMORY 0x0502 #define IL_FORMAT_NOT_SUPPORTED 0x0503 #define IL_INTERNAL_ERROR 0x0504 #define IL_INVALID_VALUE 0x0505 #define IL_ILLEGAL_OPERATION 0x0506 #define IL_ILLEGAL_FILE_VALUE 0x0507 #define IL_INVALID_FILE_HEADER 0x0508 #define IL_INVALID_PARAM 0x0509 #define IL_COULD_NOT_OPEN_FILE 0x050A #define IL_INVALID_EXTENSION 0x050B #define IL_FILE_ALREADY_EXISTS 0x050C #define IL_OUT_FORMAT_SAME 0x050D #define IL_STACK_OVERFLOW 0x050E #define IL_STACK_UNDERFLOW 0x050F #define IL_INVALID_CONVERSION 0x0510 #define IL_BAD_DIMENSIONS 0x0511 #define IL_FILE_READ_ERROR 0x0512 // 05/12/2002: Addition by Sam. #define IL_FILE_WRITE_ERROR 0x0512 #define IL_LIB_GIF_ERROR 0x05E1 #define IL_LIB_JPEG_ERROR 0x05E2 #define IL_LIB_PNG_ERROR 0x05E3 #define IL_LIB_TIFF_ERROR 0x05E4 #define IL_LIB_MNG_ERROR 0x05E5 #define IL_LIB_JP2_ERROR 0x05E6 #define IL_LIB_EXR_ERROR 0x05E7 #define IL_UNKNOWN_ERROR 0x05FF // Origin Definitions #define IL_ORIGIN_SET 0x0600 #define IL_ORIGIN_LOWER_LEFT 0x0601 #define IL_ORIGIN_UPPER_LEFT 0x0602 #define IL_ORIGIN_MODE 0x0603 // Format and Type Mode Definitions #define IL_FORMAT_SET 0x0610 #define IL_FORMAT_MODE 0x0611 #define IL_TYPE_SET 0x0612 #define IL_TYPE_MODE 0x0613 // File definitions #define IL_FILE_OVERWRITE 0x0620 #define IL_FILE_MODE 0x0621 // Palette definitions #define IL_CONV_PAL 0x0630 // Load fail definitions #define IL_DEFAULT_ON_FAIL 0x0632 // Key colour and alpha definitions #define IL_USE_KEY_COLOUR 0x0635 #define IL_USE_KEY_COLOR 0x0635 #define IL_BLIT_BLEND 0x0636 // Interlace definitions #define IL_SAVE_INTERLACED 0x0639 #define IL_INTERLACE_MODE 0x063A // Quantization definitions #define IL_QUANTIZATION_MODE 0x0640 #define IL_WU_QUANT 0x0641 #define IL_NEU_QUANT 0x0642 #define IL_NEU_QUANT_SAMPLE 0x0643 #define IL_MAX_QUANT_INDEXS 0x0644 //XIX : ILint : Maximum number of colors to reduce to, default of 256. and has a range of 2-256 #define IL_MAX_QUANT_INDICES 0x0644 // Redefined, since the above #define is misspelled // Hints #define IL_FASTEST 0x0660 #define IL_LESS_MEM 0x0661 #define IL_DONT_CARE 0x0662 #define IL_MEM_SPEED_HINT 0x0665 #define IL_USE_COMPRESSION 0x0666 #define IL_NO_COMPRESSION 0x0667 #define IL_COMPRESSION_HINT 0x0668 // Compression #define IL_NVIDIA_COMPRESS 0x0670 #define IL_SQUISH_COMPRESS 0x0671 // Subimage types #define IL_SUB_NEXT 0x0680 #define IL_SUB_MIPMAP 0x0681 #define IL_SUB_LAYER 0x0682 // Compression definitions #define IL_COMPRESS_MODE 0x0700 #define IL_COMPRESS_NONE 0x0701 #define IL_COMPRESS_RLE 0x0702 #define IL_COMPRESS_LZO 0x0703 #define IL_COMPRESS_ZLIB 0x0704 // File format-specific values #define IL_TGA_CREATE_STAMP 0x0710 #define IL_JPG_QUALITY 0x0711 #define IL_PNG_INTERLACE 0x0712 #define IL_TGA_RLE 0x0713 #define IL_BMP_RLE 0x0714 #define IL_SGI_RLE 0x0715 #define IL_TGA_ID_STRING 0x0717 #define IL_TGA_AUTHNAME_STRING 0x0718 #define IL_TGA_AUTHCOMMENT_STRING 0x0719 #define IL_PNG_AUTHNAME_STRING 0x071A #define IL_PNG_TITLE_STRING 0x071B #define IL_PNG_DESCRIPTION_STRING 0x071C #define IL_TIF_DESCRIPTION_STRING 0x071D #define IL_TIF_HOSTCOMPUTER_STRING 0x071E #define IL_TIF_DOCUMENTNAME_STRING 0x071F #define IL_TIF_AUTHNAME_STRING 0x0720 #define IL_JPG_SAVE_FORMAT 0x0721 #define IL_CHEAD_HEADER_STRING 0x0722 #define IL_PCD_PICNUM 0x0723 #define IL_PNG_ALPHA_INDEX 0x0724 //XIX : ILint : the color in the palette at this index value (0-255) is considered transparent, -1 for no trasparent color #define IL_JPG_PROGRESSIVE 0x0725 #define IL_VTF_COMP 0x0726 // DXTC definitions #define IL_DXTC_FORMAT 0x0705 #define IL_DXT1 0x0706 #define IL_DXT2 0x0707 #define IL_DXT3 0x0708 #define IL_DXT4 0x0709 #define IL_DXT5 0x070A #define IL_DXT_NO_COMP 0x070B #define IL_KEEP_DXTC_DATA 0x070C #define IL_DXTC_DATA_FORMAT 0x070D #define IL_3DC 0x070E #define IL_RXGB 0x070F #define IL_ATI1N 0x0710 #define IL_DXT1A 0x0711 // Normally the same as IL_DXT1, except for nVidia Texture Tools. // Environment map definitions #define IL_CUBEMAP_POSITIVEX 0x00000400 #define IL_CUBEMAP_NEGATIVEX 0x00000800 #define IL_CUBEMAP_POSITIVEY 0x00001000 #define IL_CUBEMAP_NEGATIVEY 0x00002000 #define IL_CUBEMAP_POSITIVEZ 0x00004000 #define IL_CUBEMAP_NEGATIVEZ 0x00008000 #define IL_SPHEREMAP 0x00010000 // Values #define IL_VERSION_NUM 0x0DE2 #define IL_IMAGE_WIDTH 0x0DE4 #define IL_IMAGE_HEIGHT 0x0DE5 #define IL_IMAGE_DEPTH 0x0DE6 #define IL_IMAGE_SIZE_OF_DATA 0x0DE7 #define IL_IMAGE_BPP 0x0DE8 #define IL_IMAGE_BYTES_PER_PIXEL 0x0DE8 #define IL_IMAGE_BPP 0x0DE8 #define IL_IMAGE_BITS_PER_PIXEL 0x0DE9 #define IL_IMAGE_FORMAT 0x0DEA #define IL_IMAGE_TYPE 0x0DEB #define IL_PALETTE_TYPE 0x0DEC #define IL_PALETTE_SIZE 0x0DED #define IL_PALETTE_BPP 0x0DEE #define IL_PALETTE_NUM_COLS 0x0DEF #define IL_PALETTE_BASE_TYPE 0x0DF0 #define IL_NUM_FACES 0x0DE1 #define IL_NUM_IMAGES 0x0DF1 #define IL_NUM_MIPMAPS 0x0DF2 #define IL_NUM_LAYERS 0x0DF3 #define IL_ACTIVE_IMAGE 0x0DF4 #define IL_ACTIVE_MIPMAP 0x0DF5 #define IL_ACTIVE_LAYER 0x0DF6 #define IL_ACTIVE_FACE 0x0E00 #define IL_CUR_IMAGE 0x0DF7 #define IL_IMAGE_DURATION 0x0DF8 #define IL_IMAGE_PLANESIZE 0x0DF9 #define IL_IMAGE_BPC 0x0DFA #define IL_IMAGE_OFFX 0x0DFB #define IL_IMAGE_OFFY 0x0DFC #define IL_IMAGE_CUBEFLAGS 0x0DFD #define IL_IMAGE_ORIGIN 0x0DFE #define IL_IMAGE_CHANNELS 0x0DFF # if defined __GNUC__ && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 0)) // __attribute__((deprecated)) is supported by GCC 3.1 and later. # define DEPRECATED(D) D __attribute__((deprecated)) # elif defined _MSC_VER && _MSC_VER >= 1300 // __declspec(deprecated) is supported by MSVC 7.0 and later. # define DEPRECATED(D) __declspec(deprecated) D # else # define DEPRECATED (D) D # endif // // Section shamelessly modified from the glut header. // // This is from Win32's #if (_MSC_VER >= 800) || defined(_STDCALL_SUPPORTED) || defined(__BORLANDC__) || defined(__LCC__) #define ILAPIENTRY __stdcall #define IL_PACKSTRUCT //#elif defined(linux) || defined(MACOSX) || defined(__CYGWIN__) //fix bug 840364 #elif defined( __GNUC__ ) // this should work for any of the above commented platforms // plus any platform using GCC #ifdef __MINGW32__ #define ILAPIENTRY __stdcall #else #define ILAPIENTRY #endif #define IL_PACKSTRUCT __attribute__ ((packed)) #else #define ILAPIENTRY #define IL_PACKSTRUCT #endif // This is from Win32's and #if defined(__LCC__) #define ILAPI __stdcall #elif defined(_WIN32) //changed 20031221 to fix bug 840421 #ifdef IL_STATIC_LIB #define ILAPI #else #ifdef _IL_BUILD_LIBRARY #define ILAPI __declspec(dllexport) #else #define ILAPI __declspec(dllimport) #endif #endif #elif __APPLE__ #define ILAPI extern #else #define ILAPI #endif #define IL_SEEK_SET 0 #define IL_SEEK_CUR 1 #define IL_SEEK_END 2 #define IL_EOF -1 // Callback functions for file reading typedef void* ILHANDLE; typedef void (ILAPIENTRY *fCloseRProc)(ILHANDLE); typedef ILboolean (ILAPIENTRY *fEofProc) (ILHANDLE); typedef ILint (ILAPIENTRY *fGetcProc) (ILHANDLE); typedef ILHANDLE (ILAPIENTRY *fOpenRProc) (ILconst_string); typedef ILint (ILAPIENTRY *fReadProc) (void*, ILuint, ILuint, ILHANDLE); typedef ILint (ILAPIENTRY *fSeekRProc) (ILHANDLE, ILint, ILint); typedef ILint (ILAPIENTRY *fTellRProc) (ILHANDLE); // Callback functions for file writing typedef void (ILAPIENTRY *fCloseWProc)(ILHANDLE); typedef ILHANDLE (ILAPIENTRY *fOpenWProc) (ILconst_string); typedef ILint (ILAPIENTRY *fPutcProc) (ILubyte, ILHANDLE); typedef ILint (ILAPIENTRY *fSeekWProc) (ILHANDLE, ILint, ILint); typedef ILint (ILAPIENTRY *fTellWProc) (ILHANDLE); typedef ILint (ILAPIENTRY *fWriteProc) (const void*, ILuint, ILuint, ILHANDLE); // Callback functions for allocation and deallocation typedef void* (ILAPIENTRY *mAlloc)(const ILsizei); typedef void (ILAPIENTRY *mFree) (const void* CONST_RESTRICT); // Registered format procedures typedef ILenum (ILAPIENTRY *IL_LOADPROC)(ILconst_string); typedef ILenum (ILAPIENTRY *IL_SAVEPROC)(ILconst_string); // ImageLib Functions ILAPI ILboolean ILAPIENTRY ilActiveFace(ILuint Number); ILAPI ILboolean ILAPIENTRY ilActiveImage(ILuint Number); ILAPI ILboolean ILAPIENTRY ilActiveLayer(ILuint Number); ILAPI ILboolean ILAPIENTRY ilActiveMipmap(ILuint Number); ILAPI ILboolean ILAPIENTRY ilApplyPal(ILconst_string FileName); ILAPI ILboolean ILAPIENTRY ilApplyProfile(ILstring InProfile, ILstring OutProfile); ILAPI void ILAPIENTRY ilBindImage(ILuint Image); ILAPI ILboolean ILAPIENTRY ilBlit(ILuint Source, ILint DestX, ILint DestY, ILint DestZ, ILuint SrcX, ILuint SrcY, ILuint SrcZ, ILuint Width, ILuint Height, ILuint Depth); ILAPI ILboolean ILAPIENTRY ilClampNTSC(void); ILAPI void ILAPIENTRY ilClearColour(ILclampf Red, ILclampf Green, ILclampf Blue, ILclampf Alpha); ILAPI ILboolean ILAPIENTRY ilClearImage(void); ILAPI ILuint ILAPIENTRY ilCloneCurImage(void); ILAPI ILubyte* ILAPIENTRY ilCompressDXT(ILubyte *Data, ILuint Width, ILuint Height, ILuint Depth, ILenum DXTCFormat, ILuint *DXTCSize); ILAPI ILboolean ILAPIENTRY ilCompressFunc(ILenum Mode); ILAPI ILboolean ILAPIENTRY ilConvertImage(ILenum DestFormat, ILenum DestType); ILAPI ILboolean ILAPIENTRY ilConvertPal(ILenum DestFormat); ILAPI ILboolean ILAPIENTRY ilCopyImage(ILuint Src); ILAPI ILuint ILAPIENTRY ilCopyPixels(ILuint XOff, ILuint YOff, ILuint ZOff, ILuint Width, ILuint Height, ILuint Depth, ILenum Format, ILenum Type, void *Data); ILAPI ILuint ILAPIENTRY ilCreateSubImage(ILenum Type, ILuint Num); ILAPI ILboolean ILAPIENTRY ilDefaultImage(void); ILAPI void ILAPIENTRY ilDeleteImage(const ILuint Num); ILAPI void ILAPIENTRY ilDeleteImages(ILsizei Num, const ILuint *Images); ILAPI ILenum ILAPIENTRY ilDetermineType(ILconst_string FileName); ILAPI ILenum ILAPIENTRY ilDetermineTypeF(ILHANDLE File); ILAPI ILenum ILAPIENTRY ilDetermineTypeL(const void *Lump, ILuint Size); ILAPI ILboolean ILAPIENTRY ilDisable(ILenum Mode); ILAPI ILboolean ILAPIENTRY ilDxtcDataToImage(void); ILAPI ILboolean ILAPIENTRY ilDxtcDataToSurface(void); ILAPI ILboolean ILAPIENTRY ilEnable(ILenum Mode); ILAPI void ILAPIENTRY ilFlipSurfaceDxtcData(void); ILAPI ILboolean ILAPIENTRY ilFormatFunc(ILenum Mode); ILAPI void ILAPIENTRY ilGenImages(ILsizei Num, ILuint *Images); ILAPI ILuint ILAPIENTRY ilGenImage(void); ILAPI ILubyte* ILAPIENTRY ilGetAlpha(ILenum Type); ILAPI ILboolean ILAPIENTRY ilGetBoolean(ILenum Mode); ILAPI void ILAPIENTRY ilGetBooleanv(ILenum Mode, ILboolean *Param); ILAPI ILubyte* ILAPIENTRY ilGetData(void); ILAPI ILuint ILAPIENTRY ilGetDXTCData(void *Buffer, ILuint BufferSize, ILenum DXTCFormat); ILAPI ILenum ILAPIENTRY ilGetError(void); ILAPI ILint ILAPIENTRY ilGetInteger(ILenum Mode); ILAPI void ILAPIENTRY ilGetIntegerv(ILenum Mode, ILint *Param); ILAPI ILuint ILAPIENTRY ilGetLumpPos(void); ILAPI ILubyte* ILAPIENTRY ilGetPalette(void); ILAPI ILconst_string ILAPIENTRY ilGetString(ILenum StringName); ILAPI void ILAPIENTRY ilHint(ILenum Target, ILenum Mode); ILAPI ILboolean ILAPIENTRY ilInvertSurfaceDxtcDataAlpha(void); ILAPI void ILAPIENTRY ilInit(void); ILAPI ILboolean ILAPIENTRY ilImageToDxtcData(ILenum Format); ILAPI ILboolean ILAPIENTRY ilIsDisabled(ILenum Mode); ILAPI ILboolean ILAPIENTRY ilIsEnabled(ILenum Mode); ILAPI ILboolean ILAPIENTRY ilIsImage(ILuint Image); ILAPI ILboolean ILAPIENTRY ilIsValid(ILenum Type, ILconst_string FileName); ILAPI ILboolean ILAPIENTRY ilIsValidF(ILenum Type, ILHANDLE File); ILAPI ILboolean ILAPIENTRY ilIsValidL(ILenum Type, void *Lump, ILuint Size); ILAPI void ILAPIENTRY ilKeyColour(ILclampf Red, ILclampf Green, ILclampf Blue, ILclampf Alpha); ILAPI ILboolean ILAPIENTRY ilLoad(ILenum Type, ILconst_string FileName); ILAPI ILboolean ILAPIENTRY ilLoadF(ILenum Type, ILHANDLE File); ILAPI ILboolean ILAPIENTRY ilLoadImage(ILconst_string FileName); ILAPI ILboolean ILAPIENTRY ilLoadL(ILenum Type, const void *Lump, ILuint Size); ILAPI ILboolean ILAPIENTRY ilLoadPal(ILconst_string FileName); ILAPI void ILAPIENTRY ilModAlpha(ILdouble AlphaValue); ILAPI ILboolean ILAPIENTRY ilOriginFunc(ILenum Mode); ILAPI ILboolean ILAPIENTRY ilOverlayImage(ILuint Source, ILint XCoord, ILint YCoord, ILint ZCoord); ILAPI void ILAPIENTRY ilPopAttrib(void); ILAPI void ILAPIENTRY ilPushAttrib(ILuint Bits); ILAPI void ILAPIENTRY ilRegisterFormat(ILenum Format); ILAPI ILboolean ILAPIENTRY ilRegisterLoad(ILconst_string Ext, IL_LOADPROC Load); ILAPI ILboolean ILAPIENTRY ilRegisterMipNum(ILuint Num); ILAPI ILboolean ILAPIENTRY ilRegisterNumFaces(ILuint Num); ILAPI ILboolean ILAPIENTRY ilRegisterNumImages(ILuint Num); ILAPI void ILAPIENTRY ilRegisterOrigin(ILenum Origin); ILAPI void ILAPIENTRY ilRegisterPal(void *Pal, ILuint Size, ILenum Type); ILAPI ILboolean ILAPIENTRY ilRegisterSave(ILconst_string Ext, IL_SAVEPROC Save); ILAPI void ILAPIENTRY ilRegisterType(ILenum Type); ILAPI ILboolean ILAPIENTRY ilRemoveLoad(ILconst_string Ext); ILAPI ILboolean ILAPIENTRY ilRemoveSave(ILconst_string Ext); ILAPI void ILAPIENTRY ilResetMemory(void); // Deprecated ILAPI void ILAPIENTRY ilResetRead(void); ILAPI void ILAPIENTRY ilResetWrite(void); ILAPI ILboolean ILAPIENTRY ilSave(ILenum Type, ILconst_string FileName); ILAPI ILuint ILAPIENTRY ilSaveF(ILenum Type, ILHANDLE File); ILAPI ILboolean ILAPIENTRY ilSaveImage(ILconst_string FileName); ILAPI ILuint ILAPIENTRY ilSaveL(ILenum Type, void *Lump, ILuint Size); ILAPI ILboolean ILAPIENTRY ilSavePal(ILconst_string FileName); ILAPI ILboolean ILAPIENTRY ilSetAlpha(ILdouble AlphaValue); ILAPI ILboolean ILAPIENTRY ilSetData(void *Data); ILAPI ILboolean ILAPIENTRY ilSetDuration(ILuint Duration); ILAPI void ILAPIENTRY ilSetInteger(ILenum Mode, ILint Param); ILAPI void ILAPIENTRY ilSetMemory(mAlloc, mFree); ILAPI void ILAPIENTRY ilSetPixels(ILint XOff, ILint YOff, ILint ZOff, ILuint Width, ILuint Height, ILuint Depth, ILenum Format, ILenum Type, void *Data); ILAPI void ILAPIENTRY ilSetRead(fOpenRProc, fCloseRProc, fEofProc, fGetcProc, fReadProc, fSeekRProc, fTellRProc); ILAPI void ILAPIENTRY ilSetString(ILenum Mode, const char *String); ILAPI void ILAPIENTRY ilSetWrite(fOpenWProc, fCloseWProc, fPutcProc, fSeekWProc, fTellWProc, fWriteProc); ILAPI void ILAPIENTRY ilShutDown(void); ILAPI ILboolean ILAPIENTRY ilSurfaceToDxtcData(ILenum Format); ILAPI ILboolean ILAPIENTRY ilTexImage(ILuint Width, ILuint Height, ILuint Depth, ILubyte NumChannels, ILenum Format, ILenum Type, void *Data); ILAPI ILboolean ILAPIENTRY ilTexImageDxtc(ILint w, ILint h, ILint d, ILenum DxtFormat, const ILubyte* data); ILAPI ILenum ILAPIENTRY ilTypeFromExt(ILconst_string FileName); ILAPI ILboolean ILAPIENTRY ilTypeFunc(ILenum Mode); ILAPI ILboolean ILAPIENTRY ilLoadData(ILconst_string FileName, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp); ILAPI ILboolean ILAPIENTRY ilLoadDataF(ILHANDLE File, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp); ILAPI ILboolean ILAPIENTRY ilLoadDataL(void *Lump, ILuint Size, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp); ILAPI ILboolean ILAPIENTRY ilSaveData(ILconst_string FileName); // For all those weirdos that spell "colour" without the 'u'. #define ilClearColor ilClearColour #define ilKeyColor ilKeyColour #define imemclear(x,y) memset(x,0,y); #ifdef __cplusplus } #endif #endif // __IL_H__ #endif // __il_h__ assimp-4.1.0/samples/DevIL/include/IL/config.h0000644002537200234200000000652513213503245021240 0ustar zmoelnigiemusers/* include/IL/config.h. Generated by configure. */ /* include/IL/config.h.in. Generated from configure.in by autoheader. */ #ifndef __CONFIG_H__ #define __CONFIG_H__ #define IL_USE_PRAGMA_LIBS // Supported image formats (IL) // #define IL_NO_BLP // #define IL_NO_BMP // #define IL_NO_CUT // #define IL_NO_CHEAD // #define IL_NO_DCX // #define IL_NO_DDS // #define IL_NO_DICOM // #define IL_NO_DOOM // #define IL_NO_EXR // #define IL_NO_FITS // #define IL_NO_FTX // #define IL_NO_GIF // #define IL_NO_HDR // #define IL_NO_ICO // #define IL_NO_ICNS // #define IL_NO_IWI // #define IL_NO_JP2 // #define IL_NO_JPG // #define IL_NO_LCMS // #define IL_NO_LIF // #define IL_NO_MDL // #define IL_NO_MNG // #define IL_NO_PCD // #define IL_NO_PCX // #define IL_NO_PIC // #define IL_NO_PIX // #define IL_NO_PNG // #define IL_NO_PNM // #define IL_NO_PSD // #define IL_NO_PSP // #define IL_NO_PXR // #define IL_NO_RAW // #define IL_NO_ROT // #define IL_NO_SGI // #define IL_NO_SUN // #define IL_NO_TGA // #define IL_NO_TIF // #define IL_NO_TPL // #define IL_NO_WAL // #define IL_NO_WDP // #define IL_NO_XPM #define IL_USE_JPEGLIB_UNMODIFIED 1 //#define IL_USE_DXTC_NVIDIA #define IL_USE_DXTC_SQUISH /* Supported api (ilut) */ // // sorry just // can't get this one to work under windows // have disabled for the now // // will look at it some more later // // Kriss // #undef ILUT_USE_ALLEGRO #undef ILUT_USE_DIRECTX8 //#define ILUT_USE_DIRECTX9 //#define ILUT_USE_DIRECTX10 //#define ILUT_USE_OPENGL //#define ILUT_USE_SDL //#define ILUT_USE_WIN32 /* Define to 1 if you have the header file. */ //#define HAVE_DLFCN_H 1 /* Define to 1 if you have the header file. */ //#define HAVE_INTTYPES_H 1 /* Define to 1 if you have the header file. */ //#define HAVE_MEMORY_H 1 /* Define to 1 if you have the header file. */ //#define HAVE_STDINT_H 1 /* Define to 1 if you have the header file. */ //#define HAVE_STDLIB_H 1 /* Define to 1 if you have the header file. */ //#define HAVE_STRINGS_H 1 /* Define to 1 if you have the header file. */ //#define HAVE_STRING_H 1 /* Define to 1 if you have the header file. */ //#define HAVE_SYS_STAT_H 1 /* Define to 1 if you have the header file. */ //#define HAVE_SYS_TYPES_H 1 /* Define to 1 if you have the header file. */ //#define HAVE_UNISTD_H 1 /* Name of package */ #define IL_PACKAGE "DevIL" /* Define to the address where bug reports for this package should be sent. */ #define PACKAGE_BUGREPORT "" /* Define to the full name of this package. */ #define IL_PACKAGE_NAME "" /* Define to the full name and version of this package. */ #define IL_PACKAGE_STRING "" /* Define to the one symbol short name of this package. */ #define IL_PACKAGE_TARNAME "" /* Define to the version of this package. */ #define IL_PACKAGE_VERSION "" /* Define to 1 if you have the ANSI C header files. */ #define STDC_HEADERS 1 /* Version number of package */ //#define IL_VERSION "1.7.3" /* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ /* #undef WORDS_BIGENDIAN */ /* If using Mac OS X uncomment this line */ /* #include "macconfig.h" */ /* Define to 1 if the X Window System is missing or not being used. */ /* #undef X_DISPLAY_MISSING */ #endif /* __CONFIG_H__ */ assimp-4.1.0/samples/DevIL/include/IL/ilut_config.h0000644002537200234200000000070613213503245022270 0ustar zmoelnigiemusers#ifndef __ILUT_CONFIG_H__ #define __ILUT_CONFIG_H__ #define IL_USE_PRAGMA_LIBS // Supported APIs (ILUT) // // sorry just // can't get this one to work under windows // have disabled for the now // // will look at it some more later // // Kriss // #undef ILUT_USE_ALLEGRO #undef ILUT_USE_DIRECTX8 //#define ILUT_USE_DIRECTX9 //#define ILUT_USE_DIRECTX10 #define ILUT_USE_OPENGL //#define ILUT_USE_SDL #define ILUT_USE_WIN32 #endif//__ILUT_CONFIG_H__ assimp-4.1.0/samples/DevIL/include/IL/ilut.h0000644002537200234200000003551713213503245020753 0ustar zmoelnigiemusers//----------------------------------------------------------------------------- // // ImageLib Utility Toolkit Sources // Copyright (C) 2000-2009 by Denton Woods // Last modified: 03/07/2009 // // Filename: IL/ilut.h // // Description: The main include file for ILUT // //----------------------------------------------------------------------------- // Doxygen comment /*! \file ilut.h The main include file for ILUT */ #ifndef __ilut_h_ #ifndef __ILUT_H__ #define __ilut_h_ #define __ILUT_H__ #include #include //----------------------------------------------------------------------------- // Defines //----------------------------------------------------------------------------- #define ILUT_VERSION_1_7_8 1 #define ILUT_VERSION 178 // Attribute Bits #define ILUT_OPENGL_BIT 0x00000001 #define ILUT_D3D_BIT 0x00000002 #define ILUT_ALL_ATTRIB_BITS 0x000FFFFF // Error Types #define ILUT_INVALID_ENUM 0x0501 #define ILUT_OUT_OF_MEMORY 0x0502 #define ILUT_INVALID_VALUE 0x0505 #define ILUT_ILLEGAL_OPERATION 0x0506 #define ILUT_INVALID_PARAM 0x0509 #define ILUT_COULD_NOT_OPEN_FILE 0x050A #define ILUT_STACK_OVERFLOW 0x050E #define ILUT_STACK_UNDERFLOW 0x050F #define ILUT_BAD_DIMENSIONS 0x0511 #define ILUT_NOT_SUPPORTED 0x0550 // State Definitions #define ILUT_PALETTE_MODE 0x0600 #define ILUT_OPENGL_CONV 0x0610 #define ILUT_D3D_MIPLEVELS 0x0620 #define ILUT_MAXTEX_WIDTH 0x0630 #define ILUT_MAXTEX_HEIGHT 0x0631 #define ILUT_MAXTEX_DEPTH 0x0632 #define ILUT_GL_USE_S3TC 0x0634 #define ILUT_D3D_USE_DXTC 0x0634 #define ILUT_GL_GEN_S3TC 0x0635 #define ILUT_D3D_GEN_DXTC 0x0635 #define ILUT_S3TC_FORMAT 0x0705 #define ILUT_DXTC_FORMAT 0x0705 #define ILUT_D3D_POOL 0x0706 #define ILUT_D3D_ALPHA_KEY_COLOR 0x0707 #define ILUT_D3D_ALPHA_KEY_COLOUR 0x0707 #define ILUT_FORCE_INTEGER_FORMAT 0x0636 //This new state does automatic texture target detection //if enabled. Currently, only cubemap detection is supported. //if the current image is no cubemap, the 2d texture is chosen. #define ILUT_GL_AUTODETECT_TEXTURE_TARGET 0x0807 // Values #define ILUT_VERSION_NUM IL_VERSION_NUM #define ILUT_VENDOR IL_VENDOR // The different rendering api's...more to be added later? #define ILUT_OPENGL 0 #define ILUT_ALLEGRO 1 #define ILUT_WIN32 2 #define ILUT_DIRECT3D8 3 #define ILUT_DIRECT3D9 4 #define ILUT_X11 5 #define ILUT_DIRECT3D10 6 /* // Includes specific config #ifdef DJGPP #define ILUT_USE_ALLEGRO #elif _WIN32_WCE #define ILUT_USE_WIN32 #elif _WIN32 //#ifdef __GNUC__ //__CYGWIN32__ (Cygwin seems to not define this with DevIL builds) #define ILUT_USE_WIN32 #include "IL/config.h" // Temporary fix for the SDL main() linker bug. //#ifdef ILUT_USE_SDL //#undef ILUT_USE_SDL //#endif//ILUT_USE_SDL //#else // #define ILUT_USE_WIN32 // #define ILUT_USE_OPENGL // #define ILUT_USE_SDL // #define ILUT_USE_DIRECTX8 //#endif #elif BEOS // Don't know the #define #define ILUT_USE_BEOS #define ILUT_USE_OPENGL #elif MACOSX #define ILUT_USE_OPENGL #else // We are surely using a *nix so the configure script // may have written the configured config.h header #include "IL/config.h" #endif */ #if (defined(_WIN32) || defined(_WIN64)) #if (defined(IL_USE_PRAGMA_LIBS)) && (!defined(_IL_BUILD_LIBRARY)) #if defined(_MSC_VER) || defined(__BORLANDC__) #pragma comment(lib, "ILUT.lib") #endif #endif #include #endif //this should remain private and hidden //#include "IL/config.h" ////////////// // OpenGL ////////////// #ifdef ILUT_USE_OPENGL #if defined(_MSC_VER) || defined(_WIN32) //#define WIN32_LEAN_AND_MEAN #include #endif//_MSC_VER #ifdef __APPLE__ #include #include #else #include #include #endif//__APPLE__ #endif #ifdef ILUT_USE_WIN32 //#define WIN32_LEAN_AND_MEAN #ifdef _DEBUG #define _CRTDBG_MAP_ALLOC #include #ifndef _WIN32_WCE #include #endif #endif #include #endif // // If we can avoid including these in all cases thing tend to break less // and we can keep all of them defined as available // // Kriss // // ImageLib Utility Toolkit's Allegro Functions #ifdef ILUT_USE_ALLEGRO // #include #endif//ILUT_USE_ALLEGRO #ifdef ILUT_USE_SDL // #include #endif #ifdef ILUT_USE_DIRECTX8 #include #endif//ILUT_USE_DIRECTX9 #ifdef ILUT_USE_DIRECTX9 #include #endif//ILUT_USE_DIRECTX9 #ifdef ILUT_USE_DIRECTX10 #pragma warning(push) #pragma warning(disable : 4201) // Disables 'nonstandard extension used : nameless struct/union' warning #include #include #include #pragma warning(pop) #endif//ILUT_USE_DIRECTX10 #ifdef ILUT_USE_X11 #include #include #ifdef ILUT_USE_XSHM #include #include #include #endif//ILUT_USE_XSHM #endif//ILUT_USE_X11 //----------------------------------------------------------------------------- // Functions //----------------------------------------------------------------------------- #ifdef __cplusplus extern "C" { #endif // ImageLib Utility Toolkit Functions ILAPI ILboolean ILAPIENTRY ilutDisable(ILenum Mode); ILAPI ILboolean ILAPIENTRY ilutEnable(ILenum Mode); ILAPI ILboolean ILAPIENTRY ilutGetBoolean(ILenum Mode); ILAPI void ILAPIENTRY ilutGetBooleanv(ILenum Mode, ILboolean *Param); ILAPI ILint ILAPIENTRY ilutGetInteger(ILenum Mode); ILAPI void ILAPIENTRY ilutGetIntegerv(ILenum Mode, ILint *Param); ILAPI ILstring ILAPIENTRY ilutGetString(ILenum StringName); ILAPI void ILAPIENTRY ilutInit(void); ILAPI ILboolean ILAPIENTRY ilutIsDisabled(ILenum Mode); ILAPI ILboolean ILAPIENTRY ilutIsEnabled(ILenum Mode); ILAPI void ILAPIENTRY ilutPopAttrib(void); ILAPI void ILAPIENTRY ilutPushAttrib(ILuint Bits); ILAPI void ILAPIENTRY ilutSetInteger(ILenum Mode, ILint Param); ILAPI ILboolean ILAPIENTRY ilutRenderer(ILenum Renderer); // ImageLib Utility Toolkit's OpenGL Functions #ifdef ILUT_USE_OPENGL ILAPI GLuint ILAPIENTRY ilutGLBindTexImage(); ILAPI GLuint ILAPIENTRY ilutGLBindMipmaps(void); ILAPI ILboolean ILAPIENTRY ilutGLBuildMipmaps(void); ILAPI GLuint ILAPIENTRY ilutGLLoadImage(ILstring FileName); ILAPI ILboolean ILAPIENTRY ilutGLScreen(void); ILAPI ILboolean ILAPIENTRY ilutGLScreenie(void); ILAPI ILboolean ILAPIENTRY ilutGLSaveImage(ILstring FileName, GLuint TexID); ILAPI ILboolean ILAPIENTRY ilutGLSubTex2D(GLuint TexID, ILuint XOff, ILuint YOff); ILAPI ILboolean ILAPIENTRY ilutGLSubTex3D(GLuint TexID, ILuint XOff, ILuint YOff, ILuint ZOff); ILAPI ILboolean ILAPIENTRY ilutGLSetTex2D(GLuint TexID); ILAPI ILboolean ILAPIENTRY ilutGLSetTex3D(GLuint TexID); ILAPI ILboolean ILAPIENTRY ilutGLTexImage(GLuint Level); ILAPI ILboolean ILAPIENTRY ilutGLSubTex(GLuint TexID, ILuint XOff, ILuint YOff); ILAPI ILboolean ILAPIENTRY ilutGLSetTex(GLuint TexID); // Deprecated - use ilutGLSetTex2D. ILAPI ILboolean ILAPIENTRY ilutGLSubTex(GLuint TexID, ILuint XOff, ILuint YOff); // Use ilutGLSubTex2D. #endif//ILUT_USE_OPENGL // ImageLib Utility Toolkit's Allegro Functions #ifdef ILUT_USE_ALLEGRO #ifdef __cplusplus extern "C" { #endif #include #ifdef __cplusplus } #endif ILAPI BITMAP* ILAPIENTRY ilutAllegLoadImage(ILstring FileName); ILAPI BITMAP* ILAPIENTRY ilutConvertToAlleg(PALETTE Pal); #endif//ILUT_USE_ALLEGRO // ImageLib Utility Toolkit's SDL Functions #ifdef ILUT_USE_SDL ILAPI struct SDL_Surface* ILAPIENTRY ilutConvertToSDLSurface(unsigned int flags); ILAPI struct SDL_Surface* ILAPIENTRY ilutSDLSurfaceLoadImage(ILstring FileName); ILAPI ILboolean ILAPIENTRY ilutSDLSurfaceFromBitmap(struct SDL_Surface *Bitmap); #endif//ILUT_USE_SDL // ImageLib Utility Toolkit's BeOS Functions #ifdef ILUT_USE_BEOS ILAPI BBitmap ILAPIENTRY ilutConvertToBBitmap(void); #endif//ILUT_USE_BEOS // ImageLib Utility Toolkit's Win32 GDI Functions #ifdef ILUT_USE_WIN32 ILAPI HBITMAP ILAPIENTRY ilutConvertToHBitmap(HDC hDC); ILAPI HBITMAP ILAPIENTRY ilutConvertSliceToHBitmap(HDC hDC, ILuint slice); ILAPI void ILAPIENTRY ilutFreePaddedData(ILubyte *Data); ILAPI void ILAPIENTRY ilutGetBmpInfo(BITMAPINFO *Info); ILAPI HPALETTE ILAPIENTRY ilutGetHPal(void); ILAPI ILubyte* ILAPIENTRY ilutGetPaddedData(void); ILAPI ILboolean ILAPIENTRY ilutGetWinClipboard(void); ILAPI ILboolean ILAPIENTRY ilutLoadResource(HINSTANCE hInst, ILint ID, ILstring ResourceType, ILenum Type); ILAPI ILboolean ILAPIENTRY ilutSetHBitmap(HBITMAP Bitmap); ILAPI ILboolean ILAPIENTRY ilutSetHPal(HPALETTE Pal); ILAPI ILboolean ILAPIENTRY ilutSetWinClipboard(void); ILAPI HBITMAP ILAPIENTRY ilutWinLoadImage(ILstring FileName, HDC hDC); ILAPI ILboolean ILAPIENTRY ilutWinLoadUrl(ILstring Url); ILAPI ILboolean ILAPIENTRY ilutWinPrint(ILuint XPos, ILuint YPos, ILuint Width, ILuint Height, HDC hDC); ILAPI ILboolean ILAPIENTRY ilutWinSaveImage(ILstring FileName, HBITMAP Bitmap); #endif//ILUT_USE_WIN32 // ImageLib Utility Toolkit's DirectX 8 Functions #ifdef ILUT_USE_DIRECTX8 // ILAPI void ILAPIENTRY ilutD3D8MipFunc(ILuint NumLevels); ILAPI struct IDirect3DTexture8* ILAPIENTRY ilutD3D8Texture(struct IDirect3DDevice8 *Device); ILAPI struct IDirect3DVolumeTexture8* ILAPIENTRY ilutD3D8VolumeTexture(struct IDirect3DDevice8 *Device); ILAPI ILboolean ILAPIENTRY ilutD3D8TexFromFile(struct IDirect3DDevice8 *Device, char *FileName, struct IDirect3DTexture8 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D8VolTexFromFile(struct IDirect3DDevice8 *Device, char *FileName, struct IDirect3DVolumeTexture8 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D8TexFromFileInMemory(struct IDirect3DDevice8 *Device, void *Lump, ILuint Size, struct IDirect3DTexture8 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D8VolTexFromFileInMemory(struct IDirect3DDevice8 *Device, void *Lump, ILuint Size, struct IDirect3DVolumeTexture8 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D8TexFromFileHandle(struct IDirect3DDevice8 *Device, ILHANDLE File, struct IDirect3DTexture8 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D8VolTexFromFileHandle(struct IDirect3DDevice8 *Device, ILHANDLE File, struct IDirect3DVolumeTexture8 **Texture); // These two are not tested yet. ILAPI ILboolean ILAPIENTRY ilutD3D8TexFromResource(struct IDirect3DDevice8 *Device, HMODULE SrcModule, char *SrcResource, struct IDirect3DTexture8 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D8VolTexFromResource(struct IDirect3DDevice8 *Device, HMODULE SrcModule, char *SrcResource, struct IDirect3DVolumeTexture8 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D8LoadSurface(struct IDirect3DDevice8 *Device, struct IDirect3DSurface8 *Surface); #endif//ILUT_USE_DIRECTX8 #ifdef ILUT_USE_DIRECTX9 #pragma warning(push) #pragma warning(disable : 4115) // Disables 'named type definition in parentheses' warning // ILAPI void ILAPIENTRY ilutD3D9MipFunc(ILuint NumLevels); ILAPI struct IDirect3DTexture9* ILAPIENTRY ilutD3D9Texture (struct IDirect3DDevice9* Device); ILAPI struct IDirect3DVolumeTexture9* ILAPIENTRY ilutD3D9VolumeTexture (struct IDirect3DDevice9* Device); ILAPI struct IDirect3DCubeTexture9* ILAPIENTRY ilutD3D9CubeTexture (struct IDirect3DDevice9* Device); ILAPI ILboolean ILAPIENTRY ilutD3D9CubeTexFromFile(struct IDirect3DDevice9 *Device, ILconst_string FileName, struct IDirect3DCubeTexture9 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D9CubeTexFromFileInMemory(struct IDirect3DDevice9 *Device, void *Lump, ILuint Size, struct IDirect3DCubeTexture9 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D9CubeTexFromFileHandle(struct IDirect3DDevice9 *Device, ILHANDLE File, struct IDirect3DCubeTexture9 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D9CubeTexFromResource(struct IDirect3DDevice9 *Device, HMODULE SrcModule, ILconst_string SrcResource, struct IDirect3DCubeTexture9 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D9TexFromFile(struct IDirect3DDevice9 *Device, ILconst_string FileName, struct IDirect3DTexture9 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D9VolTexFromFile(struct IDirect3DDevice9 *Device, ILconst_string FileName, struct IDirect3DVolumeTexture9 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D9TexFromFileInMemory(struct IDirect3DDevice9 *Device, void *Lump, ILuint Size, struct IDirect3DTexture9 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D9VolTexFromFileInMemory(struct IDirect3DDevice9 *Device, void *Lump, ILuint Size, struct IDirect3DVolumeTexture9 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D9TexFromFileHandle(struct IDirect3DDevice9 *Device, ILHANDLE File, struct IDirect3DTexture9 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D9VolTexFromFileHandle(struct IDirect3DDevice9 *Device, ILHANDLE File, struct IDirect3DVolumeTexture9 **Texture); // These three are not tested yet. ILAPI ILboolean ILAPIENTRY ilutD3D9TexFromResource(struct IDirect3DDevice9 *Device, HMODULE SrcModule, ILconst_string SrcResource, struct IDirect3DTexture9 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D9VolTexFromResource(struct IDirect3DDevice9 *Device, HMODULE SrcModule, ILconst_string SrcResource, struct IDirect3DVolumeTexture9 **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D9LoadSurface(struct IDirect3DDevice9 *Device, struct IDirect3DSurface9 *Surface); #pragma warning(pop) #endif//ILUT_USE_DIRECTX9 #ifdef ILUT_USE_DIRECTX10 ILAPI ID3D10Texture2D* ILAPIENTRY ilutD3D10Texture(ID3D10Device *Device); ILAPI ILboolean ILAPIENTRY ilutD3D10TexFromFile(ID3D10Device *Device, ILconst_string FileName, ID3D10Texture2D **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D10TexFromFileInMemory(ID3D10Device *Device, void *Lump, ILuint Size, ID3D10Texture2D **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D10TexFromResource(ID3D10Device *Device, HMODULE SrcModule, ILconst_string SrcResource, ID3D10Texture2D **Texture); ILAPI ILboolean ILAPIENTRY ilutD3D10TexFromFileHandle(ID3D10Device *Device, ILHANDLE File, ID3D10Texture2D **Texture); #endif//ILUT_USE_DIRECTX10 #ifdef ILUT_USE_X11 ILAPI XImage * ILAPIENTRY ilutXCreateImage( Display* ); ILAPI Pixmap ILAPIENTRY ilutXCreatePixmap( Display*,Drawable ); ILAPI XImage * ILAPIENTRY ilutXLoadImage( Display*,char* ); ILAPI Pixmap ILAPIENTRY ilutXLoadPixmap( Display*,Drawable,char* ); #ifdef ILUT_USE_XSHM ILAPI XImage * ILAPIENTRY ilutXShmCreateImage( Display*,XShmSegmentInfo* ); ILAPI void ILAPIENTRY ilutXShmDestroyImage( Display*,XImage*,XShmSegmentInfo* ); ILAPI Pixmap ILAPIENTRY ilutXShmCreatePixmap( Display*,Drawable,XShmSegmentInfo* ); ILAPI void ILAPIENTRY ilutXShmFreePixmap( Display*,Pixmap,XShmSegmentInfo* ); ILAPI XImage * ILAPIENTRY ilutXShmLoadImage( Display*,char*,XShmSegmentInfo* ); ILAPI Pixmap ILAPIENTRY ilutXShmLoadPixmap( Display*,Drawable,char*,XShmSegmentInfo* ); #endif//ILUT_USE_XSHM #endif//ILUT_USE_X11 #ifdef __cplusplus } #endif #endif // __ILUT_H__ #endif // __ilut_h_ assimp-4.1.0/samples/DevIL/include/IL/config.h.win0000644002537200234200000000306013213503245022023 0ustar zmoelnigiemusers#ifndef __CONFIG_H__ #define __CONFIG_H__ #define IL_USE_PRAGMA_LIBS // Links to only the libraries that are requested. #define IL_INLINE_ASM 1 // Define if you can support at least some ASM // Supported images formats (IL) // #define IL_NO_BLP // #define IL_NO_BMP // #define IL_NO_CUT // #define IL_NO_CHEAD // #define IL_NO_DCX // #define IL_NO_DDS // #define IL_NO_DICOM // #define IL_NO_DOOM // #define IL_NO_EXR // #define IL_NO_FITS // #define IL_NO_FTX // #define IL_NO_GIF // #define IL_NO_HDR // #define IL_NO_ICO // #define IL_NO_ICNS // #define IL_NO_IWI // #define IL_NO_JP2 // #define IL_NO_JPG // #define IL_NO_LCMS // #define IL_NO_LIF // #define IL_NO_MDL // #define IL_NO_MNG // #define IL_NO_PCD // #define IL_NO_PCX // #define IL_NO_PIC // #define IL_NO_PIX // #define IL_NO_PNG // #define IL_NO_PNM // #define IL_NO_PSD // #define IL_NO_PSP // #define IL_NO_PXR // #define IL_NO_RAW // #define IL_NO_ROT // #define IL_NO_SGI // #define IL_NO_SUN // #define IL_NO_TGA // #define IL_NO_TIF // #define IL_NO_TPL // #define IL_NO_WAL // #define IL_NO_WDP // #define IL_NO_XPM #define IL_USE_JPEGLIB_UNMODIFIED 1 #define IL_USE_DXTC_NVIDIA #define IL_USE_DXTC_SQUISH //#define IL_NO_GAMES /* Supported api (ilut) */ // // sorry just // can't get this one to work under windows // have disabled for the now // // will look at it some more later // // Kriss // #undef ILUT_USE_ALLEGRO #undef ILUT_USE_DIRECTX8 #define ILUT_USE_DIRECTX9 #define ILUT_USE_DIRECTX10 #define ILUT_USE_OPENGL #define ILUT_USE_SDL #define ILUT_USE_WIN32 #endif /* __CONFIG_H__ */ assimp-4.1.0/samples/DevIL/include/IL/devil_internal_exports.h0000644002537200234200000001541013213503245024547 0ustar zmoelnigiemusers//----------------------------------------------------------------------------- // // ImageLib Sources // Copyright (C) 2000-2009 by Denton Woods // Last modified: 01/06/2009 // // Filename: IL/devil_internal_exports.h // // Description: Internal stuff for DevIL (IL, ILU and ILUT) // //----------------------------------------------------------------------------- #ifndef IL_EXPORTS_H #define IL_EXPORTS_H #include "IL/il.h" #ifdef DEBUG #include #else #define assert(x) #endif //#ifndef NOINLINE #ifndef INLINE #if defined(__GNUC__) #define INLINE extern inline #elif defined(_MSC_VER) //@TODO: Get this working in MSVC++. // http://www.greenend.org.uk/rjk/2003/03/inline.html #define NOINLINE //#define INLINE /*#ifndef _WIN64 // Cannot use inline assembly in x64 target platform. #define USE_WIN32_ASM #endif//_WIN64*/ #define INLINE __inline #else #define INLINE inline #endif #endif //#else //#define INLINE //#endif //NOINLINE #ifdef __cplusplus extern "C" { #endif #define IL_MAX(a,b) (((a) > (b)) ? (a) : (b)) #define IL_MIN(a,b) (((a) < (b)) ? (a) : (b)) //! Basic Palette struct typedef struct ILpal { ILubyte* Palette; //!< the image palette (if any) ILuint PalSize; //!< size of the palette (in bytes) ILenum PalType; //!< the palette types in il.h (0x0500 range) } ILpal; //! The Fundamental Image structure /*! Every bit of information about an image is stored in this internal structure.*/ typedef struct ILimage { ILuint Width; //!< the image's width ILuint Height; //!< the image's height ILuint Depth; //!< the image's depth ILubyte Bpp; //!< bytes per pixel (now number of channels) ILubyte Bpc; //!< bytes per channel ILuint Bps; //!< bytes per scanline (components for IL) ILubyte* Data; //!< the image data ILuint SizeOfData; //!< the total size of the data (in bytes) ILuint SizeOfPlane; //!< SizeOfData in a 2d image, size of each plane slice in a 3d image (in bytes) ILenum Format; //!< image format (in IL enum style) ILenum Type; //!< image type (in IL enum style) ILenum Origin; //!< origin of the image ILpal Pal; //!< palette details ILuint Duration; //!< length of the time to display this "frame" ILenum CubeFlags; //!< cube map flags for sides present in chain struct ILimage* Mipmaps; //!< mipmapped versions of this image terminated by a NULL - usu. NULL struct ILimage* Next; //!< next image in the chain - usu. NULL struct ILimage* Faces; //!< next cubemap face in the chain - usu. NULL struct ILimage* Layers; //!< subsequent layers in the chain - usu. NULL ILuint* AnimList; //!< animation list ILuint AnimSize; //!< animation list size void* Profile; //!< colour profile ILuint ProfileSize; //!< colour profile size ILuint OffX; //!< x-offset of the image ILuint OffY; //!< y-offset of the image ILubyte* DxtcData; //!< compressed data ILenum DxtcFormat; //!< compressed data format ILuint DxtcSize; //!< compressed data size } ILimage; // Memory functions ILAPI void* ILAPIENTRY ialloc(const ILsizei Size); ILAPI void ILAPIENTRY ifree(const void *Ptr); ILAPI void* ILAPIENTRY icalloc(const ILsizei Size, const ILsizei Num); #ifdef ALTIVEC_GCC ILAPI void* ILAPIENTRY ivec_align_buffer(void *buffer, const ILuint size); #endif // Internal library functions in IL ILAPI ILimage* ILAPIENTRY ilGetCurImage(void); ILAPI void ILAPIENTRY ilSetCurImage(ILimage *Image); ILAPI void ILAPIENTRY ilSetError(ILenum Error); ILAPI void ILAPIENTRY ilSetPal(ILpal *Pal); // // Utility functions // ILAPI ILubyte ILAPIENTRY ilGetBppFormat(ILenum Format); ILAPI ILenum ILAPIENTRY ilGetFormatBpp(ILubyte Bpp); ILAPI ILubyte ILAPIENTRY ilGetBpcType(ILenum Type); ILAPI ILenum ILAPIENTRY ilGetTypeBpc(ILubyte Bpc); ILAPI ILubyte ILAPIENTRY ilGetBppPal(ILenum PalType); ILAPI ILenum ILAPIENTRY ilGetPalBaseType(ILenum PalType); ILAPI ILuint ILAPIENTRY ilNextPower2(ILuint Num); ILAPI ILenum ILAPIENTRY ilTypeFromExt(ILconst_string FileName); ILAPI void ILAPIENTRY ilReplaceCurImage(ILimage *Image); ILAPI void ILAPIENTRY iMemSwap(ILubyte *, ILubyte *, const ILuint); // // Image functions // ILAPI void ILAPIENTRY iBindImageTemp (void); ILAPI ILboolean ILAPIENTRY ilClearImage_ (ILimage *Image); ILAPI void ILAPIENTRY ilCloseImage (ILimage *Image); ILAPI void ILAPIENTRY ilClosePal (ILpal *Palette); ILAPI ILpal* ILAPIENTRY iCopyPal (void); ILAPI ILboolean ILAPIENTRY ilCopyImageAttr (ILimage *Dest, ILimage *Src); ILAPI ILimage* ILAPIENTRY ilCopyImage_ (ILimage *Src); ILAPI void ILAPIENTRY ilGetClear (void *Colours, ILenum Format, ILenum Type); ILAPI ILuint ILAPIENTRY ilGetCurName (void); ILAPI ILboolean ILAPIENTRY ilIsValidPal (ILpal *Palette); ILAPI ILimage* ILAPIENTRY ilNewImage (ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILubyte Bpc); ILAPI ILimage* ILAPIENTRY ilNewImageFull (ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILenum Format, ILenum Type, void *Data); ILAPI ILboolean ILAPIENTRY ilInitImage (ILimage *Image, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILenum Format, ILenum Type, void *Data); ILAPI ILboolean ILAPIENTRY ilResizeImage (ILimage *Image, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILubyte Bpc); ILAPI ILboolean ILAPIENTRY ilTexImage_ (ILimage *Image, ILuint Width, ILuint Height, ILuint Depth, ILubyte Bpp, ILenum Format, ILenum Type, void *Data); ILAPI ILboolean ILAPIENTRY ilTexSubImage_ (ILimage *Image, void *Data); ILAPI void* ILAPIENTRY ilConvertBuffer (ILuint SizeOfData, ILenum SrcFormat, ILenum DestFormat, ILenum SrcType, ILenum DestType, ILpal *SrcPal, void *Buffer); ILAPI ILimage* ILAPIENTRY iConvertImage (ILimage *Image, ILenum DestFormat, ILenum DestType); ILAPI ILpal* ILAPIENTRY iConvertPal (ILpal *Pal, ILenum DestFormat); ILAPI ILubyte* ILAPIENTRY iGetFlipped (ILimage *Image); ILAPI ILboolean ILAPIENTRY iMirror(); ILAPI void ILAPIENTRY iFlipBuffer(ILubyte *buff, ILuint depth, ILuint line_size, ILuint line_num); ILubyte* iFlipNewBuffer(ILubyte *buff, ILuint depth, ILuint line_size, ILuint line_num); ILAPI void ILAPIENTRY iGetIntegervImage(ILimage *Image, ILenum Mode, ILint *Param); // Internal library functions in ILU ILAPI ILimage* ILAPIENTRY iluRotate_(ILimage *Image, ILfloat Angle); ILAPI ILimage* ILAPIENTRY iluRotate3D_(ILimage *Image, ILfloat x, ILfloat y, ILfloat z, ILfloat Angle); ILAPI ILimage* ILAPIENTRY iluScale_(ILimage *Image, ILuint Width, ILuint Height, ILuint Depth); #ifdef __cplusplus } #endif #endif//IL_EXPORTS_H assimp-4.1.0/samples/DevIL/include/IL/ilu_region.h0000644002537200234200000000103113213503245022112 0ustar zmoelnigiemusers//----------------------------------------------------------------------------- // // ImageLib Utility Sources // Copyright (C) 2000-2002 by Denton Woods // Last modified: 07/09/2002 <--Y2K Compliant! =] // // Filename: src-ILU/src/ilu_region.h // // Description: Creates an image region. // //----------------------------------------------------------------------------- #ifndef ILU_REGION_H #define ILU_REGION_H typedef struct Edge { ILint yUpper; ILfloat xIntersect, dxPerScan; struct Edge *next; } Edge; #endif//ILU_REGION_H assimp-4.1.0/samples/DevIL/ChangeLog0000644002537200234200000007606113213503245017447 0ustar zmoelnigiemusers2009-03-08 Matěj Týč * docs/Makefile.am: Fixed distcheck by overriding dvi target. * lib/Makefile.am: Renoved ilu_mipmap.h file * configure.ac: Added option to disable checks for 'nvidia texture tools' and 'libsquish' 2009-03-08 Denton Woods * il_ilbm.c:410: Changed to IL_BGR from IL_RGB. * il_iff.c (ilLoadIffF/ilLoadIffL): Changed to call Lbm loading functions if Iff loading fails, since they both can have the .iff extension. * il_ilbm.c:416: Added origin reference. * configure.ac: Added more file formats to the format checks. * Makefile.am: Removed ilu_mipmap.h. Added ilu_error-french.h. 2009-03-07 Denton Woods * Updated version numbers to 1.7.8 project-wide. * DevIL_manual.texi: Added several file formats to the appendix. * il_io.c: Updated Doxygen comments for loading/saving functions. * libraries.txt: Updated with new libraries. * il_io.c (ilTypeFromExt): Changed return value of FITS files to IL_FITS. Added DICOM, FTX, Rot and Texture checks. * il_states.c/.h: Updated with newer file formats. * il_blp.c:649: Fixed ilNewImageFull call to use color index. 659: Fixed memcpy from base image to new mipmap. * il_dcx.c, il_exr.cpp and many more: Checks return value of ilFixImage now. * il_iff.c:271: Got rid of ilConvertImage call. 2009-03-06 Denton Woods * Updated VC8 projects to use il_mp3.c. * il.h: Added description to IL_WDP. 2009-03-05 Denton Woods * il_mp3.c: Added this file. * il_io.c: Added loading calls for .mp3 files. * il_internal.h: Added .mp3 loading declarations. * Makefile.am: Added il_mp3.c to source line. * il.h: Added IL_MP3 define. 2009-03-04 Denton Woods * il_utx.cpp: Started cleanup of file using C++ constructs. * Updated VC8 projects to use il_utx.cpp. 2009-03-03 Denton Woods * ilu_error-french.h: Added French translation of errors. * ilu.h: Added ILU_FRENCH define. * Changed il_utx.c to il_utx.cpp. 2009-03-02 Denton Woods * il_utx.c: Added DXT1 loading in UTX files. * il_utx.h: Added this file. * lib/Makefile.am: Added il_utx.h to include line. * il_utx.c: Fixed loading of larger images. * windows_example.rc: Fixed accelerator for menu. 2009-03-01 Denton Woods * il_utx.c: Added this file. * lib/Makefile.am: Added il_utx.c to source line. * il_internal.h: Added .utx loading declarations. * il_io.c: Added loading calls for .utx files. 2009-02-28 Denton Woods * il_states.c / il_states.h: Added ilVtfCompression to IL_STATES. * il_vtf.c: Added more formats to saving. * il.h: Added IL_VTF_COMP define. * il_io.c: Added saving calls for .vtf files. * il_dds.c: Added DecompressARGB16 to load a2r10g10b10 and a2b10g10r10 formats. * il_convbuff (iSwitchTypes): Added several missing break statements. * il_convbuff:1988: Changed to check types instead of bpc. 2009-02-27 Denton Woods * il_dpx.c / il_dpx.h: Got basic dpx loading working. * WindowsTest.cpp: Fixed memory leak when loading files. * il_vtf.c (iGetVtfHead): Added support for headers of 64 bytes. * il_iwi.c (iLoadIwiInternal): Added IL_INVALID_FILE_HEADER error. * il_vtf.c: Added VTF writing functions. 2009-02-26 Denton Woods * configure.ac, lib/Makefile.am, il.h, il_internal.h, il_ilbm.c, il_io.c: Added patch from Ben Campbell for ILBM files at https://sourceforge.net/tracker2/index.php?func=detail&aid=2635333&group_id=4470&atid=304470. * il_dpx.c / il_dpx.h: Added these files. * lib/Makefile.am: Added il_dpx.c and il_dpx.h to source/include lines. * il_internal.h: Added .dpx loading declarations. * il_io.c: Added loading calls for .dpx files. 2009-02-25 Denton Woods * il_iwi.c:329: Changed IL_MAX parameter from 16 to 8 (copy+paste error). * WindowsTest.cpp: Added mipmap functionality to 0-9 keys (0 goes to main image). 2009-02-24 Denton Woods * vc9 Unicode projects: Changed settings to use x64 and x86 directories for .obj files. * test/in: Removed this directory. * Added "Test Images" to SVN. * il_dds.c (DecompressFloat): Added proper support for G16B16, G32B32, R16 and R32 images. 2009-02-23 Denton Woods * il_pnm.c: Fixed bug at https://sourceforge.net/forum/message.php?msg_id=6491617 - Changed order of lines 448 and 450. 2009-02-22 Denton Woods * il_internal.h: Added IL_NO_EXTLIBS define. * il_dds-save.c: Removed unused variables. * ilu_mipmap.c: Finished redoing all mipmap functions. * ilu_mipmap.h: Removed this file. 2009-02-21 Denton Woods * ilu_mipmap.c: Redid mipmap functions to use iluScale functions instead of nearest. 2009-02-20 Matěj Týč * docs/Makefile.am,docs/Devil_manual.texi: Added new ILU images to the manual, set the manual license to GFDL. * testil, ilur: Licensed under GPL v3 2009-02-19 Denton Woods * windows_example\resources: Added DevIL Logo.ico, removed OpenIL Logo.ico. * windows_example\resource.h: Changed to use DevIL Logo.ico. * il_io.c (ilSaveL): Fixed bug where return type was cast to 1 byte. 2009-02-18 Denton Woods * configure.ac: Added descriptions of more image formats. * il_ftx.c (iLoadFtxInternal): Changed to load all FTX images as RGBA. 2009-02-17 Denton Woods * ilu_mipmap.c: Changed all references of Next to Mipmaps to fix bug noticed at https://sourceforge.net/forum/message.php?msg_id=6443698. * Added support for IL_NO_GAMES in il_internal.h. 2009-02-17 Matěj Týč * configure.ac, m4/devil-definitions.m4 (TEST_FORMAT): Added an option to describe image formats. 2009-02-16 Matěj Týč * src-ILU/ilur: Made ilur independent on regex.h * autogen.sh: Simplified autotools invocation to autoreconf only * configure.ac: Added support for IL_NO_GAMES if users don't want support for game formats * docs/DevIL_manual.texi: Fixed errors causing trouble when making info files + some minor syntax enhancements. 2009-02-16 Denton Woods * il_manip.c (ilGetAlpha): Added IL_ALPHA case. * il_manip.c (ilSetAlpha): Cleaned up formatting. Added IL_ALPHA case. Fixed casting issue in integer case. * il_texture.c: Added this file and the simple .texture loading. * lib/Makefile.am and src-IL/src/Makefile.am: Added il_texture.c to source line. * il.h: Added IL_TEXTURE define. * il_internal.h: Added .texture loading declarations. * DevIL.nb: Removed the test image from the notebook to drop it from over 9MB to 4.5KB. 2009-02-15 Denton Woods * il_blp.c (iLoadBlpInternal): Finished testing and fixed BLP2 RAW with 1-bit alpha. * il_dicom.c: Added this file. * config.h.win: Added defines for new image formats. * il_io.c / il_jp2.c: Added .jpx, .j2k and .j2c extensions for JPEG 2000. * il_io.c / il_jpeg.c: Added .jif and .jfif extensions for JPEG. * il_dicom.c: Added DICOM loading for uncompressed formats and little endian data. * lib/Makefile.am and src-IL/src/Makefile.am: Added il_dicom.c to source line. * il_dicom.c: Added DICOM support for big endian data. * test/in/tiff: Removed this directory. * il_rot.c: Added this file. Added .rot loading. * lib/Makefile.am and src-IL/src/Makefile.am: Added il_rot.c to source line. * il.h: Added IL_ROT define. * il_internal.h: Added Rot loading declarations. 2009-02-15 Matěj Týč * src-ILU/ilur: Added the ilur - commandline ILU frontend * bin, examples/Makefile.am: Moved examples's Makefile.am to bin directory. Added ilur to it. * docs/DevIL_manual.texi: Made slight syntax corrections, fixed the sample program and added functions index 2009-02-14 Denton Woods * il_blp.c (iLoadBlp1): Support for mipmaps added. * il_gif.h: Moved iCopyPalette declaration out of here into il_internal.h. * il_gif.c: Moved iCopyPalette definition out of here into il_pal.c. * projects/Mathematica: Added this folder. * il_fits.c (iCheckFits): Implemented this. * il_fits.c (iLoadFitsInternal): Renormalized float and double data. * il_blp.c (iLoadBlp1): Added seeks to image data (not necessarily following palette). * il_blp.c (iLoadBlpInternal): Added loading for BLP2 RAW with 1-bit alpha. 2009-02-13 Denton Woods * WindowsTest.cpp: Added slideshow capabilities with Page Up and Page Down. * il_jpeg.c:357: Added ilFixImage call. * il_jpeg.c (ilLoadFromJpegStruct): Changed return value to the return of ilFixImage. * il_blp.c:466-467: Fixed to read these images properly. * WindowsTest Project: Changed x64 debug to use runtime library debug DLLs. 2009-02-12 Denton Woods * il_ftx.c: Added this file. * lib/Makefile.am and src-IL/src/Makefile.am: Added il_ftx.c to source line. * il_io.c: Added Ftx loading function calls. * il_blp.c: Added BLP1-loading functions. 2009-02-11 Denton Woods * il_jpeg.c (ilSaveJpegL): Changed the itellw call to after iSetOutputLump (was returning bad values, since the lump was not set yet). * il_io.c (ilSaveL): Changed return value to Ret and got rid of IL_FALSE check. * il_bmp.c, il_dds-save.c, il_hdr.c, il_jp2.c, il_pcx.c, il_png.c, il_pnm.c, il_psd.c, il_raw.c, il_sgi.c, il_wbmp.c: Fixed same problem that il_jpeg.c had with saving lumps. * il_sgi.c: Put header on file. * il_iwi.c:337: Removed this line, which called iread a second time for CompData. 2009-02-10 Denton Woods * il_io.c: Added ilLoadBlp calls in il_io.c. * VC9 projects: Turned off x64 incremental linking to prevent debugging problems described here: http://stackoverflow.com/questions/218747/msvcr90ddll-not-found-in-debug-mode-with-visual-c-2008 * il_blp.c: Added code to read BLP2 files. 2009-02-09 Denton Woods * ilu_scale2d.c (iluScale2DBilinear_): Started rewrite, since results were really ugly. * il_iwi.c / il_vtf.c: Changed max references to IL_MAX. * il_wdp.c: Redid all of the code so that it actually works now. * il_internal.h:42-46: Added lines to define IL_NO_WDP if not in Windows. * il_io.c: Added Iwi and Fits loading calls. * il.h: Added IL_BLP and IL_DICOM. Switched IL_DICOM and IL_IWI defines. * il_internal.h: Added Blp and Dicom function defines. * il_blp.c: Added this file and started code. * lib/Makefile.am and src-IL/src/Makefile.am: Added il_blp.c to source line. 2009-02-09 Matěj Týč * tests/testil.c: Added checks what IL loading/saving routines ended * build system: Removed --enable-monolithic option. 2009-02-07/08 Denton Woods * il_iwi.c: Added this file and code to load .iwi files. * il_vtf.c (iLoadVtfInternal): Added checks for CompData == NULL. * il_dds.c/il_dds.h: Changed CompFormat to a local variable. Renamed Decompress to DdsDecompress. * ChangeLog (this file): Changed order to newest at the top. * il.h: Added IL_FITS and IL_IWI defines. * config.h.win: Added IL_FITS, IL_IWI, IL_SUN and IL_TPL. * lib/Makefile.am and src-IL/src/Makefile.am: Added il_fits.c and il_iwi.c to source line. --- 1.7.7 release --- 2009-02-06 Matěj Týč * configure.ac, lib/Makefile.am: Added explicit linking with libm library + fixed the ilut_x11.c file conditions of compilation * examples/Makefile.am + IL examples, test/Makefile.am + testil: Added conditional compilation option when compiling only with IL (without ILU, iluErrorString() absence workaround) 2009-02-06 Denton Woods * README.win and README.unix: Updated with Cygwin/MinGW instructions. 2009-02-05 Denton Woods * il_tga.c: Fixed bug loading malformed RLE Targa images. * il_rle.c:20: Changed size_t cast to ILint to resolve compiler warning. * il.def: Added definitions. * Updated version numbers to 1.7.7 everywhere. 2009-02-04 Denton Woods * ilut_opengl.c:160: Changed checks to see if less than 0. * il_fits.c: Got this reading FITS files properly. 2009-02-04 Matěj Týč * configure.ac: Corrected handling of --enable-debug options, added working install support for pkg-config * data/Makefile.am, *.pc.in: Corrected pkg-config files 2009-02-03 Denton Woods * il_io.c: Updated Doxygen comments. * il_fits.c: Added this file (not in any projects yet). * il_fits.c: Wrote beginning of FITS loading code. 2009-02-02 Denton Woods * il_manip.c (ilCopyPixels):311: Added check for destination format of color index. * il_convbuff.c (ilConvertBuffer): Changed to accept the source image palette. Added code to convert from buffers that are related to a palette before the large switch. * il_alloc.c (ifree): Changed so that if Ptr == NULL, it does not try to free the pointer. * il_nvidia.cpp/il_squish.cpp: Added empty functions if nVidia or libsquish support is not compiled in. * test/format_test/testil.c:5: Added _USE_MATH_DEFINES. 2009-02-01 Matěj Týč * test/format_test: Tweaked the script to use wine if cross-compiling to run the tests, extended testil capabilities * m4/devil-definitions.m4: Fixed bugs that caused that you couldn't disable support for some formats no matter what :-) * m4/devil-api-checks.m4: Added Xrender build support (by Jesse Maurais) 2009-02-01 Denton Woods * devil_internal_exports.h: Commented members of ILimage struct using Doxygen-style comments. Removed deprecated, commented-out members (NumNext, NumLayers, NumMips). * Updated several functions with appropriate Doxygen comments. * il.h: Updated IL_XXX file format defines with Doxygen comments. * ilu_rotate.c: Changed min/max calls to IL_MIN/IL_MAX. * ilut_states.c (ilutSetInteger): Fixed ILUT_MAXTEX_DEPTH call and added checks around first three calls for Param >= 1. 2009-01-31 Denton Woods * Added newlines to the end of several files to keep gcc quiet. * Added new MSVC++ projects for examples. * il_bmp.c:556: Changed to Header->biWidth from iCurImage->Width. iCurImage->Width was not updated to the new width at this point. * il_rotate.c (iluRotate_): Rewrote to fix 1 pixel shifting issue. * Updated DevIL Manual with new ilSaveL information. * il_stack.c (ilCloseImage): Added missing delete of Faces member. * il_dds-save.c (ilCompressDXT): Added this function. * il.h: Removed ilNVidiaCompressDXT and ilSquishCompressDXT - moved to il_internal.h. * il_dds-save.c:151: Changed to Faces from Images. * il_dds-save.c (CompressTo565): Added IL_ALPHA case. * Updated DevIL Manual with new DXTC information. 2009-01-30 Denton Woods * Added DevIL.NET to projects folder. * il_dds.c: Changed Image->Next code for cubemaps to read Image->Faces. Also changed Image->Next code for mipmaps to read Image->Mipmaps, even further down the chain. * il_dds.c (ilTexImageDxtc): Added call to ilCloseImage for Image->Faces. * il_endian.h:113: Fixed bug #2545848 - inline GCC ASM changed. * ilut_directx9.c (ilutD3D9CubeTexture): Changed ->Next to ->Faces. * ilut_directx9.c (iD3D9CreateMipmaps): Changed ->Next to ->Mipmaps. * il_states.c:605: Changed from ->Next to ->Mipmaps. * il_states.c (iGetActiveNum): Rewrote to not use ->Next pointer for everything. * il_vtf.c (VtfInitMipmaps): Changed to reflect the new mipmap arrangement as well. * il_wal.c:141,142: Changed ->Next to ->Mipmaps. * il_wal.c: Cleaned up the formatting a bit. * il_stack.c (ilActiveMipmap): Changed ->Next to ->Mipmaps. * il_stack.c (ilActiveImage/Mipmap/Face/Layer): Added another check for NULL, changed error. Changed order of statements in for loop. This leads to much much less in the way of ilSetError calls, since we do not have iCurImage == NULL. * il_vtf.h:43: Changed to ILuint from ILint. * il_vtf.c: Changed VtfInitMipmaps calls to VtfInitFacesMipmaps calls and changed iLoadVtfInternal to support environment maps. * il.h:384: Added IL_SPHEREMAP. * il_hdr.c:467: Changed to char* to get OS X to stop issuing a warning. * il_size.c:53: Changed return value to ILuint. * devil_cpp_wrapper.hpp: Removed MSVC++ #pragma at the top for deprecated lib. 2009-01-28 Denton Woods * il_tpl.c: Added line 219. 2009-01-27 Denton Woods * il_bits.c (bseek): Changed check for return values of iseek. * il_tpl.c: Added support for many more TPL data formats. * il_tpl.c: Added support for color indexed data formats. * il_tpl.c: Added support for multiple images in a file. * il_sdl.c (ilutConvertToSDLSurface): Overhauled this code. * ilut_opengl.c: Removed iGLSetMaxW/H/D and MaxTexW/H/D. * ilut_states.h/ilut_states.c: Added MaxTexW/H/D to ILUT_STATES. * ilut_states.c (ilutGetIntegerv): Added ILUT_MAXTEX_WIDTH/HEIGHT/DEPTH. 2009-01-26 Denton Woods * projects/win mobile: Added Windows Mobile projects. * Removed .cvsignore files from SVN. * il_bits.c:65: Commented out icloser call. * include/IL/DevIL.i: Removed IL/ prefix on header filenames. * include/IL/build-python and build-lua: Updated paths. * projects folder: Renamed msvc to msvc9. * il_tpl.c: Added for TPL support. * il_io.c: Added function calls for TPL support. * il_internal.h: Added declarations for TPL support. 2009-01-25 Denton Woods * ilut_internal.h:63-67: Redid definitions of IL_TEXT to coincide with il_internal.h. * il_states.c: Updated _ilLoadExt/_ilSaveExt with all extensions. * il_states.h: Updated with all extensions. * All image formats with saving: Changed return values of ilSaveXxxF and ilSaveXxxL to be an integer stating the number of bytes written. This is what ilSaveF/L have been trying to return all along. * il_pal.c:1075: Added error condition. * lib/Makefile.am: Added il_size.c. * simple.c: Added iluInit call. * il_dds-save.c (GetAlphaBlock): Applied code from GetBlock, since it was still reading out of bounds. * il_psd.c (ParseResources):808: Added check for ResourceSize being too small. 834-837: Added check to insure that we are not copying from past the end of Resource. * il_hdr.c:527-528: Changed order so that beg_run+run_count is tested first. * il_psd.c:829: Subtracted an additional 4 for the Size obtained in the lines before. * il_jp2.c:792-792: Added cleanup code if failure. 676-680: Added call to jas_init. Added code throughout to prevent from having to initialize Jasper more than once. * il_internal.h/il_internal.c: Added strdup for Windows CE. * il_internal.h:105-107: Added so that we do not try to compile inline ASM with Windows Mobile. 2009-01-24 Denton Woods * il_internal.h,il_tiff.c: Changed ilSaveTiffL to void* instead of const void*. * il_tiff.c: Added _tiffFileReadProcW. Changed _tiffFileSeekProc(W) to return the result of itellw instead of tOff. This allows us to finally overload the TIFF writing code. * il_internal.h: Removed #pragma comments, which were commented out anyway. * il_io.c (ilSaveL): Added call to ilDetermineSize. * il_size.c: Added this file. * il_manip.c:14: Removed #include . * il_jpeg.c:53: Added check for IL_USE_IJL. * il_exr.cpp:319,329: Changed to write functions instead of read. * il_files.c: Added iSetOutputFake. * il_files.c (iSetOutputLump): Added check for NULL to accommodate ilDetermineSize function. * il_hdr.c:457: Changed from char* to ILbyte*. * il_icns.h:24,30: Changed from ILbyte to char. * il_size.c: Added #ifdefs for when user has declared IL_NO_XXX. Changed error to ENUM instead of PARAM. * Updated MSVC8 projects with il_size.c. * src-IL/src/Makefile.am: Added il_size.c. * il_jp2.c: Added ilIsValidJp2* functions. * il.h: Added ilDetermineType and ilDetermineTypeL to declarations. * il_io.c: Changed ilDetermineTypeL to be exported. * il_pcx.c: Formatting issues fixed. * il_mdl.c: Added ilIsValidJp2* functions. * il_io.c: Added JP2, MDL and XPM support to ilDetermineType and ilIsValid functions. * il_icon.c/il_png.c: Renamed color_type to ico_color_type and png_color_type to avoid name conflicts. * il_iff.c: Changed all malloc->ialloc and free->ifree. Added checks for ialloc failure. * il_io.c (ilDetermineTypeL): Changed VTF check to return IL_VTF instead of the miscopied IL_SUN. * il_size.c (ilDetermineSize): Now calls iTargaSize for Targa files. * il_tga.c: Added iTargaSize. 2009-01-22 Denton Woods * ilut_internal.h:66: Changed to compile under Cygwin. * ilut_opengl.c:108: Replaced _MSC_VER with _WIN32 and _WIN64. * il_dds-save.c:343: Fixed bug #1067590 - Removed this line, which caused crashes. * il_pic.c (iLoadPicInternal): Fixed ilTexImage call, moved it after channel information read. * il_pic.c (readScanline):294-295: Added check for alpha channel. * il_pic.c: Added ilSetError calls throughout. * il_sgi.c (iLoadSgiInternal): Fixed bug #1060946 - Removed IL_LUMINANCE_ALPHA filetype. * WindowsTest.cpp:52,53: Changed border size to accommodate Windows Vista/7. * il_endian.h:20: Changed to give __BIG_ENDIAN__ a value of 1. The Google cached page of http://74.125.47.132/search?q=cache:YfSl36C2pAQJ:patch-tracking.debian.net/patch/series/view/devil/1.7.2-1/00_endian_and_ILvoid_fixes.diff+devil+big+endian&hl=en&ct=clnk&cd=11&gl=us&lr=lang_en has this patch (Nov. 24, 2008 cache). * devil_internal_exports.h:34: Uncommented and commented line 30. 2009-01-20 Matěj Týč * test/format_test: Added a program and script as 'make check' target. Those will test whether IL is capable of saving and loading images and whether the saved and loaded image is similar to the original. * configure.ac, lib/Makefile.am: Added support to IFF compilation. * docs/DevIL_manual.texi: Added missing documentation about getting image data + fixed some typos. * include/IL/devil_cpp_wrapper.hpp: Fixed a typo that caused compilation error 2009-01-20 Denton Woods * ilut_opengl.c (ilutGLScreen): Added glPixelStorei call. * Added il_iff.c from GAIA. * Added "x64 DLL Install.exe" to SVN. * il_internal.h: Renamed ilIsValidJpg* functions to ilIsValidJpeg*. Added Iff functions. * il_io.c: Added checks for Iff-loading. * ilut_win32.c (ilutConvertSliceToHBitmap): Added better error handling. * src-IL/src/Makefile.am: Added il_iff.c. * ilu_rotate.c (iluRotate_): Changed ilResizeImage call. * Added ilut_config.h. * ilut.h: Added reference to ilut_config.h for Windows. * il_files.c/il_icon.c/il_png.c/il_mng.c: Fixed typecasting warnings. * il_jp2.c/il_wbmp.c (ilSaveJp2L/ilSaveWbmpL): Removed const qualifier. 2009-01-19 Denton Woods * il_hdr.c: Changed line 73 to have space for terminating NULL. * src-IL/src/Makefile.am: Added il_vtf.c and *.cpp files. * Fixed the MSVC++ 9 solutions pointing to the MSVC++ 8 project files. * devil_cpp_wrapper.hpp: Updated to use ILconst_string instead of char*. * il.h: Changed definition of IL_ALPHA to match OpenGL's GL_ALPHA. * src-IL/include/Makefile.am: Added il_exr.h. * il_dds.c/il.h: Readded DXT extension code. * il_internal.h: Added declaration of ilFixCur. 2009-01-16 Denton Woods * Updated x64 projects 2009-01-15 Matěj Týč * il_io.h, include/IL/il.h, il_states.h: Changed some normal strings to constant strings (in ilSave, ilIsValid and ilGetString) * configure.ac, lib/Makefile.am: Added wbmp compilation support * il_jp2.c, il_wbmp.c: Fixed a typo that prevented compilation * include/IL/devil_cpp_wrapper.hpp: Added a hopefully harmless solution for the initialization of DevIL. 2009-01-15 Denton Woods * il_manip.c / il.h: Added ilClampNTSC function. * il_squish.cpp: Added file. * il_dds-save.c: Added line 688. * il_states.c: Added lines for libsquish support. * il_dds-save.c (Compress): Added libsquish compression. * il_io.c (ilDetermineTypeF/L and ilIsValid/F/L): Added VTF, SUN and EXR. * il_io.c (ilIsValidF/L): Added TIF * il_jp2.c:131-137: Added these lines to take care of erroneous error generated by JasPer's buffering. * il_jp2.c: Added functions to save JPEG 2000 images. * il_utility.c (ilGetBppFormat): Added IL_ALPHA. * il_jp2.c (iLoadJp2Internal): Added 1 and 2 channel format loading. * il_dds-save.c:700-701: Changed to IL_RGBA. * il_dds-save.c (ChooseEndpoints): Changed to use norm squared instead of a sum of the components. * il_dds-save.c (GetBlock): Changed to copy adjacent data if it goes beyond the bounds of the image. * il_icon.c: Removed extra whitespace. * il_icns.c / il_internal.h: Added ilIsValidIcns*. * il_icns.h: Changed comments on ICNSDATA. * il_exr.c: Added ilIsValidExr*. * il_io.c (ilLoadF): Uncommented ilLoadJp2F. * il_dds-save.c (CompressTo565): Changed 24-bit to 16-bit code based on Charles Bloom's rant. * il_dds.c (DxtcReadColor/DxtcReadColors): Changed conversion to copy high bits to lowest bits as well. * il_io.c: Reenabled PhotoCD support. * il_pcd.c (iLoadPcdInternal): Added check for end-of-file. * il_exr.c: Added EXR saving functions. 2009-01-13 Denton Woods * Converted source repository to SVN from CVS. 2009-01-12 Denton Woods * ilut_directx9.c: Cleared up formatting some. 2009-01-11 Denton Woods * MSVC9 Unicode projects: Updated to work better in 64-bit Windows. * il_vtf.c: Removed commented lines 238-242. * Created application to copy DLL files to the System32 directory. 2009-01-10 Matěj Týč * m4/devil-definitions.m4, m4/devil-reports.m4: Added a report saying what libraries were linked with DevIL (should be helpful to packagers who need to know DevIL dependencies) * il_endian.h (iGwapUShort/iSwapUInt): Finished fixing bug #2023453 (inline GCC asm, there was a typo left) * src_IL/src/il_tiff.c (ilSaveTiff): Fixed a typo that was causing conflicting declarations error * configure.ac:264: Added IL_NO_WBMP since the Wbmp loading functions that are referenced, but not implemented, caused linking errors 2009-01-09 Denton Woods * ilut_opengl.h: Moved ILGLCOMPRESSEDTEXIMAGE2DARBPROC typedef out of #ifdefs. * ilut_opengl.c: Added ilutGLSetTex2D and ilutGLSetTex3D. Changed ilutGLSetTex to just call ilutGLSetTex2D. Did the same thing for ilutGLSubTex. Added checks for volume image extensions. Renamed MakeGLCompliant to MakeGLCompliant2D. Added MakeGLCompliant3D. * ilut_opengl.c (ilutGLScreen): Added check for ilTexImage failing. * il_vtf.c (iLoadVtfInternal): Added BGRA4444 support. * il_alloc.c / ilu_scale.c: Cleaned up formatting some. * devil_internal_exports.h: Added Faces member to ILimage. * il_devil.c (iCopySubImages): Added support for faces. * il_register.c: Added ilRegisterNumFaces. * il_convert.c (ilFixImage): Added support for faces. * il_stack.c: Added ilActiveFace. * ilut_directx9:63,779: Added ILboolean typecast. * ilut_win32:102: Added ILboolean typecast. * il_jpeg.c:987: Commented out pragma warning at the end. * il_mng.c: Added #pragma warning at the top to get rid of redefinition warning when compiling. * il_nvidia.cpp (ilNVidiaCompressDXT): Added check for Data being NULL. * ilut_win32.c (ilutConvertSliceToHBitmap): Fixed bug #2496509 - added line 117 and added DataSize member. * il_hdr.c (iGetHdrHead): Fixed bug #2496518 - Added check for count. Changed sscanf to use %2s format specifier to prevent buffer overruns in x and y. * il_pnm.c (iGetWord): Fixed bug mentioned in #2496518 - igetc was moved back into the while loop. Added a check for WordPos to prevent buffer overflow. Restructured the while loop to work properly. * il_convert.c (iConvertPalette): Changed references of iCurImage to Image. * il_gif.c (GifGetData): Added DataPtr and changed line 636 to use Data instead of Image->Data. * il_gif.c (iGetPalette / GetImages): Changed to better deal with local palettes. 2009-01-08 Matěj Týč * TODO: Added some tasks that I would like to undertake * ChangeLog, NEWS: Copied old ChangeLog entries to NEWS file * lib/Makefile.am: Added two new files to the list of IL sources (il_sun.c, il_nvidia.cpp) * examples/iller: Made empty files where the ILU frontend will be in the future. * configure.ac, m4/devil-reports.m4: Put the report stage of the configure script to a separate m4 file. 2009-01-08 Denton Woods * opengl_example/gltest.c (main): Added iluInit/ilutInit calls. * ilut_opengl.c (ilutGLFormat): Added IL_ALPHA support. * il_bmp.c: Minor formatting issues fixed. * il.h: Added IL_NVIDIA_COMPRESS #define. * il_states.h: Added ilUseNVidiaDXT to IL_STATES. * il_state.c: Added IL_NVIDIA_COMPRESS support. * il_dds-save.c (Compress): Changed to use NVTT if needed. * il_nvidia.cpp: Added ilNVidiaCompressDXTFile and Depth parameter to ilNVidiaCompressDXT. 2009-01-06/07 Denton Woods * Added il_sun.c (Sun Raster file support) * ilut_opengl.c (ilutGLInit): Changed Linux ilGLCompressed2D pointer casting to coincide with the old SVN version. * il_tiff.c / il_alloc.c: Fixed a few pointer casts that were fixed in SVN. * test/DDrawTest: Fixed extra whitespace in all files in this project. * il_endian.h (iGwapUShort/iSwapUInt): Fixed bug #2023453 (inline GCC asm). * ilut_win32.c (ilutConvertSliceToBitmap): Fixed bug #1775036 (definition of buff). * il_psd.c (PsdGetData): Fixed bug #2219350 (16-bit luminance images not loading properly). * il_manip.c: Cleared up some minor formatting issues. * il_png.c (iSavePngInternal): Fixed bug #1680577 (some metadata not written correctly). * il_nvidia.cpp (ilnVidiaCompressDXT1): Disabled mipmap generation and added code to ilOutputHandler constructor to determine the proper size of the buffer. * il.h: Added IL_DXT1A define for nVidia Texture Tools. * il_nvidia.cpp: Added DXT1a, DXT3 and DXT5 support. Renamed ilnVidiaCompressDXT to ilnVidiaCompressDXT and added the DxtType parameter. * il_internal.c: Cleaned up extra whitespace toward end. 2009-01-02 Matěj Týč * src-{IL,ILU,ILUT}/src/*_internal.c: Hopefully resolved the HAVE_CONFIG_H thing once for all :-) * src-IL/src/il_exr.cpp: Undefined OPENEXR_DLL if we are not on Windows (=> when HAVE_CONFIG_H is not defined) * src-IL/src/il_io.c:765: Fixed a typo * src-IL/src/il_vtf.c: Added min and max macros to the beginning * docs/Devil_manual.texi: Corrected typos and missing @code and other formatting stuff, corrected image names and incorrect usage of @xref etc. that prevented compilation * build setup (Makefile.am and configure.ac): Added support for compilation of EXR and WDP formats + various other tweaks. Up to 2009-01-02 (since 1.7.5 release) Denton Woods * Readded EXR code. * Redefined clamping values in il.h. * Added 64-bit integer types. * Fixed bug in iRegisterLoad (https://sourceforge.net/forum/message.php?msg_id=5973761). * Changed seek functions in il_files.c to return ILint. * Added rpcsal.h and sal.h #includes to ilut.h for DX10. * Added IL_MAX_QUANT_INDICES to use instead of IL_MAX_QUANT_INDEXS (misspelled). * Added WBMP support (loading and saving). * EXR files can now be loaded as file streams and lumps. * Changed iNeuQuant to take number of colors in palette. * Compiled MNG support back in. assimp-4.1.0/samples/DevIL/AUTHORS0000644002537200234200000000030413213503245016730 0ustar zmoelnigiemusersThe main programmer is Denton Woods, but this could not have been possible without contributions and some pieces of code from other projects. For contributors and credits, read the CREDITS file. assimp-4.1.0/samples/DevIL/lib/0000755002537200234200000000000013213503245016431 5ustar zmoelnigiemusersassimp-4.1.0/samples/DevIL/README.win0000644002537200234200000000257513213503245017350 0ustar zmoelnigiemusersWhere do I find the project files ? ----------------------------------------- MSVC++ projects are in DevIL\projects\vc8 and DevIL\projects\vc9. If compiling with Cygwin or MinGW, use the instructions in README.unix. The IL_NO_XXX #define's: ------------------------ A user can recompile this library without complete image support in it. For example, if your project does not use .jpg files, you can uncomment #define IL_NO_JPG at the top of il/il.h, recompile the library, and no .jpg support will be added, meaning quicker compiles and a smaller library. The ILUT_USE_XXX #define's: --------------------------- To disable support for a specific API, edit IL/ilut.h and comment the corresponding #define. Per example, to disable OpenGL functions support, add // in front of the line that reads: #define ILUT_USE_OPENGL Libraries needed to compile DevIL* : ----------------------------------- Libraries.txt (included with the DevIL distribution) lists all libraries needed to properly compile DevIL. Precompiled versions and sources of all libraries needed to compile DevIL are available at http://openil.sourceforge.net/libs/LibCompiled.zip and http://openil.sourceforge.net/libs/LibSrc.zip , respectively. Installation: ------------- Just unzip and compile other libs included if needed. Please also refer to MSVC++.txt for further instructions if you are using Microsoft Visual C++. assimp-4.1.0/samples/DevIL/COPYING0000644002537200234200000006346513213503245016734 0ustar zmoelnigiemusers GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! assimp-4.1.0/samples/DevIL/DevIL Website.url0000644002537200234200000000015113213503245020732 0ustar zmoelnigiemusers[InternetShortcut] URL=http://openil.sf.net/ IDList= [{000214A0-0000-0000-C000-000000000046}] Prop3=19,2 assimp-4.1.0/samples/SimpleAssimpViewX/0000755002537200234200000000000013213503245020311 5ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleAssimpViewX/README0000644002537200234200000000122613213503245021172 0ustar zmoelnigiemusersMac OSX Assimp Sample, using OpenGL with VBOs ============================================= Written & donated by drparallax. See http://sourceforge.net/projects/assimp/forums/forum/817654/topic/3917829 How to build: ------------- - compile Assimp as static library, copy the generated libassimp.a right here. - copy the Assimp headers from ./../../include to ./include - open the XCode project file and build it Troubleshooting: ---------------- - OSX workspaces are not updated too frequently, so same files may be missing. If you have any problems which you can't solve on your own, please report them on the thread above.assimp-4.1.0/samples/SimpleAssimpViewX/SimpleAssimpViewX.xcodeproj/0000755002537200234200000000000013213503245025676 5ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleAssimpViewX/SimpleAssimpViewX.xcodeproj/vade.pbxuser0000644002537200234200000015360313213503245030237 0ustar zmoelnigiemusers// !$*UTF8*$! { 1B0E99FF1279E80B003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 15"; rLen = 0; rLoc = 1021; rType = 0; vrLen = 1096; vrLoc = 88; }; 1B0E9A231279EA16003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; name = "MyDocument.h: 19"; rLen = 0; rLoc = 554; rType = 0; vrLen = 462; vrLoc = 0; }; 1B0E9A241279EA16003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 34"; rLen = 0; rLoc = 1327; rType = 0; vrLen = 1080; vrLoc = 148; }; 1B0E9A251279EA16003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 34"; rLen = 0; rLoc = 1327; rType = 0; vrLen = 1080; vrLoc = 148; }; 1B0E9A2B1279EA26003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 34"; rLen = 0; rLoc = 1327; rType = 0; vrLen = 1077; vrLoc = 148; }; 1B0E9A2F1279EA37003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 56"; rLen = 0; rLoc = 7323; rType = 0; vrLen = 1110; vrLoc = 152; }; 1B0E9A331279EA40003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 34"; rLen = 0; rLoc = 1327; rType = 0; vrLen = 1112; vrLoc = 152; }; 1B0E9A371279EA45003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 34"; rLen = 0; rLoc = 1327; rType = 0; vrLen = 1110; vrLoc = 152; }; 1B0E9A3A1279EA54003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 34"; rLen = 0; rLoc = 1327; rType = 0; vrLen = 1160; vrLoc = 152; }; 1B0E9A3D1279EA64003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 35"; rLen = 0; rLoc = 1327; rType = 0; vrLen = 1162; vrLoc = 152; }; 1B0E9A4D1279EB1F003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 17"; rLen = 0; rLoc = 866; rType = 0; vrLen = 1563; vrLoc = 152; }; 1B0E9A501279EB8D003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 49"; rLen = 0; rLoc = 1539; rType = 0; vrLen = 1521; vrLoc = 742; }; 1B0E9A511279EBA9003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 61"; rLen = 0; rLoc = 3197; rType = 0; vrLen = 1521; vrLoc = 742; }; 1B0E9A541279EC57003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 88"; rLen = 0; rLoc = 8000; rType = 0; vrLen = 1457; vrLoc = 1016; }; 1B0E9A561279EC72003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; name = "MyDocument.h: 25"; rLen = 0; rLoc = 1112; rType = 0; vrLen = 481; vrLoc = 0; }; 1B0E9A571279EC72003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 105"; rLen = 16; rLoc = 8283; rType = 0; vrLen = 1569; vrLoc = 1260; }; 1B0E9A581279EC72003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 105"; rLen = 16; rLoc = 8283; rType = 0; vrLen = 1334; vrLoc = 1653; }; 1B0E9A921279ED56003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 102"; rLen = 0; rLoc = 8279; rType = 0; vrLen = 1575; vrLoc = 1297; }; 1B0E9A931279EDCD003108E7 /* ModelLoaderHelperClasses.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {806, 1326}}"; sepNavSelRange = "{217, 0}"; sepNavVisRange = "{48, 363}"; }; }; 1B0E9A941279EDCD003108E7 /* ModelLoaderHelperClasses.mm */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {779, 1261}}"; sepNavSelRange = "{585, 0}"; sepNavVisRange = "{0, 1258}"; }; }; 1B0E9A9C1279EE7D003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 1B0E9A941279EDCD003108E7 /* ModelLoaderHelperClasses.mm */; name = "ModelLoaderHelperClasses.mm: 9"; rLen = 26; rLoc = 155; rType = 0; vrLen = 1258; vrLoc = 0; }; 1B0E9A9D1279EE7D003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; name = "MyDocument.h: 42"; rLen = 0; rLoc = 977; rType = 0; vrLen = 1050; vrLoc = 0; }; 1B0E9A9E1279EE7D003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 14"; rLen = 0; rLoc = 336; rType = 0; vrLen = 1483; vrLoc = 0; }; 1B0E9A9F1279EE7D003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; comments = "AiColor4D.h: No such file or directory"; fRef = 1B0E9A931279EDCD003108E7 /* ModelLoaderHelperClasses.h */; rLen = 1; rLoc = 10; rType = 1; }; 1B0E9AA01279EE7D003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 1B0E9A931279EDCD003108E7 /* ModelLoaderHelperClasses.h */; name = "ModelLoaderHelperClasses.h: 31"; rLen = 0; rLoc = 780; rType = 0; vrLen = 1613; vrLoc = 0; }; 1B0E9AD61279EFCC003108E7 /* aiColor4D.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {806, 1144}}"; sepNavSelRange = "{2077, 35}"; sepNavVisRange = "{1794, 611}"; }; }; 1B0E9AE91279EFCC003108E7 /* aiVector3D.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {988, 1534}}"; sepNavSelRange = "{838, 0}"; sepNavVisRange = "{0, 2586}"; }; }; 1B0E9B0C1279F08F003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 1B0E9A931279EDCD003108E7 /* ModelLoaderHelperClasses.h */; name = "ModelLoaderHelperClasses.h: 11"; rLen = 0; rLoc = 217; rType = 0; vrLen = 363; vrLoc = 48; }; 1B0E9B0D1279F08F003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 1B0E9AD61279EFCC003108E7 /* aiColor4D.h */; name = "aiColor4D.h: 51"; rLen = 35; rLoc = 2077; rType = 0; vrLen = 611; vrLoc = 1794; }; 1B0E9B0E1279F08F003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; name = "MyDocument.h: 30"; rLen = 0; rLoc = 612; rType = 0; vrLen = 813; vrLoc = 229; }; 1B0E9B0F1279F08F003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; comments = "Invalid conversion from 'objc_object*' to 'CVReturn'"; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; rLen = 1; rLoc = 38; rType = 1; }; 1B0E9B101279F08F003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 36"; rLen = 93; rLoc = 836; rType = 0; vrLen = 820; vrLoc = 258; }; 1B0E9B1D1279F110003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; name = "MyDocument.h: 20"; rLen = 0; rLoc = 390; rType = 0; vrLen = 770; vrLoc = 3; }; 1B0E9B1E1279F110003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; comments = "Invalid conversion from 'void*' to '_CGLContextObject*'"; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; rLen = 1; rLoc = 267; rType = 1; }; 1B0E9B1F1279F110003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 122"; rLen = 0; rLoc = 8282; rType = 0; vrLen = 822; vrLoc = 2503; }; 1B0E9B201279F118003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 1B0E9A931279EDCD003108E7 /* ModelLoaderHelperClasses.h */; name = "ModelLoaderHelperClasses.h: 31"; rLen = 0; rLoc = 780; rType = 0; vrLen = 1613; vrLoc = 0; }; 1B0E9B211279F118003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 1B0E9A941279EDCD003108E7 /* ModelLoaderHelperClasses.mm */; name = "ModelLoaderHelperClasses.mm: 34"; rLen = 0; rLoc = 585; rType = 0; vrLen = 1258; vrLoc = 0; }; 1B0E9B221279F118003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; name = "MyDocument.h: 47"; rLen = 0; rLoc = 1094; rType = 0; vrLen = 1117; vrLoc = 0; }; 1B0E9B231279F118003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; comments = "Invalid conversion from 'void*' to '_CGLContextObject*'"; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; rLen = 1; rLoc = 267; rType = 1; }; 1B0E9B241279F118003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 100"; rLen = 0; rLoc = 7398; rType = 0; vrLen = 1510; vrLoc = 55; }; 1B0E9BA81279F2A2003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; comments = "Request for member 'inputModelPath' in 'self', which is of non-class type 'MyDocument* const'"; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; rLen = 1; rLoc = 193; rType = 1; }; 1B0E9BA91279F2A2003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 140"; rLen = 0; rLoc = 5889; rType = 0; vrLen = 2547; vrLoc = 3352; }; 1B0E9BB41279F317003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 222"; rLen = 59; rLoc = 9457; rType = 0; vrLen = 2522; vrLoc = 7077; }; 1B0E9BB51279F317003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; name = "MyDocument.h: 52"; rLen = 0; rLoc = 1285; rType = 0; vrLen = 1584; vrLoc = 0; }; 1B0E9BB61279F317003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; name = "MyDocument.h: 52"; rLen = 0; rLoc = 1225; rType = 0; vrLen = 1644; vrLoc = 0; }; 1B0E9BBC1279F38A003108E7 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; name = "MyDocument.h: 52"; rLen = 0; rLoc = 1225; rType = 0; vrLen = 1644; vrLoc = 0; }; 1BA5B1841279F5FE0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; comments = "'cgl_ctx' was not declared in this scope"; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; rLen = 1; rLoc = 231; rType = 1; }; 1BA5B1851279F5FE0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 182"; rLen = 65; rLoc = 7587; rType = 0; vrLen = 1227; vrLoc = 5670; }; 1BA5B1941279F61A0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; name = "MyDocument.h: 52"; rLen = 0; rLoc = 1225; rType = 0; vrLen = 1644; vrLoc = 0; }; 1BA5B1951279F61A0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 11"; rLen = 0; rLoc = 196; rType = 0; vrLen = 1352; vrLoc = 0; }; 1BA5B19E1279F6480089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 11"; rLen = 0; rLoc = 196; rType = 0; vrLen = 1352; vrLoc = 0; }; 1BA5B1A21279F6640089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 11"; rLen = 0; rLoc = 196; rType = 0; vrLen = 1350; vrLoc = 0; }; 1BA5B1A61279F6910089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 11"; rLen = 0; rLoc = 196; rType = 0; vrLen = 1350; vrLoc = 0; }; 1BA5B1AE1279F6D30089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 11"; rLen = 0; rLoc = 196; rType = 0; vrLen = 1350; vrLoc = 0; }; 1BA5B1B21279F7010089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 11"; rLen = 0; rLoc = 196; rType = 0; vrLen = 1350; vrLoc = 0; }; 1BA5B1B41279F72F0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 11"; rLen = 0; rLoc = 196; rType = 0; vrLen = 1380; vrLoc = 0; }; 1BA5B1B91279F7520089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 11"; rLen = 0; rLoc = 196; rType = 0; vrLen = 1350; vrLoc = 0; }; 1BA5B1BD1279F79D0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 11"; rLen = 0; rLoc = 196; rType = 0; vrLen = 1350; vrLoc = 0; }; 1BA5B1C11279F7BB0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 11"; rLen = 0; rLoc = 196; rType = 0; vrLen = 1350; vrLoc = 0; }; 1BA5B1C51279F7CC0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 11"; rLen = 0; rLoc = 196; rType = 0; vrLen = 1350; vrLoc = 0; }; 1BA5B1C91279F7F70089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 11"; rLen = 0; rLoc = 196; rType = 0; vrLen = 1350; vrLoc = 0; }; 1BA5B1CB1279F81B0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 234"; rLen = 0; rLoc = 8816; rType = 0; vrLen = 1240; vrLoc = 7025; }; 1BA5B1D01279F8BF0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 605"; rLen = 0; rLoc = 21605; rType = 0; vrLen = 1943; vrLoc = 18792; }; 1BA5B1D21279F8CF0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; comments = "'helper' was not declared in this scope"; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; rLen = 1; rLoc = 564; rType = 1; }; 1BA5B1D31279F8CF0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 536"; rLen = 0; rLoc = 19329; rType = 0; vrLen = 1740; vrLoc = 17973; }; 1BA5B1D41279F9280089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 243"; rLen = 0; rLoc = 8860; rType = 0; vrLen = 1611; vrLoc = 6880; }; 1BA5B1D91279F97C0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 261"; rLen = 0; rLoc = 8912; rType = 0; vrLen = 706; vrLoc = 7780; }; 1BA5B1DA1279F97C0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 85"; rLen = 0; rLoc = 2039; rType = 0; vrLen = 779; vrLoc = 1600; }; 1BA5B1DE1279F9AC0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 263"; rLen = 0; rLoc = 8912; rType = 0; vrLen = 706; vrLoc = 7806; }; 1BA5B1DF1279F9AC0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 101"; rLen = 0; rLoc = 3062; rType = 0; vrLen = 739; vrLoc = 1600; }; 1BA5B1E31279F9DA0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 268"; rLen = 0; rLoc = 9182; rType = 0; vrLen = 741; vrLoc = 7806; }; 1BA5B1E41279F9DA0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 101"; rLen = 0; rLoc = 3062; rType = 0; vrLen = 739; vrLoc = 1600; }; 1BA5B1E61279FA750089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 541"; rLen = 0; rLoc = 19329; rType = 0; vrLen = 1874; vrLoc = 16918; }; 1BA5B1E71279FA760089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 254"; rLen = 0; rLoc = 8702; rType = 0; vrLen = 774; vrLoc = 7806; }; 1BA5B1E81279FA760089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 101"; rLen = 0; rLoc = 3062; rType = 0; vrLen = 805; vrLoc = 1600; }; 1BA5B1ED1279FB2B0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 254"; rLen = 0; rLoc = 8702; rType = 0; vrLen = 841; vrLoc = 7703; }; 1BA5B1EE1279FB2B0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 100"; rLen = 0; rLoc = 3058; rType = 0; vrLen = 850; vrLoc = 1518; }; 1BA5B1EF1279FB7E0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 257"; rLen = 0; rLoc = 8702; rType = 0; vrLen = 794; vrLoc = 8007; }; 1BA5B1F01279FB7E0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 104"; rLen = 0; rLoc = 3062; rType = 0; vrLen = 848; vrLoc = 1625; }; 1BA5B1F31279FBBC0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 264"; rLen = 0; rLoc = 8702; rType = 0; vrLen = 770; vrLoc = 8073; }; 1BA5B1F41279FBBC0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 105"; rLen = 0; rLoc = 2826; rType = 0; vrLen = 758; vrLoc = 1904; }; 1BA5B1F81279FBCD0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 264"; rLen = 0; rLoc = 8702; rType = 0; vrLen = 770; vrLoc = 8071; }; 1BA5B1F91279FBCD0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 99"; rLen = 0; rLoc = 2499; rType = 0; vrLen = 756; vrLoc = 1904; }; 1BA5B1FF1279FBFE0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 266"; rLen = 0; rLoc = 8702; rType = 0; vrLen = 836; vrLoc = 8034; }; 1BA5B2001279FBFE0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 101"; rLen = 0; rLoc = 2513; rType = 0; vrLen = 758; vrLoc = 1904; }; 1BA5B2021279FC0D0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 268"; rLen = 0; rLoc = 8702; rType = 0; vrLen = 841; vrLoc = 8063; }; 1BA5B2031279FC0D0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 99"; rLen = 0; rLoc = 2469; rType = 0; vrLen = 840; vrLoc = 1828; }; 1BA5B2041279FC280089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 555"; rLen = 0; rLoc = 19329; rType = 0; vrLen = 1734; vrLoc = 15640; }; 1BA5B2071279FC580089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 273"; rLen = 0; rLoc = 8702; rType = 0; vrLen = 763; vrLoc = 8201; }; 1BA5B2081279FC580089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 117"; rLen = 0; rLoc = 2992; rType = 0; vrLen = 850; vrLoc = 2115; }; 1BA5B20C1279FC910089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 273"; rLen = 0; rLoc = 8702; rType = 0; vrLen = 763; vrLoc = 8212; }; 1BA5B20D1279FC910089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 113"; rLen = 0; rLoc = 2876; rType = 0; vrLen = 861; vrLoc = 2115; }; 1BA5B2111279FCA60089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 273"; rLen = 0; rLoc = 8702; rType = 0; vrLen = 763; vrLoc = 8212; }; 1BA5B2121279FCA60089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 113"; rLen = 0; rLoc = 2858; rType = 0; vrLen = 861; vrLoc = 2115; }; 1BA5B2161279FCBC0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 274"; rLen = 0; rLoc = 8702; rType = 0; vrLen = 760; vrLoc = 8208; }; 1BA5B2171279FCBC0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 120"; rLen = 0; rLoc = 3058; rType = 0; vrLen = 843; vrLoc = 2115; }; 1BA5B2191279FCF40089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 278"; rLen = 0; rLoc = 8702; rType = 0; vrLen = 620; vrLoc = 7900; }; 1BA5B21A1279FCF40089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 123"; rLen = 0; rLoc = 3057; rType = 0; vrLen = 906; vrLoc = 2115; }; 1BA5B21D1279FD420089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 564"; rLen = 0; rLoc = 19329; rType = 0; vrLen = 1837; vrLoc = 15804; }; 1BA5B21E1279FD650089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 571"; rLen = 0; rLoc = 19580; rType = 0; vrLen = 2085; vrLoc = 18311; }; 1BA5B21F1279FD650089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 122"; rLen = 0; rLoc = 3057; rType = 0; vrLen = 92; vrLoc = 2115; }; 1BA5B2221279FD7E0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 571"; rLen = 0; rLoc = 19580; rType = 0; vrLen = 2030; vrLoc = 18311; }; 1BA5B2231279FD7E0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 122"; rLen = 0; rLoc = 3057; rType = 0; vrLen = 58; vrLoc = 2115; }; 1BA5B2271279FD990089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 570"; rLen = 0; rLoc = 19529; rType = 0; vrLen = 984; vrLoc = 18313; }; 1BA5B2281279FD990089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 121"; rLen = 0; rLoc = 3054; rType = 0; vrLen = 812; vrLoc = 2115; }; 1BA5B22C1279FDAA0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 570"; rLen = 0; rLoc = 19529; rType = 0; vrLen = 984; vrLoc = 18311; }; 1BA5B22D1279FDAA0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 92"; rLen = 0; rLoc = 2215; rType = 0; vrLen = 719; vrLoc = 1758; }; 1BA5B2311279FDCF0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 570"; rLen = 0; rLoc = 19529; rType = 0; vrLen = 984; vrLoc = 18310; }; 1BA5B2321279FDCF0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 118"; rLen = 0; rLoc = 2958; rType = 0; vrLen = 821; vrLoc = 2005; }; 1BA5B2361279FDE30089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 570"; rLen = 0; rLoc = 19529; rType = 0; vrLen = 1291; vrLoc = 18982; }; 1BA5B2371279FDE30089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 90"; rLen = 0; rLoc = 2181; rType = 0; vrLen = 953; vrLoc = 2627; }; 1BA5B23E1279FF900089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; name = "MyDocument.h: 10"; rLen = 0; rLoc = 178; rType = 0; vrLen = 1644; vrLoc = 0; }; 1BA5B23F1279FF900089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 156"; rLen = 0; rLoc = 4176; rType = 0; vrLen = 2878; vrLoc = 2827; }; 1BA5B2401279FF900089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 270"; rLen = 0; rLoc = 8687; rType = 0; vrLen = 1626; vrLoc = 7772; }; 1BA5B244127A001E0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 271"; rLen = 0; rLoc = 8682; rType = 0; vrLen = 1741; vrLoc = 7798; }; 1BA5B248127A00350089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 270"; rLen = 0; rLoc = 8642; rType = 0; vrLen = 1741; vrLoc = 7798; }; 1BA5B254127A00700089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 254"; rLen = 0; rLoc = 8244; rType = 0; vrLen = 1683; vrLoc = 7798; }; 1BA5B269127A012B0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 89"; rLen = 0; rLoc = 2101; rType = 0; vrLen = 1434; vrLoc = 963; }; 1BA5B26D127A01450089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 73"; rLen = 0; rLoc = 1537; rType = 0; vrLen = 1440; vrLoc = 963; }; 1BA5B26F127A017A0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 162"; rLen = 0; rLoc = 4341; rType = 0; vrLen = 3021; vrLoc = 3030; }; 1BA5B275127A021A0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 152"; rLen = 0; rLoc = 3914; rType = 0; vrLen = 2775; vrLoc = 3073; }; 1BA5B287127A02E00089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 148"; rLen = 0; rLoc = 3740; rType = 0; vrLen = 2408; vrLoc = 5640; }; 1BA5B28D127A03AF0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 1B0E9AE91279EFCC003108E7 /* aiVector3D.h */; name = "aiVector3D.h: 23"; rLen = 0; rLoc = 838; rType = 0; vrLen = 2586; vrLoc = 0; }; 1BA5B28E127A03AF0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 148"; rLen = 0; rLoc = 3740; rType = 0; vrLen = 2453; vrLoc = 5640; }; 1BA5B28F127A03AF0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 91"; rLen = 0; rLoc = 2142; rType = 0; vrLen = 1746; vrLoc = 1327; }; 1BA5B293127A03EE0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 284"; rLen = 0; rLoc = 8856; rType = 0; vrLen = 1724; vrLoc = 8099; }; 1BA5B297127A04000089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 284"; rLen = 0; rLoc = 8856; rType = 0; vrLen = 1724; vrLoc = 8099; }; 1BA5B29B127A04200089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 292"; rLen = 0; rLoc = 9088; rType = 0; vrLen = 1680; vrLoc = 8099; }; 1BA5B29F127A042C0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 292"; rLen = 0; rLoc = 9088; rType = 0; vrLen = 1681; vrLoc = 8099; }; 1BA5B2A3127A04370089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 292"; rLen = 0; rLoc = 9088; rType = 0; vrLen = 1682; vrLoc = 8099; }; 1BA5B2A7127A04480089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 285"; rLen = 0; rLoc = 8856; rType = 0; vrLen = 1726; vrLoc = 8099; }; 1BA5B2AB127A04520089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 284"; rLen = 0; rLoc = 8851; rType = 0; vrLen = 1725; vrLoc = 8099; }; 1BA5B2AF127A04620089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 284"; rLen = 0; rLoc = 8851; rType = 0; vrLen = 1724; vrLoc = 8099; }; 1BA5B2B3127A04930089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 293"; rLen = 0; rLoc = 9129; rType = 0; vrLen = 1672; vrLoc = 8099; }; 1BA5B2B7127A04BA0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 122"; rLen = 0; rLoc = 2961; rType = 0; vrLen = 1860; vrLoc = 1587; }; 1BA5B2BB127A04D30089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 122"; rLen = 0; rLoc = 2954; rType = 0; vrLen = 1858; vrLoc = 1587; }; 1BA5B2C1127A05680089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 86"; rLen = 0; rLoc = 1889; rType = 0; vrLen = 1497; vrLoc = 1010; }; 1BA5B2C5127A05A20089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 279"; rLen = 0; rLoc = 8691; rType = 0; vrLen = 1403; vrLoc = 7978; }; 1BA5B2C9127A05CB0089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 122"; rLen = 0; rLoc = 2876; rType = 0; vrLen = 1860; vrLoc = 1862; }; 1BA5B2CD127A06090089D2EA /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.mm: 279"; rLen = 0; rLoc = 8691; rType = 0; vrLen = 1428; vrLoc = 7916; }; 1BDF445B1277729000D3E723 /* SimpleAssimpViewX */ = { isa = PBXExecutable; activeArgIndices = ( ); argumentStrings = ( ); autoAttachOnCrash = 1; breakpointsEnabled = 0; configStateDict = { }; customDataFormattersEnabled = 1; dataTipCustomDataFormattersEnabled = 1; dataTipShowTypeColumn = 1; dataTipSortType = 0; debuggerPlugin = GDBDebugging; disassemblyDisplayState = 0; dylibVariantSuffix = ""; enableDebugStr = 1; environmentEntries = ( ); executableSystemSymbolLevel = 0; executableUserSymbolLevel = 0; libgmallocEnabled = 0; name = SimpleAssimpViewX; savedGlobals = { }; showTypeColumn = 0; sourceDirectories = ( ); variableFormatDictionary = { }; }; 1BDF4468127772AF00D3E723 /* Source Control */ = { isa = PBXSourceControlManager; fallbackIsa = XCSourceControlManager; isSCMEnabled = 0; scmConfiguration = { repositoryNamesForRoots = { "" = ""; }; }; }; 1BDF4469127772AF00D3E723 /* Code sense */ = { isa = PBXCodeSenseManager; indexTemplatePath = ""; }; 1BDF44A01277739F00D3E723 /* XDModelBookmark */ = { isa = XDModelBookmark; fRef = 775BDEF0067A8BF0009058FE /* MyDocument.xcdatamodel */; fallbackIsa = PBXBookmark; }; 1BDF44A11277739F00D3E723 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 32DBCF750370BD2300C91783 /* SimpleAssimpViewX_Prefix.pch */; name = "DisplayLinkAsyncMoviePlayer_Prefix.pch: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 257; vrLoc = 0; }; 1BDF44AF127773D100D3E723 /* ImageCompression.h */ = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ImageCompression.h; path = /System/Library/Frameworks/QuickTime.framework/Versions/A/Headers/ImageCompression.h; sourceTree = ""; }; 1BDF44B91277745D00D3E723 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 1BDF44AF127773D100D3E723 /* ImageCompression.h */; name = "ImageCompression.h: 12564"; rLen = 0; rLoc = 439465; rType = 0; vrLen = 1641; vrLoc = 433255; }; 1BDF44BB1277745D00D3E723 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 1BDF44BC1277745D00D3E723 /* ImageCompression.h */; name = "ImageCompression.h: 12286"; rLen = 2; rLoc = 430618; rType = 0; vrLen = 1615; vrLoc = 429944; }; 1BDF44BC1277745D00D3E723 /* ImageCompression.h */ = { isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = ImageCompression.h; path = /Developer/SDKs/MacOSX10.6.sdk/System/Library/Frameworks/QuickTime.framework/Headers/ImageCompression.h; sourceTree = ""; }; 1BDF450D127776C900D3E723 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4B0FDCFA73011CA2CEA /* main.m */; name = "main.m: 1"; rLen = 0; rLoc = 0; rType = 0; vrLen = 266; vrLoc = 0; }; 1BDF45101277771B00D3E723 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */; name = "MyDocument.h: 28"; rLen = 0; rLoc = 1014; rType = 0; vrLen = 622; vrLoc = 0; }; 1BDF45111277771B00D3E723 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 42"; rLen = 0; rLoc = 1604; rType = 0; vrLen = 1099; vrLoc = 20; }; 1BDF45121277771B00D3E723 /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; name = "MyDocument.m: 31"; rLen = 26; rLoc = 1281; rType = 0; vrLen = 1032; vrLoc = 152; }; 2A37F4A9FDCFA73011CA2CEA /* Project object */ = { activeArchitecturePreference = x86_64; activeBuildConfigurationName = Debug; activeExecutable = 1BDF445B1277729000D3E723 /* SimpleAssimpViewX */; activeTarget = 8D15AC270486D014006FF6A4 /* SimpleAssimpViewX */; addToTargets = ( 8D15AC270486D014006FF6A4 /* SimpleAssimpViewX */, ); codeSenseManager = 1BDF4469127772AF00D3E723 /* Code sense */; executables = ( 1BDF445B1277729000D3E723 /* SimpleAssimpViewX */, ); perUserDictionary = { PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = { PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; PBXFileTableDataSourceColumnWidthsKey = ( 20, 810, 20, 48, 43, 43, 20, ); PBXFileTableDataSourceColumnsKey = ( PBXFileDataSource_FiletypeID, PBXFileDataSource_Filename_ColumnID, PBXFileDataSource_Built_ColumnID, PBXFileDataSource_ObjectSize_ColumnID, PBXFileDataSource_Errors_ColumnID, PBXFileDataSource_Warnings_ColumnID, PBXFileDataSource_Target_ColumnID, ); }; PBXConfiguration.PBXTargetDataSource.PBXTargetDataSource = { PBXFileTableDataSourceColumnSortingDirectionKey = "-1"; PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID; PBXFileTableDataSourceColumnWidthsKey = ( 20, 770, 60, 20, 48, 43, 43, ); PBXFileTableDataSourceColumnsKey = ( PBXFileDataSource_FiletypeID, PBXFileDataSource_Filename_ColumnID, PBXTargetDataSource_PrimaryAttribute, PBXFileDataSource_Built_ColumnID, PBXFileDataSource_ObjectSize_ColumnID, PBXFileDataSource_Errors_ColumnID, PBXFileDataSource_Warnings_ColumnID, ); }; PBXPerProjectTemplateStateSaveDate = 309985383; PBXWorkspaceStateSaveDate = 309985383; }; perUserProjectItems = { 1B0E99FF1279E80B003108E7 = 1B0E99FF1279E80B003108E7 /* PBXTextBookmark */; 1B0E9A231279EA16003108E7 = 1B0E9A231279EA16003108E7 /* PBXTextBookmark */; 1B0E9A241279EA16003108E7 = 1B0E9A241279EA16003108E7 /* PBXTextBookmark */; 1B0E9A251279EA16003108E7 = 1B0E9A251279EA16003108E7 /* PBXTextBookmark */; 1B0E9A2B1279EA26003108E7 = 1B0E9A2B1279EA26003108E7 /* PBXTextBookmark */; 1B0E9A2F1279EA37003108E7 = 1B0E9A2F1279EA37003108E7 /* PBXTextBookmark */; 1B0E9A331279EA40003108E7 = 1B0E9A331279EA40003108E7 /* PBXTextBookmark */; 1B0E9A371279EA45003108E7 = 1B0E9A371279EA45003108E7 /* PBXTextBookmark */; 1B0E9A3A1279EA54003108E7 = 1B0E9A3A1279EA54003108E7 /* PBXTextBookmark */; 1B0E9A3D1279EA64003108E7 = 1B0E9A3D1279EA64003108E7 /* PBXTextBookmark */; 1B0E9A4D1279EB1F003108E7 = 1B0E9A4D1279EB1F003108E7 /* PBXTextBookmark */; 1B0E9A501279EB8D003108E7 = 1B0E9A501279EB8D003108E7 /* PBXTextBookmark */; 1B0E9A511279EBA9003108E7 = 1B0E9A511279EBA9003108E7 /* PBXTextBookmark */; 1B0E9A541279EC57003108E7 = 1B0E9A541279EC57003108E7 /* PBXTextBookmark */; 1B0E9A561279EC72003108E7 = 1B0E9A561279EC72003108E7 /* PBXTextBookmark */; 1B0E9A571279EC72003108E7 = 1B0E9A571279EC72003108E7 /* PBXTextBookmark */; 1B0E9A581279EC72003108E7 = 1B0E9A581279EC72003108E7 /* PBXTextBookmark */; 1B0E9A921279ED56003108E7 = 1B0E9A921279ED56003108E7 /* PBXTextBookmark */; 1B0E9A9C1279EE7D003108E7 = 1B0E9A9C1279EE7D003108E7 /* PBXTextBookmark */; 1B0E9A9D1279EE7D003108E7 = 1B0E9A9D1279EE7D003108E7 /* PBXTextBookmark */; 1B0E9A9E1279EE7D003108E7 = 1B0E9A9E1279EE7D003108E7 /* PBXTextBookmark */; 1B0E9A9F1279EE7D003108E7 = 1B0E9A9F1279EE7D003108E7 /* PBXTextBookmark */; 1B0E9AA01279EE7D003108E7 = 1B0E9AA01279EE7D003108E7 /* PBXTextBookmark */; 1B0E9B0C1279F08F003108E7 = 1B0E9B0C1279F08F003108E7 /* PBXTextBookmark */; 1B0E9B0D1279F08F003108E7 = 1B0E9B0D1279F08F003108E7 /* PBXTextBookmark */; 1B0E9B0E1279F08F003108E7 = 1B0E9B0E1279F08F003108E7 /* PBXTextBookmark */; 1B0E9B0F1279F08F003108E7 = 1B0E9B0F1279F08F003108E7 /* PBXTextBookmark */; 1B0E9B101279F08F003108E7 = 1B0E9B101279F08F003108E7 /* PBXTextBookmark */; 1B0E9B1D1279F110003108E7 = 1B0E9B1D1279F110003108E7 /* PBXTextBookmark */; 1B0E9B1E1279F110003108E7 = 1B0E9B1E1279F110003108E7 /* PBXTextBookmark */; 1B0E9B1F1279F110003108E7 = 1B0E9B1F1279F110003108E7 /* PBXTextBookmark */; 1B0E9B201279F118003108E7 = 1B0E9B201279F118003108E7 /* PBXTextBookmark */; 1B0E9B211279F118003108E7 = 1B0E9B211279F118003108E7 /* PBXTextBookmark */; 1B0E9B221279F118003108E7 = 1B0E9B221279F118003108E7 /* PBXTextBookmark */; 1B0E9B231279F118003108E7 = 1B0E9B231279F118003108E7 /* PBXTextBookmark */; 1B0E9B241279F118003108E7 = 1B0E9B241279F118003108E7 /* PBXTextBookmark */; 1B0E9BA81279F2A2003108E7 = 1B0E9BA81279F2A2003108E7 /* PBXTextBookmark */; 1B0E9BA91279F2A2003108E7 = 1B0E9BA91279F2A2003108E7 /* PBXTextBookmark */; 1B0E9BB41279F317003108E7 = 1B0E9BB41279F317003108E7 /* PBXTextBookmark */; 1B0E9BB51279F317003108E7 = 1B0E9BB51279F317003108E7 /* PBXTextBookmark */; 1B0E9BB61279F317003108E7 = 1B0E9BB61279F317003108E7 /* PBXTextBookmark */; 1B0E9BBC1279F38A003108E7 = 1B0E9BBC1279F38A003108E7 /* PBXTextBookmark */; 1BA5B1841279F5FE0089D2EA = 1BA5B1841279F5FE0089D2EA /* PBXTextBookmark */; 1BA5B1851279F5FE0089D2EA = 1BA5B1851279F5FE0089D2EA /* PBXTextBookmark */; 1BA5B1941279F61A0089D2EA = 1BA5B1941279F61A0089D2EA /* PBXTextBookmark */; 1BA5B1951279F61A0089D2EA = 1BA5B1951279F61A0089D2EA /* PBXTextBookmark */; 1BA5B19E1279F6480089D2EA = 1BA5B19E1279F6480089D2EA /* PBXTextBookmark */; 1BA5B1A21279F6640089D2EA = 1BA5B1A21279F6640089D2EA /* PBXTextBookmark */; 1BA5B1A61279F6910089D2EA = 1BA5B1A61279F6910089D2EA /* PBXTextBookmark */; 1BA5B1AE1279F6D30089D2EA = 1BA5B1AE1279F6D30089D2EA /* PBXTextBookmark */; 1BA5B1B21279F7010089D2EA = 1BA5B1B21279F7010089D2EA /* PBXTextBookmark */; 1BA5B1B41279F72F0089D2EA = 1BA5B1B41279F72F0089D2EA /* PBXTextBookmark */; 1BA5B1B91279F7520089D2EA = 1BA5B1B91279F7520089D2EA /* PBXTextBookmark */; 1BA5B1BD1279F79D0089D2EA = 1BA5B1BD1279F79D0089D2EA /* PBXTextBookmark */; 1BA5B1C11279F7BB0089D2EA = 1BA5B1C11279F7BB0089D2EA /* PBXTextBookmark */; 1BA5B1C51279F7CC0089D2EA = 1BA5B1C51279F7CC0089D2EA /* PBXTextBookmark */; 1BA5B1C91279F7F70089D2EA = 1BA5B1C91279F7F70089D2EA /* PBXTextBookmark */; 1BA5B1CB1279F81B0089D2EA = 1BA5B1CB1279F81B0089D2EA /* PBXTextBookmark */; 1BA5B1D01279F8BF0089D2EA = 1BA5B1D01279F8BF0089D2EA /* PBXTextBookmark */; 1BA5B1D21279F8CF0089D2EA = 1BA5B1D21279F8CF0089D2EA /* PBXTextBookmark */; 1BA5B1D31279F8CF0089D2EA = 1BA5B1D31279F8CF0089D2EA /* PBXTextBookmark */; 1BA5B1D41279F9280089D2EA = 1BA5B1D41279F9280089D2EA /* PBXTextBookmark */; 1BA5B1D91279F97C0089D2EA = 1BA5B1D91279F97C0089D2EA /* PBXTextBookmark */; 1BA5B1DA1279F97C0089D2EA = 1BA5B1DA1279F97C0089D2EA /* PBXTextBookmark */; 1BA5B1DE1279F9AC0089D2EA = 1BA5B1DE1279F9AC0089D2EA /* PBXTextBookmark */; 1BA5B1DF1279F9AC0089D2EA = 1BA5B1DF1279F9AC0089D2EA /* PBXTextBookmark */; 1BA5B1E31279F9DA0089D2EA = 1BA5B1E31279F9DA0089D2EA /* PBXTextBookmark */; 1BA5B1E41279F9DA0089D2EA = 1BA5B1E41279F9DA0089D2EA /* PBXTextBookmark */; 1BA5B1E61279FA750089D2EA = 1BA5B1E61279FA750089D2EA /* PBXTextBookmark */; 1BA5B1E71279FA760089D2EA = 1BA5B1E71279FA760089D2EA /* PBXTextBookmark */; 1BA5B1E81279FA760089D2EA = 1BA5B1E81279FA760089D2EA /* PBXTextBookmark */; 1BA5B1ED1279FB2B0089D2EA = 1BA5B1ED1279FB2B0089D2EA /* PBXTextBookmark */; 1BA5B1EE1279FB2B0089D2EA = 1BA5B1EE1279FB2B0089D2EA /* PBXTextBookmark */; 1BA5B1EF1279FB7E0089D2EA = 1BA5B1EF1279FB7E0089D2EA /* PBXTextBookmark */; 1BA5B1F01279FB7E0089D2EA = 1BA5B1F01279FB7E0089D2EA /* PBXTextBookmark */; 1BA5B1F31279FBBC0089D2EA = 1BA5B1F31279FBBC0089D2EA /* PBXTextBookmark */; 1BA5B1F41279FBBC0089D2EA = 1BA5B1F41279FBBC0089D2EA /* PBXTextBookmark */; 1BA5B1F81279FBCD0089D2EA = 1BA5B1F81279FBCD0089D2EA /* PBXTextBookmark */; 1BA5B1F91279FBCD0089D2EA = 1BA5B1F91279FBCD0089D2EA /* PBXTextBookmark */; 1BA5B1FF1279FBFE0089D2EA = 1BA5B1FF1279FBFE0089D2EA /* PBXTextBookmark */; 1BA5B2001279FBFE0089D2EA = 1BA5B2001279FBFE0089D2EA /* PBXTextBookmark */; 1BA5B2021279FC0D0089D2EA = 1BA5B2021279FC0D0089D2EA /* PBXTextBookmark */; 1BA5B2031279FC0D0089D2EA = 1BA5B2031279FC0D0089D2EA /* PBXTextBookmark */; 1BA5B2041279FC280089D2EA = 1BA5B2041279FC280089D2EA /* PBXTextBookmark */; 1BA5B2071279FC580089D2EA = 1BA5B2071279FC580089D2EA /* PBXTextBookmark */; 1BA5B2081279FC580089D2EA = 1BA5B2081279FC580089D2EA /* PBXTextBookmark */; 1BA5B20C1279FC910089D2EA = 1BA5B20C1279FC910089D2EA /* PBXTextBookmark */; 1BA5B20D1279FC910089D2EA = 1BA5B20D1279FC910089D2EA /* PBXTextBookmark */; 1BA5B2111279FCA60089D2EA = 1BA5B2111279FCA60089D2EA /* PBXTextBookmark */; 1BA5B2121279FCA60089D2EA = 1BA5B2121279FCA60089D2EA /* PBXTextBookmark */; 1BA5B2161279FCBC0089D2EA = 1BA5B2161279FCBC0089D2EA /* PBXTextBookmark */; 1BA5B2171279FCBC0089D2EA = 1BA5B2171279FCBC0089D2EA /* PBXTextBookmark */; 1BA5B2191279FCF40089D2EA = 1BA5B2191279FCF40089D2EA /* PBXTextBookmark */; 1BA5B21A1279FCF40089D2EA = 1BA5B21A1279FCF40089D2EA /* PBXTextBookmark */; 1BA5B21D1279FD420089D2EA = 1BA5B21D1279FD420089D2EA /* PBXTextBookmark */; 1BA5B21E1279FD650089D2EA = 1BA5B21E1279FD650089D2EA /* PBXTextBookmark */; 1BA5B21F1279FD650089D2EA = 1BA5B21F1279FD650089D2EA /* PBXTextBookmark */; 1BA5B2221279FD7E0089D2EA = 1BA5B2221279FD7E0089D2EA /* PBXTextBookmark */; 1BA5B2231279FD7E0089D2EA = 1BA5B2231279FD7E0089D2EA /* PBXTextBookmark */; 1BA5B2271279FD990089D2EA = 1BA5B2271279FD990089D2EA /* PBXTextBookmark */; 1BA5B2281279FD990089D2EA = 1BA5B2281279FD990089D2EA /* PBXTextBookmark */; 1BA5B22C1279FDAA0089D2EA = 1BA5B22C1279FDAA0089D2EA /* PBXTextBookmark */; 1BA5B22D1279FDAA0089D2EA = 1BA5B22D1279FDAA0089D2EA /* PBXTextBookmark */; 1BA5B2311279FDCF0089D2EA = 1BA5B2311279FDCF0089D2EA /* PBXTextBookmark */; 1BA5B2321279FDCF0089D2EA = 1BA5B2321279FDCF0089D2EA /* PBXTextBookmark */; 1BA5B2361279FDE30089D2EA = 1BA5B2361279FDE30089D2EA /* PBXTextBookmark */; 1BA5B2371279FDE30089D2EA = 1BA5B2371279FDE30089D2EA /* PBXTextBookmark */; 1BA5B23E1279FF900089D2EA = 1BA5B23E1279FF900089D2EA /* PBXTextBookmark */; 1BA5B23F1279FF900089D2EA = 1BA5B23F1279FF900089D2EA /* PBXTextBookmark */; 1BA5B2401279FF900089D2EA = 1BA5B2401279FF900089D2EA /* PBXTextBookmark */; 1BA5B244127A001E0089D2EA = 1BA5B244127A001E0089D2EA /* PBXTextBookmark */; 1BA5B248127A00350089D2EA = 1BA5B248127A00350089D2EA /* PBXTextBookmark */; 1BA5B254127A00700089D2EA /* PBXTextBookmark */ = 1BA5B254127A00700089D2EA /* PBXTextBookmark */; 1BA5B269127A012B0089D2EA /* PBXTextBookmark */ = 1BA5B269127A012B0089D2EA /* PBXTextBookmark */; 1BA5B26D127A01450089D2EA /* PBXTextBookmark */ = 1BA5B26D127A01450089D2EA /* PBXTextBookmark */; 1BA5B26F127A017A0089D2EA /* PBXTextBookmark */ = 1BA5B26F127A017A0089D2EA /* PBXTextBookmark */; 1BA5B275127A021A0089D2EA /* PBXTextBookmark */ = 1BA5B275127A021A0089D2EA /* PBXTextBookmark */; 1BA5B287127A02E00089D2EA /* PBXTextBookmark */ = 1BA5B287127A02E00089D2EA /* PBXTextBookmark */; 1BA5B28D127A03AF0089D2EA /* PBXTextBookmark */ = 1BA5B28D127A03AF0089D2EA /* PBXTextBookmark */; 1BA5B28E127A03AF0089D2EA /* PBXTextBookmark */ = 1BA5B28E127A03AF0089D2EA /* PBXTextBookmark */; 1BA5B28F127A03AF0089D2EA /* PBXTextBookmark */ = 1BA5B28F127A03AF0089D2EA /* PBXTextBookmark */; 1BA5B293127A03EE0089D2EA /* PBXTextBookmark */ = 1BA5B293127A03EE0089D2EA /* PBXTextBookmark */; 1BA5B297127A04000089D2EA /* PBXTextBookmark */ = 1BA5B297127A04000089D2EA /* PBXTextBookmark */; 1BA5B29B127A04200089D2EA /* PBXTextBookmark */ = 1BA5B29B127A04200089D2EA /* PBXTextBookmark */; 1BA5B29F127A042C0089D2EA /* PBXTextBookmark */ = 1BA5B29F127A042C0089D2EA /* PBXTextBookmark */; 1BA5B2A3127A04370089D2EA /* PBXTextBookmark */ = 1BA5B2A3127A04370089D2EA /* PBXTextBookmark */; 1BA5B2A7127A04480089D2EA /* PBXTextBookmark */ = 1BA5B2A7127A04480089D2EA /* PBXTextBookmark */; 1BA5B2AB127A04520089D2EA /* PBXTextBookmark */ = 1BA5B2AB127A04520089D2EA /* PBXTextBookmark */; 1BA5B2AF127A04620089D2EA /* PBXTextBookmark */ = 1BA5B2AF127A04620089D2EA /* PBXTextBookmark */; 1BA5B2B3127A04930089D2EA /* PBXTextBookmark */ = 1BA5B2B3127A04930089D2EA /* PBXTextBookmark */; 1BA5B2B7127A04BA0089D2EA /* PBXTextBookmark */ = 1BA5B2B7127A04BA0089D2EA /* PBXTextBookmark */; 1BA5B2BB127A04D30089D2EA /* PBXTextBookmark */ = 1BA5B2BB127A04D30089D2EA /* PBXTextBookmark */; 1BA5B2C1127A05680089D2EA /* PBXTextBookmark */ = 1BA5B2C1127A05680089D2EA /* PBXTextBookmark */; 1BA5B2C5127A05A20089D2EA /* PBXTextBookmark */ = 1BA5B2C5127A05A20089D2EA /* PBXTextBookmark */; 1BA5B2C9127A05CB0089D2EA /* PBXTextBookmark */ = 1BA5B2C9127A05CB0089D2EA /* PBXTextBookmark */; 1BA5B2CD127A06090089D2EA /* PBXTextBookmark */ = 1BA5B2CD127A06090089D2EA /* PBXTextBookmark */; 1BDF44A01277739F00D3E723 = 1BDF44A01277739F00D3E723 /* XDModelBookmark */; 1BDF44A11277739F00D3E723 = 1BDF44A11277739F00D3E723 /* PBXTextBookmark */; 1BDF44B91277745D00D3E723 = 1BDF44B91277745D00D3E723 /* PBXTextBookmark */; 1BDF44BB1277745D00D3E723 = 1BDF44BB1277745D00D3E723 /* PBXTextBookmark */; 1BDF450D127776C900D3E723 = 1BDF450D127776C900D3E723 /* PBXTextBookmark */; 1BDF45101277771B00D3E723 = 1BDF45101277771B00D3E723 /* PBXTextBookmark */; 1BDF45111277771B00D3E723 = 1BDF45111277771B00D3E723 /* PBXTextBookmark */; 1BDF45121277771B00D3E723 = 1BDF45121277771B00D3E723 /* PBXTextBookmark */; }; sourceControlManager = 1BDF4468127772AF00D3E723 /* Source Control */; userBuildSettings = { }; }; 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {1622, 10283}}"; sepNavSelRange = "{8691, 0}"; sepNavVisRange = "{7916, 1428}"; }; }; 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {1146, 849}}"; sepNavSelRange = "{178, 0}"; sepNavVisRange = "{0, 1644}"; }; }; 2A37F4B0FDCFA73011CA2CEA /* main.m */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {779, 650}}"; sepNavSelRange = "{0, 0}"; sepNavVisRange = "{0, 266}"; }; }; 32DBCF750370BD2300C91783 /* SimpleAssimpViewX_Prefix.pch */ = { uiCtxt = { sepNavIntBoundsRect = "{{0, 0}, {894, 673}}"; sepNavSelRange = "{0, 0}"; sepNavVisRange = "{0, 257}"; }; }; 775BDEF0067A8BF0009058FE /* MyDocument.xcdatamodel */ = { uiCtxt = { "Xdesign Model Editor Bookmark Key" = { UIContextForDetailArea = { _indexOfSelectedPane = 0; _indexOfSelectedView = 1; }; UIContextForEntityArea = { _indexOfSelectedView = 0; chosenTableColumnns = ( "ET Entity", "ET Abstract", "ET Class", ); chosenTableColumnns_sortDirections = ( YES, ); chosenTableColumnns_sortKeys = ( name, ); chosenTableColumnns_sortSelectors = ( "_xdcaseInsensitiveNumericCompare:", ); chosenTableWidths = ( 103.000000, 22.000000, 49.080078, ); }; UIContextForLayoutManager = { detailSplitGeometry = { _collapsingFrameDimension = 0; _indexOfCollapsedView = 0; _percentageOfCollapsedView = 0; isCollapsed = yes; sizes = ( "{{0, 0}, {604, 218}}", "{{609, 0}, {318, 218}}", ); }; diagramSplitGeometry = { _collapsingFrameDimension = 0; _indexOfCollapsedView = 0; _percentageOfCollapsedView = 0; isCollapsed = yes; sizes = ( "{{0, 0}, {927, 220}}", "{{0, 225}, {927, 463}}", ); }; tableSplitGeometry = { _collapsingFrameDimension = 0; _indexOfCollapsedView = 0; _percentageOfCollapsedView = 0; isCollapsed = yes; sizes = ( "{{0, 0}, {199, 218}}", "{{204, 0}, {400, 218}}", ); }; }; UIContextForPropertyArea = { _indexOfSelectedView = 0; chosenTableColumnnFRTs = ( "FT Fetch Request", "FT Predicate", ); chosenTableColumnnFRTs_sortDirections = ( YES, ); chosenTableColumnnFRTs_sortKeys = ( name, ); chosenTableColumnnFRTs_sortSelectors = ( "_xdcaseInsensitiveNumericCompare:", ); chosenTableColumnnsAT = ( "AT Attribute", "AT Type", ); chosenTableColumnnsAT_sortDirections = ( YES, ); chosenTableColumnnsAT_sortKeys = ( name, ); chosenTableColumnnsAT_sortSelectors = ( "_xdcaseInsensitiveNumericCompare:", ); chosenTableColumnnsFPT = ( "FP FetchedProperty", "FP Destination", "FP Predicate", ); chosenTableColumnnsFPT_sortDirections = ( YES, ); chosenTableColumnnsFPT_sortKeys = ( name, ); chosenTableColumnnsFPT_sortSelectors = ( "_xdcaseInsensitiveNumericCompare:", ); chosenTableColumnnsPT = ( "PT Property", "PT Kind", "PT SharedKeyOne", ); chosenTableColumnnsPT_sortDirections = ( YES, ); chosenTableColumnnsPT_sortKeys = ( name, ); chosenTableColumnnsPT_sortSelectors = ( "_xdcaseInsensitiveNumericCompare:", ); chosenTableColumnnsRT = ( "RT Relationship", "RT Destination", ); chosenTableColumnnsRT_sortDirections = ( YES, ); chosenTableColumnnsRT_sortKeys = ( name, ); chosenTableColumnnsRT_sortSelectors = ( "_xdcaseInsensitiveNumericCompare:", ); chosenTableWidthsAT = ( 128.000000, 64.000000, ); chosenTableWidthsFPT = ( 128.000000, 64.000000, 144.764160, ); chosenTableWidthsFRT = ( 128.000000, 249.764160, ); chosenTableWidthsPT = ( 128.000000, 108.110840, 137.570801, ); chosenTableWidthsRT = ( 128.000000, 64.000000, ); }; "xdesign model browser state key - shown/hidden" = 1; "xdesign model diagram view visible rect key" = "{{-96, 0}, {912, 448}}"; }; }; }; 8D15AC270486D014006FF6A4 /* SimpleAssimpViewX */ = { activeExec = 0; executables = ( 1BDF445B1277729000D3E723 /* SimpleAssimpViewX */, ); }; } assimp-4.1.0/samples/SimpleAssimpViewX/SimpleAssimpViewX.xcodeproj/vade.mode1v30000644002537200234200000012030613213503245030017 0ustar zmoelnigiemusers ActivePerspectiveName Project AllowedModules BundleLoadPath MaxInstances n Module PBXSmartGroupTreeModule Name Groups and Files Outline View BundleLoadPath MaxInstances n Module PBXNavigatorGroup Name Editor BundleLoadPath MaxInstances n Module XCTaskListModule Name Task List BundleLoadPath MaxInstances n Module XCDetailModule Name File and Smart Group Detail Viewer BundleLoadPath MaxInstances 1 Module PBXBuildResultsModule Name Detailed Build Results Viewer BundleLoadPath MaxInstances 1 Module PBXProjectFindModule Name Project Batch Find Tool BundleLoadPath MaxInstances n Module XCProjectFormatConflictsModule Name Project Format Conflicts List BundleLoadPath MaxInstances n Module PBXBookmarksModule Name Bookmarks Tool BundleLoadPath MaxInstances n Module PBXClassBrowserModule Name Class Browser BundleLoadPath MaxInstances n Module PBXCVSModule Name Source Code Control Tool BundleLoadPath MaxInstances n Module PBXDebugBreakpointsModule Name Debug Breakpoints Tool BundleLoadPath MaxInstances n Module XCDockableInspector Name Inspector BundleLoadPath MaxInstances n Module PBXOpenQuicklyModule Name Open Quickly Tool BundleLoadPath MaxInstances 1 Module PBXDebugSessionModule Name Debugger BundleLoadPath MaxInstances 1 Module PBXDebugCLIModule Name Debug Console BundleLoadPath MaxInstances n Module XCSnapshotModule Name Snapshots Tool BundlePath /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources Description DefaultDescriptionKey DockingSystemVisible Extension mode1v3 FavBarConfig PBXProjectModuleGUID 1BDF44A71277739F00D3E723 XCBarModuleItemNames XCBarModuleItems FirstTimeWindowDisplayed Identifier com.apple.perspectives.project.mode1v3 MajorVersion 33 MinorVersion 0 Name Default Notifications OpenEditors PerspectiveWidths -1 -1 Perspectives ChosenToolbarItems active-combo-popup action NSToolbarFlexibleSpaceItem debugger-enable-breakpoints build-and-go com.apple.ide.PBXToolbarStopButton get-info NSToolbarFlexibleSpaceItem com.apple.pbx.toolbar.searchfield ControllerClassBaseName IconName WindowOfProjectWithEditor Identifier perspective.project IsVertical Layout ContentConfiguration PBXBottomSmartGroupGIDs 1C37FBAC04509CD000000102 1C37FAAC04509CD000000102 1C37FABC05509CD000000102 1C37FABC05539CD112110102 E2644B35053B69B200211256 1C37FABC04509CD000100104 1CC0EA4004350EF90044410B 1CC0EA4004350EF90041110B PBXProjectModuleGUID 1CE0B1FE06471DED0097A5F4 PBXProjectModuleLabel Files PBXProjectStructureProvided yes PBXSmartGroupTreeModuleColumnData PBXSmartGroupTreeModuleColumnWidthsKey 275 PBXSmartGroupTreeModuleColumnsKey_v4 MainColumn PBXSmartGroupTreeModuleOutlineStateKey_v7 PBXSmartGroupTreeModuleOutlineStateExpansionKey 2A37F4AAFDCFA73011CA2CEA E1B74B1A0667B4A90069E3BA 2A37F4ABFDCFA73011CA2CEA 1B0E9AD21279EFCC003108E7 1B0E9AFC1279F006003108E7 2A37F4AFFDCFA73011CA2CEA 2A37F4B8FDCFA73011CA2CEA 2A37F4C3FDCFA73011CA2CEA 1058C7A6FEA54F5311CA2CBB 1C37FBAC04509CD000000102 1C37FABC05509CD000000102 PBXSmartGroupTreeModuleOutlineStateSelectionKey 5 3 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey {{0, 0}, {275, 910}} PBXTopSmartGroupGIDs XCIncludePerspectivesSwitch XCSharingToken com.apple.Xcode.GFSharingToken GeometryConfiguration Frame {{0, 0}, {292, 928}} GroupTreeTableConfiguration MainColumn 275 RubberWindowFrame 138 59 1346 969 0 0 1680 1028 Module PBXSmartGroupTreeModule Proportion 292pt Dock BecomeActive ContentConfiguration PBXProjectModuleGUID 1CE0B20306471E060097A5F4 PBXProjectModuleLabel MyDocument.mm PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 1CE0B20406471E060097A5F4 PBXProjectModuleLabel MyDocument.mm _historyCapacity 0 bookmark 1BA5B2CD127A06090089D2EA history 1BDF44A01277739F00D3E723 1BDF44A11277739F00D3E723 1BDF44B91277745D00D3E723 1BDF44BB1277745D00D3E723 1BDF450D127776C900D3E723 1B0E9B201279F118003108E7 1B0E9B211279F118003108E7 1BA5B23E1279FF900089D2EA 1BA5B28D127A03AF0089D2EA 1BA5B28E127A03AF0089D2EA SplitCount 1 StatusBarVisibility GeometryConfiguration Frame {{0, 0}, {1049, 880}} RubberWindowFrame 138 59 1346 969 0 0 1680 1028 Module PBXNavigatorGroup Proportion 880pt ContentConfiguration PBXProjectModuleGUID 1CE0B20506471E060097A5F4 PBXProjectModuleLabel Detail GeometryConfiguration Frame {{0, 885}, {1049, 43}} RubberWindowFrame 138 59 1346 969 0 0 1680 1028 Module XCDetailModule Proportion 43pt Proportion 1049pt Name Project ServiceClasses XCModuleDock PBXSmartGroupTreeModule XCModuleDock PBXNavigatorGroup XCDetailModule TableOfContents 1BA5B255127A00700089D2EA 1CE0B1FE06471DED0097A5F4 1BA5B256127A00700089D2EA 1CE0B20306471E060097A5F4 1CE0B20506471E060097A5F4 ToolbarConfigUserDefaultsMinorVersion 2 ToolbarConfiguration xcode.toolbar.config.defaultV3 ControllerClassBaseName IconName WindowOfProject Identifier perspective.morph IsVertical 0 Layout BecomeActive 1 ContentConfiguration PBXBottomSmartGroupGIDs 1C37FBAC04509CD000000102 1C37FAAC04509CD000000102 1C08E77C0454961000C914BD 1C37FABC05509CD000000102 1C37FABC05539CD112110102 E2644B35053B69B200211256 1C37FABC04509CD000100104 1CC0EA4004350EF90044410B 1CC0EA4004350EF90041110B PBXProjectModuleGUID 11E0B1FE06471DED0097A5F4 PBXProjectModuleLabel Files PBXProjectStructureProvided yes PBXSmartGroupTreeModuleColumnData PBXSmartGroupTreeModuleColumnWidthsKey 186 PBXSmartGroupTreeModuleColumnsKey_v4 MainColumn PBXSmartGroupTreeModuleOutlineStateKey_v7 PBXSmartGroupTreeModuleOutlineStateExpansionKey 29B97314FDCFA39411CA2CEA 1C37FABC05509CD000000102 PBXSmartGroupTreeModuleOutlineStateSelectionKey 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey {{0, 0}, {186, 337}} PBXTopSmartGroupGIDs XCIncludePerspectivesSwitch 1 XCSharingToken com.apple.Xcode.GFSharingToken GeometryConfiguration Frame {{0, 0}, {203, 355}} GroupTreeTableConfiguration MainColumn 186 RubberWindowFrame 373 269 690 397 0 0 1440 878 Module PBXSmartGroupTreeModule Proportion 100% Name Morph PreferredWidth 300 ServiceClasses XCModuleDock PBXSmartGroupTreeModule TableOfContents 11E0B1FE06471DED0097A5F4 ToolbarConfiguration xcode.toolbar.config.default.shortV3 PerspectivesBarVisible ShelfIsVisible SourceDescription file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec' StatusbarIsVisible TimeStamp 0.0 ToolbarConfigUserDefaultsMinorVersion 2 ToolbarDisplayMode 1 ToolbarIsVisible ToolbarSizeMode 1 Type Perspectives UpdateMessage The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature). You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature. Do you wish to update to the latest Workspace defaults for project '%@'? WindowJustification 5 WindowOrderList 1BA5B2CE127A06090089D2EA 1BA5B260127A00700089D2EA 1BA5B261127A00700089D2EA 1CD10A99069EF8BA00B06720 1BDF44A81277739F00D3E723 1C78EAAD065D492600B07095 /SimpleAssimpViewX/SimpleAssimpViewX.xcodeproj WindowString 138 59 1346 969 0 0 1680 1028 WindowToolsV3 FirstTimeWindowDisplayed Identifier windowTool.build IsVertical Layout Dock ContentConfiguration PBXProjectModuleGUID 1CD0528F0623707200166675 PBXProjectModuleLabel StatusBarVisibility GeometryConfiguration Frame {{0, 0}, {1429, 686}} RubberWindowFrame 115 60 1429 968 0 0 1680 1028 Module PBXNavigatorGroup Proportion 686pt BecomeActive ContentConfiguration PBXProjectModuleGUID XCMainBuildResultsModuleGUID PBXProjectModuleLabel Build Results XCBuildResultsTrigger_Collapse 1021 XCBuildResultsTrigger_Open 1011 GeometryConfiguration Frame {{0, 691}, {1429, 236}} RubberWindowFrame 115 60 1429 968 0 0 1680 1028 Module PBXBuildResultsModule Proportion 236pt Proportion 927pt Name Build Results ServiceClasses PBXBuildResultsModule StatusbarIsVisible TableOfContents 1BDF44A81277739F00D3E723 1BA5B257127A00700089D2EA 1CD0528F0623707200166675 XCMainBuildResultsModuleGUID ToolbarConfiguration xcode.toolbar.config.buildV3 WindowContentMinSize 486 300 WindowString 115 60 1429 968 0 0 1680 1028 WindowToolGUID 1BDF44A81277739F00D3E723 WindowToolIsVisible FirstTimeWindowDisplayed Identifier windowTool.debugger IsVertical Layout Dock ContentConfiguration Debugger HorizontalSplitView _collapsingFrameDimension 0.0 _indexOfCollapsedView 0 _percentageOfCollapsedView 0.0 isCollapsed yes sizes {{0, 0}, {533, 396}} {{533, 0}, {706, 396}} VerticalSplitView _collapsingFrameDimension 0.0 _indexOfCollapsedView 0 _percentageOfCollapsedView 0.0 isCollapsed yes sizes {{0, 0}, {1239, 396}} {{0, 396}, {1239, 400}} LauncherConfigVersion 8 PBXProjectModuleGUID 1C162984064C10D400B95A72 PBXProjectModuleLabel Debug - GLUTExamples (Underwater) GeometryConfiguration DebugConsoleVisible None DebugConsoleWindowFrame {{200, 200}, {500, 300}} DebugSTDIOWindowFrame {{200, 200}, {500, 300}} Frame {{0, 0}, {1239, 796}} PBXDebugSessionStackFrameViewKey DebugVariablesTableConfiguration Name 120 Value 85 Summary 476 Frame {{533, 0}, {706, 396}} RubberWindowFrame 441 177 1239 837 0 0 1680 1028 RubberWindowFrame 441 177 1239 837 0 0 1680 1028 Module PBXDebugSessionModule Proportion 796pt Proportion 796pt Name Debugger ServiceClasses PBXDebugSessionModule StatusbarIsVisible TableOfContents 1CD10A99069EF8BA00B06720 1BA5B258127A00700089D2EA 1C162984064C10D400B95A72 1BA5B259127A00700089D2EA 1BA5B25A127A00700089D2EA 1BA5B25B127A00700089D2EA 1BA5B25C127A00700089D2EA 1BA5B25D127A00700089D2EA ToolbarConfiguration xcode.toolbar.config.debugV3 WindowString 441 177 1239 837 0 0 1680 1028 WindowToolGUID 1CD10A99069EF8BA00B06720 WindowToolIsVisible Identifier windowTool.find Layout Dock Dock ContentConfiguration PBXProjectModuleGUID 1CDD528C0622207200134675 PBXProjectModuleLabel <No Editor> PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 1CD0528D0623707200166675 SplitCount 1 StatusBarVisibility 1 GeometryConfiguration Frame {{0, 0}, {781, 167}} RubberWindowFrame 62 385 781 470 0 0 1440 878 Module PBXNavigatorGroup Proportion 781pt Proportion 50% BecomeActive 1 ContentConfiguration PBXProjectModuleGUID 1CD0528E0623707200166675 PBXProjectModuleLabel Project Find GeometryConfiguration Frame {{8, 0}, {773, 254}} RubberWindowFrame 62 385 781 470 0 0 1440 878 Module PBXProjectFindModule Proportion 50% Proportion 428pt Name Project Find ServiceClasses PBXProjectFindModule StatusbarIsVisible 1 TableOfContents 1C530D57069F1CE1000CFCEE 1C530D58069F1CE1000CFCEE 1C530D59069F1CE1000CFCEE 1CDD528C0622207200134675 1C530D5A069F1CE1000CFCEE 1CE0B1FE06471DED0097A5F4 1CD0528E0623707200166675 WindowString 62 385 781 470 0 0 1440 878 WindowToolGUID 1C530D57069F1CE1000CFCEE WindowToolIsVisible 0 Identifier MENUSEPARATOR FirstTimeWindowDisplayed Identifier windowTool.debuggerConsole IsVertical Layout Dock BecomeActive ContentConfiguration PBXProjectModuleGUID 1C78EAAC065D492600B07095 PBXProjectModuleLabel Debugger Console GeometryConfiguration Frame {{0, 0}, {728, 246}} RubberWindowFrame 420 718 728 287 0 0 1680 1028 Module PBXDebugCLIModule Proportion 246pt Proportion 246pt Name Debugger Console ServiceClasses PBXDebugCLIModule StatusbarIsVisible TableOfContents 1C78EAAD065D492600B07095 1BA5B25E127A00700089D2EA 1C78EAAC065D492600B07095 ToolbarConfiguration xcode.toolbar.config.consoleV3 WindowString 420 718 728 287 0 0 1680 1028 WindowToolGUID 1C78EAAD065D492600B07095 WindowToolIsVisible Identifier windowTool.snapshots Layout Dock Module XCSnapshotModule Proportion 100% Proportion 100% Name Snapshots ServiceClasses XCSnapshotModule StatusbarIsVisible Yes ToolbarConfiguration xcode.toolbar.config.snapshots WindowString 315 824 300 550 0 0 1440 878 WindowToolIsVisible Yes Identifier windowTool.scm Layout Dock ContentConfiguration PBXProjectModuleGUID 1C78EAB2065D492600B07095 PBXProjectModuleLabel <No Editor> PBXSplitModuleInNavigatorKey Split0 PBXProjectModuleGUID 1C78EAB3065D492600B07095 SplitCount 1 StatusBarVisibility 1 GeometryConfiguration Frame {{0, 0}, {452, 0}} RubberWindowFrame 743 379 452 308 0 0 1280 1002 Module PBXNavigatorGroup Proportion 0pt BecomeActive 1 ContentConfiguration PBXProjectModuleGUID 1CD052920623707200166675 PBXProjectModuleLabel SCM GeometryConfiguration ConsoleFrame {{0, 259}, {452, 0}} Frame {{0, 7}, {452, 259}} RubberWindowFrame 743 379 452 308 0 0 1280 1002 TableConfiguration Status 30 FileName 199 Path 197.0950012207031 TableFrame {{0, 0}, {452, 250}} Module PBXCVSModule Proportion 262pt Proportion 266pt Name SCM ServiceClasses PBXCVSModule StatusbarIsVisible 1 TableOfContents 1C78EAB4065D492600B07095 1C78EAB5065D492600B07095 1C78EAB2065D492600B07095 1CD052920623707200166675 ToolbarConfiguration xcode.toolbar.config.scm WindowString 743 379 452 308 0 0 1280 1002 Identifier windowTool.breakpoints IsVertical 0 Layout Dock BecomeActive 1 ContentConfiguration PBXBottomSmartGroupGIDs 1C77FABC04509CD000000102 PBXProjectModuleGUID 1CE0B1FE06471DED0097A5F4 PBXProjectModuleLabel Files PBXProjectStructureProvided no PBXSmartGroupTreeModuleColumnData PBXSmartGroupTreeModuleColumnWidthsKey 168 PBXSmartGroupTreeModuleColumnsKey_v4 MainColumn PBXSmartGroupTreeModuleOutlineStateKey_v7 PBXSmartGroupTreeModuleOutlineStateExpansionKey 1C77FABC04509CD000000102 PBXSmartGroupTreeModuleOutlineStateSelectionKey 0 PBXSmartGroupTreeModuleOutlineStateVisibleRectKey {{0, 0}, {168, 350}} PBXTopSmartGroupGIDs XCIncludePerspectivesSwitch 0 GeometryConfiguration Frame {{0, 0}, {185, 368}} GroupTreeTableConfiguration MainColumn 168 RubberWindowFrame 315 424 744 409 0 0 1440 878 Module PBXSmartGroupTreeModule Proportion 185pt ContentConfiguration PBXProjectModuleGUID 1CA1AED706398EBD00589147 PBXProjectModuleLabel Detail GeometryConfiguration Frame {{190, 0}, {554, 368}} RubberWindowFrame 315 424 744 409 0 0 1440 878 Module XCDetailModule Proportion 554pt Proportion 368pt MajorVersion 3 MinorVersion 0 Name Breakpoints ServiceClasses PBXSmartGroupTreeModule XCDetailModule StatusbarIsVisible 1 TableOfContents 1CDDB66807F98D9800BB5817 1CDDB66907F98D9800BB5817 1CE0B1FE06471DED0097A5F4 1CA1AED706398EBD00589147 ToolbarConfiguration xcode.toolbar.config.breakpointsV3 WindowString 315 424 744 409 0 0 1440 878 WindowToolGUID 1CDDB66807F98D9800BB5817 WindowToolIsVisible 1 Identifier windowTool.debugAnimator Layout Dock Module PBXNavigatorGroup Proportion 100% Proportion 100% Name Debug Visualizer ServiceClasses PBXNavigatorGroup StatusbarIsVisible 1 ToolbarConfiguration xcode.toolbar.config.debugAnimatorV3 WindowString 100 100 700 500 0 0 1280 1002 Identifier windowTool.bookmarks Layout Dock Module PBXBookmarksModule Proportion 100% Proportion 100% Name Bookmarks ServiceClasses PBXBookmarksModule StatusbarIsVisible 0 WindowString 538 42 401 187 0 0 1280 1002 Identifier windowTool.projectFormatConflicts Layout Dock Module XCProjectFormatConflictsModule Proportion 100% Proportion 100% Name Project Format Conflicts ServiceClasses XCProjectFormatConflictsModule StatusbarIsVisible 0 WindowContentMinSize 450 300 WindowString 50 850 472 307 0 0 1440 877 Identifier windowTool.classBrowser Layout Dock BecomeActive 1 ContentConfiguration OptionsSetName Hierarchy, all classes PBXProjectModuleGUID 1CA6456E063B45B4001379D8 PBXProjectModuleLabel Class Browser - NSObject GeometryConfiguration ClassesFrame {{0, 0}, {374, 96}} ClassesTreeTableConfiguration PBXClassNameColumnIdentifier 208 PBXClassBookColumnIdentifier 22 Frame {{0, 0}, {630, 331}} MembersFrame {{0, 105}, {374, 395}} MembersTreeTableConfiguration PBXMemberTypeIconColumnIdentifier 22 PBXMemberNameColumnIdentifier 216 PBXMemberTypeColumnIdentifier 97 PBXMemberBookColumnIdentifier 22 PBXModuleWindowStatusBarHidden2 1 RubberWindowFrame 385 179 630 352 0 0 1440 878 Module PBXClassBrowserModule Proportion 332pt Proportion 332pt Name Class Browser ServiceClasses PBXClassBrowserModule StatusbarIsVisible 0 TableOfContents 1C0AD2AF069F1E9B00FABCE6 1C0AD2B0069F1E9B00FABCE6 1CA6456E063B45B4001379D8 ToolbarConfiguration xcode.toolbar.config.classbrowser WindowString 385 179 630 352 0 0 1440 878 WindowToolGUID 1C0AD2AF069F1E9B00FABCE6 WindowToolIsVisible 0 Identifier windowTool.refactoring IncludeInToolsMenu 0 Layout Dock BecomeActive 1 GeometryConfiguration Frame {0, 0}, {500, 335} RubberWindowFrame {0, 0}, {500, 335} Module XCRefactoringModule Proportion 100% Proportion 100% Name Refactoring ServiceClasses XCRefactoringModule WindowString 200 200 500 356 0 0 1920 1200 assimp-4.1.0/samples/SimpleAssimpViewX/SimpleAssimpViewX.xcodeproj/project.pbxproj0000644002537200234200000006536113213503245030765 0ustar zmoelnigiemusers// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 45; objects = { /* Begin PBXBuildFile section */ 1B0E9A901279ED43003108E7 /* libassimp.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B0E9A8F1279ED43003108E7 /* libassimp.a */; }; 1B0E9A951279EDCD003108E7 /* ModelLoaderHelperClasses.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1B0E9A941279EDCD003108E7 /* ModelLoaderHelperClasses.mm */; }; 1B0E9B1A1279F107003108E7 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 1B0E9B191279F107003108E7 /* libz.dylib */; }; 1BDF446B127772AF00D3E723 /* OpenGL.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1BDF446A127772AF00D3E723 /* OpenGL.framework */; }; 1BDF446F127772AF00D3E723 /* Quartz.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1BDF446E127772AF00D3E723 /* Quartz.framework */; }; 2F7446AB0DB6BCF400F9684A /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2F7446A70DB6BCF400F9684A /* MainMenu.xib */; }; 2F7446AC0DB6BCF400F9684A /* MyDocument.xib in Resources */ = {isa = PBXBuildFile; fileRef = 2F7446A90DB6BCF400F9684A /* MyDocument.xib */; }; 775BDEF1067A8BF0009058FE /* MyDocument.xcdatamodel in Sources */ = {isa = PBXBuildFile; fileRef = 775BDEF0067A8BF0009058FE /* MyDocument.xcdatamodel */; }; 775DFF38067A968500C5B868 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; }; 8D15AC2C0486D014006FF6A4 /* Credits.rtf in Resources */ = {isa = PBXBuildFile; fileRef = 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */; }; 8D15AC2F0486D014006FF6A4 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165FFE840EACC02AAC07 /* InfoPlist.strings */; }; 8D15AC310486D014006FF6A4 /* MyDocument.mm in Sources */ = {isa = PBXBuildFile; fileRef = 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */; settings = {ATTRIBUTES = (); }; }; 8D15AC320486D014006FF6A4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 2A37F4B0FDCFA73011CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; C75BB4F617EE0B64004F0260 /* color4.inl in Resources */ = {isa = PBXBuildFile; fileRef = C75BB4F117EE0B64004F0260 /* color4.inl */; }; C75BB4F717EE0B64004F0260 /* quaternion.inl in Resources */ = {isa = PBXBuildFile; fileRef = C75BB4F517EE0B64004F0260 /* quaternion.inl */; }; C75BB51417EE0B75004F0260 /* material.inl in Resources */ = {isa = PBXBuildFile; fileRef = C75BB50317EE0B75004F0260 /* material.inl */; }; C75BB51517EE0B75004F0260 /* matrix3x3.inl in Resources */ = {isa = PBXBuildFile; fileRef = C75BB50517EE0B75004F0260 /* matrix3x3.inl */; }; C75BB51617EE0B75004F0260 /* matrix4x4.inl in Resources */ = {isa = PBXBuildFile; fileRef = C75BB50717EE0B75004F0260 /* matrix4x4.inl */; }; C75BB51717EE0B75004F0260 /* vector2.inl in Resources */ = {isa = PBXBuildFile; fileRef = C75BB51017EE0B75004F0260 /* vector2.inl */; }; C75BB51817EE0B75004F0260 /* vector3.inl in Resources */ = {isa = PBXBuildFile; fileRef = C75BB51217EE0B75004F0260 /* vector3.inl */; }; /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 089C1660FE840EACC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 10; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 1B0E9A8F1279ED43003108E7 /* libassimp.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libassimp.a; sourceTree = ""; }; 1B0E9A931279EDCD003108E7 /* ModelLoaderHelperClasses.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ModelLoaderHelperClasses.h; sourceTree = ""; }; 1B0E9A941279EDCD003108E7 /* ModelLoaderHelperClasses.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = ModelLoaderHelperClasses.mm; sourceTree = ""; }; 1B0E9AFD1279F006003108E7 /* poppack1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = poppack1.h; path = "/Users/vade/Asset Import/include/Compiler/poppack1.h"; sourceTree = ""; }; 1B0E9AFE1279F006003108E7 /* pushpack1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = pushpack1.h; path = "/Users/vade/Asset Import/include/Compiler/pushpack1.h"; sourceTree = ""; }; 1B0E9B191279F107003108E7 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; }; 1BDF446A127772AF00D3E723 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = System/Library/Frameworks/OpenGL.framework; sourceTree = SDKROOT; }; 1BDF446E127772AF00D3E723 /* Quartz.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Quartz.framework; path = System/Library/Frameworks/Quartz.framework; sourceTree = SDKROOT; }; 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = MyDocument.mm; sourceTree = ""; }; 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MyDocument.h; sourceTree = ""; }; 2A37F4B0FDCFA73011CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 2A37F4BAFDCFA73011CA2CEA /* English */ = {isa = PBXFileReference; lastKnownFileType = text.rtf; name = English; path = English.lproj/Credits.rtf; sourceTree = ""; }; 2A37F4C4FDCFA73011CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 2A37F4C5FDCFA73011CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 2F7446A80DB6BCF400F9684A /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; 2F7446AA0DB6BCF400F9684A /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MyDocument.xib; sourceTree = ""; }; 32DBCF750370BD2300C91783 /* SimpleAssimpViewX_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SimpleAssimpViewX_Prefix.pch; sourceTree = ""; }; 775BDEF0067A8BF0009058FE /* MyDocument.xcdatamodel */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = wrapper.xcdatamodel; path = MyDocument.xcdatamodel; sourceTree = ""; }; 7788DA0506752A1600599AAD /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; 8D15AC360486D014006FF6A4 /* SimpleAssimpViewX-Info.plist */ = {isa = PBXFileReference; explicitFileType = text.plist.xml; fileEncoding = 4; path = "SimpleAssimpViewX-Info.plist"; sourceTree = ""; }; 8D15AC370486D014006FF6A4 /* SimpleAssimpViewX.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SimpleAssimpViewX.app; sourceTree = BUILT_PRODUCTS_DIR; }; C75BB4EA17EE0B64004F0260 /* ai_assert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ai_assert.h; sourceTree = ""; }; C75BB4EB17EE0B64004F0260 /* anim.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = anim.h; sourceTree = ""; }; C75BB4EC17EE0B64004F0260 /* camera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = camera.h; sourceTree = ""; }; C75BB4ED17EE0B64004F0260 /* cexport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cexport.h; sourceTree = ""; }; C75BB4EE17EE0B64004F0260 /* cfileio.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cfileio.h; sourceTree = ""; }; C75BB4EF17EE0B64004F0260 /* cimport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = cimport.h; sourceTree = ""; }; C75BB4F017EE0B64004F0260 /* color4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = color4.h; sourceTree = ""; }; C75BB4F117EE0B64004F0260 /* color4.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = color4.inl; sourceTree = ""; }; C75BB4F217EE0B64004F0260 /* config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = config.h; sourceTree = ""; }; C75BB4F317EE0B64004F0260 /* metadata.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = metadata.h; sourceTree = ""; }; C75BB4F417EE0B64004F0260 /* NullLogger.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = NullLogger.hpp; sourceTree = ""; }; C75BB4F517EE0B64004F0260 /* quaternion.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = quaternion.inl; sourceTree = ""; }; C75BB4F817EE0B75004F0260 /* DefaultLogger.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DefaultLogger.hpp; sourceTree = ""; }; C75BB4F917EE0B75004F0260 /* defs.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = defs.h; sourceTree = ""; }; C75BB4FA17EE0B75004F0260 /* Exporter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Exporter.hpp; sourceTree = ""; }; C75BB4FB17EE0B75004F0260 /* Importer.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Importer.hpp; sourceTree = ""; }; C75BB4FC17EE0B75004F0260 /* importerdesc.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = importerdesc.h; sourceTree = ""; }; C75BB4FD17EE0B75004F0260 /* IOStream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = IOStream.hpp; sourceTree = ""; }; C75BB4FE17EE0B75004F0260 /* IOSystem.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = IOSystem.hpp; sourceTree = ""; }; C75BB4FF17EE0B75004F0260 /* light.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = light.h; sourceTree = ""; }; C75BB50017EE0B75004F0260 /* Logger.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Logger.hpp; sourceTree = ""; }; C75BB50117EE0B75004F0260 /* LogStream.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = LogStream.hpp; sourceTree = ""; }; C75BB50217EE0B75004F0260 /* material.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = material.h; sourceTree = ""; }; C75BB50317EE0B75004F0260 /* material.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = material.inl; sourceTree = ""; }; C75BB50417EE0B75004F0260 /* matrix3x3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = matrix3x3.h; sourceTree = ""; }; C75BB50517EE0B75004F0260 /* matrix3x3.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = matrix3x3.inl; sourceTree = ""; }; C75BB50617EE0B75004F0260 /* matrix4x4.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = matrix4x4.h; sourceTree = ""; }; C75BB50717EE0B75004F0260 /* matrix4x4.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = matrix4x4.inl; sourceTree = ""; }; C75BB50817EE0B75004F0260 /* mesh.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mesh.h; sourceTree = ""; }; C75BB50917EE0B75004F0260 /* postprocess.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = postprocess.h; sourceTree = ""; }; C75BB50A17EE0B75004F0260 /* ProgressHandler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = ProgressHandler.hpp; sourceTree = ""; }; C75BB50B17EE0B75004F0260 /* quaternion.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = quaternion.h; sourceTree = ""; }; C75BB50C17EE0B75004F0260 /* scene.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = scene.h; sourceTree = ""; }; C75BB50D17EE0B75004F0260 /* texture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = texture.h; sourceTree = ""; }; C75BB50E17EE0B75004F0260 /* types.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = types.h; sourceTree = ""; }; C75BB50F17EE0B75004F0260 /* vector2.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vector2.h; sourceTree = ""; }; C75BB51017EE0B75004F0260 /* vector2.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = vector2.inl; sourceTree = ""; }; C75BB51117EE0B75004F0260 /* vector3.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vector3.h; sourceTree = ""; }; C75BB51217EE0B75004F0260 /* vector3.inl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = vector3.inl; sourceTree = ""; }; C75BB51317EE0B75004F0260 /* version.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = version.h; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ 8D15AC330486D014006FF6A4 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( 775DFF38067A968500C5B868 /* Cocoa.framework in Frameworks */, 1BDF446B127772AF00D3E723 /* OpenGL.framework in Frameworks */, 1BDF446F127772AF00D3E723 /* Quartz.framework in Frameworks */, 1B0E9A901279ED43003108E7 /* libassimp.a in Frameworks */, 1B0E9B1A1279F107003108E7 /* libz.dylib in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ 1058C7A6FEA54F5311CA2CBB /* Linked Frameworks */ = { isa = PBXGroup; children = ( 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */, 1BDF446A127772AF00D3E723 /* OpenGL.framework */, 1BDF446E127772AF00D3E723 /* Quartz.framework */, ); name = "Linked Frameworks"; sourceTree = ""; }; 1058C7A8FEA54F5311CA2CBB /* Other Frameworks */ = { isa = PBXGroup; children = ( 2A37F4C5FDCFA73011CA2CEA /* Foundation.framework */, 7788DA0506752A1600599AAD /* CoreData.framework */, 2A37F4C4FDCFA73011CA2CEA /* AppKit.framework */, ); name = "Other Frameworks"; sourceTree = ""; }; 19C28FB0FE9D524F11CA2CBB /* Products */ = { isa = PBXGroup; children = ( 8D15AC370486D014006FF6A4 /* SimpleAssimpViewX.app */, ); name = Products; sourceTree = ""; }; 1B0E9AD21279EFCC003108E7 /* include */ = { isa = PBXGroup; children = ( C75BB4F817EE0B75004F0260 /* DefaultLogger.hpp */, C75BB4F917EE0B75004F0260 /* defs.h */, C75BB4FA17EE0B75004F0260 /* Exporter.hpp */, C75BB4FB17EE0B75004F0260 /* Importer.hpp */, C75BB4FC17EE0B75004F0260 /* importerdesc.h */, C75BB4FD17EE0B75004F0260 /* IOStream.hpp */, C75BB4FE17EE0B75004F0260 /* IOSystem.hpp */, C75BB4FF17EE0B75004F0260 /* light.h */, C75BB50017EE0B75004F0260 /* Logger.hpp */, C75BB50117EE0B75004F0260 /* LogStream.hpp */, C75BB50217EE0B75004F0260 /* material.h */, C75BB50317EE0B75004F0260 /* material.inl */, C75BB50417EE0B75004F0260 /* matrix3x3.h */, C75BB50517EE0B75004F0260 /* matrix3x3.inl */, C75BB50617EE0B75004F0260 /* matrix4x4.h */, C75BB50717EE0B75004F0260 /* matrix4x4.inl */, C75BB50817EE0B75004F0260 /* mesh.h */, C75BB50917EE0B75004F0260 /* postprocess.h */, C75BB50A17EE0B75004F0260 /* ProgressHandler.hpp */, C75BB50B17EE0B75004F0260 /* quaternion.h */, C75BB50C17EE0B75004F0260 /* scene.h */, C75BB50D17EE0B75004F0260 /* texture.h */, C75BB50E17EE0B75004F0260 /* types.h */, C75BB50F17EE0B75004F0260 /* vector2.h */, C75BB51017EE0B75004F0260 /* vector2.inl */, C75BB51117EE0B75004F0260 /* vector3.h */, C75BB51217EE0B75004F0260 /* vector3.inl */, C75BB51317EE0B75004F0260 /* version.h */, C75BB4EA17EE0B64004F0260 /* ai_assert.h */, C75BB4EB17EE0B64004F0260 /* anim.h */, C75BB4EC17EE0B64004F0260 /* camera.h */, C75BB4ED17EE0B64004F0260 /* cexport.h */, C75BB4EE17EE0B64004F0260 /* cfileio.h */, C75BB4EF17EE0B64004F0260 /* cimport.h */, C75BB4F017EE0B64004F0260 /* color4.h */, C75BB4F117EE0B64004F0260 /* color4.inl */, C75BB4F217EE0B64004F0260 /* config.h */, C75BB4F317EE0B64004F0260 /* metadata.h */, C75BB4F417EE0B64004F0260 /* NullLogger.hpp */, C75BB4F517EE0B64004F0260 /* quaternion.inl */, 1B0E9AFC1279F006003108E7 /* Compiler */, ); path = include; sourceTree = ""; }; 1B0E9AFC1279F006003108E7 /* Compiler */ = { isa = PBXGroup; children = ( 1B0E9AFD1279F006003108E7 /* poppack1.h */, 1B0E9AFE1279F006003108E7 /* pushpack1.h */, ); name = Compiler; path = "/Users/vade/Asset Import/include/Compiler"; sourceTree = ""; }; 2A37F4AAFDCFA73011CA2CEA /* DisplayLinkAsyncMoviePlayer */ = { isa = PBXGroup; children = ( E1B74B1A0667B4A90069E3BA /* Models */, 2A37F4ABFDCFA73011CA2CEA /* Classes */, 1B0E9A8F1279ED43003108E7 /* libassimp.a */, 1B0E9AD21279EFCC003108E7 /* include */, 2A37F4AFFDCFA73011CA2CEA /* Other Sources */, 2A37F4B8FDCFA73011CA2CEA /* Resources */, 2A37F4C3FDCFA73011CA2CEA /* Frameworks */, 19C28FB0FE9D524F11CA2CBB /* Products */, 1B0E9B191279F107003108E7 /* libz.dylib */, ); name = DisplayLinkAsyncMoviePlayer; sourceTree = ""; }; 2A37F4ABFDCFA73011CA2CEA /* Classes */ = { isa = PBXGroup; children = ( 2A37F4AEFDCFA73011CA2CEA /* MyDocument.h */, 2A37F4ACFDCFA73011CA2CEA /* MyDocument.mm */, 1B0E9A931279EDCD003108E7 /* ModelLoaderHelperClasses.h */, 1B0E9A941279EDCD003108E7 /* ModelLoaderHelperClasses.mm */, ); name = Classes; sourceTree = ""; }; 2A37F4AFFDCFA73011CA2CEA /* Other Sources */ = { isa = PBXGroup; children = ( 32DBCF750370BD2300C91783 /* SimpleAssimpViewX_Prefix.pch */, 2A37F4B0FDCFA73011CA2CEA /* main.m */, ); name = "Other Sources"; sourceTree = ""; }; 2A37F4B8FDCFA73011CA2CEA /* Resources */ = { isa = PBXGroup; children = ( 2F7446A70DB6BCF400F9684A /* MainMenu.xib */, 2F7446A90DB6BCF400F9684A /* MyDocument.xib */, 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */, 8D15AC360486D014006FF6A4 /* SimpleAssimpViewX-Info.plist */, 089C165FFE840EACC02AAC07 /* InfoPlist.strings */, ); name = Resources; sourceTree = ""; }; 2A37F4C3FDCFA73011CA2CEA /* Frameworks */ = { isa = PBXGroup; children = ( 1058C7A6FEA54F5311CA2CBB /* Linked Frameworks */, 1058C7A8FEA54F5311CA2CBB /* Other Frameworks */, ); name = Frameworks; sourceTree = ""; }; E1B74B1A0667B4A90069E3BA /* Models */ = { isa = PBXGroup; children = ( 775BDEF0067A8BF0009058FE /* MyDocument.xcdatamodel */, ); name = Models; sourceTree = ""; }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ 8D15AC270486D014006FF6A4 /* SimpleAssimpViewX */ = { isa = PBXNativeTarget; buildConfigurationList = 26FC0AA50875C8B900E6366F /* Build configuration list for PBXNativeTarget "SimpleAssimpViewX" */; buildPhases = ( 8D15AC2B0486D014006FF6A4 /* Resources */, 8D15AC300486D014006FF6A4 /* Sources */, 8D15AC330486D014006FF6A4 /* Frameworks */, ); buildRules = ( ); dependencies = ( ); name = SimpleAssimpViewX; productInstallPath = "$(HOME)/Applications"; productName = DisplayLinkAsyncMoviePlayer; productReference = 8D15AC370486D014006FF6A4 /* SimpleAssimpViewX.app */; productType = "com.apple.product-type.application"; }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ 2A37F4A9FDCFA73011CA2CEA /* Project object */ = { isa = PBXProject; attributes = { }; buildConfigurationList = 26FC0AA90875C8B900E6366F /* Build configuration list for PBXProject "SimpleAssimpViewX" */; compatibilityVersion = "Xcode 3.1"; developmentRegion = English; hasScannedForEncodings = 1; knownRegions = ( en, ); mainGroup = 2A37F4AAFDCFA73011CA2CEA /* DisplayLinkAsyncMoviePlayer */; projectDirPath = ""; projectRoot = ""; targets = ( 8D15AC270486D014006FF6A4 /* SimpleAssimpViewX */, ); }; /* End PBXProject section */ /* Begin PBXResourcesBuildPhase section */ 8D15AC2B0486D014006FF6A4 /* Resources */ = { isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( 8D15AC2C0486D014006FF6A4 /* Credits.rtf in Resources */, 8D15AC2F0486D014006FF6A4 /* InfoPlist.strings in Resources */, 2F7446AB0DB6BCF400F9684A /* MainMenu.xib in Resources */, 2F7446AC0DB6BCF400F9684A /* MyDocument.xib in Resources */, C75BB4F617EE0B64004F0260 /* color4.inl in Resources */, C75BB4F717EE0B64004F0260 /* quaternion.inl in Resources */, C75BB51417EE0B75004F0260 /* material.inl in Resources */, C75BB51517EE0B75004F0260 /* matrix3x3.inl in Resources */, C75BB51617EE0B75004F0260 /* matrix4x4.inl in Resources */, C75BB51717EE0B75004F0260 /* vector2.inl in Resources */, C75BB51817EE0B75004F0260 /* vector3.inl in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ 8D15AC300486D014006FF6A4 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( 8D15AC310486D014006FF6A4 /* MyDocument.mm in Sources */, 8D15AC320486D014006FF6A4 /* main.m in Sources */, 775BDEF1067A8BF0009058FE /* MyDocument.xcdatamodel in Sources */, 1B0E9A951279EDCD003108E7 /* ModelLoaderHelperClasses.mm in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; /* End PBXSourcesBuildPhase section */ /* Begin PBXVariantGroup section */ 089C165FFE840EACC02AAC07 /* InfoPlist.strings */ = { isa = PBXVariantGroup; children = ( 089C1660FE840EACC02AAC07 /* English */, ); name = InfoPlist.strings; sourceTree = ""; }; 2A37F4B9FDCFA73011CA2CEA /* Credits.rtf */ = { isa = PBXVariantGroup; children = ( 2A37F4BAFDCFA73011CA2CEA /* English */, ); name = Credits.rtf; sourceTree = ""; }; 2F7446A70DB6BCF400F9684A /* MainMenu.xib */ = { isa = PBXVariantGroup; children = ( 2F7446A80DB6BCF400F9684A /* English */, ); name = MainMenu.xib; sourceTree = ""; }; 2F7446A90DB6BCF400F9684A /* MyDocument.xib */ = { isa = PBXVariantGroup; children = ( 2F7446AA0DB6BCF400F9684A /* English */, ); name = MyDocument.xib; sourceTree = ""; }; /* End PBXVariantGroup section */ /* Begin XCBuildConfiguration section */ 26FC0AA60875C8B900E6366F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_ENABLE_FIX_AND_CONTINUE = YES; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_MODEL_TUNING = G5; GCC_OPTIMIZATION_LEVEL = 0; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = SimpleAssimpViewX_Prefix.pch; HEADER_SEARCH_PATHS = "\"$(SRCROOT)\"/**"; INFOPLIST_FILE = "SimpleAssimpViewX-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)\"", ); ONLY_ACTIVE_ARCH = YES; PRODUCT_NAME = SimpleAssimpViewX; VALID_ARCHS = "x86_64 i386"; WRAPPER_EXTENSION = app; }; name = Debug; }; 26FC0AA70875C8B900E6366F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; FRAMEWORK_SEARCH_PATHS = "\"$(SRCROOT)\""; GCC_ENABLE_OBJC_EXCEPTIONS = YES; GCC_MODEL_TUNING = G5; GCC_PRECOMPILE_PREFIX_HEADER = YES; GCC_PREFIX_HEADER = SimpleAssimpViewX_Prefix.pch; HEADER_SEARCH_PATHS = "\"$(SRCROOT)\"/**"; INFOPLIST_FILE = "SimpleAssimpViewX-Info.plist"; INSTALL_PATH = "$(HOME)/Applications"; LIBRARY_SEARCH_PATHS = ( "$(inherited)", "\"$(SRCROOT)\"", ); ONLY_ACTIVE_ARCH = NO; PRODUCT_NAME = SimpleAssimpViewX; VALID_ARCHS = "x86_64 i386"; WRAPPER_EXTENSION = app; }; name = Release; }; 26FC0AAA0875C8B900E6366F /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; ONLY_ACTIVE_ARCH = YES; PREBINDING = NO; SDKROOT = macosx; }; name = Debug; }; 26FC0AAB0875C8B900E6366F /* Release */ = { isa = XCBuildConfiguration; buildSettings = { ARCHS = "$(ARCHS_STANDARD_32_64_BIT)"; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_WARN_ABOUT_RETURN_TYPE = YES; GCC_WARN_UNUSED_VARIABLE = YES; PREBINDING = NO; SDKROOT = macosx; }; name = Release; }; /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ 26FC0AA50875C8B900E6366F /* Build configuration list for PBXNativeTarget "SimpleAssimpViewX" */ = { isa = XCConfigurationList; buildConfigurations = ( 26FC0AA60875C8B900E6366F /* Debug */, 26FC0AA70875C8B900E6366F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 26FC0AA90875C8B900E6366F /* Build configuration list for PBXProject "SimpleAssimpViewX" */ = { isa = XCConfigurationList; buildConfigurations = ( 26FC0AAA0875C8B900E6366F /* Debug */, 26FC0AAB0875C8B900E6366F /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 2A37F4A9FDCFA73011CA2CEA /* Project object */; } assimp-4.1.0/samples/SimpleAssimpViewX/ModelLoaderHelperClasses.mm0000644002537200234200000000345113213503245025514 0ustar zmoelnigiemusers// // v002MeshHelper.m // v002 Model Importer // // Created by vade on 9/26/10. // Copyright 2010 __MyCompanyName__. All rights reserved. // #import "ModelLoaderHelperClasses.h" @implementation MeshHelper @synthesize vao; @synthesize displayList; @synthesize vertexBuffer; @synthesize indexBuffer; @synthesize normalBuffer; @synthesize numIndices; @synthesize textureID; @dynamic diffuseColor; @dynamic specularColor; @dynamic ambientColor; @dynamic emissiveColor; @synthesize opacity; @synthesize shininess; @synthesize specularStrength; @synthesize twoSided; - (id) init { if((self = [super init])) { diffuseColor = aiColor4D(0.8, 0.8, 0.8, 1.0); specularColor = aiColor4D(0.0f, 0.0f, 0.0f, 1.0f); ambientColor = aiColor4D(0.2f, 0.2f, 0.2f, 1.0f); emissiveColor = aiColor4D(0.0f, 0.0f, 0.0f, 1.0f); } return self; } - (void) setDiffuseColor:(aiColor4D*) color; { diffuseColor.r = color->r; diffuseColor.g = color->g; diffuseColor.b = color->b; diffuseColor.a = color->a; } - (aiColor4D*) diffuseColor { return &diffuseColor; } - (void) setSpecularColor:(aiColor4D*) color; { specularColor.r = color->r; specularColor.g = color->g; specularColor.b = color->b; specularColor.a = color->a; } - (aiColor4D*) specularColor { return &specularColor; } - (void) setAmbientColor:(aiColor4D*) color; { ambientColor.r = color->r; ambientColor.g = color->g; ambientColor.b = color->b; ambientColor.a = color->a; } - (aiColor4D*) ambientColor { return &ambientColor; } - (void) setEmissiveColor:(aiColor4D*) color; { emissiveColor.r = color->r; emissiveColor.g = color->g; emissiveColor.b = color->b; emissiveColor.a = color->a; } - (aiColor4D*) emissiveColor { return &emissiveColor; } @end assimp-4.1.0/samples/SimpleAssimpViewX/SimpleAssimpViewX_Prefix.pch0000644002537200234200000000040113213503245025706 0ustar zmoelnigiemusers// // Prefix header for all source files of the 'DisplayLinkAsyncMoviePlayer' target in the 'DisplayLinkAsyncMoviePlayer' project // #ifdef __OBJC__ #import #import #import #endif assimp-4.1.0/samples/SimpleAssimpViewX/MyDocument.mm0000644002537200234200000006525513213503245022745 0ustar zmoelnigiemusers// // MyDocument.m // DisplayLinkAsyncMoviePlayer // // Created by vade on 10/26/10. // Copyright __MyCompanyName__ 2010 . All rights reserved. // #import "cimport.h" #import "config.h" #import "MyDocument.h" #import #pragma mark - #pragma mark Helper Functions #define aisgl_min(x,y) (xx?y:x) static void color4_to_float4(const aiColor4D *c, float f[4]) { f[0] = c->r; f[1] = c->g; f[2] = c->b; f[3] = c->a; } static void set_float4(float f[4], float a, float b, float c, float d) { f[0] = a; f[1] = b; f[2] = c; f[3] = d; } #pragma mark - #pragma mark CVDisplayLink Callback static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink,const CVTimeStamp *inNow,const CVTimeStamp *inOutputTime,CVOptionFlags flagsIn,CVOptionFlags *flagsOut,void *displayLinkContext) { CVReturn error = [(MyDocument*) displayLinkContext displayLinkRenderCallback:inOutputTime]; return error; } #pragma mark - @implementation MyDocument @synthesize _view; - (id)init { self = [super init]; if (self != nil) { // initialization code } return self; } - (NSString *)windowNibName { return @"MyDocument"; } - (void)windowControllerDidLoadNib:(NSWindowController *)windowController { [super windowControllerDidLoadNib:windowController]; NSOpenGLPixelFormatAttribute attributes[] = { NSOpenGLPFADoubleBuffer, NSOpenGLPFAAccelerated, NSOpenGLPFADepthSize, 24, NSOpenGLPFAMultisample, NSOpenGLPFASampleBuffers, 2, (NSOpenGLPixelFormatAttribute) 0 }; _glPixelFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attributes]; if(!_glPixelFormat) NSLog(@"Error creating PF"); _glContext = [[NSOpenGLContext alloc] initWithFormat:_glPixelFormat shareContext:nil]; const GLint one = 1; [_glContext setValues:&one forParameter:NSOpenGLCPSwapInterval]; [_glContext setView:_view]; // Set up initial GL state. CGLContextObj cgl_ctx = (CGLContextObj)[_glContext CGLContextObj]; glEnable(GL_MULTISAMPLE); glClearColor(0.3, 0.3, 0.3, 0.3); // enable color tracking //glEnable(GL_COLOR_MATERIAL); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_DEPTH_TEST); glDepthFunc(GL_LEQUAL); glDepthMask(GL_TRUE); glEnable(GL_NORMALIZE); glEnable(GL_TEXTURE_2D); glShadeModel(GL_SMOOTH); glEnable(GL_LIGHTING); GLfloat global_ambient[] = { 0.5f, 0.5f, 0.5f, 1.0f }; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient); GLfloat specular[] = {1.0f, 1.0f, 1.0f, 1.0f}; glLightfv(GL_LIGHT0, GL_SPECULAR, specular); GLfloat diffuse[] = {1.0f, 1.0f, 1.0f, 1.0f}; glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); GLfloat ambient[] = {0.2, 0.2f, 0.2f, 0.2f}; glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); GLfloat position[] = { 1.0f, 1.0f, 1.0f, 1.0f}; glLightfv(GL_LIGHT0, GL_POSITION, position); glEnable(GL_LIGHT0); // This is the only client state that always has to be set. glEnableClientState(GL_VERTEX_ARRAY); // end GL State setup. // Display Link setup. CVReturn error = kCVReturnSuccess; error = CVDisplayLinkCreateWithActiveCGDisplays(&_displayLink); if(error == kCVReturnError) NSLog(@"Error Creating DisplayLink"); error = CVDisplayLinkSetOutputCallback(_displayLink,MyDisplayLinkCallback, self); if(error == kCVReturnError) NSLog(@"Error Setting DisplayLink Callback"); error = CVDisplayLinkStart(_displayLink); if(error == kCVReturnError) NSLog(@"Error Starting DisplayLink"); NSOpenPanel* openPanel = [NSOpenPanel openPanel]; [openPanel beginSheetModalForWindow:[_view window] completionHandler:^(NSInteger result) { if (result == NSOKButton) { [openPanel orderOut:self]; // close panel before we might present an error if([[NSFileManager defaultManager] fileExistsAtPath:[openPanel filename]]) { // Load our new path. // only ever give us triangles. aiPropertyStore* props = aiCreatePropertyStore(); aiSetImportPropertyInteger(props, AI_CONFIG_PP_SBP_REMOVE, aiPrimitiveType_LINE | aiPrimitiveType_POINT ); NSUInteger aiPostProccesFlags; switch (2) { case 0: aiPostProccesFlags = aiProcessPreset_TargetRealtime_Fast; break; case 1: aiPostProccesFlags = aiProcessPreset_TargetRealtime_Quality; break; case 2: aiPostProccesFlags = aiProcessPreset_TargetRealtime_MaxQuality; break; default: aiPostProccesFlags = aiProcessPreset_TargetRealtime_MaxQuality; break; } // aiProcess_FlipUVs is needed for VAO / VBOs, not sure why. _scene = (aiScene*) aiImportFileExWithProperties([[openPanel filename] cStringUsingEncoding:[NSString defaultCStringEncoding]], aiPostProccesFlags | aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_PreTransformVertices | 0, NULL, props); aiReleasePropertyStore(props); if (_scene) { textureDictionary = [[NSMutableDictionary alloc] initWithCapacity:5]; // Why do I need to cast this !? CGLContextObj cgl_ctx = (CGLContextObj)[_glContext CGLContextObj]; CGLLockContext(cgl_ctx); [self loadTexturesInContext:cgl_ctx withModelPath:[[openPanel filename] stringByStandardizingPath]]; //NSDictionary* userInfo = [NSDictionary dictionaryWithObjectsAndKeys:[NSValue valueWithPointer:cgl_ctx], @"context", [self.inputModelPath stringByStandardizingPath], @"path", nil ]; //[self performSelectorInBackground:@selector(loadTexturesInBackground:) withObject:userInfo]; [self getBoundingBoxWithMinVector:&scene_min maxVectr:&scene_max]; scene_center.x = (scene_min.x + scene_max.x) / 2.0f; scene_center.y = (scene_min.y + scene_max.y) / 2.0f; scene_center.z = (scene_min.z + scene_max.z) / 2.0f; // optional normalized scaling normalizedScale = scene_max.x-scene_min.x; normalizedScale = aisgl_max(scene_max.y - scene_min.y,normalizedScale); normalizedScale = aisgl_max(scene_max.z - scene_min.z,normalizedScale); normalizedScale = 1.f / normalizedScale; if(_scene->HasAnimations()) NSLog(@"scene has animations"); [self createGLResourcesInContext:cgl_ctx]; CGLUnlockContext(cgl_ctx); } } } }]; // end block handler } - (void) close { CVDisplayLinkStop(_displayLink); CVDisplayLinkRelease(_displayLink); if(_scene) { aiReleaseImport(_scene); _scene = NULL; CGLContextObj cgl_ctx = (CGLContextObj)[_glContext CGLContextObj]; glDeleteTextures([textureDictionary count], textureIds); [textureDictionary release]; textureDictionary = nil; free(textureIds); textureIds = NULL; [self deleteGLResourcesInContext:cgl_ctx]; } [_glContext release]; _glContext = nil; [_glPixelFormat release]; _glPixelFormat = nil; [super close]; } - (CVReturn)displayLinkRenderCallback:(const CVTimeStamp *)timeStamp { CVReturn rv = kCVReturnError; NSAutoreleasePool *pool; pool = [[NSAutoreleasePool alloc] init]; { [self render]; rv = kCVReturnSuccess; } [pool release]; return rv; } - (void) render { CGLContextObj cgl_ctx = (CGLContextObj)[_glContext CGLContextObj]; CGLLockContext(cgl_ctx); [_glContext update]; glMatrixMode(GL_PROJECTION); glLoadIdentity(); glViewport(0, 0, _view.frame.size.width, _view.frame.size.height); GLfloat aspect = _view.frame.size.height/_view.frame.size.width; glOrtho(-1, 1, - (aspect), aspect, -10, 10); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glTranslated(0.0, 0.0, 1.0); // Draw our GL model. if(_scene) { glScaled(normalizedScale , normalizedScale, normalizedScale); // center the model glTranslated( -scene_center.x, -scene_center.y, -scene_center.z); glScaled(2.0, 2.0, 2.0); static float i = 0; i+=0.5; glRotated(i, 0, 1, 0); [self drawMeshesInContext:cgl_ctx]; } CGLUnlockContext(cgl_ctx); CGLFlushDrawable(cgl_ctx); } #pragma mark - #pragma mark Loading // Inspired by LoadAsset() & CreateAssetData() from AssimpView D3D project - (void) createGLResourcesInContext:(CGLContextObj)cgl_ctx { // create new mesh helpers for each mesh, will populate their data later. modelMeshes = [[NSMutableArray alloc] initWithCapacity:_scene->mNumMeshes]; // create OpenGL buffers and populate them based on each meshes pertinant info. for (unsigned int i = 0; i < _scene->mNumMeshes; ++i) { NSLog(@"%u", i); // current mesh we are introspecting const aiMesh* mesh = _scene->mMeshes[i]; // the current meshHelper we will be populating data into. MeshHelper* meshHelper = [[MeshHelper alloc] init]; // Handle material info aiMaterial* mtl = _scene->mMaterials[mesh->mMaterialIndex]; // Textures int texIndex = 0; aiString texPath; if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath)) { NSString* textureKey = [NSString stringWithCString:texPath.data encoding:[NSString defaultCStringEncoding]]; //bind texture NSNumber* textureNumber = (NSNumber*)[textureDictionary valueForKey:textureKey]; //NSLog(@"applyMaterialInContext: have texture %i", [textureNumber unsignedIntValue]); meshHelper.textureID = [textureNumber unsignedIntValue]; } else meshHelper.textureID = 0; // Colors aiColor4D dcolor = aiColor4D(0.8f, 0.8f, 0.8f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &dcolor)) [meshHelper setDiffuseColor:&dcolor]; aiColor4D scolor = aiColor4D(0.0f, 0.0f, 0.0f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &scolor)) [meshHelper setSpecularColor:&scolor]; aiColor4D acolor = aiColor4D(0.2f, 0.2f, 0.2f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &acolor)) [meshHelper setAmbientColor:&acolor]; aiColor4D ecolor = aiColor4D(0.0f, 0.0f, 0.0f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &ecolor)) [meshHelper setEmissiveColor:&ecolor]; // Culling unsigned int max = 1; int two_sided; if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided) [meshHelper setTwoSided:YES]; else [meshHelper setTwoSided:NO]; // Create a VBO for our vertices GLuint vhandle; glGenBuffers(1, &vhandle); glBindBuffer(GL_ARRAY_BUFFER, vhandle); glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex) * mesh->mNumVertices, NULL, GL_STATIC_DRAW); // populate vertices Vertex* verts = (Vertex*)glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); for (unsigned int x = 0; x < mesh->mNumVertices; ++x) { verts->vPosition = mesh->mVertices[x]; if (NULL == mesh->mNormals) verts->vNormal = aiVector3D(0.0f,0.0f,0.0f); else verts->vNormal = mesh->mNormals[x]; if (NULL == mesh->mTangents) { verts->vTangent = aiVector3D(0.0f,0.0f,0.0f); verts->vBitangent = aiVector3D(0.0f,0.0f,0.0f); } else { verts->vTangent = mesh->mTangents[x]; verts->vBitangent = mesh->mBitangents[x]; } if (mesh->HasVertexColors(0)) { verts->dColorDiffuse = mesh->mColors[0][x]; } else verts->dColorDiffuse = aiColor4D(1.0, 1.0, 1.0, 1.0); // This varies slightly form Assimp View, we support the 3rd texture component. if (mesh->HasTextureCoords(0)) verts->vTextureUV = mesh->mTextureCoords[0][x]; else verts->vTextureUV = aiVector3D(0.5f,0.5f, 0.0f); if (mesh->HasTextureCoords(1)) verts->vTextureUV2 = mesh->mTextureCoords[1][x]; else verts->vTextureUV2 = aiVector3D(0.5f,0.5f, 0.0f); // TODO: handle Bone indices and weights /* if( mesh->HasBones()) { unsigned char boneIndices[4] = { 0, 0, 0, 0 }; unsigned char boneWeights[4] = { 0, 0, 0, 0 }; ai_assert( weightsPerVertex[x].size() <= 4); for( unsigned int a = 0; a < weightsPerVertex[x].size(); a++) { boneIndices[a] = weightsPerVertex[x][a].mVertexId; boneWeights[a] = (unsigned char) (weightsPerVertex[x][a].mWeight * 255.0f); } memcpy( verts->mBoneIndices, boneIndices, sizeof( boneIndices)); memcpy( verts->mBoneWeights, boneWeights, sizeof( boneWeights)); } else */ { memset( verts->mBoneIndices, 0, sizeof( verts->mBoneIndices)); memset( verts->mBoneWeights, 0, sizeof( verts->mBoneWeights)); } ++verts; } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); //invalidates verts glBindBuffer(GL_ARRAY_BUFFER, 0); // set the mesh vertex buffer handle to our new vertex buffer. meshHelper.vertexBuffer = vhandle; // Create Index Buffer // populate the index buffer. NSUInteger nidx; switch (mesh->mPrimitiveTypes) { case aiPrimitiveType_POINT: nidx = 1;break; case aiPrimitiveType_LINE: nidx = 2;break; case aiPrimitiveType_TRIANGLE: nidx = 3;break; default: assert(false); } // create the index buffer GLuint ihandle; glGenBuffers(1, &ihandle); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ihandle); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * mesh->mNumFaces * nidx, NULL, GL_STATIC_DRAW); unsigned int* indices = (unsigned int*)glMapBuffer(GL_ELEMENT_ARRAY_BUFFER, GL_WRITE_ONLY_ARB); // now fill the index buffer for (unsigned int x = 0; x < mesh->mNumFaces; ++x) { for (unsigned int a = 0; a < nidx; ++a) { // if(mesh->mFaces[x].mNumIndices != 3) // NSLog(@"whoa don't have 3 indices..."); *indices++ = mesh->mFaces[x].mIndices[a]; } } glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // set the mesh index buffer handle to our new index buffer. meshHelper.indexBuffer = ihandle; meshHelper.numIndices = mesh->mNumFaces * nidx; // create the normal buffer. Assimp View creates a second normal buffer. Unsure why. Using only the interleaved normals for now. // This is here for reference. /* GLuint nhandle; glGenBuffers(1, &nhandle); glBindBuffer(GL_ARRAY_BUFFER, nhandle); glBufferData(GL_ARRAY_BUFFER, sizeof(aiVector3D)* mesh->mNumVertices, NULL, GL_STATIC_DRAW); // populate normals aiVector3D* normals = (aiVector3D*)glMapBuffer(GL_ARRAY_BUFFER_ARB, GL_WRITE_ONLY_ARB); for (unsigned int x = 0; x < mesh->mNumVertices; ++x) { aiVector3D vNormal = mesh->mNormals[x]; *normals = vNormal; ++normals; } glUnmapBufferARB(GL_ARRAY_BUFFER_ARB); //invalidates verts glBindBuffer(GL_ARRAY_BUFFER, 0); meshHelper.normalBuffer = nhandle; */ // Create VAO and populate it GLuint vaoHandle; glGenVertexArraysAPPLE(1, &vaoHandle); glBindVertexArrayAPPLE(vaoHandle); glBindBuffer(GL_ARRAY_BUFFER, meshHelper.vertexBuffer); glEnableClientState(GL_NORMAL_ARRAY); glNormalPointer(GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(12)); glEnableClientState(GL_COLOR_ARRAY); glColorPointer(4, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(24)); glEnableClientState(GL_TEXTURE_COORD_ARRAY); glTexCoordPointer(3, GL_FLOAT, sizeof(Vertex), BUFFER_OFFSET(64)); //TODO: handle second texture // VertexPointer ought to come last, apparently this is some optimization, since if its set once, first, it gets fiddled with every time something else is update. glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3, GL_FLOAT, sizeof(Vertex), 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, meshHelper.indexBuffer); glBindVertexArrayAPPLE(0); // save the VAO handle into our mesh helper meshHelper.vao = vaoHandle; // Create the display list GLuint list = glGenLists(1); glNewList(list, GL_COMPILE); float dc[4]; float sc[4]; float ac[4]; float emc[4]; // Material colors and properties color4_to_float4([meshHelper diffuseColor], dc); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, dc); color4_to_float4([meshHelper specularColor], sc); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, sc); color4_to_float4([meshHelper ambientColor], ac); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ac); color4_to_float4(meshHelper.emissiveColor, emc); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emc); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); // Culling if(meshHelper.twoSided) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); // Texture Binding glBindTexture(GL_TEXTURE_2D, meshHelper.textureID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); // This binds the whole VAO, inheriting all the buffer and client state. Weeee glBindVertexArrayAPPLE(meshHelper.vao); glDrawElements(GL_TRIANGLES, meshHelper.numIndices, GL_UNSIGNED_INT, 0); glEndList(); meshHelper.displayList = list; // Whew, done. Save all of this shit. [modelMeshes addObject:meshHelper]; [meshHelper release]; } } - (void) deleteGLResourcesInContext:(CGLContextObj)cgl_ctx { for(MeshHelper* helper in modelMeshes) { const GLuint indexBuffer = helper.indexBuffer; const GLuint vertexBuffer = helper.vertexBuffer; const GLuint normalBuffer = helper.normalBuffer; const GLuint vaoHandle = helper.vao; const GLuint dlist = helper.displayList; glDeleteBuffers(1, &vertexBuffer); glDeleteBuffers(1, &indexBuffer); glDeleteBuffers(1, &normalBuffer); glDeleteVertexArraysAPPLE(1, &vaoHandle); glDeleteLists(1, dlist); helper.indexBuffer = 0; helper.vertexBuffer = 0; helper.normalBuffer = 0; helper.vao = 0; helper.displayList = 0; } [modelMeshes release]; modelMeshes = nil; } - (void) drawMeshesInContext:(CGLContextObj)cgl_ctx { for(MeshHelper* helper in modelMeshes) { // Set up material state. glCallList(helper.displayList); } } - (void) loadTexturesInContext:(CGLContextObj)cgl_ctx withModelPath:(NSString*) modelPath { if (_scene->HasTextures()) { NSLog(@"Support for meshes with embedded textures is not implemented"); return; } /* getTexture Filenames and Numb of Textures */ for (unsigned int m = 0; m < _scene->mNumMaterials; m++) { int texIndex = 0; aiReturn texFound = AI_SUCCESS; aiString path; // filename // TODO: handle other aiTextureTypes while (texFound == AI_SUCCESS) { texFound = _scene->mMaterials[m]->GetTexture(aiTextureType_DIFFUSE, texIndex, &path); NSString* texturePath = [NSString stringWithCString:path.data encoding:[NSString defaultCStringEncoding]]; // add our path to the texture and the index to our texture dictionary. [textureDictionary setValue:[NSNumber numberWithUnsignedInt:texIndex] forKey:texturePath]; texIndex++; } } textureIds = (GLuint*) malloc(sizeof(GLuint) * [textureDictionary count]); //new GLuint[ [textureDictionary count] ]; glGenTextures([textureDictionary count], textureIds); NSLog(@"textureDictionary: %@", textureDictionary); // create our textures, populate them, and alter our textureID value for the specific textureID we create. // so we can modify while we enumerate... NSDictionary *textureCopy = [textureDictionary copy]; // GCD attempt. //dispatch_sync(_queue, ^{ int i = 0; for(NSString* texturePath in textureCopy) { NSString* fullTexturePath = [[[modelPath stringByDeletingLastPathComponent] stringByAppendingPathComponent:[texturePath stringByStandardizingPath]] stringByStandardizingPath]; NSLog(@"texturePath: %@", fullTexturePath); NSImage* textureImage = [[NSImage alloc] initWithContentsOfFile:fullTexturePath]; if(textureImage) { //NSLog(@"Have Texture Image"); NSBitmapImageRep* bitmap = [NSBitmapImageRep alloc]; [textureImage lockFocus]; [bitmap initWithFocusedViewRect:NSMakeRect(0, 0, textureImage.size.width, textureImage.size.height)]; [textureImage unlockFocus]; glActiveTexture(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, textureIds[i]); //glPixelStorei(GL_UNPACK_ROW_LENGTH, [bitmap pixelsWide]); //glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // generate mip maps glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // draw into our bitmap int samplesPerPixel = [bitmap samplesPerPixel]; if(![bitmap isPlanar] && (samplesPerPixel == 3 || samplesPerPixel == 4)) { glTexImage2D(GL_TEXTURE_2D, 0, //samplesPerPixel == 4 ? GL_COMPRESSED_RGBA_S3TC_DXT3_EXT : GL_COMPRESSED_RGB_S3TC_DXT1_EXT, samplesPerPixel == 4 ? GL_RGBA8 : GL_RGB8, [bitmap pixelsWide], [bitmap pixelsHigh], 0, samplesPerPixel == 4 ? GL_RGBA : GL_RGB, GL_UNSIGNED_BYTE, [bitmap bitmapData]); } // update our dictionary to contain the proper textureID value (from out array of generated IDs) [textureDictionary setValue:[NSNumber numberWithUnsignedInt:textureIds[i]] forKey:texturePath]; [bitmap release]; } else { [textureDictionary removeObjectForKey:texturePath]; NSLog(@"Could not Load Texture: %@, removing reference to it.", fullTexturePath); } [textureImage release]; i++; } //}); [textureCopy release]; } - (void) getBoundingBoxWithMinVector:(aiVector3D*) min maxVectr:(aiVector3D*) max { aiMatrix4x4 trafo; aiIdentityMatrix4(&trafo); min->x = min->y = min->z = 1e10f; max->x = max->y = max->z = -1e10f; [self getBoundingBoxForNode:_scene->mRootNode minVector:min maxVector:max matrix:&trafo]; } - (void) getBoundingBoxForNode:(const aiNode*)nd minVector:(aiVector3D*) min maxVector:(aiVector3D*) max matrix:(aiMatrix4x4*) trafo { aiMatrix4x4 prev; unsigned int n = 0, t; prev = *trafo; aiMultiplyMatrix4(trafo,&nd->mTransformation); for (; n < nd->mNumMeshes; ++n) { const aiMesh* mesh = _scene->mMeshes[nd->mMeshes[n]]; for (t = 0; t < mesh->mNumVertices; ++t) { aiVector3D tmp = mesh->mVertices[t]; aiTransformVecByMatrix4(&tmp,trafo); min->x = aisgl_min(min->x,tmp.x); min->y = aisgl_min(min->y,tmp.y); min->z = aisgl_min(min->z,tmp.z); max->x = aisgl_max(max->x,tmp.x); max->y = aisgl_max(max->y,tmp.y); max->z = aisgl_max(max->z,tmp.z); } } for (n = 0; n < nd->mNumChildren; ++n) { [self getBoundingBoxForNode:nd->mChildren[n] minVector:min maxVector:max matrix:trafo]; } *trafo = prev; } @end assimp-4.1.0/samples/SimpleAssimpViewX/MyDocument.xcdatamodel/0000755002537200234200000000000013213503245024661 5ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleAssimpViewX/MyDocument.xcdatamodel/elements0000644002537200234200000000225713213503245026426 0ustar zmoelnigiemusersbplist00 Y$archiverX$versionT$topX$objects_NSKeyedArchiver Troot 3459@BDFHKR TY]U$null __xd_rootPackage\_xd_comments__xd_modelManager__configurationsByNameV$class]_xd_modelName_untitled.xcdatamodel !"#$%&'()* ))+),-./-012_XDBucketForDataTypeswasEncodedU_name__xd_owningModel_XDBucketForPackageswasEncoded_XDBucketForClasseswasEncoded[_visibility_XDBucketForInterfaceswasEncoded_XDBucketForClassesstorageV_owner_XDBucketForInterfacesstorage_XDBucketForDataTypesstorage__uniqueElementID_XDBucketForPackagesstorageX_factory PSYES678ZNS.objects:;<=X$classesZ$classname=>?^NSMutableArrayWNSArrayXNSObject6A86C86E8G :;IJJ?_XDUMLDefaultElementFactory:;LMMNOPQ?^XDModelPackage_XDUMLPackageImp_XDUMLNamespaceImp_XDUMLNamedElementImp_XDUMLElementImp6S86UVWXWNS.keys:;Z[[\?_NSMutableDictionary\NSDictionary:;^__`?YXDPMModelWXDModel$)2DILQSio|@FXx%8U^`bdfhjlnprsw|0D[mrszaassimp-4.1.0/samples/SimpleAssimpViewX/MyDocument.xcdatamodel/layout0000644002537200234200000000073313213503245026124 0ustar zmoelnigiemusersbplist00 Y$archiverX$versionT$topX$objects_NSKeyedArchiver Troot $ +.U$null ZNS.objectsWNS.keysV$class XmappingsWstorage  !X$classesZ$classname!"#_NSMutableDictionary\NSDictionaryXNSObject%&'()*(ZXDDelegate_XDDiagramController\XDDataSource ,--#_XDDiagramStorage/""#$)2DILQS_elw%2468=@SX0[assimp-4.1.0/samples/SimpleAssimpViewX/include/0000755002537200234200000000000013213503245021734 5ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleAssimpViewX/include/copy_assimp_headers_here.txt0000644002537200234200000000000013213503245027507 0ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleAssimpViewX/ModelLoaderHelperClasses.h0000644002537200234200000000511313213503245025327 0ustar zmoelnigiemusers// // v002MeshHelper.h // v002 Model Importer // // Created by vade on 9/26/10. // Copyright 2010 __MyCompanyName__. All rights reserved. // #import #import #import "color4.h" #import "vector3.h" #import "vector2.h" #import "matrix4x4.h" /* workflow: 1) create a new scene wrapper 2) populate an array of of meshHelpers for each mesh in the original scene 3) (eventually) create an animator instance 4) scale the asset (needed?) 5) create the asset data (GL resources, textures etc) 5a) for each mesh create a material instance 5b) create a static vertex buffer 5c) create index buffer 5d) populate the index buffer 5e) (eventually) gather weights */ #define BUFFER_OFFSET(i) ((char *)NULL + (i)) struct Vertex { aiVector3D vPosition; aiVector3D vNormal; aiColor4D dColorDiffuse; aiVector3D vTangent; aiVector3D vBitangent; aiVector3D vTextureUV; aiVector3D vTextureUV2; unsigned char mBoneIndices[4]; unsigned char mBoneWeights[4]; // last Weight not used, calculated inside the vertex shader }; // Helper Class to store GPU related resources from a given aiMesh // Modeled after AssimpView asset helper @interface MeshHelper : NSObject { // Display list ID, this one shots *all drawing* of the mesh. Only ever use this to draw. Booya. GLuint displayList; // VAO that encapsulates all VBO drawing state GLuint vao; // VBOs GLuint vertexBuffer; GLuint indexBuffer; GLuint normalBuffer; GLuint numIndices; // texture GLuint textureID; // Material aiColor4D diffuseColor; aiColor4D specularColor; aiColor4D ambientColor; aiColor4D emissiveColor; GLfloat opacity; GLfloat shininess; GLfloat specularStrength; BOOL twoSided; } @property (readwrite, assign) GLuint vao; @property (readwrite, assign) GLuint displayList; @property (readwrite, assign) GLuint vertexBuffer; @property (readwrite, assign) GLuint indexBuffer; @property (readwrite, assign) GLuint normalBuffer; @property (readwrite, assign) GLuint numIndices; @property (readwrite, assign) GLuint textureID; @property (readwrite, assign) aiColor4D* diffuseColor; @property (readwrite, assign) aiColor4D* specularColor; @property (readwrite, assign) aiColor4D* ambientColor; @property (readwrite, assign) aiColor4D* emissiveColor; @property (readwrite, assign) GLfloat opacity; @property (readwrite, assign) GLfloat shininess; @property (readwrite, assign) GLfloat specularStrength; @property (readwrite, assign) BOOL twoSided; @end assimp-4.1.0/samples/SimpleAssimpViewX/English.lproj/0000755002537200234200000000000013213503245023027 5ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleAssimpViewX/English.lproj/InfoPlist.strings0000644002537200234200000000013213213503245026345 0ustar zmoelnigiemusers/* Localized versions of Info.plist keys */ assimp-4.1.0/samples/SimpleAssimpViewX/English.lproj/MainMenu.xib0000644002537200234200000041446513213503245025262 0ustar zmoelnigiemusers 1060 10F569 788 1038.29 461.00 com.apple.InterfaceBuilder.CocoaPlugin 788 YES YES com.apple.InterfaceBuilder.CocoaPlugin YES YES YES YES NSApplication FirstResponder NSApplication MainMenu YES SimpleAssimpViewX 1048576 2147483647 NSImage NSMenuCheckmark NSImage NSMenuMixedState submenuAction: SimpleAssimpViewX YES About SimpleAssimpViewX 2147483647 YES YES 1048576 2147483647 Preferences… , 1048576 2147483647 YES YES 1048576 2147483647 Services 1048576 2147483647 submenuAction: Services YES _NSServicesMenu YES YES 1048576 2147483647 Hide SimpleAssimpViewX h 1048576 2147483647 Hide Others h 1572864 2147483647 Show All 1048576 2147483647 YES YES 1048576 2147483647 Quit SimpleAssimpViewX q 1048576 2147483647 _NSAppleMenu File 1048576 2147483647 submenuAction: File YES New n 1048576 2147483647 Open… o 1048576 2147483647 Open Recent 1048576 2147483647 submenuAction: Open Recent YES Clear Menu 1048576 2147483647 _NSRecentDocumentsMenu YES YES 1048576 2147483647 Close w 1048576 2147483647 Save s 1048576 2147483647 Save As… S 1048576 2147483647 Revert to Saved 2147483647 YES YES 1048576 2147483647 Page Setup… P 1048576 2147483647 Print… p 1048576 2147483647 Edit 2147483647 submenuAction: Edit YES Undo z 1048576 2147483647 Redo Z 1048576 2147483647 YES YES 2147483647 Cut x 1048576 2147483647 Copy c 1048576 2147483647 Paste v 1048576 2147483647 Paste and Match Style V 1572864 2147483647 Delete 2147483647 Select All a 1048576 2147483647 YES YES 2147483647 Find 2147483647 submenuAction: Find YES Find… f 1048576 2147483647 1 Find Next g 1048576 2147483647 2 Find Previous G 1048576 2147483647 3 Use Selection for Find e 1048576 2147483647 7 Jump to Selection j 1048576 2147483647 Spelling and Grammar 2147483647 submenuAction: Spelling YES Show Spelling and Grammar : 1048576 2147483647 Check Document Now ; 1048576 2147483647 YES YES 2147483647 Check Spelling While Typing 2147483647 Check Grammar With Spelling 2147483647 Correct Spelling Automatically 2147483647 Substitutions 2147483647 submenuAction: Substitutions YES Show Substitutions 2147483647 YES YES 2147483647 Smart Copy/Paste 2147483647 Smart Quotes 2147483647 Smart Dashes 2147483647 Smart Links 2147483647 Text Replacement 2147483647 Transformations 2147483647 submenuAction: Transformations YES Make Upper Case 2147483647 Make Lower Case 2147483647 Capitalize 2147483647 Speech 2147483647 submenuAction: Speech YES Start Speaking 2147483647 Stop Speaking 2147483647 Format 2147483647 submenuAction: Format YES Font 2147483647 submenuAction: Font YES Show Fonts t 1048576 2147483647 Bold b 1048576 2147483647 2 Italic i 1048576 2147483647 1 Underline u 1048576 2147483647 YES YES 2147483647 Bigger + 1048576 2147483647 3 Smaller - 1048576 2147483647 4 YES YES 2147483647 Kern 2147483647 submenuAction: Kern YES Use Default 2147483647 Use None 2147483647 Tighten 2147483647 Loosen 2147483647 Ligature 2147483647 submenuAction: Ligature YES Use Default 2147483647 Use None 2147483647 Use All 2147483647 Baseline 2147483647 submenuAction: Baseline YES Use Default 2147483647 Superscript 2147483647 Subscript 2147483647 Raise 2147483647 Lower 2147483647 YES YES 2147483647 Show Colors C 1048576 2147483647 YES YES 2147483647 Copy Style c 1572864 2147483647 Paste Style v 1572864 2147483647 _NSFontMenu Text 2147483647 submenuAction: Text YES Align Left { 1048576 2147483647 Center | 1048576 2147483647 Justify 2147483647 Align Right } 1048576 2147483647 YES YES 2147483647 Show Ruler 2147483647 Copy Ruler c 1310720 2147483647 Paste Ruler v 1310720 2147483647 View 1048576 2147483647 submenuAction: View YES Show Toolbar t 1572864 2147483647 Customize Toolbar… 1048576 2147483647 Window 1048576 2147483647 submenuAction: Window YES Minimize m 1048576 2147483647 Zoom 1048576 2147483647 YES YES 1048576 2147483647 Bring All to Front 1048576 2147483647 _NSWindowsMenu Help 2147483647 submenuAction: Help YES SimpleAssimpViewX Help ? 1048576 2147483647 _NSHelpMenu _NSMainMenu NSFontManager YES runPageLayout: 87 clearRecentDocuments: 127 terminate: 139 orderFrontStandardAboutPanel: 142 hideOtherApplications: 146 hide: 152 unhideAllApplications: 153 performClose: 193 newDocument: 194 openDocument: 195 saveDocument: 196 saveDocumentAs: 197 revertDocumentToSaved: 198 printDocument: 200 performZoom: 245 performMiniaturize: 246 arrangeInFront: 247 runToolbarCustomizationPalette: 336 toggleToolbarShown: 337 addFontTrait: 386 addFontTrait: 387 modifyFont: 388 orderFrontFontPanel: 389 modifyFont: 390 raiseBaseline: 391 lowerBaseline: 392 copyFont: 393 subscript: 394 superscript: 395 tightenKerning: 396 underline: 397 orderFrontColorPanel: 398 useAllLigatures: 399 loosenKerning: 400 pasteFont: 401 unscript: 402 useStandardKerning: 403 useStandardLigatures: 404 turnOffLigatures: 405 turnOffKerning: 406 alignLeft: 407 alignJustified: 408 copyRuler: 409 alignCenter: 410 toggleRuler: 411 alignRight: 412 pasteRuler: 413 capitalizeWord: 482 cut: 483 paste: 484 toggleSmartInsertDelete: 485 toggleAutomaticQuoteSubstitution: 486 redo: 487 toggleAutomaticDashSubstitution: 488 toggleContinuousSpellChecking: 489 undo: 490 toggleGrammarChecking: 491 startSpeaking: 492 showGuessPanel: 493 checkSpelling: 494 pasteAsPlainText: 495 copy: 496 delete: 497 lowercaseWord: 498 selectAll: 499 stopSpeaking: 500 orderFrontSubstitutionsPanel: 501 toggleAutomaticTextReplacement: 502 toggleAutomaticLinkDetection: 503 toggleAutomaticSpellingCorrection: 504 uppercaseWord: 505 performFindPanelAction: 506 performFindPanelAction: 507 performFindPanelAction: 508 centerSelectionInVisibleArea: 509 performFindPanelAction: 510 showHelp: 514 YES 0 -2 File's Owner -1 First Responder 29 YES MainMenu 56 YES 57 YES 58 129 131 YES 130 134 136 143 144 145 149 150 202 83 YES 81 YES 72 73 74 75 77 78 79 80 82 112 124 YES 125 YES 126 239 YES 240 YES 241 242 243 244 330 YES 331 YES 334 335 -3 Application 340 YES 341 YES 342 YES 343 YES 344 YES 345 346 347 348 349 350 351 352 353 YES 354 355 356 357 358 359 360 361 362 YES 363 YES 364 YES 365 366 367 368 369 370 YES 371 372 373 374 375 376 YES 377 378 379 380 YES 381 382 383 384 385 437 YES 438 YES 439 440 441 442 443 444 445 446 447 448 449 YES 450 YES 451 YES 452 YES 453 YES 454 YES 455 456 457 YES 458 459 460 461 YES 462 463 464 465 466 467 468 469 YES 470 471 472 473 474 475 476 YES 477 478 479 480 481 511 YES 512 YES 513 YES YES -3.IBPluginDependency 112.IBPluginDependency 112.ImportedFromIB2 124.IBPluginDependency 124.ImportedFromIB2 125.IBPluginDependency 125.ImportedFromIB2 126.IBPluginDependency 126.ImportedFromIB2 129.IBPluginDependency 129.ImportedFromIB2 130.IBEditorWindowLastContentRect 130.IBPluginDependency 130.ImportedFromIB2 131.IBPluginDependency 131.ImportedFromIB2 134.IBPluginDependency 134.ImportedFromIB2 136.IBPluginDependency 136.ImportedFromIB2 143.IBPluginDependency 143.ImportedFromIB2 144.IBPluginDependency 144.ImportedFromIB2 145.IBPluginDependency 145.ImportedFromIB2 149.IBPluginDependency 149.ImportedFromIB2 150.IBPluginDependency 150.ImportedFromIB2 202.IBPluginDependency 202.ImportedFromIB2 239.IBPluginDependency 239.ImportedFromIB2 240.IBEditorWindowLastContentRect 240.IBPluginDependency 240.ImportedFromIB2 241.IBPluginDependency 241.ImportedFromIB2 242.IBPluginDependency 242.ImportedFromIB2 243.IBPluginDependency 243.ImportedFromIB2 244.IBPluginDependency 244.ImportedFromIB2 29.IBEditorWindowLastContentRect 29.IBPluginDependency 29.ImportedFromIB2 330.IBPluginDependency 330.ImportedFromIB2 331.IBEditorWindowLastContentRect 331.IBPluginDependency 331.ImportedFromIB2 334.IBPluginDependency 334.ImportedFromIB2 335.IBPluginDependency 335.ImportedFromIB2 340.IBPluginDependency 341.IBPluginDependency 342.IBPluginDependency 343.IBPluginDependency 344.IBPluginDependency 345.IBPluginDependency 346.IBPluginDependency 347.IBPluginDependency 348.IBPluginDependency 349.IBPluginDependency 350.IBPluginDependency 351.IBPluginDependency 352.IBPluginDependency 353.IBPluginDependency 354.IBPluginDependency 355.IBPluginDependency 356.IBPluginDependency 357.IBPluginDependency 358.IBPluginDependency 359.IBPluginDependency 360.IBPluginDependency 361.IBPluginDependency 362.IBPluginDependency 363.IBPluginDependency 364.IBPluginDependency 365.IBPluginDependency 366.IBPluginDependency 367.IBPluginDependency 368.IBPluginDependency 369.IBPluginDependency 370.IBPluginDependency 371.IBPluginDependency 372.IBPluginDependency 373.IBPluginDependency 374.IBPluginDependency 375.IBPluginDependency 376.IBPluginDependency 377.IBPluginDependency 378.IBPluginDependency 379.IBPluginDependency 380.IBPluginDependency 381.IBPluginDependency 382.IBPluginDependency 383.IBPluginDependency 384.IBPluginDependency 437.IBPluginDependency 438.IBPluginDependency 439.IBPluginDependency 440.IBPluginDependency 441.IBPluginDependency 442.IBPluginDependency 443.IBPluginDependency 444.IBPluginDependency 445.IBPluginDependency 446.IBPluginDependency 447.IBPluginDependency 448.IBPluginDependency 449.IBPluginDependency 450.IBPluginDependency 451.IBPluginDependency 452.IBPluginDependency 453.IBPluginDependency 454.IBPluginDependency 455.IBPluginDependency 456.IBPluginDependency 457.IBPluginDependency 458.IBPluginDependency 459.IBPluginDependency 460.IBPluginDependency 461.IBPluginDependency 462.IBPluginDependency 463.IBPluginDependency 464.IBPluginDependency 465.IBPluginDependency 466.IBPluginDependency 467.IBPluginDependency 468.IBPluginDependency 469.IBPluginDependency 470.IBPluginDependency 471.IBPluginDependency 472.IBPluginDependency 473.IBPluginDependency 474.IBPluginDependency 475.IBPluginDependency 476.IBPluginDependency 477.IBPluginDependency 478.IBPluginDependency 479.IBPluginDependency 480.IBPluginDependency 481.IBPluginDependency 511.IBPluginDependency 512.IBEditorWindowLastContentRect 512.IBPluginDependency 513.IBPluginDependency 56.IBPluginDependency 56.ImportedFromIB2 57.IBEditorWindowLastContentRect 57.IBPluginDependency 57.ImportedFromIB2 58.IBPluginDependency 58.ImportedFromIB2 72.IBPluginDependency 72.ImportedFromIB2 73.IBPluginDependency 73.ImportedFromIB2 74.IBPluginDependency 74.ImportedFromIB2 75.IBPluginDependency 75.ImportedFromIB2 77.IBPluginDependency 77.ImportedFromIB2 78.IBPluginDependency 78.ImportedFromIB2 79.IBPluginDependency 79.ImportedFromIB2 80.IBPluginDependency 80.ImportedFromIB2 81.IBEditorWindowLastContentRect 81.IBPluginDependency 81.ImportedFromIB2 82.IBPluginDependency 82.ImportedFromIB2 83.IBPluginDependency 83.ImportedFromIB2 YES com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{320, 909}, {64, 6}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{411, 902}, {197, 73}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{128, 752}, {517, 20}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{400, 932}, {234, 43}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{584, 729}, {250, 23}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{75, 792}, {245, 183}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{209, 772}, {199, 203}} com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin YES YES YES YES 514 YES FirstResponder NSObject IBUserSource 0 IBCocoaFramework com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 YES 3 YES YES NSMenuCheckmark NSMenuMixedState YES {9, 8} {7, 2} assimp-4.1.0/samples/SimpleAssimpViewX/English.lproj/Credits.rtf0000644002537200234200000000066413213503245025147 0ustar zmoelnigiemusers{\rtf0\ansi{\fonttbl\f0\fswiss Helvetica;} {\colortbl;\red255\green255\blue255;} \paperw9840\paperh8400 \pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural \f0\b\fs24 \cf0 Engineering: \b0 \ Some people\ \ \b Human Interface Design: \b0 \ Some other people\ \ \b Testing: \b0 \ Hopefully not nobody\ \ \b Documentation: \b0 \ Whoever\ \ \b With special thanks to: \b0 \ Mom\ } assimp-4.1.0/samples/SimpleAssimpViewX/English.lproj/MyDocument.xib0000644002537200234200000012130013213503245025614 0ustar zmoelnigiemusers 1060 10F569 788 1038.29 461.00 com.apple.InterfaceBuilder.CocoaPlugin 788 YES YES com.apple.InterfaceBuilder.CocoaPlugin YES YES YES YES MyDocument FirstResponder NSApplication 15 2 {{78, 334}, {466, 466}} 1081606144 Window NSWindow View {1.79769e+308, 1.79769e+308} {131.131, 86} 256 YES 256 {{98, 222}, {269, 22}} YES 67239424 138412032 Your document contents here LucidaGrande 18 16 6 System controlColor 3 MC42NjY2NjY2NjY3AA 6 System controlTextColor 3 MAA 274 {466, 466} NSView {466, 466} {{0, 0}, {1280, 832}} {131.131, 108} {1.79769e+308, 1.79769e+308} YES delegate 17 window 18 _view 100022 YES 0 -2 File's Owner -1 First Responder 5 YES Window 6 YES 20 YES 100020 -3 Application 100021 YES YES -3.IBPluginDependency 100020.IBPluginDependency 100021.IBPluginDependency 20.IBPluginDependency 20.ImportedFromIB2 5.IBEditorWindowLastContentRect 5.IBPluginDependency 5.IBWindowTemplateEditedContentRect 5.ImportedFromIB2 5.windowTemplate.hasMinSize 5.windowTemplate.minSize 6.IBPluginDependency 6.ImportedFromIB2 YES com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin {{424, 525}, {466, 466}} com.apple.InterfaceBuilder.CocoaPlugin {{424, 525}, {466, 466}} {131.131, 86} com.apple.InterfaceBuilder.CocoaPlugin YES YES YES YES 100022 YES FirstResponder NSObject IBUserSource MyDocument NSPersistentDocument _view NSView _view _view NSView IBProjectSource MyDocument.h MyDocument NSPersistentDocument IBUserSource NSPersistentDocument NSDocument IBUserSource YES NSActionCell NSCell IBFrameworkSource AppKit.framework/Headers/NSActionCell.h NSApplication NSResponder IBFrameworkSource AppKit.framework/Headers/NSApplication.h NSApplication IBFrameworkSource AppKit.framework/Headers/NSApplicationScripting.h NSApplication IBFrameworkSource AppKit.framework/Headers/NSColorPanel.h NSApplication IBFrameworkSource AppKit.framework/Headers/NSHelpManager.h NSApplication IBFrameworkSource AppKit.framework/Headers/NSPageLayout.h NSApplication IBFrameworkSource AppKit.framework/Headers/NSUserInterfaceItemSearching.h NSCell NSObject IBFrameworkSource AppKit.framework/Headers/NSCell.h NSControl NSView IBFrameworkSource AppKit.framework/Headers/NSControl.h NSDocument NSObject YES YES printDocument: revertDocumentToSaved: runPageLayout: saveDocument: saveDocumentAs: saveDocumentTo: YES id id id id id id YES YES printDocument: revertDocumentToSaved: runPageLayout: saveDocument: saveDocumentAs: saveDocumentTo: YES printDocument: id revertDocumentToSaved: id runPageLayout: id saveDocument: id saveDocumentAs: id saveDocumentTo: id IBFrameworkSource AppKit.framework/Headers/NSDocument.h NSDocument IBFrameworkSource AppKit.framework/Headers/NSDocumentScripting.h NSFormatter NSObject IBFrameworkSource Foundation.framework/Headers/NSFormatter.h NSMenu NSObject IBFrameworkSource AppKit.framework/Headers/NSMenu.h NSObject IBFrameworkSource AppKit.framework/Headers/NSAccessibility.h NSObject NSObject NSObject NSObject NSObject IBFrameworkSource AppKit.framework/Headers/NSDictionaryController.h NSObject IBFrameworkSource AppKit.framework/Headers/NSDragging.h NSObject IBFrameworkSource AppKit.framework/Headers/NSFontManager.h NSObject IBFrameworkSource AppKit.framework/Headers/NSFontPanel.h NSObject IBFrameworkSource AppKit.framework/Headers/NSKeyValueBinding.h NSObject NSObject IBFrameworkSource AppKit.framework/Headers/NSNibLoading.h NSObject IBFrameworkSource AppKit.framework/Headers/NSOutlineView.h NSObject IBFrameworkSource AppKit.framework/Headers/NSPasteboard.h NSObject IBFrameworkSource AppKit.framework/Headers/NSSavePanel.h NSObject IBFrameworkSource AppKit.framework/Headers/NSTableView.h NSObject IBFrameworkSource AppKit.framework/Headers/NSToolbarItem.h NSObject IBFrameworkSource AppKit.framework/Headers/NSView.h NSObject IBFrameworkSource Foundation.framework/Headers/NSArchiver.h NSObject IBFrameworkSource Foundation.framework/Headers/NSClassDescription.h NSObject IBFrameworkSource Foundation.framework/Headers/NSError.h NSObject IBFrameworkSource Foundation.framework/Headers/NSFileManager.h NSObject IBFrameworkSource Foundation.framework/Headers/NSKeyValueCoding.h NSObject IBFrameworkSource Foundation.framework/Headers/NSKeyValueObserving.h NSObject IBFrameworkSource Foundation.framework/Headers/NSKeyedArchiver.h NSObject IBFrameworkSource Foundation.framework/Headers/NSObject.h NSObject IBFrameworkSource Foundation.framework/Headers/NSObjectScripting.h NSObject IBFrameworkSource Foundation.framework/Headers/NSPortCoder.h NSObject IBFrameworkSource Foundation.framework/Headers/NSRunLoop.h NSObject IBFrameworkSource Foundation.framework/Headers/NSScriptClassDescription.h NSObject IBFrameworkSource Foundation.framework/Headers/NSScriptKeyValueCoding.h NSObject IBFrameworkSource Foundation.framework/Headers/NSScriptObjectSpecifiers.h NSObject IBFrameworkSource Foundation.framework/Headers/NSScriptWhoseTests.h NSObject IBFrameworkSource Foundation.framework/Headers/NSThread.h NSObject IBFrameworkSource Foundation.framework/Headers/NSURL.h NSObject IBFrameworkSource Foundation.framework/Headers/NSURLConnection.h NSObject IBFrameworkSource Foundation.framework/Headers/NSURLDownload.h NSObject IBFrameworkSource ImageKit.framework/Headers/IKImageBrowserView.h NSObject IBFrameworkSource ImageKit.framework/Headers/IKSaveOptions.h NSObject IBFrameworkSource ImageKit.framework/Headers/ImageKitDeprecated.h NSObject IBFrameworkSource PDFKit.framework/Headers/PDFDocument.h NSObject IBFrameworkSource PDFKit.framework/Headers/PDFView.h NSObject IBFrameworkSource QTKit.framework/Headers/QTCaptureDecompressedAudioOutput.h NSObject IBFrameworkSource QTKit.framework/Headers/QTCaptureDecompressedVideoOutput.h NSObject IBFrameworkSource QTKit.framework/Headers/QTCaptureFileOutput.h NSObject IBFrameworkSource QTKit.framework/Headers/QTCaptureVideoPreviewOutput.h NSObject IBFrameworkSource QTKit.framework/Headers/QTCaptureView.h NSObject IBFrameworkSource QTKit.framework/Headers/QTMovie.h NSObject IBFrameworkSource QTKit.framework/Headers/QTMovieView.h NSObject IBFrameworkSource QuartzComposer.framework/Headers/QCCompositionParameterView.h NSObject IBFrameworkSource QuartzComposer.framework/Headers/QCCompositionPickerView.h NSObject IBFrameworkSource QuartzFilters.framework/Headers/QuartzFilterManager.h NSObject IBFrameworkSource QuickLookUI.framework/Headers/QLPreviewPanel.h NSPersistentDocument NSDocument IBFrameworkSource AppKit.framework/Headers/NSPersistentDocument.h NSResponder IBFrameworkSource AppKit.framework/Headers/NSInterfaceStyle.h NSResponder NSObject IBFrameworkSource AppKit.framework/Headers/NSResponder.h NSTextField NSControl IBFrameworkSource AppKit.framework/Headers/NSTextField.h NSTextFieldCell NSActionCell IBFrameworkSource AppKit.framework/Headers/NSTextFieldCell.h NSView IBFrameworkSource AppKit.framework/Headers/NSClipView.h NSView IBFrameworkSource AppKit.framework/Headers/NSMenuItem.h NSView IBFrameworkSource AppKit.framework/Headers/NSRulerView.h NSView NSResponder NSWindow IBFrameworkSource AppKit.framework/Headers/NSDrawer.h NSWindow NSResponder IBFrameworkSource AppKit.framework/Headers/NSWindow.h NSWindow IBFrameworkSource AppKit.framework/Headers/NSWindowScripting.h 0 IBCocoaFramework com.apple.InterfaceBuilder.CocoaPlugin.macosx com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 YES ../SimpleAssimpViewX.xcodeproj 3 assimp-4.1.0/samples/SimpleAssimpViewX/MyDocument.h0000644002537200234200000000311213213503245022543 0ustar zmoelnigiemusers// // MyDocument.h // DisplayLinkAsyncMoviePlayer // // Created by vade on 10/26/10. // Copyright __MyCompanyName__ 2010 . All rights reserved. // #import "ModelLoaderHelperClasses.h" // assimp include files. These three are usually needed. #import "cimport.h" #import "postprocess.h" #import "scene.h" #import "types.h" #import #import #import @interface MyDocument : NSPersistentDocument { CVDisplayLinkRef _displayLink; NSOpenGLContext* _glContext; NSOpenGLPixelFormat* _glPixelFormat; NSView* _view; // Assimp Stuff aiScene* _scene; aiVector3D scene_min, scene_max, scene_center; double normalizedScale; // Our array of textures. GLuint *textureIds; // only used if we use NSMutableArray* modelMeshes; BOOL builtBuffers; NSMutableDictionary* textureDictionary; // Array of Dicionaries that map image filenames to textureIds } @property (retain) IBOutlet NSView* _view; - (CVReturn)displayLinkRenderCallback:(const CVTimeStamp *)timeStamp; - (void) render; - (void) drawMeshesInContext:(CGLContextObj)cgl_ctx; - (void) createGLResourcesInContext:(CGLContextObj)cgl_ctx; - (void) deleteGLResourcesInContext:(CGLContextObj)cgl_ctx; - (void) loadTexturesInContext:(CGLContextObj)cgl_ctx withModelPath:(NSString*) modelPath; - (void) getBoundingBoxWithMinVector:(aiVector3D*) min maxVectr:(aiVector3D*) max; - (void) getBoundingBoxForNode:(const aiNode*)nd minVector:(aiVector3D*) min maxVector:(aiVector3D*) max matrix:(aiMatrix4x4*) trafo; @end assimp-4.1.0/samples/SimpleAssimpViewX/main.m0000644002537200234200000000041213213503245021410 0ustar zmoelnigiemusers// // main.m // DisplayLinkAsyncMoviePlayer // // Created by vade on 10/26/10. // Copyright __MyCompanyName__ 2010 . All rights reserved. // #import int main(int argc, char *argv[]) { return NSApplicationMain(argc, (const char **) argv); } assimp-4.1.0/samples/SimpleAssimpViewX/SimpleAssimpViewX-Info.plist0000644002537200234200000000515513213503245025656 0ustar zmoelnigiemusers CFBundleDevelopmentRegion English CFBundleDocumentTypes CFBundleTypeExtensions binary CFBundleTypeMIMETypes application/octet-stream CFBundleTypeName Binary CFBundleTypeRole Editor LSTypeIsPackage NSDocumentClass MyDocument NSPersistentStoreTypeKey Binary CFBundleTypeExtensions sqlite CFBundleTypeMIMETypes application/octet-stream CFBundleTypeName SQLite CFBundleTypeRole Editor LSTypeIsPackage NSDocumentClass MyDocument NSPersistentStoreTypeKey SQLite CFBundleTypeExtensions xml CFBundleTypeIconFile CFBundleTypeMIMETypes text/xml CFBundleTypeName XML CFBundleTypeOSTypes ???? CFBundleTypeRole Editor LSTypeIsPackage NSDocumentClass MyDocument NSPersistentStoreTypeKey XML CFBundleName ${PRODUCT_NAME} CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier com.yourcompany.${PRODUCT_NAME:rfc1034identifier} CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType APPL CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1 LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET} NSMainNibFile MainMenu NSPrincipalClass NSApplication assimp-4.1.0/samples/SimpleTexturedOpenGL/0000755002537200234200000000000013213503245020743 5ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL.sln0000644002537200234200000000163613213503245025512 0ustar zmoelnigiemusers Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleTexturedOpenGL", "SimpleTexturedOpenGL\SimpleTexturedOpenGL.vcproj", "{A03DCB69-BBC5-4F55-A7D1-B9100E821BBE}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {A03DCB69-BBC5-4F55-A7D1-B9100E821BBE}.Debug|Win32.ActiveCfg = Debug|Win32 {A03DCB69-BBC5-4F55-A7D1-B9100E821BBE}.Debug|Win32.Build.0 = Debug|Win32 {A03DCB69-BBC5-4F55-A7D1-B9100E821BBE}.Release|Win32.ActiveCfg = Release|Win32 {A03DCB69-BBC5-4F55-A7D1-B9100E821BBE}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal assimp-4.1.0/samples/SimpleTexturedOpenGL/CMakeLists.txt0000644002537200234200000000243013213503245023502 0ustar zmoelnigiemusersFIND_PACKAGE(OpenGL) FIND_PACKAGE(GLUT) IF ( NOT GLUT_FOUND ) IF ( MSVC ) SET ( GLUT_FOUND 1 ) SET ( GLUT_INCLUDE_DIR ${Assimp_SOURCE_DIR}/samples/glut/ ) SET ( GLUT_LIBRARIES ${Assimp_SOURCE_DIR}/samples/glut/glut32.lib ) ELSE ( MSVC ) MESSAGE( WARNING "Please install glut." ) ENDIF ( MSVC ) ENDIF ( NOT GLUT_FOUND ) if ( MSVC ) ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) endif ( MSVC ) INCLUDE_DIRECTORIES( ${Assimp_SOURCE_DIR}/include ${Assimp_SOURCE_DIR}/code ${OPENGL_INCLUDE_DIR} ${GLUT_INCLUDE_DIR} ${Assimp_SOURCE_DIR}/samples/DevIL/include/ ) LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${Assimp_BINARY_DIR}/lib/ ${Assimp_SOURCE_DIR}/samples/DevIL/lib/ ) ADD_EXECUTABLE( assimp_simpletexturedogl WIN32 SimpleTexturedOpenGL/include/boost_includes.h SimpleTexturedOpenGL/src/model_loading.cpp ) SET_PROPERTY(TARGET assimp_simpletexturedogl PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) TARGET_LINK_LIBRARIES( assimp_simpletexturedogl assimp ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} DevIL.lib ) SET_TARGET_PROPERTIES( assimp_simpletexturedogl PROPERTIES OUTPUT_NAME assimp_simpletexturedogl ) INSTALL( TARGETS assimp_simpletexturedogl DESTINATION "${ASSIMP_BIN_INSTALL_DIR}" COMPONENT assimp-dev ) assimp-4.1.0/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/0000755002537200234200000000000013213503245024766 5ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/include/0000755002537200234200000000000013213503245026411 5ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/include/boost_includes.h0000644002537200234200000000004113213503245031571 0ustar zmoelnigiemusers#include assimp-4.1.0/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/0000755002537200234200000000000013213503245025555 5ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/src/model_loading.cpp0000644002537200234200000006045513213503245031070 0ustar zmoelnigiemusers// ---------------------------------------------------------------------------- // Another Assimp OpenGL sample including texturing. // Note that it is very basic and will only read and apply the model's diffuse // textures (by their material ids) // // Don't worry about the "Couldn't load Image: ...dwarf2.jpg" Message. // It's caused by a bad texture reference in the model file (I guess) // // If you intend to _use_ this code sample in your app, do yourself a favour // and replace immediate mode calls with VBOs ... // // Thanks to NeHe on whose OpenGL tutorials this one's based on! :) // http://nehe.gamedev.net/ // ---------------------------------------------------------------------------- #include #include #include #include #include #include #include //to map image filenames to textureIds #include #include // assimp include files. These three are usually needed. #include "assimp/Importer.hpp" //OO version Header! #include "assimp/postprocess.h" #include "assimp/scene.h" #include "assimp/DefaultLogger.hpp" #include "assimp/LogStream.hpp" // The default hard-coded path. Can be overridden by supplying a path through the command line. static std::string modelpath = "../../test/models/OBJ/spider.obj"; HGLRC hRC=NULL; // Permanent Rendering Context HDC hDC=NULL; // Private GDI Device Context HWND hWnd=NULL; // Holds Window Handle HINSTANCE hInstance; // Holds The Instance Of The Application bool keys[256]; // Array used for Keyboard Routine; bool active=TRUE; // Window Active Flag Set To TRUE by Default bool fullscreen=TRUE; // full-screen Flag Set To full-screen By Default GLfloat xrot; GLfloat yrot; GLfloat zrot; LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); // Declaration For WndProc GLboolean abortGLInit(const char*); const char* windowTitle = "OpenGL Framework"; GLfloat LightAmbient[]= { 0.5f, 0.5f, 0.5f, 1.0f }; GLfloat LightDiffuse[]= { 1.0f, 1.0f, 1.0f, 1.0f }; GLfloat LightPosition[]= { 0.0f, 0.0f, 15.0f, 1.0f }; // the global Assimp scene object const aiScene* scene = NULL; GLuint scene_list = 0; aiVector3D scene_min, scene_max, scene_center; // images / texture std::map textureIdMap; // map image filenames to textureIds GLuint* textureIds; // pointer to texture Array // Create an instance of the Importer class Assimp::Importer importer; void createAILogger() { // Change this line to normal if you not want to analyse the import process //Assimp::Logger::LogSeverity severity = Assimp::Logger::NORMAL; Assimp::Logger::LogSeverity severity = Assimp::Logger::VERBOSE; // Create a logger instance for Console Output Assimp::DefaultLogger::create("",severity, aiDefaultLogStream_STDOUT); // Create a logger instance for File Output (found in project folder or near .exe) Assimp::DefaultLogger::create("assimp_log.txt",severity, aiDefaultLogStream_FILE); // Now I am ready for logging my stuff Assimp::DefaultLogger::get()->info("this is my info-call"); } void destroyAILogger() { // Kill it after the work is done Assimp::DefaultLogger::kill(); } void logInfo(std::string logString) { // Will add message to File with "info" Tag Assimp::DefaultLogger::get()->info(logString.c_str()); } void logDebug(const char* logString) { // Will add message to File with "debug" Tag Assimp::DefaultLogger::get()->debug(logString); } bool Import3DFromFile( const std::string& pFile) { // Check if file exists std::ifstream fin(pFile.c_str()); if(!fin.fail()) { fin.close(); } else { MessageBox(NULL, ("Couldn't open file: " + pFile).c_str() , "ERROR", MB_OK | MB_ICONEXCLAMATION); logInfo( importer.GetErrorString()); return false; } scene = importer.ReadFile( pFile, aiProcessPreset_TargetRealtime_Quality); // If the import failed, report it if( !scene) { logInfo( importer.GetErrorString()); return false; } // Now we can access the file's contents. logInfo("Import of scene " + pFile + " succeeded."); // We're done. Everything will be cleaned up by the importer destructor return true; } // Resize And Initialize The GL Window void ReSizeGLScene(GLsizei width, GLsizei height) { // Prevent A Divide By Zero By if (height==0) { // Making Height Equal One height=1; } glViewport(0, 0, width, height); // Reset The Current Viewport glMatrixMode(GL_PROJECTION); // Select The Projection Matrix glLoadIdentity(); // Reset The Projection Matrix // Calculate The Aspect Ratio Of The Window gluPerspective(45.0f,(GLfloat)width/(GLfloat)height,0.1f,100.0f); glMatrixMode(GL_MODELVIEW); // Select The Modelview Matrix glLoadIdentity(); // Reset The Modelview Matrix } std::string getBasePath(const std::string& path) { size_t pos = path.find_last_of("\\/"); return (std::string::npos == pos) ? "" : path.substr(0, pos + 1); } int LoadGLTextures(const aiScene* scene) { ILboolean success; /* Before calling ilInit() version should be checked. */ if (ilGetInteger(IL_VERSION_NUM) < IL_VERSION) { /// wrong DevIL version /// std::string err_msg = "Wrong DevIL version. Old devil.dll in system32/SysWow64?"; char* cErr_msg = (char *) err_msg.c_str(); abortGLInit(cErr_msg); return -1; } ilInit(); /* Initialization of DevIL */ if (scene->HasTextures()) abortGLInit("Support for meshes with embedded textures is not implemented"); /* getTexture Filenames and Numb of Textures */ for (unsigned int m=0; mmNumMaterials; m++) { int texIndex = 0; aiReturn texFound = AI_SUCCESS; aiString path; // filename while (texFound == AI_SUCCESS) { texFound = scene->mMaterials[m]->GetTexture(aiTextureType_DIFFUSE, texIndex, &path); textureIdMap[path.data] = NULL; //fill map with textures, pointers still NULL yet texIndex++; } } int numTextures = textureIdMap.size(); /* array with DevIL image IDs */ ILuint* imageIds = NULL; imageIds = new ILuint[numTextures]; /* generate DevIL Image IDs */ ilGenImages(numTextures, imageIds); /* Generation of numTextures image names */ /* create and fill array with GL texture ids */ textureIds = new GLuint[numTextures]; glGenTextures(numTextures, textureIds); /* Texture name generation */ /* get iterator */ std::map::iterator itr = textureIdMap.begin(); std::string basepath = getBasePath(modelpath); for (int i=0; ir, color->g, color->b, color->a); } void set_float4(float f[4], float a, float b, float c, float d) { f[0] = a; f[1] = b; f[2] = c; f[3] = d; } void color4_to_float4(const aiColor4D *c, float f[4]) { f[0] = c->r; f[1] = c->g; f[2] = c->b; f[3] = c->a; } void apply_material(const aiMaterial *mtl) { float c[4]; GLenum fill_mode; int ret1, ret2; aiColor4D diffuse; aiColor4D specular; aiColor4D ambient; aiColor4D emission; ai_real shininess, strength; int two_sided; int wireframe; unsigned int max; // changed: to unsigned int texIndex = 0; aiString texPath; //contains filename of texture if(AI_SUCCESS == mtl->GetTexture(aiTextureType_DIFFUSE, texIndex, &texPath)) { //bind texture unsigned int texId = *textureIdMap[texPath.data]; glBindTexture(GL_TEXTURE_2D, texId); } set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse)) color4_to_float4(&diffuse, c); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, c); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular)) color4_to_float4(&specular, c); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c); set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient)) color4_to_float4(&ambient, c); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, c); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission)) color4_to_float4(&emission, c); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, c); max = 1; ret1 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max); max = 1; ret2 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS_STRENGTH, &strength, &max); if((ret1 == AI_SUCCESS) && (ret2 == AI_SUCCESS)) glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength); else { glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f); set_float4(c, 0.0f, 0.0f, 0.0f, 0.0f); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c); } max = 1; if(AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max)) fill_mode = wireframe ? GL_LINE : GL_FILL; else fill_mode = GL_FILL; glPolygonMode(GL_FRONT_AND_BACK, fill_mode); max = 1; if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided) glEnable(GL_CULL_FACE); else glDisable(GL_CULL_FACE); } void recursive_render (const struct aiScene *sc, const struct aiNode* nd, float scale) { unsigned int i; unsigned int n=0, t; aiMatrix4x4 m = nd->mTransformation; aiMatrix4x4 m2; aiMatrix4x4::Scaling(aiVector3D(scale, scale, scale), m2); m = m * m2; // update transform m.Transpose(); glPushMatrix(); glMultMatrixf((float*)&m); // draw all meshes assigned to this node for (; n < nd->mNumMeshes; ++n) { const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; apply_material(sc->mMaterials[mesh->mMaterialIndex]); if(mesh->mNormals == NULL) { glDisable(GL_LIGHTING); } else { glEnable(GL_LIGHTING); } if(mesh->mColors[0] != NULL) { glEnable(GL_COLOR_MATERIAL); } else { glDisable(GL_COLOR_MATERIAL); } for (t = 0; t < mesh->mNumFaces; ++t) { const struct aiFace* face = &mesh->mFaces[t]; GLenum face_mode; switch(face->mNumIndices) { case 1: face_mode = GL_POINTS; break; case 2: face_mode = GL_LINES; break; case 3: face_mode = GL_TRIANGLES; break; default: face_mode = GL_POLYGON; break; } glBegin(face_mode); for(i = 0; i < face->mNumIndices; i++) // go through all vertices in face { int vertexIndex = face->mIndices[i]; // get group index for current index if(mesh->mColors[0] != NULL) Color4f(&mesh->mColors[0][vertexIndex]); if(mesh->mNormals != NULL) if(mesh->HasTextureCoords(0)) //HasTextureCoords(texture_coordinates_set) { glTexCoord2f(mesh->mTextureCoords[0][vertexIndex].x, 1 - mesh->mTextureCoords[0][vertexIndex].y); //mTextureCoords[channel][vertex] } glNormal3fv(&mesh->mNormals[vertexIndex].x); glVertex3fv(&mesh->mVertices[vertexIndex].x); } glEnd(); } } // draw all children for (n = 0; n < nd->mNumChildren; ++n) { recursive_render(sc, nd->mChildren[n], scale); } glPopMatrix(); } void drawAiScene(const aiScene* scene) { logInfo("drawing objects"); recursive_render(scene, scene->mRootNode, 0.5); } int DrawGLScene() //Here's where we do all the drawing { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer glLoadIdentity(); // Reset MV Matrix glTranslatef(0.0f, -10.0f, -40.0f); // Move 40 Units And Into The Screen glRotatef(xrot, 1.0f, 0.0f, 0.0f); glRotatef(yrot, 0.0f, 1.0f, 0.0f); glRotatef(zrot, 0.0f, 0.0f, 1.0f); drawAiScene(scene); //xrot+=0.3f; yrot+=0.2f; //zrot+=0.4f; return TRUE; // okay } void KillGLWindow() // Properly Kill The Window { if (fullscreen) // Are We In Fullscreen Mode? { ChangeDisplaySettings(NULL, 0); // If So Switch Back To The Desktop ShowCursor(TRUE); // Show Mouse Pointer } if (hRC) // Do We Have A Rendering Context? { if (!wglMakeCurrent(NULL, NULL)) // Are We Able To Release The DC And RC Contexts? { MessageBox(NULL, "Release Of DC And RC Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); } if (!wglDeleteContext(hRC)) // Are We Able To Delete The RC? { MessageBox(NULL, "Release Rendering Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); } hRC = NULL; } if (hDC && !ReleaseDC(hWnd, hDC)) // Are We able to Release The DC? { MessageBox(NULL, "Release Device Context Failed.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); hDC=NULL; } if (hWnd && !DestroyWindow(hWnd)) // Are We Able To Destroy The Window { MessageBox(NULL, "Could Not Release hWnd.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); hWnd = NULL; } if (!UnregisterClass("OpenGL", hInstance)) // Are We Able To Unregister Class { MessageBox(NULL, "Could Not Unregister Class.", "SHUTDOWN ERROR", MB_OK | MB_ICONINFORMATION); hInstance = NULL; } } GLboolean abortGLInit(const char* abortMessage) { KillGLWindow(); // Reset Display MessageBox(NULL, abortMessage, "ERROR", MB_OK|MB_ICONEXCLAMATION); return FALSE; // quit and return False } BOOL CreateGLWindow(const char* title, int width, int height, int bits, bool fullscreenflag) { GLuint PixelFormat; // Hold the result after searching for a match WNDCLASS wc; // Window Class Structure DWORD dwExStyle; // Window Extended Style DWORD dwStyle; // Window Style RECT WindowRect; // Grabs Rectangle Upper Left / Lower Right Values WindowRect.left = (long)0; WindowRect.right = (long)width; WindowRect.top = (long)0; WindowRect.bottom = (long)height; fullscreen = fullscreenflag; hInstance = GetModuleHandle(NULL); // Grab An Instance For Our Window wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; // Redraw On Move, And Own DC For Window wc.lpfnWndProc = (WNDPROC) WndProc; // WndProc handles Messages wc.cbClsExtra = 0; // No Extra Window Data wc.cbWndExtra = 0; // No Extra Window Data wc.hInstance = hInstance; wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Load The Default Icon wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Load the default arrow wc.hbrBackground= NULL; // No Background required for OpenGL wc.lpszMenuName = NULL; // No Menu wc.lpszClassName= "OpenGL"; // Class Name if (!RegisterClass(&wc)) { MessageBox(NULL, "Failed to register the window class", "ERROR", MB_OK | MB_ICONEXCLAMATION); return FALSE; //exit and return false } if (fullscreen) // attempt fullscreen mode { DEVMODE dmScreenSettings; // Device Mode memset(&dmScreenSettings, 0, sizeof(dmScreenSettings)); // Make Sure Memory's Cleared dmScreenSettings.dmSize = sizeof(dmScreenSettings); // Size Of the devmode structure dmScreenSettings.dmPelsWidth = width; // Selected Screen Width dmScreenSettings.dmPelsHeight = height; // Selected Screen Height dmScreenSettings.dmBitsPerPel = bits; // bits per pixel dmScreenSettings.dmFields = DM_BITSPERPEL|DM_PELSWIDTH|DM_PELSHEIGHT; // Try To Set Selected Mode and Get Results. NOTE: CDS_FULLSCREEN Gets Rid Of Start Bar. if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN)!=DISP_CHANGE_SUCCESSFUL) { // If The Mode Fails, Offer Two Options. Quit Or Run In A Window. if (MessageBox(NULL,"The Requested Fullscreen Mode Is Not Supported By\nYour Video Card. Use Windowed Mode Instead?","NeHe GL",MB_YESNO|MB_ICONEXCLAMATION)==IDYES) { fullscreen = FALSE; // Select Windowed Mode (Fullscreen = FALSE) } else { //Popup Messagebox: Closing MessageBox(NULL, "Program will close now.", "ERROR", MB_OK|MB_ICONSTOP); return FALSE; //exit, return false } } } if (fullscreen) // when mode really succeeded { dwExStyle=WS_EX_APPWINDOW; // Window Extended Style dwStyle=WS_POPUP; ShowCursor(FALSE); } else { dwExStyle=WS_EX_APPWINDOW | WS_EX_WINDOWEDGE; // Window extended style dwStyle=WS_OVERLAPPEDWINDOW; // Windows style } AdjustWindowRectEx(&WindowRect, dwStyle, FALSE, dwExStyle); // Adjust Window To True Requestes Size if (!(hWnd=CreateWindowEx( dwExStyle, // Extended Style For The Window "OpenGL", // Class Name title, // Window Title WS_CLIPSIBLINGS | // Required Window Style WS_CLIPCHILDREN | // Required Window Style dwStyle, // Selected WIndow Style 0, 0, // Window Position WindowRect.right-WindowRect.left, // Calc adjusted Window Width WindowRect.bottom-WindowRect.top, // Calc adjustes Window Height NULL, // No Parent Window NULL, // No Menu hInstance, // Instance NULL ))) // Don't pass anything To WM_CREATE { abortGLInit("Window Creation Error."); return FALSE; } static PIXELFORMATDESCRIPTOR pfd= // pfd Tells Windows How We Want Things To Be { sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor 1, // Version Number PFD_DRAW_TO_WINDOW | // Format Must Support Window PFD_SUPPORT_OPENGL | // Format Must Support OpenGL PFD_DOUBLEBUFFER, // Must Support Double Buffering PFD_TYPE_RGBA, // Request An RGBA Format BYTE(bits), // Select Our Color Depth 0, 0, 0, 0, 0, 0, // Color Bits Ignored 0, // No Alpha Buffer 0, // Shift Bit Ignored 0, // No Accumulation Buffer 0, 0, 0, 0, // Accumulation Bits Ignored 16, // 16Bit Z-Buffer (Depth Buffer) 0, // No Stencil Buffer 0, // No Auxiliary Buffer PFD_MAIN_PLANE, // Main Drawing Layer 0, // Reserved 0, 0, 0 // Layer Masks Ignored }; if (!(hDC=GetDC(hWnd))) // Did we get the Device Context? { abortGLInit("Can't Create A GL Device Context."); return FALSE; } if (!(PixelFormat=ChoosePixelFormat(hDC, &pfd))) // Did We Find a matching pixel Format? { abortGLInit("Can't Find Suitable PixelFormat"); return FALSE; } if (!SetPixelFormat(hDC, PixelFormat, &pfd)) { abortGLInit("Can't Set The PixelFormat"); return FALSE; } if (!(hRC=wglCreateContext(hDC))) { abortGLInit("Can't Create A GL Rendering Context."); return FALSE; } if (!(wglMakeCurrent(hDC,hRC))) // Try to activate the rendering context { abortGLInit("Can't Activate The Rendering Context"); return FALSE; } //// *** everything okay *** ShowWindow(hWnd, SW_SHOW); // Show The Window SetForegroundWindow(hWnd); // Slightly Higher Prio SetFocus(hWnd); // Sets Keyboard Focus To The Window ReSizeGLScene(width, height); // Set Up Our Perspective GL Screen if (!InitGL()) { abortGLInit("Initialization failed"); return FALSE; } return TRUE; } LRESULT CALLBACK WndProc(HWND hWnd, // Handles for this Window UINT uMsg, // Message for this Window WPARAM wParam, // additional message Info LPARAM lParam) // additional message Info { switch (uMsg) // check for Window Messages { case WM_ACTIVATE: // Watch For Window Activate Message { if (!HIWORD(wParam)) // Check Minimization State { active=TRUE; } else { active=FALSE; } return 0; // return To The Message Loop } case WM_SYSCOMMAND: // Interrupt System Commands { switch (wParam) { case SC_SCREENSAVE: // Screen-saver trying to start case SC_MONITORPOWER: // Monitor trying to enter power-safe return 0; } break; } case WM_CLOSE: // close message received? { PostQuitMessage(0); // Send WM_QUIT quit message return 0; // Jump Back } case WM_KEYDOWN: // Is a key pressed? { keys[wParam] = TRUE; // If so, Mark it as true return 0; } case WM_KEYUP: // Has Key Been released? { keys[wParam] = FALSE; // If so, Mark It As FALSE return 0; } case WM_SIZE: // Resize The OpenGL Window { ReSizeGLScene(LOWORD(lParam), HIWORD(lParam)); // LoWord-Width, HiWord-Height return 0; } } // Pass All unhandled Messaged To DefWindowProc return DefWindowProc(hWnd, uMsg, wParam, lParam); } int WINAPI WinMain( HINSTANCE hInstance, // The instance HINSTANCE hPrevInstance, // Previous instance LPSTR lpCmdLine, // Command Line Parameters int nShowCmd ) // Window Show State { MSG msg; BOOL done=FALSE; createAILogger(); logInfo("App fired!"); // Check the command line for an override file path. int argc; LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc); if (argv != NULL && argc > 1) { std::wstring modelpathW(argv[1]); modelpath = std::string(modelpathW.begin(), modelpathW.end()); } if (!Import3DFromFile(modelpath)) return 0; logInfo("=============== Post Import ===================="); if (MessageBox(NULL, "Would You Like To Run In Fullscreen Mode?", "Start Fullscreen?", MB_YESNO|MB_ICONEXCLAMATION)==IDNO) { fullscreen=FALSE; } if (!CreateGLWindow(windowTitle, 640, 480, 16, fullscreen)) { return 0; } while(!done) // Game Loop { if (PeekMessage(&msg, NULL, 0,0, PM_REMOVE)) { if (msg.message==WM_QUIT) { done=TRUE; } else { TranslateMessage(&msg); DispatchMessage(&msg); } } else { // Draw The Scene. Watch For ESC Key And Quit Messaged From DrawGLScene() if (active) { if (keys[VK_ESCAPE]) { done=TRUE; } else { DrawGLScene(); SwapBuffers(hDC); } } if (keys[VK_F1]) { keys[VK_F1]=FALSE; KillGLWindow(); fullscreen=!fullscreen; if (!CreateGLWindow(windowTitle, 640, 480, 16, fullscreen)) { return 0; } } } } // *** cleanup *** textureIdMap.clear(); //no need to delete pointers in it manually here. (Pointers point to textureIds deleted in next step) if (textureIds) { delete[] textureIds; textureIds = NULL; } // *** cleanup end *** destroyAILogger(); KillGLWindow(); return (msg.wParam); } assimp-4.1.0/samples/SimpleTexturedOpenGL/SimpleTexturedOpenGL/SimpleTexturedOpenGL.vcproj0000644002537200234200000001145313213503245032242 0ustar zmoelnigiemusers assimp-4.1.0/samples/SimpleOpenGL/0000755002537200234200000000000013213503245017216 5ustar zmoelnigiemusersassimp-4.1.0/samples/SimpleOpenGL/SimpleOpenGL.vcproj0000644002537200234200000001102413213503245022737 0ustar zmoelnigiemusers assimp-4.1.0/samples/SimpleOpenGL/SimpleOpenGL.sln0000644002537200234200000000157113213503245022236 0ustar zmoelnigiemusers Microsoft Visual Studio Solution File, Format Version 10.00 # Visual Studio 2008 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SimpleOpenGL", "SimpleOpenGL.vcproj", "{A53D047C-2C35-44FB-B7DB-2066FE520950}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 Release|Win32 = Release|Win32 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {A53D047C-2C35-44FB-B7DB-2066FE520950}.Debug|Win32.ActiveCfg = Debug|Win32 {A53D047C-2C35-44FB-B7DB-2066FE520950}.Debug|Win32.Build.0 = Debug|Win32 {A53D047C-2C35-44FB-B7DB-2066FE520950}.Release|Win32.ActiveCfg = Release|Win32 {A53D047C-2C35-44FB-B7DB-2066FE520950}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection EndGlobal assimp-4.1.0/samples/SimpleOpenGL/CMakeLists.txt0000644002537200234200000000222013213503245021752 0ustar zmoelnigiemusersFIND_PACKAGE(OpenGL) FIND_PACKAGE(GLUT) IF ( MSVC ) SET(M_LIB) ELSE ( MSVC ) find_library(M_LIB m) ENDIF ( MSVC ) IF ( NOT GLUT_FOUND ) IF ( MSVC ) SET ( GLUT_FOUND 1 ) SET ( GLUT_INCLUDE_DIR ${Assimp_SOURCE_DIR}/samples/glut/ ) SET ( GLUT_LIBRARIES ${Assimp_SOURCE_DIR}/samples/glut/glut32.lib ) ELSE ( MSVC ) MESSAGE( WARNING "Please install glut." ) ENDIF ( MSVC ) ENDIF ( NOT GLUT_FOUND ) if ( MSVC ) ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) endif ( MSVC ) INCLUDE_DIRECTORIES( ${Assimp_SOURCE_DIR}/include ${Assimp_SOURCE_DIR}/code ${OPENGL_INCLUDE_DIR} ${GLUT_INCLUDE_DIR} ) LINK_DIRECTORIES( ${Assimp_BINARY_DIR} ${Assimp_BINARY_DIR}/lib ) ADD_EXECUTABLE( assimp_simpleogl Sample_SimpleOpenGL.c ) SET_PROPERTY(TARGET assimp_simpleogl PROPERTY DEBUG_POSTFIX ${CMAKE_DEBUG_POSTFIX}) TARGET_LINK_LIBRARIES( assimp_simpleogl assimp ${OPENGL_LIBRARIES} ${GLUT_LIBRARIES} ${M_LIB} ) SET_TARGET_PROPERTIES( assimp_simpleogl PROPERTIES OUTPUT_NAME assimp_simpleogl ) INSTALL( TARGETS assimp_simpleogl DESTINATION "${ASSIMP_BIN_INSTALL_DIR}" COMPONENT assimp-dev ) assimp-4.1.0/samples/SimpleOpenGL/Sample_SimpleOpenGL.c0000644002537200234200000002605613213503245023172 0ustar zmoelnigiemusers/* ---------------------------------------------------------------------------- // Simple sample to prove that Assimp is easy to use with OpenGL. // It takes a file name as command line parameter, loads it using standard // settings and displays it. // // If you intend to _use_ this code sample in your app, do yourself a favour // and replace immediate mode calls with VBOs ... // // The vc8 solution links against assimp-release-dll_win32 - be sure to // have this configuration built. // ---------------------------------------------------------------------------- */ #include #include #ifdef __APPLE__ #include #else #include #endif /* assimp include files. These three are usually needed. */ #include #include #include /* the global Assimp scene object */ const struct aiScene* scene = NULL; GLuint scene_list = 0; struct aiVector3D scene_min, scene_max, scene_center; /* current rotation angle */ static float angle = 0.f; #define aisgl_min(x,y) (xx?y:x) /* ---------------------------------------------------------------------------- */ void reshape(int width, int height) { const double aspectRatio = (float) width / height, fieldOfView = 45.0; glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(fieldOfView, aspectRatio, 1.0, 1000.0); /* Znear and Zfar */ glViewport(0, 0, width, height); } /* ---------------------------------------------------------------------------- */ void get_bounding_box_for_node (const struct aiNode* nd, struct aiVector3D* min, struct aiVector3D* max, struct aiMatrix4x4* trafo ){ struct aiMatrix4x4 prev; unsigned int n = 0, t; prev = *trafo; aiMultiplyMatrix4(trafo,&nd->mTransformation); for (; n < nd->mNumMeshes; ++n) { const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; for (t = 0; t < mesh->mNumVertices; ++t) { struct aiVector3D tmp = mesh->mVertices[t]; aiTransformVecByMatrix4(&tmp,trafo); min->x = aisgl_min(min->x,tmp.x); min->y = aisgl_min(min->y,tmp.y); min->z = aisgl_min(min->z,tmp.z); max->x = aisgl_max(max->x,tmp.x); max->y = aisgl_max(max->y,tmp.y); max->z = aisgl_max(max->z,tmp.z); } } for (n = 0; n < nd->mNumChildren; ++n) { get_bounding_box_for_node(nd->mChildren[n],min,max,trafo); } *trafo = prev; } /* ---------------------------------------------------------------------------- */ void get_bounding_box (struct aiVector3D* min, struct aiVector3D* max) { struct aiMatrix4x4 trafo; aiIdentityMatrix4(&trafo); min->x = min->y = min->z = 1e10f; max->x = max->y = max->z = -1e10f; get_bounding_box_for_node(scene->mRootNode,min,max,&trafo); } /* ---------------------------------------------------------------------------- */ void color4_to_float4(const struct aiColor4D *c, float f[4]) { f[0] = c->r; f[1] = c->g; f[2] = c->b; f[3] = c->a; } /* ---------------------------------------------------------------------------- */ void set_float4(float f[4], float a, float b, float c, float d) { f[0] = a; f[1] = b; f[2] = c; f[3] = d; } /* ---------------------------------------------------------------------------- */ void apply_material(const struct aiMaterial *mtl) { float c[4]; GLenum fill_mode; int ret1, ret2; struct aiColor4D diffuse; struct aiColor4D specular; struct aiColor4D ambient; struct aiColor4D emission; ai_real shininess, strength; int two_sided; int wireframe; unsigned int max; set_float4(c, 0.8f, 0.8f, 0.8f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_DIFFUSE, &diffuse)) color4_to_float4(&diffuse, c); glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, c); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_SPECULAR, &specular)) color4_to_float4(&specular, c); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c); set_float4(c, 0.2f, 0.2f, 0.2f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_AMBIENT, &ambient)) color4_to_float4(&ambient, c); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, c); set_float4(c, 0.0f, 0.0f, 0.0f, 1.0f); if(AI_SUCCESS == aiGetMaterialColor(mtl, AI_MATKEY_COLOR_EMISSIVE, &emission)) color4_to_float4(&emission, c); glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, c); max = 1; ret1 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS, &shininess, &max); if(ret1 == AI_SUCCESS) { max = 1; ret2 = aiGetMaterialFloatArray(mtl, AI_MATKEY_SHININESS_STRENGTH, &strength, &max); if(ret2 == AI_SUCCESS) glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess * strength); else glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess); } else { glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f); set_float4(c, 0.0f, 0.0f, 0.0f, 0.0f); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, c); } max = 1; if(AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_ENABLE_WIREFRAME, &wireframe, &max)) fill_mode = wireframe ? GL_LINE : GL_FILL; else fill_mode = GL_FILL; glPolygonMode(GL_FRONT_AND_BACK, fill_mode); max = 1; if((AI_SUCCESS == aiGetMaterialIntegerArray(mtl, AI_MATKEY_TWOSIDED, &two_sided, &max)) && two_sided) glDisable(GL_CULL_FACE); else glEnable(GL_CULL_FACE); } /* ---------------------------------------------------------------------------- */ void recursive_render (const struct aiScene *sc, const struct aiNode* nd) { unsigned int i; unsigned int n = 0, t; struct aiMatrix4x4 m = nd->mTransformation; /* update transform */ aiTransposeMatrix4(&m); glPushMatrix(); glMultMatrixf((float*)&m); /* draw all meshes assigned to this node */ for (; n < nd->mNumMeshes; ++n) { const struct aiMesh* mesh = scene->mMeshes[nd->mMeshes[n]]; apply_material(sc->mMaterials[mesh->mMaterialIndex]); if(mesh->mNormals == NULL) { glDisable(GL_LIGHTING); } else { glEnable(GL_LIGHTING); } for (t = 0; t < mesh->mNumFaces; ++t) { const struct aiFace* face = &mesh->mFaces[t]; GLenum face_mode; switch(face->mNumIndices) { case 1: face_mode = GL_POINTS; break; case 2: face_mode = GL_LINES; break; case 3: face_mode = GL_TRIANGLES; break; default: face_mode = GL_POLYGON; break; } glBegin(face_mode); for(i = 0; i < face->mNumIndices; i++) { int index = face->mIndices[i]; if(mesh->mColors[0] != NULL) glColor4fv((GLfloat*)&mesh->mColors[0][index]); if(mesh->mNormals != NULL) glNormal3fv(&mesh->mNormals[index].x); glVertex3fv(&mesh->mVertices[index].x); } glEnd(); } } /* draw all children */ for (n = 0; n < nd->mNumChildren; ++n) { recursive_render(sc, nd->mChildren[n]); } glPopMatrix(); } /* ---------------------------------------------------------------------------- */ void do_motion (void) { static GLint prev_time = 0; static GLint prev_fps_time = 0; static int frames = 0; int time = glutGet(GLUT_ELAPSED_TIME); angle += (time-prev_time)*0.01; prev_time = time; frames += 1; if ((time - prev_fps_time) > 1000) /* update every seconds */ { int current_fps = frames * 1000 / (time - prev_fps_time); printf("%d fps\n", current_fps); frames = 0; prev_fps_time = time; } glutPostRedisplay (); } /* ---------------------------------------------------------------------------- */ void display(void) { float tmp; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); gluLookAt(0.f,0.f,3.f,0.f,0.f,-5.f,0.f,1.f,0.f); /* rotate it around the y axis */ glRotatef(angle,0.f,1.f,0.f); /* scale the whole asset to fit into our view frustum */ tmp = scene_max.x-scene_min.x; tmp = aisgl_max(scene_max.y - scene_min.y,tmp); tmp = aisgl_max(scene_max.z - scene_min.z,tmp); tmp = 1.f / tmp; glScalef(tmp, tmp, tmp); /* center the model */ glTranslatef( -scene_center.x, -scene_center.y, -scene_center.z ); /* if the display list has not been made yet, create a new one and fill it with scene contents */ if(scene_list == 0) { scene_list = glGenLists(1); glNewList(scene_list, GL_COMPILE); /* now begin at the root node of the imported data and traverse the scenegraph by multiplying subsequent local transforms together on GL's matrix stack. */ recursive_render(scene, scene->mRootNode); glEndList(); } glCallList(scene_list); glutSwapBuffers(); do_motion(); } /* ---------------------------------------------------------------------------- */ int loadasset (const char* path) { /* we are taking one of the postprocessing presets to avoid spelling out 20+ single postprocessing flags here. */ scene = aiImportFile(path,aiProcessPreset_TargetRealtime_MaxQuality); if (scene) { get_bounding_box(&scene_min,&scene_max); scene_center.x = (scene_min.x + scene_max.x) / 2.0f; scene_center.y = (scene_min.y + scene_max.y) / 2.0f; scene_center.z = (scene_min.z + scene_max.z) / 2.0f; return 0; } return 1; } /* ---------------------------------------------------------------------------- */ int main(int argc, char **argv) { struct aiLogStream stream; glutInitWindowSize(900,600); glutInitWindowPosition(100,100); glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH); glutInit(&argc, argv); glutCreateWindow("Assimp - Very simple OpenGL sample"); glutDisplayFunc(display); glutReshapeFunc(reshape); /* get a handle to the predefined STDOUT log stream and attach it to the logging system. It remains active for all further calls to aiImportFile(Ex) and aiApplyPostProcessing. */ stream = aiGetPredefinedLogStream(aiDefaultLogStream_STDOUT,NULL); aiAttachLogStream(&stream); /* ... same procedure, but this stream now writes the log messages to assimp_log.txt */ stream = aiGetPredefinedLogStream(aiDefaultLogStream_FILE,"assimp_log.txt"); aiAttachLogStream(&stream); /* the model name can be specified on the command line. If none is specified, we try to locate one of the more expressive test models from the repository (/models-nonbsd may be missing in some distributions so we need a fallback from /models!). */ if( 0 != loadasset( argc >= 2 ? argv[1] : "../../test/models-nonbsd/X/dwarf.x")) { if( argc != 1 || (0 != loadasset( "../../../../test/models-nonbsd/X/dwarf.x") && 0 != loadasset( "../../test/models/X/Testwuson.X"))) { return -1; } } glClearColor(0.1f,0.1f,0.1f,1.f); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); /* Uses default lighting parameters */ glEnable(GL_DEPTH_TEST); glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE); glEnable(GL_NORMALIZE); /* XXX docs say all polygons are emitted CCW, but tests show that some aren't. */ if(getenv("MODEL_IS_BROKEN")) glFrontFace(GL_CW); glColorMaterial(GL_FRONT_AND_BACK, GL_DIFFUSE); glutGet(GLUT_ELAPSED_TIME); glutMainLoop(); /* cleanup - calling 'aiReleaseImport' is important, as the library keeps internal resources until the scene is freed again. Not doing so can cause severe resource leaking. */ aiReleaseImport(scene); /* We added a log stream to the library, it's our job to disable it again. This will definitely release the last resources allocated by Assimp.*/ aiDetachAllLogStreams(); return 0; } assimp-4.1.0/assimp-config-version.cmake.in0000644002537200234200000000445713213503245021117 0ustar zmoelnigiemusers# Open Asset Import Library (assimp) # ---------------------------------------------------------------------- # Copyright (c) 2006-2017, assimp team # All rights reserved. # # Redistribution and use of this software 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 the assimp team, nor the names of its # contributors may be used to endorse or promote products # derived from this software without specific prior # written permission of the assimp team. # # 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. #---------------------------------------------------------------------- set( PACKAGE_VERSION "@ASSIMP_VERSION@" ) if( "${PACKAGE_FIND_VERSION}" VERSION_EQUAL "@ASSIMP_VERSION@") set(PACKAGE_VERSION_EXACT 1) endif() if( "${PACKAGE_FIND_VERSION_MAJOR}.${PACKAGE_FIND_VERSION_MINOR}" EQUAL "@ASSIMP_VERSION@" ) set(PACKAGE_VERSION_COMPATIBLE 1) elseif( "${PACKAGE_FIND_VERSION_MAJOR}" EQUAL "@ASSIMP_VERSION_MAJOR@" ) # for now backward compatible if minor version is less if( ${PACKAGE_FIND_VERSION_MINOR} LESS @ASSIMP_VERSION_MINOR@ ) set(PACKAGE_VERSION_COMPATIBLE 1) endif() endif() set( ASSIMP_STATIC_LIB "@ASSIMP_BUILD_STATIC_LIB@") assimp-4.1.0/contrib/0000755002537200234200000000000013213503245014714 5ustar zmoelnigiemusersassimp-4.1.0/contrib/openddlparser/0000755002537200234200000000000013213503245017556 5ustar zmoelnigiemusersassimp-4.1.0/contrib/openddlparser/CREDITS0000644002537200234200000000067413213503245020605 0ustar zmoelnigiemusers=============================================================== OpenDDL-Parser Developers and Contributors =============================================================== - Kim Kulling ( kimmi ): Founder - Fredrik Hansson ( FredrikHson ): Improvements value interface, serveral bugfixes. - Henry Read ( henrya2 ): Static build option, Interface improvements - (wise86-android) fix several mem-leaks - Paul Holland ( pkholland ): Bugfixes. assimp-4.1.0/contrib/openddlparser/README.md0000644002537200234200000001105013213503245021032 0ustar zmoelnigiemusersThe OpenDDL-Parser ================== The OpenDDL-Parser is a small and easy to use library for OpenDDL-file-format-parsing. OpenDDL is the shortcut for Open Data Description Language, a data-declaration language introduced by Eric Lengyel. Please check http://openddl.org/ if you want to learn more about it. Build status ============ Linux build status: [![Build Status](https://travis-ci.org/kimkulling/openddl-parser.png)](https://travis-ci.org/kimkulling/openddl-parser) Current coverity check status: Coverity Scan Build Status Current test coverage:[![Coverage Status](https://coveralls.io/repos/github/kimkulling/openddl-parser/badge.svg?branch=master)](https://coveralls.io/github/kimkulling/openddl-parser?branch=cpp_coveralls) Get the source code =================== You can get the code from our git repository, which is located at GitHub. You can clone the repository with the following command: > git clone https://github.com/kimkulling/openddl-parser.git Building the source from the GitHub-Repo ======================================== To build the library you need to install cmake first ( see http://www.cmake.org/ for more information ). Make also sure that a compiler tool-chain is installed on your machine. After installing it you can open a console and enter: > cmake CMakeLists.txt This command will generate a build environment for your preferred build tool ( for Visual-Studio-users the project files will be generated, for gcc-users the makefiles will be generated ). When using an IDE open the IDE and run the build. When using GNU-make type in your console: > make and that's all. When using Visual Studio CMake will generate you a solution for ythe library. Just build it there. Use the library =============== To use the OpenDDL-parser you need to build the lib first. Now add the > /include to your include-path and the > /lib to your lib-folder. Link the openddl.lib to your application. Here is a small example how to use the lib: ```cpp #include #include #include USE_ODDLPARSER_NS; int main( int argc, char *argv[] ) { if( argc < 3 ) { return 1; } char *filename( nullptr ); if( 0 == strncmp( FileOption, argv[ 1 ], strlen( FileOption ) ) ) { filename = argv[ 2 ]; } std::cout << "file to import: " << filename << std::endl; if( nullptr == filename ) { std::cerr << "Invalid filename." << std::endl; return Error; } FILE *fileStream = fopen( filename, "r+" ); if( NULL == filename ) { std::cerr << "Cannot open file " << filename << std::endl; return 1; } // obtain file size: fseek( fileStream, 0, SEEK_END ); const size_t size( ftell( fileStream ) ); rewind( fileStream ); if( size > 0 ) { char *buffer = new char[ size ]; const size_t readSize( fread( buffer, sizeof( char ), size, fileStream ) ); assert( readSize == size ); OpenDDLParser theParser; theParser.setBuffer( buffer, size ); const bool result( theParser.parse() ); if( !result ) { std::cerr << "Error while parsing file " << filename << "." << std::endl; } } return 0; } ``` How to access the imported data =============================== The data is organized as a tree. You can get the root-node of the tree with the following code: ```cpp OpenDDLParser theParser; theParser.setBuffer( buffer, size ); const bool result( theParser.parse() ); if ( result ) { DDLNode *root = theParser.getRoot(); DDLNode::DllNodeList childs = root->getChildNodeList(); for ( size_t i=0; igetProperty(); // to get properties std::string type = child->getType(); // to get the node type Value *values = child->getValue(); // to get the data; // to loop through all values while ( values != ddl_nullptr ) { int current = values->getInt32(); values = value->getNext(); } } } ``` The node instance called root contains the data. All data lists are organized as linked lists. Reference documentation ======================= Please check http://kimkulling.github.io/openddl-parser/doxygen_html/index.html. Projects using OpenDDL-Parser ============================= - Asset Importer Lib: https://github.com/assimp/assimp . assimp-4.1.0/contrib/openddlparser/include/0000755002537200234200000000000013213503245021201 5ustar zmoelnigiemusersassimp-4.1.0/contrib/openddlparser/include/openddlparser/0000755002537200234200000000000013213503245024043 5ustar zmoelnigiemusersassimp-4.1.0/contrib/openddlparser/include/openddlparser/OpenDDLCommon.h0000644002537200234200000001743013213503245026617 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #pragma once #include #include #include #include #include #ifndef _WIN32 # include #endif #if defined(_MSC_VER) && !defined( OPENDDL_STATIC_LIBARY ) # define TAG_DLL_EXPORT __declspec(dllexport) # define TAG_DLL_IMPORT __declspec(dllimport ) # ifdef OPENDDLPARSER_BUILD # define DLL_ODDLPARSER_EXPORT TAG_DLL_EXPORT # else # define DLL_ODDLPARSER_EXPORT TAG_DLL_IMPORT # endif // OPENDDLPARSER_BUILD # pragma warning( disable : 4251 ) #else # define DLL_ODDLPARSER_EXPORT #endif // _WIN32 // Namespace declarations, override this to avoid any conflicts #define BEGIN_ODDLPARSER_NS namespace ODDLParser { #define END_ODDLPARSER_NS } // namespace ODDLParser #define USE_ODDLPARSER_NS using namespace ODDLParser; BEGIN_ODDLPARSER_NS // We will use C++11 optional #ifndef OPENDDL_NO_USE_CPP11 // All C++11 constructs # define ddl_nullptr nullptr # define ddl_override override # define ddl_final final # define ddl_no_copy = delete #else // Fall-back for older compilers # define ddl_nullptr NULL # define ddl_override # define ddl_final # define ddl_no_copy #endif // OPENDDL_NO_USE_CPP11 // Forward declarations class DDLNode; class Value; struct Name; struct Identifier; struct Reference; struct Property; struct DataArrayList; // Platform-specific typedefs #ifdef _WIN32 typedef signed __int64 int64_impl; typedef unsigned __int64 uint64_impl; #else typedef int64_t int64_impl; typedef uint64_t uint64_impl; #endif // OpenDDL-specific data typedefs typedef signed char int8; ///< Signed integer, 1 byte typedef signed short int16; ///< Signed integer, 2 byte typedef signed int int32; ///< Signed integer, 4 byte typedef int64_impl int64; ///< Signed integer, 8 byte typedef unsigned char uint8; ///< Unsigned integer, 1 byte typedef unsigned short uint16; ///< Unsigned integer, 2 byte typedef unsigned int uint32; ///< Unsigned integer, 4 byte typedef uint64_impl uint64; ///< Unsigned integer, 8 byte /// @brief Stores a text. /// /// A text is stored in a simple character buffer. Texts buffer can be /// greater than the number of stored characters in them. struct DLL_ODDLPARSER_EXPORT Text { size_t m_capacity; ///< The capacity of the text. size_t m_len; ///< The length of the text. char *m_buffer; ///< The buffer with the text. /// @brief The constructor with a given text buffer. /// @param buffer [in] The buffer. /// @param numChars [in] The number of characters in the buffer. Text( const char *buffer, size_t numChars ); /// @brief The destructor. ~Text(); /// @brief Clears the text. void clear(); /// @brief Set a new text. /// @param buffer [in] The buffer. /// @param numChars [in] The number of characters in the buffer. void set( const char *buffer, size_t numChars ); /// @brief The compare operator for std::strings. bool operator == ( const std::string &name ) const; /// @brief The compare operator for Texts. bool operator == ( const Text &rhs ) const; private: Text( const Text & ) ddl_no_copy; Text &operator = ( const Text & ) ddl_no_copy; }; /// @brief Description of the type of a name. enum NameType { GlobalName, ///< Name is global. LocalName ///< Name is local. }; /// @brief Stores an OpenDDL-specific name struct DLL_ODDLPARSER_EXPORT Name { NameType m_type; ///< The type of the name ( @see NameType ). Text *m_id; ///< The id. /// @brief The constructor with the type and the id. /// @param type [in] The name type. /// @param id [in] The id. Name( NameType type, Text *id ); Name( const Name &name ); /// @brief The destructor. ~Name(); private: Name &operator = ( const Name& ) ddl_no_copy; }; /// @brief Stores a bundle of references. struct DLL_ODDLPARSER_EXPORT Reference { size_t m_numRefs; ///< The number of stored references. Name **m_referencedName; ///< The reference names. /// @brief The default constructor. Reference(); Reference( const Reference &ref ); /// @brief The constructor with an array of ref names. /// @param numrefs [in] The number of ref names. /// @param names [in] The ref names. Reference( size_t numrefs, Name **names ); /// @brief The destructor. ~Reference(); /// @brief Returns the size in bytes to store one deep reference copy. /// @return The size on bytes. size_t sizeInBytes(); private: Reference &operator = ( const Reference & ) ddl_no_copy; }; /// @brief Stores a property list. struct DLL_ODDLPARSER_EXPORT Property { Text *m_key; ///< The identifier / key of the property. Value *m_value; ///< The value assigned to its key / id ( ddl_nullptr if none ). Reference *m_ref; ///< References assigned to its key / id ( ddl_nullptr if none ). Property *m_next; ///< The next property ( ddl_nullptr if none ). /// @brief The default constructor. Property(); /// @brief The constructor for initialization. /// @param id [in] The identifier Property( Text *id ); /// @brief The destructor. ~Property(); private: Property( const Property & ) ddl_no_copy; Property &operator = ( const Property & ) ddl_no_copy; }; /// @brief Stores a data array list. struct DLL_ODDLPARSER_EXPORT DataArrayList { size_t m_numItems; ///< The number of items in the list. Value *m_dataList; ///< The data list ( a Value ). DataArrayList *m_next; ///< The next data array list ( ddl_nullptr if last ). Reference *m_refs; size_t m_numRefs; /// @brief The default constructor for initialization. DataArrayList(); /// @brief The destructor. ~DataArrayList(); /// @brief Gets the length of the array size_t size(); private: DataArrayList( const DataArrayList & ) ddl_no_copy; DataArrayList &operator = ( const DataArrayList & ) ddl_no_copy; }; /// @brief Stores the context of a parsed OpenDDL declaration. struct DLL_ODDLPARSER_EXPORT Context { DDLNode *m_root; ///< The root node of the OpenDDL node tree. /// @brief Constructor for initialization. Context(); /// @brief Destructor. ~Context(); /// @brief Clears the whole node tree. void clear(); private: Context( const Context & ) ddl_no_copy; Context &operator = ( const Context & ) ddl_no_copy; }; END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/include/openddlparser/OpenDDLParser.h0000644002537200234200000001651113213503245026622 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #pragma once #include #include #include #include #include #include BEGIN_ODDLPARSER_NS class DDLNode; class Value; struct Identifier; struct Reference; struct Property; template inline bool isEmbeddedCommentOpenTag( T *in, T *end ) { if ( in == end ) { return false; } if ( in == '/' && in+1 == '*' ) { return true; } return false; } /// @brief Utility function to search for the next token or the end of the buffer. /// @param in [in] The start position in the buffer. /// @param end [in] The end position in the buffer. /// @return Pointer showing to the next token or the end of the buffer. /// @detail Will not increase buffer when already a valid buffer was found. template inline T *lookForNextToken( T *in, T *end ) { while( ( in != end ) && ( isSpace( *in ) || isNewLine( *in ) || ',' == *in ) ) { in++; } return in; } /// @brief Utility function to go for the next token or the end of the buffer. /// @param in [in] The start position in the buffer. /// @param end [in] The end position in the buffer. /// @return Pointer showing to the next token or the end of the buffer. /// @detail Will increase buffer by a minimum of one. template inline T *getNextToken( T *in, T *end ) { T *tmp( in ); in = lookForNextToken( in, end ); if( tmp == in ) { in++; } return in; } /// @brief Defines the log severity. enum LogSeverity { ddl_debug_msg = 0, ///< Debug message, for debugging ddl_info_msg, ///< Info messages, normal mode ddl_warn_msg, ///< Parser warnings ddl_error_msg ///< Parser errors }; DLL_ODDLPARSER_EXPORT const char *getTypeToken( Value::ValueType type ); //------------------------------------------------------------------------------------------------- /// @class OpenDDLParser /// @ingroup OpenDDLParser /// /// @brief This is the main API for the OpenDDL-parser. /// /// Use instances of this class to manage the parsing and handling of your parser contexts. //------------------------------------------------------------------------------------------------- class DLL_ODDLPARSER_EXPORT OpenDDLParser { public: /// @brief The log callback function pointer. typedef void( *logCallback )( LogSeverity severity, const std::string &msg ); public: /// @brief The default class constructor. OpenDDLParser(); /// @brief The class constructor. /// @param buffer [in] The buffer /// @param len [in] Size of the buffer OpenDDLParser( const char *buffer, size_t len ); /// @brief The class destructor. ~OpenDDLParser(); /// @brief Setter for an own log callback function. /// @param callback [in] The own callback. void setLogCallback( logCallback callback ); /// @brief Getter for the log callback. /// @return The current log callback. logCallback getLogCallback() const; /// @brief Assigns a new buffer to parse. /// @param buffer [in] The buffer /// @param len [in] Size of the buffer void setBuffer( const char *buffer, size_t len ); /// @brief Assigns a new buffer to parse. /// @param buffer [in] The buffer as a std::vector. void setBuffer( const std::vector &buffer ); /// @brief Returns the buffer pointer. /// @return The buffer pointer. const char *getBuffer() const; /// @brief Returns the size of the buffer. /// @return The buffer size. size_t getBufferSize() const; /// @brief Clears all parser data, including buffer and active context. void clear(); /// @brief Starts the parsing of the OpenDDL-file. /// @return True in case of success, false in case of an error. /// @remark In case of errors check log. bool parse(); bool exportContext( Context *ctx, const std::string &filename ); /// @brief Returns the root node. /// @return The root node. DDLNode *getRoot() const; /// @brief Returns the parser context, only available in case of a succeeded parsing. /// @return Pointer to the active context or ddl_nullptr. Context *getContext() const; public: // parser helpers char *parseNextNode( char *current, char *end ); char *parseHeader( char *in, char *end ); char *parseStructure( char *in, char *end ); char *parseStructureBody( char *in, char *end, bool &error ); void pushNode( DDLNode *node ); DDLNode *popNode(); DDLNode *top(); static void normalizeBuffer( std::vector &buffer ); static char *parseName( char *in, char *end, Name **name ); static char *parseIdentifier( char *in, char *end, Text **id ); static char *parsePrimitiveDataType( char *in, char *end, Value::ValueType &type, size_t &len ); static char *parseReference( char *in, char *end, std::vector &names ); static char *parseBooleanLiteral( char *in, char *end, Value **boolean ); static char *parseIntegerLiteral( char *in, char *end, Value **integer, Value::ValueType integerType = Value::ddl_int32 ); static char *parseFloatingLiteral( char *in, char *end, Value **floating, Value::ValueType floatType= Value::ddl_float ); static char *parseStringLiteral( char *in, char *end, Value **stringData ); static char *parseHexaLiteral( char *in, char *end, Value **data ); static char *parseProperty( char *in, char *end, Property **prop ); static char *parseDataList( char *in, char *end, Value::ValueType type, Value **data, size_t &numValues, Reference **refs, size_t &numRefs ); static char *parseDataArrayList( char *in, char *end, Value::ValueType type, DataArrayList **dataList ); static const char *getVersion(); private: OpenDDLParser( const OpenDDLParser & ) ddl_no_copy; OpenDDLParser &operator = ( const OpenDDLParser & ) ddl_no_copy; private: logCallback m_logCallback; std::vector m_buffer; typedef std::vector DDLNodeStack; DDLNodeStack m_stack; Context *m_context; }; END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/include/openddlparser/OpenDDLStream.h0000644002537200234200000000732413213503245026623 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #pragma once #include BEGIN_ODDLPARSER_NS //------------------------------------------------------------------------------------------------- /// @ingroup IOStreamBase /// @brief This class represents the stream to write out. //------------------------------------------------------------------------------------------------- class DLL_ODDLPARSER_EXPORT StreamFormatterBase { public: /// @brief The class constructor. StreamFormatterBase(); /// @brief The class destructor, virtual. virtual ~StreamFormatterBase(); /// @brief Will format the sring and return the new formatted result. /// @param statement [in] The string to reformat. /// @return The reformatted result. virtual std::string format(const std::string &statement); }; //------------------------------------------------------------------------------------------------- /// @ingroup IOStreamBase /// @brief This class represents the stream to write out. //------------------------------------------------------------------------------------------------- class DLL_ODDLPARSER_EXPORT IOStreamBase { public: /// @brief The class constructor with the formatter. /// @param formatter [in] The formatter to use. explicit IOStreamBase(StreamFormatterBase *formatter = ddl_nullptr); /// @brief The class destructor, virtual. virtual ~IOStreamBase(); /// @brief Will open the stream. /// @param name [in] The name for the stream. /// @return true, if the stream was opened successfully, false if not. virtual bool open(const std::string &name); /// @brief Will close the stream. /// @return true, if the stream was closed successfully, false if not. virtual bool close(); /// @brief Returns true, if the stream is open. /// @return true, if the stream is open, false if not. virtual bool isOpen() const; /// @brief Will read a string from the stream. /// @param sizeToRead [in] The size to read in bytes. /// @param statement [out] The read statements. /// @return The bytes read from the stream. virtual size_t read( size_t sizeToRead, std::string &statement ); /// @brief Will write a string into the stream. /// @param statement [in] The string to write. /// @return The bytes written into the stream. virtual size_t write(const std::string &statement); private: StreamFormatterBase *m_formatter; FILE *m_file; }; END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/include/openddlparser/DDLNode.h0000644002537200234200000001505013213503245025426 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #pragma once #include #include #include BEGIN_ODDLPARSER_NS // Forward declarations class IOStreamBase; class Value; class OpenDDLParser; struct Identifier; struct Reference; struct Property; struct DataArrayList; /// /// @ingroup OpenDDLParser /// @brief This class represents one single instance in the object tree of the parsed OpenDDL-file. /// /// A DDLNode represents one leaf in the OpenDDL-node tree. It can have one parent node and multiple children. /// You can assign special properties to a single DDLNode instance. /// A node instance can store values via a linked list. You can get the first value from the DDLNode. /// A node can store data-array-lists and references as well. /// class DLL_ODDLPARSER_EXPORT DDLNode { public: friend class OpenDDLParser; /// @brief The child-node-list type. typedef std::vector DllNodeList; /// @brief The child-node-list iterator. typedef std::vector::iterator DDLNodeIt; public: /// @brief The class destructor. ~DDLNode(); /// @brief Will attach a parent node instance, an older one will be released. /// @param parent [in] The parent node instance. void attachParent( DDLNode *parent ); /// @brief Will try to detach a parent node instance, if there is any. void detachParent(); /// @brief Returns the assigned parent node instance, will return ddl_nullptr id no parent is assigned. /// @return The parent node instance. DDLNode *getParent() const; /// @brief Returns the child node list. /// @return The list of child nodes. const DllNodeList &getChildNodeList() const; /// Set the type of the DDLNode instance. /// @param type [in] The type. void setType( const std::string &type ); /// @brief Returns the type of the DDLNode instance. /// @return The type of the DDLNode instance. const std::string &getType() const; /// Set the name of the DDLNode instance. /// @param name [in] The name. void setName( const std::string &name ); /// @brief Returns the name of the DDLNode instance. /// @return The name of the DDLNode instance. const std::string &getName() const; /// @brief Set a new property set. /// @param prop [in] The first element of the property set. void setProperties( Property *prop ); /// @brief Returns the first element of the assigned property set. /// @return The first property of the assigned property set. Property *getProperties() const; /// @brief Looks for a given property. /// @param name [in] The name for the property to look for. /// @return true, if a corresponding property is assigned to the node, false if not. bool hasProperty( const std::string &name ); /// @brief Will return true, if any properties are assigned to the node instance. /// @return True, if properties are assigned. bool hasProperties() const; /// @brief Search for a given property and returns it. Will return ddl_nullptr if no property was found. /// @param name [in] The name for the property to look for. /// @return The property or ddl_nullptr if no property was found. Property *findPropertyByName( const std::string &name ); /// @brief Set a new value set. /// @param val [in] The first value instance of the value set. void setValue( Value *val ); /// @brief Returns the first element of the assigned value set. /// @return The first property of the assigned value set. Value *getValue() const; /// @brief Set a new DataArrayList. /// @param dtArrayList [in] The DataArrayList instance. void setDataArrayList( DataArrayList *dtArrayList ); /// @brief Returns the DataArrayList. /// @return The DataArrayList. DataArrayList *getDataArrayList() const; /// @brief Set a new Reference set. /// @param refs [in] The first value instance of the Reference set. void setReferences( Reference *refs ); /// @brief Returns the first element of the assigned Reference set. /// @return The first property of the assigned Reference set. Reference *getReferences() const; /// @brief Will dump the node into the stream. /// @param stream [in] The stream to write to. void dump(IOStreamBase &stream); /// @brief The creation method. /// @param type [in] The DDLNode type. /// @param name [in] The name for the new DDLNode instance. /// @param parent [in] The parent node instance or ddl_nullptr if no parent node is there. /// @return The new created node instance. static DDLNode *create( const std::string &type, const std::string &name, DDLNode *parent = ddl_nullptr ); private: DDLNode( const std::string &type, const std::string &name, size_t idx, DDLNode *parent = ddl_nullptr ); DDLNode(); DDLNode( const DDLNode & ) ddl_no_copy; DDLNode &operator = ( const DDLNode & ) ddl_no_copy; static void releaseNodes(); private: std::string m_type; std::string m_name; DDLNode *m_parent; std::vector m_children; Property *m_properties; Value *m_value; DataArrayList *m_dtArrayList; Reference *m_references; size_t m_idx; static DllNodeList s_allocatedNodes; }; END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/include/openddlparser/OpenDDLParserUtils.h0000644002537200234200000001472213213503245027645 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #pragma once #include BEGIN_ODDLPARSER_NS template inline bool isUpperCase( T in ) { return ( in >= 'A' && in <= 'Z' ); } template inline bool isLowerCase( T in ) { return ( in >= 'a' && in <= 'z' ); } template inline bool isSpace( const T in ) { return ( ' ' == in || '\t' == in ); } template inline bool isNewLine( const T in ) { return ( '\n' == in || ( '\r' == in ) ); } template inline bool isSeparator( T in ) { if( isSpace( in ) || ',' == in || '{' == in || '}' == in || '[' == in || '(' == in || ')' == in ) { return true; } return false; } static const unsigned char chartype_table[ 256 ] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0-15 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16-31 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 32-47 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 48-63 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 64-79 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 80-95 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 96-111 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 112-127 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // > 127 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, }; template inline bool isNumeric( const T in ) { return ( chartype_table[ static_cast( in ) ] == 1 ); } template inline bool isNotEndOfToken( T *in, T *end ) { return ( '}' != *in && ',' != *in && !isSpace( *in ) && ')' != *in && in != end ); } template inline bool isInteger( T *in, T *end ) { if( in != end ) { if( *in == '-' ) { ++in; } } bool result( false ); while( isNotEndOfToken( in, end ) ) { result = isNumeric( *in ); if( !result ) { break; } ++in; } return result; } template inline bool isFloat( T *in, T *end ) { if( in != end ) { if( *in == '-' ) { ++in; } } // check for <1>.0f bool result( false ); while( isNotEndOfToken( in, end ) ) { if( *in == '.' ) { result = true; break; } result = isNumeric( *in ); if( !result ) { return false; } ++in; } // check for 1<.>0f if( *in == '.' ) { ++in; } else { return false; } // check for 1.<0>f while( isNotEndOfToken( in, end ) ) { result = isNumeric( *in ); if( !result ) { return false; } ++in; } return result; } template inline bool isCharacter( const T in ) { return ( ( in >= 'a' && in <= 'z' ) || ( in >= 'A' && in <= 'Z' ) ); } template inline bool isStringLiteral( const T in ) { return ( in == '\"' ); } template inline bool isHexLiteral( T *in, T *end ) { if( *in == '0' ) { if( in + 1 != end ) { if( *( in + 1 ) == 'x' || *( in + 1 ) == 'X' ) { return true; } } } return false; } template inline bool isReference( T *in, T *end ) { if( *in == 'r' ) { if( *(in+1) == 'e' ) { if( *(in+2) == 'f' ) { if( ( in + 2 ) != end ) { return true; } } } } return false; } template inline bool isEndofLine( const T in ) { return ( '\n' == in ); } template inline static T *getNextSeparator( T *in, T *end ) { while( !isSeparator( *in ) || in == end ) { ++in; } return in; } static const int ErrorHex2Decimal = 9999999; inline int hex2Decimal( char in ) { if( isNumeric( in ) ) { return ( in - 48 ); } char hexCodeLower( 'a' ), hexCodeUpper( 'A' ); for( int i = 0; i<16; i++ ) { if( in == hexCodeLower + i || in == hexCodeUpper + i ) { return ( i+10 ); } } return ErrorHex2Decimal; } template inline bool isComment( T *in, T *end ) { if ( *in=='/' ) { if ( in+1!=end ) { if ( *( in+1 )=='/' ) { char *drive( ( in+2 ) ); if ( (isUpperCase( *drive )||isLowerCase( *drive ))&&*( drive+1 )=='/' ) { return false; } else { return true; } } } } return false; } template inline bool isCommentOpenTag(T *in, T *end ) { if (*in == '/') { if (in + 1 != end) { if (*(in + 1) == '*') { return true; } } } return false; } template inline bool isCommentCloseTag(T *in, T *end) { if (*in == '*') { if (in + 1 != end) { if (*(in + 1) == '/') { return true; } } } return false; } END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/include/openddlparser/OpenDDLExport.h0000644002537200234200000000642713213503245026654 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #pragma once #include #include #include BEGIN_ODDLPARSER_NS // Forward declarations class IOStreamBase; //------------------------------------------------------------------------------------------------- /// /// @ingroup OpenDDLParser /// @brief This class represents the OpenDDLExporter. /// //------------------------------------------------------------------------------------------------- class DLL_ODDLPARSER_EXPORT OpenDDLExport { public: /// @brief The class constructor OpenDDLExport( IOStreamBase *stream = ddl_nullptr ); /// @brief The class destructor. ~OpenDDLExport(); /// @brief Export the data of a parser context. /// @param ctx [in] Pointer to the context. /// @param filename [in] The filename for the export. /// @return True in case of success, false in case of an error. bool exportContext( Context *ctx, const std::string &filename ); /// @brief Handles a node export. /// @param node [in] The node to handle with. /// @return True in case of success, false in case of an error. bool handleNode( DDLNode *node ); /// @brief Writes the statement to the stream. /// @param statement [in] The content to write. /// @return True in case of success, false in case of an error. bool writeToStream( const std::string &statement ); protected: bool writeNode( DDLNode *node, std::string &statement ); bool writeNodeHeader( DDLNode *node, std::string &statement ); bool writeProperties( DDLNode *node, std::string &statement ); bool writeValueType( Value::ValueType type, size_t numItems, std::string &statement ); bool writeValue( Value *val, std::string &statement ); bool writeValueArray( DataArrayList *al, std::string &statement ); private: OpenDDLExport( const OpenDDLExport & ) ddl_no_copy; OpenDDLExport &operator = ( const OpenDDLExport & ) ddl_no_copy; private: IOStreamBase *m_stream; }; END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/include/openddlparser/Value.h0000644002537200234200000002250213213503245025271 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #pragma once #include #include BEGIN_ODDLPARSER_NS // Forward declarations struct ValueAllocator; class IOStreamBase; ///------------------------------------------------------------------------------------------------ /// @brief This class implements a value. /// /// Values are used to store data types like boolean, integer, floats, double and many mode. To get /// an overview please check the enum VylueType ( @see Value::ValueType ). /// Values can be single items or lists of items. They are implemented as linked lists. ///------------------------------------------------------------------------------------------------ class DLL_ODDLPARSER_EXPORT Value { friend struct ValueAllocator; public: /// @brief This class implements an iterator through a Value list. /// /// When getting a new value you need to know how to iterate through it. The Value::Iterator /// will help you here: /// @code /// Value *val = node->getValue(); /// Value::Iterator it( val ); /// while( it.hasNext() ) { /// Value v( it.getNext ); /// } /// @endcode class DLL_ODDLPARSER_EXPORT Iterator { public: /// @brief The default class constructor. Iterator(); /// @brief The class constructor with the start value. /// @param start [in] The first value for iteration, Iterator( Value *start ); Iterator( const Iterator &rhs ); /// @brief The class destructor. ~Iterator(); /// @brief Will return true, if another value is in the list. /// @return true if another value is there. bool hasNext() const; /// @brief Returns the next item and moves the iterator to it. /// @return The next value, is ddl_nullptr in case of being the last item. Value *getNext(); /// @brief The post-increment operator. const Iterator operator++( int ); /// @brief The pre-increment operator. Iterator &operator++( ); /// @brief The compare operator. /// @param rhs [in] The instance to compare. /// @return true if equal. bool operator == ( const Iterator &rhs ) const; /// @brief The * operator. /// @return The instance or ddl_nullptr if end of list is reached. Value *operator->( ) const; private: Value *m_start; Value *m_current; private: Iterator &operator = ( const Iterator & ); }; /// @brief This enum describes the data type stored in the value. enum ValueType { ddl_none = -1, ///< Nothing specified ddl_bool = 0, ///< A boolean type ddl_int8, ///< Integer type, 8 bytes ddl_int16, ///< Integer type, 16 bytes ddl_int32, ///< Integer type, 32 bytes ddl_int64, ///< Integer type, 64 bytes ddl_unsigned_int8, ///< Unsigned integer type, 8 bytes ddl_unsigned_int16, ///< Unsigned integer type, 16 bytes ddl_unsigned_int32, ///< Unsigned integer type, 32 bytes ddl_unsigned_int64, ///< Unsigned integer type, 64 bytes ddl_half, ///< Half data type. ddl_float, ///< float data type ddl_double, ///< Double data type. ddl_string, ///< String data type. ddl_ref, ///< Reference, used to define references to other data definitions. ddl_types_max ///< Upper limit. }; /// @brief The class constructor. /// @param type [in] The value type. Value( ValueType type ); /// @brief The class destructor. ~Value(); /// @brief Assigns a boolean to the value. /// @param value [in9 The value. void setBool( bool value ); /// @brief Returns the boolean value. /// @return The boolean value. bool getBool(); /// @brief Assigns a int8 to the value. /// @param value [in] The value. void setInt8( int8 value ); /// @brief Returns the int8 value. /// @return The int8 value. int8 getInt8(); /// @brief Assigns a int16 to the value. /// @param value [in] The value. void setInt16( int16 value ); /// @brief Returns the int16 value. /// @return The int16 value. int16 getInt16(); /// @brief Assigns a int32 to the value. /// @param value [in] The value. void setInt32( int32 value ); /// @brief Returns the int16 value. /// @return The int32 value. int32 getInt32(); /// @brief Assigns a int64 to the value. /// @param value [in] The value. void setInt64( int64 value ); /// @brief Returns the int16 value. /// @return The int64 value. int64 getInt64(); /// @brief Assigns a unsigned int8 to the value. /// @param value [in] The value. void setUnsignedInt8( uint8 value ); /// @brief Returns the unsigned int8 value. /// @return The unsigned int8 value. uint8 getUnsignedInt8() const; /// @brief Assigns a unsigned int16 to the value. /// @param value [in] The value. void setUnsignedInt16( uint16 value ); /// @brief Returns the unsigned int16 value. /// @return The unsigned int16 value. uint16 getUnsignedInt16() const; /// @brief Assigns a unsigned int32 to the value. /// @param value [in] The value. void setUnsignedInt32( uint32 value ); /// @brief Returns the unsigned int8 value. /// @return The unsigned int32 value. uint32 getUnsignedInt32() const; /// @brief Assigns a unsigned int64 to the value. /// @param value [in] The value. void setUnsignedInt64( uint64 value ); /// @brief Returns the unsigned int64 value. /// @return The unsigned int64 value. uint64 getUnsignedInt64() const; /// @brief Assigns a float to the value. /// @param value [in] The value. void setFloat( float value ); /// @brief Returns the float value. /// @return The float value. float getFloat() const; /// @brief Assigns a double to the value. /// @param value [in] The value. void setDouble( double value ); /// @brief Returns the double value. /// @return The double value. double getDouble() const; /// @brief Assigns a std::string to the value. /// @param str [in] The value. void setString( const std::string &str ); /// @brief Returns the std::string value. /// @return The std::string value. const char *getString() const; /// @brief Set the reference. /// @param ref [in] Pointer showing to the reference. void setRef( Reference *ref ); /// @brief Returns the pointer showing to the reference. /// @return Pointer showing to the reference. Reference *getRef() const; /// @brief Dumps the value. /// @param stream [in] The stream to write in. void dump( IOStreamBase &stream ); /// @brief Assigns the next value. /// @param next [n] The next value. void setNext( Value *next ); /// @brief Returns the next value. /// @return The next value.s Value *getNext() const; /// @brief Gets the length of the array. /// @return The number of items in the array. size_t size() const; ValueType m_type; size_t m_size; unsigned char *m_data; Value *m_next; private: Value &operator =( const Value & ) ddl_no_copy; Value( const Value & ) ddl_no_copy; }; ///------------------------------------------------------------------------------------------------ /// @brief This class implements the value allocator. ///------------------------------------------------------------------------------------------------ struct DLL_ODDLPARSER_EXPORT ValueAllocator { static Value *allocPrimData( Value::ValueType type, size_t len = 1 ); static void releasePrimData( Value **data ); private: ValueAllocator() ddl_no_copy; ValueAllocator( const ValueAllocator & ) ddl_no_copy; ValueAllocator &operator = ( const ValueAllocator & ) ddl_no_copy; }; END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/code/0000755002537200234200000000000013213503245020470 5ustar zmoelnigiemusersassimp-4.1.0/contrib/openddlparser/code/OpenDDLParser.cpp0000644002537200234200000007124713213503245023611 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #include #include #include #include #include #include #include #include #ifdef _WIN32 # include #endif // _WIN32 BEGIN_ODDLPARSER_NS static const char *Version = "0.4.0"; namespace Grammar { static const char *OpenBracketToken = "{"; static const char *CloseBracketToken = "}"; static const char *OpenPropertyToken = "("; static const char *ClosePropertyToken = ")"; static const char *OpenArrayToken = "["; static const char *CloseArrayToken = "]"; static const char *BoolTrue = "true"; static const char *BoolFalse = "false"; static const char *CommaSeparator = ","; static const char *PrimitiveTypeToken[ Value::ddl_types_max ] = { "bool", "int8", "int16", "int32", "int64", "unsigned_int8", "unsigned_int16", "unsigned_int32", "unsigned_int64", "half", "float", "double", "string", "ref" }; } // Namespace Grammar const char *getTypeToken( Value::ValueType type ) { return Grammar::PrimitiveTypeToken[ type ]; } static void logInvalidTokenError( char *in, const std::string &exp, OpenDDLParser::logCallback callback ) { std::stringstream stream; stream << "Invalid token \"" << *in << "\"" << " expected \"" << exp << "\"" << std::endl; std::string full( in ); std::string part( full.substr( 0, 50 ) ); stream << part; callback( ddl_error_msg, stream.str() ); } static bool isIntegerType( Value::ValueType integerType ) { if( integerType != Value::ddl_int8 && integerType != Value::ddl_int16 && integerType != Value::ddl_int32 && integerType != Value::ddl_int64 ) { return false; } return true; } static bool isUnsignedIntegerType( Value::ValueType integerType ) { if( integerType != Value::ddl_unsigned_int8 && integerType != Value::ddl_unsigned_int16 && integerType != Value::ddl_unsigned_int32 && integerType != Value::ddl_unsigned_int64 ) { return false; } return true; } static DDLNode *createDDLNode( Text *id, OpenDDLParser *parser ) { if( ddl_nullptr == id || ddl_nullptr == parser ) { return ddl_nullptr; } const std::string type( id->m_buffer ); DDLNode *parent( parser->top() ); DDLNode *node = DDLNode::create( type, "", parent ); return node; } static void logMessage( LogSeverity severity, const std::string &msg ) { std::string log; if( ddl_debug_msg == severity ) { log += "Debug:"; } else if( ddl_info_msg == severity ) { log += "Info :"; } else if( ddl_warn_msg == severity ) { log += "Warn :"; } else if( ddl_error_msg == severity ) { log += "Error:"; } else { log += "None :"; } log += msg; std::cout << log; } OpenDDLParser::OpenDDLParser() : m_logCallback( logMessage ) , m_buffer() , m_stack() , m_context( ddl_nullptr ) { // empty } OpenDDLParser::OpenDDLParser( const char *buffer, size_t len ) : m_logCallback( &logMessage ) , m_buffer() , m_context( ddl_nullptr ) { if( 0 != len ) { setBuffer( buffer, len ); } } OpenDDLParser::~OpenDDLParser() { clear(); } void OpenDDLParser::setLogCallback( logCallback callback ) { if( ddl_nullptr != callback ) { // install user-specific log callback m_logCallback = callback; } else { // install default log callback m_logCallback = &logMessage; } } OpenDDLParser::logCallback OpenDDLParser::getLogCallback() const { return m_logCallback; } void OpenDDLParser::setBuffer( const char *buffer, size_t len ) { clear(); if( 0 == len ) { return; } m_buffer.resize( len ); ::memcpy(&m_buffer[ 0 ], buffer, len ); } void OpenDDLParser::setBuffer( const std::vector &buffer ) { clear(); m_buffer.resize( buffer.size() ); std::copy( buffer.begin(), buffer.end(), m_buffer.begin() ); } const char *OpenDDLParser::getBuffer() const { if( m_buffer.empty() ) { return ddl_nullptr; } return &m_buffer[ 0 ]; } size_t OpenDDLParser::getBufferSize() const { return m_buffer.size(); } void OpenDDLParser::clear() { m_buffer.resize( 0 ); if( ddl_nullptr != m_context ) { delete m_context; m_context=ddl_nullptr; } // DDLNode::releaseNodes(); } bool OpenDDLParser::parse() { if( m_buffer.empty() ) { return false; } normalizeBuffer( m_buffer ); m_context = new Context; m_context->m_root = DDLNode::create( "root", "", ddl_nullptr ); pushNode( m_context->m_root ); // do the main parsing char *current( &m_buffer[ 0 ] ); char *end( &m_buffer[m_buffer.size() - 1 ] + 1 ); size_t pos( current - &m_buffer[ 0 ] ); while( pos < m_buffer.size() ) { current = parseNextNode( current, end ); if ( current == ddl_nullptr ) { return false; } pos = current - &m_buffer[ 0 ]; } return true; } bool OpenDDLParser::exportContext( Context *ctx, const std::string &filename ) { if( ddl_nullptr == ctx ) { return false; } OpenDDLExport myExporter; return myExporter.exportContext( ctx, filename ); } char *OpenDDLParser::parseNextNode( char *in, char *end ) { in = parseHeader( in, end ); in = parseStructure( in, end ); return in; } #ifdef DEBUG_HEADER_NAME static void dumpId( Identifier *id ) { if( ddl_nullptr != id ) { if ( ddl_nullptr != id->m_text.m_buffer ) { std::cout << id->m_text.m_buffer << std::endl; } } } #endif char *OpenDDLParser::parseHeader( char *in, char *end ) { if( ddl_nullptr == in || in == end ) { return in; } Text *id( ddl_nullptr ); in = OpenDDLParser::parseIdentifier( in, end, &id ); #ifdef DEBUG_HEADER_NAME dumpId( id ); #endif // DEBUG_HEADER_NAME in = lookForNextToken( in, end ); if( ddl_nullptr != id ) { // store the node DDLNode *node( createDDLNode( id, this ) ); if( ddl_nullptr != node ) { pushNode( node ); } else { std::cerr << "nullptr returned by creating DDLNode." << std::endl; } delete id; Name *name_(ddl_nullptr); in = OpenDDLParser::parseName(in, end, &name_); std::unique_ptr name(name_); if( ddl_nullptr != name && ddl_nullptr != node ) { const std::string nodeName( name->m_id->m_buffer ); node->setName( nodeName ); } std::unique_ptr first; in = lookForNextToken(in, end); if (*in == Grammar::OpenPropertyToken[0]) { in++; std::unique_ptr prop, prev; while (*in != Grammar::ClosePropertyToken[0] && in != end) { Property *prop_(ddl_nullptr); in = OpenDDLParser::parseProperty(in, end, &prop_); prop.reset(prop_); in = lookForNextToken(in, end); if (*in != Grammar::CommaSeparator[0] && *in != Grammar::ClosePropertyToken[0]) { logInvalidTokenError(in, Grammar::ClosePropertyToken, m_logCallback); return ddl_nullptr; } if (ddl_nullptr != prop && *in != Grammar::CommaSeparator[0]) { if (ddl_nullptr == first) { first = std::move(prop); } if (ddl_nullptr != prev) { prev->m_next = prop.release(); } prev = std::move(prop); } } ++in; } // set the properties if (first && ddl_nullptr != node) { node->setProperties(first.release()); } } return in; } char *OpenDDLParser::parseStructure( char *in, char *end ) { if( ddl_nullptr == in || in == end ) { return in; } bool error( false ); in = lookForNextToken( in, end ); if( *in == *Grammar::OpenBracketToken) { // loop over all children ( data and nodes ) do { in = parseStructureBody( in, end, error ); if(in == ddl_nullptr){ return ddl_nullptr; } } while ( *in != *Grammar::CloseBracketToken); ++in; } else { ++in; logInvalidTokenError( in, std::string( Grammar::OpenBracketToken ), m_logCallback ); return ddl_nullptr; } in = lookForNextToken( in, end ); // pop node from stack after successful parsing if( !error ) { popNode(); } return in; } static void setNodeValues( DDLNode *currentNode, Value *values ) { if( ddl_nullptr != values ){ if( ddl_nullptr != currentNode ) { currentNode->setValue( values ); } } } static void setNodeReferences( DDLNode *currentNode, Reference *refs ) { if( ddl_nullptr != refs ) { if( ddl_nullptr != currentNode ) { currentNode->setReferences( refs ); } } } static void setNodeDataArrayList( DDLNode *currentNode, DataArrayList *dtArrayList ) { if( ddl_nullptr != dtArrayList ) { if( ddl_nullptr != currentNode ) { currentNode->setDataArrayList( dtArrayList ); } } } char *OpenDDLParser::parseStructureBody( char *in, char *end, bool &error ) { if( !isNumeric( *in ) && !isCharacter( *in ) ) { ++in; } in = lookForNextToken( in, end ); Value::ValueType type( Value::ddl_none ); size_t arrayLen( 0 ); in = OpenDDLParser::parsePrimitiveDataType( in, end, type, arrayLen ); if( Value::ddl_none != type ) { // parse a primitive data type in = lookForNextToken( in, end ); if( *in == Grammar::OpenBracketToken[ 0 ] ) { Reference *refs( ddl_nullptr ); DataArrayList *dtArrayList( ddl_nullptr ); Value *values( ddl_nullptr ); if( 1 == arrayLen ) { size_t numRefs( 0 ), numValues( 0 ); in = parseDataList( in, end, type, &values, numValues, &refs, numRefs ); setNodeValues( top(), values ); setNodeReferences( top(), refs ); } else if( arrayLen > 1 ) { in = parseDataArrayList( in, end, type, &dtArrayList ); setNodeDataArrayList( top(), dtArrayList ); } else { std::cerr << "0 for array is invalid." << std::endl; error = true; } } in = lookForNextToken( in, end ); if( *in != '}' ) { logInvalidTokenError( in, std::string( Grammar::CloseBracketToken ), m_logCallback ); return ddl_nullptr; } else { //in++; } } else { // parse a complex data type in = parseNextNode( in, end ); } return in; } void OpenDDLParser::pushNode( DDLNode *node ) { if( ddl_nullptr == node ) { return; } m_stack.push_back( node ); } DDLNode *OpenDDLParser::popNode() { if( m_stack.empty() ) { return ddl_nullptr; } DDLNode *topNode( top() ); m_stack.pop_back(); return topNode; } DDLNode *OpenDDLParser::top() { if( m_stack.empty() ) { return ddl_nullptr; } DDLNode *top( m_stack.back() ); return top; } DDLNode *OpenDDLParser::getRoot() const { if( ddl_nullptr == m_context ) { return ddl_nullptr; } return m_context->m_root; } Context *OpenDDLParser::getContext() const { return m_context; } void OpenDDLParser::normalizeBuffer( std::vector &buffer) { if( buffer.empty() ) { return; } std::vector newBuffer; const size_t len( buffer.size() ); char *end( &buffer[ len-1 ] + 1 ); for( size_t readIdx = 0; readIdx( c, end ) && !isNewLine( *c ) ) { newBuffer.push_back( buffer[ readIdx ] ); } else { if( isComment( c, end ) ) { ++readIdx; // skip the comment and the rest of the line while( !isEndofLine( buffer[ readIdx ] ) ) { ++readIdx; } } } } buffer = newBuffer; } char *OpenDDLParser::parseName( char *in, char *end, Name **name ) { *name = ddl_nullptr; if( ddl_nullptr == in || in == end ) { return in; } // ignore blanks in = lookForNextToken( in, end ); if( *in != '$' && *in != '%' ) { return in; } NameType ntype( GlobalName ); if( *in == '%' ) { ntype = LocalName; } in++; Name *currentName( ddl_nullptr ); Text *id( ddl_nullptr ); in = parseIdentifier( in, end, &id ); if( id ) { currentName = new Name( ntype, id ); if( currentName ) { *name = currentName; } } return in; } char *OpenDDLParser::parseIdentifier( char *in, char *end, Text **id ) { *id = ddl_nullptr; if( ddl_nullptr == in || in == end ) { return in; } // ignore blanks in = lookForNextToken( in, end ); // staring with a number is forbidden if( isNumeric( *in ) ) { return in; } // get size of id size_t idLen( 0 ); char *start( in ); while( !isSeparator( *in ) && !isNewLine( *in ) && ( in != end ) && *in != Grammar::OpenPropertyToken[ 0 ] && *in != Grammar::ClosePropertyToken[ 0 ] && *in != '$' ) { ++in; ++idLen; } const size_t len( idLen ); *id = new Text( start, len ); return in; } char *OpenDDLParser::parsePrimitiveDataType( char *in, char *end, Value::ValueType &type, size_t &len ) { type = Value::ddl_none; len = 0; if( ddl_nullptr == in || in == end ) { return in; } size_t prim_len( 0 ); for( unsigned int i = 0; i < Value::ddl_types_max; i++ ) { prim_len = strlen( Grammar::PrimitiveTypeToken[ i ] ); if( 0 == strncmp( in, Grammar::PrimitiveTypeToken[ i ], prim_len ) ) { type = static_cast( i ); break; } } if( Value::ddl_none == type ) { in = lookForNextToken( in, end ); return in; } else { in += prim_len; } bool ok( true ); if( *in == Grammar::OpenArrayToken[ 0 ] ) { ok = false; ++in; char *start( in ); while ( in != end ) { ++in; if( *in == Grammar::CloseArrayToken[ 0 ] ) { len = ::atoi( start ); ok = true; ++in; break; } } } else { len = 1; } if( !ok ) { type = Value::ddl_none; } return in; } char *OpenDDLParser::parseReference( char *in, char *end, std::vector &names ) { if( ddl_nullptr == in || in == end ) { return in; } Name *nextName( ddl_nullptr ); in = parseName( in, end, &nextName ); if( nextName ) { names.push_back( nextName ); } while( Grammar::CommaSeparator[ 0 ] == *in ) { in = getNextSeparator( in, end ); if( Grammar::CommaSeparator[ 0 ] == *in ) { in = parseName( in, end, &nextName ); if( nextName ) { names.push_back( nextName ); } } else { break; } } return in; } char *OpenDDLParser::parseBooleanLiteral( char *in, char *end, Value **boolean ) { *boolean = ddl_nullptr; if( ddl_nullptr == in || in == end ) { return in; } in = lookForNextToken( in, end ); char *start( in ); size_t len( 0 ); while( !isSeparator( *in ) && in != end ) { ++in; ++len; } ++len; int res = ::strncmp( Grammar::BoolTrue, start, strlen( Grammar::BoolTrue ) ); if( 0 != res ) { res = ::strncmp( Grammar::BoolFalse, start, strlen( Grammar::BoolFalse ) ); if( 0 != res ) { *boolean = ddl_nullptr; return in; } *boolean = ValueAllocator::allocPrimData( Value::ddl_bool ); (*boolean)->setBool( false ); } else { *boolean = ValueAllocator::allocPrimData( Value::ddl_bool ); (*boolean)->setBool( true ); } return in; } char *OpenDDLParser::parseIntegerLiteral( char *in, char *end, Value **integer, Value::ValueType integerType ) { *integer = ddl_nullptr; if( ddl_nullptr == in || in == end ) { return in; } if( !(isIntegerType( integerType ) || isUnsignedIntegerType(integerType)) ) { return in; } in = lookForNextToken( in, end ); char *start( in ); while( !isSeparator( *in ) && in != end ) { ++in; } if( isNumeric( *start ) ) { #ifdef OPENDDL_NO_USE_CPP11 const int64 value( atol( start ) ); // maybe not really 64bit as atoll is but exists without c++11 const uint64 uvalue( strtoul( start,ddl_nullptr,10 ) ); #else const int64 value( atoll( start ) ); const uint64 uvalue( strtoull( start,ddl_nullptr,10 ) ); #endif *integer = ValueAllocator::allocPrimData( integerType ); switch( integerType ) { case Value::ddl_int8: ( *integer )->setInt8( (int8) value ); break; case Value::ddl_int16: ( *integer )->setInt16( ( int16 ) value ); break; case Value::ddl_int32: ( *integer )->setInt32( ( int32 ) value ); break; case Value::ddl_int64: ( *integer )->setInt64( ( int64 ) value ); break; case Value::ddl_unsigned_int8: ( *integer )->setUnsignedInt8( (uint8) uvalue ); break; case Value::ddl_unsigned_int16: ( *integer )->setUnsignedInt16( ( uint16 ) uvalue ); break; case Value::ddl_unsigned_int32: ( *integer )->setUnsignedInt32( ( uint32 ) uvalue ); break; case Value::ddl_unsigned_int64: ( *integer )->setUnsignedInt64( ( uint64 ) uvalue ); break; default: break; } } return in; } char *OpenDDLParser::parseFloatingLiteral( char *in, char *end, Value **floating, Value::ValueType floatType) { *floating = ddl_nullptr; if( ddl_nullptr == in || in == end ) { return in; } in = lookForNextToken( in, end ); char *start( in ); while( !isSeparator( *in ) && in != end ) { ++in; } // parse the float value bool ok( false ); if ( isHexLiteral( start, end ) ) { parseHexaLiteral( start, end, floating ); return in; } if( isNumeric( *start ) ) { ok = true; } else { if( *start == '-' ) { if( isNumeric( *(start+1) ) ) { ok = true; } } } if( ok ) { if ( floatType == Value::ddl_double ) { const double value( atof( start ) ); *floating = ValueAllocator::allocPrimData( Value::ddl_double ); ( *floating )->setDouble( value ); } else { const float value( ( float ) atof( start ) ); *floating = ValueAllocator::allocPrimData( Value::ddl_float ); ( *floating )->setFloat( value ); } } return in; } char *OpenDDLParser::parseStringLiteral( char *in, char *end, Value **stringData ) { *stringData = ddl_nullptr; if( ddl_nullptr == in || in == end ) { return in; } in = lookForNextToken( in, end ); size_t len( 0 ); char *start( in ); if( *start == '\"' ) { ++start; ++in; while( *in != '\"' && in != end ) { ++in; ++len; } *stringData = ValueAllocator::allocPrimData( Value::ddl_string, len ); ::strncpy( ( char* ) ( *stringData )->m_data, start, len ); ( *stringData )->m_data[len] = '\0'; ++in; } return in; } static void createPropertyWithData( Text *id, Value *primData, Property **prop ) { if( ddl_nullptr != primData ) { ( *prop ) = new Property( id ); ( *prop )->m_value = primData; } } char *OpenDDLParser::parseHexaLiteral( char *in, char *end, Value **data ) { *data = ddl_nullptr; if( ddl_nullptr == in || in == end ) { return in; } in = lookForNextToken( in, end ); if( *in != '0' ) { return in; } ++in; if( *in != 'x' && *in != 'X' ) { return in; } ++in; bool ok( true ); char *start( in ); int pos( 0 ); while( !isSeparator( *in ) && in != end ) { if( ( *in < '0' && *in > '9' ) || ( *in < 'a' && *in > 'f' ) || ( *in < 'A' && *in > 'F' ) ) { ok = false; break; } ++pos; ++in; } if( !ok ) { return in; } int value( 0 ); while( pos > 0 ) { int v = hex2Decimal( *start ); --pos; value = ( value << 4 ) | v; ++start; } *data = ValueAllocator::allocPrimData( Value::ddl_unsigned_int64 ); if( ddl_nullptr != *data ) { ( *data )->setUnsignedInt64( value ); } return in; } char *OpenDDLParser::parseProperty( char *in, char *end, Property **prop ) { *prop = ddl_nullptr; if( ddl_nullptr == in || in == end ) { return in; } in = lookForNextToken( in, end ); Text *id( ddl_nullptr ); in = parseIdentifier( in, end, &id ); if( ddl_nullptr != id ) { in = lookForNextToken( in, end ); if( *in == '=' ) { ++in; in = getNextToken( in, end ); Value *primData( ddl_nullptr ); if( isInteger( in, end ) ) { in = parseIntegerLiteral( in, end, &primData ); createPropertyWithData( id, primData, prop ); } else if( isFloat( in, end ) ) { in = parseFloatingLiteral( in, end, &primData ); createPropertyWithData( id, primData, prop ); } else if( isStringLiteral( *in ) ) { // string data in = parseStringLiteral( in, end, &primData ); createPropertyWithData( id, primData, prop ); } else { // reference data std::vector names; in = parseReference( in, end, names ); if( !names.empty() ) { Reference *ref = new Reference( names.size(), &names[ 0 ] ); ( *prop ) = new Property( id ); ( *prop )->m_ref = ref; } } } else { delete id; } } return in; } char *OpenDDLParser::parseDataList( char *in, char *end, Value::ValueType type, Value **data, size_t &numValues, Reference **refs, size_t &numRefs ) { *data = ddl_nullptr; numValues = numRefs = 0; if( ddl_nullptr == in || in == end ) { return in; } in = lookForNextToken( in, end ); if( *in == '{' ) { ++in; Value *current( ddl_nullptr ), *prev( ddl_nullptr ); while( '}' != *in ) { current = ddl_nullptr; in = lookForNextToken( in, end ); if ( Value::ddl_ref == type ) { std::vector names; in = parseReference( in, end, names ); if ( !names.empty() ) { Reference *ref = new Reference( names.size(), &names[ 0 ] ); *refs = ref; numRefs = names.size(); } } else if ( Value::ddl_none == type ) { if (isInteger( in, end )) { in = parseIntegerLiteral( in, end, ¤t ); } else if (isFloat( in, end )) { in = parseFloatingLiteral( in, end, ¤t ); } else if (isStringLiteral( *in )) { in = parseStringLiteral( in, end, ¤t ); } else if (isHexLiteral( in, end )) { in = parseHexaLiteral( in, end, ¤t ); } } else { switch(type){ case Value::ddl_int8: case Value::ddl_int16: case Value::ddl_int32: case Value::ddl_int64: case Value::ddl_unsigned_int8: case Value::ddl_unsigned_int16: case Value::ddl_unsigned_int32: case Value::ddl_unsigned_int64: in = parseIntegerLiteral( in, end, ¤t, type); break; case Value::ddl_half: case Value::ddl_float: case Value::ddl_double: in = parseFloatingLiteral( in, end, ¤t, type); break; case Value::ddl_string: in = parseStringLiteral( in, end, ¤t ); break; default: break; } } if( ddl_nullptr != current ) { if( ddl_nullptr == *data ) { *data = current; prev = current; } else { prev->setNext( current ); prev = current; } ++numValues; } in = getNextSeparator( in, end ); if( ',' != *in && Grammar::CloseBracketToken[ 0 ] != *in && !isSpace( *in ) ) { break; } } ++in; } return in; } static DataArrayList *createDataArrayList( Value *currentValue, size_t numValues, Reference *refs, size_t numRefs ) { DataArrayList *dataList( new DataArrayList ); dataList->m_dataList = currentValue; dataList->m_numItems = numValues; dataList->m_refs = refs; dataList->m_numRefs = numRefs; return dataList; } char *OpenDDLParser::parseDataArrayList( char *in, char *end,Value::ValueType type, DataArrayList **dataArrayList ) { if ( ddl_nullptr == dataArrayList ) { return in; } *dataArrayList = ddl_nullptr; if( ddl_nullptr == in || in == end ) { return in; } in = lookForNextToken( in, end ); if( *in == Grammar::OpenBracketToken[ 0 ] ) { ++in; Value *currentValue( ddl_nullptr ); Reference *refs( ddl_nullptr ); DataArrayList *prev( ddl_nullptr ), *currentDataList( ddl_nullptr ); do { size_t numRefs( 0 ), numValues( 0 ); currentValue = ddl_nullptr; in = parseDataList( in, end, type, ¤tValue, numValues, &refs, numRefs ); if( ddl_nullptr != currentValue || 0 != numRefs ) { if( ddl_nullptr == prev ) { *dataArrayList = createDataArrayList( currentValue, numValues, refs, numRefs ); prev = *dataArrayList; } else { currentDataList = createDataArrayList( currentValue, numValues, refs, numRefs ); if( ddl_nullptr != prev ) { prev->m_next = currentDataList; prev = currentDataList; } } } } while( Grammar::CommaSeparator[ 0 ] == *in && in != end ); in = lookForNextToken( in, end ); ++in; } return in; } const char *OpenDDLParser::getVersion() { return Version; } END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/code/Value.cpp0000644002537200234200000002510413213503245022252 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #include #include #include BEGIN_ODDLPARSER_NS static Value::Iterator end( ddl_nullptr ); Value::Iterator::Iterator() : m_start( ddl_nullptr ) , m_current( ddl_nullptr ) { // empty } Value::Iterator::Iterator( Value *start ) : m_start( start ) , m_current( start ) { // empty } Value::Iterator::Iterator( const Iterator &rhs ) : m_start( rhs.m_start ) , m_current( rhs.m_current ) { // empty } Value::Iterator::~Iterator() { // empty } bool Value::Iterator::hasNext() const { if( ddl_nullptr == m_current ) { return false; } return ( ddl_nullptr != m_current->getNext() ); } Value *Value::Iterator::getNext() { if( !hasNext() ) { return ddl_nullptr; } Value *v( m_current->getNext() ); m_current = v; return v; } const Value::Iterator Value::Iterator::operator++( int ) { if( ddl_nullptr == m_current ) { return end; } m_current = m_current->getNext(); Iterator inst( m_current ); return inst; } Value::Iterator &Value::Iterator::operator++( ) { if( ddl_nullptr == m_current ) { return end; } m_current = m_current->getNext(); return *this; } bool Value::Iterator::operator == ( const Iterator &rhs ) const { return ( m_current == rhs.m_current ); } Value *Value::Iterator::operator->( ) const { if(ddl_nullptr == m_current ) { return ddl_nullptr; } return m_current; } Value::Value( ValueType type ) : m_type( type ) , m_size( 0 ) , m_data( ddl_nullptr ) , m_next( ddl_nullptr ) { // empty } Value::~Value() { if(m_data!=ddl_nullptr) { if (m_type == ddl_ref ) { Reference *tmp = (Reference *) m_data; if (tmp != ddl_nullptr) delete tmp; }else delete[] m_data; } if(m_next!=ddl_nullptr) delete m_next; } void Value::setBool( bool value ) { assert( ddl_bool == m_type ); ::memcpy( m_data, &value, m_size ); } bool Value::getBool() { assert( ddl_bool == m_type ); return ( *m_data == 1 ); } void Value::setInt8( int8 value ) { assert( ddl_int8 == m_type ); ::memcpy( m_data, &value, m_size ); } int8 Value::getInt8() { assert( ddl_int8 == m_type ); return ( int8 ) ( *m_data ); } void Value::setInt16( int16 value ) { assert( ddl_int16 == m_type ); ::memcpy( m_data, &value, m_size ); } int16 Value::getInt16() { assert( ddl_int16 == m_type ); int16 i; ::memcpy( &i, m_data, m_size ); return i; } void Value::setInt32( int32 value ) { assert( ddl_int32 == m_type ); ::memcpy( m_data, &value, m_size ); } int32 Value::getInt32() { assert( ddl_int32 == m_type ); int32 i; ::memcpy( &i, m_data, m_size ); return i; } void Value::setInt64( int64 value ) { assert( ddl_int64 == m_type ); ::memcpy( m_data, &value, m_size ); } int64 Value::getInt64() { assert( ddl_int64 == m_type ); int64 i; ::memcpy( &i, m_data, m_size ); return i; } void Value::setUnsignedInt8( uint8 value ) { assert( ddl_unsigned_int8 == m_type ); ::memcpy( m_data, &value, m_size ); } uint8 Value::getUnsignedInt8() const { assert( ddl_unsigned_int8 == m_type ); uint8 i; ::memcpy( &i, m_data, m_size ); return i; } void Value::setUnsignedInt16( uint16 value ) { assert( ddl_unsigned_int16 == m_type ); ::memcpy( m_data, &value, m_size ); } uint16 Value::getUnsignedInt16() const { assert( ddl_unsigned_int16 == m_type ); uint16 i; ::memcpy( &i, m_data, m_size ); return i; } void Value::setUnsignedInt32( uint32 value ) { assert( ddl_unsigned_int32 == m_type ); ::memcpy( m_data, &value, m_size ); } uint32 Value::getUnsignedInt32() const { assert( ddl_unsigned_int32 == m_type ); uint32 i; ::memcpy( &i, m_data, m_size ); return i; } void Value::setUnsignedInt64( uint64 value ) { assert( ddl_unsigned_int64 == m_type ); ::memcpy( m_data, &value, m_size ); } uint64 Value::getUnsignedInt64() const { assert( ddl_unsigned_int64 == m_type ); uint64 i; ::memcpy( &i, m_data, m_size ); return i; } void Value::setFloat( float value ) { assert( ddl_float == m_type ); ::memcpy( m_data, &value, m_size ); } float Value::getFloat() const { if( m_type == ddl_float ) { float v; ::memcpy( &v, m_data, m_size ); return ( float ) v; } else { float tmp; ::memcpy( &tmp, m_data, 4 ); return ( float ) tmp; } } void Value::setDouble( double value ) { assert( ddl_double == m_type ); ::memcpy( m_data, &value, m_size ); } double Value::getDouble() const { if ( m_type == ddl_double ) { double v; ::memcpy( &v, m_data, m_size ); return ( float ) v; } else { double tmp; ::memcpy( &tmp, m_data, 4 ); return ( double ) tmp; } } void Value::setString( const std::string &str ) { assert( ddl_string == m_type ); ::memcpy( m_data, str.c_str(), str.size() ); m_data[ str.size() ] = '\0'; } const char *Value::getString() const { assert( ddl_string == m_type ); return (const char*) m_data; } void Value::setRef( Reference *ref ) { assert( ddl_ref == m_type ); if ( ddl_nullptr != ref ) { const size_t sizeInBytes( ref->sizeInBytes() ); if ( sizeInBytes > 0 ) { if ( ddl_nullptr != m_data ) { delete [] m_data; } m_data = (unsigned char*) new Reference(*ref); } } } Reference *Value::getRef() const { assert( ddl_ref == m_type ); return (Reference*) m_data; } void Value::dump( IOStreamBase &/*stream*/ ) { switch( m_type ) { case ddl_none: std::cout << "None" << std::endl; break; case ddl_bool: std::cout << getBool() << std::endl; break; case ddl_int8: std::cout << getInt8() << std::endl; break; case ddl_int16: std::cout << getInt16() << std::endl; break; case ddl_int32: std::cout << getInt32() << std::endl; break; case ddl_int64: std::cout << getInt64() << std::endl; break; case ddl_unsigned_int8: std::cout << "Not supported" << std::endl; break; case ddl_unsigned_int16: std::cout << "Not supported" << std::endl; break; case ddl_unsigned_int32: std::cout << "Not supported" << std::endl; break; case ddl_unsigned_int64: std::cout << "Not supported" << std::endl; break; case ddl_half: std::cout << "Not supported" << std::endl; break; case ddl_float: std::cout << getFloat() << std::endl; break; case ddl_double: std::cout << getDouble() << std::endl; break; case ddl_string: std::cout << getString() << std::endl; break; case ddl_ref: std::cout << "Not supported" << std::endl; break; default: break; } } void Value::setNext( Value *next ) { m_next = next; } Value *Value::getNext() const { return m_next; } size_t Value::size() const{ size_t result=1; Value *n=m_next; while( n!=ddl_nullptr) { result++; n=n->m_next; } return result; } Value *ValueAllocator::allocPrimData( Value::ValueType type, size_t len ) { if( type == Value::ddl_none || Value::ddl_types_max == type ) { return ddl_nullptr; } Value *data = new Value( type ); switch( type ) { case Value::ddl_bool: data->m_size = sizeof( bool ); break; case Value::ddl_int8: data->m_size = sizeof( int8 ); break; case Value::ddl_int16: data->m_size = sizeof( int16 ); break; case Value::ddl_int32: data->m_size = sizeof( int32 ); break; case Value::ddl_int64: data->m_size = sizeof( int64 ); break; case Value::ddl_unsigned_int8: data->m_size = sizeof( uint8 ); break; case Value::ddl_unsigned_int16: data->m_size = sizeof( uint16 ); break; case Value::ddl_unsigned_int32: data->m_size = sizeof( uint32 ); break; case Value::ddl_unsigned_int64: data->m_size = sizeof( uint64 ); break; case Value::ddl_half: data->m_size = sizeof( short ); break; case Value::ddl_float: data->m_size = sizeof( float ); break; case Value::ddl_double: data->m_size = sizeof( double ); break; case Value::ddl_string: data->m_size = sizeof( char )*(len+1); break; case Value::ddl_ref: data->m_size = 0; break; case Value::ddl_none: case Value::ddl_types_max: default: break; } if( data->m_size ) { data->m_data = new unsigned char[ data->m_size ]; ::memset(data->m_data,0,data->m_size); } return data; } void ValueAllocator::releasePrimData( Value **data ) { if( !data ) { return; } delete *data; *data = ddl_nullptr; } END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/code/OpenDDLExport.cpp0000644002537200234200000002506213213503245023630 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #include #include #include #include #include BEGIN_ODDLPARSER_NS struct DDLNodeIterator { const DDLNode::DllNodeList &m_childs; size_t m_idx; DDLNodeIterator( const DDLNode::DllNodeList &childs ) : m_childs( childs ) , m_idx( 0 ) { // empty } ~DDLNodeIterator() { // empty } bool getNext( DDLNode **node ) { if( m_childs.size() > (m_idx+1) ) { m_idx++; *node = m_childs[ m_idx ]; return true; } return false; } private: DDLNodeIterator() ddl_no_copy; DDLNodeIterator &operator = ( const DDLNodeIterator & ) ddl_no_copy; }; static void writeLineEnd( std::string &statement ) { statement += "\n"; } OpenDDLExport::OpenDDLExport( IOStreamBase *stream ) : m_stream( stream ) { if (ddl_nullptr == m_stream) { m_stream = new IOStreamBase(); } } OpenDDLExport::~OpenDDLExport() { if (ddl_nullptr != m_stream) { m_stream->close(); } delete m_stream; } bool OpenDDLExport::exportContext( Context *ctx, const std::string &filename ) { if( ddl_nullptr == ctx ) { return false; } DDLNode *root( ctx->m_root ); if ( ddl_nullptr == root ) { return true; } if (!filename.empty()) { if (!m_stream->open( filename )) { return false; } } const bool retValue( handleNode( root ) ); return retValue; } bool OpenDDLExport::handleNode( DDLNode *node ) { if( ddl_nullptr == node ) { return true; } const DDLNode::DllNodeList &childs = node->getChildNodeList(); if( childs.empty() ) { return true; } DDLNode *current( ddl_nullptr ); DDLNodeIterator it( childs ); std::string statement; bool success( true ); while( it.getNext( ¤t ) ) { if( ddl_nullptr != current ) { success |= writeNode( current, statement ); if( !handleNode( current ) ) { success = false; } } } return success; } bool OpenDDLExport::writeToStream( const std::string &statement ) { if (ddl_nullptr == m_stream ) { return false; } if ( !statement.empty()) { m_stream->write( statement ); } return true; } bool OpenDDLExport::writeNode( DDLNode *node, std::string &statement ) { writeNodeHeader( node, statement ); if (node->hasProperties()) { writeProperties( node, statement ); } writeLineEnd( statement ); statement = "}"; DataArrayList *al( node->getDataArrayList() ); if ( ddl_nullptr != al ) { writeValueType( al->m_dataList->m_type, al->m_numItems, statement ); writeValueArray( al, statement ); } Value *v( node->getValue() ); if (ddl_nullptr != v ) { writeValueType( v->m_type, 1, statement ); statement = "{"; writeLineEnd( statement ); writeValue( v, statement ); statement = "}"; writeLineEnd( statement ); } statement = "}"; writeLineEnd( statement ); writeToStream( statement ); return true; } bool OpenDDLExport::writeNodeHeader( DDLNode *node, std::string &statement ) { if (ddl_nullptr == node) { return false; } statement += node->getType(); const std::string &name( node->getName() ); if ( !name.empty() ) { statement += " "; statement += "$"; statement += name; } return true; } bool OpenDDLExport::writeProperties( DDLNode *node, std::string &statement ) { if ( ddl_nullptr == node ) { return false; } Property *prop( node->getProperties() ); // if no properties are there, return if ( ddl_nullptr == prop ) { return true; } if ( ddl_nullptr != prop ) { // for instance (attrib = "position", bla=2) statement += "("; bool first( true ); while ( ddl_nullptr != prop ) { if (!first) { statement += ", "; } else { first = false; } statement += std::string( prop->m_key->m_buffer ); statement += " = "; writeValue( prop->m_value, statement ); prop = prop->m_next; } statement += ")"; } return true; } bool OpenDDLExport::writeValueType( Value::ValueType type, size_t numItems, std::string &statement ) { if ( Value::ddl_types_max == type) { return false; } const std::string typeStr( getTypeToken( type ) ); statement += typeStr; // if we have an array to write if ( numItems > 1 ) { statement += "["; char buffer[ 256 ]; ::memset( buffer, '\0', 256 * sizeof( char ) ); sprintf( buffer, "%d", static_cast( numItems ) ); statement += buffer; statement += "]"; } return true; } bool OpenDDLExport::writeValue( Value *val, std::string &statement ) { if (ddl_nullptr == val) { return false; } switch ( val->m_type ) { case Value::ddl_bool: if ( true == val->getBool() ) { statement += "true"; } else { statement += "false"; } break; case Value::ddl_int8: { std::stringstream stream; const int i = static_cast( val->getInt8() ); stream << i; statement += stream.str(); } break; case Value::ddl_int16: { std::stringstream stream; char buffer[ 256 ]; ::memset( buffer, '\0', 256 * sizeof( char ) ); sprintf( buffer, "%d", val->getInt16() ); statement += buffer; } break; case Value::ddl_int32: { std::stringstream stream; char buffer[ 256 ]; ::memset( buffer, '\0', 256 * sizeof( char ) ); const int i = static_cast< int >( val->getInt32() ); sprintf( buffer, "%d", i ); statement += buffer; } break; case Value::ddl_int64: { std::stringstream stream; const int i = static_cast< int >( val->getInt64() ); stream << i; statement += stream.str(); } break; case Value::ddl_unsigned_int8: { std::stringstream stream; const int i = static_cast< unsigned int >( val->getUnsignedInt8() ); stream << i; statement += stream.str(); } break; case Value::ddl_unsigned_int16: { std::stringstream stream; const int i = static_cast< unsigned int >( val->getUnsignedInt16() ); stream << i; statement += stream.str(); } break; case Value::ddl_unsigned_int32: { std::stringstream stream; const int i = static_cast< unsigned int >( val->getUnsignedInt32() ); stream << i; statement += stream.str(); } break; case Value::ddl_unsigned_int64: { std::stringstream stream; const int i = static_cast< unsigned int >( val->getUnsignedInt64() ); stream << i; statement += stream.str(); } break; case Value::ddl_half: break; case Value::ddl_float: { std::stringstream stream; stream << val->getFloat(); statement += stream.str(); } break; case Value::ddl_double: { std::stringstream stream; stream << val->getDouble(); statement += stream.str(); } break; case Value::ddl_string: { std::stringstream stream; stream << val->getString(); statement += "\""; statement += stream.str(); statement += "\""; } break; case Value::ddl_ref: break; case Value::ddl_none: case Value::ddl_types_max: default: break; } return true; } bool OpenDDLExport::writeValueArray( DataArrayList *al, std::string &statement ) { if (ddl_nullptr == al) { return false; } if (0 == al->m_numItems) { return true; } DataArrayList *nextDataArrayList = al ; while (ddl_nullptr != nextDataArrayList) { if (ddl_nullptr != nextDataArrayList) { statement += "{ "; Value *nextValue( nextDataArrayList->m_dataList ); size_t idx( 0 ); while (ddl_nullptr != nextValue) { if (idx > 0) { statement += ", "; } writeValue( nextValue, statement ); nextValue = nextValue->m_next; idx++; } statement += " }"; } nextDataArrayList = nextDataArrayList->m_next; } return true; } END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/code/OpenDDLStream.cpp0000644002537200234200000000546313213503245023605 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #include BEGIN_ODDLPARSER_NS StreamFormatterBase::StreamFormatterBase() { // empty } StreamFormatterBase::~StreamFormatterBase() { // empty } std::string StreamFormatterBase::format(const std::string &statement) { std::string tmp(statement); return tmp; } IOStreamBase::IOStreamBase(StreamFormatterBase *formatter) : m_formatter(formatter) , m_file(ddl_nullptr) { if (ddl_nullptr == m_formatter) { m_formatter = new StreamFormatterBase; } } IOStreamBase::~IOStreamBase() { delete m_formatter; m_formatter = ddl_nullptr; } bool IOStreamBase::open(const std::string &name) { m_file = ::fopen(name.c_str(), "a"); if (m_file == ddl_nullptr) { return false; } return true; } bool IOStreamBase::close() { if (ddl_nullptr == m_file) { return false; } ::fclose(m_file); m_file = ddl_nullptr; return true; } bool IOStreamBase::isOpen() const { return ( ddl_nullptr != m_file ); } size_t IOStreamBase::read( size_t sizeToRead, std::string &statement ) { if (ddl_nullptr == m_file) { return 0; } statement.resize(sizeToRead); const size_t readBytes = ::fread( &statement[0], 1, sizeToRead, m_file ); return readBytes; } size_t IOStreamBase::write(const std::string &statement) { if (ddl_nullptr == m_file) { return 0; } std::string formatStatement = m_formatter->format(statement); return ::fwrite(formatStatement.c_str(), sizeof(char), formatStatement.size(), m_file); } END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/code/OpenDDLCommon.cpp0000644002537200234200000001165513213503245023602 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #include #include #include BEGIN_ODDLPARSER_NS Text::Text( const char *buffer, size_t numChars ) : m_capacity( 0 ) , m_len( 0 ) , m_buffer( ddl_nullptr ) { set( buffer, numChars ); } Text::~Text() { clear(); } void Text::clear() { delete[] m_buffer; m_buffer = ddl_nullptr; m_capacity = 0; m_len = 0; } void Text::set( const char *buffer, size_t numChars ) { clear(); if( numChars > 0 ) { m_len = numChars; m_capacity = m_len + 1; m_buffer = new char[ m_capacity ]; strncpy( m_buffer, buffer, numChars ); m_buffer[ numChars ] = '\0'; } } bool Text::operator == ( const std::string &name ) const { if( m_len != name.size() ) { return false; } const int res( strncmp( m_buffer, name.c_str(), name.size() ) ); return ( 0 == res ); } bool Text::operator == ( const Text &rhs ) const { if( m_len != rhs.m_len ) { return false; } const int res( strncmp( m_buffer, rhs.m_buffer, m_len ) ); return ( 0 == res ); } Name::Name( NameType type, Text *id ) : m_type( type ) , m_id( id ) { // empty } Name::~Name() { delete m_id; m_id = ddl_nullptr; } Name::Name( const Name &name ){ m_type=name.m_type; m_id=new Text(name.m_id->m_buffer,name.m_id->m_len); } Reference::Reference() : m_numRefs( 0 ) , m_referencedName( ddl_nullptr ) { // empty } Reference::Reference( size_t numrefs, Name **names ) : m_numRefs( numrefs ) , m_referencedName( ddl_nullptr ) { if ( numrefs > 0 ) { m_referencedName = new Name *[ numrefs ]; for ( size_t i = 0; i < numrefs; i++ ) { m_referencedName[ i ] = names[i]; } } } Reference::Reference(const Reference &ref) { m_numRefs=ref.m_numRefs; if(m_numRefs!=0){ m_referencedName = new Name*[m_numRefs]; for ( size_t i = 0; i < m_numRefs; i++ ) { m_referencedName[i] = new Name(*ref.m_referencedName[i]); } } } Reference::~Reference() { for( size_t i = 0; i < m_numRefs; i++ ) { delete m_referencedName[ i ]; } m_numRefs = 0; delete [] m_referencedName; m_referencedName = ddl_nullptr; } size_t Reference::sizeInBytes() { if ( 0 == m_numRefs ) { return 0; } size_t size( 0 ); for ( size_t i = 0; i < m_numRefs; i++ ) { Name *name( m_referencedName[ i ] ); if ( ddl_nullptr != name ) { size += name->m_id->m_len; } } return size; } Property::Property( Text *id ) : m_key( id ) , m_value( ddl_nullptr ) , m_ref( ddl_nullptr ) , m_next( ddl_nullptr ) { // empty } Property::~Property() { delete m_key; if(m_value!=ddl_nullptr) delete m_value; if(m_ref!=ddl_nullptr) delete(m_ref); if(m_next!=ddl_nullptr) delete m_next; } DataArrayList::DataArrayList() : m_numItems( 0 ) , m_dataList( ddl_nullptr ) , m_next( ddl_nullptr ) , m_refs(ddl_nullptr) , m_numRefs(0){ // empty } DataArrayList::~DataArrayList() { delete m_dataList; if(m_next!=ddl_nullptr) delete m_next; if(m_refs!=ddl_nullptr) delete m_refs; } size_t DataArrayList::size() { size_t result( 0 ); if ( ddl_nullptr == m_next ) { if ( m_dataList != ddl_nullptr ) { result = 1; } return result; } DataArrayList *n( m_next ); while( ddl_nullptr != n ) { result++; n = n->m_next; } return result; } Context::Context() : m_root( ddl_nullptr ) { // empty } Context::~Context() { clear(); } void Context::clear() { delete m_root; m_root = ddl_nullptr; } END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/code/DDLNode.cpp0000644002537200234200000001267013213503245022413 0ustar zmoelnigiemusers/*----------------------------------------------------------------------------------------------- The MIT License (MIT) Copyright (c) 2014-2015 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -----------------------------------------------------------------------------------------------*/ #include #include #include BEGIN_ODDLPARSER_NS DDLNode::DllNodeList DDLNode::s_allocatedNodes; template inline static void releaseDataType( T *ptr ) { if( ddl_nullptr == ptr ) { return; } T *current( ddl_nullptr ); while( ptr ) { current = ptr; ptr = ptr->m_next; delete current; } } static void releaseReferencedNames( Reference *ref ) { if( ddl_nullptr == ref ) { return; } delete ref; } DDLNode::DDLNode( const std::string &type, const std::string &name, size_t idx, DDLNode *parent ) : m_type( type ) , m_name( name ) , m_parent( parent ) , m_children() , m_properties( ddl_nullptr ) , m_value( ddl_nullptr ) , m_dtArrayList( ddl_nullptr ) , m_references( ddl_nullptr ) , m_idx( idx ) { if( m_parent ) { m_parent->m_children.push_back( this ); } } DDLNode::~DDLNode() { delete m_properties; delete m_value; releaseReferencedNames( m_references ); delete m_dtArrayList; m_dtArrayList = ddl_nullptr; if( s_allocatedNodes[ m_idx ] == this ) { s_allocatedNodes[ m_idx ] = ddl_nullptr; } for ( size_t i = 0; im_children.push_back( this ); } } void DDLNode::detachParent() { if( ddl_nullptr != m_parent ) { DDLNodeIt it = std::find( m_parent->m_children.begin(), m_parent->m_children.end(), this ); if( m_parent->m_children.end() != it ) { m_parent->m_children.erase( it ); } m_parent = ddl_nullptr; } } DDLNode *DDLNode::getParent() const { return m_parent; } const DDLNode::DllNodeList &DDLNode::getChildNodeList() const { return m_children; } void DDLNode::setType( const std::string &type ) { m_type = type; } const std::string &DDLNode::getType() const { return m_type; } void DDLNode::setName( const std::string &name ) { m_name = name; } const std::string &DDLNode::getName() const { return m_name; } void DDLNode::setProperties( Property *prop ) { if(m_properties!=ddl_nullptr) delete m_properties; m_properties = prop; } Property *DDLNode::getProperties() const { return m_properties; } bool DDLNode::hasProperty( const std::string &name ) { const Property *prop( findPropertyByName( name ) ); return ( ddl_nullptr != prop ); } bool DDLNode::hasProperties() const { return( ddl_nullptr != m_properties ); } Property *DDLNode::findPropertyByName( const std::string &name ) { if( name.empty() ) { return ddl_nullptr; } if( ddl_nullptr == m_properties ) { return ddl_nullptr; } Property *current( m_properties ); while( ddl_nullptr != current ) { int res = strncmp( current->m_key->m_buffer, name.c_str(), name.size() ); if( 0 == res ) { return current; } current = current->m_next; } return ddl_nullptr; } void DDLNode::setValue( Value *val ) { m_value = val; } Value *DDLNode::getValue() const { return m_value; } void DDLNode::setDataArrayList( DataArrayList *dtArrayList ) { m_dtArrayList = dtArrayList; } DataArrayList *DDLNode::getDataArrayList() const { return m_dtArrayList; } void DDLNode::setReferences( Reference *refs ) { m_references = refs; } Reference *DDLNode::getReferences() const { return m_references; } void DDLNode::dump(IOStreamBase &/*stream*/) { // Todo! } DDLNode *DDLNode::create( const std::string &type, const std::string &name, DDLNode *parent ) { const size_t idx( s_allocatedNodes.size() ); DDLNode *node = new DDLNode( type, name, idx, parent ); s_allocatedNodes.push_back( node ); return node; } void DDLNode::releaseNodes() { if( s_allocatedNodes.size() > 0 ) { for( DDLNodeIt it = s_allocatedNodes.begin(); it != s_allocatedNodes.end(); it++ ) { if( *it ) { delete *it; } } s_allocatedNodes.clear(); } } END_ODDLPARSER_NS assimp-4.1.0/contrib/openddlparser/LICENSE0000644002537200234200000000206713213503245020570 0ustar zmoelnigiemusersThe MIT License (MIT) Copyright (c) 2014 Kim Kulling Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. assimp-4.1.0/contrib/openddlparser/CMakeLists.txt0000644002537200234200000001260413213503245022321 0ustar zmoelnigiemusersCMAKE_MINIMUM_REQUIRED( VERSION 2.6 ) PROJECT( OpenDDL-Parser ) SET ( OPENDDL_PARSER_VERSION_MAJOR 0 ) SET ( OPENDDL_PARSER_VERSION_MINOR 1 ) SET ( OPENDDL_PARSER_VERSION_PATCH 0 ) SET ( OPENDDL_PARSER_VERSION ${OPENDDL_PARSER_VERSION_MAJOR}.${OPENDDL_PARSER_VERSION_MINOR}.${OPENDDL_PARSER_VERSION_PATCH} ) SET ( PROJECT_VERSION "${OPENDDL_PARSER_VERSION}" ) option( DDL_USE_CPP11 "Set to ON to use C++11 features ( always on on windows )." ON ) option( DDL_DEBUG_OUTPUT "Set to ON to use output debug texts" OFF ) option( DDL_STATIC_LIBRARY "Set to ON to build static libary of OpenDDL Parser." ON ) option( COVERALLS "Generate coveralls data" OFF ) if ( DDL_USE_CPP11 ) if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) set( OPENDDL_CXXFLAGS -std=c++0x ) elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") set( OPENDDL_CXXFLAGS --std=c++11 ) endif() else( DDL_USE_CPP11 ) add_definitions( -DOPENDDL_NO_USE_CPP11 ) endif( DDL_USE_CPP11) if( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) find_package(Threads) else() add_definitions( -D_CRT_SECURE_NO_WARNINGS ) endif() if ( DDL_STATIC_LIBRARY ) add_definitions( -DOPENDDL_STATIC_LIBARY ) endif() add_definitions( -DOPENDDLPARSER_BUILD ) add_definitions( -D_VARIADIC_MAX=10 ) add_definitions( -DGTEST_HAS_PTHREAD=0 ) if ( DDL_DEBUG_OUTPUT ) add_definitions( -DDDL_DEBUG_HEADER_NAME) endif() INCLUDE_DIRECTORIES( ./ include/ contrib/gtest-1.7.0/include contrib/gtest-1.7.0/ ) link_directories( ${CMAKE_HOME_DIRECTORY}/lib ) set( CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake ) SET( CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/lib ) SET( CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/lib ) SET( CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/bin ) if( WIN32 AND NOT CYGWIN ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /EHsc" ) # Force to always compile with W4 if( CMAKE_CXX_FLAGS MATCHES "/W[0-4]" ) string( REGEX REPLACE "/W[0-4]" "/W4" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}" ) else() set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4" ) endif() elseif( CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX ) # Update if necessary set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic ${OPENDDL_CXXFLAGS}") elseif ( "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" ) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wno-long-long -pedantic ${OPENDDL_CXXFLAGS} -Wwrite-strings") endif() if (COVERALLS) include(Coveralls) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") endif() # Include the doc component. FIND_PACKAGE( doxygen ) IF ( DOXYGEN_FOUND ) CONFIGURE_FILE( doc/openddlparser_doc.in doc/doxygenfile @ONLY ) ADD_CUSTOM_TARGET( doc ALL ${DOXYGEN_EXECUTABLE} doc/doxygenfile WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} COMMENT "Generating API documentation with Doxygen" VERBATIM ) ENDIF ( DOXYGEN_FOUND ) SET ( openddl_parser_src code/OpenDDLCommon.cpp code/OpenDDLExport.cpp code/OpenDDLParser.cpp code/OpenDDLStream.cpp code/DDLNode.cpp code/Value.cpp include/openddlparser/OpenDDLCommon.h include/openddlparser/OpenDDLExport.h include/openddlparser/OpenDDLParser.h include/openddlparser/OpenDDLParserUtils.h include/openddlparser/OpenDDLStream.h include/openddlparser/DDLNode.h include/openddlparser/Value.h README.md ) SOURCE_GROUP( code FILES ${openddl_parser_src} ) if ( DDL_STATIC_LIBRARY ) ADD_LIBRARY( openddl_parser STATIC ${openddl_parser_src} ) else() ADD_LIBRARY( openddl_parser SHARED ${openddl_parser_src} ) endif() SET ( GTEST_PATH contrib/gtest-1.7.0 ) SET ( gtest_src ${GTEST_PATH}/src/gtest-death-test.cc ${GTEST_PATH}/src/gtest-filepath.cc ${GTEST_PATH}/src/gtest-internal-inl.h ${GTEST_PATH}/src/gtest-port.cc ${GTEST_PATH}/src/gtest-printers.cc ${GTEST_PATH}/src/gtest-test-part.cc ${GTEST_PATH}/src/gtest-typed-test.cc ${GTEST_PATH}/src/gtest.cc ${GTEST_PATH}/src/gtest_main.cc ) SET( openddl_parser_unittest_src test/UnitTestCommon.h test/DDLNodeTest.cpp test/OpenDDLCommonTest.cpp test/OpenDDLExportTest.cpp test/OpenDDLParserTest.cpp test/OpenDDLParserUtilsTest.cpp test/OpenDDLStreamTest.cpp test/OpenDDLIntegrationTest.cpp test/ValueTest.cpp test/OpenDDLDefectsTest.cpp ) SOURCE_GROUP( code FILES ${openddl_parser_unittest_src} ) SOURCE_GROUP( gtest FILES ${gtest_src} ) ADD_EXECUTABLE( openddl_parser_unittest ${gtest_src} ${openddl_parser_unittest_src} ) target_link_libraries( openddl_parser_unittest openddl_parser ${CMAKE_THREAD_LIBS_INIT} ) SET( openddl_parser_demo_src demo/main.cpp ) if (COVERALLS) set(COVERAGE_SRCS ${gtest_src} ${openddl_parser_unittest_src} ) # Create the coveralls target. coveralls_setup( "${COVERAGE_SRCS}" # The source files. ON # If we should upload. "${PROJECT_SOURCE_DIR}/cmake/") # (Optional) Alternate project cmake module path. endif() ADD_EXECUTABLE( openddl_parser_demo ${openddl_parser_demo_src} ) target_link_libraries( openddl_parser_demo openddl_parser ) assimp-4.1.0/contrib/irrXML_note.txt0000644002537200234200000000022113213503245017652 0ustar zmoelnigiemusers IrrXML Downloaded September 2008 - fixed a minor compiler warning (vs 2005, shift too large) - fixed an issue regarding wchar_t/unsigned short assimp-4.1.0/contrib/zip/0000755002537200234200000000000013213503245015516 5ustar zmoelnigiemusersassimp-4.1.0/contrib/zip/zip.png0000644002537200234200000001223313213503245017027 0ustar zmoelnigiemusersPNG  IHDR\rfsBIT|d pHYsHHetEXtSoftwarewww.inkscape.org<IDATx{eoOBA!"]\-GEE-"H+ (j[-lRak)$}`f?E|d}=3ϱid^ \liMU`f;? qzpKN5c7F}0H-,U}|??ÁՔϻ)h(K4\,nug;if-pp4Iv $ v"?jTw_ZXv'ЭbR8n R;zw#`gw?L;~d3;"vm'3,kOs+jyfMHw?9v1 ԷM;L~x'ّ)05_o1}D3;*v$x0OKN7 ᄮ@*0OY8N@*0 5ԕ +vpuj)@i\ڼt"3t&G{[IwݱfM4!+pk5ergc7QŁ}7p=T{},vuju4`%'<>e9fvpF#}yzRΚ LBFnm]R@Gb7Z` \OI- @`YzR 4rN`AFBZ<'p}"v#!= \4_F~0BmƓv9Dm;>"՝j(DH2"$ HxɄ@I@>HZ 6"he(DӺP443;0v#"; PİpHӁ7b6g&pmH\..8H|s1@6=@=1CP .gٞM i)wlF)Dg[M ifvp݃(Dt3{I(Dks`Q($= uWH n 1'UX 1xF3WGapD&:*qGbZ `M&2E|#vyO i!:!8CTH4x+pn^16 YP QJw_<ԐDrً35_=:|ic9:CSHkjef/']Fb k I(Bnf/%U&ODpG<@$ w883v/P~ qP LD Rw M>6D Rb7! z Qki6D Rgb7! St@"0H)D:L a St@"0H)D:L a Stظ4iߐ?ՀjjفV) r?Z/lSc b< j?+US9uk[`g`JMj؍ N}G{\fpo_ odcj97w~*Eyn6j%;UImpfv plOfUD}ْn? xaf>,f1cvJOFwB4o]Y> N?554C3sˀ]6=G }s}?)-IsCSH)~pb>GA*RMw:,:lJ} }H9 -@)G03vqߑOMĚ ܺ;l:pZ>bfgYE{Xe0}K58Kb\3 ezT OdY^^u^,XbŃfvW9 -⑜X{.?mlf5n- XN~)3"_-tʜ9sTfCw- 8udY6m[E&z\)p/˲*'hI9>^Ʃ+Jβ'1 8o+AQİLLp'eRlc]tdHR OKku$P [+lRA#wfye YUG ꊸgedY%K,.mA%楂 PٍlYj͚5V(&,R8ƃ~OdYv%K~T HR w$ׁzӀCCC[f7t}HP*p\vfO'9_'Q^K?IL m>B7 H9)^1\Cv)50Y@$^fYF~?EG26= |bSu:⒨6W\QWV$am [KSaf>1wkeawJQ@H8?zz@hcחX7̶݋Ӷx;7> p[DnGk[ Ogˀ/HMWe7.nG==`?bf3"nG҄*?7Lv&?DQFOD٫>ih i6 w>"!3G]wf p|~D:%f< |b #RA̓GTVRa1d[4bXp-pAExT}6v1VE_K$F,rFw2N"4wE$DZ8ݟjxLG =HD"Rt@"鰦`+JcfSs/rV4h-3{=j↤z?Ղ lƔ5xز,35`W`>fv Olc5 ҟ +6ek|3ecF5nWaZUyfXst;H)D:L a St@"0H)D:L a St@"0H)D:L a St@"0H)D:L amD&=th{< H\},pL${.>ѵ>p=|\ez" [k}<ޞ뉌f ?>$?H L X/'v?<&\[P;pYmGCΥ%W3{g"*I$j`f)Klewl |(pMk^@PL3SC]03w ;ul ,.NֈTff5#pu u _LxA Cl7s%w_~mf;T_75 Q!0H ^ US}@f6dfǓ}oĽE5&ڧ3 8D1pU8ʼnWtNmZ KkKaf;$ y30kI 3;8!o! 1Nf6x#}m~OwR H-,')ct^ɯmO}'&rA 3"}d-uUN%` w1ٟb" M dM77@iL6"K2"[wmHP:MTwuӃ&$;xwaip{^D&{OrxlKB@kIcM 'j,EdVÀ}6݋(K}73{=p1!2k}؍Cu~& I<+/ok `43 5yqpfҙJ.mGِkGpcvd\Y~^'`D#D4#IZ~1pItxۼ~TJ{9NoR̶^I,k:G[mݯovU ?;2=IENDB`assimp-4.1.0/contrib/zip/README.md0000644002537200234200000001102513213503245016774 0ustar zmoelnigiemusers### A portable (OSX/Linux/Windows), simple zip library written in C This is done by hacking awesome [miniz](https://code.google.com/p/miniz) library and layering functions on top of the miniz v1.15 API. [![Windows][win-badge]][win-link] [![OS X][osx-linux-badge]][osx-linux-link] [win-badge]: https://img.shields.io/appveyor/ci/kuba--/zip/master.svg?label=windows "AppVeyor build status" [win-link]: https://ci.appveyor.com/project/kuba--/zip "AppVeyor build status" [osx-linux-badge]: https://img.shields.io/travis/kuba--/zip/master.svg?label=linux/osx "Travis CI build status" [osx-linux-link]: https://travis-ci.org/kuba--/zip "Travis CI build status" # The Idea ... Some day, I was looking for zip library written in C for my project, but I could not find anything simple enough and lightweight. Everything what I tried required 'crazy mental gymnastics' to integrate or had some limitations or was too heavy. I hate frameworks, factories and adding new dependencies. If I must to install all those dependencies and link new library, I'm getting almost sick. I wanted something powerfull and small enough, so I could add just a few files and compile them into my project. And finally I found miniz. Miniz is a lossless, high performance data compression library in a single source file. I only needed simple interface to append buffers or files to the current zip-entry. Thanks to this feature I'm able to merge many files/buffers and compress them on-the-fly. It was the reason, why I decided to write zip module on top of the miniz. It required a little bit hacking and wrapping some functions, but I kept simplicity. So, you can grab these 3 files and compile them into your project. I hope that interface is also extremely simple, so you will not have any problems to understand it. # Examples * Create a new zip archive with default compression level. ```c struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); { zip_entry_open(zip, "foo-1.txt"); { char *buf = "Some data here..."; zip_entry_write(zip, buf, strlen(buf)); } zip_entry_close(zip); zip_entry_open(zip, "foo-2.txt"); { // merge 3 files into one entry and compress them on-the-fly. zip_entry_fwrite(zip, "foo-2.1.txt"); zip_entry_fwrite(zip, "foo-2.2.txt"); zip_entry_fwrite(zip, "foo-2.3.txt"); } zip_entry_close(zip); } zip_close(zip); ``` * Append to the existing zip archive. ```c struct zip_t *zip = zip_open("foo.zip", ZIP_DEFAULT_COMPRESSION_LEVEL, 'a'); { zip_entry_open(zip, "foo-3.txt"); { char *buf = "Append some data here..."; zip_entry_write(zip, buf, strlen(buf)); } zip_entry_close(zip); } zip_close(zip); ``` * Extract a zip archive into a folder. ```c int on_extract_entry(const char *filename, void *arg) { static int i = 0; int n = *(int *)arg; printf("Extracted: %s (%d of %d)\n", filename, ++i, n); return 0; } int arg = 2; zip_extract("foo.zip", "/tmp", on_extract_entry, &arg); ``` * Extract a zip entry into memory. ```c void *buf = NULL; size_t bufsize; struct zip_t *zip = zip_open("foo.zip", 0, 'r'); { zip_entry_open(zip, "foo-1.txt"); { zip_entry_read(zip, &buf, &bufsize); } zip_entry_close(zip); } zip_close(zip); free(buf); ``` * Extract a zip entry into memory using callback. ```c struct buffer_t { char *data; size_t size; }; static size_t on_extract(void *arg, unsigned long long offset, const void *data, size_t size) { struct buffer_t *buf = (struct buffer_t *)arg; buf->data = realloc(buf->data, buf->size + size + 1); assert(NULL != buf->data); memcpy(&(buf->data[buf->size]), data, size); buf->size += size; buf->data[buf->size] = 0; return size; } struct buffer_t buf = {0}; struct zip_t *zip = zip_open("foo.zip", 0, 'r'); { zip_entry_open(zip, "foo-1.txt"); { zip_entry_extract(zip, on_extract, &buf); } zip_entry_close(zip); } zip_close(zip); free(buf.data); ``` * Extract a zip entry into a file. ```c struct zip_t *zip = zip_open("foo.zip", 0, 'r'); { zip_entry_open(zip, "foo-2.txt"); { zip_entry_fread(zip, "foo-2.txt"); } zip_entry_close(zip); } zip_close(zip); ``` assimp-4.1.0/contrib/zip/.travis.yml0000644002537200234200000000025313213503245017627 0ustar zmoelnigiemuserslanguage: c # Compiler selection compiler: - clang - gcc # Build steps script: - mkdir build - cd build - cmake -DCMAKE_BUILD_TYPE=Debug .. && make && make test assimp-4.1.0/contrib/zip/UNLICENSE0000644002537200234200000000235113213503245016767 0ustar zmoelnigiemusers/* This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 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. For more information, please refer to */ assimp-4.1.0/contrib/zip/src/0000755002537200234200000000000013213503245016305 5ustar zmoelnigiemusersassimp-4.1.0/contrib/zip/src/zip.c0000644002537200234200000004232713213503245017263 0ustar zmoelnigiemusers/* * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ #include "zip.h" #include "miniz.h" #include #include #include #if defined _WIN32 || defined __WIN32__ /* Win32, DOS */ #include #define MKDIR(DIRNAME) _mkdir(DIRNAME) #define STRCLONE(STR) ((STR) ? _strdup(STR) : NULL) #define HAS_DEVICE(P) \ ((((P)[0] >= 'A' && (P)[0] <= 'Z') || ((P)[0] >= 'a' && (P)[0] <= 'z')) && \ (P)[1] == ':') #define FILESYSTEM_PREFIX_LEN(P) (HAS_DEVICE(P) ? 2 : 0) #define ISSLASH(C) ((C) == '/' || (C) == '\\') #else #define MKDIR(DIRNAME) mkdir(DIRNAME, 0755) #define STRCLONE(STR) ((STR) ? strdup(STR) : NULL) #endif #ifndef FILESYSTEM_PREFIX_LEN #define FILESYSTEM_PREFIX_LEN(P) 0 #endif #ifndef ISSLASH #define ISSLASH(C) ((C) == '/') #endif #define CLEANUP(ptr) \ do { \ if (ptr) { \ free((void *)ptr); \ ptr = NULL; \ } \ } while (0) static char *basename(const char *name) { char const *p; char const *base = name += FILESYSTEM_PREFIX_LEN(name); int all_slashes = 1; for (p = name; *p; p++) { if (ISSLASH(*p)) base = p + 1; else all_slashes = 0; } /* If NAME is all slashes, arrange to return `/'. */ if (*base == '\0' && ISSLASH(*name) && all_slashes) --base; return (char *)base; } static int mkpath(const char *path) { char const *p; char npath[MAX_PATH + 1] = {0}; int len = 0; for (p = path; *p && len < MAX_PATH; p++) { if (ISSLASH(*p) && len > 0) { if (MKDIR(npath) == -1) if (errno != EEXIST) return -1; } npath[len++] = *p; } return 0; } static char *strrpl(const char *str, char oldchar, char newchar) { char *rpl = (char *)malloc(sizeof(char) * (1 + strlen(str))); char *begin = rpl; char c; while((c = *str++)) { if (c == oldchar) { c = newchar; } *rpl++ = c; } *rpl = '\0'; return begin; } struct zip_entry_t { int index; const char *name; mz_uint64 uncomp_size; mz_uint64 comp_size; mz_uint32 uncomp_crc32; mz_uint64 offset; mz_uint8 header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; mz_uint64 header_offset; mz_uint16 method; mz_zip_writer_add_state state; tdefl_compressor comp; }; struct zip_t { mz_zip_archive archive; mz_uint level; struct zip_entry_t entry; char mode; }; struct zip_t *zip_open(const char *zipname, int level, char mode) { struct zip_t *zip = NULL; if (!zipname || strlen(zipname) < 1) { // zip_t archive name is empty or NULL goto cleanup; } if (level < 0) level = MZ_DEFAULT_LEVEL; if ((level & 0xF) > MZ_UBER_COMPRESSION) { // Wrong compression level goto cleanup; } zip = (struct zip_t *)calloc((size_t)1, sizeof(struct zip_t)); if (!zip) goto cleanup; zip->level = level; zip->mode = mode; switch (mode) { case 'w': // Create a new archive. if (!mz_zip_writer_init_file(&(zip->archive), zipname, 0)) { // Cannot initialize zip_archive writer goto cleanup; } break; case 'r': case 'a': if (!mz_zip_reader_init_file( &(zip->archive), zipname, level | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) { // An archive file does not exist or cannot initialize // zip_archive reader goto cleanup; } if (mode == 'a' && !mz_zip_writer_init_from_reader(&(zip->archive), zipname)) { mz_zip_reader_end(&(zip->archive)); goto cleanup; } break; default: goto cleanup; } return zip; cleanup: CLEANUP(zip); return NULL; } void zip_close(struct zip_t *zip) { if (zip) { // Always finalize, even if adding failed for some reason, so we have a // valid central directory. mz_zip_writer_finalize_archive(&(zip->archive)); mz_zip_writer_end(&(zip->archive)); mz_zip_reader_end(&(zip->archive)); CLEANUP(zip); } } int zip_entry_open(struct zip_t *zip, const char *entryname) { char *locname = NULL; size_t entrylen = 0; mz_zip_archive *pzip = NULL; mz_uint num_alignment_padding_bytes, level; if (!zip || !entryname) { return -1; } entrylen = strlen(entryname); if (entrylen < 1) { return -1; } pzip = &(zip->archive); /* .ZIP File Format Specification Version: 6.3.3 4.4.17.1 The name of the file, with optional relative path. The path stored MUST not contain a drive or device letter, or a leading slash. All slashes MUST be forward slashes '/' as opposed to backwards slashes '\' for compatibility with Amiga and UNIX file systems etc. If input came from standard input, there is no file name field. */ locname = strrpl(entryname, '\\', '/'); if (zip->mode == 'r') { zip->entry.index = mz_zip_reader_locate_file(pzip, locname, NULL, 0); CLEANUP(locname); return (zip->entry.index < 0) ? -1 : 0; } zip->entry.index = zip->archive.m_total_files; zip->entry.name = locname; if (!zip->entry.name) { // Cannot parse zip entry name return -1; } zip->entry.comp_size = 0; zip->entry.uncomp_size = 0; zip->entry.uncomp_crc32 = MZ_CRC32_INIT; zip->entry.offset = zip->archive.m_archive_size; zip->entry.header_offset = zip->archive.m_archive_size; memset(zip->entry.header, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE * sizeof(mz_uint8)); zip->entry.method = 0; num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pzip); if (!pzip->m_pState || (pzip->m_zip_mode != MZ_ZIP_MODE_WRITING)) { // Wrong zip mode return -1; } if (zip->level & MZ_ZIP_FLAG_COMPRESSED_DATA) { // Wrong zip compression level return -1; } // no zip64 support yet if ((pzip->m_total_files == 0xFFFF) || ((pzip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + entrylen) > 0xFFFFFFFF)) { // No zip64 support yet return -1; } if (!mz_zip_writer_write_zeros( pzip, zip->entry.offset, num_alignment_padding_bytes + sizeof(zip->entry.header))) { // Cannot memset zip entry header return -1; } zip->entry.header_offset += num_alignment_padding_bytes; if (pzip->m_file_offset_alignment) { MZ_ASSERT((zip->entry.header_offset & (pzip->m_file_offset_alignment - 1)) == 0); } zip->entry.offset += num_alignment_padding_bytes + sizeof(zip->entry.header); if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, zip->entry.name, entrylen) != entrylen) { // Cannot write data to zip entry return -1; } zip->entry.offset += entrylen; level = zip->level & 0xF; if (level) { zip->entry.state.m_pZip = pzip; zip->entry.state.m_cur_archive_file_ofs = zip->entry.offset; zip->entry.state.m_comp_size = 0; if (tdefl_init(&(zip->entry.comp), mz_zip_writer_add_put_buf_callback, &(zip->entry.state), tdefl_create_comp_flags_from_zip_params( level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) { // Cannot initialize the zip compressor return -1; } } return 0; } int zip_entry_close(struct zip_t *zip) { mz_zip_archive *pzip = NULL; mz_uint level; tdefl_status done; mz_uint16 entrylen; time_t t; struct tm *tm; mz_uint16 dos_time, dos_date; int status = -1; if (!zip) { // zip_t handler is not initialized return -1; } if (zip->mode == 'r') { return 0; } pzip = &(zip->archive); level = zip->level & 0xF; if (level) { done = tdefl_compress_buffer(&(zip->entry.comp), "", 0, TDEFL_FINISH); if (done != TDEFL_STATUS_DONE && done != TDEFL_STATUS_OKAY) { // Cannot flush compressed buffer goto cleanup; } zip->entry.comp_size = zip->entry.state.m_comp_size; zip->entry.offset = zip->entry.state.m_cur_archive_file_ofs; zip->entry.method = MZ_DEFLATED; } entrylen = (mz_uint16)strlen(zip->entry.name); t = time(NULL); tm = localtime(&t); dos_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); dos_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); // no zip64 support yet if ((zip->entry.comp_size > 0xFFFFFFFF) || (zip->entry.offset > 0xFFFFFFFF)) { // No zip64 support, yet goto cleanup; } if (!mz_zip_writer_create_local_dir_header( pzip, zip->entry.header, entrylen, 0, zip->entry.uncomp_size, zip->entry.comp_size, zip->entry.uncomp_crc32, zip->entry.method, 0, dos_time, dos_date)) { // Cannot create zip entry header goto cleanup; } if (pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.header_offset, zip->entry.header, sizeof(zip->entry.header)) != sizeof(zip->entry.header)) { // Cannot write zip entry header goto cleanup; } if (!mz_zip_writer_add_to_central_dir( pzip, zip->entry.name, entrylen, NULL, 0, "", 0, zip->entry.uncomp_size, zip->entry.comp_size, zip->entry.uncomp_crc32, zip->entry.method, 0, dos_time, dos_date, zip->entry.header_offset, 0)) { // Cannot write to zip central dir goto cleanup; } pzip->m_total_files++; pzip->m_archive_size = zip->entry.offset; status = 0; cleanup: CLEANUP(zip->entry.name); return status; } int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize) { mz_uint level; mz_zip_archive *pzip = NULL; tdefl_status status; if (!zip) { // zip_t handler is not initialized return -1; } pzip = &(zip->archive); if (buf && bufsize > 0) { zip->entry.uncomp_size += bufsize; zip->entry.uncomp_crc32 = (mz_uint32)mz_crc32( zip->entry.uncomp_crc32, (const mz_uint8 *)buf, bufsize); level = zip->level & 0xF; if (!level) { if ((pzip->m_pWrite(pzip->m_pIO_opaque, zip->entry.offset, buf, bufsize) != bufsize)) { // Cannot write buffer return -1; } zip->entry.offset += bufsize; zip->entry.comp_size += bufsize; } else { status = tdefl_compress_buffer(&(zip->entry.comp), buf, bufsize, TDEFL_NO_FLUSH); if (status != TDEFL_STATUS_DONE && status != TDEFL_STATUS_OKAY) { // Cannot compress buffer return -1; } } } return 0; } int zip_entry_fwrite(struct zip_t *zip, const char *filename) { int status = 0; size_t n = 0; FILE *stream = NULL; mz_uint8 buf[MZ_ZIP_MAX_IO_BUF_SIZE] = {0}; if (!zip) { // zip_t handler is not initialized return -1; } stream = fopen(filename, "rb"); if (!stream) { // Cannot open filename return -1; } while ((n = fread(buf, sizeof(mz_uint8), MZ_ZIP_MAX_IO_BUF_SIZE, stream)) > 0) { if (zip_entry_write(zip, buf, n) < 0) { status = -1; break; } } fclose(stream); return status; } int zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize) { mz_zip_archive *pzip = NULL; mz_uint idx; if (!zip) { // zip_t handler is not initialized return -1; } if (zip->mode != 'r' || zip->entry.index < 0) { // the entry is not found or we do not have read access return -1; } pzip = &(zip->archive); idx = (mz_uint)zip->entry.index; if (mz_zip_reader_is_file_a_directory(pzip, idx)) { // the entry is a directory return -1; } *buf = mz_zip_reader_extract_to_heap(pzip, idx, bufsize, 0); return (*buf) ? 0 : -1; } int zip_entry_fread(struct zip_t *zip, const char *filename) { mz_zip_archive *pzip = NULL; mz_uint idx; if (!zip) { // zip_t handler is not initialized return -1; } if (zip->mode != 'r' || zip->entry.index < 0) { // the entry is not found or we do not have read access return -1; } pzip = &(zip->archive); idx = (mz_uint)zip->entry.index; if (mz_zip_reader_is_file_a_directory(pzip, idx)) { // the entry is a directory return -1; } return (mz_zip_reader_extract_to_file(pzip, idx, filename, 0)) ? 0 : -1; } int zip_entry_extract(struct zip_t *zip, size_t (*on_extract)(void *arg, unsigned long long offset, const void *buf, size_t bufsize), void *arg) { mz_zip_archive *pzip = NULL; mz_uint idx; if (!zip) { // zip_t handler is not initialized return -1; } if (zip->mode != 'r' || zip->entry.index < 0) { // the entry is not found or we do not have read access return -1; } pzip = &(zip->archive); idx = (mz_uint)zip->entry.index; return (mz_zip_reader_extract_to_callback(pzip, idx, on_extract, arg, 0)) ? 0 : -1; } int zip_create(const char *zipname, const char *filenames[], size_t len) { int status = 0; size_t i; mz_zip_archive zip_archive; if (!zipname || strlen(zipname) < 1) { // zip_t archive name is empty or NULL return -1; } // Create a new archive. if (!memset(&(zip_archive), 0, sizeof(zip_archive))) { // Cannot memset zip archive return -1; } if (!mz_zip_writer_init_file(&zip_archive, zipname, 0)) { // Cannot initialize zip_archive writer return -1; } for (i = 0; i < len; ++i) { const char *name = filenames[i]; if (!name) { status = -1; break; } if (!mz_zip_writer_add_file(&zip_archive, basename(name), name, "", 0, ZIP_DEFAULT_COMPRESSION_LEVEL)) { // Cannot add file to zip_archive status = -1; break; } } mz_zip_writer_finalize_archive(&zip_archive); mz_zip_writer_end(&zip_archive); return status; } int zip_extract(const char *zipname, const char *dir, int (*on_extract)(const char *filename, void *arg), void *arg) { int status = -1; mz_uint i, n; char path[MAX_PATH + 1] = {0}; mz_zip_archive zip_archive; mz_zip_archive_file_stat info; size_t dirlen = 0; if (!memset(&(zip_archive), 0, sizeof(zip_archive))) { // Cannot memset zip archive return -1; } if (!zipname || !dir) { // Cannot parse zip archive name return -1; } dirlen = strlen(dir); if (dirlen + 1 > MAX_PATH) { return -1; } // Now try to open the archive. if (!mz_zip_reader_init_file(&zip_archive, zipname, 0)) { // Cannot initialize zip_archive reader return -1; } strcpy(path, dir); if (!ISSLASH(path[dirlen - 1])) { #if defined _WIN32 || defined __WIN32__ path[dirlen] = '\\'; #else path[dirlen] = '/'; #endif ++dirlen; } // Get and print information about each file in the archive. n = mz_zip_reader_get_num_files(&zip_archive); for (i = 0; i < n; ++i) { if (!mz_zip_reader_file_stat(&zip_archive, i, &info)) { // Cannot get information about zip archive; goto out; } strncpy(&path[dirlen], info.m_filename, MAX_PATH - dirlen); if (mkpath(path) < 0) { // Cannot make a path goto out; } if (!mz_zip_reader_is_file_a_directory(&zip_archive, i)) { if (!mz_zip_reader_extract_to_file(&zip_archive, i, path, 0)) { // Cannot extract zip archive to file goto out; } } if (on_extract) { if (on_extract(path, arg) < 0) { goto out; } } } status = 0; out: // Close the archive, freeing any resources it was using if (!mz_zip_reader_end(&zip_archive)) { // Cannot end zip reader status = -1; } return status; } assimp-4.1.0/contrib/zip/src/zip.h0000644002537200234200000001221213213503245017256 0ustar zmoelnigiemusers/* * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * IN NO EVENT SHALL THE AUTHORS 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. */ #pragma once #ifndef ZIP_H #define ZIP_H #include #ifdef __cplusplus extern "C" { #endif #ifndef MAX_PATH #define MAX_PATH 32767 /* # chars in a path name including NULL */ #endif #define ZIP_DEFAULT_COMPRESSION_LEVEL 6 /* This data structure is used throughout the library to represent zip archive - forward declaration. */ struct zip_t; /* Opens zip archive with compression level using the given mode. Args: zipname: zip archive file name. level: compression level (0-9 are the standard zlib-style levels). mode: file access mode. 'r': opens a file for reading/extracting (the file must exists). 'w': creates an empty file for writing. 'a': appends to an existing archive. Returns: The zip archive handler or NULL on error */ extern struct zip_t *zip_open(const char *zipname, int level, char mode); /* Closes zip archive, releases resources - always finalize. Args: zip: zip archive handler. */ extern void zip_close(struct zip_t *zip); /* Opens a new entry for writing in a zip archive. Args: zip: zip archive handler. entryname: an entry name in local dictionary. Returns: The return code - 0 on success, negative number (< 0) on error. */ extern int zip_entry_open(struct zip_t *zip, const char *entryname); /* Closes a zip entry, flushes buffer and releases resources. Args: zip: zip archive handler. Returns: The return code - 0 on success, negative number (< 0) on error. */ extern int zip_entry_close(struct zip_t *zip); /* Compresses an input buffer for the current zip entry. Args: zip: zip archive handler. buf: input buffer. bufsize: input buffer size (in bytes). Returns: The return code - 0 on success, negative number (< 0) on error. */ extern int zip_entry_write(struct zip_t *zip, const void *buf, size_t bufsize); /* Compresses a file for the current zip entry. Args: zip: zip archive handler. filename: input file. Returns: The return code - 0 on success, negative number (< 0) on error. */ extern int zip_entry_fwrite(struct zip_t *zip, const char *filename); /* Extracts the current zip entry into output buffer. The function allocates sufficient memory for a output buffer. Args: zip: zip archive handler. buf: output buffer. bufsize: output buffer size (in bytes). Note: - remember to release memory allocated for a output buffer. - for large entries, please take a look at zip_entry_extract function. Returns: The return code - 0 on success, negative number (< 0) on error. */ extern int zip_entry_read(struct zip_t *zip, void **buf, size_t *bufsize); /* Extracts the current zip entry into output file. Args: zip: zip archive handler. filename: output file. Returns: The return code - 0 on success, negative number (< 0) on error. */ extern int zip_entry_fread(struct zip_t *zip, const char *filename); /* Extract the current zip entry using a callback function (on_extract). Args: zip: zip archive handler. on_extract: callback function. arg: opaque pointer (optional argument, which you can pass to the on_extract callback) Returns: The return code - 0 on success, negative number (< 0) on error. */ extern int zip_entry_extract(struct zip_t *zip, size_t (*on_extract)(void *arg, unsigned long long offset, const void *data, size_t size), void *arg); /* Creates a new archive and puts files into a single zip archive. Args: zipname: zip archive file. filenames: input files. len: number of input files. Returns: The return code - 0 on success, negative number (< 0) on error. */ extern int zip_create(const char *zipname, const char *filenames[], size_t len); /* Extracts a zip archive file into directory. If on_extract_entry is not NULL, the callback will be called after successfully extracted each zip entry. Returning a negative value from the callback will cause abort and return an error. The last argument (void *arg) is optional, which you can use to pass data to the on_extract_entry callback. Args: zipname: zip archive file. dir: output directory. on_extract_entry: on extract callback. arg: opaque pointer. Returns: The return code - 0 on success, negative number (< 0) on error. */ extern int zip_extract(const char *zipname, const char *dir, int (*on_extract_entry)(const char *filename, void *arg), void *arg); #ifdef __cplusplus } #endif #endif assimp-4.1.0/contrib/zip/src/miniz.h0000644002537200234200000067135213213503245017622 0ustar zmoelnigiemusers/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing See "unlicense" statement at the end of this file. Rich Geldreich , last updated Oct. 13, 2013 Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros). * Change History 10/13/13 v1.15 r4 - Interim bugfix release while I work on the next major release with Zip64 support (almost there!): - Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug (thanks kahmyong.moon@hp.com) which could cause locate files to not find files. This bug would only have occured in earlier versions if you explicitly used this flag, OR if you used mz_zip_extract_archive_file_to_heap() or mz_zip_add_mem_to_archive_file_in_place() (which used this flag). If you can't switch to v1.15 but want to fix this bug, just remove the uses of this flag from both helper funcs (and of course don't use the flag). - Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when pUser_read_buf is not NULL and compressed size is > uncompressed size - Fixing mz_zip_reader_extract_*() funcs so they don't try to extract compressed data from directory entries, to account for weird zipfiles which contain zero-size compressed data on dir entries. Hopefully this fix won't cause any issues on weird zip archives, because it assumes the low 16-bits of zip external attributes are DOS attributes (which I believe they always are in practice). - Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the internal attributes, just the filename and external attributes - mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed - Added cmake support for Linux builds which builds all the examples, tested with clang v3.3 and gcc v4.6. - Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti - Merged MZ_FORCEINLINE fix from hdeanclark - Fix include before config #ifdef, thanks emil.brink - Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping (super useful for OpenGL apps), and explicit control over the compression level (so you can set it to 1 for real-time compression). - Merged in some compiler fixes from paulharris's github repro. - Retested this build under Windows (VS 2010, including static analysis), tcc 0.9.26, gcc v4.6 and clang v3.3. - Added example6.c, which dumps an image of the mandelbrot set to a PNG file. - Modified example2 to help test the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more. - In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix possible src file fclose() leak if alignment bytes+local header file write faiiled   - In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): Was pushing the wrong central dir header offset, appears harmless in this release, but it became a problem in the zip64 branch 5/20/12 v1.14 - MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include (thanks fermtect). 5/19/12 v1.13 - From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit. - Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files. - Eliminated a bunch of warnings when compiling with GCC 32-bit/64. - Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning). - Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64. - Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test. - Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives. - Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.) - Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself). 4/12/12 v1.12 - More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's. level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson for the feedback/bug report. 5/28/11 v1.11 - Added statement from unlicense.org 5/27/11 v1.10 - Substantial compressor optimizations: - Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a - Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86). - Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types. - Refactored the compression code for better readability and maintainability. - Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large drop in throughput on some files). 5/15/11 v1.09 - Initial stable release. * Low-level Deflate/Inflate implementation notes: Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses approximately as well as zlib. Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory block large enough to hold the entire file. The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation. * zlib-style API notes: miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in zlib replacement in many apps: The z_stream struct, optional memory allocation callbacks deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound inflateInit/inflateInit2/inflate/inflateEnd compress, compress2, compressBound, uncompress CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines. Supports raw deflate streams or standard zlib streams with adler-32 checking. Limitations: The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries. I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but there are no guarantees that miniz.c pulls this off perfectly. * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by Alex Evans. Supports 1-4 bytes/pixel images. * ZIP archive API notes: The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to get the job done with minimal fuss. There are simple API's to retrieve file information, read files from existing archives, create new archives, append new files to existing archives, or clone archive data from one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h), or you can specify custom file read/write callbacks. - Archive reading: Just call this function to read a single file from a disk archive: void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files. - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file: int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); The locate operation can optionally check file comments too, which (as one example) can be used to identify multiple versions of the same file in an archive. This function uses a simple linear search through the central directory, so it's not very fast. Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and retrieve detailed info on each file by calling mz_zip_reader_file_stat(). - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data to disk and builds an exact image of the central directory in memory. The central directory image is written all at once at the end of the archive file when the archive is finalized. The archive writer can optionally align each file's local header and file data to any power of 2 alignment, which can be useful when the archive will be read from optical media. Also, the writer supports placing arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still readable by any ZIP tool. - Archive appending: The simple way to add a single file to an archive is to call this function: mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); The archive will be created if it doesn't already exist, otherwise it'll be appended to. Note the appending is done in-place and is not an atomic operation, so if something goes wrong during the operation it's possible the archive could be left without a central directory (although the local file headers and file data will be fine, so the archive will be recoverable). For more complex archive modification scenarios: 1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and you're done. This is safe but requires a bunch of temporary disk space or heap memory. 2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(), append new files as needed, then finalize the archive which will write an updated central directory to the original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a possibility that the archive's central directory could be lost with this method if anything goes wrong, though. - ZIP archive support limitations: No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files. Requires streams capable of seeking. * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it. * Important: For best perf. be sure to customize the below macros for your target platform: #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1 #define MINIZ_LITTLE_ENDIAN 1 #define MINIZ_HAS_64BIT_REGISTERS 1 * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes). */ #ifndef MINIZ_HEADER_INCLUDED #define MINIZ_HEADER_INCLUDED #include // Defines to completely disable specific portions of miniz.c: // If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. // Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. //#define MINIZ_NO_STDIO // If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or // get/set file times, and the C run-time funcs that get/set times won't be called. // The current downside is the times written to your archives will be from 1979. //#define MINIZ_NO_TIME // Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. //#define MINIZ_NO_ARCHIVE_APIS // Define MINIZ_NO_ARCHIVE_APIS to disable all writing related ZIP archive API's. //#define MINIZ_NO_ARCHIVE_WRITING_APIS // Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. //#define MINIZ_NO_ZLIB_APIS // Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. //#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES // Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. // Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc // callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user // functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. //#define MINIZ_NO_MALLOC #if defined(__TINYC__) && (defined(__linux) || defined(__linux__)) // TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux #define MINIZ_NO_TIME #endif #if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS) #include #endif #if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__) // MINIZ_X86_OR_X64_CPU is only used to help set the below macros. #define MINIZ_X86_OR_X64_CPU 1 #endif #if (__BYTE_ORDER__==__ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU // Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. #define MINIZ_LITTLE_ENDIAN 1 #endif #if MINIZ_X86_OR_X64_CPU // Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 0 #endif #if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__) // Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). #define MINIZ_HAS_64BIT_REGISTERS 1 #endif #ifdef __APPLE__ #define ftello64 ftello #define fseeko64 fseeko #define fopen64 fopen #define freopen64 freopen #endif #ifdef __cplusplus extern "C" { #endif // ------------------- zlib-style API Definitions. // For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! typedef unsigned long mz_ulong; // mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. void mz_free(void *p); #define MZ_ADLER32_INIT (1) // mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len); #define MZ_CRC32_INIT (0) // mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len); // Compression strategies. enum { MZ_DEFAULT_STRATEGY = 0, MZ_FILTERED = 1, MZ_HUFFMAN_ONLY = 2, MZ_RLE = 3, MZ_FIXED = 4 }; // Method #define MZ_DEFLATED 8 #ifndef MINIZ_NO_ZLIB_APIS // Heap allocation callbacks. // Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size); typedef void (*mz_free_func)(void *opaque, void *address); typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size); #define MZ_VERSION "9.1.15" #define MZ_VERNUM 0x91F0 #define MZ_VER_MAJOR 9 #define MZ_VER_MINOR 1 #define MZ_VER_REVISION 15 #define MZ_VER_SUBREVISION 0 // Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). enum { MZ_NO_FLUSH = 0, MZ_PARTIAL_FLUSH = 1, MZ_SYNC_FLUSH = 2, MZ_FULL_FLUSH = 3, MZ_FINISH = 4, MZ_BLOCK = 5 }; // Return status codes. MZ_PARAM_ERROR is non-standard. enum { MZ_OK = 0, MZ_STREAM_END = 1, MZ_NEED_DICT = 2, MZ_ERRNO = -1, MZ_STREAM_ERROR = -2, MZ_DATA_ERROR = -3, MZ_MEM_ERROR = -4, MZ_BUF_ERROR = -5, MZ_VERSION_ERROR = -6, MZ_PARAM_ERROR = -10000 }; // Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. enum { MZ_NO_COMPRESSION = 0, MZ_BEST_SPEED = 1, MZ_BEST_COMPRESSION = 9, MZ_UBER_COMPRESSION = 10, MZ_DEFAULT_LEVEL = 6, MZ_DEFAULT_COMPRESSION = -1 }; // Window bits #define MZ_DEFAULT_WINDOW_BITS 15 struct mz_internal_state; // Compression/decompression stream struct. typedef struct mz_stream_s { const unsigned char *next_in; // pointer to next byte to read unsigned int avail_in; // number of bytes available at next_in mz_ulong total_in; // total number of bytes consumed so far unsigned char *next_out; // pointer to next byte to write unsigned int avail_out; // number of bytes that can be written to next_out mz_ulong total_out; // total number of bytes produced so far char *msg; // error msg (unused) struct mz_internal_state *state; // internal state, allocated by zalloc/zfree mz_alloc_func zalloc; // optional heap allocation function (defaults to malloc) mz_free_func zfree; // optional heap free function (defaults to free) void *opaque; // heap alloc function user pointer int data_type; // data_type (unused) mz_ulong adler; // adler32 of the source or uncompressed data mz_ulong reserved; // not used } mz_stream; typedef mz_stream *mz_streamp; // Returns the version string of miniz.c. const char *mz_version(void); // mz_deflateInit() initializes a compressor with default options: // Parameters: // pStream must point to an initialized mz_stream struct. // level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. // level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. // (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) // Return values: // MZ_OK on success. // MZ_STREAM_ERROR if the stream is bogus. // MZ_PARAM_ERROR if the input parameters are bogus. // MZ_MEM_ERROR on out of memory. int mz_deflateInit(mz_streamp pStream, int level); // mz_deflateInit2() is like mz_deflate(), except with more control: // Additional parameters: // method must be MZ_DEFLATED // window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) // mem_level must be between [1, 9] (it's checked but ignored by miniz.c) int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy); // Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). int mz_deflateReset(mz_streamp pStream); // mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. // Parameters: // pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. // flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. // Return values: // MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). // MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. // MZ_STREAM_ERROR if the stream is bogus. // MZ_PARAM_ERROR if one of the parameters is invalid. // MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) int mz_deflate(mz_streamp pStream, int flush); // mz_deflateEnd() deinitializes a compressor: // Return values: // MZ_OK on success. // MZ_STREAM_ERROR if the stream is bogus. int mz_deflateEnd(mz_streamp pStream); // mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len); // Single-call compression functions mz_compress() and mz_compress2(): // Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level); // mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). mz_ulong mz_compressBound(mz_ulong source_len); // Initializes a decompressor. int mz_inflateInit(mz_streamp pStream); // mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: // window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). int mz_inflateInit2(mz_streamp pStream, int window_bits); // Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. // Parameters: // pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. // flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. // On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). // MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. // Return values: // MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. // MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. // MZ_STREAM_ERROR if the stream is bogus. // MZ_DATA_ERROR if the deflate stream is invalid. // MZ_PARAM_ERROR if one of the parameters is invalid. // MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again // with more input data, or with more room in the output buffer (except when using single call decompression, described above). int mz_inflate(mz_streamp pStream, int flush); // Deinitializes a decompressor. int mz_inflateEnd(mz_streamp pStream); // Single-call decompression. // Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len); // Returns a string description of the specified error code, or NULL if the error code is invalid. const char *mz_error(int err); // Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. // Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES typedef unsigned char Byte; typedef unsigned int uInt; typedef mz_ulong uLong; typedef Byte Bytef; typedef uInt uIntf; typedef char charf; typedef int intf; typedef void *voidpf; typedef uLong uLongf; typedef void *voidp; typedef void *const voidpc; #define Z_NULL 0 #define Z_NO_FLUSH MZ_NO_FLUSH #define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH #define Z_SYNC_FLUSH MZ_SYNC_FLUSH #define Z_FULL_FLUSH MZ_FULL_FLUSH #define Z_FINISH MZ_FINISH #define Z_BLOCK MZ_BLOCK #define Z_OK MZ_OK #define Z_STREAM_END MZ_STREAM_END #define Z_NEED_DICT MZ_NEED_DICT #define Z_ERRNO MZ_ERRNO #define Z_STREAM_ERROR MZ_STREAM_ERROR #define Z_DATA_ERROR MZ_DATA_ERROR #define Z_MEM_ERROR MZ_MEM_ERROR #define Z_BUF_ERROR MZ_BUF_ERROR #define Z_VERSION_ERROR MZ_VERSION_ERROR #define Z_PARAM_ERROR MZ_PARAM_ERROR #define Z_NO_COMPRESSION MZ_NO_COMPRESSION #define Z_BEST_SPEED MZ_BEST_SPEED #define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION #define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION #define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY #define Z_FILTERED MZ_FILTERED #define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY #define Z_RLE MZ_RLE #define Z_FIXED MZ_FIXED #define Z_DEFLATED MZ_DEFLATED #define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS #define alloc_func mz_alloc_func #define free_func mz_free_func #define internal_state mz_internal_state #define z_stream mz_stream #define deflateInit mz_deflateInit #define deflateInit2 mz_deflateInit2 #define deflateReset mz_deflateReset #define deflate mz_deflate #define deflateEnd mz_deflateEnd #define deflateBound mz_deflateBound #define compress mz_compress #define compress2 mz_compress2 #define compressBound mz_compressBound #define inflateInit mz_inflateInit #define inflateInit2 mz_inflateInit2 #define inflate mz_inflate #define inflateEnd mz_inflateEnd #define uncompress mz_uncompress #define crc32 mz_crc32 #define adler32 mz_adler32 #define MAX_WBITS 15 #define MAX_MEM_LEVEL 9 #define zError mz_error #define ZLIB_VERSION MZ_VERSION #define ZLIB_VERNUM MZ_VERNUM #define ZLIB_VER_MAJOR MZ_VER_MAJOR #define ZLIB_VER_MINOR MZ_VER_MINOR #define ZLIB_VER_REVISION MZ_VER_REVISION #define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION #define zlibVersion mz_version #define zlib_version mz_version() #endif // #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES #endif // MINIZ_NO_ZLIB_APIS // ------------------- Types and macros typedef unsigned char mz_uint8; typedef signed short mz_int16; typedef unsigned short mz_uint16; typedef unsigned int mz_uint32; typedef unsigned int mz_uint; typedef long long mz_int64; typedef unsigned long long mz_uint64; typedef int mz_bool; #define MZ_FALSE (0) #define MZ_TRUE (1) // An attempt to work around MSVC's spammy "warning C4127: conditional expression is constant" message. #ifdef _MSC_VER #define MZ_MACRO_END while (0, 0) #else #define MZ_MACRO_END while (0) #endif // ------------------- ZIP archive reading/writing #ifndef MINIZ_NO_ARCHIVE_APIS enum { MZ_ZIP_MAX_IO_BUF_SIZE = 64*1024, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 260, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 256 }; typedef struct { mz_uint32 m_file_index; mz_uint32 m_central_dir_ofs; mz_uint16 m_version_made_by; mz_uint16 m_version_needed; mz_uint16 m_bit_flag; mz_uint16 m_method; #ifndef MINIZ_NO_TIME time_t m_time; #endif mz_uint32 m_crc32; mz_uint64 m_comp_size; mz_uint64 m_uncomp_size; mz_uint16 m_internal_attr; mz_uint32 m_external_attr; mz_uint64 m_local_header_ofs; mz_uint32 m_comment_size; char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE]; char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE]; } mz_zip_archive_file_stat; typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n); typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n); struct mz_zip_internal_state_tag; typedef struct mz_zip_internal_state_tag mz_zip_internal_state; typedef enum { MZ_ZIP_MODE_INVALID = 0, MZ_ZIP_MODE_READING = 1, MZ_ZIP_MODE_WRITING = 2, MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3 } mz_zip_mode; typedef struct mz_zip_archive_tag { mz_uint64 m_archive_size; mz_uint64 m_central_directory_file_ofs; mz_uint m_total_files; mz_zip_mode m_zip_mode; mz_uint m_file_offset_alignment; mz_alloc_func m_pAlloc; mz_free_func m_pFree; mz_realloc_func m_pRealloc; void *m_pAlloc_opaque; mz_file_read_func m_pRead; mz_file_write_func m_pWrite; void *m_pIO_opaque; mz_zip_internal_state *m_pState; } mz_zip_archive; typedef enum { MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100, MZ_ZIP_FLAG_IGNORE_PATH = 0x0200, MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400, MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800 } mz_zip_flags; // ZIP archive reading // Inits a ZIP archive reader. // These functions read and validate the archive's central directory. mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags); mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags); #ifndef MINIZ_NO_STDIO mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags); #endif // Returns the total number of files in the archive. mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip); // Returns detailed information about an archive file entry. mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat); // Determines if an archive file entry is a directory entry. mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index); mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index); // Retrieves the filename of an archive file entry. // Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size); // Attempts to locates a file in the archive's central directory. // Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH // Returns -1 if the file cannot be found. int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags); // Extracts a archive file to a memory buffer using no memory allocation. mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size); // Extracts a archive file to a memory buffer. mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags); // Extracts a archive file to a dynamically allocated heap buffer. void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags); void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags); // Extracts a archive file using a callback function to output the file's data. mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags); #ifndef MINIZ_NO_STDIO // Extracts a archive file to a disk file and sets its last accessed and modified times. // This function only extracts files, not archive directory records. mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags); mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags); #endif // Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. mz_bool mz_zip_reader_end(mz_zip_archive *pZip); // ZIP archive writing #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS // Inits a ZIP archive writer. mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size); mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size); #ifndef MINIZ_NO_STDIO mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning); #endif // Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. // For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. // For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). // Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. // Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before // the archive is finalized the file's central directory will be hosed. mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename); // Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. // To add a directory entry, call this method with an archive name ending in a forwardslash with empty buffer. // level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags); mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32); #ifndef MINIZ_NO_STDIO // Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. // level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); #endif // Adds a file to an archive by fully cloning the data from another archive. // This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data, and comment fields. mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index); // Finalizes the archive by writing the central directory records followed by the end of central directory record. // After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). // An archive must be manually finalized by calling this function for it to be valid. mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip); mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize); // Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. // Note for the archive to be valid, it must have been finalized before ending. mz_bool mz_zip_writer_end(mz_zip_archive *pZip); // Misc. high-level helper functions: // mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. // level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags); // Reads a single file from an archive into a heap block. // Returns NULL on failure. void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint zip_flags); #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS #endif // #ifndef MINIZ_NO_ARCHIVE_APIS // ------------------- Low-level Decompression API Definitions // Decompression flags used by tinfl_decompress(). // TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. // TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. // TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). // TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. enum { TINFL_FLAG_PARSE_ZLIB_HEADER = 1, TINFL_FLAG_HAS_MORE_INPUT = 2, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4, TINFL_FLAG_COMPUTE_ADLER32 = 8 }; // High level decompression functions: // tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). // On entry: // pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. // On return: // Function returns a pointer to the decompressed data, or NULL on failure. // *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. // The caller must call mz_free() on the returned block when it's no longer needed. void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); // tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. // Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. #define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1)) size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); // tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. // Returns 1 on success or 0 on failure. typedef int (*tinfl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); struct tinfl_decompressor_tag; typedef struct tinfl_decompressor_tag tinfl_decompressor; // Max size of LZ dictionary. #define TINFL_LZ_DICT_SIZE 32768 // Return status. typedef enum { TINFL_STATUS_BAD_PARAM = -3, TINFL_STATUS_ADLER32_MISMATCH = -2, TINFL_STATUS_FAILED = -1, TINFL_STATUS_DONE = 0, TINFL_STATUS_NEEDS_MORE_INPUT = 1, TINFL_STATUS_HAS_MORE_OUTPUT = 2 } tinfl_status; // Initializes the decompressor to its initial state. #define tinfl_init(r) do { (r)->m_state = 0; } MZ_MACRO_END #define tinfl_get_adler32(r) (r)->m_check_adler32 // Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. // This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags); // Internal/private bits follow. enum { TINFL_MAX_HUFF_TABLES = 3, TINFL_MAX_HUFF_SYMBOLS_0 = 288, TINFL_MAX_HUFF_SYMBOLS_1 = 32, TINFL_MAX_HUFF_SYMBOLS_2 = 19, TINFL_FAST_LOOKUP_BITS = 10, TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS }; typedef struct { mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0]; mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2]; } tinfl_huff_table; #if MINIZ_HAS_64BIT_REGISTERS #define TINFL_USE_64BIT_BITBUF 1 #endif #if TINFL_USE_64BIT_BITBUF typedef mz_uint64 tinfl_bit_buf_t; #define TINFL_BITBUF_SIZE (64) #else typedef mz_uint32 tinfl_bit_buf_t; #define TINFL_BITBUF_SIZE (32) #endif struct tinfl_decompressor_tag { mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES]; tinfl_bit_buf_t m_bit_buf; size_t m_dist_from_out_buf_start; tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES]; mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137]; }; // ------------------- Low-level Compression API Definitions // Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). #define TDEFL_LESS_MEMORY 0 // tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): // TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). enum { TDEFL_HUFFMAN_ONLY = 0, TDEFL_DEFAULT_MAX_PROBES = 128, TDEFL_MAX_PROBES_MASK = 0xFFF }; // TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. // TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). // TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. // TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). // TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) // TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. // TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. // TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. // The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). enum { TDEFL_WRITE_ZLIB_HEADER = 0x01000, TDEFL_COMPUTE_ADLER32 = 0x02000, TDEFL_GREEDY_PARSING_FLAG = 0x04000, TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000, TDEFL_RLE_MATCHES = 0x10000, TDEFL_FILTER_MATCHES = 0x20000, TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000, TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000 }; // High level compression functions: // tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). // On entry: // pSrc_buf, src_buf_len: Pointer and size of source block to compress. // flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. // On return: // Function returns a pointer to the compressed data, or NULL on failure. // *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. // The caller must free() the returned block when it's no longer needed. void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags); // tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. // Returns 0 on failure. size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags); // Compresses an image to a compressed PNG file in memory. // On entry: // pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. // The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. // level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL // If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). // On return: // Function returns a pointer to the compressed data, or NULL on failure. // *pLen_out will be set to the size of the PNG image file. // The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip); void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out); // Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. typedef mz_bool (*tdefl_put_buf_func_ptr)(const void* pBuf, int len, void *pUser); // tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); enum { TDEFL_MAX_HUFF_TABLES = 3, TDEFL_MAX_HUFF_SYMBOLS_0 = 288, TDEFL_MAX_HUFF_SYMBOLS_1 = 32, TDEFL_MAX_HUFF_SYMBOLS_2 = 19, TDEFL_LZ_DICT_SIZE = 32768, TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1, TDEFL_MIN_MATCH_LEN = 3, TDEFL_MAX_MATCH_LEN = 258 }; // TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). #if TDEFL_LESS_MEMORY enum { TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 12, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; #else enum { TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024, TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13 ) / 10, TDEFL_MAX_HUFF_SYMBOLS = 288, TDEFL_LZ_HASH_BITS = 15, TDEFL_LEVEL1_HASH_SIZE_MASK = 4095, TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3, TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS }; #endif // The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. typedef enum { TDEFL_STATUS_BAD_PARAM = -2, TDEFL_STATUS_PUT_BUF_FAILED = -1, TDEFL_STATUS_OKAY = 0, TDEFL_STATUS_DONE = 1, } tdefl_status; // Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums typedef enum { TDEFL_NO_FLUSH = 0, TDEFL_SYNC_FLUSH = 2, TDEFL_FULL_FLUSH = 3, TDEFL_FINISH = 4 } tdefl_flush; // tdefl's compression state structure. typedef struct { tdefl_put_buf_func_ptr m_pPut_buf_func; void *m_pPut_buf_user; mz_uint m_flags, m_max_probes[2]; int m_greedy_parsing; mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size; mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end; mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer; mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish; tdefl_status m_prev_return_status; const void *m_pIn_buf; void *m_pOut_buf; size_t *m_pIn_buf_size, *m_pOut_buf_size; tdefl_flush m_flush; const mz_uint8 *m_pSrc; size_t m_src_buf_left, m_out_buf_ofs; mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1]; mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS]; mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE]; mz_uint16 m_next[TDEFL_LZ_DICT_SIZE]; mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE]; mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE]; } tdefl_compressor; // Initializes the compressor. // There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. // pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. // If pBut_buf_func is NULL the user should always call the tdefl_compress() API. // flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags); // Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush); // tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. // tdefl_compress_buffer() always consumes the entire input buffer. tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush); tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d); mz_uint32 tdefl_get_adler32(tdefl_compressor *d); // Can't use tdefl_create_comp_flags_from_zip_params if MINIZ_NO_ZLIB_APIS isn't defined, because it uses some of its macros. #ifndef MINIZ_NO_ZLIB_APIS // Create tdefl_compress() flags given zlib-style compression parameters. // level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) // window_bits may be -15 (raw deflate) or 15 (zlib) // strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy); #endif // #ifndef MINIZ_NO_ZLIB_APIS #ifdef __cplusplus } #endif #endif // MINIZ_HEADER_INCLUDED // ------------------- End of Header: Implementation follows. (If you only want the header, define MINIZ_HEADER_FILE_ONLY.) #ifndef MINIZ_HEADER_FILE_ONLY typedef unsigned char mz_validate_uint16[sizeof(mz_uint16)==2 ? 1 : -1]; typedef unsigned char mz_validate_uint32[sizeof(mz_uint32)==4 ? 1 : -1]; typedef unsigned char mz_validate_uint64[sizeof(mz_uint64)==8 ? 1 : -1]; #include #include #define MZ_ASSERT(x) assert(x) #ifdef MINIZ_NO_MALLOC #define MZ_MALLOC(x) NULL #define MZ_FREE(x) (void)x, ((void)0) #define MZ_REALLOC(p, x) NULL #else #define MZ_MALLOC(x) malloc(x) #define MZ_FREE(x) free(x) #define MZ_REALLOC(p, x) realloc(p, x) #endif #define MZ_MAX(a,b) (((a)>(b))?(a):(b)) #define MZ_MIN(a,b) (((a)<(b))?(a):(b)) #define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj)) #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN #define MZ_READ_LE16(p) *((const mz_uint16 *)(p)) #define MZ_READ_LE32(p) *((const mz_uint32 *)(p)) #else #define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U)) #define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U)) #endif #ifdef _MSC_VER #define MZ_FORCEINLINE __forceinline #elif defined(__GNUC__) #define MZ_FORCEINLINE inline __attribute__((__always_inline__)) #else #define MZ_FORCEINLINE inline #endif #ifdef __cplusplus extern "C" { #endif // ------------------- zlib-style API's mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len) { mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16); size_t block_len = buf_len % 5552; if (!ptr) return MZ_ADLER32_INIT; while (buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; } for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; } return (s2 << 16) + s1; } // Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len) { static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c, 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c }; mz_uint32 crcu32 = (mz_uint32)crc; if (!ptr) return MZ_CRC32_INIT; crcu32 = ~crcu32; while (buf_len--) { mz_uint8 b = *ptr++; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)]; crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)]; } return ~crcu32; } void mz_free(void *p) { MZ_FREE(p); } #ifndef MINIZ_NO_ZLIB_APIS static void *def_alloc_func(void *opaque, size_t items, size_t size) { (void)opaque, (void)items, (void)size; return MZ_MALLOC(items * size); } static void def_free_func(void *opaque, void *address) { (void)opaque, (void)address; MZ_FREE(address); } static void *def_realloc_func(void *opaque, void *address, size_t items, size_t size) { (void)opaque, (void)address, (void)items, (void)size; return MZ_REALLOC(address, items * size); } const char *mz_version(void) { return MZ_VERSION; } int mz_deflateInit(mz_streamp pStream, int level) { return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY); } int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy) { tdefl_compressor *pComp; mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy); if (!pStream) return MZ_STREAM_ERROR; if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))) return MZ_PARAM_ERROR; pStream->data_type = 0; pStream->adler = MZ_ADLER32_INIT; pStream->msg = NULL; pStream->reserved = 0; pStream->total_in = 0; pStream->total_out = 0; if (!pStream->zalloc) pStream->zalloc = def_alloc_func; if (!pStream->zfree) pStream->zfree = def_free_func; pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor)); if (!pComp) return MZ_MEM_ERROR; pStream->state = (struct mz_internal_state *)pComp; if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY) { mz_deflateEnd(pStream); return MZ_PARAM_ERROR; } return MZ_OK; } int mz_deflateReset(mz_streamp pStream) { if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree)) return MZ_STREAM_ERROR; pStream->total_in = pStream->total_out = 0; tdefl_init((tdefl_compressor*)pStream->state, NULL, NULL, ((tdefl_compressor*)pStream->state)->m_flags); return MZ_OK; } int mz_deflate(mz_streamp pStream, int flush) { size_t in_bytes, out_bytes; mz_ulong orig_total_in, orig_total_out; int mz_status = MZ_OK; if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out)) return MZ_STREAM_ERROR; if (!pStream->avail_out) return MZ_BUF_ERROR; if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; if (((tdefl_compressor*)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE) return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR; orig_total_in = pStream->total_in; orig_total_out = pStream->total_out; for ( ; ; ) { tdefl_status defl_status; in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; defl_status = tdefl_compress((tdefl_compressor*)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush); pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tdefl_get_adler32((tdefl_compressor*)pStream->state); pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; if (defl_status < 0) { mz_status = MZ_STREAM_ERROR; break; } else if (defl_status == TDEFL_STATUS_DONE) { mz_status = MZ_STREAM_END; break; } else if (!pStream->avail_out) break; else if ((!pStream->avail_in) && (flush != MZ_FINISH)) { if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out)) break; return MZ_BUF_ERROR; // Can't make forward progress without some input. } } return mz_status; } int mz_deflateEnd(mz_streamp pStream) { if (!pStream) return MZ_STREAM_ERROR; if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); pStream->state = NULL; } return MZ_OK; } mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len) { (void)pStream; // This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5); } int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level) { int status; mz_stream stream; memset(&stream, 0, sizeof(stream)); // In case mz_ulong is 64-bits (argh I hate longs). if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; stream.next_in = pSource; stream.avail_in = (mz_uint32)source_len; stream.next_out = pDest; stream.avail_out = (mz_uint32)*pDest_len; status = mz_deflateInit(&stream, level); if (status != MZ_OK) return status; status = mz_deflate(&stream, MZ_FINISH); if (status != MZ_STREAM_END) { mz_deflateEnd(&stream); return (status == MZ_OK) ? MZ_BUF_ERROR : status; } *pDest_len = stream.total_out; return mz_deflateEnd(&stream); } int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) { return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION); } mz_ulong mz_compressBound(mz_ulong source_len) { return mz_deflateBound(NULL, source_len); } typedef struct { tinfl_decompressor m_decomp; mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed; int m_window_bits; mz_uint8 m_dict[TINFL_LZ_DICT_SIZE]; tinfl_status m_last_status; } inflate_state; int mz_inflateInit2(mz_streamp pStream, int window_bits) { inflate_state *pDecomp; if (!pStream) return MZ_STREAM_ERROR; if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)) return MZ_PARAM_ERROR; pStream->data_type = 0; pStream->adler = 0; pStream->msg = NULL; pStream->total_in = 0; pStream->total_out = 0; pStream->reserved = 0; if (!pStream->zalloc) pStream->zalloc = def_alloc_func; if (!pStream->zfree) pStream->zfree = def_free_func; pDecomp = (inflate_state*)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state)); if (!pDecomp) return MZ_MEM_ERROR; pStream->state = (struct mz_internal_state *)pDecomp; tinfl_init(&pDecomp->m_decomp); pDecomp->m_dict_ofs = 0; pDecomp->m_dict_avail = 0; pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT; pDecomp->m_first_call = 1; pDecomp->m_has_flushed = 0; pDecomp->m_window_bits = window_bits; return MZ_OK; } int mz_inflateInit(mz_streamp pStream) { return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS); } int mz_inflate(mz_streamp pStream, int flush) { inflate_state* pState; mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32; size_t in_bytes, out_bytes, orig_avail_in; tinfl_status status; if ((!pStream) || (!pStream->state)) return MZ_STREAM_ERROR; if (flush == MZ_PARTIAL_FLUSH) flush = MZ_SYNC_FLUSH; if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; pState = (inflate_state*)pStream->state; if (pState->m_window_bits > 0) decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER; orig_avail_in = pStream->avail_in; first_call = pState->m_first_call; pState->m_first_call = 0; if (pState->m_last_status < 0) return MZ_DATA_ERROR; if (pState->m_has_flushed && (flush != MZ_FINISH)) return MZ_STREAM_ERROR; pState->m_has_flushed |= (flush == MZ_FINISH); if ((flush == MZ_FINISH) && (first_call)) { // MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; in_bytes = pStream->avail_in; out_bytes = pStream->avail_out; status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags); pState->m_last_status = status; pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); pStream->next_out += (mz_uint)out_bytes; pStream->avail_out -= (mz_uint)out_bytes; pStream->total_out += (mz_uint)out_bytes; if (status < 0) return MZ_DATA_ERROR; else if (status != TINFL_STATUS_DONE) { pState->m_last_status = TINFL_STATUS_FAILED; return MZ_BUF_ERROR; } return MZ_STREAM_END; } // flush != MZ_FINISH then we must assume there's more input. if (flush != MZ_FINISH) decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT; if (pState->m_dict_avail) { n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; } for ( ; ; ) { in_bytes = pStream->avail_in; out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs; status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags); pState->m_last_status = status; pStream->next_in += (mz_uint)in_bytes; pStream->avail_in -= (mz_uint)in_bytes; pStream->total_in += (mz_uint)in_bytes; pStream->adler = tinfl_get_adler32(&pState->m_decomp); pState->m_dict_avail = (mz_uint)out_bytes; n = MZ_MIN(pState->m_dict_avail, pStream->avail_out); memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n); pStream->next_out += n; pStream->avail_out -= n; pStream->total_out += n; pState->m_dict_avail -= n; pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1); if (status < 0) return MZ_DATA_ERROR; // Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in)) return MZ_BUF_ERROR; // Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. else if (flush == MZ_FINISH) { // The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. if (status == TINFL_STATUS_DONE) return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END; // status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. else if (!pStream->avail_out) return MZ_BUF_ERROR; } else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail)) break; } return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK; } int mz_inflateEnd(mz_streamp pStream) { if (!pStream) return MZ_STREAM_ERROR; if (pStream->state) { pStream->zfree(pStream->opaque, pStream->state); pStream->state = NULL; } return MZ_OK; } int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len) { mz_stream stream; int status; memset(&stream, 0, sizeof(stream)); // In case mz_ulong is 64-bits (argh I hate longs). if ((source_len | *pDest_len) > 0xFFFFFFFFU) return MZ_PARAM_ERROR; stream.next_in = pSource; stream.avail_in = (mz_uint32)source_len; stream.next_out = pDest; stream.avail_out = (mz_uint32)*pDest_len; status = mz_inflateInit(&stream); if (status != MZ_OK) return status; status = mz_inflate(&stream, MZ_FINISH); if (status != MZ_STREAM_END) { mz_inflateEnd(&stream); return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status; } *pDest_len = stream.total_out; return mz_inflateEnd(&stream); } const char *mz_error(int err) { static struct { int m_err; const char *m_pDesc; } s_error_descs[] = { { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" }, { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" } }; mz_uint i; for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i) if (s_error_descs[i].m_err == err) return s_error_descs[i].m_pDesc; return NULL; } #endif //MINIZ_NO_ZLIB_APIS // ------------------- Low-level Decompression (completely independent from all compression API's) #define TINFL_MEMCPY(d, s, l) memcpy(d, s, l) #define TINFL_MEMSET(p, c, l) memset(p, c, l) #define TINFL_CR_BEGIN switch(r->m_state) { case 0: #define TINFL_CR_RETURN(state_index, result) do { status = result; r->m_state = state_index; goto common_exit; case state_index:; } MZ_MACRO_END #define TINFL_CR_RETURN_FOREVER(state_index, result) do { for ( ; ; ) { TINFL_CR_RETURN(state_index, result); } } MZ_MACRO_END #define TINFL_CR_FINISH } // TODO: If the caller has indicated that there's no more input, and we attempt to read beyond the input buf, then something is wrong with the input because the inflator never // reads ahead more than it needs to. Currently TINFL_GET_BYTE() pads the end of the stream with 0's in this scenario. #define TINFL_GET_BYTE(state_index, c) do { \ if (pIn_buf_cur >= pIn_buf_end) { \ for ( ; ; ) { \ if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { \ TINFL_CR_RETURN(state_index, TINFL_STATUS_NEEDS_MORE_INPUT); \ if (pIn_buf_cur < pIn_buf_end) { \ c = *pIn_buf_cur++; \ break; \ } \ } else { \ c = 0; \ break; \ } \ } \ } else c = *pIn_buf_cur++; } MZ_MACRO_END #define TINFL_NEED_BITS(state_index, n) do { mz_uint c; TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; } while (num_bits < (mz_uint)(n)) #define TINFL_SKIP_BITS(state_index, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END #define TINFL_GET_BITS(state_index, b, n) do { if (num_bits < (mz_uint)(n)) { TINFL_NEED_BITS(state_index, n); } b = bit_buf & ((1 << (n)) - 1); bit_buf >>= (n); num_bits -= (n); } MZ_MACRO_END // TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. // It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a // Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the // bit buffer contains >=15 bits (deflate's max. Huffman code size). #define TINFL_HUFF_BITBUF_FILL(state_index, pHuff) \ do { \ temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]; \ if (temp >= 0) { \ code_len = temp >> 9; \ if ((code_len) && (num_bits >= code_len)) \ break; \ } else if (num_bits > TINFL_FAST_LOOKUP_BITS) { \ code_len = TINFL_FAST_LOOKUP_BITS; \ do { \ temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \ } while ((temp < 0) && (num_bits >= (code_len + 1))); if (temp >= 0) break; \ } TINFL_GET_BYTE(state_index, c); bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); num_bits += 8; \ } while (num_bits < 15); // TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read // beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully // decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. // The slow path is only executed at the very end of the input buffer. #define TINFL_HUFF_DECODE(state_index, sym, pHuff) do { \ int temp; mz_uint code_len, c; \ if (num_bits < 15) { \ if ((pIn_buf_end - pIn_buf_cur) < 2) { \ TINFL_HUFF_BITBUF_FILL(state_index, pHuff); \ } else { \ bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); pIn_buf_cur += 2; num_bits += 16; \ } \ } \ if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) \ code_len = temp >> 9, temp &= 511; \ else { \ code_len = TINFL_FAST_LOOKUP_BITS; do { temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; } while (temp < 0); \ } sym = temp; bit_buf >>= code_len; num_bits -= code_len; } MZ_MACRO_END tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags) { static const int s_length_base[31] = { 3,4,5,6,7,8,9,10,11,13, 15,17,19,23,27,31,35,43,51,59, 67,83,99,115,131,163,195,227,258,0,0 }; static const int s_length_extra[31]= { 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 }; static const int s_dist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193, 257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0}; static const int s_dist_extra[32] = { 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13}; static const mz_uint8 s_length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 }; static const int s_min_table_sizes[3] = { 257, 1, 4 }; tinfl_status status = TINFL_STATUS_FAILED; mz_uint32 num_bits, dist, counter, num_extra; tinfl_bit_buf_t bit_buf; const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size; mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size; size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t)-1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start; // Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start)) { *pIn_buf_size = *pOut_buf_size = 0; return TINFL_STATUS_BAD_PARAM; } num_bits = r->m_num_bits; bit_buf = r->m_bit_buf; dist = r->m_dist; counter = r->m_counter; num_extra = r->m_num_extra; dist_from_out_buf_start = r->m_dist_from_out_buf_start; TINFL_CR_BEGIN bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0; r->m_z_adler32 = r->m_check_adler32 = 1; if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { TINFL_GET_BYTE(1, r->m_zhdr0); TINFL_GET_BYTE(2, r->m_zhdr1); counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8)); if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4))))); if (counter) { TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED); } } do { TINFL_GET_BITS(3, r->m_final, 3); r->m_type = r->m_final >> 1; if (r->m_type == 0) { TINFL_SKIP_BITS(5, num_bits & 7); for (counter = 0; counter < 4; ++counter) { if (num_bits) TINFL_GET_BITS(6, r->m_raw_header[counter], 8); else TINFL_GET_BYTE(7, r->m_raw_header[counter]); } if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8)))) { TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED); } while ((counter) && (num_bits)) { TINFL_GET_BITS(51, dist, 8); while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = (mz_uint8)dist; counter--; } while (counter) { size_t n; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT); } while (pIn_buf_cur >= pIn_buf_end) { if (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) { TINFL_CR_RETURN(38, TINFL_STATUS_NEEDS_MORE_INPUT); } else { TINFL_CR_RETURN_FOREVER(40, TINFL_STATUS_FAILED); } } n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter); TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n); pIn_buf_cur += n; pOut_buf_cur += n; counter -= (mz_uint)n; } } else if (r->m_type == 3) { TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED); } else { if (r->m_type == 1) { mz_uint8 *p = r->m_tables[0].m_code_size; mz_uint i; r->m_table_sizes[0] = 288; r->m_table_sizes[1] = 32; TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32); for ( i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; } else { for (counter = 0; counter < 3; counter++) { TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]); r->m_table_sizes[counter] += s_min_table_sizes[counter]; } MZ_CLEAR_OBJ(r->m_tables[2].m_code_size); for (counter = 0; counter < r->m_table_sizes[2]; counter++) { mz_uint s; TINFL_GET_BITS(14, s, 3); r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s; } r->m_table_sizes[2] = 19; } for ( ; (int)r->m_type >= 0; r->m_type--) { int tree_next, tree_cur; tinfl_huff_table *pTable; mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16]; pTable = &r->m_tables[r->m_type]; MZ_CLEAR_OBJ(total_syms); MZ_CLEAR_OBJ(pTable->m_look_up); MZ_CLEAR_OBJ(pTable->m_tree); for (i = 0; i < r->m_table_sizes[r->m_type]; ++i) total_syms[pTable->m_code_size[i]]++; used_syms = 0, total = 0; next_code[0] = next_code[1] = 0; for (i = 1; i <= 15; ++i) { used_syms += total_syms[i]; next_code[i + 1] = (total = ((total + total_syms[i]) << 1)); } if ((65536 != total) && (used_syms > 1)) { TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED); } for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index) { mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index]; if (!code_size) continue; cur_code = next_code[code_size]++; for (l = code_size; l > 0; l--, cur_code >>= 1) rev_code = (rev_code << 1) | (cur_code & 1); if (code_size <= TINFL_FAST_LOOKUP_BITS) { mz_int16 k = (mz_int16)((code_size << 9) | sym_index); while (rev_code < TINFL_FAST_LOOKUP_SIZE) { pTable->m_look_up[rev_code] = k; rev_code += (1 << code_size); } continue; } if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)])) { pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1); for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--) { tree_cur -= ((rev_code >>= 1) & 1); if (!pTable->m_tree[-tree_cur - 1]) { pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next; tree_cur = tree_next; tree_next -= 2; } else tree_cur = pTable->m_tree[-tree_cur - 1]; } tree_cur -= ((rev_code >>= 1) & 1); pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index; } if (r->m_type == 2) { for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]); ) { mz_uint s; TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]); if (dist < 16) { r->m_len_codes[counter++] = (mz_uint8)dist; continue; } if ((dist == 16) && (!counter)) { TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED); } num_extra = "\02\03\07"[dist - 16]; TINFL_GET_BITS(18, s, num_extra); s += "\03\03\013"[dist - 16]; TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s); counter += s; } if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter) { TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED); } TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]); TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]); } } for ( ; ; ) { mz_uint8 *pSrc; for ( ; ; ) { if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2)) { TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]); if (counter >= 256) break; while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = (mz_uint8)counter; } else { int sym2; mz_uint code_len; #if TINFL_USE_64BIT_BITBUF if (num_bits < 30) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits); pIn_buf_cur += 4; num_bits += 32; } #else if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } #endif if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) code_len = sym2 >> 9; else { code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); } counter = sym2; bit_buf >>= code_len; num_bits -= code_len; if (counter & 256) break; #if !TINFL_USE_64BIT_BITBUF if (num_bits < 15) { bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits); pIn_buf_cur += 2; num_bits += 16; } #endif if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0) code_len = sym2 >> 9; else { code_len = TINFL_FAST_LOOKUP_BITS; do { sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)]; } while (sym2 < 0); } bit_buf >>= code_len; num_bits -= code_len; pOut_buf_cur[0] = (mz_uint8)counter; if (sym2 & 256) { pOut_buf_cur++; counter = sym2; break; } pOut_buf_cur[1] = (mz_uint8)sym2; pOut_buf_cur += 2; } } if ((counter &= 511) == 256) break; num_extra = s_length_extra[counter - 257]; counter = s_length_base[counter - 257]; if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(25, extra_bits, num_extra); counter += extra_bits; } TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]); num_extra = s_dist_extra[dist]; dist = s_dist_base[dist]; if (num_extra) { mz_uint extra_bits; TINFL_GET_BITS(27, extra_bits, num_extra); dist += extra_bits; } dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start; if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)) { TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED); } pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask); if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end) { while (counter--) { while (pOut_buf_cur >= pOut_buf_end) { TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT); } *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask]; } continue; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES else if ((counter >= 9) && (counter <= dist)) { const mz_uint8 *pSrc_end = pSrc + (counter & ~7); do { ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0]; ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1]; pOut_buf_cur += 8; } while ((pSrc += 8) < pSrc_end); if ((counter &= 7) < 3) { if (counter) { pOut_buf_cur[0] = pSrc[0]; if (counter > 1) pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur += counter; } continue; } } #endif do { pOut_buf_cur[0] = pSrc[0]; pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur[2] = pSrc[2]; pOut_buf_cur += 3; pSrc += 3; } while ((int)(counter -= 3) > 2); if ((int)counter > 0) { pOut_buf_cur[0] = pSrc[0]; if ((int)counter > 1) pOut_buf_cur[1] = pSrc[1]; pOut_buf_cur += counter; } } } } while (!(r->m_final & 1)); if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) { TINFL_SKIP_BITS(32, num_bits & 7); for (counter = 0; counter < 4; ++counter) { mz_uint s; if (num_bits) TINFL_GET_BITS(41, s, 8); else TINFL_GET_BYTE(42, s); r->m_z_adler32 = (r->m_z_adler32 << 8) | s; } } TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE); TINFL_CR_FINISH common_exit: r->m_num_bits = num_bits; r->m_bit_buf = bit_buf; r->m_dist = dist; r->m_counter = counter; r->m_num_extra = num_extra; r->m_dist_from_out_buf_start = dist_from_out_buf_start; *pIn_buf_size = pIn_buf_cur - pIn_buf_next; *pOut_buf_size = pOut_buf_cur - pOut_buf_next; if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0)) { const mz_uint8 *ptr = pOut_buf_next; size_t buf_len = *pOut_buf_size; mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16; size_t block_len = buf_len % 5552; while (buf_len) { for (i = 0; i + 7 < block_len; i += 8, ptr += 8) { s1 += ptr[0], s2 += s1; s1 += ptr[1], s2 += s1; s1 += ptr[2], s2 += s1; s1 += ptr[3], s2 += s1; s1 += ptr[4], s2 += s1; s1 += ptr[5], s2 += s1; s1 += ptr[6], s2 += s1; s1 += ptr[7], s2 += s1; } for ( ; i < block_len; ++i) s1 += *ptr++, s2 += s1; s1 %= 65521U, s2 %= 65521U; buf_len -= block_len; block_len = 5552; } r->m_check_adler32 = (s2 << 16) + s1; if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32)) status = TINFL_STATUS_ADLER32_MISMATCH; } return status; } // Higher level helper functions. void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { tinfl_decompressor decomp; void *pBuf = NULL, *pNew_buf; size_t src_buf_ofs = 0, out_buf_capacity = 0; *pOut_len = 0; tinfl_init(&decomp); for ( ; ; ) { size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity; tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8*)pBuf, pBuf ? (mz_uint8*)pBuf + *pOut_len : NULL, &dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { MZ_FREE(pBuf); *pOut_len = 0; return NULL; } src_buf_ofs += src_buf_size; *pOut_len += dst_buf_size; if (status == TINFL_STATUS_DONE) break; new_out_buf_capacity = out_buf_capacity * 2; if (new_out_buf_capacity < 128) new_out_buf_capacity = 128; pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity); if (!pNew_buf) { MZ_FREE(pBuf); *pOut_len = 0; return NULL; } pBuf = pNew_buf; out_buf_capacity = new_out_buf_capacity; } return pBuf; } size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) { tinfl_decompressor decomp; tinfl_status status; tinfl_init(&decomp); status = tinfl_decompress(&decomp, (const mz_uint8*)pSrc_buf, &src_buf_len, (mz_uint8*)pOut_buf, (mz_uint8*)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len; } int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { int result = 0; tinfl_decompressor decomp; mz_uint8 *pDict = (mz_uint8*)MZ_MALLOC(TINFL_LZ_DICT_SIZE); size_t in_buf_ofs = 0, dict_ofs = 0; if (!pDict) return TINFL_STATUS_FAILED; tinfl_init(&decomp); for ( ; ; ) { size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs; tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8*)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); in_buf_ofs += in_buf_size; if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user))) break; if (status != TINFL_STATUS_HAS_MORE_OUTPUT) { result = (status == TINFL_STATUS_DONE); break; } dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1); } MZ_FREE(pDict); *pIn_buf_size = in_buf_ofs; return result; } // ------------------- Low-level Compression (independent from all decompression API's) // Purposely making these tables static for faster init and thread safety. static const mz_uint16 s_tdefl_len_sym[256] = { 257,258,259,260,261,262,263,264,265,265,266,266,267,267,268,268,269,269,269,269,270,270,270,270,271,271,271,271,272,272,272,272, 273,273,273,273,273,273,273,273,274,274,274,274,274,274,274,274,275,275,275,275,275,275,275,275,276,276,276,276,276,276,276,276, 277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,277,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278,278, 279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,279,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280,280, 281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281,281, 282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282,282, 283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283,283, 284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,284,285 }; static const mz_uint8 s_tdefl_len_extra[256] = { 0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,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,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,5,0 }; static const mz_uint8 s_tdefl_small_dist_sym[512] = { 0,1,2,3,4,4,5,5,6,6,6,6,7,7,7,7,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11, 11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13, 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14, 14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14, 14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15, 15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16, 16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17, 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17, 17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17 }; static const mz_uint8 s_tdefl_small_dist_extra[512] = { 0,0,0,0,1,1,1,1,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,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,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7 }; static const mz_uint8 s_tdefl_large_dist_sym[128] = { 0,0,18,19,20,20,21,21,22,22,22,22,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26, 26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28, 28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29 }; static const mz_uint8 s_tdefl_large_dist_extra[128] = { 0,0,8,8,9,9,9,9,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12, 12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13, 13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13 }; // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; static tdefl_sym_freq* tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq* pSyms0, tdefl_sym_freq* pSyms1) { mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2]; tdefl_sym_freq* pCur_syms = pSyms0, *pNew_syms = pSyms1; MZ_CLEAR_OBJ(hist); for (i = 0; i < num_syms; i++) { mz_uint freq = pSyms0[i].m_key; hist[freq & 0xFF]++; hist[256 + ((freq >> 8) & 0xFF)]++; } while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256])) total_passes--; for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8) { const mz_uint32* pHist = &hist[pass << 8]; mz_uint offsets[256], cur_ofs = 0; for (i = 0; i < 256; i++) { offsets[i] = cur_ofs; cur_ofs += pHist[i]; } for (i = 0; i < num_syms; i++) pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i]; { tdefl_sym_freq* t = pCur_syms; pCur_syms = pNew_syms; pNew_syms = t; } } return pCur_syms; } // tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n) { int root, leaf, next, avbl, used, dpth; if (n==0) return; else if (n==1) { A[0].m_key = 1; return; } A[0].m_key += A[1].m_key; root = 0; leaf = 2; for (next=1; next < n-1; next++) { if (leaf>=n || A[root].m_key=n || (root=0; next--) A[next].m_key = A[A[next].m_key].m_key+1; avbl = 1; used = dpth = 0; root = n-2; next = n-1; while (avbl>0) { while (root>=0 && (int)A[root].m_key==dpth) { used++; root--; } while (avbl>used) { A[next--].m_key = (mz_uint16)(dpth); avbl--; } avbl = 2*used; dpth++; used = 0; } } // Limits canonical Huffman code table's max code size. enum { TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32 }; static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size) { int i; mz_uint32 total = 0; if (code_list_len <= 1) return; for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++) pNum_codes[max_code_size] += pNum_codes[i]; for (i = max_code_size; i > 0; i--) total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i)); while (total != (1UL << max_code_size)) { pNum_codes[max_code_size]--; for (i = max_code_size - 1; i > 0; i--) if (pNum_codes[i]) { pNum_codes[i]--; pNum_codes[i + 1] += 2; break; } total--; } } static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table) { int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE]; mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1]; MZ_CLEAR_OBJ(num_codes); if (static_table) { for (i = 0; i < table_len; i++) num_codes[d->m_huff_code_sizes[table_num][i]]++; } else { tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms; int num_used_syms = 0; const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0]; for (i = 0; i < table_len; i++) if (pSym_count[i]) { syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i]; syms0[num_used_syms++].m_sym_index = (mz_uint16)i; } pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1); tdefl_calculate_minimum_redundancy(pSyms, num_used_syms); for (i = 0; i < num_used_syms; i++) num_codes[pSyms[i].m_key]++; tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit); MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]); MZ_CLEAR_OBJ(d->m_huff_codes[table_num]); for (i = 1, j = num_used_syms; i <= code_size_limit; i++) for (l = num_codes[i]; l > 0; l--) d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i); } next_code[1] = 0; for (j = 0, i = 2; i <= code_size_limit; i++) next_code[i] = j = ((j + num_codes[i - 1]) << 1); for (i = 0; i < table_len; i++) { mz_uint rev_code = 0, code, code_size; if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0) continue; code = next_code[code_size]++; for (l = code_size; l > 0; l--, code >>= 1) rev_code = (rev_code << 1) | (code & 1); d->m_huff_codes[table_num][i] = (mz_uint16)rev_code; } } #define TDEFL_PUT_BITS(b, l) do { \ mz_uint bits = b; mz_uint len = l; MZ_ASSERT(bits <= ((1U << len) - 1U)); \ d->m_bit_buffer |= (bits << d->m_bits_in); d->m_bits_in += len; \ while (d->m_bits_in >= 8) { \ if (d->m_pOutput_buf < d->m_pOutput_buf_end) \ *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \ d->m_bit_buffer >>= 8; \ d->m_bits_in -= 8; \ } \ } MZ_MACRO_END #define TDEFL_RLE_PREV_CODE_SIZE() { if (rle_repeat_count) { \ if (rle_repeat_count < 3) { \ d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \ while (rle_repeat_count--) packed_code_sizes[num_packed_code_sizes++] = prev_code_size; \ } else { \ d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1); packed_code_sizes[num_packed_code_sizes++] = 16; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3); \ } rle_repeat_count = 0; } } #define TDEFL_RLE_ZERO_CODE_SIZE() { if (rle_z_count) { \ if (rle_z_count < 3) { \ d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count); while (rle_z_count--) packed_code_sizes[num_packed_code_sizes++] = 0; \ } else if (rle_z_count <= 10) { \ d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1); packed_code_sizes[num_packed_code_sizes++] = 17; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3); \ } else { \ d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1); packed_code_sizes[num_packed_code_sizes++] = 18; packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \ } rle_z_count = 0; } } static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 }; static void tdefl_start_dynamic_block(tdefl_compressor *d) { int num_lit_codes, num_dist_codes, num_bit_lengths; mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index; mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF; d->m_huff_count[0][256] = 1; tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE); tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE); for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--) if (d->m_huff_code_sizes[0][num_lit_codes - 1]) break; for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--) if (d->m_huff_code_sizes[1][num_dist_codes - 1]) break; memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes); memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes); total_code_sizes_to_pack = num_lit_codes + num_dist_codes; num_packed_code_sizes = 0; rle_z_count = 0; rle_repeat_count = 0; memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2); for (i = 0; i < total_code_sizes_to_pack; i++) { mz_uint8 code_size = code_sizes_to_pack[i]; if (!code_size) { TDEFL_RLE_PREV_CODE_SIZE(); if (++rle_z_count == 138) { TDEFL_RLE_ZERO_CODE_SIZE(); } } else { TDEFL_RLE_ZERO_CODE_SIZE(); if (code_size != prev_code_size) { TDEFL_RLE_PREV_CODE_SIZE(); d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1); packed_code_sizes[num_packed_code_sizes++] = code_size; } else if (++rle_repeat_count == 6) { TDEFL_RLE_PREV_CODE_SIZE(); } } prev_code_size = code_size; } if (rle_repeat_count) { TDEFL_RLE_PREV_CODE_SIZE(); } else { TDEFL_RLE_ZERO_CODE_SIZE(); } tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE); TDEFL_PUT_BITS(2, 2); TDEFL_PUT_BITS(num_lit_codes - 257, 5); TDEFL_PUT_BITS(num_dist_codes - 1, 5); for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--) if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]]) break; num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1)); TDEFL_PUT_BITS(num_bit_lengths - 4, 4); for (i = 0; (int)i < num_bit_lengths; i++) TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3); for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes; ) { mz_uint code = packed_code_sizes[packed_code_sizes_index++]; MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2); TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]); if (code >= 16) TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]); } } static void tdefl_start_static_block(tdefl_compressor *d) { mz_uint i; mz_uint8 *p = &d->m_huff_code_sizes[0][0]; for (i = 0; i <= 143; ++i) *p++ = 8; for ( ; i <= 255; ++i) *p++ = 9; for ( ; i <= 279; ++i) *p++ = 7; for ( ; i <= 287; ++i) *p++ = 8; memset(d->m_huff_code_sizes[1], 5, 32); tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE); tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE); TDEFL_PUT_BITS(1, 2); } static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF }; #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; mz_uint8 *pOutput_buf = d->m_pOutput_buf; mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf; mz_uint64 bit_buffer = d->m_bit_buffer; mz_uint bits_in = d->m_bits_in; #define TDEFL_PUT_BITS_FAST(b, l) { bit_buffer |= (((mz_uint64)(b)) << bits_in); bits_in += (l); } flags = 1; for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; if (flags & 1) { mz_uint s0, s1, n0, n1, sym, num_extra_bits; mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); // This sequence coaxes MSVC into using cmov's vs. jmp's. s0 = s_tdefl_small_dist_sym[match_dist & 511]; n0 = s_tdefl_small_dist_extra[match_dist & 511]; s1 = s_tdefl_large_dist_sym[match_dist >> 8]; n1 = s_tdefl_large_dist_extra[match_dist >> 8]; sym = (match_dist < 512) ? s0 : s1; num_extra_bits = (match_dist < 512) ? n0 : n1; MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end)) { flags >>= 1; lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); } } } if (pOutput_buf >= d->m_pOutput_buf_end) return MZ_FALSE; *(mz_uint64*)pOutput_buf = bit_buffer; pOutput_buf += (bits_in >> 3); bit_buffer >>= (bits_in & ~7); bits_in &= 7; } #undef TDEFL_PUT_BITS_FAST d->m_pOutput_buf = pOutput_buf; d->m_bits_in = 0; d->m_bit_buffer = 0; while (bits_in) { mz_uint32 n = MZ_MIN(bits_in, 16); TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n); bit_buffer >>= n; bits_in -= n; } TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #else static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d) { mz_uint flags; mz_uint8 *pLZ_codes; flags = 1; for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1) { if (flags == 1) flags = *pLZ_codes++ | 0x100; if (flags & 1) { mz_uint sym, num_extra_bits; mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8)); pLZ_codes += 3; MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]); TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]); if (match_dist < 512) { sym = s_tdefl_small_dist_sym[match_dist]; num_extra_bits = s_tdefl_small_dist_extra[match_dist]; } else { sym = s_tdefl_large_dist_sym[match_dist >> 8]; num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8]; } MZ_ASSERT(d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]); TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits); } else { mz_uint lit = *pLZ_codes++; MZ_ASSERT(d->m_huff_code_sizes[0][lit]); TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]); } } TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]); return (d->m_pOutput_buf < d->m_pOutput_buf_end); } #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block) { if (static_block) tdefl_start_static_block(d); else tdefl_start_dynamic_block(d); return tdefl_compress_lz_codes(d); } static int tdefl_flush_block(tdefl_compressor *d, int flush) { mz_uint saved_bit_buf, saved_bits_in; mz_uint8 *pSaved_output_buf; mz_bool comp_block_succeeded = MZ_FALSE; int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size; mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf; d->m_pOutput_buf = pOutput_buf_start; d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16; MZ_ASSERT(!d->m_output_flush_remaining); d->m_output_flush_ofs = 0; d->m_output_flush_remaining = 0; *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left); d->m_pLZ_code_buf -= (d->m_num_flags_left == 8); if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index)) { TDEFL_PUT_BITS(0x78, 8); TDEFL_PUT_BITS(0x01, 8); } TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1); pSaved_output_buf = d->m_pOutput_buf; saved_bit_buf = d->m_bit_buffer; saved_bits_in = d->m_bits_in; if (!use_raw_block) comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48)); // If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. if ( ((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) && ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size) ) { mz_uint i; d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; TDEFL_PUT_BITS(0, 2); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF) { TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16); } for (i = 0; i < d->m_total_lz_bytes; ++i) { TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8); } } // Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. else if (!comp_block_succeeded) { d->m_pOutput_buf = pSaved_output_buf; d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in; tdefl_compress_block(d, MZ_TRUE); } if (flush) { if (flush == TDEFL_FINISH) { if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER) { mz_uint i, a = d->m_adler32; for (i = 0; i < 4; i++) { TDEFL_PUT_BITS((a >> 24) & 0xFF, 8); a <<= 8; } } } else { mz_uint i, z = 0; TDEFL_PUT_BITS(0, 3); if (d->m_bits_in) { TDEFL_PUT_BITS(0, 8 - d->m_bits_in); } for (i = 2; i; --i, z ^= 0xFFFF) { TDEFL_PUT_BITS(z & 0xFFFF, 16); } } } MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end); memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes; d->m_total_lz_bytes = 0; d->m_block_index++; if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0) { if (d->m_pPut_buf_func) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user)) return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED); } else if (pOutput_buf_start == d->m_output_buf) { int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs)); memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy); d->m_out_buf_ofs += bytes_to_copy; if ((n -= bytes_to_copy) != 0) { d->m_output_flush_ofs = bytes_to_copy; d->m_output_flush_remaining = n; } } else { d->m_out_buf_ofs += n; } } return d->m_output_flush_remaining; } #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES #define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16*)(p) static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint16 *s = (const mz_uint16*)(d->m_dict + pos), *p, *q; mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s); MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; for ( ; ; ) { for ( ; ; ) { if (--num_probes_left == 0) return; #define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01) break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } if (!dist) break; q = (const mz_uint16*)(d->m_dict + probe_pos); if (TDEFL_READ_UNALIGNED_WORD(q) != s01) continue; p = s; probe_len = 32; do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); if (!probe_len) { *pMatch_dist = dist; *pMatch_len = MZ_MIN(max_match_len, TDEFL_MAX_MATCH_LEN); break; } else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8*)p == *(const mz_uint8*)q)) > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len) break; c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]); } } } #else static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len) { mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len; mz_uint num_probes_left = d->m_max_probes[match_len >= 32]; const mz_uint8 *s = d->m_dict + pos, *p, *q; mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1]; MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN); if (max_match_len <= match_len) return; for ( ; ; ) { for ( ; ; ) { if (--num_probes_left == 0) return; #define TDEFL_PROBE \ next_probe_pos = d->m_next[probe_pos]; \ if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) return; \ probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK; \ if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) break; TDEFL_PROBE; TDEFL_PROBE; TDEFL_PROBE; } if (!dist) break; p = s; q = d->m_dict + probe_pos; for (probe_len = 0; probe_len < max_match_len; probe_len++) if (*p++ != *q++) break; if (probe_len > match_len) { *pMatch_dist = dist; if ((*pMatch_len = match_len = probe_len) == max_match_len) return; c0 = d->m_dict[pos + match_len]; c1 = d->m_dict[pos + match_len - 1]; } } } #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN static mz_bool tdefl_compress_fast(tdefl_compressor *d) { // Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left; mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags; mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size))) { const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096; mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size); d->m_src_buf_left -= num_bytes_to_process; lookahead_size += num_bytes_to_process; while (num_bytes_to_process) { mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process); memcpy(d->m_dict + dst_pos, d->m_pSrc, n); if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos)); d->m_pSrc += n; dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK; num_bytes_to_process -= n; } dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size); if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE)) break; while (lookahead_size >= 4) { mz_uint cur_match_dist, cur_match_len = 1; mz_uint8 *pCur_dict = d->m_dict + cur_pos; mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF; mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK; mz_uint probe_pos = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)lookahead_pos; if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram)) { const mz_uint16 *p = (const mz_uint16 *)pCur_dict; const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos); mz_uint32 probe_len = 32; do { } while ( (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0) ); cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q); if (!probe_len) cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0; if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U))) { cur_match_len = 1; *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } else { mz_uint32 s0, s1; cur_match_len = MZ_MIN(cur_match_len, lookahead_size); MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE)); cur_match_dist--; pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN); *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist; pLZ_code_buf += 3; *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80); s0 = s_tdefl_small_dist_sym[cur_match_dist & 511]; s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8]; d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++; d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++; } } else { *pLZ_code_buf++ = (mz_uint8)first_trigram; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); d->m_huff_count[0][(mz_uint8)first_trigram]++; } if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } total_lz_bytes += cur_match_len; lookahead_pos += cur_match_len; dict_size = MZ_MIN(dict_size + cur_match_len, TDEFL_LZ_DICT_SIZE); cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK; MZ_ASSERT(lookahead_size >= cur_match_len); lookahead_size -= cur_match_len; if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; } } while (lookahead_size) { mz_uint8 lit = d->m_dict[cur_pos]; total_lz_bytes++; *pLZ_code_buf++ = lit; *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1); if (--num_flags_left == 0) { num_flags_left = 8; pLZ_flags = pLZ_code_buf++; } d->m_huff_count[0][lit]++; lookahead_pos++; dict_size = MZ_MIN(dict_size + 1, TDEFL_LZ_DICT_SIZE); cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; lookahead_size--; if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) { int n; d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; total_lz_bytes = d->m_total_lz_bytes; pLZ_code_buf = d->m_pLZ_code_buf; pLZ_flags = d->m_pLZ_flags; num_flags_left = d->m_num_flags_left; } } } d->m_lookahead_pos = lookahead_pos; d->m_lookahead_size = lookahead_size; d->m_dict_size = dict_size; d->m_total_lz_bytes = total_lz_bytes; d->m_pLZ_code_buf = pLZ_code_buf; d->m_pLZ_flags = pLZ_flags; d->m_num_flags_left = num_flags_left; return MZ_TRUE; } #endif // MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit) { d->m_total_lz_bytes++; *d->m_pLZ_code_buf++ = lit; *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } d->m_huff_count[0][lit]++; } static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist) { mz_uint32 s0, s1; MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE)); d->m_total_lz_bytes += match_len; d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN); match_dist -= 1; d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF); d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8); d->m_pLZ_code_buf += 3; *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80); if (--d->m_num_flags_left == 0) { d->m_num_flags_left = 8; d->m_pLZ_flags = d->m_pLZ_code_buf++; } s0 = s_tdefl_small_dist_sym[match_dist & 511]; s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127]; d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++; if (match_len >= TDEFL_MIN_MATCH_LEN) d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++; } static mz_bool tdefl_compress_normal(tdefl_compressor *d) { const mz_uint8 *pSrc = d->m_pSrc; size_t src_buf_left = d->m_src_buf_left; tdefl_flush flush = d->m_flush; while ((src_buf_left) || ((flush) && (d->m_lookahead_size))) { mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos; // Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1)) { mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2; mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK]; mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size); const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process; src_buf_left -= num_bytes_to_process; d->m_lookahead_size += num_bytes_to_process; while (pSrc != pSrc_end) { mz_uint8 c = *pSrc++; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK; ins_pos++; } } else { while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) { mz_uint8 c = *pSrc++; mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK; src_buf_left--; d->m_dict[dst_pos] = c; if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1)) d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c; if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN) { mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2; mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1); d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash]; d->m_hash[hash] = (mz_uint16)(ins_pos); } } } d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size); if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN)) break; // Simple lazy/greedy parsing state machine. len_to_move = 1; cur_match_dist = 0; cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1); cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK; if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS)) { if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) { mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK]; cur_match_len = 0; while (cur_match_len < d->m_lookahead_size) { if (d->m_dict[cur_pos + cur_match_len] != c) break; cur_match_len++; } if (cur_match_len < TDEFL_MIN_MATCH_LEN) cur_match_len = 0; else cur_match_dist = 1; } } else { tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len); } if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U*1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5))) { cur_match_dist = cur_match_len = 0; } if (d->m_saved_match_len) { if (cur_match_len > d->m_saved_match_len) { tdefl_record_literal(d, (mz_uint8)d->m_saved_lit); if (cur_match_len >= 128) { tdefl_record_match(d, cur_match_len, cur_match_dist); d->m_saved_match_len = 0; len_to_move = cur_match_len; } else { d->m_saved_lit = d->m_dict[cur_pos]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; } } else { tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist); len_to_move = d->m_saved_match_len - 1; d->m_saved_match_len = 0; } } else if (!cur_match_dist) tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]); else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128)) { tdefl_record_match(d, cur_match_len, cur_match_dist); len_to_move = cur_match_len; } else { d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]; d->m_saved_match_dist = cur_match_dist; d->m_saved_match_len = cur_match_len; } // Move the lookahead forward by len_to_move bytes. d->m_lookahead_pos += len_to_move; MZ_ASSERT(d->m_lookahead_size >= len_to_move); d->m_lookahead_size -= len_to_move; d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, TDEFL_LZ_DICT_SIZE); // Check if it's time to flush the current LZ codes to the internal output buffer. if ( (d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) || ( (d->m_total_lz_bytes > 31*1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))) ) { int n; d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; if ((n = tdefl_flush_block(d, 0)) != 0) return (n < 0) ? MZ_FALSE : MZ_TRUE; } } d->m_pSrc = pSrc; d->m_src_buf_left = src_buf_left; return MZ_TRUE; } static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d) { if (d->m_pIn_buf_size) { *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf; } if (d->m_pOut_buf_size) { size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining); memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n); d->m_output_flush_ofs += (mz_uint)n; d->m_output_flush_remaining -= (mz_uint)n; d->m_out_buf_ofs += n; *d->m_pOut_buf_size = d->m_out_buf_ofs; } return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY; } tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush) { if (!d) { if (pIn_buf_size) *pIn_buf_size = 0; if (pOut_buf_size) *pOut_buf_size = 0; return TDEFL_STATUS_BAD_PARAM; } d->m_pIn_buf = pIn_buf; d->m_pIn_buf_size = pIn_buf_size; d->m_pOut_buf = pOut_buf; d->m_pOut_buf_size = pOut_buf_size; d->m_pSrc = (const mz_uint8 *)(pIn_buf); d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0; d->m_out_buf_ofs = 0; d->m_flush = flush; if ( ((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) || (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf) ) { if (pIn_buf_size) *pIn_buf_size = 0; if (pOut_buf_size) *pOut_buf_size = 0; return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM); } d->m_wants_to_finish |= (flush == TDEFL_FINISH); if ((d->m_output_flush_remaining) || (d->m_finished)) return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) && ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) && ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0)) { if (!tdefl_compress_fast(d)) return d->m_prev_return_status; } else #endif // #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN { if (!tdefl_compress_normal(d)) return d->m_prev_return_status; } if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf)) d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf); if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining)) { if (tdefl_flush_block(d, flush) < 0) return d->m_prev_return_status; d->m_finished = (flush == TDEFL_FINISH); if (flush == TDEFL_FULL_FLUSH) { MZ_CLEAR_OBJ(d->m_hash); MZ_CLEAR_OBJ(d->m_next); d->m_dict_size = 0; } } return (d->m_prev_return_status = tdefl_flush_output_buffer(d)); } tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush) { MZ_ASSERT(d->m_pPut_buf_func); return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush); } tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { d->m_pPut_buf_func = pPut_buf_func; d->m_pPut_buf_user = pPut_buf_user; d->m_flags = (mz_uint)(flags); d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3; d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0; d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3; if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG)) MZ_CLEAR_OBJ(d->m_hash); d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0; d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0; d->m_pLZ_code_buf = d->m_lz_code_buf + 1; d->m_pLZ_flags = d->m_lz_code_buf; d->m_num_flags_left = 8; d->m_pOutput_buf = d->m_output_buf; d->m_pOutput_buf_end = d->m_output_buf; d->m_prev_return_status = TDEFL_STATUS_OKAY; d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0; d->m_adler32 = 1; d->m_pIn_buf = NULL; d->m_pOut_buf = NULL; d->m_pIn_buf_size = NULL; d->m_pOut_buf_size = NULL; d->m_flush = TDEFL_NO_FLUSH; d->m_pSrc = NULL; d->m_src_buf_left = 0; d->m_out_buf_ofs = 0; memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0); memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1); return TDEFL_STATUS_OKAY; } tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d) { return d->m_prev_return_status; } mz_uint32 tdefl_get_adler32(tdefl_compressor *d) { return d->m_adler32; } mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags) { tdefl_compressor *pComp; mz_bool succeeded; if (((buf_len) && (!pBuf)) || (!pPut_buf_func)) return MZ_FALSE; pComp = (tdefl_compressor*)MZ_MALLOC(sizeof(tdefl_compressor)); if (!pComp) return MZ_FALSE; succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY); succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE); MZ_FREE(pComp); return succeeded; } typedef struct { size_t m_size, m_capacity; mz_uint8 *m_pBuf; mz_bool m_expandable; } tdefl_output_buffer; static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser) { tdefl_output_buffer *p = (tdefl_output_buffer *)pUser; size_t new_size = p->m_size + len; if (new_size > p->m_capacity) { size_t new_capacity = p->m_capacity; mz_uint8 *pNew_buf; if (!p->m_expandable) return MZ_FALSE; do { new_capacity = MZ_MAX(128U, new_capacity << 1U); } while (new_size > new_capacity); pNew_buf = (mz_uint8*)MZ_REALLOC(p->m_pBuf, new_capacity); if (!pNew_buf) return MZ_FALSE; p->m_pBuf = pNew_buf; p->m_capacity = new_capacity; } memcpy((mz_uint8*)p->m_pBuf + p->m_size, pBuf, len); p->m_size = new_size; return MZ_TRUE; } void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags) { tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); if (!pOut_len) return MZ_FALSE; else *pOut_len = 0; out_buf.m_expandable = MZ_TRUE; if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return NULL; *pOut_len = out_buf.m_size; return out_buf.m_pBuf; } size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags) { tdefl_output_buffer out_buf; MZ_CLEAR_OBJ(out_buf); if (!pOut_buf) return 0; out_buf.m_pBuf = (mz_uint8*)pOut_buf; out_buf.m_capacity = out_buf_len; if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags)) return 0; return out_buf.m_size; } #ifndef MINIZ_NO_ZLIB_APIS static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; // level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy) { mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0); if (window_bits > 0) comp_flags |= TDEFL_WRITE_ZLIB_HEADER; if (!level) comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS; else if (strategy == MZ_FILTERED) comp_flags |= TDEFL_FILTER_MATCHES; else if (strategy == MZ_HUFFMAN_ONLY) comp_flags &= ~TDEFL_MAX_PROBES_MASK; else if (strategy == MZ_FIXED) comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS; else if (strategy == MZ_RLE) comp_flags |= TDEFL_RLE_MATCHES; return comp_flags; } #endif //MINIZ_NO_ZLIB_APIS #ifdef _MSC_VER #pragma warning (push) #pragma warning (disable:4204) // nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) #endif // Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at // http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/. // This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip) { // Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 }; tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor)); tdefl_output_buffer out_buf; int i, bpl = w * num_chans, y, z; mz_uint32 c; *pLen_out = 0; if (!pComp) return NULL; MZ_CLEAR_OBJ(out_buf); out_buf.m_expandable = MZ_TRUE; out_buf.m_capacity = 57+MZ_MAX(64, (1+bpl)*h); if (NULL == (out_buf.m_pBuf = (mz_uint8*)MZ_MALLOC(out_buf.m_capacity))) { MZ_FREE(pComp); return NULL; } // write dummy header for (z = 41; z; --z) tdefl_output_buffer_putter(&z, 1, &out_buf); // compress image data tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER); for (y = 0; y < h; ++y) { tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH); tdefl_compress_buffer(pComp, (mz_uint8*)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH); } if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE) { MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } // write real header *pLen_out = out_buf.m_size-41; { static const mz_uint8 chans[] = {0x00, 0x00, 0x04, 0x02, 0x06}; mz_uint8 pnghdr[41]={0x89,0x50,0x4e,0x47,0x0d,0x0a,0x1a,0x0a,0x00,0x00,0x00,0x0d,0x49,0x48,0x44,0x52, 0,0,(mz_uint8)(w>>8),(mz_uint8)w,0,0,(mz_uint8)(h>>8),(mz_uint8)h,8,chans[num_chans],0,0,0,0,0,0,0, (mz_uint8)(*pLen_out>>24),(mz_uint8)(*pLen_out>>16),(mz_uint8)(*pLen_out>>8),(mz_uint8)*pLen_out,0x49,0x44,0x41,0x54}; c=(mz_uint32)mz_crc32(MZ_CRC32_INIT,pnghdr+12,17); for (i=0; i<4; ++i, c<<=8) ((mz_uint8*)(pnghdr+29))[i]=(mz_uint8)(c>>24); memcpy(out_buf.m_pBuf, pnghdr, 41); } // write footer (IDAT CRC-32, followed by IEND chunk) if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf)) { *pLen_out = 0; MZ_FREE(pComp); MZ_FREE(out_buf.m_pBuf); return NULL; } c = (mz_uint32)mz_crc32(MZ_CRC32_INIT,out_buf.m_pBuf+41-4, *pLen_out+4); for (i=0; i<4; ++i, c<<=8) (out_buf.m_pBuf+out_buf.m_size-16)[i] = (mz_uint8)(c >> 24); // compute final size of file, grab compressed data buffer and return *pLen_out += 57; MZ_FREE(pComp); return out_buf.m_pBuf; } void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out) { // Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE); } #ifdef _MSC_VER #pragma warning (pop) #endif // ------------------- .ZIP archive reading #ifndef MINIZ_NO_ARCHIVE_APIS #ifdef MINIZ_NO_STDIO #define MZ_FILE void * #else #include #include #if defined(_MSC_VER) || defined(__MINGW64__) static FILE *mz_fopen(const char *pFilename, const char *pMode) { FILE* pFile = NULL; fopen_s(&pFile, pFilename, pMode); return pFile; } static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream) { FILE* pFile = NULL; if (freopen_s(&pFile, pPath, pMode, pStream)) return NULL; return pFile; } #ifndef MINIZ_NO_TIME #include #endif #define MZ_FILE FILE #define MZ_FOPEN mz_fopen #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 _ftelli64 #define MZ_FSEEK64 _fseeki64 #define MZ_FILE_STAT_STRUCT _stat #define MZ_FILE_STAT _stat #define MZ_FFLUSH fflush #define MZ_FREOPEN mz_freopen #define MZ_DELETE_FILE remove #elif defined(__MINGW32__) #ifndef MINIZ_NO_TIME #include #endif #define MZ_FILE FILE #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello64 #define MZ_FSEEK64 fseeko64 #define MZ_FILE_STAT_STRUCT _stat #define MZ_FILE_STAT _stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #elif defined(__TINYC__) #ifndef MINIZ_NO_TIME #include #endif #define MZ_FILE FILE #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftell #define MZ_FSEEK64 fseek #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #elif defined(__GNUC__) && _LARGEFILE64_SOURCE #ifndef MINIZ_NO_TIME #include #endif #define MZ_FILE FILE #define MZ_FOPEN(f, m) fopen64(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello64 #define MZ_FSEEK64 fseeko64 #define MZ_FILE_STAT_STRUCT stat64 #define MZ_FILE_STAT stat64 #define MZ_FFLUSH fflush #define MZ_FREOPEN(p, m, s) freopen64(p, m, s) #define MZ_DELETE_FILE remove #else #ifndef MINIZ_NO_TIME #include #endif #define MZ_FILE FILE #define MZ_FOPEN(f, m) fopen(f, m) #define MZ_FCLOSE fclose #define MZ_FREAD fread #define MZ_FWRITE fwrite #define MZ_FTELL64 ftello #define MZ_FSEEK64 fseeko #define MZ_FILE_STAT_STRUCT stat #define MZ_FILE_STAT stat #define MZ_FFLUSH fflush #define MZ_FREOPEN(f, m, s) freopen(f, m, s) #define MZ_DELETE_FILE remove #endif // #ifdef _MSC_VER #endif // #ifdef MINIZ_NO_STDIO #define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c)) // Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. enum { // ZIP archive identifiers and record sizes MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50, MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50, MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50, MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22, // Central directory header record offsets MZ_ZIP_CDH_SIG_OFS = 0, MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4, MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6, MZ_ZIP_CDH_BIT_FLAG_OFS = 8, MZ_ZIP_CDH_METHOD_OFS = 10, MZ_ZIP_CDH_FILE_TIME_OFS = 12, MZ_ZIP_CDH_FILE_DATE_OFS = 14, MZ_ZIP_CDH_CRC32_OFS = 16, MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20, MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24, MZ_ZIP_CDH_FILENAME_LEN_OFS = 28, MZ_ZIP_CDH_EXTRA_LEN_OFS = 30, MZ_ZIP_CDH_COMMENT_LEN_OFS = 32, MZ_ZIP_CDH_DISK_START_OFS = 34, MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36, MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38, MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42, // Local directory header offsets MZ_ZIP_LDH_SIG_OFS = 0, MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4, MZ_ZIP_LDH_BIT_FLAG_OFS = 6, MZ_ZIP_LDH_METHOD_OFS = 8, MZ_ZIP_LDH_FILE_TIME_OFS = 10, MZ_ZIP_LDH_FILE_DATE_OFS = 12, MZ_ZIP_LDH_CRC32_OFS = 14, MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18, MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22, MZ_ZIP_LDH_FILENAME_LEN_OFS = 26, MZ_ZIP_LDH_EXTRA_LEN_OFS = 28, // End of central directory offsets MZ_ZIP_ECDH_SIG_OFS = 0, MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4, MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6, MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8, MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10, MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12, MZ_ZIP_ECDH_CDIR_OFS_OFS = 16, MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20, }; typedef struct { void *m_p; size_t m_size, m_capacity; mz_uint m_element_size; } mz_zip_array; struct mz_zip_internal_state_tag { mz_zip_array m_central_dir; mz_zip_array m_central_dir_offsets; mz_zip_array m_sorted_central_dir_offsets; MZ_FILE *m_pFile; void *m_pMem; size_t m_mem_size; size_t m_mem_capacity; }; #define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size #define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index] static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray) { pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p); memset(pArray, 0, sizeof(mz_zip_array)); } static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing) { void *pNew_p; size_t new_capacity = min_new_capacity; MZ_ASSERT(pArray->m_element_size); if (pArray->m_capacity >= min_new_capacity) return MZ_TRUE; if (growing) { new_capacity = MZ_MAX(1, pArray->m_capacity); while (new_capacity < min_new_capacity) new_capacity *= 2; } if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity))) return MZ_FALSE; pArray->m_p = pNew_p; pArray->m_capacity = new_capacity; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing) { if (new_capacity > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing)) return MZ_FALSE; } return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing) { if (new_size > pArray->m_capacity) { if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing)) return MZ_FALSE; } pArray->m_size = new_size; return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n) { return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE); } static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n) { if (n==0) return MZ_TRUE; assert(NULL!=pElements); size_t orig_size = pArray->m_size; if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE)) return MZ_FALSE; memcpy((mz_uint8*)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size); return MZ_TRUE; } #ifndef MINIZ_NO_TIME static time_t mz_zip_dos_to_time_t(int dos_time, int dos_date) { struct tm tm; memset(&tm, 0, sizeof(tm)); tm.tm_isdst = -1; tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900; tm.tm_mon = ((dos_date >> 5) & 15) - 1; tm.tm_mday = dos_date & 31; tm.tm_hour = (dos_time >> 11) & 31; tm.tm_min = (dos_time >> 5) & 63; tm.tm_sec = (dos_time << 1) & 62; return mktime(&tm); } static void mz_zip_time_to_dos_time(time_t time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) { #ifdef _MSC_VER struct tm tm_struct; struct tm *tm = &tm_struct; errno_t err = localtime_s(tm, &time); if (err) { *pDOS_date = 0; *pDOS_time = 0; return; } #else struct tm *tm = localtime(&time); #endif *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1)); *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday); } #endif #ifndef MINIZ_NO_STDIO static mz_bool mz_zip_get_file_modified_time(const char *pFilename, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date) { #ifdef MINIZ_NO_TIME (void)pFilename; *pDOS_date = *pDOS_time = 0; #else struct MZ_FILE_STAT_STRUCT file_stat; // On Linux with x86 glibc, this call will fail on large files (>= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. if (MZ_FILE_STAT(pFilename, &file_stat) != 0) return MZ_FALSE; mz_zip_time_to_dos_time(file_stat.st_mtime, pDOS_time, pDOS_date); #endif // #ifdef MINIZ_NO_TIME return MZ_TRUE; } #ifndef MINIZ_NO_TIME static mz_bool mz_zip_set_file_times(const char *pFilename, time_t access_time, time_t modified_time) { struct utimbuf t; t.actime = access_time; t.modtime = modified_time; return !utime(pFilename, &t); } #endif // #ifndef MINIZ_NO_TIME #endif // #ifndef MINIZ_NO_STDIO static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint32 flags) { (void)flags; if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) return MZ_FALSE; if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; if (!pZip->m_pFree) pZip->m_pFree = def_free_func; if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; pZip->m_zip_mode = MZ_ZIP_MODE_READING; pZip->m_archive_size = 0; pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return MZ_FALSE; memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); return MZ_TRUE; } static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index) { const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index)); mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS); mz_uint8 l = 0, r = 0; pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pE = pL + MZ_MIN(l_len, r_len); while (pL < pE) { if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; pL++; pR++; } return (pL == pE) ? (l_len < r_len) : (l < r); } #define MZ_SWAP_UINT32(a, b) do { mz_uint32 t = a; a = b; b = t; } MZ_MACRO_END // Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip) { mz_zip_internal_state *pState = pZip->m_pState; const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array *pCentral_dir = &pState->m_central_dir; mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); const int size = pZip->m_total_files; int start = (size - 2) >> 1, end; while (start >= 0) { int child, root = start; for ( ; ; ) { if ((child = (root << 1) + 1) >= size) break; child += (((child + 1) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1]))); if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) break; MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; } start--; } end = size - 1; while (end > 0) { int child, root = 0; MZ_SWAP_UINT32(pIndices[end], pIndices[0]); for ( ; ; ) { if ((child = (root << 1) + 1) >= end) break; child += (((child + 1) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1])); if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child])) break; MZ_SWAP_UINT32(pIndices[root], pIndices[child]); root = child; } end--; } } static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint32 flags) { mz_uint cdir_size, num_this_disk, cdir_disk_index; mz_uint64 cdir_ofs; mz_int64 cur_file_ofs; const mz_uint8 *p; mz_uint32 buf_u32[4096 / sizeof(mz_uint32)]; mz_uint8 *pBuf = (mz_uint8 *)buf_u32; mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0); // Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return MZ_FALSE; // Find the end of central directory record by scanning the file from the end towards the beginning. cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0); for ( ; ; ) { int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n) return MZ_FALSE; for (i = n - 4; i >= 0; --i) if (MZ_READ_LE32(pBuf + i) == MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) break; if (i >= 0) { cur_file_ofs += i; break; } if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (0xFFFF + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE))) return MZ_FALSE; cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0); } // Read and verify the end of central directory record. if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) return MZ_FALSE; if ((MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG) || ((pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS)) != MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS))) return MZ_FALSE; num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS); cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS); if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1))) return MZ_FALSE; if ((cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS)) < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) return MZ_FALSE; cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS); if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size) return MZ_FALSE; pZip->m_central_directory_file_ofs = cdir_ofs; if (pZip->m_total_files) { mz_uint i, n; // Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and another to hold the sorted indices. if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) || (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE))) return MZ_FALSE; if (sort_central_dir) { if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE)) return MZ_FALSE; } if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size) return MZ_FALSE; // Now create an index into the central directory file records, do some basic sanity checking on each record, and check for zip64 entries (which are not yet supported). p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p; for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i) { mz_uint total_header_size, comp_size, decomp_size, disk_index; if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)) return MZ_FALSE; MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p); if (sort_central_dir) MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i; comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size) || (decomp_size == 0xFFFFFFFF) || (comp_size == 0xFFFFFFFF)) return MZ_FALSE; disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS); if ((disk_index != num_this_disk) && (disk_index != 1)) return MZ_FALSE; if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size) return MZ_FALSE; if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n) return MZ_FALSE; n -= total_header_size; p += total_header_size; } } if (sort_central_dir) mz_zip_reader_sort_central_dir_offsets_by_filename(pZip); return MZ_TRUE; } mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint32 flags) { if ((!pZip) || (!pZip->m_pRead)) return MZ_FALSE; if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_archive_size = size; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end(pZip); return MZ_FALSE; } return MZ_TRUE; } static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n); memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s); return s; } mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint32 flags) { if (!mz_zip_reader_init_internal(pZip, flags)) return MZ_FALSE; pZip->m_archive_size = size; pZip->m_pRead = mz_zip_mem_read_func; pZip->m_pIO_opaque = pZip; #ifdef __cplusplus pZip->m_pState->m_pMem = const_cast(pMem); #else pZip->m_pState->m_pMem = (void *)pMem; #endif pZip->m_pState->m_mem_size = size; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end(pZip); return MZ_FALSE; } return MZ_TRUE; } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) return 0; return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile); } mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags) { mz_uint64 file_size; MZ_FILE *pFile = MZ_FOPEN(pFilename, "rb"); if (!pFile) return MZ_FALSE; if (MZ_FSEEK64(pFile, 0, SEEK_END)) { MZ_FCLOSE(pFile); return MZ_FALSE; } file_size = MZ_FTELL64(pFile); if (!mz_zip_reader_init_internal(pZip, flags)) { MZ_FCLOSE(pFile); return MZ_FALSE; } pZip->m_pRead = mz_zip_file_read_func; pZip->m_pIO_opaque = pZip; pZip->m_pState->m_pFile = pFile; pZip->m_archive_size = file_size; if (!mz_zip_reader_read_central_dir(pZip, flags)) { mz_zip_reader_end(pZip); return MZ_FALSE; } return MZ_TRUE; } #endif // #ifndef MINIZ_NO_STDIO mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip) { return pZip ? pZip->m_total_files : 0; } static MZ_FORCEINLINE const mz_uint8 *mz_zip_reader_get_cdh(mz_zip_archive *pZip, mz_uint file_index) { if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return NULL; return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); } mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index) { mz_uint m_bit_flag; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); if (!p) return MZ_FALSE; m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); return (m_bit_flag & 1); } mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index) { mz_uint filename_len, external_attr; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); if (!p) return MZ_FALSE; // First see if the filename ends with a '/' character. filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); if (filename_len) { if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/') return MZ_TRUE; } // Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. // Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. // FIXME: Remove this check? Is it necessary - we already check the filename. external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); if ((external_attr & 0x10) != 0) return MZ_TRUE; return MZ_FALSE; } mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat) { mz_uint n; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); if ((!p) || (!pStat)) return MZ_FALSE; // Unpack the central directory record. pStat->m_file_index = file_index; pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index); pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS); pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS); pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS); pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS); #ifndef MINIZ_NO_TIME pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS)); #endif pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS); pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS); pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS); pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS); // Copy as much of the filename and comment as possible. n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1); memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pStat->m_filename[n] = '\0'; n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); pStat->m_comment_size = n; memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n); pStat->m_comment[n] = '\0'; return MZ_TRUE; } mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size) { mz_uint n; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); if (!p) { if (filename_buf_size) pFilename[0] = '\0'; return 0; } n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS); if (filename_buf_size) { n = MZ_MIN(n, filename_buf_size - 1); memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n); pFilename[n] = '\0'; } return n + 1; } static MZ_FORCEINLINE mz_bool mz_zip_reader_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags) { mz_uint i; if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE) return 0 == memcmp(pA, pB, len); for (i = 0; i < len; ++i) if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i])) return MZ_FALSE; return MZ_TRUE; } static MZ_FORCEINLINE int mz_zip_reader_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len) { const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE; mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS); mz_uint8 l = 0, r = 0; pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; pE = pL + MZ_MIN(l_len, r_len); while (pL < pE) { if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR))) break; pL++; pR++; } return (pL == pE) ? (int)(l_len - r_len) : (l - r); } static int mz_zip_reader_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename) { mz_zip_internal_state *pState = pZip->m_pState; const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets; const mz_zip_array *pCentral_dir = &pState->m_central_dir; mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0); const int size = pZip->m_total_files; const mz_uint filename_len = (mz_uint)strlen(pFilename); int l = 0, h = size - 1; while (l <= h) { int m = (l + h) >> 1, file_index = pIndices[m], comp = mz_zip_reader_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len); if (!comp) return file_index; else if (comp < 0) l = m + 1; else h = m - 1; } return -1; } int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags) { mz_uint file_index; size_t name_len, comment_len; if ((!pZip) || (!pZip->m_pState) || (!pName) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return -1; if (((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size)) return mz_zip_reader_locate_file_binary_search(pZip, pName); name_len = strlen(pName); if (name_len > 0xFFFF) return -1; comment_len = pComment ? strlen(pComment) : 0; if (comment_len > 0xFFFF) return -1; for (file_index = 0; file_index < pZip->m_total_files; file_index++) { const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index)); mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS); const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE; if (filename_len < name_len) continue; if (comment_len) { mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS); const char *pFile_comment = pFilename + filename_len + file_extra_len; if ((file_comment_len != comment_len) || (!mz_zip_reader_string_equal(pComment, pFile_comment, file_comment_len, flags))) continue; } if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len)) { int ofs = filename_len - 1; do { if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':')) break; } while (--ofs >= 0); ofs++; pFilename += ofs; filename_len -= ofs; } if ((filename_len == name_len) && (mz_zip_reader_string_equal(pName, pFilename, filename_len, flags))) return file_index; } return -1; } mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { int status = TINFL_STATUS_DONE; mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail; mz_zip_archive_file_stat file_stat; void *pRead_buf; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; tinfl_decompressor inflator; if ((buf_size) && (!pBuf)) return MZ_FALSE; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) if (!file_stat.m_comp_size) return MZ_TRUE; // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). // I'm torn how to handle this case - should it fail instead? if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; // Encryption and patch files are not supported. if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE; // This function only supports stored and deflate. if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return MZ_FALSE; // Ensure supplied output buffer is large enough. needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size; if (buf_size < needed_size) return MZ_FALSE; // Read and parse the local directory entry. cur_file_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return MZ_FALSE; if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return MZ_FALSE; cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return MZ_FALSE; if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { // The file is stored or the caller has requested the compressed data. if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size) return MZ_FALSE; return ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) != 0) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) == file_stat.m_crc32); } // Decompress the file either directly from memory or from a file input buffer. tinfl_init(&inflator); if (pZip->m_pState->m_pMem) { // Read directly from the archive in memory. pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; read_buf_size = read_buf_avail = file_stat.m_comp_size; comp_remaining = 0; } else if (pUser_read_buf) { // Use a user provided read buffer. if (!user_read_buf_size) return MZ_FALSE; pRead_buf = (mz_uint8 *)pUser_read_buf; read_buf_size = user_read_buf_size; read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } else { // Temporarily allocate a read buffer. read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); #ifdef _MSC_VER if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) #else if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF)) #endif return MZ_FALSE; if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return MZ_FALSE; read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } do { size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs); if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; break; } cur_file_ofs += read_buf_avail; comp_remaining -= read_buf_avail; read_buf_ofs = 0; } in_buf_size = (size_t)read_buf_avail; status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0)); read_buf_avail -= in_buf_size; read_buf_ofs += in_buf_size; out_buf_ofs += out_buf_size; } while (status == TINFL_STATUS_NEEDS_MORE_INPUT); if (status == TINFL_STATUS_DONE) { // Make sure the entire file was decompressed, and check its CRC. if ((out_buf_ofs != file_stat.m_uncomp_size) || (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)) status = TINFL_STATUS_FAILED; } if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf)) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); return status == TINFL_STATUS_DONE; } mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size) { int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); if (file_index < 0) return MZ_FALSE; return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size); } mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags) { return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0); } mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags) { return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0); } void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags) { mz_uint64 comp_size, uncomp_size, alloc_size; const mz_uint8 *p = mz_zip_reader_get_cdh(pZip, file_index); void *pBuf; if (pSize) *pSize = 0; if (!p) return NULL; comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS); alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size; #ifdef _MSC_VER if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) #else if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF)) #endif return NULL; if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size))) return NULL; if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return NULL; } if (pSize) *pSize = (size_t)alloc_size; return pBuf; } void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags) { int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); if (file_index < 0) { if (pSize) *pSize = 0; return MZ_FALSE; } return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags); } mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { int status = TINFL_STATUS_DONE; mz_uint file_crc32 = MZ_CRC32_INIT; mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs; mz_zip_archive_file_stat file_stat; void *pRead_buf = NULL; void *pWrite_buf = NULL; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; // Empty file, or a directory (but not always a directory - I've seen odd zips with directories that have compressed data which inflates to 0 bytes) if (!file_stat.m_comp_size) return MZ_TRUE; // Entry is a subdirectory (I've seen old zips with dir entries which have compressed deflate data which inflates to 0 bytes, but these entries claim to uncompress to 512 bytes in the headers). // I'm torn how to handle this case - should it fail instead? if (mz_zip_reader_is_file_a_directory(pZip, file_index)) return MZ_TRUE; // Encryption and patch files are not supported. if (file_stat.m_bit_flag & (1 | 32)) return MZ_FALSE; // This function only supports stored and deflate. if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED)) return MZ_FALSE; // Read and parse the local directory entry. cur_file_ofs = file_stat.m_local_header_ofs; if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return MZ_FALSE; if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return MZ_FALSE; cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size) return MZ_FALSE; // Decompress the file either directly from memory or from a file input buffer. if (pZip->m_pState->m_pMem) { pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs; read_buf_size = read_buf_avail = file_stat.m_comp_size; comp_remaining = 0; } else { read_buf_size = MZ_MIN(file_stat.m_comp_size, MZ_ZIP_MAX_IO_BUF_SIZE); if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size))) return MZ_FALSE; read_buf_avail = 0; comp_remaining = file_stat.m_comp_size; } if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method)) { // The file is stored or the caller has requested the compressed data. if (pZip->m_pState->m_pMem) { #ifdef _MSC_VER if (((0, sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) #else if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > 0xFFFFFFFF)) #endif return MZ_FALSE; if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size) status = TINFL_STATUS_FAILED; else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size); out_buf_ofs += file_stat.m_comp_size; } else { while (comp_remaining) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; break; } if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail); if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; break; } cur_file_ofs += read_buf_avail; out_buf_ofs += read_buf_avail; comp_remaining -= read_buf_avail; } } } else { tinfl_decompressor inflator; tinfl_init(&inflator); if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE))) status = TINFL_STATUS_FAILED; else { do { mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1)); if ((!read_buf_avail) && (!pZip->m_pState->m_pMem)) { read_buf_avail = MZ_MIN(read_buf_size, comp_remaining); if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail) { status = TINFL_STATUS_FAILED; break; } cur_file_ofs += read_buf_avail; comp_remaining -= read_buf_avail; read_buf_ofs = 0; } in_buf_size = (size_t)read_buf_avail; status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0); read_buf_avail -= in_buf_size; read_buf_ofs += in_buf_size; if (out_buf_size) { if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size) { status = TINFL_STATUS_FAILED; break; } file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size); if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size) { status = TINFL_STATUS_FAILED; break; } } } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT)); } } if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))) { // Make sure the entire file was decompressed, and check its CRC. if ((out_buf_ofs != file_stat.m_uncomp_size) || (file_crc32 != file_stat.m_crc32)) status = TINFL_STATUS_FAILED; } if (!pZip->m_pState->m_pMem) pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); if (pWrite_buf) pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf); return status == TINFL_STATUS_DONE; } mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags) { int file_index = mz_zip_reader_locate_file(pZip, pFilename, NULL, flags); if (file_index < 0) return MZ_FALSE; return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags); } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n) { (void)ofs; return MZ_FWRITE(pBuf, 1, n, (MZ_FILE*)pOpaque); } mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags) { mz_bool status; mz_zip_archive_file_stat file_stat; MZ_FILE *pFile; if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat)) return MZ_FALSE; pFile = MZ_FOPEN(pDst_filename, "wb"); if (!pFile) return MZ_FALSE; status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags); if (MZ_FCLOSE(pFile) == EOF) return MZ_FALSE; #ifndef MINIZ_NO_TIME if (status) mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time); #endif return status; } #endif // #ifndef MINIZ_NO_STDIO mz_bool mz_zip_reader_end(mz_zip_archive *pZip) { if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return MZ_FALSE; if (pZip->m_pState) { mz_zip_internal_state *pState = pZip->m_pState; pZip->m_pState = NULL; mz_zip_array_clear(pZip, &pState->m_central_dir); mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO if (pState->m_pFile) { MZ_FCLOSE(pState->m_pFile); pState->m_pFile = NULL; } #endif // #ifndef MINIZ_NO_STDIO pZip->m_pFree(pZip->m_pAlloc_opaque, pState); } pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; return MZ_TRUE; } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags) { int file_index = mz_zip_reader_locate_file(pZip, pArchive_filename, NULL, flags); if (file_index < 0) return MZ_FALSE; return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags); } #endif // ------------------- .ZIP archive writing #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS static void mz_write_le16(mz_uint8 *p, mz_uint16 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); } static void mz_write_le32(mz_uint8 *p, mz_uint32 v) { p[0] = (mz_uint8)v; p[1] = (mz_uint8)(v >> 8); p[2] = (mz_uint8)(v >> 16); p[3] = (mz_uint8)(v >> 24); } #define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v)) #define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v)) mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size) { if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID)) return MZ_FALSE; if (pZip->m_file_offset_alignment) { // Ensure user specified file offset alignment is a power of 2. if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1)) return MZ_FALSE; } if (!pZip->m_pAlloc) pZip->m_pAlloc = def_alloc_func; if (!pZip->m_pFree) pZip->m_pFree = def_free_func; if (!pZip->m_pRealloc) pZip->m_pRealloc = def_realloc_func; pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; pZip->m_archive_size = existing_size; pZip->m_central_directory_file_ofs = 0; pZip->m_total_files = 0; if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state)))) return MZ_FALSE; memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32)); MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32)); return MZ_TRUE; } static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_zip_internal_state *pState = pZip->m_pState; mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size); #ifdef _MSC_VER if ((!n) || ((0, sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) #else if ((!n) || ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))) #endif return 0; if (new_size > pState->m_mem_capacity) { void *pNew_block; size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity); while (new_capacity < new_size) new_capacity *= 2; if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity))) return 0; pState->m_pMem = pNew_block; pState->m_mem_capacity = new_capacity; } memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n); pState->m_mem_size = (size_t)new_size; return n; } mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size) { pZip->m_pWrite = mz_zip_heap_write_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning))) { if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size))) { mz_zip_writer_end(pZip); return MZ_FALSE; } pZip->m_pState->m_mem_capacity = initial_allocation_size; } return MZ_TRUE; } #ifndef MINIZ_NO_STDIO static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n) { mz_zip_archive *pZip = (mz_zip_archive *)pOpaque; mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile); if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET)))) return 0; return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile); } mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning) { MZ_FILE *pFile; pZip->m_pWrite = mz_zip_file_write_func; pZip->m_pIO_opaque = pZip; if (!mz_zip_writer_init(pZip, size_to_reserve_at_beginning)) return MZ_FALSE; if (NULL == (pFile = MZ_FOPEN(pFilename, "wb"))) { mz_zip_writer_end(pZip); return MZ_FALSE; } pZip->m_pState->m_pFile = pFile; if (size_to_reserve_at_beginning) { mz_uint64 cur_ofs = 0; char buf[4096]; MZ_CLEAR_OBJ(buf); do { size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n) { mz_zip_writer_end(pZip); return MZ_FALSE; } cur_ofs += n; size_to_reserve_at_beginning -= n; } while (size_to_reserve_at_beginning); } return MZ_TRUE; } #endif // #ifndef MINIZ_NO_STDIO mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename) { mz_zip_internal_state *pState; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING)) return MZ_FALSE; // No sense in trying to write to an archive that's already at the support max size if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) return MZ_FALSE; pState = pZip->m_pState; if (pState->m_pFile) { #ifdef MINIZ_NO_STDIO pFilename; return MZ_FALSE; #else // Archive is being read from stdio - try to reopen as writable. if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; if (!pFilename) return MZ_FALSE; pZip->m_pWrite = mz_zip_file_write_func; if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile))) { // The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. mz_zip_reader_end(pZip); return MZ_FALSE; } #endif // #ifdef MINIZ_NO_STDIO } else if (pState->m_pMem) { // Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. if (pZip->m_pIO_opaque != pZip) return MZ_FALSE; pState->m_mem_capacity = pState->m_mem_size; pZip->m_pWrite = mz_zip_heap_write_func; } // Archive is being read via a user provided read function - make sure the user has specified a write function too. else if (!pZip->m_pWrite) return MZ_FALSE; // Start writing new files at the archive's current central directory location. pZip->m_archive_size = pZip->m_central_directory_file_ofs; pZip->m_zip_mode = MZ_ZIP_MODE_WRITING; pZip->m_central_directory_file_ofs = 0; return MZ_TRUE; } mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags) { return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0); } typedef struct { mz_zip_archive *m_pZip; mz_uint64 m_cur_archive_file_ofs; mz_uint64 m_comp_size; } mz_zip_writer_add_state; static mz_bool mz_zip_writer_add_put_buf_callback(const void* pBuf, int len, void *pUser) { mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser; if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len) return MZ_FALSE; pState->m_cur_archive_file_ofs += len; pState->m_comp_size += len; return MZ_TRUE; } static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date) { (void)pZip; memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, comp_size); MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, uncomp_size); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size); MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size); return MZ_TRUE; } static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { (void)pZip; memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, comp_size); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, uncomp_size); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size); MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes); MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_header_ofs); return MZ_TRUE; } static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size, const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date, mz_uint64 local_header_ofs, mz_uint32 ext_attributes) { mz_zip_internal_state *pState = pZip->m_pState; mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size; size_t orig_central_dir_size = pState->m_central_dir.m_size; mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; // No zip64 support yet if ((local_header_ofs > 0xFFFFFFFF) || (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + comment_size) > 0xFFFFFFFF)) return MZ_FALSE; if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes)) return MZ_FALSE; if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) || (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, ¢ral_dir_ofs, 1))) { // Try to push the central directory array back into its original state. mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return MZ_FALSE; } return MZ_TRUE; } static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name) { // Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. if (*pArchive_name == '/') return MZ_FALSE; while (*pArchive_name) { if ((*pArchive_name == '\\') || (*pArchive_name == ':')) return MZ_FALSE; pArchive_name++; } return MZ_TRUE; } static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip) { mz_uint32 n; if (!pZip->m_file_offset_alignment) return 0; n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1)); return (pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1); } static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n) { char buf[4096]; memset(buf, 0, MZ_MIN(sizeof(buf), n)); while (n) { mz_uint32 s = MZ_MIN(sizeof(buf), n); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s) return MZ_FALSE; cur_file_ofs += s; n -= s; } return MZ_TRUE; } mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32) { mz_uint16 method = 0, dos_time = 0, dos_date = 0; mz_uint level, ext_attributes = 0, num_alignment_padding_bytes; mz_uint64 local_dir_header_ofs, cur_archive_file_ofs, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; tdefl_compressor *pComp = NULL; mz_bool store_data_uncompressed; mz_zip_internal_state *pState; if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; level = level_and_flags & 0xF; store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)); if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (pZip->m_total_files == 0xFFFF) || (level > MZ_UBER_COMPRESSION)) return MZ_FALSE; local_dir_header_ofs = cur_archive_file_ofs = pZip->m_archive_size; pState = pZip->m_pState; if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size)) return MZ_FALSE; // No zip64 support yet if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF)) return MZ_FALSE; if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; #ifndef MINIZ_NO_TIME { time_t cur_time; time(&cur_time); mz_zip_time_to_dos_time(cur_time, &dos_time, &dos_date); } #endif // #ifndef MINIZ_NO_TIME archive_name_size = strlen(pArchive_name); if (archive_name_size > 0xFFFF) return MZ_FALSE; num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); // no zip64 support yet if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) return MZ_FALSE; if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/')) { // Set DOS Subdirectory attribute bit. ext_attributes |= 0x10; // Subdirectories cannot contain data. if ((buf_size) || (uncomp_size)) return MZ_FALSE; } // Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size)) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1))) return MZ_FALSE; if ((!store_data_uncompressed) && (buf_size)) { if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)))) return MZ_FALSE; } if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } local_dir_header_ofs += num_alignment_padding_bytes; if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); MZ_CLEAR_OBJ(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } cur_archive_file_ofs += archive_name_size; if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) { uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8*)pBuf, buf_size); uncomp_size = buf_size; if (uncomp_size <= 3) { level = 0; store_data_uncompressed = MZ_TRUE; } } if (store_data_uncompressed) { if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } cur_archive_file_ofs += buf_size; comp_size = buf_size; if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) method = MZ_DEFLATED; } else if (buf_size) { mz_zip_writer_add_state state; state.m_pZip = pZip; state.m_cur_archive_file_ofs = cur_archive_file_ofs; state.m_comp_size = 0; if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) || (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); return MZ_FALSE; } comp_size = state.m_comp_size; cur_archive_file_ofs = state.m_cur_archive_file_ofs; method = MZ_DEFLATED; } pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); pComp = NULL; // no zip64 support yet if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) return MZ_FALSE; if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) return MZ_FALSE; if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return MZ_FALSE; if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) return MZ_FALSE; pZip->m_total_files++; pZip->m_archive_size = cur_archive_file_ofs; return MZ_TRUE; } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes; mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0; mz_uint64 local_dir_header_ofs, cur_archive_file_ofs, uncomp_size = 0, comp_size = 0; size_t archive_name_size; mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE]; MZ_FILE *pSrc_file = NULL; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION)) return MZ_FALSE; local_dir_header_ofs = cur_archive_file_ofs = pZip->m_archive_size; if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; level = level_and_flags & 0xF; if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA) return MZ_FALSE; if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; archive_name_size = strlen(pArchive_name); if (archive_name_size > 0xFFFF) return MZ_FALSE; num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); // no zip64 support yet if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + comment_size + archive_name_size) > 0xFFFFFFFF)) return MZ_FALSE; if (!mz_zip_get_file_modified_time(pSrc_filename, &dos_time, &dos_date)) return MZ_FALSE; pSrc_file = MZ_FOPEN(pSrc_filename, "rb"); if (!pSrc_file) return MZ_FALSE; MZ_FSEEK64(pSrc_file, 0, SEEK_END); uncomp_size = MZ_FTELL64(pSrc_file); MZ_FSEEK64(pSrc_file, 0, SEEK_SET); if (uncomp_size > 0xFFFFFFFF) { // No zip64 support yet MZ_FCLOSE(pSrc_file); return MZ_FALSE; } if (uncomp_size <= 3) level = 0; if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes + sizeof(local_dir_header))) { MZ_FCLOSE(pSrc_file); return MZ_FALSE; } local_dir_header_ofs += num_alignment_padding_bytes; if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } cur_archive_file_ofs += num_alignment_padding_bytes + sizeof(local_dir_header); MZ_CLEAR_OBJ(local_dir_header); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size) { MZ_FCLOSE(pSrc_file); return MZ_FALSE; } cur_archive_file_ofs += archive_name_size; if (uncomp_size) { mz_uint64 uncomp_remaining = uncomp_size; void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE); if (!pRead_buf) { MZ_FCLOSE(pSrc_file); return MZ_FALSE; } if (!level) { while (uncomp_remaining) { mz_uint n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining); if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); MZ_FCLOSE(pSrc_file); return MZ_FALSE; } uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n); uncomp_remaining -= n; cur_archive_file_ofs += n; } comp_size = uncomp_size; } else { mz_bool result = MZ_FALSE; mz_zip_writer_add_state state; tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor)); if (!pComp) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); MZ_FCLOSE(pSrc_file); return MZ_FALSE; } state.m_pZip = pZip; state.m_cur_archive_file_ofs = cur_archive_file_ofs; state.m_comp_size = 0; if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) { pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); MZ_FCLOSE(pSrc_file); return MZ_FALSE; } for ( ; ; ) { size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, MZ_ZIP_MAX_IO_BUF_SIZE); tdefl_status status; if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size) break; uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size); uncomp_remaining -= in_buf_size; status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? TDEFL_NO_FLUSH : TDEFL_FINISH); if (status == TDEFL_STATUS_DONE) { result = MZ_TRUE; break; } else if (status != TDEFL_STATUS_OKAY) break; } pZip->m_pFree(pZip->m_pAlloc_opaque, pComp); if (!result) { pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); MZ_FCLOSE(pSrc_file); return MZ_FALSE; } comp_size = state.m_comp_size; cur_archive_file_ofs = state.m_cur_archive_file_ofs; method = MZ_DEFLATED; } pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf); } MZ_FCLOSE(pSrc_file); pSrc_file = NULL; // no zip64 support yet if ((comp_size > 0xFFFFFFFF) || (cur_archive_file_ofs > 0xFFFFFFFF)) return MZ_FALSE; if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, 0, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date)) return MZ_FALSE; if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header)) return MZ_FALSE; if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, NULL, 0, pComment, comment_size, uncomp_size, comp_size, uncomp_crc32, method, 0, dos_time, dos_date, local_dir_header_ofs, ext_attributes)) return MZ_FALSE; pZip->m_total_files++; pZip->m_archive_size = cur_archive_file_ofs; return MZ_TRUE; } #endif // #ifndef MINIZ_NO_STDIO mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint file_index) { mz_uint n, bit_flags, num_alignment_padding_bytes; mz_uint64 comp_bytes_remaining, local_dir_header_ofs; mz_uint64 cur_src_file_ofs, cur_dst_file_ofs; mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)]; mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32; mz_uint8 central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE]; size_t orig_central_dir_size; mz_zip_internal_state *pState; void *pBuf; const mz_uint8 *pSrc_central_header; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) return MZ_FALSE; if (NULL == (pSrc_central_header = mz_zip_reader_get_cdh(pSource_zip, file_index))) return MZ_FALSE; pState = pZip->m_pState; num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip); // no zip64 support yet if ((pZip->m_total_files == 0xFFFF) || ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) return MZ_FALSE; cur_src_file_ofs = MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS); cur_dst_file_ofs = pZip->m_archive_size; if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return MZ_FALSE; if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG) return MZ_FALSE; cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes)) return MZ_FALSE; cur_dst_file_ofs += num_alignment_padding_bytes; local_dir_header_ofs = cur_dst_file_ofs; if (pZip->m_file_offset_alignment) { MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0); } if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE) return MZ_FALSE; cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE; n = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS); comp_bytes_remaining = n + MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS); if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(sizeof(mz_uint32) * 4, MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining))))) return MZ_FALSE; while (comp_bytes_remaining) { n = (mz_uint)MZ_MIN(MZ_ZIP_MAX_IO_BUF_SIZE, comp_bytes_remaining); if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return MZ_FALSE; } cur_src_file_ofs += n; if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return MZ_FALSE; } cur_dst_file_ofs += n; comp_bytes_remaining -= n; } bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS); if (bit_flags & 8) { // Copy data descriptor if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return MZ_FALSE; } n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == 0x08074b50) ? 4 : 3); if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n) { pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); return MZ_FALSE; } cur_dst_file_ofs += n; } pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf); // no zip64 support yet if (cur_dst_file_ofs > 0xFFFFFFFF) return MZ_FALSE; orig_central_dir_size = pState->m_central_dir.m_size; memcpy(central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE); MZ_WRITE_LE32(central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) return MZ_FALSE; n = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS); if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n)) { mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return MZ_FALSE; } if (pState->m_central_dir.m_size > 0xFFFFFFFF) return MZ_FALSE; n = (mz_uint32)orig_central_dir_size; if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1)) { mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE); return MZ_FALSE; } pZip->m_total_files++; pZip->m_archive_size = cur_dst_file_ofs; return MZ_TRUE; } mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip) { mz_zip_internal_state *pState; mz_uint64 central_dir_ofs, central_dir_size; mz_uint8 hdr[MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE]; if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING)) return MZ_FALSE; pState = pZip->m_pState; // no zip64 support yet if ((pZip->m_total_files > 0xFFFF) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)) return MZ_FALSE; central_dir_ofs = 0; central_dir_size = 0; if (pZip->m_total_files) { // Write central directory central_dir_ofs = pZip->m_archive_size; central_dir_size = pState->m_central_dir.m_size; pZip->m_central_directory_file_ofs = central_dir_ofs; if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size) return MZ_FALSE; pZip->m_archive_size += central_dir_size; } // Write end of central directory record MZ_CLEAR_OBJ(hdr); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files); MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, central_dir_size); MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, central_dir_ofs); if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, sizeof(hdr)) != sizeof(hdr)) return MZ_FALSE; #ifndef MINIZ_NO_STDIO if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF)) return MZ_FALSE; #endif // #ifndef MINIZ_NO_STDIO pZip->m_archive_size += sizeof(hdr); pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED; return MZ_TRUE; } mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **pBuf, size_t *pSize) { if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pSize)) return MZ_FALSE; if (pZip->m_pWrite != mz_zip_heap_write_func) return MZ_FALSE; if (!mz_zip_writer_finalize_archive(pZip)) return MZ_FALSE; *pBuf = pZip->m_pState->m_pMem; *pSize = pZip->m_pState->m_mem_size; pZip->m_pState->m_pMem = NULL; pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0; return MZ_TRUE; } mz_bool mz_zip_writer_end(mz_zip_archive *pZip) { mz_zip_internal_state *pState; mz_bool status = MZ_TRUE; if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))) return MZ_FALSE; pState = pZip->m_pState; pZip->m_pState = NULL; mz_zip_array_clear(pZip, &pState->m_central_dir); mz_zip_array_clear(pZip, &pState->m_central_dir_offsets); mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets); #ifndef MINIZ_NO_STDIO if (pState->m_pFile) { MZ_FCLOSE(pState->m_pFile); pState->m_pFile = NULL; } #endif // #ifndef MINIZ_NO_STDIO if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem)) { pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem); pState->m_pMem = NULL; } pZip->m_pFree(pZip->m_pAlloc_opaque, pState); pZip->m_zip_mode = MZ_ZIP_MODE_INVALID; return status; } #ifndef MINIZ_NO_STDIO mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags) { mz_bool status, created_new_archive = MZ_FALSE; mz_zip_archive zip_archive; struct MZ_FILE_STAT_STRUCT file_stat; MZ_CLEAR_OBJ(zip_archive); if ((int)level_and_flags < 0) level_and_flags = MZ_DEFAULT_LEVEL; if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION)) return MZ_FALSE; if (!mz_zip_writer_validate_archive_name(pArchive_name)) return MZ_FALSE; if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0) { // Create a new archive. if (!mz_zip_writer_init_file(&zip_archive, pZip_filename, 0)) return MZ_FALSE; created_new_archive = MZ_TRUE; } else { // Append to an existing archive. if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) return MZ_FALSE; if (!mz_zip_writer_init_from_reader(&zip_archive, pZip_filename)) { mz_zip_reader_end(&zip_archive); return MZ_FALSE; } } status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0); // Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) if (!mz_zip_writer_finalize_archive(&zip_archive)) status = MZ_FALSE; if (!mz_zip_writer_end(&zip_archive)) status = MZ_FALSE; if ((!status) && (created_new_archive)) { // It's a new archive and something went wrong, so just delete it. int ignoredStatus = MZ_DELETE_FILE(pZip_filename); (void)ignoredStatus; } return status; } void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags) { int file_index; mz_zip_archive zip_archive; void *p = NULL; if (pSize) *pSize = 0; if ((!pZip_filename) || (!pArchive_name)) return NULL; MZ_CLEAR_OBJ(zip_archive); if (!mz_zip_reader_init_file(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY)) return NULL; if ((file_index = mz_zip_reader_locate_file(&zip_archive, pArchive_name, NULL, flags)) >= 0) p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags); mz_zip_reader_end(&zip_archive); return p; } #endif // #ifndef MINIZ_NO_STDIO #endif // #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS #endif // #ifndef MINIZ_NO_ARCHIVE_APIS #ifdef __cplusplus } #endif #endif // MINIZ_HEADER_FILE_ONLY /* This is free and unencumbered software released into the public domain. Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means. In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS 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. For more information, please refer to */ assimp-4.1.0/contrib/zip/test/0000755002537200234200000000000013213503245016475 5ustar zmoelnigiemusersassimp-4.1.0/contrib/zip/test/test.c0000644002537200234200000000521213213503245017620 0ustar zmoelnigiemusers#include #include #include #include #include #define ZIPNAME "test.zip" #define TESTDATA1 "Some test data 1...\0" #define TESTDATA2 "Some test data 2...\0" static void test_write(void) { struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'w'); assert(zip != NULL); assert(0 == zip_entry_open(zip, "test/test-1.txt")); assert(0 == zip_entry_write(zip, TESTDATA1, strlen(TESTDATA1))); assert(0 == zip_entry_close(zip)); zip_close(zip); } static void test_append(void) { struct zip_t *zip = zip_open(ZIPNAME, ZIP_DEFAULT_COMPRESSION_LEVEL, 'a'); assert(zip != NULL); assert(0 == zip_entry_open(zip, "test\\test-2.txt")); assert(0 == zip_entry_write(zip, TESTDATA2, strlen(TESTDATA2))); assert(0 == zip_entry_close(zip)); zip_close(zip); } static void test_read(void) { char *buf = NULL; size_t bufsize; struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); assert(zip != NULL); assert(0 == zip_entry_open(zip, "test\\test-1.txt")); assert(0 == zip_entry_read(zip, (void **)&buf, &bufsize)); assert(bufsize == strlen(TESTDATA1)); assert(0 == strncmp(buf, TESTDATA1, bufsize)); assert(0 == zip_entry_close(zip)); free(buf); buf = NULL; bufsize = 0; assert(0 == zip_entry_open(zip, "test/test-2.txt")); assert(0 == zip_entry_read(zip, (void **)&buf, &bufsize)); assert(bufsize == strlen(TESTDATA2)); assert(0 == strncmp(buf, TESTDATA2, bufsize)); assert(0 == zip_entry_close(zip)); free(buf); buf = NULL; bufsize = 0; zip_close(zip); } struct buffer_t { char *data; size_t size; }; static size_t on_extract(void *arg, unsigned long long offset, const void *data, size_t size) { struct buffer_t *buf = (struct buffer_t *)arg; buf->data = realloc(buf->data, buf->size + size + 1); assert(NULL != buf->data); memcpy(&(buf->data[buf->size]), data, size); buf->size += size; buf->data[buf->size] = 0; return size; } static void test_extract(void) { struct buffer_t buf = {0}; struct zip_t *zip = zip_open(ZIPNAME, 0, 'r'); assert(zip != NULL); assert(0 == zip_entry_open(zip, "test/test-1.txt")); assert(0 == zip_entry_extract(zip, on_extract, &buf)); assert(buf.size == strlen(TESTDATA1)); assert(0 == strncmp(buf.data, TESTDATA1, buf.size)); assert(0 == zip_entry_close(zip)); free(buf.data); buf.data = NULL; buf.size = 0; zip_close(zip); } int main(int argc, char *argv[]) { test_write(); test_append(); test_read(); test_extract(); return remove(ZIPNAME); } assimp-4.1.0/contrib/zip/test/CMakeLists.txt0000644002537200234200000000023313213503245021233 0ustar zmoelnigiemuserscmake_minimum_required(VERSION 2.8) # test include_directories(../src) add_executable(test.exe test.c ../src/zip.c) add_test(NAME test COMMAND test.exe) assimp-4.1.0/contrib/zip/CMakeLists.txt0000644002537200234200000000110713213503245020255 0ustar zmoelnigiemuserscmake_minimum_required(VERSION 2.8) project(zip) if (MSVC) # Use secure functions by defaualt and suppress warnings about "deprecated" functions set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES=1") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_SECURE_CPP_OVERLOAD_STANDARD_NAMES_COUNT=1") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /D _CRT_NONSTDC_NO_WARNINGS=1 /D _CRT_SECURE_NO_WARNINGS=1") endif (MSVC) # zip set(SRC src/miniz.h src/zip.h src/zip.c) add_library(${CMAKE_PROJECT_NAME} ${SRC}) # test enable_testing() add_subdirectory(test) assimp-4.1.0/contrib/Open3DGC/0000755002537200234200000000000013213503245016216 5ustar zmoelnigiemusersassimp-4.1.0/contrib/Open3DGC/o3dgcCommon.h0000644002537200234200000003144413213503245020545 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_COMMON_H #define O3DGC_COMMON_H #ifndef _CRT_SECURE_NO_WARNINGS #define _CRT_SECURE_NO_WARNINGS #endif #include #include #include #include namespace o3dgc { typedef float Real; const double O3DGC_MAX_DOUBLE = 1.79769e+308; const long O3DGC_MIN_LONG = -2147483647; const long O3DGC_MAX_LONG = 2147483647; const long O3DGC_MAX_UCHAR8 = 255; const long O3DGC_MAX_TFAN_SIZE = 256; const unsigned long O3DGC_MAX_ULONG = 4294967295; const unsigned long O3DGC_SC3DMC_START_CODE = 0x00001F1; const unsigned long O3DGC_DV_START_CODE = 0x00001F2; const unsigned long O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES = 256; const unsigned long O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES = 256; const unsigned long O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES = 32; const unsigned long O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS = 2; const unsigned long O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS = 257; enum O3DGCEndianness { O3DGC_BIG_ENDIAN = 0, O3DGC_LITTLE_ENDIAN = 1 }; enum O3DGCErrorCode { O3DGC_OK, O3DGC_ERROR_BUFFER_FULL, O3DGC_ERROR_CREATE_FILE, O3DGC_ERROR_OPEN_FILE, O3DGC_ERROR_READ_FILE, O3DGC_ERROR_CORRUPTED_STREAM, O3DGC_ERROR_NON_SUPPORTED_FEATURE }; enum O3DGCSC3DMCBinarization { O3DGC_SC3DMC_BINARIZATION_FL = 0, // Fixed Length (not supported) O3DGC_SC3DMC_BINARIZATION_BP = 1, // BPC (not supported) O3DGC_SC3DMC_BINARIZATION_FC = 2, // 4 bits Coding (not supported) O3DGC_SC3DMC_BINARIZATION_AC = 3, // Arithmetic Coding (not supported) O3DGC_SC3DMC_BINARIZATION_AC_EGC = 4, // Arithmetic Coding & EGCk O3DGC_SC3DMC_BINARIZATION_ASCII = 5 // Arithmetic Coding & EGCk }; enum O3DGCStreamType { O3DGC_STREAM_TYPE_UNKOWN = 0, O3DGC_STREAM_TYPE_ASCII = 1, O3DGC_STREAM_TYPE_BINARY = 2 }; enum O3DGCSC3DMCQuantizationMode { O3DGC_SC3DMC_DIAG_BB = 0, // supported O3DGC_SC3DMC_MAX_ALL_DIMS = 1, // supported O3DGC_SC3DMC_MAX_SEP_DIM = 2 // supported }; enum O3DGCSC3DMCPredictionMode { O3DGC_SC3DMC_NO_PREDICTION = 0, // supported O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION = 1, // supported O3DGC_SC3DMC_XOR_PREDICTION = 2, // not supported O3DGC_SC3DMC_ADAPTIVE_DIFFERENTIAL_PREDICTION = 3, // not supported O3DGC_SC3DMC_CIRCULAR_DIFFERENTIAL_PREDICTION = 4, // not supported O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION = 5, // supported O3DGC_SC3DMC_SURF_NORMALS_PREDICTION = 6 // supported }; enum O3DGCSC3DMCEncodingMode { O3DGC_SC3DMC_ENCODE_MODE_QBCR = 0, // not supported O3DGC_SC3DMC_ENCODE_MODE_SVA = 1, // not supported O3DGC_SC3DMC_ENCODE_MODE_TFAN = 2, // supported }; enum O3DGCDVEncodingMode { O3DGC_DYNAMIC_VECTOR_ENCODE_MODE_LIFT = 0 }; enum O3DGCIFSFloatAttributeType { O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_UNKOWN = 0, O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_POSITION = 1, O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_NORMAL = 2, O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_COLOR = 3, O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_TEXCOORD = 4, O3DGC_IFS_FLOAT_ATTRIBUTE_TYPE_WEIGHT = 5 }; enum O3DGCIFSIntAttributeType { O3DGC_IFS_INT_ATTRIBUTE_TYPE_UNKOWN = 0, O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX = 1, O3DGC_IFS_INT_ATTRIBUTE_TYPE_JOINT_ID = 2, O3DGC_IFS_INT_ATTRIBUTE_TYPE_INDEX_BUFFER_ID = 3 }; template inline const T absolute(const T& a) { return (a < (T)(0)) ? -a : a; } template inline const T min(const T& a, const T& b) { return (b < a) ? b : a; } template inline const T max(const T& a, const T& b) { return (b > a) ? b : a; } template inline void swap(T& a, T& b) { T tmp = a; a = b; b = tmp; } inline double log2( double n ) { return log(n) / log(2.0); } inline O3DGCEndianness SystemEndianness() { unsigned long num = 1; return ( *((char *)(&num)) == 1 )? O3DGC_LITTLE_ENDIAN : O3DGC_BIG_ENDIAN ; } class SC3DMCStats { public: SC3DMCStats(void) { memset(this, 0, sizeof(SC3DMCStats)); }; ~SC3DMCStats(void){}; double m_timeCoord; double m_timeNormal; double m_timeCoordIndex; double m_timeFloatAttribute[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; double m_timeIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ]; double m_timeReorder; unsigned long m_streamSizeCoord; unsigned long m_streamSizeNormal; unsigned long m_streamSizeCoordIndex; unsigned long m_streamSizeFloatAttribute[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; unsigned long m_streamSizeIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ]; }; typedef struct { long m_a; long m_b; long m_c; } SC3DMCTriplet; typedef struct { SC3DMCTriplet m_id; long m_pred[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]; } SC3DMCPredictor; inline bool operator< (const SC3DMCTriplet& lhs, const SC3DMCTriplet& rhs) { if (lhs.m_c != rhs.m_c) { return (lhs.m_c < rhs.m_c); } else if (lhs.m_b != rhs.m_b) { return (lhs.m_b < rhs.m_b); } return (lhs.m_a < rhs.m_a); } inline bool operator== (const SC3DMCTriplet& lhs, const SC3DMCTriplet& rhs) { return (lhs.m_c == rhs.m_c && lhs.m_b == rhs.m_b && lhs.m_a == rhs.m_a); } // fix me: optimize this function (e.g., binary search) inline unsigned long Insert(SC3DMCTriplet e, unsigned long & nPred, SC3DMCPredictor * const list) { unsigned long pos = 0xFFFFFFFF; bool foundOrInserted = false; for (unsigned long j = 0; j < nPred; ++j) { if (e == list[j].m_id) { foundOrInserted = true; break; } else if (e < list[j].m_id) { if (nPred < O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS) { ++nPred; } for (unsigned long h = nPred-1; h > j; --h) { list[h] = list[h-1]; } list[j].m_id = e; pos = j; foundOrInserted = true; break; } } if (!foundOrInserted && nPred < O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS) { pos = nPred; list[nPred++].m_id = e; } return pos; } template inline void SphereToCube(const T x, const T y, const T z, T & a, T & b, char & index) { T ax = absolute(x); T ay = absolute(y); T az = absolute(z); if (az >= ax && az >= ay) { if (z >= (T)(0)) { index = 0; a = x; b = y; } else { index = 1; a = -x; b = -y; } } else if (ay >= ax && ay >= az) { if (y >= (T)(0)) { index = 2; a = z; b = x; } else { index = 3; a = -z; b = -x; } } else if (ax >= ay && ax >= az) { if (x >= (T)(0)) { index = 4; a = y; b = z; } else { index = 5; a = -y; b = -z; } } } inline void CubeToSphere(const Real a, const Real b, const char index, Real & x, Real & y, Real & z) { switch( index ) { case 0: x = a; y = b; z = (Real) sqrt(max(0.0, 1.0 - x*x-y*y)); break; case 1: x = -a; y = -b; z = -(Real) sqrt(max(0.0, 1.0 - x*x-y*y)); break; case 2: z = a; x = b; y = (Real) sqrt(max(0.0, 1.0 - x*x-z*z)); break; case 3: z = -a; x = -b; y = -(Real) sqrt(max(0.0, 1.0 - x*x-z*z)); break; case 4: y = a; z = b; x = (Real) sqrt(max(0.0, 1.0 - y*y-z*z)); break; case 5: y = -a; z = -b; x = -(Real) sqrt(max(0.0, 1.0 - y*y-z*z)); break; } } inline unsigned long IntToUInt(long value) { return (value < 0)?(unsigned long) (-1 - (2 * value)):(unsigned long) (2 * value); } inline long UIntToInt(unsigned long uiValue) { return (uiValue & 1)?-((long) ((uiValue+1) >> 1)):((long) (uiValue >> 1)); } inline void ComputeVectorMinMax(const Real * const tab, unsigned long size, unsigned long dim, unsigned long stride, Real * minTab, Real * maxTab, O3DGCSC3DMCQuantizationMode quantMode) { if (size == 0 || dim == 0) { return; } unsigned long p = 0; for(unsigned long d = 0; d < dim; ++d) { maxTab[d] = minTab[d] = tab[p++]; } p = stride; for(unsigned long i = 1; i < size; ++i) { for(unsigned long d = 0; d < dim; ++d) { if (maxTab[d] < tab[p+d]) maxTab[d] = tab[p+d]; if (minTab[d] > tab[p+d]) minTab[d] = tab[p+d]; } p += stride; } if (quantMode == O3DGC_SC3DMC_DIAG_BB) { Real diag = Real( 0.0 ); Real r; for(unsigned long d = 0; d < dim; ++d) { r = (maxTab[d] - minTab[d]); diag += r*r; } diag = static_cast(sqrt(diag)); for(unsigned long d = 0; d < dim; ++d) { maxTab[d] = minTab[d] + diag; } } else if (quantMode == O3DGC_SC3DMC_MAX_ALL_DIMS) { Real maxr = (maxTab[0] - minTab[0]); Real r; for(unsigned long d = 1; d < dim; ++d) { r = (maxTab[d] - minTab[d]); if ( r > maxr) { maxr = r; } } for(unsigned long d = 0; d < dim; ++d) { maxTab[d] = minTab[d] + maxr; } } } } #endif // O3DGC_COMMON_H assimp-4.1.0/contrib/Open3DGC/o3dgcTools.cpp0000644002537200234200000000210713213503245020742 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ assimp-4.1.0/contrib/Open3DGC/o3dgcFIFO.h0000644002537200234200000000766513213503245020050 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_FIFO_H #define O3DGC_FIFO_H #include "o3dgcCommon.h" namespace o3dgc { //! template < typename T > class FIFO { public: //! Constructor. FIFO() { m_buffer = 0; m_allocated = 0; m_size = 0; m_start = 0; m_end = 0; }; //! Destructor. ~FIFO(void) { delete [] m_buffer; }; O3DGCErrorCode Allocate(unsigned long size) { assert(size > 0); if (size > m_allocated) { delete [] m_buffer; m_allocated = size; m_buffer = new T [m_allocated]; } Clear(); return O3DGC_OK; } const T & PopFirst() { assert(m_size > 0); --m_size; unsigned long current = m_start++; if (m_start == m_allocated) { m_end = 0; } return m_buffer[current]; }; void PushBack(const T & value) { assert( m_size < m_allocated); m_buffer[m_end] = value; ++m_size; ++m_end; if (m_end == m_allocated) { m_end = 0; } } unsigned long GetSize() const { return m_size;}; unsigned long GetAllocatedSize() const { return m_allocated;}; void Clear() { m_start = m_end = m_size = 0;}; private: T * m_buffer; unsigned long m_allocated; unsigned long m_size; unsigned long m_start; unsigned long m_end; }; } #endif // O3DGC_FIFO_H assimp-4.1.0/contrib/Open3DGC/o3dgcBinaryStream.h0000644002537200234200000005572713213503245021727 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_BINARY_STREAM_H #define O3DGC_BINARY_STREAM_H #include "o3dgcCommon.h" #include "o3dgcVector.h" namespace o3dgc { const unsigned long O3DGC_BINARY_STREAM_DEFAULT_SIZE = 4096; const unsigned long O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0 = 7; const unsigned long O3DGC_BINARY_STREAM_MAX_SYMBOL0 = (1 << O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0) - 1; const unsigned long O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1 = 6; const unsigned long O3DGC_BINARY_STREAM_MAX_SYMBOL1 = (1 << O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1) - 1; const unsigned long O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32 = (32+O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0-1) / O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0; //! class BinaryStream { public: //! Constructor. BinaryStream(unsigned long size = O3DGC_BINARY_STREAM_DEFAULT_SIZE) { m_endianness = SystemEndianness(); m_stream.Allocate(size); }; //! Destructor. ~BinaryStream(void){}; void WriteFloat32(float value, O3DGCStreamType streamType) { if (streamType == O3DGC_STREAM_TYPE_ASCII) { WriteFloat32ASCII(value); } else { WriteFloat32Bin(value); } } void WriteUInt32(unsigned long position, unsigned long value, O3DGCStreamType streamType) { if (streamType == O3DGC_STREAM_TYPE_ASCII) { WriteUInt32ASCII(position, value); } else { WriteUInt32Bin(position, value); } } void WriteUInt32(unsigned long value, O3DGCStreamType streamType) { if (streamType == O3DGC_STREAM_TYPE_ASCII) { WriteUInt32ASCII(value); } else { WriteUInt32Bin(value); } } void WriteUChar(unsigned int position, unsigned char value, O3DGCStreamType streamType) { if (streamType == O3DGC_STREAM_TYPE_ASCII) { WriteUInt32ASCII(position, value); } else { WriteUInt32Bin(position, value); } } void WriteUChar(unsigned char value, O3DGCStreamType streamType) { if (streamType == O3DGC_STREAM_TYPE_ASCII) { WriteUCharASCII(value); } else { WriteUChar8Bin(value); } } float ReadFloat32(unsigned long & position, O3DGCStreamType streamType) const { float value; if (streamType == O3DGC_STREAM_TYPE_ASCII) { value = ReadFloat32ASCII(position); } else { value = ReadFloat32Bin(position); } return value; } unsigned long ReadUInt32(unsigned long & position, O3DGCStreamType streamType) const { unsigned long value; if (streamType == O3DGC_STREAM_TYPE_ASCII) { value = ReadUInt32ASCII(position); } else { value = ReadUInt32Bin(position); } return value; } unsigned char ReadUChar(unsigned long & position, O3DGCStreamType streamType) const { unsigned char value; if (streamType == O3DGC_STREAM_TYPE_ASCII) { value = ReadUCharASCII(position); } else { value = ReadUChar8Bin(position); } return value; } void WriteFloat32Bin(unsigned long position, float value) { assert(position < m_stream.GetSize() - 4); unsigned char * ptr = (unsigned char *) (&value); if (m_endianness == O3DGC_BIG_ENDIAN) { m_stream[position++] = ptr[3]; m_stream[position++] = ptr[2]; m_stream[position++] = ptr[1]; m_stream[position ] = ptr[0]; } else { m_stream[position++] = ptr[0]; m_stream[position++] = ptr[1]; m_stream[position++] = ptr[2]; m_stream[position ] = ptr[3]; } } void WriteFloat32Bin(float value) { unsigned char * ptr = (unsigned char *) (&value); if (m_endianness == O3DGC_BIG_ENDIAN) { m_stream.PushBack(ptr[3]); m_stream.PushBack(ptr[2]); m_stream.PushBack(ptr[1]); m_stream.PushBack(ptr[0]); } else { m_stream.PushBack(ptr[0]); m_stream.PushBack(ptr[1]); m_stream.PushBack(ptr[2]); m_stream.PushBack(ptr[3]); } } void WriteUInt32Bin(unsigned long position, unsigned long value) { assert(position < m_stream.GetSize() - 4); unsigned char * ptr = (unsigned char *) (&value); if (m_endianness == O3DGC_BIG_ENDIAN) { m_stream[position++] = ptr[3]; m_stream[position++] = ptr[2]; m_stream[position++] = ptr[1]; m_stream[position ] = ptr[0]; } else { m_stream[position++] = ptr[0]; m_stream[position++] = ptr[1]; m_stream[position++] = ptr[2]; m_stream[position ] = ptr[3]; } } void WriteUInt32Bin(unsigned long value) { unsigned char * ptr = (unsigned char *) (&value); if (m_endianness == O3DGC_BIG_ENDIAN) { m_stream.PushBack(ptr[3]); m_stream.PushBack(ptr[2]); m_stream.PushBack(ptr[1]); m_stream.PushBack(ptr[0]); } else { m_stream.PushBack(ptr[0]); m_stream.PushBack(ptr[1]); m_stream.PushBack(ptr[2]); m_stream.PushBack(ptr[3]); } } void WriteUChar8Bin(unsigned int position, unsigned char value) { m_stream[position] = value; } void WriteUChar8Bin(unsigned char value) { m_stream.PushBack(value); } float ReadFloat32Bin(unsigned long & position) const { unsigned long value = ReadUInt32Bin(position); float fvalue; memcpy(&fvalue, &value, 4); return fvalue; } unsigned long ReadUInt32Bin(unsigned long & position) const { assert(position < m_stream.GetSize() - 4); unsigned long value = 0; if (m_endianness == O3DGC_BIG_ENDIAN) { value += (m_stream[position++]<<24); value += (m_stream[position++]<<16); value += (m_stream[position++]<<8); value += (m_stream[position++]); } else { value += (m_stream[position++]); value += (m_stream[position++]<<8); value += (m_stream[position++]<<16); value += (m_stream[position++]<<24); } return value; } unsigned char ReadUChar8Bin(unsigned long & position) const { return m_stream[position++]; } void WriteFloat32ASCII(float value) { unsigned long uiValue; memcpy(&uiValue, &value, 4); WriteUInt32ASCII(uiValue); } void WriteUInt32ASCII(unsigned long position, unsigned long value) { assert(position < m_stream.GetSize() - O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32); unsigned long value0 = value; for(unsigned long i = 0; i < O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32; ++i) { m_stream[position++] = (value0 & O3DGC_BINARY_STREAM_MAX_SYMBOL0); value0 >>= O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0; } } void WriteUInt32ASCII(unsigned long value) { for(unsigned long i = 0; i < O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32; ++i) { m_stream.PushBack(value & O3DGC_BINARY_STREAM_MAX_SYMBOL0); value >>= O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0; } } void WriteIntASCII(long value) { WriteUIntASCII(IntToUInt(value)); } void WriteUIntASCII(unsigned long value) { if (value >= O3DGC_BINARY_STREAM_MAX_SYMBOL0) { m_stream.PushBack(O3DGC_BINARY_STREAM_MAX_SYMBOL0); value -= O3DGC_BINARY_STREAM_MAX_SYMBOL0; unsigned char a, b; do { a = ((value & O3DGC_BINARY_STREAM_MAX_SYMBOL1) << 1); b = ( (value >>= O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1) > 0); a += b; m_stream.PushBack(a); } while (b); } else { m_stream.PushBack((unsigned char) value); } } void WriteUCharASCII(unsigned char value) { assert(value <= O3DGC_BINARY_STREAM_MAX_SYMBOL0); m_stream.PushBack(value); } float ReadFloat32ASCII(unsigned long & position) const { unsigned long value = ReadUInt32ASCII(position); float fvalue; memcpy(&fvalue, &value, 4); return fvalue; } unsigned long ReadUInt32ASCII(unsigned long & position) const { assert(position < m_stream.GetSize() - O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32); unsigned long value = 0; unsigned long shift = 0; for(unsigned long i = 0; i < O3DGC_BINARY_STREAM_NUM_SYMBOLS_UINT32; ++i) { value += (m_stream[position++] << shift); shift += O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0; } return value; } long ReadIntASCII(unsigned long & position) const { return UIntToInt(ReadUIntASCII(position)); } unsigned long ReadUIntASCII(unsigned long & position) const { unsigned long value = m_stream[position++]; if (value == O3DGC_BINARY_STREAM_MAX_SYMBOL0) { long x; unsigned long i = 0; do { x = m_stream[position++]; value += ( (x>>1) << i); i += O3DGC_BINARY_STREAM_BITS_PER_SYMBOL1; } while (x & 1); } return value; } unsigned char ReadUCharASCII(unsigned long & position) const { return m_stream[position++]; } O3DGCErrorCode Save(const char * const fileName) { FILE * fout = fopen(fileName, "wb"); if (!fout) { return O3DGC_ERROR_CREATE_FILE; } fwrite(m_stream.GetBuffer(), 1, m_stream.GetSize(), fout); fclose(fout); return O3DGC_OK; } O3DGCErrorCode Load(const char * const fileName) { FILE * fin = fopen(fileName, "rb"); if (!fin) { return O3DGC_ERROR_OPEN_FILE; } fseek(fin, 0, SEEK_END); unsigned long size = ftell(fin); m_stream.Allocate(size); rewind(fin); unsigned int nread = (unsigned int) fread((void *) m_stream.GetBuffer(), 1, size, fin); m_stream.SetSize(size); if (nread != size) { return O3DGC_ERROR_READ_FILE; } fclose(fin); return O3DGC_OK; } O3DGCErrorCode LoadFromBuffer(unsigned char * buffer, unsigned long bufferSize) { m_stream.Allocate(bufferSize); memcpy(m_stream.GetBuffer(), buffer, bufferSize); m_stream.SetSize(bufferSize); return O3DGC_OK; } unsigned long GetSize() const { return m_stream.GetSize(); } const unsigned char * GetBuffer(unsigned long position) const { return m_stream.GetBuffer() + position; } unsigned char * GetBuffer(unsigned long position) { return (m_stream.GetBuffer() + position); } unsigned char * GetBuffer() { return m_stream.GetBuffer(); } void GetBuffer(unsigned long position, unsigned char * & buffer) const { buffer = (unsigned char *) (m_stream.GetBuffer() + position); // fix me: ugly! } void SetSize(unsigned long size) { m_stream.SetSize(size); }; void Allocate(unsigned long size) { m_stream.Allocate(size); } private: Vector m_stream; O3DGCEndianness m_endianness; }; } #endif // O3DGC_BINARY_STREAM_H assimp-4.1.0/contrib/Open3DGC/o3dgcTriangleFans.h0000644002537200234200000003627513213503245021701 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_TRIANGLE_FANS_H #define O3DGC_TRIANGLE_FANS_H #include "o3dgcCommon.h" #include "o3dgcVector.h" #include "o3dgcBinaryStream.h" namespace o3dgc { const long O3DGC_TFANS_MIN_SIZE_ALLOCATED_VERTICES_BUFFER = 128; const long O3DGC_TFANS_MIN_SIZE_TFAN_SIZE_BUFFER = 8; class CompressedTriangleFans { public: //! Constructor. CompressedTriangleFans(void) { m_streamType = O3DGC_STREAM_TYPE_UNKOWN; m_bufferAC = 0; m_sizeBufferAC = 0; }; //! Destructor. ~CompressedTriangleFans(void) { delete [] m_bufferAC; }; O3DGCStreamType GetStreamType() const { return m_streamType; } void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; } O3DGCErrorCode Allocate(long numVertices, long numTriangles) { assert(numVertices > 0); m_numTFANs.Allocate(numVertices); m_degrees.Allocate(2*numVertices); m_configs.Allocate(2*numVertices); m_operations.Allocate(2*numVertices); m_indices.Allocate(2*numVertices); m_trianglesOrder.Allocate(numTriangles); Clear(); return O3DGC_OK; } O3DGCErrorCode PushNumTFans(long numTFans) { m_numTFANs.PushBack(numTFans); return O3DGC_OK; } long ReadNumTFans(unsigned long & iterator) const { assert(iterator < m_numTFANs.GetSize()); return m_numTFANs[iterator++]; } O3DGCErrorCode PushDegree(long degree) { m_degrees.PushBack(degree); return O3DGC_OK; } long ReadDegree(unsigned long & iterator) const { assert(iterator < m_degrees.GetSize()); return m_degrees[iterator++]; } O3DGCErrorCode PushConfig(long config) { m_configs.PushBack(config); return O3DGC_OK; } long ReadConfig(unsigned long & iterator) const { assert(iterator < m_configs.GetSize()); return m_configs[iterator++]; } O3DGCErrorCode PushOperation(long op) { m_operations.PushBack(op); return O3DGC_OK; } long ReadOperation(unsigned long & iterator) const { assert(iterator < m_operations.GetSize()); return m_operations[iterator++]; } O3DGCErrorCode PushIndex(long index) { m_indices.PushBack(index); return O3DGC_OK; } long ReadIndex(unsigned long & iterator) const { assert(iterator < m_indices.GetSize()); return m_indices[iterator++]; } O3DGCErrorCode PushTriangleIndex(long index) { m_trianglesOrder.PushBack(IntToUInt(index)); return O3DGC_OK; } long ReadTriangleIndex(unsigned long & iterator) const { assert(iterator < m_trianglesOrder.GetSize()); return UIntToInt(m_trianglesOrder[iterator++]); } O3DGCErrorCode Clear() { m_numTFANs.Clear(); m_degrees.Clear(); m_configs.Clear(); m_operations.Clear(); m_indices.Clear(); return O3DGC_OK; } O3DGCErrorCode Save(BinaryStream & bstream, bool encodeTrianglesOrder, O3DGCStreamType streamType); O3DGCErrorCode Load(const BinaryStream & bstream, unsigned long & iterator, bool decodeTrianglesOrder, O3DGCStreamType streamType); private: O3DGCErrorCode SaveBinAC(const Vector & data, BinaryStream & bstream); O3DGCErrorCode SaveUIntAC(const Vector & data, const unsigned long M, BinaryStream & bstream); O3DGCErrorCode SaveIntACEGC(const Vector & data, const unsigned long M, BinaryStream & bstream); Vector m_numTFANs; Vector m_degrees; Vector m_configs; Vector m_operations; Vector m_indices; Vector m_trianglesOrder; unsigned char * m_bufferAC; unsigned long m_sizeBufferAC; O3DGCStreamType m_streamType; }; //! class TriangleFans { public: //! Constructor. TriangleFans(long sizeTFAN = O3DGC_TFANS_MIN_SIZE_TFAN_SIZE_BUFFER, long verticesSize = O3DGC_TFANS_MIN_SIZE_ALLOCATED_VERTICES_BUFFER) { assert(sizeTFAN > 0); assert(verticesSize > 0); m_numTFANs = 0; m_numVertices = 0; m_verticesAllocatedSize = verticesSize; m_sizeTFANAllocatedSize = sizeTFAN; m_sizeTFAN = new long [m_sizeTFANAllocatedSize]; m_vertices = new long [m_verticesAllocatedSize]; }; //! Destructor. ~TriangleFans(void) { delete [] m_vertices; delete [] m_sizeTFAN; }; O3DGCErrorCode Allocate(long sizeTFAN, long verticesSize) { assert(sizeTFAN > 0); assert(verticesSize > 0); m_numTFANs = 0; m_numVertices = 0; if (m_verticesAllocatedSize < verticesSize) { delete [] m_vertices; m_verticesAllocatedSize = verticesSize; m_vertices = new long [m_verticesAllocatedSize]; } if (m_sizeTFANAllocatedSize < sizeTFAN) { delete [] m_sizeTFAN; m_sizeTFANAllocatedSize = sizeTFAN; m_sizeTFAN = new long [m_sizeTFANAllocatedSize]; } return O3DGC_OK; }; O3DGCErrorCode Clear() { m_numTFANs = 0; m_numVertices = 0; return O3DGC_OK; } O3DGCErrorCode AddVertex(long vertex) { assert(m_numTFANs >= 0); assert(m_numTFANs < m_sizeTFANAllocatedSize); assert(m_numVertices >= 0); ++m_numVertices; if (m_numVertices == m_verticesAllocatedSize) { m_verticesAllocatedSize *= 2; long * tmp = m_vertices; m_vertices = new long [m_verticesAllocatedSize]; memcpy(m_vertices, tmp, sizeof(long) * m_numVertices); delete [] tmp; } m_vertices[m_numVertices-1] = vertex; ++m_sizeTFAN[m_numTFANs-1]; return O3DGC_OK; } O3DGCErrorCode AddTFAN() { assert(m_numTFANs >= 0); ++m_numTFANs; if (m_numTFANs == m_sizeTFANAllocatedSize) { m_sizeTFANAllocatedSize *= 2; long * tmp = m_sizeTFAN; m_sizeTFAN = new long [m_sizeTFANAllocatedSize]; memcpy(m_sizeTFAN, tmp, sizeof(long) * m_numTFANs); delete [] tmp; } m_sizeTFAN[m_numTFANs-1] = (m_numTFANs > 1) ? m_sizeTFAN[m_numTFANs-2] : 0; return O3DGC_OK; } long Begin(long tfan) const { assert(tfan < m_numTFANs); assert(tfan >= 0); return (tfan>0)?m_sizeTFAN[tfan-1]:0; } long End(long tfan) const { assert(tfan < m_numTFANs); assert(tfan >= 0); return m_sizeTFAN[tfan]; } long GetVertex(long vertex) const { assert(vertex < m_numVertices); assert(vertex >= 0); return m_vertices[vertex]; } long GetTFANSize(long tfan) const { return End(tfan) - Begin(tfan); } long GetNumTFANs() const { return m_numTFANs; } long GetNumVertices() const { return m_numVertices; } private: long m_verticesAllocatedSize; long m_sizeTFANAllocatedSize; long m_numTFANs; long m_numVertices; long * m_vertices; long * m_sizeTFAN; }; } #endif // O3DGC_TRIANGLE_FANS_H assimp-4.1.0/contrib/Open3DGC/o3dgcTriangleListDecoder.inl0000644002537200234200000003647013213503245023543 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_TRIANGLE_LIST_DECODER_INL #define O3DGC_TRIANGLE_LIST_DECODER_INL namespace o3dgc { template O3DGCErrorCode TriangleListDecoder::Init(T * const triangles, const long numTriangles, const long numVertices, const long maxSizeV2T) { assert(numVertices > 0); assert(numTriangles > 0); m_numTriangles = numTriangles; m_numVertices = numVertices; m_triangles = triangles; m_vertexCount = 0; m_triangleCount = 0; m_itNumTFans = 0; m_itDegree = 0; m_itConfig = 0; m_itOperation = 0; m_itIndex = 0; if (m_numVertices > m_maxNumVertices) { m_maxNumVertices = m_numVertices; delete [] m_visitedVerticesValence; delete [] m_visitedVertices; m_visitedVerticesValence = new long [m_numVertices]; m_visitedVertices = new long [m_numVertices]; } if (m_decodeTrianglesOrder && m_tempTrianglesSize < m_numTriangles) { delete [] m_tempTriangles; m_tempTrianglesSize = m_numTriangles; m_tempTriangles = new T [3*m_tempTrianglesSize]; } m_ctfans.SetStreamType(m_streamType); m_ctfans.Allocate(m_numVertices, m_numTriangles); m_tfans.Allocate(2 * m_numVertices, 8 * m_numVertices); // compute vertex-to-triangle adjacency information m_vertexToTriangle.AllocateNumNeighborsArray(numVertices); long * numNeighbors = m_vertexToTriangle.GetNumNeighborsBuffer(); for(long i = 0; i < numVertices; ++i) { numNeighbors[i] = maxSizeV2T; } m_vertexToTriangle.AllocateNeighborsArray(); m_vertexToTriangle.ClearNeighborsArray(); return O3DGC_OK; } template O3DGCErrorCode TriangleListDecoder::Decompress() { for(long focusVertex = 0; focusVertex < m_numVertices; ++focusVertex) { if (focusVertex == m_vertexCount) { m_vertexCount++; // insert focusVertex } CompueLocalConnectivityInfo(focusVertex); DecompressTFAN(focusVertex); } return O3DGC_OK; } template O3DGCErrorCode TriangleListDecoder::Reorder() { if (m_decodeTrianglesOrder) { unsigned long itTriangleIndex = 0; long prevTriangleIndex = 0; long t; memcpy(m_tempTriangles, m_triangles, m_numTriangles * 3 * sizeof(T)); for(long i = 0; i < m_numTriangles; ++i) { t = m_ctfans.ReadTriangleIndex(itTriangleIndex) + prevTriangleIndex; assert( t >= 0 && t < m_numTriangles); memcpy(m_triangles + 3 * t, m_tempTriangles + 3 * i, sizeof(T) * 3); prevTriangleIndex = t + 1; } } return O3DGC_OK; } template O3DGCErrorCode TriangleListDecoder::CompueLocalConnectivityInfo(const long focusVertex) { long t = 0; long p, v; m_numConqueredTriangles = 0; m_numVisitedVertices = 0; for(long i = m_vertexToTriangle.Begin(focusVertex); (t >= 0) && (i < m_vertexToTriangle.End(focusVertex)); ++i) { t = m_vertexToTriangle.GetNeighbor(i); if ( t >= 0) { ++m_numConqueredTriangles; p = 3*t; // extract visited vertices for(long k = 0; k < 3; ++k) { v = m_triangles[p+k]; if (v > focusVertex) // vertices are insertices by increasing traversal order { bool foundOrInserted = false; for (long j = 0; j < m_numVisitedVertices; ++j) { if (v == m_visitedVertices[j]) { m_visitedVerticesValence[j]++; foundOrInserted = true; break; } else if (v < m_visitedVertices[j]) { ++m_numVisitedVertices; for (long h = m_numVisitedVertices-1; h > j; --h) { m_visitedVertices[h] = m_visitedVertices[h-1]; m_visitedVerticesValence[h] = m_visitedVerticesValence[h-1]; } m_visitedVertices[j] = v; m_visitedVerticesValence[j] = 1; foundOrInserted = true; break; } } if (!foundOrInserted) { m_visitedVertices[m_numVisitedVertices] = v; m_visitedVerticesValence[m_numVisitedVertices] = 1; m_numVisitedVertices++; } } } } } // re-order visited vertices by taking into account their valence (i.e., # of conquered triangles incident to each vertex) // in order to avoid config. 9 if (m_numVisitedVertices > 2) { long y; for(long x = 1; x < m_numVisitedVertices; ++x) { if (m_visitedVerticesValence[x] == 1) { y = x; while( (y > 0) && (m_visitedVerticesValence[y] < m_visitedVerticesValence[y-1]) ) { swap(m_visitedVerticesValence[y], m_visitedVerticesValence[y-1]); swap(m_visitedVertices[y], m_visitedVertices[y-1]); --y; } } } } return O3DGC_OK; } template O3DGCErrorCode TriangleListDecoder::DecompressTFAN(const long focusVertex) { long ntfans; long degree, config; long op; long index; long k0, k1; long b, c, t; ntfans = m_ctfans.ReadNumTFans(m_itNumTFans); if (ntfans > 0) { for(long f = 0; f != ntfans; f++) { m_tfans.AddTFAN(); degree = m_ctfans.ReadDegree(m_itDegree) +2 - m_numConqueredTriangles; config = m_ctfans.ReadConfig(m_itConfig); k0 = m_tfans.GetNumVertices(); m_tfans.AddVertex(focusVertex); switch(config) { case 0:// ops: 1000001 vertices: -1 -2 m_tfans.AddVertex(m_visitedVertices[0]); for(long u = 1; u < degree-1; u++) { m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; m_tfans.AddVertex(m_vertexCount++); } m_tfans.AddVertex(m_visitedVertices[1]); break; case 1: // ops: 1xxxxxx1 vertices: -1 x x x x x -2 m_tfans.AddVertex(m_visitedVertices[0]); for(long u = 1; u < degree-1; u++) { op = m_ctfans.ReadOperation(m_itOperation); if (op == 1) { index = m_ctfans.ReadIndex(m_itIndex); if ( index < 0) { m_tfans.AddVertex(m_visitedVertices[-index-1]); } else { m_tfans.AddVertex(index + focusVertex); } } else { m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; m_tfans.AddVertex(m_vertexCount++); } } m_tfans.AddVertex(m_visitedVertices[1]); break; case 2: // ops: 00000001 vertices: -1 for(long u = 0; u < degree-1; u++) { m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; m_tfans.AddVertex(m_vertexCount++); } m_tfans.AddVertex(m_visitedVertices[0]); break; case 3: // ops: 00000001 vertices: -2 for(long u=0; u < degree-1; u++) { m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; m_tfans.AddVertex(m_vertexCount++); } m_tfans.AddVertex(m_visitedVertices[1]); break; case 4: // ops: 10000000 vertices: -1 m_tfans.AddVertex(m_visitedVertices[0]); for(long u = 1; u < degree; u++) { m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; m_tfans.AddVertex(m_vertexCount++); } break; case 5: // ops: 10000000 vertices: -2 m_tfans.AddVertex(m_visitedVertices[1]); for(long u = 1; u < degree; u++) { m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; m_tfans.AddVertex(m_vertexCount++); } break; case 6:// ops: 00000000 vertices: for(long u = 0; u < degree; u++) { m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; m_tfans.AddVertex(m_vertexCount++); } break; case 7: // ops: 1000001 vertices: -2 -1 m_tfans.AddVertex(m_visitedVertices[1]); for(long u = 1; u < degree-1; u++) { m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; m_tfans.AddVertex(m_vertexCount++); } m_tfans.AddVertex(m_visitedVertices[0]); break; case 8: // ops: 1xxxxxx1 vertices: -2 x x x x x -1 m_tfans.AddVertex(m_visitedVertices[1]); for(long u = 1; u < degree-1; u++) { op = m_ctfans.ReadOperation(m_itOperation); if (op == 1) { index = m_ctfans.ReadIndex(m_itIndex); if ( index < 0) { m_tfans.AddVertex(m_visitedVertices[-index-1]); } else { m_tfans.AddVertex(index + focusVertex); } } else { m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; m_tfans.AddVertex(m_vertexCount++); } } m_tfans.AddVertex(m_visitedVertices[0]); break; case 9: // general case for(long u = 0; u < degree; u++) { op = m_ctfans.ReadOperation(m_itOperation); if (op == 1) { index = m_ctfans.ReadIndex(m_itIndex); if ( index < 0) { m_tfans.AddVertex(m_visitedVertices[-index-1]); } else { m_tfans.AddVertex(index + focusVertex); } } else { m_visitedVertices[m_numVisitedVertices++] = m_vertexCount; m_tfans.AddVertex(m_vertexCount++); } } break; } //logger.write_2_log("\t degree=%i \t cas = %i\n", degree, cas); k1 = m_tfans.GetNumVertices(); b = m_tfans.GetVertex(k0+1); for (long k = k0+2; k < k1; k++) { c = m_tfans.GetVertex(k); t = m_triangleCount*3; m_triangles[t++] = (T) focusVertex; m_triangles[t++] = (T) b; m_triangles[t ] = (T) c; m_vertexToTriangle.AddNeighbor(focusVertex, m_triangleCount); m_vertexToTriangle.AddNeighbor(b , m_triangleCount); m_vertexToTriangle.AddNeighbor(c , m_triangleCount); b=c; m_triangleCount++; } } } return O3DGC_OK; } } #endif //O3DGC_TRIANGLE_LIST_DECODER_INL assimp-4.1.0/contrib/Open3DGC/o3dgcSC3DMCDecoder.h0000644002537200234200000001322413213503245021513 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_SC3DMC_DECODER_H #define O3DGC_SC3DMC_DECODER_H #include "o3dgcCommon.h" #include "o3dgcBinaryStream.h" #include "o3dgcIndexedFaceSet.h" #include "o3dgcSC3DMCEncodeParams.h" #include "o3dgcTriangleListDecoder.h" namespace o3dgc { //! template class SC3DMCDecoder { public: //! Constructor. SC3DMCDecoder(void) { m_iterator = 0; m_streamSize = 0; m_quantFloatArray = 0; m_quantFloatArraySize = 0; m_normals = 0; m_normalsSize = 0; m_streamType = O3DGC_STREAM_TYPE_UNKOWN; }; //! Destructor. ~SC3DMCDecoder(void) { delete [] m_normals; delete [] m_quantFloatArray; } //! O3DGCErrorCode DecodeHeader(IndexedFaceSet & ifs, const BinaryStream & bstream); //! O3DGCErrorCode DecodePayload(IndexedFaceSet & ifs, const BinaryStream & bstream); const SC3DMCStats & GetStats() const { return m_stats;} unsigned long GetIterator() const { return m_iterator;} O3DGCErrorCode SetIterator(unsigned long iterator) { m_iterator = iterator; return O3DGC_OK; } private: O3DGCErrorCode DecodeFloatArray(Real * const floatArray, unsigned long numfloatArraySize, unsigned long dimfloatArraySize, unsigned long stride, const Real * const minfloatArray, const Real * const maxfloatArray, unsigned long nQBits, const IndexedFaceSet & ifs, O3DGCSC3DMCPredictionMode & predMode, const BinaryStream & bstream); O3DGCErrorCode IQuantizeFloatArray(Real * const floatArray, unsigned long numfloatArraySize, unsigned long dimfloatArraySize, unsigned long stride, const Real * const minfloatArray, const Real * const maxfloatArray, unsigned long nQBits); O3DGCErrorCode DecodeIntArray(long * const intArray, unsigned long numIntArraySize, unsigned long dimIntArraySize, unsigned long stride, const IndexedFaceSet & ifs, O3DGCSC3DMCPredictionMode & predMode, const BinaryStream & bstream); O3DGCErrorCode ProcessNormals(const IndexedFaceSet & ifs); unsigned long m_iterator; unsigned long m_streamSize; SC3DMCEncodeParams m_params; TriangleListDecoder m_triangleListDecoder; long * m_quantFloatArray; unsigned long m_quantFloatArraySize; Vector m_orientation; Real * m_normals; unsigned long m_normalsSize; SC3DMCStats m_stats; O3DGCStreamType m_streamType; }; } #include "o3dgcSC3DMCDecoder.inl" // template implementation #endif // O3DGC_SC3DMC_DECODER_H assimp-4.1.0/contrib/Open3DGC/o3dgcIndexedFaceSet.inl0000644002537200234200000000415013213503245022455 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_INDEXED_FACE_SET_INL #define O3DGC_INDEXED_FACE_SET_INL #include namespace o3dgc { template void IndexedFaceSet::ComputeMinMax(O3DGCSC3DMCQuantizationMode quantMode) { ComputeVectorMinMax(m_coord , m_nCoord , 3, 3, m_coordMin , m_coordMax , quantMode); ComputeVectorMinMax(m_normal , m_nNormal , 3, 3, m_normalMin , m_normalMax , quantMode); unsigned long numFloatAttributes = GetNumFloatAttributes(); for(unsigned long a = 0; a < numFloatAttributes; ++a) { ComputeVectorMinMax(m_floatAttribute[a], m_nFloatAttribute[a], m_dimFloatAttribute[a], m_dimFloatAttribute[a], // stride m_minFloatAttribute + (a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES), m_maxFloatAttribute + (a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES), quantMode); } } } #endif // O3DGC_INDEXED_FACE_SET_INL assimp-4.1.0/contrib/Open3DGC/o3dgcDynamicVectorDecoder.cpp0000644002537200234200000002317613213503245023710 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "o3dgcDynamicVectorDecoder.h" #include "o3dgcArithmeticCodec.h" //#define DEBUG_VERBOSE namespace o3dgc { #ifdef DEBUG_VERBOSE FILE * g_fileDebugDVCDec = NULL; #endif //DEBUG_VERBOSE O3DGCErrorCode IUpdate(long * const data, const long size) { assert(size > 1); const long size1 = size - 1; long p = 2; data[0] -= data[1] >> 1; while(p < size1) { data[p] -= (data[p-1] + data[p+1] + 2) >> 2; p += 2; } if ( p == size1) { data[p] -= data[p-1]>>1; } return O3DGC_OK; } O3DGCErrorCode IPredict(long * const data, const long size) { assert(size > 1); const long size1 = size - 1; long p = 1; while(p < size1) { data[p] += (data[p-1] + data[p+1] + 1) >> 1; p += 2; } if ( p == size1) { data[p] += data[p-1]; } return O3DGC_OK; } O3DGCErrorCode Merge(long * const data, const long size) { assert(size > 1); const long h = (size >> 1) + (size & 1); long a = h-1; long b = h; while (a > 0) { for (long i = a; i < b; i += 2) { swap(data[i], data[i+1]); } --a; ++b; } return O3DGC_OK; } inline O3DGCErrorCode ITransform(long * const data, const unsigned long size) { unsigned long n = size; unsigned long even = 0; unsigned long k = 0; even += ((n&1) << k++); while(n > 1) { n = (n >> 1) + (n & 1); even += ((n&1) << k++); } for(long i = k-2; i >= 0; --i) { n = (n << 1) - ((even>>i) & 1); Merge (data, n); IUpdate (data, n); IPredict(data, n); } return O3DGC_OK; } DynamicVectorDecoder::DynamicVectorDecoder(void) { m_streamSize = 0; m_maxNumVectors = 0; m_numVectors = 0; m_dimVectors = 0; m_quantVectors = 0; m_iterator = 0; m_streamType = O3DGC_STREAM_TYPE_UNKOWN; } DynamicVectorDecoder::~DynamicVectorDecoder() { delete [] m_quantVectors; } O3DGCErrorCode DynamicVectorDecoder::DecodeHeader(DynamicVector & dynamicVector, const BinaryStream & bstream) { unsigned long iterator0 = m_iterator; unsigned long start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_BINARY); if (start_code != O3DGC_DV_START_CODE) { m_iterator = iterator0; start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_ASCII); if (start_code != O3DGC_DV_START_CODE) { return O3DGC_ERROR_CORRUPTED_STREAM; } else { m_streamType = O3DGC_STREAM_TYPE_ASCII; } } else { m_streamType = O3DGC_STREAM_TYPE_BINARY; } m_streamSize = bstream.ReadUInt32(m_iterator, m_streamType); m_params.SetEncodeMode( (O3DGCDVEncodingMode) bstream.ReadUChar(m_iterator, m_streamType)); dynamicVector.SetNVector ( bstream.ReadUInt32(m_iterator, m_streamType) ); if (dynamicVector.GetNVector() > 0) { dynamicVector.SetDimVector( bstream.ReadUInt32(m_iterator, m_streamType) ); m_params.SetQuantBits(bstream.ReadUChar(m_iterator, m_streamType)); } return O3DGC_OK; } O3DGCErrorCode DynamicVectorDecoder::DecodePlayload(DynamicVector & dynamicVector, const BinaryStream & bstream) { O3DGCErrorCode ret = O3DGC_OK; #ifdef DEBUG_VERBOSE g_fileDebugDVCDec = fopen("dv_dec.txt", "w"); #endif //DEBUG_VERBOSE unsigned long start = m_iterator; unsigned long streamSize = bstream.ReadUInt32(m_iterator, m_streamType); // bitsream size const unsigned long dim = dynamicVector.GetDimVector(); const unsigned long num = dynamicVector.GetNVector(); const unsigned long size = dim * num; for(unsigned long j=0 ; j < dynamicVector.GetDimVector() ; ++j) { dynamicVector.SetMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); dynamicVector.SetMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); } Arithmetic_Codec acd; Static_Bit_Model bModel0; Adaptive_Bit_Model bModel1; unsigned char * buffer = 0; streamSize -= (m_iterator - start); unsigned int exp_k = 0; unsigned int M = 0; if (m_streamType == O3DGC_STREAM_TYPE_BINARY) { bstream.GetBuffer(m_iterator, buffer); m_iterator += streamSize; acd.set_buffer(streamSize, buffer); acd.start_decoder(); exp_k = acd.ExpGolombDecode(0, bModel0, bModel1); M = acd.ExpGolombDecode(0, bModel0, bModel1); } Adaptive_Data_Model mModelValues(M+2); if (m_maxNumVectors < size) { delete [] m_quantVectors; m_maxNumVectors = size; m_quantVectors = new long [size]; } if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { for(unsigned long v = 0; v < num; ++v) { for(unsigned long d = 0; d < dim; ++d) { m_quantVectors[d * num + v] = bstream.ReadIntASCII(m_iterator); } } } else { for(unsigned long v = 0; v < num; ++v) { for(unsigned long d = 0; d < dim; ++d) { m_quantVectors[d * num + v] = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); } } } #ifdef DEBUG_VERBOSE printf("IntArray (%i, %i)\n", num, dim); fprintf(g_fileDebugDVCDec, "IntArray (%i, %i)\n", num, dim); for(unsigned long v = 0; v < num; ++v) { for(unsigned long d = 0; d < dim; ++d) { printf("%i\t %i \t %i\n", d * num + v, m_quantVectors[d * num + v], IntToUInt(m_quantVectors[d * num + v])); fprintf(g_fileDebugDVCDec, "%i\t %i \t %i\n", d * num + v, m_quantVectors[d * num + v], IntToUInt(m_quantVectors[d * num + v])); } } fflush(g_fileDebugDVCDec); #endif //DEBUG_VERBOSE for(unsigned long d = 0; d < dim; ++d) { ITransform(m_quantVectors + d * num, num); } IQuantize(dynamicVector.GetVectors(), num, dim, dynamicVector.GetStride(), dynamicVector.GetMin(), dynamicVector.GetMax(), m_params.GetQuantBits()); #ifdef DEBUG_VERBOSE fclose(g_fileDebugDVCDec); #endif //DEBUG_VERBOSE return ret; } O3DGCErrorCode DynamicVectorDecoder::IQuantize(Real * const floatArray, unsigned long numFloatArray, unsigned long dimFloatArray, unsigned long stride, const Real * const minFloatArray, const Real * const maxFloatArray, unsigned long nQBits) { const unsigned long size = numFloatArray * dimFloatArray; Real r; if (m_maxNumVectors < size) { delete [] m_quantVectors; m_maxNumVectors = size; m_quantVectors = new long [m_maxNumVectors]; } Real idelta; for(unsigned long d = 0; d < dimFloatArray; ++d) { r = maxFloatArray[d] - minFloatArray[d]; if (r > 0.0f) { idelta = (float)(r) / ((1 << nQBits) - 1); } else { idelta = 1.0f; } for(unsigned long v = 0; v < numFloatArray; ++v) { floatArray[v * stride + d] = m_quantVectors[v + d * numFloatArray] * idelta + minFloatArray[d]; } } return O3DGC_OK; } } assimp-4.1.0/contrib/Open3DGC/o3dgcIndexedFaceSet.h0000644002537200234200000004407213213503245022131 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_INDEXED_FACE_SET_H #define O3DGC_INDEXED_FACE_SET_H #include "o3dgcCommon.h" namespace o3dgc { template class IndexedFaceSet { public: //! Constructor. IndexedFaceSet(void) { memset(this, 0, sizeof(IndexedFaceSet)); m_ccw = true; m_solid = true; m_convex = true; m_isTriangularMesh = true; m_creaseAngle = 30; }; //! Destructor. ~IndexedFaceSet(void) {}; unsigned long GetNCoordIndex() const { return m_nCoordIndex ;} // only coordIndex is supported unsigned long GetNCoord() const { return m_nCoord ;} unsigned long GetNNormal() const { return m_nNormal ;} unsigned long GetNFloatAttribute(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return m_nFloatAttribute[a]; } unsigned long GetNIntAttribute(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); return m_nIntAttribute[a]; } unsigned long GetNumFloatAttributes() const { return m_numFloatAttributes;} unsigned long GetNumIntAttributes() const { return m_numIntAttributes ;} const Real * GetCoordMin () const { return m_coordMin;} const Real * GetCoordMax () const { return m_coordMax;} const Real * GetNormalMin () const { return m_normalMin;} const Real * GetNormalMax () const { return m_normalMax;} Real GetCoordMin (int j) const { return m_coordMin[j] ;} Real GetCoordMax (int j) const { return m_coordMax[j] ;} Real GetNormalMin (int j) const { return m_normalMin[j] ;} Real GetNormalMax (int j) const { return m_normalMax[j] ;} O3DGCIFSFloatAttributeType GetFloatAttributeType(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return m_typeFloatAttribute[a]; } O3DGCIFSIntAttributeType GetIntAttributeType(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); return m_typeIntAttribute[a]; } unsigned long GetFloatAttributeDim(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return m_dimFloatAttribute[a]; } unsigned long GetIntAttributeDim(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); return m_dimIntAttribute[a]; } const Real * GetFloatAttributeMin(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return &(m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]); } const Real * GetFloatAttributeMax(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return &(m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]); } Real GetFloatAttributeMin(unsigned long a, unsigned long dim) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); return m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim]; } Real GetFloatAttributeMax(unsigned long a, unsigned long dim) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); return m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim]; } Real GetCreaseAngle() const { return m_creaseAngle ;} bool GetCCW() const { return m_ccw ;} bool GetSolid() const { return m_solid ;} bool GetConvex() const { return m_convex ;} bool GetIsTriangularMesh() const { return m_isTriangularMesh;} const unsigned long * GetIndexBufferID() const { return m_indexBufferID ;} const T * GetCoordIndex() const { return m_coordIndex;} T * GetCoordIndex() { return m_coordIndex;} Real * GetCoord() const { return m_coord ;} Real * GetNormal() const { return m_normal ;} Real * GetFloatAttribute(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return m_floatAttribute[a]; } long * GetIntAttribute(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); return m_intAttribute[a] ; } // only coordIndex is supported void SetNNormalIndex(unsigned long) {} void SetNTexCoordIndex(unsigned long) {} void SetNFloatAttributeIndex(int, unsigned long) {} void SetNIntAttributeIndex (int, unsigned long) {} // per triangle attributes not supported void SetNormalPerVertex(bool) {} void SetColorPerVertex(bool) {} void SetFloatAttributePerVertex(int, bool){} void SetIntAttributePerVertex (int, bool){} void SetNCoordIndex (unsigned long nCoordIndex) { m_nCoordIndex = nCoordIndex;} void SetNCoord (unsigned long nCoord) { m_nCoord = nCoord ;} void SetNNormal (unsigned long nNormal) { m_nNormal = nNormal ;} void SetNumFloatAttributes(unsigned long numFloatAttributes) { assert(numFloatAttributes < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); m_numFloatAttributes = numFloatAttributes; } void SetNumIntAttributes (unsigned long numIntAttributes) { assert(numIntAttributes < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); m_numIntAttributes = numIntAttributes; } void SetCreaseAngle (Real creaseAngle) { m_creaseAngle = creaseAngle ;} void SetCCW (bool ccw) { m_ccw = ccw ;} void SetSolid (bool solid) { m_solid = solid ;} void SetConvex (bool convex) { m_convex = convex ;} void SetIsTriangularMesh (bool isTriangularMesh) { m_isTriangularMesh = isTriangularMesh;} void SetCoordMin (int j, Real min) { m_coordMin[j] = min;} void SetCoordMax (int j, Real max) { m_coordMax[j] = max;} void SetNormalMin (int j, Real min) { m_normalMin[j] = min;} void SetNormalMax (int j, Real max) { m_normalMax[j] = max;} void SetNFloatAttribute(unsigned long a, unsigned long nFloatAttribute) { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); m_nFloatAttribute[a] = nFloatAttribute; } void SetNIntAttribute(unsigned long a, unsigned long nIntAttribute) { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); m_nIntAttribute[a] = nIntAttribute; } void SetFloatAttributeDim(unsigned long a, unsigned long d) { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); m_dimFloatAttribute[a] = d; } void SetIntAttributeDim(unsigned long a, unsigned long d) { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); m_dimIntAttribute[a] = d; } void SetFloatAttributeType(unsigned long a, O3DGCIFSFloatAttributeType t) { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); m_typeFloatAttribute[a] = t; } void SetIntAttributeType(unsigned long a, O3DGCIFSIntAttributeType t) { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); m_typeIntAttribute[a] = t; } void SetFloatAttributeMin(unsigned long a, unsigned long dim, Real min) { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); m_minFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim] = min; } void SetFloatAttributeMax(unsigned long a, unsigned long dim, Real max) { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); assert(dim < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); m_maxFloatAttribute[a * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES + dim] = max; } void SetIndexBufferID (unsigned long * const indexBufferID) { m_indexBufferID = indexBufferID;} void SetCoordIndex (T * const coordIndex) { m_coordIndex = coordIndex;} void SetCoord (Real * const coord ) { m_coord = coord ;} void SetNormal (Real * const normal ) { m_normal = normal ;} void SetFloatAttribute (unsigned long a, Real * const floatAttribute) { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); m_floatAttribute[a] = floatAttribute; } void SetIntAttribute (unsigned long a, long * const intAttribute) { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); m_intAttribute[a] = intAttribute ; } void ComputeMinMax(O3DGCSC3DMCQuantizationMode quantMode); private: // triangles list unsigned long m_nCoordIndex; T * m_coordIndex; unsigned long * m_indexBufferID; // coord, normals, texcoord and color unsigned long m_nCoord; unsigned long m_nNormal; Real m_coordMin [3]; Real m_coordMax [3]; Real m_normalMin [3]; Real m_normalMax [3]; Real * m_coord; Real * m_normal; // other attributes unsigned long m_numFloatAttributes; unsigned long m_numIntAttributes; O3DGCIFSFloatAttributeType m_typeFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; O3DGCIFSIntAttributeType m_typeIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ]; unsigned long m_nFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; unsigned long m_nIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ]; unsigned long m_dimFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; unsigned long m_dimIntAttribute [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES ]; Real m_minFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]; Real m_maxFloatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES * O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]; Real * m_floatAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; long * m_intAttribute [O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; // mesh info Real m_creaseAngle; bool m_ccw; bool m_solid; bool m_convex; bool m_isTriangularMesh; }; } #include "o3dgcIndexedFaceSet.inl" // template implementation #endif // O3DGC_INDEXED_FACE_SET_H assimp-4.1.0/contrib/Open3DGC/o3dgcTriangleListEncoder.inl0000644002537200234200000006630013213503245023550 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_TRIANGLE_LIST_ENCODER_INL #define O3DGC_TRIANGLE_LIST_ENCODER_INL namespace o3dgc { // extract opposite edge template inline void CompueOppositeEdge(const long focusVertex, const T * triangle, long & a, long & b) { if ((long) triangle[0] == focusVertex) { a = triangle[1]; b = triangle[2]; } else if ((long) triangle[1] == focusVertex) { a = triangle[2]; b = triangle[0]; } else { a = triangle[0]; b = triangle[1]; } } inline bool IsCase0(long degree, long numIndices, const long * const ops, const long * const indices) { // ops: 1000001 vertices: -1 -2 if ((numIndices != 2) || (degree < 2)) { return false; } if ((indices[0] != -1) ||(indices[1] != -2) || (ops[0] != 1) ||(ops[degree-1] != 1) ) return false; for (long u = 1; u < degree-1; u++) { if (ops[u] != 0) return false; } return true; } inline bool IsCase1(long degree, long numIndices, const long * const ops, const long * const indices) { // ops: 1xxxxxx1 indices: -1 x x x x x -2 if ((degree < 2) || (numIndices < 1)) { return false; } if ((indices[0] != -1) ||(indices[numIndices-1] != -2) || (ops[0] != 1) ||(ops[degree-1] != 1) ) return false; return true; } inline bool IsCase2(long degree, long numIndices, const long * const ops, const long * const indices) { // ops: 00000001 indices: -1 if ((degree < 2) || (numIndices!= 1)) { return false; } if ((indices[0] != -1) || (ops[degree-1] != 1) ) return false; for (long u = 0; u < degree-1; u++) { if (ops[u] != 0) return false; } return true; } inline bool IsCase3(long degree, long numIndices, const long * const ops, const long * const indices) { // ops: 00000001 indices: -2 if ((degree < 2) || (numIndices!= 1)) { return false; } if ((indices[0] != -2) || (ops[degree-1] != 1) ) return false; for (long u = 0; u < degree-1; u++) { if (ops[u] != 0) return false; } return true; } inline bool IsCase4(long degree, long numIndices, const long * const ops, const long * const indices) { // ops: 10000000 indices: -1 if ((degree < 2) || (numIndices!= 1)) { return false; } if ((indices[0] != -1) || (ops[0] != 1) ) return false; for (long u = 1; u < degree; u++) { if (ops[u] != 0) return false; } return true; } inline bool IsCase5(long degree, long numIndices, const long * const ops, const long * const indices) { // ops: 10000000 indices: -2 if ((degree < 2) || (numIndices!= 1)) { return false; } if ((indices[0] != -2) || (ops[0] != 1) ) return false; for (long u = 1; u < degree; u++) { if (ops[u] != 0) return false; } return true; } inline bool IsCase6(long degree, long numIndices, const long * const ops, const long * const /*indices*/) { // ops: 0000000 indices: if (numIndices!= 0) { return false; } for (long u = 0; u < degree; u++) { if (ops[u] != 0) return false; } return true; } inline bool IsCase7(long degree, long numIndices, const long * const ops, const long * const indices) { // ops: 1000001 indices: -2 -1 if ((numIndices!= 2) || (degree < 2)) { return false; } if ((indices[0] != -2) ||(indices[1] != -1) || (ops[0] != 1) ||(ops[degree-1] != 1) ) return false; for (long u = 1; u < degree-1; u++) { if (ops[u] != 0) return false; } return true; } inline bool IsCase8(long degree, long numIndices, const long * const ops, const long * const indices) { // ops: 1xxxxxx1 indices: -1 x x x x x -2 if ((degree < 2) || (numIndices < 1)) { return false; } if ((indices[0] != -2) ||(indices[numIndices-1] != -1) || (ops[0] != 1) ||(ops[degree-1] != 1) ) return false; return true; } template TriangleListEncoder::TriangleListEncoder(void) { m_vtags = 0; m_ttags = 0; m_tmap = 0; m_vmap = 0; m_count = 0; m_invVMap = 0; m_invTMap = 0; m_nonConqueredTriangles = 0; m_nonConqueredEdges = 0; m_visitedVertices = 0; m_visitedVerticesValence = 0; m_vertexCount = 0; m_triangleCount = 0; m_maxNumVertices = 0; m_maxNumTriangles = 0; m_numTriangles = 0; m_numVertices = 0; m_triangles = 0; m_maxSizeVertexToTriangle = 0; m_streamType = O3DGC_STREAM_TYPE_UNKOWN; } template TriangleListEncoder::~TriangleListEncoder() { delete [] m_vtags; delete [] m_vmap; delete [] m_invVMap; delete [] m_invTMap; delete [] m_visitedVerticesValence; delete [] m_visitedVertices; delete [] m_ttags; delete [] m_tmap; delete [] m_count; delete [] m_nonConqueredTriangles; delete [] m_nonConqueredEdges; } template O3DGCErrorCode TriangleListEncoder::Init(const T * const triangles, long numTriangles, long numVertices) { assert(numVertices > 0); assert(numTriangles > 0); m_numTriangles = numTriangles; m_numVertices = numVertices; m_triangles = triangles; m_vertexCount = 0; m_triangleCount = 0; if (m_numVertices > m_maxNumVertices) { delete [] m_vtags; delete [] m_vmap; delete [] m_invVMap; delete [] m_visitedVerticesValence; delete [] m_visitedVertices; m_maxNumVertices = m_numVertices; m_vtags = new long [m_numVertices]; m_vmap = new long [m_numVertices]; m_invVMap = new long [m_numVertices]; m_visitedVerticesValence = new long [m_numVertices]; m_visitedVertices = new long [m_numVertices]; } if (m_numTriangles > m_maxNumTriangles) { delete [] m_ttags; delete [] m_tmap; delete [] m_invTMap; delete [] m_nonConqueredTriangles; delete [] m_nonConqueredEdges; delete [] m_count; m_maxNumTriangles = m_numTriangles; m_ttags = new long [m_numTriangles]; m_tmap = new long [m_numTriangles]; m_invTMap = new long [m_numTriangles]; m_count = new long [m_numTriangles+1]; m_nonConqueredTriangles = new long [m_numTriangles]; m_nonConqueredEdges = new long [2*m_numTriangles]; } memset(m_vtags , 0x00, sizeof(long) * m_numVertices ); memset(m_vmap , 0xFF, sizeof(long) * m_numVertices ); memset(m_invVMap, 0xFF, sizeof(long) * m_numVertices ); memset(m_ttags , 0x00, sizeof(long) * m_numTriangles); memset(m_tmap , 0xFF, sizeof(long) * m_numTriangles); memset(m_invTMap, 0xFF, sizeof(long) * m_numTriangles); memset(m_count , 0x00, sizeof(long) * (m_numTriangles+1)); m_vfifo.Allocate(m_numVertices); m_ctfans.SetStreamType(m_streamType); m_ctfans.Allocate(m_numVertices, m_numTriangles); // compute vertex-to-triangle adjacency information m_vertexToTriangle.AllocateNumNeighborsArray(numVertices); m_vertexToTriangle.ClearNumNeighborsArray(); long * numNeighbors = m_vertexToTriangle.GetNumNeighborsBuffer(); for(long i = 0, t = 0; i < m_numTriangles; ++i, t+=3) { ++numNeighbors[ triangles[t ] ]; ++numNeighbors[ triangles[t+1] ]; ++numNeighbors[ triangles[t+2] ]; } m_maxSizeVertexToTriangle = 0; for(long i = 0; i < numVertices; ++i) { if (m_maxSizeVertexToTriangle < numNeighbors[i]) { m_maxSizeVertexToTriangle = numNeighbors[i]; } } m_vertexToTriangle.AllocateNeighborsArray(); m_vertexToTriangle.ClearNeighborsArray(); for(long i = 0, t = 0; i < m_numTriangles; ++i, t+=3) { m_vertexToTriangle.AddNeighbor(triangles[t ], i); m_vertexToTriangle.AddNeighbor(triangles[t+1], i); m_vertexToTriangle.AddNeighbor(triangles[t+2], i); } return O3DGC_OK; } template O3DGCErrorCode TriangleListEncoder::Encode(const T * const triangles, const unsigned long * const indexBufferIDs, const long numTriangles, const long numVertices, BinaryStream & bstream) { assert(numVertices > 0); assert(numTriangles > 0); Init(triangles, numTriangles, numVertices); unsigned char mask = 0; bool encodeTrianglesOrder = (indexBufferIDs != 0); if (encodeTrianglesOrder) { long numBufferIDs = 0; for (long t = 0; t < numTriangles; t++) { if (numBufferIDs <= (long) indexBufferIDs[t]) { ++numBufferIDs; assert(numBufferIDs <= numTriangles); } ++m_count[indexBufferIDs[t]+1]; } for (long i = 2; i <= numBufferIDs; i++) { m_count[i] += m_count[i-1]; } mask += 2; // preserved triangles order } bstream.WriteUChar(mask, m_streamType); bstream.WriteUInt32(m_maxSizeVertexToTriangle, m_streamType); long v0; for (long v = 0; v < m_numVertices; v++) { if (!m_vtags[v]) { m_vfifo.PushBack(v); m_vtags[v] = 1; m_vmap[v] = m_vertexCount++; m_invVMap[m_vmap[v]] = v; while (m_vfifo.GetSize() > 0 ) { v0 = m_vfifo.PopFirst(); ProcessVertex(v0); } } } if (encodeTrianglesOrder) { long t, prev = 0; long pred; for (long i = 0; i < numTriangles; ++i) { t = m_invTMap[i]; m_tmap[t] = m_count[ indexBufferIDs[t] ]++; pred = m_tmap[t] - prev; m_ctfans.PushTriangleIndex(pred); prev = m_tmap[t] + 1; } for (long t = 0; t < numTriangles; ++t) { m_invTMap[m_tmap[t]] = t; } } m_ctfans.Save(bstream, encodeTrianglesOrder, m_streamType); return O3DGC_OK; } template O3DGCErrorCode TriangleListEncoder::CompueLocalConnectivityInfo(const long focusVertex) { long t, v, p; m_numNonConqueredTriangles = 0; m_numConqueredTriangles = 0; m_numVisitedVertices = 0; for(long i = m_vertexToTriangle.Begin(focusVertex); i < m_vertexToTriangle.End(focusVertex); ++i) { t = m_vertexToTriangle.GetNeighbor(i); if ( m_ttags[t] == 0) // non-processed triangle { m_nonConqueredTriangles[m_numNonConqueredTriangles] = t; CompueOppositeEdge( focusVertex, m_triangles + (3*t), m_nonConqueredEdges[m_numNonConqueredTriangles*2], m_nonConqueredEdges[m_numNonConqueredTriangles*2+1]); ++m_numNonConqueredTriangles; } else // triangle already processed { m_numConqueredTriangles++; p = 3*t; // extract visited vertices for(long k = 0; k < 3; ++k) { v = m_triangles[p+k]; if (m_vmap[v] > m_vmap[focusVertex]) // vertices are insertices by increasing traversal order { bool foundOrInserted = false; for (long j = 0; j < m_numVisitedVertices; ++j) { if (m_vmap[v] == m_visitedVertices[j]) { m_visitedVerticesValence[j]++; foundOrInserted = true; break; } else if (m_vmap[v] < m_visitedVertices[j]) { ++m_numVisitedVertices; for (long h = m_numVisitedVertices-1; h > j; --h) { m_visitedVertices[h] = m_visitedVertices[h-1]; m_visitedVerticesValence[h] = m_visitedVerticesValence[h-1]; } m_visitedVertices[j] = m_vmap[v]; m_visitedVerticesValence[j] = 1; foundOrInserted = true; break; } } if (!foundOrInserted) { m_visitedVertices[m_numVisitedVertices] = m_vmap[v]; m_visitedVerticesValence[m_numVisitedVertices] = 1; m_numVisitedVertices++; } } } } } // re-order visited vertices by taking into account their valence (i.e., # of conquered triangles incident to each vertex) // in order to avoid config. 9 if (m_numVisitedVertices > 2) { long y; for(long x = 1; x < m_numVisitedVertices; ++x) { if (m_visitedVerticesValence[x] == 1) { y = x; while( (y > 0) && (m_visitedVerticesValence[y] < m_visitedVerticesValence[y-1]) ) { swap(m_visitedVerticesValence[y], m_visitedVerticesValence[y-1]); swap(m_visitedVertices[y], m_visitedVertices[y-1]); --y; } } } } if (m_numNonConqueredTriangles > 0) { // compute triangle-to-triangle adjacency information m_triangleToTriangle.AllocateNumNeighborsArray(m_numNonConqueredTriangles); m_triangleToTriangle.ClearNumNeighborsArray(); m_triangleToTriangleInv.AllocateNumNeighborsArray(m_numNonConqueredTriangles); m_triangleToTriangleInv.ClearNumNeighborsArray(); long * const numNeighbors = m_triangleToTriangle.GetNumNeighborsBuffer(); long * const invNumNeighbors = m_triangleToTriangleInv.GetNumNeighborsBuffer(); for(long i = 0; i < m_numNonConqueredTriangles; ++i) { for(long j = i+1; j < m_numNonConqueredTriangles; ++j) { if (m_nonConqueredEdges[2*i+1] == m_nonConqueredEdges[2*j]) // edge i is connected to edge j { ++numNeighbors[i]; ++invNumNeighbors[j]; } if (m_nonConqueredEdges[2*i] == m_nonConqueredEdges[2*j+1]) // edge i is connected to edge j { ++numNeighbors[j]; ++invNumNeighbors[i]; } } } m_triangleToTriangle.AllocateNeighborsArray(); m_triangleToTriangle.ClearNeighborsArray(); m_triangleToTriangleInv.AllocateNeighborsArray(); m_triangleToTriangleInv.ClearNeighborsArray(); for(long i = 0; i < m_numNonConqueredTriangles; ++i) { for(long j = 1; j < m_numNonConqueredTriangles; ++j) { if (m_nonConqueredEdges[2*i+1] == m_nonConqueredEdges[2*j]) // edge i is connected to edge j { m_triangleToTriangle.AddNeighbor(i, j); m_triangleToTriangleInv.AddNeighbor(j, i); } if (m_nonConqueredEdges[2*i] == m_nonConqueredEdges[2*j+1]) // edge i is connected to edge j { m_triangleToTriangle.AddNeighbor(j, i); m_triangleToTriangleInv.AddNeighbor(i, j); } } } } return O3DGC_OK; } template O3DGCErrorCode TriangleListEncoder::ComputeTFANDecomposition(const long focusVertex) { long processedTriangles = 0; long minNumInputEdges; long numInputEdges; long indexSeedTriangle; long seedTriangle; long currentIndex; long currentTriangle; long i0, i1, index; m_tfans.Clear(); while (processedTriangles != m_numNonConqueredTriangles) { // find non processed triangle with lowest number of inputs minNumInputEdges = m_numTriangles; indexSeedTriangle = -1; for(long i = 0; i < m_numNonConqueredTriangles; ++i) { numInputEdges = m_triangleToTriangleInv.GetNumNeighbors(i); if ( !m_ttags[m_nonConqueredTriangles[i]] && numInputEdges < minNumInputEdges ) { minNumInputEdges = numInputEdges; indexSeedTriangle = i; if (minNumInputEdges == 0) // found boundary triangle { break; } } } assert(indexSeedTriangle >= 0); seedTriangle = m_nonConqueredTriangles[indexSeedTriangle]; m_tfans.AddTFAN(); m_tfans.AddVertex( focusVertex ); m_tfans.AddVertex( m_nonConqueredEdges[indexSeedTriangle*2] ); m_tfans.AddVertex( m_nonConqueredEdges[indexSeedTriangle*2 + 1] ); m_ttags[ seedTriangle ] = 1; // mark triangle as processed m_tmap[seedTriangle] = m_triangleCount++; m_invTMap[m_tmap[seedTriangle]] = seedTriangle; ++processedTriangles; currentIndex = indexSeedTriangle; currentTriangle = seedTriangle; do { // find next triangle i0 = m_triangleToTriangle.Begin(currentIndex); i1 = m_triangleToTriangle.End(currentIndex); currentIndex = -1; for(long i = i0; i < i1; ++i) { index = m_triangleToTriangle.GetNeighbor(i); currentTriangle = m_nonConqueredTriangles[index]; if ( !m_ttags[currentTriangle] ) { currentIndex = index; m_tfans.AddVertex( m_nonConqueredEdges[currentIndex*2+1] ); m_ttags[currentTriangle] = 1; // mark triangle as processed m_tmap [currentTriangle] = m_triangleCount++; m_invTMap[m_tmap [currentTriangle]] = currentTriangle; ++processedTriangles; break; } } } while (currentIndex != -1); } return O3DGC_OK; } template O3DGCErrorCode TriangleListEncoder::CompressTFAN(const long focusVertex) { m_ctfans.PushNumTFans(m_tfans.GetNumTFANs()); const long ntfans = m_tfans.GetNumTFANs(); long degree; long k0, k1; long v0; long ops[O3DGC_MAX_TFAN_SIZE]; long indices[O3DGC_MAX_TFAN_SIZE]; long numOps; long numIndices; long pos; long found; if (m_tfans.GetNumTFANs() > 0) { for(long f = 0; f != ntfans; f++) { degree = m_tfans.GetTFANSize(f) - 1; m_ctfans.PushDegree(degree-2+ m_numConqueredTriangles); numOps = 0; numIndices = 0; k0 = 1 + m_tfans.Begin(f); k1 = m_tfans.End(f); for(long k = k0; k < k1; k++) { v0 = m_tfans.GetVertex(k); if (m_vtags[v0] == 0) { ops[numOps++] = 0; m_vtags[v0] = 1; m_vmap[v0] = m_vertexCount++; m_invVMap[m_vmap[v0]] = v0; m_vfifo.PushBack(v0); m_visitedVertices[m_numVisitedVertices++] = m_vmap[v0]; } else { ops[numOps++] = 1; pos = 0; found = 0; for(long u=0; u < m_numVisitedVertices; ++u) { pos++; if (m_visitedVertices[u] == m_vmap[v0]) { found = 1; break; } } if (found == 1) { indices[numIndices++] = -pos; } else { indices[numIndices++] = m_vmap[v0] - m_vmap[focusVertex]; } } } //----------------------------------------------- if (IsCase0(degree, numIndices, ops, indices)) { // ops: 1000001 vertices: -1 -2 m_ctfans.PushConfig(0); } else if (IsCase1(degree, numIndices, ops, indices)) { // ops: 1xxxxxx1 vertices: -1 x x x x x -2 long u = 1; for(u = 1; u < degree-1; u++) { m_ctfans.PushOperation(ops[u]); } for(u =1; u < numIndices-1; u++) { m_ctfans.PushIndex(indices[u]); } m_ctfans.PushConfig(1); } else if (IsCase2(degree, numIndices, ops, indices)) { // ops: 00000001 vertices: -1 m_ctfans.PushConfig(2); } else if (IsCase3(degree, numIndices, ops, indices)) { // ops: 00000001 vertices: -2 m_ctfans.PushConfig(3); } else if (IsCase4(degree, numIndices, ops, indices)) { // ops: 10000000 vertices: -1 m_ctfans.PushConfig(4); } else if (IsCase5(degree, numIndices, ops, indices)) { // ops: 10000000 vertices: -2 m_ctfans.PushConfig(5); } else if (IsCase6(degree, numIndices, ops, indices)) { // ops: 00000000 vertices: m_ctfans.PushConfig(6); } else if (IsCase7(degree, numIndices, ops, indices)) { // ops: 1000001 vertices: -1 -2 m_ctfans.PushConfig(7); } else if (IsCase8(degree, numIndices, ops, indices)) { // ops: 1xxxxxx1 vertices: -2 x x x x x -1 long u = 1; for(u =1; u < degree-1; u++) { m_ctfans.PushOperation(ops[u]); } for(u =1; u < numIndices-1; u++) { m_ctfans.PushIndex(indices[u]); } m_ctfans.PushConfig(8); } else { long u = 0; for(u =0; u < degree; u++) { m_ctfans.PushOperation(ops[u]); } for(u =0; u < numIndices; u++) { m_ctfans.PushIndex(indices[u]); } m_ctfans.PushConfig(9); } } } return O3DGC_OK; } template O3DGCErrorCode TriangleListEncoder::ProcessVertex(const long focusVertex) { CompueLocalConnectivityInfo(focusVertex); ComputeTFANDecomposition(focusVertex); CompressTFAN(focusVertex); return O3DGC_OK; } } #endif //O3DGC_TRIANGLE_LIST_ENCODER_INL assimp-4.1.0/contrib/Open3DGC/o3dgcTriangleListDecoder.h0000644002537200234200000001563213213503245023205 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_TRIANGLE_LIST_DECODER_H #define O3DGC_TRIANGLE_LIST_DECODER_H #include "o3dgcCommon.h" #include "o3dgcTriangleFans.h" #include "o3dgcBinaryStream.h" #include "o3dgcAdjacencyInfo.h" namespace o3dgc { //! template class TriangleListDecoder { public: //! Constructor. TriangleListDecoder(void) { m_vertexCount = 0; m_triangleCount = 0; m_numTriangles = 0; m_numVertices = 0; m_triangles = 0; m_numConqueredTriangles = 0; m_numVisitedVertices = 0; m_visitedVertices = 0; m_visitedVerticesValence = 0; m_maxNumVertices = 0; m_maxNumTriangles = 0; m_itNumTFans = 0; m_itDegree = 0; m_itConfig = 0; m_itOperation = 0; m_itIndex = 0; m_tempTriangles = 0; m_tempTrianglesSize = 0; m_decodeTrianglesOrder = false; m_decodeVerticesOrder = false; }; //! Destructor. ~TriangleListDecoder(void) { delete [] m_tempTriangles; }; O3DGCStreamType GetStreamType() const { return m_streamType; } bool GetReorderTriangles() const { return m_decodeTrianglesOrder; } bool GetReorderVertices() const { return m_decodeVerticesOrder; } void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; } const AdjacencyInfo & GetVertexToTriangle() const { return m_vertexToTriangle;} O3DGCErrorCode Decode(T * const triangles, const long numTriangles, const long numVertices, const BinaryStream & bstream, unsigned long & iterator) { unsigned char compressionMask = bstream.ReadUChar(iterator, m_streamType); m_decodeTrianglesOrder = ( (compressionMask&2) != 0); m_decodeVerticesOrder = ( (compressionMask&1) != 0); if (m_decodeVerticesOrder) // vertices reordering not supported { return O3DGC_ERROR_NON_SUPPORTED_FEATURE; } unsigned long maxSizeV2T = bstream.ReadUInt32(iterator, m_streamType); Init(triangles, numTriangles, numVertices, maxSizeV2T); m_ctfans.Load(bstream, iterator, m_decodeTrianglesOrder, m_streamType); Decompress(); return O3DGC_OK; } O3DGCErrorCode Reorder(); private: O3DGCErrorCode Init(T * const triangles, const long numTriangles, const long numVertices, const long maxSizeV2T); O3DGCErrorCode Decompress(); O3DGCErrorCode CompueLocalConnectivityInfo(const long focusVertex); O3DGCErrorCode DecompressTFAN(const long focusVertex); unsigned long m_itNumTFans; unsigned long m_itDegree; unsigned long m_itConfig; unsigned long m_itOperation; unsigned long m_itIndex; long m_maxNumVertices; long m_maxNumTriangles; long m_numTriangles; long m_numVertices; long m_tempTrianglesSize; T * m_triangles; T * m_tempTriangles; long m_vertexCount; long m_triangleCount; long m_numConqueredTriangles; long m_numVisitedVertices; long * m_visitedVertices; long * m_visitedVerticesValence; AdjacencyInfo m_vertexToTriangle; CompressedTriangleFans m_ctfans; TriangleFans m_tfans; O3DGCStreamType m_streamType; bool m_decodeTrianglesOrder; bool m_decodeVerticesOrder; }; } #include "o3dgcTriangleListDecoder.inl" // template implementation #endif // O3DGC_TRIANGLE_LIST_DECODER_H assimp-4.1.0/contrib/Open3DGC/o3dgcTimer.h0000644002537200234200000000702613213503245020374 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_TIMER_H #define O3DGC_TIMER_H #include "o3dgcCommon.h" #ifdef _WIN32 /* Thank you, Microsoft, for file WinDef.h with min/max redefinition. */ #define NOMINMAX #include #elif __MACH__ #include #include #else #include #include #endif namespace o3dgc { #ifdef _WIN32 class Timer { public: Timer(void) { m_start.QuadPart = 0; m_stop.QuadPart = 0; QueryPerformanceFrequency( &m_freq ) ; }; ~Timer(void){}; void Tic() { QueryPerformanceCounter(&m_start) ; } void Toc() { QueryPerformanceCounter(&m_stop); } double GetElapsedTime() // in ms { LARGE_INTEGER delta; delta.QuadPart = m_stop.QuadPart - m_start.QuadPart; return (1000.0 * delta.QuadPart) / (double)m_freq.QuadPart; } private: LARGE_INTEGER m_start; LARGE_INTEGER m_stop; LARGE_INTEGER m_freq; }; #elif __MACH__ class Timer { public: Timer(void) { memset(this, 0, sizeof(Timer)); host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, & m_cclock); }; ~Timer(void) { mach_port_deallocate(mach_task_self(), m_cclock); }; void Tic() { clock_get_time( m_cclock, &m_start); } void Toc() { clock_get_time( m_cclock, &m_stop); } double GetElapsedTime() // in ms { return 1000.0 * (m_stop.tv_sec - m_start.tv_sec + (1.0E-9) * (m_stop.tv_nsec - m_start.tv_nsec)); } private: clock_serv_t m_cclock; mach_timespec_t m_start; mach_timespec_t m_stop; }; #else class Timer { public: Timer(void) { memset(this, 0, sizeof(Timer)); }; ~Timer(void){}; void Tic() { clock_gettime(CLOCK_REALTIME, &m_start); } void Toc() { clock_gettime(CLOCK_REALTIME, &m_stop); } double GetElapsedTime() // in ms { return 1000.0 * (m_stop.tv_sec - m_start.tv_sec + (1.0E-9) * (m_stop.tv_nsec - m_start.tv_nsec)); } private: struct timespec m_start; struct timespec m_stop; }; #endif } #endif // O3DGC_TIMER_H assimp-4.1.0/contrib/Open3DGC/o3dgcSC3DMCEncoder.inl0000644002537200234200000011771413213503245022071 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_SC3DMC_ENCODER_INL #define O3DGC_SC3DMC_ENCODER_INL #include "o3dgcArithmeticCodec.h" #include "o3dgcTimer.h" #include "o3dgcVector.h" #include "o3dgcBinaryStream.h" #include "o3dgcCommon.h" //#define DEBUG_VERBOSE namespace o3dgc { #ifdef DEBUG_VERBOSE FILE * g_fileDebugSC3DMCEnc = NULL; #endif //DEBUG_VERBOSE template O3DGCErrorCode SC3DMCEncoder::Encode(const SC3DMCEncodeParams & params, const IndexedFaceSet & ifs, BinaryStream & bstream) { // Encode header unsigned long start = bstream.GetSize(); EncodeHeader(params, ifs, bstream); // Encode payload EncodePayload(params, ifs, bstream); bstream.WriteUInt32(m_posSize, bstream.GetSize() - start, m_streamType); return O3DGC_OK; } template O3DGCErrorCode SC3DMCEncoder::EncodeHeader(const SC3DMCEncodeParams & params, const IndexedFaceSet & ifs, BinaryStream & bstream) { m_streamType = params.GetStreamType(); bstream.WriteUInt32(O3DGC_SC3DMC_START_CODE, m_streamType); m_posSize = bstream.GetSize(); bstream.WriteUInt32(0, m_streamType); // to be filled later bstream.WriteUChar(O3DGC_SC3DMC_ENCODE_MODE_TFAN, m_streamType); bstream.WriteFloat32((float)ifs.GetCreaseAngle(), m_streamType); unsigned char mask = 0; bool markerBit0 = false; bool markerBit1 = false; bool markerBit2 = false; bool markerBit3 = false; mask += (ifs.GetCCW() ); mask += (ifs.GetSolid() << 1); mask += (ifs.GetConvex() << 2); mask += (ifs.GetIsTriangularMesh() << 3); mask += (markerBit0 << 4); mask += (markerBit1 << 5); mask += (markerBit2 << 6); mask += (markerBit3 << 7); bstream.WriteUChar(mask, m_streamType); bstream.WriteUInt32(ifs.GetNCoord(), m_streamType); bstream.WriteUInt32(ifs.GetNNormal(), m_streamType); bstream.WriteUInt32(ifs.GetNumFloatAttributes(), m_streamType); bstream.WriteUInt32(ifs.GetNumIntAttributes(), m_streamType); if (ifs.GetNCoord() > 0) { bstream.WriteUInt32(ifs.GetNCoordIndex(), m_streamType); for(int j=0 ; j<3 ; ++j) { bstream.WriteFloat32((float) ifs.GetCoordMin(j), m_streamType); bstream.WriteFloat32((float) ifs.GetCoordMax(j), m_streamType); } bstream.WriteUChar((unsigned char) params.GetCoordQuantBits(), m_streamType); } if (ifs.GetNNormal() > 0) { bstream.WriteUInt32(0, m_streamType); for(int j=0 ; j<3 ; ++j) { bstream.WriteFloat32((float) ifs.GetNormalMin(j), m_streamType); bstream.WriteFloat32((float) ifs.GetNormalMax(j), m_streamType); } bstream.WriteUChar(true, m_streamType); //(unsigned char) ifs.GetNormalPerVertex() bstream.WriteUChar((unsigned char) params.GetNormalQuantBits(), m_streamType); } for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a) { bstream.WriteUInt32(ifs.GetNFloatAttribute(a), m_streamType); if (ifs.GetNFloatAttribute(a) > 0) { assert(ifs.GetFloatAttributeDim(a) < (unsigned long) O3DGC_MAX_UCHAR8); bstream.WriteUInt32(0, m_streamType); unsigned char d = (unsigned char) ifs.GetFloatAttributeDim(a); bstream.WriteUChar(d, m_streamType); for(unsigned char j = 0 ; j < d ; ++j) { bstream.WriteFloat32((float) ifs.GetFloatAttributeMin(a, j), m_streamType); bstream.WriteFloat32((float) ifs.GetFloatAttributeMax(a, j), m_streamType); } bstream.WriteUChar(true, m_streamType); //(unsigned char) ifs.GetFloatAttributePerVertex(a) bstream.WriteUChar((unsigned char) ifs.GetFloatAttributeType(a), m_streamType); bstream.WriteUChar((unsigned char) params.GetFloatAttributeQuantBits(a), m_streamType); } } for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a) { bstream.WriteUInt32(ifs.GetNIntAttribute(a), m_streamType); if (ifs.GetNIntAttribute(a) > 0) { assert(ifs.GetFloatAttributeDim(a) < (unsigned long) O3DGC_MAX_UCHAR8); bstream.WriteUInt32(0, m_streamType); bstream.WriteUChar((unsigned char) ifs.GetIntAttributeDim(a), m_streamType); bstream.WriteUChar(true, m_streamType); // (unsigned char) ifs.GetIntAttributePerVertex(a) bstream.WriteUChar((unsigned char) ifs.GetIntAttributeType(a), m_streamType); } } return O3DGC_OK; } template O3DGCErrorCode SC3DMCEncoder::QuantizeFloatArray(const Real * const floatArray, unsigned long numFloatArray, unsigned long dimFloatArray, unsigned long stride, const Real * const minFloatArray, const Real * const maxFloatArray, unsigned long nQBits) { const unsigned long size = numFloatArray * dimFloatArray; Real delta[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]; Real r; for(unsigned long d = 0; d < dimFloatArray; d++) { r = maxFloatArray[d] - minFloatArray[d]; if (r > 0.0f) { delta[d] = (float)((1 << nQBits) - 1) / r; } else { delta[d] = 1.0f; } } if (m_quantFloatArraySize < size) { delete [] m_quantFloatArray; m_quantFloatArraySize = size; m_quantFloatArray = new long [size]; } for(unsigned long v = 0; v < numFloatArray; ++v) { for(unsigned long d = 0; d < dimFloatArray; ++d) { m_quantFloatArray[v * stride + d] = (long)((floatArray[v * stride + d]-minFloatArray[d]) * delta[d] + 0.5f); } } return O3DGC_OK; } template O3DGCErrorCode SC3DMCEncoder::EncodeFloatArray(const Real * const floatArray, unsigned long numFloatArray, unsigned long dimFloatArray, unsigned long stride, const Real * const minFloatArray, const Real * const maxFloatArray, unsigned long nQBits, const IndexedFaceSet & ifs, O3DGCSC3DMCPredictionMode predMode, BinaryStream & bstream) { assert(dimFloatArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); long predResidual, v, uPredResidual; unsigned long nPred; Arithmetic_Codec ace; Static_Bit_Model bModel0; Adaptive_Bit_Model bModel1; const AdjacencyInfo & v2T = m_triangleListEncoder.GetVertexToTriangle(); const long * const vmap = m_triangleListEncoder.GetVMap(); const long * const invVMap = m_triangleListEncoder.GetInvVMap(); const T * const triangles = ifs.GetCoordIndex(); const long nvert = (long) numFloatArray; unsigned long start = bstream.GetSize(); unsigned char mask = predMode & 7; const unsigned long M = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS - 1; unsigned long nSymbols = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS; unsigned long nPredictors = O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS; Adaptive_Data_Model mModelValues(M+2); Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1); memset(m_freqSymbols, 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS); memset(m_freqPreds , 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS); if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { mask += (O3DGC_SC3DMC_BINARIZATION_ASCII & 7)<<4; m_predictors.Allocate(nvert); m_predictors.Clear(); } else { mask += (O3DGC_SC3DMC_BINARIZATION_AC_EGC & 7)<<4; const unsigned int NMAX = numFloatArray * dimFloatArray * 8 + 100; if ( m_sizeBufferAC < NMAX ) { delete [] m_bufferAC; m_sizeBufferAC = NMAX; m_bufferAC = new unsigned char [m_sizeBufferAC]; } ace.set_buffer(NMAX, m_bufferAC); ace.start_encoder(); ace.ExpGolombEncode(0, 0, bModel0, bModel1); ace.ExpGolombEncode(M, 0, bModel0, bModel1); } bstream.WriteUInt32(0, m_streamType); bstream.WriteUChar(mask, m_streamType); #ifdef DEBUG_VERBOSE printf("FloatArray (%i, %i)\n", numFloatArray, dimFloatArray); fprintf(g_fileDebugSC3DMCEnc, "FloatArray (%i, %i)\n", numFloatArray, dimFloatArray); #endif //DEBUG_VERBOSE if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION) { const Real minFloatArray[2] = {(Real)(-2.0),(Real)(-2.0)}; const Real maxFloatArray[2] = {(Real)(2.0),(Real)(2.0)}; if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { for(unsigned long i = 0; i < numFloatArray; ++i) { bstream.WriteIntASCII(m_predictors[i]); } } else { Adaptive_Data_Model dModel(12); for(unsigned long i = 0; i < numFloatArray; ++i) { ace.encode(IntToUInt(m_predictors[i]), dModel); } } QuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits+1); } else { QuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits); } for (long vm=0; vm < nvert; ++vm) { nPred = 0; v = invVMap[vm]; assert( v >= 0 && v < nvert); if ( v2T.GetNumNeighbors(v) > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION) { int u0 = v2T.Begin(v); int u1 = v2T.End(v); for (long u = u0; u < u1; u++) { long ta = v2T.GetNeighbor(u); if ( predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION ) { long a,b; if ((long) triangles[ta*3] == v) { a = triangles[ta*3 + 1]; b = triangles[ta*3 + 2]; } else if ((long) triangles[ta*3 + 1] == v) { a = triangles[ta*3 + 0]; b = triangles[ta*3 + 2]; } else { a = triangles[ta*3 + 0]; b = triangles[ta*3 + 1]; } if ( vmap[a] < vm && vmap[b] < vm) { int u0 = v2T.Begin(a); int u1 = v2T.End(a); for (long u = u0; u < u1; u++) { long tb = v2T.GetNeighbor(u); long c = -1; bool foundB = false; for(long k = 0; k < 3; ++k) { long x = triangles[tb*3 + k]; if (x == b) { foundB = true; } if (vmap[x] < vm && x != a && x != b) { c = x; } } if (c != -1 && foundB) { SC3DMCTriplet id = {min(vmap[a], vmap[b]), max(vmap[a], vmap[b]), -vmap[c]-1}; unsigned long p = Insert(id, nPred, m_neighbors); if (p != 0xFFFFFFFF) { for (unsigned long i = 0; i < dimFloatArray; i++) { m_neighbors[p].m_pred[i] = m_quantFloatArray[a*stride+i] + m_quantFloatArray[b*stride+i] - m_quantFloatArray[c*stride+i]; } } } } } } if ( predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION || predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION || predMode == O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION ) { for(long k = 0; k < 3; ++k) { long w = triangles[ta*3 + k]; if ( vmap[w] < vm ) { SC3DMCTriplet id = {-1, -1, vmap[w]}; unsigned long p = Insert(id, nPred, m_neighbors); if (p != 0xFFFFFFFF) { for (unsigned long i = 0; i < dimFloatArray; i++) { m_neighbors[p].m_pred[i] = m_quantFloatArray[w*stride+i]; } } } } } } } if (nPred > 1) { // find best predictor unsigned long bestPred = 0xFFFFFFFF; double bestCost = O3DGC_MAX_DOUBLE; double cost; #ifdef DEBUG_VERBOSE1 printf("\t\t vm %i\n", vm); fprintf(g_fileDebugSC3DMCEnc, "\t\t vm %i\n", vm); #endif //DEBUG_VERBOSE for (unsigned long p = 0; p < nPred; ++p) { #ifdef DEBUG_VERBOSE1 printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); fprintf(g_fileDebugSC3DMCEnc, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); #endif //DEBUG_VERBOSE cost = -log2((m_freqPreds[p]+1.0) / nPredictors ); for (unsigned long i = 0; i < dimFloatArray; ++i) { #ifdef DEBUG_VERBOSE1 printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]); fprintf(g_fileDebugSC3DMCEnc, "\t\t\t %i\n", m_neighbors[p].m_pred[i]); #endif //DEBUG_VERBOSE predResidual = (long) IntToUInt(m_quantFloatArray[v*stride+i] - m_neighbors[p].m_pred[i]); if (predResidual < (long) M) { cost += -log2((m_freqSymbols[predResidual]+1.0) / nSymbols ); } else { cost += -log2((m_freqSymbols[M] + 1.0) / nSymbols ) + log2((double) (predResidual-M)); } } if (cost < bestCost) { bestCost = cost; bestPred = p; } } if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { m_predictors.PushBack((unsigned char) bestPred); } else { ace.encode(bestPred, mModelPreds); } #ifdef DEBUG_VERBOSE1 printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); fprintf(g_fileDebugSC3DMCEnc, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); #endif //DEBUG_VERBOSE // use best predictor for (unsigned long i = 0; i < dimFloatArray; ++i) { predResidual = m_quantFloatArray[v*stride+i] - m_neighbors[bestPred].m_pred[i]; uPredResidual = IntToUInt(predResidual); ++m_freqSymbols[(uPredResidual < (long) M)? uPredResidual : M]; #ifdef DEBUG_VERBOSE printf("%i \t %i \t [%i]\n", vm*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); fprintf(g_fileDebugSC3DMCEnc, "%i \t %i \t [%i]\n", vm*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); #endif //DEBUG_VERBOSE if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { bstream.WriteIntASCII(predResidual); } else { EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M); } } ++m_freqPreds[bestPred]; nSymbols += dimFloatArray; ++nPredictors; } else if ( vm > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION) { long prev = invVMap[vm-1]; for (unsigned long i = 0; i < dimFloatArray; i++) { predResidual = m_quantFloatArray[v*stride+i] - m_quantFloatArray[prev*stride+i]; if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { bstream.WriteIntASCII(predResidual); } else { EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M); } #ifdef DEBUG_VERBOSE printf("%i \t %i\n", vm*dimFloatArray+i, predResidual); fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimFloatArray+i, predResidual); #endif //DEBUG_VERBOSE } } else { for (unsigned long i = 0; i < dimFloatArray; i++) { predResidual = m_quantFloatArray[v*stride+i]; if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { bstream.WriteUIntASCII(predResidual); } else { EncodeUIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M); } #ifdef DEBUG_VERBOSE printf("%i \t %i\n", vm*dimFloatArray+i, predResidual); fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimFloatArray+i, predResidual); #endif //DEBUG_VERBOSE } } } if (m_streamType != O3DGC_STREAM_TYPE_ASCII) { unsigned long encodedBytes = ace.stop_encoder(); for(unsigned long i = 0; i < encodedBytes; ++i) { bstream.WriteUChar8Bin(m_bufferAC[i]); } } bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType); if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { unsigned long start = bstream.GetSize(); bstream.WriteUInt32ASCII(0); const unsigned long size = m_predictors.GetSize(); for(unsigned long i = 0; i < size; ++i) { bstream.WriteUCharASCII((unsigned char) m_predictors[i]); } bstream.WriteUInt32ASCII(start, bstream.GetSize() - start); } #ifdef DEBUG_VERBOSE fflush(g_fileDebugSC3DMCEnc); #endif //DEBUG_VERBOSE return O3DGC_OK; } template O3DGCErrorCode SC3DMCEncoder::EncodeIntArray(const long * const intArray, unsigned long numIntArray, unsigned long dimIntArray, unsigned long stride, const IndexedFaceSet & ifs, O3DGCSC3DMCPredictionMode predMode, BinaryStream & bstream) { assert(dimIntArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); long predResidual, v, uPredResidual; unsigned long nPred; Arithmetic_Codec ace; Static_Bit_Model bModel0; Adaptive_Bit_Model bModel1; const AdjacencyInfo & v2T = m_triangleListEncoder.GetVertexToTriangle(); const long * const vmap = m_triangleListEncoder.GetVMap(); const long * const invVMap = m_triangleListEncoder.GetInvVMap(); const T * const triangles = ifs.GetCoordIndex(); const long nvert = (long) numIntArray; unsigned long start = bstream.GetSize(); unsigned char mask = predMode & 7; const unsigned long M = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS - 1; unsigned long nSymbols = O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS; unsigned long nPredictors = O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS; Adaptive_Data_Model mModelValues(M+2); Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1); memset(m_freqSymbols, 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS); memset(m_freqPreds , 0, sizeof(unsigned long) * O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS); if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { mask += (O3DGC_SC3DMC_BINARIZATION_ASCII & 7)<<4; m_predictors.Allocate(nvert); m_predictors.Clear(); } else { mask += (O3DGC_SC3DMC_BINARIZATION_AC_EGC & 7)<<4; const unsigned int NMAX = numIntArray * dimIntArray * 8 + 100; if ( m_sizeBufferAC < NMAX ) { delete [] m_bufferAC; m_sizeBufferAC = NMAX; m_bufferAC = new unsigned char [m_sizeBufferAC]; } ace.set_buffer(NMAX, m_bufferAC); ace.start_encoder(); ace.ExpGolombEncode(0, 0, bModel0, bModel1); ace.ExpGolombEncode(M, 0, bModel0, bModel1); } bstream.WriteUInt32(0, m_streamType); bstream.WriteUChar(mask, m_streamType); #ifdef DEBUG_VERBOSE printf("IntArray (%i, %i)\n", numIntArray, dimIntArray); fprintf(g_fileDebugSC3DMCEnc, "IntArray (%i, %i)\n", numIntArray, dimIntArray); #endif //DEBUG_VERBOSE for (long vm=0; vm < nvert; ++vm) { nPred = 0; v = invVMap[vm]; assert( v >= 0 && v < nvert); if ( v2T.GetNumNeighbors(v) > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION) { int u0 = v2T.Begin(v); int u1 = v2T.End(v); for (long u = u0; u < u1; u++) { long ta = v2T.GetNeighbor(u); for(long k = 0; k < 3; ++k) { long w = triangles[ta*3 + k]; if ( vmap[w] < vm ) { SC3DMCTriplet id = {-1, -1, vmap[w]}; unsigned long p = Insert(id, nPred, m_neighbors); if (p != 0xFFFFFFFF) { for (unsigned long i = 0; i < dimIntArray; i++) { m_neighbors[p].m_pred[i] = intArray[w*stride+i]; } } } } } } if (nPred > 1) { // find best predictor unsigned long bestPred = 0xFFFFFFFF; double bestCost = O3DGC_MAX_DOUBLE; double cost; #ifdef DEBUG_VERBOSE1 printf("\t\t vm %i\n", vm); fprintf(g_fileDebugSC3DMCEnc, "\t\t vm %i\n", vm); #endif //DEBUG_VERBOSE for (unsigned long p = 0; p < nPred; ++p) { #ifdef DEBUG_VERBOSE1 printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); fprintf(g_fileDebugSC3DMCEnc, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); #endif //DEBUG_VERBOSE cost = -log2((m_freqPreds[p]+1.0) / nPredictors ); for (unsigned long i = 0; i < dimIntArray; ++i) { #ifdef DEBUG_VERBOSE1 printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]); fprintf(g_fileDebugSC3DMCEnc, "\t\t\t %i\n", m_neighbors[p].m_pred[i]); #endif //DEBUG_VERBOSE predResidual = (long) IntToUInt(intArray[v*stride+i] - m_neighbors[p].m_pred[i]); if (predResidual < (long) M) { cost += -log2((m_freqSymbols[predResidual]+1.0) / nSymbols ); } else { cost += -log2((m_freqSymbols[M] + 1.0) / nSymbols ) + log2((double) (predResidual-M)); } } if (cost < bestCost) { bestCost = cost; bestPred = p; } } if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { m_predictors.PushBack((unsigned char) bestPred); } else { ace.encode(bestPred, mModelPreds); } #ifdef DEBUG_VERBOSE1 printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); fprintf(g_fileDebugSC3DMCEnc, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); #endif //DEBUG_VERBOSE // use best predictor for (unsigned long i = 0; i < dimIntArray; ++i) { predResidual = intArray[v*stride+i] - m_neighbors[bestPred].m_pred[i]; uPredResidual = IntToUInt(predResidual); ++m_freqSymbols[(uPredResidual < (long) M)? uPredResidual : M]; #ifdef DEBUG_VERBOSE printf("%i \t %i \t [%i]\n", vm*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); fprintf(g_fileDebugSC3DMCEnc, "%i \t %i \t [%i]\n", vm*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); #endif //DEBUG_VERBOSE if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { bstream.WriteIntASCII(predResidual); } else { EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M); } } ++m_freqPreds[bestPred]; nSymbols += dimIntArray; ++nPredictors; } else if ( vm > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION) { long prev = invVMap[vm-1]; for (unsigned long i = 0; i < dimIntArray; i++) { predResidual = intArray[v*stride+i] - intArray[prev*stride+i]; if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { bstream.WriteIntASCII(predResidual); } else { EncodeIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M); } #ifdef DEBUG_VERBOSE printf("%i \t %i\n", vm*dimIntArray+i, predResidual); fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimIntArray+i, predResidual); #endif //DEBUG_VERBOSE } } else { for (unsigned long i = 0; i < dimIntArray; i++) { predResidual = intArray[v*stride+i]; if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { bstream.WriteUIntASCII(predResidual); } else { EncodeUIntACEGC(predResidual, ace, mModelValues, bModel0, bModel1, M); } #ifdef DEBUG_VERBOSE printf("%i \t %i\n", vm*dimIntArray+i, predResidual); fprintf(g_fileDebugSC3DMCEnc, "%i \t %i\n", vm*dimIntArray+i, predResidual); #endif //DEBUG_VERBOSE } } } if (m_streamType != O3DGC_STREAM_TYPE_ASCII) { unsigned long encodedBytes = ace.stop_encoder(); for(unsigned long i = 0; i < encodedBytes; ++i) { bstream.WriteUChar8Bin(m_bufferAC[i]); } } bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType); if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { unsigned long start = bstream.GetSize(); bstream.WriteUInt32ASCII(0); const unsigned long size = m_predictors.GetSize(); for(unsigned long i = 0; i < size; ++i) { bstream.WriteUCharASCII((unsigned char) m_predictors[i]); } bstream.WriteUInt32ASCII(start, bstream.GetSize() - start); } #ifdef DEBUG_VERBOSE fflush(g_fileDebugSC3DMCEnc); #endif //DEBUG_VERBOSE return O3DGC_OK; } template O3DGCErrorCode SC3DMCEncoder::ProcessNormals(const IndexedFaceSet & ifs) { const long nvert = (long) ifs.GetNNormal(); const unsigned long normalSize = ifs.GetNNormal() * 2; if (m_normalsSize < normalSize) { delete [] m_normals; m_normalsSize = normalSize; m_normals = new Real [normalSize]; } const AdjacencyInfo & v2T = m_triangleListEncoder.GetVertexToTriangle(); const long * const invVMap = m_triangleListEncoder.GetInvVMap(); const T * const triangles = ifs.GetCoordIndex(); const Real * const originalNormals = ifs.GetNormal(); Vec3 p1, p2, p3, n0, nt; Vec3 n1; long na0 = 0, nb0 = 0; Real rna0, rnb0, na1 = 0, nb1 = 0, norm0, norm1; char ni0 = 0, ni1 = 0; long a, b, c, v; m_predictors.Clear(); for (long i=0; i < nvert; ++i) { v = invVMap[i]; n0.X() = 0; n0.Y() = 0; n0.Z() = 0; int u0 = v2T.Begin(v); int u1 = v2T.End(v); for (long u = u0; u < u1; u++) { long ta = v2T.GetNeighbor(u); a = triangles[ta*3 + 0]; b = triangles[ta*3 + 1]; c = triangles[ta*3 + 2]; p1.X() = m_quantFloatArray[3*a]; p1.Y() = m_quantFloatArray[3*a+1]; p1.Z() = m_quantFloatArray[3*a+2]; p2.X() = m_quantFloatArray[3*b]; p2.Y() = m_quantFloatArray[3*b+1]; p2.Z() = m_quantFloatArray[3*b+2]; p3.X() = m_quantFloatArray[3*c]; p3.Y() = m_quantFloatArray[3*c+1]; p3.Z() = m_quantFloatArray[3*c+2]; nt = (p2-p1)^(p3-p1); n0 += nt; } norm0 = (Real) n0.GetNorm(); if (norm0 == 0.0) { norm0 = 1.0; } SphereToCube(n0.X(), n0.Y(), n0.Z(), na0, nb0, ni0); rna0 = na0 / norm0; rnb0 = nb0 / norm0; n1.X() = originalNormals[3*v]; n1.Y() = originalNormals[3*v+1]; n1.Z() = originalNormals[3*v+2]; norm1 = (Real) n1.GetNorm(); if (norm1 != 0.0) { n1.X() /= norm1; n1.Y() /= norm1; n1.Z() /= norm1; } SphereToCube(n1.X(), n1.Y(), n1.Z(), na1, nb1, ni1); m_predictors.PushBack(ni1 - ni0); if ( (ni1 >> 1) != (ni0 >> 1) ) { rna0 = (Real)0.0; rnb0 = (Real)0.0; } m_normals[2*v] = na1 - rna0; m_normals[2*v+1] = nb1 - rnb0; #ifdef DEBUG_VERBOSE1 printf("n0 \t %i \t %i \t %i \t %i (%f, %f)\n", i, n0.X(), n0.Y(), n0.Z(), rna0, rnb0); fprintf(g_fileDebugSC3DMCEnc,"n0 \t %i \t %i \t %i \t %i (%f, %f)\n", i, n0.X(), n0.Y(), n0.Z(), rna0, rnb0); #endif //DEBUG_VERBOSE #ifdef DEBUG_VERBOSE1 printf("normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", i, n1.X(), n1.Y(), n1.Z(), ni1, na1, nb1, rna0, rnb0); fprintf(g_fileDebugSC3DMCEnc, "normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", i, n1.X(), n1.Y(), n1.Z(), ni1, na1, nb1, rna0, rnb0); #endif //DEBUG_VERBOSE } return O3DGC_OK; } template O3DGCErrorCode SC3DMCEncoder::EncodePayload(const SC3DMCEncodeParams & params, const IndexedFaceSet & ifs, BinaryStream & bstream) { #ifdef DEBUG_VERBOSE g_fileDebugSC3DMCEnc = fopen("tfans_enc_main.txt", "w"); #endif //DEBUG_VERBOSE // encode triangle list m_triangleListEncoder.SetStreamType(params.GetStreamType()); m_stats.m_streamSizeCoordIndex = bstream.GetSize(); Timer timer; timer.Tic(); m_triangleListEncoder.Encode(ifs.GetCoordIndex(), ifs.GetIndexBufferID(), ifs.GetNCoordIndex(), ifs.GetNCoord(), bstream); timer.Toc(); m_stats.m_timeCoordIndex = timer.GetElapsedTime(); m_stats.m_streamSizeCoordIndex = bstream.GetSize() - m_stats.m_streamSizeCoordIndex; // encode coord m_stats.m_streamSizeCoord = bstream.GetSize(); timer.Tic(); if (ifs.GetNCoord() > 0) { EncodeFloatArray(ifs.GetCoord(), ifs.GetNCoord(), 3, 3, ifs.GetCoordMin(), ifs.GetCoordMax(), params.GetCoordQuantBits(), ifs, params.GetCoordPredMode(), bstream); } timer.Toc(); m_stats.m_timeCoord = timer.GetElapsedTime(); m_stats.m_streamSizeCoord = bstream.GetSize() - m_stats.m_streamSizeCoord; // encode Normal m_stats.m_streamSizeNormal = bstream.GetSize(); timer.Tic(); if (ifs.GetNNormal() > 0) { if (params.GetNormalPredMode() == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION) { ProcessNormals(ifs); EncodeFloatArray(m_normals, ifs.GetNNormal(), 2, 2, ifs.GetNormalMin(), ifs.GetNormalMax(), params.GetNormalQuantBits(), ifs, params.GetNormalPredMode(), bstream); } else { EncodeFloatArray(ifs.GetNormal(), ifs.GetNNormal(), 3, 3, ifs.GetNormalMin(), ifs.GetNormalMax(), params.GetNormalQuantBits(), ifs, params.GetNormalPredMode(), bstream); } } timer.Toc(); m_stats.m_timeNormal = timer.GetElapsedTime(); m_stats.m_streamSizeNormal = bstream.GetSize() - m_stats.m_streamSizeNormal; // encode FloatAttribute for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a) { m_stats.m_streamSizeFloatAttribute[a] = bstream.GetSize(); timer.Tic(); EncodeFloatArray(ifs.GetFloatAttribute(a), ifs.GetNFloatAttribute(a), ifs.GetFloatAttributeDim(a), ifs.GetFloatAttributeDim(a), ifs.GetFloatAttributeMin(a), ifs.GetFloatAttributeMax(a), params.GetFloatAttributeQuantBits(a), ifs, params.GetFloatAttributePredMode(a), bstream); timer.Toc(); m_stats.m_timeFloatAttribute[a] = timer.GetElapsedTime(); m_stats.m_streamSizeFloatAttribute[a] = bstream.GetSize() - m_stats.m_streamSizeFloatAttribute[a]; } // encode IntAttribute for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a) { m_stats.m_streamSizeIntAttribute[a] = bstream.GetSize(); timer.Tic(); EncodeIntArray(ifs.GetIntAttribute(a), ifs.GetNIntAttribute(a), ifs.GetIntAttributeDim(a), ifs.GetIntAttributeDim(a), ifs, params.GetIntAttributePredMode(a), bstream); timer.Toc(); m_stats.m_timeIntAttribute[a] = timer.GetElapsedTime(); m_stats.m_streamSizeIntAttribute[a] = bstream.GetSize() - m_stats.m_streamSizeIntAttribute[a]; } #ifdef DEBUG_VERBOSE fclose(g_fileDebugSC3DMCEnc); #endif //DEBUG_VERBOSE return O3DGC_OK; } } #endif // O3DGC_SC3DMC_ENCODER_INL assimp-4.1.0/contrib/Open3DGC/o3dgcSC3DMCEncodeParams.h0000644002537200234200000002066013213503245022511 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_SC3DMC_ENCODE_PARAMS_H #define O3DGC_SC3DMC_ENCODE_PARAMS_H #include "o3dgcCommon.h" namespace o3dgc { class SC3DMCEncodeParams { public: //! Constructor. SC3DMCEncodeParams(void) { memset(this, 0, sizeof(SC3DMCEncodeParams)); m_encodeMode = O3DGC_SC3DMC_ENCODE_MODE_TFAN; m_streamTypeMode = O3DGC_STREAM_TYPE_ASCII; m_coordQuantBits = 14; m_normalQuantBits = 8; m_coordPredMode = O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION; m_normalPredMode = O3DGC_SC3DMC_SURF_NORMALS_PREDICTION; for(unsigned long a = 0; a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES; ++a) { m_floatAttributePredMode[a] = O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION; } for(unsigned long a = 0; a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES; ++a) { m_intAttributePredMode[a] = O3DGC_SC3DMC_NO_PREDICTION; } }; //! Destructor. ~SC3DMCEncodeParams(void) {}; O3DGCStreamType GetStreamType() const { return m_streamTypeMode;} O3DGCSC3DMCEncodingMode GetEncodeMode() const { return m_encodeMode;} unsigned long GetNumFloatAttributes() const { return m_numFloatAttributes;} unsigned long GetNumIntAttributes() const { return m_numIntAttributes;} unsigned long GetCoordQuantBits() const { return m_coordQuantBits;} unsigned long GetNormalQuantBits() const { return m_normalQuantBits;} unsigned long GetFloatAttributeQuantBits(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return m_floatAttributeQuantBits[a]; } O3DGCSC3DMCPredictionMode GetCoordPredMode() const { return m_coordPredMode; } O3DGCSC3DMCPredictionMode GetNormalPredMode() const { return m_normalPredMode; } O3DGCSC3DMCPredictionMode GetFloatAttributePredMode(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return m_floatAttributePredMode[a]; } O3DGCSC3DMCPredictionMode GetIntAttributePredMode(unsigned long a) const { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); return m_intAttributePredMode[a]; } O3DGCSC3DMCPredictionMode & GetCoordPredMode() { return m_coordPredMode; } O3DGCSC3DMCPredictionMode & GetNormalPredMode() { return m_normalPredMode; } O3DGCSC3DMCPredictionMode & GetFloatAttributePredMode(unsigned long a) { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); return m_floatAttributePredMode[a]; } O3DGCSC3DMCPredictionMode & GetIntAttributePredMode(unsigned long a) { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); return m_intAttributePredMode[a]; } void SetStreamType(O3DGCStreamType streamTypeMode) { m_streamTypeMode = streamTypeMode;} void SetEncodeMode(O3DGCSC3DMCEncodingMode encodeMode) { m_encodeMode = encodeMode;} void SetNumFloatAttributes(unsigned long numFloatAttributes) { assert(numFloatAttributes < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); m_numFloatAttributes = numFloatAttributes; } void SetNumIntAttributes (unsigned long numIntAttributes) { assert(numIntAttributes < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); m_numIntAttributes = numIntAttributes; } void SetCoordQuantBits (unsigned int coordQuantBits ) { m_coordQuantBits = coordQuantBits ; } void SetNormalQuantBits (unsigned int normalQuantBits ) { m_normalQuantBits = normalQuantBits ; } void SetFloatAttributeQuantBits(unsigned long a, unsigned long q) { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); m_floatAttributeQuantBits[a] = q; } void SetCoordPredMode (O3DGCSC3DMCPredictionMode coordPredMode ) { m_coordPredMode = coordPredMode ; } void SetNormalPredMode (O3DGCSC3DMCPredictionMode normalPredMode ) { m_normalPredMode = normalPredMode ; } void SetFloatAttributePredMode(unsigned long a, O3DGCSC3DMCPredictionMode p) { assert(a < O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES); m_floatAttributePredMode[a] = p; } void SetIntAttributePredMode(unsigned long a, O3DGCSC3DMCPredictionMode p) { assert(a < O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES); m_intAttributePredMode[a] = p; } private: unsigned long m_numFloatAttributes; unsigned long m_numIntAttributes; unsigned long m_coordQuantBits; unsigned long m_normalQuantBits; unsigned long m_floatAttributeQuantBits[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; O3DGCSC3DMCPredictionMode m_coordPredMode; O3DGCSC3DMCPredictionMode m_normalPredMode; O3DGCSC3DMCPredictionMode m_floatAttributePredMode[O3DGC_SC3DMC_MAX_NUM_FLOAT_ATTRIBUTES]; O3DGCSC3DMCPredictionMode m_intAttributePredMode [O3DGC_SC3DMC_MAX_NUM_INT_ATTRIBUTES]; O3DGCStreamType m_streamTypeMode; O3DGCSC3DMCEncodingMode m_encodeMode; }; } #endif // O3DGC_SC3DMC_ENCODE_PARAMS_H assimp-4.1.0/contrib/Open3DGC/o3dgcSC3DMCDecoder.inl0000644002537200234200000011131113213503245022042 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_SC3DMC_DECODER_INL #define O3DGC_SC3DMC_DECODER_INL #include "o3dgcArithmeticCodec.h" #include "o3dgcTimer.h" //#define DEBUG_VERBOSE namespace o3dgc { #ifdef DEBUG_VERBOSE FILE * g_fileDebugSC3DMCDec = NULL; #endif //DEBUG_VERBOSE template O3DGCErrorCode SC3DMCDecoder::DecodeHeader(IndexedFaceSet & ifs, const BinaryStream & bstream) { unsigned long iterator0 = m_iterator; unsigned long start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_BINARY); if (start_code != O3DGC_SC3DMC_START_CODE) { m_iterator = iterator0; start_code = bstream.ReadUInt32(m_iterator, O3DGC_STREAM_TYPE_ASCII); if (start_code != O3DGC_SC3DMC_START_CODE) { return O3DGC_ERROR_CORRUPTED_STREAM; } else { m_streamType = O3DGC_STREAM_TYPE_ASCII; } } else { m_streamType = O3DGC_STREAM_TYPE_BINARY; } m_streamSize = bstream.ReadUInt32(m_iterator, m_streamType); m_params.SetEncodeMode( (O3DGCSC3DMCEncodingMode) bstream.ReadUChar(m_iterator, m_streamType)); ifs.SetCreaseAngle((Real) bstream.ReadFloat32(m_iterator, m_streamType)); unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType); ifs.SetCCW ((mask & 1) == 1); ifs.SetSolid ((mask & 2) == 1); ifs.SetConvex ((mask & 4) == 1); ifs.SetIsTriangularMesh((mask & 8) == 1); //bool markerBit0 = (mask & 16 ) == 1; //bool markerBit1 = (mask & 32 ) == 1; //bool markerBit2 = (mask & 64 ) == 1; //bool markerBit3 = (mask & 128) == 1; ifs.SetNCoord (bstream.ReadUInt32(m_iterator, m_streamType)); ifs.SetNNormal (bstream.ReadUInt32(m_iterator, m_streamType)); ifs.SetNumFloatAttributes(bstream.ReadUInt32(m_iterator, m_streamType)); ifs.SetNumIntAttributes (bstream.ReadUInt32(m_iterator, m_streamType)); if (ifs.GetNCoord() > 0) { ifs.SetNCoordIndex(bstream.ReadUInt32(m_iterator, m_streamType)); for(int j=0 ; j<3 ; ++j) { ifs.SetCoordMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); ifs.SetCoordMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); } m_params.SetCoordQuantBits( bstream.ReadUChar(m_iterator, m_streamType) ); } if (ifs.GetNNormal() > 0) { ifs.SetNNormalIndex(bstream.ReadUInt32(m_iterator, m_streamType)); for(int j=0 ; j<3 ; ++j) { ifs.SetNormalMin(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); ifs.SetNormalMax(j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); } ifs.SetNormalPerVertex(bstream.ReadUChar(m_iterator, m_streamType) == 1); m_params.SetNormalQuantBits(bstream.ReadUChar(m_iterator, m_streamType)); } for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a) { ifs.SetNFloatAttribute(a, bstream.ReadUInt32(m_iterator, m_streamType)); if (ifs.GetNFloatAttribute(a) > 0) { ifs.SetNFloatAttributeIndex(a, bstream.ReadUInt32(m_iterator, m_streamType)); unsigned char d = bstream.ReadUChar(m_iterator, m_streamType); ifs.SetFloatAttributeDim(a, d); for(unsigned char j = 0 ; j < d ; ++j) { ifs.SetFloatAttributeMin(a, j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); ifs.SetFloatAttributeMax(a, j, (Real) bstream.ReadFloat32(m_iterator, m_streamType)); } ifs.SetFloatAttributePerVertex(a, bstream.ReadUChar(m_iterator, m_streamType) == 1); ifs.SetFloatAttributeType(a, (O3DGCIFSFloatAttributeType) bstream.ReadUChar(m_iterator, m_streamType)); m_params.SetFloatAttributeQuantBits(a, bstream.ReadUChar(m_iterator, m_streamType)); } } for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a) { ifs.SetNIntAttribute(a, bstream.ReadUInt32(m_iterator, m_streamType)); if (ifs.GetNIntAttribute(a) > 0) { ifs.SetNIntAttributeIndex(a, bstream.ReadUInt32(m_iterator, m_streamType)); ifs.SetIntAttributeDim(a, bstream.ReadUChar(m_iterator, m_streamType)); ifs.SetIntAttributePerVertex(a, bstream.ReadUChar(m_iterator, m_streamType) == 1); ifs.SetIntAttributeType(a, (O3DGCIFSIntAttributeType) bstream.ReadUChar(m_iterator, m_streamType)); } } return O3DGC_OK; } template O3DGCErrorCode SC3DMCDecoder::DecodePayload(IndexedFaceSet & ifs, const BinaryStream & bstream) { O3DGCErrorCode ret = O3DGC_OK; #ifdef DEBUG_VERBOSE g_fileDebugSC3DMCDec = fopen("tfans_dec_main.txt", "w"); #endif //DEBUG_VERBOSE m_triangleListDecoder.SetStreamType(m_streamType); m_stats.m_streamSizeCoordIndex = m_iterator; Timer timer; timer.Tic(); m_triangleListDecoder.Decode(ifs.GetCoordIndex(), ifs.GetNCoordIndex(), ifs.GetNCoord(), bstream, m_iterator); timer.Toc(); m_stats.m_timeCoordIndex = timer.GetElapsedTime(); m_stats.m_streamSizeCoordIndex = m_iterator - m_stats.m_streamSizeCoordIndex; // decode coord m_stats.m_streamSizeCoord = m_iterator; timer.Tic(); if (ifs.GetNCoord() > 0) { ret = DecodeFloatArray(ifs.GetCoord(), ifs.GetNCoord(), 3, 3, ifs.GetCoordMin(), ifs.GetCoordMax(), m_params.GetCoordQuantBits(), ifs, m_params.GetCoordPredMode(), bstream); } if (ret != O3DGC_OK) { return ret; } timer.Toc(); m_stats.m_timeCoord = timer.GetElapsedTime(); m_stats.m_streamSizeCoord = m_iterator - m_stats.m_streamSizeCoord; // decode Normal m_stats.m_streamSizeNormal = m_iterator; timer.Tic(); if (ifs.GetNNormal() > 0) { DecodeFloatArray(ifs.GetNormal(), ifs.GetNNormal(), 3, 3, ifs.GetNormalMin(), ifs.GetNormalMax(), m_params.GetNormalQuantBits(), ifs, m_params.GetNormalPredMode(), bstream); } if (ret != O3DGC_OK) { return ret; } timer.Toc(); m_stats.m_timeNormal = timer.GetElapsedTime(); m_stats.m_streamSizeNormal = m_iterator - m_stats.m_streamSizeNormal; // decode FloatAttributes for(unsigned long a = 0; a < ifs.GetNumFloatAttributes(); ++a) { m_stats.m_streamSizeFloatAttribute[a] = m_iterator; timer.Tic(); DecodeFloatArray(ifs.GetFloatAttribute(a), ifs.GetNFloatAttribute(a), ifs.GetFloatAttributeDim(a), ifs.GetFloatAttributeDim(a), ifs.GetFloatAttributeMin(a), ifs.GetFloatAttributeMax(a), m_params.GetFloatAttributeQuantBits(a), ifs, m_params.GetFloatAttributePredMode(a), bstream); timer.Toc(); m_stats.m_timeFloatAttribute[a] = timer.GetElapsedTime(); m_stats.m_streamSizeFloatAttribute[a] = m_iterator - m_stats.m_streamSizeFloatAttribute[a]; } if (ret != O3DGC_OK) { return ret; } // decode IntAttributes for(unsigned long a = 0; a < ifs.GetNumIntAttributes(); ++a) { m_stats.m_streamSizeIntAttribute[a] = m_iterator; timer.Tic(); DecodeIntArray(ifs.GetIntAttribute(a), ifs.GetNIntAttribute(a), ifs.GetIntAttributeDim(a), ifs.GetIntAttributeDim(a), ifs, m_params.GetIntAttributePredMode(a), bstream); timer.Toc(); m_stats.m_timeIntAttribute[a] = timer.GetElapsedTime(); m_stats.m_streamSizeIntAttribute[a] = m_iterator - m_stats.m_streamSizeIntAttribute[a]; } if (ret != O3DGC_OK) { return ret; } timer.Tic(); m_triangleListDecoder.Reorder(); timer.Toc(); m_stats.m_timeReorder = timer.GetElapsedTime(); #ifdef DEBUG_VERBOSE fclose(g_fileDebugSC3DMCDec); #endif //DEBUG_VERBOSE return ret; } template O3DGCErrorCode SC3DMCDecoder::DecodeIntArray(long * const intArray, unsigned long numIntArray, unsigned long dimIntArray, unsigned long stride, const IndexedFaceSet & ifs, O3DGCSC3DMCPredictionMode & predMode, const BinaryStream & bstream) { assert(dimIntArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); long predResidual; SC3DMCPredictor m_neighbors [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS]; Arithmetic_Codec acd; Static_Bit_Model bModel0; Adaptive_Bit_Model bModel1; Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1); unsigned long nPred; const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle(); const T * const triangles = ifs.GetCoordIndex(); const long nvert = (long) numIntArray; unsigned char * buffer = 0; unsigned long start = m_iterator; unsigned long streamSize = bstream.ReadUInt32(m_iterator, m_streamType); // bitsream size unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType); O3DGCSC3DMCBinarization binarization = (O3DGCSC3DMCBinarization)((mask >> 4) & 7); predMode = (O3DGCSC3DMCPredictionMode)(mask & 7); streamSize -= (m_iterator - start); unsigned long iteratorPred = m_iterator + streamSize; unsigned int exp_k = 0; unsigned int M = 0; if (m_streamType != O3DGC_STREAM_TYPE_ASCII) { if (binarization != O3DGC_SC3DMC_BINARIZATION_AC_EGC) { return O3DGC_ERROR_CORRUPTED_STREAM; } bstream.GetBuffer(m_iterator, buffer); m_iterator += streamSize; acd.set_buffer(streamSize, buffer); acd.start_decoder(); exp_k = acd.ExpGolombDecode(0, bModel0, bModel1); M = acd.ExpGolombDecode(0, bModel0, bModel1); } else { if (binarization != O3DGC_SC3DMC_BINARIZATION_ASCII) { return O3DGC_ERROR_CORRUPTED_STREAM; } bstream.ReadUInt32(iteratorPred, m_streamType); // predictors bitsream size } Adaptive_Data_Model mModelValues(M+2); #ifdef DEBUG_VERBOSE printf("IntArray (%i, %i)\n", numIntArray, dimIntArray); fprintf(g_fileDebugSC3DMCDec, "IntArray (%i, %i)\n", numIntArray, dimIntArray); #endif //DEBUG_VERBOSE for (long v=0; v < nvert; ++v) { nPred = 0; if ( v2T.GetNumNeighbors(v) > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION) { int u0 = v2T.Begin(v); int u1 = v2T.End(v); for (long u = u0; u < u1; u++) { long ta = v2T.GetNeighbor(u); if (ta < 0) { break; } for(long k = 0; k < 3; ++k) { long w = triangles[ta*3 + k]; if ( w < v ) { SC3DMCTriplet id = {-1, -1, w}; unsigned long p = Insert(id, nPred, m_neighbors); if (p != 0xFFFFFFFF) { for (unsigned long i = 0; i < dimIntArray; i++) { m_neighbors[p].m_pred[i] = intArray[w*stride+i]; } } } } } } if (nPred > 1) { #ifdef DEBUG_VERBOSE1 printf("\t\t vm %i\n", v); fprintf(g_fileDebugSC3DMCDec, "\t\t vm %i\n", v); for (unsigned long p = 0; p < nPred; ++p) { printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); fprintf(g_fileDebugSC3DMCDec, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); for (unsigned long i = 0; i < dimIntArray; ++i) { printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]); fprintf(g_fileDebugSC3DMCDec, "\t\t\t %i\n", m_neighbors[p].m_pred[i]); } } #endif //DEBUG_VERBOSE unsigned long bestPred; if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { bestPred = bstream.ReadUCharASCII(iteratorPred); } else { bestPred = acd.decode(mModelPreds); } #ifdef DEBUG_VERBOSE1 printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); fprintf(g_fileDebugSC3DMCDec, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); #endif //DEBUG_VERBOSE for (unsigned long i = 0; i < dimIntArray; i++) { if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { predResidual = bstream.ReadIntASCII(m_iterator); } else { predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); } intArray[v*stride+i] = predResidual + m_neighbors[bestPred].m_pred[i]; #ifdef DEBUG_VERBOSE printf("%i \t %i \t [%i]\n", v*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); fprintf(g_fileDebugSC3DMCDec, "%i \t %i \t [%i]\n", v*dimIntArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); #endif //DEBUG_VERBOSE } } else if (v > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION) { for (unsigned long i = 0; i < dimIntArray; i++) { if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { predResidual = bstream.ReadIntASCII(m_iterator); } else { predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); } intArray[v*stride+i] = predResidual + intArray[(v-1)*stride+i]; #ifdef DEBUG_VERBOSE printf("%i \t %i\n", v*dimIntArray+i, predResidual); fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimIntArray+i, predResidual); #endif //DEBUG_VERBOSE } } else { for (unsigned long i = 0; i < dimIntArray; i++) { if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { predResidual = bstream.ReadUIntASCII(m_iterator); } else { predResidual = DecodeUIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); } intArray[v*stride+i] = predResidual; #ifdef DEBUG_VERBOSE printf("%i \t %i\n", v*dimIntArray+i, predResidual); fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimIntArray+i, predResidual); #endif //DEBUG_VERBOSE } } } m_iterator = iteratorPred; #ifdef DEBUG_VERBOSE fflush(g_fileDebugSC3DMCDec); #endif //DEBUG_VERBOSE return O3DGC_OK; } template O3DGCErrorCode SC3DMCDecoder::ProcessNormals(const IndexedFaceSet & ifs) { const long nvert = (long) ifs.GetNNormal(); const unsigned long normalSize = ifs.GetNNormal() * 2; if (m_normalsSize < normalSize) { delete [] m_normals; m_normalsSize = normalSize; m_normals = new Real [normalSize]; } const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle(); const T * const triangles = ifs.GetCoordIndex(); Vec3 p1, p2, p3, n0, nt; long na0 = 0, nb0 = 0; Real rna0, rnb0, norm0; char ni0 = 0, ni1 = 0; long a, b, c; for (long v=0; v < nvert; ++v) { n0.X() = 0; n0.Y() = 0; n0.Z() = 0; int u0 = v2T.Begin(v); int u1 = v2T.End(v); for (long u = u0; u < u1; u++) { long ta = v2T.GetNeighbor(u); if (ta == -1) { break; } a = triangles[ta*3 + 0]; b = triangles[ta*3 + 1]; c = triangles[ta*3 + 2]; p1.X() = m_quantFloatArray[3*a]; p1.Y() = m_quantFloatArray[3*a+1]; p1.Z() = m_quantFloatArray[3*a+2]; p2.X() = m_quantFloatArray[3*b]; p2.Y() = m_quantFloatArray[3*b+1]; p2.Z() = m_quantFloatArray[3*b+2]; p3.X() = m_quantFloatArray[3*c]; p3.Y() = m_quantFloatArray[3*c+1]; p3.Z() = m_quantFloatArray[3*c+2]; nt = (p2-p1)^(p3-p1); n0 += nt; } norm0 = (Real) n0.GetNorm(); if (norm0 == 0.0) { norm0 = 1.0; } SphereToCube(n0.X(), n0.Y(), n0.Z(), na0, nb0, ni0); rna0 = na0 / norm0; rnb0 = nb0 / norm0; ni1 = ni0 + m_orientation[v]; m_orientation[v] = ni1; if ( (ni1 >> 1) != (ni0 >> 1) ) { rna0 = Real(0.0); rnb0 = Real(0.0); } m_normals[2*v] = rna0; m_normals[2*v+1] = rnb0; #ifdef DEBUG_VERBOSE1 printf("n0 \t %i \t %i \t %i \t %i (%f, %f)\n", v, n0.X(), n0.Y(), n0.Z(), rna0, rnb0); fprintf(g_fileDebugSC3DMCDec, "n0 \t %i \t %i \t %i \t %i (%f, %f)\n", v, n0.X(), n0.Y(), n0.Z(), rna0, rnb0); #endif //DEBUG_VERBOSE } return O3DGC_OK; } template O3DGCErrorCode SC3DMCDecoder::DecodeFloatArray(Real * const floatArray, unsigned long numFloatArray, unsigned long dimFloatArray, unsigned long stride, const Real * const minFloatArray, const Real * const maxFloatArray, unsigned long nQBits, const IndexedFaceSet & ifs, O3DGCSC3DMCPredictionMode & predMode, const BinaryStream & bstream) { assert(dimFloatArray < O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES); long predResidual; SC3DMCPredictor m_neighbors [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS]; Arithmetic_Codec acd; Static_Bit_Model bModel0; Adaptive_Bit_Model bModel1; Adaptive_Data_Model mModelPreds(O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS+1); unsigned long nPred; const AdjacencyInfo & v2T = m_triangleListDecoder.GetVertexToTriangle(); const T * const triangles = ifs.GetCoordIndex(); const long nvert = (long) numFloatArray; const unsigned long size = numFloatArray * dimFloatArray; unsigned char * buffer = 0; unsigned long start = m_iterator; unsigned long streamSize = bstream.ReadUInt32(m_iterator, m_streamType); // bitsream size unsigned char mask = bstream.ReadUChar(m_iterator, m_streamType); O3DGCSC3DMCBinarization binarization = (O3DGCSC3DMCBinarization)((mask >> 4) & 7); predMode = (O3DGCSC3DMCPredictionMode)(mask & 7); streamSize -= (m_iterator - start); unsigned long iteratorPred = m_iterator + streamSize; unsigned int exp_k = 0; unsigned int M = 0; if (m_streamType != O3DGC_STREAM_TYPE_ASCII) { if (binarization != O3DGC_SC3DMC_BINARIZATION_AC_EGC) { return O3DGC_ERROR_CORRUPTED_STREAM; } bstream.GetBuffer(m_iterator, buffer); m_iterator += streamSize; acd.set_buffer(streamSize, buffer); acd.start_decoder(); exp_k = acd.ExpGolombDecode(0, bModel0, bModel1); M = acd.ExpGolombDecode(0, bModel0, bModel1); } else { if (binarization != O3DGC_SC3DMC_BINARIZATION_ASCII) { return O3DGC_ERROR_CORRUPTED_STREAM; } bstream.ReadUInt32(iteratorPred, m_streamType); // predictors bitsream size } Adaptive_Data_Model mModelValues(M+2); if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION) { m_orientation.Allocate(size); m_orientation.Clear(); if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { for(unsigned long i = 0; i < numFloatArray; ++i) { m_orientation.PushBack((unsigned char) bstream.ReadIntASCII(m_iterator)); } } else { Adaptive_Data_Model dModel(12); for(unsigned long i = 0; i < numFloatArray; ++i) { m_orientation.PushBack((unsigned char) UIntToInt(acd.decode(dModel))); } } ProcessNormals(ifs); dimFloatArray = 2; } #ifdef DEBUG_VERBOSE printf("FloatArray (%i, %i)\n", numFloatArray, dimFloatArray); fprintf(g_fileDebugSC3DMCDec, "FloatArray (%i, %i)\n", numFloatArray, dimFloatArray); #endif //DEBUG_VERBOSE if (m_quantFloatArraySize < size) { delete [] m_quantFloatArray; m_quantFloatArraySize = size; m_quantFloatArray = new long [size]; } for (long v=0; v < nvert; ++v) { nPred = 0; if ( v2T.GetNumNeighbors(v) > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION) { int u0 = v2T.Begin(v); int u1 = v2T.End(v); for (long u = u0; u < u1; u++) { long ta = v2T.GetNeighbor(u); if (ta < 0) { break; } if (predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION) { long a,b; if ((long) triangles[ta*3] == v) { a = triangles[ta*3 + 1]; b = triangles[ta*3 + 2]; } else if ((long)triangles[ta*3 + 1] == v) { a = triangles[ta*3 + 0]; b = triangles[ta*3 + 2]; } else { a = triangles[ta*3 + 0]; b = triangles[ta*3 + 1]; } if ( a < v && b < v) { int u0 = v2T.Begin(a); int u1 = v2T.End(a); for (long u = u0; u < u1; u++) { long tb = v2T.GetNeighbor(u); if (tb < 0) { break; } long c = -1; bool foundB = false; for(long k = 0; k < 3; ++k) { long x = triangles[tb*3 + k]; if (x == b) { foundB = true; } if (x < v && x != a && x != b) { c = x; } } if (c != -1 && foundB) { SC3DMCTriplet id = {min(a, b), max(a, b), -c-1}; unsigned long p = Insert(id, nPred, m_neighbors); if (p != 0xFFFFFFFF) { for (unsigned long i = 0; i < dimFloatArray; i++) { m_neighbors[p].m_pred[i] = m_quantFloatArray[a*stride+i] + m_quantFloatArray[b*stride+i] - m_quantFloatArray[c*stride+i]; } } } } } } if ( predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION || predMode == O3DGC_SC3DMC_PARALLELOGRAM_PREDICTION || predMode == O3DGC_SC3DMC_DIFFERENTIAL_PREDICTION ) { for(long k = 0; k < 3; ++k) { long w = triangles[ta*3 + k]; if ( w < v ) { SC3DMCTriplet id = {-1, -1, w}; unsigned long p = Insert(id, nPred, m_neighbors); if (p != 0xFFFFFFFF) { for (unsigned long i = 0; i < dimFloatArray; i++) { m_neighbors[p].m_pred[i] = m_quantFloatArray[w*stride+i]; } } } } } } } if (nPred > 1) { #ifdef DEBUG_VERBOSE1 printf("\t\t vm %i\n", v); fprintf(g_fileDebugSC3DMCDec, "\t\t vm %i\n", v); for (unsigned long p = 0; p < nPred; ++p) { printf("\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); fprintf(g_fileDebugSC3DMCDec, "\t\t pred a = %i b = %i c = %i \n", m_neighbors[p].m_id.m_a, m_neighbors[p].m_id.m_b, m_neighbors[p].m_id.m_c); for (unsigned long i = 0; i < dimFloatArray; ++i) { printf("\t\t\t %i\n", m_neighbors[p].m_pred[i]); fprintf(g_fileDebugSC3DMCDec, "\t\t\t %i\n", m_neighbors[p].m_pred[i]); } } #endif //DEBUG_VERBOSE unsigned long bestPred; if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { bestPred = bstream.ReadUCharASCII(iteratorPred); } else { bestPred = acd.decode(mModelPreds); } #ifdef DEBUG_VERBOSE1 printf("best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); fprintf(g_fileDebugSC3DMCDec, "best (%i, %i, %i) \t pos %i\n", m_neighbors[bestPred].m_id.m_a, m_neighbors[bestPred].m_id.m_b, m_neighbors[bestPred].m_id.m_c, bestPred); #endif //DEBUG_VERBOSE for (unsigned long i = 0; i < dimFloatArray; i++) { if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { predResidual = bstream.ReadIntASCII(m_iterator); } else { predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); } m_quantFloatArray[v*stride+i] = predResidual + m_neighbors[bestPred].m_pred[i]; #ifdef DEBUG_VERBOSE printf("%i \t %i \t [%i]\n", v*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); fprintf(g_fileDebugSC3DMCDec, "%i \t %i \t [%i]\n", v*dimFloatArray+i, predResidual, m_neighbors[bestPred].m_pred[i]); #endif //DEBUG_VERBOSE } } else if (v > 0 && predMode != O3DGC_SC3DMC_NO_PREDICTION) { for (unsigned long i = 0; i < dimFloatArray; i++) { if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { predResidual = bstream.ReadIntASCII(m_iterator); } else { predResidual = DecodeIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); } m_quantFloatArray[v*stride+i] = predResidual + m_quantFloatArray[(v-1)*stride+i]; #ifdef DEBUG_VERBOSE printf("%i \t %i\n", v*dimFloatArray+i, predResidual); fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimFloatArray+i, predResidual); #endif //DEBUG_VERBOSE } } else { for (unsigned long i = 0; i < dimFloatArray; i++) { if (m_streamType == O3DGC_STREAM_TYPE_ASCII) { predResidual = bstream.ReadUIntASCII(m_iterator); } else { predResidual = DecodeUIntACEGC(acd, mModelValues, bModel0, bModel1, exp_k, M); } m_quantFloatArray[v*stride+i] = predResidual; #ifdef DEBUG_VERBOSE printf("%i \t %i\n", v*dimFloatArray+i, predResidual); fprintf(g_fileDebugSC3DMCDec, "%i \t %i\n", v*dimFloatArray+i, predResidual); #endif //DEBUG_VERBOSE } } } m_iterator = iteratorPred; if (predMode == O3DGC_SC3DMC_SURF_NORMALS_PREDICTION) { const Real minNormal[2] = {(Real)(-2),(Real)(-2)}; const Real maxNormal[2] = {(Real)(2),(Real)(2)}; Real na1, nb1; Real na0, nb0; char ni1; IQuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minNormal, maxNormal, nQBits+1); for (long v=0; v < nvert; ++v) { na0 = m_normals[2*v]; nb0 = m_normals[2*v+1]; na1 = floatArray[stride*v] + na0; nb1 = floatArray[stride*v+1] + nb0; ni1 = m_orientation[v]; CubeToSphere(na1, nb1, ni1, floatArray[stride*v], floatArray[stride*v+1], floatArray[stride*v+2]); #ifdef DEBUG_VERBOSE1 printf("normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", v, floatArray[stride*v], floatArray[stride*v+1], floatArray[stride*v+2], ni1, na1, nb1, na0, nb0); fprintf(g_fileDebugSC3DMCDec, "normal \t %i \t %f \t %f \t %f \t (%i, %f, %f) \t (%f, %f)\n", v, floatArray[stride*v], floatArray[stride*v+1], floatArray[stride*v+2], ni1, na1, nb1, na0, nb0); #endif //DEBUG_VERBOSE } } else { IQuantizeFloatArray(floatArray, numFloatArray, dimFloatArray, stride, minFloatArray, maxFloatArray, nQBits); } #ifdef DEBUG_VERBOSE fflush(g_fileDebugSC3DMCDec); #endif //DEBUG_VERBOSE return O3DGC_OK; } template O3DGCErrorCode SC3DMCDecoder::IQuantizeFloatArray(Real * const floatArray, unsigned long numFloatArray, unsigned long dimFloatArray, unsigned long stride, const Real * const minFloatArray, const Real * const maxFloatArray, unsigned long nQBits) { Real idelta[O3DGC_SC3DMC_MAX_DIM_ATTRIBUTES]; Real r; for(unsigned long d = 0; d < dimFloatArray; d++) { r = maxFloatArray[d] - minFloatArray[d]; if (r > 0.0f) { idelta[d] = r/(float)((1 << nQBits) - 1); } else { idelta[d] = 1.0f; } } for(unsigned long v = 0; v < numFloatArray; ++v) { for(unsigned long d = 0; d < dimFloatArray; ++d) { // floatArray[v * stride + d] = m_quantFloatArray[v * stride + d]; floatArray[v * stride + d] = m_quantFloatArray[v * stride + d] * idelta[d] + minFloatArray[d]; } } return O3DGC_OK; } } #endif // O3DGC_SC3DMC_DECODER_INL assimp-4.1.0/contrib/Open3DGC/o3dgcAdjacencyInfo.h0000644002537200234200000001752113213503245022012 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_ADJACENCY_INFO_H #define O3DGC_ADJACENCY_INFO_H #include "o3dgcCommon.h" namespace o3dgc { const long O3DGC_MIN_NEIGHBORS_SIZE = 128; const long O3DGC_MIN_NUM_NEIGHBORS_SIZE = 16; //! class AdjacencyInfo { public: //! Constructor. AdjacencyInfo(long numNeighborsSize = O3DGC_MIN_NUM_NEIGHBORS_SIZE, long neighborsSize = O3DGC_MIN_NUM_NEIGHBORS_SIZE) { m_numElements = 0; m_neighborsSize = neighborsSize; m_numNeighborsSize = numNeighborsSize; m_numNeighbors = new long [m_numNeighborsSize]; m_neighbors = new long [m_neighborsSize ]; }; //! Destructor. ~AdjacencyInfo(void) { delete [] m_neighbors; delete [] m_numNeighbors; }; O3DGCErrorCode Allocate(long numNeighborsSize, long neighborsSize) { m_numElements = numNeighborsSize; if (neighborsSize > m_neighborsSize) { delete [] m_numNeighbors; m_neighborsSize = neighborsSize; m_numNeighbors = new long [m_numNeighborsSize]; } if (numNeighborsSize > m_numNeighborsSize) { delete [] m_neighbors; m_numNeighborsSize = numNeighborsSize; m_neighbors = new long [m_neighborsSize]; } return O3DGC_OK; } O3DGCErrorCode AllocateNumNeighborsArray(long numElements) { if (numElements > m_numNeighborsSize) { delete [] m_numNeighbors; m_numNeighborsSize = numElements; m_numNeighbors = new long [m_numNeighborsSize]; } m_numElements = numElements; return O3DGC_OK; } O3DGCErrorCode AllocateNeighborsArray() { for(long i = 1; i < m_numElements; ++i) { m_numNeighbors[i] += m_numNeighbors[i-1]; } if (m_numNeighbors[m_numElements-1] > m_neighborsSize) { delete [] m_neighbors; m_neighborsSize = m_numNeighbors[m_numElements-1]; m_neighbors = new long [m_neighborsSize]; } return O3DGC_OK; } O3DGCErrorCode ClearNumNeighborsArray() { memset(m_numNeighbors, 0x00, sizeof(long) * m_numElements); return O3DGC_OK; } O3DGCErrorCode ClearNeighborsArray() { memset(m_neighbors, 0xFF, sizeof(long) * m_neighborsSize); return O3DGC_OK; } O3DGCErrorCode AddNeighbor(long element, long neighbor) { assert(m_numNeighbors[element] <= m_numNeighbors[m_numElements-1]); long p0 = Begin(element); long p1 = End(element); for(long p = p0; p < p1; p++) { if (m_neighbors[p] == -1) { m_neighbors[p] = neighbor; return O3DGC_OK; } } return O3DGC_ERROR_BUFFER_FULL; } long Begin(long element) const { assert(element < m_numElements); assert(element >= 0); return (element>0)?m_numNeighbors[element-1]:0; } long End(long element) const { assert(element < m_numElements); assert(element >= 0); return m_numNeighbors[element]; } long GetNeighbor(long element) const { assert(element < m_neighborsSize); assert(element >= 0); return m_neighbors[element]; } long GetNumNeighbors(long element) const { return End(element) - Begin(element); } long * GetNumNeighborsBuffer() { return m_numNeighbors;} long * GetNeighborsBuffer() { return m_neighbors;} private: long m_neighborsSize; // actual allocated size for m_neighbors long m_numNeighborsSize; // actual allocated size for m_numNeighbors long m_numElements; // number of elements long * m_neighbors; // long * m_numNeighbors; // }; } #endif // O3DGC_ADJACENCY_INFO_H assimp-4.1.0/contrib/Open3DGC/o3dgcArithmeticCodec.h0000644002537200234200000003372413213503245022347 0ustar zmoelnigiemusers/* Copyright (c) 2004 Amir Said (said@ieee.org) & William A. Pearlman (pearlw@ecse.rpi.edu) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // **************************** - // ARITHMETIC CODING EXAMPLES - // **************************** - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // Fast arithmetic coding implementation - // -> 32-bit variables, 32-bit product, periodic updates, table decoding - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // Version 1.00 - April 25, 2004 - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // WARNING - // ========= - // - // The only purpose of this program is to demonstrate the basic principles - // of arithmetic coding. It is provided as is, without any express or - // implied warranty, without even the warranty of fitness for any particular - // purpose, or that the implementations are correct. - // - // Permission to copy and redistribute this code is hereby granted, provided - // that this warning and copyright notices are not removed or altered. - // - // Copyright (c) 2004 by Amir Said (said@ieee.org) & - // William A. Pearlman (pearlw@ecse.rpi.edu) - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // A description of the arithmetic coding method used here is available in - // - // Lossless Compression Handbook, ed. K. Sayood - // Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 - // - // A. Said, Introduction to Arithetic Coding Theory and Practice - // HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - Definitions - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #ifndef O3DGC_ARITHMETIC_CODEC #define O3DGC_ARITHMETIC_CODEC #include #include "o3dgcCommon.h" namespace o3dgc { // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - Class definitions - - - - - - - - - - - - - - - - - - - - - - - - - - - class Static_Bit_Model // static model for binary data { public: Static_Bit_Model(void); void set_probability_0(double); // set probability of symbol '0' private: // . . . . . . . . . . . . . . . . . . . . . . unsigned bit_0_prob; friend class Arithmetic_Codec; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class Static_Data_Model // static model for general data { public: Static_Data_Model(void); ~Static_Data_Model(void); unsigned model_symbols(void) { return data_symbols; } void set_distribution(unsigned number_of_symbols, const double probability[] = 0); // 0 means uniform private: // . . . . . . . . . . . . . . . . . . . . . . unsigned * distribution, * decoder_table; unsigned data_symbols, last_symbol, table_size, table_shift; friend class Arithmetic_Codec; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class Adaptive_Bit_Model // adaptive model for binary data { public: Adaptive_Bit_Model(void); void reset(void); // reset to equiprobable model private: // . . . . . . . . . . . . . . . . . . . . . . void update(void); unsigned update_cycle, bits_until_update; unsigned bit_0_prob, bit_0_count, bit_count; friend class Arithmetic_Codec; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - class Adaptive_Data_Model // adaptive model for binary data { public: Adaptive_Data_Model(void); Adaptive_Data_Model(unsigned number_of_symbols); ~Adaptive_Data_Model(void); unsigned model_symbols(void) { return data_symbols; } void reset(void); // reset to equiprobable model void set_alphabet(unsigned number_of_symbols); private: // . . . . . . . . . . . . . . . . . . . . . . void update(bool); unsigned * distribution, * symbol_count, * decoder_table; unsigned total_count, update_cycle, symbols_until_update; unsigned data_symbols, last_symbol, table_size, table_shift; friend class Arithmetic_Codec; }; // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - Encoder and decoder class - - - - - - - - - - - - - - - - - - - - - - - // Class with both the arithmetic encoder and decoder. All compressed data is // saved to a memory buffer class Arithmetic_Codec { public: Arithmetic_Codec(void); ~Arithmetic_Codec(void); Arithmetic_Codec(unsigned max_code_bytes, unsigned char * user_buffer = 0); // 0 = assign new unsigned char * buffer(void) { return code_buffer; } void set_buffer(unsigned max_code_bytes, unsigned char * user_buffer = 0); // 0 = assign new void start_encoder(void); void start_decoder(void); void read_from_file(FILE * code_file); // read code data, start decoder unsigned stop_encoder(void); // returns number of bytes used unsigned write_to_file(FILE * code_file); // stop encoder, write code data void stop_decoder(void); void put_bit(unsigned bit); unsigned get_bit(void); void put_bits(unsigned data, unsigned number_of_bits); unsigned get_bits(unsigned number_of_bits); void encode(unsigned bit, Static_Bit_Model &); unsigned decode(Static_Bit_Model &); void encode(unsigned data, Static_Data_Model &); unsigned decode(Static_Data_Model &); void encode(unsigned bit, Adaptive_Bit_Model &); unsigned decode(Adaptive_Bit_Model &); void encode(unsigned data, Adaptive_Data_Model &); unsigned decode(Adaptive_Data_Model &); // This section was added by K. Mammou void ExpGolombEncode(unsigned int symbol, int k, Static_Bit_Model & bModel0, Adaptive_Bit_Model & bModel1) { while(1) { if (symbol >= (unsigned int)(1<>k)&1), bModel0); } break; } } } unsigned ExpGolombDecode(int k, Static_Bit_Model & bModel0, Adaptive_Bit_Model & bModel1) { unsigned int l; int symbol = 0; int binary_symbol = 0; do { l=decode(bModel1); if (l==1) { symbol += (1< 1); const long size1 = size - 1; long p = 2; data[0] += data[1] >> 1; while(p < size1) { data[p] += (data[p-1] + data[p+1] + 2) >> 2; p += 2; } if ( p == size1) { data[p] += data[p-1]>>1; } return O3DGC_OK; } inline O3DGCErrorCode Predict(long * const data, const long size) { assert(size > 1); const long size1 = size - 1; long p = 1; while(p < size1) { data[p] -= (data[p-1] + data[p+1] + 1) >> 1; p += 2; } if ( p == size1) { data[p] -= data[p-1]; } return O3DGC_OK; } inline O3DGCErrorCode Split(long * const data, const long size) { assert(size > 1); long a = 1; long b = size-1; while (a < b) { for (long i = a; i < b; i += 2) { swap(data[i], data[i+1]); } ++a; --b; } return O3DGC_OK; } inline O3DGCErrorCode Transform(long * const data, const unsigned long size) { unsigned long n = size; while(n > 1) { Predict(data, n); Update (data, n); Split(data, n); n = (n >> 1) + (n & 1); } return O3DGC_OK; } DynamicVectorEncoder::DynamicVectorEncoder(void) { m_maxNumVectors = 0; m_numVectors = 0; m_dimVectors = 0; m_quantVectors = 0; m_sizeBufferAC = 0; m_bufferAC = 0; m_posSize = 0; m_streamType = O3DGC_STREAM_TYPE_UNKOWN; } DynamicVectorEncoder::~DynamicVectorEncoder() { delete [] m_quantVectors; delete [] m_bufferAC; } O3DGCErrorCode DynamicVectorEncoder::Encode(const DVEncodeParams & params, const DynamicVector & dynamicVector, BinaryStream & bstream) { assert(params.GetQuantBits() > 0); assert(dynamicVector.GetNVector() > 0); assert(dynamicVector.GetDimVector() > 0); assert(dynamicVector.GetStride() >= dynamicVector.GetDimVector()); assert(dynamicVector.GetVectors() && dynamicVector.GetMin() && dynamicVector.GetMax()); assert(m_streamType != O3DGC_STREAM_TYPE_UNKOWN); // Encode header unsigned long start = bstream.GetSize(); EncodeHeader(params, dynamicVector, bstream); // Encode payload EncodePayload(params, dynamicVector, bstream); bstream.WriteUInt32(m_posSize, bstream.GetSize() - start, m_streamType); return O3DGC_OK; } O3DGCErrorCode DynamicVectorEncoder::EncodeHeader(const DVEncodeParams & params, const DynamicVector & dynamicVector, BinaryStream & bstream) { m_streamType = params.GetStreamType(); bstream.WriteUInt32(O3DGC_DV_START_CODE, m_streamType); m_posSize = bstream.GetSize(); bstream.WriteUInt32(0, m_streamType); // to be filled later bstream.WriteUChar((unsigned char) params.GetEncodeMode(), m_streamType); bstream.WriteUInt32(dynamicVector.GetNVector() , m_streamType); if (dynamicVector.GetNVector() > 0) { bstream.WriteUInt32(dynamicVector.GetDimVector(), m_streamType); bstream.WriteUChar ((unsigned char) params.GetQuantBits(), m_streamType); } return O3DGC_OK; } O3DGCErrorCode DynamicVectorEncoder::EncodeAC(unsigned long num, unsigned long dim, unsigned long M, unsigned long & encodedBytes) { Arithmetic_Codec ace; Static_Bit_Model bModel0; Adaptive_Bit_Model bModel1; Adaptive_Data_Model mModelValues(M+2); const unsigned int NMAX = num * dim * 8 + 100; if ( m_sizeBufferAC < NMAX ) { delete [] m_bufferAC; m_sizeBufferAC = NMAX; m_bufferAC = new unsigned char [m_sizeBufferAC]; } ace.set_buffer(NMAX, m_bufferAC); ace.start_encoder(); ace.ExpGolombEncode(0, 0, bModel0, bModel1); ace.ExpGolombEncode(M, 0, bModel0, bModel1); for(unsigned long v = 0; v < num; ++v) { for(unsigned long d = 0; d < dim; ++d) { EncodeIntACEGC(m_quantVectors[d * num + v], ace, mModelValues, bModel0, bModel1, M); } } encodedBytes = ace.stop_encoder(); return O3DGC_OK; } O3DGCErrorCode DynamicVectorEncoder::EncodePayload(const DVEncodeParams & params, const DynamicVector & dynamicVector, BinaryStream & bstream) { #ifdef DEBUG_VERBOSE g_fileDebugDVEnc = fopen("dv_enc.txt", "w"); #endif //DEBUG_VERBOSE unsigned long start = bstream.GetSize(); const unsigned long dim = dynamicVector.GetDimVector(); const unsigned long num = dynamicVector.GetNVector(); bstream.WriteUInt32(0, m_streamType); for(unsigned long j=0 ; j bestEncodedBytes) { break; } bestM = M; bestEncodedBytes = encodedBytes; M *= 2; } EncodeAC(num, dim, bestM, encodedBytes); for(unsigned long i = 0; i < encodedBytes; ++i) { bstream.WriteUChar8Bin(m_bufferAC[i]); } } bstream.WriteUInt32(start, bstream.GetSize() - start, m_streamType); #ifdef DEBUG_VERBOSE fclose(g_fileDebugDVEnc); #endif //DEBUG_VERBOSE return O3DGC_OK; } O3DGCErrorCode DynamicVectorEncoder::Quantize(const Real * const floatArray, unsigned long numFloatArray, unsigned long dimFloatArray, unsigned long stride, const Real * const minFloatArray, const Real * const maxFloatArray, unsigned long nQBits) { const unsigned long size = numFloatArray * dimFloatArray; Real r; if (m_maxNumVectors < size) { delete [] m_quantVectors; m_maxNumVectors = size; m_quantVectors = new long [m_maxNumVectors]; } Real delta; for(unsigned long d = 0; d < dimFloatArray; ++d) { r = maxFloatArray[d] - minFloatArray[d]; if (r > 0.0f) { delta = (float)((1 << nQBits) - 1) / r; } else { delta = 1.0f; } for(unsigned long v = 0; v < numFloatArray; ++v) { m_quantVectors[v + d * numFloatArray] = (long)((floatArray[v * stride + d]-minFloatArray[d]) * delta + 0.5f); } } return O3DGC_OK; } } assimp-4.1.0/contrib/Open3DGC/o3dgcVector.inl0000644002537200234200000002161313213503245021107 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_VECTOR_INL #define O3DGC_VECTOR_INL namespace o3dgc { template inline Vec3 operator*(T lhs, const Vec3 & rhs) { return Vec3(lhs * rhs.X(), lhs * rhs.Y(), lhs * rhs.Z()); } template inline T & Vec3::X() { return m_data[0]; } template inline T & Vec3::Y() { return m_data[1]; } template inline T & Vec3::Z() { return m_data[2]; } template inline const T & Vec3::X() const { return m_data[0]; } template inline const T & Vec3::Y() const { return m_data[1]; } template inline const T & Vec3::Z() const { return m_data[2]; } template inline double Vec3::GetNorm() const { double a = (double) (m_data[0]); double b = (double) (m_data[1]); double c = (double) (m_data[2]); return sqrt(a*a+b*b+c*c); } template inline void Vec3::operator= (const Vec3 & rhs) { this->m_data[0] = rhs.m_data[0]; this->m_data[1] = rhs.m_data[1]; this->m_data[2] = rhs.m_data[2]; } template inline void Vec3::operator+=(const Vec3 & rhs) { this->m_data[0] += rhs.m_data[0]; this->m_data[1] += rhs.m_data[1]; this->m_data[2] += rhs.m_data[2]; } template inline void Vec3::operator-=(const Vec3 & rhs) { this->m_data[0] -= rhs.m_data[0]; this->m_data[1] -= rhs.m_data[1]; this->m_data[2] -= rhs.m_data[2]; } template inline void Vec3::operator-=(T a) { this->m_data[0] -= a; this->m_data[1] -= a; this->m_data[2] -= a; } template inline void Vec3::operator+=(T a) { this->m_data[0] += a; this->m_data[1] += a; this->m_data[2] += a; } template inline void Vec3::operator/=(T a) { this->m_data[0] /= a; this->m_data[1] /= a; this->m_data[2] /= a; } template inline void Vec3::operator*=(T a) { this->m_data[0] *= a; this->m_data[1] *= a; this->m_data[2] *= a; } template inline Vec3 Vec3::operator^ (const Vec3 & rhs) const { return Vec3(m_data[1] * rhs.m_data[2] - m_data[2] * rhs.m_data[1], m_data[2] * rhs.m_data[0] - m_data[0] * rhs.m_data[2], m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0]); } template inline T Vec3::operator*(const Vec3 & rhs) const { return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1] + m_data[2] * rhs.m_data[2]); } template inline Vec3 Vec3::operator+(const Vec3 & rhs) const { return Vec3(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1],m_data[2] + rhs.m_data[2]); } template inline Vec3 Vec3::operator-(const Vec3 & rhs) const { return Vec3(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1],m_data[2] - rhs.m_data[2]); } template inline Vec3 Vec3::operator-() const { return Vec3(-m_data[0],-m_data[1],-m_data[2]); } template inline Vec3 Vec3::operator*(T rhs) const { return Vec3(rhs * this->m_data[0], rhs * this->m_data[1], rhs * this->m_data[2]); } template inline Vec3 Vec3::operator/ (T rhs) const { return Vec3(m_data[0] / rhs, m_data[1] / rhs, m_data[2] / rhs); } template inline Vec3::Vec3(T a) { m_data[0] = m_data[1] = m_data[2] = a; } template inline Vec3::Vec3(T x, T y, T z) { m_data[0] = x; m_data[1] = y; m_data[2] = z; } template inline Vec3::Vec3(const Vec3 & rhs) { m_data[0] = rhs.m_data[0]; m_data[1] = rhs.m_data[1]; m_data[2] = rhs.m_data[2]; } template inline Vec3::~Vec3(void){}; template inline Vec3::Vec3() {} template inline Vec2 operator*(T lhs, const Vec2 & rhs) { return Vec2(lhs * rhs.X(), lhs * rhs.Y()); } template inline T & Vec2::X() { return m_data[0]; } template inline T & Vec2::Y() { return m_data[1]; } template inline const T & Vec2::X() const { return m_data[0]; } template inline const T & Vec2::Y() const { return m_data[1]; } template inline double Vec2::GetNorm() const { double a = (double) (m_data[0]); double b = (double) (m_data[1]); return sqrt(a*a+b*b); } template inline void Vec2::operator= (const Vec2 & rhs) { this->m_data[0] = rhs.m_data[0]; this->m_data[1] = rhs.m_data[1]; } template inline void Vec2::operator+=(const Vec2 & rhs) { this->m_data[0] += rhs.m_data[0]; this->m_data[1] += rhs.m_data[1]; } template inline void Vec2::operator-=(const Vec2 & rhs) { this->m_data[0] -= rhs.m_data[0]; this->m_data[1] -= rhs.m_data[1]; } template inline void Vec2::operator-=(T a) { this->m_data[0] -= a; this->m_data[1] -= a; } template inline void Vec2::operator+=(T a) { this->m_data[0] += a; this->m_data[1] += a; } template inline void Vec2::operator/=(T a) { this->m_data[0] /= a; this->m_data[1] /= a; } template inline void Vec2::operator*=(T a) { this->m_data[0] *= a; this->m_data[1] *= a; } template inline T Vec2::operator^ (const Vec2 & rhs) const { return m_data[0] * rhs.m_data[1] - m_data[1] * rhs.m_data[0]; } template inline T Vec2::operator*(const Vec2 & rhs) const { return (m_data[0] * rhs.m_data[0] + m_data[1] * rhs.m_data[1]); } template inline Vec2 Vec2::operator+(const Vec2 & rhs) const { return Vec2(m_data[0] + rhs.m_data[0],m_data[1] + rhs.m_data[1]); } template inline Vec2 Vec2::operator-(const Vec2 & rhs) const { return Vec2(m_data[0] - rhs.m_data[0],m_data[1] - rhs.m_data[1]); } template inline Vec2 Vec2::operator-() const { return Vec2(-m_data[0],-m_data[1]) ; } template inline Vec2 Vec2::operator*(T rhs) const { return Vec2(rhs * this->m_data[0], rhs * this->m_data[1]); } template inline Vec2 Vec2::operator/ (T rhs) const { return Vec2(m_data[0] / rhs, m_data[1] / rhs); } template inline Vec2::Vec2(T a) { m_data[0] = m_data[1] = a; } template inline Vec2::Vec2(T x, T y) { m_data[0] = x; m_data[1] = y; } template inline Vec2::Vec2(const Vec2 & rhs) { m_data[0] = rhs.m_data[0]; m_data[1] = rhs.m_data[1]; } template inline Vec2::~Vec2(void){}; template inline Vec2::Vec2() {} } #endif //O3DGC_VECTOR_INL assimp-4.1.0/contrib/Open3DGC/o3dgcSC3DMCEncoder.h0000644002537200234200000001422413213503245021526 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_SC3DMC_ENCODER_H #define O3DGC_SC3DMC_ENCODER_H #include "o3dgcCommon.h" #include "o3dgcBinaryStream.h" #include "o3dgcIndexedFaceSet.h" #include "o3dgcSC3DMCEncodeParams.h" #include "o3dgcTriangleListEncoder.h" namespace o3dgc { //! template class SC3DMCEncoder { public: //! Constructor. SC3DMCEncoder(void) { m_posSize = 0; m_quantFloatArray = 0; m_quantFloatArraySize = 0; m_sizeBufferAC = 0; m_bufferAC = 0; m_normals = 0; m_normalsSize = 0; m_streamType = O3DGC_STREAM_TYPE_UNKOWN; }; //! Destructor. ~SC3DMCEncoder(void) { delete [] m_normals; delete [] m_quantFloatArray; delete [] m_bufferAC; } //! O3DGCErrorCode Encode(const SC3DMCEncodeParams & params, const IndexedFaceSet & ifs, BinaryStream & bstream); const SC3DMCStats & GetStats() const { return m_stats;} private: O3DGCErrorCode EncodeHeader(const SC3DMCEncodeParams & params, const IndexedFaceSet & ifs, BinaryStream & bstream); O3DGCErrorCode EncodePayload(const SC3DMCEncodeParams & params, const IndexedFaceSet & ifs, BinaryStream & bstream); O3DGCErrorCode EncodeFloatArray(const Real * const floatArray, unsigned long numfloatArray, unsigned long dimfloatArray, unsigned long stride, const Real * const minfloatArray, const Real * const maxfloatArray, unsigned long nQBits, const IndexedFaceSet & ifs, O3DGCSC3DMCPredictionMode predMode, BinaryStream & bstream); O3DGCErrorCode QuantizeFloatArray(const Real * const floatArray, unsigned long numFloatArray, unsigned long dimFloatArray, unsigned long stride, const Real * const minfloatArray, const Real * const maxfloatArray, unsigned long nQBits); O3DGCErrorCode EncodeIntArray(const long * const intArray, unsigned long numIntArray, unsigned long dimIntArray, unsigned long stride, const IndexedFaceSet & ifs, O3DGCSC3DMCPredictionMode predMode, BinaryStream & bstream); O3DGCErrorCode ProcessNormals(const IndexedFaceSet & ifs); TriangleListEncoder m_triangleListEncoder; long * m_quantFloatArray; unsigned long m_posSize; unsigned long m_quantFloatArraySize; unsigned char * m_bufferAC; unsigned long m_sizeBufferAC; SC3DMCPredictor m_neighbors [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS]; unsigned long m_freqSymbols[O3DGC_SC3DMC_MAX_PREDICTION_SYMBOLS]; unsigned long m_freqPreds [O3DGC_SC3DMC_MAX_PREDICTION_NEIGHBORS]; Vector m_predictors; Real * m_normals; unsigned long m_normalsSize; SC3DMCStats m_stats; O3DGCStreamType m_streamType; }; } #include "o3dgcSC3DMCEncoder.inl" // template implementation #endif // O3DGC_SC3DMC_ENCODER_H assimp-4.1.0/contrib/Open3DGC/o3dgcDynamicVectorDecoder.h0000644002537200234200000000640213213503245023346 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_DYNAMIC_VECTOR_DECODER_H #define O3DGC_DYNAMIC_VECTOR_DECODER_H #include "o3dgcCommon.h" #include "o3dgcBinaryStream.h" #include "o3dgcDVEncodeParams.h" #include "o3dgcDynamicVector.h" namespace o3dgc { //! class DynamicVectorDecoder { public: //! Constructor. DynamicVectorDecoder(void); //! Destructor. ~DynamicVectorDecoder(void); //! //! O3DGCErrorCode DecodeHeader(DynamicVector & dynamicVector, const BinaryStream & bstream); //! O3DGCErrorCode DecodePlayload(DynamicVector & dynamicVector, const BinaryStream & bstream); O3DGCStreamType GetStreamType() const { return m_streamType; } void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; } unsigned long GetIterator() const { return m_iterator;} O3DGCErrorCode SetIterator(unsigned long iterator) { m_iterator = iterator; return O3DGC_OK; } private: O3DGCErrorCode IQuantize(Real * const floatArray, unsigned long numFloatArray, unsigned long dimFloatArray, unsigned long stride, const Real * const minFloatArray, const Real * const maxFloatArray, unsigned long nQBits); unsigned long m_streamSize; unsigned long m_maxNumVectors; unsigned long m_numVectors; unsigned long m_dimVectors; unsigned long m_iterator; long * m_quantVectors; DVEncodeParams m_params; O3DGCStreamType m_streamType; }; } #endif // O3DGC_DYNAMIC_VECTOR_DECODER_H assimp-4.1.0/contrib/Open3DGC/o3dgcArithmeticCodec.cpp0000644002537200234200000010232713213503245022676 0ustar zmoelnigiemusers/* Copyright (c) 2004 Amir Said (said@ieee.org) & William A. Pearlman (pearlw@ecse.rpi.edu) All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // **************************** - // ARITHMETIC CODING EXAMPLES - // **************************** - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // Fast arithmetic coding implementation - // -> 32-bit variables, 32-bit product, periodic updates, table decoding - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // Version 1.00 - April 25, 2004 - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // WARNING - // ========= - // - // The only purpose of this program is to demonstrate the basic principles - // of arithmetic coding. It is provided as is, without any express or - // implied warranty, without even the warranty of fitness for any particular - // purpose, or that the implementations are correct. - // - // Permission to copy and redistribute this code is hereby granted, provided - // that this warning and copyright notices are not removed or altered. - // - // Copyright (c) 2004 by Amir Said (said@ieee.org) & - // William A. Pearlman (pearlw@ecse.rpi.edu) - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - // A description of the arithmetic coding method used here is available in - // - // Lossless Compression Handbook, ed. K. Sayood - // Chapter 5: Arithmetic Coding (A. Said), pp. 101-152, Academic Press, 2003 - // - // A. Said, Introduction to Arithetic Coding Theory and Practice - // HP Labs report HPL-2004-76 - http://www.hpl.hp.com/techreports/ - // - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - Inclusion - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - #include #include "o3dgcArithmeticCodec.h" namespace o3dgc { // - - Constants - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - const unsigned AC__MinLength = 0x01000000U; // threshold for renormalization const unsigned AC__MaxLength = 0xFFFFFFFFU; // maximum AC interval length // Maximum values for binary models const unsigned BM__LengthShift = 13; // length bits discarded before mult. const unsigned BM__MaxCount = 1 << BM__LengthShift; // for adaptive models // Maximum values for general models const unsigned DM__LengthShift = 15; // length bits discarded before mult. const unsigned DM__MaxCount = 1 << DM__LengthShift; // for adaptive models // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - Static functions - - - - - - - - - - - - - - - - - - - - - - - - - - - static void AC_Error(const char * msg) { fprintf(stderr, "\n\n -> Arithmetic coding error: "); fputs(msg, stderr); fputs("\n Execution terminated!\n", stderr); getchar(); exit(1); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - Coding implementations - - - - - - - - - - - - - - - - - - - - - - - - inline void Arithmetic_Codec::propagate_carry(void) { unsigned char * p; // carry propagation on compressed data buffer for (p = ac_pointer - 1; *p == 0xFFU; p--) *p = 0; ++*p; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void Arithmetic_Codec::renorm_enc_interval(void) { do { // output and discard top byte *ac_pointer++ = (unsigned char)(base >> 24); base <<= 8; } while ((length <<= 8) < AC__MinLength); // length multiplied by 256 } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - inline void Arithmetic_Codec::renorm_dec_interval(void) { do { // read least-significant byte value = (value << 8) | unsigned(*++ac_pointer); } while ((length <<= 8) < AC__MinLength); // length multiplied by 256 } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Arithmetic_Codec::put_bit(unsigned bit) { #ifdef _DEBUG if (mode != 1) AC_Error("encoder not initialized"); #endif length >>= 1; // halve interval if (bit) { unsigned init_base = base; base += length; // move base if (init_base > base) propagate_carry(); // overflow = carry } if (length < AC__MinLength) renorm_enc_interval(); // renormalization } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unsigned Arithmetic_Codec::get_bit(void) { #ifdef _DEBUG if (mode != 2) AC_Error("decoder not initialized"); #endif length >>= 1; // halve interval unsigned bit = (value >= length); // decode bit if (bit) value -= length; // move base if (length < AC__MinLength) renorm_dec_interval(); // renormalization return bit; // return data bit value } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Arithmetic_Codec::put_bits(unsigned data, unsigned bits) { #ifdef _DEBUG if (mode != 1) AC_Error("encoder not initialized"); if ((bits < 1) || (bits > 20)) AC_Error("invalid number of bits"); if (data >= (1U << bits)) AC_Error("invalid data"); #endif unsigned init_base = base; base += data * (length >>= bits); // new interval base and length if (init_base > base) propagate_carry(); // overflow = carry if (length < AC__MinLength) renorm_enc_interval(); // renormalization } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unsigned Arithmetic_Codec::get_bits(unsigned bits) { #ifdef _DEBUG if (mode != 2) AC_Error("decoder not initialized"); if ((bits < 1) || (bits > 20)) AC_Error("invalid number of bits"); #endif unsigned s = value / (length >>= bits); // decode symbol, change length value -= length * s; // update interval if (length < AC__MinLength) renorm_dec_interval(); // renormalization return s; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Arithmetic_Codec::encode(unsigned bit, Static_Bit_Model & M) { #ifdef _DEBUG if (mode != 1) AC_Error("encoder not initialized"); #endif unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0 // update interval if (bit == 0) length = x; else { unsigned init_base = base; base += x; length -= x; if (init_base > base) propagate_carry(); // overflow = carry } if (length < AC__MinLength) renorm_enc_interval(); // renormalization } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unsigned Arithmetic_Codec::decode(Static_Bit_Model & M) { #ifdef _DEBUG if (mode != 2) AC_Error("decoder not initialized"); #endif unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0 unsigned bit = (value >= x); // decision // update & shift interval if (bit == 0) length = x; else { value -= x; // shifted interval base = 0 length -= x; } if (length < AC__MinLength) renorm_dec_interval(); // renormalization return bit; // return data bit value } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Arithmetic_Codec::encode(unsigned bit, Adaptive_Bit_Model & M) { #ifdef _DEBUG if (mode != 1) AC_Error("encoder not initialized"); #endif unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0 // update interval if (bit == 0) { length = x; ++M.bit_0_count; } else { unsigned init_base = base; base += x; length -= x; if (init_base > base) propagate_carry(); // overflow = carry } if (length < AC__MinLength) renorm_enc_interval(); // renormalization if (--M.bits_until_update == 0) M.update(); // periodic model update } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unsigned Arithmetic_Codec::decode(Adaptive_Bit_Model & M) { #ifdef _DEBUG if (mode != 2) AC_Error("decoder not initialized"); #endif unsigned x = M.bit_0_prob * (length >> BM__LengthShift); // product l x p0 unsigned bit = (value >= x); // decision // update interval if (bit == 0) { length = x; ++M.bit_0_count; } else { value -= x; length -= x; } if (length < AC__MinLength) renorm_dec_interval(); // renormalization if (--M.bits_until_update == 0) M.update(); // periodic model update return bit; // return data bit value } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Arithmetic_Codec::encode(unsigned data, Static_Data_Model & M) { #ifdef _DEBUG if (mode != 1) AC_Error("encoder not initialized"); if (data >= M.data_symbols) AC_Error("invalid data symbol"); #endif unsigned x, init_base = base; // compute products if (data == M.last_symbol) { x = M.distribution[data] * (length >> DM__LengthShift); base += x; // update interval length -= x; // no product needed } else { x = M.distribution[data] * (length >>= DM__LengthShift); base += x; // update interval length = M.distribution[data+1] * length - x; } if (init_base > base) propagate_carry(); // overflow = carry if (length < AC__MinLength) renorm_enc_interval(); // renormalization } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unsigned Arithmetic_Codec::decode(Static_Data_Model & M) { #ifdef _DEBUG if (mode != 2) AC_Error("decoder not initialized"); #endif unsigned n, s, x, y = length; if (M.decoder_table) { // use table look-up for faster decoding unsigned dv = value / (length >>= DM__LengthShift); unsigned t = dv >> M.table_shift; s = M.decoder_table[t]; // initial decision based on table look-up n = M.decoder_table[t+1] + 1; while (n > s + 1) { // finish with bisection search unsigned m = (s + n) >> 1; if (M.distribution[m] > dv) n = m; else s = m; } // compute products x = M.distribution[s] * length; if (s != M.last_symbol) y = M.distribution[s+1] * length; } else { // decode using only multiplications x = s = 0; length >>= DM__LengthShift; unsigned m = (n = M.data_symbols) >> 1; // decode via bisection search do { unsigned z = length * M.distribution[m]; if (z > value) { n = m; y = z; // value is smaller } else { s = m; x = z; // value is larger or equal } } while ((m = (s + n) >> 1) != s); } value -= x; // update interval length = y - x; if (length < AC__MinLength) renorm_dec_interval(); // renormalization return s; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Arithmetic_Codec::encode(unsigned data, Adaptive_Data_Model & M) { #ifdef _DEBUG if (mode != 1) AC_Error("encoder not initialized"); if (data >= M.data_symbols) { AC_Error("invalid data symbol"); } #endif unsigned x, init_base = base; // compute products if (data == M.last_symbol) { x = M.distribution[data] * (length >> DM__LengthShift); base += x; // update interval length -= x; // no product needed } else { x = M.distribution[data] * (length >>= DM__LengthShift); base += x; // update interval length = M.distribution[data+1] * length - x; } if (init_base > base) propagate_carry(); // overflow = carry if (length < AC__MinLength) renorm_enc_interval(); // renormalization ++M.symbol_count[data]; if (--M.symbols_until_update == 0) M.update(true); // periodic model update } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unsigned Arithmetic_Codec::decode(Adaptive_Data_Model & M) { #ifdef _DEBUG if (mode != 2) AC_Error("decoder not initialized"); #endif unsigned n, s, x, y = length; if (M.decoder_table) { // use table look-up for faster decoding unsigned dv = value / (length >>= DM__LengthShift); unsigned t = dv >> M.table_shift; s = M.decoder_table[t]; // initial decision based on table look-up n = M.decoder_table[t+1] + 1; while (n > s + 1) { // finish with bisection search unsigned m = (s + n) >> 1; if (M.distribution[m] > dv) n = m; else s = m; } // compute products x = M.distribution[s] * length; if (s != M.last_symbol) { y = M.distribution[s+1] * length; } } else { // decode using only multiplications x = s = 0; length >>= DM__LengthShift; unsigned m = (n = M.data_symbols) >> 1; // decode via bisection search do { unsigned z = length * M.distribution[m]; if (z > value) { n = m; y = z; // value is smaller } else { s = m; x = z; // value is larger or equal } } while ((m = (s + n) >> 1) != s); } value -= x; // update interval length = y - x; if (length < AC__MinLength) renorm_dec_interval(); // renormalization ++M.symbol_count[s]; if (--M.symbols_until_update == 0) M.update(false); // periodic model update return s; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - Other Arithmetic_Codec implementations - - - - - - - - - - - - - - - - Arithmetic_Codec::Arithmetic_Codec(void) { mode = buffer_size = 0; new_buffer = code_buffer = 0; } Arithmetic_Codec::Arithmetic_Codec(unsigned max_code_bytes, unsigned char * user_buffer) { mode = buffer_size = 0; new_buffer = code_buffer = 0; set_buffer(max_code_bytes, user_buffer); } Arithmetic_Codec::~Arithmetic_Codec(void) { delete [] new_buffer; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Arithmetic_Codec::set_buffer(unsigned max_code_bytes, unsigned char * user_buffer) { // test for reasonable sizes if (!max_code_bytes)// || (max_code_bytes > 0x10000000U)) // updated by K. Mammou { AC_Error("invalid codec buffer size"); } if (mode != 0) AC_Error("cannot set buffer while encoding or decoding"); if (user_buffer != 0) { // user provides memory buffer buffer_size = max_code_bytes; code_buffer = user_buffer; // set buffer for compressed data delete [] new_buffer; // free anything previously assigned new_buffer = 0; return; } if (max_code_bytes <= buffer_size) return; // enough available buffer_size = max_code_bytes; // assign new memory delete [] new_buffer; // free anything previously assigned if ((new_buffer = new unsigned char[buffer_size+16]) == 0) // 16 extra bytes AC_Error("cannot assign memory for compressed data buffer"); code_buffer = new_buffer; // set buffer for compressed data } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Arithmetic_Codec::start_encoder(void) { if (mode != 0) AC_Error("cannot start encoder"); if (buffer_size == 0) AC_Error("no code buffer set"); mode = 1; base = 0; // initialize encoder variables: interval and pointer length = AC__MaxLength; ac_pointer = code_buffer; // pointer to next data byte } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Arithmetic_Codec::start_decoder(void) { if (mode != 0) AC_Error("cannot start decoder"); if (buffer_size == 0) AC_Error("no code buffer set"); // initialize decoder: interval, pointer, initial code value mode = 2; length = AC__MaxLength; ac_pointer = code_buffer + 3; value = (unsigned(code_buffer[0]) << 24)|(unsigned(code_buffer[1]) << 16) | (unsigned(code_buffer[2]) << 8)| unsigned(code_buffer[3]); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Arithmetic_Codec::read_from_file(FILE * code_file) { unsigned shift = 0, code_bytes = 0; int file_byte; // read variable-length header with number of code bytes do { if ((file_byte = getc(code_file)) == EOF) AC_Error("cannot read code from file"); code_bytes |= unsigned(file_byte & 0x7F) << shift; shift += 7; } while (file_byte & 0x80); // read compressed data if (code_bytes > buffer_size) AC_Error("code buffer overflow"); if (fread(code_buffer, 1, code_bytes, code_file) != code_bytes) AC_Error("cannot read code from file"); start_decoder(); // initialize decoder } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unsigned Arithmetic_Codec::stop_encoder(void) { if (mode != 1) AC_Error("invalid to stop encoder"); mode = 0; unsigned init_base = base; // done encoding: set final data bytes if (length > 2 * AC__MinLength) { base += AC__MinLength; // base offset length = AC__MinLength >> 1; // set new length for 1 more byte } else { base += AC__MinLength >> 1; // base offset length = AC__MinLength >> 9; // set new length for 2 more bytes } if (init_base > base) propagate_carry(); // overflow = carry renorm_enc_interval(); // renormalization = output last bytes unsigned code_bytes = unsigned(ac_pointer - code_buffer); if (code_bytes > buffer_size) AC_Error("code buffer overflow"); return code_bytes; // number of bytes used } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - unsigned Arithmetic_Codec::write_to_file(FILE * code_file) { unsigned header_bytes = 0, code_bytes = stop_encoder(), nb = code_bytes; // write variable-length header with number of code bytes do { int file_byte = int(nb & 0x7FU); if ((nb >>= 7) > 0) file_byte |= 0x80; if (putc(file_byte, code_file) == EOF) AC_Error("cannot write compressed data to file"); header_bytes++; } while (nb); // write compressed data if (fwrite(code_buffer, 1, code_bytes, code_file) != code_bytes) AC_Error("cannot write compressed data to file"); return code_bytes + header_bytes; // bytes used } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Arithmetic_Codec::stop_decoder(void) { if (mode != 2) AC_Error("invalid to stop decoder"); mode = 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - Static bit model implementation - - - - - - - - - - - - - - - - - - - - - Static_Bit_Model::Static_Bit_Model(void) { bit_0_prob = 1U << (BM__LengthShift - 1); // p0 = 0.5 } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Static_Bit_Model::set_probability_0(double p0) { if ((p0 < 0.0001)||(p0 > 0.9999)) AC_Error("invalid bit probability"); bit_0_prob = unsigned(p0 * (1 << BM__LengthShift)); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - Adaptive bit model implementation - - - - - - - - - - - - - - - - - - - - Adaptive_Bit_Model::Adaptive_Bit_Model(void) { reset(); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Adaptive_Bit_Model::reset(void) { // initialization to equiprobable model bit_0_count = 1; bit_count = 2; bit_0_prob = 1U << (BM__LengthShift - 1); update_cycle = bits_until_update = 4; // start with frequent updates } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Adaptive_Bit_Model::update(void) { // halve counts when a threshold is reached if ((bit_count += update_cycle) > BM__MaxCount) { bit_count = (bit_count + 1) >> 1; bit_0_count = (bit_0_count + 1) >> 1; if (bit_0_count == bit_count) ++bit_count; } // compute scaled bit 0 probability unsigned scale = 0x80000000U / bit_count; bit_0_prob = (bit_0_count * scale) >> (31 - BM__LengthShift); // set frequency of model updates update_cycle = (5 * update_cycle) >> 2; if (update_cycle > 64) update_cycle = 64; bits_until_update = update_cycle; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - Static data model implementation - - - - - - - - - - - - - - - - - - - Static_Data_Model::Static_Data_Model(void) { data_symbols = 0; distribution = 0; } Static_Data_Model::~Static_Data_Model(void) { delete [] distribution; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Static_Data_Model::set_distribution(unsigned number_of_symbols, const double probability[]) { if ((number_of_symbols < 2) || (number_of_symbols > (1 << 11))) AC_Error("invalid number of data symbols"); if (data_symbols != number_of_symbols) { // assign memory for data model data_symbols = number_of_symbols; last_symbol = data_symbols - 1; delete [] distribution; // define size of table for fast decoding if (data_symbols > 16) { unsigned table_bits = 3; while (data_symbols > (1U << (table_bits + 2))) ++table_bits; table_size = 1 << table_bits; table_shift = DM__LengthShift - table_bits; distribution = new unsigned[data_symbols+table_size+2]; decoder_table = distribution + data_symbols; } else { // small alphabet: no table needed decoder_table = 0; table_size = table_shift = 0; distribution = new unsigned[data_symbols]; } if (distribution == 0) AC_Error("cannot assign model memory"); } // compute cumulative distribution, decoder table unsigned s = 0; double sum = 0.0, p = 1.0 / double(data_symbols); for (unsigned k = 0; k < data_symbols; k++) { if (probability) p = probability[k]; if ((p < 0.0001) || (p > 0.9999)) AC_Error("invalid symbol probability"); distribution[k] = unsigned(sum * (1 << DM__LengthShift)); sum += p; if (table_size == 0) continue; unsigned w = distribution[k] >> table_shift; while (s < w) decoder_table[++s] = k - 1; } if (table_size != 0) { decoder_table[0] = 0; while (s <= table_size) decoder_table[++s] = data_symbols - 1; } if ((sum < 0.9999) || (sum > 1.0001)) AC_Error("invalid probabilities"); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - Adaptive data model implementation - - - - - - - - - - - - - - - - - - Adaptive_Data_Model::Adaptive_Data_Model(void) { data_symbols = 0; distribution = 0; } Adaptive_Data_Model::Adaptive_Data_Model(unsigned number_of_symbols) { data_symbols = 0; distribution = 0; set_alphabet(number_of_symbols); } Adaptive_Data_Model::~Adaptive_Data_Model(void) { delete [] distribution; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Adaptive_Data_Model::set_alphabet(unsigned number_of_symbols) { if ((number_of_symbols < 2) || (number_of_symbols > (1 << 11))) AC_Error("invalid number of data symbols"); if (data_symbols != number_of_symbols) { // assign memory for data model data_symbols = number_of_symbols; last_symbol = data_symbols - 1; delete [] distribution; // define size of table for fast decoding if (data_symbols > 16) { unsigned table_bits = 3; while (data_symbols > (1U << (table_bits + 2))) ++table_bits; table_size = 1 << table_bits; table_shift = DM__LengthShift - table_bits; distribution = new unsigned[2*data_symbols+table_size+2]; decoder_table = distribution + 2 * data_symbols; } else { // small alphabet: no table needed decoder_table = 0; table_size = table_shift = 0; distribution = new unsigned[2*data_symbols]; } symbol_count = distribution + data_symbols; if (distribution == 0) AC_Error("cannot assign model memory"); } reset(); // initialize model } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Adaptive_Data_Model::update(bool from_encoder) { // halve counts when a threshold is reached if ((total_count += update_cycle) > DM__MaxCount) { total_count = 0; for (unsigned n = 0; n < data_symbols; n++) total_count += (symbol_count[n] = (symbol_count[n] + 1) >> 1); } assert(total_count > 0); // compute cumulative distribution, decoder table unsigned k, sum = 0, s = 0; unsigned scale = 0x80000000U / total_count; if (from_encoder || (table_size == 0)) for (k = 0; k < data_symbols; k++) { distribution[k] = (scale * sum) >> (31 - DM__LengthShift); sum += symbol_count[k]; } else { assert(decoder_table); for (k = 0; k < data_symbols; k++) { distribution[k] = (scale * sum) >> (31 - DM__LengthShift); sum += symbol_count[k]; unsigned w = distribution[k] >> table_shift; while (s < w) decoder_table[++s] = k - 1; } decoder_table[0] = 0; while (s <= table_size) decoder_table[++s] = data_symbols - 1; } // set frequency of model updates update_cycle = (5 * update_cycle) >> 2; unsigned max_cycle = (data_symbols + 6) << 3; if (update_cycle > max_cycle) update_cycle = max_cycle; symbols_until_update = update_cycle; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - void Adaptive_Data_Model::reset(void) { if (data_symbols == 0) return; // restore probability estimates to uniform distribution total_count = 0; update_cycle = data_symbols; for (unsigned k = 0; k < data_symbols; k++) symbol_count[k] = 1; update(false); symbols_until_update = update_cycle = (data_symbols + 6) >> 1; } } /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ assimp-4.1.0/contrib/Open3DGC/o3dgcDVEncodeParams.h0000644002537200234200000000503713213503245022107 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_DV_ENCODE_PARAMS_H #define O3DGC_DV_ENCODE_PARAMS_H #include "o3dgcCommon.h" namespace o3dgc { class DVEncodeParams { public: //! Constructor. DVEncodeParams(void) { m_quantBits = 10; m_streamTypeMode = O3DGC_STREAM_TYPE_ASCII; m_encodeMode = O3DGC_DYNAMIC_VECTOR_ENCODE_MODE_LIFT; }; //! Destructor. ~DVEncodeParams(void) {}; unsigned long GetQuantBits() const { return m_quantBits;} O3DGCStreamType GetStreamType() const { return m_streamTypeMode;} O3DGCDVEncodingMode GetEncodeMode() const { return m_encodeMode;} void SetQuantBits (unsigned long quantBits ) { m_quantBits = quantBits;} void SetStreamType(O3DGCStreamType streamTypeMode) { m_streamTypeMode = streamTypeMode;} void SetEncodeMode(O3DGCDVEncodingMode encodeMode ) { m_encodeMode = encodeMode ;} private: unsigned long m_quantBits; O3DGCStreamType m_streamTypeMode; O3DGCDVEncodingMode m_encodeMode; }; } #endif // O3DGC_DV_ENCODE_PARAMS_H assimp-4.1.0/contrib/Open3DGC/o3dgcTriangleFans.cpp0000644002537200234200000004224713213503245022230 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "o3dgcTriangleFans.h" #include "o3dgcArithmeticCodec.h" //#define DEBUG_VERBOSE namespace o3dgc { #ifdef DEBUG_VERBOSE FILE* g_fileDebugTF = NULL; #endif //DEBUG_VERBOSE O3DGCErrorCode SaveUIntData(const Vector & data, BinaryStream & bstream) { unsigned long start = bstream.GetSize(); bstream.WriteUInt32ASCII(0); const unsigned long size = data.GetSize(); bstream.WriteUInt32ASCII(size); for(unsigned long i = 0; i < size; ++i) { bstream.WriteUIntASCII(data[i]); } bstream.WriteUInt32ASCII(start, bstream.GetSize() - start); return O3DGC_OK; } O3DGCErrorCode SaveIntData(const Vector & data, BinaryStream & bstream) { unsigned long start = bstream.GetSize(); bstream.WriteUInt32ASCII(0); const unsigned long size = data.GetSize(); bstream.WriteUInt32ASCII(size); for(unsigned long i = 0; i < size; ++i) { bstream.WriteIntASCII(data[i]); } bstream.WriteUInt32ASCII(start, bstream.GetSize() - start); return O3DGC_OK; } O3DGCErrorCode SaveBinData(const Vector & data, BinaryStream & bstream) { unsigned long start = bstream.GetSize(); bstream.WriteUInt32ASCII(0); const unsigned long size = data.GetSize(); long symbol; bstream.WriteUInt32ASCII(size); for(unsigned long i = 0; i < size; ) { symbol = 0; for(unsigned long h = 0; h < O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0 && i < size; ++h) { symbol += (data[i] << h); ++i; } bstream.WriteUCharASCII((unsigned char) symbol); } bstream.WriteUInt32ASCII(start, bstream.GetSize() - start); return O3DGC_OK; } O3DGCErrorCode CompressedTriangleFans::SaveUIntAC(const Vector & data, const unsigned long M, BinaryStream & bstream) { unsigned long start = bstream.GetSize(); const unsigned int NMAX = data.GetSize() * 8 + 100; const unsigned long size = data.GetSize(); long minValue = O3DGC_MAX_LONG; bstream.WriteUInt32Bin(0); bstream.WriteUInt32Bin(size); if (size > 0) { #ifdef DEBUG_VERBOSE printf("-----------\nsize %i, start %i\n", size, start); fprintf(g_fileDebugTF, "-----------\nsize %i, start %i\n", size, start); #endif //DEBUG_VERBOSE for(unsigned long i = 0; i < size; ++i) { if (minValue > data[i]) { minValue = data[i]; } #ifdef DEBUG_VERBOSE printf("%i\t%i\n", i, data[i]); fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]); #endif //DEBUG_VERBOSE } bstream.WriteUInt32Bin(minValue); if ( m_sizeBufferAC < NMAX ) { delete [] m_bufferAC; m_sizeBufferAC = NMAX; m_bufferAC = new unsigned char [m_sizeBufferAC]; } Arithmetic_Codec ace; ace.set_buffer(NMAX, m_bufferAC); ace.start_encoder(); Adaptive_Data_Model mModelValues(M+1); for(unsigned long i = 0; i < size; ++i) { ace.encode(data[i]-minValue, mModelValues); } unsigned long encodedBytes = ace.stop_encoder(); for(unsigned long i = 0; i < encodedBytes; ++i) { bstream.WriteUChar8Bin(m_bufferAC[i]); } } bstream.WriteUInt32Bin(start, bstream.GetSize() - start); return O3DGC_OK; } O3DGCErrorCode CompressedTriangleFans::SaveBinAC(const Vector & data, BinaryStream & bstream) { unsigned long start = bstream.GetSize(); const unsigned int NMAX = data.GetSize() * 8 + 100; const unsigned long size = data.GetSize(); bstream.WriteUInt32Bin(0); bstream.WriteUInt32Bin(size); if (size > 0) { if ( m_sizeBufferAC < NMAX ) { delete [] m_bufferAC; m_sizeBufferAC = NMAX; m_bufferAC = new unsigned char [m_sizeBufferAC]; } Arithmetic_Codec ace; ace.set_buffer(NMAX, m_bufferAC); ace.start_encoder(); Adaptive_Bit_Model bModel; #ifdef DEBUG_VERBOSE printf("-----------\nsize %i, start %i\n", size, start); fprintf(g_fileDebugTF, "-----------\nsize %i, start %i\n", size, start); #endif //DEBUG_VERBOSE for(unsigned long i = 0; i < size; ++i) { ace.encode(data[i], bModel); #ifdef DEBUG_VERBOSE printf("%i\t%i\n", i, data[i]); fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]); #endif //DEBUG_VERBOSE } unsigned long encodedBytes = ace.stop_encoder(); for(unsigned long i = 0; i < encodedBytes; ++i) { bstream.WriteUChar8Bin(m_bufferAC[i]); } } bstream.WriteUInt32Bin(start, bstream.GetSize() - start); return O3DGC_OK; } O3DGCErrorCode CompressedTriangleFans::SaveIntACEGC(const Vector & data, const unsigned long M, BinaryStream & bstream) { unsigned long start = bstream.GetSize(); const unsigned int NMAX = data.GetSize() * 8 + 100; const unsigned long size = data.GetSize(); long minValue = 0; bstream.WriteUInt32Bin(0); bstream.WriteUInt32Bin(size); if (size > 0) { #ifdef DEBUG_VERBOSE printf("-----------\nsize %i, start %i\n", size, start); fprintf(g_fileDebugTF, "-----------\nsize %i, start %i\n", size, start); #endif //DEBUG_VERBOSE for(unsigned long i = 0; i < size; ++i) { if (minValue > data[i]) { minValue = data[i]; } #ifdef DEBUG_VERBOSE printf("%i\t%i\n", i, data[i]); fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]); #endif //DEBUG_VERBOSE } bstream.WriteUInt32Bin(minValue + O3DGC_MAX_LONG); if ( m_sizeBufferAC < NMAX ) { delete [] m_bufferAC; m_sizeBufferAC = NMAX; m_bufferAC = new unsigned char [m_sizeBufferAC]; } Arithmetic_Codec ace; ace.set_buffer(NMAX, m_bufferAC); ace.start_encoder(); Adaptive_Data_Model mModelValues(M+2); Static_Bit_Model bModel0; Adaptive_Bit_Model bModel1; unsigned long value; for(unsigned long i = 0; i < size; ++i) { value = data[i]-minValue; if (value < M) { ace.encode(value, mModelValues); } else { ace.encode(M, mModelValues); ace.ExpGolombEncode(value-M, 0, bModel0, bModel1); } } unsigned long encodedBytes = ace.stop_encoder(); for(unsigned long i = 0; i < encodedBytes; ++i) { bstream.WriteUChar8Bin(m_bufferAC[i]); } } bstream.WriteUInt32Bin(start, bstream.GetSize() - start); return O3DGC_OK; } O3DGCErrorCode CompressedTriangleFans::Save(BinaryStream & bstream, bool encodeTrianglesOrder, O3DGCStreamType streamType) { #ifdef DEBUG_VERBOSE g_fileDebugTF = fopen("SaveIntACEGC_new.txt", "w"); #endif //DEBUG_VERBOSE if (streamType == O3DGC_STREAM_TYPE_ASCII) { SaveUIntData(m_numTFANs , bstream); SaveUIntData(m_degrees , bstream); SaveUIntData(m_configs , bstream); SaveBinData (m_operations, bstream); SaveIntData (m_indices , bstream); if (encodeTrianglesOrder) { SaveUIntData(m_trianglesOrder, bstream); } } else { SaveIntACEGC(m_numTFANs , 4 , bstream); SaveIntACEGC(m_degrees , 16, bstream); SaveUIntAC (m_configs , 10, bstream); SaveBinAC (m_operations, bstream); SaveIntACEGC(m_indices , 8 , bstream); if (encodeTrianglesOrder) { SaveIntACEGC(m_trianglesOrder , 16, bstream); } } #ifdef DEBUG_VERBOSE fclose(g_fileDebugTF); #endif //DEBUG_VERBOSE return O3DGC_OK; } O3DGCErrorCode LoadUIntData(Vector & data, const BinaryStream & bstream, unsigned long & iterator) { bstream.ReadUInt32ASCII(iterator); const unsigned long size = bstream.ReadUInt32ASCII(iterator); data.Allocate(size); data.Clear(); for(unsigned long i = 0; i < size; ++i) { data.PushBack(bstream.ReadUIntASCII(iterator)); } return O3DGC_OK; } O3DGCErrorCode LoadIntData(Vector & data, const BinaryStream & bstream, unsigned long & iterator) { bstream.ReadUInt32ASCII(iterator); const unsigned long size = bstream.ReadUInt32ASCII(iterator); data.Allocate(size); data.Clear(); for(unsigned long i = 0; i < size; ++i) { data.PushBack(bstream.ReadIntASCII(iterator)); } return O3DGC_OK; } O3DGCErrorCode LoadBinData(Vector & data, const BinaryStream & bstream, unsigned long & iterator) { bstream.ReadUInt32ASCII(iterator); const unsigned long size = bstream.ReadUInt32ASCII(iterator); long symbol; data.Allocate(size * O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0); data.Clear(); for(unsigned long i = 0; i < size;) { symbol = bstream.ReadUCharASCII(iterator); for(unsigned long h = 0; h < O3DGC_BINARY_STREAM_BITS_PER_SYMBOL0; ++h) { data.PushBack(symbol & 1); symbol >>= 1; ++i; } } return O3DGC_OK; } O3DGCErrorCode LoadUIntAC(Vector & data, const unsigned long M, const BinaryStream & bstream, unsigned long & iterator) { unsigned long sizeSize = bstream.ReadUInt32Bin(iterator) - 12; unsigned long size = bstream.ReadUInt32Bin(iterator); if (size == 0) { return O3DGC_OK; } long minValue = bstream.ReadUInt32Bin(iterator); unsigned char * buffer = 0; bstream.GetBuffer(iterator, buffer); iterator += sizeSize; data.Allocate(size); Arithmetic_Codec acd; acd.set_buffer(sizeSize, buffer); acd.start_decoder(); Adaptive_Data_Model mModelValues(M+1); #ifdef DEBUG_VERBOSE printf("-----------\nsize %i\n", size); fprintf(g_fileDebugTF, "size %i\n", size); #endif //DEBUG_VERBOSE for(unsigned long i = 0; i < size; ++i) { data.PushBack(acd.decode(mModelValues)+minValue); #ifdef DEBUG_VERBOSE printf("%i\t%i\n", i, data[i]); fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]); #endif //DEBUG_VERBOSE } return O3DGC_OK; } O3DGCErrorCode LoadIntACEGC(Vector & data, const unsigned long M, const BinaryStream & bstream, unsigned long & iterator) { unsigned long sizeSize = bstream.ReadUInt32Bin(iterator) - 12; unsigned long size = bstream.ReadUInt32Bin(iterator); if (size == 0) { return O3DGC_OK; } long minValue = bstream.ReadUInt32Bin(iterator) - O3DGC_MAX_LONG; unsigned char * buffer = 0; bstream.GetBuffer(iterator, buffer); iterator += sizeSize; data.Allocate(size); Arithmetic_Codec acd; acd.set_buffer(sizeSize, buffer); acd.start_decoder(); Adaptive_Data_Model mModelValues(M+2); Static_Bit_Model bModel0; Adaptive_Bit_Model bModel1; unsigned long value; #ifdef DEBUG_VERBOSE printf("-----------\nsize %i\n", size); fprintf(g_fileDebugTF, "size %i\n", size); #endif //DEBUG_VERBOSE for(unsigned long i = 0; i < size; ++i) { value = acd.decode(mModelValues); if ( value == M) { value += acd.ExpGolombDecode(0, bModel0, bModel1); } data.PushBack(value + minValue); #ifdef DEBUG_VERBOSE printf("%i\t%i\n", i, data[i]); fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]); #endif //DEBUG_VERBOSE } #ifdef DEBUG_VERBOSE fflush(g_fileDebugTF); #endif //DEBUG_VERBOSE return O3DGC_OK; } O3DGCErrorCode LoadBinAC(Vector & data, const BinaryStream & bstream, unsigned long & iterator) { unsigned long sizeSize = bstream.ReadUInt32Bin(iterator) - 8; unsigned long size = bstream.ReadUInt32Bin(iterator); if (size == 0) { return O3DGC_OK; } unsigned char * buffer = 0; bstream.GetBuffer(iterator, buffer); iterator += sizeSize; data.Allocate(size); Arithmetic_Codec acd; acd.set_buffer(sizeSize, buffer); acd.start_decoder(); Adaptive_Bit_Model bModel; #ifdef DEBUG_VERBOSE printf("-----------\nsize %i\n", size); fprintf(g_fileDebugTF, "size %i\n", size); #endif //DEBUG_VERBOSE for(unsigned long i = 0; i < size; ++i) { data.PushBack(acd.decode(bModel)); #ifdef DEBUG_VERBOSE printf("%i\t%i\n", i, data[i]); fprintf(g_fileDebugTF, "%i\t%i\n", i, data[i]); #endif //DEBUG_VERBOSE } return O3DGC_OK; } O3DGCErrorCode CompressedTriangleFans::Load(const BinaryStream & bstream, unsigned long & iterator, bool decodeTrianglesOrder, O3DGCStreamType streamType) { #ifdef DEBUG_VERBOSE g_fileDebugTF = fopen("Load_new.txt", "w"); #endif //DEBUG_VERBOSE if (streamType == O3DGC_STREAM_TYPE_ASCII) { LoadUIntData(m_numTFANs , bstream, iterator); LoadUIntData(m_degrees , bstream, iterator); LoadUIntData(m_configs , bstream, iterator); LoadBinData (m_operations, bstream, iterator); LoadIntData (m_indices , bstream, iterator); if (decodeTrianglesOrder) { LoadUIntData(m_trianglesOrder , bstream, iterator); } } else { LoadIntACEGC(m_numTFANs , 4 , bstream, iterator); LoadIntACEGC(m_degrees , 16, bstream, iterator); LoadUIntAC (m_configs , 10, bstream, iterator); LoadBinAC (m_operations, bstream, iterator); LoadIntACEGC(m_indices , 8 , bstream, iterator); if (decodeTrianglesOrder) { LoadIntACEGC(m_trianglesOrder , 16, bstream, iterator); } } #ifdef DEBUG_VERBOSE fclose(g_fileDebugTF); #endif //DEBUG_VERBOSE return O3DGC_OK; } } assimp-4.1.0/contrib/Open3DGC/o3dgcDynamicVectorEncoder.h0000644002537200234200000000717113213503245023364 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_DYNAMIC_VECTOR_ENCODER_H #define O3DGC_DYNAMIC_VECTOR_ENCODER_H #include "o3dgcCommon.h" #include "o3dgcBinaryStream.h" #include "o3dgcDynamicVector.h" namespace o3dgc { //! class DynamicVectorEncoder { public: //! Constructor. DynamicVectorEncoder(void); //! Destructor. ~DynamicVectorEncoder(void); //! O3DGCErrorCode Encode(const DVEncodeParams & params, const DynamicVector & dynamicVector, BinaryStream & bstream); O3DGCStreamType GetStreamType() const { return m_streamType; } void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; } private: O3DGCErrorCode EncodeHeader(const DVEncodeParams & params, const DynamicVector & dynamicVector, BinaryStream & bstream); O3DGCErrorCode EncodePayload(const DVEncodeParams & params, const DynamicVector & dynamicVector, BinaryStream & bstream); O3DGCErrorCode Quantize(const Real * const floatArray, unsigned long numFloatArray, unsigned long dimFloatArray, unsigned long stride, const Real * const minFloatArray, const Real * const maxFloatArray, unsigned long nQBits); O3DGCErrorCode EncodeAC(unsigned long num, unsigned long dim, unsigned long M, unsigned long & encodedBytes); unsigned long m_posSize; unsigned long m_sizeBufferAC; unsigned long m_maxNumVectors; unsigned long m_numVectors; unsigned long m_dimVectors; unsigned char * m_bufferAC; long * m_quantVectors; O3DGCStreamType m_streamType; }; } #endif // O3DGC_DYNAMIC_VECTOR_ENCODER_H assimp-4.1.0/contrib/Open3DGC/o3dgcVector.h0000644002537200234200000001740713213503245020562 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_VECTOR_H #define O3DGC_VECTOR_H #include "o3dgcCommon.h" namespace o3dgc { const unsigned long O3DGC_DEFAULT_VECTOR_SIZE = 32; //! template < typename T > class Vector { public: //! Constructor. Vector() { m_allocated = 0; m_size = 0; m_buffer = 0; }; //! Destructor. ~Vector(void) { delete [] m_buffer; }; T & operator[](unsigned long i) { return m_buffer[i]; } const T & operator[](unsigned long i) const { return m_buffer[i]; } void Allocate(unsigned long size) { if (size > m_allocated) { m_allocated = size; T * tmp = new T [m_allocated]; if (m_size > 0) { memcpy(tmp, m_buffer, m_size * sizeof(T) ); delete [] m_buffer; } m_buffer = tmp; } }; void PushBack(const T & value) { if (m_size == m_allocated) { m_allocated *= 2; if (m_allocated < O3DGC_DEFAULT_VECTOR_SIZE) { m_allocated = O3DGC_DEFAULT_VECTOR_SIZE; } T * tmp = new T [m_allocated]; if (m_size > 0) { memcpy(tmp, m_buffer, m_size * sizeof(T) ); delete [] m_buffer; } m_buffer = tmp; } assert(m_size < m_allocated); m_buffer[m_size++] = value; } const T * GetBuffer() const { return m_buffer;}; T * GetBuffer() { return m_buffer;}; unsigned long GetSize() const { return m_size;}; void SetSize(unsigned long size) { assert(size <= m_allocated); m_size = size; }; unsigned long GetAllocatedSize() const { return m_allocated;}; void Clear(){ m_size = 0;}; private: T * m_buffer; unsigned long m_allocated; unsigned long m_size; }; //! Vector dim 3. template < typename T > class Vec3 { public: T & operator[](unsigned long i) { return m_data[i];} const T & operator[](unsigned long i) const { return m_data[i];} T & X(); T & Y(); T & Z(); const T & X() const; const T & Y() const; const T & Z() const; double GetNorm() const; void operator= (const Vec3 & rhs); void operator+=(const Vec3 & rhs); void operator-=(const Vec3 & rhs); void operator-=(T a); void operator+=(T a); void operator/=(T a); void operator*=(T a); Vec3 operator^ (const Vec3 & rhs) const; T operator* (const Vec3 & rhs) const; Vec3 operator+ (const Vec3 & rhs) const; Vec3 operator- (const Vec3 & rhs) const; Vec3 operator- () const; Vec3 operator* (T rhs) const; Vec3 operator/ (T rhs) const; Vec3(); Vec3(T a); Vec3(T x, T y, T z); Vec3(const Vec3 & rhs); ~Vec3(void); private: T m_data[3]; }; //! Vector dim 2. template < typename T > class Vec2 { public: T & operator[](unsigned long i) { return m_data[i];} const T & operator[](unsigned long i) const { return m_data[i];} T & X(); T & Y(); const T & X() const; const T & Y() const; double GetNorm() const; void operator= (const Vec2 & rhs); void operator+=(const Vec2 & rhs); void operator-=(const Vec2 & rhs); void operator-=(T a); void operator+=(T a); void operator/=(T a); void operator*=(T a); T operator^ (const Vec2 & rhs) const; T operator* (const Vec2 & rhs) const; Vec2 operator+ (const Vec2 & rhs) const; Vec2 operator- (const Vec2 & rhs) const; Vec2 operator- () const; Vec2 operator* (T rhs) const; Vec2 operator/ (T rhs) const; Vec2(); Vec2(T a); Vec2(T x, T y); Vec2(const Vec2 & rhs); ~Vec2(void); private: T m_data[2]; }; } #include "o3dgcVector.inl" // template implementation #endif // O3DGC_VECTOR_H assimp-4.1.0/contrib/Open3DGC/o3dgcTriangleListEncoder.h0000644002537200234200000001116413213503245023213 0ustar zmoelnigiemusers/* Copyright (c) 2013 Khaled Mammou - Advanced Micro Devices, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #pragma once #ifndef O3DGC_TRIANGLE_LIST_ENCODER_H #define O3DGC_TRIANGLE_LIST_ENCODER_H #include "o3dgcCommon.h" #include "o3dgcAdjacencyInfo.h" #include "o3dgcBinaryStream.h" #include "o3dgcFIFO.h" #include "o3dgcTriangleFans.h" namespace o3dgc { //! template class TriangleListEncoder { public: //! Constructor. TriangleListEncoder(void); //! Destructor. ~TriangleListEncoder(void); //! O3DGCErrorCode Encode(const T * const triangles, const unsigned long * const indexBufferIDs, const long numTriangles, const long numVertices, BinaryStream & bstream); O3DGCStreamType GetStreamType() const { return m_streamType; } void SetStreamType(O3DGCStreamType streamType) { m_streamType = streamType; } const long * GetInvVMap() const { return m_invVMap;} const long * GetInvTMap() const { return m_invTMap;} const long * GetVMap() const { return m_vmap;} const long * GetTMap() const { return m_tmap;} const AdjacencyInfo & GetVertexToTriangle() const { return m_vertexToTriangle;} private: O3DGCErrorCode Init(const T * const triangles, long numTriangles, long numVertices); O3DGCErrorCode CompueLocalConnectivityInfo(const long focusVertex); O3DGCErrorCode ProcessVertex( long focusVertex); O3DGCErrorCode ComputeTFANDecomposition(const long focusVertex); O3DGCErrorCode CompressTFAN(const long focusVertex); long m_vertexCount; long m_triangleCount; long m_maxNumVertices; long m_maxNumTriangles; long m_numNonConqueredTriangles; long m_numConqueredTriangles; long m_numVisitedVertices; long m_numTriangles; long m_numVertices; long m_maxSizeVertexToTriangle; T const * m_triangles; long * m_vtags; long * m_ttags; long * m_vmap; long * m_invVMap; long * m_tmap; long * m_invTMap; long * m_count; long * m_nonConqueredTriangles; long * m_nonConqueredEdges; long * m_visitedVertices; long * m_visitedVerticesValence; FIFO m_vfifo; AdjacencyInfo m_vertexToTriangle; AdjacencyInfo m_triangleToTriangle; AdjacencyInfo m_triangleToTriangleInv; TriangleFans m_tfans; CompressedTriangleFans m_ctfans; O3DGCStreamType m_streamType; }; } #include "o3dgcTriangleListEncoder.inl" // template implementation #endif // O3DGC_TRIANGLE_LIST_ENCODER_H assimp-4.1.0/contrib/zlib_note.txt0000644002537200234200000000061213213503245017441 0ustar zmoelnigiemusersThis is a heavily modified and shrinked version of zlib 1.2.3 - Removed comments from zlib.h - Removed gzip/zip archive I/O - Removed infback.c - Added Assimp #idefs to exclude it if not needed - Disabled debug macros in zutil.h Assimp itself does not use the compression part yet, so it needn't be compiled (trees.c, deflate.c, compress.c). Currently these units are just used by assimp_cmd.assimp-4.1.0/contrib/gtest/0000755002537200234200000000000013213503245016042 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/samples/0000755002537200234200000000000013213503245017506 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/samples/sample8_unittest.cc0000644002537200234200000001543513213503245023335 0ustar zmoelnigiemusers// 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< ::testing::tuple > { 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 = ::testing::get<0>(GetParam()); int max_precalculated = ::testing::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 assimp-4.1.0/contrib/gtest/samples/sample7_unittest.cc0000644002537200234200000001175313213503245023333 0ustar zmoelnigiemusers// 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, to prevent a test from affecting the tests that come // after it, you should create and destroy the tested objects for each test // instead of reusing them. 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 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 factory function which we call in fixture's SetUp() to // create and store an instance of PrimeTable. class PrimeTableTest : public TestWithParam { 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 assimp-4.1.0/contrib/gtest/samples/sample3_unittest.cc0000644002537200234200000001234713213503245023327 0ustar zmoelnigiemusers// 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. // // // // 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. // // #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 * q) { // Creates a new queue, where each element is twice as big as the // corresponding one in q. const Queue * 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 * 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 q0_; Queue q1_; Queue 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_); } assimp-4.1.0/contrib/gtest/samples/sample4.h0000644002537200234200000000404313213503245021225 0ustar zmoelnigiemusers// 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_ assimp-4.1.0/contrib/gtest/samples/sample2.cc0000644002537200234200000000437213213503245021366 0ustar zmoelnigiemusers// 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 // 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; } assimp-4.1.0/contrib/gtest/samples/sample4_unittest.cc0000644002537200234200000000356513213503245023332 0ustar zmoelnigiemusers// 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()); } assimp-4.1.0/contrib/gtest/samples/sample4.cc0000644002537200234200000000360713213503245021370 0ustar zmoelnigiemusers// 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 #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_); } assimp-4.1.0/contrib/gtest/samples/sample1_unittest.cc0000644002537200234200000001201113213503245023311 0ustar zmoelnigiemusers// 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 #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. // // // // 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. // // // 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_GT(Factorial(-10), 0); // // // 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. // // } // 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? assimp-4.1.0/contrib/gtest/samples/sample5_unittest.cc0000644002537200234200000001467613213503245023340 0ustar zmoelnigiemusers// 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 #include #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_GT(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_FALSE(IsPrime(-1)); EXPECT_FALSE(IsPrime(-2)); EXPECT_FALSE(IsPrime(INT_MIN)); // Tests some trivial cases. EXPECT_FALSE(IsPrime(0)); EXPECT_FALSE(IsPrime(1)); EXPECT_TRUE(IsPrime(2)); EXPECT_TRUE(IsPrime(3)); // Tests positive input. EXPECT_FALSE(IsPrime(4)); EXPECT_TRUE(IsPrime(5)); EXPECT_FALSE(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 q0_; Queue q1_; Queue 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. assimp-4.1.0/contrib/gtest/samples/sample6_unittest.cc0000644002537200234200000002143513213503245023330 0ustar zmoelnigiemusers// 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 PrimeTable* CreatePrimeTable(); template <> PrimeTable* CreatePrimeTable() { return new OnTheFlyPrimeTable; } template <> PrimeTable* CreatePrimeTable() { return new PreCalculatedPrimeTable(10000); } // Then we define a test fixture class template. template class PrimeTableTest : public testing::Test { protected: // The ctor calls the factory function to create a prime table // implemented by T. PrimeTableTest() : table_(CreatePrimeTable()) {} 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 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 PrimeTableTest2 : public PrimeTableTest { }; // 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 PrimeTableImplementations; INSTANTIATE_TYPED_TEST_CASE_P(OnTheFlyAndPreCalculated, // Instance name PrimeTableTest2, // Test case name PrimeTableImplementations); // Type list #endif // GTEST_HAS_TYPED_TEST_P assimp-4.1.0/contrib/gtest/samples/sample1.h0000644002537200234200000000362113213503245021223 0ustar zmoelnigiemusers// 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_ assimp-4.1.0/contrib/gtest/samples/sample9_unittest.cc0000644002537200234200000001347713213503245023342 0ustar zmoelnigiemusers// 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 #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 SUCCEED() invocation. 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; } assimp-4.1.0/contrib/gtest/samples/sample10_unittest.cc0000644002537200234200000001167513213503245023410 0ustar zmoelnigiemusers// 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 #include #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_LE(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(); } assimp-4.1.0/contrib/gtest/samples/sample2_unittest.cc0000644002537200234200000000752613213503245023331 0ustar zmoelnigiemusers// 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. // // // // If we write NULL instead of // // static_cast(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. // // 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_EQ(0, strcmp(s.c_string(), kHelloString)); 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_EQ(0, strcmp(s2.c_string(), kHelloString)); } // Tests the Set method. TEST(MyString, Set) { MyString s; s.Set(kHelloString); EXPECT_EQ(0, strcmp(s.c_string(), kHelloString)); // Set should work when the input pointer is the same as the one // already in the MyString object. s.Set(s.c_string()); EXPECT_EQ(0, strcmp(s.c_string(), kHelloString)); // Can we set the MyString to NULL? s.Set(NULL); EXPECT_STREQ(NULL, s.c_string()); } assimp-4.1.0/contrib/gtest/samples/prime_tables.h0000644002537200234200000000775013213503245022336 0ustar zmoelnigiemusers// 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 // 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_ assimp-4.1.0/contrib/gtest/samples/sample2.h0000644002537200234200000000567613213503245021240 0ustar zmoelnigiemusers// 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 // 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_ assimp-4.1.0/contrib/gtest/samples/sample3-inl.h0000644002537200234200000001236513213503245022012 0ustar zmoelnigiemusers// 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 // Queue is a simple queue implemented as a singled-linked list. // // The element type must support copy constructor. template // 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 // E is the element type class QueueNode { friend class Queue; 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. explicit 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 // 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* node = head_; QueueNode* 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* Head() { return head_; } const QueueNode* Head() const { return head_; } // Gets the last element of the queue, or NULL if the queue is empty. QueueNode* Last() { return last_; } const QueueNode* 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* new_node = new QueueNode(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* 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 Queue* Map(F function) const { Queue* new_queue = new Queue(); for (const QueueNode* node = head_; node != NULL; node = node->next_) { new_queue->Enqueue(function(node->element())); } return new_queue; } private: QueueNode* head_; // The first node of the queue. QueueNode* 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_ assimp-4.1.0/contrib/gtest/samples/sample1.cc0000644002537200234200000000470613213503245021366 0ustar zmoelnigiemusers// 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; } assimp-4.1.0/contrib/gtest/docs/0000755002537200234200000000000013213503245016772 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/docs/V1_6_XcodeGuide.md0000644002537200234200000002005713213503245022133 0ustar zmoelnigiemusers This guide will explain how to use the Google Testing Framework in your Xcode projects on Mac OS X. This tutorial begins by quickly explaining what to do for experienced users. After the quick start, the guide goes provides additional explanation about each step. # Quick Start # Here is the quick guide for using Google Test in your Xcode project. 1. Download the source from the [website](http://code.google.com/p/googletest) using this command: `svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only` 1. Open up the `gtest.xcodeproj` in the `googletest-read-only/xcode/` directory and build the gtest.framework. 1. Create a new "Shell Tool" target in your Xcode project called something like "UnitTests" 1. Add the gtest.framework to your project and add it to the "Link Binary with Libraries" build phase of "UnitTests" 1. Add your unit test source code to the "Compile Sources" build phase of "UnitTests" 1. Edit the "UnitTests" executable and add an environment variable named "DYLD\_FRAMEWORK\_PATH" with a value equal to the path to the framework containing the gtest.framework relative to the compiled executable. 1. Build and Go The following sections further explain each of the steps listed above in depth, describing in more detail how to complete it including some variations. # Get the Source # Currently, the gtest.framework discussed here isn't available in a tagged release of Google Test, it is only available in the trunk. As explained at the Google Test [site](http://code.google.com/p/googletest/source/checkout">svn), you can get the code from anonymous SVN with this command: ``` svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only ``` Alternatively, if you are working with Subversion in your own code base, you can add Google Test as an external dependency to your own Subversion repository. By following this approach, everyone that checks out your svn repository will also receive a copy of Google Test (a specific version, if you wish) without having to check it out explicitly. This makes the set up of your project simpler and reduces the copied code in the repository. To use `svn:externals`, decide where you would like to have the external source reside. You might choose to put the external source inside the trunk, because you want it to be part of the branch when you make a release. However, keeping it outside the trunk in a version-tagged directory called something like `third-party/googletest/1.0.1`, is another option. Once the location is established, use `svn propedit svn:externals _directory_` to set the svn:externals property on a directory in your repository. This directory won't contain the code, but be its versioned parent directory. The command `svn propedit` will bring up your Subversion editor, making editing the long, (potentially multi-line) property simpler. This same method can be used to check out a tagged branch, by using the appropriate URL (e.g. `http://googletest.googlecode.com/svn/tags/release-1.0.1`). Additionally, the svn:externals property allows the specification of a particular revision of the trunk with the `-r_##_` option (e.g. `externals/src/googletest -r60 http://googletest.googlecode.com/svn/trunk`). Here is an example of using the svn:externals properties on a trunk (read via `svn propget`) of a project. This value checks out a copy of Google Test into the `trunk/externals/src/googletest/` directory. ``` [Computer:svn] user$ svn propget svn:externals trunk externals/src/googletest http://googletest.googlecode.com/svn/trunk ``` # Add the Framework to Your Project # The next step is to build and add the gtest.framework to your own project. This guide describes two common ways below. * **Option 1** --- The simplest way to add Google Test to your own project, is to open gtest.xcodeproj (found in the xcode/ directory of the Google Test trunk) and build the framework manually. Then, add the built framework into your project using the "Add->Existing Framework..." from the context menu or "Project->Add..." from the main menu. The gtest.framework is relocatable and contains the headers and object code that you'll need to make tests. This method requires rebuilding every time you upgrade Google Test in your project. * **Option 2** --- If you are going to be living off the trunk of Google Test, incorporating its latest features into your unit tests (or are a Google Test developer yourself). You'll want to rebuild the framework every time the source updates. to do this, you'll need to add the gtest.xcodeproj file, not the framework itself, to your own Xcode project. Then, from the build products that are revealed by the project's disclosure triangle, you can find the gtest.framework, which can be added to your targets (discussed below). # Make a Test Target # To start writing tests, make a new "Shell Tool" target. This target template is available under BSD, Cocoa, or Carbon. Add your unit test source code to the "Compile Sources" build phase of the target. Next, you'll want to add gtest.framework in two different ways, depending upon which option you chose above. * **Option 1** --- During compilation, Xcode will need to know that you are linking against the gtest.framework. Add the gtest.framework to the "Link Binary with Libraries" build phase of your test target. This will include the Google Test headers in your header search path, and will tell the linker where to find the library. * **Option 2** --- If your working out of the trunk, you'll also want to add gtest.framework to your "Link Binary with Libraries" build phase of your test target. In addition, you'll want to add the gtest.framework as a dependency to your unit test target. This way, Xcode will make sure that gtest.framework is up to date, every time your build your target. Finally, if you don't share build directories with Google Test, you'll have to copy the gtest.framework into your own build products directory using a "Run Script" build phase. # Set Up the Executable Run Environment # Since the unit test executable is a shell tool, it doesn't have a bundle with a `Contents/Frameworks` directory, in which to place gtest.framework. Instead, the dynamic linker must be told at runtime to search for the framework in another location. This can be accomplished by setting the "DYLD\_FRAMEWORK\_PATH" environment variable in the "Edit Active Executable ..." Arguments tab, under "Variables to be set in the environment:". The path for this value is the path (relative or absolute) of the directory containing the gtest.framework. If you haven't set up the DYLD\_FRAMEWORK\_PATH, correctly, you might get a message like this: ``` [Session started at 2008-08-15 06:23:57 -0600.] dyld: Library not loaded: @loader_path/../Frameworks/gtest.framework/Versions/A/gtest Referenced from: /Users/username/Documents/Sandbox/gtestSample/build/Debug/WidgetFrameworkTest Reason: image not found ``` To correct this problem, got to the directory containing the executable named in "Referenced from:" value in the error message above. Then, with the terminal in this location, find the relative path to the directory containing the gtest.framework. That is the value you'll need to set as the DYLD\_FRAMEWORK\_PATH. # Build and Go # Now, when you click "Build and Go", the test will be executed. Dumping out something like this: ``` [Session started at 2008-08-06 06:36:13 -0600.] [==========] Running 2 tests from 1 test case. [----------] Global test environment set-up. [----------] 2 tests from WidgetInitializerTest [ RUN ] WidgetInitializerTest.TestConstructor [ OK ] WidgetInitializerTest.TestConstructor [ RUN ] WidgetInitializerTest.TestConversion [ OK ] WidgetInitializerTest.TestConversion [----------] Global test environment tear-down [==========] 2 tests from 1 test case ran. [ PASSED ] 2 tests. The Debugger has exited with status 0. ``` # Summary # Unit testing is a valuable way to ensure your data model stays valid even during rapid development or refactoring. The Google Testing Framework is a great unit testing framework for C and C++ which integrates well with an Xcode development environment.assimp-4.1.0/contrib/gtest/docs/V1_5_Primer.md0000644002537200234200000005771413213503245021362 0ustar zmoelnigiemusers # Introduction: Why Google C++ Testing Framework? # _Google C++ Testing Framework_ helps you write better C++ tests. No matter whether you work on Linux, Windows, or a Mac, if you write C++ code, Google Test can help you. So what makes a good test, and how does Google C++ Testing Framework fit in? We believe: 1. Tests should be _independent_ and _repeatable_. It's a pain to debug a test that succeeds or fails as a result of other tests. Google C++ Testing Framework isolates the tests by running each of them on a different object. When a test fails, Google C++ Testing Framework allows you to run it in isolation for quick debugging. 1. Tests should be well _organized_ and reflect the structure of the tested code. Google C++ Testing Framework groups related tests into test cases that can share data and subroutines. This common pattern is easy to recognize and makes tests easy to maintain. Such consistency is especially helpful when people switch projects and start to work on a new code base. 1. Tests should be _portable_ and _reusable_. The open-source community has a lot of code that is platform-neutral, its tests should also be platform-neutral. Google C++ Testing Framework works on different OSes, with different compilers (gcc, MSVC, and others), with or without exceptions, so Google C++ Testing Framework tests can easily work with a variety of configurations. (Note that the current release only contains build scripts for Linux - we are actively working on scripts for other platforms.) 1. When tests fail, they should provide as much _information_ about the problem as possible. Google C++ Testing Framework doesn't stop at the first test failure. Instead, it only stops the current test and continues with the next. You can also set up tests that report non-fatal failures after which the current test continues. Thus, you can detect and fix multiple bugs in a single run-edit-compile cycle. 1. The testing framework should liberate test writers from housekeeping chores and let them focus on the test _content_. Google C++ Testing Framework automatically keeps track of all tests defined, and doesn't require the user to enumerate them in order to run them. 1. Tests should be _fast_. With Google C++ Testing Framework, you can reuse shared resources across tests and pay for the set-up/tear-down only once, without making tests depend on each other. Since Google C++ Testing Framework is based on the popular xUnit architecture, you'll feel right at home if you've used JUnit or PyUnit before. If not, it will take you about 10 minutes to learn the basics and get started. So let's go! _Note:_ We sometimes refer to Google C++ Testing Framework informally as _Google Test_. # Setting up a New Test Project # To write a test program using Google Test, you need to compile Google Test into a library and link your test with it. We provide build files for some popular build systems (`msvc/` for Visual Studio, `xcode/` for Mac Xcode, `make/` for GNU make, `codegear/` for Borland C++ Builder, and the autotools script in the Google Test root directory). If your build system is not on this list, you can take a look at `make/Makefile` to learn how Google Test should be compiled (basically you want to compile `src/gtest-all.cc` with `GTEST_ROOT` and `GTEST_ROOT/include` in the header search path, where `GTEST_ROOT` is the Google Test root directory). Once you are able to compile the Google Test library, you should create a project or build target for your test program. Make sure you have `GTEST_ROOT/include` in the header search path so that the compiler can find `` when compiling your test. Set up your test project to link with the Google Test library (for example, in Visual Studio, this is done by adding a dependency on `gtest.vcproj`). If you still have questions, take a look at how Google Test's own tests are built and use them as examples. # Basic Concepts # When using Google Test, you start by writing _assertions_, which are statements that check whether a condition is true. An assertion's result can be _success_, _nonfatal failure_, or _fatal failure_. If a fatal failure occurs, it aborts the current function; otherwise the program continues normally. _Tests_ use assertions to verify the tested code's behavior. If a test crashes or has a failed assertion, then it _fails_; otherwise it _succeeds_. A _test case_ contains one or many tests. You should group your tests into test cases that reflect the structure of the tested code. When multiple tests in a test case need to share common objects and subroutines, you can put them into a _test fixture_ class. A _test program_ can contain multiple test cases. We'll now explain how to write a test program, starting at the individual assertion level and building up to tests and test cases. # Assertions # Google Test assertions are macros that resemble function calls. You test a class or function by making assertions about its behavior. When an assertion fails, Google Test prints the assertion's source file and line number location, along with a failure message. You may also supply a custom failure message which will be appended to Google Test's message. The assertions come in pairs that test the same thing but have different effects on the current function. `ASSERT_*` versions generate fatal failures when they fail, and **abort the current function**. `EXPECT_*` versions generate nonfatal failures, which don't abort the current function. Usually `EXPECT_*` are preferred, as they allow more than one failures to be reported in a test. However, you should use `ASSERT_*` if it doesn't make sense to continue when the assertion in question fails. Since a failed `ASSERT_*` returns from the current function immediately, possibly skipping clean-up code that comes after it, it may cause a space leak. Depending on the nature of the leak, it may or may not be worth fixing - so keep this in mind if you get a heap checker error in addition to assertion errors. To provide a custom failure message, simply stream it into the macro using the `<<` operator, or a sequence of such operators. An example: ``` ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length"; for (int i = 0; i < x.size(); ++i) { EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i; } ``` Anything that can be streamed to an `ostream` can be streamed to an assertion macro--in particular, C strings and `string` objects. If a wide string (`wchar_t*`, `TCHAR*` in `UNICODE` mode on Windows, or `std::wstring`) is streamed to an assertion, it will be translated to UTF-8 when printed. ## Basic Assertions ## These assertions do basic true/false condition testing. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_TRUE(`_condition_`)`; | `EXPECT_TRUE(`_condition_`)`; | _condition_ is true | | `ASSERT_FALSE(`_condition_`)`; | `EXPECT_FALSE(`_condition_`)`; | _condition_ is false | Remember, when they fail, `ASSERT_*` yields a fatal failure and returns from the current function, while `EXPECT_*` yields a nonfatal failure, allowing the function to continue running. In either case, an assertion failure means its containing test fails. _Availability_: Linux, Windows, Mac. ## Binary Comparison ## This section describes assertions that compare two values. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| |`ASSERT_EQ(`_expected_`, `_actual_`);`|`EXPECT_EQ(`_expected_`, `_actual_`);`| _expected_ `==` _actual_ | |`ASSERT_NE(`_val1_`, `_val2_`);` |`EXPECT_NE(`_val1_`, `_val2_`);` | _val1_ `!=` _val2_ | |`ASSERT_LT(`_val1_`, `_val2_`);` |`EXPECT_LT(`_val1_`, `_val2_`);` | _val1_ `<` _val2_ | |`ASSERT_LE(`_val1_`, `_val2_`);` |`EXPECT_LE(`_val1_`, `_val2_`);` | _val1_ `<=` _val2_ | |`ASSERT_GT(`_val1_`, `_val2_`);` |`EXPECT_GT(`_val1_`, `_val2_`);` | _val1_ `>` _val2_ | |`ASSERT_GE(`_val1_`, `_val2_`);` |`EXPECT_GE(`_val1_`, `_val2_`);` | _val1_ `>=` _val2_ | In the event of a failure, Google Test prints both _val1_ and _val2_ . In `ASSERT_EQ*` and `EXPECT_EQ*` (and all other equality assertions we'll introduce later), you should put the expression you want to test in the position of _actual_, and put its expected value in _expected_, as Google Test's failure messages are optimized for this convention. Value arguments must be comparable by the assertion's comparison operator or you'll get a compiler error. Values must also support the `<<` operator for streaming to an `ostream`. All built-in types support this. These assertions can work with a user-defined type, but only if you define the corresponding comparison operator (e.g. `==`, `<`, etc). If the corresponding operator is defined, prefer using the `ASSERT_*()` macros because they will print out not only the result of the comparison, but the two operands as well. Arguments are always evaluated exactly once. Therefore, it's OK for the arguments to have side effects. However, as with any ordinary C/C++ function, the arguments' evaluation order is undefined (i.e. the compiler is free to choose any order) and your code should not depend on any particular argument evaluation order. `ASSERT_EQ()` does pointer equality on pointers. If used on two C strings, it tests if they are in the same memory location, not if they have the same value. Therefore, if you want to compare C strings (e.g. `const char*`) by value, use `ASSERT_STREQ()` , which will be described later on. In particular, to assert that a C string is `NULL`, use `ASSERT_STREQ(NULL, c_string)` . However, to compare two `string` objects, you should use `ASSERT_EQ`. Macros in this section work with both narrow and wide string objects (`string` and `wstring`). _Availability_: Linux, Windows, Mac. ## String Comparison ## The assertions in this group compare two **C strings**. If you want to compare two `string` objects, use `EXPECT_EQ`, `EXPECT_NE`, and etc instead. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_STREQ(`_expected\_str_`, `_actual\_str_`);` | `EXPECT_STREQ(`_expected\_str_`, `_actual\_str_`);` | the two C strings have the same content | | `ASSERT_STRNE(`_str1_`, `_str2_`);` | `EXPECT_STRNE(`_str1_`, `_str2_`);` | the two C strings have different content | | `ASSERT_STRCASEEQ(`_expected\_str_`, `_actual\_str_`);`| `EXPECT_STRCASEEQ(`_expected\_str_`, `_actual\_str_`);` | the two C strings have the same content, ignoring case | | `ASSERT_STRCASENE(`_str1_`, `_str2_`);`| `EXPECT_STRCASENE(`_str1_`, `_str2_`);` | the two C strings have different content, ignoring case | Note that "CASE" in an assertion name means that case is ignored. `*STREQ*` and `*STRNE*` also accept wide C strings (`wchar_t*`). If a comparison of two wide strings fails, their values will be printed as UTF-8 narrow strings. A `NULL` pointer and an empty string are considered _different_. _Availability_: Linux, Windows, Mac. See also: For more string comparison tricks (substring, prefix, suffix, and regular expression matching, for example), see the [AdvancedGuide Advanced Google Test Guide]. # Simple Tests # To create a test: 1. Use the `TEST()` macro to define and name a test function, These are ordinary C++ functions that don't return a value. 1. In this function, along with any valid C++ statements you want to include, use the various Google Test assertions to check values. 1. The test's result is determined by the assertions; if any assertion in the test fails (either fatally or non-fatally), or if the test crashes, the entire test fails. Otherwise, it succeeds. ``` TEST(test_case_name, test_name) { ... test body ... } ``` `TEST()` arguments go from general to specific. The _first_ argument is the name of the test case, and the _second_ argument is the test's name within the test case. Remember that a test case can contain any number of individual tests. A test's _full name_ consists of its containing test case and its individual name. Tests from different test cases can have the same individual name. For example, let's take a simple integer function: ``` int Factorial(int n); // Returns the factorial of n ``` A test case for this function might look like: ``` // Tests factorial of 0. TEST(FactorialTest, HandlesZeroInput) { EXPECT_EQ(1, Factorial(0)); } // Tests factorial of positive numbers. TEST(FactorialTest, HandlesPositiveInput) { EXPECT_EQ(1, Factorial(1)); EXPECT_EQ(2, Factorial(2)); EXPECT_EQ(6, Factorial(3)); EXPECT_EQ(40320, Factorial(8)); } ``` Google Test groups the test results by test cases, so logically-related tests should be in the same test case; in other words, the first argument to their `TEST()` should be the same. In the above example, we have two tests, `HandlesZeroInput` and `HandlesPositiveInput`, that belong to the same test case `FactorialTest`. _Availability_: Linux, Windows, Mac. # Test Fixtures: Using the Same Data Configuration for Multiple Tests # If you find yourself writing two or more tests that operate on similar data, you can use a _test fixture_. It allows you to reuse the same configuration of objects for several different tests. To create a fixture, just: 1. Derive a class from `::testing::Test` . Start its body with `protected:` or `public:` as we'll want to access fixture members from sub-classes. 1. Inside the class, declare any objects you plan to use. 1. If necessary, write a default constructor or `SetUp()` function to prepare the objects for each test. A common mistake is to spell `SetUp()` as `Setup()` with a small `u` - don't let that happen to you. 1. If necessary, write a destructor or `TearDown()` function to release any resources you allocated in `SetUp()` . To learn when you should use the constructor/destructor and when you should use `SetUp()/TearDown()`, read this [FAQ entry](V1_5_FAQ.md#should-i-use-the-constructordestructor-of-the-test-fixture-or-the-set-uptear-down-function). 1. If needed, define subroutines for your tests to share. When using a fixture, use `TEST_F()` instead of `TEST()` as it allows you to access objects and subroutines in the test fixture: ``` TEST_F(test_case_name, test_name) { ... test body ... } ``` Like `TEST()`, the first argument is the test case name, but for `TEST_F()` this must be the name of the test fixture class. You've probably guessed: `_F` is for fixture. Unfortunately, the C++ macro system does not allow us to create a single macro that can handle both types of tests. Using the wrong macro causes a compiler error. Also, you must first define a test fixture class before using it in a `TEST_F()`, or you'll get the compiler error "`virtual outside class declaration`". For each test defined with `TEST_F()`, Google Test will: 1. Create a _fresh_ test fixture at runtime 1. Immediately initialize it via `SetUp()` , 1. Run the test 1. Clean up by calling `TearDown()` 1. Delete the test fixture. Note that different tests in the same test case have different test fixture objects, and Google Test always deletes a test fixture before it creates the next one. Google Test does not reuse the same test fixture for multiple tests. Any changes one test makes to the fixture do not affect other tests. As an example, let's write tests for a FIFO queue class named `Queue`, which has the following interface: ``` template // E is the element type. class Queue { public: Queue(); void Enqueue(const E& element); E* Dequeue(); // Returns NULL if the queue is empty. size_t size() const; ... }; ``` First, define a fixture class. By convention, you should give it the name `FooTest` where `Foo` is the class being tested. ``` class QueueTest : public ::testing::Test { protected: virtual void SetUp() { q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // virtual void TearDown() {} Queue q0_; Queue q1_; Queue q2_; }; ``` In this case, `TearDown()` is not needed since we don't have to clean up after each test, other than what's already done by the destructor. Now we'll write tests using `TEST_F()` and this fixture. ``` TEST_F(QueueTest, IsEmptyInitially) { EXPECT_EQ(0, q0_.size()); } TEST_F(QueueTest, DequeueWorks) { int* n = q0_.Dequeue(); EXPECT_EQ(NULL, n); n = q1_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(1, *n); EXPECT_EQ(0, q1_.size()); delete n; n = q2_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(2, *n); EXPECT_EQ(1, q2_.size()); delete n; } ``` The above uses both `ASSERT_*` and `EXPECT_*` assertions. The rule of thumb is to use `EXPECT_*` when you want the test to continue to reveal more errors after the assertion failure, and use `ASSERT_*` when continuing after failure doesn't make sense. For example, the second assertion in the `Dequeue` test is `ASSERT_TRUE(n != NULL)`, as we need to dereference the pointer `n` later, which would lead to a segfault when `n` is `NULL`. When these tests run, the following happens: 1. Google Test constructs a `QueueTest` object (let's call it `t1` ). 1. `t1.SetUp()` initializes `t1` . 1. The first test ( `IsEmptyInitially` ) runs on `t1` . 1. `t1.TearDown()` cleans up after the test finishes. 1. `t1` is destructed. 1. The above steps are repeated on another `QueueTest` object, this time running the `DequeueWorks` test. _Availability_: Linux, Windows, Mac. _Note_: Google Test automatically saves all _Google Test_ flags when a test object is constructed, and restores them when it is destructed. # Invoking the Tests # `TEST()` and `TEST_F()` implicitly register their tests with Google Test. So, unlike with many other C++ testing frameworks, you don't have to re-list all your defined tests in order to run them. After defining your tests, you can run them with `RUN_ALL_TESTS()` , which returns `0` if all the tests are successful, or `1` otherwise. Note that `RUN_ALL_TESTS()` runs _all tests_ in your link unit -- they can be from different test cases, or even different source files. When invoked, the `RUN_ALL_TESTS()` macro: 1. Saves the state of all Google Test flags. 1. Creates a test fixture object for the first test. 1. Initializes it via `SetUp()`. 1. Runs the test on the fixture object. 1. Cleans up the fixture via `TearDown()`. 1. Deletes the fixture. 1. Restores the state of all Google Test flags. 1. Repeats the above steps for the next test, until all tests have run. In addition, if the text fixture's constructor generates a fatal failure in step 2, there is no point for step 3 - 5 and they are thus skipped. Similarly, if step 3 generates a fatal failure, step 4 will be skipped. _Important_: You must not ignore the return value of `RUN_ALL_TESTS()`, or `gcc` will give you a compiler error. The rationale for this design is that the automated testing service determines whether a test has passed based on its exit code, not on its stdout/stderr output; thus your `main()` function must return the value of `RUN_ALL_TESTS()`. Also, you should call `RUN_ALL_TESTS()` only **once**. Calling it more than once conflicts with some advanced Google Test features (e.g. thread-safe death tests) and thus is not supported. _Availability_: Linux, Windows, Mac. # Writing the main() Function # You can start from this boilerplate: ``` #include "this/package/foo.h" #include namespace { // The fixture for testing class Foo. class FooTest : public ::testing::Test { protected: // You can remove any or all of the following functions if its body // is empty. FooTest() { // You can do set-up work for each test here. } virtual ~FooTest() { // You can do clean-up work that doesn't throw exceptions here. } // If the constructor and destructor are not enough for setting up // and cleaning up each test, you can define the following methods: virtual void SetUp() { // Code here will be called immediately after the constructor (right // before each test). } virtual void TearDown() { // Code here will be called immediately after each test (right // before the destructor). } // Objects declared here can be used by all tests in the test case for Foo. }; // Tests that the Foo::Bar() method does Abc. TEST_F(FooTest, MethodBarDoesAbc) { const string input_filepath = "this/package/testdata/myinputfile.dat"; const string output_filepath = "this/package/testdata/myoutputfile.dat"; Foo f; EXPECT_EQ(0, f.Bar(input_filepath, output_filepath)); } // Tests that Foo does Xyz. TEST_F(FooTest, DoesXyz) { // Exercises the Xyz feature of Foo. } } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ``` The `::testing::InitGoogleTest()` function parses the command line for Google Test flags, and removes all recognized flags. This allows the user to control a test program's behavior via various flags, which we'll cover in [AdvancedGuide](V1_5_AdvancedGuide.md). You must call this function before calling `RUN_ALL_TESTS()`, or the flags won't be properly initialized. On Windows, `InitGoogleTest()` also works with wide strings, so it can be used in programs compiled in `UNICODE` mode as well. But maybe you think that writing all those main() functions is too much work? We agree with you completely and that's why Google Test provides a basic implementation of main(). If it fits your needs, then just link your test with gtest\_main library and you are good to go. ## Important note for Visual C++ users ## If you put your tests into a library and your `main()` function is in a different library or in your .exe file, those tests will not run. The reason is a [bug](https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&siteid=210) in Visual C++. When you define your tests, Google Test creates certain static objects to register them. These objects are not referenced from elsewhere but their constructors are still supposed to run. When Visual C++ linker sees that nothing in the library is referenced from other places it throws the library out. You have to reference your library with tests from your main program to keep the linker from discarding it. Here is how to do it. Somewhere in your library code declare a function: ``` __declspec(dllexport) int PullInMyLibrary() { return 0; } ``` If you put your tests in a static library (not DLL) then `__declspec(dllexport)` is not required. Now, in your main program, write a code that invokes that function: ``` int PullInMyLibrary(); static int dummy = PullInMyLibrary(); ``` This will keep your tests referenced and will make them register themselves at startup. In addition, if you define your tests in a static library, add `/OPT:NOREF` to your main program linker options. If you use MSVC++ IDE, go to your .exe project properties/Configuration Properties/Linker/Optimization and set References setting to `Keep Unreferenced Data (/OPT:NOREF)`. This will keep Visual C++ linker from discarding individual symbols generated by your tests from the final executable. There is one more pitfall, though. If you use Google Test as a static library (that's how it is defined in gtest.vcproj) your tests must also reside in a static library. If you have to have them in a DLL, you _must_ change Google Test to build into a DLL as well. Otherwise your tests will not run correctly or will not run at all. The general conclusion here is: make your life easier - do not write your tests in libraries! # Where to Go from Here # Congratulations! You've learned the Google Test basics. You can start writing and running Google Test tests, read some [samples](Samples.md), or continue with [AdvancedGuide](V1_5_AdvancedGuide.md), which describes many more useful Google Test features. # Known Limitations # Google Test is designed to be thread-safe. The implementation is thread-safe on systems where the `pthreads` library is available. It is currently _unsafe_ to use Google Test assertions from two threads concurrently on other systems (e.g. Windows). In most tests this is not an issue as usually the assertions are done in the main thread. If you want to help, you can volunteer to implement the necessary synchronization primitives in `gtest-port.h` for your platform. assimp-4.1.0/contrib/gtest/docs/AdvancedGuide.md0000644002537200234200000025325513213503245022013 0ustar zmoelnigiemusers Now that you have read [Primer](Primer.md) and learned how to write tests using Google Test, it's time to learn some new tricks. This document will show you more assertions as well as how to construct complex failure messages, propagate fatal failures, reuse and speed up your test fixtures, and use various flags with your tests. # More Assertions # This section covers some less frequently used, but still significant, assertions. ## Explicit Success and Failure ## These three assertions do not actually test a value or expression. Instead, they generate a success or failure directly. Like the macros that actually perform a test, you may stream a custom failure message into the them. | `SUCCEED();` | |:-------------| Generates a success. This does NOT make the overall test succeed. A test is considered successful only if none of its assertions fail during its execution. Note: `SUCCEED()` is purely documentary and currently doesn't generate any user-visible output. However, we may add `SUCCEED()` messages to Google Test's output in the future. | `FAIL();` | `ADD_FAILURE();` | `ADD_FAILURE_AT("`_file\_path_`", `_line\_number_`);` | |:-----------|:-----------------|:------------------------------------------------------| `FAIL()` generates a fatal failure, while `ADD_FAILURE()` and `ADD_FAILURE_AT()` generate a nonfatal failure. These are useful when control flow, rather than a Boolean expression, deteremines the test's success or failure. For example, you might want to write something like: ``` switch(expression) { case 1: ... some checks ... case 2: ... some other checks ... default: FAIL() << "We shouldn't get here."; } ``` Note: you can only use `FAIL()` in functions that return `void`. See the [Assertion Placement section](#assertion-placement) for more information. _Availability_: Linux, Windows, Mac. ## Exception Assertions ## These are for verifying that a piece of code throws (or does not throw) an exception of the given type: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_THROW(`_statement_, _exception\_type_`);` | `EXPECT_THROW(`_statement_, _exception\_type_`);` | _statement_ throws an exception of the given type | | `ASSERT_ANY_THROW(`_statement_`);` | `EXPECT_ANY_THROW(`_statement_`);` | _statement_ throws an exception of any type | | `ASSERT_NO_THROW(`_statement_`);` | `EXPECT_NO_THROW(`_statement_`);` | _statement_ doesn't throw any exception | Examples: ``` ASSERT_THROW(Foo(5), bar_exception); EXPECT_NO_THROW({ int n = 5; Bar(&n); }); ``` _Availability_: Linux, Windows, Mac; since version 1.1.0. ## Predicate Assertions for Better Error Messages ## Even though Google Test has a rich set of assertions, they can never be complete, as it's impossible (nor a good idea) to anticipate all the scenarios a user might run into. Therefore, sometimes a user has to use `EXPECT_TRUE()` to check a complex expression, for lack of a better macro. This has the problem of not showing you the values of the parts of the expression, making it hard to understand what went wrong. As a workaround, some users choose to construct the failure message by themselves, streaming it into `EXPECT_TRUE()`. However, this is awkward especially when the expression has side-effects or is expensive to evaluate. Google Test gives you three different options to solve this problem: ### Using an Existing Boolean Function ### If you already have a function or a functor that returns `bool` (or a type that can be implicitly converted to `bool`), you can use it in a _predicate assertion_ to get the function arguments printed for free: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_PRED1(`_pred1, val1_`);` | `EXPECT_PRED1(`_pred1, val1_`);` | _pred1(val1)_ returns true | | `ASSERT_PRED2(`_pred2, val1, val2_`);` | `EXPECT_PRED2(`_pred2, val1, val2_`);` | _pred2(val1, val2)_ returns true | | ... | ... | ... | In the above, _predn_ is an _n_-ary predicate function or functor, where _val1_, _val2_, ..., and _valn_ are its arguments. The assertion succeeds if the predicate returns `true` when applied to the given arguments, and fails otherwise. When the assertion fails, it prints the value of each argument. In either case, the arguments are evaluated exactly once. Here's an example. Given ``` // Returns true iff m and n have no common divisors except 1. bool MutuallyPrime(int m, int n) { ... } const int a = 3; const int b = 4; const int c = 10; ``` the assertion `EXPECT_PRED2(MutuallyPrime, a, b);` will succeed, while the assertion `EXPECT_PRED2(MutuallyPrime, b, c);` will fail with the message
!MutuallyPrime(b, c) is false, where
b is 4
c is 10
**Notes:** 1. If you see a compiler error "no matching function to call" when using `ASSERT_PRED*` or `EXPECT_PRED*`, please see [this FAQ](FAQ.md#the-compiler-complains-no-matching-function-to-call-when-i-use-assert_predn-how-do-i-fix-it) for how to resolve it. 1. Currently we only provide predicate assertions of arity <= 5. If you need a higher-arity assertion, let us know. _Availability_: Linux, Windows, Mac ### Using a Function That Returns an AssertionResult ### While `EXPECT_PRED*()` and friends are handy for a quick job, the syntax is not satisfactory: you have to use different macros for different arities, and it feels more like Lisp than C++. The `::testing::AssertionResult` class solves this problem. An `AssertionResult` object represents the result of an assertion (whether it's a success or a failure, and an associated message). You can create an `AssertionResult` using one of these factory functions: ``` namespace testing { // Returns an AssertionResult object to indicate that an assertion has // succeeded. AssertionResult AssertionSuccess(); // Returns an AssertionResult object to indicate that an assertion has // failed. AssertionResult AssertionFailure(); } ``` You can then use the `<<` operator to stream messages to the `AssertionResult` object. To provide more readable messages in Boolean assertions (e.g. `EXPECT_TRUE()`), write a predicate function that returns `AssertionResult` instead of `bool`. For example, if you define `IsEven()` as: ``` ::testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return ::testing::AssertionSuccess(); else return ::testing::AssertionFailure() << n << " is odd"; } ``` instead of: ``` bool IsEven(int n) { return (n % 2) == 0; } ``` the failed assertion `EXPECT_TRUE(IsEven(Fib(4)))` will print:
Value of: IsEven(Fib(4))
Actual: false (*3 is odd*)
Expected: true
instead of a more opaque
Value of: IsEven(Fib(4))
Actual: false
Expected: true
If you want informative messages in `EXPECT_FALSE` and `ASSERT_FALSE` as well, and are fine with making the predicate slower in the success case, you can supply a success message: ``` ::testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return ::testing::AssertionSuccess() << n << " is even"; else return ::testing::AssertionFailure() << n << " is odd"; } ``` Then the statement `EXPECT_FALSE(IsEven(Fib(6)))` will print
Value of: IsEven(Fib(6))
Actual: true (8 is even)
Expected: false
_Availability_: Linux, Windows, Mac; since version 1.4.1. ### Using a Predicate-Formatter ### If you find the default message generated by `(ASSERT|EXPECT)_PRED*` and `(ASSERT|EXPECT)_(TRUE|FALSE)` unsatisfactory, or some arguments to your predicate do not support streaming to `ostream`, you can instead use the following _predicate-formatter assertions_ to _fully_ customize how the message is formatted: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_PRED_FORMAT1(`_pred\_format1, val1_`);` | `EXPECT_PRED_FORMAT1(`_pred\_format1, val1_`);` | _pred\_format1(val1)_ is successful | | `ASSERT_PRED_FORMAT2(`_pred\_format2, val1, val2_`);` | `EXPECT_PRED_FORMAT2(`_pred\_format2, val1, val2_`);` | _pred\_format2(val1, val2)_ is successful | | `...` | `...` | `...` | The difference between this and the previous two groups of macros is that instead of a predicate, `(ASSERT|EXPECT)_PRED_FORMAT*` take a _predicate-formatter_ (_pred\_formatn_), which is a function or functor with the signature: `::testing::AssertionResult PredicateFormattern(const char* `_expr1_`, const char* `_expr2_`, ... const char* `_exprn_`, T1 `_val1_`, T2 `_val2_`, ... Tn `_valn_`);` where _val1_, _val2_, ..., and _valn_ are the values of the predicate arguments, and _expr1_, _expr2_, ..., and _exprn_ are the corresponding expressions as they appear in the source code. The types `T1`, `T2`, ..., and `Tn` can be either value types or reference types. For example, if an argument has type `Foo`, you can declare it as either `Foo` or `const Foo&`, whichever is appropriate. A predicate-formatter returns a `::testing::AssertionResult` object to indicate whether the assertion has succeeded or not. The only way to create such an object is to call one of these factory functions: As an example, let's improve the failure message in the previous example, which uses `EXPECT_PRED2()`: ``` // Returns the smallest prime common divisor of m and n, // or 1 when m and n are mutually prime. int SmallestPrimeCommonDivisor(int m, int n) { ... } // A predicate-formatter for asserting that two integers are mutually prime. ::testing::AssertionResult AssertMutuallyPrime(const char* m_expr, const char* n_expr, int m, int n) { if (MutuallyPrime(m, n)) return ::testing::AssertionSuccess(); return ::testing::AssertionFailure() << m_expr << " and " << n_expr << " (" << m << " and " << n << ") are not mutually prime, " << "as they have a common divisor " << SmallestPrimeCommonDivisor(m, n); } ``` With this predicate-formatter, we can use ``` EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c); ``` to generate the message
b and c (4 and 10) are not mutually prime, as they have a common divisor 2.
As you may have realized, many of the assertions we introduced earlier are special cases of `(EXPECT|ASSERT)_PRED_FORMAT*`. In fact, most of them are indeed defined using `(EXPECT|ASSERT)_PRED_FORMAT*`. _Availability_: Linux, Windows, Mac. ## Floating-Point Comparison ## Comparing floating-point numbers is tricky. Due to round-off errors, it is very unlikely that two floating-points will match exactly. Therefore, `ASSERT_EQ` 's naive comparison usually doesn't work. And since floating-points can have a wide value range, no single fixed error bound works. It's better to compare by a fixed relative error bound, except for values close to 0 due to the loss of precision there. In general, for floating-point comparison to make sense, the user needs to carefully choose the error bound. If they don't want or care to, comparing in terms of Units in the Last Place (ULPs) is a good default, and Google Test provides assertions to do this. Full details about ULPs are quite long; if you want to learn more, see [this article on float comparison](http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm). ### Floating-Point Macros ### | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_FLOAT_EQ(`_val1, val2_`);` | `EXPECT_FLOAT_EQ(`_val1, val2_`);` | the two `float` values are almost equal | | `ASSERT_DOUBLE_EQ(`_val1, val2_`);` | `EXPECT_DOUBLE_EQ(`_val1, val2_`);` | the two `double` values are almost equal | By "almost equal", we mean the two values are within 4 ULP's from each other. The following assertions allow you to choose the acceptable error bound: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_NEAR(`_val1, val2, abs\_error_`);` | `EXPECT_NEAR`_(val1, val2, abs\_error_`);` | the difference between _val1_ and _val2_ doesn't exceed the given absolute error | _Availability_: Linux, Windows, Mac. ### Floating-Point Predicate-Format Functions ### Some floating-point operations are useful, but not that often used. In order to avoid an explosion of new macros, we provide them as predicate-format functions that can be used in predicate assertion macros (e.g. `EXPECT_PRED_FORMAT2`, etc). ``` EXPECT_PRED_FORMAT2(::testing::FloatLE, val1, val2); EXPECT_PRED_FORMAT2(::testing::DoubleLE, val1, val2); ``` Verifies that _val1_ is less than, or almost equal to, _val2_. You can replace `EXPECT_PRED_FORMAT2` in the above table with `ASSERT_PRED_FORMAT2`. _Availability_: Linux, Windows, Mac. ## Windows HRESULT assertions ## These assertions test for `HRESULT` success or failure. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_HRESULT_SUCCEEDED(`_expression_`);` | `EXPECT_HRESULT_SUCCEEDED(`_expression_`);` | _expression_ is a success `HRESULT` | | `ASSERT_HRESULT_FAILED(`_expression_`);` | `EXPECT_HRESULT_FAILED(`_expression_`);` | _expression_ is a failure `HRESULT` | The generated output contains the human-readable error message associated with the `HRESULT` code returned by _expression_. You might use them like this: ``` CComPtr shell; ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application")); CComVariant empty; ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty)); ``` _Availability_: Windows. ## Type Assertions ## You can call the function ``` ::testing::StaticAssertTypeEq(); ``` to assert that types `T1` and `T2` are the same. The function does nothing if the assertion is satisfied. If the types are different, the function call will fail to compile, and the compiler error message will likely (depending on the compiler) show you the actual values of `T1` and `T2`. This is mainly useful inside template code. _Caveat:_ When used inside a member function of a class template or a function template, `StaticAssertTypeEq()` is effective _only if_ the function is instantiated. For example, given: ``` template class Foo { public: void Bar() { ::testing::StaticAssertTypeEq(); } }; ``` the code: ``` void Test1() { Foo foo; } ``` will _not_ generate a compiler error, as `Foo::Bar()` is never actually instantiated. Instead, you need: ``` void Test2() { Foo foo; foo.Bar(); } ``` to cause a compiler error. _Availability:_ Linux, Windows, Mac; since version 1.3.0. ## Assertion Placement ## You can use assertions in any C++ function. In particular, it doesn't have to be a method of the test fixture class. The one constraint is that assertions that generate a fatal failure (`FAIL*` and `ASSERT_*`) can only be used in void-returning functions. This is a consequence of Google Test not using exceptions. By placing it in a non-void function you'll get a confusing compile error like `"error: void value not ignored as it ought to be"`. If you need to use assertions in a function that returns non-void, one option is to make the function return the value in an out parameter instead. For example, you can rewrite `T2 Foo(T1 x)` to `void Foo(T1 x, T2* result)`. You need to make sure that `*result` contains some sensible value even when the function returns prematurely. As the function now returns `void`, you can use any assertion inside of it. If changing the function's type is not an option, you should just use assertions that generate non-fatal failures, such as `ADD_FAILURE*` and `EXPECT_*`. _Note_: Constructors and destructors are not considered void-returning functions, according to the C++ language specification, and so you may not use fatal assertions in them. You'll get a compilation error if you try. A simple workaround is to transfer the entire body of the constructor or destructor to a private void-returning method. However, you should be aware that a fatal assertion failure in a constructor does not terminate the current test, as your intuition might suggest; it merely returns from the constructor early, possibly leaving your object in a partially-constructed state. Likewise, a fatal assertion failure in a destructor may leave your object in a partially-destructed state. Use assertions carefully in these situations! # Teaching Google Test How to Print Your Values # When a test assertion such as `EXPECT_EQ` fails, Google Test prints the argument values to help you debug. It does this using a user-extensible value printer. This printer knows how to print built-in C++ types, native arrays, STL containers, and any type that supports the `<<` operator. For other types, it prints the raw bytes in the value and hopes that you the user can figure it out. As mentioned earlier, the printer is _extensible_. That means you can teach it to do a better job at printing your particular type than to dump the bytes. To do that, define `<<` for your type: ``` #include namespace foo { class Bar { ... }; // We want Google Test to be able to print instances of this. // It's important that the << operator is defined in the SAME // namespace that defines Bar. C++'s look-up rules rely on that. ::std::ostream& operator<<(::std::ostream& os, const Bar& bar) { return os << bar.DebugString(); // whatever needed to print bar to os } } // namespace foo ``` Sometimes, this might not be an option: your team may consider it bad style to have a `<<` operator for `Bar`, or `Bar` may already have a `<<` operator that doesn't do what you want (and you cannot change it). If so, you can instead define a `PrintTo()` function like this: ``` #include namespace foo { class Bar { ... }; // It's important that PrintTo() is defined in the SAME // namespace that defines Bar. C++'s look-up rules rely on that. void PrintTo(const Bar& bar, ::std::ostream* os) { *os << bar.DebugString(); // whatever needed to print bar to os } } // namespace foo ``` If you have defined both `<<` and `PrintTo()`, the latter will be used when Google Test is concerned. This allows you to customize how the value appears in Google Test's output without affecting code that relies on the behavior of its `<<` operator. If you want to print a value `x` using Google Test's value printer yourself, just call `::testing::PrintToString(`_x_`)`, which returns an `std::string`: ``` vector > bar_ints = GetBarIntVector(); EXPECT_TRUE(IsCorrectBarIntVector(bar_ints)) << "bar_ints = " << ::testing::PrintToString(bar_ints); ``` # Death Tests # In many applications, there are assertions that can cause application failure if a condition is not met. These sanity checks, which ensure that the program is in a known good state, are there to fail at the earliest possible time after some program state is corrupted. If the assertion checks the wrong condition, then the program may proceed in an erroneous state, which could lead to memory corruption, security holes, or worse. Hence it is vitally important to test that such assertion statements work as expected. Since these precondition checks cause the processes to die, we call such tests _death tests_. More generally, any test that checks that a program terminates (except by throwing an exception) in an expected fashion is also a death test. Note that if a piece of code throws an exception, we don't consider it "death" for the purpose of death tests, as the caller of the code could catch the exception and avoid the crash. If you want to verify exceptions thrown by your code, see [Exception Assertions](#exception-assertions). If you want to test `EXPECT_*()/ASSERT_*()` failures in your test code, see [Catching Failures](#catching-failures). ## How to Write a Death Test ## Google Test has the following macros to support death tests: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_DEATH(`_statement, regex_`);` | `EXPECT_DEATH(`_statement, regex_`);` | _statement_ crashes with the given error | | `ASSERT_DEATH_IF_SUPPORTED(`_statement, regex_`);` | `EXPECT_DEATH_IF_SUPPORTED(`_statement, regex_`);` | if death tests are supported, verifies that _statement_ crashes with the given error; otherwise verifies nothing | | `ASSERT_EXIT(`_statement, predicate, regex_`);` | `EXPECT_EXIT(`_statement, predicate, regex_`);` |_statement_ exits with the given error and its exit code matches _predicate_ | where _statement_ is a statement that is expected to cause the process to die, _predicate_ is a function or function object that evaluates an integer exit status, and _regex_ is a regular expression that the stderr output of _statement_ is expected to match. Note that _statement_ can be _any valid statement_ (including _compound statement_) and doesn't have to be an expression. As usual, the `ASSERT` variants abort the current test function, while the `EXPECT` variants do not. **Note:** We use the word "crash" here to mean that the process terminates with a _non-zero_ exit status code. There are two possibilities: either the process has called `exit()` or `_exit()` with a non-zero value, or it may be killed by a signal. This means that if _statement_ terminates the process with a 0 exit code, it is _not_ considered a crash by `EXPECT_DEATH`. Use `EXPECT_EXIT` instead if this is the case, or if you want to restrict the exit code more precisely. A predicate here must accept an `int` and return a `bool`. The death test succeeds only if the predicate returns `true`. Google Test defines a few predicates that handle the most common cases: ``` ::testing::ExitedWithCode(exit_code) ``` This expression is `true` if the program exited normally with the given exit code. ``` ::testing::KilledBySignal(signal_number) // Not available on Windows. ``` This expression is `true` if the program was killed by the given signal. The `*_DEATH` macros are convenient wrappers for `*_EXIT` that use a predicate that verifies the process' exit code is non-zero. Note that a death test only cares about three things: 1. does _statement_ abort or exit the process? 1. (in the case of `ASSERT_EXIT` and `EXPECT_EXIT`) does the exit status satisfy _predicate_? Or (in the case of `ASSERT_DEATH` and `EXPECT_DEATH`) is the exit status non-zero? And 1. does the stderr output match _regex_? In particular, if _statement_ generates an `ASSERT_*` or `EXPECT_*` failure, it will **not** cause the death test to fail, as Google Test assertions don't abort the process. To write a death test, simply use one of the above macros inside your test function. For example, ``` TEST(MyDeathTest, Foo) { // This death test uses a compound statement. ASSERT_DEATH({ int n = 5; Foo(&n); }, "Error on line .* of Foo()"); } TEST(MyDeathTest, NormalExit) { EXPECT_EXIT(NormalExit(), ::testing::ExitedWithCode(0), "Success"); } TEST(MyDeathTest, KillMyself) { EXPECT_EXIT(KillMyself(), ::testing::KilledBySignal(SIGKILL), "Sending myself unblockable signal"); } ``` verifies that: * calling `Foo(5)` causes the process to die with the given error message, * calling `NormalExit()` causes the process to print `"Success"` to stderr and exit with exit code 0, and * calling `KillMyself()` kills the process with signal `SIGKILL`. The test function body may contain other assertions and statements as well, if necessary. _Important:_ We strongly recommend you to follow the convention of naming your test case (not test) `*DeathTest` when it contains a death test, as demonstrated in the above example. The `Death Tests And Threads` section below explains why. If a test fixture class is shared by normal tests and death tests, you can use typedef to introduce an alias for the fixture class and avoid duplicating its code: ``` class FooTest : public ::testing::Test { ... }; typedef FooTest FooDeathTest; TEST_F(FooTest, DoesThis) { // normal test } TEST_F(FooDeathTest, DoesThat) { // death test } ``` _Availability:_ Linux, Windows (requires MSVC 8.0 or above), Cygwin, and Mac (the latter three are supported since v1.3.0). `(ASSERT|EXPECT)_DEATH_IF_SUPPORTED` are new in v1.4.0. ## Regular Expression Syntax ## On POSIX systems (e.g. Linux, Cygwin, and Mac), Google Test uses the [POSIX extended regular expression](http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04) syntax in death tests. To learn about this syntax, you may want to read this [Wikipedia entry](http://en.wikipedia.org/wiki/Regular_expression#POSIX_Extended_Regular_Expressions). On Windows, Google Test uses its own simple regular expression implementation. It lacks many features you can find in POSIX extended regular expressions. For example, we don't support union (`"x|y"`), grouping (`"(xy)"`), brackets (`"[xy]"`), and repetition count (`"x{5,7}"`), among others. Below is what we do support (Letter `A` denotes a literal character, period (`.`), or a single `\\` escape sequence; `x` and `y` denote regular expressions.): | `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 the `.` character | | `.` | 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` | To help you determine which capability is available on your system, Google Test defines macro `GTEST_USES_POSIX_RE=1` when it uses POSIX extended regular expressions, or `GTEST_USES_SIMPLE_RE=1` when it uses the simple version. If you want your death tests to work in both cases, you can either `#if` on these macros or use the more limited syntax only. ## How It Works ## Under the hood, `ASSERT_EXIT()` spawns a new process and executes the death test statement in that process. The details of of how precisely that happens depend on the platform and the variable `::testing::GTEST_FLAG(death_test_style)` (which is initialized from the command-line flag `--gtest_death_test_style`). * On POSIX systems, `fork()` (or `clone()` on Linux) is used to spawn the child, after which: * If the variable's value is `"fast"`, the death test statement is immediately executed. * If the variable's value is `"threadsafe"`, the child process re-executes the unit test binary just as it was originally invoked, but with some extra flags to cause just the single death test under consideration to be run. * On Windows, the child is spawned using the `CreateProcess()` API, and re-executes the binary to cause just the single death test under consideration to be run - much like the `threadsafe` mode on POSIX. Other values for the variable are illegal and will cause the death test to fail. Currently, the flag's default value is `"fast"`. However, we reserve the right to change it in the future. Therefore, your tests should not depend on this. In either case, the parent process waits for the child process to complete, and checks that 1. the child's exit status satisfies the predicate, and 1. the child's stderr matches the regular expression. If the death test statement runs to completion without dying, the child process will nonetheless terminate, and the assertion fails. ## Death Tests And Threads ## The reason for the two death test styles has to do with thread safety. Due to well-known problems with forking in the presence of threads, death tests should be run in a single-threaded context. Sometimes, however, it isn't feasible to arrange that kind of environment. For example, statically-initialized modules may start threads before main is ever reached. Once threads have been created, it may be difficult or impossible to clean them up. Google Test has three features intended to raise awareness of threading issues. 1. A warning is emitted if multiple threads are running when a death test is encountered. 1. Test cases with a name ending in "DeathTest" are run before all other tests. 1. It uses `clone()` instead of `fork()` to spawn the child process on Linux (`clone()` is not available on Cygwin and Mac), as `fork()` is more likely to cause the child to hang when the parent process has multiple threads. It's perfectly fine to create threads inside a death test statement; they are executed in a separate process and cannot affect the parent. ## Death Test Styles ## The "threadsafe" death test style was introduced in order to help mitigate the risks of testing in a possibly multithreaded environment. It trades increased test execution time (potentially dramatically so) for improved thread safety. We suggest using the faster, default "fast" style unless your test has specific problems with it. You can choose a particular style of death tests by setting the flag programmatically: ``` ::testing::FLAGS_gtest_death_test_style = "threadsafe"; ``` You can do this in `main()` to set the style for all death tests in the binary, or in individual tests. Recall that flags are saved before running each test and restored afterwards, so you need not do that yourself. For example: ``` TEST(MyDeathTest, TestOne) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; // This test is run in the "threadsafe" style: ASSERT_DEATH(ThisShouldDie(), ""); } TEST(MyDeathTest, TestTwo) { // This test is run in the "fast" style: ASSERT_DEATH(ThisShouldDie(), ""); } int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); ::testing::FLAGS_gtest_death_test_style = "fast"; return RUN_ALL_TESTS(); } ``` ## Caveats ## The _statement_ argument of `ASSERT_EXIT()` can be any valid C++ statement. If it leaves the current function via a `return` statement or by throwing an exception, the death test is considered to have failed. Some Google Test macros may return from the current function (e.g. `ASSERT_TRUE()`), so be sure to avoid them in _statement_. Since _statement_ runs in the child process, any in-memory side effect (e.g. modifying a variable, releasing memory, etc) it causes will _not_ be observable in the parent process. In particular, if you release memory in a death test, your program will fail the heap check as the parent process will never see the memory reclaimed. To solve this problem, you can 1. try not to free memory in a death test; 1. free the memory again in the parent process; or 1. do not use the heap checker in your program. Due to an implementation detail, you cannot place multiple death test assertions on the same line; otherwise, compilation will fail with an unobvious error message. Despite the improved thread safety afforded by the "threadsafe" style of death test, thread problems such as deadlock are still possible in the presence of handlers registered with `pthread_atfork(3)`. # Using Assertions in Sub-routines # ## Adding Traces to Assertions ## If a test sub-routine is called from several places, when an assertion inside it fails, it can be hard to tell which invocation of the sub-routine the failure is from. You can alleviate this problem using extra logging or custom failure messages, but that usually clutters up your tests. A better solution is to use the `SCOPED_TRACE` macro: | `SCOPED_TRACE(`_message_`);` | |:-----------------------------| where _message_ can be anything streamable to `std::ostream`. This macro will cause the current file name, line number, and the given message to be added in every failure message. The effect will be undone when the control leaves the current lexical scope. For example, ``` 10: void Sub1(int n) { 11: EXPECT_EQ(1, Bar(n)); 12: EXPECT_EQ(2, Bar(n + 1)); 13: } 14: 15: TEST(FooTest, Bar) { 16: { 17: SCOPED_TRACE("A"); // This trace point will be included in 18: // every failure in this scope. 19: Sub1(1); 20: } 21: // Now it won't. 22: Sub1(9); 23: } ``` could result in messages like these: ``` path/to/foo_test.cc:11: Failure Value of: Bar(n) Expected: 1 Actual: 2 Trace: path/to/foo_test.cc:17: A path/to/foo_test.cc:12: Failure Value of: Bar(n + 1) Expected: 2 Actual: 3 ``` Without the trace, it would've been difficult to know which invocation of `Sub1()` the two failures come from respectively. (You could add an extra message to each assertion in `Sub1()` to indicate the value of `n`, but that's tedious.) Some tips on using `SCOPED_TRACE`: 1. With a suitable message, it's often enough to use `SCOPED_TRACE` at the beginning of a sub-routine, instead of at each call site. 1. When calling sub-routines inside a loop, make the loop iterator part of the message in `SCOPED_TRACE` such that you can know which iteration the failure is from. 1. Sometimes the line number of the trace point is enough for identifying the particular invocation of a sub-routine. In this case, you don't have to choose a unique message for `SCOPED_TRACE`. You can simply use `""`. 1. You can use `SCOPED_TRACE` in an inner scope when there is one in the outer scope. In this case, all active trace points will be included in the failure messages, in reverse order they are encountered. 1. The trace dump is clickable in Emacs' compilation buffer - hit return on a line number and you'll be taken to that line in the source file! _Availability:_ Linux, Windows, Mac. ## Propagating Fatal Failures ## A common pitfall when using `ASSERT_*` and `FAIL*` is not understanding that when they fail they only abort the _current function_, not the entire test. For example, the following test will segfault: ``` void Subroutine() { // Generates a fatal failure and aborts the current function. ASSERT_EQ(1, 2); // The following won't be executed. ... } TEST(FooTest, Bar) { Subroutine(); // The intended behavior is for the fatal failure // in Subroutine() to abort the entire test. // The actual behavior: the function goes on after Subroutine() returns. int* p = NULL; *p = 3; // Segfault! } ``` Since we don't use exceptions, it is technically impossible to implement the intended behavior here. To alleviate this, Google Test provides two solutions. You could use either the `(ASSERT|EXPECT)_NO_FATAL_FAILURE` assertions or the `HasFatalFailure()` function. They are described in the following two subsections. ### Asserting on Subroutines ### As shown above, if your test calls a subroutine that has an `ASSERT_*` failure in it, the test will continue after the subroutine returns. This may not be what you want. Often people want fatal failures to propagate like exceptions. For that Google Test offers the following macros: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_NO_FATAL_FAILURE(`_statement_`);` | `EXPECT_NO_FATAL_FAILURE(`_statement_`);` | _statement_ doesn't generate any new fatal failures in the current thread. | Only failures in the thread that executes the assertion are checked to determine the result of this type of assertions. If _statement_ creates new threads, failures in these threads are ignored. Examples: ``` ASSERT_NO_FATAL_FAILURE(Foo()); int i; EXPECT_NO_FATAL_FAILURE({ i = Bar(); }); ``` _Availability:_ Linux, Windows, Mac. Assertions from multiple threads are currently not supported. ### Checking for Failures in the Current Test ### `HasFatalFailure()` in the `::testing::Test` class returns `true` if an assertion in the current test has suffered a fatal failure. This allows functions to catch fatal failures in a sub-routine and return early. ``` class Test { public: ... static bool HasFatalFailure(); }; ``` The typical usage, which basically simulates the behavior of a thrown exception, is: ``` TEST(FooTest, Bar) { Subroutine(); // Aborts if Subroutine() had a fatal failure. if (HasFatalFailure()) return; // The following won't be executed. ... } ``` If `HasFatalFailure()` is used outside of `TEST()` , `TEST_F()` , or a test fixture, you must add the `::testing::Test::` prefix, as in: ``` if (::testing::Test::HasFatalFailure()) return; ``` Similarly, `HasNonfatalFailure()` returns `true` if the current test has at least one non-fatal failure, and `HasFailure()` returns `true` if the current test has at least one failure of either kind. _Availability:_ Linux, Windows, Mac. `HasNonfatalFailure()` and `HasFailure()` are available since version 1.4.0. # Logging Additional Information # In your test code, you can call `RecordProperty("key", value)` to log additional information, where `value` can be either a string or an `int`. The _last_ value recorded for a key will be emitted to the XML output if you specify one. For example, the test ``` TEST_F(WidgetUsageTest, MinAndMaxWidgets) { RecordProperty("MaximumWidgets", ComputeMaxUsage()); RecordProperty("MinimumWidgets", ComputeMinUsage()); } ``` will output XML like this: ``` ... ... ``` _Note_: * `RecordProperty()` is a static member of the `Test` class. Therefore it needs to be prefixed with `::testing::Test::` if used outside of the `TEST` body and the test fixture class. * `key` must be a valid XML attribute name, and cannot conflict with the ones already used by Google Test (`name`, `status`, `time`, `classname`, `type_param`, and `value_param`). * Calling `RecordProperty()` outside of the lifespan of a test is allowed. If it's called outside of a test but between a test case's `SetUpTestCase()` and `TearDownTestCase()` methods, it will be attributed to the XML element for the test case. If it's called outside of all test cases (e.g. in a test environment), it will be attributed to the top-level XML element. _Availability_: Linux, Windows, Mac. # Sharing Resources Between Tests in the Same Test Case # Google Test creates a new test fixture object for each test in order to make tests independent and easier to debug. However, sometimes tests use resources that are expensive to set up, making the one-copy-per-test model prohibitively expensive. If the tests don't change the resource, there's no harm in them sharing a single resource copy. So, in addition to per-test set-up/tear-down, Google Test also supports per-test-case set-up/tear-down. To use it: 1. In your test fixture class (say `FooTest` ), define as `static` some member variables to hold the shared resources. 1. In the same test fixture class, define a `static void SetUpTestCase()` function (remember not to spell it as **`SetupTestCase`** with a small `u`!) to set up the shared resources and a `static void TearDownTestCase()` function to tear them down. That's it! Google Test automatically calls `SetUpTestCase()` before running the _first test_ in the `FooTest` test case (i.e. before creating the first `FooTest` object), and calls `TearDownTestCase()` after running the _last test_ in it (i.e. after deleting the last `FooTest` object). In between, the tests can use the shared resources. Remember that the test order is undefined, so your code can't depend on a test preceding or following another. Also, the tests must either not modify the state of any shared resource, or, if they do modify the state, they must restore the state to its original value before passing control to the next test. Here's an example of per-test-case set-up and tear-down: ``` class FooTest : public ::testing::Test { protected: // Per-test-case set-up. // Called before the first test in this test case. // Can be omitted if not needed. static void SetUpTestCase() { shared_resource_ = new ...; } // Per-test-case tear-down. // Called after the last test in this test case. // Can be omitted if not needed. static void TearDownTestCase() { delete shared_resource_; shared_resource_ = NULL; } // You can define per-test set-up and tear-down logic as usual. virtual void SetUp() { ... } virtual void TearDown() { ... } // Some expensive resource shared by all tests. static T* shared_resource_; }; T* FooTest::shared_resource_ = NULL; TEST_F(FooTest, Test1) { ... you can refer to shared_resource here ... } TEST_F(FooTest, Test2) { ... you can refer to shared_resource here ... } ``` _Availability:_ Linux, Windows, Mac. # Global Set-Up and Tear-Down # Just as you can do set-up and tear-down at the test level and the test case level, you can also do it at the test program level. Here's how. First, you subclass the `::testing::Environment` class to define a test environment, which knows how to set-up and tear-down: ``` class Environment { public: 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() {} }; ``` Then, you register an instance of your environment class with Google Test by calling the `::testing::AddGlobalTestEnvironment()` function: ``` Environment* AddGlobalTestEnvironment(Environment* env); ``` Now, when `RUN_ALL_TESTS()` is called, it first calls the `SetUp()` method of the environment object, then runs the tests if there was no fatal failures, and finally calls `TearDown()` of the environment object. It's OK to register multiple environment objects. In this case, their `SetUp()` will be called in the order they are registered, and their `TearDown()` will be called in the reverse order. Note that Google Test takes ownership of the registered environment objects. Therefore **do not delete them** by yourself. You should call `AddGlobalTestEnvironment()` 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. One way to do this is to 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). _Availability:_ Linux, Windows, Mac. # Value Parameterized Tests # _Value-parameterized tests_ allow you to test your code with different parameters without writing multiple copies of the same test. Suppose you write a test for your code and then realize that your code is affected by a presence of a Boolean command line flag. ``` TEST(MyCodeTest, TestFoo) { // A code to test foo(). } ``` Usually people factor their test code into a function with a Boolean parameter in such situations. The function sets the flag, then executes the testing code. ``` void TestFooHelper(bool flag_value) { flag = flag_value; // A code to test foo(). } TEST(MyCodeTest, TestFoo) { TestFooHelper(false); TestFooHelper(true); } ``` But this setup has serious drawbacks. First, when a test assertion fails in your tests, it becomes unclear what value of the parameter caused it to fail. You can stream a clarifying message into your `EXPECT`/`ASSERT` statements, but it you'll have to do it with all of them. Second, you have to add one such helper function per test. What if you have ten tests? Twenty? A hundred? Value-parameterized tests will let you write your test only once and then easily instantiate and run it with an arbitrary number of parameter values. Here are some other situations when value-parameterized tests come handy: * You want to test different implementations of an OO interface. * You want to test your code over various inputs (a.k.a. data-driven testing). This feature is easy to abuse, so please exercise your good sense when doing it! ## How to Write Value-Parameterized Tests ## To write value-parameterized tests, first you should define a fixture class. It must be derived from both `::testing::Test` and `::testing::WithParamInterface` (the latter is a pure interface), where `T` is the type of your parameter values. For convenience, you can just derive the fixture class from `::testing::TestWithParam`, which itself is derived from both `::testing::Test` and `::testing::WithParamInterface`. `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 { // You can implement all the usual fixture class members here. // To access the test parameter, call GetParam() from class // TestWithParam. }; // Or, when you want to add parameters to a pre-existing fixture class: class BaseTest : public ::testing::Test { ... }; class BarTest : public BaseTest, public ::testing::WithParamInterface { ... }; ``` Then, use the `TEST_P` macro to define as many test patterns using 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 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)` and `ValuesIn(begin, end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)`. `container`, `begin`, and `end` can be expressions whose values are determined at run time. | | `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. This is only available if your system provides the `` header. If you are sure your system does, and Google Test disagrees, you can override it by defining `GTEST_HAS_TR1_TUPLE=1`. See comments in [include/gtest/internal/gtest-port.h](../include/gtest/internal/gtest-port.h) for more information. | For more details, see the comments at the definitions of these functions in the [source code](../include/gtest/gtest-param-test.h). 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, ::testing::Values("meeny", "miny", "moe")); ``` To distinguish different instances of the pattern (yes, you can instantiate it more than once), the first argument to `INSTANTIATE_TEST_CASE_P` 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](#running-a-subset-of-the-tests). 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, ::testing::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. You can see [these](../samples/sample7_unittest.cc) [files](../samples/sample8_unittest.cc) for more examples. _Availability_: Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.2.0. ## Creating Value-Parameterized Abstract Tests ## In the above, we define and instantiate `FooTest` in the same source file. Sometimes you may want to define value-parameterized tests in a library and let other people instantiate them later. This pattern is known as abstract tests. As an example of its application, when you are designing an interface you can write a standard suite of abstract tests (perhaps using a factory function as the test parameter) that all implementations of the interface are expected to pass. When someone implements the interface, he can instantiate your suite to get all the interface-conformance tests for free. To define abstract tests, you should organize your code like this: 1. Put the definition of the parameterized test fixture class (e.g. `FooTest`) in a header file, say `foo_param_test.h`. Think of this as _declaring_ your abstract tests. 1. Put the `TEST_P` definitions in `foo_param_test.cc`, which includes `foo_param_test.h`. Think of this as _implementing_ your abstract tests. Once they are defined, you can instantiate them by including `foo_param_test.h`, invoking `INSTANTIATE_TEST_CASE_P()`, and linking with `foo_param_test.cc`. You can instantiate the same abstract test case multiple times, possibly in different source files. # Typed Tests # Suppose you have multiple implementations of the same interface and want to make sure that all of them satisfy some common requirements. Or, you may have defined several types that are supposed to conform to the same "concept" and you want to verify it. In both cases, you want the same test logic repeated for different types. While you can write one `TEST` or `TEST_F` for each type you want to test (and you may even factor the test logic into a function template that you invoke from the `TEST`), it's tedious and doesn't scale: if you want _m_ tests over _n_ types, you'll end up writing _m\*n_ `TEST`s. _Typed tests_ allow you to repeat the same test logic over a list of types. You only need to write the test logic once, although you must know the type list when writing typed tests. Here's how you do it: First, define a fixture class template. It should be parameterized by a type. Remember to derive it from `::testing::Test`: ``` template class FooTest : public ::testing::Test { public: ... typedef std::list 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: ``` typedef ::testing::Types MyTypes; TYPED_TEST_CASE(FooTest, MyTypes); ``` The `typedef` is necessary for the `TYPED_TEST_CASE` macro to parse correctly. Otherwise the compiler will think that each comma in the type list introduces a new macro argument. Then, use `TYPED_TEST()` instead of `TEST_F()` to define a typed test for this test case. You can repeat this as many times as you want: ``` TYPED_TEST(FooTest, DoesBlah) { // Inside a test, refer to the special name TypeParam to get the type // parameter. Since we are inside a derived class template, C++ requires // us 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. The 'typename' is required to satisfy the compiler. typename TestFixture::List values; values.push_back(n); ... } TYPED_TEST(FooTest, HasPropertyA) { ... } ``` You can see `samples/sample6_unittest.cc` for a complete example. _Availability:_ Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.1.0. # Type-Parameterized Tests # _Type-parameterized tests_ are like typed tests, except that they don't require you to know the list of types ahead of time. Instead, you can define the test logic first and instantiate it with different type lists later. You can even instantiate it more than once in the same program. 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, the author of each implementation can just instantiate the test suite with his type to verify that it conforms to the requirements, without having to write similar tests repeatedly. Here's an example: First, define a fixture class template, as we did with typed tests: ``` template class FooTest : public ::testing::Test { ... }; ``` Next, declare that you will define a type-parameterized test case: ``` TYPED_TEST_CASE_P(FooTest); ``` The `_P` suffix is for "parameterized" or "pattern", whichever you prefer to think. Then, use `TYPED_TEST_P()` to define a type-parameterized test. You can repeat this as many times 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 using the `REGISTER_TYPED_TEST_CASE_P` macro 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. ``` typedef ::testing::Types MyTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); ``` To distinguish different instances of the pattern, the first argument to the `INSTANTIATE_TYPED_TEST_CASE_P` macro is a prefix that will be added to the actual test case name. Remember to pick unique prefixes for different instances. In the special case where the type list contains only one type, you can write that type directly without `::testing::Types<...>`, like this: ``` INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); ``` You can see `samples/sample6_unittest.cc` for a complete example. _Availability:_ Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.1.0. # Testing Private Code # If you change your software's internal implementation, your tests should not break as long as the change is not observable by users. Therefore, per the _black-box testing principle_, most of the time you should test your code through its public interfaces. If you still find yourself needing to test internal implementation code, consider if there's a better design that wouldn't require you to do so. If you absolutely have to test non-public interface code though, you can. There are two cases to consider: * Static functions (_not_ the same as static member functions!) or unnamed namespaces, and * Private or protected class members ## Static Functions ## Both static functions and definitions/declarations in an unnamed namespace are only visible within the same translation unit. To test them, you can `#include` the entire `.cc` file being tested in your `*_test.cc` file. (`#include`ing `.cc` files is not a good way to reuse code - you should not do this in production code!) However, a better approach is to move the private code into the `foo::internal` namespace, where `foo` is the namespace your project normally uses, and put the private declarations in a `*-internal.h` file. Your production `.cc` files and your tests are allowed to include this internal header, but your clients are not. This way, you can fully test your internal implementation without leaking it to your clients. ## Private Class Members ## Private class members are only accessible from within the class or by friends. To access a class' private members, you can declare your test fixture as a friend to the class and define accessors in your fixture. Tests using the fixture can then access the private members of your production class via the accessors in the fixture. Note that even though your fixture is a friend to your production class, your tests are not automatically friends to it, as they are technically defined in sub-classes of the fixture. Another way to test private members is to refactor them into an implementation class, which is then declared in a `*-internal.h` file. Your clients aren't allowed to include this header but your tests can. Such is called the Pimpl (Private Implementation) idiom. Or, you can declare an individual test as a friend of your class by adding this line in the class body: ``` FRIEND_TEST(TestCaseName, TestName); ``` For example, ``` // foo.h #include "gtest/gtest_prod.h" // Defines FRIEND_TEST. class Foo { ... private: FRIEND_TEST(FooTest, BarReturnsZeroOnNull); int Bar(void* x); }; // foo_test.cc ... TEST(FooTest, BarReturnsZeroOnNull) { Foo foo; EXPECT_EQ(0, foo.Bar(NULL)); // Uses Foo's private member Bar(). } ``` Pay special attention when your class is defined in a namespace, as you should define your test fixtures and tests in the same namespace if you want them to be friends of your class. For example, if the code to be tested looks like: ``` namespace my_namespace { class Foo { friend class FooTest; FRIEND_TEST(FooTest, Bar); FRIEND_TEST(FooTest, Baz); ... definition of the class Foo ... }; } // namespace my_namespace ``` Your test code should be something like: ``` namespace my_namespace { class FooTest : public ::testing::Test { protected: ... }; TEST_F(FooTest, Bar) { ... } TEST_F(FooTest, Baz) { ... } } // namespace my_namespace ``` # Catching Failures # If you are building a testing utility on top of Google Test, you'll want to test your utility. What framework would you use to test it? Google Test, of course. The challenge is to verify that your testing utility reports failures correctly. In frameworks that report a failure by throwing an exception, you could catch the exception and assert on it. But Google Test doesn't use exceptions, so how do we test that a piece of code generates an expected failure? `"gtest/gtest-spi.h"` contains some constructs to do this. After `#include`ing this header, you can use | `EXPECT_FATAL_FAILURE(`_statement, substring_`);` | |:--------------------------------------------------| to assert that _statement_ generates a fatal (e.g. `ASSERT_*`) failure whose message contains the given _substring_, or use | `EXPECT_NONFATAL_FAILURE(`_statement, substring_`);` | |:-----------------------------------------------------| if you are expecting a non-fatal (e.g. `EXPECT_*`) failure. For technical reasons, there are some caveats: 1. You cannot stream a failure message to either macro. 1. _statement_ in `EXPECT_FATAL_FAILURE()` cannot reference local non-static variables or non-static members of `this` object. 1. _statement_ in `EXPECT_FATAL_FAILURE()` cannot return a value. _Note:_ Google Test is designed with threads in mind. Once the synchronization primitives in `"gtest/internal/gtest-port.h"` have been implemented, Google Test will become thread-safe, meaning that you can then use assertions in multiple threads concurrently. Before that, however, Google Test only supports single-threaded usage. Once thread-safe, `EXPECT_FATAL_FAILURE()` and `EXPECT_NONFATAL_FAILURE()` will capture failures in the current thread only. If _statement_ creates new threads, failures in these threads will be ignored. If you want to capture failures from all threads instead, you should use the following macros: | `EXPECT_FATAL_FAILURE_ON_ALL_THREADS(`_statement, substring_`);` | |:-----------------------------------------------------------------| | `EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(`_statement, substring_`);` | # Getting the Current Test's Name # Sometimes a function may need to know the name of the currently running test. For example, you may be using the `SetUp()` method of your test fixture to set the golden file name based on which test is running. The `::testing::TestInfo` class has this information: ``` namespace testing { class TestInfo { public: // Returns the test case name and the test name, respectively. // // Do NOT delete or free the return value - it's managed by the // TestInfo class. const char* test_case_name() const; const char* name() const; }; } // namespace testing ``` > To obtain a `TestInfo` object for the currently running test, call `current_test_info()` on the `UnitTest` singleton object: ``` // Gets information about the currently running test. // Do NOT delete the returned object - it's managed by the UnitTest class. const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); printf("We are in test %s of test case %s.\n", test_info->name(), test_info->test_case_name()); ``` `current_test_info()` returns a null pointer if no test is running. In particular, you cannot find the test case name in `TestCaseSetUp()`, `TestCaseTearDown()` (where you know the test case name implicitly), or functions called from them. _Availability:_ Linux, Windows, Mac. # Extending Google Test by Handling Test Events # Google Test provides an event listener API to let you receive notifications about the progress of a test program and test failures. The events you can listen to include the start and end of the test program, a test case, or a test method, among others. You may use this API to augment or replace the standard console output, replace the XML output, or provide a completely different form of output, such as a GUI or a database. You can also use test events as checkpoints to implement a resource leak checker, for example. _Availability:_ Linux, Windows, Mac; since v1.4.0. ## Defining Event Listeners ## To define a event listener, you subclass either [testing::TestEventListener](../include/gtest/gtest.h#L991) or [testing::EmptyTestEventListener](../include/gtest/gtest.h#L1044). The former is an (abstract) interface, where each pure virtual method
can be overridden to handle a test event
(For example, when a test starts, the `OnTestStart()` method will be called.). The latter provides an empty implementation of all methods in the interface, such that a subclass only needs to override the methods it cares about. When an event is fired, its context is passed to the handler function as an argument. The following argument types are used: * [UnitTest](../include/gtest/gtest.h#L1151) reflects the state of the entire test program, * [TestCase](../include/gtest/gtest.h#L778) has information about a test case, which can contain one or more tests, * [TestInfo](../include/gtest/gtest.h#L644) contains the state of a test, and * [TestPartResult](../include/gtest/gtest-test-part.h#L47) represents the result of a test assertion. An event handler function can examine the argument it receives to find out interesting information about the event and the test program's state. Here's an example: ``` class MinimalistPrinter : public ::testing::EmptyTestEventListener { // Called before a test starts. virtual void OnTestStart(const ::testing::TestInfo& test_info) { printf("*** Test %s.%s starting.\n", test_info.test_case_name(), test_info.name()); } // Called after a failed assertion or a SUCCEED() invocation. virtual void OnTestPartResult( const ::testing::TestPartResult& test_part_result) { printf("%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()); } // Called after a test ends. virtual void OnTestEnd(const ::testing::TestInfo& test_info) { printf("*** Test %s.%s ending.\n", test_info.test_case_name(), test_info.name()); } }; ``` ## Using Event Listeners ## To use the event listener you have defined, add an instance of it to the Google Test event listener list (represented by class [TestEventListeners](../include/gtest/gtest.h#L1064) - note the "s" at the end of the name) in your `main()` function, before calling `RUN_ALL_TESTS()`: ``` int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); // Gets hold of the event listener list. ::testing::TestEventListeners& listeners = ::testing::UnitTest::GetInstance()->listeners(); // Adds a listener to the end. Google Test takes the ownership. listeners.Append(new MinimalistPrinter); return RUN_ALL_TESTS(); } ``` There's only one problem: the default test result printer is still in effect, so its output will mingle with the output from your minimalist printer. To suppress the default printer, just release it from the event listener list and delete it. You can do so by adding one line: ``` ... delete listeners.Release(listeners.default_result_printer()); listeners.Append(new MinimalistPrinter); return RUN_ALL_TESTS(); ``` Now, sit back and enjoy a completely different output from your tests. For more details, you can read this [sample](../samples/sample9_unittest.cc). You may append more than one listener to the list. When an `On*Start()` or `OnTestPartResult()` event is fired, the listeners will receive it in the order they appear in the list (since new listeners are added to the end of the list, the default text printer and the default XML generator will receive the event first). An `On*End()` event will be received by the listeners in the _reverse_ order. This allows output by listeners added later to be framed by output from listeners added earlier. ## Generating Failures in Listeners ## You may use failure-raising macros (`EXPECT_*()`, `ASSERT_*()`, `FAIL()`, etc) when processing an event. There are some restrictions: 1. You cannot generate any failure in `OnTestPartResult()` (otherwise it will cause `OnTestPartResult()` to be called recursively). 1. A listener that handles `OnTestPartResult()` is not allowed to generate any failure. When you add listeners to the listener list, you should put listeners that handle `OnTestPartResult()` _before_ listeners that can generate failures. This ensures that failures generated by the latter are attributed to the right test by the former. We have a sample of failure-raising listener [here](../samples/sample10_unittest.cc). # Running Test Programs: Advanced Options # Google Test test programs are ordinary executables. Once built, you can run them directly and affect their behavior via the following environment variables and/or command line flags. For the flags to work, your programs must call `::testing::InitGoogleTest()` before calling `RUN_ALL_TESTS()`. To see a list of supported flags and their usage, please run your test program with the `--help` flag. You can also use `-h`, `-?`, or `/?` for short. This feature is added in version 1.3.0. If an option is specified both by an environment variable and by a flag, the latter takes precedence. Most of the options can also be set/read in code: to access the value of command line flag `--gtest_foo`, write `::testing::GTEST_FLAG(foo)`. A common pattern is to set the value of a flag before calling `::testing::InitGoogleTest()` to change the default value of the flag: ``` int main(int argc, char** argv) { // Disables elapsed time by default. ::testing::GTEST_FLAG(print_time) = false; // This allows the user to override the flag on the command line. ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ``` ## Selecting Tests ## This section shows various options for choosing which tests to run. ### Listing Test Names ### Sometimes it is necessary to list the available tests in a program before running them so that a filter may be applied if needed. Including the flag `--gtest_list_tests` overrides all other flags and lists tests in the following format: ``` TestCase1. TestName1 TestName2 TestCase2. TestName ``` None of the tests listed are actually run if the flag is provided. There is no corresponding environment variable for this flag. _Availability:_ Linux, Windows, Mac. ### Running a Subset of the Tests ### By default, a Google Test program runs all tests the user has defined. Sometimes, you want to run only a subset of the tests (e.g. for debugging or quickly verifying a change). If you set the `GTEST_FILTER` environment variable or the `--gtest_filter` flag to a filter string, Google Test will only run the tests whose full names (in the form of `TestCaseName.TestName`) match the filter. The format of a filter is a '`:`'-separated list of wildcard patterns (called the positive patterns) optionally followed by a '`-`' and another '`:`'-separated pattern list (called the negative patterns). A test matches the filter if and only if it matches any of the positive patterns but does not match any of the negative patterns. A pattern may contain `'*'` (matches any string) or `'?'` (matches any single character). For convenience, the filter `'*-NegativePatterns'` can be also written as `'-NegativePatterns'`. For example: * `./foo_test` Has no flag, and thus runs all its tests. * `./foo_test --gtest_filter=*` Also runs everything, due to the single match-everything `*` value. * `./foo_test --gtest_filter=FooTest.*` Runs everything in test case `FooTest`. * `./foo_test --gtest_filter=*Null*:*Constructor*` Runs any test whose full name contains either `"Null"` or `"Constructor"`. * `./foo_test --gtest_filter=-*DeathTest.*` Runs all non-death tests. * `./foo_test --gtest_filter=FooTest.*-FooTest.Bar` Runs everything in test case `FooTest` except `FooTest.Bar`. _Availability:_ Linux, Windows, Mac. ### Temporarily Disabling Tests ### If you have a broken test that you cannot fix right away, you can add the `DISABLED_` prefix to its name. This will exclude it from execution. This is better than commenting out the code or using `#if 0`, as disabled tests are still compiled (and thus won't rot). If you need to disable all tests in a test case, you can either add `DISABLED_` to the front of the name of each test, or alternatively add it to the front of the test case name. For example, the following tests won't be run by Google Test, even though they will still be compiled: ``` // Tests that Foo does Abc. TEST(FooTest, DISABLED_DoesAbc) { ... } class DISABLED_BarTest : public ::testing::Test { ... }; // Tests that Bar does Xyz. TEST_F(DISABLED_BarTest, DoesXyz) { ... } ``` _Note:_ This feature should only be used for temporary pain-relief. You still have to fix the disabled tests at a later date. As a reminder, Google Test will print a banner warning you if a test program contains any disabled tests. _Tip:_ You can easily count the number of disabled tests you have using `grep`. This number can be used as a metric for improving your test quality. _Availability:_ Linux, Windows, Mac. ### Temporarily Enabling Disabled Tests ### To include [disabled tests](#temporarily-disabling-tests) in test execution, just invoke the test program with the `--gtest_also_run_disabled_tests` flag or set the `GTEST_ALSO_RUN_DISABLED_TESTS` environment variable to a value other than `0`. You can combine this with the [--gtest\_filter](#running-a-subset-of-the-tests) flag to further select which disabled tests to run. _Availability:_ Linux, Windows, Mac; since version 1.3.0. ## Repeating the Tests ## Once in a while you'll run into a test whose result is hit-or-miss. Perhaps it will fail only 1% of the time, making it rather hard to reproduce the bug under a debugger. This can be a major source of frustration. The `--gtest_repeat` flag allows you to repeat all (or selected) test methods in a program many times. Hopefully, a flaky test will eventually fail and give you a chance to debug. Here's how to use it: | `$ foo_test --gtest_repeat=1000` | Repeat foo\_test 1000 times and don't stop at failures. | |:---------------------------------|:--------------------------------------------------------| | `$ foo_test --gtest_repeat=-1` | A negative count means repeating forever. | | `$ foo_test --gtest_repeat=1000 --gtest_break_on_failure` | Repeat foo\_test 1000 times, stopping at the first failure. This is especially useful when running under a debugger: when the testfails, it will drop into the debugger and you can then inspect variables and stacks. | | `$ foo_test --gtest_repeat=1000 --gtest_filter=FooBar` | Repeat the tests whose name matches the filter 1000 times. | If your test program contains global set-up/tear-down code registered using `AddGlobalTestEnvironment()`, it will be repeated in each iteration as well, as the flakiness may be in it. You can also specify the repeat count by setting the `GTEST_REPEAT` environment variable. _Availability:_ Linux, Windows, Mac. ## Shuffling the Tests ## You can specify the `--gtest_shuffle` flag (or set the `GTEST_SHUFFLE` environment variable to `1`) to run the tests in a program in a random order. This helps to reveal bad dependencies between tests. By default, Google Test uses a random seed calculated from the current time. Therefore you'll get a different order every time. The console output includes the random seed value, such that you can reproduce an order-related test failure later. To specify the random seed explicitly, use the `--gtest_random_seed=SEED` flag (or set the `GTEST_RANDOM_SEED` environment variable), where `SEED` is an integer between 0 and 99999. The seed value 0 is special: it tells Google Test to do the default behavior of calculating the seed from the current time. If you combine this with `--gtest_repeat=N`, Google Test will pick a different random seed and re-shuffle the tests in each iteration. _Availability:_ Linux, Windows, Mac; since v1.4.0. ## Controlling Test Output ## This section teaches how to tweak the way test results are reported. ### Colored Terminal Output ### Google Test can use colors in its terminal output to make it easier to spot the separation between tests, and whether tests passed. You can set the GTEST\_COLOR environment variable or set the `--gtest_color` command line flag to `yes`, `no`, or `auto` (the default) to enable colors, disable colors, or let Google Test decide. When the value is `auto`, Google Test will use colors if and only if the output goes to a terminal and (on non-Windows platforms) the `TERM` environment variable is set to `xterm` or `xterm-color`. _Availability:_ Linux, Windows, Mac. ### Suppressing the Elapsed Time ### By default, Google Test prints the time it takes to run each test. To suppress that, run the test program with the `--gtest_print_time=0` command line flag. Setting the `GTEST_PRINT_TIME` environment variable to `0` has the same effect. _Availability:_ Linux, Windows, Mac. (In Google Test 1.3.0 and lower, the default behavior is that the elapsed time is **not** printed.) ### Generating an XML Report ### Google Test can emit a detailed XML report to a file in addition to its normal textual output. The report contains the duration of each test, and thus can help you identify slow tests. To generate the XML report, set the `GTEST_OUTPUT` environment variable or the `--gtest_output` flag to the string `"xml:_path_to_output_file_"`, which will create the file at the given location. You can also just use the string `"xml"`, in which case the output can be found in the `test_detail.xml` file in the current directory. If you specify a directory (for example, `"xml:output/directory/"` on Linux or `"xml:output\directory\"` on Windows), Google Test will create the XML file in that directory, named after the test executable (e.g. `foo_test.xml` for test program `foo_test` or `foo_test.exe`). If the file already exists (perhaps left over from a previous run), Google Test will pick a different name (e.g. `foo_test_1.xml`) to avoid overwriting it. The report uses the format described here. It is based on the `junitreport` Ant task and can be parsed by popular continuous build systems like [Hudson](https://hudson.dev.java.net/). Since that format was originally intended for Java, a little interpretation is required to make it apply to Google Test tests, as shown here: ``` ``` * The root `` element corresponds to the entire test program. * `` elements correspond to Google Test test cases. * `` elements correspond to Google Test test functions. For instance, the following program ``` TEST(MathTest, Addition) { ... } TEST(MathTest, Subtraction) { ... } TEST(LogicTest, NonContradiction) { ... } ``` could generate this report: ``` ``` Things to note: * The `tests` attribute of a `` or `` element tells how many test functions the Google Test program or test case contains, while the `failures` attribute tells how many of them failed. * The `time` attribute expresses the duration of the test, test case, or entire test program in milliseconds. * Each `` element corresponds to a single failed Google Test assertion. * Some JUnit concepts don't apply to Google Test, yet we have to conform to the DTD. Therefore you'll see some dummy elements and attributes in the report. You can safely ignore these parts. _Availability:_ Linux, Windows, Mac. ## Controlling How Failures Are Reported ## ### Turning Assertion Failures into Break-Points ### When running test programs under a debugger, it's very convenient if the debugger can catch an assertion failure and automatically drop into interactive mode. Google Test's _break-on-failure_ mode supports this behavior. To enable it, set the `GTEST_BREAK_ON_FAILURE` environment variable to a value other than `0` . Alternatively, you can use the `--gtest_break_on_failure` command line flag. _Availability:_ Linux, Windows, Mac. ### Disabling Catching Test-Thrown Exceptions ### Google Test can be used either with or without exceptions enabled. If a test throws a C++ exception or (on Windows) a structured exception (SEH), by default Google Test catches it, reports it as a test failure, and continues with the next test method. This maximizes the coverage of a test run. Also, on Windows an uncaught exception will cause a pop-up window, so catching the exceptions allows you to run the tests automatically. When debugging the test failures, however, you may instead want the exceptions to be handled by the debugger, such that you can examine the call stack when an exception is thrown. To achieve that, set the `GTEST_CATCH_EXCEPTIONS` environment variable to `0`, or use the `--gtest_catch_exceptions=0` flag when running the tests. **Availability**: Linux, Windows, Mac. ### Letting Another Testing Framework Drive ### If you work on a project that has already been using another testing framework and is not ready to completely switch to Google Test yet, you can get much of Google Test's benefit by using its assertions in your existing tests. Just change your `main()` function to look like: ``` #include "gtest/gtest.h" int main(int argc, char** argv) { ::testing::GTEST_FLAG(throw_on_failure) = true; // Important: Google Test must be initialized. ::testing::InitGoogleTest(&argc, argv); ... whatever your existing testing framework requires ... } ``` With that, you can use Google Test assertions in addition to the native assertions your testing framework provides, for example: ``` void TestFooDoesBar() { Foo foo; EXPECT_LE(foo.Bar(1), 100); // A Google Test assertion. CPPUNIT_ASSERT(foo.IsEmpty()); // A native assertion. } ``` If a Google Test assertion fails, it will print an error message and throw an exception, which will be treated as a failure by your host testing framework. If you compile your code with exceptions disabled, a failed Google Test assertion will instead exit your program with a non-zero code, which will also signal a test failure to your test runner. If you don't write `::testing::GTEST_FLAG(throw_on_failure) = true;` in your `main()`, you can alternatively enable this feature by specifying the `--gtest_throw_on_failure` flag on the command-line or setting the `GTEST_THROW_ON_FAILURE` environment variable to a non-zero value. Death tests are _not_ supported when other test framework is used to organize tests. _Availability:_ Linux, Windows, Mac; since v1.3.0. ## Distributing Test Functions to Multiple Machines ## If you have more than one machine you can use to run a test program, you might want to run the test functions in parallel and get the result faster. We call this technique _sharding_, where each machine is called a _shard_. Google Test is compatible with test sharding. To take advantage of this feature, your test runner (not part of Google Test) needs to do the following: 1. Allocate a number of machines (shards) to run the tests. 1. On each shard, set the `GTEST_TOTAL_SHARDS` environment variable to the total number of shards. It must be the same for all shards. 1. On each shard, set the `GTEST_SHARD_INDEX` environment variable to the index of the shard. Different shards must be assigned different indices, which must be in the range `[0, GTEST_TOTAL_SHARDS - 1]`. 1. Run the same test program on all shards. When Google Test sees the above two environment variables, it will select a subset of the test functions to run. Across all shards, each test function in the program will be run exactly once. 1. Wait for all shards to finish, then collect and report the results. Your project may have tests that were written without Google Test and thus don't understand this protocol. In order for your test runner to figure out which test supports sharding, it can set the environment variable `GTEST_SHARD_STATUS_FILE` to a non-existent file path. If a test program supports sharding, it will create this file to acknowledge the fact (the actual contents of the file are not important at this time; although we may stick some useful information in it in the future.); otherwise it will not create it. Here's an example to make it clear. Suppose you have a test program `foo_test` that contains the following 5 test functions: ``` TEST(A, V) TEST(A, W) TEST(B, X) TEST(B, Y) TEST(B, Z) ``` and you have 3 machines at your disposal. To run the test functions in parallel, you would set `GTEST_TOTAL_SHARDS` to 3 on all machines, and set `GTEST_SHARD_INDEX` to 0, 1, and 2 on the machines respectively. Then you would run the same `foo_test` on each machine. Google Test reserves the right to change how the work is distributed across the shards, but here's one possible scenario: * Machine #0 runs `A.V` and `B.X`. * Machine #1 runs `A.W` and `B.Y`. * Machine #2 runs `B.Z`. _Availability:_ Linux, Windows, Mac; since version 1.3.0. # Fusing Google Test Source Files # Google Test's implementation consists of ~30 files (excluding its own tests). Sometimes you may want them to be packaged up in two files (a `.h` and a `.cc`) instead, such that you can easily copy them to a new machine and start hacking there. For this we provide an experimental Python script `fuse_gtest_files.py` in the `scripts/` directory (since release 1.3.0). Assuming you have Python 2.4 or above installed on your machine, just go to that directory and run ``` python fuse_gtest_files.py OUTPUT_DIR ``` and you should see an `OUTPUT_DIR` directory being created with files `gtest/gtest.h` and `gtest/gtest-all.cc` in it. These files contain everything you need to use Google Test. Just copy them to anywhere you want and you are ready to write tests. You can use the [scripts/test/Makefile](../scripts/test/Makefile) file as an example on how to compile your tests against them. # Where to Go from Here # Congratulations! You've now learned more advanced Google Test tools and are ready to tackle more complex testing tasks. If you want to dive even deeper, you can read the [Frequently-Asked Questions](FAQ.md). assimp-4.1.0/contrib/gtest/docs/DevGuide.md0000644002537200234200000001415313213503245021014 0ustar zmoelnigiemusers If you are interested in understanding the internals of Google Test, building from source, or contributing ideas or modifications to the project, then this document is for you. # Introduction # First, let's give you some background of the project. ## Licensing ## All Google Test source and pre-built packages are provided under the [New BSD License](http://www.opensource.org/licenses/bsd-license.php). ## The Google Test Community ## The Google Test community exists primarily through the [discussion group](http://groups.google.com/group/googletestframework) and the GitHub repository. You are definitely encouraged to contribute to the discussion and you can also help us to keep the effectiveness of the group high by following and promoting the guidelines listed here. ### Please Be Friendly ### Showing courtesy and respect to others is a vital part of the Google culture, and we strongly encourage everyone participating in Google Test development to join us in accepting nothing less. Of course, being courteous is not the same as failing to constructively disagree with each other, but it does mean that we should be respectful of each other when enumerating the 42 technical reasons that a particular proposal may not be the best choice. There's never a reason to be antagonistic or dismissive toward anyone who is sincerely trying to contribute to a discussion. Sure, C++ testing is serious business and all that, but it's also a lot of fun. Let's keep it that way. Let's strive to be one of the friendliest communities in all of open source. As always, discuss Google Test in the official GoogleTest discussion group. You don't have to actually submit code in order to sign up. Your participation itself is a valuable contribution. # Working with the Code # If you want to get your hands dirty with the code inside Google Test, this is the section for you. ## Compiling from Source ## Once you check out the code, you can find instructions on how to compile it in the [README](../README.md) file. ## Testing ## A testing framework is of no good if itself is not thoroughly tested. Tests should be written for any new code, and changes should be verified to not break existing tests before they are submitted for review. To perform the tests, follow the instructions in [README](../README.md) and verify that there are no failures. # Contributing Code # We are excited that Google Test is now open source, and hope to get great patches from the community. Before you fire up your favorite IDE and begin hammering away at that new feature, though, please take the time to read this section and understand the process. While it seems rigorous, we want to keep a high standard of quality in the code base. ## Contributor License Agreements ## You must sign a Contributor License Agreement (CLA) before we can accept any code. The CLA protects you and us. * If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA](http://code.google.com/legal/individual-cla-v1.0.html). * If you work for a company that wants to allow you to contribute your work to Google Test, then you'll need to sign a [corporate CLA](http://code.google.com/legal/corporate-cla-v1.0.html). Follow either of the two links above to access the appropriate CLA and instructions for how to sign and return it. ## Coding Style ## To keep the source consistent, readable, diffable and easy to merge, we use a fairly rigid coding style, as defined by the [google-styleguide](http://code.google.com/p/google-styleguide/) project. All patches will be expected to conform to the style outlined [here](http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml). ## Updating Generated Code ## Some of Google Test's source files are generated by the Pump tool (a Python script). If you need to update such files, please modify the source (`foo.h.pump`) and re-generate the C++ file using Pump. You can read the PumpManual for details. ## Submitting Patches ## Please do submit code. Here's what you need to do: 1. A submission should be a set of changes that addresses one issue in the [issue tracker](https://github.com/google/googletest/issues). Please don't mix more than one logical change per submittal, because it makes the history hard to follow. If you want to make a change that doesn't have a corresponding issue in the issue tracker, please create one. 1. Also, coordinate with team members that are listed on the issue in question. This ensures that work isn't being duplicated and communicating your plan early also generally leads to better patches. 1. Ensure that your code adheres to the [Google Test source code style](#Coding_Style.md). 1. Ensure that there are unit tests for your code. 1. Sign a Contributor License Agreement. 1. Create a Pull Request in the usual way. ## Google Test Committers ## The current members of the Google Test engineering team are the only committers at present. In the great tradition of eating one's own dogfood, we will be requiring each new Google Test engineering team member to earn the right to become a committer by following the procedures in this document, writing consistently great code, and demonstrating repeatedly that he or she truly gets the zen of Google Test. # Release Process # We follow a typical release process: 1. A release branch named `release-X.Y` is created. 1. Bugs are fixed and features are added in trunk; those individual patches are merged into the release branch until it's stable. 1. An individual point release (the `Z` in `X.Y.Z`) is made by creating a tag from the branch. 1. Repeat steps 2 and 3 throughout one release cycle (as determined by features or time). 1. Go back to step 1 to create another release branch and so on. --- This page is based on the [Making GWT Better](http://code.google.com/webtoolkit/makinggwtbetter.html) guide from the [Google Web Toolkit](http://code.google.com/webtoolkit/) project. Except as otherwise [noted](http://code.google.com/policies.html#restrictions), the content of this page is licensed under the [Creative Commons Attribution 2.5 License](http://creativecommons.org/licenses/by/2.5/). assimp-4.1.0/contrib/gtest/docs/V1_5_XcodeGuide.md0000644002537200234200000002005713213503245022132 0ustar zmoelnigiemusers This guide will explain how to use the Google Testing Framework in your Xcode projects on Mac OS X. This tutorial begins by quickly explaining what to do for experienced users. After the quick start, the guide goes provides additional explanation about each step. # Quick Start # Here is the quick guide for using Google Test in your Xcode project. 1. Download the source from the [website](http://code.google.com/p/googletest) using this command: `svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only` 1. Open up the `gtest.xcodeproj` in the `googletest-read-only/xcode/` directory and build the gtest.framework. 1. Create a new "Shell Tool" target in your Xcode project called something like "UnitTests" 1. Add the gtest.framework to your project and add it to the "Link Binary with Libraries" build phase of "UnitTests" 1. Add your unit test source code to the "Compile Sources" build phase of "UnitTests" 1. Edit the "UnitTests" executable and add an environment variable named "DYLD\_FRAMEWORK\_PATH" with a value equal to the path to the framework containing the gtest.framework relative to the compiled executable. 1. Build and Go The following sections further explain each of the steps listed above in depth, describing in more detail how to complete it including some variations. # Get the Source # Currently, the gtest.framework discussed here isn't available in a tagged release of Google Test, it is only available in the trunk. As explained at the Google Test [site](http://code.google.com/p/googletest/source/checkout">svn), you can get the code from anonymous SVN with this command: ``` svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only ``` Alternatively, if you are working with Subversion in your own code base, you can add Google Test as an external dependency to your own Subversion repository. By following this approach, everyone that checks out your svn repository will also receive a copy of Google Test (a specific version, if you wish) without having to check it out explicitly. This makes the set up of your project simpler and reduces the copied code in the repository. To use `svn:externals`, decide where you would like to have the external source reside. You might choose to put the external source inside the trunk, because you want it to be part of the branch when you make a release. However, keeping it outside the trunk in a version-tagged directory called something like `third-party/googletest/1.0.1`, is another option. Once the location is established, use `svn propedit svn:externals _directory_` to set the svn:externals property on a directory in your repository. This directory won't contain the code, but be its versioned parent directory. The command `svn propedit` will bring up your Subversion editor, making editing the long, (potentially multi-line) property simpler. This same method can be used to check out a tagged branch, by using the appropriate URL (e.g. `http://googletest.googlecode.com/svn/tags/release-1.0.1`). Additionally, the svn:externals property allows the specification of a particular revision of the trunk with the `-r_##_` option (e.g. `externals/src/googletest -r60 http://googletest.googlecode.com/svn/trunk`). Here is an example of using the svn:externals properties on a trunk (read via `svn propget`) of a project. This value checks out a copy of Google Test into the `trunk/externals/src/googletest/` directory. ``` [Computer:svn] user$ svn propget svn:externals trunk externals/src/googletest http://googletest.googlecode.com/svn/trunk ``` # Add the Framework to Your Project # The next step is to build and add the gtest.framework to your own project. This guide describes two common ways below. * **Option 1** --- The simplest way to add Google Test to your own project, is to open gtest.xcodeproj (found in the xcode/ directory of the Google Test trunk) and build the framework manually. Then, add the built framework into your project using the "Add->Existing Framework..." from the context menu or "Project->Add..." from the main menu. The gtest.framework is relocatable and contains the headers and object code that you'll need to make tests. This method requires rebuilding every time you upgrade Google Test in your project. * **Option 2** --- If you are going to be living off the trunk of Google Test, incorporating its latest features into your unit tests (or are a Google Test developer yourself). You'll want to rebuild the framework every time the source updates. to do this, you'll need to add the gtest.xcodeproj file, not the framework itself, to your own Xcode project. Then, from the build products that are revealed by the project's disclosure triangle, you can find the gtest.framework, which can be added to your targets (discussed below). # Make a Test Target # To start writing tests, make a new "Shell Tool" target. This target template is available under BSD, Cocoa, or Carbon. Add your unit test source code to the "Compile Sources" build phase of the target. Next, you'll want to add gtest.framework in two different ways, depending upon which option you chose above. * **Option 1** --- During compilation, Xcode will need to know that you are linking against the gtest.framework. Add the gtest.framework to the "Link Binary with Libraries" build phase of your test target. This will include the Google Test headers in your header search path, and will tell the linker where to find the library. * **Option 2** --- If your working out of the trunk, you'll also want to add gtest.framework to your "Link Binary with Libraries" build phase of your test target. In addition, you'll want to add the gtest.framework as a dependency to your unit test target. This way, Xcode will make sure that gtest.framework is up to date, every time your build your target. Finally, if you don't share build directories with Google Test, you'll have to copy the gtest.framework into your own build products directory using a "Run Script" build phase. # Set Up the Executable Run Environment # Since the unit test executable is a shell tool, it doesn't have a bundle with a `Contents/Frameworks` directory, in which to place gtest.framework. Instead, the dynamic linker must be told at runtime to search for the framework in another location. This can be accomplished by setting the "DYLD\_FRAMEWORK\_PATH" environment variable in the "Edit Active Executable ..." Arguments tab, under "Variables to be set in the environment:". The path for this value is the path (relative or absolute) of the directory containing the gtest.framework. If you haven't set up the DYLD\_FRAMEWORK\_PATH, correctly, you might get a message like this: ``` [Session started at 2008-08-15 06:23:57 -0600.] dyld: Library not loaded: @loader_path/../Frameworks/gtest.framework/Versions/A/gtest Referenced from: /Users/username/Documents/Sandbox/gtestSample/build/Debug/WidgetFrameworkTest Reason: image not found ``` To correct this problem, got to the directory containing the executable named in "Referenced from:" value in the error message above. Then, with the terminal in this location, find the relative path to the directory containing the gtest.framework. That is the value you'll need to set as the DYLD\_FRAMEWORK\_PATH. # Build and Go # Now, when you click "Build and Go", the test will be executed. Dumping out something like this: ``` [Session started at 2008-08-06 06:36:13 -0600.] [==========] Running 2 tests from 1 test case. [----------] Global test environment set-up. [----------] 2 tests from WidgetInitializerTest [ RUN ] WidgetInitializerTest.TestConstructor [ OK ] WidgetInitializerTest.TestConstructor [ RUN ] WidgetInitializerTest.TestConversion [ OK ] WidgetInitializerTest.TestConversion [----------] Global test environment tear-down [==========] 2 tests from 1 test case ran. [ PASSED ] 2 tests. The Debugger has exited with status 0. ``` # Summary # Unit testing is a valuable way to ensure your data model stays valid even during rapid development or refactoring. The Google Testing Framework is a great unit testing framework for C and C++ which integrates well with an Xcode development environment.assimp-4.1.0/contrib/gtest/docs/PumpManual.md0000644002537200234200000001561413213503245021402 0ustar zmoelnigiemusers Pump is Useful for Meta Programming. # The Problem # Template and macro libraries often need to define many classes, functions, or macros that vary only (or almost only) in the number of arguments they take. It's a lot of repetitive, mechanical, and error-prone work. Variadic templates and variadic macros can alleviate the problem. However, while both are being considered by the C++ committee, neither is in the standard yet or widely supported by compilers. Thus they are often not a good choice, especially when your code needs to be portable. And their capabilities are still limited. As a result, authors of such libraries often have to write scripts to generate their implementation. However, our experience is that it's tedious to write such scripts, which tend to reflect the structure of the generated code poorly and are often hard to read and edit. For example, a small change needed in the generated code may require some non-intuitive, non-trivial changes in the script. This is especially painful when experimenting with the code. # Our Solution # Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta Programming, or Practical Utility for Meta Programming, whichever you prefer) is a simple meta-programming tool for C++. The idea is that a programmer writes a `foo.pump` file which contains C++ code plus meta code that manipulates the C++ code. The meta code can handle iterations over a range, nested iterations, local meta variable definitions, simple arithmetic, and conditional expressions. You can view it as a small Domain-Specific Language. The meta language is designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, for example) and concise, making Pump code intuitive and easy to maintain. ## Highlights ## * The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms. * Pump tries to be smart with respect to [Google's style guide](http://code.google.com/p/google-styleguide/): it breaks long lines (easy to have when they are generated) at acceptable places to fit within 80 columns and indent the continuation lines correctly. * The format is human-readable and more concise than XML. * The format works relatively well with Emacs' C++ mode. ## Examples ## The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line): ``` $var n = 3 $$ Defines a meta variable n. $range i 0..n $$ Declares the range of meta iterator i (inclusive). $for i [[ $$ Meta loop. // Foo$i does blah for $i-ary predicates. $range j 1..i template class Foo$i { $if i == 0 [[ blah a; ]] $elif i <= 2 [[ blah b; ]] $else [[ blah c; ]] }; ]] ``` will be translated by the Pump compiler to: ``` // Foo0 does blah for 0-ary predicates. template class Foo0 { blah a; }; // Foo1 does blah for 1-ary predicates. template class Foo1 { blah b; }; // Foo2 does blah for 2-ary predicates. template class Foo2 { blah b; }; // Foo3 does blah for 3-ary predicates. template class Foo3 { blah c; }; ``` In another example, ``` $range i 1..n Func($for i + [[a$i]]); $$ The text between i and [[ is the separator between iterations. ``` will generate one of the following lines (without the comments), depending on the value of `n`: ``` Func(); // If n is 0. Func(a1); // If n is 1. Func(a1 + a2); // If n is 2. Func(a1 + a2 + a3); // If n is 3. // And so on... ``` ## Constructs ## We support the following meta programming constructs: | `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. | |:----------------|:-----------------------------------------------------------------------------------------------| | `$range id exp..exp` | Sets the range of an iteration variable, which can be reused in multiple loops later. | | `$for id sep [[ code ]]` | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`. | | `$($)` | Generates a single `$` character. | | `$id` | Value of the named constant or iteration variable. | | `$(exp)` | Value of the expression. | | `$if exp [[ code ]] else_branch` | Conditional. | | `[[ code ]]` | Meta lexical block. | | `cpp_code` | Raw C++ code. | | `$$ comment` | Meta comment. | **Note:** To give the user some freedom in formatting the Pump source code, Pump ignores a new-line character if it's right after `$for foo` or next to `[[` or `]]`. Without this rule you'll often be forced to write very long lines to get the desired output. Therefore sometimes you may need to insert an extra new-line in such places for a new-line to show up in your output. ## Grammar ## ``` code ::= atomic_code* atomic_code ::= $var id = exp | $var id = [[ code ]] | $range id exp..exp | $for id sep [[ code ]] | $($) | $id | $(exp) | $if exp [[ code ]] else_branch | [[ code ]] | cpp_code sep ::= cpp_code | empty_string else_branch ::= $else [[ code ]] | $elif exp [[ code ]] else_branch | empty_string exp ::= simple_expression_in_Python_syntax ``` ## Code ## You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still very unpolished and lacks automated tests, although it has been successfully used many times. If you find a chance to use it in your project, please let us know what you think! We also welcome help on improving Pump. ## Real Examples ## You can find real-world applications of Pump in [Google Test](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgoogletest\.googlecode\.com) and [Google Mock](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgooglemock\.googlecode\.com). The source file `foo.h.pump` generates `foo.h`. ## Tips ## * If a meta variable is followed by a letter or digit, you can separate them using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper` generate `Foo1Helper` when `j` is 1. * To avoid extra-long Pump source lines, you can break a line anywhere you want by inserting `[[]]` followed by a new line. Since any new-line character next to `[[` or `]]` is ignored, the generated code won't contain this new line. assimp-4.1.0/contrib/gtest/docs/V1_7_AdvancedGuide.md0000644002537200234200000025314213213503245022602 0ustar zmoelnigiemusers Now that you have read [Primer](V1_7_Primer.md) and learned how to write tests using Google Test, it's time to learn some new tricks. This document will show you more assertions as well as how to construct complex failure messages, propagate fatal failures, reuse and speed up your test fixtures, and use various flags with your tests. # More Assertions # This section covers some less frequently used, but still significant, assertions. ## Explicit Success and Failure ## These three assertions do not actually test a value or expression. Instead, they generate a success or failure directly. Like the macros that actually perform a test, you may stream a custom failure message into the them. | `SUCCEED();` | |:-------------| Generates a success. This does NOT make the overall test succeed. A test is considered successful only if none of its assertions fail during its execution. Note: `SUCCEED()` is purely documentary and currently doesn't generate any user-visible output. However, we may add `SUCCEED()` messages to Google Test's output in the future. | `FAIL();` | `ADD_FAILURE();` | `ADD_FAILURE_AT("`_file\_path_`", `_line\_number_`);` | |:-----------|:-----------------|:------------------------------------------------------| `FAIL()` generates a fatal failure, while `ADD_FAILURE()` and `ADD_FAILURE_AT()` generate a nonfatal failure. These are useful when control flow, rather than a Boolean expression, deteremines the test's success or failure. For example, you might want to write something like: ``` switch(expression) { case 1: ... some checks ... case 2: ... some other checks ... default: FAIL() << "We shouldn't get here."; } ``` _Availability_: Linux, Windows, Mac. ## Exception Assertions ## These are for verifying that a piece of code throws (or does not throw) an exception of the given type: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_THROW(`_statement_, _exception\_type_`);` | `EXPECT_THROW(`_statement_, _exception\_type_`);` | _statement_ throws an exception of the given type | | `ASSERT_ANY_THROW(`_statement_`);` | `EXPECT_ANY_THROW(`_statement_`);` | _statement_ throws an exception of any type | | `ASSERT_NO_THROW(`_statement_`);` | `EXPECT_NO_THROW(`_statement_`);` | _statement_ doesn't throw any exception | Examples: ``` ASSERT_THROW(Foo(5), bar_exception); EXPECT_NO_THROW({ int n = 5; Bar(&n); }); ``` _Availability_: Linux, Windows, Mac; since version 1.1.0. ## Predicate Assertions for Better Error Messages ## Even though Google Test has a rich set of assertions, they can never be complete, as it's impossible (nor a good idea) to anticipate all the scenarios a user might run into. Therefore, sometimes a user has to use `EXPECT_TRUE()` to check a complex expression, for lack of a better macro. This has the problem of not showing you the values of the parts of the expression, making it hard to understand what went wrong. As a workaround, some users choose to construct the failure message by themselves, streaming it into `EXPECT_TRUE()`. However, this is awkward especially when the expression has side-effects or is expensive to evaluate. Google Test gives you three different options to solve this problem: ### Using an Existing Boolean Function ### If you already have a function or a functor that returns `bool` (or a type that can be implicitly converted to `bool`), you can use it in a _predicate assertion_ to get the function arguments printed for free: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_PRED1(`_pred1, val1_`);` | `EXPECT_PRED1(`_pred1, val1_`);` | _pred1(val1)_ returns true | | `ASSERT_PRED2(`_pred2, val1, val2_`);` | `EXPECT_PRED2(`_pred2, val1, val2_`);` | _pred2(val1, val2)_ returns true | | ... | ... | ... | In the above, _predn_ is an _n_-ary predicate function or functor, where _val1_, _val2_, ..., and _valn_ are its arguments. The assertion succeeds if the predicate returns `true` when applied to the given arguments, and fails otherwise. When the assertion fails, it prints the value of each argument. In either case, the arguments are evaluated exactly once. Here's an example. Given ``` // Returns true iff m and n have no common divisors except 1. bool MutuallyPrime(int m, int n) { ... } const int a = 3; const int b = 4; const int c = 10; ``` the assertion `EXPECT_PRED2(MutuallyPrime, a, b);` will succeed, while the assertion `EXPECT_PRED2(MutuallyPrime, b, c);` will fail with the message
!MutuallyPrime(b, c) is false, where
b is 4
c is 10
**Notes:** 1. If you see a compiler error "no matching function to call" when using `ASSERT_PRED*` or `EXPECT_PRED*`, please see [this](V1_7_FAQ.md#the-compiler-complains-about-undefined-references-to-some-static-const-member-variables-but-i-did-define-them-in-the-class-body-whats-wrong) for how to resolve it. 1. Currently we only provide predicate assertions of arity <= 5. If you need a higher-arity assertion, let us know. _Availability_: Linux, Windows, Mac ### Using a Function That Returns an AssertionResult ### While `EXPECT_PRED*()` and friends are handy for a quick job, the syntax is not satisfactory: you have to use different macros for different arities, and it feels more like Lisp than C++. The `::testing::AssertionResult` class solves this problem. An `AssertionResult` object represents the result of an assertion (whether it's a success or a failure, and an associated message). You can create an `AssertionResult` using one of these factory functions: ``` namespace testing { // Returns an AssertionResult object to indicate that an assertion has // succeeded. AssertionResult AssertionSuccess(); // Returns an AssertionResult object to indicate that an assertion has // failed. AssertionResult AssertionFailure(); } ``` You can then use the `<<` operator to stream messages to the `AssertionResult` object. To provide more readable messages in Boolean assertions (e.g. `EXPECT_TRUE()`), write a predicate function that returns `AssertionResult` instead of `bool`. For example, if you define `IsEven()` as: ``` ::testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return ::testing::AssertionSuccess(); else return ::testing::AssertionFailure() << n << " is odd"; } ``` instead of: ``` bool IsEven(int n) { return (n % 2) == 0; } ``` the failed assertion `EXPECT_TRUE(IsEven(Fib(4)))` will print:
Value of: IsEven(Fib(4))
Actual: false (*3 is odd*)
Expected: true
instead of a more opaque
Value of: IsEven(Fib(4))
Actual: false
Expected: true
If you want informative messages in `EXPECT_FALSE` and `ASSERT_FALSE` as well, and are fine with making the predicate slower in the success case, you can supply a success message: ``` ::testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return ::testing::AssertionSuccess() << n << " is even"; else return ::testing::AssertionFailure() << n << " is odd"; } ``` Then the statement `EXPECT_FALSE(IsEven(Fib(6)))` will print
Value of: IsEven(Fib(6))
Actual: true (8 is even)
Expected: false
_Availability_: Linux, Windows, Mac; since version 1.4.1. ### Using a Predicate-Formatter ### If you find the default message generated by `(ASSERT|EXPECT)_PRED*` and `(ASSERT|EXPECT)_(TRUE|FALSE)` unsatisfactory, or some arguments to your predicate do not support streaming to `ostream`, you can instead use the following _predicate-formatter assertions_ to _fully_ customize how the message is formatted: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_PRED_FORMAT1(`_pred\_format1, val1_`);` | `EXPECT_PRED_FORMAT1(`_pred\_format1, val1_`); | _pred\_format1(val1)_ is successful | | `ASSERT_PRED_FORMAT2(`_pred\_format2, val1, val2_`);` | `EXPECT_PRED_FORMAT2(`_pred\_format2, val1, val2_`);` | _pred\_format2(val1, val2)_ is successful | | `...` | `...` | `...` | The difference between this and the previous two groups of macros is that instead of a predicate, `(ASSERT|EXPECT)_PRED_FORMAT*` take a _predicate-formatter_ (_pred\_formatn_), which is a function or functor with the signature: `::testing::AssertionResult PredicateFormattern(const char* `_expr1_`, const char* `_expr2_`, ... const char* `_exprn_`, T1 `_val1_`, T2 `_val2_`, ... Tn `_valn_`);` where _val1_, _val2_, ..., and _valn_ are the values of the predicate arguments, and _expr1_, _expr2_, ..., and _exprn_ are the corresponding expressions as they appear in the source code. The types `T1`, `T2`, ..., and `Tn` can be either value types or reference types. For example, if an argument has type `Foo`, you can declare it as either `Foo` or `const Foo&`, whichever is appropriate. A predicate-formatter returns a `::testing::AssertionResult` object to indicate whether the assertion has succeeded or not. The only way to create such an object is to call one of these factory functions: As an example, let's improve the failure message in the previous example, which uses `EXPECT_PRED2()`: ``` // Returns the smallest prime common divisor of m and n, // or 1 when m and n are mutually prime. int SmallestPrimeCommonDivisor(int m, int n) { ... } // A predicate-formatter for asserting that two integers are mutually prime. ::testing::AssertionResult AssertMutuallyPrime(const char* m_expr, const char* n_expr, int m, int n) { if (MutuallyPrime(m, n)) return ::testing::AssertionSuccess(); return ::testing::AssertionFailure() << m_expr << " and " << n_expr << " (" << m << " and " << n << ") are not mutually prime, " << "as they have a common divisor " << SmallestPrimeCommonDivisor(m, n); } ``` With this predicate-formatter, we can use ``` EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c); ``` to generate the message
b and c (4 and 10) are not mutually prime, as they have a common divisor 2.
As you may have realized, many of the assertions we introduced earlier are special cases of `(EXPECT|ASSERT)_PRED_FORMAT*`. In fact, most of them are indeed defined using `(EXPECT|ASSERT)_PRED_FORMAT*`. _Availability_: Linux, Windows, Mac. ## Floating-Point Comparison ## Comparing floating-point numbers is tricky. Due to round-off errors, it is very unlikely that two floating-points will match exactly. Therefore, `ASSERT_EQ` 's naive comparison usually doesn't work. And since floating-points can have a wide value range, no single fixed error bound works. It's better to compare by a fixed relative error bound, except for values close to 0 due to the loss of precision there. In general, for floating-point comparison to make sense, the user needs to carefully choose the error bound. If they don't want or care to, comparing in terms of Units in the Last Place (ULPs) is a good default, and Google Test provides assertions to do this. Full details about ULPs are quite long; if you want to learn more, see [this article on float comparison](http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm). ### Floating-Point Macros ### | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_FLOAT_EQ(`_expected, actual_`);` | `EXPECT_FLOAT_EQ(`_expected, actual_`);` | the two `float` values are almost equal | | `ASSERT_DOUBLE_EQ(`_expected, actual_`);` | `EXPECT_DOUBLE_EQ(`_expected, actual_`);` | the two `double` values are almost equal | By "almost equal", we mean the two values are within 4 ULP's from each other. The following assertions allow you to choose the acceptable error bound: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_NEAR(`_val1, val2, abs\_error_`);` | `EXPECT_NEAR`_(val1, val2, abs\_error_`);` | the difference between _val1_ and _val2_ doesn't exceed the given absolute error | _Availability_: Linux, Windows, Mac. ### Floating-Point Predicate-Format Functions ### Some floating-point operations are useful, but not that often used. In order to avoid an explosion of new macros, we provide them as predicate-format functions that can be used in predicate assertion macros (e.g. `EXPECT_PRED_FORMAT2`, etc). ``` EXPECT_PRED_FORMAT2(::testing::FloatLE, val1, val2); EXPECT_PRED_FORMAT2(::testing::DoubleLE, val1, val2); ``` Verifies that _val1_ is less than, or almost equal to, _val2_. You can replace `EXPECT_PRED_FORMAT2` in the above table with `ASSERT_PRED_FORMAT2`. _Availability_: Linux, Windows, Mac. ## Windows HRESULT assertions ## These assertions test for `HRESULT` success or failure. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_HRESULT_SUCCEEDED(`_expression_`);` | `EXPECT_HRESULT_SUCCEEDED(`_expression_`);` | _expression_ is a success `HRESULT` | | `ASSERT_HRESULT_FAILED(`_expression_`);` | `EXPECT_HRESULT_FAILED(`_expression_`);` | _expression_ is a failure `HRESULT` | The generated output contains the human-readable error message associated with the `HRESULT` code returned by _expression_. You might use them like this: ``` CComPtr shell; ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application")); CComVariant empty; ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty)); ``` _Availability_: Windows. ## Type Assertions ## You can call the function ``` ::testing::StaticAssertTypeEq(); ``` to assert that types `T1` and `T2` are the same. The function does nothing if the assertion is satisfied. If the types are different, the function call will fail to compile, and the compiler error message will likely (depending on the compiler) show you the actual values of `T1` and `T2`. This is mainly useful inside template code. _Caveat:_ When used inside a member function of a class template or a function template, `StaticAssertTypeEq()` is effective _only if_ the function is instantiated. For example, given: ``` template class Foo { public: void Bar() { ::testing::StaticAssertTypeEq(); } }; ``` the code: ``` void Test1() { Foo foo; } ``` will _not_ generate a compiler error, as `Foo::Bar()` is never actually instantiated. Instead, you need: ``` void Test2() { Foo foo; foo.Bar(); } ``` to cause a compiler error. _Availability:_ Linux, Windows, Mac; since version 1.3.0. ## Assertion Placement ## You can use assertions in any C++ function. In particular, it doesn't have to be a method of the test fixture class. The one constraint is that assertions that generate a fatal failure (`FAIL*` and `ASSERT_*`) can only be used in void-returning functions. This is a consequence of Google Test not using exceptions. By placing it in a non-void function you'll get a confusing compile error like `"error: void value not ignored as it ought to be"`. If you need to use assertions in a function that returns non-void, one option is to make the function return the value in an out parameter instead. For example, you can rewrite `T2 Foo(T1 x)` to `void Foo(T1 x, T2* result)`. You need to make sure that `*result` contains some sensible value even when the function returns prematurely. As the function now returns `void`, you can use any assertion inside of it. If changing the function's type is not an option, you should just use assertions that generate non-fatal failures, such as `ADD_FAILURE*` and `EXPECT_*`. _Note_: Constructors and destructors are not considered void-returning functions, according to the C++ language specification, and so you may not use fatal assertions in them. You'll get a compilation error if you try. A simple workaround is to transfer the entire body of the constructor or destructor to a private void-returning method. However, you should be aware that a fatal assertion failure in a constructor does not terminate the current test, as your intuition might suggest; it merely returns from the constructor early, possibly leaving your object in a partially-constructed state. Likewise, a fatal assertion failure in a destructor may leave your object in a partially-destructed state. Use assertions carefully in these situations! # Teaching Google Test How to Print Your Values # When a test assertion such as `EXPECT_EQ` fails, Google Test prints the argument values to help you debug. It does this using a user-extensible value printer. This printer knows how to print built-in C++ types, native arrays, STL containers, and any type that supports the `<<` operator. For other types, it prints the raw bytes in the value and hopes that you the user can figure it out. As mentioned earlier, the printer is _extensible_. That means you can teach it to do a better job at printing your particular type than to dump the bytes. To do that, define `<<` for your type: ``` #include namespace foo { class Bar { ... }; // We want Google Test to be able to print instances of this. // It's important that the << operator is defined in the SAME // namespace that defines Bar. C++'s look-up rules rely on that. ::std::ostream& operator<<(::std::ostream& os, const Bar& bar) { return os << bar.DebugString(); // whatever needed to print bar to os } } // namespace foo ``` Sometimes, this might not be an option: your team may consider it bad style to have a `<<` operator for `Bar`, or `Bar` may already have a `<<` operator that doesn't do what you want (and you cannot change it). If so, you can instead define a `PrintTo()` function like this: ``` #include namespace foo { class Bar { ... }; // It's important that PrintTo() is defined in the SAME // namespace that defines Bar. C++'s look-up rules rely on that. void PrintTo(const Bar& bar, ::std::ostream* os) { *os << bar.DebugString(); // whatever needed to print bar to os } } // namespace foo ``` If you have defined both `<<` and `PrintTo()`, the latter will be used when Google Test is concerned. This allows you to customize how the value appears in Google Test's output without affecting code that relies on the behavior of its `<<` operator. If you want to print a value `x` using Google Test's value printer yourself, just call `::testing::PrintToString(`_x_`)`, which returns an `std::string`: ``` vector > bar_ints = GetBarIntVector(); EXPECT_TRUE(IsCorrectBarIntVector(bar_ints)) << "bar_ints = " << ::testing::PrintToString(bar_ints); ``` # Death Tests # In many applications, there are assertions that can cause application failure if a condition is not met. These sanity checks, which ensure that the program is in a known good state, are there to fail at the earliest possible time after some program state is corrupted. If the assertion checks the wrong condition, then the program may proceed in an erroneous state, which could lead to memory corruption, security holes, or worse. Hence it is vitally important to test that such assertion statements work as expected. Since these precondition checks cause the processes to die, we call such tests _death tests_. More generally, any test that checks that a program terminates (except by throwing an exception) in an expected fashion is also a death test. Note that if a piece of code throws an exception, we don't consider it "death" for the purpose of death tests, as the caller of the code could catch the exception and avoid the crash. If you want to verify exceptions thrown by your code, see [Exception Assertions](#exception-assertions). If you want to test `EXPECT_*()/ASSERT_*()` failures in your test code, see [Catching Failures](#catching-failures). ## How to Write a Death Test ## Google Test has the following macros to support death tests: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_DEATH(`_statement, regex_`); | `EXPECT_DEATH(`_statement, regex_`); | _statement_ crashes with the given error | | `ASSERT_DEATH_IF_SUPPORTED(`_statement, regex_`); | `EXPECT_DEATH_IF_SUPPORTED(`_statement, regex_`); | if death tests are supported, verifies that _statement_ crashes with the given error; otherwise verifies nothing | | `ASSERT_EXIT(`_statement, predicate, regex_`); | `EXPECT_EXIT(`_statement, predicate, regex_`); |_statement_ exits with the given error and its exit code matches _predicate_ | where _statement_ is a statement that is expected to cause the process to die, _predicate_ is a function or function object that evaluates an integer exit status, and _regex_ is a regular expression that the stderr output of _statement_ is expected to match. Note that _statement_ can be _any valid statement_ (including _compound statement_) and doesn't have to be an expression. As usual, the `ASSERT` variants abort the current test function, while the `EXPECT` variants do not. **Note:** We use the word "crash" here to mean that the process terminates with a _non-zero_ exit status code. There are two possibilities: either the process has called `exit()` or `_exit()` with a non-zero value, or it may be killed by a signal. This means that if _statement_ terminates the process with a 0 exit code, it is _not_ considered a crash by `EXPECT_DEATH`. Use `EXPECT_EXIT` instead if this is the case, or if you want to restrict the exit code more precisely. A predicate here must accept an `int` and return a `bool`. The death test succeeds only if the predicate returns `true`. Google Test defines a few predicates that handle the most common cases: ``` ::testing::ExitedWithCode(exit_code) ``` This expression is `true` if the program exited normally with the given exit code. ``` ::testing::KilledBySignal(signal_number) // Not available on Windows. ``` This expression is `true` if the program was killed by the given signal. The `*_DEATH` macros are convenient wrappers for `*_EXIT` that use a predicate that verifies the process' exit code is non-zero. Note that a death test only cares about three things: 1. does _statement_ abort or exit the process? 1. (in the case of `ASSERT_EXIT` and `EXPECT_EXIT`) does the exit status satisfy _predicate_? Or (in the case of `ASSERT_DEATH` and `EXPECT_DEATH`) is the exit status non-zero? And 1. does the stderr output match _regex_? In particular, if _statement_ generates an `ASSERT_*` or `EXPECT_*` failure, it will **not** cause the death test to fail, as Google Test assertions don't abort the process. To write a death test, simply use one of the above macros inside your test function. For example, ``` TEST(MyDeathTest, Foo) { // This death test uses a compound statement. ASSERT_DEATH({ int n = 5; Foo(&n); }, "Error on line .* of Foo()"); } TEST(MyDeathTest, NormalExit) { EXPECT_EXIT(NormalExit(), ::testing::ExitedWithCode(0), "Success"); } TEST(MyDeathTest, KillMyself) { EXPECT_EXIT(KillMyself(), ::testing::KilledBySignal(SIGKILL), "Sending myself unblockable signal"); } ``` verifies that: * calling `Foo(5)` causes the process to die with the given error message, * calling `NormalExit()` causes the process to print `"Success"` to stderr and exit with exit code 0, and * calling `KillMyself()` kills the process with signal `SIGKILL`. The test function body may contain other assertions and statements as well, if necessary. _Important:_ We strongly recommend you to follow the convention of naming your test case (not test) `*DeathTest` when it contains a death test, as demonstrated in the above example. The `Death Tests And Threads` section below explains why. If a test fixture class is shared by normal tests and death tests, you can use typedef to introduce an alias for the fixture class and avoid duplicating its code: ``` class FooTest : public ::testing::Test { ... }; typedef FooTest FooDeathTest; TEST_F(FooTest, DoesThis) { // normal test } TEST_F(FooDeathTest, DoesThat) { // death test } ``` _Availability:_ Linux, Windows (requires MSVC 8.0 or above), Cygwin, and Mac (the latter three are supported since v1.3.0). `(ASSERT|EXPECT)_DEATH_IF_SUPPORTED` are new in v1.4.0. ## Regular Expression Syntax ## On POSIX systems (e.g. Linux, Cygwin, and Mac), Google Test uses the [POSIX extended regular expression](http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04) syntax in death tests. To learn about this syntax, you may want to read this [Wikipedia entry](http://en.wikipedia.org/wiki/Regular_expression#POSIX_Extended_Regular_Expressions). On Windows, Google Test uses its own simple regular expression implementation. It lacks many features you can find in POSIX extended regular expressions. For example, we don't support union (`"x|y"`), grouping (`"(xy)"`), brackets (`"[xy]"`), and repetition count (`"x{5,7}"`), among others. Below is what we do support (Letter `A` denotes a literal character, period (`.`), or a single `\\` escape sequence; `x` and `y` denote regular expressions.): | `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 the `.` character | | `.` | 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` | To help you determine which capability is available on your system, Google Test defines macro `GTEST_USES_POSIX_RE=1` when it uses POSIX extended regular expressions, or `GTEST_USES_SIMPLE_RE=1` when it uses the simple version. If you want your death tests to work in both cases, you can either `#if` on these macros or use the more limited syntax only. ## How It Works ## Under the hood, `ASSERT_EXIT()` spawns a new process and executes the death test statement in that process. The details of of how precisely that happens depend on the platform and the variable `::testing::GTEST_FLAG(death_test_style)` (which is initialized from the command-line flag `--gtest_death_test_style`). * On POSIX systems, `fork()` (or `clone()` on Linux) is used to spawn the child, after which: * If the variable's value is `"fast"`, the death test statement is immediately executed. * If the variable's value is `"threadsafe"`, the child process re-executes the unit test binary just as it was originally invoked, but with some extra flags to cause just the single death test under consideration to be run. * On Windows, the child is spawned using the `CreateProcess()` API, and re-executes the binary to cause just the single death test under consideration to be run - much like the `threadsafe` mode on POSIX. Other values for the variable are illegal and will cause the death test to fail. Currently, the flag's default value is `"fast"`. However, we reserve the right to change it in the future. Therefore, your tests should not depend on this. In either case, the parent process waits for the child process to complete, and checks that 1. the child's exit status satisfies the predicate, and 1. the child's stderr matches the regular expression. If the death test statement runs to completion without dying, the child process will nonetheless terminate, and the assertion fails. ## Death Tests And Threads ## The reason for the two death test styles has to do with thread safety. Due to well-known problems with forking in the presence of threads, death tests should be run in a single-threaded context. Sometimes, however, it isn't feasible to arrange that kind of environment. For example, statically-initialized modules may start threads before main is ever reached. Once threads have been created, it may be difficult or impossible to clean them up. Google Test has three features intended to raise awareness of threading issues. 1. A warning is emitted if multiple threads are running when a death test is encountered. 1. Test cases with a name ending in "DeathTest" are run before all other tests. 1. It uses `clone()` instead of `fork()` to spawn the child process on Linux (`clone()` is not available on Cygwin and Mac), as `fork()` is more likely to cause the child to hang when the parent process has multiple threads. It's perfectly fine to create threads inside a death test statement; they are executed in a separate process and cannot affect the parent. ## Death Test Styles ## The "threadsafe" death test style was introduced in order to help mitigate the risks of testing in a possibly multithreaded environment. It trades increased test execution time (potentially dramatically so) for improved thread safety. We suggest using the faster, default "fast" style unless your test has specific problems with it. You can choose a particular style of death tests by setting the flag programmatically: ``` ::testing::FLAGS_gtest_death_test_style = "threadsafe"; ``` You can do this in `main()` to set the style for all death tests in the binary, or in individual tests. Recall that flags are saved before running each test and restored afterwards, so you need not do that yourself. For example: ``` TEST(MyDeathTest, TestOne) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; // This test is run in the "threadsafe" style: ASSERT_DEATH(ThisShouldDie(), ""); } TEST(MyDeathTest, TestTwo) { // This test is run in the "fast" style: ASSERT_DEATH(ThisShouldDie(), ""); } int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); ::testing::FLAGS_gtest_death_test_style = "fast"; return RUN_ALL_TESTS(); } ``` ## Caveats ## The _statement_ argument of `ASSERT_EXIT()` can be any valid C++ statement. If it leaves the current function via a `return` statement or by throwing an exception, the death test is considered to have failed. Some Google Test macros may return from the current function (e.g. `ASSERT_TRUE()`), so be sure to avoid them in _statement_. Since _statement_ runs in the child process, any in-memory side effect (e.g. modifying a variable, releasing memory, etc) it causes will _not_ be observable in the parent process. In particular, if you release memory in a death test, your program will fail the heap check as the parent process will never see the memory reclaimed. To solve this problem, you can 1. try not to free memory in a death test; 1. free the memory again in the parent process; or 1. do not use the heap checker in your program. Due to an implementation detail, you cannot place multiple death test assertions on the same line; otherwise, compilation will fail with an unobvious error message. Despite the improved thread safety afforded by the "threadsafe" style of death test, thread problems such as deadlock are still possible in the presence of handlers registered with `pthread_atfork(3)`. # Using Assertions in Sub-routines # ## Adding Traces to Assertions ## If a test sub-routine is called from several places, when an assertion inside it fails, it can be hard to tell which invocation of the sub-routine the failure is from. You can alleviate this problem using extra logging or custom failure messages, but that usually clutters up your tests. A better solution is to use the `SCOPED_TRACE` macro: | `SCOPED_TRACE(`_message_`);` | |:-----------------------------| where _message_ can be anything streamable to `std::ostream`. This macro will cause the current file name, line number, and the given message to be added in every failure message. The effect will be undone when the control leaves the current lexical scope. For example, ``` 10: void Sub1(int n) { 11: EXPECT_EQ(1, Bar(n)); 12: EXPECT_EQ(2, Bar(n + 1)); 13: } 14: 15: TEST(FooTest, Bar) { 16: { 17: SCOPED_TRACE("A"); // This trace point will be included in 18: // every failure in this scope. 19: Sub1(1); 20: } 21: // Now it won't. 22: Sub1(9); 23: } ``` could result in messages like these: ``` path/to/foo_test.cc:11: Failure Value of: Bar(n) Expected: 1 Actual: 2 Trace: path/to/foo_test.cc:17: A path/to/foo_test.cc:12: Failure Value of: Bar(n + 1) Expected: 2 Actual: 3 ``` Without the trace, it would've been difficult to know which invocation of `Sub1()` the two failures come from respectively. (You could add an extra message to each assertion in `Sub1()` to indicate the value of `n`, but that's tedious.) Some tips on using `SCOPED_TRACE`: 1. With a suitable message, it's often enough to use `SCOPED_TRACE` at the beginning of a sub-routine, instead of at each call site. 1. When calling sub-routines inside a loop, make the loop iterator part of the message in `SCOPED_TRACE` such that you can know which iteration the failure is from. 1. Sometimes the line number of the trace point is enough for identifying the particular invocation of a sub-routine. In this case, you don't have to choose a unique message for `SCOPED_TRACE`. You can simply use `""`. 1. You can use `SCOPED_TRACE` in an inner scope when there is one in the outer scope. In this case, all active trace points will be included in the failure messages, in reverse order they are encountered. 1. The trace dump is clickable in Emacs' compilation buffer - hit return on a line number and you'll be taken to that line in the source file! _Availability:_ Linux, Windows, Mac. ## Propagating Fatal Failures ## A common pitfall when using `ASSERT_*` and `FAIL*` is not understanding that when they fail they only abort the _current function_, not the entire test. For example, the following test will segfault: ``` void Subroutine() { // Generates a fatal failure and aborts the current function. ASSERT_EQ(1, 2); // The following won't be executed. ... } TEST(FooTest, Bar) { Subroutine(); // The intended behavior is for the fatal failure // in Subroutine() to abort the entire test. // The actual behavior: the function goes on after Subroutine() returns. int* p = NULL; *p = 3; // Segfault! } ``` Since we don't use exceptions, it is technically impossible to implement the intended behavior here. To alleviate this, Google Test provides two solutions. You could use either the `(ASSERT|EXPECT)_NO_FATAL_FAILURE` assertions or the `HasFatalFailure()` function. They are described in the following two subsections. ### Asserting on Subroutines ### As shown above, if your test calls a subroutine that has an `ASSERT_*` failure in it, the test will continue after the subroutine returns. This may not be what you want. Often people want fatal failures to propagate like exceptions. For that Google Test offers the following macros: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_NO_FATAL_FAILURE(`_statement_`);` | `EXPECT_NO_FATAL_FAILURE(`_statement_`);` | _statement_ doesn't generate any new fatal failures in the current thread. | Only failures in the thread that executes the assertion are checked to determine the result of this type of assertions. If _statement_ creates new threads, failures in these threads are ignored. Examples: ``` ASSERT_NO_FATAL_FAILURE(Foo()); int i; EXPECT_NO_FATAL_FAILURE({ i = Bar(); }); ``` _Availability:_ Linux, Windows, Mac. Assertions from multiple threads are currently not supported. ### Checking for Failures in the Current Test ### `HasFatalFailure()` in the `::testing::Test` class returns `true` if an assertion in the current test has suffered a fatal failure. This allows functions to catch fatal failures in a sub-routine and return early. ``` class Test { public: ... static bool HasFatalFailure(); }; ``` The typical usage, which basically simulates the behavior of a thrown exception, is: ``` TEST(FooTest, Bar) { Subroutine(); // Aborts if Subroutine() had a fatal failure. if (HasFatalFailure()) return; // The following won't be executed. ... } ``` If `HasFatalFailure()` is used outside of `TEST()` , `TEST_F()` , or a test fixture, you must add the `::testing::Test::` prefix, as in: ``` if (::testing::Test::HasFatalFailure()) return; ``` Similarly, `HasNonfatalFailure()` returns `true` if the current test has at least one non-fatal failure, and `HasFailure()` returns `true` if the current test has at least one failure of either kind. _Availability:_ Linux, Windows, Mac. `HasNonfatalFailure()` and `HasFailure()` are available since version 1.4.0. # Logging Additional Information # In your test code, you can call `RecordProperty("key", value)` to log additional information, where `value` can be either a string or an `int`. The _last_ value recorded for a key will be emitted to the XML output if you specify one. For example, the test ``` TEST_F(WidgetUsageTest, MinAndMaxWidgets) { RecordProperty("MaximumWidgets", ComputeMaxUsage()); RecordProperty("MinimumWidgets", ComputeMinUsage()); } ``` will output XML like this: ``` ... ... ``` _Note_: * `RecordProperty()` is a static member of the `Test` class. Therefore it needs to be prefixed with `::testing::Test::` if used outside of the `TEST` body and the test fixture class. * `key` must be a valid XML attribute name, and cannot conflict with the ones already used by Google Test (`name`, `status`, `time`, `classname`, `type_param`, and `value_param`). * Calling `RecordProperty()` outside of the lifespan of a test is allowed. If it's called outside of a test but between a test case's `SetUpTestCase()` and `TearDownTestCase()` methods, it will be attributed to the XML element for the test case. If it's called outside of all test cases (e.g. in a test environment), it will be attributed to the top-level XML element. _Availability_: Linux, Windows, Mac. # Sharing Resources Between Tests in the Same Test Case # Google Test creates a new test fixture object for each test in order to make tests independent and easier to debug. However, sometimes tests use resources that are expensive to set up, making the one-copy-per-test model prohibitively expensive. If the tests don't change the resource, there's no harm in them sharing a single resource copy. So, in addition to per-test set-up/tear-down, Google Test also supports per-test-case set-up/tear-down. To use it: 1. In your test fixture class (say `FooTest` ), define as `static` some member variables to hold the shared resources. 1. In the same test fixture class, define a `static void SetUpTestCase()` function (remember not to spell it as **`SetupTestCase`** with a small `u`!) to set up the shared resources and a `static void TearDownTestCase()` function to tear them down. That's it! Google Test automatically calls `SetUpTestCase()` before running the _first test_ in the `FooTest` test case (i.e. before creating the first `FooTest` object), and calls `TearDownTestCase()` after running the _last test_ in it (i.e. after deleting the last `FooTest` object). In between, the tests can use the shared resources. Remember that the test order is undefined, so your code can't depend on a test preceding or following another. Also, the tests must either not modify the state of any shared resource, or, if they do modify the state, they must restore the state to its original value before passing control to the next test. Here's an example of per-test-case set-up and tear-down: ``` class FooTest : public ::testing::Test { protected: // Per-test-case set-up. // Called before the first test in this test case. // Can be omitted if not needed. static void SetUpTestCase() { shared_resource_ = new ...; } // Per-test-case tear-down. // Called after the last test in this test case. // Can be omitted if not needed. static void TearDownTestCase() { delete shared_resource_; shared_resource_ = NULL; } // You can define per-test set-up and tear-down logic as usual. virtual void SetUp() { ... } virtual void TearDown() { ... } // Some expensive resource shared by all tests. static T* shared_resource_; }; T* FooTest::shared_resource_ = NULL; TEST_F(FooTest, Test1) { ... you can refer to shared_resource here ... } TEST_F(FooTest, Test2) { ... you can refer to shared_resource here ... } ``` _Availability:_ Linux, Windows, Mac. # Global Set-Up and Tear-Down # Just as you can do set-up and tear-down at the test level and the test case level, you can also do it at the test program level. Here's how. First, you subclass the `::testing::Environment` class to define a test environment, which knows how to set-up and tear-down: ``` class Environment { public: 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() {} }; ``` Then, you register an instance of your environment class with Google Test by calling the `::testing::AddGlobalTestEnvironment()` function: ``` Environment* AddGlobalTestEnvironment(Environment* env); ``` Now, when `RUN_ALL_TESTS()` is called, it first calls the `SetUp()` method of the environment object, then runs the tests if there was no fatal failures, and finally calls `TearDown()` of the environment object. It's OK to register multiple environment objects. In this case, their `SetUp()` will be called in the order they are registered, and their `TearDown()` will be called in the reverse order. Note that Google Test takes ownership of the registered environment objects. Therefore **do not delete them** by yourself. You should call `AddGlobalTestEnvironment()` 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. One way to do this is to 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). _Availability:_ Linux, Windows, Mac. # Value Parameterized Tests # _Value-parameterized tests_ allow you to test your code with different parameters without writing multiple copies of the same test. Suppose you write a test for your code and then realize that your code is affected by a presence of a Boolean command line flag. ``` TEST(MyCodeTest, TestFoo) { // A code to test foo(). } ``` Usually people factor their test code into a function with a Boolean parameter in such situations. The function sets the flag, then executes the testing code. ``` void TestFooHelper(bool flag_value) { flag = flag_value; // A code to test foo(). } TEST(MyCodeTest, TestFoo) { TestFooHelper(false); TestFooHelper(true); } ``` But this setup has serious drawbacks. First, when a test assertion fails in your tests, it becomes unclear what value of the parameter caused it to fail. You can stream a clarifying message into your `EXPECT`/`ASSERT` statements, but it you'll have to do it with all of them. Second, you have to add one such helper function per test. What if you have ten tests? Twenty? A hundred? Value-parameterized tests will let you write your test only once and then easily instantiate and run it with an arbitrary number of parameter values. Here are some other situations when value-parameterized tests come handy: * You want to test different implementations of an OO interface. * You want to test your code over various inputs (a.k.a. data-driven testing). This feature is easy to abuse, so please exercise your good sense when doing it! ## How to Write Value-Parameterized Tests ## To write value-parameterized tests, first you should define a fixture class. It must be derived from both `::testing::Test` and `::testing::WithParamInterface` (the latter is a pure interface), where `T` is the type of your parameter values. For convenience, you can just derive the fixture class from `::testing::TestWithParam`, which itself is derived from both `::testing::Test` and `::testing::WithParamInterface`. `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 { // You can implement all the usual fixture class members here. // To access the test parameter, call GetParam() from class // TestWithParam. }; // Or, when you want to add parameters to a pre-existing fixture class: class BaseTest : public ::testing::Test { ... }; class BarTest : public BaseTest, public ::testing::WithParamInterface { ... }; ``` Then, use the `TEST_P` macro to define as many test patterns using 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 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)` and `ValuesIn(begin, end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)`. `container`, `begin`, and `end` can be expressions whose values are determined at run time. | | `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. This is only available if your system provides the `` header. If you are sure your system does, and Google Test disagrees, you can override it by defining `GTEST_HAS_TR1_TUPLE=1`. See comments in [include/gtest/internal/gtest-port.h](../include/gtest/internal/gtest-port.h) for more information. | For more details, see the comments at the definitions of these functions in the [source code](../include/gtest/gtest-param-test.h). 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, ::testing::Values("meeny", "miny", "moe")); ``` To distinguish different instances of the pattern (yes, you can instantiate it more than once), the first argument to `INSTANTIATE_TEST_CASE_P` 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](#running-a-subset-of-the-tests). 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, ::testing::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. You can see [these](../samples/sample7_unittest.cc) [files](../samples/sample8_unittest.cc) for more examples. _Availability_: Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.2.0. ## Creating Value-Parameterized Abstract Tests ## In the above, we define and instantiate `FooTest` in the same source file. Sometimes you may want to define value-parameterized tests in a library and let other people instantiate them later. This pattern is known as abstract tests. As an example of its application, when you are designing an interface you can write a standard suite of abstract tests (perhaps using a factory function as the test parameter) that all implementations of the interface are expected to pass. When someone implements the interface, he can instantiate your suite to get all the interface-conformance tests for free. To define abstract tests, you should organize your code like this: 1. Put the definition of the parameterized test fixture class (e.g. `FooTest`) in a header file, say `foo_param_test.h`. Think of this as _declaring_ your abstract tests. 1. Put the `TEST_P` definitions in `foo_param_test.cc`, which includes `foo_param_test.h`. Think of this as _implementing_ your abstract tests. Once they are defined, you can instantiate them by including `foo_param_test.h`, invoking `INSTANTIATE_TEST_CASE_P()`, and linking with `foo_param_test.cc`. You can instantiate the same abstract test case multiple times, possibly in different source files. # Typed Tests # Suppose you have multiple implementations of the same interface and want to make sure that all of them satisfy some common requirements. Or, you may have defined several types that are supposed to conform to the same "concept" and you want to verify it. In both cases, you want the same test logic repeated for different types. While you can write one `TEST` or `TEST_F` for each type you want to test (and you may even factor the test logic into a function template that you invoke from the `TEST`), it's tedious and doesn't scale: if you want _m_ tests over _n_ types, you'll end up writing _m\*n_ `TEST`s. _Typed tests_ allow you to repeat the same test logic over a list of types. You only need to write the test logic once, although you must know the type list when writing typed tests. Here's how you do it: First, define a fixture class template. It should be parameterized by a type. Remember to derive it from `::testing::Test`: ``` template class FooTest : public ::testing::Test { public: ... typedef std::list 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: ``` typedef ::testing::Types MyTypes; TYPED_TEST_CASE(FooTest, MyTypes); ``` The `typedef` is necessary for the `TYPED_TEST_CASE` macro to parse correctly. Otherwise the compiler will think that each comma in the type list introduces a new macro argument. Then, use `TYPED_TEST()` instead of `TEST_F()` to define a typed test for this test case. You can repeat this as many times as you want: ``` TYPED_TEST(FooTest, DoesBlah) { // Inside a test, refer to the special name TypeParam to get the type // parameter. Since we are inside a derived class template, C++ requires // us 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. The 'typename' is required to satisfy the compiler. typename TestFixture::List values; values.push_back(n); ... } TYPED_TEST(FooTest, HasPropertyA) { ... } ``` You can see `samples/sample6_unittest.cc` for a complete example. _Availability:_ Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.1.0. # Type-Parameterized Tests # _Type-parameterized tests_ are like typed tests, except that they don't require you to know the list of types ahead of time. Instead, you can define the test logic first and instantiate it with different type lists later. You can even instantiate it more than once in the same program. 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, the author of each implementation can just instantiate the test suite with his type to verify that it conforms to the requirements, without having to write similar tests repeatedly. Here's an example: First, define a fixture class template, as we did with typed tests: ``` template class FooTest : public ::testing::Test { ... }; ``` Next, declare that you will define a type-parameterized test case: ``` TYPED_TEST_CASE_P(FooTest); ``` The `_P` suffix is for "parameterized" or "pattern", whichever you prefer to think. Then, use `TYPED_TEST_P()` to define a type-parameterized test. You can repeat this as many times 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 using the `REGISTER_TYPED_TEST_CASE_P` macro 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. ``` typedef ::testing::Types MyTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); ``` To distinguish different instances of the pattern, the first argument to the `INSTANTIATE_TYPED_TEST_CASE_P` macro is a prefix that will be added to the actual test case name. Remember to pick unique prefixes for different instances. In the special case where the type list contains only one type, you can write that type directly without `::testing::Types<...>`, like this: ``` INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); ``` You can see `samples/sample6_unittest.cc` for a complete example. _Availability:_ Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.1.0. # Testing Private Code # If you change your software's internal implementation, your tests should not break as long as the change is not observable by users. Therefore, per the _black-box testing principle_, most of the time you should test your code through its public interfaces. If you still find yourself needing to test internal implementation code, consider if there's a better design that wouldn't require you to do so. If you absolutely have to test non-public interface code though, you can. There are two cases to consider: * Static functions (_not_ the same as static member functions!) or unnamed namespaces, and * Private or protected class members ## Static Functions ## Both static functions and definitions/declarations in an unnamed namespace are only visible within the same translation unit. To test them, you can `#include` the entire `.cc` file being tested in your `*_test.cc` file. (`#include`ing `.cc` files is not a good way to reuse code - you should not do this in production code!) However, a better approach is to move the private code into the `foo::internal` namespace, where `foo` is the namespace your project normally uses, and put the private declarations in a `*-internal.h` file. Your production `.cc` files and your tests are allowed to include this internal header, but your clients are not. This way, you can fully test your internal implementation without leaking it to your clients. ## Private Class Members ## Private class members are only accessible from within the class or by friends. To access a class' private members, you can declare your test fixture as a friend to the class and define accessors in your fixture. Tests using the fixture can then access the private members of your production class via the accessors in the fixture. Note that even though your fixture is a friend to your production class, your tests are not automatically friends to it, as they are technically defined in sub-classes of the fixture. Another way to test private members is to refactor them into an implementation class, which is then declared in a `*-internal.h` file. Your clients aren't allowed to include this header but your tests can. Such is called the Pimpl (Private Implementation) idiom. Or, you can declare an individual test as a friend of your class by adding this line in the class body: ``` FRIEND_TEST(TestCaseName, TestName); ``` For example, ``` // foo.h #include "gtest/gtest_prod.h" // Defines FRIEND_TEST. class Foo { ... private: FRIEND_TEST(FooTest, BarReturnsZeroOnNull); int Bar(void* x); }; // foo_test.cc ... TEST(FooTest, BarReturnsZeroOnNull) { Foo foo; EXPECT_EQ(0, foo.Bar(NULL)); // Uses Foo's private member Bar(). } ``` Pay special attention when your class is defined in a namespace, as you should define your test fixtures and tests in the same namespace if you want them to be friends of your class. For example, if the code to be tested looks like: ``` namespace my_namespace { class Foo { friend class FooTest; FRIEND_TEST(FooTest, Bar); FRIEND_TEST(FooTest, Baz); ... definition of the class Foo ... }; } // namespace my_namespace ``` Your test code should be something like: ``` namespace my_namespace { class FooTest : public ::testing::Test { protected: ... }; TEST_F(FooTest, Bar) { ... } TEST_F(FooTest, Baz) { ... } } // namespace my_namespace ``` # Catching Failures # If you are building a testing utility on top of Google Test, you'll want to test your utility. What framework would you use to test it? Google Test, of course. The challenge is to verify that your testing utility reports failures correctly. In frameworks that report a failure by throwing an exception, you could catch the exception and assert on it. But Google Test doesn't use exceptions, so how do we test that a piece of code generates an expected failure? `"gtest/gtest-spi.h"` contains some constructs to do this. After `#include`ing this header, you can use | `EXPECT_FATAL_FAILURE(`_statement, substring_`);` | |:--------------------------------------------------| to assert that _statement_ generates a fatal (e.g. `ASSERT_*`) failure whose message contains the given _substring_, or use | `EXPECT_NONFATAL_FAILURE(`_statement, substring_`);` | |:-----------------------------------------------------| if you are expecting a non-fatal (e.g. `EXPECT_*`) failure. For technical reasons, there are some caveats: 1. You cannot stream a failure message to either macro. 1. _statement_ in `EXPECT_FATAL_FAILURE()` cannot reference local non-static variables or non-static members of `this` object. 1. _statement_ in `EXPECT_FATAL_FAILURE()` cannot return a value. _Note:_ Google Test is designed with threads in mind. Once the synchronization primitives in `"gtest/internal/gtest-port.h"` have been implemented, Google Test will become thread-safe, meaning that you can then use assertions in multiple threads concurrently. Before that, however, Google Test only supports single-threaded usage. Once thread-safe, `EXPECT_FATAL_FAILURE()` and `EXPECT_NONFATAL_FAILURE()` will capture failures in the current thread only. If _statement_ creates new threads, failures in these threads will be ignored. If you want to capture failures from all threads instead, you should use the following macros: | `EXPECT_FATAL_FAILURE_ON_ALL_THREADS(`_statement, substring_`);` | |:-----------------------------------------------------------------| | `EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(`_statement, substring_`);` | # Getting the Current Test's Name # Sometimes a function may need to know the name of the currently running test. For example, you may be using the `SetUp()` method of your test fixture to set the golden file name based on which test is running. The `::testing::TestInfo` class has this information: ``` namespace testing { class TestInfo { public: // Returns the test case name and the test name, respectively. // // Do NOT delete or free the return value - it's managed by the // TestInfo class. const char* test_case_name() const; const char* name() const; }; } // namespace testing ``` > To obtain a `TestInfo` object for the currently running test, call `current_test_info()` on the `UnitTest` singleton object: ``` // Gets information about the currently running test. // Do NOT delete the returned object - it's managed by the UnitTest class. const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); printf("We are in test %s of test case %s.\n", test_info->name(), test_info->test_case_name()); ``` `current_test_info()` returns a null pointer if no test is running. In particular, you cannot find the test case name in `TestCaseSetUp()`, `TestCaseTearDown()` (where you know the test case name implicitly), or functions called from them. _Availability:_ Linux, Windows, Mac. # Extending Google Test by Handling Test Events # Google Test provides an event listener API to let you receive notifications about the progress of a test program and test failures. The events you can listen to include the start and end of the test program, a test case, or a test method, among others. You may use this API to augment or replace the standard console output, replace the XML output, or provide a completely different form of output, such as a GUI or a database. You can also use test events as checkpoints to implement a resource leak checker, for example. _Availability:_ Linux, Windows, Mac; since v1.4.0. ## Defining Event Listeners ## To define a event listener, you subclass either [testing::TestEventListener](../include/gtest/gtest.h#L855) or [testing::EmptyTestEventListener](../include/gtest/gtest.h#L905). The former is an (abstract) interface, where each pure virtual method
can be overridden to handle a test event
(For example, when a test starts, the `OnTestStart()` method will be called.). The latter provides an empty implementation of all methods in the interface, such that a subclass only needs to override the methods it cares about. When an event is fired, its context is passed to the handler function as an argument. The following argument types are used: * [UnitTest](../include/gtest/gtest.h#L1007) reflects the state of the entire test program, * [TestCase](../include/gtest/gtest.h#L689) has information about a test case, which can contain one or more tests, * [TestInfo](../include/gtest/gtest.h#L599) contains the state of a test, and * [TestPartResult](../include/gtest/gtest-test-part.h#L42) represents the result of a test assertion. An event handler function can examine the argument it receives to find out interesting information about the event and the test program's state. Here's an example: ``` class MinimalistPrinter : public ::testing::EmptyTestEventListener { // Called before a test starts. virtual void OnTestStart(const ::testing::TestInfo& test_info) { printf("*** Test %s.%s starting.\n", test_info.test_case_name(), test_info.name()); } // Called after a failed assertion or a SUCCEED() invocation. virtual void OnTestPartResult( const ::testing::TestPartResult& test_part_result) { printf("%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()); } // Called after a test ends. virtual void OnTestEnd(const ::testing::TestInfo& test_info) { printf("*** Test %s.%s ending.\n", test_info.test_case_name(), test_info.name()); } }; ``` ## Using Event Listeners ## To use the event listener you have defined, add an instance of it to the Google Test event listener list (represented by class [TestEventListeners](../include/gtest/gtest.h#L929) - note the "s" at the end of the name) in your `main()` function, before calling `RUN_ALL_TESTS()`: ``` int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); // Gets hold of the event listener list. ::testing::TestEventListeners& listeners = ::testing::UnitTest::GetInstance()->listeners(); // Adds a listener to the end. Google Test takes the ownership. listeners.Append(new MinimalistPrinter); return RUN_ALL_TESTS(); } ``` There's only one problem: the default test result printer is still in effect, so its output will mingle with the output from your minimalist printer. To suppress the default printer, just release it from the event listener list and delete it. You can do so by adding one line: ``` ... delete listeners.Release(listeners.default_result_printer()); listeners.Append(new MinimalistPrinter); return RUN_ALL_TESTS(); ``` Now, sit back and enjoy a completely different output from your tests. For more details, you can read this [sample](../samples/sample9_unittest.cc). You may append more than one listener to the list. When an `On*Start()` or `OnTestPartResult()` event is fired, the listeners will receive it in the order they appear in the list (since new listeners are added to the end of the list, the default text printer and the default XML generator will receive the event first). An `On*End()` event will be received by the listeners in the _reverse_ order. This allows output by listeners added later to be framed by output from listeners added earlier. ## Generating Failures in Listeners ## You may use failure-raising macros (`EXPECT_*()`, `ASSERT_*()`, `FAIL()`, etc) when processing an event. There are some restrictions: 1. You cannot generate any failure in `OnTestPartResult()` (otherwise it will cause `OnTestPartResult()` to be called recursively). 1. A listener that handles `OnTestPartResult()` is not allowed to generate any failure. When you add listeners to the listener list, you should put listeners that handle `OnTestPartResult()` _before_ listeners that can generate failures. This ensures that failures generated by the latter are attributed to the right test by the former. We have a sample of failure-raising listener [here](../samples/sample10_unittest.cc). # Running Test Programs: Advanced Options # Google Test test programs are ordinary executables. Once built, you can run them directly and affect their behavior via the following environment variables and/or command line flags. For the flags to work, your programs must call `::testing::InitGoogleTest()` before calling `RUN_ALL_TESTS()`. To see a list of supported flags and their usage, please run your test program with the `--help` flag. You can also use `-h`, `-?`, or `/?` for short. This feature is added in version 1.3.0. If an option is specified both by an environment variable and by a flag, the latter takes precedence. Most of the options can also be set/read in code: to access the value of command line flag `--gtest_foo`, write `::testing::GTEST_FLAG(foo)`. A common pattern is to set the value of a flag before calling `::testing::InitGoogleTest()` to change the default value of the flag: ``` int main(int argc, char** argv) { // Disables elapsed time by default. ::testing::GTEST_FLAG(print_time) = false; // This allows the user to override the flag on the command line. ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ``` ## Selecting Tests ## This section shows various options for choosing which tests to run. ### Listing Test Names ### Sometimes it is necessary to list the available tests in a program before running them so that a filter may be applied if needed. Including the flag `--gtest_list_tests` overrides all other flags and lists tests in the following format: ``` TestCase1. TestName1 TestName2 TestCase2. TestName ``` None of the tests listed are actually run if the flag is provided. There is no corresponding environment variable for this flag. _Availability:_ Linux, Windows, Mac. ### Running a Subset of the Tests ### By default, a Google Test program runs all tests the user has defined. Sometimes, you want to run only a subset of the tests (e.g. for debugging or quickly verifying a change). If you set the `GTEST_FILTER` environment variable or the `--gtest_filter` flag to a filter string, Google Test will only run the tests whose full names (in the form of `TestCaseName.TestName`) match the filter. The format of a filter is a '`:`'-separated list of wildcard patterns (called the positive patterns) optionally followed by a '`-`' and another '`:`'-separated pattern list (called the negative patterns). A test matches the filter if and only if it matches any of the positive patterns but does not match any of the negative patterns. A pattern may contain `'*'` (matches any string) or `'?'` (matches any single character). For convenience, the filter `'*-NegativePatterns'` can be also written as `'-NegativePatterns'`. For example: * `./foo_test` Has no flag, and thus runs all its tests. * `./foo_test --gtest_filter=*` Also runs everything, due to the single match-everything `*` value. * `./foo_test --gtest_filter=FooTest.*` Runs everything in test case `FooTest`. * `./foo_test --gtest_filter=*Null*:*Constructor*` Runs any test whose full name contains either `"Null"` or `"Constructor"`. * `./foo_test --gtest_filter=-*DeathTest.*` Runs all non-death tests. * `./foo_test --gtest_filter=FooTest.*-FooTest.Bar` Runs everything in test case `FooTest` except `FooTest.Bar`. _Availability:_ Linux, Windows, Mac. ### Temporarily Disabling Tests ### If you have a broken test that you cannot fix right away, you can add the `DISABLED_` prefix to its name. This will exclude it from execution. This is better than commenting out the code or using `#if 0`, as disabled tests are still compiled (and thus won't rot). If you need to disable all tests in a test case, you can either add `DISABLED_` to the front of the name of each test, or alternatively add it to the front of the test case name. For example, the following tests won't be run by Google Test, even though they will still be compiled: ``` // Tests that Foo does Abc. TEST(FooTest, DISABLED_DoesAbc) { ... } class DISABLED_BarTest : public ::testing::Test { ... }; // Tests that Bar does Xyz. TEST_F(DISABLED_BarTest, DoesXyz) { ... } ``` _Note:_ This feature should only be used for temporary pain-relief. You still have to fix the disabled tests at a later date. As a reminder, Google Test will print a banner warning you if a test program contains any disabled tests. _Tip:_ You can easily count the number of disabled tests you have using `grep`. This number can be used as a metric for improving your test quality. _Availability:_ Linux, Windows, Mac. ### Temporarily Enabling Disabled Tests ### To include [disabled tests](#temporarily-disabling-tests) in test execution, just invoke the test program with the `--gtest_also_run_disabled_tests` flag or set the `GTEST_ALSO_RUN_DISABLED_TESTS` environment variable to a value other than `0`. You can combine this with the [--gtest\_filter](#running-a-subset-of-the-tests) flag to further select which disabled tests to run. _Availability:_ Linux, Windows, Mac; since version 1.3.0. ## Repeating the Tests ## Once in a while you'll run into a test whose result is hit-or-miss. Perhaps it will fail only 1% of the time, making it rather hard to reproduce the bug under a debugger. This can be a major source of frustration. The `--gtest_repeat` flag allows you to repeat all (or selected) test methods in a program many times. Hopefully, a flaky test will eventually fail and give you a chance to debug. Here's how to use it: | `$ foo_test --gtest_repeat=1000` | Repeat foo\_test 1000 times and don't stop at failures. | |:---------------------------------|:--------------------------------------------------------| | `$ foo_test --gtest_repeat=-1` | A negative count means repeating forever. | | `$ foo_test --gtest_repeat=1000 --gtest_break_on_failure` | Repeat foo\_test 1000 times, stopping at the first failure. This is especially useful when running under a debugger: when the testfails, it will drop into the debugger and you can then inspect variables and stacks. | | `$ foo_test --gtest_repeat=1000 --gtest_filter=FooBar` | Repeat the tests whose name matches the filter 1000 times. | If your test program contains global set-up/tear-down code registered using `AddGlobalTestEnvironment()`, it will be repeated in each iteration as well, as the flakiness may be in it. You can also specify the repeat count by setting the `GTEST_REPEAT` environment variable. _Availability:_ Linux, Windows, Mac. ## Shuffling the Tests ## You can specify the `--gtest_shuffle` flag (or set the `GTEST_SHUFFLE` environment variable to `1`) to run the tests in a program in a random order. This helps to reveal bad dependencies between tests. By default, Google Test uses a random seed calculated from the current time. Therefore you'll get a different order every time. The console output includes the random seed value, such that you can reproduce an order-related test failure later. To specify the random seed explicitly, use the `--gtest_random_seed=SEED` flag (or set the `GTEST_RANDOM_SEED` environment variable), where `SEED` is an integer between 0 and 99999. The seed value 0 is special: it tells Google Test to do the default behavior of calculating the seed from the current time. If you combine this with `--gtest_repeat=N`, Google Test will pick a different random seed and re-shuffle the tests in each iteration. _Availability:_ Linux, Windows, Mac; since v1.4.0. ## Controlling Test Output ## This section teaches how to tweak the way test results are reported. ### Colored Terminal Output ### Google Test can use colors in its terminal output to make it easier to spot the separation between tests, and whether tests passed. You can set the GTEST\_COLOR environment variable or set the `--gtest_color` command line flag to `yes`, `no`, or `auto` (the default) to enable colors, disable colors, or let Google Test decide. When the value is `auto`, Google Test will use colors if and only if the output goes to a terminal and (on non-Windows platforms) the `TERM` environment variable is set to `xterm` or `xterm-color`. _Availability:_ Linux, Windows, Mac. ### Suppressing the Elapsed Time ### By default, Google Test prints the time it takes to run each test. To suppress that, run the test program with the `--gtest_print_time=0` command line flag. Setting the `GTEST_PRINT_TIME` environment variable to `0` has the same effect. _Availability:_ Linux, Windows, Mac. (In Google Test 1.3.0 and lower, the default behavior is that the elapsed time is **not** printed.) ### Generating an XML Report ### Google Test can emit a detailed XML report to a file in addition to its normal textual output. The report contains the duration of each test, and thus can help you identify slow tests. To generate the XML report, set the `GTEST_OUTPUT` environment variable or the `--gtest_output` flag to the string `"xml:_path_to_output_file_"`, which will create the file at the given location. You can also just use the string `"xml"`, in which case the output can be found in the `test_detail.xml` file in the current directory. If you specify a directory (for example, `"xml:output/directory/"` on Linux or `"xml:output\directory\"` on Windows), Google Test will create the XML file in that directory, named after the test executable (e.g. `foo_test.xml` for test program `foo_test` or `foo_test.exe`). If the file already exists (perhaps left over from a previous run), Google Test will pick a different name (e.g. `foo_test_1.xml`) to avoid overwriting it. The report uses the format described here. It is based on the `junitreport` Ant task and can be parsed by popular continuous build systems like [Jenkins](http://jenkins-ci.org/). Since that format was originally intended for Java, a little interpretation is required to make it apply to Google Test tests, as shown here: ``` ``` * The root `` element corresponds to the entire test program. * `` elements correspond to Google Test test cases. * `` elements correspond to Google Test test functions. For instance, the following program ``` TEST(MathTest, Addition) { ... } TEST(MathTest, Subtraction) { ... } TEST(LogicTest, NonContradiction) { ... } ``` could generate this report: ``` ``` Things to note: * The `tests` attribute of a `` or `` element tells how many test functions the Google Test program or test case contains, while the `failures` attribute tells how many of them failed. * The `time` attribute expresses the duration of the test, test case, or entire test program in milliseconds. * Each `` element corresponds to a single failed Google Test assertion. * Some JUnit concepts don't apply to Google Test, yet we have to conform to the DTD. Therefore you'll see some dummy elements and attributes in the report. You can safely ignore these parts. _Availability:_ Linux, Windows, Mac. ## Controlling How Failures Are Reported ## ### Turning Assertion Failures into Break-Points ### When running test programs under a debugger, it's very convenient if the debugger can catch an assertion failure and automatically drop into interactive mode. Google Test's _break-on-failure_ mode supports this behavior. To enable it, set the `GTEST_BREAK_ON_FAILURE` environment variable to a value other than `0` . Alternatively, you can use the `--gtest_break_on_failure` command line flag. _Availability:_ Linux, Windows, Mac. ### Disabling Catching Test-Thrown Exceptions ### Google Test can be used either with or without exceptions enabled. If a test throws a C++ exception or (on Windows) a structured exception (SEH), by default Google Test catches it, reports it as a test failure, and continues with the next test method. This maximizes the coverage of a test run. Also, on Windows an uncaught exception will cause a pop-up window, so catching the exceptions allows you to run the tests automatically. When debugging the test failures, however, you may instead want the exceptions to be handled by the debugger, such that you can examine the call stack when an exception is thrown. To achieve that, set the `GTEST_CATCH_EXCEPTIONS` environment variable to `0`, or use the `--gtest_catch_exceptions=0` flag when running the tests. **Availability**: Linux, Windows, Mac. ### Letting Another Testing Framework Drive ### If you work on a project that has already been using another testing framework and is not ready to completely switch to Google Test yet, you can get much of Google Test's benefit by using its assertions in your existing tests. Just change your `main()` function to look like: ``` #include "gtest/gtest.h" int main(int argc, char** argv) { ::testing::GTEST_FLAG(throw_on_failure) = true; // Important: Google Test must be initialized. ::testing::InitGoogleTest(&argc, argv); ... whatever your existing testing framework requires ... } ``` With that, you can use Google Test assertions in addition to the native assertions your testing framework provides, for example: ``` void TestFooDoesBar() { Foo foo; EXPECT_LE(foo.Bar(1), 100); // A Google Test assertion. CPPUNIT_ASSERT(foo.IsEmpty()); // A native assertion. } ``` If a Google Test assertion fails, it will print an error message and throw an exception, which will be treated as a failure by your host testing framework. If you compile your code with exceptions disabled, a failed Google Test assertion will instead exit your program with a non-zero code, which will also signal a test failure to your test runner. If you don't write `::testing::GTEST_FLAG(throw_on_failure) = true;` in your `main()`, you can alternatively enable this feature by specifying the `--gtest_throw_on_failure` flag on the command-line or setting the `GTEST_THROW_ON_FAILURE` environment variable to a non-zero value. Death tests are _not_ supported when other test framework is used to organize tests. _Availability:_ Linux, Windows, Mac; since v1.3.0. ## Distributing Test Functions to Multiple Machines ## If you have more than one machine you can use to run a test program, you might want to run the test functions in parallel and get the result faster. We call this technique _sharding_, where each machine is called a _shard_. Google Test is compatible with test sharding. To take advantage of this feature, your test runner (not part of Google Test) needs to do the following: 1. Allocate a number of machines (shards) to run the tests. 1. On each shard, set the `GTEST_TOTAL_SHARDS` environment variable to the total number of shards. It must be the same for all shards. 1. On each shard, set the `GTEST_SHARD_INDEX` environment variable to the index of the shard. Different shards must be assigned different indices, which must be in the range `[0, GTEST_TOTAL_SHARDS - 1]`. 1. Run the same test program on all shards. When Google Test sees the above two environment variables, it will select a subset of the test functions to run. Across all shards, each test function in the program will be run exactly once. 1. Wait for all shards to finish, then collect and report the results. Your project may have tests that were written without Google Test and thus don't understand this protocol. In order for your test runner to figure out which test supports sharding, it can set the environment variable `GTEST_SHARD_STATUS_FILE` to a non-existent file path. If a test program supports sharding, it will create this file to acknowledge the fact (the actual contents of the file are not important at this time; although we may stick some useful information in it in the future.); otherwise it will not create it. Here's an example to make it clear. Suppose you have a test program `foo_test` that contains the following 5 test functions: ``` TEST(A, V) TEST(A, W) TEST(B, X) TEST(B, Y) TEST(B, Z) ``` and you have 3 machines at your disposal. To run the test functions in parallel, you would set `GTEST_TOTAL_SHARDS` to 3 on all machines, and set `GTEST_SHARD_INDEX` to 0, 1, and 2 on the machines respectively. Then you would run the same `foo_test` on each machine. Google Test reserves the right to change how the work is distributed across the shards, but here's one possible scenario: * Machine #0 runs `A.V` and `B.X`. * Machine #1 runs `A.W` and `B.Y`. * Machine #2 runs `B.Z`. _Availability:_ Linux, Windows, Mac; since version 1.3.0. # Fusing Google Test Source Files # Google Test's implementation consists of ~30 files (excluding its own tests). Sometimes you may want them to be packaged up in two files (a `.h` and a `.cc`) instead, such that you can easily copy them to a new machine and start hacking there. For this we provide an experimental Python script `fuse_gtest_files.py` in the `scripts/` directory (since release 1.3.0). Assuming you have Python 2.4 or above installed on your machine, just go to that directory and run ``` python fuse_gtest_files.py OUTPUT_DIR ``` and you should see an `OUTPUT_DIR` directory being created with files `gtest/gtest.h` and `gtest/gtest-all.cc` in it. These files contain everything you need to use Google Test. Just copy them to anywhere you want and you are ready to write tests. You can use the [scripts/test/Makefile](../scripts/test/Makefile) file as an example on how to compile your tests against them. # Where to Go from Here # Congratulations! You've now learned more advanced Google Test tools and are ready to tackle more complex testing tasks. If you want to dive even deeper, you can read the [Frequently-Asked Questions](V1_7_FAQ.md). assimp-4.1.0/contrib/gtest/docs/Primer.md0000644002537200234200000006025413213503245020561 0ustar zmoelnigiemusers # Introduction: Why Google C++ Testing Framework? # _Google C++ Testing Framework_ helps you write better C++ tests. No matter whether you work on Linux, Windows, or a Mac, if you write C++ code, Google Test can help you. So what makes a good test, and how does Google C++ Testing Framework fit in? We believe: 1. Tests should be _independent_ and _repeatable_. It's a pain to debug a test that succeeds or fails as a result of other tests. Google C++ Testing Framework isolates the tests by running each of them on a different object. When a test fails, Google C++ Testing Framework allows you to run it in isolation for quick debugging. 1. Tests should be well _organized_ and reflect the structure of the tested code. Google C++ Testing Framework groups related tests into test cases that can share data and subroutines. This common pattern is easy to recognize and makes tests easy to maintain. Such consistency is especially helpful when people switch projects and start to work on a new code base. 1. Tests should be _portable_ and _reusable_. The open-source community has a lot of code that is platform-neutral, its tests should also be platform-neutral. Google C++ Testing Framework works on different OSes, with different compilers (gcc, MSVC, and others), with or without exceptions, so Google C++ Testing Framework tests can easily work with a variety of configurations. (Note that the current release only contains build scripts for Linux - we are actively working on scripts for other platforms.) 1. When tests fail, they should provide as much _information_ about the problem as possible. Google C++ Testing Framework doesn't stop at the first test failure. Instead, it only stops the current test and continues with the next. You can also set up tests that report non-fatal failures after which the current test continues. Thus, you can detect and fix multiple bugs in a single run-edit-compile cycle. 1. The testing framework should liberate test writers from housekeeping chores and let them focus on the test _content_. Google C++ Testing Framework automatically keeps track of all tests defined, and doesn't require the user to enumerate them in order to run them. 1. Tests should be _fast_. With Google C++ Testing Framework, you can reuse shared resources across tests and pay for the set-up/tear-down only once, without making tests depend on each other. Since Google C++ Testing Framework is based on the popular xUnit architecture, you'll feel right at home if you've used JUnit or PyUnit before. If not, it will take you about 10 minutes to learn the basics and get started. So let's go! _Note:_ We sometimes refer to Google C++ Testing Framework informally as _Google Test_. # Setting up a New Test Project # To write a test program using Google Test, you need to compile Google Test into a library and link your test with it. We provide build files for some popular build systems: `msvc/` for Visual Studio, `xcode/` for Mac Xcode, `make/` for GNU make, `codegear/` for Borland C++ Builder, and the autotools script (deprecated) and `CMakeLists.txt` for CMake (recommended) in the Google Test root directory. If your build system is not on this list, you can take a look at `make/Makefile` to learn how Google Test should be compiled (basically you want to compile `src/gtest-all.cc` with `GTEST_ROOT` and `GTEST_ROOT/include` in the header search path, where `GTEST_ROOT` is the Google Test root directory). Once you are able to compile the Google Test library, you should create a project or build target for your test program. Make sure you have `GTEST_ROOT/include` in the header search path so that the compiler can find `"gtest/gtest.h"` when compiling your test. Set up your test project to link with the Google Test library (for example, in Visual Studio, this is done by adding a dependency on `gtest.vcproj`). If you still have questions, take a look at how Google Test's own tests are built and use them as examples. # Basic Concepts # When using Google Test, you start by writing _assertions_, which are statements that check whether a condition is true. An assertion's result can be _success_, _nonfatal failure_, or _fatal failure_. If a fatal failure occurs, it aborts the current function; otherwise the program continues normally. _Tests_ use assertions to verify the tested code's behavior. If a test crashes or has a failed assertion, then it _fails_; otherwise it _succeeds_. A _test case_ contains one or many tests. You should group your tests into test cases that reflect the structure of the tested code. When multiple tests in a test case need to share common objects and subroutines, you can put them into a _test fixture_ class. A _test program_ can contain multiple test cases. We'll now explain how to write a test program, starting at the individual assertion level and building up to tests and test cases. # Assertions # Google Test assertions are macros that resemble function calls. You test a class or function by making assertions about its behavior. When an assertion fails, Google Test prints the assertion's source file and line number location, along with a failure message. You may also supply a custom failure message which will be appended to Google Test's message. The assertions come in pairs that test the same thing but have different effects on the current function. `ASSERT_*` versions generate fatal failures when they fail, and **abort the current function**. `EXPECT_*` versions generate nonfatal failures, which don't abort the current function. Usually `EXPECT_*` are preferred, as they allow more than one failures to be reported in a test. However, you should use `ASSERT_*` if it doesn't make sense to continue when the assertion in question fails. Since a failed `ASSERT_*` returns from the current function immediately, possibly skipping clean-up code that comes after it, it may cause a space leak. Depending on the nature of the leak, it may or may not be worth fixing - so keep this in mind if you get a heap checker error in addition to assertion errors. To provide a custom failure message, simply stream it into the macro using the `<<` operator, or a sequence of such operators. An example: ``` ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length"; for (int i = 0; i < x.size(); ++i) { EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i; } ``` Anything that can be streamed to an `ostream` can be streamed to an assertion macro--in particular, C strings and `string` objects. If a wide string (`wchar_t*`, `TCHAR*` in `UNICODE` mode on Windows, or `std::wstring`) is streamed to an assertion, it will be translated to UTF-8 when printed. ## Basic Assertions ## These assertions do basic true/false condition testing. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_TRUE(`_condition_`)`; | `EXPECT_TRUE(`_condition_`)`; | _condition_ is true | | `ASSERT_FALSE(`_condition_`)`; | `EXPECT_FALSE(`_condition_`)`; | _condition_ is false | Remember, when they fail, `ASSERT_*` yields a fatal failure and returns from the current function, while `EXPECT_*` yields a nonfatal failure, allowing the function to continue running. In either case, an assertion failure means its containing test fails. _Availability_: Linux, Windows, Mac. ## Binary Comparison ## This section describes assertions that compare two values. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| |`ASSERT_EQ(`_val1_`, `_val2_`);`|`EXPECT_EQ(`_val1_`, `_val2_`);`| _val1_ `==` _val2_ | |`ASSERT_NE(`_val1_`, `_val2_`);`|`EXPECT_NE(`_val1_`, `_val2_`);`| _val1_ `!=` _val2_ | |`ASSERT_LT(`_val1_`, `_val2_`);`|`EXPECT_LT(`_val1_`, `_val2_`);`| _val1_ `<` _val2_ | |`ASSERT_LE(`_val1_`, `_val2_`);`|`EXPECT_LE(`_val1_`, `_val2_`);`| _val1_ `<=` _val2_ | |`ASSERT_GT(`_val1_`, `_val2_`);`|`EXPECT_GT(`_val1_`, `_val2_`);`| _val1_ `>` _val2_ | |`ASSERT_GE(`_val1_`, `_val2_`);`|`EXPECT_GE(`_val1_`, `_val2_`);`| _val1_ `>=` _val2_ | In the event of a failure, Google Test prints both _val1_ and _val2_. Value arguments must be comparable by the assertion's comparison operator or you'll get a compiler error. We used to require the arguments to support the `<<` operator for streaming to an `ostream`, but it's no longer necessary since v1.6.0 (if `<<` is supported, it will be called to print the arguments when the assertion fails; otherwise Google Test will attempt to print them in the best way it can. For more details and how to customize the printing of the arguments, see this Google Mock [recipe](../../googlemock/docs/CookBook.md#teaching-google-mock-how-to-print-your-values).). These assertions can work with a user-defined type, but only if you define the corresponding comparison operator (e.g. `==`, `<`, etc). If the corresponding operator is defined, prefer using the `ASSERT_*()` macros because they will print out not only the result of the comparison, but the two operands as well. Arguments are always evaluated exactly once. Therefore, it's OK for the arguments to have side effects. However, as with any ordinary C/C++ function, the arguments' evaluation order is undefined (i.e. the compiler is free to choose any order) and your code should not depend on any particular argument evaluation order. `ASSERT_EQ()` does pointer equality on pointers. If used on two C strings, it tests if they are in the same memory location, not if they have the same value. Therefore, if you want to compare C strings (e.g. `const char*`) by value, use `ASSERT_STREQ()` , which will be described later on. In particular, to assert that a C string is `NULL`, use `ASSERT_STREQ(NULL, c_string)` . However, to compare two `string` objects, you should use `ASSERT_EQ`. Macros in this section work with both narrow and wide string objects (`string` and `wstring`). _Availability_: Linux, Windows, Mac. _Historical note_: Before February 2016 `*_EQ` had a convention of calling it as `ASSERT_EQ(expected, actual)`, so lots of existing code uses this order. Now `*_EQ` treats both parameters in the same way. ## String Comparison ## The assertions in this group compare two **C strings**. If you want to compare two `string` objects, use `EXPECT_EQ`, `EXPECT_NE`, and etc instead. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_STREQ(`_str1_`, `_str2_`);` | `EXPECT_STREQ(`_str1_`, `_str_2`);` | the two C strings have the same content | | `ASSERT_STRNE(`_str1_`, `_str2_`);` | `EXPECT_STRNE(`_str1_`, `_str2_`);` | the two C strings have different content | | `ASSERT_STRCASEEQ(`_str1_`, `_str2_`);`| `EXPECT_STRCASEEQ(`_str1_`, `_str2_`);` | the two C strings have the same content, ignoring case | | `ASSERT_STRCASENE(`_str1_`, `_str2_`);`| `EXPECT_STRCASENE(`_str1_`, `_str2_`);` | the two C strings have different content, ignoring case | Note that "CASE" in an assertion name means that case is ignored. `*STREQ*` and `*STRNE*` also accept wide C strings (`wchar_t*`). If a comparison of two wide strings fails, their values will be printed as UTF-8 narrow strings. A `NULL` pointer and an empty string are considered _different_. _Availability_: Linux, Windows, Mac. See also: For more string comparison tricks (substring, prefix, suffix, and regular expression matching, for example), see the [Advanced Google Test Guide](AdvancedGuide.md). # Simple Tests # To create a test: 1. Use the `TEST()` macro to define and name a test function, These are ordinary C++ functions that don't return a value. 1. In this function, along with any valid C++ statements you want to include, use the various Google Test assertions to check values. 1. The test's result is determined by the assertions; if any assertion in the test fails (either fatally or non-fatally), or if the test crashes, the entire test fails. Otherwise, it succeeds. ``` TEST(test_case_name, test_name) { ... test body ... } ``` `TEST()` arguments go from general to specific. The _first_ argument is the name of the test case, and the _second_ argument is the test's name within the test case. Both names must be valid C++ identifiers, and they should not contain underscore (`_`). A test's _full name_ consists of its containing test case and its individual name. Tests from different test cases can have the same individual name. For example, let's take a simple integer function: ``` int Factorial(int n); // Returns the factorial of n ``` A test case for this function might look like: ``` // Tests factorial of 0. TEST(FactorialTest, HandlesZeroInput) { EXPECT_EQ(1, Factorial(0)); } // Tests factorial of positive numbers. TEST(FactorialTest, HandlesPositiveInput) { EXPECT_EQ(1, Factorial(1)); EXPECT_EQ(2, Factorial(2)); EXPECT_EQ(6, Factorial(3)); EXPECT_EQ(40320, Factorial(8)); } ``` Google Test groups the test results by test cases, so logically-related tests should be in the same test case; in other words, the first argument to their `TEST()` should be the same. In the above example, we have two tests, `HandlesZeroInput` and `HandlesPositiveInput`, that belong to the same test case `FactorialTest`. _Availability_: Linux, Windows, Mac. # Test Fixtures: Using the Same Data Configuration for Multiple Tests # If you find yourself writing two or more tests that operate on similar data, you can use a _test fixture_. It allows you to reuse the same configuration of objects for several different tests. To create a fixture, just: 1. Derive a class from `::testing::Test` . Start its body with `protected:` or `public:` as we'll want to access fixture members from sub-classes. 1. Inside the class, declare any objects you plan to use. 1. If necessary, write a default constructor or `SetUp()` function to prepare the objects for each test. A common mistake is to spell `SetUp()` as `Setup()` with a small `u` - don't let that happen to you. 1. If necessary, write a destructor or `TearDown()` function to release any resources you allocated in `SetUp()` . To learn when you should use the constructor/destructor and when you should use `SetUp()/TearDown()`, read this [FAQ entry](FAQ.md#should-i-use-the-constructordestructor-of-the-test-fixture-or-the-set-uptear-down-function). 1. If needed, define subroutines for your tests to share. When using a fixture, use `TEST_F()` instead of `TEST()` as it allows you to access objects and subroutines in the test fixture: ``` TEST_F(test_case_name, test_name) { ... test body ... } ``` Like `TEST()`, the first argument is the test case name, but for `TEST_F()` this must be the name of the test fixture class. You've probably guessed: `_F` is for fixture. Unfortunately, the C++ macro system does not allow us to create a single macro that can handle both types of tests. Using the wrong macro causes a compiler error. Also, you must first define a test fixture class before using it in a `TEST_F()`, or you'll get the compiler error "`virtual outside class declaration`". For each test defined with `TEST_F()`, Google Test will: 1. Create a _fresh_ test fixture at runtime 1. Immediately initialize it via `SetUp()` , 1. Run the test 1. Clean up by calling `TearDown()` 1. Delete the test fixture. Note that different tests in the same test case have different test fixture objects, and Google Test always deletes a test fixture before it creates the next one. Google Test does not reuse the same test fixture for multiple tests. Any changes one test makes to the fixture do not affect other tests. As an example, let's write tests for a FIFO queue class named `Queue`, which has the following interface: ``` template // E is the element type. class Queue { public: Queue(); void Enqueue(const E& element); E* Dequeue(); // Returns NULL if the queue is empty. size_t size() const; ... }; ``` First, define a fixture class. By convention, you should give it the name `FooTest` where `Foo` is the class being tested. ``` class QueueTest : public ::testing::Test { protected: virtual void SetUp() { q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // virtual void TearDown() {} Queue q0_; Queue q1_; Queue q2_; }; ``` In this case, `TearDown()` is not needed since we don't have to clean up after each test, other than what's already done by the destructor. Now we'll write tests using `TEST_F()` and this fixture. ``` TEST_F(QueueTest, IsEmptyInitially) { EXPECT_EQ(0, q0_.size()); } TEST_F(QueueTest, DequeueWorks) { int* n = q0_.Dequeue(); EXPECT_EQ(NULL, n); n = q1_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(1, *n); EXPECT_EQ(0, q1_.size()); delete n; n = q2_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(2, *n); EXPECT_EQ(1, q2_.size()); delete n; } ``` The above uses both `ASSERT_*` and `EXPECT_*` assertions. The rule of thumb is to use `EXPECT_*` when you want the test to continue to reveal more errors after the assertion failure, and use `ASSERT_*` when continuing after failure doesn't make sense. For example, the second assertion in the `Dequeue` test is `ASSERT_TRUE(n != NULL)`, as we need to dereference the pointer `n` later, which would lead to a segfault when `n` is `NULL`. When these tests run, the following happens: 1. Google Test constructs a `QueueTest` object (let's call it `t1` ). 1. `t1.SetUp()` initializes `t1` . 1. The first test ( `IsEmptyInitially` ) runs on `t1` . 1. `t1.TearDown()` cleans up after the test finishes. 1. `t1` is destructed. 1. The above steps are repeated on another `QueueTest` object, this time running the `DequeueWorks` test. _Availability_: Linux, Windows, Mac. _Note_: Google Test automatically saves all _Google Test_ flags when a test object is constructed, and restores them when it is destructed. # Invoking the Tests # `TEST()` and `TEST_F()` implicitly register their tests with Google Test. So, unlike with many other C++ testing frameworks, you don't have to re-list all your defined tests in order to run them. After defining your tests, you can run them with `RUN_ALL_TESTS()` , which returns `0` if all the tests are successful, or `1` otherwise. Note that `RUN_ALL_TESTS()` runs _all tests_ in your link unit -- they can be from different test cases, or even different source files. When invoked, the `RUN_ALL_TESTS()` macro: 1. Saves the state of all Google Test flags. 1. Creates a test fixture object for the first test. 1. Initializes it via `SetUp()`. 1. Runs the test on the fixture object. 1. Cleans up the fixture via `TearDown()`. 1. Deletes the fixture. 1. Restores the state of all Google Test flags. 1. Repeats the above steps for the next test, until all tests have run. In addition, if the text fixture's constructor generates a fatal failure in step 2, there is no point for step 3 - 5 and they are thus skipped. Similarly, if step 3 generates a fatal failure, step 4 will be skipped. _Important_: You must not ignore the return value of `RUN_ALL_TESTS()`, or `gcc` will give you a compiler error. The rationale for this design is that the automated testing service determines whether a test has passed based on its exit code, not on its stdout/stderr output; thus your `main()` function must return the value of `RUN_ALL_TESTS()`. Also, you should call `RUN_ALL_TESTS()` only **once**. Calling it more than once conflicts with some advanced Google Test features (e.g. thread-safe death tests) and thus is not supported. _Availability_: Linux, Windows, Mac. # Writing the main() Function # You can start from this boilerplate: ``` #include "this/package/foo.h" #include "gtest/gtest.h" namespace { // The fixture for testing class Foo. class FooTest : public ::testing::Test { protected: // You can remove any or all of the following functions if its body // is empty. FooTest() { // You can do set-up work for each test here. } virtual ~FooTest() { // You can do clean-up work that doesn't throw exceptions here. } // If the constructor and destructor are not enough for setting up // and cleaning up each test, you can define the following methods: virtual void SetUp() { // Code here will be called immediately after the constructor (right // before each test). } virtual void TearDown() { // Code here will be called immediately after each test (right // before the destructor). } // Objects declared here can be used by all tests in the test case for Foo. }; // Tests that the Foo::Bar() method does Abc. TEST_F(FooTest, MethodBarDoesAbc) { const string input_filepath = "this/package/testdata/myinputfile.dat"; const string output_filepath = "this/package/testdata/myoutputfile.dat"; Foo f; EXPECT_EQ(0, f.Bar(input_filepath, output_filepath)); } // Tests that Foo does Xyz. TEST_F(FooTest, DoesXyz) { // Exercises the Xyz feature of Foo. } } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ``` The `::testing::InitGoogleTest()` function parses the command line for Google Test flags, and removes all recognized flags. This allows the user to control a test program's behavior via various flags, which we'll cover in [AdvancedGuide](AdvancedGuide.md). You must call this function before calling `RUN_ALL_TESTS()`, or the flags won't be properly initialized. On Windows, `InitGoogleTest()` also works with wide strings, so it can be used in programs compiled in `UNICODE` mode as well. But maybe you think that writing all those main() functions is too much work? We agree with you completely and that's why Google Test provides a basic implementation of main(). If it fits your needs, then just link your test with gtest\_main library and you are good to go. ## Important note for Visual C++ users ## If you put your tests into a library and your `main()` function is in a different library or in your .exe file, those tests will not run. The reason is a [bug](https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&siteid=210) in Visual C++. When you define your tests, Google Test creates certain static objects to register them. These objects are not referenced from elsewhere but their constructors are still supposed to run. When Visual C++ linker sees that nothing in the library is referenced from other places it throws the library out. You have to reference your library with tests from your main program to keep the linker from discarding it. Here is how to do it. Somewhere in your library code declare a function: ``` __declspec(dllexport) int PullInMyLibrary() { return 0; } ``` If you put your tests in a static library (not DLL) then `__declspec(dllexport)` is not required. Now, in your main program, write a code that invokes that function: ``` int PullInMyLibrary(); static int dummy = PullInMyLibrary(); ``` This will keep your tests referenced and will make them register themselves at startup. In addition, if you define your tests in a static library, add `/OPT:NOREF` to your main program linker options. If you use MSVC++ IDE, go to your .exe project properties/Configuration Properties/Linker/Optimization and set References setting to `Keep Unreferenced Data (/OPT:NOREF)`. This will keep Visual C++ linker from discarding individual symbols generated by your tests from the final executable. There is one more pitfall, though. If you use Google Test as a static library (that's how it is defined in gtest.vcproj) your tests must also reside in a static library. If you have to have them in a DLL, you _must_ change Google Test to build into a DLL as well. Otherwise your tests will not run correctly or will not run at all. The general conclusion here is: make your life easier - do not write your tests in libraries! # Where to Go from Here # Congratulations! You've learned the Google Test basics. You can start writing and running Google Test tests, read some [samples](Samples.md), or continue with [AdvancedGuide](AdvancedGuide.md), which describes many more useful Google Test features. # Known Limitations # Google Test is designed to be thread-safe. The implementation is thread-safe on systems where the `pthreads` library is available. It is currently _unsafe_ to use Google Test assertions from two threads concurrently on other systems (e.g. Windows). In most tests this is not an issue as usually the assertions are done in the main thread. If you want to help, you can volunteer to implement the necessary synchronization primitives in `gtest-port.h` for your platform. assimp-4.1.0/contrib/gtest/docs/V1_6_PumpManual.md0000644002537200234200000001561413213503245022175 0ustar zmoelnigiemusers Pump is Useful for Meta Programming. # The Problem # Template and macro libraries often need to define many classes, functions, or macros that vary only (or almost only) in the number of arguments they take. It's a lot of repetitive, mechanical, and error-prone work. Variadic templates and variadic macros can alleviate the problem. However, while both are being considered by the C++ committee, neither is in the standard yet or widely supported by compilers. Thus they are often not a good choice, especially when your code needs to be portable. And their capabilities are still limited. As a result, authors of such libraries often have to write scripts to generate their implementation. However, our experience is that it's tedious to write such scripts, which tend to reflect the structure of the generated code poorly and are often hard to read and edit. For example, a small change needed in the generated code may require some non-intuitive, non-trivial changes in the script. This is especially painful when experimenting with the code. # Our Solution # Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta Programming, or Practical Utility for Meta Programming, whichever you prefer) is a simple meta-programming tool for C++. The idea is that a programmer writes a `foo.pump` file which contains C++ code plus meta code that manipulates the C++ code. The meta code can handle iterations over a range, nested iterations, local meta variable definitions, simple arithmetic, and conditional expressions. You can view it as a small Domain-Specific Language. The meta language is designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, for example) and concise, making Pump code intuitive and easy to maintain. ## Highlights ## * The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms. * Pump tries to be smart with respect to [Google's style guide](http://code.google.com/p/google-styleguide/): it breaks long lines (easy to have when they are generated) at acceptable places to fit within 80 columns and indent the continuation lines correctly. * The format is human-readable and more concise than XML. * The format works relatively well with Emacs' C++ mode. ## Examples ## The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line): ``` $var n = 3 $$ Defines a meta variable n. $range i 0..n $$ Declares the range of meta iterator i (inclusive). $for i [[ $$ Meta loop. // Foo$i does blah for $i-ary predicates. $range j 1..i template class Foo$i { $if i == 0 [[ blah a; ]] $elif i <= 2 [[ blah b; ]] $else [[ blah c; ]] }; ]] ``` will be translated by the Pump compiler to: ``` // Foo0 does blah for 0-ary predicates. template class Foo0 { blah a; }; // Foo1 does blah for 1-ary predicates. template class Foo1 { blah b; }; // Foo2 does blah for 2-ary predicates. template class Foo2 { blah b; }; // Foo3 does blah for 3-ary predicates. template class Foo3 { blah c; }; ``` In another example, ``` $range i 1..n Func($for i + [[a$i]]); $$ The text between i and [[ is the separator between iterations. ``` will generate one of the following lines (without the comments), depending on the value of `n`: ``` Func(); // If n is 0. Func(a1); // If n is 1. Func(a1 + a2); // If n is 2. Func(a1 + a2 + a3); // If n is 3. // And so on... ``` ## Constructs ## We support the following meta programming constructs: | `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. | |:----------------|:-----------------------------------------------------------------------------------------------| | `$range id exp..exp` | Sets the range of an iteration variable, which can be reused in multiple loops later. | | `$for id sep [[ code ]]` | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`. | | `$($)` | Generates a single `$` character. | | `$id` | Value of the named constant or iteration variable. | | `$(exp)` | Value of the expression. | | `$if exp [[ code ]] else_branch` | Conditional. | | `[[ code ]]` | Meta lexical block. | | `cpp_code` | Raw C++ code. | | `$$ comment` | Meta comment. | **Note:** To give the user some freedom in formatting the Pump source code, Pump ignores a new-line character if it's right after `$for foo` or next to `[[` or `]]`. Without this rule you'll often be forced to write very long lines to get the desired output. Therefore sometimes you may need to insert an extra new-line in such places for a new-line to show up in your output. ## Grammar ## ``` code ::= atomic_code* atomic_code ::= $var id = exp | $var id = [[ code ]] | $range id exp..exp | $for id sep [[ code ]] | $($) | $id | $(exp) | $if exp [[ code ]] else_branch | [[ code ]] | cpp_code sep ::= cpp_code | empty_string else_branch ::= $else [[ code ]] | $elif exp [[ code ]] else_branch | empty_string exp ::= simple_expression_in_Python_syntax ``` ## Code ## You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still very unpolished and lacks automated tests, although it has been successfully used many times. If you find a chance to use it in your project, please let us know what you think! We also welcome help on improving Pump. ## Real Examples ## You can find real-world applications of Pump in [Google Test](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgoogletest\.googlecode\.com) and [Google Mock](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgooglemock\.googlecode\.com). The source file `foo.h.pump` generates `foo.h`. ## Tips ## * If a meta variable is followed by a letter or digit, you can separate them using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper` generate `Foo1Helper` when `j` is 1. * To avoid extra-long Pump source lines, you can break a line anywhere you want by inserting `[[]]` followed by a new line. Since any new-line character next to `[[` or `]]` is ignored, the generated code won't contain this new line. assimp-4.1.0/contrib/gtest/docs/V1_7_Documentation.md0000644002537200234200000000145113213503245022722 0ustar zmoelnigiemusersThis page lists all documentation wiki pages for Google Test **(the SVN trunk version)** -- **if you use a released version of Google Test, please read the documentation for that specific version instead.** * [Primer](V1_7_Primer.md) -- start here if you are new to Google Test. * [Samples](V1_7_Samples.md) -- learn from examples. * [AdvancedGuide](V1_7_AdvancedGuide.md) -- learn more about Google Test. * [XcodeGuide](V1_7_XcodeGuide.md) -- how to use Google Test in Xcode on Mac. * [Frequently-Asked Questions](V1_7_FAQ.md) -- check here before asking a question on the mailing list. To contribute code to Google Test, read: * [DevGuide](DevGuide.md) -- read this _before_ writing your first patch. * [PumpManual](V1_7_PumpManual.md) -- how we generate some of Google Test's source files.assimp-4.1.0/contrib/gtest/docs/V1_6_Documentation.md0000644002537200234200000000142513213503245022722 0ustar zmoelnigiemusersThis page lists all documentation wiki pages for Google Test **1.6** -- **if you use a released version of Google Test, please read the documentation for that specific version instead.** * [Primer](V1_6_Primer.md) -- start here if you are new to Google Test. * [Samples](V1_6_Samples.md) -- learn from examples. * [AdvancedGuide](V1_6_AdvancedGuide.md) -- learn more about Google Test. * [XcodeGuide](V1_6_XcodeGuide.md) -- how to use Google Test in Xcode on Mac. * [Frequently-Asked Questions](V1_6_FAQ.md) -- check here before asking a question on the mailing list. To contribute code to Google Test, read: * [DevGuide](DevGuide.md) -- read this _before_ writing your first patch. * [PumpManual](V1_6_PumpManual.md) -- how we generate some of Google Test's source files.assimp-4.1.0/contrib/gtest/docs/V1_7_Samples.md0000644002537200234200000000246113213503245021517 0ustar zmoelnigiemusersIf you're like us, you'd like to look at some Google Test sample code. The [samples folder](../samples) has a number of well-commented samples showing how to use a variety of Google Test features. * [Sample #1](../samples/sample1_unittest.cc) shows the basic steps of using Google Test to test C++ functions. * [Sample #2](../samples/sample2_unittest.cc) shows a more complex unit test for a class with multiple member functions. * [Sample #3](../samples/sample3_unittest.cc) uses a test fixture. * [Sample #4](../samples/sample4_unittest.cc) is another basic example of using Google Test. * [Sample #5](../samples/sample5_unittest.cc) teaches how to reuse a test fixture in multiple test cases by deriving sub-fixtures from it. * [Sample #6](../samples/sample6_unittest.cc) demonstrates type-parameterized tests. * [Sample #7](../samples/sample7_unittest.cc) teaches the basics of value-parameterized tests. * [Sample #8](../samples/sample8_unittest.cc) shows using `Combine()` in value-parameterized tests. * [Sample #9](../samples/sample9_unittest.cc) shows use of the listener API to modify Google Test's console output and the use of its reflection API to inspect test results. * [Sample #10](../samples/sample10_unittest.cc) shows use of the listener API to implement a primitive memory leak checker. assimp-4.1.0/contrib/gtest/docs/V1_5_AdvancedGuide.md0000644002537200234200000024411213213503245022575 0ustar zmoelnigiemusers Now that you have read [Primer](V1_5_Primer.md) and learned how to write tests using Google Test, it's time to learn some new tricks. This document will show you more assertions as well as how to construct complex failure messages, propagate fatal failures, reuse and speed up your test fixtures, and use various flags with your tests. # More Assertions # This section covers some less frequently used, but still significant, assertions. ## Explicit Success and Failure ## These three assertions do not actually test a value or expression. Instead, they generate a success or failure directly. Like the macros that actually perform a test, you may stream a custom failure message into the them. | `SUCCEED();` | |:-------------| Generates a success. This does NOT make the overall test succeed. A test is considered successful only if none of its assertions fail during its execution. Note: `SUCCEED()` is purely documentary and currently doesn't generate any user-visible output. However, we may add `SUCCEED()` messages to Google Test's output in the future. | `FAIL();` | `ADD_FAILURE();` | |:-----------|:-----------------| `FAIL*` generates a fatal failure while `ADD_FAILURE*` generates a nonfatal failure. These are useful when control flow, rather than a Boolean expression, deteremines the test's success or failure. For example, you might want to write something like: ``` switch(expression) { case 1: ... some checks ... case 2: ... some other checks ... default: FAIL() << "We shouldn't get here."; } ``` _Availability_: Linux, Windows, Mac. ## Exception Assertions ## These are for verifying that a piece of code throws (or does not throw) an exception of the given type: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_THROW(`_statement_, _exception\_type_`);` | `EXPECT_THROW(`_statement_, _exception\_type_`);` | _statement_ throws an exception of the given type | | `ASSERT_ANY_THROW(`_statement_`);` | `EXPECT_ANY_THROW(`_statement_`);` | _statement_ throws an exception of any type | | `ASSERT_NO_THROW(`_statement_`);` | `EXPECT_NO_THROW(`_statement_`);` | _statement_ doesn't throw any exception | Examples: ``` ASSERT_THROW(Foo(5), bar_exception); EXPECT_NO_THROW({ int n = 5; Bar(&n); }); ``` _Availability_: Linux, Windows, Mac; since version 1.1.0. ## Predicate Assertions for Better Error Messages ## Even though Google Test has a rich set of assertions, they can never be complete, as it's impossible (nor a good idea) to anticipate all the scenarios a user might run into. Therefore, sometimes a user has to use `EXPECT_TRUE()` to check a complex expression, for lack of a better macro. This has the problem of not showing you the values of the parts of the expression, making it hard to understand what went wrong. As a workaround, some users choose to construct the failure message by themselves, streaming it into `EXPECT_TRUE()`. However, this is awkward especially when the expression has side-effects or is expensive to evaluate. Google Test gives you three different options to solve this problem: ### Using an Existing Boolean Function ### If you already have a function or a functor that returns `bool` (or a type that can be implicitly converted to `bool`), you can use it in a _predicate assertion_ to get the function arguments printed for free: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_PRED1(`_pred1, val1_`);` | `EXPECT_PRED1(`_pred1, val1_`);` | _pred1(val1)_ returns true | | `ASSERT_PRED2(`_pred2, val1, val2_`);` | `EXPECT_PRED2(`_pred2, val1, val2_`);` | _pred2(val1, val2)_ returns true | | ... | ... | ... | In the above, _predn_ is an _n_-ary predicate function or functor, where _val1_, _val2_, ..., and _valn_ are its arguments. The assertion succeeds if the predicate returns `true` when applied to the given arguments, and fails otherwise. When the assertion fails, it prints the value of each argument. In either case, the arguments are evaluated exactly once. Here's an example. Given ``` // Returns true iff m and n have no common divisors except 1. bool MutuallyPrime(int m, int n) { ... } const int a = 3; const int b = 4; const int c = 10; ``` the assertion `EXPECT_PRED2(MutuallyPrime, a, b);` will succeed, while the assertion `EXPECT_PRED2(MutuallyPrime, b, c);` will fail with the message
!MutuallyPrime(b, c) is false, where
b is 4
c is 10
**Notes:** 1. If you see a compiler error "no matching function to call" when using `ASSERT_PRED*` or `EXPECT_PRED*`, please see [this](V1_5_FAQ.md#the-compiler-complains-about-undefined-references-to-some-static-const-member-variables-but-i-did-define-them-in-the-class-body-whats-wrong) for how to resolve it. 1. Currently we only provide predicate assertions of arity <= 5. If you need a higher-arity assertion, let us know. _Availability_: Linux, Windows, Mac ### Using a Function That Returns an AssertionResult ### While `EXPECT_PRED*()` and friends are handy for a quick job, the syntax is not satisfactory: you have to use different macros for different arities, and it feels more like Lisp than C++. The `::testing::AssertionResult` class solves this problem. An `AssertionResult` object represents the result of an assertion (whether it's a success or a failure, and an associated message). You can create an `AssertionResult` using one of these factory functions: ``` namespace testing { // Returns an AssertionResult object to indicate that an assertion has // succeeded. AssertionResult AssertionSuccess(); // Returns an AssertionResult object to indicate that an assertion has // failed. AssertionResult AssertionFailure(); } ``` You can then use the `<<` operator to stream messages to the `AssertionResult` object. To provide more readable messages in Boolean assertions (e.g. `EXPECT_TRUE()`), write a predicate function that returns `AssertionResult` instead of `bool`. For example, if you define `IsEven()` as: ``` ::testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return ::testing::AssertionSuccess(); else return ::testing::AssertionFailure() << n << " is odd"; } ``` instead of: ``` bool IsEven(int n) { return (n % 2) == 0; } ``` the failed assertion `EXPECT_TRUE(IsEven(Fib(4)))` will print:
Value of: !IsEven(Fib(4))
Actual: false (*3 is odd*)
Expected: true
instead of a more opaque
Value of: !IsEven(Fib(4))
Actual: false
Expected: true
If you want informative messages in `EXPECT_FALSE` and `ASSERT_FALSE` as well, and are fine with making the predicate slower in the success case, you can supply a success message: ``` ::testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return ::testing::AssertionSuccess() << n << " is even"; else return ::testing::AssertionFailure() << n << " is odd"; } ``` Then the statement `EXPECT_FALSE(IsEven(Fib(6)))` will print
Value of: !IsEven(Fib(6))
Actual: true (8 is even)
Expected: false
_Availability_: Linux, Windows, Mac; since version 1.4.1. ### Using a Predicate-Formatter ### If you find the default message generated by `(ASSERT|EXPECT)_PRED*` and `(ASSERT|EXPECT)_(TRUE|FALSE)` unsatisfactory, or some arguments to your predicate do not support streaming to `ostream`, you can instead use the following _predicate-formatter assertions_ to _fully_ customize how the message is formatted: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_PRED_FORMAT1(`_pred\_format1, val1_`);` | `EXPECT_PRED_FORMAT1(`_pred\_format1, val1_`); | _pred\_format1(val1)_ is successful | | `ASSERT_PRED_FORMAT2(`_pred\_format2, val1, val2_`);` | `EXPECT_PRED_FORMAT2(`_pred\_format2, val1, val2_`);` | _pred\_format2(val1, val2)_ is successful | | `...` | `...` | `...` | The difference between this and the previous two groups of macros is that instead of a predicate, `(ASSERT|EXPECT)_PRED_FORMAT*` take a _predicate-formatter_ (_pred\_formatn_), which is a function or functor with the signature: `::testing::AssertionResult PredicateFormattern(const char* `_expr1_`, const char* `_expr2_`, ... const char* `_exprn_`, T1 `_val1_`, T2 `_val2_`, ... Tn `_valn_`);` where _val1_, _val2_, ..., and _valn_ are the values of the predicate arguments, and _expr1_, _expr2_, ..., and _exprn_ are the corresponding expressions as they appear in the source code. The types `T1`, `T2`, ..., and `Tn` can be either value types or reference types. For example, if an argument has type `Foo`, you can declare it as either `Foo` or `const Foo&`, whichever is appropriate. A predicate-formatter returns a `::testing::AssertionResult` object to indicate whether the assertion has succeeded or not. The only way to create such an object is to call one of these factory functions: As an example, let's improve the failure message in the previous example, which uses `EXPECT_PRED2()`: ``` // Returns the smallest prime common divisor of m and n, // or 1 when m and n are mutually prime. int SmallestPrimeCommonDivisor(int m, int n) { ... } // A predicate-formatter for asserting that two integers are mutually prime. ::testing::AssertionResult AssertMutuallyPrime(const char* m_expr, const char* n_expr, int m, int n) { if (MutuallyPrime(m, n)) return ::testing::AssertionSuccess(); return ::testing::AssertionFailure() << m_expr << " and " << n_expr << " (" << m << " and " << n << ") are not mutually prime, " << "as they have a common divisor " << SmallestPrimeCommonDivisor(m, n); } ``` With this predicate-formatter, we can use ``` EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c); ``` to generate the message
b and c (4 and 10) are not mutually prime, as they have a common divisor 2.
As you may have realized, many of the assertions we introduced earlier are special cases of `(EXPECT|ASSERT)_PRED_FORMAT*`. In fact, most of them are indeed defined using `(EXPECT|ASSERT)_PRED_FORMAT*`. _Availability_: Linux, Windows, Mac. ## Floating-Point Comparison ## Comparing floating-point numbers is tricky. Due to round-off errors, it is very unlikely that two floating-points will match exactly. Therefore, `ASSERT_EQ` 's naive comparison usually doesn't work. And since floating-points can have a wide value range, no single fixed error bound works. It's better to compare by a fixed relative error bound, except for values close to 0 due to the loss of precision there. In general, for floating-point comparison to make sense, the user needs to carefully choose the error bound. If they don't want or care to, comparing in terms of Units in the Last Place (ULPs) is a good default, and Google Test provides assertions to do this. Full details about ULPs are quite long; if you want to learn more, see [this article on float comparison](http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm). ### Floating-Point Macros ### | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_FLOAT_EQ(`_expected, actual_`);` | `EXPECT_FLOAT_EQ(`_expected, actual_`);` | the two `float` values are almost equal | | `ASSERT_DOUBLE_EQ(`_expected, actual_`);` | `EXPECT_DOUBLE_EQ(`_expected, actual_`);` | the two `double` values are almost equal | By "almost equal", we mean the two values are within 4 ULP's from each other. The following assertions allow you to choose the acceptable error bound: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_NEAR(`_val1, val2, abs\_error_`);` | `EXPECT_NEAR`_(val1, val2, abs\_error_`);` | the difference between _val1_ and _val2_ doesn't exceed the given absolute error | _Availability_: Linux, Windows, Mac. ### Floating-Point Predicate-Format Functions ### Some floating-point operations are useful, but not that often used. In order to avoid an explosion of new macros, we provide them as predicate-format functions that can be used in predicate assertion macros (e.g. `EXPECT_PRED_FORMAT2`, etc). ``` EXPECT_PRED_FORMAT2(::testing::FloatLE, val1, val2); EXPECT_PRED_FORMAT2(::testing::DoubleLE, val1, val2); ``` Verifies that _val1_ is less than, or almost equal to, _val2_. You can replace `EXPECT_PRED_FORMAT2` in the above table with `ASSERT_PRED_FORMAT2`. _Availability_: Linux, Windows, Mac. ## Windows HRESULT assertions ## These assertions test for `HRESULT` success or failure. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_HRESULT_SUCCEEDED(`_expression_`);` | `EXPECT_HRESULT_SUCCEEDED(`_expression_`);` | _expression_ is a success `HRESULT` | | `ASSERT_HRESULT_FAILED(`_expression_`);` | `EXPECT_HRESULT_FAILED(`_expression_`);` | _expression_ is a failure `HRESULT` | The generated output contains the human-readable error message associated with the `HRESULT` code returned by _expression_. You might use them like this: ``` CComPtr shell; ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application")); CComVariant empty; ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty)); ``` _Availability_: Windows. ## Type Assertions ## You can call the function ``` ::testing::StaticAssertTypeEq(); ``` to assert that types `T1` and `T2` are the same. The function does nothing if the assertion is satisfied. If the types are different, the function call will fail to compile, and the compiler error message will likely (depending on the compiler) show you the actual values of `T1` and `T2`. This is mainly useful inside template code. _Caveat:_ When used inside a member function of a class template or a function template, `StaticAssertTypeEq()` is effective _only if_ the function is instantiated. For example, given: ``` template class Foo { public: void Bar() { ::testing::StaticAssertTypeEq(); } }; ``` the code: ``` void Test1() { Foo foo; } ``` will _not_ generate a compiler error, as `Foo::Bar()` is never actually instantiated. Instead, you need: ``` void Test2() { Foo foo; foo.Bar(); } ``` to cause a compiler error. _Availability:_ Linux, Windows, Mac; since version 1.3.0. ## Assertion Placement ## You can use assertions in any C++ function. In particular, it doesn't have to be a method of the test fixture class. The one constraint is that assertions that generate a fatal failure (`FAIL*` and `ASSERT_*`) can only be used in void-returning functions. This is a consequence of Google Test not using exceptions. By placing it in a non-void function you'll get a confusing compile error like `"error: void value not ignored as it ought to be"`. If you need to use assertions in a function that returns non-void, one option is to make the function return the value in an out parameter instead. For example, you can rewrite `T2 Foo(T1 x)` to `void Foo(T1 x, T2* result)`. You need to make sure that `*result` contains some sensible value even when the function returns prematurely. As the function now returns `void`, you can use any assertion inside of it. If changing the function's type is not an option, you should just use assertions that generate non-fatal failures, such as `ADD_FAILURE*` and `EXPECT_*`. _Note_: Constructors and destructors are not considered void-returning functions, according to the C++ language specification, and so you may not use fatal assertions in them. You'll get a compilation error if you try. A simple workaround is to transfer the entire body of the constructor or destructor to a private void-returning method. However, you should be aware that a fatal assertion failure in a constructor does not terminate the current test, as your intuition might suggest; it merely returns from the constructor early, possibly leaving your object in a partially-constructed state. Likewise, a fatal assertion failure in a destructor may leave your object in a partially-destructed state. Use assertions carefully in these situations! # Death Tests # In many applications, there are assertions that can cause application failure if a condition is not met. These sanity checks, which ensure that the program is in a known good state, are there to fail at the earliest possible time after some program state is corrupted. If the assertion checks the wrong condition, then the program may proceed in an erroneous state, which could lead to memory corruption, security holes, or worse. Hence it is vitally important to test that such assertion statements work as expected. Since these precondition checks cause the processes to die, we call such tests _death tests_. More generally, any test that checks that a program terminates in an expected fashion is also a death test. If you want to test `EXPECT_*()/ASSERT_*()` failures in your test code, see [Catching Failures](#catching-failures). ## How to Write a Death Test ## Google Test has the following macros to support death tests: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_DEATH(`_statement, regex_`); | `EXPECT_DEATH(`_statement, regex_`); | _statement_ crashes with the given error | | `ASSERT_DEATH_IF_SUPPORTED(`_statement, regex_`); | `EXPECT_DEATH_IF_SUPPORTED(`_statement, regex_`); | if death tests are supported, verifies that _statement_ crashes with the given error; otherwise verifies nothing | | `ASSERT_EXIT(`_statement, predicate, regex_`); | `EXPECT_EXIT(`_statement, predicate, regex_`); |_statement_ exits with the given error and its exit code matches _predicate_ | where _statement_ is a statement that is expected to cause the process to die, _predicate_ is a function or function object that evaluates an integer exit status, and _regex_ is a regular expression that the stderr output of _statement_ is expected to match. Note that _statement_ can be _any valid statement_ (including _compound statement_) and doesn't have to be an expression. As usual, the `ASSERT` variants abort the current test function, while the `EXPECT` variants do not. **Note:** We use the word "crash" here to mean that the process terminates with a _non-zero_ exit status code. There are two possibilities: either the process has called `exit()` or `_exit()` with a non-zero value, or it may be killed by a signal. This means that if _statement_ terminates the process with a 0 exit code, it is _not_ considered a crash by `EXPECT_DEATH`. Use `EXPECT_EXIT` instead if this is the case, or if you want to restrict the exit code more precisely. A predicate here must accept an `int` and return a `bool`. The death test succeeds only if the predicate returns `true`. Google Test defines a few predicates that handle the most common cases: ``` ::testing::ExitedWithCode(exit_code) ``` This expression is `true` if the program exited normally with the given exit code. ``` ::testing::KilledBySignal(signal_number) // Not available on Windows. ``` This expression is `true` if the program was killed by the given signal. The `*_DEATH` macros are convenient wrappers for `*_EXIT` that use a predicate that verifies the process' exit code is non-zero. Note that a death test only cares about three things: 1. does _statement_ abort or exit the process? 1. (in the case of `ASSERT_EXIT` and `EXPECT_EXIT`) does the exit status satisfy _predicate_? Or (in the case of `ASSERT_DEATH` and `EXPECT_DEATH`) is the exit status non-zero? And 1. does the stderr output match _regex_? In particular, if _statement_ generates an `ASSERT_*` or `EXPECT_*` failure, it will **not** cause the death test to fail, as Google Test assertions don't abort the process. To write a death test, simply use one of the above macros inside your test function. For example, ``` TEST(My*DeathTest*, Foo) { // This death test uses a compound statement. ASSERT_DEATH({ int n = 5; Foo(&n); }, "Error on line .* of Foo()"); } TEST(MyDeathTest, NormalExit) { EXPECT_EXIT(NormalExit(), ::testing::ExitedWithCode(0), "Success"); } TEST(MyDeathTest, KillMyself) { EXPECT_EXIT(KillMyself(), ::testing::KilledBySignal(SIGKILL), "Sending myself unblockable signal"); } ``` verifies that: * calling `Foo(5)` causes the process to die with the given error message, * calling `NormalExit()` causes the process to print `"Success"` to stderr and exit with exit code 0, and * calling `KillMyself()` kills the process with signal `SIGKILL`. The test function body may contain other assertions and statements as well, if necessary. _Important:_ We strongly recommend you to follow the convention of naming your test case (not test) `*DeathTest` when it contains a death test, as demonstrated in the above example. The `Death Tests And Threads` section below explains why. If a test fixture class is shared by normal tests and death tests, you can use typedef to introduce an alias for the fixture class and avoid duplicating its code: ``` class FooTest : public ::testing::Test { ... }; typedef FooTest FooDeathTest; TEST_F(FooTest, DoesThis) { // normal test } TEST_F(FooDeathTest, DoesThat) { // death test } ``` _Availability:_ Linux, Windows (requires MSVC 8.0 or above), Cygwin, and Mac (the latter three are supported since v1.3.0). `(ASSERT|EXPECT)_DEATH_IF_SUPPORTED` are new in v1.4.0. ## Regular Expression Syntax ## On POSIX systems (e.g. Linux, Cygwin, and Mac), Google Test uses the [POSIX extended regular expression](http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04) syntax in death tests. To learn about this syntax, you may want to read this [Wikipedia entry](http://en.wikipedia.org/wiki/Regular_expression#POSIX_Extended_Regular_Expressions). On Windows, Google Test uses its own simple regular expression implementation. It lacks many features you can find in POSIX extended regular expressions. For example, we don't support union (`"x|y"`), grouping (`"(xy)"`), brackets (`"[xy]"`), and repetition count (`"x{5,7}"`), among others. Below is what we do support (`A` denotes a literal character, period (`.`), or a single `\\` escape sequence; `x` and `y` denote regular expressions.): | `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` | To help you determine which capability is available on your system, Google Test defines macro `GTEST_USES_POSIX_RE=1` when it uses POSIX extended regular expressions, or `GTEST_USES_SIMPLE_RE=1` when it uses the simple version. If you want your death tests to work in both cases, you can either `#if` on these macros or use the more limited syntax only. ## How It Works ## Under the hood, `ASSERT_EXIT()` spawns a new process and executes the death test statement in that process. The details of of how precisely that happens depend on the platform and the variable `::testing::GTEST_FLAG(death_test_style)` (which is initialized from the command-line flag `--gtest_death_test_style`). * On POSIX systems, `fork()` (or `clone()` on Linux) is used to spawn the child, after which: * If the variable's value is `"fast"`, the death test statement is immediately executed. * If the variable's value is `"threadsafe"`, the child process re-executes the unit test binary just as it was originally invoked, but with some extra flags to cause just the single death test under consideration to be run. * On Windows, the child is spawned using the `CreateProcess()` API, and re-executes the binary to cause just the single death test under consideration to be run - much like the `threadsafe` mode on POSIX. Other values for the variable are illegal and will cause the death test to fail. Currently, the flag's default value is `"fast"`. However, we reserve the right to change it in the future. Therefore, your tests should not depend on this. In either case, the parent process waits for the child process to complete, and checks that 1. the child's exit status satisfies the predicate, and 1. the child's stderr matches the regular expression. If the death test statement runs to completion without dying, the child process will nonetheless terminate, and the assertion fails. ## Death Tests And Threads ## The reason for the two death test styles has to do with thread safety. Due to well-known problems with forking in the presence of threads, death tests should be run in a single-threaded context. Sometimes, however, it isn't feasible to arrange that kind of environment. For example, statically-initialized modules may start threads before main is ever reached. Once threads have been created, it may be difficult or impossible to clean them up. Google Test has three features intended to raise awareness of threading issues. 1. A warning is emitted if multiple threads are running when a death test is encountered. 1. Test cases with a name ending in "DeathTest" are run before all other tests. 1. It uses `clone()` instead of `fork()` to spawn the child process on Linux (`clone()` is not available on Cygwin and Mac), as `fork()` is more likely to cause the child to hang when the parent process has multiple threads. It's perfectly fine to create threads inside a death test statement; they are executed in a separate process and cannot affect the parent. ## Death Test Styles ## The "threadsafe" death test style was introduced in order to help mitigate the risks of testing in a possibly multithreaded environment. It trades increased test execution time (potentially dramatically so) for improved thread safety. We suggest using the faster, default "fast" style unless your test has specific problems with it. You can choose a particular style of death tests by setting the flag programmatically: ``` ::testing::FLAGS_gtest_death_test_style = "threadsafe"; ``` You can do this in `main()` to set the style for all death tests in the binary, or in individual tests. Recall that flags are saved before running each test and restored afterwards, so you need not do that yourself. For example: ``` TEST(MyDeathTest, TestOne) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; // This test is run in the "threadsafe" style: ASSERT_DEATH(ThisShouldDie(), ""); } TEST(MyDeathTest, TestTwo) { // This test is run in the "fast" style: ASSERT_DEATH(ThisShouldDie(), ""); } int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); ::testing::FLAGS_gtest_death_test_style = "fast"; return RUN_ALL_TESTS(); } ``` ## Caveats ## The _statement_ argument of `ASSERT_EXIT()` can be any valid C++ statement except that it can not return from the current function. This means _statement_ should not contain `return` or a macro that might return (e.g. `ASSERT_TRUE()` ). If _statement_ returns before it crashes, Google Test will print an error message, and the test will fail. Since _statement_ runs in the child process, any in-memory side effect (e.g. modifying a variable, releasing memory, etc) it causes will _not_ be observable in the parent process. In particular, if you release memory in a death test, your program will fail the heap check as the parent process will never see the memory reclaimed. To solve this problem, you can 1. try not to free memory in a death test; 1. free the memory again in the parent process; or 1. do not use the heap checker in your program. Due to an implementation detail, you cannot place multiple death test assertions on the same line; otherwise, compilation will fail with an unobvious error message. Despite the improved thread safety afforded by the "threadsafe" style of death test, thread problems such as deadlock are still possible in the presence of handlers registered with `pthread_atfork(3)`. # Using Assertions in Sub-routines # ## Adding Traces to Assertions ## If a test sub-routine is called from several places, when an assertion inside it fails, it can be hard to tell which invocation of the sub-routine the failure is from. You can alleviate this problem using extra logging or custom failure messages, but that usually clutters up your tests. A better solution is to use the `SCOPED_TRACE` macro: | `SCOPED_TRACE(`_message_`);` | |:-----------------------------| where _message_ can be anything streamable to `std::ostream`. This macro will cause the current file name, line number, and the given message to be added in every failure message. The effect will be undone when the control leaves the current lexical scope. For example, ``` 10: void Sub1(int n) { 11: EXPECT_EQ(1, Bar(n)); 12: EXPECT_EQ(2, Bar(n + 1)); 13: } 14: 15: TEST(FooTest, Bar) { 16: { 17: SCOPED_TRACE("A"); // This trace point will be included in 18: // every failure in this scope. 19: Sub1(1); 20: } 21: // Now it won't. 22: Sub1(9); 23: } ``` could result in messages like these: ``` path/to/foo_test.cc:11: Failure Value of: Bar(n) Expected: 1 Actual: 2 Trace: path/to/foo_test.cc:17: A path/to/foo_test.cc:12: Failure Value of: Bar(n + 1) Expected: 2 Actual: 3 ``` Without the trace, it would've been difficult to know which invocation of `Sub1()` the two failures come from respectively. (You could add an extra message to each assertion in `Sub1()` to indicate the value of `n`, but that's tedious.) Some tips on using `SCOPED_TRACE`: 1. With a suitable message, it's often enough to use `SCOPED_TRACE` at the beginning of a sub-routine, instead of at each call site. 1. When calling sub-routines inside a loop, make the loop iterator part of the message in `SCOPED_TRACE` such that you can know which iteration the failure is from. 1. Sometimes the line number of the trace point is enough for identifying the particular invocation of a sub-routine. In this case, you don't have to choose a unique message for `SCOPED_TRACE`. You can simply use `""`. 1. You can use `SCOPED_TRACE` in an inner scope when there is one in the outer scope. In this case, all active trace points will be included in the failure messages, in reverse order they are encountered. 1. The trace dump is clickable in Emacs' compilation buffer - hit return on a line number and you'll be taken to that line in the source file! _Availability:_ Linux, Windows, Mac. ## Propagating Fatal Failures ## A common pitfall when using `ASSERT_*` and `FAIL*` is not understanding that when they fail they only abort the _current function_, not the entire test. For example, the following test will segfault: ``` void Subroutine() { // Generates a fatal failure and aborts the current function. ASSERT_EQ(1, 2); // The following won't be executed. ... } TEST(FooTest, Bar) { Subroutine(); // The intended behavior is for the fatal failure // in Subroutine() to abort the entire test. // The actual behavior: the function goes on after Subroutine() returns. int* p = NULL; *p = 3; // Segfault! } ``` Since we don't use exceptions, it is technically impossible to implement the intended behavior here. To alleviate this, Google Test provides two solutions. You could use either the `(ASSERT|EXPECT)_NO_FATAL_FAILURE` assertions or the `HasFatalFailure()` function. They are described in the following two subsections. ### Asserting on Subroutines ### As shown above, if your test calls a subroutine that has an `ASSERT_*` failure in it, the test will continue after the subroutine returns. This may not be what you want. Often people want fatal failures to propagate like exceptions. For that Google Test offers the following macros: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_NO_FATAL_FAILURE(`_statement_`);` | `EXPECT_NO_FATAL_FAILURE(`_statement_`);` | _statement_ doesn't generate any new fatal failures in the current thread. | Only failures in the thread that executes the assertion are checked to determine the result of this type of assertions. If _statement_ creates new threads, failures in these threads are ignored. Examples: ``` ASSERT_NO_FATAL_FAILURE(Foo()); int i; EXPECT_NO_FATAL_FAILURE({ i = Bar(); }); ``` _Availability:_ Linux, Windows, Mac. Assertions from multiple threads are currently not supported. ### Checking for Failures in the Current Test ### `HasFatalFailure()` in the `::testing::Test` class returns `true` if an assertion in the current test has suffered a fatal failure. This allows functions to catch fatal failures in a sub-routine and return early. ``` class Test { public: ... static bool HasFatalFailure(); }; ``` The typical usage, which basically simulates the behavior of a thrown exception, is: ``` TEST(FooTest, Bar) { Subroutine(); // Aborts if Subroutine() had a fatal failure. if (HasFatalFailure()) return; // The following won't be executed. ... } ``` If `HasFatalFailure()` is used outside of `TEST()` , `TEST_F()` , or a test fixture, you must add the `::testing::Test::` prefix, as in: ``` if (::testing::Test::HasFatalFailure()) return; ``` Similarly, `HasNonfatalFailure()` returns `true` if the current test has at least one non-fatal failure, and `HasFailure()` returns `true` if the current test has at least one failure of either kind. _Availability:_ Linux, Windows, Mac. `HasNonfatalFailure()` and `HasFailure()` are available since version 1.4.0. # Logging Additional Information # In your test code, you can call `RecordProperty("key", value)` to log additional information, where `value` can be either a C string or a 32-bit integer. The _last_ value recorded for a key will be emitted to the XML output if you specify one. For example, the test ``` TEST_F(WidgetUsageTest, MinAndMaxWidgets) { RecordProperty("MaximumWidgets", ComputeMaxUsage()); RecordProperty("MinimumWidgets", ComputeMinUsage()); } ``` will output XML like this: ``` ... ... ``` _Note_: * `RecordProperty()` is a static member of the `Test` class. Therefore it needs to be prefixed with `::testing::Test::` if used outside of the `TEST` body and the test fixture class. * `key` must be a valid XML attribute name, and cannot conflict with the ones already used by Google Test (`name`, `status`, `time`, and `classname`). _Availability_: Linux, Windows, Mac. # Sharing Resources Between Tests in the Same Test Case # Google Test creates a new test fixture object for each test in order to make tests independent and easier to debug. However, sometimes tests use resources that are expensive to set up, making the one-copy-per-test model prohibitively expensive. If the tests don't change the resource, there's no harm in them sharing a single resource copy. So, in addition to per-test set-up/tear-down, Google Test also supports per-test-case set-up/tear-down. To use it: 1. In your test fixture class (say `FooTest` ), define as `static` some member variables to hold the shared resources. 1. In the same test fixture class, define a `static void SetUpTestCase()` function (remember not to spell it as **`SetupTestCase`** with a small `u`!) to set up the shared resources and a `static void TearDownTestCase()` function to tear them down. That's it! Google Test automatically calls `SetUpTestCase()` before running the _first test_ in the `FooTest` test case (i.e. before creating the first `FooTest` object), and calls `TearDownTestCase()` after running the _last test_ in it (i.e. after deleting the last `FooTest` object). In between, the tests can use the shared resources. Remember that the test order is undefined, so your code can't depend on a test preceding or following another. Also, the tests must either not modify the state of any shared resource, or, if they do modify the state, they must restore the state to its original value before passing control to the next test. Here's an example of per-test-case set-up and tear-down: ``` class FooTest : public ::testing::Test { protected: // Per-test-case set-up. // Called before the first test in this test case. // Can be omitted if not needed. static void SetUpTestCase() { shared_resource_ = new ...; } // Per-test-case tear-down. // Called after the last test in this test case. // Can be omitted if not needed. static void TearDownTestCase() { delete shared_resource_; shared_resource_ = NULL; } // You can define per-test set-up and tear-down logic as usual. virtual void SetUp() { ... } virtual void TearDown() { ... } // Some expensive resource shared by all tests. static T* shared_resource_; }; T* FooTest::shared_resource_ = NULL; TEST_F(FooTest, Test1) { ... you can refer to shared_resource here ... } TEST_F(FooTest, Test2) { ... you can refer to shared_resource here ... } ``` _Availability:_ Linux, Windows, Mac. # Global Set-Up and Tear-Down # Just as you can do set-up and tear-down at the test level and the test case level, you can also do it at the test program level. Here's how. First, you subclass the `::testing::Environment` class to define a test environment, which knows how to set-up and tear-down: ``` class Environment { public: 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() {} }; ``` Then, you register an instance of your environment class with Google Test by calling the `::testing::AddGlobalTestEnvironment()` function: ``` Environment* AddGlobalTestEnvironment(Environment* env); ``` Now, when `RUN_ALL_TESTS()` is called, it first calls the `SetUp()` method of the environment object, then runs the tests if there was no fatal failures, and finally calls `TearDown()` of the environment object. It's OK to register multiple environment objects. In this case, their `SetUp()` will be called in the order they are registered, and their `TearDown()` will be called in the reverse order. Note that Google Test takes ownership of the registered environment objects. Therefore **do not delete them** by yourself. You should call `AddGlobalTestEnvironment()` 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. One way to do this is to 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). _Availability:_ Linux, Windows, Mac. # Value Parameterized Tests # _Value-parameterized tests_ allow you to test your code with different parameters without writing multiple copies of the same test. Suppose you write a test for your code and then realize that your code is affected by a presence of a Boolean command line flag. ``` TEST(MyCodeTest, TestFoo) { // A code to test foo(). } ``` Usually people factor their test code into a function with a Boolean parameter in such situations. The function sets the flag, then executes the testing code. ``` void TestFooHelper(bool flag_value) { flag = flag_value; // A code to test foo(). } TEST(MyCodeTest, TestFooo) { TestFooHelper(false); TestFooHelper(true); } ``` But this setup has serious drawbacks. First, when a test assertion fails in your tests, it becomes unclear what value of the parameter caused it to fail. You can stream a clarifying message into your `EXPECT`/`ASSERT` statements, but it you'll have to do it with all of them. Second, you have to add one such helper function per test. What if you have ten tests? Twenty? A hundred? Value-parameterized tests will let you write your test only once and then easily instantiate and run it with an arbitrary number of parameter values. Here are some other situations when value-parameterized tests come handy: * You wan to test different implementations of an OO interface. * You want to test your code over various inputs (a.k.a. data-driven testing). This feature is easy to abuse, so please exercise your good sense when doing it! ## How to Write Value-Parameterized Tests ## To write value-parameterized tests, first you should define a fixture class. It must be derived from `::testing::TestWithParam`, where `T` is the type of your parameter values. `TestWithParam` 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 { // You can implement all the usual fixture class members here. // To access the test parameter, call GetParam() from class // TestWithParam. }; ``` Then, use the `TEST_P` macro to define as many test patterns using 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 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)` and `ValuesIn(begin, end)` | Yields values from a C-style array, an STL-style 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. This is only available if your system provides the `` header. If you are sure your system does, and Google Test disagrees, you can override it by defining `GTEST_HAS_TR1_TUPLE=1`. See comments in [include/gtest/internal/gtest-port.h](../include/gtest/internal/gtest-port.h) for more information. | For more details, see the comments at the definitions of these functions in the [source code](../include/gtest/gtest-param-test.h). 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, ::testing::Values("meeny", "miny", "moe")); ``` To distinguish different instances of the pattern (yes, you can instantiate it more than once), the first argument to `INSTANTIATE_TEST_CASE_P` 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](#running-a-subset-of-the-tests). 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, ::testing::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. You can see [these](../samples/sample7_unittest.cc) [files](../samples/sample8_unittest.cc) for more examples. _Availability_: Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.2.0. ## Creating Value-Parameterized Abstract Tests ## In the above, we define and instantiate `FooTest` in the same source file. Sometimes you may want to define value-parameterized tests in a library and let other people instantiate them later. This pattern is known as abstract tests. As an example of its application, when you are designing an interface you can write a standard suite of abstract tests (perhaps using a factory function as the test parameter) that all implementations of the interface are expected to pass. When someone implements the interface, he can instantiate your suite to get all the interface-conformance tests for free. To define abstract tests, you should organize your code like this: 1. Put the definition of the parameterized test fixture class (e.g. `FooTest`) in a header file, say `foo_param_test.h`. Think of this as _declaring_ your abstract tests. 1. Put the `TEST_P` definitions in `foo_param_test.cc`, which includes `foo_param_test.h`. Think of this as _implementing_ your abstract tests. Once they are defined, you can instantiate them by including `foo_param_test.h`, invoking `INSTANTIATE_TEST_CASE_P()`, and linking with `foo_param_test.cc`. You can instantiate the same abstract test case multiple times, possibly in different source files. # Typed Tests # Suppose you have multiple implementations of the same interface and want to make sure that all of them satisfy some common requirements. Or, you may have defined several types that are supposed to conform to the same "concept" and you want to verify it. In both cases, you want the same test logic repeated for different types. While you can write one `TEST` or `TEST_F` for each type you want to test (and you may even factor the test logic into a function template that you invoke from the `TEST`), it's tedious and doesn't scale: if you want _m_ tests over _n_ types, you'll end up writing _m\*n_ `TEST`s. _Typed tests_ allow you to repeat the same test logic over a list of types. You only need to write the test logic once, although you must know the type list when writing typed tests. Here's how you do it: First, define a fixture class template. It should be parameterized by a type. Remember to derive it from `::testing::Test`: ``` template class FooTest : public ::testing::Test { public: ... typedef std::list 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: ``` typedef ::testing::Types MyTypes; TYPED_TEST_CASE(FooTest, MyTypes); ``` The `typedef` is necessary for the `TYPED_TEST_CASE` macro to parse correctly. Otherwise the compiler will think that each comma in the type list introduces a new macro argument. Then, use `TYPED_TEST()` instead of `TEST_F()` to define a typed test for this test case. You can repeat this as many times as you want: ``` TYPED_TEST(FooTest, DoesBlah) { // Inside a test, refer to the special name TypeParam to get the type // parameter. Since we are inside a derived class template, C++ requires // us 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. The 'typename' is required to satisfy the compiler. typename TestFixture::List values; values.push_back(n); ... } TYPED_TEST(FooTest, HasPropertyA) { ... } ``` You can see `samples/sample6_unittest.cc` for a complete example. _Availability:_ Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.1.0. # Type-Parameterized Tests # _Type-parameterized tests_ are like typed tests, except that they don't require you to know the list of types ahead of time. Instead, you can define the test logic first and instantiate it with different type lists later. You can even instantiate it more than once in the same program. 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, the author of each implementation can just instantiate the test suite with his type to verify that it conforms to the requirements, without having to write similar tests repeatedly. Here's an example: First, define a fixture class template, as we did with typed tests: ``` template class FooTest : public ::testing::Test { ... }; ``` Next, declare that you will define a type-parameterized test case: ``` TYPED_TEST_CASE_P(FooTest); ``` The `_P` suffix is for "parameterized" or "pattern", whichever you prefer to think. Then, use `TYPED_TEST_P()` to define a type-parameterized test. You can repeat this as many times 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 using the `REGISTER_TYPED_TEST_CASE_P` macro 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. ``` typedef ::testing::Types MyTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); ``` To distinguish different instances of the pattern, the first argument to the `INSTANTIATE_TYPED_TEST_CASE_P` macro is a prefix that will be added to the actual test case name. Remember to pick unique prefixes for different instances. In the special case where the type list contains only one type, you can write that type directly without `::testing::Types<...>`, like this: ``` INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); ``` You can see `samples/sample6_unittest.cc` for a complete example. _Availability:_ Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.1.0. # Testing Private Code # If you change your software's internal implementation, your tests should not break as long as the change is not observable by users. Therefore, per the _black-box testing principle_, most of the time you should test your code through its public interfaces. If you still find yourself needing to test internal implementation code, consider if there's a better design that wouldn't require you to do so. If you absolutely have to test non-public interface code though, you can. There are two cases to consider: * Static functions (_not_ the same as static member functions!) or unnamed namespaces, and * Private or protected class members ## Static Functions ## Both static functions and definitions/declarations in an unnamed namespace are only visible within the same translation unit. To test them, you can `#include` the entire `.cc` file being tested in your `*_test.cc` file. (`#include`ing `.cc` files is not a good way to reuse code - you should not do this in production code!) However, a better approach is to move the private code into the `foo::internal` namespace, where `foo` is the namespace your project normally uses, and put the private declarations in a `*-internal.h` file. Your production `.cc` files and your tests are allowed to include this internal header, but your clients are not. This way, you can fully test your internal implementation without leaking it to your clients. ## Private Class Members ## Private class members are only accessible from within the class or by friends. To access a class' private members, you can declare your test fixture as a friend to the class and define accessors in your fixture. Tests using the fixture can then access the private members of your production class via the accessors in the fixture. Note that even though your fixture is a friend to your production class, your tests are not automatically friends to it, as they are technically defined in sub-classes of the fixture. Another way to test private members is to refactor them into an implementation class, which is then declared in a `*-internal.h` file. Your clients aren't allowed to include this header but your tests can. Such is called the Pimpl (Private Implementation) idiom. Or, you can declare an individual test as a friend of your class by adding this line in the class body: ``` FRIEND_TEST(TestCaseName, TestName); ``` For example, ``` // foo.h #include // Defines FRIEND_TEST. class Foo { ... private: FRIEND_TEST(FooTest, BarReturnsZeroOnNull); int Bar(void* x); }; // foo_test.cc ... TEST(FooTest, BarReturnsZeroOnNull) { Foo foo; EXPECT_EQ(0, foo.Bar(NULL)); // Uses Foo's private member Bar(). } ``` Pay special attention when your class is defined in a namespace, as you should define your test fixtures and tests in the same namespace if you want them to be friends of your class. For example, if the code to be tested looks like: ``` namespace my_namespace { class Foo { friend class FooTest; FRIEND_TEST(FooTest, Bar); FRIEND_TEST(FooTest, Baz); ... definition of the class Foo ... }; } // namespace my_namespace ``` Your test code should be something like: ``` namespace my_namespace { class FooTest : public ::testing::Test { protected: ... }; TEST_F(FooTest, Bar) { ... } TEST_F(FooTest, Baz) { ... } } // namespace my_namespace ``` # Catching Failures # If you are building a testing utility on top of Google Test, you'll want to test your utility. What framework would you use to test it? Google Test, of course. The challenge is to verify that your testing utility reports failures correctly. In frameworks that report a failure by throwing an exception, you could catch the exception and assert on it. But Google Test doesn't use exceptions, so how do we test that a piece of code generates an expected failure? `` contains some constructs to do this. After `#include`ing this header, you can use | `EXPECT_FATAL_FAILURE(`_statement, substring_`);` | |:--------------------------------------------------| to assert that _statement_ generates a fatal (e.g. `ASSERT_*`) failure whose message contains the given _substring_, or use | `EXPECT_NONFATAL_FAILURE(`_statement, substring_`);` | |:-----------------------------------------------------| if you are expecting a non-fatal (e.g. `EXPECT_*`) failure. For technical reasons, there are some caveats: 1. You cannot stream a failure message to either macro. 1. _statement_ in `EXPECT_FATAL_FAILURE()` cannot reference local non-static variables or non-static members of `this` object. 1. _statement_ in `EXPECT_FATAL_FAILURE()` cannot return a value. _Note:_ Google Test is designed with threads in mind. Once the synchronization primitives in `` have been implemented, Google Test will become thread-safe, meaning that you can then use assertions in multiple threads concurrently. Before that, however, Google Test only supports single-threaded usage. Once thread-safe, `EXPECT_FATAL_FAILURE()` and `EXPECT_NONFATAL_FAILURE()` will capture failures in the current thread only. If _statement_ creates new threads, failures in these threads will be ignored. If you want to capture failures from all threads instead, you should use the following macros: | `EXPECT_FATAL_FAILURE_ON_ALL_THREADS(`_statement, substring_`);` | |:-----------------------------------------------------------------| | `EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(`_statement, substring_`);` | # Getting the Current Test's Name # Sometimes a function may need to know the name of the currently running test. For example, you may be using the `SetUp()` method of your test fixture to set the golden file name based on which test is running. The `::testing::TestInfo` class has this information: ``` namespace testing { class TestInfo { public: // Returns the test case name and the test name, respectively. // // Do NOT delete or free the return value - it's managed by the // TestInfo class. const char* test_case_name() const; const char* name() const; }; } // namespace testing ``` > To obtain a `TestInfo` object for the currently running test, call `current_test_info()` on the `UnitTest` singleton object: ``` // Gets information about the currently running test. // Do NOT delete the returned object - it's managed by the UnitTest class. const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); printf("We are in test %s of test case %s.\n", test_info->name(), test_info->test_case_name()); ``` `current_test_info()` returns a null pointer if no test is running. In particular, you cannot find the test case name in `TestCaseSetUp()`, `TestCaseTearDown()` (where you know the test case name implicitly), or functions called from them. _Availability:_ Linux, Windows, Mac. # Extending Google Test by Handling Test Events # Google Test provides an event listener API to let you receive notifications about the progress of a test program and test failures. The events you can listen to include the start and end of the test program, a test case, or a test method, among others. You may use this API to augment or replace the standard console output, replace the XML output, or provide a completely different form of output, such as a GUI or a database. You can also use test events as checkpoints to implement a resource leak checker, for example. _Availability:_ Linux, Windows, Mac; since v1.4.0. ## Defining Event Listeners ## To define a event listener, you subclass either [testing::TestEventListener](../include/gtest/gtest.h#L855) or [testing::EmptyTestEventListener](../include/gtest/gtest.h#L905). The former is an (abstract) interface, where each pure virtual method
can be overridden to handle a test event
(For example, when a test starts, the `OnTestStart()` method will be called.). The latter provides an empty implementation of all methods in the interface, such that a subclass only needs to override the methods it cares about. When an event is fired, its context is passed to the handler function as an argument. The following argument types are used: * [UnitTest](../include/gtest/gtest.h#L1007) reflects the state of the entire test program, * [TestCase](../include/gtest/gtest.h#L689) has information about a test case, which can contain one or more tests, * [TestInfo](../include/gtest/gtest.h#L599) contains the state of a test, and * [TestPartResult](../include/gtest/gtest-test-part.h#L42) represents the result of a test assertion. An event handler function can examine the argument it receives to find out interesting information about the event and the test program's state. Here's an example: ``` class MinimalistPrinter : public ::testing::EmptyTestEventListener { // Called before a test starts. virtual void OnTestStart(const ::testing::TestInfo& test_info) { printf("*** Test %s.%s starting.\n", test_info.test_case_name(), test_info.name()); } // Called after a failed assertion or a SUCCESS(). virtual void OnTestPartResult( const ::testing::TestPartResult& test_part_result) { printf("%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()); } // Called after a test ends. virtual void OnTestEnd(const ::testing::TestInfo& test_info) { printf("*** Test %s.%s ending.\n", test_info.test_case_name(), test_info.name()); } }; ``` ## Using Event Listeners ## To use the event listener you have defined, add an instance of it to the Google Test event listener list (represented by class [TestEventListeners](../include/gtest/gtest.h#L929) - note the "s" at the end of the name) in your `main()` function, before calling `RUN_ALL_TESTS()`: ``` int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); // Gets hold of the event listener list. ::testing::TestEventListeners& listeners = ::testing::UnitTest::GetInstance()->listeners(); // Adds a listener to the end. Google Test takes the ownership. listeners.Append(new MinimalistPrinter); return RUN_ALL_TESTS(); } ``` There's only one problem: the default test result printer is still in effect, so its output will mingle with the output from your minimalist printer. To suppress the default printer, just release it from the event listener list and delete it. You can do so by adding one line: ``` ... delete listeners.Release(listeners.default_result_printer()); listeners.Append(new MinimalistPrinter); return RUN_ALL_TESTS(); ``` Now, sit back and enjoy a completely different output from your tests. For more details, you can read this [sample](../samples/sample9_unittest.cc). You may append more than one listener to the list. When an `On*Start()` or `OnTestPartResult()` event is fired, the listeners will receive it in the order they appear in the list (since new listeners are added to the end of the list, the default text printer and the default XML generator will receive the event first). An `On*End()` event will be received by the listeners in the _reverse_ order. This allows output by listeners added later to be framed by output from listeners added earlier. ## Generating Failures in Listeners ## You may use failure-raising macros (`EXPECT_*()`, `ASSERT_*()`, `FAIL()`, etc) when processing an event. There are some restrictions: 1. You cannot generate any failure in `OnTestPartResult()` (otherwise it will cause `OnTestPartResult()` to be called recursively). 1. A listener that handles `OnTestPartResult()` is not allowed to generate any failure. When you add listeners to the listener list, you should put listeners that handle `OnTestPartResult()` _before_ listeners that can generate failures. This ensures that failures generated by the latter are attributed to the right test by the former. We have a sample of failure-raising listener [here](../samples/sample10_unittest.cc). # Running Test Programs: Advanced Options # Google Test test programs are ordinary executables. Once built, you can run them directly and affect their behavior via the following environment variables and/or command line flags. For the flags to work, your programs must call `::testing::InitGoogleTest()` before calling `RUN_ALL_TESTS()`. To see a list of supported flags and their usage, please run your test program with the `--help` flag. You can also use `-h`, `-?`, or `/?` for short. This feature is added in version 1.3.0. If an option is specified both by an environment variable and by a flag, the latter takes precedence. Most of the options can also be set/read in code: to access the value of command line flag `--gtest_foo`, write `::testing::GTEST_FLAG(foo)`. A common pattern is to set the value of a flag before calling `::testing::InitGoogleTest()` to change the default value of the flag: ``` int main(int argc, char** argv) { // Disables elapsed time by default. ::testing::GTEST_FLAG(print_time) = false; // This allows the user to override the flag on the command line. ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ``` ## Selecting Tests ## This section shows various options for choosing which tests to run. ### Listing Test Names ### Sometimes it is necessary to list the available tests in a program before running them so that a filter may be applied if needed. Including the flag `--gtest_list_tests` overrides all other flags and lists tests in the following format: ``` TestCase1. TestName1 TestName2 TestCase2. TestName ``` None of the tests listed are actually run if the flag is provided. There is no corresponding environment variable for this flag. _Availability:_ Linux, Windows, Mac. ### Running a Subset of the Tests ### By default, a Google Test program runs all tests the user has defined. Sometimes, you want to run only a subset of the tests (e.g. for debugging or quickly verifying a change). If you set the `GTEST_FILTER` environment variable or the `--gtest_filter` flag to a filter string, Google Test will only run the tests whose full names (in the form of `TestCaseName.TestName`) match the filter. The format of a filter is a '`:`'-separated list of wildcard patterns (called the positive patterns) optionally followed by a '`-`' and another '`:`'-separated pattern list (called the negative patterns). A test matches the filter if and only if it matches any of the positive patterns but does not match any of the negative patterns. A pattern may contain `'*'` (matches any string) or `'?'` (matches any single character). For convenience, the filter `'*-NegativePatterns'` can be also written as `'-NegativePatterns'`. For example: * `./foo_test` Has no flag, and thus runs all its tests. * `./foo_test --gtest_filter=*` Also runs everything, due to the single match-everything `*` value. * `./foo_test --gtest_filter=FooTest.*` Runs everything in test case `FooTest`. * `./foo_test --gtest_filter=*Null*:*Constructor*` Runs any test whose full name contains either `"Null"` or `"Constructor"`. * `./foo_test --gtest_filter=-*DeathTest.*` Runs all non-death tests. * `./foo_test --gtest_filter=FooTest.*-FooTest.Bar` Runs everything in test case `FooTest` except `FooTest.Bar`. _Availability:_ Linux, Windows, Mac. ### Temporarily Disabling Tests ### If you have a broken test that you cannot fix right away, you can add the `DISABLED_` prefix to its name. This will exclude it from execution. This is better than commenting out the code or using `#if 0`, as disabled tests are still compiled (and thus won't rot). If you need to disable all tests in a test case, you can either add `DISABLED_` to the front of the name of each test, or alternatively add it to the front of the test case name. For example, the following tests won't be run by Google Test, even though they will still be compiled: ``` // Tests that Foo does Abc. TEST(FooTest, DISABLED_DoesAbc) { ... } class DISABLED_BarTest : public ::testing::Test { ... }; // Tests that Bar does Xyz. TEST_F(DISABLED_BarTest, DoesXyz) { ... } ``` _Note:_ This feature should only be used for temporary pain-relief. You still have to fix the disabled tests at a later date. As a reminder, Google Test will print a banner warning you if a test program contains any disabled tests. _Tip:_ You can easily count the number of disabled tests you have using `grep`. This number can be used as a metric for improving your test quality. _Availability:_ Linux, Windows, Mac. ### Temporarily Enabling Disabled Tests ### To include [disabled tests](#temporarily-disabling-tests) in test execution, just invoke the test program with the `--gtest_also_run_disabled_tests` flag or set the `GTEST_ALSO_RUN_DISABLED_TESTS` environment variable to a value other than `0`. You can combine this with the [--gtest\_filter](#running-a-subset-of-the-tests) flag to further select which disabled tests to run. _Availability:_ Linux, Windows, Mac; since version 1.3.0. ## Repeating the Tests ## Once in a while you'll run into a test whose result is hit-or-miss. Perhaps it will fail only 1% of the time, making it rather hard to reproduce the bug under a debugger. This can be a major source of frustration. The `--gtest_repeat` flag allows you to repeat all (or selected) test methods in a program many times. Hopefully, a flaky test will eventually fail and give you a chance to debug. Here's how to use it: | `$ foo_test --gtest_repeat=1000` | Repeat foo\_test 1000 times and don't stop at failures. | |:---------------------------------|:--------------------------------------------------------| | `$ foo_test --gtest_repeat=-1` | A negative count means repeating forever. | | `$ foo_test --gtest_repeat=1000 --gtest_break_on_failure` | Repeat foo\_test 1000 times, stopping at the first failure. This is especially useful when running under a debugger: when the testfails, it will drop into the debugger and you can then inspect variables and stacks. | | `$ foo_test --gtest_repeat=1000 --gtest_filter=FooBar` | Repeat the tests whose name matches the filter 1000 times. | If your test program contains global set-up/tear-down code registered using `AddGlobalTestEnvironment()`, it will be repeated in each iteration as well, as the flakiness may be in it. You can also specify the repeat count by setting the `GTEST_REPEAT` environment variable. _Availability:_ Linux, Windows, Mac. ## Shuffling the Tests ## You can specify the `--gtest_shuffle` flag (or set the `GTEST_SHUFFLE` environment variable to `1`) to run the tests in a program in a random order. This helps to reveal bad dependencies between tests. By default, Google Test uses a random seed calculated from the current time. Therefore you'll get a different order every time. The console output includes the random seed value, such that you can reproduce an order-related test failure later. To specify the random seed explicitly, use the `--gtest_random_seed=SEED` flag (or set the `GTEST_RANDOM_SEED` environment variable), where `SEED` is an integer between 0 and 99999. The seed value 0 is special: it tells Google Test to do the default behavior of calculating the seed from the current time. If you combine this with `--gtest_repeat=N`, Google Test will pick a different random seed and re-shuffle the tests in each iteration. _Availability:_ Linux, Windows, Mac; since v1.4.0. ## Controlling Test Output ## This section teaches how to tweak the way test results are reported. ### Colored Terminal Output ### Google Test can use colors in its terminal output to make it easier to spot the separation between tests, and whether tests passed. You can set the GTEST\_COLOR environment variable or set the `--gtest_color` command line flag to `yes`, `no`, or `auto` (the default) to enable colors, disable colors, or let Google Test decide. When the value is `auto`, Google Test will use colors if and only if the output goes to a terminal and (on non-Windows platforms) the `TERM` environment variable is set to `xterm` or `xterm-color`. _Availability:_ Linux, Windows, Mac. ### Suppressing the Elapsed Time ### By default, Google Test prints the time it takes to run each test. To suppress that, run the test program with the `--gtest_print_time=0` command line flag. Setting the `GTEST_PRINT_TIME` environment variable to `0` has the same effect. _Availability:_ Linux, Windows, Mac. (In Google Test 1.3.0 and lower, the default behavior is that the elapsed time is **not** printed.) ### Generating an XML Report ### Google Test can emit a detailed XML report to a file in addition to its normal textual output. The report contains the duration of each test, and thus can help you identify slow tests. To generate the XML report, set the `GTEST_OUTPUT` environment variable or the `--gtest_output` flag to the string `"xml:_path_to_output_file_"`, which will create the file at the given location. You can also just use the string `"xml"`, in which case the output can be found in the `test_detail.xml` file in the current directory. If you specify a directory (for example, `"xml:output/directory/"` on Linux or `"xml:output\directory\"` on Windows), Google Test will create the XML file in that directory, named after the test executable (e.g. `foo_test.xml` for test program `foo_test` or `foo_test.exe`). If the file already exists (perhaps left over from a previous run), Google Test will pick a different name (e.g. `foo_test_1.xml`) to avoid overwriting it. The report uses the format described here. It is based on the `junitreport` Ant task and can be parsed by popular continuous build systems like [Hudson](https://hudson.dev.java.net/). Since that format was originally intended for Java, a little interpretation is required to make it apply to Google Test tests, as shown here: ``` ``` * The root `` element corresponds to the entire test program. * `` elements correspond to Google Test test cases. * `` elements correspond to Google Test test functions. For instance, the following program ``` TEST(MathTest, Addition) { ... } TEST(MathTest, Subtraction) { ... } TEST(LogicTest, NonContradiction) { ... } ``` could generate this report: ``` ``` Things to note: * The `tests` attribute of a `` or `` element tells how many test functions the Google Test program or test case contains, while the `failures` attribute tells how many of them failed. * The `time` attribute expresses the duration of the test, test case, or entire test program in milliseconds. * Each `` element corresponds to a single failed Google Test assertion. * Some JUnit concepts don't apply to Google Test, yet we have to conform to the DTD. Therefore you'll see some dummy elements and attributes in the report. You can safely ignore these parts. _Availability:_ Linux, Windows, Mac. ## Controlling How Failures Are Reported ## ### Turning Assertion Failures into Break-Points ### When running test programs under a debugger, it's very convenient if the debugger can catch an assertion failure and automatically drop into interactive mode. Google Test's _break-on-failure_ mode supports this behavior. To enable it, set the `GTEST_BREAK_ON_FAILURE` environment variable to a value other than `0` . Alternatively, you can use the `--gtest_break_on_failure` command line flag. _Availability:_ Linux, Windows, Mac. ### Suppressing Pop-ups Caused by Exceptions ### On Windows, Google Test may be used with exceptions enabled. Even when exceptions are disabled, an application can still throw structured exceptions (SEH's). If a test throws an exception, by default Google Test doesn't try to catch it. Instead, you'll see a pop-up dialog, at which point you can attach the process to a debugger and easily find out what went wrong. However, if you don't want to see the pop-ups (for example, if you run the tests in a batch job), set the `GTEST_CATCH_EXCEPTIONS` environment variable to a non- `0` value, or use the `--gtest_catch_exceptions` flag. Google Test now catches all test-thrown exceptions and logs them as failures. _Availability:_ Windows. `GTEST_CATCH_EXCEPTIONS` and `--gtest_catch_exceptions` have no effect on Google Test's behavior on Linux or Mac, even if exceptions are enabled. It is possible to add support for catching exceptions on these platforms, but it is not implemented yet. ### Letting Another Testing Framework Drive ### If you work on a project that has already been using another testing framework and is not ready to completely switch to Google Test yet, you can get much of Google Test's benefit by using its assertions in your existing tests. Just change your `main()` function to look like: ``` #include int main(int argc, char** argv) { ::testing::GTEST_FLAG(throw_on_failure) = true; // Important: Google Test must be initialized. ::testing::InitGoogleTest(&argc, argv); ... whatever your existing testing framework requires ... } ``` With that, you can use Google Test assertions in addition to the native assertions your testing framework provides, for example: ``` void TestFooDoesBar() { Foo foo; EXPECT_LE(foo.Bar(1), 100); // A Google Test assertion. CPPUNIT_ASSERT(foo.IsEmpty()); // A native assertion. } ``` If a Google Test assertion fails, it will print an error message and throw an exception, which will be treated as a failure by your host testing framework. If you compile your code with exceptions disabled, a failed Google Test assertion will instead exit your program with a non-zero code, which will also signal a test failure to your test runner. If you don't write `::testing::GTEST_FLAG(throw_on_failure) = true;` in your `main()`, you can alternatively enable this feature by specifying the `--gtest_throw_on_failure` flag on the command-line or setting the `GTEST_THROW_ON_FAILURE` environment variable to a non-zero value. _Availability:_ Linux, Windows, Mac; since v1.3.0. ## Distributing Test Functions to Multiple Machines ## If you have more than one machine you can use to run a test program, you might want to run the test functions in parallel and get the result faster. We call this technique _sharding_, where each machine is called a _shard_. Google Test is compatible with test sharding. To take advantage of this feature, your test runner (not part of Google Test) needs to do the following: 1. Allocate a number of machines (shards) to run the tests. 1. On each shard, set the `GTEST_TOTAL_SHARDS` environment variable to the total number of shards. It must be the same for all shards. 1. On each shard, set the `GTEST_SHARD_INDEX` environment variable to the index of the shard. Different shards must be assigned different indices, which must be in the range `[0, GTEST_TOTAL_SHARDS - 1]`. 1. Run the same test program on all shards. When Google Test sees the above two environment variables, it will select a subset of the test functions to run. Across all shards, each test function in the program will be run exactly once. 1. Wait for all shards to finish, then collect and report the results. Your project may have tests that were written without Google Test and thus don't understand this protocol. In order for your test runner to figure out which test supports sharding, it can set the environment variable `GTEST_SHARD_STATUS_FILE` to a non-existent file path. If a test program supports sharding, it will create this file to acknowledge the fact (the actual contents of the file are not important at this time; although we may stick some useful information in it in the future.); otherwise it will not create it. Here's an example to make it clear. Suppose you have a test program `foo_test` that contains the following 5 test functions: ``` TEST(A, V) TEST(A, W) TEST(B, X) TEST(B, Y) TEST(B, Z) ``` and you have 3 machines at your disposal. To run the test functions in parallel, you would set `GTEST_TOTAL_SHARDS` to 3 on all machines, and set `GTEST_SHARD_INDEX` to 0, 1, and 2 on the machines respectively. Then you would run the same `foo_test` on each machine. Google Test reserves the right to change how the work is distributed across the shards, but here's one possible scenario: * Machine #0 runs `A.V` and `B.X`. * Machine #1 runs `A.W` and `B.Y`. * Machine #2 runs `B.Z`. _Availability:_ Linux, Windows, Mac; since version 1.3.0. # Fusing Google Test Source Files # Google Test's implementation consists of ~30 files (excluding its own tests). Sometimes you may want them to be packaged up in two files (a `.h` and a `.cc`) instead, such that you can easily copy them to a new machine and start hacking there. For this we provide an experimental Python script `fuse_gtest_files.py` in the `scripts/` directory (since release 1.3.0). Assuming you have Python 2.4 or above installed on your machine, just go to that directory and run ``` python fuse_gtest_files.py OUTPUT_DIR ``` and you should see an `OUTPUT_DIR` directory being created with files `gtest/gtest.h` and `gtest/gtest-all.cc` in it. These files contain everything you need to use Google Test. Just copy them to anywhere you want and you are ready to write tests. You can use the [scrpts/test/Makefile](../scripts/test/Makefile) file as an example on how to compile your tests against them. # Where to Go from Here # Congratulations! You've now learned more advanced Google Test tools and are ready to tackle more complex testing tasks. If you want to dive even deeper, you can read the [FAQ](V1_5_FAQ.md). assimp-4.1.0/contrib/gtest/docs/FAQ.md0000644002537200234200000013540713213503245017735 0ustar zmoelnigiemusers If you cannot find the answer to your question here, and you have read [Primer](Primer.md) and [AdvancedGuide](AdvancedGuide.md), send it to googletestframework@googlegroups.com. ## Why should I use Google Test instead of my favorite C++ testing framework? ## First, let us say clearly that we don't want to get into the debate of which C++ testing framework is **the best**. There exist many fine frameworks for writing C++ tests, and we have tremendous respect for the developers and users of them. We don't think there is (or will be) a single best framework - you have to pick the right tool for the particular task you are tackling. We created Google Test because we couldn't find the right combination of features and conveniences in an existing framework to satisfy _our_ needs. The following is a list of things that _we_ like about Google Test. We don't claim them to be unique to Google Test - rather, the combination of them makes Google Test the choice for us. We hope this list can help you decide whether it is for you too. * Google Test is designed to be portable: it doesn't require exceptions or RTTI; it works around various bugs in various compilers and environments; etc. As a result, it works on Linux, Mac OS X, Windows and several embedded operating systems. * Nonfatal assertions (`EXPECT_*`) have proven to be great time savers, as they allow a test to report multiple failures in a single edit-compile-test cycle. * It's easy to write assertions that generate informative messages: you just use the stream syntax to append any additional information, e.g. `ASSERT_EQ(5, Foo(i)) << " where i = " << i;`. It doesn't require a new set of macros or special functions. * Google Test automatically detects your tests and doesn't require you to enumerate them in order to run them. * Death tests are pretty handy for ensuring that your asserts in production code are triggered by the right conditions. * `SCOPED_TRACE` helps you understand the context of an assertion failure when it comes from inside a sub-routine or loop. * You can decide which tests to run using name patterns. This saves time when you want to quickly reproduce a test failure. * Google Test can generate XML test result reports that can be parsed by popular continuous build system like Hudson. * Simple things are easy in Google Test, while hard things are possible: in addition to advanced features like [global test environments](AdvancedGuide.md#global-set-up-and-tear-down) and tests parameterized by [values](AdvancedGuide.md#value-parameterized-tests) or [types](docs/AdvancedGuide.md#typed-tests), Google Test supports various ways for the user to extend the framework -- if Google Test doesn't do something out of the box, chances are that a user can implement the feature using Google Test's public API, without changing Google Test itself. In particular, you can: * expand your testing vocabulary by defining [custom predicates](AdvancedGuide.md#predicate-assertions-for-better-error-messages), * teach Google Test how to [print your types](AdvancedGuide.md#teaching-google-test-how-to-print-your-values), * define your own testing macros or utilities and verify them using Google Test's [Service Provider Interface](AdvancedGuide.md#catching-failures), and * reflect on the test cases or change the test output format by intercepting the [test events](AdvancedGuide.md#extending-google-test-by-handling-test-events). ## I'm getting warnings when compiling Google Test. Would you fix them? ## We strive to minimize compiler warnings Google Test generates. Before releasing a new version, we test to make sure that it doesn't generate warnings when compiled using its CMake script on Windows, Linux, and Mac OS. Unfortunately, this doesn't mean you are guaranteed to see no warnings when compiling Google Test in your environment: * You may be using a different compiler as we use, or a different version of the same compiler. We cannot possibly test for all compilers. * You may be compiling on a different platform as we do. * Your project may be using different compiler flags as we do. It is not always possible to make Google Test warning-free for everyone. Or, it may not be desirable if the warning is rarely enabled and fixing the violations makes the code more complex. If you see warnings when compiling Google Test, we suggest that you use the `-isystem` flag (assuming your are using GCC) to mark Google Test headers as system headers. That'll suppress warnings from Google Test headers. ## Why should not test case names and test names contain underscore? ## Underscore (`_`) is special, as C++ reserves the following to be used by the compiler and the standard library: 1. any identifier that starts with an `_` followed by an upper-case letter, and 1. any identifier that containers two consecutive underscores (i.e. `__`) _anywhere_ in its name. User code is _prohibited_ from using such identifiers. Now let's look at what this means for `TEST` and `TEST_F`. Currently `TEST(TestCaseName, TestName)` generates a class named `TestCaseName_TestName_Test`. What happens if `TestCaseName` or `TestName` contains `_`? 1. If `TestCaseName` starts with an `_` followed by an upper-case letter (say, `_Foo`), we end up with `_Foo_TestName_Test`, which is reserved and thus invalid. 1. If `TestCaseName` ends with an `_` (say, `Foo_`), we get `Foo__TestName_Test`, which is invalid. 1. If `TestName` starts with an `_` (say, `_Bar`), we get `TestCaseName__Bar_Test`, which is invalid. 1. If `TestName` ends with an `_` (say, `Bar_`), we get `TestCaseName_Bar__Test`, which is invalid. So clearly `TestCaseName` and `TestName` cannot start or end with `_` (Actually, `TestCaseName` can start with `_` -- as long as the `_` isn't followed by an upper-case letter. But that's getting complicated. So for simplicity we just say that it cannot start with `_`.). It may seem fine for `TestCaseName` and `TestName` to contain `_` in the middle. However, consider this: ``` cpp TEST(Time, Flies_Like_An_Arrow) { ... } TEST(Time_Flies, Like_An_Arrow) { ... } ``` Now, the two `TEST`s will both generate the same class (`Time_Files_Like_An_Arrow_Test`). That's not good. So for simplicity, we just ask the users to avoid `_` in `TestCaseName` and `TestName`. The rule is more constraining than necessary, but it's simple and easy to remember. It also gives Google Test some wiggle room in case its implementation needs to change in the future. If you violate the rule, there may not be immediately consequences, but your test may (just may) break with a new compiler (or a new version of the compiler you are using) or with a new version of Google Test. Therefore it's best to follow the rule. ## Why is it not recommended to install a pre-compiled copy of Google Test (for example, into /usr/local)? ## In the early days, we said that you could install compiled Google Test libraries on `*`nix systems using `make install`. Then every user of your machine can write tests without recompiling Google Test. This seemed like a good idea, but it has a got-cha: every user needs to compile his tests using the _same_ compiler flags used to compile the installed Google Test libraries; otherwise he may run into undefined behaviors (i.e. the tests can behave strangely and may even crash for no obvious reasons). Why? Because C++ has this thing called the One-Definition Rule: if two C++ source files contain different definitions of the same class/function/variable, and you link them together, you violate the rule. The linker may or may not catch the error (in many cases it's not required by the C++ standard to catch the violation). If it doesn't, you get strange run-time behaviors that are unexpected and hard to debug. If you compile Google Test and your test code using different compiler flags, they may see different definitions of the same class/function/variable (e.g. due to the use of `#if` in Google Test). Therefore, for your sanity, we recommend to avoid installing pre-compiled Google Test libraries. Instead, each project should compile Google Test itself such that it can be sure that the same flags are used for both Google Test and the tests. ## How do I generate 64-bit binaries on Windows (using Visual Studio 2008)? ## (Answered by Trevor Robinson) Load the supplied Visual Studio solution file, either `msvc\gtest-md.sln` or `msvc\gtest.sln`. Go through the migration wizard to migrate the solution and project files to Visual Studio 2008. Select `Configuration Manager...` from the `Build` menu. Select `` from the `Active solution platform` dropdown. Select `x64` from the new platform dropdown, leave `Copy settings from` set to `Win32` and `Create new project platforms` checked, then click `OK`. You now have `Win32` and `x64` platform configurations, selectable from the `Standard` toolbar, which allow you to toggle between building 32-bit or 64-bit binaries (or both at once using Batch Build). In order to prevent build output files from overwriting one another, you'll need to change the `Intermediate Directory` settings for the newly created platform configuration across all the projects. To do this, multi-select (e.g. using shift-click) all projects (but not the solution) in the `Solution Explorer`. Right-click one of them and select `Properties`. In the left pane, select `Configuration Properties`, and from the `Configuration` dropdown, select `All Configurations`. Make sure the selected platform is `x64`. For the `Intermediate Directory` setting, change the value from `$(PlatformName)\$(ConfigurationName)` to `$(OutDir)\$(ProjectName)`. Click `OK` and then build the solution. When the build is complete, the 64-bit binaries will be in the `msvc\x64\Debug` directory. ## Can I use Google Test on MinGW? ## We haven't tested this ourselves, but Per Abrahamsen reported that he was able to compile and install Google Test successfully when using MinGW from Cygwin. You'll need to configure it with: `PATH/TO/configure CC="gcc -mno-cygwin" CXX="g++ -mno-cygwin"` You should be able to replace the `-mno-cygwin` option with direct links to the real MinGW binaries, but we haven't tried that. Caveats: * There are many warnings when compiling. * `make check` will produce some errors as not all tests for Google Test itself are compatible with MinGW. We also have reports on successful cross compilation of Google Test MinGW binaries on Linux using [these instructions](http://wiki.wxwidgets.org/Cross-Compiling_Under_Linux#Cross-compiling_under_Linux_for_MS_Windows) on the WxWidgets site. Please contact `googletestframework@googlegroups.com` if you are interested in improving the support for MinGW. ## Why does Google Test support EXPECT\_EQ(NULL, ptr) and ASSERT\_EQ(NULL, ptr) but not EXPECT\_NE(NULL, ptr) and ASSERT\_NE(NULL, ptr)? ## Due to some peculiarity of C++, it requires some non-trivial template meta programming tricks to support using `NULL` as an argument of the `EXPECT_XX()` and `ASSERT_XX()` macros. Therefore we only do it where it's most needed (otherwise we make the implementation of Google Test harder to maintain and more error-prone than necessary). The `EXPECT_EQ()` macro takes the _expected_ value as its first argument and the _actual_ value as the second. It's reasonable that someone wants to write `EXPECT_EQ(NULL, some_expression)`, and this indeed was requested several times. Therefore we implemented it. The need for `EXPECT_NE(NULL, ptr)` isn't nearly as strong. When the assertion fails, you already know that `ptr` must be `NULL`, so it doesn't add any information to print ptr in this case. That means `EXPECT_TRUE(ptr != NULL)` works just as well. If we were to support `EXPECT_NE(NULL, ptr)`, for consistency we'll have to support `EXPECT_NE(ptr, NULL)` as well, as unlike `EXPECT_EQ`, we don't have a convention on the order of the two arguments for `EXPECT_NE`. This means using the template meta programming tricks twice in the implementation, making it even harder to understand and maintain. We believe the benefit doesn't justify the cost. Finally, with the growth of Google Mock's [matcher](../../googlemock/docs/CookBook.md#using-matchers-in-google-test-assertions) library, we are encouraging people to use the unified `EXPECT_THAT(value, matcher)` syntax more often in tests. One significant advantage of the matcher approach is that matchers can be easily combined to form new matchers, while the `EXPECT_NE`, etc, macros cannot be easily combined. Therefore we want to invest more in the matchers than in the `EXPECT_XX()` macros. ## Does Google Test support running tests in parallel? ## Test runners tend to be tightly coupled with the build/test environment, and Google Test doesn't try to solve the problem of running tests in parallel. Instead, we tried to make Google Test work nicely with test runners. For example, Google Test's XML report contains the time spent on each test, and its `gtest_list_tests` and `gtest_filter` flags can be used for splitting the execution of test methods into multiple processes. These functionalities can help the test runner run the tests in parallel. ## Why don't Google Test run the tests in different threads to speed things up? ## It's difficult to write thread-safe code. Most tests are not written with thread-safety in mind, and thus may not work correctly in a multi-threaded setting. If you think about it, it's already hard to make your code work when you know what other threads are doing. It's much harder, and sometimes even impossible, to make your code work when you don't know what other threads are doing (remember that test methods can be added, deleted, or modified after your test was written). If you want to run the tests in parallel, you'd better run them in different processes. ## Why aren't Google Test assertions implemented using exceptions? ## Our original motivation was to be able to use Google Test in projects that disable exceptions. Later we realized some additional benefits of this approach: 1. Throwing in a destructor is undefined behavior in C++. Not using exceptions means Google Test's assertions are safe to use in destructors. 1. The `EXPECT_*` family of macros will continue even after a failure, allowing multiple failures in a `TEST` to be reported in a single run. This is a popular feature, as in C++ the edit-compile-test cycle is usually quite long and being able to fixing more than one thing at a time is a blessing. 1. If assertions are implemented using exceptions, a test may falsely ignore a failure if it's caught by user code: ``` cpp try { ... ASSERT_TRUE(...) ... } catch (...) { ... } ``` The above code will pass even if the `ASSERT_TRUE` throws. While it's unlikely for someone to write this in a test, it's possible to run into this pattern when you write assertions in callbacks that are called by the code under test. The downside of not using exceptions is that `ASSERT_*` (implemented using `return`) will only abort the current function, not the current `TEST`. ## Why do we use two different macros for tests with and without fixtures? ## Unfortunately, C++'s macro system doesn't allow us to use the same macro for both cases. One possibility is to provide only one macro for tests with fixtures, and require the user to define an empty fixture sometimes: ``` cpp class FooTest : public ::testing::Test {}; TEST_F(FooTest, DoesThis) { ... } ``` or ``` cpp typedef ::testing::Test FooTest; TEST_F(FooTest, DoesThat) { ... } ``` Yet, many people think this is one line too many. :-) Our goal was to make it really easy to write tests, so we tried to make simple tests trivial to create. That means using a separate macro for such tests. We think neither approach is ideal, yet either of them is reasonable. In the end, it probably doesn't matter much either way. ## Why don't we use structs as test fixtures? ## We like to use structs only when representing passive data. This distinction between structs and classes is good for documenting the intent of the code's author. Since test fixtures have logic like `SetUp()` and `TearDown()`, they are better defined as classes. ## Why are death tests implemented as assertions instead of using a test runner? ## Our goal was to make death tests as convenient for a user as C++ possibly allows. In particular: * The runner-style requires to split the information into two pieces: the definition of the death test itself, and the specification for the runner on how to run the death test and what to expect. The death test would be written in C++, while the runner spec may or may not be. A user needs to carefully keep the two in sync. `ASSERT_DEATH(statement, expected_message)` specifies all necessary information in one place, in one language, without boilerplate code. It is very declarative. * `ASSERT_DEATH` has a similar syntax and error-reporting semantics as other Google Test assertions, and thus is easy to learn. * `ASSERT_DEATH` can be mixed with other assertions and other logic at your will. You are not limited to one death test per test method. For example, you can write something like: ``` cpp if (FooCondition()) { ASSERT_DEATH(Bar(), "blah"); } else { ASSERT_EQ(5, Bar()); } ``` If you prefer one death test per test method, you can write your tests in that style too, but we don't want to impose that on the users. The fewer artificial limitations the better. * `ASSERT_DEATH` can reference local variables in the current function, and you can decide how many death tests you want based on run-time information. For example, ``` cpp const int count = GetCount(); // Only known at run time. for (int i = 1; i <= count; i++) { ASSERT_DEATH({ double* buffer = new double[i]; ... initializes buffer ... Foo(buffer, i) }, "blah blah"); } ``` The runner-based approach tends to be more static and less flexible, or requires more user effort to get this kind of flexibility. Another interesting thing about `ASSERT_DEATH` is that it calls `fork()` to create a child process to run the death test. This is lightening fast, as `fork()` uses copy-on-write pages and incurs almost zero overhead, and the child process starts from the user-supplied statement directly, skipping all global and local initialization and any code leading to the given statement. If you launch the child process from scratch, it can take seconds just to load everything and start running if the test links to many libraries dynamically. ## My death test modifies some state, but the change seems lost after the death test finishes. Why? ## Death tests (`EXPECT_DEATH`, etc) are executed in a sub-process s.t. the expected crash won't kill the test program (i.e. the parent process). As a result, any in-memory side effects they incur are observable in their respective sub-processes, but not in the parent process. You can think of them as running in a parallel universe, more or less. ## The compiler complains about "undefined references" to some static const member variables, but I did define them in the class body. What's wrong? ## If your class has a static data member: ``` cpp // foo.h class Foo { ... static const int kBar = 100; }; ``` You also need to define it _outside_ of the class body in `foo.cc`: ``` cpp const int Foo::kBar; // No initializer here. ``` Otherwise your code is **invalid C++**, and may break in unexpected ways. In particular, using it in Google Test comparison assertions (`EXPECT_EQ`, etc) will generate an "undefined reference" linker error. ## I have an interface that has several implementations. Can I write a set of tests once and repeat them over all the implementations? ## Google Test doesn't yet have good support for this kind of tests, or data-driven tests in general. We hope to be able to make improvements in this area soon. ## Can I derive a test fixture from another? ## Yes. Each test fixture has a corresponding and same named test case. This means only one test case can use a particular fixture. Sometimes, however, multiple test cases may want to use the same or slightly different fixtures. For example, you may want to make sure that all of a GUI library's test cases don't leak important system resources like fonts and brushes. In Google Test, you share a fixture among test cases by putting the shared logic in a base test fixture, then deriving from that base a separate fixture for each test case that wants to use this common logic. You then use `TEST_F()` to write tests using each derived fixture. Typically, your code looks like this: ``` cpp // Defines a base test fixture. class BaseTest : public ::testing::Test { protected: ... }; // Derives a fixture FooTest from BaseTest. class FooTest : public BaseTest { protected: virtual void SetUp() { BaseTest::SetUp(); // Sets up the base fixture first. ... additional set-up work ... } virtual void TearDown() { ... clean-up work for FooTest ... BaseTest::TearDown(); // Remember to tear down the base fixture // after cleaning up FooTest! } ... functions and variables for FooTest ... }; // Tests that use the fixture FooTest. TEST_F(FooTest, Bar) { ... } TEST_F(FooTest, Baz) { ... } ... additional fixtures derived from BaseTest ... ``` If necessary, you can continue to derive test fixtures from a derived fixture. Google Test has no limit on how deep the hierarchy can be. For a complete example using derived test fixtures, see [sample5](../samples/sample5_unittest.cc). ## My compiler complains "void value not ignored as it ought to be." What does this mean? ## You're probably using an `ASSERT_*()` in a function that doesn't return `void`. `ASSERT_*()` can only be used in `void` functions. ## My death test hangs (or seg-faults). How do I fix it? ## In Google Test, death tests are run in a child process and the way they work is delicate. To write death tests you really need to understand how they work. Please make sure you have read this. In particular, death tests don't like having multiple threads in the parent process. So the first thing you can try is to eliminate creating threads outside of `EXPECT_DEATH()`. Sometimes this is impossible as some library you must use may be creating threads before `main()` is even reached. In this case, you can try to minimize the chance of conflicts by either moving as many activities as possible inside `EXPECT_DEATH()` (in the extreme case, you want to move everything inside), or leaving as few things as possible in it. Also, you can try to set the death test style to `"threadsafe"`, which is safer but slower, and see if it helps. If you go with thread-safe death tests, remember that they rerun the test program from the beginning in the child process. Therefore make sure your program can run side-by-side with itself and is deterministic. In the end, this boils down to good concurrent programming. You have to make sure that there is no race conditions or dead locks in your program. No silver bullet - sorry! ## Should I use the constructor/destructor of the test fixture or the set-up/tear-down function? ## The first thing to remember is that Google Test does not reuse the same test fixture object across multiple tests. For each `TEST_F`, Google Test will create a fresh test fixture object, _immediately_ call `SetUp()`, run the test body, call `TearDown()`, and then _immediately_ delete the test fixture object. When you need to write per-test set-up and tear-down logic, you have the choice between using the test fixture constructor/destructor or `SetUp()/TearDown()`. The former is usually preferred, as it has the following benefits: * By initializing a member variable in the constructor, we have the option to make it `const`, which helps prevent accidental changes to its value and makes the tests more obviously correct. * In case we need to subclass the test fixture class, the subclass' constructor is guaranteed to call the base class' constructor first, and the subclass' destructor is guaranteed to call the base class' destructor afterward. With `SetUp()/TearDown()`, a subclass may make the mistake of forgetting to call the base class' `SetUp()/TearDown()` or call them at the wrong moment. You may still want to use `SetUp()/TearDown()` in the following rare cases: * If the tear-down operation could throw an exception, you must use `TearDown()` as opposed to the destructor, as throwing in a destructor leads to undefined behavior and usually will kill your program right away. Note that many standard libraries (like STL) may throw when exceptions are enabled in the compiler. Therefore you should prefer `TearDown()` if you want to write portable tests that work with or without exceptions. * The assertion macros throw an exception when flag `--gtest_throw_on_failure` is specified. Therefore, you shouldn't use Google Test assertions in a destructor if you plan to run your tests with this flag. * In a constructor or destructor, you cannot make a virtual function call on this object. (You can call a method declared as virtual, but it will be statically bound.) Therefore, if you need to call a method that will be overriden in a derived class, you have to use `SetUp()/TearDown()`. ## The compiler complains "no matching function to call" when I use ASSERT\_PREDn. How do I fix it? ## If the predicate function you use in `ASSERT_PRED*` or `EXPECT_PRED*` is overloaded or a template, the compiler will have trouble figuring out which overloaded version it should use. `ASSERT_PRED_FORMAT*` and `EXPECT_PRED_FORMAT*` don't have this problem. If you see this error, you might want to switch to `(ASSERT|EXPECT)_PRED_FORMAT*`, which will also give you a better failure message. If, however, that is not an option, you can resolve the problem by explicitly telling the compiler which version to pick. For example, suppose you have ``` cpp bool IsPositive(int n) { return n > 0; } bool IsPositive(double x) { return x > 0; } ``` you will get a compiler error if you write ``` cpp EXPECT_PRED1(IsPositive, 5); ``` However, this will work: ``` cpp EXPECT_PRED1(*static_cast*(IsPositive), 5); ``` (The stuff inside the angled brackets for the `static_cast` operator is the type of the function pointer for the `int`-version of `IsPositive()`.) As another example, when you have a template function ``` cpp template bool IsNegative(T x) { return x < 0; } ``` you can use it in a predicate assertion like this: ``` cpp ASSERT_PRED1(IsNegative**, -5); ``` Things are more interesting if your template has more than one parameters. The following won't compile: ``` cpp ASSERT_PRED2(*GreaterThan*, 5, 0); ``` as the C++ pre-processor thinks you are giving `ASSERT_PRED2` 4 arguments, which is one more than expected. The workaround is to wrap the predicate function in parentheses: ``` cpp ASSERT_PRED2(*(GreaterThan)*, 5, 0); ``` ## My compiler complains about "ignoring return value" when I call RUN\_ALL\_TESTS(). Why? ## Some people had been ignoring the return value of `RUN_ALL_TESTS()`. That is, instead of ``` cpp return RUN_ALL_TESTS(); ``` they write ``` cpp RUN_ALL_TESTS(); ``` This is wrong and dangerous. A test runner needs to see the return value of `RUN_ALL_TESTS()` in order to determine if a test has passed. If your `main()` function ignores it, your test will be considered successful even if it has a Google Test assertion failure. Very bad. To help the users avoid this dangerous bug, the implementation of `RUN_ALL_TESTS()` causes gcc to raise this warning, when the return value is ignored. If you see this warning, the fix is simple: just make sure its value is used as the return value of `main()`. ## My compiler complains that a constructor (or destructor) cannot return a value. What's going on? ## Due to a peculiarity of C++, in order to support the syntax for streaming messages to an `ASSERT_*`, e.g. ``` cpp ASSERT_EQ(1, Foo()) << "blah blah" << foo; ``` we had to give up using `ASSERT*` and `FAIL*` (but not `EXPECT*` and `ADD_FAILURE*`) in constructors and destructors. The workaround is to move the content of your constructor/destructor to a private void member function, or switch to `EXPECT_*()` if that works. This section in the user's guide explains it. ## My set-up function is not called. Why? ## C++ is case-sensitive. It should be spelled as `SetUp()`. Did you spell it as `Setup()`? Similarly, sometimes people spell `SetUpTestCase()` as `SetupTestCase()` and wonder why it's never called. ## How do I jump to the line of a failure in Emacs directly? ## Google Test's failure message format is understood by Emacs and many other IDEs, like acme and XCode. If a Google Test message is in a compilation buffer in Emacs, then it's clickable. You can now hit `enter` on a message to jump to the corresponding source code, or use `C-x `` to jump to the next failure. ## I have several test cases which share the same test fixture logic, do I have to define a new test fixture class for each of them? This seems pretty tedious. ## You don't have to. Instead of ``` cpp class FooTest : public BaseTest {}; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } class BarTest : public BaseTest {}; TEST_F(BarTest, Abc) { ... } TEST_F(BarTest, Def) { ... } ``` you can simply `typedef` the test fixtures: ``` cpp typedef BaseTest FooTest; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } typedef BaseTest BarTest; TEST_F(BarTest, Abc) { ... } TEST_F(BarTest, Def) { ... } ``` ## The Google Test output is buried in a whole bunch of log messages. What do I do? ## The Google Test output is meant to be a concise and human-friendly report. If your test generates textual output itself, it will mix with the Google Test output, making it hard to read. However, there is an easy solution to this problem. Since most log messages go to stderr, we decided to let Google Test output go to stdout. This way, you can easily separate the two using redirection. For example: ``` ./my_test > googletest_output.txt ``` ## Why should I prefer test fixtures over global variables? ## There are several good reasons: 1. It's likely your test needs to change the states of its global variables. This makes it difficult to keep side effects from escaping one test and contaminating others, making debugging difficult. By using fixtures, each test has a fresh set of variables that's different (but with the same names). Thus, tests are kept independent of each other. 1. Global variables pollute the global namespace. 1. Test fixtures can be reused via subclassing, which cannot be done easily with global variables. This is useful if many test cases have something in common. ## How do I test private class members without writing FRIEND\_TEST()s? ## You should try to write testable code, which means classes should be easily tested from their public interface. One way to achieve this is the Pimpl idiom: you move all private members of a class into a helper class, and make all members of the helper class public. You have several other options that don't require using `FRIEND_TEST`: * Write the tests as members of the fixture class: ``` cpp class Foo { friend class FooTest; ... }; class FooTest : public ::testing::Test { protected: ... void Test1() {...} // This accesses private members of class Foo. void Test2() {...} // So does this one. }; TEST_F(FooTest, Test1) { Test1(); } TEST_F(FooTest, Test2) { Test2(); } ``` * In the fixture class, write accessors for the tested class' private members, then use the accessors in your tests: ``` cpp class Foo { friend class FooTest; ... }; class FooTest : public ::testing::Test { protected: ... T1 get_private_member1(Foo* obj) { return obj->private_member1_; } }; TEST_F(FooTest, Test1) { ... get_private_member1(x) ... } ``` * If the methods are declared **protected**, you can change their access level in a test-only subclass: ``` cpp class YourClass { ... protected: // protected access for testability. int DoSomethingReturningInt(); ... }; // in the your_class_test.cc file: class TestableYourClass : public YourClass { ... public: using YourClass::DoSomethingReturningInt; // changes access rights ... }; TEST_F(YourClassTest, DoSomethingTest) { TestableYourClass obj; assertEquals(expected_value, obj.DoSomethingReturningInt()); } ``` ## How do I test private class static members without writing FRIEND\_TEST()s? ## We find private static methods clutter the header file. They are implementation details and ideally should be kept out of a .h. So often I make them free functions instead. Instead of: ``` cpp // foo.h class Foo { ... private: static bool Func(int n); }; // foo.cc bool Foo::Func(int n) { ... } // foo_test.cc EXPECT_TRUE(Foo::Func(12345)); ``` You probably should better write: ``` cpp // foo.h class Foo { ... }; // foo.cc namespace internal { bool Func(int n) { ... } } // foo_test.cc namespace internal { bool Func(int n); } EXPECT_TRUE(internal::Func(12345)); ``` ## I would like to run a test several times with different parameters. Do I need to write several similar copies of it? ## No. You can use a feature called [value-parameterized tests](AdvancedGuide.md#Value_Parameterized_Tests) which lets you repeat your tests with different parameters, without defining it more than once. ## How do I test a file that defines main()? ## To test a `foo.cc` file, you need to compile and link it into your unit test program. However, when the file contains a definition for the `main()` function, it will clash with the `main()` of your unit test, and will result in a build error. The right solution is to split it into three files: 1. `foo.h` which contains the declarations, 1. `foo.cc` which contains the definitions except `main()`, and 1. `foo_main.cc` which contains nothing but the definition of `main()`. Then `foo.cc` can be easily tested. If you are adding tests to an existing file and don't want an intrusive change like this, there is a hack: just include the entire `foo.cc` file in your unit test. For example: ``` cpp // File foo_unittest.cc // The headers section ... // Renames main() in foo.cc to make room for the unit test main() #define main FooMain #include "a/b/foo.cc" // The tests start here. ... ``` However, please remember this is a hack and should only be used as the last resort. ## What can the statement argument in ASSERT\_DEATH() be? ## `ASSERT_DEATH(_statement_, _regex_)` (or any death assertion macro) can be used wherever `_statement_` is valid. So basically `_statement_` can be any C++ statement that makes sense in the current context. In particular, it can reference global and/or local variables, and can be: * a simple function call (often the case), * a complex expression, or * a compound statement. Some examples are shown here: ``` cpp // A death test can be a simple function call. TEST(MyDeathTest, FunctionCall) { ASSERT_DEATH(Xyz(5), "Xyz failed"); } // Or a complex expression that references variables and functions. TEST(MyDeathTest, ComplexExpression) { const bool c = Condition(); ASSERT_DEATH((c ? Func1(0) : object2.Method("test")), "(Func1|Method) failed"); } // Death assertions can be used any where in a function. In // particular, they can be inside a loop. TEST(MyDeathTest, InsideLoop) { // Verifies that Foo(0), Foo(1), ..., and Foo(4) all die. for (int i = 0; i < 5; i++) { EXPECT_DEATH_M(Foo(i), "Foo has \\d+ errors", ::testing::Message() << "where i is " << i); } } // A death assertion can contain a compound statement. TEST(MyDeathTest, CompoundStatement) { // Verifies that at lease one of Bar(0), Bar(1), ..., and // Bar(4) dies. ASSERT_DEATH({ for (int i = 0; i < 5; i++) { Bar(i); } }, "Bar has \\d+ errors");} ``` `googletest_unittest.cc` contains more examples if you are interested. ## What syntax does the regular expression in ASSERT\_DEATH use? ## On POSIX systems, Google Test uses the POSIX Extended regular expression syntax (http://en.wikipedia.org/wiki/Regular_expression#POSIX_Extended_Regular_Expressions). On Windows, it uses a limited variant of regular expression syntax. For more details, see the [regular expression syntax](AdvancedGuide.md#Regular_Expression_Syntax). ## I have a fixture class Foo, but TEST\_F(Foo, Bar) gives me error "no matching function for call to Foo::Foo()". Why? ## Google Test needs to be able to create objects of your test fixture class, so it must have a default constructor. Normally the compiler will define one for you. However, there are cases where you have to define your own: * If you explicitly declare a non-default constructor for class `Foo`, then you need to define a default constructor, even if it would be empty. * If `Foo` has a const non-static data member, then you have to define the default constructor _and_ initialize the const member in the initializer list of the constructor. (Early versions of `gcc` doesn't force you to initialize the const member. It's a bug that has been fixed in `gcc 4`.) ## Why does ASSERT\_DEATH complain about previous threads that were already joined? ## With the Linux pthread library, there is no turning back once you cross the line from single thread to multiple threads. The first time you create a thread, a manager thread is created in addition, so you get 3, not 2, threads. Later when the thread you create joins the main thread, the thread count decrements by 1, but the manager thread will never be killed, so you still have 2 threads, which means you cannot safely run a death test. The new NPTL thread library doesn't suffer from this problem, as it doesn't create a manager thread. However, if you don't control which machine your test runs on, you shouldn't depend on this. ## Why does Google Test require the entire test case, instead of individual tests, to be named FOODeathTest when it uses ASSERT\_DEATH? ## Google Test does not interleave tests from different test cases. That is, it runs all tests in one test case first, and then runs all tests in the next test case, and so on. Google Test does this because it needs to set up a test case before the first test in it is run, and tear it down afterwords. Splitting up the test case would require multiple set-up and tear-down processes, which is inefficient and makes the semantics unclean. If we were to determine the order of tests based on test name instead of test case name, then we would have a problem with the following situation: ``` cpp TEST_F(FooTest, AbcDeathTest) { ... } TEST_F(FooTest, Uvw) { ... } TEST_F(BarTest, DefDeathTest) { ... } TEST_F(BarTest, Xyz) { ... } ``` Since `FooTest.AbcDeathTest` needs to run before `BarTest.Xyz`, and we don't interleave tests from different test cases, we need to run all tests in the `FooTest` case before running any test in the `BarTest` case. This contradicts with the requirement to run `BarTest.DefDeathTest` before `FooTest.Uvw`. ## But I don't like calling my entire test case FOODeathTest when it contains both death tests and non-death tests. What do I do? ## You don't have to, but if you like, you may split up the test case into `FooTest` and `FooDeathTest`, where the names make it clear that they are related: ``` cpp class FooTest : public ::testing::Test { ... }; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } typedef FooTest FooDeathTest; TEST_F(FooDeathTest, Uvw) { ... EXPECT_DEATH(...) ... } TEST_F(FooDeathTest, Xyz) { ... ASSERT_DEATH(...) ... } ``` ## The compiler complains about "no match for 'operator<<'" when I use an assertion. What gives? ## If you use a user-defined type `FooType` in an assertion, you must make sure there is an `std::ostream& operator<<(std::ostream&, const FooType&)` function defined such that we can print a value of `FooType`. In addition, if `FooType` is declared in a name space, the `<<` operator also needs to be defined in the _same_ name space. ## How do I suppress the memory leak messages on Windows? ## Since the statically initialized Google Test singleton requires allocations on the heap, the Visual C++ memory leak detector will report memory leaks at the end of the program run. The easiest way to avoid this is to use the `_CrtMemCheckpoint` and `_CrtMemDumpAllObjectsSince` calls to not report any statically initialized heap objects. See MSDN for more details and additional heap check/debug routines. ## I am building my project with Google Test in Visual Studio and all I'm getting is a bunch of linker errors (or warnings). Help! ## You may get a number of the following linker error or warnings if you attempt to link your test project with the Google Test library when your project and the are not built using the same compiler settings. * LNK2005: symbol already defined in object * LNK4217: locally defined symbol 'symbol' imported in function 'function' * LNK4049: locally defined symbol 'symbol' imported The Google Test project (gtest.vcproj) has the Runtime Library option set to /MT (use multi-threaded static libraries, /MTd for debug). If your project uses something else, for example /MD (use multi-threaded DLLs, /MDd for debug), you need to change the setting in the Google Test project to match your project's. To update this setting open the project properties in the Visual Studio IDE then select the branch Configuration Properties | C/C++ | Code Generation and change the option "Runtime Library". You may also try using gtest-md.vcproj instead of gtest.vcproj. ## I put my tests in a library and Google Test doesn't run them. What's happening? ## Have you read a [warning](Primer.md#important-note-for-visual-c-users) on the Google Test Primer page? ## I want to use Google Test with Visual Studio but don't know where to start. ## Many people are in your position and one of the posted his solution to our mailing list. ## I am seeing compile errors mentioning std::type\_traits when I try to use Google Test on Solaris. ## Google Test uses parts of the standard C++ library that SunStudio does not support. Our users reported success using alternative implementations. Try running the build after runing this commad: `export CC=cc CXX=CC CXXFLAGS='-library=stlport4'` ## How can my code detect if it is running in a test? ## If you write code that sniffs whether it's running in a test and does different things accordingly, you are leaking test-only logic into production code and there is no easy way to ensure that the test-only code paths aren't run by mistake in production. Such cleverness also leads to [Heisenbugs](http://en.wikipedia.org/wiki/Unusual_software_bug#Heisenbug). Therefore we strongly advise against the practice, and Google Test doesn't provide a way to do it. In general, the recommended way to cause the code to behave differently under test is [dependency injection](http://jamesshore.com/Blog/Dependency-Injection-Demystified.html). You can inject different functionality from the test and from the production code. Since your production code doesn't link in the for-test logic at all, there is no danger in accidentally running it. However, if you _really_, _really_, _really_ have no choice, and if you follow the rule of ending your test program names with `_test`, you can use the _horrible_ hack of sniffing your executable name (`argv[0]` in `main()`) to know whether the code is under test. ## Google Test defines a macro that clashes with one defined by another library. How do I deal with that? ## 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`. For example, with `-DGTEST_DONT_DEFINE_TEST=1`, you'll need to write ``` cpp GTEST_TEST(SomeTest, DoesThis) { ... } ``` instead of ``` cpp TEST(SomeTest, DoesThis) { ... } ``` in order to define a test. Currently, the following `TEST`, `FAIL`, `SUCCEED`, and the basic comparison assertion macros can have alternative names. You can see the full list of covered macros [here](http://www.google.com/codesearch?q=if+!GTEST_DONT_DEFINE_\w%2B+package:http://googletest\.googlecode\.com+file:/include/gtest/gtest.h). More information can be found in the "Avoiding Macro Name Clashes" section of the README file. ## Is it OK if I have two separate `TEST(Foo, Bar)` test methods defined in different namespaces? ## Yes. The rule is **all test methods in the same test case must use the same fixture class**. This means that the following is **allowed** because both tests use the same fixture class (`::testing::Test`). ``` cpp namespace foo { TEST(CoolTest, DoSomething) { SUCCEED(); } } // namespace foo namespace bar { TEST(CoolTest, DoSomething) { SUCCEED(); } } // namespace foo ``` However, the following code is **not allowed** and will produce a runtime error from Google Test because the test methods are using different test fixture classes with the same test case name. ``` cpp namespace foo { class CoolTest : public ::testing::Test {}; // Fixture foo::CoolTest TEST_F(CoolTest, DoSomething) { SUCCEED(); } } // namespace foo namespace bar { class CoolTest : public ::testing::Test {}; // Fixture: bar::CoolTest TEST_F(CoolTest, DoSomething) { SUCCEED(); } } // namespace foo ``` ## How do I build Google Testing Framework with Xcode 4? ## If you try to build Google Test's Xcode project with Xcode 4.0 or later, you may encounter an error message that looks like "Missing SDK in target gtest\_framework: /Developer/SDKs/MacOSX10.4u.sdk". That means that Xcode does not support the SDK the project is targeting. See the Xcode section in the [README](../README.md) file on how to resolve this. ## My question is not covered in your FAQ! ## If you cannot find the answer to your question in this FAQ, there are some other resources you can use: 1. read other [wiki pages](../docs), 1. search the mailing list [archive](https://groups.google.com/forum/#!forum/googletestframework), 1. ask it on [googletestframework@googlegroups.com](mailto:googletestframework@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googletestframework) before you can post.). Please note that creating an issue in the [issue tracker](https://github.com/google/googletest/issues) is _not_ a good way to get your answer, as it is monitored infrequently by a very small number of people. When asking a question, it's helpful to provide as much of the following information as possible (people cannot help you if there's not enough information in your question): * the version (or the commit hash if you check out from Git directly) of Google Test you use (Google Test is under active development, so it's possible that your problem has been solved in a later version), * your operating system, * the name and version of your compiler, * the complete command line flags you give to your compiler, * the complete compiler error messages (if the question is about compilation), * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. assimp-4.1.0/contrib/gtest/docs/V1_7_PumpManual.md0000644002537200234200000001561413213503245022176 0ustar zmoelnigiemusers Pump is Useful for Meta Programming. # The Problem # Template and macro libraries often need to define many classes, functions, or macros that vary only (or almost only) in the number of arguments they take. It's a lot of repetitive, mechanical, and error-prone work. Variadic templates and variadic macros can alleviate the problem. However, while both are being considered by the C++ committee, neither is in the standard yet or widely supported by compilers. Thus they are often not a good choice, especially when your code needs to be portable. And their capabilities are still limited. As a result, authors of such libraries often have to write scripts to generate their implementation. However, our experience is that it's tedious to write such scripts, which tend to reflect the structure of the generated code poorly and are often hard to read and edit. For example, a small change needed in the generated code may require some non-intuitive, non-trivial changes in the script. This is especially painful when experimenting with the code. # Our Solution # Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta Programming, or Practical Utility for Meta Programming, whichever you prefer) is a simple meta-programming tool for C++. The idea is that a programmer writes a `foo.pump` file which contains C++ code plus meta code that manipulates the C++ code. The meta code can handle iterations over a range, nested iterations, local meta variable definitions, simple arithmetic, and conditional expressions. You can view it as a small Domain-Specific Language. The meta language is designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, for example) and concise, making Pump code intuitive and easy to maintain. ## Highlights ## * The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms. * Pump tries to be smart with respect to [Google's style guide](http://code.google.com/p/google-styleguide/): it breaks long lines (easy to have when they are generated) at acceptable places to fit within 80 columns and indent the continuation lines correctly. * The format is human-readable and more concise than XML. * The format works relatively well with Emacs' C++ mode. ## Examples ## The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line): ``` $var n = 3 $$ Defines a meta variable n. $range i 0..n $$ Declares the range of meta iterator i (inclusive). $for i [[ $$ Meta loop. // Foo$i does blah for $i-ary predicates. $range j 1..i template class Foo$i { $if i == 0 [[ blah a; ]] $elif i <= 2 [[ blah b; ]] $else [[ blah c; ]] }; ]] ``` will be translated by the Pump compiler to: ``` // Foo0 does blah for 0-ary predicates. template class Foo0 { blah a; }; // Foo1 does blah for 1-ary predicates. template class Foo1 { blah b; }; // Foo2 does blah for 2-ary predicates. template class Foo2 { blah b; }; // Foo3 does blah for 3-ary predicates. template class Foo3 { blah c; }; ``` In another example, ``` $range i 1..n Func($for i + [[a$i]]); $$ The text between i and [[ is the separator between iterations. ``` will generate one of the following lines (without the comments), depending on the value of `n`: ``` Func(); // If n is 0. Func(a1); // If n is 1. Func(a1 + a2); // If n is 2. Func(a1 + a2 + a3); // If n is 3. // And so on... ``` ## Constructs ## We support the following meta programming constructs: | `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. | |:----------------|:-----------------------------------------------------------------------------------------------| | `$range id exp..exp` | Sets the range of an iteration variable, which can be reused in multiple loops later. | | `$for id sep [[ code ]]` | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`. | | `$($)` | Generates a single `$` character. | | `$id` | Value of the named constant or iteration variable. | | `$(exp)` | Value of the expression. | | `$if exp [[ code ]] else_branch` | Conditional. | | `[[ code ]]` | Meta lexical block. | | `cpp_code` | Raw C++ code. | | `$$ comment` | Meta comment. | **Note:** To give the user some freedom in formatting the Pump source code, Pump ignores a new-line character if it's right after `$for foo` or next to `[[` or `]]`. Without this rule you'll often be forced to write very long lines to get the desired output. Therefore sometimes you may need to insert an extra new-line in such places for a new-line to show up in your output. ## Grammar ## ``` code ::= atomic_code* atomic_code ::= $var id = exp | $var id = [[ code ]] | $range id exp..exp | $for id sep [[ code ]] | $($) | $id | $(exp) | $if exp [[ code ]] else_branch | [[ code ]] | cpp_code sep ::= cpp_code | empty_string else_branch ::= $else [[ code ]] | $elif exp [[ code ]] else_branch | empty_string exp ::= simple_expression_in_Python_syntax ``` ## Code ## You can find the source code of Pump in [scripts/pump.py](../scripts/pump.py). It is still very unpolished and lacks automated tests, although it has been successfully used many times. If you find a chance to use it in your project, please let us know what you think! We also welcome help on improving Pump. ## Real Examples ## You can find real-world applications of Pump in [Google Test](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgoogletest\.googlecode\.com) and [Google Mock](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgooglemock\.googlecode\.com). The source file `foo.h.pump` generates `foo.h`. ## Tips ## * If a meta variable is followed by a letter or digit, you can separate them using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper` generate `Foo1Helper` when `j` is 1. * To avoid extra-long Pump source lines, you can break a line anywhere you want by inserting `[[]]` followed by a new line. Since any new-line character next to `[[` or `]]` is ignored, the generated code won't contain this new line. assimp-4.1.0/contrib/gtest/docs/V1_7_Primer.md0000644002537200234200000006063413213503245021357 0ustar zmoelnigiemusers # Introduction: Why Google C++ Testing Framework? # _Google C++ Testing Framework_ helps you write better C++ tests. No matter whether you work on Linux, Windows, or a Mac, if you write C++ code, Google Test can help you. So what makes a good test, and how does Google C++ Testing Framework fit in? We believe: 1. Tests should be _independent_ and _repeatable_. It's a pain to debug a test that succeeds or fails as a result of other tests. Google C++ Testing Framework isolates the tests by running each of them on a different object. When a test fails, Google C++ Testing Framework allows you to run it in isolation for quick debugging. 1. Tests should be well _organized_ and reflect the structure of the tested code. Google C++ Testing Framework groups related tests into test cases that can share data and subroutines. This common pattern is easy to recognize and makes tests easy to maintain. Such consistency is especially helpful when people switch projects and start to work on a new code base. 1. Tests should be _portable_ and _reusable_. The open-source community has a lot of code that is platform-neutral, its tests should also be platform-neutral. Google C++ Testing Framework works on different OSes, with different compilers (gcc, MSVC, and others), with or without exceptions, so Google C++ Testing Framework tests can easily work with a variety of configurations. (Note that the current release only contains build scripts for Linux - we are actively working on scripts for other platforms.) 1. When tests fail, they should provide as much _information_ about the problem as possible. Google C++ Testing Framework doesn't stop at the first test failure. Instead, it only stops the current test and continues with the next. You can also set up tests that report non-fatal failures after which the current test continues. Thus, you can detect and fix multiple bugs in a single run-edit-compile cycle. 1. The testing framework should liberate test writers from housekeeping chores and let them focus on the test _content_. Google C++ Testing Framework automatically keeps track of all tests defined, and doesn't require the user to enumerate them in order to run them. 1. Tests should be _fast_. With Google C++ Testing Framework, you can reuse shared resources across tests and pay for the set-up/tear-down only once, without making tests depend on each other. Since Google C++ Testing Framework is based on the popular xUnit architecture, you'll feel right at home if you've used JUnit or PyUnit before. If not, it will take you about 10 minutes to learn the basics and get started. So let's go! _Note:_ We sometimes refer to Google C++ Testing Framework informally as _Google Test_. # Setting up a New Test Project # To write a test program using Google Test, you need to compile Google Test into a library and link your test with it. We provide build files for some popular build systems: `msvc/` for Visual Studio, `xcode/` for Mac Xcode, `make/` for GNU make, `codegear/` for Borland C++ Builder, and the autotools script (deprecated) and `CMakeLists.txt` for CMake (recommended) in the Google Test root directory. If your build system is not on this list, you can take a look at `make/Makefile` to learn how Google Test should be compiled (basically you want to compile `src/gtest-all.cc` with `GTEST_ROOT` and `GTEST_ROOT/include` in the header search path, where `GTEST_ROOT` is the Google Test root directory). Once you are able to compile the Google Test library, you should create a project or build target for your test program. Make sure you have `GTEST_ROOT/include` in the header search path so that the compiler can find `"gtest/gtest.h"` when compiling your test. Set up your test project to link with the Google Test library (for example, in Visual Studio, this is done by adding a dependency on `gtest.vcproj`). If you still have questions, take a look at how Google Test's own tests are built and use them as examples. # Basic Concepts # When using Google Test, you start by writing _assertions_, which are statements that check whether a condition is true. An assertion's result can be _success_, _nonfatal failure_, or _fatal failure_. If a fatal failure occurs, it aborts the current function; otherwise the program continues normally. _Tests_ use assertions to verify the tested code's behavior. If a test crashes or has a failed assertion, then it _fails_; otherwise it _succeeds_. A _test case_ contains one or many tests. You should group your tests into test cases that reflect the structure of the tested code. When multiple tests in a test case need to share common objects and subroutines, you can put them into a _test fixture_ class. A _test program_ can contain multiple test cases. We'll now explain how to write a test program, starting at the individual assertion level and building up to tests and test cases. # Assertions # Google Test assertions are macros that resemble function calls. You test a class or function by making assertions about its behavior. When an assertion fails, Google Test prints the assertion's source file and line number location, along with a failure message. You may also supply a custom failure message which will be appended to Google Test's message. The assertions come in pairs that test the same thing but have different effects on the current function. `ASSERT_*` versions generate fatal failures when they fail, and **abort the current function**. `EXPECT_*` versions generate nonfatal failures, which don't abort the current function. Usually `EXPECT_*` are preferred, as they allow more than one failures to be reported in a test. However, you should use `ASSERT_*` if it doesn't make sense to continue when the assertion in question fails. Since a failed `ASSERT_*` returns from the current function immediately, possibly skipping clean-up code that comes after it, it may cause a space leak. Depending on the nature of the leak, it may or may not be worth fixing - so keep this in mind if you get a heap checker error in addition to assertion errors. To provide a custom failure message, simply stream it into the macro using the `<<` operator, or a sequence of such operators. An example: ``` ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length"; for (int i = 0; i < x.size(); ++i) { EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i; } ``` Anything that can be streamed to an `ostream` can be streamed to an assertion macro--in particular, C strings and `string` objects. If a wide string (`wchar_t*`, `TCHAR*` in `UNICODE` mode on Windows, or `std::wstring`) is streamed to an assertion, it will be translated to UTF-8 when printed. ## Basic Assertions ## These assertions do basic true/false condition testing. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_TRUE(`_condition_`)`; | `EXPECT_TRUE(`_condition_`)`; | _condition_ is true | | `ASSERT_FALSE(`_condition_`)`; | `EXPECT_FALSE(`_condition_`)`; | _condition_ is false | Remember, when they fail, `ASSERT_*` yields a fatal failure and returns from the current function, while `EXPECT_*` yields a nonfatal failure, allowing the function to continue running. In either case, an assertion failure means its containing test fails. _Availability_: Linux, Windows, Mac. ## Binary Comparison ## This section describes assertions that compare two values. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| |`ASSERT_EQ(`_expected_`, `_actual_`);`|`EXPECT_EQ(`_expected_`, `_actual_`);`| _expected_ `==` _actual_ | |`ASSERT_NE(`_val1_`, `_val2_`);` |`EXPECT_NE(`_val1_`, `_val2_`);` | _val1_ `!=` _val2_ | |`ASSERT_LT(`_val1_`, `_val2_`);` |`EXPECT_LT(`_val1_`, `_val2_`);` | _val1_ `<` _val2_ | |`ASSERT_LE(`_val1_`, `_val2_`);` |`EXPECT_LE(`_val1_`, `_val2_`);` | _val1_ `<=` _val2_ | |`ASSERT_GT(`_val1_`, `_val2_`);` |`EXPECT_GT(`_val1_`, `_val2_`);` | _val1_ `>` _val2_ | |`ASSERT_GE(`_val1_`, `_val2_`);` |`EXPECT_GE(`_val1_`, `_val2_`);` | _val1_ `>=` _val2_ | In the event of a failure, Google Test prints both _val1_ and _val2_ . In `ASSERT_EQ*` and `EXPECT_EQ*` (and all other equality assertions we'll introduce later), you should put the expression you want to test in the position of _actual_, and put its expected value in _expected_, as Google Test's failure messages are optimized for this convention. Value arguments must be comparable by the assertion's comparison operator or you'll get a compiler error. We used to require the arguments to support the `<<` operator for streaming to an `ostream`, but it's no longer necessary since v1.6.0 (if `<<` is supported, it will be called to print the arguments when the assertion fails; otherwise Google Test will attempt to print them in the best way it can. For more details and how to customize the printing of the arguments, see this Google Mock [recipe](../../googlemock/docs/CookBook.md#teaching-google-mock-how-to-print-your-values).). These assertions can work with a user-defined type, but only if you define the corresponding comparison operator (e.g. `==`, `<`, etc). If the corresponding operator is defined, prefer using the `ASSERT_*()` macros because they will print out not only the result of the comparison, but the two operands as well. Arguments are always evaluated exactly once. Therefore, it's OK for the arguments to have side effects. However, as with any ordinary C/C++ function, the arguments' evaluation order is undefined (i.e. the compiler is free to choose any order) and your code should not depend on any particular argument evaluation order. `ASSERT_EQ()` does pointer equality on pointers. If used on two C strings, it tests if they are in the same memory location, not if they have the same value. Therefore, if you want to compare C strings (e.g. `const char*`) by value, use `ASSERT_STREQ()` , which will be described later on. In particular, to assert that a C string is `NULL`, use `ASSERT_STREQ(NULL, c_string)` . However, to compare two `string` objects, you should use `ASSERT_EQ`. Macros in this section work with both narrow and wide string objects (`string` and `wstring`). _Availability_: Linux, Windows, Mac. ## String Comparison ## The assertions in this group compare two **C strings**. If you want to compare two `string` objects, use `EXPECT_EQ`, `EXPECT_NE`, and etc instead. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_STREQ(`_expected\_str_`, `_actual\_str_`);` | `EXPECT_STREQ(`_expected\_str_`, `_actual\_str_`);` | the two C strings have the same content | | `ASSERT_STRNE(`_str1_`, `_str2_`);` | `EXPECT_STRNE(`_str1_`, `_str2_`);` | the two C strings have different content | | `ASSERT_STRCASEEQ(`_expected\_str_`, `_actual\_str_`);`| `EXPECT_STRCASEEQ(`_expected\_str_`, `_actual\_str_`);` | the two C strings have the same content, ignoring case | | `ASSERT_STRCASENE(`_str1_`, `_str2_`);`| `EXPECT_STRCASENE(`_str1_`, `_str2_`);` | the two C strings have different content, ignoring case | Note that "CASE" in an assertion name means that case is ignored. `*STREQ*` and `*STRNE*` also accept wide C strings (`wchar_t*`). If a comparison of two wide strings fails, their values will be printed as UTF-8 narrow strings. A `NULL` pointer and an empty string are considered _different_. _Availability_: Linux, Windows, Mac. See also: For more string comparison tricks (substring, prefix, suffix, and regular expression matching, for example), see the [Advanced Google Test Guide](V1_7_AdvancedGuide.md). # Simple Tests # To create a test: 1. Use the `TEST()` macro to define and name a test function, These are ordinary C++ functions that don't return a value. 1. In this function, along with any valid C++ statements you want to include, use the various Google Test assertions to check values. 1. The test's result is determined by the assertions; if any assertion in the test fails (either fatally or non-fatally), or if the test crashes, the entire test fails. Otherwise, it succeeds. ``` TEST(test_case_name, test_name) { ... test body ... } ``` `TEST()` arguments go from general to specific. The _first_ argument is the name of the test case, and the _second_ argument is the test's name within the test case. Both names must be valid C++ identifiers, and they should not contain underscore (`_`). A test's _full name_ consists of its containing test case and its individual name. Tests from different test cases can have the same individual name. For example, let's take a simple integer function: ``` int Factorial(int n); // Returns the factorial of n ``` A test case for this function might look like: ``` // Tests factorial of 0. TEST(FactorialTest, HandlesZeroInput) { EXPECT_EQ(1, Factorial(0)); } // Tests factorial of positive numbers. TEST(FactorialTest, HandlesPositiveInput) { EXPECT_EQ(1, Factorial(1)); EXPECT_EQ(2, Factorial(2)); EXPECT_EQ(6, Factorial(3)); EXPECT_EQ(40320, Factorial(8)); } ``` Google Test groups the test results by test cases, so logically-related tests should be in the same test case; in other words, the first argument to their `TEST()` should be the same. In the above example, we have two tests, `HandlesZeroInput` and `HandlesPositiveInput`, that belong to the same test case `FactorialTest`. _Availability_: Linux, Windows, Mac. # Test Fixtures: Using the Same Data Configuration for Multiple Tests # If you find yourself writing two or more tests that operate on similar data, you can use a _test fixture_. It allows you to reuse the same configuration of objects for several different tests. To create a fixture, just: 1. Derive a class from `::testing::Test` . Start its body with `protected:` or `public:` as we'll want to access fixture members from sub-classes. 1. Inside the class, declare any objects you plan to use. 1. If necessary, write a default constructor or `SetUp()` function to prepare the objects for each test. A common mistake is to spell `SetUp()` as `Setup()` with a small `u` - don't let that happen to you. 1. If necessary, write a destructor or `TearDown()` function to release any resources you allocated in `SetUp()` . To learn when you should use the constructor/destructor and when you should use `SetUp()/TearDown()`, read this [FAQ entry](V1_7_FAQ.md#should-i-use-the-constructordestructor-of-the-test-fixture-or-the-set-uptear-down-function). 1. If needed, define subroutines for your tests to share. When using a fixture, use `TEST_F()` instead of `TEST()` as it allows you to access objects and subroutines in the test fixture: ``` TEST_F(test_case_name, test_name) { ... test body ... } ``` Like `TEST()`, the first argument is the test case name, but for `TEST_F()` this must be the name of the test fixture class. You've probably guessed: `_F` is for fixture. Unfortunately, the C++ macro system does not allow us to create a single macro that can handle both types of tests. Using the wrong macro causes a compiler error. Also, you must first define a test fixture class before using it in a `TEST_F()`, or you'll get the compiler error "`virtual outside class declaration`". For each test defined with `TEST_F()`, Google Test will: 1. Create a _fresh_ test fixture at runtime 1. Immediately initialize it via `SetUp()` , 1. Run the test 1. Clean up by calling `TearDown()` 1. Delete the test fixture. Note that different tests in the same test case have different test fixture objects, and Google Test always deletes a test fixture before it creates the next one. Google Test does not reuse the same test fixture for multiple tests. Any changes one test makes to the fixture do not affect other tests. As an example, let's write tests for a FIFO queue class named `Queue`, which has the following interface: ``` template // E is the element type. class Queue { public: Queue(); void Enqueue(const E& element); E* Dequeue(); // Returns NULL if the queue is empty. size_t size() const; ... }; ``` First, define a fixture class. By convention, you should give it the name `FooTest` where `Foo` is the class being tested. ``` class QueueTest : public ::testing::Test { protected: virtual void SetUp() { q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // virtual void TearDown() {} Queue q0_; Queue q1_; Queue q2_; }; ``` In this case, `TearDown()` is not needed since we don't have to clean up after each test, other than what's already done by the destructor. Now we'll write tests using `TEST_F()` and this fixture. ``` TEST_F(QueueTest, IsEmptyInitially) { EXPECT_EQ(0, q0_.size()); } TEST_F(QueueTest, DequeueWorks) { int* n = q0_.Dequeue(); EXPECT_EQ(NULL, n); n = q1_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(1, *n); EXPECT_EQ(0, q1_.size()); delete n; n = q2_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(2, *n); EXPECT_EQ(1, q2_.size()); delete n; } ``` The above uses both `ASSERT_*` and `EXPECT_*` assertions. The rule of thumb is to use `EXPECT_*` when you want the test to continue to reveal more errors after the assertion failure, and use `ASSERT_*` when continuing after failure doesn't make sense. For example, the second assertion in the `Dequeue` test is `ASSERT_TRUE(n != NULL)`, as we need to dereference the pointer `n` later, which would lead to a segfault when `n` is `NULL`. When these tests run, the following happens: 1. Google Test constructs a `QueueTest` object (let's call it `t1` ). 1. `t1.SetUp()` initializes `t1` . 1. The first test ( `IsEmptyInitially` ) runs on `t1` . 1. `t1.TearDown()` cleans up after the test finishes. 1. `t1` is destructed. 1. The above steps are repeated on another `QueueTest` object, this time running the `DequeueWorks` test. _Availability_: Linux, Windows, Mac. _Note_: Google Test automatically saves all _Google Test_ flags when a test object is constructed, and restores them when it is destructed. # Invoking the Tests # `TEST()` and `TEST_F()` implicitly register their tests with Google Test. So, unlike with many other C++ testing frameworks, you don't have to re-list all your defined tests in order to run them. After defining your tests, you can run them with `RUN_ALL_TESTS()` , which returns `0` if all the tests are successful, or `1` otherwise. Note that `RUN_ALL_TESTS()` runs _all tests_ in your link unit -- they can be from different test cases, or even different source files. When invoked, the `RUN_ALL_TESTS()` macro: 1. Saves the state of all Google Test flags. 1. Creates a test fixture object for the first test. 1. Initializes it via `SetUp()`. 1. Runs the test on the fixture object. 1. Cleans up the fixture via `TearDown()`. 1. Deletes the fixture. 1. Restores the state of all Google Test flags. 1. Repeats the above steps for the next test, until all tests have run. In addition, if the text fixture's constructor generates a fatal failure in step 2, there is no point for step 3 - 5 and they are thus skipped. Similarly, if step 3 generates a fatal failure, step 4 will be skipped. _Important_: You must not ignore the return value of `RUN_ALL_TESTS()`, or `gcc` will give you a compiler error. The rationale for this design is that the automated testing service determines whether a test has passed based on its exit code, not on its stdout/stderr output; thus your `main()` function must return the value of `RUN_ALL_TESTS()`. Also, you should call `RUN_ALL_TESTS()` only **once**. Calling it more than once conflicts with some advanced Google Test features (e.g. thread-safe death tests) and thus is not supported. _Availability_: Linux, Windows, Mac. # Writing the main() Function # You can start from this boilerplate: ``` #include "this/package/foo.h" #include "gtest/gtest.h" namespace { // The fixture for testing class Foo. class FooTest : public ::testing::Test { protected: // You can remove any or all of the following functions if its body // is empty. FooTest() { // You can do set-up work for each test here. } virtual ~FooTest() { // You can do clean-up work that doesn't throw exceptions here. } // If the constructor and destructor are not enough for setting up // and cleaning up each test, you can define the following methods: virtual void SetUp() { // Code here will be called immediately after the constructor (right // before each test). } virtual void TearDown() { // Code here will be called immediately after each test (right // before the destructor). } // Objects declared here can be used by all tests in the test case for Foo. }; // Tests that the Foo::Bar() method does Abc. TEST_F(FooTest, MethodBarDoesAbc) { const string input_filepath = "this/package/testdata/myinputfile.dat"; const string output_filepath = "this/package/testdata/myoutputfile.dat"; Foo f; EXPECT_EQ(0, f.Bar(input_filepath, output_filepath)); } // Tests that Foo does Xyz. TEST_F(FooTest, DoesXyz) { // Exercises the Xyz feature of Foo. } } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ``` The `::testing::InitGoogleTest()` function parses the command line for Google Test flags, and removes all recognized flags. This allows the user to control a test program's behavior via various flags, which we'll cover in [AdvancedGuide](V1_7_AdvancedGuide.md). You must call this function before calling `RUN_ALL_TESTS()`, or the flags won't be properly initialized. On Windows, `InitGoogleTest()` also works with wide strings, so it can be used in programs compiled in `UNICODE` mode as well. But maybe you think that writing all those main() functions is too much work? We agree with you completely and that's why Google Test provides a basic implementation of main(). If it fits your needs, then just link your test with gtest\_main library and you are good to go. ## Important note for Visual C++ users ## If you put your tests into a library and your `main()` function is in a different library or in your .exe file, those tests will not run. The reason is a [bug](https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&siteid=210) in Visual C++. When you define your tests, Google Test creates certain static objects to register them. These objects are not referenced from elsewhere but their constructors are still supposed to run. When Visual C++ linker sees that nothing in the library is referenced from other places it throws the library out. You have to reference your library with tests from your main program to keep the linker from discarding it. Here is how to do it. Somewhere in your library code declare a function: ``` __declspec(dllexport) int PullInMyLibrary() { return 0; } ``` If you put your tests in a static library (not DLL) then `__declspec(dllexport)` is not required. Now, in your main program, write a code that invokes that function: ``` int PullInMyLibrary(); static int dummy = PullInMyLibrary(); ``` This will keep your tests referenced and will make them register themselves at startup. In addition, if you define your tests in a static library, add `/OPT:NOREF` to your main program linker options. If you use MSVC++ IDE, go to your .exe project properties/Configuration Properties/Linker/Optimization and set References setting to `Keep Unreferenced Data (/OPT:NOREF)`. This will keep Visual C++ linker from discarding individual symbols generated by your tests from the final executable. There is one more pitfall, though. If you use Google Test as a static library (that's how it is defined in gtest.vcproj) your tests must also reside in a static library. If you have to have them in a DLL, you _must_ change Google Test to build into a DLL as well. Otherwise your tests will not run correctly or will not run at all. The general conclusion here is: make your life easier - do not write your tests in libraries! # Where to Go from Here # Congratulations! You've learned the Google Test basics. You can start writing and running Google Test tests, read some [samples](V1_7_Samples.md), or continue with [AdvancedGuide](V1_7_AdvancedGuide.md), which describes many more useful Google Test features. # Known Limitations # Google Test is designed to be thread-safe. The implementation is thread-safe on systems where the `pthreads` library is available. It is currently _unsafe_ to use Google Test assertions from two threads concurrently on other systems (e.g. Windows). In most tests this is not an issue as usually the assertions are done in the main thread. If you want to help, you can volunteer to implement the necessary synchronization primitives in `gtest-port.h` for your platform. assimp-4.1.0/contrib/gtest/docs/V1_5_FAQ.md0000644002537200234200000011103313213503245020514 0ustar zmoelnigiemusers If you cannot find the answer to your question here, and you have read [Primer](V1_5_Primer.md) and [AdvancedGuide](V1_5_AdvancedGuide.md), send it to googletestframework@googlegroups.com. ## Why should I use Google Test instead of my favorite C++ testing framework? ## First, let's say clearly that we don't want to get into the debate of which C++ testing framework is **the best**. There exist many fine frameworks for writing C++ tests, and we have tremendous respect for the developers and users of them. We don't think there is (or will be) a single best framework - you have to pick the right tool for the particular task you are tackling. We created Google Test because we couldn't find the right combination of features and conveniences in an existing framework to satisfy _our_ needs. The following is a list of things that _we_ like about Google Test. We don't claim them to be unique to Google Test - rather, the combination of them makes Google Test the choice for us. We hope this list can help you decide whether it is for you too. * Google Test is designed to be portable. It works where many STL types (e.g. `std::string` and `std::vector`) don't compile. It doesn't require exceptions or RTTI. As a result, it runs on Linux, Mac OS X, Windows and several embedded operating systems. * Nonfatal assertions (`EXPECT_*`) have proven to be great time savers, as they allow a test to report multiple failures in a single edit-compile-test cycle. * It's easy to write assertions that generate informative messages: you just use the stream syntax to append any additional information, e.g. `ASSERT_EQ(5, Foo(i)) << " where i = " << i;`. It doesn't require a new set of macros or special functions. * Google Test automatically detects your tests and doesn't require you to enumerate them in order to run them. * No framework can anticipate all your needs, so Google Test provides `EXPECT_PRED*` to make it easy to extend your assertion vocabulary. For a nicer syntax, you can define your own assertion macros trivially in terms of `EXPECT_PRED*`. * Death tests are pretty handy for ensuring that your asserts in production code are triggered by the right conditions. * `SCOPED_TRACE` helps you understand the context of an assertion failure when it comes from inside a sub-routine or loop. * You can decide which tests to run using name patterns. This saves time when you want to quickly reproduce a test failure. ## How do I generate 64-bit binaries on Windows (using Visual Studio 2008)? ## (Answered by Trevor Robinson) Load the supplied Visual Studio solution file, either `msvc\gtest-md.sln` or `msvc\gtest.sln`. Go through the migration wizard to migrate the solution and project files to Visual Studio 2008. Select `Configuration Manager...` from the `Build` menu. Select `` from the `Active solution platform` dropdown. Select `x64` from the new platform dropdown, leave `Copy settings from` set to `Win32` and `Create new project platforms` checked, then click `OK`. You now have `Win32` and `x64` platform configurations, selectable from the `Standard` toolbar, which allow you to toggle between building 32-bit or 64-bit binaries (or both at once using Batch Build). In order to prevent build output files from overwriting one another, you'll need to change the `Intermediate Directory` settings for the newly created platform configuration across all the projects. To do this, multi-select (e.g. using shift-click) all projects (but not the solution) in the `Solution Explorer`. Right-click one of them and select `Properties`. In the left pane, select `Configuration Properties`, and from the `Configuration` dropdown, select `All Configurations`. Make sure the selected platform is `x64`. For the `Intermediate Directory` setting, change the value from `$(PlatformName)\$(ConfigurationName)` to `$(OutDir)\$(ProjectName)`. Click `OK` and then build the solution. When the build is complete, the 64-bit binaries will be in the `msvc\x64\Debug` directory. ## Can I use Google Test on MinGW? ## We haven't tested this ourselves, but Per Abrahamsen reported that he was able to compile and install Google Test successfully when using MinGW from Cygwin. You'll need to configure it with: `PATH/TO/configure CC="gcc -mno-cygwin" CXX="g++ -mno-cygwin"` You should be able to replace the `-mno-cygwin` option with direct links to the real MinGW binaries, but we haven't tried that. Caveats: * There are many warnings when compiling. * `make check` will produce some errors as not all tests for Google Test itself are compatible with MinGW. We also have reports on successful cross compilation of Google Test MinGW binaries on Linux using [these instructions](http://wiki.wxwidgets.org/Cross-Compiling_Under_Linux#Cross-compiling_under_Linux_for_MS_Windows) on the WxWidgets site. Please contact `googletestframework@googlegroups.com` if you are interested in improving the support for MinGW. ## Why does Google Test support EXPECT\_EQ(NULL, ptr) and ASSERT\_EQ(NULL, ptr) but not EXPECT\_NE(NULL, ptr) and ASSERT\_NE(NULL, ptr)? ## Due to some peculiarity of C++, it requires some non-trivial template meta programming tricks to support using `NULL` as an argument of the `EXPECT_XX()` and `ASSERT_XX()` macros. Therefore we only do it where it's most needed (otherwise we make the implementation of Google Test harder to maintain and more error-prone than necessary). The `EXPECT_EQ()` macro takes the _expected_ value as its first argument and the _actual_ value as the second. It's reasonable that someone wants to write `EXPECT_EQ(NULL, some_expression)`, and this indeed was requested several times. Therefore we implemented it. The need for `EXPECT_NE(NULL, ptr)` isn't nearly as strong. When the assertion fails, you already know that `ptr` must be `NULL`, so it doesn't add any information to print ptr in this case. That means `EXPECT_TRUE(ptr ! NULL)` works just as well. If we were to support `EXPECT_NE(NULL, ptr)`, for consistency we'll have to support `EXPECT_NE(ptr, NULL)` as well, as unlike `EXPECT_EQ`, we don't have a convention on the order of the two arguments for `EXPECT_NE`. This means using the template meta programming tricks twice in the implementation, making it even harder to understand and maintain. We believe the benefit doesn't justify the cost. Finally, with the growth of Google Mock's [matcher](../../CookBook.md#using-matchers-in-google-test-assertions) library, we are encouraging people to use the unified `EXPECT_THAT(value, matcher)` syntax more often in tests. One significant advantage of the matcher approach is that matchers can be easily combined to form new matchers, while the `EXPECT_NE`, etc, macros cannot be easily combined. Therefore we want to invest more in the matchers than in the `EXPECT_XX()` macros. ## Does Google Test support running tests in parallel? ## Test runners tend to be tightly coupled with the build/test environment, and Google Test doesn't try to solve the problem of running tests in parallel. Instead, we tried to make Google Test work nicely with test runners. For example, Google Test's XML report contains the time spent on each test, and its `gtest_list_tests` and `gtest_filter` flags can be used for splitting the execution of test methods into multiple processes. These functionalities can help the test runner run the tests in parallel. ## Why don't Google Test run the tests in different threads to speed things up? ## It's difficult to write thread-safe code. Most tests are not written with thread-safety in mind, and thus may not work correctly in a multi-threaded setting. If you think about it, it's already hard to make your code work when you know what other threads are doing. It's much harder, and sometimes even impossible, to make your code work when you don't know what other threads are doing (remember that test methods can be added, deleted, or modified after your test was written). If you want to run the tests in parallel, you'd better run them in different processes. ## Why aren't Google Test assertions implemented using exceptions? ## Our original motivation was to be able to use Google Test in projects that disable exceptions. Later we realized some additional benefits of this approach: 1. Throwing in a destructor is undefined behavior in C++. Not using exceptions means Google Test's assertions are safe to use in destructors. 1. The `EXPECT_*` family of macros will continue even after a failure, allowing multiple failures in a `TEST` to be reported in a single run. This is a popular feature, as in C++ the edit-compile-test cycle is usually quite long and being able to fixing more than one thing at a time is a blessing. 1. If assertions are implemented using exceptions, a test may falsely ignore a failure if it's caught by user code: ``` try { ... ASSERT_TRUE(...) ... } catch (...) { ... } ``` The above code will pass even if the `ASSERT_TRUE` throws. While it's unlikely for someone to write this in a test, it's possible to run into this pattern when you write assertions in callbacks that are called by the code under test. The downside of not using exceptions is that `ASSERT_*` (implemented using `return`) will only abort the current function, not the current `TEST`. ## Why do we use two different macros for tests with and without fixtures? ## Unfortunately, C++'s macro system doesn't allow us to use the same macro for both cases. One possibility is to provide only one macro for tests with fixtures, and require the user to define an empty fixture sometimes: ``` class FooTest : public ::testing::Test {}; TEST_F(FooTest, DoesThis) { ... } ``` or ``` typedef ::testing::Test FooTest; TEST_F(FooTest, DoesThat) { ... } ``` Yet, many people think this is one line too many. :-) Our goal was to make it really easy to write tests, so we tried to make simple tests trivial to create. That means using a separate macro for such tests. We think neither approach is ideal, yet either of them is reasonable. In the end, it probably doesn't matter much either way. ## Why don't we use structs as test fixtures? ## We like to use structs only when representing passive data. This distinction between structs and classes is good for documenting the intent of the code's author. Since test fixtures have logic like `SetUp()` and `TearDown()`, they are better defined as classes. ## Why are death tests implemented as assertions instead of using a test runner? ## Our goal was to make death tests as convenient for a user as C++ possibly allows. In particular: * The runner-style requires to split the information into two pieces: the definition of the death test itself, and the specification for the runner on how to run the death test and what to expect. The death test would be written in C++, while the runner spec may or may not be. A user needs to carefully keep the two in sync. `ASSERT_DEATH(statement, expected_message)` specifies all necessary information in one place, in one language, without boilerplate code. It is very declarative. * `ASSERT_DEATH` has a similar syntax and error-reporting semantics as other Google Test assertions, and thus is easy to learn. * `ASSERT_DEATH` can be mixed with other assertions and other logic at your will. You are not limited to one death test per test method. For example, you can write something like: ``` if (FooCondition()) { ASSERT_DEATH(Bar(), "blah"); } else { ASSERT_EQ(5, Bar()); } ``` If you prefer one death test per test method, you can write your tests in that style too, but we don't want to impose that on the users. The fewer artificial limitations the better. * `ASSERT_DEATH` can reference local variables in the current function, and you can decide how many death tests you want based on run-time information. For example, ``` const int count = GetCount(); // Only known at run time. for (int i = 1; i <= count; i++) { ASSERT_DEATH({ double* buffer = new double[i]; ... initializes buffer ... Foo(buffer, i) }, "blah blah"); } ``` The runner-based approach tends to be more static and less flexible, or requires more user effort to get this kind of flexibility. Another interesting thing about `ASSERT_DEATH` is that it calls `fork()` to create a child process to run the death test. This is lightening fast, as `fork()` uses copy-on-write pages and incurs almost zero overhead, and the child process starts from the user-supplied statement directly, skipping all global and local initialization and any code leading to the given statement. If you launch the child process from scratch, it can take seconds just to load everything and start running if the test links to many libraries dynamically. ## My death test modifies some state, but the change seems lost after the death test finishes. Why? ## Death tests (`EXPECT_DEATH`, etc) are executed in a sub-process s.t. the expected crash won't kill the test program (i.e. the parent process). As a result, any in-memory side effects they incur are observable in their respective sub-processes, but not in the parent process. You can think of them as running in a parallel universe, more or less. ## The compiler complains about "undefined references" to some static const member variables, but I did define them in the class body. What's wrong? ## If your class has a static data member: ``` // foo.h class Foo { ... static const int kBar = 100; }; ``` You also need to define it _outside_ of the class body in `foo.cc`: ``` const int Foo::kBar; // No initializer here. ``` Otherwise your code is **invalid C++**, and may break in unexpected ways. In particular, using it in Google Test comparison assertions (`EXPECT_EQ`, etc) will generate an "undefined reference" linker error. ## I have an interface that has several implementations. Can I write a set of tests once and repeat them over all the implementations? ## Google Test doesn't yet have good support for this kind of tests, or data-driven tests in general. We hope to be able to make improvements in this area soon. ## Can I derive a test fixture from another? ## Yes. Each test fixture has a corresponding and same named test case. This means only one test case can use a particular fixture. Sometimes, however, multiple test cases may want to use the same or slightly different fixtures. For example, you may want to make sure that all of a GUI library's test cases don't leak important system resources like fonts and brushes. In Google Test, you share a fixture among test cases by putting the shared logic in a base test fixture, then deriving from that base a separate fixture for each test case that wants to use this common logic. You then use `TEST_F()` to write tests using each derived fixture. Typically, your code looks like this: ``` // Defines a base test fixture. class BaseTest : public ::testing::Test { protected: ... }; // Derives a fixture FooTest from BaseTest. class FooTest : public BaseTest { protected: virtual void SetUp() { BaseTest::SetUp(); // Sets up the base fixture first. ... additional set-up work ... } virtual void TearDown() { ... clean-up work for FooTest ... BaseTest::TearDown(); // Remember to tear down the base fixture // after cleaning up FooTest! } ... functions and variables for FooTest ... }; // Tests that use the fixture FooTest. TEST_F(FooTest, Bar) { ... } TEST_F(FooTest, Baz) { ... } ... additional fixtures derived from BaseTest ... ``` If necessary, you can continue to derive test fixtures from a derived fixture. Google Test has no limit on how deep the hierarchy can be. For a complete example using derived test fixtures, see `samples/sample5_unittest.cc`. ## My compiler complains "void value not ignored as it ought to be." What does this mean? ## You're probably using an `ASSERT_*()` in a function that doesn't return `void`. `ASSERT_*()` can only be used in `void` functions. ## My death test hangs (or seg-faults). How do I fix it? ## In Google Test, death tests are run in a child process and the way they work is delicate. To write death tests you really need to understand how they work. Please make sure you have read this. In particular, death tests don't like having multiple threads in the parent process. So the first thing you can try is to eliminate creating threads outside of `EXPECT_DEATH()`. Sometimes this is impossible as some library you must use may be creating threads before `main()` is even reached. In this case, you can try to minimize the chance of conflicts by either moving as many activities as possible inside `EXPECT_DEATH()` (in the extreme case, you want to move everything inside), or leaving as few things as possible in it. Also, you can try to set the death test style to `"threadsafe"`, which is safer but slower, and see if it helps. If you go with thread-safe death tests, remember that they rerun the test program from the beginning in the child process. Therefore make sure your program can run side-by-side with itself and is deterministic. In the end, this boils down to good concurrent programming. You have to make sure that there is no race conditions or dead locks in your program. No silver bullet - sorry! ## Should I use the constructor/destructor of the test fixture or the set-up/tear-down function? ## The first thing to remember is that Google Test does not reuse the same test fixture object across multiple tests. For each `TEST_F`, Google Test will create a fresh test fixture object, _immediately_ call `SetUp()`, run the test, call `TearDown()`, and then _immediately_ delete the test fixture object. Therefore, there is no need to write a `SetUp()` or `TearDown()` function if the constructor or destructor already does the job. You may still want to use `SetUp()/TearDown()` in the following cases: * If the tear-down operation could throw an exception, you must use `TearDown()` as opposed to the destructor, as throwing in a destructor leads to undefined behavior and usually will kill your program right away. Note that many standard libraries (like STL) may throw when exceptions are enabled in the compiler. Therefore you should prefer `TearDown()` if you want to write portable tests that work with or without exceptions. * The Google Test team is considering making the assertion macros throw on platforms where exceptions are enabled (e.g. Windows, Mac OS, and Linux client-side), which will eliminate the need for the user to propagate failures from a subroutine to its caller. Therefore, you shouldn't use Google Test assertions in a destructor if your code could run on such a platform. * In a constructor or destructor, you cannot make a virtual function call on this object. (You can call a method declared as virtual, but it will be statically bound.) Therefore, if you need to call a method that will be overriden in a derived class, you have to use `SetUp()/TearDown()`. ## The compiler complains "no matching function to call" when I use ASSERT\_PREDn. How do I fix it? ## If the predicate function you use in `ASSERT_PRED*` or `EXPECT_PRED*` is overloaded or a template, the compiler will have trouble figuring out which overloaded version it should use. `ASSERT_PRED_FORMAT*` and `EXPECT_PRED_FORMAT*` don't have this problem. If you see this error, you might want to switch to `(ASSERT|EXPECT)_PRED_FORMAT*`, which will also give you a better failure message. If, however, that is not an option, you can resolve the problem by explicitly telling the compiler which version to pick. For example, suppose you have ``` bool IsPositive(int n) { return n > 0; } bool IsPositive(double x) { return x > 0; } ``` you will get a compiler error if you write ``` EXPECT_PRED1(IsPositive, 5); ``` However, this will work: ``` EXPECT_PRED1(*static_cast*(IsPositive), 5); ``` (The stuff inside the angled brackets for the `static_cast` operator is the type of the function pointer for the `int`-version of `IsPositive()`.) As another example, when you have a template function ``` template bool IsNegative(T x) { return x < 0; } ``` you can use it in a predicate assertion like this: ``` ASSERT_PRED1(IsNegative**, -5); ``` Things are more interesting if your template has more than one parameters. The following won't compile: ``` ASSERT_PRED2(*GreaterThan*, 5, 0); ``` as the C++ pre-processor thinks you are giving `ASSERT_PRED2` 4 arguments, which is one more than expected. The workaround is to wrap the predicate function in parentheses: ``` ASSERT_PRED2(*(GreaterThan)*, 5, 0); ``` ## My compiler complains about "ignoring return value" when I call RUN\_ALL\_TESTS(). Why? ## Some people had been ignoring the return value of `RUN_ALL_TESTS()`. That is, instead of ``` return RUN_ALL_TESTS(); ``` they write ``` RUN_ALL_TESTS(); ``` This is wrong and dangerous. A test runner needs to see the return value of `RUN_ALL_TESTS()` in order to determine if a test has passed. If your `main()` function ignores it, your test will be considered successful even if it has a Google Test assertion failure. Very bad. To help the users avoid this dangerous bug, the implementation of `RUN_ALL_TESTS()` causes gcc to raise this warning, when the return value is ignored. If you see this warning, the fix is simple: just make sure its value is used as the return value of `main()`. ## My compiler complains that a constructor (or destructor) cannot return a value. What's going on? ## Due to a peculiarity of C++, in order to support the syntax for streaming messages to an `ASSERT_*`, e.g. ``` ASSERT_EQ(1, Foo()) << "blah blah" << foo; ``` we had to give up using `ASSERT*` and `FAIL*` (but not `EXPECT*` and `ADD_FAILURE*`) in constructors and destructors. The workaround is to move the content of your constructor/destructor to a private void member function, or switch to `EXPECT_*()` if that works. This section in the user's guide explains it. ## My set-up function is not called. Why? ## C++ is case-sensitive. It should be spelled as `SetUp()`. Did you spell it as `Setup()`? Similarly, sometimes people spell `SetUpTestCase()` as `SetupTestCase()` and wonder why it's never called. ## How do I jump to the line of a failure in Emacs directly? ## Google Test's failure message format is understood by Emacs and many other IDEs, like acme and XCode. If a Google Test message is in a compilation buffer in Emacs, then it's clickable. You can now hit `enter` on a message to jump to the corresponding source code, or use `C-x `` to jump to the next failure. ## I have several test cases which share the same test fixture logic, do I have to define a new test fixture class for each of them? This seems pretty tedious. ## You don't have to. Instead of ``` class FooTest : public BaseTest {}; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } class BarTest : public BaseTest {}; TEST_F(BarTest, Abc) { ... } TEST_F(BarTest, Def) { ... } ``` you can simply `typedef` the test fixtures: ``` typedef BaseTest FooTest; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } typedef BaseTest BarTest; TEST_F(BarTest, Abc) { ... } TEST_F(BarTest, Def) { ... } ``` ## The Google Test output is buried in a whole bunch of log messages. What do I do? ## The Google Test output is meant to be a concise and human-friendly report. If your test generates textual output itself, it will mix with the Google Test output, making it hard to read. However, there is an easy solution to this problem. Since most log messages go to stderr, we decided to let Google Test output go to stdout. This way, you can easily separate the two using redirection. For example: ``` ./my_test > googletest_output.txt ``` ## Why should I prefer test fixtures over global variables? ## There are several good reasons: 1. It's likely your test needs to change the states of its global variables. This makes it difficult to keep side effects from escaping one test and contaminating others, making debugging difficult. By using fixtures, each test has a fresh set of variables that's different (but with the same names). Thus, tests are kept independent of each other. 1. Global variables pollute the global namespace. 1. Test fixtures can be reused via subclassing, which cannot be done easily with global variables. This is useful if many test cases have something in common. ## How do I test private class members without writing FRIEND\_TEST()s? ## You should try to write testable code, which means classes should be easily tested from their public interface. One way to achieve this is the Pimpl idiom: you move all private members of a class into a helper class, and make all members of the helper class public. You have several other options that don't require using `FRIEND_TEST`: * Write the tests as members of the fixture class: ``` class Foo { friend class FooTest; ... }; class FooTest : public ::testing::Test { protected: ... void Test1() {...} // This accesses private members of class Foo. void Test2() {...} // So does this one. }; TEST_F(FooTest, Test1) { Test1(); } TEST_F(FooTest, Test2) { Test2(); } ``` * In the fixture class, write accessors for the tested class' private members, then use the accessors in your tests: ``` class Foo { friend class FooTest; ... }; class FooTest : public ::testing::Test { protected: ... T1 get_private_member1(Foo* obj) { return obj->private_member1_; } }; TEST_F(FooTest, Test1) { ... get_private_member1(x) ... } ``` * If the methods are declared **protected**, you can change their access level in a test-only subclass: ``` class YourClass { ... protected: // protected access for testability. int DoSomethingReturningInt(); ... }; // in the your_class_test.cc file: class TestableYourClass : public YourClass { ... public: using YourClass::DoSomethingReturningInt; // changes access rights ... }; TEST_F(YourClassTest, DoSomethingTest) { TestableYourClass obj; assertEquals(expected_value, obj.DoSomethingReturningInt()); } ``` ## How do I test private class static members without writing FRIEND\_TEST()s? ## We find private static methods clutter the header file. They are implementation details and ideally should be kept out of a .h. So often I make them free functions instead. Instead of: ``` // foo.h class Foo { ... private: static bool Func(int n); }; // foo.cc bool Foo::Func(int n) { ... } // foo_test.cc EXPECT_TRUE(Foo::Func(12345)); ``` You probably should better write: ``` // foo.h class Foo { ... }; // foo.cc namespace internal { bool Func(int n) { ... } } // foo_test.cc namespace internal { bool Func(int n); } EXPECT_TRUE(internal::Func(12345)); ``` ## I would like to run a test several times with different parameters. Do I need to write several similar copies of it? ## No. You can use a feature called [value-parameterized tests](V1_5_AdvancedGuide.md#Value_Parameterized_Tests) which lets you repeat your tests with different parameters, without defining it more than once. ## How do I test a file that defines main()? ## To test a `foo.cc` file, you need to compile and link it into your unit test program. However, when the file contains a definition for the `main()` function, it will clash with the `main()` of your unit test, and will result in a build error. The right solution is to split it into three files: 1. `foo.h` which contains the declarations, 1. `foo.cc` which contains the definitions except `main()`, and 1. `foo_main.cc` which contains nothing but the definition of `main()`. Then `foo.cc` can be easily tested. If you are adding tests to an existing file and don't want an intrusive change like this, there is a hack: just include the entire `foo.cc` file in your unit test. For example: ``` // File foo_unittest.cc // The headers section ... // Renames main() in foo.cc to make room for the unit test main() #define main FooMain #include "a/b/foo.cc" // The tests start here. ... ``` However, please remember this is a hack and should only be used as the last resort. ## What can the statement argument in ASSERT\_DEATH() be? ## `ASSERT_DEATH(_statement_, _regex_)` (or any death assertion macro) can be used wherever `_statement_` is valid. So basically `_statement_` can be any C++ statement that makes sense in the current context. In particular, it can reference global and/or local variables, and can be: * a simple function call (often the case), * a complex expression, or * a compound statement. > Some examples are shown here: ``` // A death test can be a simple function call. TEST(MyDeathTest, FunctionCall) { ASSERT_DEATH(Xyz(5), "Xyz failed"); } // Or a complex expression that references variables and functions. TEST(MyDeathTest, ComplexExpression) { const bool c = Condition(); ASSERT_DEATH((c ? Func1(0) : object2.Method("test")), "(Func1|Method) failed"); } // Death assertions can be used any where in a function. In // particular, they can be inside a loop. TEST(MyDeathTest, InsideLoop) { // Verifies that Foo(0), Foo(1), ..., and Foo(4) all die. for (int i = 0; i < 5; i++) { EXPECT_DEATH_M(Foo(i), "Foo has \\d+ errors", ::testing::Message() << "where i is " << i); } } // A death assertion can contain a compound statement. TEST(MyDeathTest, CompoundStatement) { // Verifies that at lease one of Bar(0), Bar(1), ..., and // Bar(4) dies. ASSERT_DEATH({ for (int i = 0; i < 5; i++) { Bar(i); } }, "Bar has \\d+ errors");} ``` `googletest_unittest.cc` contains more examples if you are interested. ## What syntax does the regular expression in ASSERT\_DEATH use? ## On POSIX systems, Google Test uses the POSIX Extended regular expression syntax (http://en.wikipedia.org/wiki/Regular_expression#POSIX_Extended_Regular_Expressions). On Windows, it uses a limited variant of regular expression syntax. For more details, see the [regular expression syntax](V1_5_AdvancedGuide.md#Regular_Expression_Syntax). ## I have a fixture class Foo, but TEST\_F(Foo, Bar) gives me error "no matching function for call to Foo::Foo()". Why? ## Google Test needs to be able to create objects of your test fixture class, so it must have a default constructor. Normally the compiler will define one for you. However, there are cases where you have to define your own: * If you explicitly declare a non-default constructor for class `Foo`, then you need to define a default constructor, even if it would be empty. * If `Foo` has a const non-static data member, then you have to define the default constructor _and_ initialize the const member in the initializer list of the constructor. (Early versions of `gcc` doesn't force you to initialize the const member. It's a bug that has been fixed in `gcc 4`.) ## Why does ASSERT\_DEATH complain about previous threads that were already joined? ## With the Linux pthread library, there is no turning back once you cross the line from single thread to multiple threads. The first time you create a thread, a manager thread is created in addition, so you get 3, not 2, threads. Later when the thread you create joins the main thread, the thread count decrements by 1, but the manager thread will never be killed, so you still have 2 threads, which means you cannot safely run a death test. The new NPTL thread library doesn't suffer from this problem, as it doesn't create a manager thread. However, if you don't control which machine your test runs on, you shouldn't depend on this. ## Why does Google Test require the entire test case, instead of individual tests, to be named FOODeathTest when it uses ASSERT\_DEATH? ## Google Test does not interleave tests from different test cases. That is, it runs all tests in one test case first, and then runs all tests in the next test case, and so on. Google Test does this because it needs to set up a test case before the first test in it is run, and tear it down afterwords. Splitting up the test case would require multiple set-up and tear-down processes, which is inefficient and makes the semantics unclean. If we were to determine the order of tests based on test name instead of test case name, then we would have a problem with the following situation: ``` TEST_F(FooTest, AbcDeathTest) { ... } TEST_F(FooTest, Uvw) { ... } TEST_F(BarTest, DefDeathTest) { ... } TEST_F(BarTest, Xyz) { ... } ``` Since `FooTest.AbcDeathTest` needs to run before `BarTest.Xyz`, and we don't interleave tests from different test cases, we need to run all tests in the `FooTest` case before running any test in the `BarTest` case. This contradicts with the requirement to run `BarTest.DefDeathTest` before `FooTest.Uvw`. ## But I don't like calling my entire test case FOODeathTest when it contains both death tests and non-death tests. What do I do? ## You don't have to, but if you like, you may split up the test case into `FooTest` and `FooDeathTest`, where the names make it clear that they are related: ``` class FooTest : public ::testing::Test { ... }; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } typedef FooTest FooDeathTest; TEST_F(FooDeathTest, Uvw) { ... EXPECT_DEATH(...) ... } TEST_F(FooDeathTest, Xyz) { ... ASSERT_DEATH(...) ... } ``` ## The compiler complains about "no match for 'operator<<'" when I use an assertion. What gives? ## If you use a user-defined type `FooType` in an assertion, you must make sure there is an `std::ostream& operator<<(std::ostream&, const FooType&)` function defined such that we can print a value of `FooType`. In addition, if `FooType` is declared in a name space, the `<<` operator also needs to be defined in the _same_ name space. ## How do I suppress the memory leak messages on Windows? ## Since the statically initialized Google Test singleton requires allocations on the heap, the Visual C++ memory leak detector will report memory leaks at the end of the program run. The easiest way to avoid this is to use the `_CrtMemCheckpoint` and `_CrtMemDumpAllObjectsSince` calls to not report any statically initialized heap objects. See MSDN for more details and additional heap check/debug routines. ## I am building my project with Google Test in Visual Studio and all I'm getting is a bunch of linker errors (or warnings). Help! ## You may get a number of the following linker error or warnings if you attempt to link your test project with the Google Test library when your project and the are not built using the same compiler settings. * LNK2005: symbol already defined in object * LNK4217: locally defined symbol 'symbol' imported in function 'function' * LNK4049: locally defined symbol 'symbol' imported The Google Test project (gtest.vcproj) has the Runtime Library option set to /MT (use multi-threaded static libraries, /MTd for debug). If your project uses something else, for example /MD (use multi-threaded DLLs, /MDd for debug), you need to change the setting in the Google Test project to match your project's. To update this setting open the project properties in the Visual Studio IDE then select the branch Configuration Properties | C/C++ | Code Generation and change the option "Runtime Library". You may also try using gtest-md.vcproj instead of gtest.vcproj. ## I put my tests in a library and Google Test doesn't run them. What's happening? ## Have you read a [warning](V1_5_Primer.md#important-note-for-visual-c-users) on the Google Test Primer page? ## I want to use Google Test with Visual Studio but don't know where to start. ## Many people are in your position and one of the posted his solution to our mailing list. Here is his link: http://hassanjamilahmad.blogspot.com/2009/07/gtest-starters-help.html. ## My question is not covered in your FAQ! ## If you cannot find the answer to your question in this FAQ, there are some other resources you can use: 1. read other [wiki pages](http://code.google.com/p/googletest/w/list), 1. search the mailing list [archive](http://groups.google.com/group/googletestframework/topics), 1. ask it on [googletestframework@googlegroups.com](mailto:googletestframework@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googletestframework) before you can post.). Please note that creating an issue in the [issue tracker](http://code.google.com/p/googletest/issues/list) is _not_ a good way to get your answer, as it is monitored infrequently by a very small number of people. When asking a question, it's helpful to provide as much of the following information as possible (people cannot help you if there's not enough information in your question): * the version (or the revision number if you check out from SVN directly) of Google Test you use (Google Test is under active development, so it's possible that your problem has been solved in a later version), * your operating system, * the name and version of your compiler, * the complete command line flags you give to your compiler, * the complete compiler error messages (if the question is about compilation), * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. assimp-4.1.0/contrib/gtest/docs/Samples.md0000644002537200234200000000246113213503245020723 0ustar zmoelnigiemusersIf you're like us, you'd like to look at some Google Test sample code. The [samples folder](../samples) has a number of well-commented samples showing how to use a variety of Google Test features. * [Sample #1](../samples/sample1_unittest.cc) shows the basic steps of using Google Test to test C++ functions. * [Sample #2](../samples/sample2_unittest.cc) shows a more complex unit test for a class with multiple member functions. * [Sample #3](../samples/sample3_unittest.cc) uses a test fixture. * [Sample #4](../samples/sample4_unittest.cc) is another basic example of using Google Test. * [Sample #5](../samples/sample5_unittest.cc) teaches how to reuse a test fixture in multiple test cases by deriving sub-fixtures from it. * [Sample #6](../samples/sample6_unittest.cc) demonstrates type-parameterized tests. * [Sample #7](../samples/sample7_unittest.cc) teaches the basics of value-parameterized tests. * [Sample #8](../samples/sample8_unittest.cc) shows using `Combine()` in value-parameterized tests. * [Sample #9](../samples/sample9_unittest.cc) shows use of the listener API to modify Google Test's console output and the use of its reflection API to inspect test results. * [Sample #10](../samples/sample10_unittest.cc) shows use of the listener API to implement a primitive memory leak checker. assimp-4.1.0/contrib/gtest/docs/V1_7_XcodeGuide.md0000644002537200234200000002005713213503245022134 0ustar zmoelnigiemusers This guide will explain how to use the Google Testing Framework in your Xcode projects on Mac OS X. This tutorial begins by quickly explaining what to do for experienced users. After the quick start, the guide goes provides additional explanation about each step. # Quick Start # Here is the quick guide for using Google Test in your Xcode project. 1. Download the source from the [website](http://code.google.com/p/googletest) using this command: `svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only` 1. Open up the `gtest.xcodeproj` in the `googletest-read-only/xcode/` directory and build the gtest.framework. 1. Create a new "Shell Tool" target in your Xcode project called something like "UnitTests" 1. Add the gtest.framework to your project and add it to the "Link Binary with Libraries" build phase of "UnitTests" 1. Add your unit test source code to the "Compile Sources" build phase of "UnitTests" 1. Edit the "UnitTests" executable and add an environment variable named "DYLD\_FRAMEWORK\_PATH" with a value equal to the path to the framework containing the gtest.framework relative to the compiled executable. 1. Build and Go The following sections further explain each of the steps listed above in depth, describing in more detail how to complete it including some variations. # Get the Source # Currently, the gtest.framework discussed here isn't available in a tagged release of Google Test, it is only available in the trunk. As explained at the Google Test [site](http://code.google.com/p/googletest/source/checkout">svn), you can get the code from anonymous SVN with this command: ``` svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only ``` Alternatively, if you are working with Subversion in your own code base, you can add Google Test as an external dependency to your own Subversion repository. By following this approach, everyone that checks out your svn repository will also receive a copy of Google Test (a specific version, if you wish) without having to check it out explicitly. This makes the set up of your project simpler and reduces the copied code in the repository. To use `svn:externals`, decide where you would like to have the external source reside. You might choose to put the external source inside the trunk, because you want it to be part of the branch when you make a release. However, keeping it outside the trunk in a version-tagged directory called something like `third-party/googletest/1.0.1`, is another option. Once the location is established, use `svn propedit svn:externals _directory_` to set the svn:externals property on a directory in your repository. This directory won't contain the code, but be its versioned parent directory. The command `svn propedit` will bring up your Subversion editor, making editing the long, (potentially multi-line) property simpler. This same method can be used to check out a tagged branch, by using the appropriate URL (e.g. `http://googletest.googlecode.com/svn/tags/release-1.0.1`). Additionally, the svn:externals property allows the specification of a particular revision of the trunk with the `-r_##_` option (e.g. `externals/src/googletest -r60 http://googletest.googlecode.com/svn/trunk`). Here is an example of using the svn:externals properties on a trunk (read via `svn propget`) of a project. This value checks out a copy of Google Test into the `trunk/externals/src/googletest/` directory. ``` [Computer:svn] user$ svn propget svn:externals trunk externals/src/googletest http://googletest.googlecode.com/svn/trunk ``` # Add the Framework to Your Project # The next step is to build and add the gtest.framework to your own project. This guide describes two common ways below. * **Option 1** --- The simplest way to add Google Test to your own project, is to open gtest.xcodeproj (found in the xcode/ directory of the Google Test trunk) and build the framework manually. Then, add the built framework into your project using the "Add->Existing Framework..." from the context menu or "Project->Add..." from the main menu. The gtest.framework is relocatable and contains the headers and object code that you'll need to make tests. This method requires rebuilding every time you upgrade Google Test in your project. * **Option 2** --- If you are going to be living off the trunk of Google Test, incorporating its latest features into your unit tests (or are a Google Test developer yourself). You'll want to rebuild the framework every time the source updates. to do this, you'll need to add the gtest.xcodeproj file, not the framework itself, to your own Xcode project. Then, from the build products that are revealed by the project's disclosure triangle, you can find the gtest.framework, which can be added to your targets (discussed below). # Make a Test Target # To start writing tests, make a new "Shell Tool" target. This target template is available under BSD, Cocoa, or Carbon. Add your unit test source code to the "Compile Sources" build phase of the target. Next, you'll want to add gtest.framework in two different ways, depending upon which option you chose above. * **Option 1** --- During compilation, Xcode will need to know that you are linking against the gtest.framework. Add the gtest.framework to the "Link Binary with Libraries" build phase of your test target. This will include the Google Test headers in your header search path, and will tell the linker where to find the library. * **Option 2** --- If your working out of the trunk, you'll also want to add gtest.framework to your "Link Binary with Libraries" build phase of your test target. In addition, you'll want to add the gtest.framework as a dependency to your unit test target. This way, Xcode will make sure that gtest.framework is up to date, every time your build your target. Finally, if you don't share build directories with Google Test, you'll have to copy the gtest.framework into your own build products directory using a "Run Script" build phase. # Set Up the Executable Run Environment # Since the unit test executable is a shell tool, it doesn't have a bundle with a `Contents/Frameworks` directory, in which to place gtest.framework. Instead, the dynamic linker must be told at runtime to search for the framework in another location. This can be accomplished by setting the "DYLD\_FRAMEWORK\_PATH" environment variable in the "Edit Active Executable ..." Arguments tab, under "Variables to be set in the environment:". The path for this value is the path (relative or absolute) of the directory containing the gtest.framework. If you haven't set up the DYLD\_FRAMEWORK\_PATH, correctly, you might get a message like this: ``` [Session started at 2008-08-15 06:23:57 -0600.] dyld: Library not loaded: @loader_path/../Frameworks/gtest.framework/Versions/A/gtest Referenced from: /Users/username/Documents/Sandbox/gtestSample/build/Debug/WidgetFrameworkTest Reason: image not found ``` To correct this problem, got to the directory containing the executable named in "Referenced from:" value in the error message above. Then, with the terminal in this location, find the relative path to the directory containing the gtest.framework. That is the value you'll need to set as the DYLD\_FRAMEWORK\_PATH. # Build and Go # Now, when you click "Build and Go", the test will be executed. Dumping out something like this: ``` [Session started at 2008-08-06 06:36:13 -0600.] [==========] Running 2 tests from 1 test case. [----------] Global test environment set-up. [----------] 2 tests from WidgetInitializerTest [ RUN ] WidgetInitializerTest.TestConstructor [ OK ] WidgetInitializerTest.TestConstructor [ RUN ] WidgetInitializerTest.TestConversion [ OK ] WidgetInitializerTest.TestConversion [----------] Global test environment tear-down [==========] 2 tests from 1 test case ran. [ PASSED ] 2 tests. The Debugger has exited with status 0. ``` # Summary # Unit testing is a valuable way to ensure your data model stays valid even during rapid development or refactoring. The Google Testing Framework is a great unit testing framework for C and C++ which integrates well with an Xcode development environment.assimp-4.1.0/contrib/gtest/docs/V1_6_FAQ.md0000644002537200234200000013164213213503245020525 0ustar zmoelnigiemusers If you cannot find the answer to your question here, and you have read [Primer](V1_6_Primer.md) and [AdvancedGuide](V1_6_AdvancedGuide.md), send it to googletestframework@googlegroups.com. ## Why should I use Google Test instead of my favorite C++ testing framework? ## First, let us say clearly that we don't want to get into the debate of which C++ testing framework is **the best**. There exist many fine frameworks for writing C++ tests, and we have tremendous respect for the developers and users of them. We don't think there is (or will be) a single best framework - you have to pick the right tool for the particular task you are tackling. We created Google Test because we couldn't find the right combination of features and conveniences in an existing framework to satisfy _our_ needs. The following is a list of things that _we_ like about Google Test. We don't claim them to be unique to Google Test - rather, the combination of them makes Google Test the choice for us. We hope this list can help you decide whether it is for you too. * Google Test is designed to be portable: it doesn't require exceptions or RTTI; it works around various bugs in various compilers and environments; etc. As a result, it works on Linux, Mac OS X, Windows and several embedded operating systems. * Nonfatal assertions (`EXPECT_*`) have proven to be great time savers, as they allow a test to report multiple failures in a single edit-compile-test cycle. * It's easy to write assertions that generate informative messages: you just use the stream syntax to append any additional information, e.g. `ASSERT_EQ(5, Foo(i)) << " where i = " << i;`. It doesn't require a new set of macros or special functions. * Google Test automatically detects your tests and doesn't require you to enumerate them in order to run them. * Death tests are pretty handy for ensuring that your asserts in production code are triggered by the right conditions. * `SCOPED_TRACE` helps you understand the context of an assertion failure when it comes from inside a sub-routine or loop. * You can decide which tests to run using name patterns. This saves time when you want to quickly reproduce a test failure. * Google Test can generate XML test result reports that can be parsed by popular continuous build system like Hudson. * Simple things are easy in Google Test, while hard things are possible: in addition to advanced features like [global test environments](V1_6_AdvancedGuide.md#Global_Set-Up_and_Tear-Down) and tests parameterized by [values](V1_6_AdvancedGuide.md#value-parameterized-tests) or [types](V1_6_AdvancedGuide.md#typed-tests), Google Test supports various ways for the user to extend the framework -- if Google Test doesn't do something out of the box, chances are that a user can implement the feature using Google Test's public API, without changing Google Test itself. In particular, you can: * expand your testing vocabulary by defining [custom predicates](V1_6_AdvancedGuide.md#predicate-assertions-for-better-error-messages), * teach Google Test how to [print your types](V1_6_AdvancedGuide.md#teaching-google-test-how-to-print-your-values), * define your own testing macros or utilities and verify them using Google Test's [Service Provider Interface](V1_6_AdvancedGuide.md#catching-failures), and * reflect on the test cases or change the test output format by intercepting the [test events](V1_6_AdvancedGuide.md#extending-google-test-by-handling-test-events). ## I'm getting warnings when compiling Google Test. Would you fix them? ## We strive to minimize compiler warnings Google Test generates. Before releasing a new version, we test to make sure that it doesn't generate warnings when compiled using its CMake script on Windows, Linux, and Mac OS. Unfortunately, this doesn't mean you are guaranteed to see no warnings when compiling Google Test in your environment: * You may be using a different compiler as we use, or a different version of the same compiler. We cannot possibly test for all compilers. * You may be compiling on a different platform as we do. * Your project may be using different compiler flags as we do. It is not always possible to make Google Test warning-free for everyone. Or, it may not be desirable if the warning is rarely enabled and fixing the violations makes the code more complex. If you see warnings when compiling Google Test, we suggest that you use the `-isystem` flag (assuming your are using GCC) to mark Google Test headers as system headers. That'll suppress warnings from Google Test headers. ## Why should not test case names and test names contain underscore? ## Underscore (`_`) is special, as C++ reserves the following to be used by the compiler and the standard library: 1. any identifier that starts with an `_` followed by an upper-case letter, and 1. any identifier that containers two consecutive underscores (i.e. `__`) _anywhere_ in its name. User code is _prohibited_ from using such identifiers. Now let's look at what this means for `TEST` and `TEST_F`. Currently `TEST(TestCaseName, TestName)` generates a class named `TestCaseName_TestName_Test`. What happens if `TestCaseName` or `TestName` contains `_`? 1. If `TestCaseName` starts with an `_` followed by an upper-case letter (say, `_Foo`), we end up with `_Foo_TestName_Test`, which is reserved and thus invalid. 1. If `TestCaseName` ends with an `_` (say, `Foo_`), we get `Foo__TestName_Test`, which is invalid. 1. If `TestName` starts with an `_` (say, `_Bar`), we get `TestCaseName__Bar_Test`, which is invalid. 1. If `TestName` ends with an `_` (say, `Bar_`), we get `TestCaseName_Bar__Test`, which is invalid. So clearly `TestCaseName` and `TestName` cannot start or end with `_` (Actually, `TestCaseName` can start with `_` -- as long as the `_` isn't followed by an upper-case letter. But that's getting complicated. So for simplicity we just say that it cannot start with `_`.). It may seem fine for `TestCaseName` and `TestName` to contain `_` in the middle. However, consider this: ``` TEST(Time, Flies_Like_An_Arrow) { ... } TEST(Time_Flies, Like_An_Arrow) { ... } ``` Now, the two `TEST`s will both generate the same class (`Time_Files_Like_An_Arrow_Test`). That's not good. So for simplicity, we just ask the users to avoid `_` in `TestCaseName` and `TestName`. The rule is more constraining than necessary, but it's simple and easy to remember. It also gives Google Test some wiggle room in case its implementation needs to change in the future. If you violate the rule, there may not be immediately consequences, but your test may (just may) break with a new compiler (or a new version of the compiler you are using) or with a new version of Google Test. Therefore it's best to follow the rule. ## Why is it not recommended to install a pre-compiled copy of Google Test (for example, into /usr/local)? ## In the early days, we said that you could install compiled Google Test libraries on `*`nix systems using `make install`. Then every user of your machine can write tests without recompiling Google Test. This seemed like a good idea, but it has a got-cha: every user needs to compile his tests using the _same_ compiler flags used to compile the installed Google Test libraries; otherwise he may run into undefined behaviors (i.e. the tests can behave strangely and may even crash for no obvious reasons). Why? Because C++ has this thing called the One-Definition Rule: if two C++ source files contain different definitions of the same class/function/variable, and you link them together, you violate the rule. The linker may or may not catch the error (in many cases it's not required by the C++ standard to catch the violation). If it doesn't, you get strange run-time behaviors that are unexpected and hard to debug. If you compile Google Test and your test code using different compiler flags, they may see different definitions of the same class/function/variable (e.g. due to the use of `#if` in Google Test). Therefore, for your sanity, we recommend to avoid installing pre-compiled Google Test libraries. Instead, each project should compile Google Test itself such that it can be sure that the same flags are used for both Google Test and the tests. ## How do I generate 64-bit binaries on Windows (using Visual Studio 2008)? ## (Answered by Trevor Robinson) Load the supplied Visual Studio solution file, either `msvc\gtest-md.sln` or `msvc\gtest.sln`. Go through the migration wizard to migrate the solution and project files to Visual Studio 2008. Select `Configuration Manager...` from the `Build` menu. Select `` from the `Active solution platform` dropdown. Select `x64` from the new platform dropdown, leave `Copy settings from` set to `Win32` and `Create new project platforms` checked, then click `OK`. You now have `Win32` and `x64` platform configurations, selectable from the `Standard` toolbar, which allow you to toggle between building 32-bit or 64-bit binaries (or both at once using Batch Build). In order to prevent build output files from overwriting one another, you'll need to change the `Intermediate Directory` settings for the newly created platform configuration across all the projects. To do this, multi-select (e.g. using shift-click) all projects (but not the solution) in the `Solution Explorer`. Right-click one of them and select `Properties`. In the left pane, select `Configuration Properties`, and from the `Configuration` dropdown, select `All Configurations`. Make sure the selected platform is `x64`. For the `Intermediate Directory` setting, change the value from `$(PlatformName)\$(ConfigurationName)` to `$(OutDir)\$(ProjectName)`. Click `OK` and then build the solution. When the build is complete, the 64-bit binaries will be in the `msvc\x64\Debug` directory. ## Can I use Google Test on MinGW? ## We haven't tested this ourselves, but Per Abrahamsen reported that he was able to compile and install Google Test successfully when using MinGW from Cygwin. You'll need to configure it with: `PATH/TO/configure CC="gcc -mno-cygwin" CXX="g++ -mno-cygwin"` You should be able to replace the `-mno-cygwin` option with direct links to the real MinGW binaries, but we haven't tried that. Caveats: * There are many warnings when compiling. * `make check` will produce some errors as not all tests for Google Test itself are compatible with MinGW. We also have reports on successful cross compilation of Google Test MinGW binaries on Linux using [these instructions](http://wiki.wxwidgets.org/Cross-Compiling_Under_Linux#Cross-compiling_under_Linux_for_MS_Windows) on the WxWidgets site. Please contact `googletestframework@googlegroups.com` if you are interested in improving the support for MinGW. ## Why does Google Test support EXPECT\_EQ(NULL, ptr) and ASSERT\_EQ(NULL, ptr) but not EXPECT\_NE(NULL, ptr) and ASSERT\_NE(NULL, ptr)? ## Due to some peculiarity of C++, it requires some non-trivial template meta programming tricks to support using `NULL` as an argument of the `EXPECT_XX()` and `ASSERT_XX()` macros. Therefore we only do it where it's most needed (otherwise we make the implementation of Google Test harder to maintain and more error-prone than necessary). The `EXPECT_EQ()` macro takes the _expected_ value as its first argument and the _actual_ value as the second. It's reasonable that someone wants to write `EXPECT_EQ(NULL, some_expression)`, and this indeed was requested several times. Therefore we implemented it. The need for `EXPECT_NE(NULL, ptr)` isn't nearly as strong. When the assertion fails, you already know that `ptr` must be `NULL`, so it doesn't add any information to print ptr in this case. That means `EXPECT_TRUE(ptr ! NULL)` works just as well. If we were to support `EXPECT_NE(NULL, ptr)`, for consistency we'll have to support `EXPECT_NE(ptr, NULL)` as well, as unlike `EXPECT_EQ`, we don't have a convention on the order of the two arguments for `EXPECT_NE`. This means using the template meta programming tricks twice in the implementation, making it even harder to understand and maintain. We believe the benefit doesn't justify the cost. Finally, with the growth of Google Mock's [matcher](../../CookBook.md#using-matchers-in-google-test-assertions) library, we are encouraging people to use the unified `EXPECT_THAT(value, matcher)` syntax more often in tests. One significant advantage of the matcher approach is that matchers can be easily combined to form new matchers, while the `EXPECT_NE`, etc, macros cannot be easily combined. Therefore we want to invest more in the matchers than in the `EXPECT_XX()` macros. ## Does Google Test support running tests in parallel? ## Test runners tend to be tightly coupled with the build/test environment, and Google Test doesn't try to solve the problem of running tests in parallel. Instead, we tried to make Google Test work nicely with test runners. For example, Google Test's XML report contains the time spent on each test, and its `gtest_list_tests` and `gtest_filter` flags can be used for splitting the execution of test methods into multiple processes. These functionalities can help the test runner run the tests in parallel. ## Why don't Google Test run the tests in different threads to speed things up? ## It's difficult to write thread-safe code. Most tests are not written with thread-safety in mind, and thus may not work correctly in a multi-threaded setting. If you think about it, it's already hard to make your code work when you know what other threads are doing. It's much harder, and sometimes even impossible, to make your code work when you don't know what other threads are doing (remember that test methods can be added, deleted, or modified after your test was written). If you want to run the tests in parallel, you'd better run them in different processes. ## Why aren't Google Test assertions implemented using exceptions? ## Our original motivation was to be able to use Google Test in projects that disable exceptions. Later we realized some additional benefits of this approach: 1. Throwing in a destructor is undefined behavior in C++. Not using exceptions means Google Test's assertions are safe to use in destructors. 1. The `EXPECT_*` family of macros will continue even after a failure, allowing multiple failures in a `TEST` to be reported in a single run. This is a popular feature, as in C++ the edit-compile-test cycle is usually quite long and being able to fixing more than one thing at a time is a blessing. 1. If assertions are implemented using exceptions, a test may falsely ignore a failure if it's caught by user code: ``` try { ... ASSERT_TRUE(...) ... } catch (...) { ... } ``` The above code will pass even if the `ASSERT_TRUE` throws. While it's unlikely for someone to write this in a test, it's possible to run into this pattern when you write assertions in callbacks that are called by the code under test. The downside of not using exceptions is that `ASSERT_*` (implemented using `return`) will only abort the current function, not the current `TEST`. ## Why do we use two different macros for tests with and without fixtures? ## Unfortunately, C++'s macro system doesn't allow us to use the same macro for both cases. One possibility is to provide only one macro for tests with fixtures, and require the user to define an empty fixture sometimes: ``` class FooTest : public ::testing::Test {}; TEST_F(FooTest, DoesThis) { ... } ``` or ``` typedef ::testing::Test FooTest; TEST_F(FooTest, DoesThat) { ... } ``` Yet, many people think this is one line too many. :-) Our goal was to make it really easy to write tests, so we tried to make simple tests trivial to create. That means using a separate macro for such tests. We think neither approach is ideal, yet either of them is reasonable. In the end, it probably doesn't matter much either way. ## Why don't we use structs as test fixtures? ## We like to use structs only when representing passive data. This distinction between structs and classes is good for documenting the intent of the code's author. Since test fixtures have logic like `SetUp()` and `TearDown()`, they are better defined as classes. ## Why are death tests implemented as assertions instead of using a test runner? ## Our goal was to make death tests as convenient for a user as C++ possibly allows. In particular: * The runner-style requires to split the information into two pieces: the definition of the death test itself, and the specification for the runner on how to run the death test and what to expect. The death test would be written in C++, while the runner spec may or may not be. A user needs to carefully keep the two in sync. `ASSERT_DEATH(statement, expected_message)` specifies all necessary information in one place, in one language, without boilerplate code. It is very declarative. * `ASSERT_DEATH` has a similar syntax and error-reporting semantics as other Google Test assertions, and thus is easy to learn. * `ASSERT_DEATH` can be mixed with other assertions and other logic at your will. You are not limited to one death test per test method. For example, you can write something like: ``` if (FooCondition()) { ASSERT_DEATH(Bar(), "blah"); } else { ASSERT_EQ(5, Bar()); } ``` If you prefer one death test per test method, you can write your tests in that style too, but we don't want to impose that on the users. The fewer artificial limitations the better. * `ASSERT_DEATH` can reference local variables in the current function, and you can decide how many death tests you want based on run-time information. For example, ``` const int count = GetCount(); // Only known at run time. for (int i = 1; i <= count; i++) { ASSERT_DEATH({ double* buffer = new double[i]; ... initializes buffer ... Foo(buffer, i) }, "blah blah"); } ``` The runner-based approach tends to be more static and less flexible, or requires more user effort to get this kind of flexibility. Another interesting thing about `ASSERT_DEATH` is that it calls `fork()` to create a child process to run the death test. This is lightening fast, as `fork()` uses copy-on-write pages and incurs almost zero overhead, and the child process starts from the user-supplied statement directly, skipping all global and local initialization and any code leading to the given statement. If you launch the child process from scratch, it can take seconds just to load everything and start running if the test links to many libraries dynamically. ## My death test modifies some state, but the change seems lost after the death test finishes. Why? ## Death tests (`EXPECT_DEATH`, etc) are executed in a sub-process s.t. the expected crash won't kill the test program (i.e. the parent process). As a result, any in-memory side effects they incur are observable in their respective sub-processes, but not in the parent process. You can think of them as running in a parallel universe, more or less. ## The compiler complains about "undefined references" to some static const member variables, but I did define them in the class body. What's wrong? ## If your class has a static data member: ``` // foo.h class Foo { ... static const int kBar = 100; }; ``` You also need to define it _outside_ of the class body in `foo.cc`: ``` const int Foo::kBar; // No initializer here. ``` Otherwise your code is **invalid C++**, and may break in unexpected ways. In particular, using it in Google Test comparison assertions (`EXPECT_EQ`, etc) will generate an "undefined reference" linker error. ## I have an interface that has several implementations. Can I write a set of tests once and repeat them over all the implementations? ## Google Test doesn't yet have good support for this kind of tests, or data-driven tests in general. We hope to be able to make improvements in this area soon. ## Can I derive a test fixture from another? ## Yes. Each test fixture has a corresponding and same named test case. This means only one test case can use a particular fixture. Sometimes, however, multiple test cases may want to use the same or slightly different fixtures. For example, you may want to make sure that all of a GUI library's test cases don't leak important system resources like fonts and brushes. In Google Test, you share a fixture among test cases by putting the shared logic in a base test fixture, then deriving from that base a separate fixture for each test case that wants to use this common logic. You then use `TEST_F()` to write tests using each derived fixture. Typically, your code looks like this: ``` // Defines a base test fixture. class BaseTest : public ::testing::Test { protected: ... }; // Derives a fixture FooTest from BaseTest. class FooTest : public BaseTest { protected: virtual void SetUp() { BaseTest::SetUp(); // Sets up the base fixture first. ... additional set-up work ... } virtual void TearDown() { ... clean-up work for FooTest ... BaseTest::TearDown(); // Remember to tear down the base fixture // after cleaning up FooTest! } ... functions and variables for FooTest ... }; // Tests that use the fixture FooTest. TEST_F(FooTest, Bar) { ... } TEST_F(FooTest, Baz) { ... } ... additional fixtures derived from BaseTest ... ``` If necessary, you can continue to derive test fixtures from a derived fixture. Google Test has no limit on how deep the hierarchy can be. For a complete example using derived test fixtures, see [sample5](../samples/sample5_unittest.cc). ## My compiler complains "void value not ignored as it ought to be." What does this mean? ## You're probably using an `ASSERT_*()` in a function that doesn't return `void`. `ASSERT_*()` can only be used in `void` functions. ## My death test hangs (or seg-faults). How do I fix it? ## In Google Test, death tests are run in a child process and the way they work is delicate. To write death tests you really need to understand how they work. Please make sure you have read this. In particular, death tests don't like having multiple threads in the parent process. So the first thing you can try is to eliminate creating threads outside of `EXPECT_DEATH()`. Sometimes this is impossible as some library you must use may be creating threads before `main()` is even reached. In this case, you can try to minimize the chance of conflicts by either moving as many activities as possible inside `EXPECT_DEATH()` (in the extreme case, you want to move everything inside), or leaving as few things as possible in it. Also, you can try to set the death test style to `"threadsafe"`, which is safer but slower, and see if it helps. If you go with thread-safe death tests, remember that they rerun the test program from the beginning in the child process. Therefore make sure your program can run side-by-side with itself and is deterministic. In the end, this boils down to good concurrent programming. You have to make sure that there is no race conditions or dead locks in your program. No silver bullet - sorry! ## Should I use the constructor/destructor of the test fixture or the set-up/tear-down function? ## The first thing to remember is that Google Test does not reuse the same test fixture object across multiple tests. For each `TEST_F`, Google Test will create a fresh test fixture object, _immediately_ call `SetUp()`, run the test, call `TearDown()`, and then _immediately_ delete the test fixture object. Therefore, there is no need to write a `SetUp()` or `TearDown()` function if the constructor or destructor already does the job. You may still want to use `SetUp()/TearDown()` in the following cases: * If the tear-down operation could throw an exception, you must use `TearDown()` as opposed to the destructor, as throwing in a destructor leads to undefined behavior and usually will kill your program right away. Note that many standard libraries (like STL) may throw when exceptions are enabled in the compiler. Therefore you should prefer `TearDown()` if you want to write portable tests that work with or without exceptions. * The Google Test team is considering making the assertion macros throw on platforms where exceptions are enabled (e.g. Windows, Mac OS, and Linux client-side), which will eliminate the need for the user to propagate failures from a subroutine to its caller. Therefore, you shouldn't use Google Test assertions in a destructor if your code could run on such a platform. * In a constructor or destructor, you cannot make a virtual function call on this object. (You can call a method declared as virtual, but it will be statically bound.) Therefore, if you need to call a method that will be overriden in a derived class, you have to use `SetUp()/TearDown()`. ## The compiler complains "no matching function to call" when I use ASSERT\_PREDn. How do I fix it? ## If the predicate function you use in `ASSERT_PRED*` or `EXPECT_PRED*` is overloaded or a template, the compiler will have trouble figuring out which overloaded version it should use. `ASSERT_PRED_FORMAT*` and `EXPECT_PRED_FORMAT*` don't have this problem. If you see this error, you might want to switch to `(ASSERT|EXPECT)_PRED_FORMAT*`, which will also give you a better failure message. If, however, that is not an option, you can resolve the problem by explicitly telling the compiler which version to pick. For example, suppose you have ``` bool IsPositive(int n) { return n > 0; } bool IsPositive(double x) { return x > 0; } ``` you will get a compiler error if you write ``` EXPECT_PRED1(IsPositive, 5); ``` However, this will work: ``` EXPECT_PRED1(*static_cast*(IsPositive), 5); ``` (The stuff inside the angled brackets for the `static_cast` operator is the type of the function pointer for the `int`-version of `IsPositive()`.) As another example, when you have a template function ``` template bool IsNegative(T x) { return x < 0; } ``` you can use it in a predicate assertion like this: ``` ASSERT_PRED1(IsNegative**, -5); ``` Things are more interesting if your template has more than one parameters. The following won't compile: ``` ASSERT_PRED2(*GreaterThan*, 5, 0); ``` as the C++ pre-processor thinks you are giving `ASSERT_PRED2` 4 arguments, which is one more than expected. The workaround is to wrap the predicate function in parentheses: ``` ASSERT_PRED2(*(GreaterThan)*, 5, 0); ``` ## My compiler complains about "ignoring return value" when I call RUN\_ALL\_TESTS(). Why? ## Some people had been ignoring the return value of `RUN_ALL_TESTS()`. That is, instead of ``` return RUN_ALL_TESTS(); ``` they write ``` RUN_ALL_TESTS(); ``` This is wrong and dangerous. A test runner needs to see the return value of `RUN_ALL_TESTS()` in order to determine if a test has passed. If your `main()` function ignores it, your test will be considered successful even if it has a Google Test assertion failure. Very bad. To help the users avoid this dangerous bug, the implementation of `RUN_ALL_TESTS()` causes gcc to raise this warning, when the return value is ignored. If you see this warning, the fix is simple: just make sure its value is used as the return value of `main()`. ## My compiler complains that a constructor (or destructor) cannot return a value. What's going on? ## Due to a peculiarity of C++, in order to support the syntax for streaming messages to an `ASSERT_*`, e.g. ``` ASSERT_EQ(1, Foo()) << "blah blah" << foo; ``` we had to give up using `ASSERT*` and `FAIL*` (but not `EXPECT*` and `ADD_FAILURE*`) in constructors and destructors. The workaround is to move the content of your constructor/destructor to a private void member function, or switch to `EXPECT_*()` if that works. This section in the user's guide explains it. ## My set-up function is not called. Why? ## C++ is case-sensitive. It should be spelled as `SetUp()`. Did you spell it as `Setup()`? Similarly, sometimes people spell `SetUpTestCase()` as `SetupTestCase()` and wonder why it's never called. ## How do I jump to the line of a failure in Emacs directly? ## Google Test's failure message format is understood by Emacs and many other IDEs, like acme and XCode. If a Google Test message is in a compilation buffer in Emacs, then it's clickable. You can now hit `enter` on a message to jump to the corresponding source code, or use `C-x `` to jump to the next failure. ## I have several test cases which share the same test fixture logic, do I have to define a new test fixture class for each of them? This seems pretty tedious. ## You don't have to. Instead of ``` class FooTest : public BaseTest {}; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } class BarTest : public BaseTest {}; TEST_F(BarTest, Abc) { ... } TEST_F(BarTest, Def) { ... } ``` you can simply `typedef` the test fixtures: ``` typedef BaseTest FooTest; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } typedef BaseTest BarTest; TEST_F(BarTest, Abc) { ... } TEST_F(BarTest, Def) { ... } ``` ## The Google Test output is buried in a whole bunch of log messages. What do I do? ## The Google Test output is meant to be a concise and human-friendly report. If your test generates textual output itself, it will mix with the Google Test output, making it hard to read. However, there is an easy solution to this problem. Since most log messages go to stderr, we decided to let Google Test output go to stdout. This way, you can easily separate the two using redirection. For example: ``` ./my_test > googletest_output.txt ``` ## Why should I prefer test fixtures over global variables? ## There are several good reasons: 1. It's likely your test needs to change the states of its global variables. This makes it difficult to keep side effects from escaping one test and contaminating others, making debugging difficult. By using fixtures, each test has a fresh set of variables that's different (but with the same names). Thus, tests are kept independent of each other. 1. Global variables pollute the global namespace. 1. Test fixtures can be reused via subclassing, which cannot be done easily with global variables. This is useful if many test cases have something in common. ## How do I test private class members without writing FRIEND\_TEST()s? ## You should try to write testable code, which means classes should be easily tested from their public interface. One way to achieve this is the Pimpl idiom: you move all private members of a class into a helper class, and make all members of the helper class public. You have several other options that don't require using `FRIEND_TEST`: * Write the tests as members of the fixture class: ``` class Foo { friend class FooTest; ... }; class FooTest : public ::testing::Test { protected: ... void Test1() {...} // This accesses private members of class Foo. void Test2() {...} // So does this one. }; TEST_F(FooTest, Test1) { Test1(); } TEST_F(FooTest, Test2) { Test2(); } ``` * In the fixture class, write accessors for the tested class' private members, then use the accessors in your tests: ``` class Foo { friend class FooTest; ... }; class FooTest : public ::testing::Test { protected: ... T1 get_private_member1(Foo* obj) { return obj->private_member1_; } }; TEST_F(FooTest, Test1) { ... get_private_member1(x) ... } ``` * If the methods are declared **protected**, you can change their access level in a test-only subclass: ``` class YourClass { ... protected: // protected access for testability. int DoSomethingReturningInt(); ... }; // in the your_class_test.cc file: class TestableYourClass : public YourClass { ... public: using YourClass::DoSomethingReturningInt; // changes access rights ... }; TEST_F(YourClassTest, DoSomethingTest) { TestableYourClass obj; assertEquals(expected_value, obj.DoSomethingReturningInt()); } ``` ## How do I test private class static members without writing FRIEND\_TEST()s? ## We find private static methods clutter the header file. They are implementation details and ideally should be kept out of a .h. So often I make them free functions instead. Instead of: ``` // foo.h class Foo { ... private: static bool Func(int n); }; // foo.cc bool Foo::Func(int n) { ... } // foo_test.cc EXPECT_TRUE(Foo::Func(12345)); ``` You probably should better write: ``` // foo.h class Foo { ... }; // foo.cc namespace internal { bool Func(int n) { ... } } // foo_test.cc namespace internal { bool Func(int n); } EXPECT_TRUE(internal::Func(12345)); ``` ## I would like to run a test several times with different parameters. Do I need to write several similar copies of it? ## No. You can use a feature called [value-parameterized tests](V1_6_AdvancedGuide.md#Value_Parameterized_Tests) which lets you repeat your tests with different parameters, without defining it more than once. ## How do I test a file that defines main()? ## To test a `foo.cc` file, you need to compile and link it into your unit test program. However, when the file contains a definition for the `main()` function, it will clash with the `main()` of your unit test, and will result in a build error. The right solution is to split it into three files: 1. `foo.h` which contains the declarations, 1. `foo.cc` which contains the definitions except `main()`, and 1. `foo_main.cc` which contains nothing but the definition of `main()`. Then `foo.cc` can be easily tested. If you are adding tests to an existing file and don't want an intrusive change like this, there is a hack: just include the entire `foo.cc` file in your unit test. For example: ``` // File foo_unittest.cc // The headers section ... // Renames main() in foo.cc to make room for the unit test main() #define main FooMain #include "a/b/foo.cc" // The tests start here. ... ``` However, please remember this is a hack and should only be used as the last resort. ## What can the statement argument in ASSERT\_DEATH() be? ## `ASSERT_DEATH(_statement_, _regex_)` (or any death assertion macro) can be used wherever `_statement_` is valid. So basically `_statement_` can be any C++ statement that makes sense in the current context. In particular, it can reference global and/or local variables, and can be: * a simple function call (often the case), * a complex expression, or * a compound statement. > Some examples are shown here: ``` // A death test can be a simple function call. TEST(MyDeathTest, FunctionCall) { ASSERT_DEATH(Xyz(5), "Xyz failed"); } // Or a complex expression that references variables and functions. TEST(MyDeathTest, ComplexExpression) { const bool c = Condition(); ASSERT_DEATH((c ? Func1(0) : object2.Method("test")), "(Func1|Method) failed"); } // Death assertions can be used any where in a function. In // particular, they can be inside a loop. TEST(MyDeathTest, InsideLoop) { // Verifies that Foo(0), Foo(1), ..., and Foo(4) all die. for (int i = 0; i < 5; i++) { EXPECT_DEATH_M(Foo(i), "Foo has \\d+ errors", ::testing::Message() << "where i is " << i); } } // A death assertion can contain a compound statement. TEST(MyDeathTest, CompoundStatement) { // Verifies that at lease one of Bar(0), Bar(1), ..., and // Bar(4) dies. ASSERT_DEATH({ for (int i = 0; i < 5; i++) { Bar(i); } }, "Bar has \\d+ errors");} ``` `googletest_unittest.cc` contains more examples if you are interested. ## What syntax does the regular expression in ASSERT\_DEATH use? ## On POSIX systems, Google Test uses the POSIX Extended regular expression syntax (http://en.wikipedia.org/wiki/Regular_expression#POSIX_Extended_Regular_Expressions). On Windows, it uses a limited variant of regular expression syntax. For more details, see the [regular expression syntax](V1_6_AdvancedGuide.md#Regular_Expression_Syntax). ## I have a fixture class Foo, but TEST\_F(Foo, Bar) gives me error "no matching function for call to Foo::Foo()". Why? ## Google Test needs to be able to create objects of your test fixture class, so it must have a default constructor. Normally the compiler will define one for you. However, there are cases where you have to define your own: * If you explicitly declare a non-default constructor for class `Foo`, then you need to define a default constructor, even if it would be empty. * If `Foo` has a const non-static data member, then you have to define the default constructor _and_ initialize the const member in the initializer list of the constructor. (Early versions of `gcc` doesn't force you to initialize the const member. It's a bug that has been fixed in `gcc 4`.) ## Why does ASSERT\_DEATH complain about previous threads that were already joined? ## With the Linux pthread library, there is no turning back once you cross the line from single thread to multiple threads. The first time you create a thread, a manager thread is created in addition, so you get 3, not 2, threads. Later when the thread you create joins the main thread, the thread count decrements by 1, but the manager thread will never be killed, so you still have 2 threads, which means you cannot safely run a death test. The new NPTL thread library doesn't suffer from this problem, as it doesn't create a manager thread. However, if you don't control which machine your test runs on, you shouldn't depend on this. ## Why does Google Test require the entire test case, instead of individual tests, to be named FOODeathTest when it uses ASSERT\_DEATH? ## Google Test does not interleave tests from different test cases. That is, it runs all tests in one test case first, and then runs all tests in the next test case, and so on. Google Test does this because it needs to set up a test case before the first test in it is run, and tear it down afterwords. Splitting up the test case would require multiple set-up and tear-down processes, which is inefficient and makes the semantics unclean. If we were to determine the order of tests based on test name instead of test case name, then we would have a problem with the following situation: ``` TEST_F(FooTest, AbcDeathTest) { ... } TEST_F(FooTest, Uvw) { ... } TEST_F(BarTest, DefDeathTest) { ... } TEST_F(BarTest, Xyz) { ... } ``` Since `FooTest.AbcDeathTest` needs to run before `BarTest.Xyz`, and we don't interleave tests from different test cases, we need to run all tests in the `FooTest` case before running any test in the `BarTest` case. This contradicts with the requirement to run `BarTest.DefDeathTest` before `FooTest.Uvw`. ## But I don't like calling my entire test case FOODeathTest when it contains both death tests and non-death tests. What do I do? ## You don't have to, but if you like, you may split up the test case into `FooTest` and `FooDeathTest`, where the names make it clear that they are related: ``` class FooTest : public ::testing::Test { ... }; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } typedef FooTest FooDeathTest; TEST_F(FooDeathTest, Uvw) { ... EXPECT_DEATH(...) ... } TEST_F(FooDeathTest, Xyz) { ... ASSERT_DEATH(...) ... } ``` ## The compiler complains about "no match for 'operator<<'" when I use an assertion. What gives? ## If you use a user-defined type `FooType` in an assertion, you must make sure there is an `std::ostream& operator<<(std::ostream&, const FooType&)` function defined such that we can print a value of `FooType`. In addition, if `FooType` is declared in a name space, the `<<` operator also needs to be defined in the _same_ name space. ## How do I suppress the memory leak messages on Windows? ## Since the statically initialized Google Test singleton requires allocations on the heap, the Visual C++ memory leak detector will report memory leaks at the end of the program run. The easiest way to avoid this is to use the `_CrtMemCheckpoint` and `_CrtMemDumpAllObjectsSince` calls to not report any statically initialized heap objects. See MSDN for more details and additional heap check/debug routines. ## I am building my project with Google Test in Visual Studio and all I'm getting is a bunch of linker errors (or warnings). Help! ## You may get a number of the following linker error or warnings if you attempt to link your test project with the Google Test library when your project and the are not built using the same compiler settings. * LNK2005: symbol already defined in object * LNK4217: locally defined symbol 'symbol' imported in function 'function' * LNK4049: locally defined symbol 'symbol' imported The Google Test project (gtest.vcproj) has the Runtime Library option set to /MT (use multi-threaded static libraries, /MTd for debug). If your project uses something else, for example /MD (use multi-threaded DLLs, /MDd for debug), you need to change the setting in the Google Test project to match your project's. To update this setting open the project properties in the Visual Studio IDE then select the branch Configuration Properties | C/C++ | Code Generation and change the option "Runtime Library". You may also try using gtest-md.vcproj instead of gtest.vcproj. ## I put my tests in a library and Google Test doesn't run them. What's happening? ## Have you read a [warning](V1_6_Primer.md#important-note-for-visual-c-users) on the Google Test Primer page? ## I want to use Google Test with Visual Studio but don't know where to start. ## Many people are in your position and one of the posted his solution to our mailing list. Here is his link: http://hassanjamilahmad.blogspot.com/2009/07/gtest-starters-help.html. ## I am seeing compile errors mentioning std::type\_traits when I try to use Google Test on Solaris. ## Google Test uses parts of the standard C++ library that SunStudio does not support. Our users reported success using alternative implementations. Try running the build after runing this commad: `export CC=cc CXX=CC CXXFLAGS='-library=stlport4'` ## How can my code detect if it is running in a test? ## If you write code that sniffs whether it's running in a test and does different things accordingly, you are leaking test-only logic into production code and there is no easy way to ensure that the test-only code paths aren't run by mistake in production. Such cleverness also leads to [Heisenbugs](http://en.wikipedia.org/wiki/Unusual_software_bug#Heisenbug). Therefore we strongly advise against the practice, and Google Test doesn't provide a way to do it. In general, the recommended way to cause the code to behave differently under test is [dependency injection](http://jamesshore.com/Blog/Dependency-Injection-Demystified.html). You can inject different functionality from the test and from the production code. Since your production code doesn't link in the for-test logic at all, there is no danger in accidentally running it. However, if you _really_, _really_, _really_ have no choice, and if you follow the rule of ending your test program names with `_test`, you can use the _horrible_ hack of sniffing your executable name (`argv[0]` in `main()`) to know whether the code is under test. ## Google Test defines a macro that clashes with one defined by another library. How do I deal with that? ## 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`. 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. Currently, the following `TEST`, `FAIL`, `SUCCEED`, and the basic comparison assertion macros can have alternative names. You can see the full list of covered macros [here](http://www.google.com/codesearch?q=if+!GTEST_DONT_DEFINE_\w%2B+package:http://googletest\.googlecode\.com+file:/include/gtest/gtest.h). More information can be found in the "Avoiding Macro Name Clashes" section of the README file. ## My question is not covered in your FAQ! ## If you cannot find the answer to your question in this FAQ, there are some other resources you can use: 1. read other [wiki pages](http://code.google.com/p/googletest/w/list), 1. search the mailing list [archive](http://groups.google.com/group/googletestframework/topics), 1. ask it on [googletestframework@googlegroups.com](mailto:googletestframework@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googletestframework) before you can post.). Please note that creating an issue in the [issue tracker](http://code.google.com/p/googletest/issues/list) is _not_ a good way to get your answer, as it is monitored infrequently by a very small number of people. When asking a question, it's helpful to provide as much of the following information as possible (people cannot help you if there's not enough information in your question): * the version (or the revision number if you check out from SVN directly) of Google Test you use (Google Test is under active development, so it's possible that your problem has been solved in a later version), * your operating system, * the name and version of your compiler, * the complete command line flags you give to your compiler, * the complete compiler error messages (if the question is about compilation), * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. assimp-4.1.0/contrib/gtest/docs/V1_7_FAQ.md0000644002537200234200000013420313213503245020522 0ustar zmoelnigiemusers If you cannot find the answer to your question here, and you have read [Primer](V1_7_Primer.md) and [AdvancedGuide](V1_7_AdvancedGuide.md), send it to googletestframework@googlegroups.com. ## Why should I use Google Test instead of my favorite C++ testing framework? ## First, let us say clearly that we don't want to get into the debate of which C++ testing framework is **the best**. There exist many fine frameworks for writing C++ tests, and we have tremendous respect for the developers and users of them. We don't think there is (or will be) a single best framework - you have to pick the right tool for the particular task you are tackling. We created Google Test because we couldn't find the right combination of features and conveniences in an existing framework to satisfy _our_ needs. The following is a list of things that _we_ like about Google Test. We don't claim them to be unique to Google Test - rather, the combination of them makes Google Test the choice for us. We hope this list can help you decide whether it is for you too. * Google Test is designed to be portable: it doesn't require exceptions or RTTI; it works around various bugs in various compilers and environments; etc. As a result, it works on Linux, Mac OS X, Windows and several embedded operating systems. * Nonfatal assertions (`EXPECT_*`) have proven to be great time savers, as they allow a test to report multiple failures in a single edit-compile-test cycle. * It's easy to write assertions that generate informative messages: you just use the stream syntax to append any additional information, e.g. `ASSERT_EQ(5, Foo(i)) << " where i = " << i;`. It doesn't require a new set of macros or special functions. * Google Test automatically detects your tests and doesn't require you to enumerate them in order to run them. * Death tests are pretty handy for ensuring that your asserts in production code are triggered by the right conditions. * `SCOPED_TRACE` helps you understand the context of an assertion failure when it comes from inside a sub-routine or loop. * You can decide which tests to run using name patterns. This saves time when you want to quickly reproduce a test failure. * Google Test can generate XML test result reports that can be parsed by popular continuous build system like Hudson. * Simple things are easy in Google Test, while hard things are possible: in addition to advanced features like [global test environments](V1_7_AdvancedGuide.md#global-set-up-and-tear-down) and tests parameterized by [values](V1_7_AdvancedGuide.md#value-parameterized-tests) or [types](V1_7_AdvancedGuide.md#typed-tests), Google Test supports various ways for the user to extend the framework -- if Google Test doesn't do something out of the box, chances are that a user can implement the feature using Google Test's public API, without changing Google Test itself. In particular, you can: * expand your testing vocabulary by defining [custom predicates](V1_7_AdvancedGuide.md#predicate-assertions-for-better-error-messages), * teach Google Test how to [print your types](V1_7_AdvancedGuide.md#teaching-google-test-how-to-print-your-values), * define your own testing macros or utilities and verify them using Google Test's [Service Provider Interface](V1_7_AdvancedGuide.md#catching-failures), and * reflect on the test cases or change the test output format by intercepting the [test events](V1_7_AdvancedGuide.md#extending-google-test-by-handling-test-events). ## I'm getting warnings when compiling Google Test. Would you fix them? ## We strive to minimize compiler warnings Google Test generates. Before releasing a new version, we test to make sure that it doesn't generate warnings when compiled using its CMake script on Windows, Linux, and Mac OS. Unfortunately, this doesn't mean you are guaranteed to see no warnings when compiling Google Test in your environment: * You may be using a different compiler as we use, or a different version of the same compiler. We cannot possibly test for all compilers. * You may be compiling on a different platform as we do. * Your project may be using different compiler flags as we do. It is not always possible to make Google Test warning-free for everyone. Or, it may not be desirable if the warning is rarely enabled and fixing the violations makes the code more complex. If you see warnings when compiling Google Test, we suggest that you use the `-isystem` flag (assuming your are using GCC) to mark Google Test headers as system headers. That'll suppress warnings from Google Test headers. ## Why should not test case names and test names contain underscore? ## Underscore (`_`) is special, as C++ reserves the following to be used by the compiler and the standard library: 1. any identifier that starts with an `_` followed by an upper-case letter, and 1. any identifier that containers two consecutive underscores (i.e. `__`) _anywhere_ in its name. User code is _prohibited_ from using such identifiers. Now let's look at what this means for `TEST` and `TEST_F`. Currently `TEST(TestCaseName, TestName)` generates a class named `TestCaseName_TestName_Test`. What happens if `TestCaseName` or `TestName` contains `_`? 1. If `TestCaseName` starts with an `_` followed by an upper-case letter (say, `_Foo`), we end up with `_Foo_TestName_Test`, which is reserved and thus invalid. 1. If `TestCaseName` ends with an `_` (say, `Foo_`), we get `Foo__TestName_Test`, which is invalid. 1. If `TestName` starts with an `_` (say, `_Bar`), we get `TestCaseName__Bar_Test`, which is invalid. 1. If `TestName` ends with an `_` (say, `Bar_`), we get `TestCaseName_Bar__Test`, which is invalid. So clearly `TestCaseName` and `TestName` cannot start or end with `_` (Actually, `TestCaseName` can start with `_` -- as long as the `_` isn't followed by an upper-case letter. But that's getting complicated. So for simplicity we just say that it cannot start with `_`.). It may seem fine for `TestCaseName` and `TestName` to contain `_` in the middle. However, consider this: ``` TEST(Time, Flies_Like_An_Arrow) { ... } TEST(Time_Flies, Like_An_Arrow) { ... } ``` Now, the two `TEST`s will both generate the same class (`Time_Files_Like_An_Arrow_Test`). That's not good. So for simplicity, we just ask the users to avoid `_` in `TestCaseName` and `TestName`. The rule is more constraining than necessary, but it's simple and easy to remember. It also gives Google Test some wiggle room in case its implementation needs to change in the future. If you violate the rule, there may not be immediately consequences, but your test may (just may) break with a new compiler (or a new version of the compiler you are using) or with a new version of Google Test. Therefore it's best to follow the rule. ## Why is it not recommended to install a pre-compiled copy of Google Test (for example, into /usr/local)? ## In the early days, we said that you could install compiled Google Test libraries on `*`nix systems using `make install`. Then every user of your machine can write tests without recompiling Google Test. This seemed like a good idea, but it has a got-cha: every user needs to compile his tests using the _same_ compiler flags used to compile the installed Google Test libraries; otherwise he may run into undefined behaviors (i.e. the tests can behave strangely and may even crash for no obvious reasons). Why? Because C++ has this thing called the One-Definition Rule: if two C++ source files contain different definitions of the same class/function/variable, and you link them together, you violate the rule. The linker may or may not catch the error (in many cases it's not required by the C++ standard to catch the violation). If it doesn't, you get strange run-time behaviors that are unexpected and hard to debug. If you compile Google Test and your test code using different compiler flags, they may see different definitions of the same class/function/variable (e.g. due to the use of `#if` in Google Test). Therefore, for your sanity, we recommend to avoid installing pre-compiled Google Test libraries. Instead, each project should compile Google Test itself such that it can be sure that the same flags are used for both Google Test and the tests. ## How do I generate 64-bit binaries on Windows (using Visual Studio 2008)? ## (Answered by Trevor Robinson) Load the supplied Visual Studio solution file, either `msvc\gtest-md.sln` or `msvc\gtest.sln`. Go through the migration wizard to migrate the solution and project files to Visual Studio 2008. Select `Configuration Manager...` from the `Build` menu. Select `` from the `Active solution platform` dropdown. Select `x64` from the new platform dropdown, leave `Copy settings from` set to `Win32` and `Create new project platforms` checked, then click `OK`. You now have `Win32` and `x64` platform configurations, selectable from the `Standard` toolbar, which allow you to toggle between building 32-bit or 64-bit binaries (or both at once using Batch Build). In order to prevent build output files from overwriting one another, you'll need to change the `Intermediate Directory` settings for the newly created platform configuration across all the projects. To do this, multi-select (e.g. using shift-click) all projects (but not the solution) in the `Solution Explorer`. Right-click one of them and select `Properties`. In the left pane, select `Configuration Properties`, and from the `Configuration` dropdown, select `All Configurations`. Make sure the selected platform is `x64`. For the `Intermediate Directory` setting, change the value from `$(PlatformName)\$(ConfigurationName)` to `$(OutDir)\$(ProjectName)`. Click `OK` and then build the solution. When the build is complete, the 64-bit binaries will be in the `msvc\x64\Debug` directory. ## Can I use Google Test on MinGW? ## We haven't tested this ourselves, but Per Abrahamsen reported that he was able to compile and install Google Test successfully when using MinGW from Cygwin. You'll need to configure it with: `PATH/TO/configure CC="gcc -mno-cygwin" CXX="g++ -mno-cygwin"` You should be able to replace the `-mno-cygwin` option with direct links to the real MinGW binaries, but we haven't tried that. Caveats: * There are many warnings when compiling. * `make check` will produce some errors as not all tests for Google Test itself are compatible with MinGW. We also have reports on successful cross compilation of Google Test MinGW binaries on Linux using [these instructions](http://wiki.wxwidgets.org/Cross-Compiling_Under_Linux#Cross-compiling_under_Linux_for_MS_Windows) on the WxWidgets site. Please contact `googletestframework@googlegroups.com` if you are interested in improving the support for MinGW. ## Why does Google Test support EXPECT\_EQ(NULL, ptr) and ASSERT\_EQ(NULL, ptr) but not EXPECT\_NE(NULL, ptr) and ASSERT\_NE(NULL, ptr)? ## Due to some peculiarity of C++, it requires some non-trivial template meta programming tricks to support using `NULL` as an argument of the `EXPECT_XX()` and `ASSERT_XX()` macros. Therefore we only do it where it's most needed (otherwise we make the implementation of Google Test harder to maintain and more error-prone than necessary). The `EXPECT_EQ()` macro takes the _expected_ value as its first argument and the _actual_ value as the second. It's reasonable that someone wants to write `EXPECT_EQ(NULL, some_expression)`, and this indeed was requested several times. Therefore we implemented it. The need for `EXPECT_NE(NULL, ptr)` isn't nearly as strong. When the assertion fails, you already know that `ptr` must be `NULL`, so it doesn't add any information to print ptr in this case. That means `EXPECT_TRUE(ptr != NULL)` works just as well. If we were to support `EXPECT_NE(NULL, ptr)`, for consistency we'll have to support `EXPECT_NE(ptr, NULL)` as well, as unlike `EXPECT_EQ`, we don't have a convention on the order of the two arguments for `EXPECT_NE`. This means using the template meta programming tricks twice in the implementation, making it even harder to understand and maintain. We believe the benefit doesn't justify the cost. Finally, with the growth of Google Mock's [matcher](../../CookBook.md#using-matchers-in-google-test-assertions) library, we are encouraging people to use the unified `EXPECT_THAT(value, matcher)` syntax more often in tests. One significant advantage of the matcher approach is that matchers can be easily combined to form new matchers, while the `EXPECT_NE`, etc, macros cannot be easily combined. Therefore we want to invest more in the matchers than in the `EXPECT_XX()` macros. ## Does Google Test support running tests in parallel? ## Test runners tend to be tightly coupled with the build/test environment, and Google Test doesn't try to solve the problem of running tests in parallel. Instead, we tried to make Google Test work nicely with test runners. For example, Google Test's XML report contains the time spent on each test, and its `gtest_list_tests` and `gtest_filter` flags can be used for splitting the execution of test methods into multiple processes. These functionalities can help the test runner run the tests in parallel. ## Why don't Google Test run the tests in different threads to speed things up? ## It's difficult to write thread-safe code. Most tests are not written with thread-safety in mind, and thus may not work correctly in a multi-threaded setting. If you think about it, it's already hard to make your code work when you know what other threads are doing. It's much harder, and sometimes even impossible, to make your code work when you don't know what other threads are doing (remember that test methods can be added, deleted, or modified after your test was written). If you want to run the tests in parallel, you'd better run them in different processes. ## Why aren't Google Test assertions implemented using exceptions? ## Our original motivation was to be able to use Google Test in projects that disable exceptions. Later we realized some additional benefits of this approach: 1. Throwing in a destructor is undefined behavior in C++. Not using exceptions means Google Test's assertions are safe to use in destructors. 1. The `EXPECT_*` family of macros will continue even after a failure, allowing multiple failures in a `TEST` to be reported in a single run. This is a popular feature, as in C++ the edit-compile-test cycle is usually quite long and being able to fixing more than one thing at a time is a blessing. 1. If assertions are implemented using exceptions, a test may falsely ignore a failure if it's caught by user code: ``` try { ... ASSERT_TRUE(...) ... } catch (...) { ... } ``` The above code will pass even if the `ASSERT_TRUE` throws. While it's unlikely for someone to write this in a test, it's possible to run into this pattern when you write assertions in callbacks that are called by the code under test. The downside of not using exceptions is that `ASSERT_*` (implemented using `return`) will only abort the current function, not the current `TEST`. ## Why do we use two different macros for tests with and without fixtures? ## Unfortunately, C++'s macro system doesn't allow us to use the same macro for both cases. One possibility is to provide only one macro for tests with fixtures, and require the user to define an empty fixture sometimes: ``` class FooTest : public ::testing::Test {}; TEST_F(FooTest, DoesThis) { ... } ``` or ``` typedef ::testing::Test FooTest; TEST_F(FooTest, DoesThat) { ... } ``` Yet, many people think this is one line too many. :-) Our goal was to make it really easy to write tests, so we tried to make simple tests trivial to create. That means using a separate macro for such tests. We think neither approach is ideal, yet either of them is reasonable. In the end, it probably doesn't matter much either way. ## Why don't we use structs as test fixtures? ## We like to use structs only when representing passive data. This distinction between structs and classes is good for documenting the intent of the code's author. Since test fixtures have logic like `SetUp()` and `TearDown()`, they are better defined as classes. ## Why are death tests implemented as assertions instead of using a test runner? ## Our goal was to make death tests as convenient for a user as C++ possibly allows. In particular: * The runner-style requires to split the information into two pieces: the definition of the death test itself, and the specification for the runner on how to run the death test and what to expect. The death test would be written in C++, while the runner spec may or may not be. A user needs to carefully keep the two in sync. `ASSERT_DEATH(statement, expected_message)` specifies all necessary information in one place, in one language, without boilerplate code. It is very declarative. * `ASSERT_DEATH` has a similar syntax and error-reporting semantics as other Google Test assertions, and thus is easy to learn. * `ASSERT_DEATH` can be mixed with other assertions and other logic at your will. You are not limited to one death test per test method. For example, you can write something like: ``` if (FooCondition()) { ASSERT_DEATH(Bar(), "blah"); } else { ASSERT_EQ(5, Bar()); } ``` If you prefer one death test per test method, you can write your tests in that style too, but we don't want to impose that on the users. The fewer artificial limitations the better. * `ASSERT_DEATH` can reference local variables in the current function, and you can decide how many death tests you want based on run-time information. For example, ``` const int count = GetCount(); // Only known at run time. for (int i = 1; i <= count; i++) { ASSERT_DEATH({ double* buffer = new double[i]; ... initializes buffer ... Foo(buffer, i) }, "blah blah"); } ``` The runner-based approach tends to be more static and less flexible, or requires more user effort to get this kind of flexibility. Another interesting thing about `ASSERT_DEATH` is that it calls `fork()` to create a child process to run the death test. This is lightening fast, as `fork()` uses copy-on-write pages and incurs almost zero overhead, and the child process starts from the user-supplied statement directly, skipping all global and local initialization and any code leading to the given statement. If you launch the child process from scratch, it can take seconds just to load everything and start running if the test links to many libraries dynamically. ## My death test modifies some state, but the change seems lost after the death test finishes. Why? ## Death tests (`EXPECT_DEATH`, etc) are executed in a sub-process s.t. the expected crash won't kill the test program (i.e. the parent process). As a result, any in-memory side effects they incur are observable in their respective sub-processes, but not in the parent process. You can think of them as running in a parallel universe, more or less. ## The compiler complains about "undefined references" to some static const member variables, but I did define them in the class body. What's wrong? ## If your class has a static data member: ``` // foo.h class Foo { ... static const int kBar = 100; }; ``` You also need to define it _outside_ of the class body in `foo.cc`: ``` const int Foo::kBar; // No initializer here. ``` Otherwise your code is **invalid C++**, and may break in unexpected ways. In particular, using it in Google Test comparison assertions (`EXPECT_EQ`, etc) will generate an "undefined reference" linker error. ## I have an interface that has several implementations. Can I write a set of tests once and repeat them over all the implementations? ## Google Test doesn't yet have good support for this kind of tests, or data-driven tests in general. We hope to be able to make improvements in this area soon. ## Can I derive a test fixture from another? ## Yes. Each test fixture has a corresponding and same named test case. This means only one test case can use a particular fixture. Sometimes, however, multiple test cases may want to use the same or slightly different fixtures. For example, you may want to make sure that all of a GUI library's test cases don't leak important system resources like fonts and brushes. In Google Test, you share a fixture among test cases by putting the shared logic in a base test fixture, then deriving from that base a separate fixture for each test case that wants to use this common logic. You then use `TEST_F()` to write tests using each derived fixture. Typically, your code looks like this: ``` // Defines a base test fixture. class BaseTest : public ::testing::Test { protected: ... }; // Derives a fixture FooTest from BaseTest. class FooTest : public BaseTest { protected: virtual void SetUp() { BaseTest::SetUp(); // Sets up the base fixture first. ... additional set-up work ... } virtual void TearDown() { ... clean-up work for FooTest ... BaseTest::TearDown(); // Remember to tear down the base fixture // after cleaning up FooTest! } ... functions and variables for FooTest ... }; // Tests that use the fixture FooTest. TEST_F(FooTest, Bar) { ... } TEST_F(FooTest, Baz) { ... } ... additional fixtures derived from BaseTest ... ``` If necessary, you can continue to derive test fixtures from a derived fixture. Google Test has no limit on how deep the hierarchy can be. For a complete example using derived test fixtures, see [sample5](../samples/sample5_unittest.cc). ## My compiler complains "void value not ignored as it ought to be." What does this mean? ## You're probably using an `ASSERT_*()` in a function that doesn't return `void`. `ASSERT_*()` can only be used in `void` functions. ## My death test hangs (or seg-faults). How do I fix it? ## In Google Test, death tests are run in a child process and the way they work is delicate. To write death tests you really need to understand how they work. Please make sure you have read this. In particular, death tests don't like having multiple threads in the parent process. So the first thing you can try is to eliminate creating threads outside of `EXPECT_DEATH()`. Sometimes this is impossible as some library you must use may be creating threads before `main()` is even reached. In this case, you can try to minimize the chance of conflicts by either moving as many activities as possible inside `EXPECT_DEATH()` (in the extreme case, you want to move everything inside), or leaving as few things as possible in it. Also, you can try to set the death test style to `"threadsafe"`, which is safer but slower, and see if it helps. If you go with thread-safe death tests, remember that they rerun the test program from the beginning in the child process. Therefore make sure your program can run side-by-side with itself and is deterministic. In the end, this boils down to good concurrent programming. You have to make sure that there is no race conditions or dead locks in your program. No silver bullet - sorry! ## Should I use the constructor/destructor of the test fixture or the set-up/tear-down function? ## The first thing to remember is that Google Test does not reuse the same test fixture object across multiple tests. For each `TEST_F`, Google Test will create a fresh test fixture object, _immediately_ call `SetUp()`, run the test, call `TearDown()`, and then _immediately_ delete the test fixture object. Therefore, there is no need to write a `SetUp()` or `TearDown()` function if the constructor or destructor already does the job. You may still want to use `SetUp()/TearDown()` in the following cases: * If the tear-down operation could throw an exception, you must use `TearDown()` as opposed to the destructor, as throwing in a destructor leads to undefined behavior and usually will kill your program right away. Note that many standard libraries (like STL) may throw when exceptions are enabled in the compiler. Therefore you should prefer `TearDown()` if you want to write portable tests that work with or without exceptions. * The assertion macros throw an exception when flag `--gtest_throw_on_failure` is specified. Therefore, you shouldn't use Google Test assertions in a destructor if you plan to run your tests with this flag. * In a constructor or destructor, you cannot make a virtual function call on this object. (You can call a method declared as virtual, but it will be statically bound.) Therefore, if you need to call a method that will be overriden in a derived class, you have to use `SetUp()/TearDown()`. ## The compiler complains "no matching function to call" when I use ASSERT\_PREDn. How do I fix it? ## If the predicate function you use in `ASSERT_PRED*` or `EXPECT_PRED*` is overloaded or a template, the compiler will have trouble figuring out which overloaded version it should use. `ASSERT_PRED_FORMAT*` and `EXPECT_PRED_FORMAT*` don't have this problem. If you see this error, you might want to switch to `(ASSERT|EXPECT)_PRED_FORMAT*`, which will also give you a better failure message. If, however, that is not an option, you can resolve the problem by explicitly telling the compiler which version to pick. For example, suppose you have ``` bool IsPositive(int n) { return n > 0; } bool IsPositive(double x) { return x > 0; } ``` you will get a compiler error if you write ``` EXPECT_PRED1(IsPositive, 5); ``` However, this will work: ``` EXPECT_PRED1(*static_cast*(IsPositive), 5); ``` (The stuff inside the angled brackets for the `static_cast` operator is the type of the function pointer for the `int`-version of `IsPositive()`.) As another example, when you have a template function ``` template bool IsNegative(T x) { return x < 0; } ``` you can use it in a predicate assertion like this: ``` ASSERT_PRED1(IsNegative**, -5); ``` Things are more interesting if your template has more than one parameters. The following won't compile: ``` ASSERT_PRED2(*GreaterThan*, 5, 0); ``` as the C++ pre-processor thinks you are giving `ASSERT_PRED2` 4 arguments, which is one more than expected. The workaround is to wrap the predicate function in parentheses: ``` ASSERT_PRED2(*(GreaterThan)*, 5, 0); ``` ## My compiler complains about "ignoring return value" when I call RUN\_ALL\_TESTS(). Why? ## Some people had been ignoring the return value of `RUN_ALL_TESTS()`. That is, instead of ``` return RUN_ALL_TESTS(); ``` they write ``` RUN_ALL_TESTS(); ``` This is wrong and dangerous. A test runner needs to see the return value of `RUN_ALL_TESTS()` in order to determine if a test has passed. If your `main()` function ignores it, your test will be considered successful even if it has a Google Test assertion failure. Very bad. To help the users avoid this dangerous bug, the implementation of `RUN_ALL_TESTS()` causes gcc to raise this warning, when the return value is ignored. If you see this warning, the fix is simple: just make sure its value is used as the return value of `main()`. ## My compiler complains that a constructor (or destructor) cannot return a value. What's going on? ## Due to a peculiarity of C++, in order to support the syntax for streaming messages to an `ASSERT_*`, e.g. ``` ASSERT_EQ(1, Foo()) << "blah blah" << foo; ``` we had to give up using `ASSERT*` and `FAIL*` (but not `EXPECT*` and `ADD_FAILURE*`) in constructors and destructors. The workaround is to move the content of your constructor/destructor to a private void member function, or switch to `EXPECT_*()` if that works. This section in the user's guide explains it. ## My set-up function is not called. Why? ## C++ is case-sensitive. It should be spelled as `SetUp()`. Did you spell it as `Setup()`? Similarly, sometimes people spell `SetUpTestCase()` as `SetupTestCase()` and wonder why it's never called. ## How do I jump to the line of a failure in Emacs directly? ## Google Test's failure message format is understood by Emacs and many other IDEs, like acme and XCode. If a Google Test message is in a compilation buffer in Emacs, then it's clickable. You can now hit `enter` on a message to jump to the corresponding source code, or use `C-x `` to jump to the next failure. ## I have several test cases which share the same test fixture logic, do I have to define a new test fixture class for each of them? This seems pretty tedious. ## You don't have to. Instead of ``` class FooTest : public BaseTest {}; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } class BarTest : public BaseTest {}; TEST_F(BarTest, Abc) { ... } TEST_F(BarTest, Def) { ... } ``` you can simply `typedef` the test fixtures: ``` typedef BaseTest FooTest; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } typedef BaseTest BarTest; TEST_F(BarTest, Abc) { ... } TEST_F(BarTest, Def) { ... } ``` ## The Google Test output is buried in a whole bunch of log messages. What do I do? ## The Google Test output is meant to be a concise and human-friendly report. If your test generates textual output itself, it will mix with the Google Test output, making it hard to read. However, there is an easy solution to this problem. Since most log messages go to stderr, we decided to let Google Test output go to stdout. This way, you can easily separate the two using redirection. For example: ``` ./my_test > googletest_output.txt ``` ## Why should I prefer test fixtures over global variables? ## There are several good reasons: 1. It's likely your test needs to change the states of its global variables. This makes it difficult to keep side effects from escaping one test and contaminating others, making debugging difficult. By using fixtures, each test has a fresh set of variables that's different (but with the same names). Thus, tests are kept independent of each other. 1. Global variables pollute the global namespace. 1. Test fixtures can be reused via subclassing, which cannot be done easily with global variables. This is useful if many test cases have something in common. ## How do I test private class members without writing FRIEND\_TEST()s? ## You should try to write testable code, which means classes should be easily tested from their public interface. One way to achieve this is the Pimpl idiom: you move all private members of a class into a helper class, and make all members of the helper class public. You have several other options that don't require using `FRIEND_TEST`: * Write the tests as members of the fixture class: ``` class Foo { friend class FooTest; ... }; class FooTest : public ::testing::Test { protected: ... void Test1() {...} // This accesses private members of class Foo. void Test2() {...} // So does this one. }; TEST_F(FooTest, Test1) { Test1(); } TEST_F(FooTest, Test2) { Test2(); } ``` * In the fixture class, write accessors for the tested class' private members, then use the accessors in your tests: ``` class Foo { friend class FooTest; ... }; class FooTest : public ::testing::Test { protected: ... T1 get_private_member1(Foo* obj) { return obj->private_member1_; } }; TEST_F(FooTest, Test1) { ... get_private_member1(x) ... } ``` * If the methods are declared **protected**, you can change their access level in a test-only subclass: ``` class YourClass { ... protected: // protected access for testability. int DoSomethingReturningInt(); ... }; // in the your_class_test.cc file: class TestableYourClass : public YourClass { ... public: using YourClass::DoSomethingReturningInt; // changes access rights ... }; TEST_F(YourClassTest, DoSomethingTest) { TestableYourClass obj; assertEquals(expected_value, obj.DoSomethingReturningInt()); } ``` ## How do I test private class static members without writing FRIEND\_TEST()s? ## We find private static methods clutter the header file. They are implementation details and ideally should be kept out of a .h. So often I make them free functions instead. Instead of: ``` // foo.h class Foo { ... private: static bool Func(int n); }; // foo.cc bool Foo::Func(int n) { ... } // foo_test.cc EXPECT_TRUE(Foo::Func(12345)); ``` You probably should better write: ``` // foo.h class Foo { ... }; // foo.cc namespace internal { bool Func(int n) { ... } } // foo_test.cc namespace internal { bool Func(int n); } EXPECT_TRUE(internal::Func(12345)); ``` ## I would like to run a test several times with different parameters. Do I need to write several similar copies of it? ## No. You can use a feature called [value-parameterized tests](V1_7_AdvancedGuide.md#Value_Parameterized_Tests) which lets you repeat your tests with different parameters, without defining it more than once. ## How do I test a file that defines main()? ## To test a `foo.cc` file, you need to compile and link it into your unit test program. However, when the file contains a definition for the `main()` function, it will clash with the `main()` of your unit test, and will result in a build error. The right solution is to split it into three files: 1. `foo.h` which contains the declarations, 1. `foo.cc` which contains the definitions except `main()`, and 1. `foo_main.cc` which contains nothing but the definition of `main()`. Then `foo.cc` can be easily tested. If you are adding tests to an existing file and don't want an intrusive change like this, there is a hack: just include the entire `foo.cc` file in your unit test. For example: ``` // File foo_unittest.cc // The headers section ... // Renames main() in foo.cc to make room for the unit test main() #define main FooMain #include "a/b/foo.cc" // The tests start here. ... ``` However, please remember this is a hack and should only be used as the last resort. ## What can the statement argument in ASSERT\_DEATH() be? ## `ASSERT_DEATH(_statement_, _regex_)` (or any death assertion macro) can be used wherever `_statement_` is valid. So basically `_statement_` can be any C++ statement that makes sense in the current context. In particular, it can reference global and/or local variables, and can be: * a simple function call (often the case), * a complex expression, or * a compound statement. > Some examples are shown here: ``` // A death test can be a simple function call. TEST(MyDeathTest, FunctionCall) { ASSERT_DEATH(Xyz(5), "Xyz failed"); } // Or a complex expression that references variables and functions. TEST(MyDeathTest, ComplexExpression) { const bool c = Condition(); ASSERT_DEATH((c ? Func1(0) : object2.Method("test")), "(Func1|Method) failed"); } // Death assertions can be used any where in a function. In // particular, they can be inside a loop. TEST(MyDeathTest, InsideLoop) { // Verifies that Foo(0), Foo(1), ..., and Foo(4) all die. for (int i = 0; i < 5; i++) { EXPECT_DEATH_M(Foo(i), "Foo has \\d+ errors", ::testing::Message() << "where i is " << i); } } // A death assertion can contain a compound statement. TEST(MyDeathTest, CompoundStatement) { // Verifies that at lease one of Bar(0), Bar(1), ..., and // Bar(4) dies. ASSERT_DEATH({ for (int i = 0; i < 5; i++) { Bar(i); } }, "Bar has \\d+ errors");} ``` `googletest_unittest.cc` contains more examples if you are interested. ## What syntax does the regular expression in ASSERT\_DEATH use? ## On POSIX systems, Google Test uses the POSIX Extended regular expression syntax (http://en.wikipedia.org/wiki/Regular_expression#POSIX_Extended_Regular_Expressions). On Windows, it uses a limited variant of regular expression syntax. For more details, see the [regular expression syntax](V1_7_AdvancedGuide.md#Regular_Expression_Syntax). ## I have a fixture class Foo, but TEST\_F(Foo, Bar) gives me error "no matching function for call to Foo::Foo()". Why? ## Google Test needs to be able to create objects of your test fixture class, so it must have a default constructor. Normally the compiler will define one for you. However, there are cases where you have to define your own: * If you explicitly declare a non-default constructor for class `Foo`, then you need to define a default constructor, even if it would be empty. * If `Foo` has a const non-static data member, then you have to define the default constructor _and_ initialize the const member in the initializer list of the constructor. (Early versions of `gcc` doesn't force you to initialize the const member. It's a bug that has been fixed in `gcc 4`.) ## Why does ASSERT\_DEATH complain about previous threads that were already joined? ## With the Linux pthread library, there is no turning back once you cross the line from single thread to multiple threads. The first time you create a thread, a manager thread is created in addition, so you get 3, not 2, threads. Later when the thread you create joins the main thread, the thread count decrements by 1, but the manager thread will never be killed, so you still have 2 threads, which means you cannot safely run a death test. The new NPTL thread library doesn't suffer from this problem, as it doesn't create a manager thread. However, if you don't control which machine your test runs on, you shouldn't depend on this. ## Why does Google Test require the entire test case, instead of individual tests, to be named FOODeathTest when it uses ASSERT\_DEATH? ## Google Test does not interleave tests from different test cases. That is, it runs all tests in one test case first, and then runs all tests in the next test case, and so on. Google Test does this because it needs to set up a test case before the first test in it is run, and tear it down afterwords. Splitting up the test case would require multiple set-up and tear-down processes, which is inefficient and makes the semantics unclean. If we were to determine the order of tests based on test name instead of test case name, then we would have a problem with the following situation: ``` TEST_F(FooTest, AbcDeathTest) { ... } TEST_F(FooTest, Uvw) { ... } TEST_F(BarTest, DefDeathTest) { ... } TEST_F(BarTest, Xyz) { ... } ``` Since `FooTest.AbcDeathTest` needs to run before `BarTest.Xyz`, and we don't interleave tests from different test cases, we need to run all tests in the `FooTest` case before running any test in the `BarTest` case. This contradicts with the requirement to run `BarTest.DefDeathTest` before `FooTest.Uvw`. ## But I don't like calling my entire test case FOODeathTest when it contains both death tests and non-death tests. What do I do? ## You don't have to, but if you like, you may split up the test case into `FooTest` and `FooDeathTest`, where the names make it clear that they are related: ``` class FooTest : public ::testing::Test { ... }; TEST_F(FooTest, Abc) { ... } TEST_F(FooTest, Def) { ... } typedef FooTest FooDeathTest; TEST_F(FooDeathTest, Uvw) { ... EXPECT_DEATH(...) ... } TEST_F(FooDeathTest, Xyz) { ... ASSERT_DEATH(...) ... } ``` ## The compiler complains about "no match for 'operator<<'" when I use an assertion. What gives? ## If you use a user-defined type `FooType` in an assertion, you must make sure there is an `std::ostream& operator<<(std::ostream&, const FooType&)` function defined such that we can print a value of `FooType`. In addition, if `FooType` is declared in a name space, the `<<` operator also needs to be defined in the _same_ name space. ## How do I suppress the memory leak messages on Windows? ## Since the statically initialized Google Test singleton requires allocations on the heap, the Visual C++ memory leak detector will report memory leaks at the end of the program run. The easiest way to avoid this is to use the `_CrtMemCheckpoint` and `_CrtMemDumpAllObjectsSince` calls to not report any statically initialized heap objects. See MSDN for more details and additional heap check/debug routines. ## I am building my project with Google Test in Visual Studio and all I'm getting is a bunch of linker errors (or warnings). Help! ## You may get a number of the following linker error or warnings if you attempt to link your test project with the Google Test library when your project and the are not built using the same compiler settings. * LNK2005: symbol already defined in object * LNK4217: locally defined symbol 'symbol' imported in function 'function' * LNK4049: locally defined symbol 'symbol' imported The Google Test project (gtest.vcproj) has the Runtime Library option set to /MT (use multi-threaded static libraries, /MTd for debug). If your project uses something else, for example /MD (use multi-threaded DLLs, /MDd for debug), you need to change the setting in the Google Test project to match your project's. To update this setting open the project properties in the Visual Studio IDE then select the branch Configuration Properties | C/C++ | Code Generation and change the option "Runtime Library". You may also try using gtest-md.vcproj instead of gtest.vcproj. ## I put my tests in a library and Google Test doesn't run them. What's happening? ## Have you read a [warning](V1_7_Primer.md#important-note-for-visual-c-users) on the Google Test Primer page? ## I want to use Google Test with Visual Studio but don't know where to start. ## Many people are in your position and one of the posted his solution to our mailing list. Here is his link: http://hassanjamilahmad.blogspot.com/2009/07/gtest-starters-help.html. ## I am seeing compile errors mentioning std::type\_traits when I try to use Google Test on Solaris. ## Google Test uses parts of the standard C++ library that SunStudio does not support. Our users reported success using alternative implementations. Try running the build after runing this commad: `export CC=cc CXX=CC CXXFLAGS='-library=stlport4'` ## How can my code detect if it is running in a test? ## If you write code that sniffs whether it's running in a test and does different things accordingly, you are leaking test-only logic into production code and there is no easy way to ensure that the test-only code paths aren't run by mistake in production. Such cleverness also leads to [Heisenbugs](http://en.wikipedia.org/wiki/Unusual_software_bug#Heisenbug). Therefore we strongly advise against the practice, and Google Test doesn't provide a way to do it. In general, the recommended way to cause the code to behave differently under test is [dependency injection](http://jamesshore.com/Blog/Dependency-Injection-Demystified.html). You can inject different functionality from the test and from the production code. Since your production code doesn't link in the for-test logic at all, there is no danger in accidentally running it. However, if you _really_, _really_, _really_ have no choice, and if you follow the rule of ending your test program names with `_test`, you can use the _horrible_ hack of sniffing your executable name (`argv[0]` in `main()`) to know whether the code is under test. ## Google Test defines a macro that clashes with one defined by another library. How do I deal with that? ## 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`. 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. Currently, the following `TEST`, `FAIL`, `SUCCEED`, and the basic comparison assertion macros can have alternative names. You can see the full list of covered macros [here](http://www.google.com/codesearch?q=if+!GTEST_DONT_DEFINE_\w%2B+package:http://googletest\.googlecode\.com+file:/include/gtest/gtest.h). More information can be found in the "Avoiding Macro Name Clashes" section of the README file. ## Is it OK if I have two separate `TEST(Foo, Bar)` test methods defined in different namespaces? ## Yes. The rule is **all test methods in the same test case must use the same fixture class**. This means that the following is **allowed** because both tests use the same fixture class (`::testing::Test`). ``` namespace foo { TEST(CoolTest, DoSomething) { SUCCEED(); } } // namespace foo namespace bar { TEST(CoolTest, DoSomething) { SUCCEED(); } } // namespace foo ``` However, the following code is **not allowed** and will produce a runtime error from Google Test because the test methods are using different test fixture classes with the same test case name. ``` namespace foo { class CoolTest : public ::testing::Test {}; // Fixture foo::CoolTest TEST_F(CoolTest, DoSomething) { SUCCEED(); } } // namespace foo namespace bar { class CoolTest : public ::testing::Test {}; // Fixture: bar::CoolTest TEST_F(CoolTest, DoSomething) { SUCCEED(); } } // namespace foo ``` ## How do I build Google Testing Framework with Xcode 4? ## If you try to build Google Test's Xcode project with Xcode 4.0 or later, you may encounter an error message that looks like "Missing SDK in target gtest\_framework: /Developer/SDKs/MacOSX10.4u.sdk". That means that Xcode does not support the SDK the project is targeting. See the Xcode section in the [README](../../README.MD) file on how to resolve this. ## My question is not covered in your FAQ! ## If you cannot find the answer to your question in this FAQ, there are some other resources you can use: 1. read other [wiki pages](http://code.google.com/p/googletest/w/list), 1. search the mailing list [archive](http://groups.google.com/group/googletestframework/topics), 1. ask it on [googletestframework@googlegroups.com](mailto:googletestframework@googlegroups.com) and someone will answer it (to prevent spam, we require you to join the [discussion group](http://groups.google.com/group/googletestframework) before you can post.). Please note that creating an issue in the [issue tracker](http://code.google.com/p/googletest/issues/list) is _not_ a good way to get your answer, as it is monitored infrequently by a very small number of people. When asking a question, it's helpful to provide as much of the following information as possible (people cannot help you if there's not enough information in your question): * the version (or the revision number if you check out from SVN directly) of Google Test you use (Google Test is under active development, so it's possible that your problem has been solved in a later version), * your operating system, * the name and version of your compiler, * the complete command line flags you give to your compiler, * the complete compiler error messages (if the question is about compilation), * the _actual_ code (ideally, a minimal but complete program) that has the problem you encounter. assimp-4.1.0/contrib/gtest/docs/V1_6_AdvancedGuide.md0000644002537200234200000025214113213503245022577 0ustar zmoelnigiemusers Now that you have read [Primer](V1_6_Primer.md) and learned how to write tests using Google Test, it's time to learn some new tricks. This document will show you more assertions as well as how to construct complex failure messages, propagate fatal failures, reuse and speed up your test fixtures, and use various flags with your tests. # More Assertions # This section covers some less frequently used, but still significant, assertions. ## Explicit Success and Failure ## These three assertions do not actually test a value or expression. Instead, they generate a success or failure directly. Like the macros that actually perform a test, you may stream a custom failure message into the them. | `SUCCEED();` | |:-------------| Generates a success. This does NOT make the overall test succeed. A test is considered successful only if none of its assertions fail during its execution. Note: `SUCCEED()` is purely documentary and currently doesn't generate any user-visible output. However, we may add `SUCCEED()` messages to Google Test's output in the future. | `FAIL();` | `ADD_FAILURE();` | `ADD_FAILURE_AT("`_file\_path_`", `_line\_number_`);` | |:-----------|:-----------------|:------------------------------------------------------| `FAIL()` generates a fatal failure, while `ADD_FAILURE()` and `ADD_FAILURE_AT()` generate a nonfatal failure. These are useful when control flow, rather than a Boolean expression, deteremines the test's success or failure. For example, you might want to write something like: ``` switch(expression) { case 1: ... some checks ... case 2: ... some other checks ... default: FAIL() << "We shouldn't get here."; } ``` _Availability_: Linux, Windows, Mac. ## Exception Assertions ## These are for verifying that a piece of code throws (or does not throw) an exception of the given type: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_THROW(`_statement_, _exception\_type_`);` | `EXPECT_THROW(`_statement_, _exception\_type_`);` | _statement_ throws an exception of the given type | | `ASSERT_ANY_THROW(`_statement_`);` | `EXPECT_ANY_THROW(`_statement_`);` | _statement_ throws an exception of any type | | `ASSERT_NO_THROW(`_statement_`);` | `EXPECT_NO_THROW(`_statement_`);` | _statement_ doesn't throw any exception | Examples: ``` ASSERT_THROW(Foo(5), bar_exception); EXPECT_NO_THROW({ int n = 5; Bar(&n); }); ``` _Availability_: Linux, Windows, Mac; since version 1.1.0. ## Predicate Assertions for Better Error Messages ## Even though Google Test has a rich set of assertions, they can never be complete, as it's impossible (nor a good idea) to anticipate all the scenarios a user might run into. Therefore, sometimes a user has to use `EXPECT_TRUE()` to check a complex expression, for lack of a better macro. This has the problem of not showing you the values of the parts of the expression, making it hard to understand what went wrong. As a workaround, some users choose to construct the failure message by themselves, streaming it into `EXPECT_TRUE()`. However, this is awkward especially when the expression has side-effects or is expensive to evaluate. Google Test gives you three different options to solve this problem: ### Using an Existing Boolean Function ### If you already have a function or a functor that returns `bool` (or a type that can be implicitly converted to `bool`), you can use it in a _predicate assertion_ to get the function arguments printed for free: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_PRED1(`_pred1, val1_`);` | `EXPECT_PRED1(`_pred1, val1_`);` | _pred1(val1)_ returns true | | `ASSERT_PRED2(`_pred2, val1, val2_`);` | `EXPECT_PRED2(`_pred2, val1, val2_`);` | _pred2(val1, val2)_ returns true | | ... | ... | ... | In the above, _predn_ is an _n_-ary predicate function or functor, where _val1_, _val2_, ..., and _valn_ are its arguments. The assertion succeeds if the predicate returns `true` when applied to the given arguments, and fails otherwise. When the assertion fails, it prints the value of each argument. In either case, the arguments are evaluated exactly once. Here's an example. Given ``` // Returns true iff m and n have no common divisors except 1. bool MutuallyPrime(int m, int n) { ... } const int a = 3; const int b = 4; const int c = 10; ``` the assertion `EXPECT_PRED2(MutuallyPrime, a, b);` will succeed, while the assertion `EXPECT_PRED2(MutuallyPrime, b, c);` will fail with the message
!MutuallyPrime(b, c) is false, where
b is 4
c is 10
**Notes:** 1. If you see a compiler error "no matching function to call" when using `ASSERT_PRED*` or `EXPECT_PRED*`, please see [this](v1_6_FAQ.md#ithe-compiler-complains-about-undefined-references-to-some-static-const-member-variables-but-i-did-define-them-in-the-class-body-whats-wrong) for how to resolve it. 1. Currently we only provide predicate assertions of arity <= 5. If you need a higher-arity assertion, let us know. _Availability_: Linux, Windows, Mac ### Using a Function That Returns an AssertionResult ### While `EXPECT_PRED*()` and friends are handy for a quick job, the syntax is not satisfactory: you have to use different macros for different arities, and it feels more like Lisp than C++. The `::testing::AssertionResult` class solves this problem. An `AssertionResult` object represents the result of an assertion (whether it's a success or a failure, and an associated message). You can create an `AssertionResult` using one of these factory functions: ``` namespace testing { // Returns an AssertionResult object to indicate that an assertion has // succeeded. AssertionResult AssertionSuccess(); // Returns an AssertionResult object to indicate that an assertion has // failed. AssertionResult AssertionFailure(); } ``` You can then use the `<<` operator to stream messages to the `AssertionResult` object. To provide more readable messages in Boolean assertions (e.g. `EXPECT_TRUE()`), write a predicate function that returns `AssertionResult` instead of `bool`. For example, if you define `IsEven()` as: ``` ::testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return ::testing::AssertionSuccess(); else return ::testing::AssertionFailure() << n << " is odd"; } ``` instead of: ``` bool IsEven(int n) { return (n % 2) == 0; } ``` the failed assertion `EXPECT_TRUE(IsEven(Fib(4)))` will print:
Value of: !IsEven(Fib(4))
Actual: false (*3 is odd*)
Expected: true
instead of a more opaque
Value of: !IsEven(Fib(4))
Actual: false
Expected: true
If you want informative messages in `EXPECT_FALSE` and `ASSERT_FALSE` as well, and are fine with making the predicate slower in the success case, you can supply a success message: ``` ::testing::AssertionResult IsEven(int n) { if ((n % 2) == 0) return ::testing::AssertionSuccess() << n << " is even"; else return ::testing::AssertionFailure() << n << " is odd"; } ``` Then the statement `EXPECT_FALSE(IsEven(Fib(6)))` will print
Value of: !IsEven(Fib(6))
Actual: true (8 is even)
Expected: false
_Availability_: Linux, Windows, Mac; since version 1.4.1. ### Using a Predicate-Formatter ### If you find the default message generated by `(ASSERT|EXPECT)_PRED*` and `(ASSERT|EXPECT)_(TRUE|FALSE)` unsatisfactory, or some arguments to your predicate do not support streaming to `ostream`, you can instead use the following _predicate-formatter assertions_ to _fully_ customize how the message is formatted: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_PRED_FORMAT1(`_pred\_format1, val1_`);` | `EXPECT_PRED_FORMAT1(`_pred\_format1, val1_`); | _pred\_format1(val1)_ is successful | | `ASSERT_PRED_FORMAT2(`_pred\_format2, val1, val2_`);` | `EXPECT_PRED_FORMAT2(`_pred\_format2, val1, val2_`);` | _pred\_format2(val1, val2)_ is successful | | `...` | `...` | `...` | The difference between this and the previous two groups of macros is that instead of a predicate, `(ASSERT|EXPECT)_PRED_FORMAT*` take a _predicate-formatter_ (_pred\_formatn_), which is a function or functor with the signature: `::testing::AssertionResult PredicateFormattern(const char* `_expr1_`, const char* `_expr2_`, ... const char* `_exprn_`, T1 `_val1_`, T2 `_val2_`, ... Tn `_valn_`);` where _val1_, _val2_, ..., and _valn_ are the values of the predicate arguments, and _expr1_, _expr2_, ..., and _exprn_ are the corresponding expressions as they appear in the source code. The types `T1`, `T2`, ..., and `Tn` can be either value types or reference types. For example, if an argument has type `Foo`, you can declare it as either `Foo` or `const Foo&`, whichever is appropriate. A predicate-formatter returns a `::testing::AssertionResult` object to indicate whether the assertion has succeeded or not. The only way to create such an object is to call one of these factory functions: As an example, let's improve the failure message in the previous example, which uses `EXPECT_PRED2()`: ``` // Returns the smallest prime common divisor of m and n, // or 1 when m and n are mutually prime. int SmallestPrimeCommonDivisor(int m, int n) { ... } // A predicate-formatter for asserting that two integers are mutually prime. ::testing::AssertionResult AssertMutuallyPrime(const char* m_expr, const char* n_expr, int m, int n) { if (MutuallyPrime(m, n)) return ::testing::AssertionSuccess(); return ::testing::AssertionFailure() << m_expr << " and " << n_expr << " (" << m << " and " << n << ") are not mutually prime, " << "as they have a common divisor " << SmallestPrimeCommonDivisor(m, n); } ``` With this predicate-formatter, we can use ``` EXPECT_PRED_FORMAT2(AssertMutuallyPrime, b, c); ``` to generate the message
b and c (4 and 10) are not mutually prime, as they have a common divisor 2.
As you may have realized, many of the assertions we introduced earlier are special cases of `(EXPECT|ASSERT)_PRED_FORMAT*`. In fact, most of them are indeed defined using `(EXPECT|ASSERT)_PRED_FORMAT*`. _Availability_: Linux, Windows, Mac. ## Floating-Point Comparison ## Comparing floating-point numbers is tricky. Due to round-off errors, it is very unlikely that two floating-points will match exactly. Therefore, `ASSERT_EQ` 's naive comparison usually doesn't work. And since floating-points can have a wide value range, no single fixed error bound works. It's better to compare by a fixed relative error bound, except for values close to 0 due to the loss of precision there. In general, for floating-point comparison to make sense, the user needs to carefully choose the error bound. If they don't want or care to, comparing in terms of Units in the Last Place (ULPs) is a good default, and Google Test provides assertions to do this. Full details about ULPs are quite long; if you want to learn more, see [this article on float comparison](http://www.cygnus-software.com/papers/comparingfloats/comparingfloats.htm). ### Floating-Point Macros ### | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_FLOAT_EQ(`_expected, actual_`);` | `EXPECT_FLOAT_EQ(`_expected, actual_`);` | the two `float` values are almost equal | | `ASSERT_DOUBLE_EQ(`_expected, actual_`);` | `EXPECT_DOUBLE_EQ(`_expected, actual_`);` | the two `double` values are almost equal | By "almost equal", we mean the two values are within 4 ULP's from each other. The following assertions allow you to choose the acceptable error bound: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_NEAR(`_val1, val2, abs\_error_`);` | `EXPECT_NEAR`_(val1, val2, abs\_error_`);` | the difference between _val1_ and _val2_ doesn't exceed the given absolute error | _Availability_: Linux, Windows, Mac. ### Floating-Point Predicate-Format Functions ### Some floating-point operations are useful, but not that often used. In order to avoid an explosion of new macros, we provide them as predicate-format functions that can be used in predicate assertion macros (e.g. `EXPECT_PRED_FORMAT2`, etc). ``` EXPECT_PRED_FORMAT2(::testing::FloatLE, val1, val2); EXPECT_PRED_FORMAT2(::testing::DoubleLE, val1, val2); ``` Verifies that _val1_ is less than, or almost equal to, _val2_. You can replace `EXPECT_PRED_FORMAT2` in the above table with `ASSERT_PRED_FORMAT2`. _Availability_: Linux, Windows, Mac. ## Windows HRESULT assertions ## These assertions test for `HRESULT` success or failure. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_HRESULT_SUCCEEDED(`_expression_`);` | `EXPECT_HRESULT_SUCCEEDED(`_expression_`);` | _expression_ is a success `HRESULT` | | `ASSERT_HRESULT_FAILED(`_expression_`);` | `EXPECT_HRESULT_FAILED(`_expression_`);` | _expression_ is a failure `HRESULT` | The generated output contains the human-readable error message associated with the `HRESULT` code returned by _expression_. You might use them like this: ``` CComPtr shell; ASSERT_HRESULT_SUCCEEDED(shell.CoCreateInstance(L"Shell.Application")); CComVariant empty; ASSERT_HRESULT_SUCCEEDED(shell->ShellExecute(CComBSTR(url), empty, empty, empty, empty)); ``` _Availability_: Windows. ## Type Assertions ## You can call the function ``` ::testing::StaticAssertTypeEq(); ``` to assert that types `T1` and `T2` are the same. The function does nothing if the assertion is satisfied. If the types are different, the function call will fail to compile, and the compiler error message will likely (depending on the compiler) show you the actual values of `T1` and `T2`. This is mainly useful inside template code. _Caveat:_ When used inside a member function of a class template or a function template, `StaticAssertTypeEq()` is effective _only if_ the function is instantiated. For example, given: ``` template class Foo { public: void Bar() { ::testing::StaticAssertTypeEq(); } }; ``` the code: ``` void Test1() { Foo foo; } ``` will _not_ generate a compiler error, as `Foo::Bar()` is never actually instantiated. Instead, you need: ``` void Test2() { Foo foo; foo.Bar(); } ``` to cause a compiler error. _Availability:_ Linux, Windows, Mac; since version 1.3.0. ## Assertion Placement ## You can use assertions in any C++ function. In particular, it doesn't have to be a method of the test fixture class. The one constraint is that assertions that generate a fatal failure (`FAIL*` and `ASSERT_*`) can only be used in void-returning functions. This is a consequence of Google Test not using exceptions. By placing it in a non-void function you'll get a confusing compile error like `"error: void value not ignored as it ought to be"`. If you need to use assertions in a function that returns non-void, one option is to make the function return the value in an out parameter instead. For example, you can rewrite `T2 Foo(T1 x)` to `void Foo(T1 x, T2* result)`. You need to make sure that `*result` contains some sensible value even when the function returns prematurely. As the function now returns `void`, you can use any assertion inside of it. If changing the function's type is not an option, you should just use assertions that generate non-fatal failures, such as `ADD_FAILURE*` and `EXPECT_*`. _Note_: Constructors and destructors are not considered void-returning functions, according to the C++ language specification, and so you may not use fatal assertions in them. You'll get a compilation error if you try. A simple workaround is to transfer the entire body of the constructor or destructor to a private void-returning method. However, you should be aware that a fatal assertion failure in a constructor does not terminate the current test, as your intuition might suggest; it merely returns from the constructor early, possibly leaving your object in a partially-constructed state. Likewise, a fatal assertion failure in a destructor may leave your object in a partially-destructed state. Use assertions carefully in these situations! # Teaching Google Test How to Print Your Values # When a test assertion such as `EXPECT_EQ` fails, Google Test prints the argument values to help you debug. It does this using a user-extensible value printer. This printer knows how to print built-in C++ types, native arrays, STL containers, and any type that supports the `<<` operator. For other types, it prints the raw bytes in the value and hopes that you the user can figure it out. As mentioned earlier, the printer is _extensible_. That means you can teach it to do a better job at printing your particular type than to dump the bytes. To do that, define `<<` for your type: ``` #include namespace foo { class Bar { ... }; // We want Google Test to be able to print instances of this. // It's important that the << operator is defined in the SAME // namespace that defines Bar. C++'s look-up rules rely on that. ::std::ostream& operator<<(::std::ostream& os, const Bar& bar) { return os << bar.DebugString(); // whatever needed to print bar to os } } // namespace foo ``` Sometimes, this might not be an option: your team may consider it bad style to have a `<<` operator for `Bar`, or `Bar` may already have a `<<` operator that doesn't do what you want (and you cannot change it). If so, you can instead define a `PrintTo()` function like this: ``` #include namespace foo { class Bar { ... }; // It's important that PrintTo() is defined in the SAME // namespace that defines Bar. C++'s look-up rules rely on that. void PrintTo(const Bar& bar, ::std::ostream* os) { *os << bar.DebugString(); // whatever needed to print bar to os } } // namespace foo ``` If you have defined both `<<` and `PrintTo()`, the latter will be used when Google Test is concerned. This allows you to customize how the value appears in Google Test's output without affecting code that relies on the behavior of its `<<` operator. If you want to print a value `x` using Google Test's value printer yourself, just call `::testing::PrintToString(`_x_`)`, which returns an `std::string`: ``` vector > bar_ints = GetBarIntVector(); EXPECT_TRUE(IsCorrectBarIntVector(bar_ints)) << "bar_ints = " << ::testing::PrintToString(bar_ints); ``` # Death Tests # In many applications, there are assertions that can cause application failure if a condition is not met. These sanity checks, which ensure that the program is in a known good state, are there to fail at the earliest possible time after some program state is corrupted. If the assertion checks the wrong condition, then the program may proceed in an erroneous state, which could lead to memory corruption, security holes, or worse. Hence it is vitally important to test that such assertion statements work as expected. Since these precondition checks cause the processes to die, we call such tests _death tests_. More generally, any test that checks that a program terminates (except by throwing an exception) in an expected fashion is also a death test. Note that if a piece of code throws an exception, we don't consider it "death" for the purpose of death tests, as the caller of the code could catch the exception and avoid the crash. If you want to verify exceptions thrown by your code, see [Exception Assertions](#exception-assertions). If you want to test `EXPECT_*()/ASSERT_*()` failures in your test code, see [Catching Failures](#catching-failures). ## How to Write a Death Test ## Google Test has the following macros to support death tests: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_DEATH(`_statement, regex_`); | `EXPECT_DEATH(`_statement, regex_`); | _statement_ crashes with the given error | | `ASSERT_DEATH_IF_SUPPORTED(`_statement, regex_`); | `EXPECT_DEATH_IF_SUPPORTED(`_statement, regex_`); | if death tests are supported, verifies that _statement_ crashes with the given error; otherwise verifies nothing | | `ASSERT_EXIT(`_statement, predicate, regex_`); | `EXPECT_EXIT(`_statement, predicate, regex_`); |_statement_ exits with the given error and its exit code matches _predicate_ | where _statement_ is a statement that is expected to cause the process to die, _predicate_ is a function or function object that evaluates an integer exit status, and _regex_ is a regular expression that the stderr output of _statement_ is expected to match. Note that _statement_ can be _any valid statement_ (including _compound statement_) and doesn't have to be an expression. As usual, the `ASSERT` variants abort the current test function, while the `EXPECT` variants do not. **Note:** We use the word "crash" here to mean that the process terminates with a _non-zero_ exit status code. There are two possibilities: either the process has called `exit()` or `_exit()` with a non-zero value, or it may be killed by a signal. This means that if _statement_ terminates the process with a 0 exit code, it is _not_ considered a crash by `EXPECT_DEATH`. Use `EXPECT_EXIT` instead if this is the case, or if you want to restrict the exit code more precisely. A predicate here must accept an `int` and return a `bool`. The death test succeeds only if the predicate returns `true`. Google Test defines a few predicates that handle the most common cases: ``` ::testing::ExitedWithCode(exit_code) ``` This expression is `true` if the program exited normally with the given exit code. ``` ::testing::KilledBySignal(signal_number) // Not available on Windows. ``` This expression is `true` if the program was killed by the given signal. The `*_DEATH` macros are convenient wrappers for `*_EXIT` that use a predicate that verifies the process' exit code is non-zero. Note that a death test only cares about three things: 1. does _statement_ abort or exit the process? 1. (in the case of `ASSERT_EXIT` and `EXPECT_EXIT`) does the exit status satisfy _predicate_? Or (in the case of `ASSERT_DEATH` and `EXPECT_DEATH`) is the exit status non-zero? And 1. does the stderr output match _regex_? In particular, if _statement_ generates an `ASSERT_*` or `EXPECT_*` failure, it will **not** cause the death test to fail, as Google Test assertions don't abort the process. To write a death test, simply use one of the above macros inside your test function. For example, ``` TEST(My*DeathTest*, Foo) { // This death test uses a compound statement. ASSERT_DEATH({ int n = 5; Foo(&n); }, "Error on line .* of Foo()"); } TEST(MyDeathTest, NormalExit) { EXPECT_EXIT(NormalExit(), ::testing::ExitedWithCode(0), "Success"); } TEST(MyDeathTest, KillMyself) { EXPECT_EXIT(KillMyself(), ::testing::KilledBySignal(SIGKILL), "Sending myself unblockable signal"); } ``` verifies that: * calling `Foo(5)` causes the process to die with the given error message, * calling `NormalExit()` causes the process to print `"Success"` to stderr and exit with exit code 0, and * calling `KillMyself()` kills the process with signal `SIGKILL`. The test function body may contain other assertions and statements as well, if necessary. _Important:_ We strongly recommend you to follow the convention of naming your test case (not test) `*DeathTest` when it contains a death test, as demonstrated in the above example. The `Death Tests And Threads` section below explains why. If a test fixture class is shared by normal tests and death tests, you can use typedef to introduce an alias for the fixture class and avoid duplicating its code: ``` class FooTest : public ::testing::Test { ... }; typedef FooTest FooDeathTest; TEST_F(FooTest, DoesThis) { // normal test } TEST_F(FooDeathTest, DoesThat) { // death test } ``` _Availability:_ Linux, Windows (requires MSVC 8.0 or above), Cygwin, and Mac (the latter three are supported since v1.3.0). `(ASSERT|EXPECT)_DEATH_IF_SUPPORTED` are new in v1.4.0. ## Regular Expression Syntax ## On POSIX systems (e.g. Linux, Cygwin, and Mac), Google Test uses the [POSIX extended regular expression](http://www.opengroup.org/onlinepubs/009695399/basedefs/xbd_chap09.html#tag_09_04) syntax in death tests. To learn about this syntax, you may want to read this [Wikipedia entry](http://en.wikipedia.org/wiki/Regular_expression#POSIX_Extended_Regular_Expressions). On Windows, Google Test uses its own simple regular expression implementation. It lacks many features you can find in POSIX extended regular expressions. For example, we don't support union (`"x|y"`), grouping (`"(xy)"`), brackets (`"[xy]"`), and repetition count (`"x{5,7}"`), among others. Below is what we do support (`A` denotes a literal character, period (`.`), or a single `\\` escape sequence; `x` and `y` denote regular expressions.): | `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` | To help you determine which capability is available on your system, Google Test defines macro `GTEST_USES_POSIX_RE=1` when it uses POSIX extended regular expressions, or `GTEST_USES_SIMPLE_RE=1` when it uses the simple version. If you want your death tests to work in both cases, you can either `#if` on these macros or use the more limited syntax only. ## How It Works ## Under the hood, `ASSERT_EXIT()` spawns a new process and executes the death test statement in that process. The details of of how precisely that happens depend on the platform and the variable `::testing::GTEST_FLAG(death_test_style)` (which is initialized from the command-line flag `--gtest_death_test_style`). * On POSIX systems, `fork()` (or `clone()` on Linux) is used to spawn the child, after which: * If the variable's value is `"fast"`, the death test statement is immediately executed. * If the variable's value is `"threadsafe"`, the child process re-executes the unit test binary just as it was originally invoked, but with some extra flags to cause just the single death test under consideration to be run. * On Windows, the child is spawned using the `CreateProcess()` API, and re-executes the binary to cause just the single death test under consideration to be run - much like the `threadsafe` mode on POSIX. Other values for the variable are illegal and will cause the death test to fail. Currently, the flag's default value is `"fast"`. However, we reserve the right to change it in the future. Therefore, your tests should not depend on this. In either case, the parent process waits for the child process to complete, and checks that 1. the child's exit status satisfies the predicate, and 1. the child's stderr matches the regular expression. If the death test statement runs to completion without dying, the child process will nonetheless terminate, and the assertion fails. ## Death Tests And Threads ## The reason for the two death test styles has to do with thread safety. Due to well-known problems with forking in the presence of threads, death tests should be run in a single-threaded context. Sometimes, however, it isn't feasible to arrange that kind of environment. For example, statically-initialized modules may start threads before main is ever reached. Once threads have been created, it may be difficult or impossible to clean them up. Google Test has three features intended to raise awareness of threading issues. 1. A warning is emitted if multiple threads are running when a death test is encountered. 1. Test cases with a name ending in "DeathTest" are run before all other tests. 1. It uses `clone()` instead of `fork()` to spawn the child process on Linux (`clone()` is not available on Cygwin and Mac), as `fork()` is more likely to cause the child to hang when the parent process has multiple threads. It's perfectly fine to create threads inside a death test statement; they are executed in a separate process and cannot affect the parent. ## Death Test Styles ## The "threadsafe" death test style was introduced in order to help mitigate the risks of testing in a possibly multithreaded environment. It trades increased test execution time (potentially dramatically so) for improved thread safety. We suggest using the faster, default "fast" style unless your test has specific problems with it. You can choose a particular style of death tests by setting the flag programmatically: ``` ::testing::FLAGS_gtest_death_test_style = "threadsafe"; ``` You can do this in `main()` to set the style for all death tests in the binary, or in individual tests. Recall that flags are saved before running each test and restored afterwards, so you need not do that yourself. For example: ``` TEST(MyDeathTest, TestOne) { ::testing::FLAGS_gtest_death_test_style = "threadsafe"; // This test is run in the "threadsafe" style: ASSERT_DEATH(ThisShouldDie(), ""); } TEST(MyDeathTest, TestTwo) { // This test is run in the "fast" style: ASSERT_DEATH(ThisShouldDie(), ""); } int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); ::testing::FLAGS_gtest_death_test_style = "fast"; return RUN_ALL_TESTS(); } ``` ## Caveats ## The _statement_ argument of `ASSERT_EXIT()` can be any valid C++ statement. If it leaves the current function via a `return` statement or by throwing an exception, the death test is considered to have failed. Some Google Test macros may return from the current function (e.g. `ASSERT_TRUE()`), so be sure to avoid them in _statement_. Since _statement_ runs in the child process, any in-memory side effect (e.g. modifying a variable, releasing memory, etc) it causes will _not_ be observable in the parent process. In particular, if you release memory in a death test, your program will fail the heap check as the parent process will never see the memory reclaimed. To solve this problem, you can 1. try not to free memory in a death test; 1. free the memory again in the parent process; or 1. do not use the heap checker in your program. Due to an implementation detail, you cannot place multiple death test assertions on the same line; otherwise, compilation will fail with an unobvious error message. Despite the improved thread safety afforded by the "threadsafe" style of death test, thread problems such as deadlock are still possible in the presence of handlers registered with `pthread_atfork(3)`. # Using Assertions in Sub-routines # ## Adding Traces to Assertions ## If a test sub-routine is called from several places, when an assertion inside it fails, it can be hard to tell which invocation of the sub-routine the failure is from. You can alleviate this problem using extra logging or custom failure messages, but that usually clutters up your tests. A better solution is to use the `SCOPED_TRACE` macro: | `SCOPED_TRACE(`_message_`);` | |:-----------------------------| where _message_ can be anything streamable to `std::ostream`. This macro will cause the current file name, line number, and the given message to be added in every failure message. The effect will be undone when the control leaves the current lexical scope. For example, ``` 10: void Sub1(int n) { 11: EXPECT_EQ(1, Bar(n)); 12: EXPECT_EQ(2, Bar(n + 1)); 13: } 14: 15: TEST(FooTest, Bar) { 16: { 17: SCOPED_TRACE("A"); // This trace point will be included in 18: // every failure in this scope. 19: Sub1(1); 20: } 21: // Now it won't. 22: Sub1(9); 23: } ``` could result in messages like these: ``` path/to/foo_test.cc:11: Failure Value of: Bar(n) Expected: 1 Actual: 2 Trace: path/to/foo_test.cc:17: A path/to/foo_test.cc:12: Failure Value of: Bar(n + 1) Expected: 2 Actual: 3 ``` Without the trace, it would've been difficult to know which invocation of `Sub1()` the two failures come from respectively. (You could add an extra message to each assertion in `Sub1()` to indicate the value of `n`, but that's tedious.) Some tips on using `SCOPED_TRACE`: 1. With a suitable message, it's often enough to use `SCOPED_TRACE` at the beginning of a sub-routine, instead of at each call site. 1. When calling sub-routines inside a loop, make the loop iterator part of the message in `SCOPED_TRACE` such that you can know which iteration the failure is from. 1. Sometimes the line number of the trace point is enough for identifying the particular invocation of a sub-routine. In this case, you don't have to choose a unique message for `SCOPED_TRACE`. You can simply use `""`. 1. You can use `SCOPED_TRACE` in an inner scope when there is one in the outer scope. In this case, all active trace points will be included in the failure messages, in reverse order they are encountered. 1. The trace dump is clickable in Emacs' compilation buffer - hit return on a line number and you'll be taken to that line in the source file! _Availability:_ Linux, Windows, Mac. ## Propagating Fatal Failures ## A common pitfall when using `ASSERT_*` and `FAIL*` is not understanding that when they fail they only abort the _current function_, not the entire test. For example, the following test will segfault: ``` void Subroutine() { // Generates a fatal failure and aborts the current function. ASSERT_EQ(1, 2); // The following won't be executed. ... } TEST(FooTest, Bar) { Subroutine(); // The intended behavior is for the fatal failure // in Subroutine() to abort the entire test. // The actual behavior: the function goes on after Subroutine() returns. int* p = NULL; *p = 3; // Segfault! } ``` Since we don't use exceptions, it is technically impossible to implement the intended behavior here. To alleviate this, Google Test provides two solutions. You could use either the `(ASSERT|EXPECT)_NO_FATAL_FAILURE` assertions or the `HasFatalFailure()` function. They are described in the following two subsections. ### Asserting on Subroutines ### As shown above, if your test calls a subroutine that has an `ASSERT_*` failure in it, the test will continue after the subroutine returns. This may not be what you want. Often people want fatal failures to propagate like exceptions. For that Google Test offers the following macros: | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_NO_FATAL_FAILURE(`_statement_`);` | `EXPECT_NO_FATAL_FAILURE(`_statement_`);` | _statement_ doesn't generate any new fatal failures in the current thread. | Only failures in the thread that executes the assertion are checked to determine the result of this type of assertions. If _statement_ creates new threads, failures in these threads are ignored. Examples: ``` ASSERT_NO_FATAL_FAILURE(Foo()); int i; EXPECT_NO_FATAL_FAILURE({ i = Bar(); }); ``` _Availability:_ Linux, Windows, Mac. Assertions from multiple threads are currently not supported. ### Checking for Failures in the Current Test ### `HasFatalFailure()` in the `::testing::Test` class returns `true` if an assertion in the current test has suffered a fatal failure. This allows functions to catch fatal failures in a sub-routine and return early. ``` class Test { public: ... static bool HasFatalFailure(); }; ``` The typical usage, which basically simulates the behavior of a thrown exception, is: ``` TEST(FooTest, Bar) { Subroutine(); // Aborts if Subroutine() had a fatal failure. if (HasFatalFailure()) return; // The following won't be executed. ... } ``` If `HasFatalFailure()` is used outside of `TEST()` , `TEST_F()` , or a test fixture, you must add the `::testing::Test::` prefix, as in: ``` if (::testing::Test::HasFatalFailure()) return; ``` Similarly, `HasNonfatalFailure()` returns `true` if the current test has at least one non-fatal failure, and `HasFailure()` returns `true` if the current test has at least one failure of either kind. _Availability:_ Linux, Windows, Mac. `HasNonfatalFailure()` and `HasFailure()` are available since version 1.4.0. # Logging Additional Information # In your test code, you can call `RecordProperty("key", value)` to log additional information, where `value` can be either a C string or a 32-bit integer. The _last_ value recorded for a key will be emitted to the XML output if you specify one. For example, the test ``` TEST_F(WidgetUsageTest, MinAndMaxWidgets) { RecordProperty("MaximumWidgets", ComputeMaxUsage()); RecordProperty("MinimumWidgets", ComputeMinUsage()); } ``` will output XML like this: ``` ... ... ``` _Note_: * `RecordProperty()` is a static member of the `Test` class. Therefore it needs to be prefixed with `::testing::Test::` if used outside of the `TEST` body and the test fixture class. * `key` must be a valid XML attribute name, and cannot conflict with the ones already used by Google Test (`name`, `status`, `time`, and `classname`). _Availability_: Linux, Windows, Mac. # Sharing Resources Between Tests in the Same Test Case # Google Test creates a new test fixture object for each test in order to make tests independent and easier to debug. However, sometimes tests use resources that are expensive to set up, making the one-copy-per-test model prohibitively expensive. If the tests don't change the resource, there's no harm in them sharing a single resource copy. So, in addition to per-test set-up/tear-down, Google Test also supports per-test-case set-up/tear-down. To use it: 1. In your test fixture class (say `FooTest` ), define as `static` some member variables to hold the shared resources. 1. In the same test fixture class, define a `static void SetUpTestCase()` function (remember not to spell it as **`SetupTestCase`** with a small `u`!) to set up the shared resources and a `static void TearDownTestCase()` function to tear them down. That's it! Google Test automatically calls `SetUpTestCase()` before running the _first test_ in the `FooTest` test case (i.e. before creating the first `FooTest` object), and calls `TearDownTestCase()` after running the _last test_ in it (i.e. after deleting the last `FooTest` object). In between, the tests can use the shared resources. Remember that the test order is undefined, so your code can't depend on a test preceding or following another. Also, the tests must either not modify the state of any shared resource, or, if they do modify the state, they must restore the state to its original value before passing control to the next test. Here's an example of per-test-case set-up and tear-down: ``` class FooTest : public ::testing::Test { protected: // Per-test-case set-up. // Called before the first test in this test case. // Can be omitted if not needed. static void SetUpTestCase() { shared_resource_ = new ...; } // Per-test-case tear-down. // Called after the last test in this test case. // Can be omitted if not needed. static void TearDownTestCase() { delete shared_resource_; shared_resource_ = NULL; } // You can define per-test set-up and tear-down logic as usual. virtual void SetUp() { ... } virtual void TearDown() { ... } // Some expensive resource shared by all tests. static T* shared_resource_; }; T* FooTest::shared_resource_ = NULL; TEST_F(FooTest, Test1) { ... you can refer to shared_resource here ... } TEST_F(FooTest, Test2) { ... you can refer to shared_resource here ... } ``` _Availability:_ Linux, Windows, Mac. # Global Set-Up and Tear-Down # Just as you can do set-up and tear-down at the test level and the test case level, you can also do it at the test program level. Here's how. First, you subclass the `::testing::Environment` class to define a test environment, which knows how to set-up and tear-down: ``` class Environment { public: 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() {} }; ``` Then, you register an instance of your environment class with Google Test by calling the `::testing::AddGlobalTestEnvironment()` function: ``` Environment* AddGlobalTestEnvironment(Environment* env); ``` Now, when `RUN_ALL_TESTS()` is called, it first calls the `SetUp()` method of the environment object, then runs the tests if there was no fatal failures, and finally calls `TearDown()` of the environment object. It's OK to register multiple environment objects. In this case, their `SetUp()` will be called in the order they are registered, and their `TearDown()` will be called in the reverse order. Note that Google Test takes ownership of the registered environment objects. Therefore **do not delete them** by yourself. You should call `AddGlobalTestEnvironment()` 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. One way to do this is to 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). _Availability:_ Linux, Windows, Mac. # Value Parameterized Tests # _Value-parameterized tests_ allow you to test your code with different parameters without writing multiple copies of the same test. Suppose you write a test for your code and then realize that your code is affected by a presence of a Boolean command line flag. ``` TEST(MyCodeTest, TestFoo) { // A code to test foo(). } ``` Usually people factor their test code into a function with a Boolean parameter in such situations. The function sets the flag, then executes the testing code. ``` void TestFooHelper(bool flag_value) { flag = flag_value; // A code to test foo(). } TEST(MyCodeTest, TestFooo) { TestFooHelper(false); TestFooHelper(true); } ``` But this setup has serious drawbacks. First, when a test assertion fails in your tests, it becomes unclear what value of the parameter caused it to fail. You can stream a clarifying message into your `EXPECT`/`ASSERT` statements, but it you'll have to do it with all of them. Second, you have to add one such helper function per test. What if you have ten tests? Twenty? A hundred? Value-parameterized tests will let you write your test only once and then easily instantiate and run it with an arbitrary number of parameter values. Here are some other situations when value-parameterized tests come handy: * You want to test different implementations of an OO interface. * You want to test your code over various inputs (a.k.a. data-driven testing). This feature is easy to abuse, so please exercise your good sense when doing it! ## How to Write Value-Parameterized Tests ## To write value-parameterized tests, first you should define a fixture class. It must be derived from both `::testing::Test` and `::testing::WithParamInterface` (the latter is a pure interface), where `T` is the type of your parameter values. For convenience, you can just derive the fixture class from `::testing::TestWithParam`, which itself is derived from both `::testing::Test` and `::testing::WithParamInterface`. `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 { // You can implement all the usual fixture class members here. // To access the test parameter, call GetParam() from class // TestWithParam. }; // Or, when you want to add parameters to a pre-existing fixture class: class BaseTest : public ::testing::Test { ... }; class BarTest : public BaseTest, public ::testing::WithParamInterface { ... }; ``` Then, use the `TEST_P` macro to define as many test patterns using 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 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)` and `ValuesIn(begin, end)` | Yields values from a C-style array, an STL-style container, or an iterator range `[begin, end)`. `container`, `begin`, and `end` can be expressions whose values are determined at run time. | | `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. This is only available if your system provides the `` header. If you are sure your system does, and Google Test disagrees, you can override it by defining `GTEST_HAS_TR1_TUPLE=1`. See comments in [include/gtest/internal/gtest-port.h](../include/gtest/internal/gtest-port.h) for more information. | For more details, see the comments at the definitions of these functions in the [source code](../include/gtest/gtest-param-test.h). 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, ::testing::Values("meeny", "miny", "moe")); ``` To distinguish different instances of the pattern (yes, you can instantiate it more than once), the first argument to `INSTANTIATE_TEST_CASE_P` 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](#running-a-subset-of-the-tests). 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, ::testing::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. You can see [these](../samples/sample7_unittest.cc) [files](../samples/sample8_unittest.cc) for more examples. _Availability_: Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.2.0. ## Creating Value-Parameterized Abstract Tests ## In the above, we define and instantiate `FooTest` in the same source file. Sometimes you may want to define value-parameterized tests in a library and let other people instantiate them later. This pattern is known as abstract tests. As an example of its application, when you are designing an interface you can write a standard suite of abstract tests (perhaps using a factory function as the test parameter) that all implementations of the interface are expected to pass. When someone implements the interface, he can instantiate your suite to get all the interface-conformance tests for free. To define abstract tests, you should organize your code like this: 1. Put the definition of the parameterized test fixture class (e.g. `FooTest`) in a header file, say `foo_param_test.h`. Think of this as _declaring_ your abstract tests. 1. Put the `TEST_P` definitions in `foo_param_test.cc`, which includes `foo_param_test.h`. Think of this as _implementing_ your abstract tests. Once they are defined, you can instantiate them by including `foo_param_test.h`, invoking `INSTANTIATE_TEST_CASE_P()`, and linking with `foo_param_test.cc`. You can instantiate the same abstract test case multiple times, possibly in different source files. # Typed Tests # Suppose you have multiple implementations of the same interface and want to make sure that all of them satisfy some common requirements. Or, you may have defined several types that are supposed to conform to the same "concept" and you want to verify it. In both cases, you want the same test logic repeated for different types. While you can write one `TEST` or `TEST_F` for each type you want to test (and you may even factor the test logic into a function template that you invoke from the `TEST`), it's tedious and doesn't scale: if you want _m_ tests over _n_ types, you'll end up writing _m\*n_ `TEST`s. _Typed tests_ allow you to repeat the same test logic over a list of types. You only need to write the test logic once, although you must know the type list when writing typed tests. Here's how you do it: First, define a fixture class template. It should be parameterized by a type. Remember to derive it from `::testing::Test`: ``` template class FooTest : public ::testing::Test { public: ... typedef std::list 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: ``` typedef ::testing::Types MyTypes; TYPED_TEST_CASE(FooTest, MyTypes); ``` The `typedef` is necessary for the `TYPED_TEST_CASE` macro to parse correctly. Otherwise the compiler will think that each comma in the type list introduces a new macro argument. Then, use `TYPED_TEST()` instead of `TEST_F()` to define a typed test for this test case. You can repeat this as many times as you want: ``` TYPED_TEST(FooTest, DoesBlah) { // Inside a test, refer to the special name TypeParam to get the type // parameter. Since we are inside a derived class template, C++ requires // us 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. The 'typename' is required to satisfy the compiler. typename TestFixture::List values; values.push_back(n); ... } TYPED_TEST(FooTest, HasPropertyA) { ... } ``` You can see `samples/sample6_unittest.cc` for a complete example. _Availability:_ Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.1.0. # Type-Parameterized Tests # _Type-parameterized tests_ are like typed tests, except that they don't require you to know the list of types ahead of time. Instead, you can define the test logic first and instantiate it with different type lists later. You can even instantiate it more than once in the same program. 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, the author of each implementation can just instantiate the test suite with his type to verify that it conforms to the requirements, without having to write similar tests repeatedly. Here's an example: First, define a fixture class template, as we did with typed tests: ``` template class FooTest : public ::testing::Test { ... }; ``` Next, declare that you will define a type-parameterized test case: ``` TYPED_TEST_CASE_P(FooTest); ``` The `_P` suffix is for "parameterized" or "pattern", whichever you prefer to think. Then, use `TYPED_TEST_P()` to define a type-parameterized test. You can repeat this as many times 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 using the `REGISTER_TYPED_TEST_CASE_P` macro 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. ``` typedef ::testing::Types MyTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, MyTypes); ``` To distinguish different instances of the pattern, the first argument to the `INSTANTIATE_TYPED_TEST_CASE_P` macro is a prefix that will be added to the actual test case name. Remember to pick unique prefixes for different instances. In the special case where the type list contains only one type, you can write that type directly without `::testing::Types<...>`, like this: ``` INSTANTIATE_TYPED_TEST_CASE_P(My, FooTest, int); ``` You can see `samples/sample6_unittest.cc` for a complete example. _Availability:_ Linux, Windows (requires MSVC 8.0 or above), Mac; since version 1.1.0. # Testing Private Code # If you change your software's internal implementation, your tests should not break as long as the change is not observable by users. Therefore, per the _black-box testing principle_, most of the time you should test your code through its public interfaces. If you still find yourself needing to test internal implementation code, consider if there's a better design that wouldn't require you to do so. If you absolutely have to test non-public interface code though, you can. There are two cases to consider: * Static functions (_not_ the same as static member functions!) or unnamed namespaces, and * Private or protected class members ## Static Functions ## Both static functions and definitions/declarations in an unnamed namespace are only visible within the same translation unit. To test them, you can `#include` the entire `.cc` file being tested in your `*_test.cc` file. (`#include`ing `.cc` files is not a good way to reuse code - you should not do this in production code!) However, a better approach is to move the private code into the `foo::internal` namespace, where `foo` is the namespace your project normally uses, and put the private declarations in a `*-internal.h` file. Your production `.cc` files and your tests are allowed to include this internal header, but your clients are not. This way, you can fully test your internal implementation without leaking it to your clients. ## Private Class Members ## Private class members are only accessible from within the class or by friends. To access a class' private members, you can declare your test fixture as a friend to the class and define accessors in your fixture. Tests using the fixture can then access the private members of your production class via the accessors in the fixture. Note that even though your fixture is a friend to your production class, your tests are not automatically friends to it, as they are technically defined in sub-classes of the fixture. Another way to test private members is to refactor them into an implementation class, which is then declared in a `*-internal.h` file. Your clients aren't allowed to include this header but your tests can. Such is called the Pimpl (Private Implementation) idiom. Or, you can declare an individual test as a friend of your class by adding this line in the class body: ``` FRIEND_TEST(TestCaseName, TestName); ``` For example, ``` // foo.h #include "gtest/gtest_prod.h" // Defines FRIEND_TEST. class Foo { ... private: FRIEND_TEST(FooTest, BarReturnsZeroOnNull); int Bar(void* x); }; // foo_test.cc ... TEST(FooTest, BarReturnsZeroOnNull) { Foo foo; EXPECT_EQ(0, foo.Bar(NULL)); // Uses Foo's private member Bar(). } ``` Pay special attention when your class is defined in a namespace, as you should define your test fixtures and tests in the same namespace if you want them to be friends of your class. For example, if the code to be tested looks like: ``` namespace my_namespace { class Foo { friend class FooTest; FRIEND_TEST(FooTest, Bar); FRIEND_TEST(FooTest, Baz); ... definition of the class Foo ... }; } // namespace my_namespace ``` Your test code should be something like: ``` namespace my_namespace { class FooTest : public ::testing::Test { protected: ... }; TEST_F(FooTest, Bar) { ... } TEST_F(FooTest, Baz) { ... } } // namespace my_namespace ``` # Catching Failures # If you are building a testing utility on top of Google Test, you'll want to test your utility. What framework would you use to test it? Google Test, of course. The challenge is to verify that your testing utility reports failures correctly. In frameworks that report a failure by throwing an exception, you could catch the exception and assert on it. But Google Test doesn't use exceptions, so how do we test that a piece of code generates an expected failure? `"gtest/gtest-spi.h"` contains some constructs to do this. After `#include`ing this header, you can use | `EXPECT_FATAL_FAILURE(`_statement, substring_`);` | |:--------------------------------------------------| to assert that _statement_ generates a fatal (e.g. `ASSERT_*`) failure whose message contains the given _substring_, or use | `EXPECT_NONFATAL_FAILURE(`_statement, substring_`);` | |:-----------------------------------------------------| if you are expecting a non-fatal (e.g. `EXPECT_*`) failure. For technical reasons, there are some caveats: 1. You cannot stream a failure message to either macro. 1. _statement_ in `EXPECT_FATAL_FAILURE()` cannot reference local non-static variables or non-static members of `this` object. 1. _statement_ in `EXPECT_FATAL_FAILURE()` cannot return a value. _Note:_ Google Test is designed with threads in mind. Once the synchronization primitives in `"gtest/internal/gtest-port.h"` have been implemented, Google Test will become thread-safe, meaning that you can then use assertions in multiple threads concurrently. Before that, however, Google Test only supports single-threaded usage. Once thread-safe, `EXPECT_FATAL_FAILURE()` and `EXPECT_NONFATAL_FAILURE()` will capture failures in the current thread only. If _statement_ creates new threads, failures in these threads will be ignored. If you want to capture failures from all threads instead, you should use the following macros: | `EXPECT_FATAL_FAILURE_ON_ALL_THREADS(`_statement, substring_`);` | |:-----------------------------------------------------------------| | `EXPECT_NONFATAL_FAILURE_ON_ALL_THREADS(`_statement, substring_`);` | # Getting the Current Test's Name # Sometimes a function may need to know the name of the currently running test. For example, you may be using the `SetUp()` method of your test fixture to set the golden file name based on which test is running. The `::testing::TestInfo` class has this information: ``` namespace testing { class TestInfo { public: // Returns the test case name and the test name, respectively. // // Do NOT delete or free the return value - it's managed by the // TestInfo class. const char* test_case_name() const; const char* name() const; }; } // namespace testing ``` > To obtain a `TestInfo` object for the currently running test, call `current_test_info()` on the `UnitTest` singleton object: ``` // Gets information about the currently running test. // Do NOT delete the returned object - it's managed by the UnitTest class. const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); printf("We are in test %s of test case %s.\n", test_info->name(), test_info->test_case_name()); ``` `current_test_info()` returns a null pointer if no test is running. In particular, you cannot find the test case name in `TestCaseSetUp()`, `TestCaseTearDown()` (where you know the test case name implicitly), or functions called from them. _Availability:_ Linux, Windows, Mac. # Extending Google Test by Handling Test Events # Google Test provides an event listener API to let you receive notifications about the progress of a test program and test failures. The events you can listen to include the start and end of the test program, a test case, or a test method, among others. You may use this API to augment or replace the standard console output, replace the XML output, or provide a completely different form of output, such as a GUI or a database. You can also use test events as checkpoints to implement a resource leak checker, for example. _Availability:_ Linux, Windows, Mac; since v1.4.0. ## Defining Event Listeners ## To define a event listener, you subclass either [testing::TestEventListener](../include/gtest/gtest.h#L855) or [testing::EmptyTestEventListener](../include/gtest/gtest.h#L905). The former is an (abstract) interface, where each pure virtual method
can be overridden to handle a test event
(For example, when a test starts, the `OnTestStart()` method will be called.). The latter provides an empty implementation of all methods in the interface, such that a subclass only needs to override the methods it cares about. When an event is fired, its context is passed to the handler function as an argument. The following argument types are used: * [UnitTest](../include/gtest/gtest.h#L1007) reflects the state of the entire test program, * [TestCase](../include/gtest/gtest.h#L689) has information about a test case, which can contain one or more tests, * [TestInfo](../include/gtest/gtest.h#L599) contains the state of a test, and * [TestPartResult](../include/gtest/gtest-test-part.h#L42) represents the result of a test assertion. An event handler function can examine the argument it receives to find out interesting information about the event and the test program's state. Here's an example: ``` class MinimalistPrinter : public ::testing::EmptyTestEventListener { // Called before a test starts. virtual void OnTestStart(const ::testing::TestInfo& test_info) { printf("*** Test %s.%s starting.\n", test_info.test_case_name(), test_info.name()); } // Called after a failed assertion or a SUCCEED() invocation. virtual void OnTestPartResult( const ::testing::TestPartResult& test_part_result) { printf("%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()); } // Called after a test ends. virtual void OnTestEnd(const ::testing::TestInfo& test_info) { printf("*** Test %s.%s ending.\n", test_info.test_case_name(), test_info.name()); } }; ``` ## Using Event Listeners ## To use the event listener you have defined, add an instance of it to the Google Test event listener list (represented by class [TestEventListeners](../include/gtest/gtest.h#L929) - note the "s" at the end of the name) in your `main()` function, before calling `RUN_ALL_TESTS()`: ``` int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); // Gets hold of the event listener list. ::testing::TestEventListeners& listeners = ::testing::UnitTest::GetInstance()->listeners(); // Adds a listener to the end. Google Test takes the ownership. listeners.Append(new MinimalistPrinter); return RUN_ALL_TESTS(); } ``` There's only one problem: the default test result printer is still in effect, so its output will mingle with the output from your minimalist printer. To suppress the default printer, just release it from the event listener list and delete it. You can do so by adding one line: ``` ... delete listeners.Release(listeners.default_result_printer()); listeners.Append(new MinimalistPrinter); return RUN_ALL_TESTS(); ``` Now, sit back and enjoy a completely different output from your tests. For more details, you can read this [sample](../samples/sample9_unittest.cc). You may append more than one listener to the list. When an `On*Start()` or `OnTestPartResult()` event is fired, the listeners will receive it in the order they appear in the list (since new listeners are added to the end of the list, the default text printer and the default XML generator will receive the event first). An `On*End()` event will be received by the listeners in the _reverse_ order. This allows output by listeners added later to be framed by output from listeners added earlier. ## Generating Failures in Listeners ## You may use failure-raising macros (`EXPECT_*()`, `ASSERT_*()`, `FAIL()`, etc) when processing an event. There are some restrictions: 1. You cannot generate any failure in `OnTestPartResult()` (otherwise it will cause `OnTestPartResult()` to be called recursively). 1. A listener that handles `OnTestPartResult()` is not allowed to generate any failure. When you add listeners to the listener list, you should put listeners that handle `OnTestPartResult()` _before_ listeners that can generate failures. This ensures that failures generated by the latter are attributed to the right test by the former. We have a sample of failure-raising listener [here](../samples/sample10_unittest.cc). # Running Test Programs: Advanced Options # Google Test test programs are ordinary executables. Once built, you can run them directly and affect their behavior via the following environment variables and/or command line flags. For the flags to work, your programs must call `::testing::InitGoogleTest()` before calling `RUN_ALL_TESTS()`. To see a list of supported flags and their usage, please run your test program with the `--help` flag. You can also use `-h`, `-?`, or `/?` for short. This feature is added in version 1.3.0. If an option is specified both by an environment variable and by a flag, the latter takes precedence. Most of the options can also be set/read in code: to access the value of command line flag `--gtest_foo`, write `::testing::GTEST_FLAG(foo)`. A common pattern is to set the value of a flag before calling `::testing::InitGoogleTest()` to change the default value of the flag: ``` int main(int argc, char** argv) { // Disables elapsed time by default. ::testing::GTEST_FLAG(print_time) = false; // This allows the user to override the flag on the command line. ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ``` ## Selecting Tests ## This section shows various options for choosing which tests to run. ### Listing Test Names ### Sometimes it is necessary to list the available tests in a program before running them so that a filter may be applied if needed. Including the flag `--gtest_list_tests` overrides all other flags and lists tests in the following format: ``` TestCase1. TestName1 TestName2 TestCase2. TestName ``` None of the tests listed are actually run if the flag is provided. There is no corresponding environment variable for this flag. _Availability:_ Linux, Windows, Mac. ### Running a Subset of the Tests ### By default, a Google Test program runs all tests the user has defined. Sometimes, you want to run only a subset of the tests (e.g. for debugging or quickly verifying a change). If you set the `GTEST_FILTER` environment variable or the `--gtest_filter` flag to a filter string, Google Test will only run the tests whose full names (in the form of `TestCaseName.TestName`) match the filter. The format of a filter is a '`:`'-separated list of wildcard patterns (called the positive patterns) optionally followed by a '`-`' and another '`:`'-separated pattern list (called the negative patterns). A test matches the filter if and only if it matches any of the positive patterns but does not match any of the negative patterns. A pattern may contain `'*'` (matches any string) or `'?'` (matches any single character). For convenience, the filter `'*-NegativePatterns'` can be also written as `'-NegativePatterns'`. For example: * `./foo_test` Has no flag, and thus runs all its tests. * `./foo_test --gtest_filter=*` Also runs everything, due to the single match-everything `*` value. * `./foo_test --gtest_filter=FooTest.*` Runs everything in test case `FooTest`. * `./foo_test --gtest_filter=*Null*:*Constructor*` Runs any test whose full name contains either `"Null"` or `"Constructor"`. * `./foo_test --gtest_filter=-*DeathTest.*` Runs all non-death tests. * `./foo_test --gtest_filter=FooTest.*-FooTest.Bar` Runs everything in test case `FooTest` except `FooTest.Bar`. _Availability:_ Linux, Windows, Mac. ### Temporarily Disabling Tests ### If you have a broken test that you cannot fix right away, you can add the `DISABLED_` prefix to its name. This will exclude it from execution. This is better than commenting out the code or using `#if 0`, as disabled tests are still compiled (and thus won't rot). If you need to disable all tests in a test case, you can either add `DISABLED_` to the front of the name of each test, or alternatively add it to the front of the test case name. For example, the following tests won't be run by Google Test, even though they will still be compiled: ``` // Tests that Foo does Abc. TEST(FooTest, DISABLED_DoesAbc) { ... } class DISABLED_BarTest : public ::testing::Test { ... }; // Tests that Bar does Xyz. TEST_F(DISABLED_BarTest, DoesXyz) { ... } ``` _Note:_ This feature should only be used for temporary pain-relief. You still have to fix the disabled tests at a later date. As a reminder, Google Test will print a banner warning you if a test program contains any disabled tests. _Tip:_ You can easily count the number of disabled tests you have using `grep`. This number can be used as a metric for improving your test quality. _Availability:_ Linux, Windows, Mac. ### Temporarily Enabling Disabled Tests ### To include [disabled tests](#temporarily-disabling-tests) in test execution, just invoke the test program with the `--gtest_also_run_disabled_tests` flag or set the `GTEST_ALSO_RUN_DISABLED_TESTS` environment variable to a value other than `0`. You can combine this with the [--gtest\-filter](#running-a-subset-of-the_tests) flag to further select which disabled tests to run. _Availability:_ Linux, Windows, Mac; since version 1.3.0. ## Repeating the Tests ## Once in a while you'll run into a test whose result is hit-or-miss. Perhaps it will fail only 1% of the time, making it rather hard to reproduce the bug under a debugger. This can be a major source of frustration. The `--gtest_repeat` flag allows you to repeat all (or selected) test methods in a program many times. Hopefully, a flaky test will eventually fail and give you a chance to debug. Here's how to use it: | `$ foo_test --gtest_repeat=1000` | Repeat foo\_test 1000 times and don't stop at failures. | |:---------------------------------|:--------------------------------------------------------| | `$ foo_test --gtest_repeat=-1` | A negative count means repeating forever. | | `$ foo_test --gtest_repeat=1000 --gtest_break_on_failure` | Repeat foo\_test 1000 times, stopping at the first failure. This is especially useful when running under a debugger: when the testfails, it will drop into the debugger and you can then inspect variables and stacks. | | `$ foo_test --gtest_repeat=1000 --gtest_filter=FooBar` | Repeat the tests whose name matches the filter 1000 times. | If your test program contains global set-up/tear-down code registered using `AddGlobalTestEnvironment()`, it will be repeated in each iteration as well, as the flakiness may be in it. You can also specify the repeat count by setting the `GTEST_REPEAT` environment variable. _Availability:_ Linux, Windows, Mac. ## Shuffling the Tests ## You can specify the `--gtest_shuffle` flag (or set the `GTEST_SHUFFLE` environment variable to `1`) to run the tests in a program in a random order. This helps to reveal bad dependencies between tests. By default, Google Test uses a random seed calculated from the current time. Therefore you'll get a different order every time. The console output includes the random seed value, such that you can reproduce an order-related test failure later. To specify the random seed explicitly, use the `--gtest_random_seed=SEED` flag (or set the `GTEST_RANDOM_SEED` environment variable), where `SEED` is an integer between 0 and 99999. The seed value 0 is special: it tells Google Test to do the default behavior of calculating the seed from the current time. If you combine this with `--gtest_repeat=N`, Google Test will pick a different random seed and re-shuffle the tests in each iteration. _Availability:_ Linux, Windows, Mac; since v1.4.0. ## Controlling Test Output ## This section teaches how to tweak the way test results are reported. ### Colored Terminal Output ### Google Test can use colors in its terminal output to make it easier to spot the separation between tests, and whether tests passed. You can set the GTEST\_COLOR environment variable or set the `--gtest_color` command line flag to `yes`, `no`, or `auto` (the default) to enable colors, disable colors, or let Google Test decide. When the value is `auto`, Google Test will use colors if and only if the output goes to a terminal and (on non-Windows platforms) the `TERM` environment variable is set to `xterm` or `xterm-color`. _Availability:_ Linux, Windows, Mac. ### Suppressing the Elapsed Time ### By default, Google Test prints the time it takes to run each test. To suppress that, run the test program with the `--gtest_print_time=0` command line flag. Setting the `GTEST_PRINT_TIME` environment variable to `0` has the same effect. _Availability:_ Linux, Windows, Mac. (In Google Test 1.3.0 and lower, the default behavior is that the elapsed time is **not** printed.) ### Generating an XML Report ### Google Test can emit a detailed XML report to a file in addition to its normal textual output. The report contains the duration of each test, and thus can help you identify slow tests. To generate the XML report, set the `GTEST_OUTPUT` environment variable or the `--gtest_output` flag to the string `"xml:_path_to_output_file_"`, which will create the file at the given location. You can also just use the string `"xml"`, in which case the output can be found in the `test_detail.xml` file in the current directory. If you specify a directory (for example, `"xml:output/directory/"` on Linux or `"xml:output\directory\"` on Windows), Google Test will create the XML file in that directory, named after the test executable (e.g. `foo_test.xml` for test program `foo_test` or `foo_test.exe`). If the file already exists (perhaps left over from a previous run), Google Test will pick a different name (e.g. `foo_test_1.xml`) to avoid overwriting it. The report uses the format described here. It is based on the `junitreport` Ant task and can be parsed by popular continuous build systems like [Hudson](https://hudson.dev.java.net/). Since that format was originally intended for Java, a little interpretation is required to make it apply to Google Test tests, as shown here: ``` ``` * The root `` element corresponds to the entire test program. * `` elements correspond to Google Test test cases. * `` elements correspond to Google Test test functions. For instance, the following program ``` TEST(MathTest, Addition) { ... } TEST(MathTest, Subtraction) { ... } TEST(LogicTest, NonContradiction) { ... } ``` could generate this report: ``` ``` Things to note: * The `tests` attribute of a `` or `` element tells how many test functions the Google Test program or test case contains, while the `failures` attribute tells how many of them failed. * The `time` attribute expresses the duration of the test, test case, or entire test program in milliseconds. * Each `` element corresponds to a single failed Google Test assertion. * Some JUnit concepts don't apply to Google Test, yet we have to conform to the DTD. Therefore you'll see some dummy elements and attributes in the report. You can safely ignore these parts. _Availability:_ Linux, Windows, Mac. ## Controlling How Failures Are Reported ## ### Turning Assertion Failures into Break-Points ### When running test programs under a debugger, it's very convenient if the debugger can catch an assertion failure and automatically drop into interactive mode. Google Test's _break-on-failure_ mode supports this behavior. To enable it, set the `GTEST_BREAK_ON_FAILURE` environment variable to a value other than `0` . Alternatively, you can use the `--gtest_break_on_failure` command line flag. _Availability:_ Linux, Windows, Mac. ### Disabling Catching Test-Thrown Exceptions ### Google Test can be used either with or without exceptions enabled. If a test throws a C++ exception or (on Windows) a structured exception (SEH), by default Google Test catches it, reports it as a test failure, and continues with the next test method. This maximizes the coverage of a test run. Also, on Windows an uncaught exception will cause a pop-up window, so catching the exceptions allows you to run the tests automatically. When debugging the test failures, however, you may instead want the exceptions to be handled by the debugger, such that you can examine the call stack when an exception is thrown. To achieve that, set the `GTEST_CATCH_EXCEPTIONS` environment variable to `0`, or use the `--gtest_catch_exceptions=0` flag when running the tests. **Availability**: Linux, Windows, Mac. ### Letting Another Testing Framework Drive ### If you work on a project that has already been using another testing framework and is not ready to completely switch to Google Test yet, you can get much of Google Test's benefit by using its assertions in your existing tests. Just change your `main()` function to look like: ``` #include "gtest/gtest.h" int main(int argc, char** argv) { ::testing::GTEST_FLAG(throw_on_failure) = true; // Important: Google Test must be initialized. ::testing::InitGoogleTest(&argc, argv); ... whatever your existing testing framework requires ... } ``` With that, you can use Google Test assertions in addition to the native assertions your testing framework provides, for example: ``` void TestFooDoesBar() { Foo foo; EXPECT_LE(foo.Bar(1), 100); // A Google Test assertion. CPPUNIT_ASSERT(foo.IsEmpty()); // A native assertion. } ``` If a Google Test assertion fails, it will print an error message and throw an exception, which will be treated as a failure by your host testing framework. If you compile your code with exceptions disabled, a failed Google Test assertion will instead exit your program with a non-zero code, which will also signal a test failure to your test runner. If you don't write `::testing::GTEST_FLAG(throw_on_failure) = true;` in your `main()`, you can alternatively enable this feature by specifying the `--gtest_throw_on_failure` flag on the command-line or setting the `GTEST_THROW_ON_FAILURE` environment variable to a non-zero value. _Availability:_ Linux, Windows, Mac; since v1.3.0. ## Distributing Test Functions to Multiple Machines ## If you have more than one machine you can use to run a test program, you might want to run the test functions in parallel and get the result faster. We call this technique _sharding_, where each machine is called a _shard_. Google Test is compatible with test sharding. To take advantage of this feature, your test runner (not part of Google Test) needs to do the following: 1. Allocate a number of machines (shards) to run the tests. 1. On each shard, set the `GTEST_TOTAL_SHARDS` environment variable to the total number of shards. It must be the same for all shards. 1. On each shard, set the `GTEST_SHARD_INDEX` environment variable to the index of the shard. Different shards must be assigned different indices, which must be in the range `[0, GTEST_TOTAL_SHARDS - 1]`. 1. Run the same test program on all shards. When Google Test sees the above two environment variables, it will select a subset of the test functions to run. Across all shards, each test function in the program will be run exactly once. 1. Wait for all shards to finish, then collect and report the results. Your project may have tests that were written without Google Test and thus don't understand this protocol. In order for your test runner to figure out which test supports sharding, it can set the environment variable `GTEST_SHARD_STATUS_FILE` to a non-existent file path. If a test program supports sharding, it will create this file to acknowledge the fact (the actual contents of the file are not important at this time; although we may stick some useful information in it in the future.); otherwise it will not create it. Here's an example to make it clear. Suppose you have a test program `foo_test` that contains the following 5 test functions: ``` TEST(A, V) TEST(A, W) TEST(B, X) TEST(B, Y) TEST(B, Z) ``` and you have 3 machines at your disposal. To run the test functions in parallel, you would set `GTEST_TOTAL_SHARDS` to 3 on all machines, and set `GTEST_SHARD_INDEX` to 0, 1, and 2 on the machines respectively. Then you would run the same `foo_test` on each machine. Google Test reserves the right to change how the work is distributed across the shards, but here's one possible scenario: * Machine #0 runs `A.V` and `B.X`. * Machine #1 runs `A.W` and `B.Y`. * Machine #2 runs `B.Z`. _Availability:_ Linux, Windows, Mac; since version 1.3.0. # Fusing Google Test Source Files # Google Test's implementation consists of ~30 files (excluding its own tests). Sometimes you may want them to be packaged up in two files (a `.h` and a `.cc`) instead, such that you can easily copy them to a new machine and start hacking there. For this we provide an experimental Python script `fuse_gtest_files.py` in the `scripts/` directory (since release 1.3.0). Assuming you have Python 2.4 or above installed on your machine, just go to that directory and run ``` python fuse_gtest_files.py OUTPUT_DIR ``` and you should see an `OUTPUT_DIR` directory being created with files `gtest/gtest.h` and `gtest/gtest-all.cc` in it. These files contain everything you need to use Google Test. Just copy them to anywhere you want and you are ready to write tests. You can use the [scripts/test/Makefile](../scripts/test/Makefile) file as an example on how to compile your tests against them. # Where to Go from Here # Congratulations! You've now learned more advanced Google Test tools and are ready to tackle more complex testing tasks. If you want to dive even deeper, you can read the [Frequently-Asked Questions](V1_6_FAQ.md). assimp-4.1.0/contrib/gtest/docs/V1_6_Samples.md0000644002537200234200000000246113213503245021516 0ustar zmoelnigiemusersIf you're like us, you'd like to look at some Google Test sample code. The [samples folder](../samples) has a number of well-commented samples showing how to use a variety of Google Test features. * [Sample #1](../samples/sample1_unittest.cc) shows the basic steps of using Google Test to test C++ functions. * [Sample #2](../samples/sample2_unittest.cc) shows a more complex unit test for a class with multiple member functions. * [Sample #3](../samples/sample3_unittest.cc) uses a test fixture. * [Sample #4](../samples/sample4_unittest.cc) is another basic example of using Google Test. * [Sample #5](../samples/sample5_unittest.cc) teaches how to reuse a test fixture in multiple test cases by deriving sub-fixtures from it. * [Sample #6](../samples/sample6_unittest.cc) demonstrates type-parameterized tests. * [Sample #7](../samples/sample7_unittest.cc) teaches the basics of value-parameterized tests. * [Sample #8](../samples/sample8_unittest.cc) shows using `Combine()` in value-parameterized tests. * [Sample #9](../samples/sample9_unittest.cc) shows use of the listener API to modify Google Test's console output and the use of its reflection API to inspect test results. * [Sample #10](../samples/sample10_unittest.cc) shows use of the listener API to implement a primitive memory leak checker. assimp-4.1.0/contrib/gtest/docs/XcodeGuide.md0000644002537200234200000002005713213503245021340 0ustar zmoelnigiemusers This guide will explain how to use the Google Testing Framework in your Xcode projects on Mac OS X. This tutorial begins by quickly explaining what to do for experienced users. After the quick start, the guide goes provides additional explanation about each step. # Quick Start # Here is the quick guide for using Google Test in your Xcode project. 1. Download the source from the [website](http://code.google.com/p/googletest) using this command: `svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only` 1. Open up the `gtest.xcodeproj` in the `googletest-read-only/xcode/` directory and build the gtest.framework. 1. Create a new "Shell Tool" target in your Xcode project called something like "UnitTests" 1. Add the gtest.framework to your project and add it to the "Link Binary with Libraries" build phase of "UnitTests" 1. Add your unit test source code to the "Compile Sources" build phase of "UnitTests" 1. Edit the "UnitTests" executable and add an environment variable named "DYLD\_FRAMEWORK\_PATH" with a value equal to the path to the framework containing the gtest.framework relative to the compiled executable. 1. Build and Go The following sections further explain each of the steps listed above in depth, describing in more detail how to complete it including some variations. # Get the Source # Currently, the gtest.framework discussed here isn't available in a tagged release of Google Test, it is only available in the trunk. As explained at the Google Test [site](http://code.google.com/p/googletest/source/checkout">svn), you can get the code from anonymous SVN with this command: ``` svn checkout http://googletest.googlecode.com/svn/trunk/ googletest-read-only ``` Alternatively, if you are working with Subversion in your own code base, you can add Google Test as an external dependency to your own Subversion repository. By following this approach, everyone that checks out your svn repository will also receive a copy of Google Test (a specific version, if you wish) without having to check it out explicitly. This makes the set up of your project simpler and reduces the copied code in the repository. To use `svn:externals`, decide where you would like to have the external source reside. You might choose to put the external source inside the trunk, because you want it to be part of the branch when you make a release. However, keeping it outside the trunk in a version-tagged directory called something like `third-party/googletest/1.0.1`, is another option. Once the location is established, use `svn propedit svn:externals _directory_` to set the svn:externals property on a directory in your repository. This directory won't contain the code, but be its versioned parent directory. The command `svn propedit` will bring up your Subversion editor, making editing the long, (potentially multi-line) property simpler. This same method can be used to check out a tagged branch, by using the appropriate URL (e.g. `http://googletest.googlecode.com/svn/tags/release-1.0.1`). Additionally, the svn:externals property allows the specification of a particular revision of the trunk with the `-r_##_` option (e.g. `externals/src/googletest -r60 http://googletest.googlecode.com/svn/trunk`). Here is an example of using the svn:externals properties on a trunk (read via `svn propget`) of a project. This value checks out a copy of Google Test into the `trunk/externals/src/googletest/` directory. ``` [Computer:svn] user$ svn propget svn:externals trunk externals/src/googletest http://googletest.googlecode.com/svn/trunk ``` # Add the Framework to Your Project # The next step is to build and add the gtest.framework to your own project. This guide describes two common ways below. * **Option 1** --- The simplest way to add Google Test to your own project, is to open gtest.xcodeproj (found in the xcode/ directory of the Google Test trunk) and build the framework manually. Then, add the built framework into your project using the "Add->Existing Framework..." from the context menu or "Project->Add..." from the main menu. The gtest.framework is relocatable and contains the headers and object code that you'll need to make tests. This method requires rebuilding every time you upgrade Google Test in your project. * **Option 2** --- If you are going to be living off the trunk of Google Test, incorporating its latest features into your unit tests (or are a Google Test developer yourself). You'll want to rebuild the framework every time the source updates. to do this, you'll need to add the gtest.xcodeproj file, not the framework itself, to your own Xcode project. Then, from the build products that are revealed by the project's disclosure triangle, you can find the gtest.framework, which can be added to your targets (discussed below). # Make a Test Target # To start writing tests, make a new "Shell Tool" target. This target template is available under BSD, Cocoa, or Carbon. Add your unit test source code to the "Compile Sources" build phase of the target. Next, you'll want to add gtest.framework in two different ways, depending upon which option you chose above. * **Option 1** --- During compilation, Xcode will need to know that you are linking against the gtest.framework. Add the gtest.framework to the "Link Binary with Libraries" build phase of your test target. This will include the Google Test headers in your header search path, and will tell the linker where to find the library. * **Option 2** --- If your working out of the trunk, you'll also want to add gtest.framework to your "Link Binary with Libraries" build phase of your test target. In addition, you'll want to add the gtest.framework as a dependency to your unit test target. This way, Xcode will make sure that gtest.framework is up to date, every time your build your target. Finally, if you don't share build directories with Google Test, you'll have to copy the gtest.framework into your own build products directory using a "Run Script" build phase. # Set Up the Executable Run Environment # Since the unit test executable is a shell tool, it doesn't have a bundle with a `Contents/Frameworks` directory, in which to place gtest.framework. Instead, the dynamic linker must be told at runtime to search for the framework in another location. This can be accomplished by setting the "DYLD\_FRAMEWORK\_PATH" environment variable in the "Edit Active Executable ..." Arguments tab, under "Variables to be set in the environment:". The path for this value is the path (relative or absolute) of the directory containing the gtest.framework. If you haven't set up the DYLD\_FRAMEWORK\_PATH, correctly, you might get a message like this: ``` [Session started at 2008-08-15 06:23:57 -0600.] dyld: Library not loaded: @loader_path/../Frameworks/gtest.framework/Versions/A/gtest Referenced from: /Users/username/Documents/Sandbox/gtestSample/build/Debug/WidgetFrameworkTest Reason: image not found ``` To correct this problem, got to the directory containing the executable named in "Referenced from:" value in the error message above. Then, with the terminal in this location, find the relative path to the directory containing the gtest.framework. That is the value you'll need to set as the DYLD\_FRAMEWORK\_PATH. # Build and Go # Now, when you click "Build and Go", the test will be executed. Dumping out something like this: ``` [Session started at 2008-08-06 06:36:13 -0600.] [==========] Running 2 tests from 1 test case. [----------] Global test environment set-up. [----------] 2 tests from WidgetInitializerTest [ RUN ] WidgetInitializerTest.TestConstructor [ OK ] WidgetInitializerTest.TestConstructor [ RUN ] WidgetInitializerTest.TestConversion [ OK ] WidgetInitializerTest.TestConversion [----------] Global test environment tear-down [==========] 2 tests from 1 test case ran. [ PASSED ] 2 tests. The Debugger has exited with status 0. ``` # Summary # Unit testing is a valuable way to ensure your data model stays valid even during rapid development or refactoring. The Google Testing Framework is a great unit testing framework for C and C++ which integrates well with an Xcode development environment.assimp-4.1.0/contrib/gtest/docs/V1_5_PumpManual.md0000644002537200234200000001570013213503245022170 0ustar zmoelnigiemusers Pump is Useful for Meta Programming. # The Problem # Template and macro libraries often need to define many classes, functions, or macros that vary only (or almost only) in the number of arguments they take. It's a lot of repetitive, mechanical, and error-prone work. Variadic templates and variadic macros can alleviate the problem. However, while both are being considered by the C++ committee, neither is in the standard yet or widely supported by compilers. Thus they are often not a good choice, especially when your code needs to be portable. And their capabilities are still limited. As a result, authors of such libraries often have to write scripts to generate their implementation. However, our experience is that it's tedious to write such scripts, which tend to reflect the structure of the generated code poorly and are often hard to read and edit. For example, a small change needed in the generated code may require some non-intuitive, non-trivial changes in the script. This is especially painful when experimenting with the code. # Our Solution # Pump (for Pump is Useful for Meta Programming, Pretty Useful for Meta Programming, or Practical Utility for Meta Programming, whichever you prefer) is a simple meta-programming tool for C++. The idea is that a programmer writes a `foo.pump` file which contains C++ code plus meta code that manipulates the C++ code. The meta code can handle iterations over a range, nested iterations, local meta variable definitions, simple arithmetic, and conditional expressions. You can view it as a small Domain-Specific Language. The meta language is designed to be non-intrusive (s.t. it won't confuse Emacs' C++ mode, for example) and concise, making Pump code intuitive and easy to maintain. ## Highlights ## * The implementation is in a single Python script and thus ultra portable: no build or installation is needed and it works cross platforms. * Pump tries to be smart with respect to [Google's style guide](http://code.google.com/p/google-styleguide/): it breaks long lines (easy to have when they are generated) at acceptable places to fit within 80 columns and indent the continuation lines correctly. * The format is human-readable and more concise than XML. * The format works relatively well with Emacs' C++ mode. ## Examples ## The following Pump code (where meta keywords start with `$`, `[[` and `]]` are meta brackets, and `$$` starts a meta comment that ends with the line): ``` $var n = 3 $$ Defines a meta variable n. $range i 0..n $$ Declares the range of meta iterator i (inclusive). $for i [[ $$ Meta loop. // Foo$i does blah for $i-ary predicates. $range j 1..i template class Foo$i { $if i == 0 [[ blah a; ]] $elif i <= 2 [[ blah b; ]] $else [[ blah c; ]] }; ]] ``` will be translated by the Pump compiler to: ``` // Foo0 does blah for 0-ary predicates. template class Foo0 { blah a; }; // Foo1 does blah for 1-ary predicates. template class Foo1 { blah b; }; // Foo2 does blah for 2-ary predicates. template class Foo2 { blah b; }; // Foo3 does blah for 3-ary predicates. template class Foo3 { blah c; }; ``` In another example, ``` $range i 1..n Func($for i + [[a$i]]); $$ The text between i and [[ is the separator between iterations. ``` will generate one of the following lines (without the comments), depending on the value of `n`: ``` Func(); // If n is 0. Func(a1); // If n is 1. Func(a1 + a2); // If n is 2. Func(a1 + a2 + a3); // If n is 3. // And so on... ``` ## Constructs ## We support the following meta programming constructs: | `$var id = exp` | Defines a named constant value. `$id` is valid util the end of the current meta lexical block. | |:----------------|:-----------------------------------------------------------------------------------------------| | $range id exp..exp | Sets the range of an iteration variable, which can be reused in multiple loops later. | | $for id sep [[code ](.md)] | Iteration. The range of `id` must have been defined earlier. `$id` is valid in `code`. | | `$($)` | Generates a single `$` character. | | `$id` | Value of the named constant or iteration variable. | | `$(exp)` | Value of the expression. | | `$if exp [[ code ]] else_branch` | Conditional. | | `[[ code ]]` | Meta lexical block. | | `cpp_code` | Raw C++ code. | | `$$ comment` | Meta comment. | **Note:** To give the user some freedom in formatting the Pump source code, Pump ignores a new-line character if it's right after `$for foo` or next to `[[` or `]]`. Without this rule you'll often be forced to write very long lines to get the desired output. Therefore sometimes you may need to insert an extra new-line in such places for a new-line to show up in your output. ## Grammar ## ``` code ::= atomic_code* atomic_code ::= $var id = exp | $var id = [[ code ]] | $range id exp..exp | $for id sep [[ code ]] | $($) | $id | $(exp) | $if exp [[ code ]] else_branch | [[ code ]] | cpp_code sep ::= cpp_code | empty_string else_branch ::= $else [[ code ]] | $elif exp [[ code ]] else_branch | empty_string exp ::= simple_expression_in_Python_syntax ``` ## Code ## You can find the source code of Pump in [scripts/pump.py](http://code.google.com/p/googletest/source/browse/trunk/scripts/pump.py). It is still very unpolished and lacks automated tests, although it has been successfully used many times. If you find a chance to use it in your project, please let us know what you think! We also welcome help on improving Pump. ## Real Examples ## You can find real-world applications of Pump in [Google Test](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgoogletest\.googlecode\.com) and [Google Mock](http://www.google.com/codesearch?q=file%3A\.pump%24+package%3Ahttp%3A%2F%2Fgooglemock\.googlecode\.com). The source file `foo.h.pump` generates `foo.h`. ## Tips ## * If a meta variable is followed by a letter or digit, you can separate them using `[[]]`, which inserts an empty string. For example `Foo$j[[]]Helper` generate `Foo1Helper` when `j` is 1. * To avoid extra-long Pump source lines, you can break a line anywhere you want by inserting `[[]]` followed by a new line. Since any new-line character next to `[[` or `]]` is ignored, the generated code won't contain this new line.assimp-4.1.0/contrib/gtest/docs/V1_6_Primer.md0000644002537200234200000006063413213503245021356 0ustar zmoelnigiemusers # Introduction: Why Google C++ Testing Framework? # _Google C++ Testing Framework_ helps you write better C++ tests. No matter whether you work on Linux, Windows, or a Mac, if you write C++ code, Google Test can help you. So what makes a good test, and how does Google C++ Testing Framework fit in? We believe: 1. Tests should be _independent_ and _repeatable_. It's a pain to debug a test that succeeds or fails as a result of other tests. Google C++ Testing Framework isolates the tests by running each of them on a different object. When a test fails, Google C++ Testing Framework allows you to run it in isolation for quick debugging. 1. Tests should be well _organized_ and reflect the structure of the tested code. Google C++ Testing Framework groups related tests into test cases that can share data and subroutines. This common pattern is easy to recognize and makes tests easy to maintain. Such consistency is especially helpful when people switch projects and start to work on a new code base. 1. Tests should be _portable_ and _reusable_. The open-source community has a lot of code that is platform-neutral, its tests should also be platform-neutral. Google C++ Testing Framework works on different OSes, with different compilers (gcc, MSVC, and others), with or without exceptions, so Google C++ Testing Framework tests can easily work with a variety of configurations. (Note that the current release only contains build scripts for Linux - we are actively working on scripts for other platforms.) 1. When tests fail, they should provide as much _information_ about the problem as possible. Google C++ Testing Framework doesn't stop at the first test failure. Instead, it only stops the current test and continues with the next. You can also set up tests that report non-fatal failures after which the current test continues. Thus, you can detect and fix multiple bugs in a single run-edit-compile cycle. 1. The testing framework should liberate test writers from housekeeping chores and let them focus on the test _content_. Google C++ Testing Framework automatically keeps track of all tests defined, and doesn't require the user to enumerate them in order to run them. 1. Tests should be _fast_. With Google C++ Testing Framework, you can reuse shared resources across tests and pay for the set-up/tear-down only once, without making tests depend on each other. Since Google C++ Testing Framework is based on the popular xUnit architecture, you'll feel right at home if you've used JUnit or PyUnit before. If not, it will take you about 10 minutes to learn the basics and get started. So let's go! _Note:_ We sometimes refer to Google C++ Testing Framework informally as _Google Test_. # Setting up a New Test Project # To write a test program using Google Test, you need to compile Google Test into a library and link your test with it. We provide build files for some popular build systems: `msvc/` for Visual Studio, `xcode/` for Mac Xcode, `make/` for GNU make, `codegear/` for Borland C++ Builder, and the autotools script (deprecated) and `CMakeLists.txt` for CMake (recommended) in the Google Test root directory. If your build system is not on this list, you can take a look at `make/Makefile` to learn how Google Test should be compiled (basically you want to compile `src/gtest-all.cc` with `GTEST_ROOT` and `GTEST_ROOT/include` in the header search path, where `GTEST_ROOT` is the Google Test root directory). Once you are able to compile the Google Test library, you should create a project or build target for your test program. Make sure you have `GTEST_ROOT/include` in the header search path so that the compiler can find `"gtest/gtest.h"` when compiling your test. Set up your test project to link with the Google Test library (for example, in Visual Studio, this is done by adding a dependency on `gtest.vcproj`). If you still have questions, take a look at how Google Test's own tests are built and use them as examples. # Basic Concepts # When using Google Test, you start by writing _assertions_, which are statements that check whether a condition is true. An assertion's result can be _success_, _nonfatal failure_, or _fatal failure_. If a fatal failure occurs, it aborts the current function; otherwise the program continues normally. _Tests_ use assertions to verify the tested code's behavior. If a test crashes or has a failed assertion, then it _fails_; otherwise it _succeeds_. A _test case_ contains one or many tests. You should group your tests into test cases that reflect the structure of the tested code. When multiple tests in a test case need to share common objects and subroutines, you can put them into a _test fixture_ class. A _test program_ can contain multiple test cases. We'll now explain how to write a test program, starting at the individual assertion level and building up to tests and test cases. # Assertions # Google Test assertions are macros that resemble function calls. You test a class or function by making assertions about its behavior. When an assertion fails, Google Test prints the assertion's source file and line number location, along with a failure message. You may also supply a custom failure message which will be appended to Google Test's message. The assertions come in pairs that test the same thing but have different effects on the current function. `ASSERT_*` versions generate fatal failures when they fail, and **abort the current function**. `EXPECT_*` versions generate nonfatal failures, which don't abort the current function. Usually `EXPECT_*` are preferred, as they allow more than one failures to be reported in a test. However, you should use `ASSERT_*` if it doesn't make sense to continue when the assertion in question fails. Since a failed `ASSERT_*` returns from the current function immediately, possibly skipping clean-up code that comes after it, it may cause a space leak. Depending on the nature of the leak, it may or may not be worth fixing - so keep this in mind if you get a heap checker error in addition to assertion errors. To provide a custom failure message, simply stream it into the macro using the `<<` operator, or a sequence of such operators. An example: ``` ASSERT_EQ(x.size(), y.size()) << "Vectors x and y are of unequal length"; for (int i = 0; i < x.size(); ++i) { EXPECT_EQ(x[i], y[i]) << "Vectors x and y differ at index " << i; } ``` Anything that can be streamed to an `ostream` can be streamed to an assertion macro--in particular, C strings and `string` objects. If a wide string (`wchar_t*`, `TCHAR*` in `UNICODE` mode on Windows, or `std::wstring`) is streamed to an assertion, it will be translated to UTF-8 when printed. ## Basic Assertions ## These assertions do basic true/false condition testing. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_TRUE(`_condition_`)`; | `EXPECT_TRUE(`_condition_`)`; | _condition_ is true | | `ASSERT_FALSE(`_condition_`)`; | `EXPECT_FALSE(`_condition_`)`; | _condition_ is false | Remember, when they fail, `ASSERT_*` yields a fatal failure and returns from the current function, while `EXPECT_*` yields a nonfatal failure, allowing the function to continue running. In either case, an assertion failure means its containing test fails. _Availability_: Linux, Windows, Mac. ## Binary Comparison ## This section describes assertions that compare two values. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| |`ASSERT_EQ(`_expected_`, `_actual_`);`|`EXPECT_EQ(`_expected_`, `_actual_`);`| _expected_ `==` _actual_ | |`ASSERT_NE(`_val1_`, `_val2_`);` |`EXPECT_NE(`_val1_`, `_val2_`);` | _val1_ `!=` _val2_ | |`ASSERT_LT(`_val1_`, `_val2_`);` |`EXPECT_LT(`_val1_`, `_val2_`);` | _val1_ `<` _val2_ | |`ASSERT_LE(`_val1_`, `_val2_`);` |`EXPECT_LE(`_val1_`, `_val2_`);` | _val1_ `<=` _val2_ | |`ASSERT_GT(`_val1_`, `_val2_`);` |`EXPECT_GT(`_val1_`, `_val2_`);` | _val1_ `>` _val2_ | |`ASSERT_GE(`_val1_`, `_val2_`);` |`EXPECT_GE(`_val1_`, `_val2_`);` | _val1_ `>=` _val2_ | In the event of a failure, Google Test prints both _val1_ and _val2_ . In `ASSERT_EQ*` and `EXPECT_EQ*` (and all other equality assertions we'll introduce later), you should put the expression you want to test in the position of _actual_, and put its expected value in _expected_, as Google Test's failure messages are optimized for this convention. Value arguments must be comparable by the assertion's comparison operator or you'll get a compiler error. We used to require the arguments to support the `<<` operator for streaming to an `ostream`, but it's no longer necessary since v1.6.0 (if `<<` is supported, it will be called to print the arguments when the assertion fails; otherwise Google Test will attempt to print them in the best way it can. For more details and how to customize the printing of the arguments, see this Google Mock [recipe](../../googlemock/docs/CookBook.md#teaching-google-mock-how-to-print-your-values).). These assertions can work with a user-defined type, but only if you define the corresponding comparison operator (e.g. `==`, `<`, etc). If the corresponding operator is defined, prefer using the `ASSERT_*()` macros because they will print out not only the result of the comparison, but the two operands as well. Arguments are always evaluated exactly once. Therefore, it's OK for the arguments to have side effects. However, as with any ordinary C/C++ function, the arguments' evaluation order is undefined (i.e. the compiler is free to choose any order) and your code should not depend on any particular argument evaluation order. `ASSERT_EQ()` does pointer equality on pointers. If used on two C strings, it tests if they are in the same memory location, not if they have the same value. Therefore, if you want to compare C strings (e.g. `const char*`) by value, use `ASSERT_STREQ()` , which will be described later on. In particular, to assert that a C string is `NULL`, use `ASSERT_STREQ(NULL, c_string)` . However, to compare two `string` objects, you should use `ASSERT_EQ`. Macros in this section work with both narrow and wide string objects (`string` and `wstring`). _Availability_: Linux, Windows, Mac. ## String Comparison ## The assertions in this group compare two **C strings**. If you want to compare two `string` objects, use `EXPECT_EQ`, `EXPECT_NE`, and etc instead. | **Fatal assertion** | **Nonfatal assertion** | **Verifies** | |:--------------------|:-----------------------|:-------------| | `ASSERT_STREQ(`_expected\_str_`, `_actual\_str_`);` | `EXPECT_STREQ(`_expected\_str_`, `_actual\_str_`);` | the two C strings have the same content | | `ASSERT_STRNE(`_str1_`, `_str2_`);` | `EXPECT_STRNE(`_str1_`, `_str2_`);` | the two C strings have different content | | `ASSERT_STRCASEEQ(`_expected\_str_`, `_actual\_str_`);`| `EXPECT_STRCASEEQ(`_expected\_str_`, `_actual\_str_`);` | the two C strings have the same content, ignoring case | | `ASSERT_STRCASENE(`_str1_`, `_str2_`);`| `EXPECT_STRCASENE(`_str1_`, `_str2_`);` | the two C strings have different content, ignoring case | Note that "CASE" in an assertion name means that case is ignored. `*STREQ*` and `*STRNE*` also accept wide C strings (`wchar_t*`). If a comparison of two wide strings fails, their values will be printed as UTF-8 narrow strings. A `NULL` pointer and an empty string are considered _different_. _Availability_: Linux, Windows, Mac. See also: For more string comparison tricks (substring, prefix, suffix, and regular expression matching, for example), see the [Advanced Google Test Guide](V1_6_AdvancedGuide.md). # Simple Tests # To create a test: 1. Use the `TEST()` macro to define and name a test function, These are ordinary C++ functions that don't return a value. 1. In this function, along with any valid C++ statements you want to include, use the various Google Test assertions to check values. 1. The test's result is determined by the assertions; if any assertion in the test fails (either fatally or non-fatally), or if the test crashes, the entire test fails. Otherwise, it succeeds. ``` TEST(test_case_name, test_name) { ... test body ... } ``` `TEST()` arguments go from general to specific. The _first_ argument is the name of the test case, and the _second_ argument is the test's name within the test case. Both names must be valid C++ identifiers, and they should not contain underscore (`_`). A test's _full name_ consists of its containing test case and its individual name. Tests from different test cases can have the same individual name. For example, let's take a simple integer function: ``` int Factorial(int n); // Returns the factorial of n ``` A test case for this function might look like: ``` // Tests factorial of 0. TEST(FactorialTest, HandlesZeroInput) { EXPECT_EQ(1, Factorial(0)); } // Tests factorial of positive numbers. TEST(FactorialTest, HandlesPositiveInput) { EXPECT_EQ(1, Factorial(1)); EXPECT_EQ(2, Factorial(2)); EXPECT_EQ(6, Factorial(3)); EXPECT_EQ(40320, Factorial(8)); } ``` Google Test groups the test results by test cases, so logically-related tests should be in the same test case; in other words, the first argument to their `TEST()` should be the same. In the above example, we have two tests, `HandlesZeroInput` and `HandlesPositiveInput`, that belong to the same test case `FactorialTest`. _Availability_: Linux, Windows, Mac. # Test Fixtures: Using the Same Data Configuration for Multiple Tests # If you find yourself writing two or more tests that operate on similar data, you can use a _test fixture_. It allows you to reuse the same configuration of objects for several different tests. To create a fixture, just: 1. Derive a class from `::testing::Test` . Start its body with `protected:` or `public:` as we'll want to access fixture members from sub-classes. 1. Inside the class, declare any objects you plan to use. 1. If necessary, write a default constructor or `SetUp()` function to prepare the objects for each test. A common mistake is to spell `SetUp()` as `Setup()` with a small `u` - don't let that happen to you. 1. If necessary, write a destructor or `TearDown()` function to release any resources you allocated in `SetUp()` . To learn when you should use the constructor/destructor and when you should use `SetUp()/TearDown()`, read this [FAQ entry](V1_6_FAQ.md#should-i-use-the-constructordestructor-of-the-test-fixture-or-the-set-uptear-down-function). 1. If needed, define subroutines for your tests to share. When using a fixture, use `TEST_F()` instead of `TEST()` as it allows you to access objects and subroutines in the test fixture: ``` TEST_F(test_case_name, test_name) { ... test body ... } ``` Like `TEST()`, the first argument is the test case name, but for `TEST_F()` this must be the name of the test fixture class. You've probably guessed: `_F` is for fixture. Unfortunately, the C++ macro system does not allow us to create a single macro that can handle both types of tests. Using the wrong macro causes a compiler error. Also, you must first define a test fixture class before using it in a `TEST_F()`, or you'll get the compiler error "`virtual outside class declaration`". For each test defined with `TEST_F()`, Google Test will: 1. Create a _fresh_ test fixture at runtime 1. Immediately initialize it via `SetUp()` , 1. Run the test 1. Clean up by calling `TearDown()` 1. Delete the test fixture. Note that different tests in the same test case have different test fixture objects, and Google Test always deletes a test fixture before it creates the next one. Google Test does not reuse the same test fixture for multiple tests. Any changes one test makes to the fixture do not affect other tests. As an example, let's write tests for a FIFO queue class named `Queue`, which has the following interface: ``` template // E is the element type. class Queue { public: Queue(); void Enqueue(const E& element); E* Dequeue(); // Returns NULL if the queue is empty. size_t size() const; ... }; ``` First, define a fixture class. By convention, you should give it the name `FooTest` where `Foo` is the class being tested. ``` class QueueTest : public ::testing::Test { protected: virtual void SetUp() { q1_.Enqueue(1); q2_.Enqueue(2); q2_.Enqueue(3); } // virtual void TearDown() {} Queue q0_; Queue q1_; Queue q2_; }; ``` In this case, `TearDown()` is not needed since we don't have to clean up after each test, other than what's already done by the destructor. Now we'll write tests using `TEST_F()` and this fixture. ``` TEST_F(QueueTest, IsEmptyInitially) { EXPECT_EQ(0, q0_.size()); } TEST_F(QueueTest, DequeueWorks) { int* n = q0_.Dequeue(); EXPECT_EQ(NULL, n); n = q1_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(1, *n); EXPECT_EQ(0, q1_.size()); delete n; n = q2_.Dequeue(); ASSERT_TRUE(n != NULL); EXPECT_EQ(2, *n); EXPECT_EQ(1, q2_.size()); delete n; } ``` The above uses both `ASSERT_*` and `EXPECT_*` assertions. The rule of thumb is to use `EXPECT_*` when you want the test to continue to reveal more errors after the assertion failure, and use `ASSERT_*` when continuing after failure doesn't make sense. For example, the second assertion in the `Dequeue` test is `ASSERT_TRUE(n != NULL)`, as we need to dereference the pointer `n` later, which would lead to a segfault when `n` is `NULL`. When these tests run, the following happens: 1. Google Test constructs a `QueueTest` object (let's call it `t1` ). 1. `t1.SetUp()` initializes `t1` . 1. The first test ( `IsEmptyInitially` ) runs on `t1` . 1. `t1.TearDown()` cleans up after the test finishes. 1. `t1` is destructed. 1. The above steps are repeated on another `QueueTest` object, this time running the `DequeueWorks` test. _Availability_: Linux, Windows, Mac. _Note_: Google Test automatically saves all _Google Test_ flags when a test object is constructed, and restores them when it is destructed. # Invoking the Tests # `TEST()` and `TEST_F()` implicitly register their tests with Google Test. So, unlike with many other C++ testing frameworks, you don't have to re-list all your defined tests in order to run them. After defining your tests, you can run them with `RUN_ALL_TESTS()` , which returns `0` if all the tests are successful, or `1` otherwise. Note that `RUN_ALL_TESTS()` runs _all tests_ in your link unit -- they can be from different test cases, or even different source files. When invoked, the `RUN_ALL_TESTS()` macro: 1. Saves the state of all Google Test flags. 1. Creates a test fixture object for the first test. 1. Initializes it via `SetUp()`. 1. Runs the test on the fixture object. 1. Cleans up the fixture via `TearDown()`. 1. Deletes the fixture. 1. Restores the state of all Google Test flags. 1. Repeats the above steps for the next test, until all tests have run. In addition, if the text fixture's constructor generates a fatal failure in step 2, there is no point for step 3 - 5 and they are thus skipped. Similarly, if step 3 generates a fatal failure, step 4 will be skipped. _Important_: You must not ignore the return value of `RUN_ALL_TESTS()`, or `gcc` will give you a compiler error. The rationale for this design is that the automated testing service determines whether a test has passed based on its exit code, not on its stdout/stderr output; thus your `main()` function must return the value of `RUN_ALL_TESTS()`. Also, you should call `RUN_ALL_TESTS()` only **once**. Calling it more than once conflicts with some advanced Google Test features (e.g. thread-safe death tests) and thus is not supported. _Availability_: Linux, Windows, Mac. # Writing the main() Function # You can start from this boilerplate: ``` #include "this/package/foo.h" #include "gtest/gtest.h" namespace { // The fixture for testing class Foo. class FooTest : public ::testing::Test { protected: // You can remove any or all of the following functions if its body // is empty. FooTest() { // You can do set-up work for each test here. } virtual ~FooTest() { // You can do clean-up work that doesn't throw exceptions here. } // If the constructor and destructor are not enough for setting up // and cleaning up each test, you can define the following methods: virtual void SetUp() { // Code here will be called immediately after the constructor (right // before each test). } virtual void TearDown() { // Code here will be called immediately after each test (right // before the destructor). } // Objects declared here can be used by all tests in the test case for Foo. }; // Tests that the Foo::Bar() method does Abc. TEST_F(FooTest, MethodBarDoesAbc) { const string input_filepath = "this/package/testdata/myinputfile.dat"; const string output_filepath = "this/package/testdata/myoutputfile.dat"; Foo f; EXPECT_EQ(0, f.Bar(input_filepath, output_filepath)); } // Tests that Foo does Xyz. TEST_F(FooTest, DoesXyz) { // Exercises the Xyz feature of Foo. } } // namespace int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } ``` The `::testing::InitGoogleTest()` function parses the command line for Google Test flags, and removes all recognized flags. This allows the user to control a test program's behavior via various flags, which we'll cover in [AdvancedGuide](V1_6_AdvancedGuide.md). You must call this function before calling `RUN_ALL_TESTS()`, or the flags won't be properly initialized. On Windows, `InitGoogleTest()` also works with wide strings, so it can be used in programs compiled in `UNICODE` mode as well. But maybe you think that writing all those main() functions is too much work? We agree with you completely and that's why Google Test provides a basic implementation of main(). If it fits your needs, then just link your test with gtest\_main library and you are good to go. ## Important note for Visual C++ users ## If you put your tests into a library and your `main()` function is in a different library or in your .exe file, those tests will not run. The reason is a [bug](https://connect.microsoft.com/feedback/viewfeedback.aspx?FeedbackID=244410&siteid=210) in Visual C++. When you define your tests, Google Test creates certain static objects to register them. These objects are not referenced from elsewhere but their constructors are still supposed to run. When Visual C++ linker sees that nothing in the library is referenced from other places it throws the library out. You have to reference your library with tests from your main program to keep the linker from discarding it. Here is how to do it. Somewhere in your library code declare a function: ``` __declspec(dllexport) int PullInMyLibrary() { return 0; } ``` If you put your tests in a static library (not DLL) then `__declspec(dllexport)` is not required. Now, in your main program, write a code that invokes that function: ``` int PullInMyLibrary(); static int dummy = PullInMyLibrary(); ``` This will keep your tests referenced and will make them register themselves at startup. In addition, if you define your tests in a static library, add `/OPT:NOREF` to your main program linker options. If you use MSVC++ IDE, go to your .exe project properties/Configuration Properties/Linker/Optimization and set References setting to `Keep Unreferenced Data (/OPT:NOREF)`. This will keep Visual C++ linker from discarding individual symbols generated by your tests from the final executable. There is one more pitfall, though. If you use Google Test as a static library (that's how it is defined in gtest.vcproj) your tests must also reside in a static library. If you have to have them in a DLL, you _must_ change Google Test to build into a DLL as well. Otherwise your tests will not run correctly or will not run at all. The general conclusion here is: make your life easier - do not write your tests in libraries! # Where to Go from Here # Congratulations! You've learned the Google Test basics. You can start writing and running Google Test tests, read some [samples](V1_6_Samples.md), or continue with [AdvancedGuide](V1_6_AdvancedGuide.md), which describes many more useful Google Test features. # Known Limitations # Google Test is designed to be thread-safe. The implementation is thread-safe on systems where the `pthreads` library is available. It is currently _unsafe_ to use Google Test assertions from two threads concurrently on other systems (e.g. Windows). In most tests this is not an issue as usually the assertions are done in the main thread. If you want to help, you can volunteer to implement the necessary synchronization primitives in `gtest-port.h` for your platform. assimp-4.1.0/contrib/gtest/docs/V1_5_Documentation.md0000644002537200234200000000141213213503245022715 0ustar zmoelnigiemusersThis page lists all official documentation wiki pages for Google Test **1.5.0** -- **if you use a different version of Google Test, make sure to read the documentation for that version instead.** * [Primer](V1_5_Primer.md) -- start here if you are new to Google Test. * [Samples](Samples.md) -- learn from examples. * [AdvancedGuide](V1_5_AdvancedGuide.md) -- learn more about Google Test. * [XcodeGuide](V1_5_XcodeGuide.md) -- how to use Google Test in Xcode on Mac. * [Frequently-Asked Questions](V1_5_FAQ.md) -- check here before asking a question on the mailing list. To contribute code to Google Test, read: * DevGuide -- read this _before_ writing your first patch. * [PumpManual](V1_5_PumpManual.md) -- how we generate some of Google Test's source files.assimp-4.1.0/contrib/gtest/docs/Documentation.md0000644002537200234200000000141313213503245022124 0ustar zmoelnigiemusersThis page lists all documentation wiki pages for Google Test **(the SVN trunk version)** -- **if you use a released version of Google Test, please read the documentation for that specific version instead.** * [Primer](Primer.md) -- start here if you are new to Google Test. * [Samples](Samples.md) -- learn from examples. * [AdvancedGuide](AdvancedGuide.md) -- learn more about Google Test. * [XcodeGuide](XcodeGuide.md) -- how to use Google Test in Xcode on Mac. * [Frequently-Asked Questions](FAQ.md) -- check here before asking a question on the mailing list. To contribute code to Google Test, read: * [DevGuide](DevGuide.md) -- read this _before_ writing your first patch. * [PumpManual](PumpManual.md) -- how we generate some of Google Test's source files.assimp-4.1.0/contrib/gtest/CHANGES0000644002537200234200000001476513213503245017052 0ustar zmoelnigiemusersChanges for 1.7.0: * New feature: death tests are supported on OpenBSD and in iOS simulator now. * New feature: Google Test now implements a protocol to allow a test runner to detect that a test program has exited prematurely and report it as a failure (before it would be falsely reported as a success if the exit code is 0). * New feature: Test::RecordProperty() can now be used outside of the lifespan of a test method, in which case it will be attributed to the current test case or the test program in the XML report. * New feature (potentially breaking): --gtest_list_tests now prints the type parameters and value parameters for each test. * Improvement: char pointers and char arrays are now escaped properly in failure messages. * Improvement: failure summary in XML reports now includes file and line information. * Improvement: the XML element now has a timestamp attribute. * Improvement: When --gtest_filter is specified, XML report now doesn't contain information about tests that are filtered out. * Fixed the bug where long --gtest_filter flag values are truncated in death tests. * Potentially breaking change: RUN_ALL_TESTS() is now implemented as a function instead of a macro in order to work better with Clang. * Compatibility fixes with C++ 11 and various platforms. * Bug/warning fixes. Changes for 1.6.0: * New feature: ADD_FAILURE_AT() for reporting a test failure at the given source location -- useful for writing testing utilities. * New feature: the universal value printer is moved from Google Mock to Google Test. * New feature: type parameters and value parameters are reported in the XML report now. * A gtest_disable_pthreads CMake option. * Colored output works in GNU Screen sessions now. * Parameters of value-parameterized tests are now printed in the textual output. * Failures from ad hoc test assertions run before RUN_ALL_TESTS() are now correctly reported. * Arguments of ASSERT_XY and EXPECT_XY no longer need to support << to ostream. * More complete handling of exceptions. * GTEST_ASSERT_XY can be used instead of ASSERT_XY in case the latter name is already used by another library. * --gtest_catch_exceptions is now true by default, allowing a test program to continue after an exception is thrown. * Value-parameterized test fixtures can now derive from Test and WithParamInterface separately, easing conversion of legacy tests. * Death test messages are clearly marked to make them more distinguishable from other messages. * Compatibility fixes for Android, Google Native Client, MinGW, HP UX, PowerPC, Lucid autotools, libCStd, Sun C++, Borland C++ Builder (Code Gear), IBM XL C++ (Visual Age C++), and C++0x. * Bug fixes and implementation clean-ups. * Potentially incompatible changes: disables the harmful 'make install' command in autotools. 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 assimp-4.1.0/contrib/gtest/make/0000755002537200234200000000000013213503245016757 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/make/Makefile0000644002537200234200000000530113213503245020416 0ustar zmoelnigiemusers# 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. # Set Google Test's header directory as a system directory, such that # the compiler doesn't generate warnings in Google Test headers. CPPFLAGS += -isystem $(GTEST_DIR)/include # Flags passed to the C++ compiler. CXXFLAGS += -g -Wall -Wextra -pthread # 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 $@ assimp-4.1.0/contrib/gtest/configure.ac0000644002537200234200000000501613213503245020332 0ustar zmoelnigiemusersm4_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.7.0], [googletestframework@googlegroups.com], [gtest]) # Provide various options to initialize the Autoconf and configure processes. AC_PREREQ([2.59]) AC_CONFIG_SRCDIR([./LICENSE]) AC_CONFIG_MACRO_DIR([m4]) 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 assimp-4.1.0/contrib/gtest/README.md0000644002537200234200000002443413213503245017330 0ustar zmoelnigiemusers ### Generic Build Instructions ### #### Setup #### 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. #### Build #### 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` in the system header search path and `${GTEST_DIR}` in the normal header search path. Assuming a Linux-like system and gcc, something like the following will do: g++ -isystem ${GTEST_DIR}/include -I${GTEST_DIR} \ -pthread -c ${GTEST_DIR}/src/gtest-all.cc ar -rv libgtest.a gtest-all.o (We need `-pthread` as Google Test uses threads.) Next, you should compile your test source file with `${GTEST_DIR}/include` in the system header search path, and link it with gtest and any other necessary libraries: g++ -isystem ${GTEST_DIR}/include -pthread 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](CMakeLists.txt)) that can be used on a wide range of platforms ("C" stands for cross-platform.). If you don't have CMake installed already, you can download it for free from . 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 -Dgtest_build_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 Visual 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. If you wish to use the Google Test Xcode project with Xcode 4.x and above, you need to either: * update the SDK configuration options in xcode/Config/General.xconfig. Comment options `SDKROOT`, `MACOS_DEPLOYMENT_TARGET`, and `GCC_VERSION`. If you choose this route you lose the ability to target earlier versions of MacOS X. * Install an SDK for an earlier version. This doesn't appear to be supported by Apple, but has been reported to work (http://stackoverflow.com/questions/5378518). ### 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](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. Note: while the above steps aren't technically necessary today when using some compilers (e.g. GCC), they may become necessary in the future, if we decide to improve the speed of loading the library (see for details). Therefore you are recommended to always add the above flags when using Google Test as a shared library. Otherwise a future release of Google Test may break your build script. ### 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. ## 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 -Dgtest_build_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 -Dgtest_build_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. 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/](scripts/) directory. Read the [Pump manual](docs/PumpManual.md) for how to use it. assimp-4.1.0/contrib/gtest/scripts/0000755002537200234200000000000013213503245017531 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/scripts/release_docs.py0000644002537200234200000001376413213503245022546 0ustar zmoelnigiemusers#!/usr/bin/env python # # Copyright 2013 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. """Script for branching Google Test/Mock wiki pages for a new version. SYNOPSIS release_docs.py NEW_RELEASE_VERSION Google Test and Google Mock's external user documentation is in interlinked wiki files. When we release a new version of Google Test or Google Mock, we need to branch the wiki files such that users of a specific version of Google Test/Mock can look up documenation relevant for that version. This script automates that process by: - branching the current wiki pages (which document the behavior of the SVN trunk head) to pages for the specified version (e.g. branching FAQ.wiki to V2_6_FAQ.wiki when NEW_RELEASE_VERSION is 2.6); - updating the links in the branched files to point to the branched version (e.g. a link in V2_6_FAQ.wiki that pointed to Primer.wiki#Anchor will now point to V2_6_Primer.wiki#Anchor). NOTE: NEW_RELEASE_VERSION must be a NEW version number for which the wiki pages don't yet exist; otherwise you'll get SVN errors like "svn: Path 'V1_7_PumpManual.wiki' is not a directory" when running the script. EXAMPLE $ cd PATH/TO/GTEST_SVN_WORKSPACE/trunk $ scripts/release_docs.py 2.6 # create wiki pages for v2.6 $ svn status # verify the file list $ svn diff # verify the file contents $ svn commit -m "release wiki pages for v2.6" """ __author__ = 'wan@google.com (Zhanyong Wan)' import os import re import sys import common # Wiki pages that shouldn't be branched for every gtest/gmock release. GTEST_UNVERSIONED_WIKIS = ['DevGuide.wiki'] GMOCK_UNVERSIONED_WIKIS = [ 'DesignDoc.wiki', 'DevGuide.wiki', 'KnownIssues.wiki' ] def DropWikiSuffix(wiki_filename): """Removes the .wiki suffix (if any) from the given filename.""" return (wiki_filename[:-len('.wiki')] if wiki_filename.endswith('.wiki') else wiki_filename) class WikiBrancher(object): """Branches ...""" def __init__(self, dot_version): self.project, svn_root_path = common.GetSvnInfo() if self.project not in ('googletest', 'googlemock'): sys.exit('This script must be run in a gtest or gmock SVN workspace.') self.wiki_dir = svn_root_path + '/wiki' # Turn '2.6' to 'V2_6_'. self.version_prefix = 'V' + dot_version.replace('.', '_') + '_' self.files_to_branch = self.GetFilesToBranch() page_names = [DropWikiSuffix(f) for f in self.files_to_branch] # A link to Foo.wiki is in one of the following forms: # [Foo words] # [Foo#Anchor words] # [http://code.google.com/.../wiki/Foo words] # [http://code.google.com/.../wiki/Foo#Anchor words] # We want to replace 'Foo' with 'V2_6_Foo' in the above cases. self.search_for_re = re.compile( # This regex matches either # [Foo # or # /wiki/Foo # followed by a space or a #, where Foo is the name of an # unversioned wiki page. r'(\[|/wiki/)(%s)([ #])' % '|'.join(page_names)) self.replace_with = r'\1%s\2\3' % (self.version_prefix,) def GetFilesToBranch(self): """Returns a list of .wiki file names that need to be branched.""" unversioned_wikis = (GTEST_UNVERSIONED_WIKIS if self.project == 'googletest' else GMOCK_UNVERSIONED_WIKIS) return [f for f in os.listdir(self.wiki_dir) if (f.endswith('.wiki') and not re.match(r'^V\d', f) and # Excluded versioned .wiki files. f not in unversioned_wikis)] def BranchFiles(self): """Branches the .wiki files needed to be branched.""" print 'Branching %d .wiki files:' % (len(self.files_to_branch),) os.chdir(self.wiki_dir) for f in self.files_to_branch: command = 'svn cp %s %s%s' % (f, self.version_prefix, f) print command os.system(command) def UpdateLinksInBranchedFiles(self): for f in self.files_to_branch: source_file = os.path.join(self.wiki_dir, f) versioned_file = os.path.join(self.wiki_dir, self.version_prefix + f) print 'Updating links in %s.' % (versioned_file,) text = file(source_file, 'r').read() new_text = self.search_for_re.sub(self.replace_with, text) file(versioned_file, 'w').write(new_text) def main(): if len(sys.argv) != 2: sys.exit(__doc__) brancher = WikiBrancher(sys.argv[1]) brancher.BranchFiles() brancher.UpdateLinksInBranchedFiles() if __name__ == '__main__': main() assimp-4.1.0/contrib/gtest/scripts/fuse_gtest_files.py0000644002537200234200000002126413213503245023442 0ustar zmoelnigiemusers#!/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 try: from sets import Set as set # For Python 2.3 compatibility except ImportError: pass 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 = open(os.path.join(output_dir, GTEST_H_OUTPUT), 'w') processed_files = 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 open(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 = 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 open(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 = open(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() assimp-4.1.0/contrib/gtest/scripts/gtest-config.in0000644002537200234200000002354713213503245022465 0ustar zmoelnigiemusers#!/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= overrides the installation prefix --exec-prefix= overrides the executable installation prefix --libdir= overrides the library installation prefix --includedir= 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}; cd @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 assimp-4.1.0/contrib/gtest/scripts/pump.py0000644002537200234200000005617113213503245021076 0ustar zmoelnigiemusers#!/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.2.0 - 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'\[\[\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 StripMetaComments(str): """Strip meta comments from each line in the given string.""" # First, completely remove lines containing nothing but a meta # comment, including the trailing \n. str = re.sub(r'^\s*\$\$.*\n', '', str) # Then, remove meta comments from contentful lines. return re.sub(r'\s*\$\$.*', '', str) 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 == '$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): """A generator that yields the tokens in the given string.""" if s != '': lines = s.splitlines(True) for token in TokenizeLines(lines, Cursor(0, 0)): yield token 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 ParseToAST(pump_src_text): """Convert the given Pump source text into an AST.""" tokens = list(Tokenize(pump_src_text)) 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 IsSingleLineComment(cur_line): return '//' in cur_line def IsInPreprocessorDirective(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 WrapPreprocessorDirective(line, output): WrapCode(line, ' \\', output) def WrapPlainCode(line, output): WrapCode(line, '', output) def IsMultiLineIWYUPragma(line): return re.search(r'/\* IWYU pragma: ', line) def IsHeaderGuardIncludeOrOneLineIWYUPragma(line): return (re.match(r'^#(ifndef|define|endif\s*//)\s*[\w_]+\s*$', line) or re.match(r'^#include\s', line) or # Don't break IWYU pragmas, either; that causes iwyu.py problems. re.search(r'// IWYU pragma: ', line)) def WrapLongLine(line, output): line = line.rstrip() if len(line) <= 80: output.append(line) elif IsSingleLineComment(line): if IsHeaderGuardIncludeOrOneLineIWYUPragma(line): # The style guide made an exception to allow long header guard lines, # includes and IWYU pragmas. output.append(line) else: WrapComment(line, output) elif IsInPreprocessorDirective(output, line): if IsHeaderGuardIncludeOrOneLineIWYUPragma(line): # The style guide made an exception to allow long header guard lines, # includes and IWYU pragmas. output.append(line) else: WrapPreprocessorDirective(line, output) elif IsMultiLineIWYUPragma(line): output.append(line) 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 ConvertFromPumpSource(src_text): """Return the text generated from the given Pump source text.""" ast = ParseToAST(StripMetaComments(src_text)) output = Output() RunCode(Env(), ast, output) return BeautifyCode(output.string) def main(argv): if len(argv) == 1: print __doc__ sys.exit(1) file_path = argv[-1] output_str = ConvertFromPumpSource(file(file_path, 'r').read()) 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) assimp-4.1.0/contrib/gtest/scripts/upload_gtest.py0000644002537200234200000000544313213503245022603 0ustar zmoelnigiemusers#!/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() assimp-4.1.0/contrib/gtest/scripts/gen_gtest_pred_impl.py0000644002537200234200000005274213213503245024127 0ustar zmoelnigiemusers#!/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 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(); """ % DEFS impl += ' return AssertionFailure() << pred_text << "("' impl += Iter(n, """ << e%s""", sep=' << ", "') impl += ' << ") evaluates to false, where"' impl += Iter(n, """ << "\\n" << e%s << " evaluates to " << v%s""") impl += """; } // 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 #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(); return testing::AssertionFailure() << """ % DEFS tests += Iter(n, 'e%s', sep=' << " + " << ') tests += """ << " is expected to be positive, but evaluates to " << %(v_sum)s << "."; } """ % 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() assimp-4.1.0/contrib/gtest/scripts/upload.py0000644002537200234200000014352013213503245021374 0ustar zmoelnigiemusers#!/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() assimp-4.1.0/contrib/gtest/scripts/test/0000755002537200234200000000000013213503245020510 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/scripts/test/Makefile0000644002537200234200000000341213213503245022150 0ustar zmoelnigiemusers# 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. # We have no idea here whether pthreads is available in the system, so # disable its use. CPPFLAGS += -I$(FUSED_GTEST_DIR) -DGTEST_HAS_PTHREAD=0 # 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 $@ assimp-4.1.0/contrib/gtest/scripts/common.py0000644002537200234200000000554713213503245021406 0ustar zmoelnigiemusers# Copyright 2013 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. """Shared utilities for writing scripts for Google Test/Mock.""" __author__ = 'wan@google.com (Zhanyong Wan)' import os import re # Matches the line from 'svn info .' output that describes what SVN # path the current local directory corresponds to. For example, in # a googletest SVN workspace's trunk/test directory, the output will be: # # URL: https://googletest.googlecode.com/svn/trunk/test _SVN_INFO_URL_RE = re.compile(r'^URL: https://(\w+)\.googlecode\.com/svn(.*)') def GetCommandOutput(command): """Runs the shell command and returns its stdout as a list of lines.""" f = os.popen(command, 'r') lines = [line.strip() for line in f.readlines()] f.close() return lines def GetSvnInfo(): """Returns the project name and the current SVN workspace's root path.""" for line in GetCommandOutput('svn info .'): m = _SVN_INFO_URL_RE.match(line) if m: project = m.group(1) # googletest or googlemock rel_path = m.group(2) root = os.path.realpath(rel_path.count('/') * '../') return project, root return None, None def GetSvnTrunk(): """Returns the current SVN workspace's trunk root path.""" _, root = GetSvnInfo() return root + '/trunk' if root else None def IsInGTestSvn(): project, _ = GetSvnInfo() return project == 'googletest' def IsInGMockSvn(): project, _ = GetSvnInfo() return project == 'googlemock' assimp-4.1.0/contrib/gtest/include/0000755002537200234200000000000013213503245017465 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/include/gtest/0000755002537200234200000000000013213503245020613 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/include/gtest/internal/0000755002537200234200000000000013213503245022427 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-tuple.h.pump0000644002537200234200000002262413213503245026043 0ustar zmoelnigiemusers$$ -*- 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 // 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 friend class tuple; \ private: #endif // Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that conflict // with our own definitions. Therefore using our own tuple does not work on // those compilers. #if defined(_MSC_VER) && _MSC_VER >= 1600 /* 1600 is Visual Studio 2010 */ # error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \ GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers." #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::type is T if T is a reference; otherwise it's const T&. template struct ByRef { typedef const T& type; }; // NOLINT template struct ByRef { typedef T& type; }; // NOLINT // A handy wrapper for ByRef. #define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type // AddRef::type is T if T is a reference; otherwise it's T&. This // is the same as tr1::add_reference::type. template struct AddRef { typedef T& type; }; // NOLINT template struct AddRef { typedef T& type; }; // NOLINT // A handy wrapper for AddRef. #define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type // A helper for implementing get(). template class Get; // A helper for implementing tuple_element. kIndexValid is true // iff k < the number of fields in tuple type T. template struct TupleElement; $for i [[ template struct TupleElement { 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 class $if k < n [[GTEST_$(k)_TUPLE_(T)]] $else [[tuple]] { public: template 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 tuple(const GTEST_$(k)_TUPLE_(U)& t) : $for m, [[f$(m)_(t.f$(m)_)]] {} $if k == 2 [[ template tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} ]] tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_$(k)_TUPLE_(U)& t) { return CopyFrom(t); } $if k == 2 [[ template tuple& operator=(const ::std::pair& p) { f0_ = p.first; f1_ = p.second; return *this; } ]] GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 to make_tuple(). And we don't // implement tie(). inline tuple<> make_tuple() { return tuple<>(); } $for k [[ $range m 0..k-1 template 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 struct tuple_size; $for j [[ template struct tuple_size { static const int value = $j; }; ]] template struct tuple_element { typedef typename gtest_internal::TupleElement< k < (tuple_size::value), k, Tuple>::type type; }; #define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type // 6.1.3.4 Element access. namespace gtest_internal { $for i [[ template <> class Get<$i> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) Field(Tuple& t) { return t.f$(i)_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_($i, Tuple)) ConstField(const Tuple& t) { return t.f$(i)_; } }; ]] } // namespace gtest_internal template GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) get(GTEST_$(n)_TUPLE_(T)& t) { return gtest_internal::Get::Field(t); } template GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_$(n)_TUPLE_(T))) get(const GTEST_$(n)_TUPLE_(T)& t) { return gtest_internal::Get::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::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 struct SameSizeTuplePrefixComparator; template <> struct SameSizeTuplePrefixComparator<0, 0> { template static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { return true; } }; template struct SameSizeTuplePrefixComparator { template static bool Eq(const Tuple1& t1, const Tuple2& t2) { return SameSizeTuplePrefixComparator::Eq(t1, t2) && ::std::tr1::get(t1) == ::std::tr1::get(t2); } }; } // namespace gtest_internal template inline bool operator==(const GTEST_$(n)_TUPLE_(T)& t, const GTEST_$(n)_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< tuple_size::value, tuple_size::value>::Eq(t, u); } template 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_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-port.h0000644002537200234200000025725013213503245024723 0ustar zmoelnigiemusers// 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. All macros ending with _ and symbols defined in an // internal namespace are subject to change without notice. Code // outside Google Test MUST NOT USE THEM DIRECTLY. Macros that don't // end with _ are part of Google Test's public API and can be used by // code outside Google Test. // // This file is fundamental to Google Test. All other Google Test source // files are expected to #include this. Therefore, it cannot #include // any other Google Test header. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ // Environment-describing macros // ----------------------------- // // Google Test can be used in many different environments. Macros in // this section tell Google Test what kind of environment it is being // used in, such that Google Test can provide environment-specific // features and implementations. // // Google Test tries to automatically detect the properties of its // environment, so users usually don't need to worry about these // macros. However, the automatic detection is not perfect. // Sometimes it's necessary for a user to define some of the following // macros in the build script to override Google Test's decisions. // // If the user doesn't define a macro in the list, Google Test will // provide a default definition. After this header is #included, all // macros in this list will be defined to either 1 or 0. // // Notes to maintainers: // - Each macro here is a user-tweakable knob; do not grow the list // lightly. // - Use #if to key off these macros. Don't use #ifdef or "#if // defined(...)", which will not work as these macros are ALWAYS // defined. // // 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_POSIX_RE - Define it to 1/0 to indicate that POSIX regular // expressions are/aren't available. // GTEST_HAS_PTHREAD - Define it to 1/0 to indicate that // 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_HAS_STREAM_REDIRECTION // - Define it to 1/0 to indicate whether the // platform supports I/O stream redirection using // dup() and dup2(). // 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_LANG_CXX11 - Define it to 1/0 to indicate that Google Test // is building in C++11/C++98 mode. // 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. // Platform-indicating macros // -------------------------- // // Macros indicating the platform on which Google Test is being used // (a macro is defined to 1 if compiled on the given platform; // otherwise UNDEFINED -- it's never defined to 0.). Google Test // defines these macros automatically. Code outside Google Test MUST // NOT define them. // // GTEST_OS_AIX - IBM AIX // GTEST_OS_CYGWIN - Cygwin // GTEST_OS_FREEBSD - FreeBSD // GTEST_OS_HPUX - HP-UX // GTEST_OS_LINUX - Linux // GTEST_OS_LINUX_ANDROID - Google Android // GTEST_OS_MAC - Mac OS X // GTEST_OS_IOS - iOS // GTEST_OS_NACL - Google Native Client (NaCl) // GTEST_OS_OPENBSD - OpenBSD // GTEST_OS_QNX - QNX // 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_WINDOWS_PHONE - Windows Phone // GTEST_OS_WINDOWS_RT - Windows Store App/WinRT // 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!). // // It is possible that none of the GTEST_OS_* macros are defined. // Feature-indicating macros // ------------------------- // // Macros indicating which Google Test features are available (a macro // is defined to 1 if the corresponding feature is supported; // otherwise UNDEFINED -- it's never defined to 0.). Google Test // defines these macros automatically. Code outside Google Test MUST // NOT define them. // // These macros are public so that portable tests can be written. // Such tests typically surround code using a feature with an #if // which controls that code. For example: // // #if GTEST_HAS_DEATH_TEST // EXPECT_DEATH(DoSomethingDeadly()); // #endif // // 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_IS_THREADSAFE - Google Test is thread-safe. // GTEST_USES_POSIX_RE - enhanced POSIX regex is used. Do not confuse with // GTEST_HAS_POSIX_RE (see above) which users can // define themselves. // 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(). // Misc public macros // ------------------ // // GTEST_FLAG(flag_name) - references the variable corresponding to // the given Google Test flag. // Internal utilities // ------------------ // // The following macros and utilities are for Google Test's INTERNAL // use only. Code outside Google Test MUST NOT USE THEM DIRECTLY. // // 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. // GTEST_INTENTIONAL_CONST_COND_PUSH_ - start code section where MSVC C4127 is // suppressed (constant conditional). // GTEST_INTENTIONAL_CONST_COND_POP_ - finish code section where MSVC C4127 // is suppressed. // // C++11 feature wrappers: // // testing::internal::move - portability wrapper for std::move. // // Synchronization: // Mutex, MutexLock, ThreadLocal, GetThreadCount() // - synchronization primitives. // // Template meta programming: // is_pointer - as in TR1; needed on Symbian and IBM XL C/C++ only. // IteratorTraits - partial implementation of std::iterator_traits, which // is not available in libCstd when compiled with Sun C++. // // Smart pointers: // scoped_ptr - as in TR2. // // Regular expressions: // RE - a simple regular expression class using the POSIX // Extended Regular Expression syntax on UNIX-like // platforms, or a reduced regular exception syntax on // other platforms, including 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_DECLARE_*() - declares a flag. // GTEST_DEFINE_*() - defines a flag. // GetInjectableArgvs() - 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 // for isspace, etc #include // for ptrdiff_t #include #include #include #ifndef _WIN32_WCE # include # include #endif // !_WIN32_WCE #if defined __APPLE__ # include # include #endif #include // NOLINT #include // NOLINT #include // NOLINT #include // NOLINT #include #include // NOLINT #include "gtest/internal/gtest-port-arch.h" #include "gtest/internal/custom/gtest-port.h" #if !defined(GTEST_DEV_EMAIL_) # 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_ "https://github.com/google/googletest/" #endif // !defined(GTEST_DEV_EMAIL_) #if !defined(GTEST_INIT_GOOGLE_TEST_NAME_) # define GTEST_INIT_GOOGLE_TEST_NAME_ "testing::InitGoogleTest" #endif // !defined(GTEST_INIT_GOOGLE_TEST_NAME_) // 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__ // Macros for disabling Microsoft Visual C++ warnings. // // GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 4385) // /* code that triggers warnings C4800 and C4385 */ // GTEST_DISABLE_MSC_WARNINGS_POP_() #if _MSC_VER >= 1500 # define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) \ __pragma(warning(push)) \ __pragma(warning(disable: warnings)) # define GTEST_DISABLE_MSC_WARNINGS_POP_() \ __pragma(warning(pop)) #else // Older versions of MSVC don't have __pragma. # define GTEST_DISABLE_MSC_WARNINGS_PUSH_(warnings) # define GTEST_DISABLE_MSC_WARNINGS_POP_() #endif #ifndef GTEST_LANG_CXX11 // gcc and clang define __GXX_EXPERIMENTAL_CXX0X__ when // -std={c,gnu}++{0x,11} is passed. The C++11 standard specifies a // value for __cplusplus, and recent versions of clang, gcc, and // probably other compilers set that too in C++11 mode. # if __GXX_EXPERIMENTAL_CXX0X__ || __cplusplus >= 201103L // Compiling in at least C++11 mode. # define GTEST_LANG_CXX11 1 # else # define GTEST_LANG_CXX11 0 # endif #endif // Distinct from C++11 language support, some environments don't provide // proper C++11 library support. Notably, it's possible to build in // C++11 mode when targeting Mac OS X 10.6, which has an old libstdc++ // with no C++11 support. // // libstdc++ has sufficient C++11 support as of GCC 4.6.0, __GLIBCXX__ // 20110325, but maintenance releases in the 4.4 and 4.5 series followed // this date, so check for those versions by their date stamps. // https://gcc.gnu.org/onlinedocs/libstdc++/manual/abi.html#abi.versioning #if GTEST_LANG_CXX11 && \ (!defined(__GLIBCXX__) || ( \ __GLIBCXX__ >= 20110325ul && /* GCC >= 4.6.0 */ \ /* Blacklist of patch releases of older branches: */ \ __GLIBCXX__ != 20110416ul && /* GCC 4.4.6 */ \ __GLIBCXX__ != 20120313ul && /* GCC 4.4.7 */ \ __GLIBCXX__ != 20110428ul && /* GCC 4.5.3 */ \ __GLIBCXX__ != 20120702ul)) /* GCC 4.5.4 */ # define GTEST_STDLIB_CXX11 1 #endif // Only use C++11 library features if the library provides them. #if GTEST_STDLIB_CXX11 # define GTEST_HAS_STD_BEGIN_AND_END_ 1 # define GTEST_HAS_STD_FORWARD_LIST_ 1 # define GTEST_HAS_STD_FUNCTION_ 1 # define GTEST_HAS_STD_INITIALIZER_LIST_ 1 # define GTEST_HAS_STD_MOVE_ 1 # define GTEST_HAS_STD_SHARED_PTR_ 1 # define GTEST_HAS_STD_TYPE_TRAITS_ 1 # define GTEST_HAS_STD_UNIQUE_PTR_ 1 #endif // C++11 specifies that provides std::tuple. // Some platforms still might not have it, however. #if GTEST_LANG_CXX11 # define GTEST_HAS_STD_TUPLE_ 1 # if defined(__clang__) // Inspired by http://clang.llvm.org/docs/LanguageExtensions.html#__has_include # if defined(__has_include) && !__has_include() # undef GTEST_HAS_STD_TUPLE_ # endif # elif defined(_MSC_VER) // Inspired by boost/config/stdlib/dinkumware.hpp # if defined(_CPPLIB_VER) && _CPPLIB_VER < 520 # undef GTEST_HAS_STD_TUPLE_ # endif # elif defined(__GLIBCXX__) // Inspired by boost/config/stdlib/libstdcpp3.hpp, // http://gcc.gnu.org/gcc-4.2/changes.html and // http://gcc.gnu.org/onlinedocs/libstdc++/manual/bk01pt01ch01.html#manual.intro.status.standard.200x # if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 2) # undef GTEST_HAS_STD_TUPLE_ # endif # endif #endif // Brings in definitions for functions used in the testing::internal::posix // namespace (read, write, close, chdir, isatty, stat). We do not currently // use them on Windows Mobile. #if GTEST_OS_WINDOWS # if !GTEST_OS_WINDOWS_MOBILE # include # include # endif // In order to avoid having to include , use forward declaration // assuming CRITICAL_SECTION is a typedef of _RTL_CRITICAL_SECTION. // This assumption is verified by // WindowsTypesTest.CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION. struct _RTL_CRITICAL_SECTION; #else // This assumes that non-Windows OSes provide unistd.h. For OSes where this // is not the case, we need to include headers that provide the functions // mentioned above. # include # include #endif // GTEST_OS_WINDOWS #if GTEST_OS_LINUX_ANDROID // Used to define __ANDROID_API__ matching the target NDK API level. # include // NOLINT #endif // Defines this to true iff Google Test can use POSIX regular expressions. #ifndef GTEST_HAS_POSIX_RE # if GTEST_OS_LINUX_ANDROID // On Android, is only available starting with Gingerbread. # define GTEST_HAS_POSIX_RE (__ANDROID_API__ >= 9) # else # define GTEST_HAS_POSIX_RE (!GTEST_OS_WINDOWS) # endif #endif #if GTEST_USES_PCRE // The appropriate headers have already been included. #elif GTEST_HAS_POSIX_RE // On some platforms, needs someone to define size_t, and // won't compile otherwise. We can #include it here as we already // included , which is guaranteed to define size_t through // . # include // NOLINT # define GTEST_USES_POSIX_RE 1 #elif GTEST_OS_WINDOWS // is not available on Windows. Use our own simple regex // implementation instead. # define GTEST_USES_SIMPLE_RE 1 #else // may not be available on this platform. Use our own // simple regex implementation instead. # define GTEST_USES_SIMPLE_RE 1 #endif // GTEST_USES_PCRE #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(__clang__) // clang defines __EXCEPTIONS iff exceptions are enabled before clang 220714, // but iff cleanups are enabled after that. In Obj-C++ files, there can be // cleanups for ObjC exceptions which also need cleanups, even if C++ exceptions // are disabled. clang has __has_feature(cxx_exceptions) which checks for C++ // exceptions starting at clang r206352, but which checked for cleanups prior to // that. To reliably check for C++ exception availability with clang, check for // __EXCEPTIONS && __has_feature(cxx_exceptions). # define GTEST_HAS_EXCEPTIONS (__EXCEPTIONS && __has_feature(cxx_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 # elif defined(__HP_aCC) // Exception handling is in effect by default in HP aCC compiler. It has to // be turned of by +noeh compiler option if desired. # 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.7 and below doesn't support ::std::wstring. // Solaris' libc++ doesn't support it either. Android has // no support for it at least as recent as Froyo (2.2). # define GTEST_HAS_STD_WSTRING \ (!(GTEST_OS_LINUX_ANDROID || 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 // When building against STLport with the Android NDK and with // -frtti -fno-exceptions, the build fails at link time with undefined // references to __cxa_bad_typeid. Note sure if STL or toolchain bug, // so disable RTTI when detected. # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) && \ !defined(__EXCEPTIONS) # define GTEST_HAS_RTTI 0 # else # define GTEST_HAS_RTTI 1 # endif // GTEST_OS_LINUX_ANDROID && __STLPORT_MAJOR && !__EXCEPTIONS # else # define GTEST_HAS_RTTI 0 # endif // __GXX_RTTI // Clang defines __GXX_RTTI starting with version 3.0, but its manual recommends // using has_feature instead. has_feature(cxx_rtti) is supported since 2.7, the // first version with C++ support. # elif defined(__clang__) # define GTEST_HAS_RTTI __has_feature(cxx_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 when RTTI // is enabled. #if GTEST_HAS_RTTI # include #endif // Determines whether Google Test can use the pthreads library. #ifndef GTEST_HAS_PTHREAD // The user didn't tell us explicitly, so we make reasonable assumptions about // which platforms have pthreads support. // // 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 || GTEST_OS_HPUX \ || GTEST_OS_QNX || GTEST_OS_FREEBSD || GTEST_OS_NACL) #endif // GTEST_HAS_PTHREAD #if GTEST_HAS_PTHREAD // gtest-port.h guarantees to #include when GTEST_HAS_PTHREAD is // true. # include // NOLINT // For timespec and nanosleep, used below. # include // NOLINT #endif // Determines if hash_map/hash_set are available. // Only used for testing against those containers. #if !defined(GTEST_HAS_HASH_MAP_) # if _MSC_VER # define GTEST_HAS_HASH_MAP_ 1 // Indicates that hash_map is available. # define GTEST_HAS_HASH_SET_ 1 // Indicates that hash_set is available. # endif // _MSC_VER #endif // !defined(GTEST_HAS_HASH_MAP_) // 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 # if GTEST_OS_LINUX_ANDROID && defined(_STLPORT_MAJOR) // STLport, provided with the Android NDK, has neither or . # define GTEST_HAS_TR1_TUPLE 0 # else // The user didn't tell us not to do it, so we assume it's OK. # define GTEST_HAS_TR1_TUPLE 1 # endif #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, libstdc++ 4.0.0+ and // MSVC 2010 are the only mainstream standard libraries 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. QNX's QCC compiler is a modified GCC but it doesn't // support TR1 tuple. libc++ only provides std::tuple, in C++11 mode, // and it can be used with some compilers that define __GNUC__. # if (defined(__GNUC__) && !defined(__CUDACC__) && (GTEST_GCC_VER_ >= 40000) \ && !GTEST_OS_QNX && !defined(_LIBCPP_VERSION)) || _MSC_VER >= 1600 # define GTEST_ENV_HAS_TR1_TUPLE_ 1 # endif // C++11 specifies that provides std::tuple. Use that if gtest is used // in C++11 mode and libstdc++ isn't very old (binaries targeting OS X 10.6 // can build with clang but need to use gcc4.2's libstdc++). # if GTEST_LANG_CXX11 && (!defined(__GLIBCXX__) || __GLIBCXX__ > 20110325) # define GTEST_ENV_HAS_STD_TUPLE_ 1 # endif # if GTEST_ENV_HAS_TR1_TUPLE_ || GTEST_ENV_HAS_STD_TUPLE_ # 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 // tuple. #if GTEST_HAS_STD_TUPLE_ # include // IWYU pragma: export # define GTEST_TUPLE_NAMESPACE_ ::std #endif // GTEST_HAS_STD_TUPLE_ // We include tr1::tuple even if std::tuple is available to define printers for // them. #if GTEST_HAS_TR1_TUPLE # ifndef GTEST_TUPLE_NAMESPACE_ # define GTEST_TUPLE_NAMESPACE_ ::std::tr1 # endif // GTEST_TUPLE_NAMESPACE_ # if GTEST_USE_OWN_TR1_TUPLE # include "gtest/internal/gtest-tuple.h" // IWYU pragma: export // NOLINT # elif GTEST_ENV_HAS_STD_TUPLE_ # include // C++11 puts its tuple into the ::std namespace rather than // ::std::tr1. gtest expects tuple to live in ::std::tr1, so put it there. // This causes undefined behavior, but supported compilers react in // the way we intend. namespace std { namespace tr1 { using ::std::get; using ::std::make_tuple; using ::std::tuple; using ::std::tuple_element; using ::std::tuple_size; } } # 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 , which defines // BOOST_HAS_TR1_TUPLE, from being #included by Boost's . # define BOOST_TR1_DETAIL_CONFIG_HPP_INCLUDED # include // IWYU pragma: export // NOLINT # elif defined(__GNUC__) && (GTEST_GCC_VER_ >= 40000) // GCC 4.0+ implements tr1/tuple in the header. This does // not conform to the TR1 spec, which requires the header to be . # if !GTEST_HAS_RTTI && GTEST_GCC_VER_ < 40302 // Until version 4.3.2, gcc has a bug that causes , // which is #included by , to not compile when RTTI is // disabled. _TR1_FUNCTIONAL is the header guard for // . Hence the following #define is a hack to prevent // from being included. # define _TR1_FUNCTIONAL 1 # include # undef _TR1_FUNCTIONAL // Allows the user to #include // if he chooses to. # else # include // 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 // IWYU pragma: export // 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__) # if GTEST_OS_LINUX_ANDROID // On Android, clone() is only available on ARM starting with Gingerbread. # if defined(__arm__) && __ANDROID_API__ >= 9 # define GTEST_HAS_CLONE 1 # else # define GTEST_HAS_CLONE 0 # endif # else # define GTEST_HAS_CLONE 1 # endif # 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. #ifndef GTEST_HAS_STREAM_REDIRECTION // By default, we assume that stream redirection is supported on all // platforms except known mobile ones. # if GTEST_OS_WINDOWS_MOBILE || GTEST_OS_SYMBIAN || \ GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT # define GTEST_HAS_STREAM_REDIRECTION 0 # else # define GTEST_HAS_STREAM_REDIRECTION 1 # endif // !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_SYMBIAN #endif // GTEST_HAS_STREAM_REDIRECTION // 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_CYGWIN || GTEST_OS_SOLARIS || \ (GTEST_OS_MAC && !GTEST_OS_IOS) || \ (GTEST_OS_WINDOWS_DESKTOP && _MSC_VER >= 1400) || \ GTEST_OS_WINDOWS_MINGW || GTEST_OS_AIX || GTEST_OS_HPUX || \ GTEST_OS_OPENBSD || GTEST_OS_QNX || GTEST_OS_FREEBSD) # define GTEST_HAS_DEATH_TEST 1 #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 and variadic macros, which GCC, VC++ 8.0, // Sun Pro CC, IBM Visual Age, and HP aCC support. #if defined(__GNUC__) || (_MSC_VER >= 1400) || defined(__SUNPRO_CC) || \ defined(__IBMCPP__) || defined(__HP_aCC) # 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) // Determines whether test results can be streamed to a socket. #if GTEST_OS_LINUX # define GTEST_CAN_STREAM_RESULTS_ 1 #endif // 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: default: // 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)) #elif defined(__clang__) # if __has_attribute(unused) # define GTEST_ATTRIBUTE_UNUSED_ __attribute__ ((unused)) # endif #endif #ifndef GTEST_ATTRIBUTE_UNUSED_ # 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 // MS C++ compiler emits warning when a conditional expression is compile time // constant. In some contexts this warning is false positive and needs to be // suppressed. Use the following two macros in such cases: // // GTEST_INTENTIONAL_CONST_COND_PUSH_() // while (true) { // GTEST_INTENTIONAL_CONST_COND_POP_() // } # define GTEST_INTENTIONAL_CONST_COND_PUSH_() \ GTEST_DISABLE_MSC_WARNINGS_PUSH_(4127) # define GTEST_INTENTIONAL_CONST_COND_POP_() \ GTEST_DISABLE_MSC_WARNINGS_POP_() // 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 #define GTEST_IS_THREADSAFE \ (GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ \ || (GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT) \ || GTEST_HAS_PTHREAD) #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 #elif __GNUC__ >= 4 || defined(__clang__) # define GTEST_API_ __attribute__((visibility ("default"))) #endif // _MSC_VER #ifndef GTEST_API_ # define GTEST_API_ #endif #ifdef __GNUC__ // Ask the compiler to never inline a given function. # define GTEST_NO_INLINE_ __attribute__((noinline)) #else # define GTEST_NO_INLINE_ #endif // _LIBCPP_VERSION is defined by the libc++ library from the LLVM project. #if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) # define GTEST_HAS_CXXABI_H_ 1 #else # define GTEST_HAS_CXXABI_H_ 0 #endif // A function level attribute to disable checking for use of uninitialized // memory when built with MemorySanitizer. #if defined(__clang__) # if __has_feature(memory_sanitizer) # define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ \ __attribute__((no_sanitize_memory)) # else # define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ # endif // __has_feature(memory_sanitizer) #else # define GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ #endif // __clang__ // A function level attribute to disable AddressSanitizer instrumentation. #if defined(__clang__) # if __has_feature(address_sanitizer) # define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ \ __attribute__((no_sanitize_address)) # else # define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ # endif // __has_feature(address_sanitizer) #else # define GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ #endif // __clang__ // A function level attribute to disable ThreadSanitizer instrumentation. #if defined(__clang__) # if __has_feature(thread_sanitizer) # define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ \ __attribute__((no_sanitize_thread)) # else # define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ # endif // __has_feature(thread_sanitizer) #else # define GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ #endif // __clang__ namespace testing { class Message; #if defined(GTEST_TUPLE_NAMESPACE_) // Import tuple and friends into the ::testing namespace. // It is part of our interface, having them in ::testing allows us to change // their types as needed. using GTEST_TUPLE_NAMESPACE_::get; using GTEST_TUPLE_NAMESPACE_::make_tuple; using GTEST_TUPLE_NAMESPACE_::tuple; using GTEST_TUPLE_NAMESPACE_::tuple_size; using GTEST_TUPLE_NAMESPACE_::tuple_element; #endif // defined(GTEST_TUPLE_NAMESPACE_) namespace internal { // 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; // The GTEST_COMPILE_ASSERT_ macro can be used to verify that a compile time // expression is true. For example, you could use it to verify the // size of a static array: // // GTEST_COMPILE_ASSERT_(GTEST_ARRAY_SIZE_(names) == NUM_NAMES, // names_incorrect_size); // // or to make sure a struct is smaller than a certain size: // // GTEST_COMPILE_ASSERT_(sizeof(foo) < 128, foo_too_large); // // The second argument to the macro is the name of the variable. If // the expression is false, most compilers will issue a warning/error // containing the name of the variable. #if GTEST_LANG_CXX11 # define GTEST_COMPILE_ASSERT_(expr, msg) static_assert(expr, #msg) #else // !GTEST_LANG_CXX11 template struct CompileAssert { }; # define GTEST_COMPILE_ASSERT_(expr, msg) \ typedef ::testing::internal::CompileAssert<(static_cast(expr))> \ msg[static_cast(expr) ? 1 : -1] GTEST_ATTRIBUTE_UNUSED_ #endif // !GTEST_LANG_CXX11 // Implementation details of GTEST_COMPILE_ASSERT_: // // (In C++11, we simply use static_assert instead of the following) // // - GTEST_COMPILE_ASSERT_ works by defining an array type that has -1 // elements (and thus is invalid) when the expression is false. // // - The simpler definition // // #define GTEST_COMPILE_ASSERT_(expr, msg) typedef char msg[(expr) ? 1 : -1] // // does not work, as gcc supports variable-length arrays whose sizes // are determined at run-time (this is gcc's extension and not part // of the C++ standard). As a result, gcc fails to reject the // following code with the simple definition: // // int foo; // GTEST_COMPILE_ASSERT_(foo, msg); // not supposed to compile as foo is // // not a compile-time constant. // // - By using the type CompileAssert<(bool(expr))>, we ensures that // expr is a compile-time constant. (Template arguments must be // determined at compile-time.) // // - The outter parentheses in CompileAssert<(bool(expr))> are necessary // to work around a bug in gcc 3.4.4 and 4.0.1. If we had written // // CompileAssert // // instead, these compilers will refuse to compile // // GTEST_COMPILE_ASSERT_(5 > 0, some_message); // // (They seem to think the ">" in "5 > 0" marks the end of the // template argument list.) // // - The array size is (bool(expr) ? 1 : -1), instead of simply // // ((expr) ? 1 : -1). // // This is to avoid running into a bug in MS VC 7.1, which // causes ((0.0) ? 1 : -1) to incorrectly evaluate to 1. // StaticAssertTypeEqHelper is used by StaticAssertTypeEq defined in gtest.h. // // This template is declared, but intentionally undefined. template struct StaticAssertTypeEqHelper; template struct StaticAssertTypeEqHelper { enum { value = true }; }; // Evaluates to the number of elements in 'array'. #define GTEST_ARRAY_SIZE_(array) (sizeof(array) / sizeof(array[0])) #if GTEST_HAS_GLOBAL_STRING typedef ::string string; #else typedef ::std::string string; #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING typedef ::wstring wstring; #elif GTEST_HAS_STD_WSTRING typedef ::std::wstring wstring; #endif // GTEST_HAS_GLOBAL_WSTRING // 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 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; } } friend void swap(scoped_ptr& a, scoped_ptr& b) { using std::swap; swap(a.ptr_, b.ptr_); } private: T* ptr_; GTEST_DISALLOW_COPY_AND_ASSIGN_(scoped_ptr); }; // Defines RE. // A simple C++ wrapper for . 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 an std::string, as Google Test used to be // used where std::string is not available. TODO(wan@google.com): change to // std::string. 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); }; // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line); // Formats a file location for compiler-independent XML output. // Although this function is not platform dependent, we put it next to // FormatFileLocation in order to contrast the two functions. GTEST_API_ ::std::string FormatCompilerIndependentFileLocation(const char* file, int line); // 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); }; #if !defined(GTEST_LOG_) # define GTEST_LOG_(severity) \ ::testing::internal::GTestLog(::testing::internal::GTEST_##severity, \ __FILE__, __LINE__).GetStream() inline void LogToStderr() {} inline void FlushInfoLog() { fflush(NULL); } #endif // !defined(GTEST_LOG_) #if !defined(GTEST_CHECK_) // 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. " #endif // !defined(GTEST_CHECK_) // 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 #if GTEST_HAS_STD_MOVE_ using std::move; #else // GTEST_HAS_STD_MOVE_ template const T& move(const T& t) { return t; } #endif // GTEST_HAS_STD_MOVE_ // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Use ImplicitCast_ as a safe version of static_cast for upcasting in // the type hierarchy (e.g. casting a Foo* to a SuperclassOfFoo* or a // const Foo*). When you use ImplicitCast_, the compiler checks that // the cast is safe. Such explicit ImplicitCast_s are necessary in // surprisingly many situations where C++ demands an exact type match // instead of an argument type convertable to a target type. // // The syntax for using ImplicitCast_ is the same as for static_cast: // // ImplicitCast_(expr) // // ImplicitCast_ would have been part of the C++ standard library, // but the proposal was submitted too late. It will probably make // its way into the language in the future. // // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., implicit_cast). The internal // namespace alone is not enough because the function can be found by ADL. template inline To ImplicitCast_(To x) { return x; } // When you upcast (that is, cast a pointer from type Foo to type // SuperclassOfFoo), it's fine to use ImplicitCast_<>, since upcasts // always succeed. When you downcast (that is, cast a pointer from // type Foo to type SubclassOfFoo), static_cast<> isn't safe, because // how do you know the pointer is really of type SubclassOfFoo? It // could be a bare Foo, or of type DifferentSubclassOfFoo. Thus, // when you downcast, you should use this macro. In debug mode, we // use dynamic_cast<> to double-check the downcast is legal (we die // if it's not). In normal mode, we do the efficient static_cast<> // instead. Thus, it's important to test in debug mode to make sure // the cast is legal! // This is the only place in the code we should use dynamic_cast<>. // In particular, you SHOULDN'T be using dynamic_cast<> in order to // do RTTI (eg code like this: // if (dynamic_cast(foo)) HandleASubclass1Object(foo); // if (dynamic_cast(foo)) HandleASubclass2Object(foo); // You should design the code some other way not to need this. // // This relatively ugly name is intentional. It prevents clashes with // similar functions users may have (e.g., down_cast). The internal // namespace alone is not enough because the function can be found by ADL. template // use like this: DownCast_(foo); inline To DownCast_(From* f) { // so we only accept pointers // Ensures that To is a sub-type of From *. This test is here only // for compile-time type checking, and has no overhead in an // optimized build at run-time, as it will be optimized away // completely. GTEST_INTENTIONAL_CONST_COND_PUSH_() if (false) { GTEST_INTENTIONAL_CONST_COND_POP_() const To to = NULL; ::testing::internal::ImplicitCast_(to); } #if GTEST_HAS_RTTI // RTTI: debug mode only! GTEST_CHECK_(f == NULL || dynamic_cast(f) != NULL); #endif return static_cast(f); } // 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 Derived* CheckedDowncastToActualType(Base* base) { #if GTEST_HAS_RTTI GTEST_CHECK_(typeid(*base) == typeid(Derived)); #endif #if GTEST_HAS_DOWNCAST_ return ::down_cast(base); #elif GTEST_HAS_RTTI return dynamic_cast(base); // NOLINT #else return static_cast(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_ std::string GetCapturedStdout(); GTEST_API_ void CaptureStderr(); GTEST_API_ std::string GetCapturedStderr(); #endif // GTEST_HAS_STREAM_REDIRECTION // Returns a path to temporary directory. GTEST_API_ std::string TempDir(); // Returns the size (in bytes) of a file. GTEST_API_ size_t GetFileSize(FILE* file); // Reads the entire content of a file as a string. GTEST_API_ std::string ReadEntireFile(FILE* file); // All command line arguments. GTEST_API_ const ::std::vector& GetArgvs(); #if GTEST_HAS_DEATH_TEST const ::std::vector& GetInjectableArgvs(); void SetInjectableArgvs(const ::std::vector* new_argvs); #endif // GTEST_HAS_DEATH_TEST // Defines synchronization primitives. #if GTEST_IS_THREADSAFE # if GTEST_HAS_PTHREAD // Sleeps for (roughly) n milliseconds. 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); } # endif // GTEST_HAS_PTHREAD # if GTEST_HAS_NOTIFICATION_ // Notification has already been imported into the namespace. // Nothing to do here. # elif GTEST_HAS_PTHREAD // 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) { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_init(&mutex_, NULL)); } ~Notification() { pthread_mutex_destroy(&mutex_); } // Notifies all threads created with this notification to start. Must // be called from the controller thread. void Notify() { pthread_mutex_lock(&mutex_); notified_ = true; pthread_mutex_unlock(&mutex_); } // Blocks until the controller thread notifies. Must be called from a test // thread. void WaitForNotification() { for (;;) { pthread_mutex_lock(&mutex_); const bool notified = notified_; pthread_mutex_unlock(&mutex_); if (notified) break; SleepMilliseconds(10); } } private: pthread_mutex_t mutex_; bool notified_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; # elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT GTEST_API_ void SleepMilliseconds(int n); // Provides leak-safe Windows kernel handle ownership. // Used in death tests and in threading support. class GTEST_API_ AutoHandle { public: // Assume that Win32 HANDLE type is equivalent to void*. Doing so allows us to // avoid including in this header file. Including is // undesirable because it defines a lot of symbols and macros that tend to // conflict with client code. This assumption is verified by // WindowsTypesTest.HANDLEIsVoidStar. typedef void* Handle; AutoHandle(); explicit AutoHandle(Handle handle); ~AutoHandle(); Handle Get() const; void Reset(); void Reset(Handle handle); private: // Returns true iff the handle is a valid handle object that can be closed. bool IsCloseable() const; Handle handle_; GTEST_DISALLOW_COPY_AND_ASSIGN_(AutoHandle); }; // 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 GTEST_API_ Notification { public: Notification(); void Notify(); void WaitForNotification(); private: AutoHandle event_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Notification); }; # endif // GTEST_HAS_NOTIFICATION_ // On MinGW, we can have both GTEST_OS_WINDOWS and GTEST_HAS_PTHREAD // defined, but we don't want to use MinGW's pthreads implementation, which // has conformance problems with some versions of the POSIX standard. # if GTEST_HAS_PTHREAD && !GTEST_OS_WINDOWS_MINGW // 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(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 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 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: UserThreadFunc* const 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); }; # endif // !GTEST_OS_WINDOWS && GTEST_HAS_PTHREAD || // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ # if GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ // Mutex and ThreadLocal have already been imported into the namespace. // Nothing to do here. # elif GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // Mutex implements mutex on Windows platforms. It is used in conjunction // with class MutexLock: // // Mutex mutex; // ... // MutexLock lock(&mutex); // Acquires the mutex and releases it at the // // end of the current scope. // // A static Mutex *must* be defined or declared using one of the following // macros: // GTEST_DEFINE_STATIC_MUTEX_(g_some_mutex); // GTEST_DECLARE_STATIC_MUTEX_(g_some_mutex); // // (A non-static Mutex is defined/declared in the usual way). class GTEST_API_ Mutex { public: enum MutexType { kStatic = 0, kDynamic = 1 }; // We rely on kStaticMutex being 0 as it is to what the linker initializes // type_ in static mutexes. critical_section_ will be initialized lazily // in ThreadSafeLazyInit(). enum StaticConstructorSelector { kStaticMutex = 0 }; // This constructor intentionally does nothing. It relies on type_ being // statically initialized to 0 (effectively setting it to kStatic) and on // ThreadSafeLazyInit() to lazily initialize the rest of the members. explicit Mutex(StaticConstructorSelector /*dummy*/) {} Mutex(); ~Mutex(); void Lock(); void Unlock(); // Does nothing if the current thread holds the mutex. Otherwise, crashes // with high probability. void AssertHeld(); private: // Initializes owner_thread_id_ and critical_section_ in static mutexes. void ThreadSafeLazyInit(); // Per http://blogs.msdn.com/b/oldnewthing/archive/2004/02/23/78395.aspx, // we assume that 0 is an invalid value for thread IDs. unsigned int owner_thread_id_; // For static mutexes, we rely on these members being initialized to zeros // by the linker. MutexType type_; long critical_section_init_phase_; // NOLINT _RTL_CRITICAL_SECTION* critical_section_; GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::Mutex mutex # define GTEST_DEFINE_STATIC_MUTEX_(mutex) \ ::testing::internal::Mutex mutex(::testing::internal::Mutex::kStaticMutex) // We cannot name this class MutexLock because the ctor declaration would // conflict with a macro named MutexLock, which is defined on some // platforms. That macro is used as a defensive measure to prevent against // inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than // "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(Mutex* mutex) : mutex_(mutex) { mutex_->Lock(); } ~GTestMutexLock() { mutex_->Unlock(); } private: Mutex* const mutex_; GTEST_DISALLOW_COPY_AND_ASSIGN_(GTestMutexLock); }; typedef GTestMutexLock MutexLock; // Base class for ValueHolder. Allows a caller to hold and delete a value // without knowing its type. class ThreadLocalValueHolderBase { public: virtual ~ThreadLocalValueHolderBase() {} }; // Provides a way for a thread to send notifications to a ThreadLocal // regardless of its parameter type. class ThreadLocalBase { public: // Creates a new ValueHolder object holding a default value passed to // this ThreadLocal's constructor and returns it. It is the caller's // responsibility not to call this when the ThreadLocal instance already // has a value on the current thread. virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const = 0; protected: ThreadLocalBase() {} virtual ~ThreadLocalBase() {} private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocalBase); }; // Maps a thread to a set of ThreadLocals that have values instantiated on that // thread and notifies them when the thread exits. A ThreadLocal instance is // expected to persist until all threads it has values on have terminated. class GTEST_API_ ThreadLocalRegistry { public: // Registers thread_local_instance as having value on the current thread. // Returns a value that can be used to identify the thread from other threads. static ThreadLocalValueHolderBase* GetValueOnCurrentThread( const ThreadLocalBase* thread_local_instance); // Invoked when a ThreadLocal instance is destroyed. static void OnThreadLocalDestroyed( const ThreadLocalBase* thread_local_instance); }; class GTEST_API_ ThreadWithParamBase { public: void Join(); protected: class Runnable { public: virtual ~Runnable() {} virtual void Run() = 0; }; ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start); virtual ~ThreadWithParamBase(); private: AutoHandle thread_; }; // Helper class for testing Google Test's multi-threading constructs. template class ThreadWithParam : public ThreadWithParamBase { public: typedef void UserThreadFunc(T); ThreadWithParam(UserThreadFunc* func, T param, Notification* thread_can_start) : ThreadWithParamBase(new RunnableImpl(func, param), thread_can_start) { } virtual ~ThreadWithParam() {} private: class RunnableImpl : public Runnable { public: RunnableImpl(UserThreadFunc* func, T param) : func_(func), param_(param) { } virtual ~RunnableImpl() {} virtual void Run() { func_(param_); } private: UserThreadFunc* const func_; const T param_; GTEST_DISALLOW_COPY_AND_ASSIGN_(RunnableImpl); }; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParam); }; // Implements thread-local storage on Windows systems. // // // Thread 1 // ThreadLocal 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. // // The users of a TheadLocal instance have to make sure that all but one // threads (including the main one) using that instance have exited before // destroying it. Otherwise, the per-thread objects managed for them by the // ThreadLocal instance are not guaranteed to be destroyed on all platforms. // // 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 class ThreadLocal : public ThreadLocalBase { public: ThreadLocal() : default_factory_(new DefaultValueHolderFactory()) {} explicit ThreadLocal(const T& value) : default_factory_(new InstanceValueHolderFactory(value)) {} ~ThreadLocal() { ThreadLocalRegistry::OnThreadLocalDestroyed(this); } 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 T. Can be deleted via its base class without the caller // knowing the type of T. class ValueHolder : public ThreadLocalValueHolderBase { public: ValueHolder() : value_() {} explicit ValueHolder(const T& value) : value_(value) {} T* pointer() { return &value_; } private: T value_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolder); }; T* GetOrCreateValue() const { return static_cast( ThreadLocalRegistry::GetValueOnCurrentThread(this))->pointer(); } virtual ThreadLocalValueHolderBase* NewValueForCurrentThread() const { return default_factory_->MakeNewHolder(); } class ValueHolderFactory { public: ValueHolderFactory() {} virtual ~ValueHolderFactory() {} virtual ValueHolder* MakeNewHolder() const = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); }; class DefaultValueHolderFactory : public ValueHolderFactory { public: DefaultValueHolderFactory() {} virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); }; class InstanceValueHolderFactory : public ValueHolderFactory { public: explicit InstanceValueHolderFactory(const T& value) : value_(value) {} virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(value_); } private: const T value_; // The value for each thread. GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); }; scoped_ptr default_factory_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; # elif GTEST_HAS_PTHREAD // MutexBase and Mutex implement mutex on pthreads-based platforms. class MutexBase { public: // Acquires this mutex. void Lock() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_lock(&mutex_)); owner_ = pthread_self(); has_owner_ = true; } // Releases this mutex. void Unlock() { // Since the lock is being released the owner_ field should no longer be // considered valid. We don't protect writing to has_owner_ here, as it's // the caller's responsibility to ensure that the current thread holds the // mutex when this is called. has_owner_ = false; 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_(has_owner_ && pthread_equal(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. // has_owner_ indicates whether the owner_ field below contains a valid thread // ID and is therefore safe to inspect (e.g., to use in pthread_equal()). All // accesses to the owner_ field should be protected by a check of this field. // An alternative might be to memset() owner_ to all zeros, but there's no // guarantee that a zero'd pthread_t is necessarily invalid or even different // from pthread_self(). bool has_owner_; pthread_t owner_; // The thread holding the mutex. }; // 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, false, pthread_t() } // 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)); has_owner_ = false; } ~Mutex() { GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&mutex_)); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(Mutex); }; // We cannot name this class MutexLock because the ctor declaration would // conflict with a macro named MutexLock, which is defined on some // platforms. That macro is used as a defensive measure to prevent against // inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than // "MutexLock l(&mu)". 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. 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(value_holder); } // Implements thread-local storage on pthreads-based systems. template class ThreadLocal { public: ThreadLocal() : key_(CreateKey()), default_factory_(new DefaultValueHolderFactory()) {} explicit ThreadLocal(const T& value) : key_(CreateKey()), default_factory_(new InstanceValueHolderFactory(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: ValueHolder() : value_() {} 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(pthread_getspecific(key_)); if (holder != NULL) { return CheckedDowncastToActualType(holder)->pointer(); } ValueHolder* const new_holder = default_factory_->MakeNewHolder(); ThreadLocalValueHolderBase* const holder_base = new_holder; GTEST_CHECK_POSIX_SUCCESS_(pthread_setspecific(key_, holder_base)); return new_holder->pointer(); } class ValueHolderFactory { public: ValueHolderFactory() {} virtual ~ValueHolderFactory() {} virtual ValueHolder* MakeNewHolder() const = 0; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(ValueHolderFactory); }; class DefaultValueHolderFactory : public ValueHolderFactory { public: DefaultValueHolderFactory() {} virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(); } private: GTEST_DISALLOW_COPY_AND_ASSIGN_(DefaultValueHolderFactory); }; class InstanceValueHolderFactory : public ValueHolderFactory { public: explicit InstanceValueHolderFactory(const T& value) : value_(value) {} virtual ValueHolder* MakeNewHolder() const { return new ValueHolder(value_); } private: const T value_; // The value for each thread. GTEST_DISALLOW_COPY_AND_ASSIGN_(InstanceValueHolderFactory); }; // A key pthreads uses for looking up per-thread values. const pthread_key_t key_; scoped_ptr default_factory_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadLocal); }; # endif // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ #else // GTEST_IS_THREADSAFE // 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 Lock() {} void Unlock() {} void AssertHeld() const {} }; # define GTEST_DECLARE_STATIC_MUTEX_(mutex) \ extern ::testing::internal::Mutex mutex # define GTEST_DEFINE_STATIC_MUTEX_(mutex) ::testing::internal::Mutex mutex // We cannot name this class MutexLock because the ctor declaration would // conflict with a macro named MutexLock, which is defined on some // platforms. That macro is used as a defensive measure to prevent against // inadvertent misuses of MutexLock like "MutexLock(&mu)" rather than // "MutexLock l(&mu)". Hence the typedef trick below. class GTestMutexLock { public: explicit GTestMutexLock(Mutex*) {} // NOLINT }; typedef GTestMutexLock MutexLock; template 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_; }; #endif // GTEST_IS_THREADSAFE // 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 struct bool_constant { typedef bool_constant type; static const bool value = bool_value; }; template const bool bool_constant::value; typedef bool_constant false_type; typedef bool_constant true_type; template struct is_pointer : public false_type {}; template struct is_pointer : public true_type {}; template struct IteratorTraits { typedef typename Iterator::value_type value_type; }; template struct IteratorTraits { typedef T value_type; }; template struct IteratorTraits { typedef T value_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 // Utilities for char. // isspace(int ch) and friends accept an unsigned char or EOF. char // may be signed, depending on the compiler (or compiler flags). // Therefore we need to cast a char to unsigned char before calling // isspace(), etc. inline bool IsAlpha(char ch) { return isalpha(static_cast(ch)) != 0; } inline bool IsAlNum(char ch) { return isalnum(static_cast(ch)) != 0; } inline bool IsDigit(char ch) { return isdigit(static_cast(ch)) != 0; } inline bool IsLower(char ch) { return islower(static_cast(ch)) != 0; } inline bool IsSpace(char ch) { return isspace(static_cast(ch)) != 0; } inline bool IsUpper(char ch) { return isupper(static_cast(ch)) != 0; } inline bool IsXDigit(char ch) { return isxdigit(static_cast(ch)) != 0; } inline bool IsXDigit(wchar_t ch) { const unsigned char low_byte = static_cast(ch); return ch == low_byte && isxdigit(low_byte) != 0; } inline char ToLower(char ch) { return static_cast(tolower(static_cast(ch))); } inline char ToUpper(char ch) { return static_cast(toupper(static_cast(ch))); } inline std::string StripTrailingSpaces(std::string str) { std::string::iterator it = str.end(); while (it != str.begin() && IsSpace(*--it)) it = str.erase(it); return str; } // 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(_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. GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* deprecated function */) 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 && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT 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(read(fd, buf, count)); } inline int Write(int fd, const void* buf, unsigned int count) { return static_cast(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 || GTEST_OS_WINDOWS_PHONE | GTEST_OS_WINDOWS_RT // We are on Windows CE, which has no environment variables. static_cast(name); // To prevent 'unused argument' warning. 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 } GTEST_DISABLE_MSC_WARNINGS_POP_() #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 // MSVC "deprecates" snprintf and issues warnings wherever it is used. In // order to avoid these warnings, we need to use _snprintf or _snprintf_s on // MSVC-based platforms. We map the GTEST_SNPRINTF_ macro to the appropriate // function in order to achieve that. We use macro definition here because // snprintf is a variadic function. #if _MSC_VER >= 1400 && !GTEST_OS_WINDOWS_MOBILE // MSVC 2005 and above support variadic macros. # define GTEST_SNPRINTF_(buffer, size, format, ...) \ _snprintf_s(buffer, size, size, format, __VA_ARGS__) #elif defined(_MSC_VER) // Windows CE does not define _snprintf_s and MSVC prior to 2005 doesn't // complain about _snprintf. # define GTEST_SNPRINTF_ _snprintf #else # define GTEST_SNPRINTF_ snprintf #endif // 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(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 class TypeWithSize { public: // This prevents the user from using TypeWithSize 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. #if !defined(GTEST_FLAG) # define GTEST_FLAG(name) FLAGS_gtest_##name #endif // !defined(GTEST_FLAG) #if !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) # define GTEST_USE_OWN_FLAGFILE_FLAG_ 1 #endif // !defined(GTEST_USE_OWN_FLAGFILE_FLAG_) #if !defined(GTEST_DECLARE_bool_) # define GTEST_FLAG_SAVER_ ::testing::internal::GTestFlagSaver // 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 ::std::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_ ::std::string GTEST_FLAG(name) = (default_val) #endif // !defined(GTEST_DECLARE_bool_) // Thread annotations #if !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) # define GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) # define GTEST_LOCK_EXCLUDED_(locks) #endif // !defined(GTEST_EXCLUSIVE_LOCK_REQUIRED_) // 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); std::string StringFromGTestEnv(const char* flag, const char* default_val); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_H_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-linked_ptr.h0000644002537200234200000002035013213503245026057 0ustar zmoelnigiemusers// 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 #include #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(obj) vs linked_ptr(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. 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, linked_ptr, and // linked_ptr). 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. void join(linked_ptr_internal const* ptr) GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { MutexLock lock(&g_linked_ptr_mutex); linked_ptr_internal const* p = ptr; while (p->next_ != ptr) { assert(p->next_ != this && "Trying to join() a linked ring we are already in. " "Is GMock thread safety enabled?"); 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. bool depart() GTEST_LOCK_EXCLUDED_(g_linked_ptr_mutex) { MutexLock lock(&g_linked_ptr_mutex); if (next_ == this) return true; linked_ptr_internal const* p = next_; while (p->next_ != this) { assert(p->next_ != next_ && "Trying to depart() a linked ring we are not in. " "Is GMock thread safety enabled?"); p = p->next_; } p->next_ = next_; return false; } private: mutable linked_ptr_internal const* next_; }; template 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 linked_ptr(linked_ptr 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 linked_ptr& operator=(linked_ptr 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_; } bool operator==(T* p) const { return value_ == p; } bool operator!=(T* p) const { return value_ != p; } template bool operator==(linked_ptr const& ptr) const { return value_ == ptr.get(); } template bool operator!=(linked_ptr const& ptr) const { return value_ != ptr.get(); } private: template 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 void copy(linked_ptr const* ptr) { value_ = ptr->get(); if (value_) link_.join(&ptr->link_); else link_.join_new(); } }; template inline bool operator==(T* ptr, const linked_ptr& x) { return ptr == x.get(); } template inline bool operator!=(T* ptr, const linked_ptr& x) { return ptr != x.get(); } // A function to convert T* into linked_ptr // Doing e.g. make_linked_ptr(new FooBarBaz(arg)) is a shorter notation // for linked_ptr >(new FooBarBaz(arg)) template linked_ptr make_linked_ptr(T* ptr) { return linked_ptr(ptr); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_LINKED_PTR_H_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-internal.h0000644002537200234200000013426413213503245025552 0ustar zmoelnigiemusers// 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 # include # include # include #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #include #include #include #include #include #include #include #include #include #include "gtest/gtest-message.h" #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 class ProtocolMessage; namespace proto2 { class Message; } namespace testing { // Forward declarations. 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. template ::std::string PrintToString(const T& value); 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 // The text used in failure messages to indicate the start of the // stack trace. GTEST_API_ extern const char kStackTraceMarker[]; // 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_ std::string AppendUserMessage( const std::string& gtest_msg, const Message& user_msg); #if GTEST_HAS_EXCEPTIONS // This exception is thrown by (and only by) a failed Google Test // assertion when GTEST_FLAG(throw_on_failure) is true (if 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 GTEST_API_ GoogleTestFailureException : public ::std::runtime_error { public: explicit GoogleTestFailureException(const TestPartResult& failure); }; #endif // GTEST_HAS_EXCEPTIONS // 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. namespace edit_distance { // Returns the optimal edits to go from 'left' to 'right'. // All edits cost the same, with replace having lower priority than // add/remove. // Simple implementation of the Wagner–Fischer algorithm. // See http://en.wikipedia.org/wiki/Wagner-Fischer_algorithm enum EditType { kMatch, kAdd, kRemove, kReplace }; GTEST_API_ std::vector CalculateOptimalEdits( const std::vector& left, const std::vector& right); // Same as above, but the input is represented as strings. GTEST_API_ std::vector CalculateOptimalEdits( const std::vector& left, const std::vector& right); // Create a diff of the input strings in Unified diff format. GTEST_API_ std::string CreateUnifiedDiff(const std::vector& left, const std::vector& right, size_t context = 2); } // namespace edit_distance // Calculate the diff between 'left' and 'right' and return it in unified diff // format. // If not null, stores in 'total_line_count' the total number of lines found // in left + right. GTEST_API_ std::string DiffStrings(const std::string& left, const std::string& right, size_t* total_line_count); // 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 std::string& expected_value, const std::string& actual_value, bool ignoring_case); // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. GTEST_API_ std::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 class FloatingPoint { public: // Defines the unsigned integer type that has the same size as the // floating point number. typedef typename TypeWithSize::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::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(1) << (kBitCount - 1); // The mask for the fraction bits. static const Bits kFractionBitMask = ~static_cast(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://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/ 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); } // Returns the maximum representable finite floating-point number. static RawType Max(); // 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_; }; // We cannot use std::numeric_limits::max() as it clashes with the max() // macro defined by . template <> inline float FloatingPoint::Max() { return FLT_MAX; } template <> inline double FloatingPoint::Max() { return DBL_MAX; } // Typedefs the instances of the FloatingPoint template class that we // care to use. typedef FloatingPoint Float; typedef FloatingPoint 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 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::dummy_ for different Ts as an "optimization". static bool dummy_; }; template bool TypeIdHelper::dummy_ = false; // GetTypeId() 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 TypeId GetTypeId() { // The compiler is required to allocate a different // TypeIdHelper::dummy_ variable for each T used to instantiate // the template. Therefore, the address of dummy_ is guaranteed to // be unique. return &(TypeIdHelper::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 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 // Types of SetUpTestCase() and TearDownTestCase() functions. typedef void (*SetUpTestCaseFunc)(); typedef void (*TearDownTestCaseFunc)(); struct CodeLocation { CodeLocation(const string& a_file, int a_line) : file(a_file), line(a_line) {} string file; int line; }; // 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 // type_param the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param text representation of the test's value parameter, // or NULL if this is not a type-parameterized test. // code_location: code location where the test is defined // 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* type_param, const char* value_param, CodeLocation code_location, 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. GTEST_API_ 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(); } registered_tests_.insert( ::std::make_pair(test_name, CodeLocation(file, line))); return true; } bool TestExists(const std::string& test_name) const { return registered_tests_.count(test_name) > 0; } const CodeLocation& GetCodeLocation(const std::string& test_name) const { RegisteredTestsMap::const_iterator it = registered_tests_.find(test_name); GTEST_CHECK_(it != registered_tests_.end()); return it->second; } // 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: typedef ::std::map RegisteredTestsMap; bool registered_; RegisteredTestsMap registered_tests_; }; // 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 std::string GetPrefixUntilComma(const char* str) { const char* comma = strchr(str, ','); return comma == NULL ? str : std::string(str, comma); } // Splits a given string on a given delimiter, populating a given // vector with the fields. void SplitString(const ::std::string& str, char delimiter, ::std::vector< ::std::string>* dest); // TypeParameterizedTest::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 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, CodeLocation code_location, const char* case_name, const char* test_names, int index) { typedef typename Types::Head Type; typedef Fixture FixtureClass; typedef typename GTEST_BIND_(TestSel, Type) TestClass; // First, registers the first type-parameterized test in the type // list. MakeAndRegisterTestInfo( (std::string(prefix) + (prefix[0] == '\0' ? "" : "/") + case_name + "/" + StreamableToString(index)).c_str(), StripTrailingSpaces(GetPrefixUntilComma(test_names)).c_str(), GetTypeName().c_str(), NULL, // No value parameter. code_location, GetTypeId(), TestClass::SetUpTestCase, TestClass::TearDownTestCase, new TestFactoryImpl); // Next, recurses (at compile time) with the tail of the type list. return TypeParameterizedTest ::Register(prefix, code_location, case_name, test_names, index + 1); } }; // The base case for the compile time recursion. template class TypeParameterizedTest { public: static bool Register(const char* /*prefix*/, CodeLocation, const char* /*case_name*/, const char* /*test_names*/, int /*index*/) { return true; } }; // TypeParameterizedTestCase::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 class TypeParameterizedTestCase { public: static bool Register(const char* prefix, CodeLocation code_location, const TypedTestCasePState* state, const char* case_name, const char* test_names) { std::string test_name = StripTrailingSpaces( GetPrefixUntilComma(test_names)); if (!state->TestExists(test_name)) { fprintf(stderr, "Failed to get code location for test %s.%s at %s.", case_name, test_name.c_str(), FormatFileLocation(code_location.file.c_str(), code_location.line).c_str()); fflush(stderr); posix::Abort(); } const CodeLocation& test_location = state->GetCodeLocation(test_name); typedef typename Tests::Head Head; // First, register the first test in 'Test' for each type in 'Types'. TypeParameterizedTest::Register( prefix, test_location, case_name, test_names, 0); // Next, recurses (at compile time) with the tail of the test list. return TypeParameterizedTestCase ::Register(prefix, code_location, state, case_name, SkipComma(test_names)); } }; // The base case for the compile time recursion. template class TypeParameterizedTestCase { public: static bool Register(const char* /*prefix*/, CodeLocation, const TypedTestCasePState* /*state*/, 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 an std::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_ std::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(); } // Helper for suppressing false warning from Clang on a const char* // variable declared in a conditional expression always being NULL in // the else branch. struct GTEST_API_ ConstCharPtr { ConstCharPtr(const char* str) : value(str) {} operator bool() const { return true; } const char* value; }; // 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); }; // Defining a variable of type CompileAssertTypesEqual will cause a // compiler error iff T1 and T2 are different types. template struct CompileAssertTypesEqual; template struct CompileAssertTypesEqual { }; // Removes the reference from a type if it is a reference type, // otherwise leaves it unchanged. This is the same as // tr1::remove_reference, which is not widely available yet. template struct RemoveReference { typedef T type; }; // NOLINT template struct RemoveReference { typedef T type; }; // NOLINT // A handy wrapper around RemoveReference that works when the argument // T depends on template parameters. #define GTEST_REMOVE_REFERENCE_(T) \ typename ::testing::internal::RemoveReference::type // Removes const from a type if it is a const type, otherwise leaves // it unchanged. This is the same as tr1::remove_const, which is not // widely available yet. template struct RemoveConst { typedef T type; }; // NOLINT template struct RemoveConst { typedef T type; }; // NOLINT // MSVC 8.0, Sun C++, and IBM XL C++ have a bug which causes the above // definition to fail to remove the const in 'const int[3]' and 'const // char[3][4]'. The following specialization works around the bug. template struct RemoveConst { typedef typename RemoveConst::type type[N]; }; #if defined(_MSC_VER) && _MSC_VER < 1400 // This is the only specialization that allows VC++ 7.1 to remove const in // 'const int[3] and 'const int[3][4]'. However, it causes trouble with GCC // and thus needs to be conditionally compiled. template struct RemoveConst { typedef typename RemoveConst::type type[N]; }; #endif // A handy wrapper around RemoveConst that works when the argument // T depends on template parameters. #define GTEST_REMOVE_CONST_(T) \ typename ::testing::internal::RemoveConst::type // Turns const U&, U&, const U, and U all into U. #define GTEST_REMOVE_REFERENCE_AND_CONST_(T) \ GTEST_REMOVE_CONST_(GTEST_REMOVE_REFERENCE_(T)) // Adds reference to a type if it is not a reference type, // otherwise leaves it unchanged. This is the same as // tr1::add_reference, which is not widely available yet. template struct AddReference { typedef T& type; }; // NOLINT template struct AddReference { typedef T& type; }; // NOLINT // A handy wrapper around AddReference that works when the argument T // depends on template parameters. #define GTEST_ADD_REFERENCE_(T) \ typename ::testing::internal::AddReference::type // Adds a reference to const on top of T as necessary. For example, // it transforms // // char ==> const char& // const char ==> const char& // char& ==> const char& // const char& ==> const char& // // The argument T must depend on some template parameters. #define GTEST_REFERENCE_TO_CONST_(T) \ GTEST_ADD_REFERENCE_(const GTEST_REMOVE_REFERENCE_(T)) // ImplicitlyConvertible::value is a compile-time bool // constant that's true iff type From can be implicitly converted to // type To. template class ImplicitlyConvertible { private: // We need the following helper functions only for their types. // They have no implementations. // MakeFrom() is an expression whose type is From. We cannot simply // use From(), as the type From may not have a public default // constructor. static typename AddReference::type MakeFrom(); // These two functions are overloaded. Given an expression // Helper(x), the compiler will pick the first version if x can be // implicitly converted to type To; otherwise it will pick the // second version. // // The first version returns a value of size 1, and the second // version returns a value of size 2. Therefore, by checking the // size of Helper(x), which can be done at compile time, we can tell // which version of Helper() is used, and hence whether x can be // implicitly converted to type To. static char Helper(To); static char (&Helper(...))[2]; // NOLINT // We have to put the 'public' section after the 'private' section, // or MSVC refuses to compile the code. public: #if defined(__BORLANDC__) // C++Builder cannot use member overload resolution during template // instantiation. The simplest workaround is to use its C++0x type traits // functions (C++Builder 2009 and above only). static const bool value = __is_convertible(From, To); #else // MSVC warns about implicitly converting from double to int for // possible loss of data, so we need to temporarily disable the // warning. GTEST_DISABLE_MSC_WARNINGS_PUSH_(4244) static const bool value = sizeof(Helper(ImplicitlyConvertible::MakeFrom())) == 1; GTEST_DISABLE_MSC_WARNINGS_POP_() #endif // __BORLANDC__ }; template const bool ImplicitlyConvertible::value; // IsAProtocolMessage::value is a compile-time bool constant that's // true iff T is type ProtocolMessage, proto2::Message, or a subclass // of those. template struct IsAProtocolMessage : public bool_constant< ImplicitlyConvertible::value || ImplicitlyConvertible::value> { }; // When the compiler sees expression IsContainerTest(0), if C is an // STL-style container class, the first overload of IsContainerTest // will be viable (since both C::iterator* and C::const_iterator* are // valid types and NULL can be implicitly converted to them). It will // be picked over the second overload as 'int' is a perfect match for // the type of argument 0. If C::iterator or C::const_iterator is not // a valid type, the first overload is not viable, and the second // overload will be picked. Therefore, we can determine whether C is // a container class by checking the type of IsContainerTest(0). // The value of the expression is insignificant. // // Note that we look for both C::iterator and C::const_iterator. The // reason is that C++ injects the name of a class as a member of the // class itself (e.g. you can refer to class iterator as either // 'iterator' or 'iterator::iterator'). If we look for C::iterator // only, for example, we would mistakenly think that a class named // iterator is an STL container. // // Also note that the simpler approach of overloading // IsContainerTest(typename C::const_iterator*) and // IsContainerTest(...) doesn't work with Visual Age C++ and Sun C++. typedef int IsContainer; template IsContainer IsContainerTest(int /* dummy */, typename C::iterator* /* it */ = NULL, typename C::const_iterator* /* const_it */ = NULL) { return 0; } typedef char IsNotContainer; template IsNotContainer IsContainerTest(long /* dummy */) { return '\0'; } // EnableIf::type is void when 'Cond' is true, and // undefined when 'Cond' is false. To use SFINAE to make a function // overload only apply when a particular expression is true, add // "typename EnableIf::type* = 0" as the last parameter. template struct EnableIf; template<> struct EnableIf { typedef void type; }; // NOLINT // Utilities for native arrays. // ArrayEq() compares two k-dimensional native arrays using the // elements' operator==, where k can be any integer >= 0. When k is // 0, ArrayEq() degenerates into comparing a single pair of values. template bool ArrayEq(const T* lhs, size_t size, const U* rhs); // This generic version is used when k is 0. template inline bool ArrayEq(const T& lhs, const U& rhs) { return lhs == rhs; } // This overload is used when k >= 1. template inline bool ArrayEq(const T(&lhs)[N], const U(&rhs)[N]) { return internal::ArrayEq(lhs, N, rhs); } // This helper reduces code bloat. If we instead put its logic inside // the previous ArrayEq() function, arrays with different sizes would // lead to different copies of the template code. template bool ArrayEq(const T* lhs, size_t size, const U* rhs) { for (size_t i = 0; i != size; i++) { if (!internal::ArrayEq(lhs[i], rhs[i])) return false; } return true; } // Finds the first element in the iterator range [begin, end) that // equals elem. Element may be a native array type itself. template Iter ArrayAwareFind(Iter begin, Iter end, const Element& elem) { for (Iter it = begin; it != end; ++it) { if (internal::ArrayEq(*it, elem)) return it; } return end; } // CopyArray() copies a k-dimensional native array using the elements' // operator=, where k can be any integer >= 0. When k is 0, // CopyArray() degenerates into copying a single value. template void CopyArray(const T* from, size_t size, U* to); // This generic version is used when k is 0. template inline void CopyArray(const T& from, U* to) { *to = from; } // This overload is used when k >= 1. template inline void CopyArray(const T(&from)[N], U(*to)[N]) { internal::CopyArray(from, N, *to); } // This helper reduces code bloat. If we instead put its logic inside // the previous CopyArray() function, arrays with different sizes // would lead to different copies of the template code. template void CopyArray(const T* from, size_t size, U* to) { for (size_t i = 0; i != size; i++) { internal::CopyArray(from[i], to + i); } } // The relation between an NativeArray object (see below) and the // native array it represents. // We use 2 different structs to allow non-copyable types to be used, as long // as RelationToSourceReference() is passed. struct RelationToSourceReference {}; struct RelationToSourceCopy {}; // Adapts a native array to a read-only STL-style container. Instead // of the complete STL container concept, this adaptor only implements // members useful for Google Mock's container matchers. New members // should be added as needed. To simplify the implementation, we only // support Element being a raw type (i.e. having no top-level const or // reference modifier). It's the client's responsibility to satisfy // this requirement. Element can be an array type itself (hence // multi-dimensional arrays are supported). template class NativeArray { public: // STL-style container typedefs. typedef Element value_type; typedef Element* iterator; typedef const Element* const_iterator; // Constructs from a native array. References the source. NativeArray(const Element* array, size_t count, RelationToSourceReference) { InitRef(array, count); } // Constructs from a native array. Copies the source. NativeArray(const Element* array, size_t count, RelationToSourceCopy) { InitCopy(array, count); } // Copy constructor. NativeArray(const NativeArray& rhs) { (this->*rhs.clone_)(rhs.array_, rhs.size_); } ~NativeArray() { if (clone_ != &NativeArray::InitRef) delete[] array_; } // STL-style container methods. size_t size() const { return size_; } const_iterator begin() const { return array_; } const_iterator end() const { return array_ + size_; } bool operator==(const NativeArray& rhs) const { return size() == rhs.size() && ArrayEq(begin(), size(), rhs.begin()); } private: enum { kCheckTypeIsNotConstOrAReference = StaticAssertTypeEqHelper< Element, GTEST_REMOVE_REFERENCE_AND_CONST_(Element)>::value, }; // Initializes this object with a copy of the input. void InitCopy(const Element* array, size_t a_size) { Element* const copy = new Element[a_size]; CopyArray(array, a_size, copy); array_ = copy; size_ = a_size; clone_ = &NativeArray::InitCopy; } // Initializes this object with a reference of the input. void InitRef(const Element* array, size_t a_size) { array_ = array; size_ = a_size; clone_ = &NativeArray::InitRef; } const Element* array_; size_t size_; void (NativeArray::*clone_)(const Element*, size_t); GTEST_DISALLOW_ASSIGN_(NativeArray); }; } // namespace internal } // namespace testing #define GTEST_MESSAGE_AT_(file, line, message, result_type) \ ::testing::internal::AssertHelper(result_type, file, line, message) \ = ::testing::Message() #define GTEST_MESSAGE_(message, result_type) \ GTEST_MESSAGE_AT_(__FILE__, __LINE__, message, result_type) #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 (::testing::internal::ConstCharPtr 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.value = \ "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.value = \ "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.value) #define GTEST_TEST_NO_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnothrow_, __LINE__): \ fail("Expected: " #statement " doesn't throw an exception.\n" \ " Actual: it throws.") #define GTEST_TEST_ANY_THROW_(statement, fail) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ bool gtest_caught_any = false; \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } \ catch (...) { \ gtest_caught_any = true; \ } \ if (!gtest_caught_any) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testanythrow_, __LINE__): \ fail("Expected: " #statement " throws an exception.\n" \ " Actual: it doesn't.") // 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 (::testing::internal::AlwaysTrue()) { \ ::testing::internal::HasNewFatalFailureHelper gtest_fatal_failure_checker; \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ if (gtest_fatal_failure_checker.has_new_fatal_failure()) { \ goto GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__); \ } \ } else \ GTEST_CONCAT_TOKEN_(gtest_label_testnofatal_, __LINE__): \ fail("Expected: " #statement " doesn't generate new fatal " \ "failures in the current thread.\n" \ " Actual: it does.") // 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_ATTRIBUTE_UNUSED_;\ 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, NULL, NULL, \ ::testing::internal::CodeLocation(__FILE__, __LINE__), \ (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_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-tuple.h0000644002537200234200000006771113213503245025071 0ustar zmoelnigiemusers// This file was GENERATED by command: // pump.py gtest-tuple.h.pump // 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 // 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 friend class tuple; \ private: #endif // Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that conflict // with our own definitions. Therefore using our own tuple does not work on // those compilers. #if defined(_MSC_VER) && _MSC_VER >= 1600 /* 1600 is Visual Studio 2010 */ # error "gtest's tuple doesn't compile on Visual Studio 2010 or later. \ GTEST_USE_OWN_TR1_TUPLE must be set to 0 on those compilers." #endif // GTEST_n_TUPLE_(T) is the type of an n-tuple. #define GTEST_0_TUPLE_(T) tuple<> #define GTEST_1_TUPLE_(T) tuple #define GTEST_2_TUPLE_(T) tuple #define GTEST_3_TUPLE_(T) tuple #define GTEST_4_TUPLE_(T) tuple #define GTEST_5_TUPLE_(T) tuple #define GTEST_6_TUPLE_(T) tuple #define GTEST_7_TUPLE_(T) tuple #define GTEST_8_TUPLE_(T) tuple #define GTEST_9_TUPLE_(T) tuple #define GTEST_10_TUPLE_(T) tuple // 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 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::type is T if T is a reference; otherwise it's const T&. template struct ByRef { typedef const T& type; }; // NOLINT template struct ByRef { typedef T& type; }; // NOLINT // A handy wrapper for ByRef. #define GTEST_BY_REF_(T) typename ::std::tr1::gtest_internal::ByRef::type // AddRef::type is T if T is a reference; otherwise it's T&. This // is the same as tr1::add_reference::type. template struct AddRef { typedef T& type; }; // NOLINT template struct AddRef { typedef T& type; }; // NOLINT // A handy wrapper for AddRef. #define GTEST_ADD_REF_(T) typename ::std::tr1::gtest_internal::AddRef::type // A helper for implementing get(). template class Get; // A helper for implementing tuple_element. kIndexValid is true // iff k < the number of fields in tuple type T. template struct TupleElement; template struct TupleElement { typedef T0 type; }; template struct TupleElement { typedef T1 type; }; template struct TupleElement { typedef T2 type; }; template struct TupleElement { typedef T3 type; }; template struct TupleElement { typedef T4 type; }; template struct TupleElement { typedef T5 type; }; template struct TupleElement { typedef T6 type; }; template struct TupleElement { typedef T7 type; }; template struct TupleElement { typedef T8 type; }; template struct TupleElement { typedef T9 type; }; } // namespace gtest_internal template <> class tuple<> { public: tuple() {} tuple(const tuple& /* t */) {} tuple& operator=(const tuple& /* t */) { return *this; } }; template class GTEST_1_TUPLE_(T) { public: template friend class gtest_internal::Get; tuple() : f0_() {} explicit tuple(GTEST_BY_REF_(T0) f0) : f0_(f0) {} tuple(const tuple& t) : f0_(t.f0_) {} template tuple(const GTEST_1_TUPLE_(U)& t) : f0_(t.f0_) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_1_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_1_TUPLE_(U)& t) { f0_ = t.f0_; return *this; } T0 f0_; }; template class GTEST_2_TUPLE_(T) { public: template 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 tuple(const GTEST_2_TUPLE_(U)& t) : f0_(t.f0_), f1_(t.f1_) {} template tuple(const ::std::pair& p) : f0_(p.first), f1_(p.second) {} tuple& operator=(const tuple& t) { return CopyFrom(t); } template tuple& operator=(const GTEST_2_TUPLE_(U)& t) { return CopyFrom(t); } template tuple& operator=(const ::std::pair& p) { f0_ = p.first; f1_ = p.second; return *this; } GTEST_DECLARE_TUPLE_AS_FRIEND_ template tuple& CopyFrom(const GTEST_2_TUPLE_(U)& t) { f0_ = t.f0_; f1_ = t.f1_; return *this; } T0 f0_; T1 f1_; }; template class GTEST_3_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_3_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class GTEST_4_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_4_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class GTEST_5_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_5_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class GTEST_6_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_6_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class GTEST_7_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_7_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class GTEST_8_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_8_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class GTEST_9_TUPLE_(T) { public: template 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 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 tuple& operator=(const GTEST_9_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 class tuple { public: template 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 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 tuple& operator=(const GTEST_10_TUPLE_(U)& t) { return CopyFrom(t); } GTEST_DECLARE_TUPLE_AS_FRIEND_ template 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 to make_tuple(). And we don't // implement tie(). inline tuple<> make_tuple() { return tuple<>(); } template inline GTEST_1_TUPLE_(T) make_tuple(const T0& f0) { return GTEST_1_TUPLE_(T)(f0); } template inline GTEST_2_TUPLE_(T) make_tuple(const T0& f0, const T1& f1) { return GTEST_2_TUPLE_(T)(f0, f1); } template 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 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 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 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 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 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 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 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 struct tuple_size; template struct tuple_size { static const int value = 0; }; template struct tuple_size { static const int value = 1; }; template struct tuple_size { static const int value = 2; }; template struct tuple_size { static const int value = 3; }; template struct tuple_size { static const int value = 4; }; template struct tuple_size { static const int value = 5; }; template struct tuple_size { static const int value = 6; }; template struct tuple_size { static const int value = 7; }; template struct tuple_size { static const int value = 8; }; template struct tuple_size { static const int value = 9; }; template struct tuple_size { static const int value = 10; }; template struct tuple_element { typedef typename gtest_internal::TupleElement< k < (tuple_size::value), k, Tuple>::type type; }; #define GTEST_TUPLE_ELEMENT_(k, Tuple) typename tuple_element::type // 6.1.3.4 Element access. namespace gtest_internal { template <> class Get<0> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) Field(Tuple& t) { return t.f0_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(0, Tuple)) ConstField(const Tuple& t) { return t.f0_; } }; template <> class Get<1> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) Field(Tuple& t) { return t.f1_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(1, Tuple)) ConstField(const Tuple& t) { return t.f1_; } }; template <> class Get<2> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) Field(Tuple& t) { return t.f2_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(2, Tuple)) ConstField(const Tuple& t) { return t.f2_; } }; template <> class Get<3> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) Field(Tuple& t) { return t.f3_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(3, Tuple)) ConstField(const Tuple& t) { return t.f3_; } }; template <> class Get<4> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) Field(Tuple& t) { return t.f4_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(4, Tuple)) ConstField(const Tuple& t) { return t.f4_; } }; template <> class Get<5> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) Field(Tuple& t) { return t.f5_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(5, Tuple)) ConstField(const Tuple& t) { return t.f5_; } }; template <> class Get<6> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) Field(Tuple& t) { return t.f6_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(6, Tuple)) ConstField(const Tuple& t) { return t.f6_; } }; template <> class Get<7> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) Field(Tuple& t) { return t.f7_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(7, Tuple)) ConstField(const Tuple& t) { return t.f7_; } }; template <> class Get<8> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) Field(Tuple& t) { return t.f8_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(8, Tuple)) ConstField(const Tuple& t) { return t.f8_; } }; template <> class Get<9> { public: template static GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) Field(Tuple& t) { return t.f9_; } // NOLINT template static GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(9, Tuple)) ConstField(const Tuple& t) { return t.f9_; } }; } // namespace gtest_internal template GTEST_ADD_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::Field(t); } template GTEST_BY_REF_(GTEST_TUPLE_ELEMENT_(k, GTEST_10_TUPLE_(T))) get(const GTEST_10_TUPLE_(T)& t) { return gtest_internal::Get::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::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 struct SameSizeTuplePrefixComparator; template <> struct SameSizeTuplePrefixComparator<0, 0> { template static bool Eq(const Tuple1& /* t1 */, const Tuple2& /* t2 */) { return true; } }; template struct SameSizeTuplePrefixComparator { template static bool Eq(const Tuple1& t1, const Tuple2& t2) { return SameSizeTuplePrefixComparator::Eq(t1, t2) && ::std::tr1::get(t1) == ::std::tr1::get(t2); } }; } // namespace gtest_internal template inline bool operator==(const GTEST_10_TUPLE_(T)& t, const GTEST_10_TUPLE_(U)& u) { return gtest_internal::SameSizeTuplePrefixComparator< tuple_size::value, tuple_size::value>::Eq(t, u); } template 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_ assimp-4.1.0/contrib/gtest/include/gtest/internal/custom/0000755002537200234200000000000013213503245023741 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/include/gtest/internal/custom/gtest-port.h0000644002537200234200000000610713213503245026226 0ustar zmoelnigiemusers// Copyright 2015, 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. // // Injection point for custom user configurations. // The following macros can be defined: // // Flag related macros: // GTEST_FLAG(flag_name) // GTEST_USE_OWN_FLAGFILE_FLAG_ - Define to 0 when the system provides its // own flagfile flag parsing. // GTEST_DECLARE_bool_(name) // GTEST_DECLARE_int32_(name) // GTEST_DECLARE_string_(name) // GTEST_DEFINE_bool_(name, default_val, doc) // GTEST_DEFINE_int32_(name, default_val, doc) // GTEST_DEFINE_string_(name, default_val, doc) // // Test filtering: // GTEST_TEST_FILTER_ENV_VAR_ - The name of an environment variable that // will be used if --GTEST_FLAG(test_filter) // is not provided. // // Logging: // GTEST_LOG_(severity) // GTEST_CHECK_(condition) // Functions LogToStderr() and FlushInfoLog() have to be provided too. // // Threading: // GTEST_HAS_NOTIFICATION_ - Enabled if Notification is already provided. // GTEST_HAS_MUTEX_AND_THREAD_LOCAL_ - Enabled if Mutex and ThreadLocal are // already provided. // Must also provide GTEST_DECLARE_STATIC_MUTEX_(mutex) and // GTEST_DEFINE_STATIC_MUTEX_(mutex) // // GTEST_EXCLUSIVE_LOCK_REQUIRED_(locks) // GTEST_LOCK_EXCLUDED_(locks) // // ** Custom implementation starts here ** #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PORT_H_ assimp-4.1.0/contrib/gtest/include/gtest/internal/custom/gtest-printers.h0000644002537200234200000000406313213503245027107 0ustar zmoelnigiemusers// Copyright 2015, 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 provides an injection point for custom printers in a local // installation of gTest. // It will be included from gtest-printers.h and the overrides in this file // will be visible to everyone. // See documentation at gtest/gtest-printers.h for details on how to define a // custom printer. // // ** Custom implementation starts here ** #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_PRINTERS_H_ assimp-4.1.0/contrib/gtest/include/gtest/internal/custom/gtest.h0000644002537200234200000000371313213503245025244 0ustar zmoelnigiemusers// Copyright 2015, 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. // // Injection point for custom user configurations. // The following macros can be defined: // // GTEST_OS_STACK_TRACE_GETTER_ - The name of an implementation of // OsStackTraceGetterInterface. // // ** Custom implementation starts here ** #ifndef GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ #endif // GTEST_INCLUDE_GTEST_INTERNAL_CUSTOM_GTEST_H_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-type-util.h0000644002537200234200000055250213213503245025671 0ustar zmoelnigiemusers// 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" // #ifdef __GNUC__ is too general here. It is possible to use gcc without using // libstdc++ (which is where cxxabi.h comes from). # if GTEST_HAS_CXXABI_H_ # include # elif defined(__HP_aCC) # include # endif // GTEST_HASH_CXXABI_H_ namespace testing { namespace internal { // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. template std::string GetTypeName() { # if GTEST_HAS_RTTI const char* const name = typeid(T).name(); # if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ char* const readable_name = __cxa_demangle(name, 0, 0, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); return name_str; # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC # else return ""; # endif // GTEST_HAS_RTTI } #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // AssertyTypeEq::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 struct AssertTypeEq; template struct AssertTypeEq { typedef bool type; }; // 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, Type, 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 // 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 struct Types1 { typedef T1 Head; typedef Types0 Tail; }; template struct Types2 { typedef T1 Head; typedef Types1 Tail; }; template struct Types3 { typedef T1 Head; typedef Types2 Tail; }; template struct Types4 { typedef T1 Head; typedef Types3 Tail; }; template struct Types5 { typedef T1 Head; typedef Types4 Tail; }; template struct Types6 { typedef T1 Head; typedef Types5 Tail; }; template struct Types7 { typedef T1 Head; typedef Types6 Tail; }; template struct Types8 { typedef T1 Head; typedef Types7 Tail; }; template struct Types9 { typedef T1 Head; typedef Types8 Tail; }; template struct Types10 { typedef T1 Head; typedef Types9 Tail; }; template struct Types11 { typedef T1 Head; typedef Types10 Tail; }; template struct Types12 { typedef T1 Head; typedef Types11 Tail; }; template struct Types13 { typedef T1 Head; typedef Types12 Tail; }; template struct Types14 { typedef T1 Head; typedef Types13 Tail; }; template struct Types15 { typedef T1 Head; typedef Types14 Tail; }; template struct Types16 { typedef T1 Head; typedef Types15 Tail; }; template struct Types17 { typedef T1 Head; typedef Types16 Tail; }; template struct Types18 { typedef T1 Head; typedef Types17 Tail; }; template struct Types19 { typedef T1 Head; typedef Types18 Tail; }; template struct Types20 { typedef T1 Head; typedef Types19 Tail; }; template struct Types21 { typedef T1 Head; typedef Types20 Tail; }; template struct Types22 { typedef T1 Head; typedef Types21 Tail; }; template struct Types23 { typedef T1 Head; typedef Types22 Tail; }; template struct Types24 { typedef T1 Head; typedef Types23 Tail; }; template struct Types25 { typedef T1 Head; typedef Types24 Tail; }; template struct Types26 { typedef T1 Head; typedef Types25 Tail; }; template struct Types27 { typedef T1 Head; typedef Types26 Tail; }; template struct Types28 { typedef T1 Head; typedef Types27 Tail; }; template struct Types29 { typedef T1 Head; typedef Types28 Tail; }; template struct Types30 { typedef T1 Head; typedef Types29 Tail; }; template struct Types31 { typedef T1 Head; typedef Types30 Tail; }; template struct Types32 { typedef T1 Head; typedef Types31 Tail; }; template struct Types33 { typedef T1 Head; typedef Types32 Tail; }; template struct Types34 { typedef T1 Head; typedef Types33 Tail; }; template struct Types35 { typedef T1 Head; typedef Types34 Tail; }; template struct Types36 { typedef T1 Head; typedef Types35 Tail; }; template struct Types37 { typedef T1 Head; typedef Types36 Tail; }; template struct Types38 { typedef T1 Head; typedef Types37 Tail; }; template struct Types39 { typedef T1 Head; typedef Types38 Tail; }; template struct Types40 { typedef T1 Head; typedef Types39 Tail; }; template struct Types41 { typedef T1 Head; typedef Types40 Tail; }; template struct Types42 { typedef T1 Head; typedef Types41 Tail; }; template struct Types43 { typedef T1 Head; typedef Types42 Tail; }; template struct Types44 { typedef T1 Head; typedef Types43 Tail; }; template struct Types45 { typedef T1 Head; typedef Types44 Tail; }; template struct Types46 { typedef T1 Head; typedef Types45 Tail; }; template struct Types47 { typedef T1 Head; typedef Types46 Tail; }; template struct Types48 { typedef T1 Head; typedef Types47 Tail; }; template struct Types49 { typedef T1 Head; typedef Types48 Tail; }; template struct Types50 { typedef T1 Head; typedef Types49 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 // will appear as Types in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Types, and Google Test will translate // that to TypesN internally to make error messages // readable. The translation is done by the 'type' member of the // Types template. template struct Types { typedef internal::Types50 type; }; template <> struct Types { typedef internal::Types0 type; }; template struct Types { typedef internal::Types1 type; }; template struct Types { typedef internal::Types2 type; }; template struct Types { typedef internal::Types3 type; }; template struct Types { typedef internal::Types4 type; }; template struct Types { typedef internal::Types5 type; }; template struct Types { typedef internal::Types6 type; }; template struct Types { typedef internal::Types7 type; }; template struct Types { typedef internal::Types8 type; }; template struct Types { typedef internal::Types9 type; }; template struct Types { typedef internal::Types10 type; }; template struct Types { typedef internal::Types11 type; }; template struct Types { typedef internal::Types12 type; }; template struct Types { typedef internal::Types13 type; }; template struct Types { typedef internal::Types14 type; }; template struct Types { typedef internal::Types15 type; }; template struct Types { typedef internal::Types16 type; }; template struct Types { typedef internal::Types17 type; }; template struct Types { typedef internal::Types18 type; }; template struct Types { typedef internal::Types19 type; }; template struct Types { typedef internal::Types20 type; }; template struct Types { typedef internal::Types21 type; }; template struct Types { typedef internal::Types22 type; }; template struct Types { typedef internal::Types23 type; }; template struct Types { typedef internal::Types24 type; }; template struct Types { typedef internal::Types25 type; }; template struct Types { typedef internal::Types26 type; }; template struct Types { typedef internal::Types27 type; }; template struct Types { typedef internal::Types28 type; }; template struct Types { typedef internal::Types29 type; }; template struct Types { typedef internal::Types30 type; }; template struct Types { typedef internal::Types31 type; }; template struct Types { typedef internal::Types32 type; }; template struct Types { typedef internal::Types33 type; }; template struct Types { typedef internal::Types34 type; }; template struct Types { typedef internal::Types35 type; }; template struct Types { typedef internal::Types36 type; }; template struct Types { typedef internal::Types37 type; }; template struct Types { typedef internal::Types38 type; }; template struct Types { typedef internal::Types39 type; }; template struct Types { typedef internal::Types40 type; }; template struct Types { typedef internal::Types41 type; }; template struct Types { typedef internal::Types42 type; }; template struct Types { typedef internal::Types43 type; }; template struct Types { typedef internal::Types44 type; }; template struct Types { typedef internal::Types45 type; }; template struct Types { typedef internal::Types46 type; }; template struct Types { typedef internal::Types47 type; }; template struct Types { typedef internal::Types48 type; }; template struct Types { typedef internal::Types49 type; }; namespace internal { # define GTEST_TEMPLATE_ template class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; # define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::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, Templates, // and etc), which C++ doesn't support directly. template struct NoneT {}; // The following family of struct and struct templates are used to // represent template lists. In particular, TemplatesN 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 struct Templates1 { typedef TemplateSel Head; typedef Templates0 Tail; }; template struct Templates2 { typedef TemplateSel Head; typedef Templates1 Tail; }; template struct Templates3 { typedef TemplateSel Head; typedef Templates2 Tail; }; template struct Templates4 { typedef TemplateSel Head; typedef Templates3 Tail; }; template struct Templates5 { typedef TemplateSel Head; typedef Templates4 Tail; }; template struct Templates6 { typedef TemplateSel Head; typedef Templates5 Tail; }; template struct Templates7 { typedef TemplateSel Head; typedef Templates6 Tail; }; template struct Templates8 { typedef TemplateSel Head; typedef Templates7 Tail; }; template struct Templates9 { typedef TemplateSel Head; typedef Templates8 Tail; }; template struct Templates10 { typedef TemplateSel Head; typedef Templates9 Tail; }; template struct Templates11 { typedef TemplateSel Head; typedef Templates10 Tail; }; template struct Templates12 { typedef TemplateSel Head; typedef Templates11 Tail; }; template struct Templates13 { typedef TemplateSel Head; typedef Templates12 Tail; }; template struct Templates14 { typedef TemplateSel Head; typedef Templates13 Tail; }; template struct Templates15 { typedef TemplateSel Head; typedef Templates14 Tail; }; template struct Templates16 { typedef TemplateSel Head; typedef Templates15 Tail; }; template struct Templates17 { typedef TemplateSel Head; typedef Templates16 Tail; }; template struct Templates18 { typedef TemplateSel Head; typedef Templates17 Tail; }; template struct Templates19 { typedef TemplateSel Head; typedef Templates18 Tail; }; template struct Templates20 { typedef TemplateSel Head; typedef Templates19 Tail; }; template struct Templates21 { typedef TemplateSel Head; typedef Templates20 Tail; }; template struct Templates22 { typedef TemplateSel Head; typedef Templates21 Tail; }; template struct Templates23 { typedef TemplateSel Head; typedef Templates22 Tail; }; template struct Templates24 { typedef TemplateSel Head; typedef Templates23 Tail; }; template struct Templates25 { typedef TemplateSel Head; typedef Templates24 Tail; }; template struct Templates26 { typedef TemplateSel Head; typedef Templates25 Tail; }; template struct Templates27 { typedef TemplateSel Head; typedef Templates26 Tail; }; template struct Templates28 { typedef TemplateSel Head; typedef Templates27 Tail; }; template struct Templates29 { typedef TemplateSel Head; typedef Templates28 Tail; }; template struct Templates30 { typedef TemplateSel Head; typedef Templates29 Tail; }; template struct Templates31 { typedef TemplateSel Head; typedef Templates30 Tail; }; template struct Templates32 { typedef TemplateSel Head; typedef Templates31 Tail; }; template struct Templates33 { typedef TemplateSel Head; typedef Templates32 Tail; }; template struct Templates34 { typedef TemplateSel Head; typedef Templates33 Tail; }; template struct Templates35 { typedef TemplateSel Head; typedef Templates34 Tail; }; template struct Templates36 { typedef TemplateSel Head; typedef Templates35 Tail; }; template struct Templates37 { typedef TemplateSel Head; typedef Templates36 Tail; }; template struct Templates38 { typedef TemplateSel Head; typedef Templates37 Tail; }; template struct Templates39 { typedef TemplateSel Head; typedef Templates38 Tail; }; template struct Templates40 { typedef TemplateSel Head; typedef Templates39 Tail; }; template struct Templates41 { typedef TemplateSel Head; typedef Templates40 Tail; }; template struct Templates42 { typedef TemplateSel Head; typedef Templates41 Tail; }; template struct Templates43 { typedef TemplateSel Head; typedef Templates42 Tail; }; template struct Templates44 { typedef TemplateSel Head; typedef Templates43 Tail; }; template struct Templates45 { typedef TemplateSel Head; typedef Templates44 Tail; }; template struct Templates46 { typedef TemplateSel Head; typedef Templates45 Tail; }; template struct Templates47 { typedef TemplateSel Head; typedef Templates46 Tail; }; template struct Templates48 { typedef TemplateSel Head; typedef Templates47 Tail; }; template struct Templates49 { typedef TemplateSel Head; typedef Templates48 Tail; }; template struct Templates50 { typedef TemplateSel Head; typedef Templates49 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 // will appear as Templates in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Templates, and Google Test will translate // that to TemplatesN internally to make error messages // readable. The translation is done by the 'type' member of the // Templates template. template struct Templates { typedef Templates50 type; }; template <> struct Templates { typedef Templates0 type; }; template struct Templates { typedef Templates1 type; }; template struct Templates { typedef Templates2 type; }; template struct Templates { typedef Templates3 type; }; template struct Templates { typedef Templates4 type; }; template struct Templates { typedef Templates5 type; }; template struct Templates { typedef Templates6 type; }; template struct Templates { typedef Templates7 type; }; template struct Templates { typedef Templates8 type; }; template struct Templates { typedef Templates9 type; }; template struct Templates { typedef Templates10 type; }; template struct Templates { typedef Templates11 type; }; template struct Templates { typedef Templates12 type; }; template struct Templates { typedef Templates13 type; }; template struct Templates { typedef Templates14 type; }; template struct Templates { typedef Templates15 type; }; template struct Templates { typedef Templates16 type; }; template struct Templates { typedef Templates17 type; }; template struct Templates { typedef Templates18 type; }; template struct Templates { typedef Templates19 type; }; template struct Templates { typedef Templates20 type; }; template struct Templates { typedef Templates21 type; }; template struct Templates { typedef Templates22 type; }; template struct Templates { typedef Templates23 type; }; template struct Templates { typedef Templates24 type; }; template struct Templates { typedef Templates25 type; }; template struct Templates { typedef Templates26 type; }; template struct Templates { typedef Templates27 type; }; template struct Templates { typedef Templates28 type; }; template struct Templates { typedef Templates29 type; }; template struct Templates { typedef Templates30 type; }; template struct Templates { typedef Templates31 type; }; template struct Templates { typedef Templates32 type; }; template struct Templates { typedef Templates33 type; }; template struct Templates { typedef Templates34 type; }; template struct Templates { typedef Templates35 type; }; template struct Templates { typedef Templates36 type; }; template struct Templates { typedef Templates37 type; }; template struct Templates { typedef Templates38 type; }; template struct Templates { typedef Templates39 type; }; template struct Templates { typedef Templates40 type; }; template struct Templates { typedef Templates41 type; }; template struct Templates { typedef Templates42 type; }; template struct Templates { typedef Templates43 type; }; template struct Templates { typedef Templates44 type; }; template struct Templates { typedef Templates45 type; }; template struct Templates { typedef Templates46 type; }; template struct Templates { typedef Templates47 type; }; template struct Templates { typedef Templates48 type; }; template struct Templates { typedef Templates49 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 struct TypeList { typedef Types1 type; }; template struct TypeList > { typedef typename Types::type type; }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-filepath.h0000644002537200234200000002260313213503245025523 0ustar zmoelnigiemusers// 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 . // 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 std::string& pathname) : pathname_(pathname) { Normalize(); } FilePath& operator=(const FilePath& rhs) { Set(rhs); return *this; } void Set(const FilePath& rhs) { pathname_ = rhs.pathname_; } const std::string& string() 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_.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 "". bool IsEmpty() const { return pathname_.empty(); } // 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; std::string pathname_; }; // class FilePath } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-port-arch.h0000644002537200234200000000661713213503245025635 0ustar zmoelnigiemusers// Copyright 2015, 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. // // The Google C++ Testing Framework (Google Test) // // This header file defines the GTEST_OS_* macro. // It is separate from gtest-port.h so that custom/gtest-port.h can include it. #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ // 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 # elif defined(WINAPI_FAMILY) # include # if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) # define GTEST_OS_WINDOWS_DESKTOP 1 # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_PHONE_APP) # define GTEST_OS_WINDOWS_PHONE 1 # elif WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP) # define GTEST_OS_WINDOWS_RT 1 # else // WINAPI_FAMILY defined but no known partition matched. // Default to desktop. # define GTEST_OS_WINDOWS_DESKTOP 1 # endif # else # define GTEST_OS_WINDOWS_DESKTOP 1 # endif // _WIN32_WCE #elif defined __APPLE__ # define GTEST_OS_MAC 1 # if TARGET_OS_IPHONE # define GTEST_OS_IOS 1 # endif #elif defined __FreeBSD__ # define GTEST_OS_FREEBSD 1 #elif defined __linux__ # define GTEST_OS_LINUX 1 # if defined __ANDROID__ # define GTEST_OS_LINUX_ANDROID 1 # endif #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 #elif defined(__hpux) # define GTEST_OS_HPUX 1 #elif defined __native_client__ # define GTEST_OS_NACL 1 #elif defined __OpenBSD__ # define GTEST_OS_OPENBSD 1 #elif defined __QNX__ # define GTEST_OS_QNX 1 #endif // __CYGWIN__ #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_PORT_ARCH_H_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-param-util-generated.h0000644002537200234200000056726113213503245027754 0ustar zmoelnigiemusers// This file was GENERATED by command: // pump.py gtest-param-util-generated.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: 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 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 internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end); template internal::ParamGenerator ValuesIn(const T (&array)[N]); template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. template class ValueArray1 { public: explicit ValueArray1(T1 v1) : v1_(v1) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray1& other); const T1 v1_; }; template class ValueArray2 { public: ValueArray2(T1 v1, T2 v2) : v1_(v1), v2_(v2) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_)}; return ValuesIn(array); } private: // No implementation - assignment is unsupported. void operator=(const ValueArray2& other); const T1 v1_; const T2 v2_; }; template class ValueArray3 { public: ValueArray3(T1 v1, T2 v2, T3 v3) : v1_(v1), v2_(v2), v3_(v3) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(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 class ValueArray4 { public: ValueArray4(T1 v1, T2 v2, T3 v3, T4 v4) : v1_(v1), v2_(v2), v3_(v3), v4_(v4) {} template operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_), static_cast(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 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 operator ParamGenerator() const { const T array[] = {static_cast(v1_), static_cast(v2_), static_cast(v3_), static_cast(v4_), static_cast(v5_), static_cast(v6_), static_cast(v7_), static_cast(v8_), static_cast(v9_), static_cast(v10_), static_cast(v11_), static_cast(v12_), static_cast(v13_), static_cast(v14_), static_cast(v15_), static_cast(v16_), static_cast(v17_), static_cast(v18_), static_cast(v19_), static_cast(v20_), static_cast(v21_), static_cast(v22_), static_cast(v23_), static_cast(v24_), static_cast(v25_), static_cast(v26_), static_cast(v27_), static_cast(v28_), static_cast(v29_), static_cast(v30_), static_cast(v31_), static_cast(v32_), static_cast(v33_), static_cast(v34_), static_cast(v35_), static_cast(v36_), static_cast(v37_), static_cast(v38_), static_cast(v39_), static_cast(v40_), static_cast(v41_), static_cast(v42_), static_cast(v43_), static_cast(v44_), static_cast(v45_), static_cast(v46_), static_cast(v47_), static_cast(v48_), static_cast(v49_), static_cast(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 class CartesianProductGenerator2 : public ParamGeneratorInterface< ::testing::tuple > { public: typedef ::testing::tuple ParamType; CartesianProductGenerator2(const ParamGenerator& g1, const ParamGenerator& g2) : g1_(g1), g2_(g2) {} virtual ~CartesianProductGenerator2() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; ParamType current_value_; }; // class CartesianProductGenerator2::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator2& other); const ParamGenerator g1_; const ParamGenerator g2_; }; // class CartesianProductGenerator2 template class CartesianProductGenerator3 : public ParamGeneratorInterface< ::testing::tuple > { public: typedef ::testing::tuple ParamType; CartesianProductGenerator3(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3) : g1_(g1), g2_(g2), g3_(g3) {} virtual ~CartesianProductGenerator3() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; ParamType current_value_; }; // class CartesianProductGenerator3::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator3& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; }; // class CartesianProductGenerator3 template class CartesianProductGenerator4 : public ParamGeneratorInterface< ::testing::tuple > { public: typedef ::testing::tuple ParamType; CartesianProductGenerator4(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} virtual ~CartesianProductGenerator4() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, g1_, g1_.end(), g2_, g2_.end(), g3_, g3_.end(), g4_, g4_.end()); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; ParamType current_value_; }; // class CartesianProductGenerator4::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator4& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; }; // class CartesianProductGenerator4 template class CartesianProductGenerator5 : public ParamGeneratorInterface< ::testing::tuple > { public: typedef ::testing::tuple ParamType; CartesianProductGenerator5(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5) {} virtual ~CartesianProductGenerator5() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, g1_, g1_.begin(), g2_, g2_.begin(), g3_, g3_.begin(), g4_, g4_.begin(), g5_, g5_.begin()); } virtual ParamIteratorInterface* 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 { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; ParamType current_value_; }; // class CartesianProductGenerator5::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator5& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; }; // class CartesianProductGenerator5 template class CartesianProductGenerator6 : public ParamGeneratorInterface< ::testing::tuple > { public: typedef ::testing::tuple ParamType; CartesianProductGenerator6(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6) {} virtual ~CartesianProductGenerator6() {} virtual ParamIteratorInterface* 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* 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 { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; ParamType current_value_; }; // class CartesianProductGenerator6::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator6& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; }; // class CartesianProductGenerator6 template class CartesianProductGenerator7 : public ParamGeneratorInterface< ::testing::tuple > { public: typedef ::testing::tuple ParamType; CartesianProductGenerator7(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7) {} virtual ~CartesianProductGenerator7() {} virtual ParamIteratorInterface* 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* 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 { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; ParamType current_value_; }; // class CartesianProductGenerator7::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator7& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; }; // class CartesianProductGenerator7 template class CartesianProductGenerator8 : public ParamGeneratorInterface< ::testing::tuple > { public: typedef ::testing::tuple ParamType; CartesianProductGenerator8(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8) {} virtual ~CartesianProductGenerator8() {} virtual ParamIteratorInterface* 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* 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 { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; ParamType current_value_; }; // class CartesianProductGenerator8::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator8& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; }; // class CartesianProductGenerator8 template class CartesianProductGenerator9 : public ParamGeneratorInterface< ::testing::tuple > { public: typedef ::testing::tuple ParamType; CartesianProductGenerator9(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9) : g1_(g1), g2_(g2), g3_(g3), g4_(g4), g5_(g5), g6_(g6), g7_(g7), g8_(g8), g9_(g9) {} virtual ~CartesianProductGenerator9() {} virtual ParamIteratorInterface* 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* 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 { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; ParamType current_value_; }; // class CartesianProductGenerator9::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator9& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; }; // class CartesianProductGenerator9 template class CartesianProductGenerator10 : public ParamGeneratorInterface< ::testing::tuple > { public: typedef ::testing::tuple ParamType; CartesianProductGenerator10(const ParamGenerator& g1, const ParamGenerator& g2, const ParamGenerator& g3, const ParamGenerator& g4, const ParamGenerator& g5, const ParamGenerator& g6, const ParamGenerator& g7, const ParamGenerator& g8, const ParamGenerator& g9, const ParamGenerator& 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* 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* 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 { public: Iterator(const ParamGeneratorInterface* base, const ParamGenerator& g1, const typename ParamGenerator::iterator& current1, const ParamGenerator& g2, const typename ParamGenerator::iterator& current2, const ParamGenerator& g3, const typename ParamGenerator::iterator& current3, const ParamGenerator& g4, const typename ParamGenerator::iterator& current4, const ParamGenerator& g5, const typename ParamGenerator::iterator& current5, const ParamGenerator& g6, const typename ParamGenerator::iterator& current6, const ParamGenerator& g7, const typename ParamGenerator::iterator& current7, const ParamGenerator& g8, const typename ParamGenerator::iterator& current8, const ParamGenerator& g9, const typename ParamGenerator::iterator& current9, const ParamGenerator& g10, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin1_; const typename ParamGenerator::iterator end1_; typename ParamGenerator::iterator current1_; const typename ParamGenerator::iterator begin2_; const typename ParamGenerator::iterator end2_; typename ParamGenerator::iterator current2_; const typename ParamGenerator::iterator begin3_; const typename ParamGenerator::iterator end3_; typename ParamGenerator::iterator current3_; const typename ParamGenerator::iterator begin4_; const typename ParamGenerator::iterator end4_; typename ParamGenerator::iterator current4_; const typename ParamGenerator::iterator begin5_; const typename ParamGenerator::iterator end5_; typename ParamGenerator::iterator current5_; const typename ParamGenerator::iterator begin6_; const typename ParamGenerator::iterator end6_; typename ParamGenerator::iterator current6_; const typename ParamGenerator::iterator begin7_; const typename ParamGenerator::iterator end7_; typename ParamGenerator::iterator current7_; const typename ParamGenerator::iterator begin8_; const typename ParamGenerator::iterator end8_; typename ParamGenerator::iterator current8_; const typename ParamGenerator::iterator begin9_; const typename ParamGenerator::iterator end9_; typename ParamGenerator::iterator current9_; const typename ParamGenerator::iterator begin10_; const typename ParamGenerator::iterator end10_; typename ParamGenerator::iterator current10_; ParamType current_value_; }; // class CartesianProductGenerator10::Iterator // No implementation - assignment is unsupported. void operator=(const CartesianProductGenerator10& other); const ParamGenerator g1_; const ParamGenerator g2_; const ParamGenerator g3_; const ParamGenerator g4_; const ParamGenerator g5_; const ParamGenerator g6_; const ParamGenerator g7_; const ParamGenerator g8_; const ParamGenerator g9_; const ParamGenerator g10_; }; // class CartesianProductGenerator10 // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Helper classes providing Combine() with polymorphic features. They allow // casting CartesianProductGeneratorN to ParamGenerator if T is // convertible to U. // template class CartesianProductHolder2 { public: CartesianProductHolder2(const Generator1& g1, const Generator2& g2) : g1_(g1), g2_(g2) {} template operator ParamGenerator< ::testing::tuple >() const { return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator2( static_cast >(g1_), static_cast >(g2_))); } private: // No implementation - assignment is unsupported. void operator=(const CartesianProductHolder2& other); const Generator1 g1_; const Generator2 g2_; }; // class CartesianProductHolder2 template class CartesianProductHolder3 { public: CartesianProductHolder3(const Generator1& g1, const Generator2& g2, const Generator3& g3) : g1_(g1), g2_(g2), g3_(g3) {} template operator ParamGenerator< ::testing::tuple >() const { return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator3( static_cast >(g1_), static_cast >(g2_), static_cast >(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 CartesianProductHolder4 { public: CartesianProductHolder4(const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) : g1_(g1), g2_(g2), g3_(g3), g4_(g4) {} template operator ParamGenerator< ::testing::tuple >() const { return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator4( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(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 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 operator ParamGenerator< ::testing::tuple >() const { return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator5( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(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 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 operator ParamGenerator< ::testing::tuple >() const { return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator6( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(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 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 operator ParamGenerator< ::testing::tuple >() const { return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator7( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(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 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 operator ParamGenerator< ::testing::tuple >() const { return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator8( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(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 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 operator ParamGenerator< ::testing::tuple >() const { return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator9( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(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 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 operator ParamGenerator< ::testing::tuple >() const { return ParamGenerator< ::testing::tuple >( new CartesianProductGenerator10( static_cast >(g1_), static_cast >(g2_), static_cast >(g3_), static_cast >(g4_), static_cast >(g5_), static_cast >(g6_), static_cast >(g7_), static_cast >(g8_), static_cast >(g9_), static_cast >(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_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-param-util-generated.h.pump0000644002537200234200000002162313213503245030717 0ustar zmoelnigiemusers$$ -*- 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 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 internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end); template internal::ParamGenerator ValuesIn(const T (&array)[N]); template internal::ParamGenerator ValuesIn( const Container& container); namespace internal { // Used in the Values() function to provide polymorphic capabilities. $range i 1..n $for i [[ $range j 1..i template <$for j, [[typename T$j]]> class ValueArray$i { public: $if i==1 [[explicit ]]ValueArray$i($for j, [[T$j v$j]]) : $for j, [[v$(j)_(v$j)]] {} template operator ParamGenerator() const { const T array[] = {$for j, [[static_cast(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< ::testing::tuple<$for j, [[T$j]]> > { public: typedef ::testing::tuple<$for j, [[T$j]]> ParamType; CartesianProductGenerator$i($for j, [[const ParamGenerator& g$j]]) : $for j, [[g$(j)_(g$j)]] {} virtual ~CartesianProductGenerator$i() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, $for j, [[g$(j)_, g$(j)_.begin()]]); } virtual ParamIteratorInterface* End() const { return new Iterator(this, $for j, [[g$(j)_, g$(j)_.end()]]); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, $for j, [[ const ParamGenerator& g$j, const typename ParamGenerator::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* 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* Clone() const { return new Iterator(*this); } virtual const ParamType* Current() const { return ¤t_value_; } virtual bool Equals(const ParamIteratorInterface& 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(&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* 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::iterator begin$(j)_; const typename ParamGenerator::iterator end$(j)_; typename ParamGenerator::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 g$(j)_; ]] }; // class CartesianProductGenerator$i ]] // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Helper classes providing Combine() with polymorphic features. They allow // casting CartesianProductGeneratorN to ParamGenerator 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< ::testing::tuple<$for j, [[T$j]]> >() const { return ParamGenerator< ::testing::tuple<$for j, [[T$j]]> >( new CartesianProductGenerator$i<$for j, [[T$j]]>( $for j,[[ static_cast >(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_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-string.h0000644002537200234200000001547013213503245025241 0ustar zmoelnigiemusers// 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 . // 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 #endif #include #include #include "gtest/internal/gtest-port.h" namespace testing { namespace internal { // String - an abstract class holding static string utilities. class GTEST_API_ String { public: // Static utility methods // 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 std::string ShowWideCString(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); // Returns true iff the given string ends with the given suffix, ignoring // case. Any string is considered to end with an empty suffix. static bool EndsWithCaseInsensitive( const std::string& str, const std::string& suffix); // Formats an int value as "%02d". static std::string FormatIntWidth2(int value); // "%02d" for width == 2 // Formats an int value as "%X". static std::string FormatHexInt(int value); // Formats a byte as "%02X". static std::string FormatByte(unsigned char value); private: String(); // Not meant to be instantiated. }; // class String // Gets the content of the stringstream's buffer as an std::string. Each '\0' // character in the buffer is replaced with "\\0". GTEST_API_ std::string StringStreamToString(::std::stringstream* stream); } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_STRING_H_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-type-util.h.pump0000644002537200234200000002214513213503245026644 0ustar zmoelnigiemusers$$ -*- 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" // #ifdef __GNUC__ is too general here. It is possible to use gcc without using // libstdc++ (which is where cxxabi.h comes from). # if GTEST_HAS_CXXABI_H_ # include # elif defined(__HP_aCC) # include # endif // GTEST_HASH_CXXABI_H_ namespace testing { namespace internal { // GetTypeName() returns a human-readable name of type T. // NB: This function is also used in Google Mock, so don't move it inside of // the typed-test-only section below. template std::string GetTypeName() { # if GTEST_HAS_RTTI const char* const name = typeid(T).name(); # if GTEST_HAS_CXXABI_H_ || defined(__HP_aCC) int status = 0; // gcc's implementation of typeid(T).name() mangles the type name, // so we have to demangle it. # if GTEST_HAS_CXXABI_H_ using abi::__cxa_demangle; # endif // GTEST_HAS_CXXABI_H_ char* const readable_name = __cxa_demangle(name, 0, 0, &status); const std::string name_str(status == 0 ? readable_name : name); free(readable_name); return name_str; # else return name; # endif // GTEST_HAS_CXXABI_H_ || __HP_aCC # else return ""; # endif // GTEST_HAS_RTTI } #if GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P // AssertyTypeEq::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 struct AssertTypeEq; template struct AssertTypeEq { typedef bool type; }; // 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, Type, 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 // 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 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 // will appear as Types in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Types, and Google Test will translate // that to TypesN 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 class // The template "selector" struct TemplateSel is used to // represent Tmpl, which must be a class template with one type // parameter, as a type. TemplateSel::Bind::type is defined // as the type Tmpl. This allows us to actually instantiate the // template "selected" by TemplateSel. // // This trick is necessary for simulating typedef for class templates, // which C++ doesn't support directly. template struct TemplateSel { template struct Bind { typedef Tmpl type; }; }; # define GTEST_BIND_(TmplSel, T) \ TmplSel::template Bind::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, Templates, // and etc), which C++ doesn't support directly. template struct NoneT {}; // The following family of struct and struct templates are used to // represent template lists. In particular, TemplatesN 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 struct Templates1 { typedef TemplateSel 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 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 // will appear as Templates in the compiler // errors). // // Our solution is to combine the best part of the two approaches: a // user would write Templates, and Google Test will translate // that to TemplatesN 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 struct TypeList { typedef Types1 type; }; $range i 1..n template <$for i, [[typename T$i]]> struct TypeList > { typedef typename Types<$for i, [[T$i]]>::type type; }; #endif // GTEST_HAS_TYPED_TEST || GTEST_HAS_TYPED_TEST_P } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_TYPE_UTIL_H_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-death-test-internal.h0000644002537200234200000003216513213503245027607 0ustar zmoelnigiemusers// 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" #include 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 three reasons that a test might be aborted. enum AbortReason { TEST_ENCOUNTERED_RETURN_STATEMENT, TEST_THREW_EXCEPTION, 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 std::string& message); private: // A string containing a description of the outcome of the last death test. static std::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); // Traps C++ exceptions escaping statement and reports them as test // failures. Note that trapping SEH exceptions is not implemented here. # if GTEST_HAS_EXCEPTIONS # define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ try { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } catch (const ::std::exception& gtest_exception) { \ fprintf(\ stderr, \ "\n%s: Caught std::exception-derived exception escaping the " \ "death test statement. Exception message: %s\n", \ ::testing::internal::FormatFileLocation(__FILE__, __LINE__).c_str(), \ gtest_exception.what()); \ fflush(stderr); \ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ } catch (...) { \ death_test->Abort(::testing::internal::DeathTest::TEST_THREW_EXCEPTION); \ } # else # define GTEST_EXECUTE_DEATH_TEST_STATEMENT_(statement, death_test) \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement) # endif // 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, >est_regex, \ __FILE__, __LINE__, >est_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_EXECUTE_DEATH_TEST_STATEMENT_(statement, gtest_dt); \ gtest_dt->Abort(::testing::internal::DeathTest::TEST_DID_NOT_DIE); \ break; \ } \ default: \ 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. // This macro is for implementing ASSERT/EXPECT_DEBUG_DEATH when compiled in // NDEBUG mode. In this case we need the statements to be executed, the regex is // ignored, and the macro must accept a streamed message even though the message // is never printed. # define GTEST_EXECUTE_STATEMENT_(statement, regex) \ GTEST_AMBIGUOUS_ELSE_BLOCKER_ \ if (::testing::internal::AlwaysTrue()) { \ GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_(statement); \ } else \ ::testing::Message() // 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 std::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_); } const std::string& file() const { return file_; } int line() const { return line_; } int index() const { return index_; } int write_fd() const { return write_fd_; } private: std::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_ assimp-4.1.0/contrib/gtest/include/gtest/internal/gtest-param-util.h0000644002537200234200000006636413213503245026016 0ustar zmoelnigiemusers// 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 #include #include #include #include // 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" #include "gtest/gtest-printers.h" #if GTEST_HAS_PARAM_TEST namespace testing { // Input to a parameterized test name generator, describing a test parameter. // Consists of the parameter value and the integer parameter index. template struct TestParamInfo { TestParamInfo(const ParamType& a_param, size_t an_index) : param(a_param), index(an_index) {} ParamType param; size_t index; }; // A builtin parameterized test name generator which returns the result of // testing::PrintToString. struct PrintToStringParamName { template std::string operator()(const TestParamInfo& info) const { return PrintToString(info.param); } }; 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, CodeLocation code_location); template class ParamGeneratorInterface; template class ParamGenerator; // Interface for iterating over elements provided by an implementation // of ParamGeneratorInterface. template 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* 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. 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::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::operator==(). virtual bool Equals(const ParamIteratorInterface& other) const = 0; }; // Class iterating over elements provided by an implementation of // ParamGeneratorInterface. It wraps ParamIteratorInterface // and implements the const forward iterator concept. template 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* 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; explicit ParamIterator(ParamIteratorInterface* impl) : impl_(impl) {} scoped_ptr > impl_; }; // ParamGeneratorInterface is the binary interface to access generators // defined in other translation units. template class ParamGeneratorInterface { public: typedef T ParamType; virtual ~ParamGeneratorInterface() {} // Generator interface definition virtual ParamIteratorInterface* Begin() const = 0; virtual ParamIteratorInterface* End() const = 0; }; // Wraps ParamGeneratorInterface and provides general generator syntax // compatible with the STL Container concept. // This class implements copy initialization semantics and the contained // ParamGeneratorInterface instance is shared among all copies // of the original object. This is possible because that instance is immutable. template class ParamGenerator { public: typedef ParamIterator iterator; explicit ParamGenerator(ParamGeneratorInterface* 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: linked_ptr > 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 class RangeGenerator : public ParamGeneratorInterface { public: RangeGenerator(T begin, T end, IncrementT step) : begin_(begin), end_(end), step_(step), end_index_(CalculateEndIndex(begin, end, step)) {} virtual ~RangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, begin_, 0, step_); } virtual ParamIteratorInterface* End() const { return new Iterator(this, end_, end_index_, step_); } private: class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, T value, int index, IncrementT step) : base_(base), value_(value), index_(index), step_(step) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { value_ = static_cast(value_ + step_); index_++; } virtual ParamIteratorInterface* Clone() const { return new Iterator(*this); } virtual const T* Current() const { return &value_; } virtual bool Equals(const ParamIteratorInterface& 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(&other)->index_; return index_ == other_index; } private: Iterator(const Iterator& other) : ParamIteratorInterface(), base_(other.base_), value_(other.value_), index_(other.index_), step_(other.step_) {} // No implementation - assignment is unsupported. void operator=(const Iterator& other); const ParamGeneratorInterface* 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 = static_cast(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 class ValuesInIteratorRangeGenerator : public ParamGeneratorInterface { public: template ValuesInIteratorRangeGenerator(ForwardIterator begin, ForwardIterator end) : container_(begin, end) {} virtual ~ValuesInIteratorRangeGenerator() {} virtual ParamIteratorInterface* Begin() const { return new Iterator(this, container_.begin()); } virtual ParamIteratorInterface* End() const { return new Iterator(this, container_.end()); } private: typedef typename ::std::vector ContainerType; class Iterator : public ParamIteratorInterface { public: Iterator(const ParamGeneratorInterface* base, typename ContainerType::const_iterator iterator) : base_(base), iterator_(iterator) {} virtual ~Iterator() {} virtual const ParamGeneratorInterface* BaseGenerator() const { return base_; } virtual void Advance() { ++iterator_; value_.reset(); } virtual ParamIteratorInterface* 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& 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(&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(), base_(other.base_), iterator_(other.iterator_) {} const ParamGeneratorInterface* 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 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. // // Default parameterized test name generator, returns a string containing the // integer test parameter index. template std::string DefaultParamName(const TestParamInfo& info) { Message name_stream; name_stream << info.index; return name_stream.GetString(); } // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Parameterized test name overload helpers, which help the // INSTANTIATE_TEST_CASE_P macro choose between the default parameterized // test name generator and user param name generator. template ParamNameGenFunctor GetParamNameGen(ParamNameGenFunctor func) { return func; } template struct ParamNameGenFunc { typedef std::string Type(const TestParamInfo&); }; template typename ParamNameGenFunc::Type *GetParamNameGen() { return DefaultParamName; } // INTERNAL IMPLEMENTATION - DO NOT USE IN USER CODE. // // Stores a parameter value and later creates tests parameterized with that // value. template class ParameterizedTestFactory : public TestFactoryBase { public: typedef typename TestClass::ParamType ParamType; explicit ParameterizedTestFactory(ParamType parameter) : parameter_(parameter) {} virtual Test* CreateTest() { TestClass::SetParam(¶meter_); 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 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 TestMetaFactory : public TestMetaFactoryBase { public: typedef typename TestCase::ParamType ParamType; TestMetaFactory() {} virtual TestFactoryBase* CreateTestFactory(ParamType parameter) { return new ParameterizedTestFactory(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 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(GeneratorCreationFunc)(); typedef typename ParamNameGenFunc::Type ParamNameGeneratorFunc; explicit ParameterizedTestCaseInfo( const char* name, CodeLocation code_location) : test_case_name_(name), code_location_(code_location) {} // 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(); } // 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* meta_factory) { tests_.push_back(linked_ptr(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 string& instantiation_name, GeneratorCreationFunc* func, ParamNameGeneratorFunc* name_func, const char* file, int line) { instantiations_.push_back( InstantiationInfo(instantiation_name, func, name_func, file, line)); 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 test_info = *test_it; for (typename InstantiationContainer::iterator gen_it = instantiations_.begin(); gen_it != instantiations_.end(); ++gen_it) { const string& instantiation_name = gen_it->name; ParamGenerator generator((*gen_it->generator)()); ParamNameGeneratorFunc* name_func = gen_it->name_func; const char* file = gen_it->file; int line = gen_it->line; string test_case_name; if ( !instantiation_name.empty() ) test_case_name = instantiation_name + "/"; test_case_name += test_info->test_case_base_name; size_t i = 0; std::set test_param_names; for (typename ParamGenerator::iterator param_it = generator.begin(); param_it != generator.end(); ++param_it, ++i) { Message test_name_stream; std::string param_name = name_func( TestParamInfo(*param_it, i)); GTEST_CHECK_(IsValidParamName(param_name)) << "Parameterized test name '" << param_name << "' is invalid, in " << file << " line " << line << std::endl; GTEST_CHECK_(test_param_names.count(param_name) == 0) << "Duplicate parameterized test name '" << param_name << "', in " << file << " line " << line << std::endl; test_param_names.insert(param_name); test_name_stream << test_info->test_base_name << "/" << param_name; MakeAndRegisterTestInfo( test_case_name.c_str(), test_name_stream.GetString().c_str(), NULL, // No type parameter. PrintToString(*param_it).c_str(), code_location_, 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* 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 > test_meta_factory; }; typedef ::std::vector > TestInfoContainer; // Records data received from INSTANTIATE_TEST_CASE_P macros: // struct InstantiationInfo { InstantiationInfo(const std::string &name_in, GeneratorCreationFunc* generator_in, ParamNameGeneratorFunc* name_func_in, const char* file_in, int line_in) : name(name_in), generator(generator_in), name_func(name_func_in), file(file_in), line(line_in) {} std::string name; GeneratorCreationFunc* generator; ParamNameGeneratorFunc* name_func; const char* file; int line; }; typedef ::std::vector InstantiationContainer; static bool IsValidParamName(const std::string& name) { // Check for empty string if (name.empty()) return false; // Check for invalid characters for (std::string::size_type index = 0; index < name.size(); ++index) { if (!isalnum(name[index]) && name[index] != '_') return false; } return true; } const string test_case_name_; CodeLocation code_location_; 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 ParameterizedTestCaseInfo* GetTestCasePatternHolder( const char* test_case_name, CodeLocation code_location) { ParameterizedTestCaseInfo* 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()) { // 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, code_location); posix::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 >(*it); } break; } } if (typed_test_info == NULL) { typed_test_info = new ParameterizedTestCaseInfo( test_case_name, code_location); 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 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_ assimp-4.1.0/contrib/gtest/include/gtest/gtest-printers.h0000644002537200234200000010770613213503245023771 0ustar zmoelnigiemusers// 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) // Google Test - The Google C++ Testing Framework // // This file implements a universal value printer that can print a // value of any type T: // // void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); // // A user can teach this function how to print a class type T by // defining either operator<<() or PrintTo() in the namespace that // defines T. More specifically, the FIRST defined function in the // following list will be used (assuming T is defined in namespace // foo): // // 1. foo::PrintTo(const T&, ostream*) // 2. operator<<(ostream&, const T&) defined in either foo or the // global namespace. // // If none of the above is defined, it will print the debug string of // the value if it is a protocol buffer, or print the raw bytes in the // value otherwise. // // To aid debugging: when T is a reference type, the address of the // value is also printed; when T is a (const) char pointer, both the // pointer value and the NUL-terminated string it points to are // printed. // // We also provide some convenient wrappers: // // // Prints a value to a string. For a (const or not) char // // pointer, the NUL-terminated string (but not the pointer) is // // printed. // std::string ::testing::PrintToString(const T& value); // // // Prints a value tersely: for a reference type, the referenced // // value (but not the address) is printed; for a (const or not) char // // pointer, the NUL-terminated string (but not the pointer) is // // printed. // void ::testing::internal::UniversalTersePrint(const T& value, ostream*); // // // Prints value using the type inferred by the compiler. The difference // // from UniversalTersePrint() is that this function prints both the // // pointer and the NUL-terminated string for a (const or not) char pointer. // void ::testing::internal::UniversalPrint(const T& value, ostream*); // // // Prints the fields of a tuple tersely to a string vector, one // // element for each field. Tuple support must be enabled in // // gtest-port.h. // std::vector UniversalTersePrintTupleFieldsToStrings( // const Tuple& value); // // Known limitation: // // The print primitives print the elements of an STL-style container // using the compiler-inferred type of *iter where iter is a // const_iterator of the container. When const_iterator is an input // iterator but not a forward iterator, this inferred type may not // match value_type, and the print output may be incorrect. In // practice, this is rarely a problem as for most containers // const_iterator is a forward iterator. We'll fix this if there's an // actual need for it. Note that this fix cannot rely on value_type // being defined as many user-defined container types don't have // value_type. #ifndef GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #define GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ #include // NOLINT #include #include #include #include #include "gtest/internal/gtest-port.h" #include "gtest/internal/gtest-internal.h" #if GTEST_HAS_STD_TUPLE_ # include #endif namespace testing { // Definitions in the 'internal' and 'internal2' name spaces are // subject to change without notice. DO NOT USE THEM IN USER CODE! namespace internal2 { // Prints the given number of bytes in the given object to the given // ostream. GTEST_API_ void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, ::std::ostream* os); // For selecting which printer to use when a given type has neither << // nor PrintTo(). enum TypeKind { kProtobuf, // a protobuf type kConvertibleToInteger, // a type implicitly convertible to BiggestInt // (e.g. a named or unnamed enum type) kOtherType // anything else }; // TypeWithoutFormatter::PrintValue(value, os) is called // by the universal printer to print a value of type T when neither // operator<< nor PrintTo() is defined for T, where kTypeKind is the // "kind" of T as defined by enum TypeKind. template class TypeWithoutFormatter { public: // This default version is called when kTypeKind is kOtherType. static void PrintValue(const T& value, ::std::ostream* os) { PrintBytesInObjectTo(reinterpret_cast(&value), sizeof(value), os); } }; // We print a protobuf using its ShortDebugString() when the string // doesn't exceed this many characters; otherwise we print it using // DebugString() for better readability. const size_t kProtobufOneLinerMaxLength = 50; template class TypeWithoutFormatter { public: static void PrintValue(const T& value, ::std::ostream* os) { const ::testing::internal::string short_str = value.ShortDebugString(); const ::testing::internal::string pretty_str = short_str.length() <= kProtobufOneLinerMaxLength ? short_str : ("\n" + value.DebugString()); *os << ("<" + pretty_str + ">"); } }; template class TypeWithoutFormatter { public: // Since T has no << operator or PrintTo() but can be implicitly // converted to BiggestInt, we print it as a BiggestInt. // // Most likely T is an enum type (either named or unnamed), in which // case printing it as an integer is the desired behavior. In case // T is not an enum, printing it as an integer is the best we can do // given that it has no user-defined printer. static void PrintValue(const T& value, ::std::ostream* os) { const internal::BiggestInt kBigInt = value; *os << kBigInt; } }; // Prints the given value to the given ostream. If the value is a // protocol message, its debug string is printed; if it's an enum or // of a type implicitly convertible to BiggestInt, it's printed as an // integer; otherwise the bytes in the value are printed. This is // what UniversalPrinter::Print() does when it knows nothing about // type T and T has neither << operator nor PrintTo(). // // A user can override this behavior for a class type Foo by defining // a << operator in the namespace where Foo is defined. // // We put this operator in namespace 'internal2' instead of 'internal' // to simplify the implementation, as much code in 'internal' needs to // use << in STL, which would conflict with our own << were it defined // in 'internal'. // // Note that this operator<< takes a generic std::basic_ostream type instead of the more restricted std::ostream. If // we define it to take an std::ostream instead, we'll get an // "ambiguous overloads" compiler error when trying to print a type // Foo that supports streaming to std::basic_ostream, as the compiler cannot tell whether // operator<<(std::ostream&, const T&) or // operator<<(std::basic_stream, const Foo&) is more // specific. template ::std::basic_ostream& operator<<( ::std::basic_ostream& os, const T& x) { TypeWithoutFormatter::value ? kProtobuf : internal::ImplicitlyConvertible::value ? kConvertibleToInteger : kOtherType)>::PrintValue(x, &os); return os; } } // namespace internal2 } // namespace testing // This namespace MUST NOT BE NESTED IN ::testing, or the name look-up // magic needed for implementing UniversalPrinter won't work. namespace testing_internal { // Used to print a value that is not an STL-style container when the // user doesn't define PrintTo() for it. template void DefaultPrintNonContainerTo(const T& value, ::std::ostream* os) { // With the following statement, during unqualified name lookup, // testing::internal2::operator<< appears as if it was declared in // the nearest enclosing namespace that contains both // ::testing_internal and ::testing::internal2, i.e. the global // namespace. For more details, refer to the C++ Standard section // 7.3.4-1 [namespace.udir]. This allows us to fall back onto // testing::internal2::operator<< in case T doesn't come with a << // operator. // // We cannot write 'using ::testing::internal2::operator<<;', which // gcc 3.3 fails to compile due to a compiler bug. using namespace ::testing::internal2; // NOLINT // Assuming T is defined in namespace foo, in the next statement, // the compiler will consider all of: // // 1. foo::operator<< (thanks to Koenig look-up), // 2. ::operator<< (as the current namespace is enclosed in ::), // 3. testing::internal2::operator<< (thanks to the using statement above). // // The operator<< whose type matches T best will be picked. // // We deliberately allow #2 to be a candidate, as sometimes it's // impossible to define #1 (e.g. when foo is ::std, defining // anything in it is undefined behavior unless you are a compiler // vendor.). *os << value; } } // namespace testing_internal namespace testing { namespace internal { // FormatForComparison::Format(value) formats a // value of type ToPrint that is an operand of a comparison assertion // (e.g. ASSERT_EQ). OtherOperand is the type of the other operand in // the comparison, and is used to help determine the best way to // format the value. In particular, when the value is a C string // (char pointer) and the other operand is an STL string object, we // want to format the C string as a string, since we know it is // compared by value with the string object. If the value is a char // pointer but the other operand is not an STL string object, we don't // know whether the pointer is supposed to point to a NUL-terminated // string, and thus want to print it as a pointer to be safe. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. // The default case. template class FormatForComparison { public: static ::std::string Format(const ToPrint& value) { return ::testing::PrintToString(value); } }; // Array. template class FormatForComparison { public: static ::std::string Format(const ToPrint* value) { return FormatForComparison::Format(value); } }; // By default, print C string as pointers to be safe, as we don't know // whether they actually point to a NUL-terminated string. #define GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(CharType) \ template \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(static_cast(value)); \ } \ } GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const char); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(wchar_t); GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_(const wchar_t); #undef GTEST_IMPL_FORMAT_C_STRING_AS_POINTER_ // If a C string is compared with an STL string object, we know it's meant // to point to a NUL-terminated string, and thus can print it as a string. #define GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(CharType, OtherStringType) \ template <> \ class FormatForComparison { \ public: \ static ::std::string Format(CharType* value) { \ return ::testing::PrintToString(value); \ } \ } GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::std::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::std::string); #if GTEST_HAS_GLOBAL_STRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(char, ::string); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const char, ::string); #endif #if GTEST_HAS_GLOBAL_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::wstring); #endif #if GTEST_HAS_STD_WSTRING GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(wchar_t, ::std::wstring); GTEST_IMPL_FORMAT_C_STRING_AS_STRING_(const wchar_t, ::std::wstring); #endif #undef GTEST_IMPL_FORMAT_C_STRING_AS_STRING_ // 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* or void*, and print it as a C string when it is compared // against an std::string object, for example. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. template std::string FormatForComparisonFailureMessage( const T1& value, const T2& /* other_operand */) { return FormatForComparison::Format(value); } // UniversalPrinter::Print(value, ostream_ptr) prints the given // value to the given ostream. The caller must ensure that // 'ostream_ptr' is not NULL, or the behavior is undefined. // // We define UniversalPrinter as a class template (as opposed to a // function template), as we need to partially specialize it for // reference types, which cannot be done with function templates. template class UniversalPrinter; template void UniversalPrint(const T& value, ::std::ostream* os); // Used to print an STL-style container when the user doesn't define // a PrintTo() for it. template void DefaultPrintTo(IsContainer /* dummy */, false_type /* is not a pointer */, const C& container, ::std::ostream* os) { const size_t kMaxCount = 32; // The maximum number of elements to print. *os << '{'; size_t count = 0; for (typename C::const_iterator it = container.begin(); it != container.end(); ++it, ++count) { if (count > 0) { *os << ','; if (count == kMaxCount) { // Enough has been printed. *os << " ..."; break; } } *os << ' '; // We cannot call PrintTo(*it, os) here as PrintTo() doesn't // handle *it being a native array. internal::UniversalPrint(*it, os); } if (count > 0) { *os << ' '; } *os << '}'; } // Used to print a pointer that is neither a char pointer nor a member // pointer, when the user doesn't define PrintTo() for it. (A member // variable pointer or member function pointer doesn't really point to // a location in the address space. Their representation is // implementation-defined. Therefore they will be printed as raw // bytes.) template void DefaultPrintTo(IsNotContainer /* dummy */, true_type /* is a pointer */, T* p, ::std::ostream* os) { if (p == NULL) { *os << "NULL"; } else { // C++ doesn't allow casting from a function pointer to any object // pointer. // // IsTrue() silences warnings: "Condition is always true", // "unreachable code". if (IsTrue(ImplicitlyConvertible::value)) { // T is not a function type. We just call << to print p, // relying on ADL to pick up user-defined << for their pointer // types, if any. *os << p; } else { // T is a function type, so '*os << p' doesn't do what we want // (it just prints p as bool). We want to print p as a const // void*. However, we cannot cast it to const void* directly, // even using reinterpret_cast, as earlier versions of gcc // (e.g. 3.4.5) cannot compile the cast when p is a function // pointer. Casting to UInt64 first solves the problem. *os << reinterpret_cast( reinterpret_cast(p)); } } } // Used to print a non-container, non-pointer value when the user // doesn't define PrintTo() for it. template void DefaultPrintTo(IsNotContainer /* dummy */, false_type /* is not a pointer */, const T& value, ::std::ostream* os) { ::testing_internal::DefaultPrintNonContainerTo(value, os); } // Prints the given value using the << operator if it has one; // otherwise prints the bytes in it. This is what // UniversalPrinter::Print() does when PrintTo() is not specialized // or overloaded for type T. // // A user can override this behavior for a class type Foo by defining // an overload of PrintTo() in the namespace where Foo is defined. We // give the user this option as sometimes defining a << operator for // Foo is not desirable (e.g. the coding style may prevent doing it, // or there is already a << operator but it doesn't do what the user // wants). template void PrintTo(const T& value, ::std::ostream* os) { // DefaultPrintTo() is overloaded. The type of its first two // arguments determine which version will be picked. If T is an // STL-style container, the version for container will be called; if // T is a pointer, the pointer version will be called; otherwise the // generic version will be called. // // Note that we check for container types here, prior to we check // for protocol message types in our operator<<. The rationale is: // // For protocol messages, we want to give people a chance to // override Google Mock's format by defining a PrintTo() or // operator<<. For STL containers, other formats can be // incompatible with Google Mock's format for the container // elements; therefore we check for container types here to ensure // that our format is used. // // The second argument of DefaultPrintTo() is needed to bypass a bug // in Symbian's C++ compiler that prevents it from picking the right // overload between: // // PrintTo(const T& x, ...); // PrintTo(T* x, ...); DefaultPrintTo(IsContainerTest(0), is_pointer(), value, os); } // The following list of PrintTo() overloads tells // UniversalPrinter::Print() how to print standard types (built-in // types, strings, plain arrays, and pointers). // Overloads for various char types. GTEST_API_ void PrintTo(unsigned char c, ::std::ostream* os); GTEST_API_ void PrintTo(signed char c, ::std::ostream* os); inline void PrintTo(char c, ::std::ostream* os) { // When printing a plain char, we always treat it as unsigned. This // way, the output won't be affected by whether the compiler thinks // char is signed or not. PrintTo(static_cast(c), os); } // Overloads for other simple built-in types. inline void PrintTo(bool x, ::std::ostream* os) { *os << (x ? "true" : "false"); } // Overload for wchar_t type. // Prints a wchar_t as a symbol if it is printable or as its internal // code otherwise and also as its decimal code (except for L'\0'). // The L'\0' char is printed as "L'\\0'". The decimal code is printed // as signed integer when wchar_t is implemented by the compiler // as a signed type and is printed as an unsigned integer when wchar_t // is implemented as an unsigned type. GTEST_API_ void PrintTo(wchar_t wc, ::std::ostream* os); // Overloads for C strings. GTEST_API_ void PrintTo(const char* s, ::std::ostream* os); inline void PrintTo(char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } // signed/unsigned char is often used for representing binary data, so // we print pointers to it as void* to be safe. inline void PrintTo(const signed char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(signed char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(const unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } inline void PrintTo(unsigned char* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } // MSVC can be configured to define wchar_t as a typedef of unsigned // short. It defines _NATIVE_WCHAR_T_DEFINED when wchar_t is a native // type. When wchar_t is a typedef, defining an overload for const // wchar_t* would cause unsigned short* be printed as a wide string, // possibly causing invalid memory accesses. #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Overloads for wide C strings GTEST_API_ void PrintTo(const wchar_t* s, ::std::ostream* os); inline void PrintTo(wchar_t* s, ::std::ostream* os) { PrintTo(ImplicitCast_(s), os); } #endif // Overload for C arrays. Multi-dimensional arrays are printed // properly. // Prints the given number of elements in an array, without printing // the curly braces. template void PrintRawArrayTo(const T a[], size_t count, ::std::ostream* os) { UniversalPrint(a[0], os); for (size_t i = 1; i != count; i++) { *os << ", "; UniversalPrint(a[i], os); } } // Overloads for ::string and ::std::string. #if GTEST_HAS_GLOBAL_STRING GTEST_API_ void PrintStringTo(const ::string&s, ::std::ostream* os); inline void PrintTo(const ::string& s, ::std::ostream* os) { PrintStringTo(s, os); } #endif // GTEST_HAS_GLOBAL_STRING GTEST_API_ void PrintStringTo(const ::std::string&s, ::std::ostream* os); inline void PrintTo(const ::std::string& s, ::std::ostream* os) { PrintStringTo(s, os); } // Overloads for ::wstring and ::std::wstring. #if GTEST_HAS_GLOBAL_WSTRING GTEST_API_ void PrintWideStringTo(const ::wstring&s, ::std::ostream* os); inline void PrintTo(const ::wstring& s, ::std::ostream* os) { PrintWideStringTo(s, os); } #endif // GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_STD_WSTRING GTEST_API_ void PrintWideStringTo(const ::std::wstring&s, ::std::ostream* os); inline void PrintTo(const ::std::wstring& s, ::std::ostream* os) { PrintWideStringTo(s, os); } #endif // GTEST_HAS_STD_WSTRING #if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ // Helper function for printing a tuple. T must be instantiated with // a tuple type. template void PrintTupleTo(const T& t, ::std::ostream* os); #endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ #if GTEST_HAS_TR1_TUPLE // Overload for ::std::tr1::tuple. Needed for printing function arguments, // which are packed as tuples. // Overloaded PrintTo() for tuples of various arities. We support // tuples of up-to 10 fields. The following implementation works // regardless of whether tr1::tuple is implemented using the // non-standard variadic template feature or not. inline void PrintTo(const ::std::tr1::tuple<>& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo(const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } template void PrintTo( const ::std::tr1::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } #endif // GTEST_HAS_TR1_TUPLE #if GTEST_HAS_STD_TUPLE_ template void PrintTo(const ::std::tuple& t, ::std::ostream* os) { PrintTupleTo(t, os); } #endif // GTEST_HAS_STD_TUPLE_ // Overload for std::pair. template void PrintTo(const ::std::pair& value, ::std::ostream* os) { *os << '('; // We cannot use UniversalPrint(value.first, os) here, as T1 may be // a reference type. The same for printing value.second. UniversalPrinter::Print(value.first, os); *os << ", "; UniversalPrinter::Print(value.second, os); *os << ')'; } // Implements printing a non-reference type T by letting the compiler // pick the right overload of PrintTo() for T. template class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) // Note: we deliberately don't call this PrintTo(), as that name // conflicts with ::testing::internal::PrintTo in the body of the // function. static void Print(const T& value, ::std::ostream* os) { // By default, ::testing::internal::PrintTo() is used for printing // the value. // // Thanks to Koenig look-up, if T is a class and has its own // PrintTo() function defined in its namespace, that function will // be visible here. Since it is more specific than the generic ones // in ::testing::internal, it will be picked by the compiler in the // following statement - exactly what we want. PrintTo(value, os); } GTEST_DISABLE_MSC_WARNINGS_POP_() }; // UniversalPrintArray(begin, len, os) prints an array of 'len' // elements, starting at address 'begin'. template void UniversalPrintArray(const T* begin, size_t len, ::std::ostream* os) { if (len == 0) { *os << "{}"; } else { *os << "{ "; const size_t kThreshold = 18; const size_t kChunkSize = 8; // If the array has more than kThreshold elements, we'll have to // omit some details by printing only the first and the last // kChunkSize elements. // TODO(wan@google.com): let the user control the threshold using a flag. if (len <= kThreshold) { PrintRawArrayTo(begin, len, os); } else { PrintRawArrayTo(begin, kChunkSize, os); *os << ", ..., "; PrintRawArrayTo(begin + len - kChunkSize, kChunkSize, os); } *os << " }"; } } // This overload prints a (const) char array compactly. GTEST_API_ void UniversalPrintArray( const char* begin, size_t len, ::std::ostream* os); // This overload prints a (const) wchar_t array compactly. GTEST_API_ void UniversalPrintArray( const wchar_t* begin, size_t len, ::std::ostream* os); // Implements printing an array type T[N]. template class UniversalPrinter { public: // Prints the given array, omitting some elements when there are too // many. static void Print(const T (&a)[N], ::std::ostream* os) { UniversalPrintArray(a, N, os); } }; // Implements printing a reference type T&. template class UniversalPrinter { public: // MSVC warns about adding const to a function type, so we want to // disable the warning. GTEST_DISABLE_MSC_WARNINGS_PUSH_(4180) static void Print(const T& value, ::std::ostream* os) { // Prints the address of the value. We use reinterpret_cast here // as static_cast doesn't compile when T is a function type. *os << "@" << reinterpret_cast(&value) << " "; // Then prints the value itself. UniversalPrint(value, os); } GTEST_DISABLE_MSC_WARNINGS_POP_() }; // Prints a value tersely: for a reference type, the referenced value // (but not the address) is printed; for a (const) char pointer, the // NUL-terminated string (but not the pointer) is printed. template class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T& value, ::std::ostream* os) { UniversalPrint(value, os); } }; template class UniversalTersePrinter { public: static void Print(const T (&value)[N], ::std::ostream* os) { UniversalPrinter::Print(value, os); } }; template <> class UniversalTersePrinter { public: static void Print(const char* str, ::std::ostream* os) { if (str == NULL) { *os << "NULL"; } else { UniversalPrint(string(str), os); } } }; template <> class UniversalTersePrinter { public: static void Print(char* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; #if GTEST_HAS_STD_WSTRING template <> class UniversalTersePrinter { public: static void Print(const wchar_t* str, ::std::ostream* os) { if (str == NULL) { *os << "NULL"; } else { UniversalPrint(::std::wstring(str), os); } } }; #endif template <> class UniversalTersePrinter { public: static void Print(wchar_t* str, ::std::ostream* os) { UniversalTersePrinter::Print(str, os); } }; template void UniversalTersePrint(const T& value, ::std::ostream* os) { UniversalTersePrinter::Print(value, os); } // Prints a value using the type inferred by the compiler. The // difference between this and UniversalTersePrint() is that for a // (const) char pointer, this prints both the pointer and the // NUL-terminated string. template void UniversalPrint(const T& value, ::std::ostream* os) { // A workarond for the bug in VC++ 7.1 that prevents us from instantiating // UniversalPrinter with T directly. typedef T T1; UniversalPrinter::Print(value, os); } typedef ::std::vector Strings; // TuplePolicy must provide: // - tuple_size // size of tuple TupleT. // - get(const TupleT& t) // static function extracting element I of tuple TupleT. // - tuple_element::type // type of element I of tuple TupleT. template struct TuplePolicy; #if GTEST_HAS_TR1_TUPLE template struct TuplePolicy { typedef TupleT Tuple; static const size_t tuple_size = ::std::tr1::tuple_size::value; template struct tuple_element : ::std::tr1::tuple_element {}; template static typename AddReference< const typename ::std::tr1::tuple_element::type>::type get( const Tuple& tuple) { return ::std::tr1::get(tuple); } }; template const size_t TuplePolicy::tuple_size; #endif // GTEST_HAS_TR1_TUPLE #if GTEST_HAS_STD_TUPLE_ template struct TuplePolicy< ::std::tuple > { typedef ::std::tuple Tuple; static const size_t tuple_size = ::std::tuple_size::value; template struct tuple_element : ::std::tuple_element {}; template static const typename ::std::tuple_element::type& get( const Tuple& tuple) { return ::std::get(tuple); } }; template const size_t TuplePolicy< ::std::tuple >::tuple_size; #endif // GTEST_HAS_STD_TUPLE_ #if GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ // This helper template allows PrintTo() for tuples and // UniversalTersePrintTupleFieldsToStrings() to be defined by // induction on the number of tuple fields. The idea is that // TuplePrefixPrinter::PrintPrefixTo(t, os) prints the first N // fields in tuple t, and can be defined in terms of // TuplePrefixPrinter. // // The inductive case. template struct TuplePrefixPrinter { // Prints the first N fields of a tuple. template static void PrintPrefixTo(const Tuple& t, ::std::ostream* os) { TuplePrefixPrinter::PrintPrefixTo(t, os); GTEST_INTENTIONAL_CONST_COND_PUSH_() if (N > 1) { GTEST_INTENTIONAL_CONST_COND_POP_() *os << ", "; } UniversalPrinter< typename TuplePolicy::template tuple_element::type> ::Print(TuplePolicy::template get(t), os); } // Tersely prints the first N fields of a tuple to a string vector, // one element for each field. template static void TersePrintPrefixToStrings(const Tuple& t, Strings* strings) { TuplePrefixPrinter::TersePrintPrefixToStrings(t, strings); ::std::stringstream ss; UniversalTersePrint(TuplePolicy::template get(t), &ss); strings->push_back(ss.str()); } }; // Base case. template <> struct TuplePrefixPrinter<0> { template static void PrintPrefixTo(const Tuple&, ::std::ostream*) {} template static void TersePrintPrefixToStrings(const Tuple&, Strings*) {} }; // Helper function for printing a tuple. // Tuple must be either std::tr1::tuple or std::tuple type. template void PrintTupleTo(const Tuple& t, ::std::ostream* os) { *os << "("; TuplePrefixPrinter::tuple_size>::PrintPrefixTo(t, os); *os << ")"; } // Prints the fields of a tuple tersely to a string vector, one // element for each field. See the comment before // UniversalTersePrint() for how we define "tersely". template Strings UniversalTersePrintTupleFieldsToStrings(const Tuple& value) { Strings result; TuplePrefixPrinter::tuple_size>:: TersePrintPrefixToStrings(value, &result); return result; } #endif // GTEST_HAS_TR1_TUPLE || GTEST_HAS_STD_TUPLE_ } // namespace internal template ::std::string PrintToString(const T& value) { ::std::stringstream ss; internal::UniversalTersePrinter::Print(value, &ss); return ss.str(); } } // namespace testing // Include any custom printer added by the local installation. // We must include this header at the end to make sure it can use the // declarations from this file. #include "gtest/internal/custom/gtest-printers.h" #endif // GTEST_INCLUDE_GTEST_GTEST_PRINTERS_H_ assimp-4.1.0/contrib/gtest/include/gtest/gtest_prod.h0000644002537200234200000000442413213503245023142 0ustar zmoelnigiemusers// 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_ assimp-4.1.0/contrib/gtest/include/gtest/gtest-param-test.h.pump0000644002537200234200000004711213213503245025152 0ustar zmoelnigiemusers$$ -*- 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 is usually derived from testing::TestWithParam (see below for // another inheritance scheme that's sometimes useful in more complicated // class hierarchies), where the type of your parameter values. // TestWithParam 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 { // 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 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. // // // A parameterized test fixture must be derived from testing::Test and from // testing::WithParamInterface, where T is the type of the parameter // values. Inheriting from TestWithParam satisfies that requirement because // TestWithParam inherits from both Test and WithParamInterface. In more // complicated hierarchies, however, it is occasionally useful to inherit // separately from Test and WithParamInterface. For example: class BaseTest : public ::testing::Test { // You can inherit all the usual members for a non-parameterized test // fixture here. }; class DerivedTest : public BaseTest, public ::testing::WithParamInterface { // The usual test fixture members go here too. }; TEST_F(BaseTest, HasFoo) { // This is an ordinary non-parameterized test. } TEST_P(DerivedTest, DoesBlah) { // GetParam works just the same here as if you inherit from TestWithParam. EXPECT_TRUE(foo.Blah(GetParam())); } #endif // 0 #include "gtest/internal/gtest-port.h" #if !GTEST_OS_SYMBIAN # include #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 { ... }; // // 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 internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator 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 GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_CASE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { typedef typename ::testing::internal::IteratorTraits ::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T (&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator 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 { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator 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 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 > {...}; // // 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 > { // 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, \ ::testing::internal::CodeLocation(\ __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_ATTRIBUTE_UNUSED_; \ 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() // The optional last argument to INSTANTIATE_TEST_CASE_P allows the user // to specify a function or functor that generates custom test name suffixes // based on the test parameters. The function should accept one argument of // type testing::TestParamInfo, and return std::string. // // testing::PrintToStringParamName is a builtin test suffix generator that // returns the value of testing::PrintToString(GetParam()). // // Note: test names must be non-empty, unique, and may only contain ASCII // alphanumeric characters or underscore. Because PrintToString adds quotes // to std::string and C strings, it won't work for these types. # define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ const ::testing::TestParamInfo& info) { \ return ::testing::internal::GetParamNameGen \ (__VA_ARGS__)(info); \ } \ int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, \ ::testing::internal::CodeLocation(\ __FILE__, __LINE__))->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ >est_##prefix##test_case_name##_EvalGenerateName_, \ __FILE__, __LINE__) } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ assimp-4.1.0/contrib/gtest/include/gtest/gtest-message.h0000644002537200234200000002174213213503245023542 0ustar zmoelnigiemusers// 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 #include "gtest/internal/gtest-port.h" // Ensures that there is at least one operator<< in the global namespace. // See Message& operator<<(...) below for why. void operator<<(const testing::internal::Secret&, int); 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 stringstream. // 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 stringstream 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. Message(); // Copy constructor. Message(const Message& msg) : ss_(new ::std::stringstream) { // NOLINT *ss_ << msg.GetString(); } // Constructs a Message from a C-string. explicit Message(const char* str) : ss_(new ::std::stringstream) { *ss_ << str; } #if GTEST_OS_SYMBIAN // Streams a value (either a pointer or not) to this object. template inline Message& operator <<(const T& value) { StreamHelper(typename internal::is_pointer::type(), value); return *this; } #else // Streams a non-pointer value to this object. template inline Message& operator <<(const T& val) { // Some libraries overload << for STL containers. These // overloads are defined in the global namespace instead of ::std. // // 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. With this using declaration, // overloads of << defined in the global namespace and those // visible via Koenig lookup are both exposed in this function. using ::operator <<; *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 inline Message& operator <<(T* const& pointer) { // NOLINT if (pointer == NULL) { *ss_ << "(null)"; } else { *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); Message& operator <<(wchar_t* 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 an std::string. // Each '\0' character in the buffer is replaced with "\\0". // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. std::string GetString() const; 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 inline void StreamHelper(internal::true_type /*is_pointer*/, T* pointer) { if (pointer == NULL) { *ss_ << "(null)"; } else { *ss_ << pointer; } } template inline void StreamHelper(internal::false_type /*is_pointer*/, const T& value) { // See the comments in Message& operator <<(const T&) above for why // we need this using statement. using ::operator <<; *ss_ << value; } #endif // GTEST_OS_SYMBIAN // We'll hold the text streamed to this object here. const internal::scoped_ptr< ::std::stringstream> 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 internal { // Converts a streamable value to an std::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". template std::string StreamableToString(const T& streamable) { return (Message() << streamable).GetString(); } } // namespace internal } // namespace testing #endif // GTEST_INCLUDE_GTEST_GTEST_MESSAGE_H_ assimp-4.1.0/contrib/gtest/include/gtest/gtest_pred_impl.h0000644002537200234200000003545113213503245024155 0ustar zmoelnigiemusers// 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/31/2011 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 AssertionResult AssertPred1Helper(const char* pred_text, const char* e1, Pred pred, const T1& v1) { if (pred(v1)) return AssertionSuccess(); return AssertionFailure() << pred_text << "(" << e1 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1; } // 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 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(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2; } // 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 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(); return AssertionFailure() << pred_text << "(" << e1 << ", " << e2 << ", " << e3 << ") evaluates to false, where" << "\n" << e1 << " evaluates to " << v1 << "\n" << e2 << " evaluates to " << v2 << "\n" << e3 << " evaluates to " << v3; } // 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 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(); return AssertionFailure() << 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; } // 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 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(); return AssertionFailure() << 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; } // 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_ assimp-4.1.0/contrib/gtest/include/gtest/gtest-spi.h0000644002537200234200000002334013213503245022705 0ustar zmoelnigiemusers// 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 string& 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(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_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(\ >est_failures, ::testing::TestPartResult::kFatalFailure, (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ALL_THREADS, >est_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(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter:: \ INTERCEPT_ONLY_CURRENT_THREAD, >est_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(\ >est_failures, ::testing::TestPartResult::kNonFatalFailure, \ (substr));\ {\ ::testing::ScopedFakeTestPartResultReporter gtest_reporter(\ ::testing::ScopedFakeTestPartResultReporter::INTERCEPT_ALL_THREADS, \ >est_failures);\ if (::testing::internal::AlwaysTrue()) { statement; }\ }\ } while (::testing::internal::AlwaysFalse()) #endif // GTEST_INCLUDE_GTEST_GTEST_SPI_H_ assimp-4.1.0/contrib/gtest/include/gtest/gtest-param-test.h0000644002537200234200000022640613213503245024177 0ustar zmoelnigiemusers// This file was GENERATED by command: // pump.py gtest-param-test.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. // // 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 is usually derived from testing::TestWithParam (see below for // another inheritance scheme that's sometimes useful in more complicated // class hierarchies), where the type of your parameter values. // TestWithParam 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 { // 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 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. // // // A parameterized test fixture must be derived from testing::Test and from // testing::WithParamInterface, where T is the type of the parameter // values. Inheriting from TestWithParam satisfies that requirement because // TestWithParam inherits from both Test and WithParamInterface. In more // complicated hierarchies, however, it is occasionally useful to inherit // separately from Test and WithParamInterface. For example: class BaseTest : public ::testing::Test { // You can inherit all the usual members for a non-parameterized test // fixture here. }; class DerivedTest : public BaseTest, public ::testing::WithParamInterface { // The usual test fixture members go here too. }; TEST_F(BaseTest, HasFoo) { // This is an ordinary non-parameterized test. } TEST_P(DerivedTest, DoesBlah) { // GetParam works just the same here as if you inherit from TestWithParam. EXPECT_TRUE(foo.Blah(GetParam())); } #endif // 0 #include "gtest/internal/gtest-port.h" #if !GTEST_OS_SYMBIAN # include #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 { ... }; // // 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 internal::ParamGenerator Range(T start, T end, IncrementT step) { return internal::ParamGenerator( new internal::RangeGenerator(start, end, step)); } template internal::ParamGenerator 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 GetParameterChars() { // ::std::list list; // list.push_back('a'); // list.push_back('b'); // return list; // } // ::std::list l = GetParameterChars(); // INSTANTIATE_TEST_CASE_P(CharSequence2, // CharTest, // ValuesIn(l.begin(), l.end())); // template internal::ParamGenerator< typename ::testing::internal::IteratorTraits::value_type> ValuesIn(ForwardIterator begin, ForwardIterator end) { typedef typename ::testing::internal::IteratorTraits ::value_type ParamType; return internal::ParamGenerator( new internal::ValuesInIteratorRangeGenerator(begin, end)); } template internal::ParamGenerator ValuesIn(const T (&array)[N]) { return ValuesIn(array, array + N); } template internal::ParamGenerator 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 internal::ValueArray1 Values(T1 v1) { return internal::ValueArray1(v1); } template internal::ValueArray2 Values(T1 v1, T2 v2) { return internal::ValueArray2(v1, v2); } template internal::ValueArray3 Values(T1 v1, T2 v2, T3 v3) { return internal::ValueArray3(v1, v2, v3); } template internal::ValueArray4 Values(T1 v1, T2 v2, T3 v3, T4 v4) { return internal::ValueArray4(v1, v2, v3, v4); } template internal::ValueArray5 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5) { return internal::ValueArray5(v1, v2, v3, v4, v5); } template internal::ValueArray6 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6) { return internal::ValueArray6(v1, v2, v3, v4, v5, v6); } template internal::ValueArray7 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7) { return internal::ValueArray7(v1, v2, v3, v4, v5, v6, v7); } template internal::ValueArray8 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8) { return internal::ValueArray8(v1, v2, v3, v4, v5, v6, v7, v8); } template internal::ValueArray9 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9) { return internal::ValueArray9(v1, v2, v3, v4, v5, v6, v7, v8, v9); } template internal::ValueArray10 Values(T1 v1, T2 v2, T3 v3, T4 v4, T5 v5, T6 v6, T7 v7, T8 v8, T9 v9, T10 v10) { return internal::ValueArray10(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10); } template internal::ValueArray11 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11); } template internal::ValueArray12 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12); } template internal::ValueArray13 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13); } template internal::ValueArray14 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14); } template internal::ValueArray15 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15); } template internal::ValueArray16 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16); } template internal::ValueArray17 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17); } template internal::ValueArray18 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18); } template internal::ValueArray19 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19); } template internal::ValueArray20 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20); } template internal::ValueArray21 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21); } template internal::ValueArray22 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22); } template internal::ValueArray23 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(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22, v23); } template internal::ValueArray24 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(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 internal::ValueArray25 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(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 internal::ValueArray26 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(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 internal::ValueArray27 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(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 internal::ValueArray28 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(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 internal::ValueArray29 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(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 internal::ValueArray30 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(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 internal::ValueArray31 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(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 internal::ValueArray32 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(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 internal::ValueArray33 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(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 internal::ValueArray34 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(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 internal::ValueArray35 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(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 internal::ValueArray36 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(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 internal::ValueArray37 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(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 internal::ValueArray38 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(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 internal::ValueArray39 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(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 internal::ValueArray40 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(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 internal::ValueArray41 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(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 internal::ValueArray42 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(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 internal::ValueArray43 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(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 internal::ValueArray44 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(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 internal::ValueArray45 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(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 internal::ValueArray46 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(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 internal::ValueArray47 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(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 internal::ValueArray48 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(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 internal::ValueArray49 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(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 internal::ValueArray50 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(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 { // virtual void SetUp() { // external_flag = GetParam(); // } // } // INSTANTIATE_TEST_CASE_P(BoolSequence, FlagDependentTest, Bool()); // inline internal::ParamGenerator 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 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 > {...}; // // 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 > { // 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 internal::CartesianProductHolder2 Combine( const Generator1& g1, const Generator2& g2) { return internal::CartesianProductHolder2( g1, g2); } template internal::CartesianProductHolder3 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3) { return internal::CartesianProductHolder3( g1, g2, g3); } template internal::CartesianProductHolder4 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4) { return internal::CartesianProductHolder4( g1, g2, g3, g4); } template internal::CartesianProductHolder5 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5) { return internal::CartesianProductHolder5( g1, g2, g3, g4, g5); } template internal::CartesianProductHolder6 Combine( const Generator1& g1, const Generator2& g2, const Generator3& g3, const Generator4& g4, const Generator5& g5, const Generator6& g6) { return internal::CartesianProductHolder6( g1, g2, g3, g4, g5, g6); } template internal::CartesianProductHolder7 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( g1, g2, g3, g4, g5, g6, g7); } template internal::CartesianProductHolder8 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( g1, g2, g3, g4, g5, g6, g7, g8); } template internal::CartesianProductHolder9 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( g1, g2, g3, g4, g5, g6, g7, g8, g9); } template internal::CartesianProductHolder10 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( 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, \ ::testing::internal::CodeLocation(\ __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_ATTRIBUTE_UNUSED_; \ 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() // The optional last argument to INSTANTIATE_TEST_CASE_P allows the user // to specify a function or functor that generates custom test name suffixes // based on the test parameters. The function should accept one argument of // type testing::TestParamInfo, and return std::string. // // testing::PrintToStringParamName is a builtin test suffix generator that // returns the value of testing::PrintToString(GetParam()). It does not work // for std::string or C strings. // // Note: test names must be non-empty, unique, and may only contain ASCII // alphanumeric characters or underscore. # define INSTANTIATE_TEST_CASE_P(prefix, test_case_name, generator, ...) \ ::testing::internal::ParamGenerator \ gtest_##prefix##test_case_name##_EvalGenerator_() { return generator; } \ ::std::string gtest_##prefix##test_case_name##_EvalGenerateName_( \ const ::testing::TestParamInfo& info) { \ return ::testing::internal::GetParamNameGen \ (__VA_ARGS__)(info); \ } \ int gtest_##prefix##test_case_name##_dummy_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::UnitTest::GetInstance()->parameterized_test_registry(). \ GetTestCasePatternHolder(\ #test_case_name, \ ::testing::internal::CodeLocation(\ __FILE__, __LINE__))->AddTestCaseInstantiation(\ #prefix, \ >est_##prefix##test_case_name##_EvalGenerator_, \ >est_##prefix##test_case_name##_EvalGenerateName_, \ __FILE__, __LINE__) } // namespace testing #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_INCLUDE_GTEST_GTEST_PARAM_TEST_H_ assimp-4.1.0/contrib/gtest/include/gtest/gtest.h0000644002537200234200000024672313213503245022130 0ustar zmoelnigiemusers// 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 #include #include #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-printers.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. // // You 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 ::std::string and ::string are the same class on your platform // due to aliasing, you should define GTEST_HAS_GLOBAL_STRING to 0. // // If you do not 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); // When this flag is set with a "host:port" string, on supported // platforms test results are streamed to the specified port on // the specified host machine. GTEST_DECLARE_string_(stream_result_to); // 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 StreamingListenerTest; class TestResultAccessor; class TestEventListenersAccessor; class TestEventRepeater; class UnitTestRecordPropertyTestHelper; class WindowsDeathTest; class UnitTestImpl* GetUnitTestImpl(); void ReportFailureInUnknownLocation(TestPartResult::Type result_type, const std::string& message); } // namespace internal // The friend relationship of some of these classes is cyclic. // If we don't forward declare them the compiler might confuse the classes // in friendship clauses with same named classes on the scope. class Test; class TestCase; class TestInfo; class UnitTest; // 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); GTEST_DISABLE_MSC_WARNINGS_PUSH_(4800 /* forcing value to bool */) // Used in the EXPECT_TRUE/FALSE(bool_expression). // // T must be contextually convertible to bool. // // The second parameter prevents this overload from being considered if // the argument is implicitly convertible to AssertionResult. In that case // we want AssertionResult's copy constructor to be used. template explicit AssertionResult( const T& success, typename internal::EnableIf< !internal::ImplicitlyConvertible::value>::type* /*enabler*/ = NULL) : success_(success) {} GTEST_DISABLE_MSC_WARNINGS_POP_() // Assignment operator. AssertionResult& operator=(AssertionResult other) { swap(other); return *this; } // 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() : ""; } // 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 AssertionResult& operator<<(const T& value) { AppendMessage(Message() << value); return *this; } // Allows streaming basic output manipulators such as endl or flush into // this object. AssertionResult& operator<<( ::std::ostream& (*basic_manipulator)(::std::ostream& stream)) { AppendMessage(Message() << basic_manipulator); return *this; } private: // Appends the contents of message to message_. void AppendMessage(const Message& a_message) { if (message_.get() == NULL) message_.reset(new ::std::string); message_->append(a_message.GetString().c_str()); } // Swap the contents of this AssertionResult with other. void swap(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< ::std::string> message_; }; // 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: // void SetUp() override { ... } // void TearDown() override { ... } // ... // }; // // TEST_F(FooTest, Bar) { ... } // TEST_F(FooTest, Baz) { ... } // // Test is not copyable. class GTEST_API_ Test { public: friend class TestInfo; // 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, test case, or for the entire // invocation of the test program when used outside of the context of a // test case. 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. Calls to RecordProperty made during // lifespan of the test (from the moment its constructor starts to the // moment its destructor finishes) will be output in XML as attributes of // the element. Properties recorded from fixture's // SetUpTestCase or TearDownTestCase are logged as attributes of the // corresponding element. Calls to RecordProperty made in the // global context (before or after invocation of RUN_ALL_TESTS and from // SetUp/TearDown method of Environment objects registered with Google // Test) will be output as attributes of the element. static void RecordProperty(const std::string& key, const std::string& value); static void RecordProperty(const std::string& 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(); // Deletes self. We deliberately pick an unusual name for this // internal method to avoid clashing with names used in user TESTs. void DeleteSelf_() { delete this; } const internal::scoped_ptr< GTEST_FLAG_SAVER_ > gtest_flag_saver_; // Often a user misspells 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 void Setup() is declared in the user's // test fixture. // // - This method is private, so it will be another compiler error // if the method is called from the user's 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 std::string& a_key, const std::string& 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 std::string& new_value) { value_ = new_value; } private: // The key supplied by the user. std::string key_; // The value supplied by the user. std::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 TestCase; friend class UnitTest; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::ExecDeathTest; friend class internal::TestResultAccessor; friend class internal::UnitTestImpl; friend class internal::WindowsDeathTest; // Gets the vector of TestPartResults. const std::vector& test_part_results() const { return test_part_results_; } // Gets the vector of TestProperties. const std::vector& 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. xml_element specifies the element for which the property is being // recorded and is used for validation. void RecordProperty(const std::string& xml_element, 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 std::string& xml_element, 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 test_part_results_; // The vector of TestProperties std::vector 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 { return test_case_name_.c_str(); } // Returns the test name. const char* name() const { return name_.c_str(); } // Returns the name of the parameter type, or NULL if this is not a typed // or a type-parameterized test. const char* type_param() const { if (type_param_.get() != NULL) return type_param_->c_str(); return NULL; } // Returns the text representation of the value parameter, or NULL if this // is not a value-parameterized test. const char* value_param() const { if (value_param_.get() != NULL) return value_param_->c_str(); return NULL; } // Returns the file name where this test is defined. const char* file() const { return location_.file.c_str(); } // Returns the line where this test is defined. int line() const { return location_.line; } // 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 { return should_run_; } // Returns true iff this test will appear in the XML report. bool is_reportable() const { // For now, the XML report includes all tests matching the filter. // In the future, we may trim tests that are excluded because of // sharding. return matches_filter_; } // Returns the result of the test. const TestResult* result() const { return &result_; } private: #if GTEST_HAS_DEATH_TEST friend class internal::DefaultDeathTestFactory; #endif // GTEST_HAS_DEATH_TEST friend class Test; friend class TestCase; friend class internal::UnitTestImpl; friend class internal::StreamingListenerTest; friend TestInfo* internal::MakeAndRegisterTestInfo( const char* test_case_name, const char* name, const char* type_param, const char* value_param, internal::CodeLocation code_location, internal::TypeId fixture_class_id, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc, internal::TestFactoryBase* factory); // Constructs a TestInfo object. The newly constructed instance assumes // ownership of the factory object. TestInfo(const std::string& test_case_name, const std::string& name, const char* a_type_param, // NULL if not a type-parameterized test const char* a_value_param, // NULL if not a value-parameterized test internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory); // Increments the number of death tests encountered in this test so // far. int increment_death_test_count() { return result_.increment_death_test_count(); } // Creates the test object, runs it, records its result, and then // deletes it. void Run(); static void ClearTestResult(TestInfo* test_info) { test_info->result_.Clear(); } // These fields are immutable properties of the test. const std::string test_case_name_; // Test case name const std::string name_; // Test name // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const internal::scoped_ptr type_param_; // Text representation of the value parameter, or NULL if this is not a // value-parameterized test. const internal::scoped_ptr value_param_; internal::CodeLocation location_; const internal::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_(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 // a_type_param: the name of the test's type parameter, or NULL if // this is not a type-parameterized test. // 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* a_type_param, 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 name of the parameter type, or NULL if this is not a // type-parameterized test case. const char* type_param() const { if (type_param_.get() != NULL) return type_param_->c_str(); return NULL; } // 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 that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests in this test case. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_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; // Returns the TestResult that holds test properties recorded during // execution of SetUpTestCase and TearDownTestCase. const TestResult& ad_hoc_test_result() const { return ad_hoc_test_result_; } private: friend class Test; friend class internal::UnitTestImpl; // Gets the (mutable) vector of TestInfos in this TestCase. std::vector& test_info_list() { return test_info_list_; } // Gets the (immutable) vector of TestInfos in this TestCase. const std::vector& 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(); // Runs SetUpTestCase() for this TestCase. This wrapper is needed // for catching exceptions thrown from SetUpTestCase(). void RunSetUpTestCase() { (*set_up_tc_)(); } // Runs TearDownTestCase() for this TestCase. This wrapper is // needed for catching exceptions thrown from TearDownTestCase(). void RunTearDownTestCase() { (*tear_down_tc_)(); } // Returns true iff test passed. static bool TestPassed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Passed(); } // Returns true iff test failed. static bool TestFailed(const TestInfo* test_info) { return test_info->should_run() && test_info->result()->Failed(); } // Returns true iff the test is disabled and will be reported in the XML // report. static bool TestReportableDisabled(const TestInfo* test_info) { return test_info->is_reportable() && test_info->is_disabled_; } // Returns true iff test is disabled. static bool TestDisabled(const TestInfo* test_info) { return test_info->is_disabled_; } // Returns true iff this test will appear in the XML report. static bool TestReportable(const TestInfo* test_info) { return test_info->is_reportable(); } // Returns true if the given test should run. static bool ShouldRunTest(const TestInfo* test_info) { return test_info->should_run(); } // 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. std::string name_; // Name of the parameter type, or NULL if this is not a typed or a // type-parameterized test. const internal::scoped_ptr type_param_; // The vector of TestInfos in their original order. It owns the // elements in the vector. std::vector 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 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_; // Holds test properties recorded during execution of SetUpTestCase and // TearDownTestCase. TestResult ad_hoc_test_result_; // We disallow copying TestCases. GTEST_DISALLOW_COPY_AND_ASSIGN_(TestCase); }; // An Environment object is capable of setting up and tearing down an // environment. You should subclass this to define your 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 SUCCEED() invocation. 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 TestInfo; friend class internal::DefaultGlobalTestPartResultReporter; friend class internal::NoExecDeathTest; friend class internal::TestEventListenersAccessor; 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 GTEST_LOCK_EXCLUDED_(mutex_); // Returns the TestInfo object for the test that's currently running, // or NULL if no test is running. const TestInfo* current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_); // 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() GTEST_LOCK_EXCLUDED_(mutex_); #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 that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_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 time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() 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 TestResult containing information on test failures and // properties logged outside of individual test cases. const TestResult& ad_hoc_test_result() 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 std::string& message, const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_); // Adds a TestProperty to the current TestResult object when invoked from // inside a test, to current TestCase's ad_hoc_test_result_ when invoked // from SetUpTestCase or TearDownTestCase, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void RecordProperty(const std::string& key, const std::string& 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 class internal::StreamingListenerTest; friend class internal::UnitTestRecordPropertyTestHelper; friend Environment* AddGlobalTestEnvironment(Environment* env); friend internal::UnitTestImpl* internal::GetUnitTestImpl(); friend void internal::ReportFailureInUnknownLocation( TestPartResult::Type result_type, const std::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) GTEST_LOCK_EXCLUDED_(mutex_); // Pops a trace from the per-thread Google Test trace stack. void PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_); // 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 { // Separate the error generating code from the code path to reduce the stack // frame size of CmpHelperEQ. This helps reduce the overhead of some sanitizers // when calling EXPECT_* in a tight loop. template AssertionResult CmpHelperEQFailure(const char* lhs_expression, const char* rhs_expression, const T1& lhs, const T2& rhs) { return EqFailure(lhs_expression, rhs_expression, FormatForComparisonFailureMessage(lhs, rhs), FormatForComparisonFailureMessage(rhs, lhs), false); } // The helper function for {ASSERT|EXPECT}_EQ. template AssertionResult CmpHelperEQ(const char* lhs_expression, const char* rhs_expression, const T1& lhs, const T2& rhs) { GTEST_DISABLE_MSC_WARNINGS_PUSH_(4389 /* signed/unsigned mismatch */) if (lhs == rhs) { return AssertionSuccess(); } GTEST_DISABLE_MSC_WARNINGS_POP_() return CmpHelperEQFailure(lhs_expression, rhs_expression, lhs, rhs); } // 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* lhs_expression, const char* rhs_expression, BiggestInt lhs, BiggestInt rhs); // 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 class EqHelper { public: // This templatized version is for the general case. template static AssertionResult Compare(const char* lhs_expression, const char* rhs_expression, const T1& lhs, const T2& rhs) { return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } // 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* lhs_expression, const char* rhs_expression, BiggestInt lhs, BiggestInt rhs) { return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } }; // This specialization is used when the first argument to ASSERT_EQ() // is a null pointer literal, like NULL, false, or 0. template <> class EqHelper { 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 static AssertionResult Compare( const char* lhs_expression, const char* rhs_expression, const T1& lhs, const T2& rhs, // The following line prevents this overload from being considered if T2 // is not a pointer type. We need this because ASSERT_EQ(NULL, my_ptr) // expands to Compare("", "", NULL, my_ptr), which requires a conversion // to match the Secret* in the other overload, which would otherwise make // this template match better. typename EnableIf::value>::type* = 0) { return CmpHelperEQ(lhs_expression, rhs_expression, lhs, rhs); } // This version will be picked when the second argument to ASSERT_EQ() is a // pointer, e.g. ASSERT_EQ(NULL, a_pointer). template static AssertionResult Compare( const char* lhs_expression, const char* rhs_expression, // We used to have a second template parameter instead of Secret*. That // template parameter would deduce to 'long', making this a better match // than the first overload even without the first overload's EnableIf. // Unfortunately, gcc with -Wconversion-null warns when "passing NULL to // non-pointer argument" (even a deduced integral argument), so the old // implementation caused warnings in user code. Secret* /* lhs (NULL) */, T* rhs) { // We already know that 'lhs' is a null pointer. return CmpHelperEQ(lhs_expression, rhs_expression, static_cast(NULL), rhs); } }; // Separate the error generating code from the code path to reduce the stack // frame size of CmpHelperOP. This helps reduce the overhead of some sanitizers // when calling EXPECT_OP in a tight loop. template AssertionResult CmpHelperOpFailure(const char* expr1, const char* expr2, const T1& val1, const T2& val2, const char* op) { return AssertionFailure() << "Expected: (" << expr1 << ") " << op << " (" << expr2 << "), actual: " << FormatForComparisonFailureMessage(val1, val2) << " vs " << FormatForComparisonFailureMessage(val2, val1); } // 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 \ AssertionResult CmpHelper##op_name(const char* expr1, const char* expr2, \ const T1& val1, const T2& val2) {\ if (val1 op val2) {\ return AssertionSuccess();\ } else {\ return CmpHelperOpFailure(expr1, expr2, val1, val2, #op);\ }\ }\ 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* s1_expression, const char* s2_expression, const char* s1, const char* s2); // The helper function for {ASSERT|EXPECT}_STRCASEEQ. // // INTERNAL IMPLEMENTATION - DO NOT USE IN A USER PROGRAM. GTEST_API_ AssertionResult CmpHelperSTRCASEEQ(const char* s1_expression, const char* s2_expression, const char* s1, const char* s2); // 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* s1_expression, const char* s2_expression, const wchar_t* s1, const wchar_t* s2); // 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 AssertionResult CmpHelperFloatingPointEQ(const char* lhs_expression, const char* rhs_expression, RawType lhs_value, RawType rhs_value) { const FloatingPoint lhs(lhs_value), rhs(rhs_value); if (lhs.AlmostEquals(rhs)) { return AssertionSuccess(); } ::std::stringstream lhs_ss; lhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) << lhs_value; ::std::stringstream rhs_ss; rhs_ss << std::setprecision(std::numeric_limits::digits10 + 2) << rhs_value; return EqFailure(lhs_expression, rhs_expression, StringStreamToString(&lhs_ss), StringStreamToString(&rhs_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; std::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 pure interface class that all value-parameterized tests inherit from. // A value-parameterized class must inherit from both ::testing::Test and // ::testing::WithParamInterface. In most cases that just means inheriting // from ::testing::TestWithParam, but more complicated test hierarchies // may need to inherit from Test and WithParamInterface at different levels. // // This interface has 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 { // 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 class WithParamInterface { public: typedef T ParamType; virtual ~WithParamInterface() {} // The current parameter value. Is also available in the test fixture's // constructor. This member function is non-static, even though it only // references static data, to reduce the opportunity for incorrect uses // like writing 'WithParamInterface::GetParam()' for a test that // uses a fixture whose parameter type is int. const ParamType& GetParam() const { GTEST_CHECK_(parameter_ != NULL) << "GetParam() can only be called inside a value-parameterized test " << "-- did you intend to write TEST_P instead of TEST_F?"; 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 WithParamInterface and Test. template friend class internal::ParameterizedTestFactory; }; template const T* WithParamInterface::parameter_ = NULL; // Most value-parameterized classes can ignore the existence of // WithParamInterface, and can just inherit from ::testing::TestWithParam. template class TestWithParam : public Test, public WithParamInterface { }; #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. // Generates a nonfatal failure with a generic message. #define ADD_FAILURE() GTEST_NONFATAL_FAILURE_("Failed") // Generates a nonfatal failure at the given source file location with // a generic message. #define ADD_FAILURE_AT(file, line) \ GTEST_MESSAGE_AT_(file, line, "Failed", \ ::testing::TestPartResult::kNonFatalFailure) // 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(v1, v2): Tests that v1 == v2 // * {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(v1, v2) is preferred to // {ASSERT|EXPECT}_TRUE(v1 == v2), 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(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ val1, val2) #define EXPECT_NE(val1, val2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #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 GTEST_ASSERT_EQ(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal:: \ EqHelper::Compare, \ val1, val2) #define GTEST_ASSERT_NE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperNE, val1, val2) #define GTEST_ASSERT_LE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLE, val1, val2) #define GTEST_ASSERT_LT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperLT, val1, val2) #define GTEST_ASSERT_GE(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGE, val1, val2) #define GTEST_ASSERT_GT(val1, val2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperGT, val1, val2) // Define macro GTEST_DONT_DEFINE_ASSERT_XY to 1 to omit the definition of // ASSERT_XY(), which clashes with some users' own code. #if !GTEST_DONT_DEFINE_ASSERT_EQ # define ASSERT_EQ(val1, val2) GTEST_ASSERT_EQ(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_NE # define ASSERT_NE(val1, val2) GTEST_ASSERT_NE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LE # define ASSERT_LE(val1, val2) GTEST_ASSERT_LE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_LT # define ASSERT_LT(val1, val2) GTEST_ASSERT_LT(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GE # define ASSERT_GE(val1, val2) GTEST_ASSERT_GE(val1, val2) #endif #if !GTEST_DONT_DEFINE_ASSERT_GT # define ASSERT_GT(val1, val2) GTEST_ASSERT_GT(val1, val2) #endif // 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(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) #define EXPECT_STRNE(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define EXPECT_STRCASEEQ(s1, s2) \ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) #define EXPECT_STRCASENE(s1, s2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) #define ASSERT_STREQ(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTREQ, s1, s2) #define ASSERT_STRNE(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRNE, s1, s2) #define ASSERT_STRCASEEQ(s1, s2) \ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASEEQ, s1, s2) #define ASSERT_STRCASENE(s1, s2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperSTRCASENE, s1, s2) // Macros for comparing floating-point numbers. // // * {ASSERT|EXPECT}_FLOAT_EQ(val1, val2): // Tests that two float values are almost equal. // * {ASSERT|EXPECT}_DOUBLE_EQ(val1, val2): // 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(val1, val2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ val1, val2) #define EXPECT_DOUBLE_EQ(val1, val2)\ EXPECT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ val1, val2) #define ASSERT_FLOAT_EQ(val1, val2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ val1, val2) #define ASSERT_DOUBLE_EQ(val1, val2)\ ASSERT_PRED_FORMAT2(::testing::internal::CmpHelperFloatingPointEQ, \ val1, val2) #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)) // Compile-time assertion for type equality. // StaticAssertTypeEq() 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 by // defining objects of that type. // // CAVEAT: // // When used inside a method of a class template, // StaticAssertTypeEq() is effective ONLY IF the method is // instantiated. For example, given: // // template class Foo { // public: // void Bar() { testing::StaticAssertTypeEq(); } // }; // // the code: // // void Test1() { Foo foo; } // // will NOT generate a compiler error, as Foo::Bar() is never // actually instantiated. Instead, you need: // // void Test2() { Foo foo; foo.Bar(); } // // to cause a compiler error. template bool StaticAssertTypeEq() { (void)internal::StaticAssertTypeEqHelper(); 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. // // Test code should appear between braces after an invocation of // 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()) } // namespace testing // Use this function 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(). // // This function was formerly a macro; thus, it is in the global // namespace and has an all-caps name. int RUN_ALL_TESTS() GTEST_MUST_USE_RESULT_; inline int RUN_ALL_TESTS() { return ::testing::UnitTest::GetInstance()->Run(); } #endif // GTEST_INCLUDE_GTEST_GTEST_H_ assimp-4.1.0/contrib/gtest/include/gtest/gtest-death-test.h0000644002537200234200000002640313213503245024157 0ustar zmoelnigiemusers// 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 namespace internal { // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as // Valgrind heap checkers may need this to modify their behavior in death // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. GTEST_API_ bool InDeathTestChild(); } // namespace internal // 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 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) \ GTEST_EXECUTE_STATEMENT_(statement, regex) # define ASSERT_DEBUG_DEATH(statement, regex) \ GTEST_EXECUTE_STATEMENT_(statement, regex) # 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_ assimp-4.1.0/contrib/gtest/include/gtest/gtest-typed-test.h0000644002537200234200000002433313213503245024217 0ustar zmoelnigiemusers// 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 class FooTest : public testing::Test { public: ... typedef std::list 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 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 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 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) # define TYPED_TEST_CASE(CaseName, Types) \ typedef ::testing::internal::TypeList< Types >::type \ GTEST_TYPE_PARAMS_(CaseName) # define TYPED_TEST(CaseName, TestName) \ template \ class GTEST_TEST_CLASS_NAME_(CaseName, TestName) \ : public CaseName { \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ virtual void TestBody(); \ }; \ bool gtest_##CaseName##_##TestName##_registered_ GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::internal::TypeParameterizedTest< \ CaseName, \ ::testing::internal::TemplateSel< \ GTEST_TEST_CLASS_NAME_(CaseName, TestName)>, \ GTEST_TYPE_PARAMS_(CaseName)>::Register(\ "", ::testing::internal::CodeLocation(__FILE__, __LINE__), \ #CaseName, #TestName, 0); \ template \ void GTEST_TEST_CLASS_NAME_(CaseName, TestName)::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 \ class TestName : public CaseName { \ private: \ typedef CaseName TestFixture; \ typedef gtest_TypeParam_ TypeParam; \ virtual void TestBody(); \ }; \ static bool gtest_##TestName##_defined_ GTEST_ATTRIBUTE_UNUSED_ = \ GTEST_TYPED_TEST_CASE_P_STATE_(CaseName).AddTestName(\ __FILE__, __LINE__, #CaseName, #TestName); \ } \ template \ void GTEST_CASE_NAMESPACE_(CaseName)::TestName::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) # define INSTANTIATE_TYPED_TEST_CASE_P(Prefix, CaseName, Types) \ bool gtest_##Prefix##_##CaseName GTEST_ATTRIBUTE_UNUSED_ = \ ::testing::internal::TypeParameterizedTestCase::type>::Register(\ #Prefix, \ ::testing::internal::CodeLocation(__FILE__, __LINE__), \ >EST_TYPED_TEST_CASE_P_STATE_(CaseName), \ #CaseName, GTEST_REGISTERED_TEST_NAMES_(CaseName)) #endif // GTEST_HAS_TYPED_TEST_P #endif // GTEST_INCLUDE_GTEST_GTEST_TYPED_TEST_H_ assimp-4.1.0/contrib/gtest/include/gtest/gtest-test-part.h0000644002537200234200000001455513213503245024045 0ustar zmoelnigiemusers// 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 #include #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 == NULL ? "" : 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_.empty() ? NULL : 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 std::string ExtractSummary(const char* message); // The name of the source file where the test part took place, or // "" if the source file is unknown. std::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_; std::string summary_; // The test failure summary. std::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 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_ assimp-4.1.0/contrib/gtest/src/0000755002537200234200000000000013213503245016631 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/src/gtest-printers.cc0000644002537200234200000003052113213503245022133 0ustar zmoelnigiemusers// 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) // Google Test - The Google C++ Testing Framework // // This file implements a universal value printer that can print a // value of any type T: // // void ::testing::internal::UniversalPrinter::Print(value, ostream_ptr); // // It uses the << operator when possible, and prints the bytes in the // object otherwise. A user can override its behavior for a class // type Foo by defining either operator<<(::std::ostream&, const Foo&) // or void PrintTo(const Foo&, ::std::ostream*) in the namespace that // defines Foo. #include "gtest/gtest-printers.h" #include #include #include #include // NOLINT #include #include "gtest/internal/gtest-port.h" namespace testing { namespace { using ::std::ostream; // Prints a segment of bytes in the given object. GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ void PrintByteSegmentInObjectTo(const unsigned char* obj_bytes, size_t start, size_t count, ostream* os) { char text[5] = ""; for (size_t i = 0; i != count; i++) { const size_t j = start + i; if (i != 0) { // Organizes the bytes into groups of 2 for easy parsing by // human. if ((j % 2) == 0) *os << ' '; else *os << '-'; } GTEST_SNPRINTF_(text, sizeof(text), "%02X", obj_bytes[j]); *os << text; } } // Prints the bytes in the given value to the given ostream. void PrintBytesInObjectToImpl(const unsigned char* obj_bytes, size_t count, ostream* os) { // Tells the user how big the object is. *os << count << "-byte object <"; const size_t kThreshold = 132; const size_t kChunkSize = 64; // If the object size is bigger than kThreshold, we'll have to omit // some details by printing only the first and the last kChunkSize // bytes. // TODO(wan): let the user control the threshold using a flag. if (count < kThreshold) { PrintByteSegmentInObjectTo(obj_bytes, 0, count, os); } else { PrintByteSegmentInObjectTo(obj_bytes, 0, kChunkSize, os); *os << " ... "; // Rounds up to 2-byte boundary. const size_t resume_pos = (count - kChunkSize + 1)/2*2; PrintByteSegmentInObjectTo(obj_bytes, resume_pos, count - resume_pos, os); } *os << ">"; } } // namespace namespace internal2 { // Delegates to PrintBytesInObjectToImpl() to print the bytes in the // given object. The delegation simplifies the implementation, which // uses the << operator and thus is easier done outside of the // ::testing::internal namespace, which contains a << operator that // sometimes conflicts with the one in STL. void PrintBytesInObjectTo(const unsigned char* obj_bytes, size_t count, ostream* os) { PrintBytesInObjectToImpl(obj_bytes, count, os); } } // namespace internal2 namespace internal { // Depending on the value of a char (or wchar_t), we print it in one // of three formats: // - as is if it's a printable ASCII (e.g. 'a', '2', ' '), // - as a hexidecimal escape sequence (e.g. '\x7F'), or // - as a special escape sequence (e.g. '\r', '\n'). enum CharFormat { kAsIs, kHexEscape, kSpecialEscape }; // Returns true if c is a printable ASCII character. We test the // value of c directly instead of calling isprint(), which is buggy on // Windows Mobile. inline bool IsPrintableAscii(wchar_t c) { return 0x20 <= c && c <= 0x7E; } // Prints a wide or narrow char c as a character literal without the // quotes, escaping it when necessary; returns how c was formatted. // The template argument UnsignedChar is the unsigned version of Char, // which is the type of c. template static CharFormat PrintAsCharLiteralTo(Char c, ostream* os) { switch (static_cast(c)) { case L'\0': *os << "\\0"; break; case L'\'': *os << "\\'"; break; case L'\\': *os << "\\\\"; break; case L'\a': *os << "\\a"; break; case L'\b': *os << "\\b"; break; case L'\f': *os << "\\f"; break; case L'\n': *os << "\\n"; break; case L'\r': *os << "\\r"; break; case L'\t': *os << "\\t"; break; case L'\v': *os << "\\v"; break; default: if (IsPrintableAscii(c)) { *os << static_cast(c); return kAsIs; } else { *os << "\\x" + String::FormatHexInt(static_cast(c)); return kHexEscape; } } return kSpecialEscape; } // Prints a wchar_t c as if it's part of a string literal, escaping it when // necessary; returns how c was formatted. static CharFormat PrintAsStringLiteralTo(wchar_t c, ostream* os) { switch (c) { case L'\'': *os << "'"; return kAsIs; case L'"': *os << "\\\""; return kSpecialEscape; default: return PrintAsCharLiteralTo(c, os); } } // Prints a char c as if it's part of a string literal, escaping it when // necessary; returns how c was formatted. static CharFormat PrintAsStringLiteralTo(char c, ostream* os) { return PrintAsStringLiteralTo( static_cast(static_cast(c)), os); } // Prints a wide or narrow character c and its code. '\0' is printed // as "'\\0'", other unprintable characters are also properly escaped // using the standard C++ escape sequence. The template argument // UnsignedChar is the unsigned version of Char, which is the type of c. template void PrintCharAndCodeTo(Char c, ostream* os) { // First, print c as a literal in the most readable form we can find. *os << ((sizeof(c) > 1) ? "L'" : "'"); const CharFormat format = PrintAsCharLiteralTo(c, os); *os << "'"; // To aid user debugging, we also print c's code in decimal, unless // it's 0 (in which case c was printed as '\\0', making the code // obvious). if (c == 0) return; *os << " (" << static_cast(c); // For more convenience, we print c's code again in hexidecimal, // unless c was already printed in the form '\x##' or the code is in // [1, 9]. if (format == kHexEscape || (1 <= c && c <= 9)) { // Do nothing. } else { *os << ", 0x" << String::FormatHexInt(static_cast(c)); } *os << ")"; } void PrintTo(unsigned char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); } void PrintTo(signed char c, ::std::ostream* os) { PrintCharAndCodeTo(c, os); } // Prints a wchar_t as a symbol if it is printable or as its internal // code otherwise and also as its code. L'\0' is printed as "L'\\0'". void PrintTo(wchar_t wc, ostream* os) { PrintCharAndCodeTo(wc, os); } // Prints the given array of characters to the ostream. CharType must be either // char or wchar_t. // The array starts at begin, the length is len, it may include '\0' characters // and may not be NUL-terminated. template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void PrintCharsAsStringTo( const CharType* begin, size_t len, ostream* os) { const char* const kQuoteBegin = sizeof(CharType) == 1 ? "\"" : "L\""; *os << kQuoteBegin; bool is_previous_hex = false; for (size_t index = 0; index < len; ++index) { const CharType cur = begin[index]; if (is_previous_hex && IsXDigit(cur)) { // Previous character is of '\x..' form and this character can be // interpreted as another hexadecimal digit in its number. Break string to // disambiguate. *os << "\" " << kQuoteBegin; } is_previous_hex = PrintAsStringLiteralTo(cur, os) == kHexEscape; } *os << "\""; } // Prints a (const) char/wchar_t array of 'len' elements, starting at address // 'begin'. CharType must be either char or wchar_t. template GTEST_ATTRIBUTE_NO_SANITIZE_MEMORY_ GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ GTEST_ATTRIBUTE_NO_SANITIZE_THREAD_ static void UniversalPrintCharArray( const CharType* begin, size_t len, ostream* os) { // The code // const char kFoo[] = "foo"; // generates an array of 4, not 3, elements, with the last one being '\0'. // // Therefore when printing a char array, we don't print the last element if // it's '\0', such that the output matches the string literal as it's // written in the source code. if (len > 0 && begin[len - 1] == '\0') { PrintCharsAsStringTo(begin, len - 1, os); return; } // If, however, the last element in the array is not '\0', e.g. // const char kFoo[] = { 'f', 'o', 'o' }; // we must print the entire array. We also print a message to indicate // that the array is not NUL-terminated. PrintCharsAsStringTo(begin, len, os); *os << " (no terminating NUL)"; } // Prints a (const) char array of 'len' elements, starting at address 'begin'. void UniversalPrintArray(const char* begin, size_t len, ostream* os) { UniversalPrintCharArray(begin, len, os); } // Prints a (const) wchar_t array of 'len' elements, starting at address // 'begin'. void UniversalPrintArray(const wchar_t* begin, size_t len, ostream* os) { UniversalPrintCharArray(begin, len, os); } // Prints the given C string to the ostream. void PrintTo(const char* s, ostream* os) { if (s == NULL) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; PrintCharsAsStringTo(s, strlen(s), os); } } // MSVC compiler can be configured to define whar_t as a typedef // of unsigned short. Defining an overload for const wchar_t* in that case // would cause pointers to unsigned shorts be printed as wide strings, // possibly accessing more memory than intended and causing invalid // memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when // wchar_t is implemented as a native type. #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // Prints the given wide C string to the ostream. void PrintTo(const wchar_t* s, ostream* os) { if (s == NULL) { *os << "NULL"; } else { *os << ImplicitCast_(s) << " pointing to "; PrintCharsAsStringTo(s, std::wcslen(s), os); } } #endif // wchar_t is native // Prints a ::string object. #if GTEST_HAS_GLOBAL_STRING void PrintStringTo(const ::string& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_GLOBAL_STRING void PrintStringTo(const ::std::string& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } // Prints a ::wstring object. #if GTEST_HAS_GLOBAL_WSTRING void PrintWideStringTo(const ::wstring& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_STD_WSTRING void PrintWideStringTo(const ::std::wstring& s, ostream* os) { PrintCharsAsStringTo(s.data(), s.size(), os); } #endif // GTEST_HAS_STD_WSTRING } // namespace internal } // namespace testing assimp-4.1.0/contrib/gtest/src/gtest.cc0000644002537200234200000057624713213503245020313 0ustar zmoelnigiemusers// 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/internal/custom/gtest.h" #include "gtest/gtest-spi.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include // NOLINT #include #include #if GTEST_OS_LINUX // TODO(kenton@google.com): Use autoconf to detect availability of // gettimeofday(). # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT # include // NOLINT # include // NOLINT // Declares vsnprintf(). This header is not available on Windows. # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT # include #elif GTEST_OS_SYMBIAN # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT #elif GTEST_OS_ZOS # define GTEST_HAS_GETTIMEOFDAY_ 1 # include // NOLINT // On z/OS we additionally need strings.h for strcasecmp. # include // NOLINT #elif GTEST_OS_WINDOWS_MOBILE // We are on Windows CE. # include // NOLINT # undef min #elif GTEST_OS_WINDOWS // We are on Windows proper. # include // NOLINT # include // NOLINT # include // NOLINT # include // 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 // NOLINT # endif // GTEST_OS_WINDOWS_MINGW // cpplint thinks that the header is already included, so we want to // silence it. # include // NOLINT # undef min #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 // NOLINT # include // NOLINT #endif // GTEST_OS_LINUX #if GTEST_HAS_EXCEPTIONS # include #endif #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT # include // NOLINT # include // NOLINT #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 static const char* GetDefaultFilter() { #ifdef GTEST_TEST_FILTER_ENV_VAR_ const char* const testbridge_test_only = getenv(GTEST_TEST_FILTER_ENV_VAR_); if (testbridge_test_only != NULL) { return testbridge_test_only; } #endif // GTEST_TEST_FILTER_ENV_VAR_ return kUniversalFilter; } 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", true), "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 a terminal type that supports colors."); GTEST_DEFINE_string_( filter, internal::StringFromGTestEnv("filter", GetDefaultFilter()), "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_string_( stream_result_to, internal::StringFromGTestEnv("stream_result_to", ""), "This flag specifies the host name and the port number on which to stream " "test results. Example: \"localhost:555\". The flag is effective only on " "Linux."); 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."); #if GTEST_USE_OWN_FLAGFILE_FLAG_ GTEST_DEFINE_string_( flagfile, internal::StringFromGTestEnv("flagfile", ""), "This flag specifies the flagfile to read command-line flags from."); #endif // GTEST_USE_OWN_FLAGFILE_FLAG_ 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(). static bool GTestIsInitialized() { return GetArgvs().size() > 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& 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_API_ GTEST_DEFINE_STATIC_MUTEX_(g_linked_ptr_mutex); // A copy of all command line arguments. Set by InitGoogleTest(). ::std::vector g_argvs; const ::std::vector& GetArgvs() { #if defined(GTEST_CUSTOM_GET_ARGVS_) return GTEST_CUSTOM_GET_ARGVS_(); #else // defined(GTEST_CUSTOM_GET_ARGVS_) return g_argvs; #endif // defined(GTEST_CUSTOM_GET_ARGVS_) } // Returns the current application's name, removing directory path if that // is present. FilePath GetCurrentExecutableName() { FilePath result; #if GTEST_OS_WINDOWS result.Set(FilePath(GetArgvs()[0]).RemoveExtension("exe")); #else result.Set(FilePath(GetArgvs()[0])); #endif // GTEST_OS_WINDOWS return result.RemoveDirectoryName(); } // Functions for processing the gtest_output flag. // Returns the output format, or "" for normal printed output. std::string UnitTestOptions::GetOutputFormat() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return std::string(""); const char* const colon = strchr(gtest_output_flag, ':'); return (colon == NULL) ? std::string(gtest_output_flag) : std::string(gtest_output_flag, colon - gtest_output_flag); } // Returns the name of the requested output file, or the default if none // was explicitly specified. std::string UnitTestOptions::GetAbsolutePathToOutputFile() { const char* const gtest_output_flag = GTEST_FLAG(output).c_str(); if (gtest_output_flag == NULL) return ""; const char* const colon = strchr(gtest_output_flag, ':'); if (colon == NULL) return internal::FilePath::ConcatPaths( internal::FilePath( UnitTest::GetInstance()->original_working_dir()), internal::FilePath(kDefaultOutputFile)).string(); 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.string(); internal::FilePath result(internal::FilePath::GenerateUniqueFileName( output_name, internal::GetCurrentExecutableName(), GetOutputFormat().c_str())); return result.string(); } // 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 std::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++; } } // Returns true iff the user-specified filter matches the test case // name and the test name. bool UnitTestOptions::FilterMatchesTest(const std::string &test_case_name, const std::string &test_name) { const std::string& full_name = test_case_name + "." + 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, '-'); std::string positive; std::string negative; if (dash == NULL) { positive = GTEST_FLAG(filter).c_str(); // Whole string is a positive filter negative = ""; } else { positive = std::string(p, dash); // Everything up to the dash negative = std::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_HAS_SEH // 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 a SEH exception if: // 1. the user wants it to, AND // 2. this is not a breakpoint exception, AND // 3. this is not a C++ exception (VC++ implements them via SEH, // apparently). // // SEH exception code for C++ exceptions. // (see http://support.microsoft.com/kb/185294 for more information). const DWORD kCxxExceptionCode = 0xe06d7363; bool should_handle = true; if (!GTEST_FLAG(catch_exceptions)) should_handle = false; else if (exception_code == EXCEPTION_BREAKPOINT) should_handle = false; else if (exception_code == kCxxExceptionCode) should_handle = false; return should_handle ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH; } #endif // GTEST_HAS_SEH } // 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(); } // 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 string& substr) { const std::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) { return AssertionFailure() << "Expected: " << expected << "\n" << " Actual:\n" << r; } if (strstr(r.message(), substr.c_str()) == NULL) { return AssertionFailure() << "Expected: " << expected << " containing \"" << substr << "\"\n" << " Actual:\n" << r; } 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 string& 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_); } 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(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 that will be reported in the XML report. int UnitTestImpl::reportable_disabled_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::reportable_disabled_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 tests to be printed in the XML report. int UnitTestImpl::reportable_test_count() const { return SumOverTestCaseList(test_cases_, &TestCase::reportable_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 an std::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. std::string UnitTestImpl::CurrentOsStackTraceExceptTop(int skip_count) { return os_stack_trace_getter()->CurrentStackTrace( static_cast(GTEST_FLAG(stack_trace_depth)), skip_count + 1 // Skips the user-specified number of frames plus this function // itself. ); // NOLINT } // 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(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; // MSVC 8 deprecates _ftime64(), so we want to suppress warning 4996 // (deprecated function) there. // TODO(kenton@google.com): Use GetTickCount()? Or use // SystemTimeToFileTime() GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) _ftime64(&now); GTEST_DISABLE_MSC_WARNINGS_POP_() return static_cast(now.time) * 1000 + now.millitm; #elif GTEST_HAS_GETTIMEOFDAY_ struct timeval now; gettimeofday(&now, NULL); return static_cast(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. #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) { for (size_t i = 0; i != length; ) { // NOLINT if (wstr[i] != L'\0') { *msg << WideStringToUtf8(wstr + i, static_cast(length - i)); while (i != length && wstr[i] != L'\0') i++; } else { *msg << '\0'; i++; } } } #endif // GTEST_HAS_STD_WSTRING || GTEST_HAS_GLOBAL_WSTRING 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); } } // namespace internal // Constructs an empty Message. // We allocate the stringstream separately because 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::Message() : ss_(new ::std::stringstream) { // By default, we want there to be enough precision when printing // a double to a Message. *ss_ << std::setprecision(std::numeric_limits::digits10 + 2); } // These two overloads allow streaming a wide C string to a Message // using the UTF-8 encoding. Message& Message::operator <<(const wchar_t* wide_c_str) { return *this << internal::String::ShowWideCString(wide_c_str); } Message& 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& 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 // Gets the text streamed to this object so far as an std::string. // Each '\0' character in the buffer is replaced with "\\0". std::string Message::GetString() const { return internal::StringStreamToString(ss_.get()); } // AssertionResult constructors. // Used in EXPECT_TRUE/FALSE(assertion_result). AssertionResult::AssertionResult(const AssertionResult& other) : success_(other.success_), message_(other.message_.get() != NULL ? new ::std::string(*other.message_) : static_cast< ::std::string*>(NULL)) { } // Swaps two AssertionResults. void AssertionResult::swap(AssertionResult& other) { using std::swap; swap(success_, other.success_); swap(message_, other.message_); } // 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 { namespace edit_distance { std::vector CalculateOptimalEdits(const std::vector& left, const std::vector& right) { std::vector > costs( left.size() + 1, std::vector(right.size() + 1)); std::vector > best_move( left.size() + 1, std::vector(right.size() + 1)); // Populate for empty right. for (size_t l_i = 0; l_i < costs.size(); ++l_i) { costs[l_i][0] = static_cast(l_i); best_move[l_i][0] = kRemove; } // Populate for empty left. for (size_t r_i = 1; r_i < costs[0].size(); ++r_i) { costs[0][r_i] = static_cast(r_i); best_move[0][r_i] = kAdd; } for (size_t l_i = 0; l_i < left.size(); ++l_i) { for (size_t r_i = 0; r_i < right.size(); ++r_i) { if (left[l_i] == right[r_i]) { // Found a match. Consume it. costs[l_i + 1][r_i + 1] = costs[l_i][r_i]; best_move[l_i + 1][r_i + 1] = kMatch; continue; } const double add = costs[l_i + 1][r_i]; const double remove = costs[l_i][r_i + 1]; const double replace = costs[l_i][r_i]; if (add < remove && add < replace) { costs[l_i + 1][r_i + 1] = add + 1; best_move[l_i + 1][r_i + 1] = kAdd; } else if (remove < add && remove < replace) { costs[l_i + 1][r_i + 1] = remove + 1; best_move[l_i + 1][r_i + 1] = kRemove; } else { // We make replace a little more expensive than add/remove to lower // their priority. costs[l_i + 1][r_i + 1] = replace + 1.00001; best_move[l_i + 1][r_i + 1] = kReplace; } } } // Reconstruct the best path. We do it in reverse order. std::vector best_path; for (size_t l_i = left.size(), r_i = right.size(); l_i > 0 || r_i > 0;) { EditType move = best_move[l_i][r_i]; best_path.push_back(move); l_i -= move != kAdd; r_i -= move != kRemove; } std::reverse(best_path.begin(), best_path.end()); return best_path; } namespace { // Helper class to convert string into ids with deduplication. class InternalStrings { public: size_t GetId(const std::string& str) { IdMap::iterator it = ids_.find(str); if (it != ids_.end()) return it->second; size_t id = ids_.size(); return ids_[str] = id; } private: typedef std::map IdMap; IdMap ids_; }; } // namespace std::vector CalculateOptimalEdits( const std::vector& left, const std::vector& right) { std::vector left_ids, right_ids; { InternalStrings intern_table; for (size_t i = 0; i < left.size(); ++i) { left_ids.push_back(intern_table.GetId(left[i])); } for (size_t i = 0; i < right.size(); ++i) { right_ids.push_back(intern_table.GetId(right[i])); } } return CalculateOptimalEdits(left_ids, right_ids); } namespace { // Helper class that holds the state for one hunk and prints it out to the // stream. // It reorders adds/removes when possible to group all removes before all // adds. It also adds the hunk header before printint into the stream. class Hunk { public: Hunk(size_t left_start, size_t right_start) : left_start_(left_start), right_start_(right_start), adds_(), removes_(), common_() {} void PushLine(char edit, const char* line) { switch (edit) { case ' ': ++common_; FlushEdits(); hunk_.push_back(std::make_pair(' ', line)); break; case '-': ++removes_; hunk_removes_.push_back(std::make_pair('-', line)); break; case '+': ++adds_; hunk_adds_.push_back(std::make_pair('+', line)); break; } } void PrintTo(std::ostream* os) { PrintHeader(os); FlushEdits(); for (std::list >::const_iterator it = hunk_.begin(); it != hunk_.end(); ++it) { *os << it->first << it->second << "\n"; } } bool has_edits() const { return adds_ || removes_; } private: void FlushEdits() { hunk_.splice(hunk_.end(), hunk_removes_); hunk_.splice(hunk_.end(), hunk_adds_); } // Print a unified diff header for one hunk. // The format is // "@@ -, +, @@" // where the left/right parts are ommitted if unnecessary. void PrintHeader(std::ostream* ss) const { *ss << "@@ "; if (removes_) { *ss << "-" << left_start_ << "," << (removes_ + common_); } if (removes_ && adds_) { *ss << " "; } if (adds_) { *ss << "+" << right_start_ << "," << (adds_ + common_); } *ss << " @@\n"; } size_t left_start_, right_start_; size_t adds_, removes_, common_; std::list > hunk_, hunk_adds_, hunk_removes_; }; } // namespace // Create a list of diff hunks in Unified diff format. // Each hunk has a header generated by PrintHeader above plus a body with // lines prefixed with ' ' for no change, '-' for deletion and '+' for // addition. // 'context' represents the desired unchanged prefix/suffix around the diff. // If two hunks are close enough that their contexts overlap, then they are // joined into one hunk. std::string CreateUnifiedDiff(const std::vector& left, const std::vector& right, size_t context) { const std::vector edits = CalculateOptimalEdits(left, right); size_t l_i = 0, r_i = 0, edit_i = 0; std::stringstream ss; while (edit_i < edits.size()) { // Find first edit. while (edit_i < edits.size() && edits[edit_i] == kMatch) { ++l_i; ++r_i; ++edit_i; } // Find the first line to include in the hunk. const size_t prefix_context = std::min(l_i, context); Hunk hunk(l_i - prefix_context + 1, r_i - prefix_context + 1); for (size_t i = prefix_context; i > 0; --i) { hunk.PushLine(' ', left[l_i - i].c_str()); } // Iterate the edits until we found enough suffix for the hunk or the input // is over. size_t n_suffix = 0; for (; edit_i < edits.size(); ++edit_i) { if (n_suffix >= context) { // Continue only if the next hunk is very close. std::vector::const_iterator it = edits.begin() + edit_i; while (it != edits.end() && *it == kMatch) ++it; if (it == edits.end() || (it - edits.begin()) - edit_i >= context) { // There is no next edit or it is too far away. break; } } EditType edit = edits[edit_i]; // Reset count when a non match is found. n_suffix = edit == kMatch ? n_suffix + 1 : 0; if (edit == kMatch || edit == kRemove || edit == kReplace) { hunk.PushLine(edit == kMatch ? ' ' : '-', left[l_i].c_str()); } if (edit == kAdd || edit == kReplace) { hunk.PushLine('+', right[r_i].c_str()); } // Advance indices, depending on edit type. l_i += edit != kAdd; r_i += edit != kRemove; } if (!hunk.has_edits()) { // We are done. We don't want this hunk. break; } hunk.PrintTo(&ss); } return ss.str(); } } // namespace edit_distance namespace { // The string representation of the values received in EqFailure() are already // escaped. Split them on escaped '\n' boundaries. Leave all other escaped // characters the same. std::vector SplitEscapedString(const std::string& str) { std::vector lines; size_t start = 0, end = str.size(); if (end > 2 && str[0] == '"' && str[end - 1] == '"') { ++start; --end; } bool escaped = false; for (size_t i = start; i + 1 < end; ++i) { if (escaped) { escaped = false; if (str[i] == 'n') { lines.push_back(str.substr(start, i - start - 1)); start = i + 1; } } else { escaped = str[i] == '\\'; } } lines.push_back(str.substr(start, end - start)); return lines; } } // namespace // 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: // // lhs_expression: "foo" // rhs_expression: "bar" // lhs_value: "5" // rhs_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* lhs_expression, const char* rhs_expression, const std::string& lhs_value, const std::string& rhs_value, bool ignoring_case) { Message msg; msg << " Expected: " << lhs_expression; if (lhs_value != lhs_expression) { msg << "\n Which is: " << lhs_value; } msg << "\nTo be equal to: " << rhs_expression; if (rhs_value != rhs_expression) { msg << "\n Which is: " << rhs_value; } if (ignoring_case) { msg << "\nIgnoring case"; } if (!lhs_value.empty() && !rhs_value.empty()) { const std::vector lhs_lines = SplitEscapedString(lhs_value); const std::vector rhs_lines = SplitEscapedString(rhs_value); if (lhs_lines.size() > 1 || rhs_lines.size() > 1) { msg << "\nWith diff:\n" << edit_distance::CreateUnifiedDiff(lhs_lines, rhs_lines); } } return AssertionFailure() << msg; } // Constructs a failure message for Boolean assertions such as EXPECT_TRUE. std::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. return AssertionFailure() << "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 << "."; } // Helper template for implementing FloatLE() and DoubleLE(). template 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 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. ::std::stringstream val1_ss; val1_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val1; ::std::stringstream val2_ss; val2_ss << std::setprecision(std::numeric_limits::digits10 + 2) << val2; return AssertionFailure() << "Expected: (" << expr1 << ") <= (" << expr2 << ")\n" << " Actual: " << StringStreamToString(&val1_ss) << " vs " << StringStreamToString(&val2_ss); } } // 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(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(expr1, expr2, val1, val2); } namespace internal { // The helper function for {ASSERT|EXPECT}_EQ with int or enum // arguments. AssertionResult CmpHelperEQ(const char* lhs_expression, const char* rhs_expression, BiggestInt lhs, BiggestInt rhs) { if (lhs == rhs) { return AssertionSuccess(); } return EqFailure(lhs_expression, rhs_expression, FormatForComparisonFailureMessage(lhs, rhs), FormatForComparisonFailureMessage(rhs, lhs), 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 {\ return AssertionFailure() \ << "Expected: (" << expr1 << ") " #op " (" << expr2\ << "), actual: " << FormatForComparisonFailureMessage(val1, val2)\ << " vs " << FormatForComparisonFailureMessage(val2, val1);\ }\ } // 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* lhs_expression, const char* rhs_expression, const char* lhs, const char* rhs) { if (String::CStringEquals(lhs, rhs)) { return AssertionSuccess(); } return EqFailure(lhs_expression, rhs_expression, PrintToString(lhs), PrintToString(rhs), false); } // The helper function for {ASSERT|EXPECT}_STRCASEEQ. AssertionResult CmpHelperSTRCASEEQ(const char* lhs_expression, const char* rhs_expression, const char* lhs, const char* rhs) { if (String::CaseInsensitiveCStringEquals(lhs, rhs)) { return AssertionSuccess(); } return EqFailure(lhs_expression, rhs_expression, PrintToString(lhs), PrintToString(rhs), 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 { return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } // 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 { return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << ") (ignoring case), actual: \"" << s1 << "\" vs \"" << s2 << "\""; } } } // 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 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 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() << "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; // 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 std::string error_hex("0x" + String::FormatHexInt(hr)); return ::testing::AssertionFailure() << "Expected: " << expr << " " << expected << ".\n" << " Actual: " << error_hex << " " << error_text << "\n"; } } // 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(1) << 7) - 1; // The maximum code-point a two-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint2 = (static_cast(1) << (5 + 6)) - 1; // The maximum code-point a three-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint3 = (static_cast(1) << (4 + 2*6)) - 1; // The maximum code-point a four-byte UTF-8 sequence can represent. const UInt32 kMaxCodePoint4 = (static_cast(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(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. // 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 converted // to "(Invalid Unicode 0xXXXXXXXX)". std::string CodePointToUtf8(UInt32 code_point) { if (code_point > kMaxCodePoint4) { return "(Invalid Unicode 0x" + String::FormatHexInt(code_point) + ")"; } char str[5]; // Big enough for the largest valid code point. if (code_point <= kMaxCodePoint1) { str[1] = '\0'; str[0] = static_cast(code_point); // 0xxxxxxx } else if (code_point <= kMaxCodePoint2) { str[2] = '\0'; str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xC0 | code_point); // 110xxxxx } else if (code_point <= kMaxCodePoint3) { str[3] = '\0'; str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xE0 | code_point); // 1110xxxx } else { // code_point <= kMaxCodePoint4 str[4] = '\0'; str[3] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[2] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[1] = static_cast(0x80 | ChopLowBits(&code_point, 6)); // 10xxxxxx str[0] = static_cast(0xF0 | code_point); // 11110xxx } 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(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. std::string WideStringToUtf8(const wchar_t* str, int num_chars) { if (num_chars == -1) num_chars = static_cast(wcslen(str)); ::std::stringstream 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(str[i]); } stream << CodePointToUtf8(unicode_code_point); } return StringStreamToString(&stream); } // Converts a wide C string to an std::string using the UTF-8 encoding. // NULL will be converted to "(null)". std::string String::ShowWideCString(const wchar_t * wide_c_str) { if (wide_c_str == NULL) return "(null)"; return internal::WideStringToUtf8(wide_c_str, -1); } // 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* lhs_expression, const char* rhs_expression, const wchar_t* lhs, const wchar_t* rhs) { if (String::WideCStringEquals(lhs, rhs)) { return AssertionSuccess(); } return EqFailure(lhs_expression, rhs_expression, PrintToString(lhs), PrintToString(rhs), 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(); } return AssertionFailure() << "Expected: (" << s1_expression << ") != (" << s2_expression << "), actual: " << PrintToString(s1) << " vs " << PrintToString(s2); } // 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 && !GTEST_OS_LINUX_ANDROID return wcscasecmp(lhs, rhs) == 0; #else // Android, 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 } // Returns true iff str ends with the given suffix, ignoring case. // Any string is considered to end with an empty suffix. bool String::EndsWithCaseInsensitive( const std::string& str, const std::string& suffix) { const size_t str_len = str.length(); const size_t suffix_len = suffix.length(); return (str_len >= suffix_len) && CaseInsensitiveCStringEquals(str.c_str() + str_len - suffix_len, suffix.c_str()); } // Formats an int value as "%02d". std::string String::FormatIntWidth2(int value) { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << value; return ss.str(); } // Formats an int value as "%X". std::string String::FormatHexInt(int value) { std::stringstream ss; ss << std::hex << std::uppercase << value; return ss.str(); } // Formats a byte as "%02X". std::string String::FormatByte(unsigned char value) { std::stringstream ss; ss << std::setfill('0') << std::setw(2) << std::hex << std::uppercase << static_cast(value); return ss.str(); } // Converts the buffer in a stringstream to an std::string, converting NUL // bytes to "\\0" along the way. std::string StringStreamToString(::std::stringstream* ss) { const ::std::string& str = ss->str(); const char* const start = str.c_str(); const char* const end = start + str.length(); std::string result; result.reserve(2 * (end - start)); for (const char* ch = start; ch != end; ++ch) { if (*ch == '\0') { result += "\\0"; // Replaces NUL with "\\0"; } else { result += *ch; } } return result; } // Appends the user-supplied message to the Google-Test-generated message. std::string AppendUserMessage(const std::string& gtest_msg, const Message& user_msg) { // Appends the user message if it's non-empty. const std::string user_msg_string = user_msg.GetString(); if (user_msg_string.empty()) { return gtest_msg; } return gtest_msg + "\n" + user_msg_string; } } // 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 std::string& xml_element, const TestProperty& test_property) { if (!ValidateTestProperty(xml_element, test_property)) { return; } internal::MutexLock lock(&test_properites_mutex_); const std::vector::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()); } // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuitesAttributes[] = { "disabled", "errors", "failures", "name", "random_seed", "tests", "time", "timestamp" }; // The list of reserved attributes used in the element of XML // output. static const char* const kReservedTestSuiteAttributes[] = { "disabled", "errors", "failures", "name", "tests", "time" }; // The list of reserved attributes used in the element of XML output. static const char* const kReservedTestCaseAttributes[] = { "classname", "name", "status", "time", "type_param", "value_param" }; template std::vector ArrayAsVector(const char* const (&array)[kSize]) { return std::vector(array, array + kSize); } static std::vector GetReservedAttributesForElement( const std::string& xml_element) { if (xml_element == "testsuites") { return ArrayAsVector(kReservedTestSuitesAttributes); } else if (xml_element == "testsuite") { return ArrayAsVector(kReservedTestSuiteAttributes); } else if (xml_element == "testcase") { return ArrayAsVector(kReservedTestCaseAttributes); } else { GTEST_CHECK_(false) << "Unrecognized xml_element provided: " << xml_element; } // This code is unreachable but some compilers may not realizes that. return std::vector(); } static std::string FormatWordList(const std::vector& words) { Message word_list; for (size_t i = 0; i < words.size(); ++i) { if (i > 0 && words.size() > 2) { word_list << ", "; } if (i == words.size() - 1) { word_list << "and "; } word_list << "'" << words[i] << "'"; } return word_list.GetString(); } bool ValidateTestPropertyName(const std::string& property_name, const std::vector& reserved_names) { if (std::find(reserved_names.begin(), reserved_names.end(), property_name) != reserved_names.end()) { ADD_FAILURE() << "Reserved key used in RecordProperty(): " << property_name << " (" << FormatWordList(reserved_names) << " are reserved by " << GTEST_NAME_ << ")"; return false; } return true; } // Adds a failure if the key is a reserved attribute of the element named // xml_element. Returns true if the property is valid. bool TestResult::ValidateTestProperty(const std::string& xml_element, const TestProperty& test_property) { return ValidateTestPropertyName(test_property.key(), GetReservedAttributesForElement(xml_element)); } // 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(test_part_results_.size()); } // Returns the number of the test properties. int TestResult::test_property_count() const { return static_cast(test_properties_.size()); } // class Test // Creates a Test object. // The c'tor saves the states of all flags. Test::Test() : gtest_flag_saver_(new GTEST_FLAG_SAVER_) { } // The d'tor restores the states of all flags. The actual work is // done by the d'tor of the gtest_flag_saver_ field, and thus not // visible here. Test::~Test() { } // 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 std::string& key, const std::string& value) { UnitTest::GetInstance()->RecordProperty(key, value); } // Allows user supplied key value pairs to be recorded for later output. void Test::RecordProperty(const std::string& 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 std::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, ""); // No stack trace, either. } } // namespace internal // 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 TestInfo* const first_test_info = test_case->test_info_list()[0]; 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 TestInfo* const this_test_info = impl->current_test_info(); 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) { // Both TEST and TEST_F appear in same test case, which is incorrect. // Tell the user how to fix this. // 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 { // Two fixture classes with the same name appear in two different // namespaces, which is not allowed. Tell the user how to fix this. 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; } #if GTEST_HAS_SEH // Adds an "exception thrown" fatal failure to the current test. This // function returns its result via an output parameter pointer because VC++ // prohibits creation of objects with destructors on stack in functions // using __try (see error C2712). static std::string* FormatSehExceptionMessage(DWORD exception_code, const char* location) { Message message; message << "SEH exception with code 0x" << std::setbase(16) << exception_code << std::setbase(10) << " thrown in " << location << "."; return new std::string(message.GetString()); } #endif // GTEST_HAS_SEH namespace internal { #if GTEST_HAS_EXCEPTIONS // Adds an "exception thrown" fatal failure to the current test. static std::string FormatCxxExceptionMessage(const char* description, const char* location) { Message message; if (description != NULL) { message << "C++ exception with description \"" << description << "\""; } else { message << "Unknown C++ exception"; } message << " thrown in " << location << "."; return message.GetString(); } static std::string PrintTestPartResultToString( const TestPartResult& test_part_result); GoogleTestFailureException::GoogleTestFailureException( const TestPartResult& failure) : ::std::runtime_error(PrintTestPartResultToString(failure).c_str()) {} #endif // GTEST_HAS_EXCEPTIONS // We put these helper functions in the internal namespace as IBM's xlC // compiler rejects the code if they were declared static. // Runs the given method and handles SEH exceptions it throws, when // SEH is supported; returns the 0-value for type Result in case of an // SEH exception. (Microsoft compilers cannot handle SEH and C++ // exceptions in the same function. Therefore, we provide a separate // wrapper function for handling SEH exceptions.) template Result HandleSehExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { #if GTEST_HAS_SEH __try { return (object->*method)(); } __except (internal::UnitTestOptions::GTestShouldProcessSEH( // NOLINT GetExceptionCode())) { // We create the exception message on the heap because VC++ prohibits // creation of objects with destructors on stack in functions using __try // (see error C2712). std::string* exception_message = FormatSehExceptionMessage( GetExceptionCode(), location); internal::ReportFailureInUnknownLocation(TestPartResult::kFatalFailure, *exception_message); delete exception_message; return static_cast(0); } #else (void)location; return (object->*method)(); #endif // GTEST_HAS_SEH } // Runs the given method and catches and reports C++ and/or SEH-style // exceptions, if they are supported; returns the 0-value for type // Result in case of an SEH exception. template Result HandleExceptionsInMethodIfSupported( T* object, Result (T::*method)(), const char* location) { // NOTE: The user code can affect the way in which Google Test handles // exceptions by setting GTEST_FLAG(catch_exceptions), but only before // RUN_ALL_TESTS() starts. It is technically possible to check the flag // after the exception is caught and either report or re-throw the // exception based on the flag's value: // // try { // // Perform the test method. // } catch (...) { // if (GTEST_FLAG(catch_exceptions)) // // Report the exception as failure. // else // throw; // Re-throws the original exception. // } // // However, the purpose of this flag is to allow the program to drop into // the debugger when the exception is thrown. On most platforms, once the // control enters the catch block, the exception origin information is // lost and the debugger will stop the program at the point of the // re-throw in this function -- instead of at the point of the original // throw statement in the code under test. For this reason, we perform // the check early, sacrificing the ability to affect Google Test's // exception handling in the method where the exception is thrown. if (internal::GetUnitTestImpl()->catch_exceptions()) { #if GTEST_HAS_EXCEPTIONS try { return HandleSehExceptionsInMethodIfSupported(object, method, location); } catch (const internal::GoogleTestFailureException&) { // NOLINT // This exception type can only be thrown by a failed Google // Test assertion with the intention of letting another testing // framework catch it. Therefore we just re-throw it. throw; } catch (const std::exception& e) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(e.what(), location)); } catch (...) { // NOLINT internal::ReportFailureInUnknownLocation( TestPartResult::kFatalFailure, FormatCxxExceptionMessage(NULL, location)); } return static_cast(0); #else return HandleSehExceptionsInMethodIfSupported(object, method, location); #endif // GTEST_HAS_EXCEPTIONS } else { return (object->*method)(); } } } // namespace internal // Runs the test and updates the test result. void Test::Run() { if (!HasSameFixtureClass()) return; internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported(this, &Test::SetUp, "SetUp()"); // We will run the test only if SetUp() was successful. if (!HasFatalFailure()) { impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TestBody, "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(); internal::HandleExceptionsInMethodIfSupported( this, &Test::TearDown, "TearDown()"); } // 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. TestInfo::TestInfo(const std::string& a_test_case_name, const std::string& a_name, const char* a_type_param, const char* a_value_param, internal::CodeLocation a_code_location, internal::TypeId fixture_class_id, internal::TestFactoryBase* factory) : test_case_name_(a_test_case_name), name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : NULL), value_param_(a_value_param ? new std::string(a_value_param) : NULL), location_(a_code_location), fixture_class_id_(fixture_class_id), should_run_(false), is_disabled_(false), matches_filter_(false), factory_(factory), result_() {} // Destructs a TestInfo object. TestInfo::~TestInfo() { delete factory_; } 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 // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // value_param: text representation of the test's value parameter, // or NULL if this is not a value-parameterized test. // code_location: code location where the test is defined // 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* type_param, const char* value_param, CodeLocation code_location, TypeId fixture_class_id, SetUpTestCaseFunc set_up_tc, TearDownTestCaseFunc tear_down_tc, TestFactoryBase* factory) { TestInfo* const test_info = new TestInfo(test_case_name, name, type_param, value_param, code_location, 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, CodeLocation code_location) { 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(code_location.file.c_str(), code_location.line).c_str(), errors.GetString().c_str()); } #endif // GTEST_HAS_PARAM_TEST } // namespace internal 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 && test_info->name() == name_; } private: std::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 } } // namespace internal // Creates the test object, runs it, records its result, and then // deletes it. void TestInfo::Run() { if (!should_run_) return; // Tells UnitTest where to store test result. internal::UnitTestImpl* const impl = internal::GetUnitTestImpl(); impl->set_current_test_info(this); TestEventListener* repeater = UnitTest::GetInstance()->listeners().repeater(); // Notifies the unit test event listeners that a test is about to start. repeater->OnTestStart(*this); const TimeInMillis start = internal::GetTimeInMillis(); impl->os_stack_trace_getter()->UponLeavingGTest(); // Creates the test object. Test* const test = internal::HandleExceptionsInMethodIfSupported( factory_, &internal::TestFactoryBase::CreateTest, "the test fixture's constructor"); // Runs the test only if the test object was created and its // constructor didn't generate a fatal failure. if ((test != NULL) && !Test::HasFatalFailure()) { // This doesn't throw as all user code that can throw are wrapped into // exception handling code. test->Run(); } // Deletes the test object. impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( test, &Test::DeleteSelf_, "the test fixture's destructor"); result_.set_elapsed_time(internal::GetTimeInMillis() - start); // Notifies the unit test event listener that a test has just finished. repeater->OnTestEnd(*this); // Tells UnitTest to stop associating assertion results to this // test. impl->set_current_test_info(NULL); } // 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); } // Gets the number of disabled tests that will be reported in the XML report. int TestCase::reportable_disabled_test_count() const { return CountIf(test_info_list_, TestReportableDisabled); } // Gets the number of disabled tests in this test case. int TestCase::disabled_test_count() const { return CountIf(test_info_list_, TestDisabled); } // Gets the number of tests to be printed in the XML report. int TestCase::reportable_test_count() const { return CountIf(test_info_list_, TestReportable); } // 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(test_info_list_.size()); } // Creates a TestCase with the given name. // // Arguments: // // name: name of the test case // a_type_param: the name of the test case's type parameter, or NULL if // this is not a typed or a type-parameterized 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_type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) : name_(a_name), type_param_(a_type_param ? new std::string(a_type_param) : NULL), 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); } // 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(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(); internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunSetUpTestCase, "SetUpTestCase()"); const internal::TimeInMillis start = internal::GetTimeInMillis(); for (int i = 0; i < total_test_count(); i++) { GetMutableTestInfo(i)->Run(); } elapsed_time_ = internal::GetTimeInMillis() - start; impl->os_stack_trace_getter()->UponLeavingGTest(); internal::HandleExceptionsInMethodIfSupported( this, &TestCase::RunTearDownTestCase, "TearDownTestCase()"); repeater->OnTestCaseEnd(*this); impl->set_current_test_case(NULL); } // Clears the results of all tests in this test case. void TestCase::ClearResult() { ad_hoc_test_result_.Clear(); ForEach(test_info_list_, TestInfo::ClearTestResult); } // 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(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 std::string FormatCountableNoun(int count, const char * singular_form, const char * plural_form) { return internal::StreamableToString(count) + " " + (count == 1 ? singular_form : plural_form); } // Formats the count of tests. static std::string FormatTestCount(int test_count) { return FormatCountableNoun(test_count, "test", "tests"); } // Formats the count of test cases. static std::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 default: return "Unknown result type"; } } namespace internal { // Prints a TestPartResult to an std::string. static std::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 std::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 enum GTestColor { COLOR_DEFAULT, COLOR_RED, COLOR_GREEN, COLOR_YELLOW }; #if GTEST_OS_WINDOWS && !GTEST_OS_WINDOWS_MOBILE && \ !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // 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, "screen") || String::CStringEquals(term, "screen-256color") || String::CStringEquals(term, "tmux") || String::CStringEquals(term, "tmux-256color") || String::CStringEquals(term, "rxvt-unicode") || String::CStringEquals(term, "rxvt-unicode-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 || \ GTEST_OS_IOS || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT const bool use_color = AlwaysFalse(); #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 && \ !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT 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); } // Text printed in Google Test's text output and --gunit_list_tests // output to label the type parameter and value parameter for a test. static const char kTypeParamLabel[] = "TypeParam"; static const char kValueParamLabel[] = "GetParam()"; void PrintFullTestCommentIfPresent(const TestInfo& test_info) { const char* const type_param = test_info.type_param(); const char* const value_param = test_info.value_param(); if (type_param != NULL || value_param != NULL) { printf(", where "); if (type_param != NULL) { printf("%s = %s", kTypeParamLabel, type_param); if (value_param != NULL) printf(" and "); } if (value_param != NULL) { printf("%s = %s", kValueParamLabel, value_param); } } } // 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); }; // 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 (!String::CStringEquals(filter, kUniversalFilter)) { ColoredPrintf(COLOR_YELLOW, "Note: %s filter = %s\n", GTEST_NAME_, filter); } if (internal::ShouldShard(kTestTotalShards, kTestShardIndex, false)) { const Int32 shard_index = Int32FromEnvOrDie(kTestShardIndex, -1); ColoredPrintf(COLOR_YELLOW, "Note: This is test shard %d of %s.\n", static_cast(shard_index) + 1, 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) { const std::string counts = FormatCountableNoun(test_case.test_to_run_count(), "test", "tests"); ColoredPrintf(COLOR_GREEN, "[----------] "); printf("%s from %s", counts.c_str(), test_case.name()); if (test_case.type_param() == NULL) { printf("\n"); } else { printf(", where %s = %s\n", kTypeParamLabel, test_case.type_param()); } fflush(stdout); } void PrettyUnitTestResultPrinter::OnTestStart(const TestInfo& test_info) { ColoredPrintf(COLOR_GREEN, "[ RUN ] "); PrintTestName(test_info.test_case_name(), test_info.name()); printf("\n"); 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_info.test_case_name(), test_info.name()); if (test_info.result()->Failed()) PrintFullTestCommentIfPresent(test_info); 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; const std::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(), 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()); PrintFullTestCommentIfPresent(test_info); printf("\n"); } } } 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.reportable_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 listeners_; GTEST_DISALLOW_COPY_AND_ASSIGN_(TestEventRepeater); }; TestEventRepeater::~TestEventRepeater() { ForEach(listeners_, Delete); } 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(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(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 std::string EscapeXml(const std::string& str, bool is_attribute); // Returns the given string with all characters invalid in XML removed. static std::string RemoveInvalidXmlCharacters(const std::string& str); // Convenience wrapper around EscapeXml when str is an attribute value. static std::string EscapeXmlAttribute(const std::string& str) { return EscapeXml(str, true); } // Convenience wrapper around EscapeXml when str is not an attribute value. static std::string EscapeXmlText(const char* str) { return EscapeXml(str, false); } // Verifies that the given attribute belongs to the given element and // streams the attribute as XML. static void OutputXmlAttribute(std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value); // 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(::std::ostream* stream, const TestCase& test_case); // Prints an XML summary of unit_test to output stream out. static void PrintXmlUnitTest(::std::ostream* stream, 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 std::string is not empty, it includes a space at the beginning, // to delimit this attribute from prior attributes. static std::string TestPropertiesAsXmlAttributes(const TestResult& result); // The output file. const std::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); } std::stringstream stream; PrintXmlUnitTest(&stream, unit_test); fprintf(xmlout, "%s", StringStreamToString(&stream).c_str()); 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. std::string XmlUnitTestResultPrinter::EscapeXml( const std::string& str, bool is_attribute) { Message m; for (size_t i = 0; i < str.size(); ++i) { const char ch = str[i]; switch (ch) { case '<': m << "<"; break; case '>': m << ">"; break; case '&': m << "&"; break; case '\'': if (is_attribute) m << "'"; else m << '\''; break; case '"': if (is_attribute) m << """; else m << '"'; break; default: if (IsValidXmlCharacter(ch)) { if (is_attribute && IsNormalizableWhitespace(ch)) m << "&#x" << String::FormatByte(static_cast(ch)) << ";"; else m << ch; } 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 ?. std::string XmlUnitTestResultPrinter::RemoveInvalidXmlCharacters( const std::string& str) { std::string output; output.reserve(str.size()); for (std::string::const_iterator it = str.begin(); it != str.end(); ++it) if (IsValidXmlCharacter(*it)) output.push_back(*it); return output; } // The following routines generate an XML representation of a UnitTest // object. // // This is how Google Test concepts map to the DTD: // // <-- corresponds to a UnitTest object // <-- corresponds to a TestCase object // <-- corresponds to a TestInfo object // ... // ... // ... // <-- individual assertion failures // // // // Formats the given time in milliseconds as seconds. std::string FormatTimeInMillisAsSeconds(TimeInMillis ms) { ::std::stringstream ss; ss << (static_cast(ms) * 1e-3); return ss.str(); } static bool PortableLocaltime(time_t seconds, struct tm* out) { #if defined(_MSC_VER) return localtime_s(out, &seconds) == 0; #elif defined(__MINGW32__) || defined(__MINGW64__) // MINGW provides neither localtime_r nor localtime_s, but uses // Windows' localtime(), which has a thread-local tm buffer. struct tm* tm_ptr = localtime(&seconds); // NOLINT if (tm_ptr == NULL) return false; *out = *tm_ptr; return true; #else return localtime_r(&seconds, out) != NULL; #endif } // Converts the given epoch time in milliseconds to a date string in the ISO // 8601 format, without the timezone information. std::string FormatEpochTimeInMillisAsIso8601(TimeInMillis ms) { struct tm time_struct; if (!PortableLocaltime(static_cast(ms / 1000), &time_struct)) return ""; // YYYY-MM-DDThh:mm:ss return StreamableToString(time_struct.tm_year + 1900) + "-" + String::FormatIntWidth2(time_struct.tm_mon + 1) + "-" + String::FormatIntWidth2(time_struct.tm_mday) + "T" + String::FormatIntWidth2(time_struct.tm_hour) + ":" + String::FormatIntWidth2(time_struct.tm_min) + ":" + String::FormatIntWidth2(time_struct.tm_sec); } // 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 << ""); if (next_segment != NULL) { stream->write( segment, static_cast(next_segment - segment)); *stream << "]]>]]>"); } else { *stream << segment; break; } } *stream << "]]>"; } void XmlUnitTestResultPrinter::OutputXmlAttribute( std::ostream* stream, const std::string& element_name, const std::string& name, const std::string& value) { const std::vector& allowed_names = GetReservedAttributesForElement(element_name); GTEST_CHECK_(std::find(allowed_names.begin(), allowed_names.end(), name) != allowed_names.end()) << "Attribute " << name << " is not allowed for element <" << element_name << ">."; *stream << " " << name << "=\"" << EscapeXmlAttribute(value) << "\""; } // 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(); const std::string kTestcase = "testcase"; *stream << " \n"; } const string location = internal::FormatCompilerIndependentFileLocation( part.file_name(), part.line_number()); const string summary = location + "\n" + part.summary(); *stream << " "; const string detail = location + "\n" + part.message(); OutputXmlCDataSection(stream, RemoveInvalidXmlCharacters(detail).c_str()); *stream << "\n"; } } if (failures == 0) *stream << " />\n"; else *stream << " \n"; } // Prints an XML representation of a TestCase object void XmlUnitTestResultPrinter::PrintXmlTestCase(std::ostream* stream, const TestCase& test_case) { const std::string kTestsuite = "testsuite"; *stream << " <" << kTestsuite; OutputXmlAttribute(stream, kTestsuite, "name", test_case.name()); OutputXmlAttribute(stream, kTestsuite, "tests", StreamableToString(test_case.reportable_test_count())); OutputXmlAttribute(stream, kTestsuite, "failures", StreamableToString(test_case.failed_test_count())); OutputXmlAttribute( stream, kTestsuite, "disabled", StreamableToString(test_case.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuite, "errors", "0"); OutputXmlAttribute(stream, kTestsuite, "time", FormatTimeInMillisAsSeconds(test_case.elapsed_time())); *stream << TestPropertiesAsXmlAttributes(test_case.ad_hoc_test_result()) << ">\n"; for (int i = 0; i < test_case.total_test_count(); ++i) { if (test_case.GetTestInfo(i)->is_reportable()) OutputXmlTestInfo(stream, test_case.name(), *test_case.GetTestInfo(i)); } *stream << " \n"; } // Prints an XML summary of unit_test to output stream out. void XmlUnitTestResultPrinter::PrintXmlUnitTest(std::ostream* stream, const UnitTest& unit_test) { const std::string kTestsuites = "testsuites"; *stream << "\n"; *stream << "<" << kTestsuites; OutputXmlAttribute(stream, kTestsuites, "tests", StreamableToString(unit_test.reportable_test_count())); OutputXmlAttribute(stream, kTestsuites, "failures", StreamableToString(unit_test.failed_test_count())); OutputXmlAttribute( stream, kTestsuites, "disabled", StreamableToString(unit_test.reportable_disabled_test_count())); OutputXmlAttribute(stream, kTestsuites, "errors", "0"); OutputXmlAttribute( stream, kTestsuites, "timestamp", FormatEpochTimeInMillisAsIso8601(unit_test.start_timestamp())); OutputXmlAttribute(stream, kTestsuites, "time", FormatTimeInMillisAsSeconds(unit_test.elapsed_time())); if (GTEST_FLAG(shuffle)) { OutputXmlAttribute(stream, kTestsuites, "random_seed", StreamableToString(unit_test.random_seed())); } *stream << TestPropertiesAsXmlAttributes(unit_test.ad_hoc_test_result()); OutputXmlAttribute(stream, kTestsuites, "name", "AllTests"); *stream << ">\n"; for (int i = 0; i < unit_test.total_test_case_count(); ++i) { if (unit_test.GetTestCase(i)->reportable_test_count() > 0) PrintXmlTestCase(stream, *unit_test.GetTestCase(i)); } *stream << "\n"; } // Produces a string representing the test properties in a result as space // delimited XML attributes based on the property key="value" pairs. std::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 #if GTEST_CAN_STREAM_RESULTS_ // Checks if str contains '=', '&', '%' or '\n' characters. If yes, // replaces them by "%xx" where xx is their hexadecimal value. For // example, replaces "=" with "%3D". This algorithm is O(strlen(str)) // in both time and space -- important as the input str may contain an // arbitrarily long test failure message and stack trace. string StreamingListener::UrlEncode(const char* str) { string result; result.reserve(strlen(str) + 1); for (char ch = *str; ch != '\0'; ch = *++str) { switch (ch) { case '%': case '=': case '&': case '\n': result.append("%" + String::FormatByte(static_cast(ch))); break; default: result.push_back(ch); break; } } return result; } void StreamingListener::SocketWriter::MakeConnection() { GTEST_CHECK_(sockfd_ == -1) << "MakeConnection() can't be called when there is already a connection."; addrinfo hints; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; // To allow both IPv4 and IPv6 addresses. hints.ai_socktype = SOCK_STREAM; addrinfo* servinfo = NULL; // Use the getaddrinfo() to get a linked list of IP addresses for // the given host name. const int error_num = getaddrinfo( host_name_.c_str(), port_num_.c_str(), &hints, &servinfo); if (error_num != 0) { GTEST_LOG_(WARNING) << "stream_result_to: getaddrinfo() failed: " << gai_strerror(error_num); } // Loop through all the results and connect to the first we can. for (addrinfo* cur_addr = servinfo; sockfd_ == -1 && cur_addr != NULL; cur_addr = cur_addr->ai_next) { sockfd_ = socket( cur_addr->ai_family, cur_addr->ai_socktype, cur_addr->ai_protocol); if (sockfd_ != -1) { // Connect the client socket to the server socket. if (connect(sockfd_, cur_addr->ai_addr, cur_addr->ai_addrlen) == -1) { close(sockfd_); sockfd_ = -1; } } } freeaddrinfo(servinfo); // all done with this structure if (sockfd_ == -1) { GTEST_LOG_(WARNING) << "stream_result_to: failed to connect to " << host_name_ << ":" << port_num_; } } // End of class Streaming Listener #endif // GTEST_CAN_STREAM_RESULTS__ // Class ScopedTrace // Pushes the given source file location and message onto a per-thread // trace stack maintained by Google Test. ScopedTrace::ScopedTrace(const char* file, int line, const Message& message) GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { TraceInfo trace; trace.file = file; trace.line = line; trace.message = message.GetString(); UnitTest::GetInstance()->PushGTestTrace(trace); } // Pops the info pushed by the c'tor. ScopedTrace::~ScopedTrace() GTEST_LOCK_EXCLUDED_(&UnitTest::mutex_) { UnitTest::GetInstance()->PopGTestTrace(); } // class OsStackTraceGetter const char* const OsStackTraceGetterInterface::kElidedFramesMarker = "... " GTEST_NAME_ " internal frames ..."; string OsStackTraceGetter::CurrentStackTrace(int /*max_depth*/, int /*skip_count*/) { return ""; } void OsStackTraceGetter::UponLeavingGTest() {} // A helper class that creates the premature-exit file in its // constructor and deletes the file in its destructor. class ScopedPrematureExitFile { public: explicit ScopedPrematureExitFile(const char* premature_exit_filepath) : premature_exit_filepath_(premature_exit_filepath) { // If a path to the premature-exit file is specified... if (premature_exit_filepath != NULL && *premature_exit_filepath != '\0') { // create the file with a single "0" character in it. I/O // errors are ignored as there's nothing better we can do and we // don't want to fail the test because of this. FILE* pfile = posix::FOpen(premature_exit_filepath, "w"); fwrite("0", 1, 1, pfile); fclose(pfile); } } ~ScopedPrematureExitFile() { if (premature_exit_filepath_ != NULL && *premature_exit_filepath_ != '\0') { remove(premature_exit_filepath_); } } private: const char* const premature_exit_filepath_; GTEST_DISALLOW_COPY_AND_ASSIGN_(ScopedPrematureExitFile); }; } // 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 that will be reported in the XML report. int UnitTest::reportable_disabled_test_count() const { return impl()->reportable_disabled_test_count(); } // Gets the number of disabled tests. int UnitTest::disabled_test_count() const { return impl()->disabled_test_count(); } // Gets the number of tests to be printed in the XML report. int UnitTest::reportable_test_count() const { return impl()->reportable_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 time of the test program start, in ms from the start of the // UNIX epoch. internal::TimeInMillis UnitTest::start_timestamp() const { return impl()->start_timestamp(); } // 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); } // Returns the TestResult containing information on test failures and // properties logged outside of individual test cases. const TestResult& UnitTest::ad_hoc_test_result() const { return *impl()->ad_hoc_test_result(); } // 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; } // 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 UnitTest::AddTestPartResult( TestPartResult::Type result_type, const char* file_name, int line_number, const std::string& message, const std::string& os_stack_trace) GTEST_LOCK_EXCLUDED_(mutex_) { 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(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 && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // 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 // Dereference NULL through a volatile pointer to prevent the compiler // from removing. We use this rather than abort() or __builtin_trap() for // portability: Symbian doesn't implement abort() well, and some debuggers // don't correctly trap abort(). *static_cast(NULL) = 1; #endif // GTEST_OS_WINDOWS } else if (GTEST_FLAG(throw_on_failure)) { #if GTEST_HAS_EXCEPTIONS throw internal::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 } } } // Adds a TestProperty to the current TestResult object when invoked from // inside a test, to current TestCase's ad_hoc_test_result_ when invoked // from SetUpTestCase or TearDownTestCase, or to the global property set // when invoked elsewhere. If the result already contains a property with // the same key, the value will be updated. void UnitTest::RecordProperty(const std::string& key, const std::string& value) { impl_->RecordProperty(TestProperty(key, value)); } // 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() { const bool in_death_test_child_process = internal::GTEST_FLAG(internal_run_death_test).length() > 0; // Google Test implements this protocol for catching that a test // program exits before returning control to Google Test: // // 1. Upon start, Google Test creates a file whose absolute path // is specified by the environment variable // TEST_PREMATURE_EXIT_FILE. // 2. When Google Test has finished its work, it deletes the file. // // This allows a test runner to set TEST_PREMATURE_EXIT_FILE before // running a Google-Test-based test program and check the existence // of the file at the end of the test execution to see if it has // exited prematurely. // If we are in the child process of a death test, don't // create/delete the premature exit file, as doing so is unnecessary // and will confuse the parent process. Otherwise, create/delete // the file upon entering/leaving this function. If the program // somehow exits before this function has a chance to return, the // premature-exit file will be left undeleted, causing a test runner // that understands the premature-exit-file protocol to report the // test as having failed. const internal::ScopedPrematureExitFile premature_exit_file( in_death_test_child_process ? NULL : internal::posix::GetEnv("TEST_PREMATURE_EXIT_FILE")); // Captures the value of GTEST_FLAG(catch_exceptions). This value will be // used for the duration of the program. impl()->set_catch_exceptions(GTEST_FLAG(catch_exceptions)); #if GTEST_HAS_SEH // 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 (impl()->catch_exceptions() || in_death_test_child_process) { # if !GTEST_OS_WINDOWS_MOBILE && !GTEST_OS_WINDOWS_PHONE && !GTEST_OS_WINDOWS_RT // 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 } #endif // GTEST_HAS_SEH return internal::HandleExceptionsInMethodIfSupported( impl(), &internal::UnitTestImpl::RunAllTests, "auxiliary test code (environments or event listeners)") ? 0 : 1; } // 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. const TestCase* UnitTest::current_test_case() const GTEST_LOCK_EXCLUDED_(mutex_) { 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. const TestInfo* UnitTest::current_test_info() const GTEST_LOCK_EXCLUDED_(mutex_) { 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. internal::ParameterizedTestCaseRegistry& UnitTest::parameterized_test_registry() GTEST_LOCK_EXCLUDED_(mutex_) { 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. void UnitTest::PushGTestTrace(const internal::TraceInfo& trace) GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().push_back(trace); } // Pops a trace from the per-thread Google Test trace stack. void UnitTest::PopGTestTrace() GTEST_LOCK_EXCLUDED_(mutex_) { internal::MutexLock lock(&mutex_); impl_->gtest_trace_stack().pop_back(); } namespace internal { UnitTestImpl::UnitTestImpl(UnitTest* parent) : parent_(parent), GTEST_DISABLE_MSC_WARNINGS_PUSH_(4355 /* using this in initializer */) default_global_test_part_result_reporter_(this), default_per_thread_test_part_result_reporter_(this), GTEST_DISABLE_MSC_WARNINGS_POP_() 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. start_timestamp_(0), elapsed_time_(0), #if GTEST_HAS_DEATH_TEST death_test_factory_(new DefaultDeathTestFactory), #endif // Will be overridden by the flag before first use. catch_exceptions_(false) { listeners()->SetDefaultResultPrinter(new PrettyUnitTestResultPrinter); } UnitTestImpl::~UnitTestImpl() { // Deletes every TestCase. ForEach(test_cases_, internal::Delete); // Deletes every Environment. ForEach(environments_, internal::Delete); delete os_stack_trace_getter_; } // Adds a TestProperty to the current TestResult object when invoked in a // context of a test, to current test case's ad_hoc_test_result when invoke // from SetUpTestCase/TearDownTestCase, or to the global property set // otherwise. If the result already contains a property with the same key, // the value will be updated. void UnitTestImpl::RecordProperty(const TestProperty& test_property) { std::string xml_element; TestResult* test_result; // TestResult appropriate for property recording. if (current_test_info_ != NULL) { xml_element = "testcase"; test_result = &(current_test_info_->result_); } else if (current_test_case_ != NULL) { xml_element = "testsuite"; test_result = &(current_test_case_->ad_hoc_test_result_); } else { xml_element = "testsuites"; test_result = &ad_hoc_test_result_; } test_result->RecordProperty(xml_element, test_property); } #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 std::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); } } #if GTEST_CAN_STREAM_RESULTS_ // Initializes event listeners for streaming test results in string form. // Must not be called before InitGoogleTest. void UnitTestImpl::ConfigureStreamingOutput() { const std::string& target = GTEST_FLAG(stream_result_to); if (!target.empty()) { const size_t pos = target.find(':'); if (pos != std::string::npos) { listeners()->Append(new StreamingListener(target.substr(0, pos), target.substr(pos+1))); } else { printf("WARNING: unrecognized streaming target \"%s\" ignored.\n", target.c_str()); fflush(stdout); } } } #endif // GTEST_CAN_STREAM_RESULTS_ // 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 defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) // Register to send notifications about key process state changes. listeners()->Append(new GTEST_CUSTOM_TEST_EVENT_LISTENER_()); #endif // defined(GTEST_CUSTOM_TEST_EVENT_LISTENER_) #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(); #if GTEST_CAN_STREAM_RESULTS_ // Configures listeners for streaming test results to the specified server. ConfigureStreamingOutput(); #endif // GTEST_CAN_STREAM_RESULTS_ } } // 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 std::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: std::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 // type_param: the name of the test case's type parameter, or NULL if // this is not a typed or a type-parameterized 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* type_param, Test::SetUpTestCaseFunc set_up_tc, Test::TearDownTestCaseFunc tear_down_tc) { // Can we find a TestCase with the given name? const std::vector::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, type_param, set_up_tc, tear_down_tc); // Is this a death test case? if (internal::UnitTestOptions::MatchesFilter(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(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 true if all tests are successful. If any exception is // thrown during a test, the test is considered to be failed, but the // rest of the tests will still be run. // // 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. bool 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 false; } // Do not run any test if the --help flag was specified. if (g_help_flag) return true; // 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); # if defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) if (in_subprocess_for_death_test) { GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_(); } # endif // defined(GTEST_EXTRA_DEATH_TEST_CHILD_SETUP_) #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 true; } 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(); start_timestamp_ = GetTimeInMillis(); 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++) { // We want to preserve failures generated by ad-hoc test // assertions executed before RUN_ALL_TESTS(). ClearNonAdHocTestResult(); 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_); return !failed; } // 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* 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 std::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 std::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->is_disabled_ = is_disabled; const bool matches_filter = internal::UnitTestOptions::FilterMatchesTest(test_case_name, test_name); test_info->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->should_run_ = is_selected; test_case->set_should_run(test_case->should_run() || is_selected); } } return num_selected_tests; } // Prints the given C-string on a single line by replacing all '\n' // characters with string "\\n". If the output takes more than // max_length characters, only prints the first max_length characters // and "...". static void PrintOnOneLine(const char* str, int max_length) { if (str != NULL) { for (int i = 0; *str != '\0'; ++str) { if (i >= max_length) { printf("..."); break; } if (*str == '\n') { printf("\\n"); i += 2; } else { printf("%c", *str); ++i; } } } } // Prints the names of the tests matching the user-specified filter flag. void UnitTestImpl::ListTestsMatchingFilter() { // Print at most this many characters for each type/value parameter. const int kMaxParamLength = 250; 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.", test_case->name()); if (test_case->type_param() != NULL) { printf(" # %s = ", kTypeParamLabel); // We print the type parameter on a single line to make // the output easy to parse by a program. PrintOnOneLine(test_case->type_param(), kMaxParamLength); } printf("\n"); } printf(" %s", test_info->name()); if (test_info->value_param() != NULL) { printf(" # %s = ", kValueParamLabel); // We print the value parameter on a single line to make the // output easy to parse by a program. PrintOnOneLine(test_info->value_param(), kMaxParamLength); } printf("\n"); } } } 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) { #ifdef GTEST_OS_STACK_TRACE_GETTER_ os_stack_trace_getter_ = new GTEST_OS_STACK_TRACE_GETTER_; #else os_stack_trace_getter_ = new OsStackTraceGetter; #endif // GTEST_OS_STACK_TRACE_GETTER_ } 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_->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(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(i); } } // Returns the current OS stack trace as an std::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. std::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_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_ 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 std::string flag_str = std::string("--") + 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, std::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", std::string(str, p).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" #if GTEST_CAN_STREAM_RESULTS_ " @G--" GTEST_FLAG_PREFIX_ "stream_result_to=@YHOST@G:@YPORT@D\n" " Stream test results to the given server.\n" #endif // GTEST_CAN_STREAM_RESULTS_ "\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" " @G--" GTEST_FLAG_PREFIX_ "catch_exceptions=0@D\n" " Do not report exceptions as test failures. Instead, allow them\n" " to crash the program or throw a pop-up (on Windows).\n" "\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"; bool ParseGoogleTestFlag(const char* const arg) { return ParseBoolFlag(arg, kAlsoRunDisabledTestsFlag, >EST_FLAG(also_run_disabled_tests)) || ParseBoolFlag(arg, kBreakOnFailureFlag, >EST_FLAG(break_on_failure)) || ParseBoolFlag(arg, kCatchExceptionsFlag, >EST_FLAG(catch_exceptions)) || ParseStringFlag(arg, kColorFlag, >EST_FLAG(color)) || ParseStringFlag(arg, kDeathTestStyleFlag, >EST_FLAG(death_test_style)) || ParseBoolFlag(arg, kDeathTestUseFork, >EST_FLAG(death_test_use_fork)) || ParseStringFlag(arg, kFilterFlag, >EST_FLAG(filter)) || ParseStringFlag(arg, kInternalRunDeathTestFlag, >EST_FLAG(internal_run_death_test)) || ParseBoolFlag(arg, kListTestsFlag, >EST_FLAG(list_tests)) || ParseStringFlag(arg, kOutputFlag, >EST_FLAG(output)) || ParseBoolFlag(arg, kPrintTimeFlag, >EST_FLAG(print_time)) || ParseInt32Flag(arg, kRandomSeedFlag, >EST_FLAG(random_seed)) || ParseInt32Flag(arg, kRepeatFlag, >EST_FLAG(repeat)) || ParseBoolFlag(arg, kShuffleFlag, >EST_FLAG(shuffle)) || ParseInt32Flag(arg, kStackTraceDepthFlag, >EST_FLAG(stack_trace_depth)) || ParseStringFlag(arg, kStreamResultToFlag, >EST_FLAG(stream_result_to)) || ParseBoolFlag(arg, kThrowOnFailureFlag, >EST_FLAG(throw_on_failure)); } #if GTEST_USE_OWN_FLAGFILE_FLAG_ void LoadFlagsFromFile(const std::string& path) { FILE* flagfile = posix::FOpen(path.c_str(), "r"); if (!flagfile) { fprintf(stderr, "Unable to open file \"%s\"\n", GTEST_FLAG(flagfile).c_str()); fflush(stderr); exit(EXIT_FAILURE); } std::string contents(ReadEntireFile(flagfile)); posix::FClose(flagfile); std::vector lines; SplitString(contents, '\n', &lines); for (size_t i = 0; i < lines.size(); ++i) { if (lines[i].empty()) continue; if (!ParseGoogleTestFlag(lines[i].c_str())) g_help_flag = true; } } #endif // GTEST_USE_OWN_FLAGFILE_FLAG_ // 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 void ParseGoogleTestFlagsOnlyImpl(int* argc, CharType** argv) { for (int i = 1; i < *argc; i++) { const std::string arg_string = StreamableToString(argv[i]); const char* const arg = arg_string.c_str(); using internal::ParseBoolFlag; using internal::ParseInt32Flag; using internal::ParseStringFlag; bool remove_flag = false; if (ParseGoogleTestFlag(arg)) { remove_flag = true; #if GTEST_USE_OWN_FLAGFILE_FLAG_ } else if (ParseStringFlag(arg, kFlagfileFlag, >EST_FLAG(flagfile))) { LoadFlagsFromFile(GTEST_FLAG(flagfile)); remove_flag = true; #endif // GTEST_USE_OWN_FLAGFILE_FLAG_ } 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 (remove_flag) { // 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--; } } 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 void InitGoogleTestImpl(int* argc, CharType** argv) { // We don't want to run the initialization code twice. if (GTestIsInitialized()) return; if (*argc <= 0) return; g_argvs.clear(); for (int i = 0; i != *argc; i++) { g_argvs.push_back(StreamableToString(argv[i])); } 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) { #if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); #else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); #endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } // This overloaded version can be used in Windows programs compiled in // UNICODE mode. void InitGoogleTest(int* argc, wchar_t** argv) { #if defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_(argc, argv); #else // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) internal::InitGoogleTestImpl(argc, argv); #endif // defined(GTEST_CUSTOM_INIT_GOOGLE_TEST_FUNCTION_) } } // namespace testing assimp-4.1.0/contrib/gtest/src/gtest-test-part.cc0000644002537200234200000001010313213503245022202 0ustar zmoelnigiemusers// 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 exists to // prevent the accidental inclusion of gtest-internal-inl.h in the // user's 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. std::string TestPartResult::ExtractSummary(const char* message) { const char* const stack_trace = strstr(message, internal::kStackTraceMarker); return stack_trace == NULL ? message : std::string(message, stack_trace); } // 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(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 assimp-4.1.0/contrib/gtest/src/gtest_main.cc0000644002537200234200000000334513213503245021277 0ustar zmoelnigiemusers// 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 #include "gtest/gtest.h" GTEST_API_ int main(int argc, char **argv) { printf("Running main() from gtest_main.cc\n"); testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } assimp-4.1.0/contrib/gtest/src/gtest-death-test.cc0000644002537200234200000014337613213503245022344 0ustar zmoelnigiemusers// 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" #include "gtest/internal/custom/gtest.h" #if GTEST_HAS_DEATH_TEST # if GTEST_OS_MAC # include # endif // GTEST_OS_MAC # include # include # include # if GTEST_OS_LINUX # include # endif // GTEST_OS_LINUX # include # if GTEST_OS_WINDOWS # include # else # include # include # endif // GTEST_OS_WINDOWS # if GTEST_OS_QNX # include # endif // GTEST_OS_QNX #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 exists to // prevent the accidental inclusion of gtest-internal-inl.h in the // user's 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 " "the '|' characters. 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 namespace internal { // Valid only for fast death tests. Indicates the code is running in the // child process of a fast style death test. # if !GTEST_OS_WINDOWS static bool g_in_fast_death_test_child = false; # endif // Returns a Boolean value indicating whether the caller is currently // executing in the context of the death test child process. Tools such as // Valgrind heap checkers may need this to modify their behavior in death // tests. IMPORTANT: This is an internal utility. Using it may break the // implementation of death tests. User code MUST NOT use it. bool InDeathTestChild() { # if GTEST_OS_WINDOWS // On Windows, death tests are thread-safe regardless of the value of the // death_test_style flag. return !GTEST_FLAG(internal_run_death_test).empty(); # else if (GTEST_FLAG(death_test_style) == "threadsafe") return !GTEST_FLAG(internal_run_death_test).empty(); else return g_in_fast_death_test_child; #endif } } // namespace internal // 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 { # if defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) { bool result; if (GTEST_KILLED_BY_SIGNAL_OVERRIDE_(signum_, exit_status, &result)) { return result; } } # endif // defined(GTEST_KILLED_BY_SIGNAL_OVERRIDE_) 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 std::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 std::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 kDeathTestThrew = 'T'; 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; // RETURNED means that the test statement attempted to execute a return // statement, which is not allowed; THREW means that the test statement // returned control by throwing an exception. IN_PROGRESS means the test // has not yet concluded. // TODO(vladl@google.com): Unify names and possibly values for // AbortReason, DeathTestOutcome, and flag characters above. enum DeathTestOutcome { IN_PROGRESS, DIED, LIVED, RETURNED, THREW }; // 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 std::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); posix::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( \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + ::testing::internal::StreamableToString(__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( \ ::std::string("CHECK failed: File ") + __FILE__ + ", line " \ + ::testing::internal::StreamableToString(__LINE__) + ": " \ + #expression + " != -1"); \ } \ } while (::testing::internal::AlwaysFalse()) // Returns the message describing the last system error in errno. std::string GetLastErrnoDescription() { return 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 std::string& message) { last_death_test_message_ = message; } std::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 kDeathTestThrew: set_outcome(THREW); 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(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 : reason == TEST_THREW_EXCEPTION ? kDeathTestThrew : kDeathTestReturned; GTEST_DEATH_TEST_CHECK_SYSCALL_(posix::Write(write_fd(), &status_ch, 1)); // We are leaking the descriptor here because on some platforms (i.e., // when built as Windows DLL), destructors of global objects will still // run after calling _exit(). On such systems, write_fd_ will be // indirectly closed from the destructor of UnitTestImpl, causing double // close if it is also closed here. On debug configurations, double close // may assert. As there are no in-process buffers to flush here, we are // relying on the OS to close the descriptor after the process terminates // when the destructors are not run. _exit(1); // Exits w/o any normal exit hooks (we were supposed to crash) } // Returns an indented copy of stderr output for a death test. // This makes distinguishing death test output lines from regular log lines // much easier. static ::std::string FormatDeathTestOutput(const ::std::string& output) { ::std::string ret; for (size_t at = 0; ; ) { const size_t line_end = output.find('\n', at); ret += "[ DEATH ] "; if (line_end == ::std::string::npos) { ret += output.substr(at); break; } ret += output.substr(at, line_end + 1 - at); at = line_end + 1; } return ret; } // 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, THREW, or RETURNED. The death test // fails in the latter three 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 std::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:\n" << FormatDeathTestOutput(error_message); break; case THREW: buffer << " Result: threw an exception.\n" << " Error msg:\n" << FormatDeathTestOutput(error_message); break; case RETURNED: buffer << " Result: illegal return in test statement.\n" << " Error msg:\n" << FormatDeathTestOutput(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:\n" << FormatDeathTestOutput(error_message); } } else { buffer << " Result: died but not with expected exit code:\n" << " " << ExitSummary(status()) << "\n" << "Actual msg:\n" << FormatDeathTestOutput(error_message); } 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* a_statement, const RE* a_regex, const char* file, int line) : DeathTestImpl(a_statement, a_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_code; GTEST_DEATH_TEST_CHECK_( ::GetExitCodeProcess(child_handle_.Get(), &status_code) != FALSE); child_handle_.Reset(); set_status(static_cast(status_code)); return 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(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 std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_case_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(static_cast(::GetCurrentProcessId())) + // size_t has the same width as pointers on both 32-bit and 64-bit // Windows platforms. // See http://msdn.microsoft.com/en-us/library/tcxf1dw6.aspx. "|" + StreamableToString(reinterpret_cast(write_handle)) + "|" + StreamableToString(reinterpret_cast(event_handle_.Get())); char executable_path[_MAX_PATH + 1]; // NOLINT GTEST_DEATH_TEST_CHECK_( _MAX_PATH + 1 != ::GetModuleFileNameA(NULL, executable_path, _MAX_PATH)); std::string command_line = std::string(::GetCommandLineA()) + " " + filter_flag + " \"" + internal_flag + "\""; 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(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(); g_in_fast_death_test_child = true; 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: static ::std::vector GetArgvsForDeathTestChildProcess() { ::std::vector args = GetInjectableArgvs(); # if defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) ::std::vector extra_args = GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_(); args.insert(args.end(), extra_args.begin(), extra_args.end()); # endif // defined(GTEST_EXTRA_DEATH_TEST_COMMAND_LINE_ARGS_) return args; } // 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::iterator i = args_.begin(); i != args_.end(); ++i) { free(*i); } } void AddArgument(const char* argument) { args_.insert(args_.end() - 1, posix::StrDup(argument)); } template void AddArguments(const ::std::vector& arguments) { for (typename ::std::vector::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 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 # if !GTEST_OS_QNX // 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(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(std::string("chdir(\"") + original_dir + "\") failed: " + GetLastErrnoDescription()); 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(std::string("execve(") + args->argv[0] + ", ...) in " + original_dir + " failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } # endif // !GTEST_OS_QNX // 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. // // GTEST_NO_INLINE_ is required to prevent GCC 4.6 from inlining // StackLowerThanAddress into StackGrowsDown, which then doesn't give // correct answer. void StackLowerThanAddress(const void* ptr, bool* result) GTEST_NO_INLINE_; void StackLowerThanAddress(const void* ptr, bool* result) { int dummy; *result = (&dummy < ptr); } // Make sure AddressSanitizer does not tamper with the stack here. GTEST_ATTRIBUTE_NO_SANITIZE_ADDRESS_ bool StackGrowsDown() { int dummy; bool result; StackLowerThanAddress(&dummy, &result); return result; } // Spawns a child process with the same executable as the current process in // a thread-safe manner and instructs it to run the death test. The // implementation uses fork(2) + exec. On systems where clone(2) is // available, it is used instead, being slightly more thread-safe. On QNX, // fork supports only single-threaded environments, so this function uses // spawn(2) there instead. The function dies with an error message if // anything goes wrong. static pid_t ExecDeathTestSpawnChild(char* const* argv, int close_fd) { ExecDeathTestArgs args = { argv, close_fd }; pid_t child_pid = -1; # if GTEST_OS_QNX // Obtains the current directory and sets it to be closed in the child // process. const int cwd_fd = open(".", O_RDONLY); GTEST_DEATH_TEST_CHECK_(cwd_fd != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(cwd_fd, F_SETFD, FD_CLOEXEC)); // 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(std::string("chdir(\"") + original_dir + "\") failed: " + GetLastErrnoDescription()); return EXIT_FAILURE; } int fd_flags; // Set close_fd to be closed after spawn. GTEST_DEATH_TEST_CHECK_SYSCALL_(fd_flags = fcntl(close_fd, F_GETFD)); GTEST_DEATH_TEST_CHECK_SYSCALL_(fcntl(close_fd, F_SETFD, fd_flags | FD_CLOEXEC)); struct inheritance inherit = {0}; // spawn is a system call. child_pid = spawn(args.argv[0], 0, NULL, &inherit, args.argv, GetEnviron()); // Restores the current working directory. GTEST_DEATH_TEST_CHECK_(fchdir(cwd_fd) != -1); GTEST_DEATH_TEST_CHECK_SYSCALL_(close(cwd_fd)); # else // GTEST_OS_QNX # if GTEST_OS_LINUX // When a SIGPROF signal is received while fork() or clone() are executing, // the process may hang. To avoid this, we ignore SIGPROF here and re-enable // it after the call to fork()/clone() is complete. struct sigaction saved_sigprof_action; struct sigaction ignore_sigprof_action; memset(&ignore_sigprof_action, 0, sizeof(ignore_sigprof_action)); sigemptyset(&ignore_sigprof_action.sa_mask); ignore_sigprof_action.sa_handler = SIG_IGN; GTEST_DEATH_TEST_CHECK_SYSCALL_(sigaction( SIGPROF, &ignore_sigprof_action, &saved_sigprof_action)); # endif // GTEST_OS_LINUX # 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); // Maximum stack alignment in bytes: For a downward-growing stack, this // amount is subtracted from size of the stack space to get an address // that is within the stack space and is aligned on all systems we care // about. As far as I know there is no ABI with stack alignment greater // than 64. We assume stack and stack_size already have alignment of // kMaxStackAlignment. const size_t kMaxStackAlignment = 64; void* const stack_top = static_cast(stack) + (stack_grows_down ? stack_size - kMaxStackAlignment : 0); GTEST_DEATH_TEST_CHECK_(stack_size > kMaxStackAlignment && reinterpret_cast(stack_top) % kMaxStackAlignment == 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); } # endif // GTEST_OS_QNX # if GTEST_OS_LINUX GTEST_DEATH_TEST_CHECK_SYSCALL_( sigaction(SIGPROF, &saved_sigprof_action, NULL)); # endif // GTEST_OS_LINUX 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 std::string filter_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kFilterFlag + "=" + info->test_case_name() + "." + info->name(); const std::string internal_flag = std::string("--") + GTEST_FLAG_PREFIX_ + kInternalRunDeathTestFlag + "=" + file_ + "|" + StreamableToString(line_) + "|" + StreamableToString(death_test_index) + "|" + StreamableToString(pipe_fd[1]); Arguments args; args.AddArguments(GetArgvsForDeathTestChildProcess()); 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 = ExecDeathTestSpawnChild(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( "Death test count (" + StreamableToString(death_test_index) + ") somehow exceeded expected maximum (" + StreamableToString(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( "Unknown death test style \"" + GTEST_FLAG(death_test_style) + "\" encountered"); return false; } return true; } # 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("Unable to open parent process " + StreamableToString(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(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("Unable to duplicate the pipe handle " + StreamableToString(write_handle_as_size_t) + " from the parent process " + StreamableToString(parent_process_id)); } const HANDLE event_handle = reinterpret_cast(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("Unable to duplicate the event handle " + StreamableToString(event_handle_as_size_t) + " from the parent process " + StreamableToString(parent_process_id)); } const int write_fd = ::_open_osfhandle(reinterpret_cast(dup_write_handle), O_APPEND); if (write_fd == -1) { DeathTestAbort("Unable to convert pipe handle " + StreamableToString(write_handle_as_size_t) + " to a file descriptor"); } // 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("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } 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("Bad --gtest_internal_run_death_test flag: " + GTEST_FLAG(internal_run_death_test)); } # endif // GTEST_OS_WINDOWS return new InternalRunDeathTestFlag(fields[0], line, index, write_fd); } } // namespace internal #endif // GTEST_HAS_DEATH_TEST } // namespace testing assimp-4.1.0/contrib/gtest/src/gtest-port.cc0000644002537200234200000012375113213503245021261 0ustar zmoelnigiemusers// 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 #include #include #include #include #if GTEST_OS_WINDOWS # include # include # include # include // Used in ThreadLocal. #else # include #endif // GTEST_OS_WINDOWS #if GTEST_OS_MAC # include # include # include #endif // GTEST_OS_MAC #if GTEST_OS_QNX # include # include # include #endif // GTEST_OS_QNX #if GTEST_OS_AIX # include # include #endif // GTEST_OS_AIX #include "gtest/gtest-spi.h" #include "gtest/gtest-message.h" #include "gtest/internal/gtest-internal.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 exists to // prevent the accidental inclusion of gtest-internal-inl.h in the // user's 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_LINUX namespace { template T ReadProcFileField(const string& filename, int field) { std::string dummy; std::ifstream file(filename.c_str()); while (field-- > 0) { file >> dummy; } T output = 0; file >> output; return output; } } // namespace // Returns the number of active threads, or 0 when there is an error. size_t GetThreadCount() { const string filename = (Message() << "/proc/" << getpid() << "/stat").GetString(); return ReadProcFileField(filename, 19); } #elif GTEST_OS_MAC 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(thread_list), sizeof(thread_t) * thread_count); return static_cast(thread_count); } else { return 0; } } #elif GTEST_OS_QNX // Returns the number of threads running in the process, or 0 to indicate that // we cannot detect it. size_t GetThreadCount() { const int fd = open("/proc/self/as", O_RDONLY); if (fd < 0) { return 0; } procfs_info process_info; const int status = devctl(fd, DCMD_PROC_INFO, &process_info, sizeof(process_info), NULL); close(fd); if (status == EOK) { return static_cast(process_info.num_threads); } else { return 0; } } #elif GTEST_OS_AIX size_t GetThreadCount() { struct procentry64 entry; pid_t pid = getpid(); int status = getprocs64(&entry, sizeof(entry), NULL, 0, &pid, 1); if (status == 1) { return entry.pi_thcount; } 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_LINUX #if GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS void SleepMilliseconds(int n) { ::Sleep(n); } AutoHandle::AutoHandle() : handle_(INVALID_HANDLE_VALUE) {} AutoHandle::AutoHandle(Handle handle) : handle_(handle) {} AutoHandle::~AutoHandle() { Reset(); } AutoHandle::Handle AutoHandle::Get() const { return handle_; } void AutoHandle::Reset() { Reset(INVALID_HANDLE_VALUE); } void AutoHandle::Reset(HANDLE handle) { // Resetting with the same handle we already own is invalid. if (handle_ != handle) { if (IsCloseable()) { ::CloseHandle(handle_); } handle_ = handle; } else { GTEST_CHECK_(!IsCloseable()) << "Resetting a valid handle to itself is likely a programmer error " "and thus not allowed."; } } bool AutoHandle::IsCloseable() const { // Different Windows APIs may use either of these values to represent an // invalid handle. return handle_ != NULL && handle_ != INVALID_HANDLE_VALUE; } Notification::Notification() : event_(::CreateEvent(NULL, // Default security attributes. TRUE, // Do not reset automatically. FALSE, // Initially unset. NULL)) { // Anonymous event. GTEST_CHECK_(event_.Get() != NULL); } void Notification::Notify() { GTEST_CHECK_(::SetEvent(event_.Get()) != FALSE); } void Notification::WaitForNotification() { GTEST_CHECK_( ::WaitForSingleObject(event_.Get(), INFINITE) == WAIT_OBJECT_0); } Mutex::Mutex() : owner_thread_id_(0), type_(kDynamic), critical_section_init_phase_(0), critical_section_(new CRITICAL_SECTION) { ::InitializeCriticalSection(critical_section_); } Mutex::~Mutex() { // Static mutexes are leaked intentionally. It is not thread-safe to try // to clean them up. // TODO(yukawa): Switch to Slim Reader/Writer (SRW) Locks, which requires // nothing to clean it up but is available only on Vista and later. // http://msdn.microsoft.com/en-us/library/windows/desktop/aa904937.aspx if (type_ == kDynamic) { ::DeleteCriticalSection(critical_section_); delete critical_section_; critical_section_ = NULL; } } void Mutex::Lock() { ThreadSafeLazyInit(); ::EnterCriticalSection(critical_section_); owner_thread_id_ = ::GetCurrentThreadId(); } void Mutex::Unlock() { ThreadSafeLazyInit(); // We don't protect writing to owner_thread_id_ here, as it's the // caller's responsibility to ensure that the current thread holds the // mutex when this is called. owner_thread_id_ = 0; ::LeaveCriticalSection(critical_section_); } // Does nothing if the current thread holds the mutex. Otherwise, crashes // with high probability. void Mutex::AssertHeld() { ThreadSafeLazyInit(); GTEST_CHECK_(owner_thread_id_ == ::GetCurrentThreadId()) << "The current thread is not holding the mutex @" << this; } // Initializes owner_thread_id_ and critical_section_ in static mutexes. void Mutex::ThreadSafeLazyInit() { // Dynamic mutexes are initialized in the constructor. if (type_ == kStatic) { switch ( ::InterlockedCompareExchange(&critical_section_init_phase_, 1L, 0L)) { case 0: // If critical_section_init_phase_ was 0 before the exchange, we // are the first to test it and need to perform the initialization. owner_thread_id_ = 0; critical_section_ = new CRITICAL_SECTION; ::InitializeCriticalSection(critical_section_); // Updates the critical_section_init_phase_ to 2 to signal // initialization complete. GTEST_CHECK_(::InterlockedCompareExchange( &critical_section_init_phase_, 2L, 1L) == 1L); break; case 1: // Somebody else is already initializing the mutex; spin until they // are done. while (::InterlockedCompareExchange(&critical_section_init_phase_, 2L, 2L) != 2L) { // Possibly yields the rest of the thread's time slice to other // threads. ::Sleep(0); } break; case 2: break; // The mutex is already initialized and ready for use. default: GTEST_CHECK_(false) << "Unexpected value of critical_section_init_phase_ " << "while initializing a static mutex."; } } } namespace { class ThreadWithParamSupport : public ThreadWithParamBase { public: static HANDLE CreateThread(Runnable* runnable, Notification* thread_can_start) { ThreadMainParam* param = new ThreadMainParam(runnable, thread_can_start); DWORD thread_id; // TODO(yukawa): Consider to use _beginthreadex instead. HANDLE thread_handle = ::CreateThread( NULL, // Default security. 0, // Default stack size. &ThreadWithParamSupport::ThreadMain, param, // Parameter to ThreadMainStatic 0x0, // Default creation flags. &thread_id); // Need a valid pointer for the call to work under Win98. GTEST_CHECK_(thread_handle != NULL) << "CreateThread failed with error " << ::GetLastError() << "."; if (thread_handle == NULL) { delete param; } return thread_handle; } private: struct ThreadMainParam { ThreadMainParam(Runnable* runnable, Notification* thread_can_start) : runnable_(runnable), thread_can_start_(thread_can_start) { } scoped_ptr runnable_; // Does not own. Notification* thread_can_start_; }; static DWORD WINAPI ThreadMain(void* ptr) { // Transfers ownership. scoped_ptr param(static_cast(ptr)); if (param->thread_can_start_ != NULL) param->thread_can_start_->WaitForNotification(); param->runnable_->Run(); return 0; } // Prohibit instantiation. ThreadWithParamSupport(); GTEST_DISALLOW_COPY_AND_ASSIGN_(ThreadWithParamSupport); }; } // namespace ThreadWithParamBase::ThreadWithParamBase(Runnable *runnable, Notification* thread_can_start) : thread_(ThreadWithParamSupport::CreateThread(runnable, thread_can_start)) { } ThreadWithParamBase::~ThreadWithParamBase() { Join(); } void ThreadWithParamBase::Join() { GTEST_CHECK_(::WaitForSingleObject(thread_.Get(), INFINITE) == WAIT_OBJECT_0) << "Failed to join the thread with error " << ::GetLastError() << "."; } // Maps a thread to a set of ThreadIdToThreadLocals that have values // instantiated on that thread and notifies them when the thread exits. A // ThreadLocal instance is expected to persist until all threads it has // values on have terminated. class ThreadLocalRegistryImpl { public: // Registers thread_local_instance as having value on the current thread. // Returns a value that can be used to identify the thread from other threads. static ThreadLocalValueHolderBase* GetValueOnCurrentThread( const ThreadLocalBase* thread_local_instance) { DWORD current_thread = ::GetCurrentThreadId(); MutexLock lock(&mutex_); ThreadIdToThreadLocals* const thread_to_thread_locals = GetThreadLocalsMapLocked(); ThreadIdToThreadLocals::iterator thread_local_pos = thread_to_thread_locals->find(current_thread); if (thread_local_pos == thread_to_thread_locals->end()) { thread_local_pos = thread_to_thread_locals->insert( std::make_pair(current_thread, ThreadLocalValues())).first; StartWatcherThreadFor(current_thread); } ThreadLocalValues& thread_local_values = thread_local_pos->second; ThreadLocalValues::iterator value_pos = thread_local_values.find(thread_local_instance); if (value_pos == thread_local_values.end()) { value_pos = thread_local_values .insert(std::make_pair( thread_local_instance, linked_ptr( thread_local_instance->NewValueForCurrentThread()))) .first; } return value_pos->second.get(); } static void OnThreadLocalDestroyed( const ThreadLocalBase* thread_local_instance) { std::vector > value_holders; // Clean up the ThreadLocalValues data structure while holding the lock, but // defer the destruction of the ThreadLocalValueHolderBases. { MutexLock lock(&mutex_); ThreadIdToThreadLocals* const thread_to_thread_locals = GetThreadLocalsMapLocked(); for (ThreadIdToThreadLocals::iterator it = thread_to_thread_locals->begin(); it != thread_to_thread_locals->end(); ++it) { ThreadLocalValues& thread_local_values = it->second; ThreadLocalValues::iterator value_pos = thread_local_values.find(thread_local_instance); if (value_pos != thread_local_values.end()) { value_holders.push_back(value_pos->second); thread_local_values.erase(value_pos); // This 'if' can only be successful at most once, so theoretically we // could break out of the loop here, but we don't bother doing so. } } } // Outside the lock, let the destructor for 'value_holders' deallocate the // ThreadLocalValueHolderBases. } static void OnThreadExit(DWORD thread_id) { GTEST_CHECK_(thread_id != 0) << ::GetLastError(); std::vector > value_holders; // Clean up the ThreadIdToThreadLocals data structure while holding the // lock, but defer the destruction of the ThreadLocalValueHolderBases. { MutexLock lock(&mutex_); ThreadIdToThreadLocals* const thread_to_thread_locals = GetThreadLocalsMapLocked(); ThreadIdToThreadLocals::iterator thread_local_pos = thread_to_thread_locals->find(thread_id); if (thread_local_pos != thread_to_thread_locals->end()) { ThreadLocalValues& thread_local_values = thread_local_pos->second; for (ThreadLocalValues::iterator value_pos = thread_local_values.begin(); value_pos != thread_local_values.end(); ++value_pos) { value_holders.push_back(value_pos->second); } thread_to_thread_locals->erase(thread_local_pos); } } // Outside the lock, let the destructor for 'value_holders' deallocate the // ThreadLocalValueHolderBases. } private: // In a particular thread, maps a ThreadLocal object to its value. typedef std::map > ThreadLocalValues; // Stores all ThreadIdToThreadLocals having values in a thread, indexed by // thread's ID. typedef std::map ThreadIdToThreadLocals; // Holds the thread id and thread handle that we pass from // StartWatcherThreadFor to WatcherThreadFunc. typedef std::pair ThreadIdAndHandle; static void StartWatcherThreadFor(DWORD thread_id) { // The returned handle will be kept in thread_map and closed by // watcher_thread in WatcherThreadFunc. HANDLE thread = ::OpenThread(SYNCHRONIZE | THREAD_QUERY_INFORMATION, FALSE, thread_id); GTEST_CHECK_(thread != NULL); // We need to to pass a valid thread ID pointer into CreateThread for it // to work correctly under Win98. DWORD watcher_thread_id; HANDLE watcher_thread = ::CreateThread( NULL, // Default security. 0, // Default stack size &ThreadLocalRegistryImpl::WatcherThreadFunc, reinterpret_cast(new ThreadIdAndHandle(thread_id, thread)), CREATE_SUSPENDED, &watcher_thread_id); GTEST_CHECK_(watcher_thread != NULL); // Give the watcher thread the same priority as ours to avoid being // blocked by it. ::SetThreadPriority(watcher_thread, ::GetThreadPriority(::GetCurrentThread())); ::ResumeThread(watcher_thread); ::CloseHandle(watcher_thread); } // Monitors exit from a given thread and notifies those // ThreadIdToThreadLocals about thread termination. static DWORD WINAPI WatcherThreadFunc(LPVOID param) { const ThreadIdAndHandle* tah = reinterpret_cast(param); GTEST_CHECK_( ::WaitForSingleObject(tah->second, INFINITE) == WAIT_OBJECT_0); OnThreadExit(tah->first); ::CloseHandle(tah->second); delete tah; return 0; } // Returns map of thread local instances. static ThreadIdToThreadLocals* GetThreadLocalsMapLocked() { mutex_.AssertHeld(); static ThreadIdToThreadLocals* map = new ThreadIdToThreadLocals; return map; } // Protects access to GetThreadLocalsMapLocked() and its return value. static Mutex mutex_; // Protects access to GetThreadMapLocked() and its return value. static Mutex thread_map_mutex_; }; Mutex ThreadLocalRegistryImpl::mutex_(Mutex::kStaticMutex); Mutex ThreadLocalRegistryImpl::thread_map_mutex_(Mutex::kStaticMutex); ThreadLocalValueHolderBase* ThreadLocalRegistry::GetValueOnCurrentThread( const ThreadLocalBase* thread_local_instance) { return ThreadLocalRegistryImpl::GetValueOnCurrentThread( thread_local_instance); } void ThreadLocalRegistry::OnThreadLocalDestroyed( const ThreadLocalBase* thread_local_instance) { ThreadLocalRegistryImpl::OnThreadLocalDestroyed(thread_local_instance); } #endif // GTEST_IS_THREADSAFE && GTEST_OS_WINDOWS #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(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 , these aren't affected by the // current locale. bool IsAsciiDigit(char ch) { return '0' <= ch && ch <= '9'; } bool IsAsciiPunct(char ch) { return IsInSet(ch, "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"); } bool IsRepeat(char ch) { return IsInSet(ch, "?*+"); } bool IsAsciiWhiteSpace(char ch) { return IsInSet(ch, " \f\n\r\t\v"); } bool IsAsciiWordChar(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 (IsAsciiPunct(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 IsAsciiDigit(ch); case 'D': return !IsAsciiDigit(ch); case 'f': return ch == '\f'; case 'n': return ch == '\n'; case 'r': return ch == '\r'; case 's': return IsAsciiWhiteSpace(ch); case 'S': return !IsAsciiWhiteSpace(ch); case 't': return ch == '\t'; case 'v': return ch == '\v'; case 'w': return IsAsciiWordChar(ch); case 'W': return !IsAsciiWordChar(ch); } return IsAsciiPunct(pattern_char) && pattern_char == ch; } return (pattern_char == '.' && ch != '\n') || pattern_char == ch; } // Helper function used by ValidateRegex() to format error messages. std::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(-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(pattern_)); free(const_cast(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(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 const char kUnknownFile[] = "unknown file"; // Formats a source file path and a line number as they would appear // in an error message from the compiler used to compile this code. GTEST_API_ ::std::string FormatFileLocation(const char* file, int line) { const std::string file_name(file == NULL ? kUnknownFile : file); if (line < 0) { return file_name + ":"; } #ifdef _MSC_VER return file_name + "(" + StreamableToString(line) + "):"; #else return file_name + ":" + StreamableToString(line) + ":"; #endif // _MSC_VER } // Formats a file location for compiler-independent XML output. // Although this function is not platform dependent, we put it next to // FormatFileLocation in order to contrast the two functions. // Note that FormatCompilerIndependentFileLocation() does NOT append colon // to the file location it produces, unlike FormatFileLocation(). GTEST_API_ ::std::string FormatCompilerIndependentFileLocation( const char* file, int line) { const std::string file_name(file == NULL ? kUnknownFile : file); if (line < 0) return file_name; else return file_name + ":" + StreamableToString(line); } 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) GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996) #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. explicit 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. We use /tmp on most systems, and /sdcard on Android. // That's because Android doesn't have /tmp. # if GTEST_OS_LINUX_ANDROID // Note: Android applications are expected to call the framework's // Context.getExternalStorageDirectory() method through JNI to get // the location of the world-writable SD Card directory. However, // this requires a Context handle, which cannot be retrieved // globally from native code. Doing so also precludes running the // code as part of a regular standalone executable, which doesn't // run in a Dalvik process (e.g. when running it through 'adb shell'). // // The location /sdcard is directly accessible from native code // and is the only location (unofficially) supported by the Android // team. It's generally a symlink to the real SD Card mount point // which can be /mnt/sdcard, /mnt/sdcard0, /system/media/sdcard, or // other OEM-customized locations. Never rely on these, and always // use /sdcard. char name_template[] = "/sdcard/gtest_captured_stream.XXXXXX"; # else char name_template[] = "/tmp/captured_stream.XXXXXX"; # endif // GTEST_OS_LINUX_ANDROID 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()); } std::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 std::string content = ReadEntireFile(file); posix::FClose(file); return content; } private: 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); }; GTEST_DISABLE_MSC_WARNINGS_POP_() 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. std::string GetCapturedStream(CapturedStream** captured_stream) { const std::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. std::string GetCapturedStdout() { return GetCapturedStream(&g_captured_stdout); } // Stops capturing stderr and returns the captured string. std::string GetCapturedStderr() { return GetCapturedStream(&g_captured_stderr); } #endif // GTEST_HAS_STREAM_REDIRECTION std::string TempDir() { #if GTEST_OS_WINDOWS_MOBILE return "\\temp\\"; #elif GTEST_OS_WINDOWS const char* temp_dir = posix::GetEnv("TEMP"); if (temp_dir == NULL || temp_dir[0] == '\0') return "\\temp\\"; else if (temp_dir[strlen(temp_dir) - 1] == '\\') return temp_dir; else return std::string(temp_dir) + "\\"; #elif GTEST_OS_LINUX_ANDROID return "/sdcard/"; #else return "/tmp/"; #endif // GTEST_OS_WINDOWS_MOBILE } size_t GetFileSize(FILE* file) { fseek(file, 0, SEEK_END); return static_cast(ftell(file)); } std::string 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 std::string content(buffer, bytes_read); delete[] buffer; return content; } #if GTEST_HAS_DEATH_TEST static const ::std::vector* g_injected_test_argvs = NULL; // Owned. void SetInjectableArgvs(const ::std::vector* argvs) { if (g_injected_test_argvs != argvs) delete g_injected_test_argvs; g_injected_test_argvs = argvs; } const ::std::vector& GetInjectableArgvs() { if (g_injected_test_argvs != NULL) { return *g_injected_test_argvs; } return GetArgvs(); } #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 std::string FlagToEnvVar(const char* flag) { const std::string full_flag = (Message() << GTEST_FLAG_PREFIX_ << flag).GetString(); Message env_var; for (size_t i = 0; i != full_flag.length(); i++) { env_var << 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(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) { #if defined(GTEST_GET_BOOL_FROM_ENV_) return GTEST_GET_BOOL_FROM_ENV_(flag, default_value); #endif // defined(GTEST_GET_BOOL_FROM_ENV_) const std::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) { #if defined(GTEST_GET_INT32_FROM_ENV_) return GTEST_GET_INT32_FROM_ENV_(flag, default_value); #endif // defined(GTEST_GET_INT32_FROM_ENV_) const std::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. std::string StringFromGTestEnv(const char* flag, const char* default_value) { #if defined(GTEST_GET_STRING_FROM_ENV_) return GTEST_GET_STRING_FROM_ENV_(flag, default_value); #endif // defined(GTEST_GET_STRING_FROM_ENV_) const std::string env_var = FlagToEnvVar(flag); const char* value = posix::GetEnv(env_var.c_str()); if (value != NULL) { return value; } // As a special case for the 'output' flag, if GTEST_OUTPUT is not // set, we look for XML_OUTPUT_FILE, which is set by the Bazel build // system. The value of XML_OUTPUT_FILE is a filename without the // "xml:" prefix of GTEST_OUTPUT. // // The net priority order after flag processing is thus: // --gtest_output command line flag // GTEST_OUTPUT environment variable // XML_OUTPUT_FILE environment variable // 'default_value' if (strcmp(flag, "output") == 0) { value = posix::GetEnv("XML_OUTPUT_FILE"); if (value != NULL) { return std::string("xml:") + value; } } return default_value; } } // namespace internal } // namespace testing assimp-4.1.0/contrib/gtest/src/gtest-filepath.cc0000644002537200234200000003433113213503245022064 0ustar zmoelnigiemusers// 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/gtest-message.h" #include "gtest/internal/gtest-filepath.h" #include "gtest/internal/gtest-port.h" #include #if GTEST_OS_WINDOWS_MOBILE # include #elif GTEST_OS_WINDOWS # include # include #elif GTEST_OS_SYMBIAN // Symbian OpenC has PATH_MAX in sys/syslimits.h # include #else # include # include // 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 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 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 || GTEST_OS_WINDOWS_PHONE || GTEST_OS_WINDOWS_RT // 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' }; char* result = getcwd(cwd, sizeof(cwd)); # if GTEST_OS_NACL // getcwd will likely fail in NaCl due to the sandbox, so return something // reasonable. The user may have provided a shim implementation for getcwd, // however, so fallback only when failure is detected. return FilePath(result == NULL ? kCurrentDirectoryString : cwd); # endif // GTEST_OS_NACL return FilePath(result == 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 { const std::string dot_extension = std::string(".") + extension; if (String::EndsWithCaseInsensitive(pathname_, dot_extension)) { return FilePath(pathname_.substr( 0, pathname_.length() - dot_extension.length())); } 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(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(); std::string dir; if (last_sep) { dir = std::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) { std::string file; if (number == 0) { file = base_name.string() + "." + extension; } else { file = base_name.string() + "_" + StreamableToString(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(dir.string() + kPathSeparator + relative_path.string()); } // 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_.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(pathname_.substr(0, 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 assimp-4.1.0/contrib/gtest/src/gtest-all.cc0000644002537200234200000000416113213503245021036 0ustar zmoelnigiemusers// 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-printers.cc" #include "src/gtest-test-part.cc" #include "src/gtest-typed-test.cc" assimp-4.1.0/contrib/gtest/src/gtest-typed-test.cc0000644002537200234200000000757013213503245022377 0ustar zmoelnigiemusers// 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; } static std::vector SplitIntoTestNames(const char* src) { std::vector name_vec; src = SkipSpaces(src); for (; src != NULL; src = SkipComma(src)) { name_vec.push_back(StripTrailingSpaces(GetPrefixUntilComma(src))); } return name_vec; } // Verifies that registered_tests match the test names in // registered_tests_; returns registered_tests if successful, or // aborts the program otherwise. const char* TypedTestCasePState::VerifyRegisteredTestNames( const char* file, int line, const char* registered_tests) { typedef RegisteredTestsMap::const_iterator RegisteredTestIter; registered_ = true; std::vector name_vec = SplitIntoTestNames(registered_tests); Message errors; std::set tests; for (std::vector::const_iterator name_it = name_vec.begin(); name_it != name_vec.end(); ++name_it) { const std::string& name = *name_it; if (tests.count(name) != 0) { errors << "Test " << name << " is listed more than once.\n"; continue; } bool found = false; for (RegisteredTestIter it = registered_tests_.begin(); it != registered_tests_.end(); ++it) { if (name == it->first) { found = true; break; } } if (found) { tests.insert(name); } else { errors << "No test named " << name << " can be found in this test case.\n"; } } for (RegisteredTestIter it = registered_tests_.begin(); it != registered_tests_.end(); ++it) { if (tests.count(it->first) == 0) { errors << "You forgot to list test " << it->first << ".\n"; } } const std::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 assimp-4.1.0/contrib/gtest/src/gtest-internal-inl.h0000644002537200234200000013064313213503245022531 0ustar zmoelnigiemusers// 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_ // If this file is included from the user's 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 #endif // !_WIN32_WCE #include #include // For strtoll/_strtoul64/malloc/free. #include // For memmove. #include #include #include #include "gtest/internal/gtest-port.h" #if GTEST_CAN_STREAM_RESULTS_ # include // NOLINT # include // NOLINT #endif #if GTEST_OS_WINDOWS # include // NOLINT #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 kStreamResultToFlag[] = "stream_result_to"; const char kThrowOnFailureFlag[] = "throw_on_failure"; const char kFlagfileFlag[] = "flagfile"; // 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); // Converts the given time in milliseconds to a date string in the ISO 8601 // format, without the timezone information. N.B.: due to the use the // non-reentrant localtime() function, this function is not thread safe. Do // not use it in any code that can be called from multiple threads. GTEST_API_ std::string FormatEpochTimeInMillisAsIso8601(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(GetTimeInMillis()) : static_cast(random_seed_flag); // Normalizes the actual seed to range [1, kMaxRandomSeed] such that // it's easy to type. const int normalized_seed = static_cast((raw_seed - 1U) % static_cast(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); stream_result_to_ = GTEST_FLAG(stream_result_to); 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(stream_result_to) = stream_result_to_; 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_; std::string color_; std::string death_test_style_; bool death_test_use_fork_; std::string filter_; std::string internal_run_death_test_; bool list_tests_; std::string output_; bool print_time_; internal::Int32 random_seed_; internal::Int32 repeat_; bool shuffle_; internal::Int32 stack_trace_depth_; std::string stream_result_to_; 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. // 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 converted // to "(Invalid Unicode 0xXXXXXXXX)". GTEST_API_ std::string CodePointToUtf8(UInt32 code_point); // 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_ std::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 inline int CountIf(const Container& c, Predicate predicate) { // Implemented as an explicit loop since std::count_if() in libCstd on // Solaris has a non-standard signature. int count = 0; for (typename Container::const_iterator it = c.begin(); it != c.end(); ++it) { if (predicate(*it)) ++count; } return count; } // Applies a function/functor to each element in the container. template 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 inline E GetElementOr(const std::vector& v, int i, E default_value) { return (i < 0 || i >= static_cast(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 void ShuffleRange(internal::Random* random, int begin, int end, std::vector* v) { const int size = static_cast(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 inline void Shuffle(internal::Random* random, std::vector* v) { ShuffleRange(random, 0, static_cast(v->size()), v); } // A function for deleting an object. Handy for being used as a // functor. template 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 std::string& key) : key_(key) {} // Returns true iff the test name of test property matches on key_. bool operator()(const TestProperty& test_property) const { return test_property.key() == key_; } private: std::string key_; }; // 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 std::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 std::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 std::string &test_case_name, const std::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 std::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 an std::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; // This string is inserted in place of stack frames that are part of // Google Test's implementation. static const char* const kElidedFramesMarker; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetterInterface); }; // A working implementation of the OsStackTraceGetterInterface interface. class OsStackTraceGetter : public OsStackTraceGetterInterface { public: OsStackTraceGetter() {} virtual string CurrentStackTrace(int max_depth, int skip_count); virtual void UponLeavingGTest(); private: GTEST_DISALLOW_COPY_AND_ASSIGN_(OsStackTraceGetter); }; // Information about a Google Test trace point. struct TraceInfo { const char* file; int line; std::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 that will be reported in the XML report. int reportable_disabled_test_count() const; // Gets the number of disabled tests. int disabled_test_count() const; // Gets the number of tests to be printed in the XML report. int reportable_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 time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp() const { return start_timestamp_; } // 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 an std::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. std::string CurrentOsStackTraceExceptTop(int skip_count) GTEST_NO_INLINE_; // 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 // type_param: the name of the test's type parameter, or NULL if // this is not a typed or a type-parameterized test. // 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* type_param, 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->type_param(), 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_CASE_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 true if all tests are successful. If any exception is // thrown during a test, this test is considered to be failed, but // the rest of the tests will still be run. bool RunAllTests(); // Clears the results of all tests, except the ad hoc tests. void ClearNonAdHocTestResult() { ForEach(test_cases_, TestCase::ClearTestCaseResult); } // Clears the results of ad-hoc test assertions. void ClearAdHocTestResult() { ad_hoc_test_result_.Clear(); } // Adds a TestProperty to the current TestResult object when invoked in a // context of a test or a test case, or to the global property set. If the // result already contains a property with the same key, the value will be // updated. void RecordProperty(const TestProperty& test_property); 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& environments() { return environments_; } // Getters for the per-thread Google Test trace stack. std::vector& gtest_trace_stack() { return *(gtest_trace_stack_.pointer()); } const std::vector& 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(); #if GTEST_CAN_STREAM_RESULTS_ // Initializes the event listener for streaming test results to a socket. // Must not be called before InitGoogleTest. void ConfigureStreamingOutput(); #endif // 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(); // Returns the value of GTEST_FLAG(catch_exceptions) at the moment // UnitTest::Run() starts. bool catch_exceptions() const { return catch_exceptions_; } private: friend class ::testing::UnitTest; // Used by UnitTest::Run() to capture the state of // GTEST_FLAG(catch_exceptions) at the moment it starts. void set_catch_exceptions(bool value) { catch_exceptions_ = value; } // 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 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 environments_; // The vector of TestCases in their original order. It owns the // elements in the vector. std::vector 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 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_; // The time of the test program start, in ms from the start of the // UNIX epoch. TimeInMillis start_timestamp_; // 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 internal_run_death_test_flag_; internal::scoped_ptr death_test_factory_; #endif // GTEST_HAS_DEATH_TEST // A per-thread stack of traces created by the SCOPED_TRACE() macro. internal::ThreadLocal > gtest_trace_stack_; // The value of GTEST_FLAG(catch_exceptions) at the moment RunAllTests() // starts. bool catch_exceptions_; GTEST_DISALLOW_COPY_AND_ASSIGN_(UnitTestImpl); }; // class UnitTestImpl // Convenience function for accessing the global UnitTest // implementation object. inline UnitTestImpl* GetUnitTestImpl() { return UnitTest::GetInstance()->impl(); } #if GTEST_USES_SIMPLE_RE // Internal helper functions for implementing the simple regular // expression matcher. GTEST_API_ bool IsInSet(char ch, const char* str); GTEST_API_ bool IsAsciiDigit(char ch); GTEST_API_ bool IsAsciiPunct(char ch); GTEST_API_ bool IsRepeat(char ch); GTEST_API_ bool IsAsciiWhiteSpace(char ch); GTEST_API_ bool IsAsciiWordChar(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); #endif // GTEST_USES_SIMPLE_RE // 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. GTEST_API_ std::string GetLastErrnoDescription(); // 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 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(parsed); if (parse_success && static_cast(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 std::string& xml_element, const TestProperty& property) { test_result->RecordProperty(xml_element, property); } static void ClearTestPartResults(TestResult* test_result) { test_result->ClearTestPartResults(); } static const std::vector& test_part_results( const TestResult& test_result) { return test_result.test_part_results(); } }; #if GTEST_CAN_STREAM_RESULTS_ // Streams test results to the given port on the given host machine. class GTEST_API_ StreamingListener : public EmptyTestEventListener { public: // Abstract base class for writing strings to a socket. class AbstractSocketWriter { public: virtual ~AbstractSocketWriter() {} // Sends a string to the socket. virtual void Send(const string& message) = 0; // Closes the socket. virtual void CloseConnection() {} // Sends a string and a newline to the socket. void SendLn(const string& message) { Send(message + "\n"); } }; // Concrete class for actually writing strings to a socket. class SocketWriter : public AbstractSocketWriter { public: SocketWriter(const string& host, const string& port) : sockfd_(-1), host_name_(host), port_num_(port) { MakeConnection(); } virtual ~SocketWriter() { if (sockfd_ != -1) CloseConnection(); } // Sends a string to the socket. virtual void Send(const string& message) { GTEST_CHECK_(sockfd_ != -1) << "Send() can be called only when there is a connection."; const int len = static_cast(message.length()); if (write(sockfd_, message.c_str(), len) != len) { GTEST_LOG_(WARNING) << "stream_result_to: failed to stream to " << host_name_ << ":" << port_num_; } } private: // Creates a client socket and connects to the server. void MakeConnection(); // Closes the socket. void CloseConnection() { GTEST_CHECK_(sockfd_ != -1) << "CloseConnection() can be called only when there is a connection."; close(sockfd_); sockfd_ = -1; } int sockfd_; // socket file descriptor const string host_name_; const string port_num_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SocketWriter); }; // class SocketWriter // Escapes '=', '&', '%', and '\n' characters in str as "%xx". static string UrlEncode(const char* str); StreamingListener(const string& host, const string& port) : socket_writer_(new SocketWriter(host, port)) { Start(); } explicit StreamingListener(AbstractSocketWriter* socket_writer) : socket_writer_(socket_writer) { Start(); } void OnTestProgramStart(const UnitTest& /* unit_test */) { SendLn("event=TestProgramStart"); } void OnTestProgramEnd(const UnitTest& unit_test) { // Note that Google Test current only report elapsed time for each // test iteration, not for the entire test program. SendLn("event=TestProgramEnd&passed=" + FormatBool(unit_test.Passed())); // Notify the streaming server to stop. socket_writer_->CloseConnection(); } void OnTestIterationStart(const UnitTest& /* unit_test */, int iteration) { SendLn("event=TestIterationStart&iteration=" + StreamableToString(iteration)); } void OnTestIterationEnd(const UnitTest& unit_test, int /* iteration */) { SendLn("event=TestIterationEnd&passed=" + FormatBool(unit_test.Passed()) + "&elapsed_time=" + StreamableToString(unit_test.elapsed_time()) + "ms"); } void OnTestCaseStart(const TestCase& test_case) { SendLn(std::string("event=TestCaseStart&name=") + test_case.name()); } void OnTestCaseEnd(const TestCase& test_case) { SendLn("event=TestCaseEnd&passed=" + FormatBool(test_case.Passed()) + "&elapsed_time=" + StreamableToString(test_case.elapsed_time()) + "ms"); } void OnTestStart(const TestInfo& test_info) { SendLn(std::string("event=TestStart&name=") + test_info.name()); } void OnTestEnd(const TestInfo& test_info) { SendLn("event=TestEnd&passed=" + FormatBool((test_info.result())->Passed()) + "&elapsed_time=" + StreamableToString((test_info.result())->elapsed_time()) + "ms"); } void OnTestPartResult(const TestPartResult& test_part_result) { const char* file_name = test_part_result.file_name(); if (file_name == NULL) file_name = ""; SendLn("event=TestPartResult&file=" + UrlEncode(file_name) + "&line=" + StreamableToString(test_part_result.line_number()) + "&message=" + UrlEncode(test_part_result.message())); } private: // Sends the given message and a newline to the socket. void SendLn(const string& message) { socket_writer_->SendLn(message); } // Called at the start of streaming to notify the receiver what // protocol we are using. void Start() { SendLn("gtest_streaming_protocol_version=1.0"); } string FormatBool(bool value) { return value ? "1" : "0"; } const scoped_ptr socket_writer_; GTEST_DISALLOW_COPY_AND_ASSIGN_(StreamingListener); }; // class StreamingListener #endif // GTEST_CAN_STREAM_RESULTS_ } // namespace internal } // namespace testing #endif // GTEST_SRC_GTEST_INTERNAL_INL_H_ assimp-4.1.0/contrib/gtest/m4/0000755002537200234200000000000013213503245016362 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/m4/gtest.m40000644002537200234200000000622113213503245017753 0ustar zmoelnigiemusersdnl 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])]) ]) assimp-4.1.0/contrib/gtest/m4/acx_pthread.m40000644002537200234200000003176613213503245021123 0ustar zmoelnigiemusers# 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 dnl @version 2006-05-29 dnl @license GPLWithACException dnl dnl Checks for GCC shared/pthread inconsistency based on work by dnl Marcin Owsiany 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_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 ], [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_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_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_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 assimp-4.1.0/contrib/gtest/xcode/0000755002537200234200000000000013213503245017144 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/xcode/Config/0000755002537200234200000000000013213503245020351 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/xcode/Config/FrameworkTarget.xcconfig0000644002537200234200000000104713213503245025201 0ustar zmoelnigiemusers// // 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 assimp-4.1.0/contrib/gtest/xcode/Config/DebugProject.xcconfig0000644002537200234200000000172713213503245024457 0ustar zmoelnigiemusers// // 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 assimp-4.1.0/contrib/gtest/xcode/Config/TestTarget.xcconfig0000644002537200234200000000035613213503245024165 0ustar zmoelnigiemusers// // 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 assimp-4.1.0/contrib/gtest/xcode/Config/General.xcconfig0000644002537200234200000000225713213503245023456 0ustar zmoelnigiemusers// // 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/ // // Build for PPC and Intel, 32- and 64-bit ARCHS = i386 x86_64 ppc ppc64 // 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 // Default SDK and minimum OS version is 10.4 SDKROOT = $(DEVELOPER_SDK_DIR)/MacOSX10.4u.sdk MACOSX_DEPLOYMENT_TARGET = 10.4 GCC_VERSION = 4.0 // VERSIONING BUILD SETTINGS (used in Info.plist) GTEST_VERSIONINFO_ABOUT = © 2008 Google Inc. assimp-4.1.0/contrib/gtest/xcode/Config/ReleaseProject.xcconfig0000644002537200234200000000174113213503245025005 0ustar zmoelnigiemusers// // 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 assimp-4.1.0/contrib/gtest/xcode/Config/StaticLibraryTarget.xcconfig0000644002537200234200000000111313213503245026012 0ustar zmoelnigiemusers// // 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 assimp-4.1.0/contrib/gtest/xcode/Resources/0000755002537200234200000000000013213503245021116 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/xcode/Resources/Info.plist0000644002537200234200000000176213213503245023074 0ustar zmoelnigiemusers CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier com.google.${PRODUCT_NAME} CFBundleInfoDictionaryVersion 6.0 CFBundlePackageType FMWK CFBundleSignature ???? CFBundleVersion GTEST_VERSIONINFO_LONG CFBundleShortVersionString GTEST_VERSIONINFO_SHORT CFBundleGetInfoString ${PRODUCT_NAME} GTEST_VERSIONINFO_LONG, ${GTEST_VERSIONINFO_ABOUT} NSHumanReadableCopyright ${GTEST_VERSIONINFO_ABOUT} CSResourcesFileMapped assimp-4.1.0/contrib/gtest/xcode/Samples/0000755002537200234200000000000013213503245020550 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/xcode/Samples/FrameworkSample/0000755002537200234200000000000013213503245023647 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/xcode/Samples/FrameworkSample/widget_test.cc0000644002537200234200000000515513213503245026506 0ustar zmoelnigiemusers// 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 #include "gtest/gtest.h" #include // 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(); // } assimp-4.1.0/contrib/gtest/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/0000755002537200234200000000000013213503245030744 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj0000644002537200234200000003727413213503245034035 0ustar zmoelnigiemusers// !$*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 = ""; }; 3B7EB1240E5AEE3500C7F239 /* widget.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = widget.h; sourceTree = ""; }; 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = widget_test.cc; sourceTree = ""; }; 4024D183113D7D5500C7059E /* libgtest_main.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgtest_main.a; path = /usr/local/lib/libgtest_main.a; sourceTree = ""; }; 4024D185113D7D5500C7059E /* libgtest.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libgtest.a; path = /usr/local/lib/libgtest.a; sourceTree = ""; }; 4024D1E2113D838200C7059E /* runtests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = runtests.sh; sourceTree = ""; }; 8D07F2C70486CC7A007CD1D0 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = ""; }; 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 = ""; }; 0867D691FE84028FC02AAC07 /* gTestExample */ = { isa = PBXGroup; children = ( 4024D1E1113D836C00C7059E /* Scripts */, 08FB77ACFE841707C02AAC07 /* Source */, 089C1665FE841158C02AAC07 /* Resources */, 3B07BE350E4094E400647869 /* Test */, 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */, 034768DDFF38A45A11DB9C8B /* Products */, ); name = gTestExample; sourceTree = ""; }; 0867D69AFE84028FC02AAC07 /* External Frameworks and Libraries */ = { isa = PBXGroup; children = ( 4024D183113D7D5500C7059E /* libgtest_main.a */, 4024D185113D7D5500C7059E /* libgtest.a */, ); name = "External Frameworks and Libraries"; sourceTree = ""; }; 089C1665FE841158C02AAC07 /* Resources */ = { isa = PBXGroup; children = ( 8D07F2C70486CC7A007CD1D0 /* Info.plist */, ); name = Resources; sourceTree = ""; }; 08FB77ACFE841707C02AAC07 /* Source */ = { isa = PBXGroup; children = ( 3B7EB1230E5AEE3500C7F239 /* widget.cc */, 3B7EB1240E5AEE3500C7F239 /* widget.h */, ); name = Source; sourceTree = ""; }; 3B07BE350E4094E400647869 /* Test */ = { isa = PBXGroup; children = ( 3B7EB1270E5AEE4600C7F239 /* widget_test.cc */, ); name = Test; sourceTree = ""; }; 4024D1E1113D836C00C7059E /* Scripts */ = { isa = PBXGroup; children = ( 4024D1E2113D838200C7059E /* runtests.sh */, ); name = Scripts; sourceTree = ""; }; /* 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 */; } assimp-4.1.0/contrib/gtest/xcode/Samples/FrameworkSample/Info.plist0000644002537200234200000000151613213503245025622 0ustar zmoelnigiemusers CFBundleDevelopmentRegion English CFBundleExecutable ${EXECUTABLE_NAME} CFBundleIconFile CFBundleIdentifier com.google.gtest.${PRODUCT_NAME:identifier} CFBundleInfoDictionaryVersion 6.0 CFBundleName ${PRODUCT_NAME} CFBundlePackageType FMWK CFBundleShortVersionString 1.0 CFBundleSignature ???? CFBundleVersion 1.0 CSResourcesFileMapped assimp-4.1.0/contrib/gtest/xcode/Samples/FrameworkSample/runtests.sh0000644002537200234200000000446213213503245026100 0ustar zmoelnigiemusers#!/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 assimp-4.1.0/contrib/gtest/xcode/Samples/FrameworkSample/widget.h0000644002537200234200000000433613213503245025311 0ustar zmoelnigiemusers// 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 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_; }; assimp-4.1.0/contrib/gtest/xcode/Samples/FrameworkSample/widget.cc0000644002537200234200000000440313213503245025442 0ustar zmoelnigiemusers// 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(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; } assimp-4.1.0/contrib/gtest/xcode/gtest.xcodeproj/0000755002537200234200000000000013213503245022266 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/xcode/gtest.xcodeproj/project.pbxproj0000644002537200234200000014346113213503245025353 0ustar zmoelnigiemusers// !$*UTF8*$! { archiveVersion = 1; classes = { }; objectVersion = 46; 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.md in Resources */ = {isa = PBXBuildFile; fileRef = 404883F60E2F799B00CF7658 /* README.md */; }; 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 /* LICENSE in Resources */ = {isa = PBXBuildFile; fileRef = 404884AB0E2F7CD900CF7658 /* LICENSE */; }; 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 */; }; 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 */; }; 4567C8181264FF71007740BE /* gtest-printers.h in Headers */ = {isa = PBXBuildFile; fileRef = 4567C8171264FF71007740BE /* gtest-printers.h */; settings = {ATTRIBUTES = (Public, ); }; }; /* 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 = ""; }; 224A12A20E9EADCC00BD17FD /* gtest-test-part.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = "gtest-test-part.h"; sourceTree = ""; }; 3B238C120E7FE13C00846E11 /* gtest_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gtest_unittest.cc; sourceTree = ""; }; 3B87D2100E96B92E000D1852 /* runtests.sh */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.sh; path = runtests.sh; sourceTree = ""; }; 3BF6F29F0E79B5AD000F2EEE /* gtest-type-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-type-util.h"; sourceTree = ""; }; 3BF6F2A40E79B616000F2EEE /* gtest-typed-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-typed-test.h"; sourceTree = ""; }; 403EE37C0E377822004BD1E2 /* versiongenerate.py */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.script.python; path = versiongenerate.py; sourceTree = ""; }; 404883DB0E2F799B00CF7658 /* gtest-death-test.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test.h"; sourceTree = ""; }; 404883DC0E2F799B00CF7658 /* gtest-message.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-message.h"; sourceTree = ""; }; 404883DD0E2F799B00CF7658 /* gtest-spi.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-spi.h"; sourceTree = ""; }; 404883DE0E2F799B00CF7658 /* gtest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest.h; sourceTree = ""; }; 404883DF0E2F799B00CF7658 /* gtest_pred_impl.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest_pred_impl.h; sourceTree = ""; }; 404883E00E2F799B00CF7658 /* gtest_prod.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = gtest_prod.h; sourceTree = ""; }; 404883E20E2F799B00CF7658 /* gtest-death-test-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-death-test-internal.h"; sourceTree = ""; }; 404883E30E2F799B00CF7658 /* gtest-filepath.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-filepath.h"; sourceTree = ""; }; 404883E40E2F799B00CF7658 /* gtest-internal.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-internal.h"; sourceTree = ""; }; 404883E50E2F799B00CF7658 /* gtest-port.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-port.h"; sourceTree = ""; }; 404883E60E2F799B00CF7658 /* gtest-string.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-string.h"; sourceTree = ""; }; 404883F60E2F799B00CF7658 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = README.md; path = ../README.md; sourceTree = SOURCE_ROOT; }; 4048840D0E2F799B00CF7658 /* gtest_main.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = gtest_main.cc; sourceTree = ""; }; 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 /* LICENSE */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = LICENSE; path = ../LICENSE; 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 = ""; }; 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = StaticLibraryTarget.xcconfig; sourceTree = ""; }; 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 = ""; }; 4089A02D0FFACF7F000B29AE /* sample1.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = sample1.h; sourceTree = ""; }; 4089A02E0FFACF7F000B29AE /* sample1_unittest.cc */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = sample1_unittest.cc; sourceTree = ""; }; 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 = ""; }; 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = FrameworkTarget.xcconfig; sourceTree = ""; }; 40D4CDF30E30E07400294801 /* General.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = General.xcconfig; sourceTree = ""; }; 40D4CDF40E30E07400294801 /* ReleaseProject.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = ReleaseProject.xcconfig; sourceTree = ""; }; 40D4CF510E30F5E200294801 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 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 = ""; }; 4539C9350EC280E200A70F4C /* gtest-linked_ptr.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-linked_ptr.h"; sourceTree = ""; }; 4539C9360EC280E200A70F4C /* gtest-param-util-generated.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-util-generated.h"; sourceTree = ""; }; 4539C9370EC280E200A70F4C /* gtest-param-util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-param-util.h"; sourceTree = ""; }; 4567C8171264FF71007740BE /* gtest-printers.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "gtest-printers.h"; sourceTree = ""; }; /* 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; }; /* 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 = ""; }; 0867D691FE84028FC02AAC07 /* gtest */ = { isa = PBXGroup; children = ( 40D4CDF00E30E07400294801 /* Config */, 08FB77ACFE841707C02AAC07 /* Source */, 40D4CF4E0E30F5E200294801 /* Resources */, 403EE37B0E377822004BD1E2 /* Scripts */, 034768DDFF38A45A11DB9C8B /* Products */, ); name = gtest; sourceTree = ""; }; 08FB77ACFE841707C02AAC07 /* Source */ = { isa = PBXGroup; children = ( 404884A90E2F7CD900CF7658 /* CHANGES */, 404884AA0E2F7CD900CF7658 /* CONTRIBUTORS */, 404884AB0E2F7CD900CF7658 /* LICENSE */, 404883F60E2F799B00CF7658 /* README.md */, 404883D90E2F799B00CF7658 /* include */, 4089A02F0FFACF84000B29AE /* samples */, 404884070E2F799B00CF7658 /* src */, 3B238BF00E7FE13B00846E11 /* test */, ); name = Source; sourceTree = ""; }; 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 = ""; }; 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 */, 4567C8171264FF71007740BE /* gtest-printers.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 = ""; }; 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 = ""; }; 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 */, 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */, ); path = Config; sourceTree = ""; }; 40D4CF4E0E30F5E200294801 /* Resources */ = { isa = PBXGroup; children = ( 40D4CF510E30F5E200294801 /* Info.plist */, ); path = Resources; sourceTree = ""; }; /* 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 */, 4567C8181264FF71007740BE /* gtest-printers.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 */, ); 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; attributes = { LastUpgradeCheck = 0460; }; buildConfigurationList = 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "gtest" */; compatibilityVersion = "Xcode 3.2"; 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.md in Resources */, 404884AC0E2F7CD900CF7658 /* CHANGES in Resources */, 404884AD0E2F7CD900CF7658 /* CONTRIBUTORS in Resources */, 404884AE0E2F7CD900CF7658 /* LICENSE 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 = { COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = NO; GCC_DYNAMIC_NO_PIC = NO; GCC_OPTIMIZATION_LEVEL = 0; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; PRODUCT_NAME = Check; SDKROOT = macosx; }; name = Debug; }; 3B238F610E828B5400846E11 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; COPY_PHASE_STRIP = YES; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; PRODUCT_NAME = Check; SDKROOT = macosx; ZERO_LINK = NO; }; name = Release; }; 40899F450FFA7185000B29AE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ../; PRODUCT_NAME = "gtest_unittest-framework"; SDKROOT = macosx; }; name = Debug; }; 40899F460FFA7185000B29AE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ../; PRODUCT_NAME = "gtest_unittest-framework"; SDKROOT = macosx; }; name = Release; }; 4089A0150FFACEFD000B29AE /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; PRODUCT_NAME = "sample1_unittest-framework"; SDKROOT = macosx; }; name = Debug; }; 4089A0160FFACEFD000B29AE /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; PRODUCT_NAME = "sample1_unittest-framework"; SDKROOT = macosx; }; name = Release; }; 40C44ADF0E3798F4008FCC51 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = gtest; SDKROOT = macosx; TARGET_NAME = gtest; }; name = Debug; }; 40C44AE00E3798F4008FCC51 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = gtest; SDKROOT = macosx; TARGET_NAME = gtest; }; name = Release; }; 40C848FB101A209D0083642A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = YES; GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( ../, ../include/, ); PRODUCT_NAME = gtest; SDKROOT = macosx; }; name = Debug; }; 40C848FC101A209D0083642A /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_INLINES_ARE_PRIVATE_EXTERN = YES; GCC_SYMBOLS_PRIVATE_EXTERN = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( ../, ../include/, ); PRODUCT_NAME = gtest; SDKROOT = macosx; }; name = Release; }; 40C8490E101A217F0083642A /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( ../, ../include/, ); PRODUCT_NAME = gtest_main; SDKROOT = macosx; }; name = Debug; }; 40C8490F101A217F0083642A /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40899FB30FFA7567000B29AE /* StaticLibraryTarget.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( ../, ../include/, ); PRODUCT_NAME = gtest_main; SDKROOT = macosx; }; name = Release; }; 40C84985101A36850083642A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ../; PRODUCT_NAME = gtest_unittest; SDKROOT = macosx; }; name = Debug; }; 40C84986101A36850083642A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ../; PRODUCT_NAME = gtest_unittest; SDKROOT = macosx; }; name = Release; }; 40C84995101A36A60083642A /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; PRODUCT_NAME = "sample1_unittest-static"; SDKROOT = macosx; }; name = Debug; }; 40C84996101A36A60083642A /* Release */ = { isa = XCBuildConfiguration; buildSettings = { GCC_VERSION = com.apple.compilers.llvm.clang.1_0; PRODUCT_NAME = "sample1_unittest-static"; SDKROOT = macosx; }; name = Release; }; 4FADC24308B4156D00ABE55E /* Debug */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( ../, ../include/, ); INFOPLIST_FILE = Resources/Info.plist; INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h"; INFOPLIST_PREPROCESS = YES; PRODUCT_NAME = gtest; SDKROOT = macosx; VERSIONING_SYSTEM = "apple-generic"; }; name = Debug; }; 4FADC24408B4156D00ABE55E /* Release */ = { isa = XCBuildConfiguration; baseConfigurationReference = 40D4CDF20E30E07400294801 /* FrameworkTarget.xcconfig */; buildSettings = { COMBINE_HIDPI_IMAGES = YES; DYLIB_COMPATIBILITY_VERSION = 1; DYLIB_CURRENT_VERSION = 1; GCC_VERSION = com.apple.compilers.llvm.clang.1_0; HEADER_SEARCH_PATHS = ( ../, ../include/, ); INFOPLIST_FILE = Resources/Info.plist; INFOPLIST_PREFIX_HEADER = "$(PROJECT_TEMP_DIR)/Version.h"; INFOPLIST_PREPROCESS = YES; PRODUCT_NAME = gtest; SDKROOT = macosx; 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 */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40899F4A0FFA71BC000B29AE /* Build configuration list for PBXNativeTarget "gtest_unittest-framework" */ = { isa = XCConfigurationList; buildConfigurations = ( 40899F450FFA7185000B29AE /* Debug */, 40899F460FFA7185000B29AE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4089A0240FFACF01000B29AE /* Build configuration list for PBXNativeTarget "sample1_unittest-framework" */ = { isa = XCConfigurationList; buildConfigurations = ( 4089A0150FFACEFD000B29AE /* Debug */, 4089A0160FFACEFD000B29AE /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C44AE40E379905008FCC51 /* Build configuration list for PBXAggregateTarget "Version Info" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C44ADF0E3798F4008FCC51 /* Debug */, 40C44AE00E3798F4008FCC51 /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C84902101A212E0083642A /* Build configuration list for PBXNativeTarget "gtest-static" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C848FB101A209D0083642A /* Debug */, 40C848FC101A209D0083642A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C84912101A21D20083642A /* Build configuration list for PBXNativeTarget "gtest_main-static" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C8490E101A217F0083642A /* Debug */, 40C8490F101A217F0083642A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C84984101A36850083642A /* Build configuration list for PBXNativeTarget "gtest_unittest-static" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C84985101A36850083642A /* Debug */, 40C84986101A36850083642A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 40C84994101A36A60083642A /* Build configuration list for PBXNativeTarget "sample1_unittest-static" */ = { isa = XCConfigurationList; buildConfigurations = ( 40C84995101A36A60083642A /* Debug */, 40C84996101A36A60083642A /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4FADC24208B4156D00ABE55E /* Build configuration list for PBXNativeTarget "gtest-framework" */ = { isa = XCConfigurationList; buildConfigurations = ( 4FADC24308B4156D00ABE55E /* Debug */, 4FADC24408B4156D00ABE55E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; 4FADC24608B4156D00ABE55E /* Build configuration list for PBXProject "gtest" */ = { isa = XCConfigurationList; buildConfigurations = ( 4FADC24708B4156D00ABE55E /* Debug */, 4FADC24808B4156D00ABE55E /* Release */, ); defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; /* End XCConfigurationList section */ }; rootObject = 0867D690FE84028FC02AAC07 /* Project object */; } assimp-4.1.0/contrib/gtest/xcode/Scripts/0000755002537200234200000000000013213503245020573 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/xcode/Scripts/versiongenerate.py0000644002537200234200000001067013213503245024351 0ustar zmoelnigiemusers#!/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() assimp-4.1.0/contrib/gtest/xcode/Scripts/runtests.sh0000644002537200234200000000503313213503245023017 0ustar zmoelnigiemusers#!/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 assimp-4.1.0/contrib/gtest/build-aux/0000755002537200234200000000000013213503245017734 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/build-aux/.keep0000644002537200234200000000000013213503245020647 0ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/codegear/0000755002537200234200000000000013213503245017613 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/codegear/gtest.cbproj0000644002537200234200000002436613213503245022155 0ustar zmoelnigiemusers {bca37a72-5b07-46cf-b44e-89f8e06451a2} Release true true true Base true true Base true lib JPHNE NO_STRICT true true CppStaticLibrary true 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 false $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;.. rtl.lib;vcl.lib 32 $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk false false true _DEBUG;$(Defines) true false true None DEBUG true Debug true true true $(BDS)\lib\debug;$(ILINK_LibraryPath) Full true NDEBUG;$(Defines) Release $(BDS)\lib\release;$(ILINK_LibraryPath) None CPlusPlusBuilder.Personality CppStaticLibrary FalseFalse1000FalseFalseFalseFalseFalse103312521.0.0.01.0.0.0FalseFalseFalseTrueFalse CodeGear C++Builder Office 2000 Servers Package CodeGear C++Builder Office XP Servers Package FalseTrueTrue3$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include1$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk1NO_STRICT13216 3 4 5 6 7 8 0 1 2 9 10 11 12 14 13 15 16 17 18 Cfg_1 Cfg_2 assimp-4.1.0/contrib/gtest/codegear/gtest_link.cc0000644002537200234200000000371113213503245022267 0ustar zmoelnigiemusers// 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" assimp-4.1.0/contrib/gtest/codegear/gtest_all.cc0000644002537200234200000000351113213503245022100 0ustar zmoelnigiemusers// 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" assimp-4.1.0/contrib/gtest/codegear/gtest_unittest.cbproj0000644002537200234200000002076313213503245024111 0ustar zmoelnigiemusers {eea63393-5ac5-4b9c-8909-d75fef2daa41} Release true true true Base true true Base exe true NO_STRICT JPHNE true ..\test true CppConsoleApplication true true 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 false $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;.. $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test true false false true _DEBUG;$(Defines) true false true None DEBUG true Debug true true true $(BDS)\lib\debug;$(ILINK_LibraryPath) Full true NDEBUG;$(Defines) Release $(BDS)\lib\release;$(ILINK_LibraryPath) None CPlusPlusBuilder.Personality CppConsoleApplication FalseFalse1000FalseFalseFalseFalseFalse103312521.0.0.01.0.0.0FalseFalseFalseTrueFalse CodeGear C++Builder Office 2000 Servers Package CodeGear C++Builder Office XP Servers Package FalseTrueTrue3$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include;..\test$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\include1$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;..\test$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk;$(OUTPUTDIR);..\test2NO_STRICTSTRICT 0 1 Cfg_1 Cfg_2 assimp-4.1.0/contrib/gtest/codegear/gtest_main.cbproj0000644002537200234200000002060413213503245023150 0ustar zmoelnigiemusers {bca37a72-5b07-46cf-b44e-89f8e06451a2} Release true true true Base true true Base true lib JPHNE NO_STRICT true true CppStaticLibrary true 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 false $(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;.. rtl.lib;vcl.lib 32 $(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk false false true _DEBUG;$(Defines) true false true None DEBUG true Debug true true true $(BDS)\lib\debug;$(ILINK_LibraryPath) Full true NDEBUG;$(Defines) Release $(BDS)\lib\release;$(ILINK_LibraryPath) None CPlusPlusBuilder.Personality CppStaticLibrary FalseFalse1000FalseFalseFalseFalseFalse103312521.0.0.01.0.0.0FalseFalseFalseTrueFalse CodeGear C++Builder Office 2000 Servers Package CodeGear C++Builder Office XP Servers Package FalseTrueTrue3$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\include;..$(BDS)\include;$(BDS)\include\dinkumware;$(BDS)\include\vcl;..\src;..\src;..\include1$(BDS)\lib;$(BDS)\lib\obj;$(BDS)\lib\psdk1NO_STRICT13216 0 Cfg_1 Cfg_2 assimp-4.1.0/contrib/gtest/codegear/gtest.groupproj0000644002537200234200000000373013213503245022715 0ustar zmoelnigiemusers {c1d923e0-6cba-4332-9b6f-3420acbf5091} Default.Personality assimp-4.1.0/contrib/gtest/test/0000755002537200234200000000000013213503245017021 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/test/gtest_uninitialized_test.py0000644002537200234200000000466213213503245024520 0ustar zmoelnigiemusers#!/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() assimp-4.1.0/contrib/gtest/test/gtest_throw_on_failure_test_.cc0000644002537200234200000000604013213503245025302 0ustar zmoelnigiemusers// 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" #include // for fflush, fprintf, NULL, etc. #include // for exit #include // for set_terminate // This terminate handler aborts the program using exit() rather than abort(). // This avoids showing pop-ups on Windows systems and core dumps on Unix-like // ones. void TerminateHandler() { fprintf(stderr, "%s\n", "Unhandled C++ exception terminating the program."); fflush(NULL); exit(1); } int main(int argc, char** argv) { #if GTEST_HAS_EXCEPTIONS std::set_terminate(&TerminateHandler); #endif 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 throw-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; } assimp-4.1.0/contrib/gtest/test/gtest-typed-test_test.h0000644002537200234200000000466513213503245023472 0ustar zmoelnigiemusers// 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 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_ assimp-4.1.0/contrib/gtest/test/gtest_all_test.cc0000644002537200234200000000431313213503245022346 0ustar zmoelnigiemusers// 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" assimp-4.1.0/contrib/gtest/test/gtest-tuple_test.cc0000644002537200234200000002204213213503245022644 0ustar zmoelnigiemusers// 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 #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 >::type returns TK. TEST(tuple_element_Test, ReturnsElementType) { StaticAssertTypeEq >::type>(); StaticAssertTypeEq >::type>(); StaticAssertTypeEq >::type>(); } // Tests that tuple_size::value gives the number of fields in tuple // type T. TEST(tuple_size_Test, ReturnsNumberOfFields) { EXPECT_EQ(0, +tuple_size >::value); EXPECT_EQ(1, +tuple_size >::value); EXPECT_EQ(1, +tuple_size >::value); EXPECT_EQ(1, +(tuple_size > >::value)); EXPECT_EQ(2, +(tuple_size >::value)); EXPECT_EQ(3, +(tuple_size >::value)); } // Tests comparing a tuple with itself. TEST(ComparisonTest, ComparesWithSelf) { const tuple 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 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 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 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 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 a1, b1; b1 = a1; EXPECT_EQ(0, get<0>(b1)); tuple a2, b2; b2 = a2; EXPECT_EQ(0, get<0>(b2)); EXPECT_EQ(0.0, get<1>(b2)); tuple a3, b3; b3 = a3; EXPECT_EQ(0.0, get<0>(b3)); EXPECT_EQ('\0', get<1>(b3)); EXPECT_TRUE(get<2>(b3) == NULL); tuple 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 a(n); EXPECT_EQ(&n, &(get<0>(a))); // Non-reference fields. tuple b(5, 'a'); EXPECT_EQ(5, get<0>(b)); EXPECT_EQ('a', get<1>(b)); // Const reference field. const int m = 2; tuple c(true, m); EXPECT_TRUE(get<0>(c)); EXPECT_EQ(&m, &(get<1>(c))); } // Tests tuple's copy constructor. TEST(TupleConstructorTest, CopyConstructor) { tuple a(0.0, true); tuple 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 a(0, 1, 'a'); tuple 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 a(1, 'a'); tuple b(a); tuple c(a); } // Tests assigning a tuple to another tuple with the same type. TEST(TupleAssignmentTest, AssignsToSameTupleType) { const tuple a(5, 7L); tuple 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 a(1, 7L, true); tuple 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 a(5, true); tuple b; b = a; EXPECT_EQ(5, get<0>(b)); EXPECT_TRUE(get<1>(b)); tuple 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 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(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 a; a = make_tuple(true, 5); EXPECT_TRUE(get<0>(a)); EXPECT_EQ(5, get<1>(a)); tuple 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 t; t = make_tuple(str, p); EXPECT_EQ(str, get<0>(t)); EXPECT_EQ(p, get<1>(t)); } } // namespace assimp-4.1.0/contrib/gtest/test/gtest_color_test_.cc0000644002537200234200000000551013213503245023053 0ustar zmoelnigiemusers// 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 #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; } } assimp-4.1.0/contrib/gtest/test/gtest_xml_outfile2_test_.cc0000644002537200234200000000373313213503245024353 0ustar zmoelnigiemusers// 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); } assimp-4.1.0/contrib/gtest/test/gtest-linked_ptr_test.cc0000644002537200234200000001003513213503245023645 0ustar zmoelnigiemusers// 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 #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 a0, a1, a2; // Use explicit function call notation here to suppress self-assign warning. a0.operator=(a0); a1 = a2; ASSERT_EQ(a0.get(), static_cast(NULL)); ASSERT_EQ(a1.get(), static_cast(NULL)); ASSERT_EQ(a2.get(), static_cast(NULL)); ASSERT_TRUE(a0 == NULL); ASSERT_TRUE(a1 == NULL); ASSERT_TRUE(a2 == NULL); { linked_ptr 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 a4(a0); a1 = a4; linked_ptr a5(new A); ASSERT_TRUE(a5.get() != a3); ASSERT_TRUE(a5 != a3.get()); a2 = a5; linked_ptr b0(new B); linked_ptr 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 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 assimp-4.1.0/contrib/gtest/test/gtest_help_test.py0000644002537200234200000001334013213503245022571 0ustar zmoelnigiemusers#!/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 --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_LINUX = os.name == 'posix' and os.uname()[0] == 'Linux' IS_WINDOWS = os.name == 'nt' PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath('gtest_help_test_') FLAG_PREFIX = '--gtest_' DEATH_TEST_STYLE_FLAG = FLAG_PREFIX + 'death_test_style' STREAM_RESULT_TO_FLAG = FLAG_PREFIX + 'stream_result_to' 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.*' + FLAG_PREFIX + r'catch_exceptions=0.*', 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_LINUX: self.assert_(STREAM_RESULT_TO_FLAG in output, output) else: self.assert_(STREAM_RESULT_TO_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() assimp-4.1.0/contrib/gtest/test/gtest_break_on_failure_unittest_.cc0000644002537200234200000000627713213503245026137 0ustar zmoelnigiemusers// 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 # include #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_HAS_SEH && !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(); } assimp-4.1.0/contrib/gtest/test/gtest-death-test_ex_test.cc0000644002537200234200000000713713213503245024261 0ustar zmoelnigiemusers// 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. // // Author: vladl@google.com (Vlad Losev) // // Tests that verify interaction of exceptions and death tests. #include "gtest/gtest-death-test.h" #include "gtest/gtest.h" #if GTEST_HAS_DEATH_TEST # if GTEST_HAS_SEH # include // For RaiseException(). # endif # include "gtest/gtest-spi.h" # if GTEST_HAS_EXCEPTIONS # include // For std::exception. // Tests that death tests report thrown exceptions as failures and that the // exceptions do not escape death test macros. TEST(CxxExceptionDeathTest, ExceptionIsFailure) { try { EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw 1, ""), "threw an exception"); } catch (...) { // NOLINT FAIL() << "An exception escaped a death test macro invocation " << "with catch_exceptions " << (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled"); } } class TestException : public std::exception { public: virtual const char* what() const throw() { return "exceptional message"; } }; TEST(CxxExceptionDeathTest, PrintsMessageForStdExceptions) { // Verifies that the exception message is quoted in the failure text. EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""), "exceptional message"); // Verifies that the location is mentioned in the failure text. EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(throw TestException(), ""), "gtest-death-test_ex_test.cc"); } # endif // GTEST_HAS_EXCEPTIONS # if GTEST_HAS_SEH // Tests that enabling interception of SEH exceptions with the // catch_exceptions flag does not interfere with SEH exceptions being // treated as death by death tests. TEST(SehExceptionDeasTest, CatchExceptionsDoesNotInterfere) { EXPECT_DEATH(RaiseException(42, 0x0, 0, NULL), "") << "with catch_exceptions " << (testing::GTEST_FLAG(catch_exceptions) ? "enabled" : "disabled"); } # endif #endif // GTEST_HAS_DEATH_TEST int main(int argc, char** argv) { testing::InitGoogleTest(&argc, argv); testing::GTEST_FLAG(catch_exceptions) = GTEST_ENABLE_CATCH_EXCEPTIONS_ != 0; return RUN_ALL_TESTS(); } assimp-4.1.0/contrib/gtest/test/gtest_stress_test.cc0000644002537200234200000002265113213503245023126 0ustar zmoelnigiemusers// 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 #include // 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::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; std::string IdToKey(int id, const char* suffix) { Message key; key << "key_" << id << "_" << suffix; return key.GetString(); } std::string IdToString(int id) { Message id_message; id_message << id; return id_message.GetString(); } void ExpectKeyAndValueWereRecordedForId( const std::vector& properties, int id, const char* suffix) { TestPropertyKeyIs matches_key(IdToKey(id, suffix).c_str()); const std::vector::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 > threads[kThreadCount]; Notification threads_can_start; for (int i = 0; i != kThreadCount; i++) threads[i].reset(new ThreadWithParam(&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 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 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 assimp-4.1.0/contrib/gtest/test/gtest_premature_exit_test.cc0000644002537200234200000001031213213503245024627 0ustar zmoelnigiemusers// Copyright 2013, 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 Google Test manipulates the premature-exit-detection // file correctly. #include #include "gtest/gtest.h" using ::testing::InitGoogleTest; using ::testing::Test; using ::testing::internal::posix::GetEnv; using ::testing::internal::posix::Stat; using ::testing::internal::posix::StatStruct; namespace { class PrematureExitTest : public Test { public: // Returns true iff the given file exists. static bool FileExists(const char* filepath) { StatStruct stat; return Stat(filepath, &stat) == 0; } protected: PrematureExitTest() { premature_exit_file_path_ = GetEnv("TEST_PREMATURE_EXIT_FILE"); // Normalize NULL to "" for ease of handling. if (premature_exit_file_path_ == NULL) { premature_exit_file_path_ = ""; } } // Returns true iff the premature-exit file exists. bool PrematureExitFileExists() const { return FileExists(premature_exit_file_path_); } const char* premature_exit_file_path_; }; typedef PrematureExitTest PrematureExitDeathTest; // Tests that: // - the premature-exit file exists during the execution of a // death test (EXPECT_DEATH*), and // - a death test doesn't interfere with the main test process's // handling of the premature-exit file. TEST_F(PrematureExitDeathTest, FileExistsDuringExecutionOfDeathTest) { if (*premature_exit_file_path_ == '\0') { return; } EXPECT_DEATH_IF_SUPPORTED({ // If the file exists, crash the process such that the main test // process will catch the (expected) crash and report a success; // otherwise don't crash, which will cause the main test process // to report that the death test has failed. if (PrematureExitFileExists()) { exit(1); } }, ""); } // Tests that the premature-exit file exists during the execution of a // normal (non-death) test. TEST_F(PrematureExitTest, PrematureExitFileExistsDuringTestExecution) { if (*premature_exit_file_path_ == '\0') { return; } EXPECT_TRUE(PrematureExitFileExists()) << " file " << premature_exit_file_path_ << " should exist during test execution, but doesn't."; } } // namespace int main(int argc, char **argv) { InitGoogleTest(&argc, argv); const int exit_code = RUN_ALL_TESTS(); // Test that the premature-exit file is deleted upon return from // RUN_ALL_TESTS(). const char* const filepath = GetEnv("TEST_PREMATURE_EXIT_FILE"); if (filepath != NULL && *filepath != '\0') { if (PrematureExitTest::FileExists(filepath)) { printf( "File %s shouldn't exist after the test program finishes, but does.", filepath); return 1; } } return exit_code; } assimp-4.1.0/contrib/gtest/test/gtest_output_test_golden_lin.txt0000644002537200234200000007124413213503245025571 0ustar zmoelnigiemusersThe 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 Expected: 2 To be equal to: 3 [==========] Running 66 tests from 29 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 [----------] 2 tests from NonfatalFailureTest [ RUN ] NonfatalFailureTest.EscapesStringOperands gtest_output_test_.cc:#: Failure Expected: kGoldenString Which is: "\"Line" To be equal to: actual Which is: "actual \"string\"" gtest_output_test_.cc:#: Failure Expected: golden Which is: "\"Line" To be equal to: actual Which is: "actual \"string\"" [ FAILED ] NonfatalFailureTest.EscapesStringOperands [ RUN ] NonfatalFailureTest.DiffForLongStrings gtest_output_test_.cc:#: Failure Expected: golden_str Which is: "\"Line\0 1\"\nLine 2" To be equal to: "Line 2" With diff: @@ -1,2 @@ -\"Line\0 1\" Line 2 [ FAILED ] NonfatalFailureTest.DiffForLongStrings [----------] 3 tests from FatalFailureTest [ RUN ] FatalFailureTest.FatalFailureInSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: Failure Expected: 1 To be equal to: x Which is: 2 [ FAILED ] FatalFailureTest.FatalFailureInSubroutine [ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: Failure Expected: 1 To be equal to: x Which is: 2 [ 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 Expected: 2 To be equal to: n Which is: 1 Google Test trace: gtest_output_test_.cc:#: i = 1 gtest_output_test_.cc:#: Failure Expected: 1 To be equal to: n Which is: 2 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 Expected: 2 To be equal to: n Which is: 1 Google Test trace: gtest_output_test_.cc:#: n = 1 gtest_output_test_.cc:#: Failure Expected: 1 To be equal to: n Which is: 2 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 Expected: 1 To be equal to: n Which is: 2 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 [----------] 1 test from AddFailureAtTest [ RUN ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber foo.cc:42: Failure Failed Expected failure in foo.cc [ FAILED ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber [----------] 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 Expected: 1 To be equal to: TypeParam() Which is: 0 Expected failure [ FAILED ] TypedTest/0.Failure, where TypeParam = int [----------] 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 Expected: 1U Which is: 1 To be equal to: TypeParam() Which is: '\0' Expected failure [ FAILED ] Unsigned/TypedTestP/0.Failure, where TypeParam = unsigned char [----------] 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 Expected: 1U Which is: 1 To be equal to: TypeParam() Which is: 0 Expected failure [ FAILED ] Unsigned/TypedTestP/1.Failure, where TypeParam = unsigned int [----------] 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 [----------] 1 test from PrintingFailingParams/FailingParamTest [ RUN ] PrintingFailingParams/FailingParamTest.Fails/0 gtest_output_test_.cc:#: Failure Expected: 1 To be equal to: GetParam() Which is: 2 [ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2 [----------] 2 tests from PrintingStrings/ParamTest [ RUN ] PrintingStrings/ParamTest.Success/a [ OK ] PrintingStrings/ParamTest.Success/a [ RUN ] PrintingStrings/ParamTest.Failure/a gtest_output_test_.cc:#: Failure Expected: "b" To be equal to: GetParam() Which is: "a" Expected failure [ FAILED ] PrintingStrings/ParamTest.Failure/a, where GetParam() = "a" [----------] 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. [==========] 66 tests from 29 test cases ran. [ PASSED ] 22 tests. [ FAILED ] 44 tests, listed below: [ FAILED ] NonfatalFailureTest.EscapesStringOperands [ FAILED ] NonfatalFailureTest.DiffForLongStrings [ 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 ] AddFailureAtTest.MessageContainsSpecifiedFileAndLineNumber [ 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 [ FAILED ] PrintingFailingParams/FailingParamTest.Fails/0, where GetParam() = 2 [ FAILED ] PrintingStrings/ParamTest.Failure/a, where GetParam() = "a" 44 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 Expected: 1 To be equal to: x Which is: 2 [ FAILED ] FatalFailureTest.FatalFailureInSubroutine (? ms) [ RUN ] FatalFailureTest.FatalFailureInNestedSubroutine (expecting a failure that x should be 1) gtest_output_test_.cc:#: Failure Expected: 1 To be equal to: x Which is: 2 [ 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 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 2 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. assimp-4.1.0/contrib/gtest/test/gtest_shuffle_test_.cc0000644002537200234200000000635213213503245023376 0ustar zmoelnigiemusers// 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::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(); } assimp-4.1.0/contrib/gtest/test/gtest-port_test.cc0000644002537200234200000011706513213503245022511 0ustar zmoelnigiemusers// 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 #if GTEST_OS_MAC # include #endif // GTEST_OS_MAC #include #include // For std::pair and std::make_pair. #include #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 { TEST(IsXDigitTest, WorksForNarrowAscii) { EXPECT_TRUE(IsXDigit('0')); EXPECT_TRUE(IsXDigit('9')); EXPECT_TRUE(IsXDigit('A')); EXPECT_TRUE(IsXDigit('F')); EXPECT_TRUE(IsXDigit('a')); EXPECT_TRUE(IsXDigit('f')); EXPECT_FALSE(IsXDigit('-')); EXPECT_FALSE(IsXDigit('g')); EXPECT_FALSE(IsXDigit('G')); } TEST(IsXDigitTest, ReturnsFalseForNarrowNonAscii) { EXPECT_FALSE(IsXDigit('\x80')); EXPECT_FALSE(IsXDigit(static_cast('0' | '\x80'))); } TEST(IsXDigitTest, WorksForWideAscii) { EXPECT_TRUE(IsXDigit(L'0')); EXPECT_TRUE(IsXDigit(L'9')); EXPECT_TRUE(IsXDigit(L'A')); EXPECT_TRUE(IsXDigit(L'F')); EXPECT_TRUE(IsXDigit(L'a')); EXPECT_TRUE(IsXDigit(L'f')); EXPECT_FALSE(IsXDigit(L'-')); EXPECT_FALSE(IsXDigit(L'g')); EXPECT_FALSE(IsXDigit(L'G')); } TEST(IsXDigitTest, ReturnsFalseForWideNonAscii) { EXPECT_FALSE(IsXDigit(static_cast(0x80))); EXPECT_FALSE(IsXDigit(static_cast(L'0' | 0x80))); EXPECT_FALSE(IsXDigit(static_cast(L'0' | 0x100))); } class Base { public: // Copy constructor and assignment operator do exactly what we need, so we // use them. Base() : member_(0) {} explicit Base(int n) : member_(n) {} virtual ~Base() {} int member() { return member_; } private: int member_; }; class Derived : public Base { public: explicit Derived(int n) : Base(n) {} }; TEST(ImplicitCastTest, ConvertsPointers) { Derived derived(0); EXPECT_TRUE(&derived == ::testing::internal::ImplicitCast_(&derived)); } TEST(ImplicitCastTest, CanUseInheritance) { Derived derived(1); Base base = ::testing::internal::ImplicitCast_(derived); EXPECT_EQ(derived.member(), base.member()); } class Castable { public: explicit Castable(bool* converted) : converted_(converted) {} operator Base() { *converted_ = true; return Base(); } private: bool* converted_; }; TEST(ImplicitCastTest, CanUseNonConstCastOperator) { bool converted = false; Castable castable(&converted); Base base = ::testing::internal::ImplicitCast_(castable); EXPECT_TRUE(converted); } class ConstCastable { public: explicit ConstCastable(bool* converted) : converted_(converted) {} operator Base() const { *converted_ = true; return Base(); } private: bool* converted_; }; TEST(ImplicitCastTest, CanUseConstCastOperatorOnConstValues) { bool converted = false; const ConstCastable const_castable(&converted); Base base = ::testing::internal::ImplicitCast_(const_castable); EXPECT_TRUE(converted); } class ConstAndNonConstCastable { public: ConstAndNonConstCastable(bool* converted, bool* const_converted) : converted_(converted), const_converted_(const_converted) {} operator Base() { *converted_ = true; return Base(); } operator Base() const { *const_converted_ = true; return Base(); } private: bool* converted_; bool* const_converted_; }; TEST(ImplicitCastTest, CanSelectBetweenConstAndNonConstCasrAppropriately) { bool converted = false; bool const_converted = false; ConstAndNonConstCastable castable(&converted, &const_converted); Base base = ::testing::internal::ImplicitCast_(castable); EXPECT_TRUE(converted); EXPECT_FALSE(const_converted); converted = false; const_converted = false; const ConstAndNonConstCastable const_castable(&converted, &const_converted); base = ::testing::internal::ImplicitCast_(const_castable); EXPECT_FALSE(converted); EXPECT_TRUE(const_converted); } class To { public: To(bool* converted) { *converted = true; } // NOLINT }; TEST(ImplicitCastTest, CanUseImplicitConstructor) { bool converted = false; To to = ::testing::internal::ImplicitCast_(&converted); (void)to; EXPECT_TRUE(converted); } TEST(IteratorTraitsTest, WorksForSTLContainerIterators) { StaticAssertTypeEq::const_iterator>::value_type>(); StaticAssertTypeEq::iterator>::value_type>(); } TEST(IteratorTraitsTest, WorksForPointerToNonConst) { StaticAssertTypeEq::value_type>(); StaticAssertTypeEq::value_type>(); } TEST(IteratorTraitsTest, WorksForPointerToConst) { StaticAssertTypeEq::value_type>(); StaticAssertTypeEq::value_type>(); } // Tests that the element_type typedef is available in scoped_ptr and refers // to the parameter type. TEST(ScopedPtrTest, DefinesElementType) { StaticAssertTypeEq::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"; } // Verifies behavior of FormatFileLocation. TEST(FormatFileLocationTest, FormatsFileLocation) { EXPECT_PRED_FORMAT2(IsSubstring, "foo.cc", FormatFileLocation("foo.cc", 42)); EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation("foo.cc", 42)); } TEST(FormatFileLocationTest, FormatsUnknownFile) { EXPECT_PRED_FORMAT2( IsSubstring, "unknown file", FormatFileLocation(NULL, 42)); EXPECT_PRED_FORMAT2(IsSubstring, "42", FormatFileLocation(NULL, 42)); } TEST(FormatFileLocationTest, FormatsUknownLine) { EXPECT_EQ("foo.cc:", FormatFileLocation("foo.cc", -1)); } TEST(FormatFileLocationTest, FormatsUknownFileAndLine) { EXPECT_EQ("unknown file:", FormatFileLocation(NULL, -1)); } // Verifies behavior of FormatCompilerIndependentFileLocation. TEST(FormatCompilerIndependentFileLocationTest, FormatsFileLocation) { EXPECT_EQ("foo.cc:42", FormatCompilerIndependentFileLocation("foo.cc", 42)); } TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFile) { EXPECT_EQ("unknown file:42", FormatCompilerIndependentFileLocation(NULL, 42)); } TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownLine) { EXPECT_EQ("foo.cc", FormatCompilerIndependentFileLocation("foo.cc", -1)); } TEST(FormatCompilerIndependentFileLocationTest, FormatsUknownFileAndLine) { EXPECT_EQ("unknown file", FormatCompilerIndependentFileLocation(NULL, -1)); } #if GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX void* ThreadFunc(void* data) { internal::Mutex* mutex = static_cast(data); mutex->Lock(); mutex->Unlock(); return NULL; } TEST(GetThreadCountTest, ReturnsCorrectValue) { const size_t starting_count = GetThreadCount(); pthread_t thread_id; internal::Mutex mutex; { internal::MutexLock lock(&mutex); pthread_attr_t attr; 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(starting_count + 1, GetThreadCount()); } void* dummy; ASSERT_EQ(0, pthread_join(thread_id, &dummy)); // The OS 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() == starting_count) break; SleepMilliseconds(100); } EXPECT_EQ(starting_count, GetThreadCount()); } #else TEST(GetThreadCountTest, ReturnsZeroWhenUnableToCountThreads) { EXPECT_EQ(0U, GetThreadCount()); } #endif // GTEST_OS_LINUX || GTEST_OS_MAC || GTEST_OS_QNX TEST(GtestCheckDeathTest, DiesWithCorrectOutputOnFailure) { const bool a_false_condition = false; const char regex[] = #ifdef _MSC_VER "gtest-port_test\\.cc\\(\\d+\\):" #elif GTEST_USES_POSIX_RE "gtest-port_test\\.cc:[0-9]+" #else "gtest-port_test\\.cc:\\d+" #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 // Verifies that Google Test choose regular expression engine appropriate to // the platform. The test will produce compiler errors in case of failure. // For simplicity, we only cover the most important platforms here. TEST(RegexEngineSelectionTest, SelectsCorrectRegexEngine) { #if !GTEST_USES_PCRE # if GTEST_HAS_POSIX_RE EXPECT_TRUE(GTEST_USES_POSIX_RE); # else EXPECT_TRUE(GTEST_USES_SIMPLE_RE); # endif #endif // !GTEST_USES_PCRE } #if GTEST_USES_POSIX_RE # if GTEST_HAS_TYPED_TEST template 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(IsAsciiDigitTest, IsFalseForNonDigit) { EXPECT_FALSE(IsAsciiDigit('\0')); EXPECT_FALSE(IsAsciiDigit(' ')); EXPECT_FALSE(IsAsciiDigit('+')); EXPECT_FALSE(IsAsciiDigit('-')); EXPECT_FALSE(IsAsciiDigit('.')); EXPECT_FALSE(IsAsciiDigit('a')); } TEST(IsAsciiDigitTest, IsTrueForDigit) { EXPECT_TRUE(IsAsciiDigit('0')); EXPECT_TRUE(IsAsciiDigit('1')); EXPECT_TRUE(IsAsciiDigit('5')); EXPECT_TRUE(IsAsciiDigit('9')); } TEST(IsAsciiPunctTest, IsFalseForNonPunct) { EXPECT_FALSE(IsAsciiPunct('\0')); EXPECT_FALSE(IsAsciiPunct(' ')); EXPECT_FALSE(IsAsciiPunct('\n')); EXPECT_FALSE(IsAsciiPunct('a')); EXPECT_FALSE(IsAsciiPunct('0')); } TEST(IsAsciiPunctTest, IsTrueForPunct) { for (const char* p = "^-!\"#$%&'()*+,./:;<=>?@[\\]_`{|}~"; *p; p++) { EXPECT_PRED1(IsAsciiPunct, *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(IsAsciiWhiteSpaceTest, IsFalseForNonWhiteSpace) { EXPECT_FALSE(IsAsciiWhiteSpace('\0')); EXPECT_FALSE(IsAsciiWhiteSpace('a')); EXPECT_FALSE(IsAsciiWhiteSpace('1')); EXPECT_FALSE(IsAsciiWhiteSpace('+')); EXPECT_FALSE(IsAsciiWhiteSpace('_')); } TEST(IsAsciiWhiteSpaceTest, IsTrueForWhiteSpace) { EXPECT_TRUE(IsAsciiWhiteSpace(' ')); EXPECT_TRUE(IsAsciiWhiteSpace('\n')); EXPECT_TRUE(IsAsciiWhiteSpace('\r')); EXPECT_TRUE(IsAsciiWhiteSpace('\t')); EXPECT_TRUE(IsAsciiWhiteSpace('\v')); EXPECT_TRUE(IsAsciiWhiteSpace('\f')); } TEST(IsAsciiWordCharTest, IsFalseForNonWordChar) { EXPECT_FALSE(IsAsciiWordChar('\0')); EXPECT_FALSE(IsAsciiWordChar('+')); EXPECT_FALSE(IsAsciiWordChar('.')); EXPECT_FALSE(IsAsciiWordChar(' ')); EXPECT_FALSE(IsAsciiWordChar('\n')); } TEST(IsAsciiWordCharTest, IsTrueForLetter) { EXPECT_TRUE(IsAsciiWordChar('a')); EXPECT_TRUE(IsAsciiWordChar('b')); EXPECT_TRUE(IsAsciiWordChar('A')); EXPECT_TRUE(IsAsciiWordChar('Z')); } TEST(IsAsciiWordCharTest, IsTrueForDigit) { EXPECT_TRUE(IsAsciiWordChar('0')); EXPECT_TRUE(IsAsciiWordChar('1')); EXPECT_TRUE(IsAsciiWordChar('7')); EXPECT_TRUE(IsAsciiWordChar('9')); } TEST(IsAsciiWordCharTest, IsTrueForUnderscore) { EXPECT_TRUE(IsAsciiWordChar('_')); } 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 t1; EXPECT_EQ(0, t1.get()); ThreadLocal t2; EXPECT_TRUE(t2.get() == NULL); } TEST(ThreadLocalTest, SingleParamConstructorInitializesToParam) { ThreadLocal t1(123); EXPECT_EQ(123, t1.get()); int i = 0; ThreadLocal t2(&i); EXPECT_EQ(&i, t2.get()); } class NoDefaultContructor { public: explicit NoDefaultContructor(const char*) {} NoDefaultContructor(const NoDefaultContructor&) {} }; TEST(ThreadLocalTest, ValueDefaultContructorIsNotRequiredForParamVersion) { ThreadLocal bar(NoDefaultContructor("foo")); bar.pointer(); } TEST(ThreadLocalTest, GetAndPointerReturnSameValue) { ThreadLocal thread_local_string; EXPECT_EQ(thread_local_string.pointer(), &(thread_local_string.get())); // Verifies the condition still holds after calling set. thread_local_string.set("foo"); EXPECT_EQ(thread_local_string.pointer(), &(thread_local_string.get())); } TEST(ThreadLocalTest, PointerAndConstPointerReturnSameValue) { ThreadLocal thread_local_string; const ThreadLocal& const_thread_local_string = thread_local_string; EXPECT_EQ(thread_local_string.pointer(), const_thread_local_string.pointer()); thread_local_string.set("foo"); EXPECT_EQ(thread_local_string.pointer(), const_thread_local_string.pointer()); } #if GTEST_IS_THREADSAFE void AddTwo(int* param) { *param += 2; } TEST(ThreadWithParamTest, ConstructorExecutesThreadFunc) { int i = 40; ThreadWithParam 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_; { // We need to put up a memory barrier to prevent reads and writes to // value_ rearranged with the call to SleepMilliseconds when observed // from other threads. #if GTEST_HAS_PTHREAD // On POSIX, locking a mutex puts up a memory barrier. 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)); GTEST_CHECK_POSIX_SUCCESS_(pthread_mutex_destroy(&memory_barrier_mutex)); #elif GTEST_OS_WINDOWS // On Windows, performing an interlocked access puts up a memory barrier. volatile LONG dummy = 0; ::InterlockedIncrement(&dummy); SleepMilliseconds(random_.Generate(30)); ::InterlockedIncrement(&dummy); #else # error "Memory barrier not implemented on this platform." #endif // GTEST_HAS_PTHREAD } value_ = temp + 1; } int value() const { return value_; } private: volatile int value_; Mutex* const mutex_; // Protects value_. Random random_; }; void CountingThreadFunc(pair 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 > ThreadType; const int kCycleCount = 20; const int kThreadCount = 7; scoped_ptr 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 void RunFromThread(void (func)(T), T param) { ThreadWithParam thread(func, param, NULL); thread.Join(); } void RetrieveThreadLocalValue( pair*, std::string*> param) { *param.second = param.first->get(); } TEST(ThreadLocalTest, ParameterizedConstructorSetsDefault) { ThreadLocal thread_local_string("foo"); EXPECT_STREQ("foo", thread_local_string.get().c_str()); thread_local_string.set("bar"); EXPECT_STREQ("bar", thread_local_string.get().c_str()); std::string result; RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local_string, &result)); EXPECT_STREQ("foo", result.c_str()); } // Keeps track of whether of destructors being called on instances of // DestructorTracker. On Windows, waits for the destructor call reports. class DestructorCall { public: DestructorCall() { invoked_ = false; #if GTEST_OS_WINDOWS wait_event_.Reset(::CreateEvent(NULL, TRUE, FALSE, NULL)); GTEST_CHECK_(wait_event_.Get() != NULL); #endif } bool CheckDestroyed() const { #if GTEST_OS_WINDOWS if (::WaitForSingleObject(wait_event_.Get(), 1000) != WAIT_OBJECT_0) return false; #endif return invoked_; } void ReportDestroyed() { invoked_ = true; #if GTEST_OS_WINDOWS ::SetEvent(wait_event_.Get()); #endif } static std::vector& List() { return *list_; } static void ResetList() { for (size_t i = 0; i < list_->size(); ++i) { delete list_->at(i); } list_->clear(); } private: bool invoked_; #if GTEST_OS_WINDOWS AutoHandle wait_event_; #endif static std::vector* const list_; GTEST_DISALLOW_COPY_AND_ASSIGN_(DestructorCall); }; std::vector* const DestructorCall::list_ = new std::vector; // DestructorTracker keeps track of whether its instances have been // destroyed. class DestructorTracker { public: DestructorTracker() : index_(GetNewIndex()) {} DestructorTracker(const DestructorTracker& /* rhs */) : index_(GetNewIndex()) {} ~DestructorTracker() { // We never access DestructorCall::List() concurrently, so we don't need // to protect this acccess with a mutex. DestructorCall::List()[index_]->ReportDestroyed(); } private: static size_t GetNewIndex() { DestructorCall::List().push_back(new DestructorCall); return DestructorCall::List().size() - 1; } const size_t index_; GTEST_DISALLOW_ASSIGN_(DestructorTracker); }; typedef ThreadLocal* ThreadParam; void CallThreadLocalGet(ThreadParam thread_local_param) { thread_local_param->get(); } // Tests that when a ThreadLocal object dies in a thread, it destroys // the managed object for that thread. TEST(ThreadLocalTest, DestroysManagedObjectForOwnThreadWhenDying) { DestructorCall::ResetList(); { ThreadLocal thread_local_tracker; ASSERT_EQ(0U, DestructorCall::List().size()); // This creates another DestructorTracker object for the main thread. thread_local_tracker.get(); ASSERT_EQ(1U, DestructorCall::List().size()); ASSERT_FALSE(DestructorCall::List()[0]->CheckDestroyed()); } // Now thread_local_tracker has died. ASSERT_EQ(1U, DestructorCall::List().size()); EXPECT_TRUE(DestructorCall::List()[0]->CheckDestroyed()); DestructorCall::ResetList(); } // Tests that when a thread exits, the thread-local object for that // thread is destroyed. TEST(ThreadLocalTest, DestroysManagedObjectAtThreadExit) { DestructorCall::ResetList(); { ThreadLocal thread_local_tracker; ASSERT_EQ(0U, DestructorCall::List().size()); // This creates another DestructorTracker object in the new thread. ThreadWithParam thread( &CallThreadLocalGet, &thread_local_tracker, NULL); thread.Join(); // The thread has exited, and we should have a DestroyedTracker // instance created for it. But it may not have been destroyed yet. ASSERT_EQ(1U, DestructorCall::List().size()); } // The thread has exited and thread_local_tracker has died. ASSERT_EQ(1U, DestructorCall::List().size()); EXPECT_TRUE(DestructorCall::List()[0]->CheckDestroyed()); DestructorCall::ResetList(); } TEST(ThreadLocalTest, ThreadLocalMutationsAffectOnlyCurrentThread) { ThreadLocal thread_local_string; thread_local_string.set("Foo"); EXPECT_STREQ("Foo", thread_local_string.get().c_str()); std::string result; RunFromThread(&RetrieveThreadLocalValue, make_pair(&thread_local_string, &result)); EXPECT_TRUE(result.empty()); } #endif // GTEST_IS_THREADSAFE #if GTEST_OS_WINDOWS TEST(WindowsTypesTest, HANDLEIsVoidStar) { StaticAssertTypeEq(); } TEST(WindowsTypesTest, CRITICAL_SECTIONIs_RTL_CRITICAL_SECTION) { StaticAssertTypeEq(); } #endif // GTEST_OS_WINDOWS } // namespace internal } // namespace testing assimp-4.1.0/contrib/gtest/test/gtest-unittest-api_test.cc0000644002537200234200000003161313213503245024145 0ustar zmoelnigiemusers// 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 // For strcmp. #include using ::testing::InitGoogleTest; namespace testing { namespace internal { template 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** 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()); 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** 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()); return tests; } }; #if GTEST_HAS_TYPED_TEST template class TestCaseWithCommentTest : public Test {}; TYPED_TEST_CASE(TestCaseWithCommentTest, Types); TYPED_TEST(TestCaseWithCommentTest, Dummy) {} const int kTypedTestCases = 1; const int kTypedTests = 1; #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"); } AssertionResult IsNull(const char* str) { if (str != NULL) { return testing::AssertionFailure() << "argument is " << str; } return AssertionSuccess(); } TEST(ApiTest, TestCaseImmutableAccessorsWork) { const TestCase* test_case = UnitTestHelper::FindTestCase("ApiTest"); ASSERT_TRUE(test_case != NULL); EXPECT_STREQ("ApiTest", test_case->name()); EXPECT_TRUE(IsNull(test_case->type_param())); 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_TRUE(IsNull(tests[0]->value_param())); EXPECT_TRUE(IsNull(tests[0]->type_param())); EXPECT_FALSE(tests[0]->should_run()); EXPECT_STREQ("TestCaseDisabledAccessorsWork", tests[1]->name()); EXPECT_STREQ("ApiTest", tests[1]->test_case_name()); EXPECT_TRUE(IsNull(tests[1]->value_param())); EXPECT_TRUE(IsNull(tests[1]->type_param())); EXPECT_TRUE(tests[1]->should_run()); EXPECT_STREQ("TestCaseImmutableAccessorsWork", tests[2]->name()); EXPECT_STREQ("ApiTest", tests[2]->test_case_name()); EXPECT_TRUE(IsNull(tests[2]->value_param())); EXPECT_TRUE(IsNull(tests[2]->type_param())); EXPECT_TRUE(tests[2]->should_run()); EXPECT_STREQ("UnitTestImmutableAccessorsWork", tests[3]->name()); EXPECT_STREQ("ApiTest", tests[3]->test_case_name()); EXPECT_TRUE(IsNull(tests[3]->value_param())); EXPECT_TRUE(IsNull(tests[3]->type_param())); 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(GetTypeName().c_str(), test_case->type_param()); 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_TRUE(IsNull(tests[0]->value_param())); EXPECT_STREQ(GetTypeName().c_str(), tests[0]->type_param()); 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_TRUE(IsNull(test_case->type_param())); 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_TRUE(IsNull(test_info->value_param())); EXPECT_TRUE(IsNull(test_info->type_param())); 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_TRUE(IsNull(test_cases[0]->type_param())); 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_TRUE(IsNull(test_cases[1]->type_param())); 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(GetTypeName().c_str(), test_cases[2]->type_param()); 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_TRUE(IsNull(tests[1]->value_param())); EXPECT_TRUE(IsNull(tests[1]->type_param())); 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_TRUE(IsNull(tests[2]->value_param())); EXPECT_TRUE(IsNull(tests[2]->type_param())); 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_TRUE(IsNull(tests[3]->value_param())); EXPECT_TRUE(IsNull(tests[3]->type_param())); 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_TRUE(IsNull(tests[0]->value_param())); EXPECT_STREQ(GetTypeName().c_str(), tests[0]->type_param()); 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(); } assimp-4.1.0/contrib/gtest/test/gtest_break_on_failure_unittest.py0000644002537200234200000001625313213503245026036 0ustar zmoelnigiemusers#!/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_') environ = gtest_test_utils.environ SetEnvVar = gtest_test_utils.SetEnvVar # Tests in this file run a Google-Test-based test program and expect it # to terminate prematurely. Therefore they are incompatible with # the premature-exit-file protocol by design. Unset the # premature-exit filepath to prevent Google Test from creating # the file. SetEnvVar(gtest_test_utils.PREMATURE_EXIT_FILE_ENV_VAR, None) 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() assimp-4.1.0/contrib/gtest/test/gtest-death-test_test.cc0000644002537200234200000012770513213503245023571 0ustar zmoelnigiemusers// 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 // For chdir(). # else # include # include // For waitpid. # endif // GTEST_OS_WINDOWS # include # include # include # if GTEST_OS_LINUX # include # endif // GTEST_OS_LINUX # 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::InDeathTestChild; using testing::internal::ParseNaturalNumber; 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 DieWithMessage(const ::std::string& message) { fprintf(stderr, "%s", message.c_str()); fflush(stderr); // Make sure the text is printed before the process exits. // 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); } void DieInside(const ::std::string& function) { DieWithMessage("death inside " + function + "()."); } // 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): 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. GTEST_DISABLE_MSC_WARNINGS_PUSH_(4065) switch (0) default: ASSERT_DEATH(_exit(1), "") << "exit in default switch handler"; switch (0) case 0: EXPECT_DEATH(_exit(1), "") << "exit in switch case"; GTEST_DISABLE_MSC_WARNINGS_POP_() } // 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), ""); } # if GTEST_OS_LINUX void SigprofAction(int, siginfo_t*, void*) { /* no op */ } // Sets SIGPROF action and ITIMER_PROF timer (interval: 1ms). void SetSigprofActionAndTimer() { struct itimerval timer; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 1; timer.it_value = timer.it_interval; ASSERT_EQ(0, setitimer(ITIMER_PROF, &timer, NULL)); struct sigaction signal_action; memset(&signal_action, 0, sizeof(signal_action)); sigemptyset(&signal_action.sa_mask); signal_action.sa_sigaction = SigprofAction; signal_action.sa_flags = SA_RESTART | SA_SIGINFO; ASSERT_EQ(0, sigaction(SIGPROF, &signal_action, NULL)); } // Disables ITIMER_PROF timer and ignores SIGPROF signal. void DisableSigprofActionAndTimer(struct sigaction* old_signal_action) { struct itimerval timer; timer.it_interval.tv_sec = 0; timer.it_interval.tv_usec = 0; timer.it_value = timer.it_interval; ASSERT_EQ(0, setitimer(ITIMER_PROF, &timer, NULL)); struct sigaction signal_action; memset(&signal_action, 0, sizeof(signal_action)); sigemptyset(&signal_action.sa_mask); signal_action.sa_handler = SIG_IGN; ASSERT_EQ(0, sigaction(SIGPROF, &signal_action, old_signal_action)); } // Tests that death tests work when SIGPROF handler and timer are set. TEST_F(TestForDeathTest, FastSigprofActionSet) { testing::GTEST_FLAG(death_test_style) = "fast"; SetSigprofActionAndTimer(); EXPECT_DEATH(_exit(1), ""); struct sigaction old_signal_action; DisableSigprofActionAndTimer(&old_signal_action); EXPECT_TRUE(old_signal_action.sa_sigaction == SigprofAction); } TEST_F(TestForDeathTest, ThreadSafeSigprofActionSet) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; SetSigprofActionAndTimer(); EXPECT_DEATH(_exit(1), ""); struct sigaction old_signal_action; DisableSigprofActionAndTimer(&old_signal_action); EXPECT_TRUE(old_signal_action.sa_sigaction == SigprofAction); } # endif // GTEST_OS_LINUX // 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), ""); } # if GTEST_HAS_CLONE && GTEST_HAS_PTHREAD namespace { bool pthread_flag; void SetPthreadFlag() { pthread_flag = true; } } // namespace 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 # if !GTEST_USES_PCRE const ::std::string regex_std_str(regex_c_str); EXPECT_DEATH(GlobalFunction(), regex_std_str); # endif // !GTEST_USES_PCRE } // 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, RunawayIsFailure) { EXPECT_NONFATAL_FAILURE(EXPECT_DEATH(static_cast(0), "Foo"), "failed to die."); } // Tests that death tests report executing 'return' in the statement as // failure. TEST_F(TestForDeathTest, ReturnIsFailure) { EXPECT_FATAL_FAILURE(ASSERT_DEATH(return, "Bar"), "illegal return in test statement."); } // Tests that EXPECT_DEBUG_DEATH works as expected, that is, you can stream a // message to it, and 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") << "Must accept a streamed message"; # 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, that is, you can stream a // message to it, and 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, TestAssertDebugDeath) { int sideeffect = 0; ASSERT_DEBUG_DEATH(DieInDebugElse12(&sideeffect), "death.*DieInDebugElse12") << "Must accept a streamed message"; # 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(); }, ""); } # 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; GTEST_LOG_(INFO) << "Before ASSERT_DEBUG_DEATH"; ASSERT_DEBUG_DEATH(GTEST_LOG_(INFO) << "In ASSERT_DEBUG_DEATH"; return, "") << "This is expected to fail."; GTEST_LOG_(INFO) << "After ASSERT_DEBUG_DEATH"; *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); } TEST_F(TestForDeathTest, AssertDebugDeathAborts2) { static bool aborted; aborted = false; EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); EXPECT_TRUE(aborted); } TEST_F(TestForDeathTest, AssertDebugDeathAborts3) { static bool aborted; aborted = false; EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); EXPECT_TRUE(aborted); } TEST_F(TestForDeathTest, AssertDebugDeathAborts4) { static bool aborted; aborted = false; EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); EXPECT_TRUE(aborted); } TEST_F(TestForDeathTest, AssertDebugDeathAborts5) { static bool aborted; aborted = false; EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); EXPECT_TRUE(aborted); } TEST_F(TestForDeathTest, AssertDebugDeathAborts6) { static bool aborted; aborted = false; EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); EXPECT_TRUE(aborted); } TEST_F(TestForDeathTest, AssertDebugDeathAborts7) { static bool aborted; aborted = false; EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); EXPECT_TRUE(aborted); } TEST_F(TestForDeathTest, AssertDebugDeathAborts8) { static bool aborted; aborted = false; EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); EXPECT_TRUE(aborted); } TEST_F(TestForDeathTest, AssertDebugDeathAborts9) { static bool aborted; aborted = false; EXPECT_FATAL_FAILURE(AssertDebugDeathHelper(&aborted), ""); EXPECT_TRUE(aborted); } TEST_F(TestForDeathTest, AssertDebugDeathAborts10) { 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), "") << "b_ar"; # 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."); } TEST_F(TestForDeathTest, DeathTestFailedOutput) { testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_NONFATAL_FAILURE( EXPECT_DEATH(DieWithMessage("death\n"), "expected message"), "Actual msg:\n" "[ DEATH ] death\n"); } TEST_F(TestForDeathTest, DeathTestUnexpectedReturnOutput) { testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_NONFATAL_FAILURE( EXPECT_DEATH({ fprintf(stderr, "returning\n"); fflush(stderr); return; }, ""), " Result: illegal return in test statement.\n" " Error msg:\n" "[ DEATH ] returning\n"); } TEST_F(TestForDeathTest, DeathTestBadExitCodeOutput) { testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_NONFATAL_FAILURE( EXPECT_EXIT(DieWithMessage("exiting with rc 1\n"), testing::ExitedWithCode(3), "expected message"), " Result: died but not with expected exit code:\n" " Exited with exit status 1\n" "Actual msg:\n" "[ DEATH ] exiting with rc 1\n"); } TEST_F(TestForDeathTest, DeathTestMultiLineMatchFail) { testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_NONFATAL_FAILURE( EXPECT_DEATH(DieWithMessage("line 1\nline 2\nline 3\n"), "line 1\nxyz\nline 3\n"), "Actual msg:\n" "[ DEATH ] line 1\n" "[ DEATH ] line 2\n" "[ DEATH ] line 3\n"); } TEST_F(TestForDeathTest, DeathTestMultiLineMatchPass) { testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_DEATH(DieWithMessage("line 1\nline 2\nline 3\n"), "line 1\nline 2\nline 3\n"); } // 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_; } size_t PassedCalls() const { return passed_args_.size(); } bool PassedArgument(int n) const { return passed_args_[n]; } size_t 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 passed_args_; // The arguments to the calls to Abort since the last call to // SetParameters. std::vector 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(0U, factory_->PassedCalls()); EXPECT_EQ(0U, 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(1U, factory_->PassedCalls()); EXPECT_FALSE(factory_->PassedArgument(0)); EXPECT_EQ(0U, 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(1U, factory_->PassedCalls()); EXPECT_TRUE(factory_->PassedArgument(0)); EXPECT_EQ(0U, 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(0U, factory_->PassedCalls()); EXPECT_EQ(1U, 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(0U, 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(2U, 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; # else typedef unsigned long long BiggestParsable; typedef signed long long BiggestSignedParsable; # endif // GTEST_OS_WINDOWS // We cannot use std::numeric_limits::max() as it clashes with the // max() macro defined by . const BiggestParsable kBiggestParsableMax = ULLONG_MAX; const BiggestSignedParsable kBiggestSignedParsableMax = LLONG_MAX; TEST(ParseNaturalNumberTest, RejectsInvalidFormat) { BiggestParsable result = 0; // Rejects non-numbers. EXPECT_FALSE(ParseNaturalNumber("non-number string", &result)); // Rejects numbers with whitespace prefix. EXPECT_FALSE(ParseNaturalNumber(" 123", &result)); // Rejects negative numbers. EXPECT_FALSE(ParseNaturalNumber("-123", &result)); // Rejects numbers starting with a plus sign. EXPECT_FALSE(ParseNaturalNumber("+123", &result)); errno = 0; } TEST(ParseNaturalNumberTest, RejectsOverflownNumbers) { BiggestParsable result = 0; EXPECT_FALSE(ParseNaturalNumber("99999999999999999999999", &result)); signed char char_result = 0; EXPECT_FALSE(ParseNaturalNumber("200", &char_result)); errno = 0; } TEST(ParseNaturalNumberTest, AcceptsValidNumbers) { BiggestParsable result = 0; result = 0; ASSERT_TRUE(ParseNaturalNumber("123", &result)); EXPECT_EQ(123U, result); // Check 0 as an edge case. result = 1; ASSERT_TRUE(ParseNaturalNumber("0", &result)); EXPECT_EQ(0U, result); result = 1; ASSERT_TRUE(ParseNaturalNumber("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("123", &short_result)); EXPECT_EQ(123, short_result); signed char char_result = 0; ASSERT_TRUE(ParseNaturalNumber("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(;, ""), ""); } TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInFastStyle) { testing::GTEST_FLAG(death_test_style) = "fast"; EXPECT_FALSE(InDeathTestChild()); EXPECT_DEATH({ fprintf(stderr, InDeathTestChild() ? "Inside" : "Outside"); fflush(stderr); _exit(1); }, "Inside"); } TEST(InDeathTestChildDeathTest, ReportsDeathTestCorrectlyInThreadSafeStyle) { testing::GTEST_FLAG(death_test_style) = "threadsafe"; EXPECT_FALSE(InDeathTestChild()); EXPECT_DEATH({ fprintf(stderr, InDeathTestChild() ? "Inside" : "Outside"); fflush(stderr); _exit(1); }, "Inside"); } #else // !GTEST_HAS_DEATH_TEST follows using testing::internal::CaptureStderr; using testing::internal::GetCapturedStderr; // 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(;, ""); std::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. GTEST_DISABLE_MSC_WARNINGS_PUSH_(4065) 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"; GTEST_DISABLE_MSC_WARNINGS_POP_() } // Tests that a test case whose name ends with "DeathTest" works fine // on Windows. TEST(NotADeathTest, Test) { SUCCEED(); } assimp-4.1.0/contrib/gtest/test/gtest-test-part_test.cc0000644002537200234200000001616213213503245023444 0ustar zmoelnigiemusers// 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(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 assimp-4.1.0/contrib/gtest/test/gtest_shuffle_test.py0000644002537200234200000003040513213503245023276 0ustar zmoelnigiemusers#!/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() assimp-4.1.0/contrib/gtest/test/gtest_xml_output_unittest_.cc0000644002537200234200000001377713213503245025073 0ustar zmoelnigiemusers// 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::TestWithParam; using ::testing::UnitTest; using ::testing::Test; using ::testing::Values; class SuccessfulTest : public Test { }; TEST_F(SuccessfulTest, Succeeds) { SUCCEED() << "This is a success."; ASSERT_EQ(1, 1); } class FailedTest : public Test { }; TEST_F(FailedTest, Fails) { ASSERT_EQ(1, 2); } class DisabledTest : public 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: " ""; } // 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 Test { public: static void SetUpTestCase() { RecordProperty("SetUpTestCase", "yes"); } static void TearDownTestCase() { RecordProperty("TearDownTestCase", "aye"); } }; 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 std::string& key, int value) { testing::Test::RecordProperty(key, value); } void ExternalUtilityThatCallsRecordProperty(const std::string& key, const std::string& value) { testing::Test::RecordProperty(key, value); } TEST(NoFixtureTest, ExternalUtilityThatCallsRecordIntValuedProperty) { ExternalUtilityThatCallsRecordProperty("key_for_utility_int", 1); } TEST(NoFixtureTest, ExternalUtilityThatCallsRecordStringValuedProperty) { ExternalUtilityThatCallsRecordProperty("key_for_utility_string", "1"); } // Verifies that the test parameter value is output in the 'value_param' // XML attribute for value-parameterized tests. class ValueParamTest : public TestWithParam {}; TEST_P(ValueParamTest, HasValueParamAttribute) {} TEST_P(ValueParamTest, AnotherTestThatHasValueParamAttribute) {} INSTANTIATE_TEST_CASE_P(Single, ValueParamTest, Values(33, 42)); #if GTEST_HAS_TYPED_TEST // Verifies that the type parameter name is output in the 'type_param' // XML attribute for typed tests. template class TypedTest : public Test {}; typedef testing::Types TypedTestTypes; TYPED_TEST_CASE(TypedTest, TypedTestTypes); TYPED_TEST(TypedTest, HasTypeParamAttribute) {} #endif #if GTEST_HAS_TYPED_TEST_P // Verifies that the type parameter name is output in the 'type_param' // XML attribute for type-parameterized tests. template class TypeParameterizedTestCase : public Test {}; TYPED_TEST_CASE_P(TypeParameterizedTestCase); TYPED_TEST_P(TypeParameterizedTestCase, HasTypeParamAttribute) {} REGISTER_TYPED_TEST_CASE_P(TypeParameterizedTestCase, HasTypeParamAttribute); typedef testing::Types TypeParameterizedTestCaseTypes; INSTANTIATE_TYPED_TEST_CASE_P(Single, TypeParameterizedTestCase, TypeParameterizedTestCaseTypes); #endif 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()); } testing::Test::RecordProperty("ad_hoc_property", "42"); return RUN_ALL_TESTS(); } assimp-4.1.0/contrib/gtest/test/gtest_filter_unittest.py0000644002537200234200000005151513213503245024034 0ustar zmoelnigiemusers#!/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 try: from sets import Set as set # For Python 2.3 compatibility except ImportError: pass 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(set(set_var), 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(set(tests_to_run) - 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() assimp-4.1.0/contrib/gtest/test/gtest_catch_exceptions_test.py0000644002537200234200000002325513213503245025172 0ustar zmoelnigiemusers#!/usr/bin/env python # # 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. """Tests Google Test's exception catching behavior. This script invokes gtest_catch_exceptions_test_ and gtest_catch_exceptions_ex_test_ (programs written with Google Test) and verifies their output. """ __author__ = 'vladl@google.com (Vlad Losev)' import os import gtest_test_utils # Constants. FLAG_PREFIX = '--gtest_' LIST_TESTS_FLAG = FLAG_PREFIX + 'list_tests' NO_CATCH_EXCEPTIONS_FLAG = FLAG_PREFIX + 'catch_exceptions=0' FILTER_FLAG = FLAG_PREFIX + 'filter' # Path to the gtest_catch_exceptions_ex_test_ binary, compiled with # exceptions enabled. EX_EXE_PATH = gtest_test_utils.GetTestExecutablePath( 'gtest_catch_exceptions_ex_test_') # Path to the gtest_catch_exceptions_test_ binary, compiled with # exceptions disabled. EXE_PATH = gtest_test_utils.GetTestExecutablePath( 'gtest_catch_exceptions_no_ex_test_') environ = gtest_test_utils.environ SetEnvVar = gtest_test_utils.SetEnvVar # Tests in this file run a Google-Test-based test program and expect it # to terminate prematurely. Therefore they are incompatible with # the premature-exit-file protocol by design. Unset the # premature-exit filepath to prevent Google Test from creating # the file. SetEnvVar(gtest_test_utils.PREMATURE_EXIT_FILE_ENV_VAR, None) TEST_LIST = gtest_test_utils.Subprocess( [EXE_PATH, LIST_TESTS_FLAG], env=environ).output SUPPORTS_SEH_EXCEPTIONS = 'ThrowsSehException' in TEST_LIST if SUPPORTS_SEH_EXCEPTIONS: BINARY_OUTPUT = gtest_test_utils.Subprocess([EXE_PATH], env=environ).output EX_BINARY_OUTPUT = gtest_test_utils.Subprocess( [EX_EXE_PATH], env=environ).output # The tests. if SUPPORTS_SEH_EXCEPTIONS: # pylint:disable-msg=C6302 class CatchSehExceptionsTest(gtest_test_utils.TestCase): """Tests exception-catching behavior.""" def TestSehExceptions(self, test_output): self.assert_('SEH exception with code 0x2a thrown ' 'in the test fixture\'s constructor' in test_output) self.assert_('SEH exception with code 0x2a thrown ' 'in the test fixture\'s destructor' in test_output) self.assert_('SEH exception with code 0x2a thrown in SetUpTestCase()' in test_output) self.assert_('SEH exception with code 0x2a thrown in TearDownTestCase()' in test_output) self.assert_('SEH exception with code 0x2a thrown in SetUp()' in test_output) self.assert_('SEH exception with code 0x2a thrown in TearDown()' in test_output) self.assert_('SEH exception with code 0x2a thrown in the test body' in test_output) def testCatchesSehExceptionsWithCxxExceptionsEnabled(self): self.TestSehExceptions(EX_BINARY_OUTPUT) def testCatchesSehExceptionsWithCxxExceptionsDisabled(self): self.TestSehExceptions(BINARY_OUTPUT) class CatchCxxExceptionsTest(gtest_test_utils.TestCase): """Tests C++ exception-catching behavior. Tests in this test case verify that: * C++ exceptions are caught and logged as C++ (not SEH) exceptions * Exception thrown affect the remainder of the test work flow in the expected manner. """ def testCatchesCxxExceptionsInFixtureConstructor(self): self.assert_('C++ exception with description ' '"Standard C++ exception" thrown ' 'in the test fixture\'s constructor' in EX_BINARY_OUTPUT) self.assert_('unexpected' not in EX_BINARY_OUTPUT, 'This failure belongs in this test only if ' '"CxxExceptionInConstructorTest" (no quotes) ' 'appears on the same line as words "called unexpectedly"') if ('CxxExceptionInDestructorTest.ThrowsExceptionInDestructor' in EX_BINARY_OUTPUT): def testCatchesCxxExceptionsInFixtureDestructor(self): self.assert_('C++ exception with description ' '"Standard C++ exception" thrown ' 'in the test fixture\'s destructor' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInDestructorTest::TearDownTestCase() ' 'called as expected.' in EX_BINARY_OUTPUT) def testCatchesCxxExceptionsInSetUpTestCase(self): self.assert_('C++ exception with description "Standard C++ exception"' ' thrown in SetUpTestCase()' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInConstructorTest::TearDownTestCase() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTestCaseTest constructor ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTestCaseTest destructor ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTestCaseTest::SetUp() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTestCaseTest::TearDown() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTestCaseTest test body ' 'called as expected.' in EX_BINARY_OUTPUT) def testCatchesCxxExceptionsInTearDownTestCase(self): self.assert_('C++ exception with description "Standard C++ exception"' ' thrown in TearDownTestCase()' in EX_BINARY_OUTPUT) def testCatchesCxxExceptionsInSetUp(self): self.assert_('C++ exception with description "Standard C++ exception"' ' thrown in SetUp()' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTest::TearDownTestCase() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTest destructor ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInSetUpTest::TearDown() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('unexpected' not in EX_BINARY_OUTPUT, 'This failure belongs in this test only if ' '"CxxExceptionInSetUpTest" (no quotes) ' 'appears on the same line as words "called unexpectedly"') def testCatchesCxxExceptionsInTearDown(self): self.assert_('C++ exception with description "Standard C++ exception"' ' thrown in TearDown()' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInTearDownTest::TearDownTestCase() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInTearDownTest destructor ' 'called as expected.' in EX_BINARY_OUTPUT) def testCatchesCxxExceptionsInTestBody(self): self.assert_('C++ exception with description "Standard C++ exception"' ' thrown in the test body' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInTestBodyTest::TearDownTestCase() ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInTestBodyTest destructor ' 'called as expected.' in EX_BINARY_OUTPUT) self.assert_('CxxExceptionInTestBodyTest::TearDown() ' 'called as expected.' in EX_BINARY_OUTPUT) def testCatchesNonStdCxxExceptions(self): self.assert_('Unknown C++ exception thrown in the test body' in EX_BINARY_OUTPUT) def testUnhandledCxxExceptionsAbortTheProgram(self): # Filters out SEH exception tests on Windows. Unhandled SEH exceptions # cause tests to show pop-up windows there. FITLER_OUT_SEH_TESTS_FLAG = FILTER_FLAG + '=-*Seh*' # By default, Google Test doesn't catch the exceptions. uncaught_exceptions_ex_binary_output = gtest_test_utils.Subprocess( [EX_EXE_PATH, NO_CATCH_EXCEPTIONS_FLAG, FITLER_OUT_SEH_TESTS_FLAG], env=environ).output self.assert_('Unhandled C++ exception terminating the program' in uncaught_exceptions_ex_binary_output) self.assert_('unexpected' not in uncaught_exceptions_ex_binary_output) if __name__ == '__main__': gtest_test_utils.Main() assimp-4.1.0/contrib/gtest/test/gtest_unittest.cc0000644002537200234200000074474113213503245022436 0ustar zmoelnigiemusers// 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" // Verifies that the command line flag variables can be accessed // in code once 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(stream_result_to) != "unknown" || testing::GTEST_FLAG(throw_on_failure); EXPECT_TRUE(dummy || !dummy); // Suppresses warning that dummy is unused. } #include // For INT_MAX. #include #include #include #include #include #include #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 testing { namespace internal { #if GTEST_CAN_STREAM_RESULTS_ class StreamingListenerTest : public Test { public: class FakeSocketWriter : public StreamingListener::AbstractSocketWriter { public: // Sends a string to the socket. virtual void Send(const string& message) { output_ += message; } string output_; }; StreamingListenerTest() : fake_sock_writer_(new FakeSocketWriter), streamer_(fake_sock_writer_), test_info_obj_("FooTest", "Bar", NULL, NULL, CodeLocation(__FILE__, __LINE__), 0, NULL) {} protected: string* output() { return &(fake_sock_writer_->output_); } FakeSocketWriter* const fake_sock_writer_; StreamingListener streamer_; UnitTest unit_test_; TestInfo test_info_obj_; // The name test_info_ was taken by testing::Test. }; TEST_F(StreamingListenerTest, OnTestProgramEnd) { *output() = ""; streamer_.OnTestProgramEnd(unit_test_); EXPECT_EQ("event=TestProgramEnd&passed=1\n", *output()); } TEST_F(StreamingListenerTest, OnTestIterationEnd) { *output() = ""; streamer_.OnTestIterationEnd(unit_test_, 42); EXPECT_EQ("event=TestIterationEnd&passed=1&elapsed_time=0ms\n", *output()); } TEST_F(StreamingListenerTest, OnTestCaseStart) { *output() = ""; streamer_.OnTestCaseStart(TestCase("FooTest", "Bar", NULL, NULL)); EXPECT_EQ("event=TestCaseStart&name=FooTest\n", *output()); } TEST_F(StreamingListenerTest, OnTestCaseEnd) { *output() = ""; streamer_.OnTestCaseEnd(TestCase("FooTest", "Bar", NULL, NULL)); EXPECT_EQ("event=TestCaseEnd&passed=1&elapsed_time=0ms\n", *output()); } TEST_F(StreamingListenerTest, OnTestStart) { *output() = ""; streamer_.OnTestStart(test_info_obj_); EXPECT_EQ("event=TestStart&name=Bar\n", *output()); } TEST_F(StreamingListenerTest, OnTestEnd) { *output() = ""; streamer_.OnTestEnd(test_info_obj_); EXPECT_EQ("event=TestEnd&passed=1&elapsed_time=0ms\n", *output()); } TEST_F(StreamingListenerTest, OnTestPartResult) { *output() = ""; streamer_.OnTestPartResult(TestPartResult( TestPartResult::kFatalFailure, "foo.cc", 42, "failed=\n&%")); // Meta characters in the failure message should be properly escaped. EXPECT_EQ( "event=TestPartResult&file=foo.cc&line=42&message=failed%3D%0A%26%25\n", *output()); } #endif // GTEST_CAN_STREAM_RESULTS_ // 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(); } }; class UnitTestRecordPropertyTestHelper : public Test { protected: UnitTestRecordPropertyTestHelper() {} // Forwards to UnitTest::RecordProperty() to bypass access controls. void UnitTestRecordProperty(const char* key, const std::string& value) { unit_test_.RecordProperty(key, value); } UnitTest unit_test_; }; } // namespace internal } // namespace testing using testing::AssertionFailure; using testing::AssertionResult; using testing::AssertionSuccess; using testing::DoubleLE; using testing::EmptyTestEventListener; using testing::Environment; 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(stream_result_to); 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::TestCase; using testing::TestEventListeners; using testing::TestInfo; using testing::TestPartResult; using testing::TestPartResultArray; using testing::TestProperty; using testing::TestResult; using testing::TimeInMillis; using testing::UnitTest; using testing::internal::AddReference; using testing::internal::AlwaysFalse; using testing::internal::AlwaysTrue; using testing::internal::AppendUserMessage; using testing::internal::ArrayAwareFind; using testing::internal::ArrayEq; using testing::internal::CodePointToUtf8; using testing::internal::CompileAssertTypesEqual; using testing::internal::CopyArray; using testing::internal::CountIf; using testing::internal::EqFailure; using testing::internal::FloatingPoint; using testing::internal::ForEach; using testing::internal::FormatEpochTimeInMillisAsIso8601; using testing::internal::FormatTimeInMillisAsSeconds; 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::GetTimeInMillis; using testing::internal::GetTypeId; using testing::internal::GetUnitTestImpl; using testing::internal::ImplicitlyConvertible; using testing::internal::Int32; using testing::internal::Int32FromEnvOrDie; using testing::internal::IsAProtocolMessage; using testing::internal::IsContainer; using testing::internal::IsContainerTest; using testing::internal::IsNotContainer; using testing::internal::NativeArray; using testing::internal::ParseInt32Flag; using testing::internal::RelationToSourceCopy; using testing::internal::RelationToSourceReference; using testing::internal::RemoveConst; using testing::internal::RemoveReference; using testing::internal::ShouldRunTestOnShard; using testing::internal::ShouldShard; using testing::internal::ShouldUseColor; using testing::internal::Shuffle; using testing::internal::ShuffleRange; using testing::internal::SkipPrefix; 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::edit_distance::CalculateOptimalEdits; using testing::internal::edit_distance::CreateUnifiedDiff; using testing::internal::edit_distance::EditType; using testing::internal::kMaxRandomSeed; using testing::internal::kTestTypeIdInGoogleTest; using testing::kMaxStackTraceDepth; #if GTEST_HAS_STREAM_REDIRECTION using testing::internal::CaptureStdout; using testing::internal::GetCapturedStdout; #endif #if GTEST_IS_THREADSAFE using testing::internal::ThreadWithParam; #endif class TestingVector : public std::vector { }; ::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(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(kMaxRandomSeed), GetRandomSeedFromFlag(kMaxRandomSeed)); } TEST(GetRandomSeedFromFlagTest, NormalizesInvalidSeed) { const int seed1 = GetRandomSeedFromFlag(-1); EXPECT_LE(1, seed1); EXPECT_LE(seed1, static_cast(kMaxRandomSeed)); const int seed2 = GetRandomSeedFromFlag(kMaxRandomSeed + 1); EXPECT_LE(1, seed2); EXPECT_LE(seed2, static_cast(kMaxRandomSeed)); } TEST(GetNextRandomSeedTest, WorksForValidInput) { EXPECT_EQ(2, GetNextRandomSeed(1)); EXPECT_EQ(3, GetNextRandomSeed(2)); EXPECT_EQ(static_cast(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(), GetTypeId()); EXPECT_EQ(GetTypeId(), GetTypeId()); } class SubClassOfTest : public Test {}; class AnotherSubClassOfTest : public Test {}; TEST(GetTypeIdTest, ReturnsDifferentValuesForDifferentTypes) { EXPECT_NE(GetTypeId(), GetTypeId()); EXPECT_NE(GetTypeId(), GetTypeId()); EXPECT_NE(GetTypeId(), GetTestTypeId()); EXPECT_NE(GetTypeId(), GetTestTypeId()); EXPECT_NE(GetTypeId(), GetTestTypeId()); EXPECT_NE(GetTypeId(), GetTypeId()); } // 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)); } // Tests FormatEpochTimeInMillisAsIso8601(). The correctness of conversion // for particular dates below was verified in Python using // datetime.datetime.fromutctimestamp(/1000). // FormatEpochTimeInMillisAsIso8601 depends on the current timezone, so we // have to set up a particular timezone to obtain predictable results. class FormatEpochTimeInMillisAsIso8601Test : public Test { public: // On Cygwin, GCC doesn't allow unqualified integer literals to exceed // 32 bits, even when 64-bit integer types are available. We have to // force the constants to have a 64-bit type here. static const TimeInMillis kMillisPerSec = 1000; private: virtual void SetUp() { saved_tz_ = NULL; GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* getenv, strdup: deprecated */) if (getenv("TZ")) saved_tz_ = strdup(getenv("TZ")); GTEST_DISABLE_MSC_WARNINGS_POP_() // Set up the time zone for FormatEpochTimeInMillisAsIso8601 to use. We // cannot use the local time zone because the function's output depends // on the time zone. SetTimeZone("UTC+00"); } virtual void TearDown() { SetTimeZone(saved_tz_); free(const_cast(saved_tz_)); saved_tz_ = NULL; } static void SetTimeZone(const char* time_zone) { // tzset() distinguishes between the TZ variable being present and empty // and not being present, so we have to consider the case of time_zone // being NULL. #if _MSC_VER // ...Unless it's MSVC, whose standard library's _putenv doesn't // distinguish between an empty and a missing variable. const std::string env_var = std::string("TZ=") + (time_zone ? time_zone : ""); _putenv(env_var.c_str()); GTEST_DISABLE_MSC_WARNINGS_PUSH_(4996 /* deprecated function */) tzset(); GTEST_DISABLE_MSC_WARNINGS_POP_() #else if (time_zone) { setenv(("TZ"), time_zone, 1); } else { unsetenv("TZ"); } tzset(); #endif } const char* saved_tz_; }; const TimeInMillis FormatEpochTimeInMillisAsIso8601Test::kMillisPerSec; TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsTwoDigitSegments) { EXPECT_EQ("2011-10-31T18:52:42", FormatEpochTimeInMillisAsIso8601(1320087162 * kMillisPerSec)); } TEST_F(FormatEpochTimeInMillisAsIso8601Test, MillisecondsDoNotAffectResult) { EXPECT_EQ( "2011-10-31T18:52:42", FormatEpochTimeInMillisAsIso8601(1320087162 * kMillisPerSec + 234)); } TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsLeadingZeroes) { EXPECT_EQ("2011-09-03T05:07:02", FormatEpochTimeInMillisAsIso8601(1315026422 * kMillisPerSec)); } TEST_F(FormatEpochTimeInMillisAsIso8601Test, Prints24HourTime) { EXPECT_EQ("2011-09-28T17:08:22", FormatEpochTimeInMillisAsIso8601(1317229702 * kMillisPerSec)); } TEST_F(FormatEpochTimeInMillisAsIso8601Test, PrintsEpochStart) { EXPECT_EQ("1970-01-01T00:00:00", FormatEpochTimeInMillisAsIso8601(0)); } #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)); } // 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(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) { EXPECT_EQ("", CodePointToUtf8(L'\0')); } // Tests that ASCII characters are encoded correctly. TEST(CodePointToUtf8Test, CanEncodeAscii) { EXPECT_EQ("a", CodePointToUtf8(L'a')); EXPECT_EQ("Z", CodePointToUtf8(L'Z')); EXPECT_EQ("&", CodePointToUtf8(L'&')); EXPECT_EQ("\x7F", CodePointToUtf8(L'\x7F')); } // Tests that Unicode code-points that have 8 to 11 bits are encoded // as 110xxxxx 10xxxxxx. TEST(CodePointToUtf8Test, CanEncode8To11Bits) { // 000 1101 0011 => 110-00011 10-010011 EXPECT_EQ("\xC3\x93", CodePointToUtf8(L'\xD3')); // 101 0111 0110 => 110-10101 10-110110 // Some compilers (e.g., GCC on MinGW) cannot handle non-ASCII codepoints // in wide strings and wide chars. In order to accomodate them, we have to // introduce such character constants as integers. EXPECT_EQ("\xD5\xB6", CodePointToUtf8(static_cast(0x576))); } // Tests that Unicode code-points that have 12 to 16 bits are encoded // as 1110xxxx 10xxxxxx 10xxxxxx. TEST(CodePointToUtf8Test, CanEncode12To16Bits) { // 0000 1000 1101 0011 => 1110-0000 10-100011 10-010011 EXPECT_EQ("\xE0\xA3\x93", CodePointToUtf8(static_cast(0x8D3))); // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101 EXPECT_EQ("\xEC\x9D\x8D", CodePointToUtf8(static_cast(0xC74D))); } #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) { // 0 0001 0000 1000 1101 0011 => 11110-000 10-010000 10-100011 10-010011 EXPECT_EQ("\xF0\x90\xA3\x93", CodePointToUtf8(L'\x108D3')); // 0 0001 0000 0100 0000 0000 => 11110-000 10-010000 10-010000 10-000000 EXPECT_EQ("\xF0\x90\x90\x80", CodePointToUtf8(L'\x10400')); // 1 0000 1000 0110 0011 0100 => 11110-100 10-001000 10-011000 10-110100 EXPECT_EQ("\xF4\x88\x98\xB4", CodePointToUtf8(L'\x108634')); } // Tests that encoding an invalid code-point generates the expected result. TEST(CodePointToUtf8Test, CanEncodeInvalidCodePoint) { EXPECT_EQ("(Invalid Unicode 0x1234ABCD)", CodePointToUtf8(L'\x1234ABCD')); } #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 const wchar_t s[] = { 0x576, '\0' }; EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(s, 1).c_str()); EXPECT_STREQ("\xD5\xB6", WideStringToUtf8(s, -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 const wchar_t s1[] = { 0x8D3, '\0' }; EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(s1, 1).c_str()); EXPECT_STREQ("\xE0\xA3\x93", WideStringToUtf8(s1, -1).c_str()); // 1100 0111 0100 1101 => 1110-1100 10-011101 10-001101 const wchar_t s2[] = { 0xC74D, '\0' }; EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(s2, 1).c_str()); EXPECT_STREQ("\xEC\x9D\x8D", WideStringToUtf8(s2, -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) { const wchar_t s[] = { 0xD801, 0xDC00, '\0' }; EXPECT_STREQ("\xF0\x90\x90\x80", WideStringToUtf8(s, -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. const wchar_t s1[] = { 0xD800, '\0' }; EXPECT_STREQ("\xED\xA0\x80", WideStringToUtf8(s1, -1).c_str()); // Leading surrogate is not followed by the trailing surrogate. const wchar_t s2[] = { 0xD800, 'M', '\0' }; EXPECT_STREQ("\xED\xA0\x80M", WideStringToUtf8(s2, -1).c_str()); // Trailing surrogate appearas without a leading surrogate. const wchar_t s3[] = { 0xDC00, 'P', 'Q', 'R', '\0' }; EXPECT_STREQ("\xED\xB0\x80PQR", WideStringToUtf8(s3, -1).c_str()); } #endif // !GTEST_WIDE_STRING_USES_UTF16_ // Tests that codepoint concatenation works correctly. #if !GTEST_WIDE_STRING_USES_UTF16_ TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) { const wchar_t s[] = { 0x108634, 0xC74D, '\n', 0x576, 0x8D3, 0x108634, '\0'}; EXPECT_STREQ( "\xF4\x88\x98\xB4" "\xEC\x9D\x8D" "\n" "\xD5\xB6" "\xE0\xA3\x93" "\xF4\x88\x98\xB4", WideStringToUtf8(s, -1).c_str()); } #else TEST(WideStringToUtf8Test, ConcatenatesCodepointsCorrectly) { const wchar_t s[] = { 0xC74D, '\n', 0x576, 0x8D3, '\0'}; EXPECT_STREQ( "\xEC\x9D\x8D" "\n" "\xD5\xB6" "\xE0\xA3\x93", WideStringToUtf8(s, -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 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 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 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 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(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(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 String::EndsWithCaseInsensitive(). TEST(StringTest, EndsWithCaseInsensitive) { EXPECT_TRUE(String::EndsWithCaseInsensitive("foobar", "BAR")); EXPECT_TRUE(String::EndsWithCaseInsensitive("foobaR", "bar")); EXPECT_TRUE(String::EndsWithCaseInsensitive("foobar", "")); EXPECT_TRUE(String::EndsWithCaseInsensitive("", "")); EXPECT_FALSE(String::EndsWithCaseInsensitive("Foobar", "foo")); EXPECT_FALSE(String::EndsWithCaseInsensitive("foobar", "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")); } #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()); } # 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 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."); } #if GTEST_HAS_GLOBAL_STRING TEST_F(ExpectFatalFailureTest, AcceptsStringObject) { EXPECT_FATAL_FAILURE(AddFatalFailure(), ::string("Expected fatal failure.")); } #endif TEST_F(ExpectFatalFailureTest, AcceptsStdStringObject) { EXPECT_FATAL_FAILURE(AddFatalFailure(), ::std::string("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) { #ifndef __BORLANDC__ // ICE's in C++Builder. 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."); } #if GTEST_HAS_GLOBAL_STRING TEST_F(ExpectNonfatalFailureTest, AcceptsStringObject) { EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(), ::string("Expected non-fatal failure.")); } #endif TEST_F(ExpectNonfatalFailureTest, AcceptsStdStringObject) { EXPECT_NONFATAL_FAILURE(AddNonfatalFailure(), ::std::string("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 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( &TestResultAccessor::test_part_results(*r1)); TPRVector* results2 = const_cast( &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, "testcase", 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, "testcase", property_1); TestResultAccessor::RecordProperty(&test_result, "testcase", 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, "testcase", property_1_1); TestResultAccessor::RecordProperty(&test_result, "testcase", property_2_1); TestResultAccessor::RecordProperty(&test_result, "testcase", property_1_2); TestResultAccessor::RecordProperty(&test_result, "testcase", 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(TestResultPropertyTest, 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, "testcase", property_1); TestResultAccessor::RecordProperty(&test_result, "testcase", property_2); TestResultAccessor::RecordProperty(&test_result, "testcase", 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), ""); } // Tests the Test class. // // It's difficult to test every public method of this class (we are // already stretching the limit of Google Test by using it to test itself!). // Fortunately, we don't have to do that, as we are already testing // the functionalities of the Test class extensively by using Google Test // alone. // // Therefore, this section only contains one test. // 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(stream_result_to) = ""; 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_STREQ("", GTEST_FLAG(stream_result_to).c_str()); 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(stream_result_to) = "localhost:1234"; 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 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. std::string *prev_env = NULL; if (added_env.find(name) != added_env.end()) { prev_env = added_env[name]; } added_env[name] = new std::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(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)); } # if !defined(GTEST_GET_INT32_FROM_ENV_) // 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)); } # endif // !defined(GTEST_GET_INT32_FROM_ENV_) // 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(), ""); } TEST(UnitTestTest, ReturnsPlausibleTimestamp) { EXPECT_LT(0, UnitTest::GetInstance()->start_timestamp()); EXPECT_LE(UnitTest::GetInstance()->start_timestamp(), GetTimeInMillis()); } // 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 TestResult& test_result, const char* key) { EXPECT_NONFATAL_FAILURE(Test::RecordProperty(key, "1"), "Reserved key"); ASSERT_EQ(0, test_result.test_property_count()) << "Property for key '" << key << "' recorded unexpectedly."; } void ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( const char* key) { const TestInfo* test_info = UnitTest::GetInstance()->current_test_info(); ASSERT_TRUE(test_info != NULL); ExpectNonFatalFailureRecordingPropertyWithReservedKey(*test_info->result(), key); } void ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( const char* key) { const TestCase* test_case = UnitTest::GetInstance()->current_test_case(); ASSERT_TRUE(test_case != NULL); ExpectNonFatalFailureRecordingPropertyWithReservedKey( test_case->ad_hoc_test_result(), key); } void ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( const char* key) { ExpectNonFatalFailureRecordingPropertyWithReservedKey( UnitTest::GetInstance()->ad_hoc_test_result(), key); } // Tests that property recording functions in UnitTest outside of tests // functions correcly. Creating a separate instance of UnitTest ensures it // is in a state similar to the UnitTest's singleton's between tests. class UnitTestRecordPropertyTest : public testing::internal::UnitTestRecordPropertyTestHelper { public: static void SetUpTestCase() { ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( "disabled"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( "errors"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( "failures"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( "name"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( "tests"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTestCase( "time"); Test::RecordProperty("test_case_key_1", "1"); const TestCase* test_case = UnitTest::GetInstance()->current_test_case(); ASSERT_TRUE(test_case != NULL); ASSERT_EQ(1, test_case->ad_hoc_test_result().test_property_count()); EXPECT_STREQ("test_case_key_1", test_case->ad_hoc_test_result().GetTestProperty(0).key()); EXPECT_STREQ("1", test_case->ad_hoc_test_result().GetTestProperty(0).value()); } }; // Tests TestResult has the expected property when added. TEST_F(UnitTestRecordPropertyTest, OnePropertyFoundWhenAdded) { UnitTestRecordProperty("key_1", "1"); ASSERT_EQ(1, unit_test_.ad_hoc_test_result().test_property_count()); EXPECT_STREQ("key_1", unit_test_.ad_hoc_test_result().GetTestProperty(0).key()); EXPECT_STREQ("1", unit_test_.ad_hoc_test_result().GetTestProperty(0).value()); } // Tests TestResult has multiple properties when added. TEST_F(UnitTestRecordPropertyTest, MultiplePropertiesFoundWhenAdded) { UnitTestRecordProperty("key_1", "1"); UnitTestRecordProperty("key_2", "2"); ASSERT_EQ(2, unit_test_.ad_hoc_test_result().test_property_count()); EXPECT_STREQ("key_1", unit_test_.ad_hoc_test_result().GetTestProperty(0).key()); EXPECT_STREQ("1", unit_test_.ad_hoc_test_result().GetTestProperty(0).value()); EXPECT_STREQ("key_2", unit_test_.ad_hoc_test_result().GetTestProperty(1).key()); EXPECT_STREQ("2", unit_test_.ad_hoc_test_result().GetTestProperty(1).value()); } // Tests TestResult::RecordProperty() overrides values for duplicate keys. TEST_F(UnitTestRecordPropertyTest, OverridesValuesForDuplicateKeys) { UnitTestRecordProperty("key_1", "1"); UnitTestRecordProperty("key_2", "2"); UnitTestRecordProperty("key_1", "12"); UnitTestRecordProperty("key_2", "22"); ASSERT_EQ(2, unit_test_.ad_hoc_test_result().test_property_count()); EXPECT_STREQ("key_1", unit_test_.ad_hoc_test_result().GetTestProperty(0).key()); EXPECT_STREQ("12", unit_test_.ad_hoc_test_result().GetTestProperty(0).value()); EXPECT_STREQ("key_2", unit_test_.ad_hoc_test_result().GetTestProperty(1).key()); EXPECT_STREQ("22", unit_test_.ad_hoc_test_result().GetTestProperty(1).value()); } TEST_F(UnitTestRecordPropertyTest, AddFailureInsideTestsWhenUsingTestCaseReservedKeys) { ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( "name"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( "value_param"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( "type_param"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( "status"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( "time"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyForCurrentTest( "classname"); } TEST_F(UnitTestRecordPropertyTest, AddRecordWithReservedKeysGeneratesCorrectPropertyList) { EXPECT_NONFATAL_FAILURE( Test::RecordProperty("name", "1"), "'classname', 'name', 'status', 'time', 'type_param', and 'value_param'" " are reserved"); } class UnitTestRecordPropertyTestEnvironment : public Environment { public: virtual void TearDown() { ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "tests"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "failures"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "disabled"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "errors"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "name"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "timestamp"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "time"); ExpectNonFatalFailureRecordingPropertyWithReservedKeyOutsideOfTestCase( "random_seed"); } }; // This will test property recording outside of any test or test case. static Environment* record_property_env = AddGlobalTestEnvironment(new UnitTestRecordPropertyTestEnvironment); // 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 bool IsNegative(T x) { return x < 0; } template 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, -5); // Makes sure that we can handle templates with more than one // parameter. ASSERT_PRED2((GreaterThan), 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 AssertionResult IsNegativeFormat(const char* /* expr */, T x) { return x < 0 ? AssertionSuccess() : AssertionFailure(Message() << "Failure"); } template 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(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(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(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"); // The streaming variation. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_STREQ(L"abc\x8119", L"abc\x8121") << "Expected failure"; }, "Expected failure"); } // Tests *_STRNE on wide strings. TEST(StringAssertionTest, STRNE_Wide) { // NULL strings. EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_STRNE(static_cast(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"); // The streaming variation. ASSERT_STRNE(L"abc\x8119", L"abc\x8120") << "This shouldn't happen"; } // 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(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(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 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 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(1) << (Floating::kFractionBitCount - 1)) | 1); values_.nan2 = Floating::ReinterpretBits(Floating::kExponentBitMask | (static_cast(1) << (Floating::kFractionBitCount - 1)) | 200); } void TestSize() { EXPECT_EQ(sizeof(RawType), sizeof(Bits)); } static TestValues values_; }; template typename FloatingPointTest::TestValues FloatingPointTest::values_; // Instantiates FloatingPointTest for testing *_FLOAT_EQ. typedef FloatingPointTest 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 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 class TypedTest : public Test { }; typedef testing::Types NumericTypes; TYPED_TEST_CASE(TypedTest, NumericTypes); TYPED_TEST(TypedTest, DISABLED_ShouldNotRun) { FAIL() << "Unexpected failure: Disabled typed test should not run."; } template 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 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 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(>est_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(>est_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(>est_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. std::string EditsToString(const std::vector& edits) { std::string out; for (size_t i = 0; i < edits.size(); ++i) { static const char kEdits[] = " +-/"; out.append(1, kEdits[edits[i]]); } return out; } std::vector CharsToIndices(const std::string& str) { std::vector out; for (size_t i = 0; i < str.size(); ++i) { out.push_back(str[i]); } return out; } std::vector CharsToLines(const std::string& str) { std::vector out; for (size_t i = 0; i < str.size(); ++i) { out.push_back(str.substr(i, 1)); } return out; } TEST(EditDistance, TestCases) { struct Case { int line; const char* left; const char* right; const char* expected_edits; const char* expected_diff; }; static const Case kCases[] = { // No change. {__LINE__, "A", "A", " ", ""}, {__LINE__, "ABCDE", "ABCDE", " ", ""}, // Simple adds. {__LINE__, "X", "XA", " +", "@@ +1,2 @@\n X\n+A\n"}, {__LINE__, "X", "XABCD", " ++++", "@@ +1,5 @@\n X\n+A\n+B\n+C\n+D\n"}, // Simple removes. {__LINE__, "XA", "X", " -", "@@ -1,2 @@\n X\n-A\n"}, {__LINE__, "XABCD", "X", " ----", "@@ -1,5 @@\n X\n-A\n-B\n-C\n-D\n"}, // Simple replaces. {__LINE__, "A", "a", "/", "@@ -1,1 +1,1 @@\n-A\n+a\n"}, {__LINE__, "ABCD", "abcd", "////", "@@ -1,4 +1,4 @@\n-A\n-B\n-C\n-D\n+a\n+b\n+c\n+d\n"}, // Path finding. {__LINE__, "ABCDEFGH", "ABXEGH1", " -/ - +", "@@ -1,8 +1,7 @@\n A\n B\n-C\n-D\n+X\n E\n-F\n G\n H\n+1\n"}, {__LINE__, "AAAABCCCC", "ABABCDCDC", "- / + / ", "@@ -1,9 +1,9 @@\n-A\n A\n-A\n+B\n A\n B\n C\n+D\n C\n-C\n+D\n C\n"}, {__LINE__, "ABCDE", "BCDCD", "- +/", "@@ -1,5 +1,5 @@\n-A\n B\n C\n D\n-E\n+C\n+D\n"}, {__LINE__, "ABCDEFGHIJKL", "BCDCDEFGJKLJK", "- ++ -- ++", "@@ -1,4 +1,5 @@\n-A\n B\n+C\n+D\n C\n D\n" "@@ -6,7 +7,7 @@\n F\n G\n-H\n-I\n J\n K\n L\n+J\n+K\n"}, {}}; for (const Case* c = kCases; c->left; ++c) { EXPECT_TRUE(c->expected_edits == EditsToString(CalculateOptimalEdits(CharsToIndices(c->left), CharsToIndices(c->right)))) << "Left <" << c->left << "> Right <" << c->right << "> Edits <" << EditsToString(CalculateOptimalEdits( CharsToIndices(c->left), CharsToIndices(c->right))) << ">"; EXPECT_TRUE(c->expected_diff == CreateUnifiedDiff(CharsToLines(c->left), CharsToLines(c->right))) << "Left <" << c->left << "> Right <" << c->right << "> Diff <" << CreateUnifiedDiff(CharsToLines(c->left), CharsToLines(c->right)) << ">"; } } // Tests EqFailure(), used for implementing *EQ* assertions. TEST(AssertionTest, EqFailure) { const std::string foo_val("5"), bar_val("6"); const std::string msg1( EqFailure("foo", "bar", foo_val, bar_val, false) .failure_message()); EXPECT_STREQ( " Expected: foo\n" " Which is: 5\n" "To be equal to: bar\n" " Which is: 6", msg1.c_str()); const std::string msg2( EqFailure("foo", "6", foo_val, bar_val, false) .failure_message()); EXPECT_STREQ( " Expected: foo\n" " Which is: 5\n" "To be equal to: 6", msg2.c_str()); const std::string msg3( EqFailure("5", "bar", foo_val, bar_val, false) .failure_message()); EXPECT_STREQ( " Expected: 5\n" "To be equal to: bar\n" " Which is: 6", msg3.c_str()); const std::string msg4( EqFailure("5", "6", foo_val, bar_val, false).failure_message()); EXPECT_STREQ( " Expected: 5\n" "To be equal to: 6", msg4.c_str()); const std::string msg5( EqFailure("foo", "bar", std::string("\"x\""), std::string("\"y\""), true).failure_message()); EXPECT_STREQ( " Expected: foo\n" " Which is: \"x\"\n" "To be equal to: bar\n" " Which is: \"y\"\n" "Ignoring case", msg5.c_str()); } TEST(AssertionTest, EqFailureWithDiff) { const std::string left( "1\\n2XXX\\n3\\n5\\n6\\n7\\n8\\n9\\n10\\n11\\n12XXX\\n13\\n14\\n15"); const std::string right( "1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\\n11\\n12\\n13\\n14"); const std::string msg1( EqFailure("left", "right", left, right, false).failure_message()); EXPECT_STREQ( " Expected: left\n" " Which is: " "1\\n2XXX\\n3\\n5\\n6\\n7\\n8\\n9\\n10\\n11\\n12XXX\\n13\\n14\\n15\n" "To be equal to: right\n" " Which is: 1\\n2\\n3\\n4\\n5\\n6\\n7\\n8\\n9\\n11\\n12\\n13\\n14\n" "With diff:\n@@ -1,5 +1,6 @@\n 1\n-2XXX\n+2\n 3\n+4\n 5\n 6\n" "@@ -7,8 +8,6 @@\n 8\n 9\n-10\n 11\n-12XXX\n+12\n 13\n 14\n-15\n", msg1.c_str()); } // Tests AppendUserMessage(), used for implementing the *EQ* macros. TEST(AssertionTest, AppendUserMessage) { const std::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)); #ifndef __BORLANDC__ // ICE's in C++Builder. 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)); #ifndef __BORLANDC__ // ICE's in C++Builder. 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), " Expected: 5\n" "To be equal to: 2*3\n" " Which is: 6"); } // 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), "To be equal to: &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(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); bool false_value = false; ASSERT_EQ(true && false_value, 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), "To be equal to: 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(), "Expected: x\n Which is: 5\nTo be equal to: y\n Which is: -1"); } // 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), "Expected: x\n Which is: 5\nTo be equal to: y\n Which is: -1"); } enum NamedEnum { kE1 = 0, kE2 = 1 }; TEST(AssertionTest, NamedEnum) { EXPECT_EQ(kE1, kE1); EXPECT_LT(kE1, kE2); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(kE1, kE2), "Which is: 0"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(kE1, kE2), "Which is: 1"); } // 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 and HP aCC also reject this code. #if !GTEST_OS_MAC && !defined(__SUNPRO_CC) && !defined(__HP_aCC) // Tests using assertions with anonymous enums. enum { kCaseA = -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, kCaseB and kCaseA have the same value when truncated to // int size. We want to test whether this will confuse the // assertions. kCaseB = testing::internal::kMaxBiggestInt, # else kCaseB = INT_MAX, # endif // GTEST_OS_LINUX kCaseC = 42 }; TEST(AssertionTest, AnonymousEnum) { # if GTEST_OS_LINUX EXPECT_EQ(static_cast(kCaseA), static_cast(kCaseB)); # endif // GTEST_OS_LINUX EXPECT_EQ(kCaseA, kCaseA); EXPECT_NE(kCaseA, kCaseB); EXPECT_LT(kCaseA, kCaseB); EXPECT_LE(kCaseA, kCaseB); EXPECT_GT(kCaseB, kCaseA); EXPECT_GE(kCaseA, kCaseA); EXPECT_NONFATAL_FAILURE(EXPECT_GE(kCaseA, kCaseB), "(kCaseA) >= (kCaseB)"); EXPECT_NONFATAL_FAILURE(EXPECT_GE(kCaseA, kCaseC), "-1 vs 42"); ASSERT_EQ(kCaseA, kCaseA); ASSERT_NE(kCaseA, kCaseB); ASSERT_LT(kCaseA, kCaseB); ASSERT_LE(kCaseA, kCaseB); ASSERT_GT(kCaseB, kCaseA); ASSERT_GE(kCaseA, kCaseA); # ifndef __BORLANDC__ // ICE's in C++Builder. EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseB), "To be equal to: kCaseB"); EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseC), "Which is: 42"); # endif EXPECT_FATAL_FAILURE(ASSERT_EQ(kCaseA, kCaseC), "Which is: -1"); } #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: 0x0"); EXPECT_NONFATAL_FAILURE(EXPECT_HRESULT_FAILED(FalseHRESULTSuccess()), "Expected: (FalseHRESULTSuccess()) fails.\n" " Actual: 0x1"); } 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: 0x0"); # endif EXPECT_FATAL_FAILURE(ASSERT_HRESULT_FAILED(FalseHRESULTSuccess()), "Expected: (FalseHRESULTSuccess()) fails.\n" " Actual: 0x1"); } // 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 "std::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 the message streaming variation of assertions. TEST(AssertionWithMessageTest, EXPECT) { EXPECT_EQ(1, 1) << "This should succeed."; EXPECT_NONFATAL_FAILURE(EXPECT_NE(1, 1) << "Expected failure #1.", "Expected failure #1"); EXPECT_LE(1, 2) << "This should succeed."; EXPECT_NONFATAL_FAILURE(EXPECT_LT(1, 0) << "Expected failure #2.", "Expected failure #2."); EXPECT_GE(1, 0) << "This should succeed."; EXPECT_NONFATAL_FAILURE(EXPECT_GT(1, 2) << "Expected failure #3.", "Expected failure #3."); EXPECT_STREQ("1", "1") << "This should succeed."; EXPECT_NONFATAL_FAILURE(EXPECT_STRNE("1", "1") << "Expected failure #4.", "Expected failure #4."); EXPECT_STRCASEEQ("a", "A") << "This should succeed."; EXPECT_NONFATAL_FAILURE(EXPECT_STRCASENE("a", "A") << "Expected failure #5.", "Expected failure #5."); EXPECT_FLOAT_EQ(1, 1) << "This should succeed."; EXPECT_NONFATAL_FAILURE(EXPECT_DOUBLE_EQ(1, 1.2) << "Expected failure #6.", "Expected failure #6."); EXPECT_NEAR(1, 1.1, 0.2) << "This should succeed."; } TEST(AssertionWithMessageTest, ASSERT) { ASSERT_EQ(1, 1) << "This should succeed."; ASSERT_NE(1, 2) << "This should succeed."; ASSERT_LE(1, 2) << "This should succeed."; ASSERT_LT(1, 2) << "This should succeed."; ASSERT_GE(1, 0) << "This should succeed."; EXPECT_FATAL_FAILURE(ASSERT_GT(1, 2) << "Expected failure.", "Expected failure."); } TEST(AssertionWithMessageTest, ASSERT_STR) { ASSERT_STREQ("1", "1") << "This should succeed."; ASSERT_STRNE("1", "2") << "This should succeed."; ASSERT_STRCASEEQ("a", "A") << "This should succeed."; EXPECT_FATAL_FAILURE(ASSERT_STRCASENE("a", "A") << "Expected failure.", "Expected failure."); } TEST(AssertionWithMessageTest, ASSERT_FLOATING) { ASSERT_FLOAT_EQ(1, 1) << "This should succeed."; ASSERT_DOUBLE_EQ(1, 1) << "This should succeed."; EXPECT_FATAL_FAILURE(ASSERT_NEAR(1,1.2, 0.1) << "Expect failure.", // NOLINT "Expect failure."); // To work around a bug in gcc 2.95.0, there is intentionally no // space after the first comma in the previous statement. } // Tests using ASSERT_FALSE with a streamed message. TEST(AssertionWithMessageTest, ASSERT_FALSE) { ASSERT_FALSE(false) << "This shouldn't fail."; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_FALSE(true) << "Expected failure: " << 2 << " > " << 1 << " evaluates to " << true; }, "Expected failure"); } // Tests using FAIL with a streamed message. TEST(AssertionWithMessageTest, FAIL) { EXPECT_FATAL_FAILURE(FAIL() << 0, "0"); } // Tests using SUCCEED with a streamed message. TEST(AssertionWithMessageTest, SUCCEED) { SUCCEED() << "Success == " << 1; } // Tests using ASSERT_TRUE with a streamed message. TEST(AssertionWithMessageTest, ASSERT_TRUE) { ASSERT_TRUE(true) << "This should succeed."; ASSERT_TRUE(true) << true; EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_TRUE(false) << static_cast(NULL) << static_cast(NULL); }, "(null)(null)"); } #if GTEST_OS_WINDOWS // Tests using wide strings in assertion messages. TEST(AssertionWithMessageTest, WideStringMessage) { EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_TRUE(false) << L"This failure is expected.\x8119"; }, "This failure is expected."); EXPECT_FATAL_FAILURE({ // NOLINT ASSERT_EQ(1, 2) << "This failure is " << L"expected too.\x8120"; }, "This failure is expected too."); } #endif // GTEST_OS_WINDOWS // Tests EXPECT_TRUE. TEST(ExpectTest, EXPECT_TRUE) { EXPECT_TRUE(true) << "Intentional success"; EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "Intentional failure #1.", "Intentional failure #1."); EXPECT_NONFATAL_FAILURE(EXPECT_TRUE(false) << "Intentional failure #2.", "Intentional failure #2."); 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 with a streamed message. TEST(ExpectTest, EXPECT_FALSE) { EXPECT_FALSE(2 < 1); // NOLINT EXPECT_FALSE(false) << "Intentional success"; EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "Intentional failure #1.", "Intentional failure #1."); EXPECT_NONFATAL_FAILURE(EXPECT_FALSE(true) << "Intentional failure #2.", "Intentional failure #2."); 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), " Expected: 5\n" "To be equal to: 2*3\n" " Which is: 6"); 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 warning 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), "To be equal to: &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(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(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), "To be equal to: 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(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() << "Intentional failure."; *aborted = false; } // Tests ADD_FAILURE. TEST(MacroTest, ADD_FAILURE) { bool aborted = true; EXPECT_NONFATAL_FAILURE(AddFailureHelper(&aborted), "Intentional failure."); EXPECT_FALSE(aborted); } // Tests ADD_FAILURE_AT. TEST(MacroTest, ADD_FAILURE_AT) { // Verifies that ADD_FAILURE_AT does generate a nonfatal failure and // the failure message contains the user-streamed part. EXPECT_NONFATAL_FAILURE(ADD_FAILURE_AT("foo.cc", 42) << "Wrong!", "Wrong!"); // Verifies that the user-streamed part is optional. EXPECT_NONFATAL_FAILURE(ADD_FAILURE_AT("foo.cc", 42), "Failed"); // Unfortunately, we cannot verify that the failure message contains // the right file path and line number the same way, as // EXPECT_NONFATAL_FAILURE() doesn't get to see the file path and // line number. Instead, we do that in gtest_output_test_.cc. } // 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({ bool false_value = false; ASSERT_EQ(false_value, true); }, "To be equal to: 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(0), static_cast(0)); EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(0), static_cast(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'), " Expected: L'\0'\n" " Which is: L'\0' (0, 0x0)\n" "To be equal to: L'x'\n" " Which is: L'x' (120, 0x78)"); static wchar_t wchar; wchar = L'b'; EXPECT_NONFATAL_FAILURE(EXPECT_EQ(L'a', wchar), "wchar"); wchar = 0x8119; EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(0x8120), wchar), "To be equal to: 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")), "\"test\""); // Compares an std::string to a char* that has different content. char* const p1 = const_cast("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), "To be equal to: str3\n" " Which is: \"A \\0 in the middle\""); } #if GTEST_HAS_STD_WSTRING // Tests using ::std::wstring values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, StdWideString) { // 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 identical // content. const wchar_t kTestX8119[] = { 'T', 'e', 's', 't', 0x8119, '\0' }; EXPECT_EQ(::std::wstring(kTestX8119), kTestX8119); // Compares an std::wstring to a const wchar_t* that has different // content. const wchar_t kTestX8120[] = { 'T', 'e', 's', 't', 0x8120, '\0' }; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_EQ(::std::wstring(kTestX8119), kTestX8120); }, "kTestX8120"); // 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(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("foo")); }, ""); } #endif // GTEST_HAS_GLOBAL_STRING #if GTEST_HAS_GLOBAL_WSTRING // Tests using ::wstring values in {EXPECT|ASSERT}_EQ. TEST(EqAssertionTest, GlobalWideString) { // 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 identical content. const wchar_t kTestX8119[] = { 'T', 'e', 's', 't', 0x8119, '\0' }; ASSERT_EQ(kTestX8119, ::wstring(kTestX8119)); // Compares a const wchar_t* to a ::wstring that has different // content. const wchar_t kTestX8120[] = { 'T', 'e', 's', 't', 0x8120, '\0' }; EXPECT_NONFATAL_FAILURE({ // NOLINT EXPECT_EQ(kTestX8120, ::wstring(kTestX8119)); }, "Test\\x8119"); // Compares a wchar_t* to a ::wstring that has different content. wchar_t* const p1 = const_cast(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(pv1); char* const p2 = reinterpret_cast(pv2); ASSERT_EQ(p1, p1); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2), "To be equal to: p2"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p1, p2), "p2"); EXPECT_FATAL_FAILURE(ASSERT_EQ(reinterpret_cast(0x1234), reinterpret_cast(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(pv1); wchar_t* const p2 = reinterpret_cast(pv2); EXPECT_EQ(p0, p0); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(p0, p2), "To be equal to: 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(pv3); const wchar_t* p4 = reinterpret_cast(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(NULL), static_cast(NULL)); EXPECT_FATAL_FAILURE(ASSERT_EQ(static_cast(NULL), reinterpret_cast(0x1234)), "0x1234"); } // A class that supports binary comparison operators but not streaming. class UnprintableChar { public: explicit UnprintableChar(char ch) : char_(ch) {} bool operator==(const UnprintableChar& rhs) const { return char_ == rhs.char_; } bool operator!=(const UnprintableChar& rhs) const { return char_ != rhs.char_; } bool operator<(const UnprintableChar& rhs) const { return char_ < rhs.char_; } bool operator<=(const UnprintableChar& rhs) const { return char_ <= rhs.char_; } bool operator>(const UnprintableChar& rhs) const { return char_ > rhs.char_; } bool operator>=(const UnprintableChar& rhs) const { return char_ >= rhs.char_; } private: char char_; }; // Tests that ASSERT_EQ() and friends don't require the arguments to // be printable. TEST(ComparisonAssertionTest, AcceptsUnprintableArgs) { const UnprintableChar x('x'), y('y'); ASSERT_EQ(x, x); EXPECT_NE(x, y); ASSERT_LT(x, y); EXPECT_LE(x, y); ASSERT_GT(y, x); EXPECT_GE(x, x); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), "1-byte object <78>"); EXPECT_NONFATAL_FAILURE(EXPECT_EQ(x, y), "1-byte object <79>"); EXPECT_NONFATAL_FAILURE(EXPECT_LT(y, y), "1-byte object <79>"); EXPECT_NONFATAL_FAILURE(EXPECT_GT(x, y), "1-byte object <78>"); EXPECT_NONFATAL_FAILURE(EXPECT_GT(x, y), "1-byte object <79>"); // Code tested by EXPECT_FATAL_FAILURE cannot reference local // variables, so we have to write UnprintableChar('x') instead of x. #ifndef __BORLANDC__ // ICE's in C++Builder. EXPECT_FATAL_FAILURE(ASSERT_NE(UnprintableChar('x'), UnprintableChar('x')), "1-byte object <78>"); EXPECT_FATAL_FAILURE(ASSERT_LE(UnprintableChar('y'), UnprintableChar('x')), "1-byte object <78>"); #endif EXPECT_FATAL_FAILURE(ASSERT_LE(UnprintableChar('y'), UnprintableChar('x')), "1-byte object <79>"); EXPECT_FATAL_FAILURE(ASSERT_GE(UnprintableChar('x'), UnprintableChar('y')), "1-byte object <78>"); EXPECT_FATAL_FAILURE(ASSERT_GE(UnprintableChar('x'), UnprintableChar('y')), "1-byte object <79>"); } // 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(r3), static_cast(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 flips 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()); } TEST(AssertionResultTest, CanStreamOstreamManipulators) { AssertionResult r = AssertionSuccess(); r << "Data" << std::endl << std::flush << std::ends << "Will be visible"; EXPECT_STREQ("Data\n\\0Will be visible", r.message()); } // The next test uses explicit conversion operators -- a C++11 feature. #if GTEST_LANG_CXX11 TEST(AssertionResultTest, ConstructibleFromContextuallyConvertibleToBool) { struct ExplicitlyConvertibleToBool { explicit operator bool() const { return value; } bool value; }; ExplicitlyConvertibleToBool v1 = {false}; ExplicitlyConvertibleToBool v2 = {true}; EXPECT_FALSE(v1); EXPECT_TRUE(v2); } #endif // GTEST_LANG_CXX11 struct ConvertibleToAssertionResult { operator AssertionResult() const { return AssertionResult(true); } }; TEST(AssertionResultTest, ConstructibleFromImplicitlyConvertible) { ConvertibleToAssertionResult obj; EXPECT_TRUE(obj); } // 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 ::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(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()); } #define VERIFY_CODE_LOCATION \ const int expected_line = __LINE__ - 1; \ const TestInfo* const test_info = GetUnitTestImpl()->current_test_info(); \ ASSERT_TRUE(test_info); \ EXPECT_STREQ(__FILE__, test_info->file()); \ EXPECT_EQ(expected_line, test_info->line()) TEST(CodeLocationForTEST, Verify) { VERIFY_CODE_LOCATION; } class CodeLocationForTESTF : public Test { }; TEST_F(CodeLocationForTESTF, Verify) { VERIFY_CODE_LOCATION; } class CodeLocationForTESTP : public TestWithParam { }; TEST_P(CodeLocationForTESTP, Verify) { VERIFY_CODE_LOCATION; } INSTANTIATE_TEST_CASE_P(, CodeLocationForTESTP, Values(0)); template class CodeLocationForTYPEDTEST : public Test { }; TYPED_TEST_CASE(CodeLocationForTYPEDTEST, int); TYPED_TEST(CodeLocationForTYPEDTEST, Verify) { VERIFY_CODE_LOCATION; } template class CodeLocationForTYPEDTESTP : public Test { }; TYPED_TEST_CASE_P(CodeLocationForTYPEDTESTP); TYPED_TEST_P(CodeLocationForTYPEDTESTP, Verify) { VERIFY_CODE_LOCATION; } REGISTER_TYPED_TEST_CASE_P(CodeLocationForTYPEDTESTP, Verify); INSTANTIATE_TYPED_TEST_CASE_P(My, CodeLocationForTYPEDTESTP, int); #undef VERIFY_CODE_LOCATION // 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), stream_result_to(""), 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_FLAG(stream_result_to) flag has // the given value. static Flags StreamResultTo(const char* stream_result_to) { Flags flags; flags.stream_result_to = stream_result_to; 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; const char* stream_result_to; 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(stream_result_to) = ""; GTEST_FLAG(throw_on_failure) = false; } // Asserts that two narrow or wide string arrays are equal. template 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.stack_trace_depth, GTEST_FLAG(stack_trace_depth)); EXPECT_STREQ(expected.stream_result_to, GTEST_FLAG(stream_result_to).c_str()); EXPECT_EQ(expected.throw_on_failure, GTEST_FLAG(throw_on_failure)); } // 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 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 // Parses the command line. internal::ParseGoogleTestFlagsOnly(&argc1, const_cast(argv1)); #if GTEST_HAS_STREAM_REDIRECTION const std::string captured_stdout = GetCapturedStdout(); #endif // 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); } TEST_F(InitGoogleTestTest, StreamResultTo) { const char* argv[] = { "foo.exe", "--gtest_stream_result_to=localhost:1234", NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_( argv, argv2, Flags::StreamResultTo("localhost:1234"), 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 #if GTEST_USE_OWN_FLAGFILE_FLAG_ class FlagfileTest : public InitGoogleTestTest { public: virtual void SetUp() { InitGoogleTestTest::SetUp(); testdata_path_.Set(internal::FilePath( internal::TempDir() + internal::GetCurrentExecutableName().string() + "_flagfile_test")); testing::internal::posix::RmDir(testdata_path_.c_str()); EXPECT_TRUE(testdata_path_.CreateFolder()); } virtual void TearDown() { testing::internal::posix::RmDir(testdata_path_.c_str()); InitGoogleTestTest::TearDown(); } internal::FilePath CreateFlagfile(const char* contents) { internal::FilePath file_path(internal::FilePath::GenerateUniqueFileName( testdata_path_, internal::FilePath("unique"), "txt")); FILE* f = testing::internal::posix::FOpen(file_path.c_str(), "w"); fprintf(f, "%s", contents); fclose(f); return file_path; } private: internal::FilePath testdata_path_; }; // Tests an empty flagfile. TEST_F(FlagfileTest, Empty) { internal::FilePath flagfile_path(CreateFlagfile("")); std::string flagfile_flag = std::string("--" GTEST_FLAG_PREFIX_ "flagfile=") + flagfile_path.c_str(); const char* argv[] = { "foo.exe", flagfile_flag.c_str(), NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags(), false); } // Tests passing a non-empty --gtest_filter flag via --gtest_flagfile. TEST_F(FlagfileTest, FilterNonEmpty) { internal::FilePath flagfile_path(CreateFlagfile( "--" GTEST_FLAG_PREFIX_ "filter=abc")); std::string flagfile_flag = std::string("--" GTEST_FLAG_PREFIX_ "flagfile=") + flagfile_path.c_str(); const char* argv[] = { "foo.exe", flagfile_flag.c_str(), NULL }; const char* argv2[] = { "foo.exe", NULL }; GTEST_TEST_PARSING_FLAGS_(argv, argv2, Flags::Filter("abc"), false); } // Tests passing several flags via --gtest_flagfile. TEST_F(FlagfileTest, SeveralFlags) { internal::FilePath flagfile_path(CreateFlagfile( "--" GTEST_FLAG_PREFIX_ "filter=abc\n" "--" GTEST_FLAG_PREFIX_ "break_on_failure\n" "--" GTEST_FLAG_PREFIX_ "list_tests")); std::string flagfile_flag = std::string("--" GTEST_FLAG_PREFIX_ "flagfile=") + flagfile_path.c_str(); const char* argv[] = { "foo.exe", flagfile_flag.c_str(), NULL }; const char* argv2[] = { "foo.exe", NULL }; Flags expected_flags; expected_flags.break_on_failure = true; expected_flags.filter = "abc"; expected_flags.list_tests = true; GTEST_TEST_PARSING_FLAGS_(argv, argv2, expected_flags, false); } #endif // GTEST_USE_OWN_FLAGFILE_FLAG_ // 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", "xterm-256color"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "screen"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "screen-256color"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "tmux"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "tmux-256color"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "rxvt-unicode"); // TERM supports colors. EXPECT_TRUE(ShouldUseColor(true)); // Stdout is a TTY. SetEnv("TERM", "rxvt-unicode-256color"); // 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. SetEnv("TERM", "cygwin"); // 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 GTEST_ATTRIBUTE_UNUSED_ = StaticAssertTypeEq(); static bool dummy2 GTEST_ATTRIBUTE_UNUSED_ = StaticAssertTypeEq(); // Verifies that StaticAssertTypeEq works in a class. template class StaticAssertTypeEqTestHelper { public: StaticAssertTypeEqTestHelper() { StaticAssertTypeEq(); } }; TEST(StaticAssertTypeEqTest, WorksInClass) { StaticAssertTypeEqTestHelper(); } // Verifies that StaticAssertTypeEq works inside a function. typedef int IntAlias; TEST(StaticAssertTypeEqTest, CompilesForEqualTypes) { StaticAssertTypeEq(); StaticAssertTypeEq(); } 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* 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: std::string GetEventDescription(const char* method) { Message message; message << id_ << "." << method; return message.GetString(); } std::vector* vector_; const char* const id_; GTEST_DISALLOW_COPY_AND_ASSIGN_(SequenceTestingListener); }; TEST(EventListenerTest, AppendKeepsOrder) { std::vector 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"); // GTEST_ASSERT_XY is the same as ASSERT_XY. GTEST_ASSERT_EQ(0, 0); EXPECT_FATAL_FAILURE(GTEST_ASSERT_EQ(0, 1) << "An expected failure", "An expected failure"); EXPECT_FATAL_FAILURE(GTEST_ASSERT_EQ(1, 0) << "An expected failure", "An expected failure"); GTEST_ASSERT_NE(0, 1); GTEST_ASSERT_NE(1, 0); EXPECT_FATAL_FAILURE(GTEST_ASSERT_NE(0, 0) << "An expected failure", "An expected failure"); GTEST_ASSERT_LE(0, 0); GTEST_ASSERT_LE(0, 1); EXPECT_FATAL_FAILURE(GTEST_ASSERT_LE(1, 0) << "An expected failure", "An expected failure"); GTEST_ASSERT_LT(0, 1); EXPECT_FATAL_FAILURE(GTEST_ASSERT_LT(0, 0) << "An expected failure", "An expected failure"); EXPECT_FATAL_FAILURE(GTEST_ASSERT_LT(1, 0) << "An expected failure", "An expected failure"); GTEST_ASSERT_GE(0, 0); GTEST_ASSERT_GE(1, 0); EXPECT_FATAL_FAILURE(GTEST_ASSERT_GE(0, 1) << "An expected failure", "An expected failure"); GTEST_ASSERT_GT(1, 0); EXPECT_FATAL_FAILURE(GTEST_ASSERT_GT(0, 1) << "An expected failure", "An expected failure"); EXPECT_FATAL_FAILURE(GTEST_ASSERT_GT(1, 1) << "An expected failure", "An expected failure"); } // Tests for internal utilities necessary for implementation of the universal // printing. // TODO(vladl@google.com): Find a better home for them. class ConversionHelperBase {}; class ConversionHelperDerived : public ConversionHelperBase {}; // Tests that IsAProtocolMessage::value is a compile-time constant. TEST(IsAProtocolMessageTest, ValueIsCompileTimeConstant) { GTEST_COMPILE_ASSERT_(IsAProtocolMessage::value, const_true); GTEST_COMPILE_ASSERT_(!IsAProtocolMessage::value, const_false); } // Tests that IsAProtocolMessage::value is true when T is // proto2::Message or a sub-class of it. TEST(IsAProtocolMessageTest, ValueIsTrueWhenTypeIsAProtocolMessage) { EXPECT_TRUE(IsAProtocolMessage< ::proto2::Message>::value); EXPECT_TRUE(IsAProtocolMessage::value); } // Tests that IsAProtocolMessage::value is false when T is neither // ProtocolMessage nor a sub-class of it. TEST(IsAProtocolMessageTest, ValueIsFalseWhenTypeIsNotAProtocolMessage) { EXPECT_FALSE(IsAProtocolMessage::value); EXPECT_FALSE(IsAProtocolMessage::value); } // Tests that CompileAssertTypesEqual compiles when the type arguments are // equal. TEST(CompileAssertTypesEqual, CompilesWhenTypesAreEqual) { CompileAssertTypesEqual(); CompileAssertTypesEqual(); } // Tests that RemoveReference does not affect non-reference types. TEST(RemoveReferenceTest, DoesNotAffectNonReferenceType) { CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); } // Tests that RemoveReference removes reference from reference types. TEST(RemoveReferenceTest, RemovesReference) { CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); } // Tests GTEST_REMOVE_REFERENCE_. template void TestGTestRemoveReference() { CompileAssertTypesEqual(); } TEST(RemoveReferenceTest, MacroVersion) { TestGTestRemoveReference(); TestGTestRemoveReference(); } // Tests that RemoveConst does not affect non-const types. TEST(RemoveConstTest, DoesNotAffectNonConstType) { CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); } // Tests that RemoveConst removes const from const types. TEST(RemoveConstTest, RemovesConst) { CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); } // Tests GTEST_REMOVE_CONST_. template void TestGTestRemoveConst() { CompileAssertTypesEqual(); } TEST(RemoveConstTest, MacroVersion) { TestGTestRemoveConst(); TestGTestRemoveConst(); TestGTestRemoveConst(); } // Tests GTEST_REMOVE_REFERENCE_AND_CONST_. template void TestGTestRemoveReferenceAndConst() { CompileAssertTypesEqual(); } TEST(RemoveReferenceToConstTest, Works) { TestGTestRemoveReferenceAndConst(); TestGTestRemoveReferenceAndConst(); TestGTestRemoveReferenceAndConst(); TestGTestRemoveReferenceAndConst(); TestGTestRemoveReferenceAndConst(); } // Tests that AddReference does not affect reference types. TEST(AddReferenceTest, DoesNotAffectReferenceType) { CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); } // Tests that AddReference adds reference to non-reference types. TEST(AddReferenceTest, AddsReference) { CompileAssertTypesEqual::type>(); CompileAssertTypesEqual::type>(); } // Tests GTEST_ADD_REFERENCE_. template void TestGTestAddReference() { CompileAssertTypesEqual(); } TEST(AddReferenceTest, MacroVersion) { TestGTestAddReference(); TestGTestAddReference(); } // Tests GTEST_REFERENCE_TO_CONST_. template void TestGTestReferenceToConst() { CompileAssertTypesEqual(); } TEST(GTestReferenceToConstTest, Works) { TestGTestReferenceToConst(); TestGTestReferenceToConst(); TestGTestReferenceToConst(); TestGTestReferenceToConst(); } // Tests that ImplicitlyConvertible::value is a compile-time constant. TEST(ImplicitlyConvertibleTest, ValueIsCompileTimeConstant) { GTEST_COMPILE_ASSERT_((ImplicitlyConvertible::value), const_true); GTEST_COMPILE_ASSERT_((!ImplicitlyConvertible::value), const_false); } // Tests that ImplicitlyConvertible::value is true when T1 can // be implicitly converted to T2. TEST(ImplicitlyConvertibleTest, ValueIsTrueWhenConvertible) { EXPECT_TRUE((ImplicitlyConvertible::value)); EXPECT_TRUE((ImplicitlyConvertible::value)); EXPECT_TRUE((ImplicitlyConvertible::value)); EXPECT_TRUE((ImplicitlyConvertible::value)); EXPECT_TRUE((ImplicitlyConvertible::value)); EXPECT_TRUE((ImplicitlyConvertible::value)); } // Tests that ImplicitlyConvertible::value is false when T1 // cannot be implicitly converted to T2. TEST(ImplicitlyConvertibleTest, ValueIsFalseWhenNotConvertible) { EXPECT_FALSE((ImplicitlyConvertible::value)); EXPECT_FALSE((ImplicitlyConvertible::value)); EXPECT_FALSE((ImplicitlyConvertible::value)); EXPECT_FALSE((ImplicitlyConvertible::value)); } // Tests IsContainerTest. class NonContainer {}; TEST(IsContainerTestTest, WorksForNonContainer) { EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); EXPECT_EQ(sizeof(IsNotContainer), sizeof(IsContainerTest(0))); } TEST(IsContainerTestTest, WorksForContainer) { EXPECT_EQ(sizeof(IsContainer), sizeof(IsContainerTest >(0))); EXPECT_EQ(sizeof(IsContainer), sizeof(IsContainerTest >(0))); } // Tests ArrayEq(). TEST(ArrayEqTest, WorksForDegeneratedArrays) { EXPECT_TRUE(ArrayEq(5, 5L)); EXPECT_FALSE(ArrayEq('a', 0)); } TEST(ArrayEqTest, WorksForOneDimensionalArrays) { // Note that a and b are distinct but compatible types. const int a[] = { 0, 1 }; long b[] = { 0, 1 }; EXPECT_TRUE(ArrayEq(a, b)); EXPECT_TRUE(ArrayEq(a, 2, b)); b[0] = 2; EXPECT_FALSE(ArrayEq(a, b)); EXPECT_FALSE(ArrayEq(a, 1, b)); } TEST(ArrayEqTest, WorksForTwoDimensionalArrays) { const char a[][3] = { "hi", "lo" }; const char b[][3] = { "hi", "lo" }; const char c[][3] = { "hi", "li" }; EXPECT_TRUE(ArrayEq(a, b)); EXPECT_TRUE(ArrayEq(a, 2, b)); EXPECT_FALSE(ArrayEq(a, c)); EXPECT_FALSE(ArrayEq(a, 2, c)); } // Tests ArrayAwareFind(). TEST(ArrayAwareFindTest, WorksForOneDimensionalArray) { const char a[] = "hello"; EXPECT_EQ(a + 4, ArrayAwareFind(a, a + 5, 'o')); EXPECT_EQ(a + 5, ArrayAwareFind(a, a + 5, 'x')); } TEST(ArrayAwareFindTest, WorksForTwoDimensionalArray) { int a[][2] = { { 0, 1 }, { 2, 3 }, { 4, 5 } }; const int b[2] = { 2, 3 }; EXPECT_EQ(a + 1, ArrayAwareFind(a, a + 3, b)); const int c[2] = { 6, 7 }; EXPECT_EQ(a + 3, ArrayAwareFind(a, a + 3, c)); } // Tests CopyArray(). TEST(CopyArrayTest, WorksForDegeneratedArrays) { int n = 0; CopyArray('a', &n); EXPECT_EQ('a', n); } TEST(CopyArrayTest, WorksForOneDimensionalArrays) { const char a[3] = "hi"; int b[3]; #ifndef __BORLANDC__ // C++Builder cannot compile some array size deductions. CopyArray(a, &b); EXPECT_TRUE(ArrayEq(a, b)); #endif int c[3]; CopyArray(a, 3, c); EXPECT_TRUE(ArrayEq(a, c)); } TEST(CopyArrayTest, WorksForTwoDimensionalArrays) { const int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } }; int b[2][3]; #ifndef __BORLANDC__ // C++Builder cannot compile some array size deductions. CopyArray(a, &b); EXPECT_TRUE(ArrayEq(a, b)); #endif int c[2][3]; CopyArray(a, 2, c); EXPECT_TRUE(ArrayEq(a, c)); } // Tests NativeArray. TEST(NativeArrayTest, ConstructorFromArrayWorks) { const int a[3] = { 0, 1, 2 }; NativeArray na(a, 3, RelationToSourceReference()); EXPECT_EQ(3U, na.size()); EXPECT_EQ(a, na.begin()); } TEST(NativeArrayTest, CreatesAndDeletesCopyOfArrayWhenAskedTo) { typedef int Array[2]; Array* a = new Array[1]; (*a)[0] = 0; (*a)[1] = 1; NativeArray na(*a, 2, RelationToSourceCopy()); EXPECT_NE(*a, na.begin()); delete[] a; EXPECT_EQ(0, na.begin()[0]); EXPECT_EQ(1, na.begin()[1]); // We rely on the heap checker to verify that na deletes the copy of // array. } TEST(NativeArrayTest, TypeMembersAreCorrect) { StaticAssertTypeEq::value_type>(); StaticAssertTypeEq::value_type>(); StaticAssertTypeEq::const_iterator>(); StaticAssertTypeEq::const_iterator>(); } TEST(NativeArrayTest, MethodsWork) { const int a[3] = { 0, 1, 2 }; NativeArray na(a, 3, RelationToSourceCopy()); ASSERT_EQ(3U, na.size()); EXPECT_EQ(3, na.end() - na.begin()); NativeArray::const_iterator it = na.begin(); EXPECT_EQ(0, *it); ++it; EXPECT_EQ(1, *it); it++; EXPECT_EQ(2, *it); ++it; EXPECT_EQ(na.end(), it); EXPECT_TRUE(na == na); NativeArray na2(a, 3, RelationToSourceReference()); EXPECT_TRUE(na == na2); const int b1[3] = { 0, 1, 1 }; const int b2[4] = { 0, 1, 2, 3 }; EXPECT_FALSE(na == NativeArray(b1, 3, RelationToSourceReference())); EXPECT_FALSE(na == NativeArray(b2, 4, RelationToSourceCopy())); } TEST(NativeArrayTest, WorksForTwoDimensionalArray) { const char a[2][3] = { "hi", "lo" }; NativeArray na(a, 2, RelationToSourceReference()); ASSERT_EQ(2U, na.size()); EXPECT_EQ(a, na.begin()); } // Tests SkipPrefix(). TEST(SkipPrefixTest, SkipsWhenPrefixMatches) { const char* const str = "hello"; const char* p = str; EXPECT_TRUE(SkipPrefix("", &p)); EXPECT_EQ(str, p); p = str; EXPECT_TRUE(SkipPrefix("hell", &p)); EXPECT_EQ(str + 4, p); } TEST(SkipPrefixTest, DoesNotSkipWhenPrefixDoesNotMatch) { const char* const str = "world"; const char* p = str; EXPECT_FALSE(SkipPrefix("W", &p)); EXPECT_EQ(str, p); p = str; EXPECT_FALSE(SkipPrefix("world!", &p)); EXPECT_EQ(str, p); } assimp-4.1.0/contrib/gtest/test/gtest_xml_test_utils.py0000644002537200234200000002125013213503245023660 0ustar zmoelnigiemusers#!/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. Exceptions are any attribute named "time", which needs only be convertible to a floating-point number and any attribute named "type_param" which only has to be non-empty. * 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 %s:\nExpected: %r\nActual: %r' % ( actual_node.tagName, expected_attributes.keys(), actual_attributes.keys())) 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: %s vs %s' % (expected_attr.name, actual_node.tagName, expected_attr.value, actual_attr.value)) 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.items(): 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 , and elements, the ID is the value of their "name" attribute; for 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 , and elements is replaced with a single asterisk, if it contains only digit characters. * The "timestamp" attribute of elements is replaced with a single asterisk, if it contains a valid ISO8601 datetime value. * The "type_param" attribute of elements is replaced with a single asterisk (if it sn non-empty) as it is the type name returned by the compiler and is platform dependent. * The line info reported in the first line of the "message" attribute and CDATA section of elements is replaced with the file's basename and a single asterisk for the line number. * The directory names in file paths are removed. * The stack traces are removed. """ if element.tagName == 'testsuites': timestamp = element.getAttributeNode('timestamp') timestamp.value = re.sub(r'^\d{4}-\d\d-\d\dT\d\d:\d\d:\d\d$', '*', timestamp.value) if element.tagName in ('testsuites', 'testsuite', 'testcase'): time = element.getAttributeNode('time') time.value = re.sub(r'^\d+(\.\d+)?$', '*', time.value) type_param = element.getAttributeNode('type_param') if type_param and type_param.value: type_param.value = '*' elif element.tagName == 'failure': source_line_pat = r'^.*[/\\](.*:)\d+\n' # Replaces the source line information with a normalized form. message = element.getAttributeNode('message') message.value = re.sub(source_line_pat, '\\1*\n', message.value) for child in element.childNodes: if child.nodeType == Node.CDATA_SECTION_NODE: # Replaces the source line information with a normalized form. cdata = re.sub(source_line_pat, '\\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) assimp-4.1.0/contrib/gtest/test/gtest_pred_impl_unittest.cc0000644002537200234200000022710213213503245024454 0ustar zmoelnigiemusers// 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/31/2011 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 #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 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 bool operator()(const T1& v1) { return v1 > 0; } }; // A unary predicate-formatter function. template testing::AssertionResult PredFormatFunction1(const char* e1, const T1& v1) { if (PredFunction1(v1)) return testing::AssertionSuccess(); return testing::AssertionFailure() << e1 << " is expected to be positive, but evaluates to " << v1 << "."; } // A unary predicate-formatter functor. struct PredFormatFunctor1 { template 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 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 bool operator()(const T1& v1, const T2& v2) { return v1 + v2 > 0; } }; // A binary predicate-formatter function. template testing::AssertionResult PredFormatFunction2(const char* e1, const char* e2, const T1& v1, const T2& v2) { if (PredFunction2(v1, v2)) return testing::AssertionSuccess(); return testing::AssertionFailure() << e1 << " + " << e2 << " is expected to be positive, but evaluates to " << v1 + v2 << "."; } // A binary predicate-formatter functor. struct PredFormatFunctor2 { template 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 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 bool operator()(const T1& v1, const T2& v2, const T3& v3) { return v1 + v2 + v3 > 0; } }; // A ternary predicate-formatter function. template 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(); return testing::AssertionFailure() << e1 << " + " << e2 << " + " << e3 << " is expected to be positive, but evaluates to " << v1 + v2 + v3 << "."; } // A ternary predicate-formatter functor. struct PredFormatFunctor3 { template 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 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 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 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(); return testing::AssertionFailure() << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " is expected to be positive, but evaluates to " << v1 + v2 + v3 + v4 << "."; } // A 4-ary predicate-formatter functor. struct PredFormatFunctor4 { template 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 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 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 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(); return testing::AssertionFailure() << e1 << " + " << e2 << " + " << e3 << " + " << e4 << " + " << e5 << " is expected to be positive, but evaluates to " << v1 + v2 + v3 + v4 + v5 << "."; } // A 5-ary predicate-formatter functor. struct PredFormatFunctor5 { template 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; }, ""); } assimp-4.1.0/contrib/gtest/test/gtest_env_var_test.py0000644002537200234200000000770413213503245023310 0ustar zmoelnigiemusers#!/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', '*') SetEnvVar('XML_OUTPUT_FILE', None) # For 'output' test 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') TestFlag('catch_exceptions', '0', '1') if IS_LINUX: TestFlag('death_test_use_fork', '1', '0') TestFlag('stack_trace_depth', '0', '100') def testXmlOutputFile(self): """Tests that $XML_OUTPUT_FILE affects the output flag.""" SetEnvVar('GTEST_OUTPUT', None) SetEnvVar('XML_OUTPUT_FILE', 'tmp/bar.xml') AssertEq('xml:tmp/bar.xml', GetFlag('output')) def testXmlOutputFileOverride(self): """Tests that $XML_OUTPUT_FILE is overridden by $GTEST_OUTPUT""" SetEnvVar('GTEST_OUTPUT', 'xml:tmp/foo.xml') SetEnvVar('XML_OUTPUT_FILE', 'tmp/bar.xml') AssertEq('xml:tmp/foo.xml', GetFlag('output')) if __name__ == '__main__': gtest_test_utils.Main() assimp-4.1.0/contrib/gtest/test/production.h0000644002537200234200000000417413213503245021366 0ustar zmoelnigiemusers// 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_ assimp-4.1.0/contrib/gtest/test/gtest_list_tests_unittest.py0000644002537200234200000001461113213503245024740 0ustar zmoelnigiemusers#!/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 import re # 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_RE = re.compile(r"""FooDeathTest\. Test1 Foo\. Bar1 Bar2 DISABLED_Bar3 Abc\. Xyz Def FooBar\. Baz FooTest\. Test1 DISABLED_Test2 Test3 TypedTest/0\. # TypeParam = (VeryLo{245}|class VeryLo{239})\.\.\. TestA TestB TypedTest/1\. # TypeParam = int\s*\*( __ptr64)? TestA TestB TypedTest/2\. # TypeParam = .*MyArray TestA TestB My/TypeParamTest/0\. # TypeParam = (VeryLo{245}|class VeryLo{239})\.\.\. TestA TestB My/TypeParamTest/1\. # TypeParam = int\s*\*( __ptr64)? TestA TestB My/TypeParamTest/2\. # TypeParam = .*MyArray TestA TestB MyInstantiation/ValueParamTest\. TestA/0 # GetParam\(\) = one line TestA/1 # GetParam\(\) = two\\nlines TestA/2 # GetParam\(\) = a very\\nlo{241}\.\.\. TestB/0 # GetParam\(\) = one line TestB/1 # GetParam\(\) = two\\nlines TestB/2 # GetParam\(\) = a very\\nlo{241}\.\.\. """) # The expected output when running gtest_list_tests_unittest_ with # --gtest_list_tests and --gtest_filter=Foo*. EXPECTED_OUTPUT_FILTER_FOO_RE = re.compile(r"""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_re, 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_re: regular expression that matches 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) if expected_output_re: self.assert_( expected_output_re.match(output), ('when %s is %s, the output of "%s" is "%s",\n' 'which does not match regex "%s"' % (LIST_TESTS_FLAG, flag_expression, ' '.join(args), output, expected_output_re.pattern))) else: self.assert_( not EXPECTED_OUTPUT_NO_FILTER_RE.match(output), ('when %s is %s, the output of "%s" is "%s"'% (LIST_TESTS_FLAG, flag_expression, ' '.join(args), output))) def testDefaultBehavior(self): """Tests the behavior of the default mode.""" self.RunAndVerify(flag_value=None, expected_output_re=None, other_flag=None) def testFlag(self): """Tests using the --gtest_list_tests flag.""" self.RunAndVerify(flag_value='0', expected_output_re=None, other_flag=None) self.RunAndVerify(flag_value='1', expected_output_re=EXPECTED_OUTPUT_NO_FILTER_RE, other_flag=None) def testOverrideNonFilterFlags(self): """Tests that --gtest_list_tests overrides the non-filter flags.""" self.RunAndVerify(flag_value='1', expected_output_re=EXPECTED_OUTPUT_NO_FILTER_RE, 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_re=EXPECTED_OUTPUT_FILTER_FOO_RE, other_flag='--gtest_filter=Foo*') if __name__ == '__main__': gtest_test_utils.Main() assimp-4.1.0/contrib/gtest/test/gtest-param-test2_test.cc0000644002537200234200000000550413213503245023656 0ustar zmoelnigiemusers// 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 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 assimp-4.1.0/contrib/gtest/test/gtest_color_test.py0000644002537200234200000001145713213503245022766 0ustar zmoelnigiemusers#!/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() assimp-4.1.0/contrib/gtest/test/gtest_sole_header_test.cc0000644002537200234200000000425513213503245024055 0ustar zmoelnigiemusers// 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 assimp-4.1.0/contrib/gtest/test/gtest-message_test.cc0000644002537200234200000001226613213503245023146 0ustar zmoelnigiemusers// 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; // Tests the testing::Message class // Tests the default constructor. TEST(MessageTest, DefaultConstructor) { const Message msg; EXPECT_EQ("", msg.GetString()); } // Tests the copy constructor. TEST(MessageTest, CopyConstructor) { const Message msg1("Hello"); const Message msg2(msg1); EXPECT_EQ("Hello", msg2.GetString()); } // Tests constructing a Message from a C-string. TEST(MessageTest, ConstructsFromCString) { Message msg("Hello"); EXPECT_EQ("Hello", msg.GetString()); } // Tests streaming a float. TEST(MessageTest, StreamsFloat) { const std::string s = (Message() << 1.23456F << " " << 2.34567F).GetString(); // Both numbers should be printed with enough precision. EXPECT_PRED_FORMAT2(testing::IsSubstring, "1.234560", s.c_str()); EXPECT_PRED_FORMAT2(testing::IsSubstring, " 2.345669", s.c_str()); } // Tests streaming a double. TEST(MessageTest, StreamsDouble) { const std::string s = (Message() << 1260570880.4555497 << " " << 1260572265.1954534).GetString(); // Both numbers should be printed with enough precision. EXPECT_PRED_FORMAT2(testing::IsSubstring, "1260570880.45", s.c_str()); EXPECT_PRED_FORMAT2(testing::IsSubstring, " 1260572265.19", s.c_str()); } // Tests streaming a non-char pointer. TEST(MessageTest, StreamsPointer) { int n = 0; int* p = &n; EXPECT_NE("(null)", (Message() << p).GetString()); } // Tests streaming a NULL non-char pointer. TEST(MessageTest, StreamsNullPointer) { int* p = NULL; EXPECT_EQ("(null)", (Message() << p).GetString()); } // Tests streaming a C string. TEST(MessageTest, StreamsCString) { EXPECT_EQ("Foo", (Message() << "Foo").GetString()); } // Tests streaming a NULL C string. TEST(MessageTest, StreamsNullCString) { char* p = NULL; EXPECT_EQ("(null)", (Message() << p).GetString()); } // Tests streaming std::string. TEST(MessageTest, StreamsString) { const ::std::string str("Hello"); EXPECT_EQ("Hello", (Message() << str).GetString()); } // 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_EQ("Here's a NUL\\0 and some more string", (Message() << string_with_nul).GetString()); } // Tests streaming a NUL char. TEST(MessageTest, StreamsNULChar) { EXPECT_EQ("\\0", (Message() << '\0').GetString()); } // Tests streaming int. TEST(MessageTest, StreamsInt) { EXPECT_EQ("123", (Message() << 123).GetString()); } // Tests that basic IO manipulators (endl, ends, and flush) can be // streamed to Message. TEST(MessageTest, StreamsBasicIoManip) { EXPECT_EQ("Line 1.\nA NUL char \\0 in line 2.", (Message() << "Line 1." << std::endl << "A NUL char " << std::ends << std::flush << " in line 2.").GetString()); } // Tests Message::GetString() TEST(MessageTest, GetString) { Message msg; msg << 1 << " lamb"; EXPECT_EQ("1 lamb", msg.GetString()); } // Tests streaming a Message object to an ostream. TEST(MessageTest, StreamsToOStream) { Message msg("Hello"); ::std::stringstream ss; ss << msg; EXPECT_EQ("Hello", testing::internal::StringStreamToString(&ss)); } // Tests that a Message object doesn't take up too much stack space. TEST(MessageTest, DoesNotTakeUpMuchStackSpace) { EXPECT_LE(sizeof(Message), 16U); } } // namespace assimp-4.1.0/contrib/gtest/test/gtest-listener_test.cc0000644002537200234200000002315013213503245023341 0ustar zmoelnigiemusers// 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 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; // Used by tests to register their events. std::vector* g_events = NULL; namespace testing { namespace internal { class EventRecordingListener : public TestEventListener { public: explicit 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: std::string GetFullMethodName(const char* name) { return name_ + "." + name; } std::string name_; }; class EnvironmentInvocationCatcher : public Environment { protected: virtual void SetUp() { g_events->push_back("Environment::SetUp"); } virtual void TearDown() { g_events->push_back("Environment::TearDown"); } }; class ListenerTest : public Test { protected: static void SetUpTestCase() { g_events->push_back("ListenerTest::SetUpTestCase"); } static void TearDownTestCase() { g_events->push_back("ListenerTest::TearDownTestCase"); } virtual void SetUp() { g_events->push_back("ListenerTest::SetUp"); } virtual void TearDown() { g_events->push_back("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("ListenerTest::* Test Body"); SUCCEED(); // Triggers OnTestPartResult. } TEST_F(ListenerTest, DoesBar) { g_events->push_back("ListenerTest::* Test Body"); SUCCEED(); // Triggers OnTestPartResult. } } // namespace internal } // namespace testing using ::testing::internal::EnvironmentInvocationCatcher; using ::testing::internal::EventRecordingListener; void VerifyResults(const std::vector& data, const char* const* expected_data, size_t expected_data_size) { const size_t 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 size_t shorter_size = expected_data_size <= actual_size ? expected_data_size : actual_size; size_t 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 #%lu: %s\n", static_cast(i), data[i].c_str()); } } int main(int argc, char **argv) { std::vector 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; } assimp-4.1.0/contrib/gtest/test/gtest_xml_outfiles_test.py0000644002537200234200000001233413213503245024355 0ustar zmoelnigiemusers#!/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 = """ """ EXPECTED_XML_2 = """ """ 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() assimp-4.1.0/contrib/gtest/test/gtest_uninitialized_test_.cc0000644002537200234200000000360113213503245024604 0ustar zmoelnigiemusers// 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(); } assimp-4.1.0/contrib/gtest/test/gtest_no_test_unittest.cc0000644002537200234200000000461713213503245024160 0ustar zmoelnigiemusers// 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 three purposes: // // 1. It verifies that an ad-hoc assertion can be executed even if // no test is defined. // 2. It verifies that a failed ad-hoc assertion causes the test // program to fail. // 3. 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, 2); // The above EXPECT_EQ() should cause RUN_ALL_TESTS() to return non-zero. return RUN_ALL_TESTS() ? 0 : 1; } assimp-4.1.0/contrib/gtest/test/gtest_environment_test.cc0000644002537200234200000001471613213503245024152 0ustar zmoelnigiemusers// 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 #include #include "gtest/gtest.h" #define GTEST_IMPLEMENTATION_ 1 // Required for the next #include. #include "src/gtest-internal-inl.h" #undef GTEST_IMPLEMENTATION_ 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); testing::internal::posix::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; testing::internal::GetUnitTestImpl()->ClearAdHocTestResult(); 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; } assimp-4.1.0/contrib/gtest/test/gtest_help_test_.cc0000644002537200234200000000412313213503245022664 0ustar zmoelnigiemusers// 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 assimp-4.1.0/contrib/gtest/test/gtest_throw_on_failure_test.py0000644002537200234200000001320713213503245025211 0ustar zmoelnigiemusers#!/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() assimp-4.1.0/contrib/gtest/test/gtest-param-test_test.h0000644002537200234200000000444713213503245023443 0ustar zmoelnigiemusers// 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 { }; // Test fixture for testing instantiation of a test in multiple // translation units. class InstantiationInMultipleTranslaionUnitsTest : public ::testing::TestWithParam { }; #endif // GTEST_HAS_PARAM_TEST #endif // GTEST_TEST_GTEST_PARAM_TEST_TEST_H_ assimp-4.1.0/contrib/gtest/test/gtest_throw_on_failure_ex_test.cc0000644002537200234200000000656413213503245025652 0ustar zmoelnigiemusers// 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 #include #include #include // 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; } assimp-4.1.0/contrib/gtest/test/gtest-typed-test2_test.cc0000644002537200234200000000401313213503245023675 0ustar zmoelnigiemusers// 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 #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 >); #endif // GTEST_HAS_TYPED_TEST_P assimp-4.1.0/contrib/gtest/test/gtest-filepath_test.cc0000644002537200234200000005521113213503245023313 0ustar zmoelnigiemusers// 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 // NOLINT #elif GTEST_OS_WINDOWS # include // 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_EQ(GTEST_PATH_SEP_, cwd.string()); # endif } #endif // GTEST_OS_WINDOWS_MOBILE TEST(IsEmptyTest, ReturnsTrueForEmptyPath) { EXPECT_TRUE(FilePath("").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_EQ("", FilePath("").RemoveDirectoryName().string()); } // RemoveDirectoryName "afile" -> "afile" TEST(RemoveDirectoryNameTest, ButNoDirectory) { EXPECT_EQ("afile", FilePath("afile").RemoveDirectoryName().string()); } // RemoveDirectoryName "/afile" -> "afile" TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileName) { EXPECT_EQ("afile", FilePath(GTEST_PATH_SEP_ "afile").RemoveDirectoryName().string()); } // RemoveDirectoryName "adir/" -> "" TEST(RemoveDirectoryNameTest, WhereThereIsNoFileName) { EXPECT_EQ("", FilePath("adir" GTEST_PATH_SEP_).RemoveDirectoryName().string()); } // RemoveDirectoryName "adir/afile" -> "afile" TEST(RemoveDirectoryNameTest, ShouldGiveFileName) { EXPECT_EQ("afile", FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveDirectoryName().string()); } // RemoveDirectoryName "adir/subdir/afile" -> "afile" TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileName) { EXPECT_EQ("afile", FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile") .RemoveDirectoryName().string()); } #if GTEST_HAS_ALT_PATH_SEP_ // Tests that RemoveDirectoryName() works with the alternate separator // on Windows. // RemoveDirectoryName("/afile") -> "afile" TEST(RemoveDirectoryNameTest, RootFileShouldGiveFileNameForAlternateSeparator) { EXPECT_EQ("afile", FilePath("/afile").RemoveDirectoryName().string()); } // RemoveDirectoryName("adir/") -> "" TEST(RemoveDirectoryNameTest, WhereThereIsNoFileNameForAlternateSeparator) { EXPECT_EQ("", FilePath("adir/").RemoveDirectoryName().string()); } // RemoveDirectoryName("adir/afile") -> "afile" TEST(RemoveDirectoryNameTest, ShouldGiveFileNameForAlternateSeparator) { EXPECT_EQ("afile", FilePath("adir/afile").RemoveDirectoryName().string()); } // RemoveDirectoryName("adir/subdir/afile") -> "afile" TEST(RemoveDirectoryNameTest, ShouldAlsoGiveFileNameForAlternateSeparator) { EXPECT_EQ("afile", FilePath("adir/subdir/afile").RemoveDirectoryName().string()); } #endif // RemoveFileName "" -> "./" TEST(RemoveFileNameTest, EmptyName) { #if GTEST_OS_WINDOWS_MOBILE // On Windows CE, we use the root as the current directory. EXPECT_EQ(GTEST_PATH_SEP_, FilePath("").RemoveFileName().string()); #else EXPECT_EQ("." GTEST_PATH_SEP_, FilePath("").RemoveFileName().string()); #endif } // RemoveFileName "adir/" -> "adir/" TEST(RemoveFileNameTest, ButNoFile) { EXPECT_EQ("adir" GTEST_PATH_SEP_, FilePath("adir" GTEST_PATH_SEP_).RemoveFileName().string()); } // RemoveFileName "adir/afile" -> "adir/" TEST(RemoveFileNameTest, GivesDirName) { EXPECT_EQ("adir" GTEST_PATH_SEP_, FilePath("adir" GTEST_PATH_SEP_ "afile").RemoveFileName().string()); } // RemoveFileName "adir/subdir/afile" -> "adir/subdir/" TEST(RemoveFileNameTest, GivesDirAndSubDirName) { EXPECT_EQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_, FilePath("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_ "afile") .RemoveFileName().string()); } // RemoveFileName "/afile" -> "/" TEST(RemoveFileNameTest, GivesRootDir) { EXPECT_EQ(GTEST_PATH_SEP_, FilePath(GTEST_PATH_SEP_ "afile").RemoveFileName().string()); } #if GTEST_HAS_ALT_PATH_SEP_ // Tests that RemoveFileName() works with the alternate separator on // Windows. // RemoveFileName("adir/") -> "adir/" TEST(RemoveFileNameTest, ButNoFileForAlternateSeparator) { EXPECT_EQ("adir" GTEST_PATH_SEP_, FilePath("adir/").RemoveFileName().string()); } // RemoveFileName("adir/afile") -> "adir/" TEST(RemoveFileNameTest, GivesDirNameForAlternateSeparator) { EXPECT_EQ("adir" GTEST_PATH_SEP_, FilePath("adir/afile").RemoveFileName().string()); } // RemoveFileName("adir/subdir/afile") -> "adir/subdir/" TEST(RemoveFileNameTest, GivesDirAndSubDirNameForAlternateSeparator) { EXPECT_EQ("adir" GTEST_PATH_SEP_ "subdir" GTEST_PATH_SEP_, FilePath("adir/subdir/afile").RemoveFileName().string()); } // RemoveFileName("/afile") -> "\" TEST(RemoveFileNameTest, GivesRootDirForAlternateSeparator) { EXPECT_EQ(GTEST_PATH_SEP_, FilePath("/afile").RemoveFileName().string()); } #endif TEST(MakeFileNameTest, GenerateWhenNumberIsZero) { FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"), 0, "xml"); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string()); } TEST(MakeFileNameTest, GenerateFileNameNumberGtZero) { FilePath actual = FilePath::MakeFileName(FilePath("foo"), FilePath("bar"), 12, "xml"); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.string()); } TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberIsZero) { FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_), FilePath("bar"), 0, "xml"); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string()); } TEST(MakeFileNameTest, GenerateFileNameWithSlashNumberGtZero) { FilePath actual = FilePath::MakeFileName(FilePath("foo" GTEST_PATH_SEP_), FilePath("bar"), 12, "xml"); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar_12.xml", actual.string()); } TEST(MakeFileNameTest, GenerateWhenNumberIsZeroAndDirIsEmpty) { FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"), 0, "xml"); EXPECT_EQ("bar.xml", actual.string()); } TEST(MakeFileNameTest, GenerateWhenNumberIsNotZeroAndDirIsEmpty) { FilePath actual = FilePath::MakeFileName(FilePath(""), FilePath("bar"), 14, "xml"); EXPECT_EQ("bar_14.xml", actual.string()); } TEST(ConcatPathsTest, WorksWhenDirDoesNotEndWithPathSep) { FilePath actual = FilePath::ConcatPaths(FilePath("foo"), FilePath("bar.xml")); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string()); } TEST(ConcatPathsTest, WorksWhenPath1EndsWithPathSep) { FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_), FilePath("bar.xml")); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar.xml", actual.string()); } TEST(ConcatPathsTest, Path1BeingEmpty) { FilePath actual = FilePath::ConcatPaths(FilePath(""), FilePath("bar.xml")); EXPECT_EQ("bar.xml", actual.string()); } TEST(ConcatPathsTest, Path2BeingEmpty) { FilePath actual = FilePath::ConcatPaths(FilePath("foo"), FilePath("")); EXPECT_EQ("foo" GTEST_PATH_SEP_, actual.string()); } TEST(ConcatPathsTest, BothPathBeingEmpty) { FilePath actual = FilePath::ConcatPaths(FilePath(""), FilePath("")); EXPECT_EQ("", actual.string()); } TEST(ConcatPathsTest, Path1ContainsPathSep) { FilePath actual = FilePath::ConcatPaths(FilePath("foo" GTEST_PATH_SEP_ "bar"), FilePath("foobar.xml")); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "foobar.xml", actual.string()); } TEST(ConcatPathsTest, Path2ContainsPathSep) { FilePath actual = FilePath::ConcatPaths( FilePath("foo" GTEST_PATH_SEP_), FilePath("bar" GTEST_PATH_SEP_ "bar.xml")); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_ "bar.xml", actual.string()); } TEST(ConcatPathsTest, Path2EndsWithPathSep) { FilePath actual = FilePath::ConcatPaths(FilePath("foo"), FilePath("bar" GTEST_PATH_SEP_)); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_, actual.string()); } // RemoveTrailingPathSeparator "" -> "" TEST(RemoveTrailingPathSeparatorTest, EmptyString) { EXPECT_EQ("", FilePath("").RemoveTrailingPathSeparator().string()); } // RemoveTrailingPathSeparator "foo" -> "foo" TEST(RemoveTrailingPathSeparatorTest, FileNoSlashString) { EXPECT_EQ("foo", FilePath("foo").RemoveTrailingPathSeparator().string()); } // RemoveTrailingPathSeparator "foo/" -> "foo" TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveTrailingSeparator) { EXPECT_EQ("foo", FilePath("foo" GTEST_PATH_SEP_).RemoveTrailingPathSeparator().string()); #if GTEST_HAS_ALT_PATH_SEP_ EXPECT_EQ("foo", FilePath("foo/").RemoveTrailingPathSeparator().string()); #endif } // RemoveTrailingPathSeparator "foo/bar/" -> "foo/bar/" TEST(RemoveTrailingPathSeparatorTest, ShouldRemoveLastSeparator) { EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ "bar" GTEST_PATH_SEP_) .RemoveTrailingPathSeparator().string()); } // RemoveTrailingPathSeparator "foo/bar" -> "foo/bar" TEST(RemoveTrailingPathSeparatorTest, ShouldReturnUnmodified) { EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ "bar") .RemoveTrailingPathSeparator().string()); } TEST(DirectoryTest, RootDirectoryExists) { #if GTEST_OS_WINDOWS // We are on Windows. char current_drive[_MAX_PATH]; // NOLINT current_drive[0] = static_cast(_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 } // "foo/bar" == foo//bar" == "foo///bar" TEST(NormalizeTest, MultipleConsecutiveSepaparatorsInMidstring) { EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ "bar").string()); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string()); EXPECT_EQ("foo" GTEST_PATH_SEP_ "bar", FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string()); } // "/bar" == //bar" == "///bar" TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringStart) { EXPECT_EQ(GTEST_PATH_SEP_ "bar", FilePath(GTEST_PATH_SEP_ "bar").string()); EXPECT_EQ(GTEST_PATH_SEP_ "bar", FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string()); EXPECT_EQ(GTEST_PATH_SEP_ "bar", FilePath(GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_ "bar").string()); } // "foo/" == foo//" == "foo///" TEST(NormalizeTest, MultipleConsecutiveSepaparatorsAtStringEnd) { EXPECT_EQ("foo" GTEST_PATH_SEP_, FilePath("foo" GTEST_PATH_SEP_).string()); EXPECT_EQ("foo" GTEST_PATH_SEP_, FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_).string()); EXPECT_EQ("foo" GTEST_PATH_SEP_, FilePath("foo" GTEST_PATH_SEP_ GTEST_PATH_SEP_ GTEST_PATH_SEP_).string()); } #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_EQ("foo" GTEST_PATH_SEP_, FilePath("foo/").string()); EXPECT_EQ("foo" GTEST_PATH_SEP_, FilePath("foo" GTEST_PATH_SEP_ "/").string()); EXPECT_EQ("foo" GTEST_PATH_SEP_, FilePath("foo//" GTEST_PATH_SEP_).string()); } #endif TEST(AssignmentOperatorTest, DefaultAssignedToNonDefault) { FilePath default_path; FilePath non_default_path("path"); non_default_path = default_path; EXPECT_EQ("", non_default_path.string()); EXPECT_EQ("", default_path.string()); // RHS var is unchanged. } TEST(AssignmentOperatorTest, NonDefaultAssignedToDefault) { FilePath non_default_path("path"); FilePath default_path; default_path = non_default_path; EXPECT_EQ("path", default_path.string()); EXPECT_EQ("path", non_default_path.string()); // 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_EQ("const_path", non_default_path.string()); } class DirectoryCreationTest : public Test { protected: virtual void SetUp() { testdata_path_.Set(FilePath( TempDir() + GetCurrentExecutableName().string() + "_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()); } 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_.string(); EXPECT_TRUE(testdata_path_.CreateDirectoriesRecursively()); EXPECT_TRUE(testdata_path_.DirectoryExists()); } TEST_F(DirectoryCreationTest, CreateDirectoriesForAlreadyExistingPath) { EXPECT_FALSE(testdata_path_.DirectoryExists()) << testdata_path_.string(); 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_EQ(unique_file0_.string(), file_path.string()); 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_EQ(unique_file1_.string(), file_path2.string()); 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_EQ("", fp.string()); } TEST(FilePathTest, CharAndCopyConstructors) { const FilePath fp("spicy"); EXPECT_EQ("spicy", fp.string()); const FilePath fp_copy(fp); EXPECT_EQ("spicy", fp_copy.string()); } TEST(FilePathTest, StringConstructor) { const FilePath fp(std::string("cider")); EXPECT_EQ("cider", fp.string()); } TEST(FilePathTest, Set) { const FilePath apple("apple"); FilePath mac("mac"); mac.Set(apple); // Implement Set() since overloading operator= is forbidden. EXPECT_EQ("apple", mac.string()); EXPECT_EQ("apple", apple.string()); } TEST(FilePathTest, ToString) { const FilePath file("drink"); EXPECT_EQ("drink", file.string()); } TEST(FilePathTest, RemoveExtension) { EXPECT_EQ("app", FilePath("app.cc").RemoveExtension("cc").string()); EXPECT_EQ("app", FilePath("app.exe").RemoveExtension("exe").string()); EXPECT_EQ("APP", FilePath("APP.EXE").RemoveExtension("exe").string()); } TEST(FilePathTest, RemoveExtensionWhenThereIsNoExtension) { EXPECT_EQ("app", FilePath("app").RemoveExtension("exe").string()); } 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 assimp-4.1.0/contrib/gtest/test/gtest_list_tests_unittest_.cc0000644002537200234200000001114613213503245025034 0ustar zmoelnigiemusers// 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" // 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) { } // A group of value-parameterized tests. class MyType { public: explicit MyType(const std::string& a_value) : value_(a_value) {} const std::string& value() const { return value_; } private: std::string value_; }; // Teaches Google Test how to print a MyType. void PrintTo(const MyType& x, std::ostream* os) { *os << x.value(); } class ValueParamTest : public testing::TestWithParam { }; TEST_P(ValueParamTest, TestA) { } TEST_P(ValueParamTest, TestB) { } INSTANTIATE_TEST_CASE_P( MyInstantiation, ValueParamTest, testing::Values(MyType("one line"), MyType("two\nlines"), MyType("a very\nloooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong line"))); // NOLINT // A group of typed tests. // A deliberately long type name for testing the line-truncating // behavior when printing a type parameter. class VeryLoooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooogName { // NOLINT }; template class TypedTest : public testing::Test { }; template class MyArray { }; typedef testing::Types > MyTypes; TYPED_TEST_CASE(TypedTest, MyTypes); TYPED_TEST(TypedTest, TestA) { } TYPED_TEST(TypedTest, TestB) { } // A group of type-parameterized tests. template class TypeParamTest : public testing::Test { }; TYPED_TEST_CASE_P(TypeParamTest); TYPED_TEST_P(TypeParamTest, TestA) { } TYPED_TEST_P(TypeParamTest, TestB) { } REGISTER_TYPED_TEST_CASE_P(TypeParamTest, TestA, TestB); INSTANTIATE_TYPED_TEST_CASE_P(My, TypeParamTest, MyTypes); int main(int argc, char **argv) { ::testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } assimp-4.1.0/contrib/gtest/test/gtest-printers_test.cc0000644002537200234200000014600513213503245023367 0ustar zmoelnigiemusers// 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) // Google Test - The Google C++ Testing Framework // // This file tests the universal value printer. #include "gtest/gtest-printers.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "gtest/gtest.h" // hash_map and hash_set are available under Visual C++, or on Linux. #if GTEST_HAS_HASH_MAP_ # include // NOLINT #endif // GTEST_HAS_HASH_MAP_ #if GTEST_HAS_HASH_SET_ # include // NOLINT #endif // GTEST_HAS_HASH_SET_ #if GTEST_HAS_STD_FORWARD_LIST_ # include // NOLINT #endif // GTEST_HAS_STD_FORWARD_LIST_ // Some user-defined types for testing the universal value printer. // An anonymous enum type. enum AnonymousEnum { kAE1 = -1, kAE2 = 1 }; // An enum without a user-defined printer. enum EnumWithoutPrinter { kEWP1 = -2, kEWP2 = 42 }; // An enum with a << operator. enum EnumWithStreaming { kEWS1 = 10 }; std::ostream& operator<<(std::ostream& os, EnumWithStreaming e) { return os << (e == kEWS1 ? "kEWS1" : "invalid"); } // An enum with a PrintTo() function. enum EnumWithPrintTo { kEWPT1 = 1 }; void PrintTo(EnumWithPrintTo e, std::ostream* os) { *os << (e == kEWPT1 ? "kEWPT1" : "invalid"); } // A class implicitly convertible to BiggestInt. class BiggestIntConvertible { public: operator ::testing::internal::BiggestInt() const { return 42; } }; // A user-defined unprintable class template in the global namespace. template class UnprintableTemplateInGlobal { public: UnprintableTemplateInGlobal() : value_() {} private: T value_; }; // A user-defined streamable type in the global namespace. class StreamableInGlobal { public: virtual ~StreamableInGlobal() {} }; inline void operator<<(::std::ostream& os, const StreamableInGlobal& /* x */) { os << "StreamableInGlobal"; } void operator<<(::std::ostream& os, const StreamableInGlobal* /* x */) { os << "StreamableInGlobal*"; } namespace foo { // A user-defined unprintable type in a user namespace. class UnprintableInFoo { public: UnprintableInFoo() : z_(0) { memcpy(xy_, "\xEF\x12\x0\x0\x34\xAB\x0\x0", 8); } double z() const { return z_; } private: char xy_[8]; double z_; }; // A user-defined printable type in a user-chosen namespace. struct PrintableViaPrintTo { PrintableViaPrintTo() : value() {} int value; }; void PrintTo(const PrintableViaPrintTo& x, ::std::ostream* os) { *os << "PrintableViaPrintTo: " << x.value; } // A type with a user-defined << for printing its pointer. struct PointerPrintable { }; ::std::ostream& operator<<(::std::ostream& os, const PointerPrintable* /* x */) { return os << "PointerPrintable*"; } // A user-defined printable class template in a user-chosen namespace. template class PrintableViaPrintToTemplate { public: explicit PrintableViaPrintToTemplate(const T& a_value) : value_(a_value) {} const T& value() const { return value_; } private: T value_; }; template void PrintTo(const PrintableViaPrintToTemplate& x, ::std::ostream* os) { *os << "PrintableViaPrintToTemplate: " << x.value(); } // A user-defined streamable class template in a user namespace. template class StreamableTemplateInFoo { public: StreamableTemplateInFoo() : value_() {} const T& value() const { return value_; } private: T value_; }; template inline ::std::ostream& operator<<(::std::ostream& os, const StreamableTemplateInFoo& x) { return os << "StreamableTemplateInFoo: " << x.value(); } } // namespace foo namespace testing { namespace gtest_printers_test { using ::std::deque; using ::std::list; using ::std::make_pair; using ::std::map; using ::std::multimap; using ::std::multiset; using ::std::pair; using ::std::set; using ::std::vector; using ::testing::PrintToString; using ::testing::internal::FormatForComparisonFailureMessage; using ::testing::internal::ImplicitCast_; using ::testing::internal::NativeArray; using ::testing::internal::RE; using ::testing::internal::RelationToSourceReference; using ::testing::internal::Strings; using ::testing::internal::UniversalPrint; using ::testing::internal::UniversalPrinter; using ::testing::internal::UniversalTersePrint; using ::testing::internal::UniversalTersePrintTupleFieldsToStrings; using ::testing::internal::string; // The hash_* classes are not part of the C++ standard. STLport // defines them in namespace std. MSVC defines them in ::stdext. GCC // defines them in ::. #ifdef _STLP_HASH_MAP // We got from STLport. using ::std::hash_map; using ::std::hash_set; using ::std::hash_multimap; using ::std::hash_multiset; #elif _MSC_VER using ::stdext::hash_map; using ::stdext::hash_set; using ::stdext::hash_multimap; using ::stdext::hash_multiset; #endif // Prints a value to a string using the universal value printer. This // is a helper for testing UniversalPrinter::Print() for various types. template string Print(const T& value) { ::std::stringstream ss; UniversalPrinter::Print(value, &ss); return ss.str(); } // Prints a value passed by reference to a string, using the universal // value printer. This is a helper for testing // UniversalPrinter::Print() for various types. template string PrintByRef(const T& value) { ::std::stringstream ss; UniversalPrinter::Print(value, &ss); return ss.str(); } // Tests printing various enum types. TEST(PrintEnumTest, AnonymousEnum) { EXPECT_EQ("-1", Print(kAE1)); EXPECT_EQ("1", Print(kAE2)); } TEST(PrintEnumTest, EnumWithoutPrinter) { EXPECT_EQ("-2", Print(kEWP1)); EXPECT_EQ("42", Print(kEWP2)); } TEST(PrintEnumTest, EnumWithStreaming) { EXPECT_EQ("kEWS1", Print(kEWS1)); EXPECT_EQ("invalid", Print(static_cast(0))); } TEST(PrintEnumTest, EnumWithPrintTo) { EXPECT_EQ("kEWPT1", Print(kEWPT1)); EXPECT_EQ("invalid", Print(static_cast(0))); } // Tests printing a class implicitly convertible to BiggestInt. TEST(PrintClassTest, BiggestIntConvertible) { EXPECT_EQ("42", Print(BiggestIntConvertible())); } // Tests printing various char types. // char. TEST(PrintCharTest, PlainChar) { EXPECT_EQ("'\\0'", Print('\0')); EXPECT_EQ("'\\'' (39, 0x27)", Print('\'')); EXPECT_EQ("'\"' (34, 0x22)", Print('"')); EXPECT_EQ("'?' (63, 0x3F)", Print('?')); EXPECT_EQ("'\\\\' (92, 0x5C)", Print('\\')); EXPECT_EQ("'\\a' (7)", Print('\a')); EXPECT_EQ("'\\b' (8)", Print('\b')); EXPECT_EQ("'\\f' (12, 0xC)", Print('\f')); EXPECT_EQ("'\\n' (10, 0xA)", Print('\n')); EXPECT_EQ("'\\r' (13, 0xD)", Print('\r')); EXPECT_EQ("'\\t' (9)", Print('\t')); EXPECT_EQ("'\\v' (11, 0xB)", Print('\v')); EXPECT_EQ("'\\x7F' (127)", Print('\x7F')); EXPECT_EQ("'\\xFF' (255)", Print('\xFF')); EXPECT_EQ("' ' (32, 0x20)", Print(' ')); EXPECT_EQ("'a' (97, 0x61)", Print('a')); } // signed char. TEST(PrintCharTest, SignedChar) { EXPECT_EQ("'\\0'", Print(static_cast('\0'))); EXPECT_EQ("'\\xCE' (-50)", Print(static_cast(-50))); } // unsigned char. TEST(PrintCharTest, UnsignedChar) { EXPECT_EQ("'\\0'", Print(static_cast('\0'))); EXPECT_EQ("'b' (98, 0x62)", Print(static_cast('b'))); } // Tests printing other simple, built-in types. // bool. TEST(PrintBuiltInTypeTest, Bool) { EXPECT_EQ("false", Print(false)); EXPECT_EQ("true", Print(true)); } // wchar_t. TEST(PrintBuiltInTypeTest, Wchar_t) { EXPECT_EQ("L'\\0'", Print(L'\0')); EXPECT_EQ("L'\\'' (39, 0x27)", Print(L'\'')); EXPECT_EQ("L'\"' (34, 0x22)", Print(L'"')); EXPECT_EQ("L'?' (63, 0x3F)", Print(L'?')); EXPECT_EQ("L'\\\\' (92, 0x5C)", Print(L'\\')); EXPECT_EQ("L'\\a' (7)", Print(L'\a')); EXPECT_EQ("L'\\b' (8)", Print(L'\b')); EXPECT_EQ("L'\\f' (12, 0xC)", Print(L'\f')); EXPECT_EQ("L'\\n' (10, 0xA)", Print(L'\n')); EXPECT_EQ("L'\\r' (13, 0xD)", Print(L'\r')); EXPECT_EQ("L'\\t' (9)", Print(L'\t')); EXPECT_EQ("L'\\v' (11, 0xB)", Print(L'\v')); EXPECT_EQ("L'\\x7F' (127)", Print(L'\x7F')); EXPECT_EQ("L'\\xFF' (255)", Print(L'\xFF')); EXPECT_EQ("L' ' (32, 0x20)", Print(L' ')); EXPECT_EQ("L'a' (97, 0x61)", Print(L'a')); EXPECT_EQ("L'\\x576' (1398)", Print(static_cast(0x576))); EXPECT_EQ("L'\\xC74D' (51021)", Print(static_cast(0xC74D))); } // Test that Int64 provides more storage than wchar_t. TEST(PrintTypeSizeTest, Wchar_t) { EXPECT_LT(sizeof(wchar_t), sizeof(testing::internal::Int64)); } // Various integer types. TEST(PrintBuiltInTypeTest, Integer) { EXPECT_EQ("'\\xFF' (255)", Print(static_cast(255))); // uint8 EXPECT_EQ("'\\x80' (-128)", Print(static_cast(-128))); // int8 EXPECT_EQ("65535", Print(USHRT_MAX)); // uint16 EXPECT_EQ("-32768", Print(SHRT_MIN)); // int16 EXPECT_EQ("4294967295", Print(UINT_MAX)); // uint32 EXPECT_EQ("-2147483648", Print(INT_MIN)); // int32 EXPECT_EQ("18446744073709551615", Print(static_cast(-1))); // uint64 EXPECT_EQ("-9223372036854775808", Print(static_cast(1) << 63)); // int64 } // Size types. TEST(PrintBuiltInTypeTest, Size_t) { EXPECT_EQ("1", Print(sizeof('a'))); // size_t. #if !GTEST_OS_WINDOWS // Windows has no ssize_t type. EXPECT_EQ("-2", Print(static_cast(-2))); // ssize_t. #endif // !GTEST_OS_WINDOWS } // Floating-points. TEST(PrintBuiltInTypeTest, FloatingPoints) { EXPECT_EQ("1.5", Print(1.5f)); // float EXPECT_EQ("-2.5", Print(-2.5)); // double } // Since ::std::stringstream::operator<<(const void *) formats the pointer // output differently with different compilers, we have to create the expected // output first and use it as our expectation. static string PrintPointer(const void *p) { ::std::stringstream expected_result_stream; expected_result_stream << p; return expected_result_stream.str(); } // Tests printing C strings. // const char*. TEST(PrintCStringTest, Const) { const char* p = "World"; EXPECT_EQ(PrintPointer(p) + " pointing to \"World\"", Print(p)); } // char*. TEST(PrintCStringTest, NonConst) { char p[] = "Hi"; EXPECT_EQ(PrintPointer(p) + " pointing to \"Hi\"", Print(static_cast(p))); } // NULL C string. TEST(PrintCStringTest, Null) { const char* p = NULL; EXPECT_EQ("NULL", Print(p)); } // Tests that C strings are escaped properly. TEST(PrintCStringTest, EscapesProperly) { const char* p = "'\"?\\\a\b\f\n\r\t\v\x7F\xFF a"; EXPECT_EQ(PrintPointer(p) + " pointing to \"'\\\"?\\\\\\a\\b\\f" "\\n\\r\\t\\v\\x7F\\xFF a\"", Print(p)); } // MSVC compiler can be configured to define whar_t as a typedef // of unsigned short. Defining an overload for const wchar_t* in that case // would cause pointers to unsigned shorts be printed as wide strings, // possibly accessing more memory than intended and causing invalid // memory accesses. MSVC defines _NATIVE_WCHAR_T_DEFINED symbol when // wchar_t is implemented as a native type. #if !defined(_MSC_VER) || defined(_NATIVE_WCHAR_T_DEFINED) // const wchar_t*. TEST(PrintWideCStringTest, Const) { const wchar_t* p = L"World"; EXPECT_EQ(PrintPointer(p) + " pointing to L\"World\"", Print(p)); } // wchar_t*. TEST(PrintWideCStringTest, NonConst) { wchar_t p[] = L"Hi"; EXPECT_EQ(PrintPointer(p) + " pointing to L\"Hi\"", Print(static_cast(p))); } // NULL wide C string. TEST(PrintWideCStringTest, Null) { const wchar_t* p = NULL; EXPECT_EQ("NULL", Print(p)); } // Tests that wide C strings are escaped properly. TEST(PrintWideCStringTest, EscapesProperly) { const wchar_t s[] = {'\'', '"', '?', '\\', '\a', '\b', '\f', '\n', '\r', '\t', '\v', 0xD3, 0x576, 0x8D3, 0xC74D, ' ', 'a', '\0'}; EXPECT_EQ(PrintPointer(s) + " pointing to L\"'\\\"?\\\\\\a\\b\\f" "\\n\\r\\t\\v\\xD3\\x576\\x8D3\\xC74D a\"", Print(static_cast(s))); } #endif // native wchar_t // Tests printing pointers to other char types. // signed char*. TEST(PrintCharPointerTest, SignedChar) { signed char* p = reinterpret_cast(0x1234); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // const signed char*. TEST(PrintCharPointerTest, ConstSignedChar) { signed char* p = reinterpret_cast(0x1234); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // unsigned char*. TEST(PrintCharPointerTest, UnsignedChar) { unsigned char* p = reinterpret_cast(0x1234); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // const unsigned char*. TEST(PrintCharPointerTest, ConstUnsignedChar) { const unsigned char* p = reinterpret_cast(0x1234); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // Tests printing pointers to simple, built-in types. // bool*. TEST(PrintPointerToBuiltInTypeTest, Bool) { bool* p = reinterpret_cast(0xABCD); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // void*. TEST(PrintPointerToBuiltInTypeTest, Void) { void* p = reinterpret_cast(0xABCD); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // const void*. TEST(PrintPointerToBuiltInTypeTest, ConstVoid) { const void* p = reinterpret_cast(0xABCD); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // Tests printing pointers to pointers. TEST(PrintPointerToPointerTest, IntPointerPointer) { int** p = reinterpret_cast(0xABCD); EXPECT_EQ(PrintPointer(p), Print(p)); p = NULL; EXPECT_EQ("NULL", Print(p)); } // Tests printing (non-member) function pointers. void MyFunction(int /* n */) {} TEST(PrintPointerTest, NonMemberFunctionPointer) { // We cannot directly cast &MyFunction to const void* because the // standard disallows casting between pointers to functions and // pointers to objects, and some compilers (e.g. GCC 3.4) enforce // this limitation. EXPECT_EQ( PrintPointer(reinterpret_cast( reinterpret_cast(&MyFunction))), Print(&MyFunction)); int (*p)(bool) = NULL; // NOLINT EXPECT_EQ("NULL", Print(p)); } // An assertion predicate determining whether a one string is a prefix for // another. template AssertionResult HasPrefix(const StringType& str, const StringType& prefix) { if (str.find(prefix, 0) == 0) return AssertionSuccess(); const bool is_wide_string = sizeof(prefix[0]) > 1; const char* const begin_string_quote = is_wide_string ? "L\"" : "\""; return AssertionFailure() << begin_string_quote << prefix << "\" is not a prefix of " << begin_string_quote << str << "\"\n"; } // Tests printing member variable pointers. Although they are called // pointers, they don't point to a location in the address space. // Their representation is implementation-defined. Thus they will be // printed as raw bytes. struct Foo { public: virtual ~Foo() {} int MyMethod(char x) { return x + 1; } virtual char MyVirtualMethod(int /* n */) { return 'a'; } int value; }; TEST(PrintPointerTest, MemberVariablePointer) { EXPECT_TRUE(HasPrefix(Print(&Foo::value), Print(sizeof(&Foo::value)) + "-byte object ")); int (Foo::*p) = NULL; // NOLINT EXPECT_TRUE(HasPrefix(Print(p), Print(sizeof(p)) + "-byte object ")); } // Tests printing member function pointers. Although they are called // pointers, they don't point to a location in the address space. // Their representation is implementation-defined. Thus they will be // printed as raw bytes. TEST(PrintPointerTest, MemberFunctionPointer) { EXPECT_TRUE(HasPrefix(Print(&Foo::MyMethod), Print(sizeof(&Foo::MyMethod)) + "-byte object ")); EXPECT_TRUE( HasPrefix(Print(&Foo::MyVirtualMethod), Print(sizeof((&Foo::MyVirtualMethod))) + "-byte object ")); int (Foo::*p)(char) = NULL; // NOLINT EXPECT_TRUE(HasPrefix(Print(p), Print(sizeof(p)) + "-byte object ")); } // Tests printing C arrays. // The difference between this and Print() is that it ensures that the // argument is a reference to an array. template string PrintArrayHelper(T (&a)[N]) { return Print(a); } // One-dimensional array. TEST(PrintArrayTest, OneDimensionalArray) { int a[5] = { 1, 2, 3, 4, 5 }; EXPECT_EQ("{ 1, 2, 3, 4, 5 }", PrintArrayHelper(a)); } // Two-dimensional array. TEST(PrintArrayTest, TwoDimensionalArray) { int a[2][5] = { { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }; EXPECT_EQ("{ { 1, 2, 3, 4, 5 }, { 6, 7, 8, 9, 0 } }", PrintArrayHelper(a)); } // Array of const elements. TEST(PrintArrayTest, ConstArray) { const bool a[1] = { false }; EXPECT_EQ("{ false }", PrintArrayHelper(a)); } // char array without terminating NUL. TEST(PrintArrayTest, CharArrayWithNoTerminatingNul) { // Array a contains '\0' in the middle and doesn't end with '\0'. char a[] = { 'H', '\0', 'i' }; EXPECT_EQ("\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a)); } // const char array with terminating NUL. TEST(PrintArrayTest, ConstCharArrayWithTerminatingNul) { const char a[] = "\0Hi"; EXPECT_EQ("\"\\0Hi\"", PrintArrayHelper(a)); } // const wchar_t array without terminating NUL. TEST(PrintArrayTest, WCharArrayWithNoTerminatingNul) { // Array a contains '\0' in the middle and doesn't end with '\0'. const wchar_t a[] = { L'H', L'\0', L'i' }; EXPECT_EQ("L\"H\\0i\" (no terminating NUL)", PrintArrayHelper(a)); } // wchar_t array with terminating NUL. TEST(PrintArrayTest, WConstCharArrayWithTerminatingNul) { const wchar_t a[] = L"\0Hi"; EXPECT_EQ("L\"\\0Hi\"", PrintArrayHelper(a)); } // Array of objects. TEST(PrintArrayTest, ObjectArray) { string a[3] = { "Hi", "Hello", "Ni hao" }; EXPECT_EQ("{ \"Hi\", \"Hello\", \"Ni hao\" }", PrintArrayHelper(a)); } // Array with many elements. TEST(PrintArrayTest, BigArray) { int a[100] = { 1, 2, 3 }; EXPECT_EQ("{ 1, 2, 3, 0, 0, 0, 0, 0, ..., 0, 0, 0, 0, 0, 0, 0, 0 }", PrintArrayHelper(a)); } // Tests printing ::string and ::std::string. #if GTEST_HAS_GLOBAL_STRING // ::string. TEST(PrintStringTest, StringInGlobalNamespace) { const char s[] = "'\"?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; const ::string str(s, sizeof(s)); EXPECT_EQ("\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", Print(str)); } #endif // GTEST_HAS_GLOBAL_STRING // ::std::string. TEST(PrintStringTest, StringInStdNamespace) { const char s[] = "'\"?\\\a\b\f\n\0\r\t\v\x7F\xFF a"; const ::std::string str(s, sizeof(s)); EXPECT_EQ("\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v\\x7F\\xFF a\\0\"", Print(str)); } TEST(PrintStringTest, StringAmbiguousHex) { // "\x6BANANA" is ambiguous, it can be interpreted as starting with either of: // '\x6', '\x6B', or '\x6BA'. // a hex escaping sequence following by a decimal digit EXPECT_EQ("\"0\\x12\" \"3\"", Print(::std::string("0\x12" "3"))); // a hex escaping sequence following by a hex digit (lower-case) EXPECT_EQ("\"mm\\x6\" \"bananas\"", Print(::std::string("mm\x6" "bananas"))); // a hex escaping sequence following by a hex digit (upper-case) EXPECT_EQ("\"NOM\\x6\" \"BANANA\"", Print(::std::string("NOM\x6" "BANANA"))); // a hex escaping sequence following by a non-xdigit EXPECT_EQ("\"!\\x5-!\"", Print(::std::string("!\x5-!"))); } // Tests printing ::wstring and ::std::wstring. #if GTEST_HAS_GLOBAL_WSTRING // ::wstring. TEST(PrintWideStringTest, StringInGlobalNamespace) { const wchar_t s[] = L"'\"?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; const ::wstring str(s, sizeof(s)/sizeof(wchar_t)); EXPECT_EQ("L\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" "\\xD3\\x576\\x8D3\\xC74D a\\0\"", Print(str)); } #endif // GTEST_HAS_GLOBAL_WSTRING #if GTEST_HAS_STD_WSTRING // ::std::wstring. TEST(PrintWideStringTest, StringInStdNamespace) { const wchar_t s[] = L"'\"?\\\a\b\f\n\0\r\t\v\xD3\x576\x8D3\xC74D a"; const ::std::wstring str(s, sizeof(s)/sizeof(wchar_t)); EXPECT_EQ("L\"'\\\"?\\\\\\a\\b\\f\\n\\0\\r\\t\\v" "\\xD3\\x576\\x8D3\\xC74D a\\0\"", Print(str)); } TEST(PrintWideStringTest, StringAmbiguousHex) { // same for wide strings. EXPECT_EQ("L\"0\\x12\" L\"3\"", Print(::std::wstring(L"0\x12" L"3"))); EXPECT_EQ("L\"mm\\x6\" L\"bananas\"", Print(::std::wstring(L"mm\x6" L"bananas"))); EXPECT_EQ("L\"NOM\\x6\" L\"BANANA\"", Print(::std::wstring(L"NOM\x6" L"BANANA"))); EXPECT_EQ("L\"!\\x5-!\"", Print(::std::wstring(L"!\x5-!"))); } #endif // GTEST_HAS_STD_WSTRING // Tests printing types that support generic streaming (i.e. streaming // to std::basic_ostream for any valid Char and // CharTraits types). // Tests printing a non-template type that supports generic streaming. class AllowsGenericStreaming {}; template std::basic_ostream& operator<<( std::basic_ostream& os, const AllowsGenericStreaming& /* a */) { return os << "AllowsGenericStreaming"; } TEST(PrintTypeWithGenericStreamingTest, NonTemplateType) { AllowsGenericStreaming a; EXPECT_EQ("AllowsGenericStreaming", Print(a)); } // Tests printing a template type that supports generic streaming. template class AllowsGenericStreamingTemplate {}; template std::basic_ostream& operator<<( std::basic_ostream& os, const AllowsGenericStreamingTemplate& /* a */) { return os << "AllowsGenericStreamingTemplate"; } TEST(PrintTypeWithGenericStreamingTest, TemplateType) { AllowsGenericStreamingTemplate a; EXPECT_EQ("AllowsGenericStreamingTemplate", Print(a)); } // Tests printing a type that supports generic streaming and can be // implicitly converted to another printable type. template class AllowsGenericStreamingAndImplicitConversionTemplate { public: operator bool() const { return false; } }; template std::basic_ostream& operator<<( std::basic_ostream& os, const AllowsGenericStreamingAndImplicitConversionTemplate& /* a */) { return os << "AllowsGenericStreamingAndImplicitConversionTemplate"; } TEST(PrintTypeWithGenericStreamingTest, TypeImplicitlyConvertible) { AllowsGenericStreamingAndImplicitConversionTemplate a; EXPECT_EQ("AllowsGenericStreamingAndImplicitConversionTemplate", Print(a)); } #if GTEST_HAS_STRING_PIECE_ // Tests printing StringPiece. TEST(PrintStringPieceTest, SimpleStringPiece) { const StringPiece sp = "Hello"; EXPECT_EQ("\"Hello\"", Print(sp)); } TEST(PrintStringPieceTest, UnprintableCharacters) { const char str[] = "NUL (\0) and \r\t"; const StringPiece sp(str, sizeof(str) - 1); EXPECT_EQ("\"NUL (\\0) and \\r\\t\"", Print(sp)); } #endif // GTEST_HAS_STRING_PIECE_ // Tests printing STL containers. TEST(PrintStlContainerTest, EmptyDeque) { deque empty; EXPECT_EQ("{}", Print(empty)); } TEST(PrintStlContainerTest, NonEmptyDeque) { deque non_empty; non_empty.push_back(1); non_empty.push_back(3); EXPECT_EQ("{ 1, 3 }", Print(non_empty)); } #if GTEST_HAS_HASH_MAP_ TEST(PrintStlContainerTest, OneElementHashMap) { hash_map map1; map1[1] = 'a'; EXPECT_EQ("{ (1, 'a' (97, 0x61)) }", Print(map1)); } TEST(PrintStlContainerTest, HashMultiMap) { hash_multimap map1; map1.insert(make_pair(5, true)); map1.insert(make_pair(5, false)); // Elements of hash_multimap can be printed in any order. const string result = Print(map1); EXPECT_TRUE(result == "{ (5, true), (5, false) }" || result == "{ (5, false), (5, true) }") << " where Print(map1) returns \"" << result << "\"."; } #endif // GTEST_HAS_HASH_MAP_ #if GTEST_HAS_HASH_SET_ TEST(PrintStlContainerTest, HashSet) { hash_set set1; set1.insert("hello"); EXPECT_EQ("{ \"hello\" }", Print(set1)); } TEST(PrintStlContainerTest, HashMultiSet) { const int kSize = 5; int a[kSize] = { 1, 1, 2, 5, 1 }; hash_multiset set1(a, a + kSize); // Elements of hash_multiset can be printed in any order. const string result = Print(set1); const string expected_pattern = "{ d, d, d, d, d }"; // d means a digit. // Verifies the result matches the expected pattern; also extracts // the numbers in the result. ASSERT_EQ(expected_pattern.length(), result.length()); std::vector numbers; for (size_t i = 0; i != result.length(); i++) { if (expected_pattern[i] == 'd') { ASSERT_NE(isdigit(static_cast(result[i])), 0); numbers.push_back(result[i] - '0'); } else { EXPECT_EQ(expected_pattern[i], result[i]) << " where result is " << result; } } // Makes sure the result contains the right numbers. std::sort(numbers.begin(), numbers.end()); std::sort(a, a + kSize); EXPECT_TRUE(std::equal(a, a + kSize, numbers.begin())); } #endif // GTEST_HAS_HASH_SET_ TEST(PrintStlContainerTest, List) { const string a[] = { "hello", "world" }; const list strings(a, a + 2); EXPECT_EQ("{ \"hello\", \"world\" }", Print(strings)); } TEST(PrintStlContainerTest, Map) { map map1; map1[1] = true; map1[5] = false; map1[3] = true; EXPECT_EQ("{ (1, true), (3, true), (5, false) }", Print(map1)); } TEST(PrintStlContainerTest, MultiMap) { multimap map1; // The make_pair template function would deduce the type as // pair here, and since the key part in a multimap has to // be constant, without a templated ctor in the pair class (as in // libCstd on Solaris), make_pair call would fail to compile as no // implicit conversion is found. Thus explicit typename is used // here instead. map1.insert(pair(true, 0)); map1.insert(pair(true, 1)); map1.insert(pair(false, 2)); EXPECT_EQ("{ (false, 2), (true, 0), (true, 1) }", Print(map1)); } TEST(PrintStlContainerTest, Set) { const unsigned int a[] = { 3, 0, 5 }; set set1(a, a + 3); EXPECT_EQ("{ 0, 3, 5 }", Print(set1)); } TEST(PrintStlContainerTest, MultiSet) { const int a[] = { 1, 1, 2, 5, 1 }; multiset set1(a, a + 5); EXPECT_EQ("{ 1, 1, 1, 2, 5 }", Print(set1)); } #if GTEST_HAS_STD_FORWARD_LIST_ // is available on Linux in the google3 mode, but not on // Windows or Mac OS X. TEST(PrintStlContainerTest, SinglyLinkedList) { int a[] = { 9, 2, 8 }; const std::forward_list ints(a, a + 3); EXPECT_EQ("{ 9, 2, 8 }", Print(ints)); } #endif // GTEST_HAS_STD_FORWARD_LIST_ TEST(PrintStlContainerTest, Pair) { pair p(true, 5); EXPECT_EQ("(true, 5)", Print(p)); } TEST(PrintStlContainerTest, Vector) { vector v; v.push_back(1); v.push_back(2); EXPECT_EQ("{ 1, 2 }", Print(v)); } TEST(PrintStlContainerTest, LongSequence) { const int a[100] = { 1, 2, 3 }; const vector v(a, a + 100); EXPECT_EQ("{ 1, 2, 3, 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, ... }", Print(v)); } TEST(PrintStlContainerTest, NestedContainer) { const int a1[] = { 1, 2 }; const int a2[] = { 3, 4, 5 }; const list l1(a1, a1 + 2); const list l2(a2, a2 + 3); vector > v; v.push_back(l1); v.push_back(l2); EXPECT_EQ("{ { 1, 2 }, { 3, 4, 5 } }", Print(v)); } TEST(PrintStlContainerTest, OneDimensionalNativeArray) { const int a[3] = { 1, 2, 3 }; NativeArray b(a, 3, RelationToSourceReference()); EXPECT_EQ("{ 1, 2, 3 }", Print(b)); } TEST(PrintStlContainerTest, TwoDimensionalNativeArray) { const int a[2][3] = { { 1, 2, 3 }, { 4, 5, 6 } }; NativeArray b(a, 2, RelationToSourceReference()); EXPECT_EQ("{ { 1, 2, 3 }, { 4, 5, 6 } }", Print(b)); } // Tests that a class named iterator isn't treated as a container. struct iterator { char x; }; TEST(PrintStlContainerTest, Iterator) { iterator it = {}; EXPECT_EQ("1-byte object <00>", Print(it)); } // Tests that a class named const_iterator isn't treated as a container. struct const_iterator { char x; }; TEST(PrintStlContainerTest, ConstIterator) { const_iterator it = {}; EXPECT_EQ("1-byte object <00>", Print(it)); } #if GTEST_HAS_TR1_TUPLE // Tests printing ::std::tr1::tuples. // Tuples of various arities. TEST(PrintTr1TupleTest, VariousSizes) { ::std::tr1::tuple<> t0; EXPECT_EQ("()", Print(t0)); ::std::tr1::tuple t1(5); EXPECT_EQ("(5)", Print(t1)); ::std::tr1::tuple t2('a', true); EXPECT_EQ("('a' (97, 0x61), true)", Print(t2)); ::std::tr1::tuple t3(false, 2, 3); EXPECT_EQ("(false, 2, 3)", Print(t3)); ::std::tr1::tuple t4(false, 2, 3, 4); EXPECT_EQ("(false, 2, 3, 4)", Print(t4)); ::std::tr1::tuple t5(false, 2, 3, 4, true); EXPECT_EQ("(false, 2, 3, 4, true)", Print(t5)); ::std::tr1::tuple t6(false, 2, 3, 4, true, 6); EXPECT_EQ("(false, 2, 3, 4, true, 6)", Print(t6)); ::std::tr1::tuple t7( false, 2, 3, 4, true, 6, 7); EXPECT_EQ("(false, 2, 3, 4, true, 6, 7)", Print(t7)); ::std::tr1::tuple t8( false, 2, 3, 4, true, 6, 7, true); EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true)", Print(t8)); ::std::tr1::tuple t9( false, 2, 3, 4, true, 6, 7, true, 9); EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true, 9)", Print(t9)); const char* const str = "8"; // VC++ 2010's implementation of tuple of C++0x is deficient, requiring // an explicit type cast of NULL to be used. ::std::tr1::tuple t10(false, 'a', 3, 4, 5, 1.5F, -2.5, str, ImplicitCast_(NULL), "10"); EXPECT_EQ("(false, 'a' (97, 0x61), 3, 4, 5, 1.5, -2.5, " + PrintPointer(str) + " pointing to \"8\", NULL, \"10\")", Print(t10)); } // Nested tuples. TEST(PrintTr1TupleTest, NestedTuple) { ::std::tr1::tuple< ::std::tr1::tuple, char> nested( ::std::tr1::make_tuple(5, true), 'a'); EXPECT_EQ("((5, true), 'a' (97, 0x61))", Print(nested)); } #endif // GTEST_HAS_TR1_TUPLE #if GTEST_HAS_STD_TUPLE_ // Tests printing ::std::tuples. // Tuples of various arities. TEST(PrintStdTupleTest, VariousSizes) { ::std::tuple<> t0; EXPECT_EQ("()", Print(t0)); ::std::tuple t1(5); EXPECT_EQ("(5)", Print(t1)); ::std::tuple t2('a', true); EXPECT_EQ("('a' (97, 0x61), true)", Print(t2)); ::std::tuple t3(false, 2, 3); EXPECT_EQ("(false, 2, 3)", Print(t3)); ::std::tuple t4(false, 2, 3, 4); EXPECT_EQ("(false, 2, 3, 4)", Print(t4)); ::std::tuple t5(false, 2, 3, 4, true); EXPECT_EQ("(false, 2, 3, 4, true)", Print(t5)); ::std::tuple t6(false, 2, 3, 4, true, 6); EXPECT_EQ("(false, 2, 3, 4, true, 6)", Print(t6)); ::std::tuple t7( false, 2, 3, 4, true, 6, 7); EXPECT_EQ("(false, 2, 3, 4, true, 6, 7)", Print(t7)); ::std::tuple t8( false, 2, 3, 4, true, 6, 7, true); EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true)", Print(t8)); ::std::tuple t9( false, 2, 3, 4, true, 6, 7, true, 9); EXPECT_EQ("(false, 2, 3, 4, true, 6, 7, true, 9)", Print(t9)); const char* const str = "8"; // VC++ 2010's implementation of tuple of C++0x is deficient, requiring // an explicit type cast of NULL to be used. ::std::tuple t10(false, 'a', 3, 4, 5, 1.5F, -2.5, str, ImplicitCast_(NULL), "10"); EXPECT_EQ("(false, 'a' (97, 0x61), 3, 4, 5, 1.5, -2.5, " + PrintPointer(str) + " pointing to \"8\", NULL, \"10\")", Print(t10)); } // Nested tuples. TEST(PrintStdTupleTest, NestedTuple) { ::std::tuple< ::std::tuple, char> nested( ::std::make_tuple(5, true), 'a'); EXPECT_EQ("((5, true), 'a' (97, 0x61))", Print(nested)); } #endif // GTEST_LANG_CXX11 // Tests printing user-defined unprintable types. // Unprintable types in the global namespace. TEST(PrintUnprintableTypeTest, InGlobalNamespace) { EXPECT_EQ("1-byte object <00>", Print(UnprintableTemplateInGlobal())); } // Unprintable types in a user namespace. TEST(PrintUnprintableTypeTest, InUserNamespace) { EXPECT_EQ("16-byte object ", Print(::foo::UnprintableInFoo())); } // Unprintable types are that too big to be printed completely. struct Big { Big() { memset(array, 0, sizeof(array)); } char array[257]; }; TEST(PrintUnpritableTypeTest, BigObject) { EXPECT_EQ("257-byte object <00-00 00-00 00-00 00-00 00-00 00-00 " "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " "00-00 00-00 00-00 00-00 00-00 00-00 ... 00-00 00-00 00-00 " "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 " "00-00 00-00 00-00 00-00 00-00 00-00 00-00 00-00 00>", Print(Big())); } // Tests printing user-defined streamable types. // Streamable types in the global namespace. TEST(PrintStreamableTypeTest, InGlobalNamespace) { StreamableInGlobal x; EXPECT_EQ("StreamableInGlobal", Print(x)); EXPECT_EQ("StreamableInGlobal*", Print(&x)); } // Printable template types in a user namespace. TEST(PrintStreamableTypeTest, TemplateTypeInUserNamespace) { EXPECT_EQ("StreamableTemplateInFoo: 0", Print(::foo::StreamableTemplateInFoo())); } // Tests printing user-defined types that have a PrintTo() function. TEST(PrintPrintableTypeTest, InUserNamespace) { EXPECT_EQ("PrintableViaPrintTo: 0", Print(::foo::PrintableViaPrintTo())); } // Tests printing a pointer to a user-defined type that has a << // operator for its pointer. TEST(PrintPrintableTypeTest, PointerInUserNamespace) { ::foo::PointerPrintable x; EXPECT_EQ("PointerPrintable*", Print(&x)); } // Tests printing user-defined class template that have a PrintTo() function. TEST(PrintPrintableTypeTest, TemplateInUserNamespace) { EXPECT_EQ("PrintableViaPrintToTemplate: 5", Print(::foo::PrintableViaPrintToTemplate(5))); } // Tests that the universal printer prints both the address and the // value of a reference. TEST(PrintReferenceTest, PrintsAddressAndValue) { int n = 5; EXPECT_EQ("@" + PrintPointer(&n) + " 5", PrintByRef(n)); int a[2][3] = { { 0, 1, 2 }, { 3, 4, 5 } }; EXPECT_EQ("@" + PrintPointer(a) + " { { 0, 1, 2 }, { 3, 4, 5 } }", PrintByRef(a)); const ::foo::UnprintableInFoo x; EXPECT_EQ("@" + PrintPointer(&x) + " 16-byte object " "", PrintByRef(x)); } // Tests that the universal printer prints a function pointer passed by // reference. TEST(PrintReferenceTest, HandlesFunctionPointer) { void (*fp)(int n) = &MyFunction; const string fp_pointer_string = PrintPointer(reinterpret_cast(&fp)); // We cannot directly cast &MyFunction to const void* because the // standard disallows casting between pointers to functions and // pointers to objects, and some compilers (e.g. GCC 3.4) enforce // this limitation. const string fp_string = PrintPointer(reinterpret_cast( reinterpret_cast(fp))); EXPECT_EQ("@" + fp_pointer_string + " " + fp_string, PrintByRef(fp)); } // Tests that the universal printer prints a member function pointer // passed by reference. TEST(PrintReferenceTest, HandlesMemberFunctionPointer) { int (Foo::*p)(char ch) = &Foo::MyMethod; EXPECT_TRUE(HasPrefix( PrintByRef(p), "@" + PrintPointer(reinterpret_cast(&p)) + " " + Print(sizeof(p)) + "-byte object ")); char (Foo::*p2)(int n) = &Foo::MyVirtualMethod; EXPECT_TRUE(HasPrefix( PrintByRef(p2), "@" + PrintPointer(reinterpret_cast(&p2)) + " " + Print(sizeof(p2)) + "-byte object ")); } // Tests that the universal printer prints a member variable pointer // passed by reference. TEST(PrintReferenceTest, HandlesMemberVariablePointer) { int (Foo::*p) = &Foo::value; // NOLINT EXPECT_TRUE(HasPrefix( PrintByRef(p), "@" + PrintPointer(&p) + " " + Print(sizeof(p)) + "-byte object ")); } // Tests that FormatForComparisonFailureMessage(), which is used to print // an operand in a comparison assertion (e.g. ASSERT_EQ) when the assertion // fails, formats the operand in the desired way. // scalar TEST(FormatForComparisonFailureMessageTest, WorksForScalar) { EXPECT_STREQ("123", FormatForComparisonFailureMessage(123, 124).c_str()); } // non-char pointer TEST(FormatForComparisonFailureMessageTest, WorksForNonCharPointer) { int n = 0; EXPECT_EQ(PrintPointer(&n), FormatForComparisonFailureMessage(&n, &n).c_str()); } // non-char array TEST(FormatForComparisonFailureMessageTest, FormatsNonCharArrayAsPointer) { // In expression 'array == x', 'array' is compared by pointer. // Therefore we want to print an array operand as a pointer. int n[] = { 1, 2, 3 }; EXPECT_EQ(PrintPointer(n), FormatForComparisonFailureMessage(n, n).c_str()); } // Tests formatting a char pointer when it's compared with another pointer. // In this case we want to print it as a raw pointer, as the comparision is by // pointer. // char pointer vs pointer TEST(FormatForComparisonFailureMessageTest, WorksForCharPointerVsPointer) { // In expression 'p == x', where 'p' and 'x' are (const or not) char // pointers, the operands are compared by pointer. Therefore we // want to print 'p' as a pointer instead of a C string (we don't // even know if it's supposed to point to a valid C string). // const char* const char* s = "hello"; EXPECT_EQ(PrintPointer(s), FormatForComparisonFailureMessage(s, s).c_str()); // char* char ch = 'a'; EXPECT_EQ(PrintPointer(&ch), FormatForComparisonFailureMessage(&ch, &ch).c_str()); } // wchar_t pointer vs pointer TEST(FormatForComparisonFailureMessageTest, WorksForWCharPointerVsPointer) { // In expression 'p == x', where 'p' and 'x' are (const or not) char // pointers, the operands are compared by pointer. Therefore we // want to print 'p' as a pointer instead of a wide C string (we don't // even know if it's supposed to point to a valid wide C string). // const wchar_t* const wchar_t* s = L"hello"; EXPECT_EQ(PrintPointer(s), FormatForComparisonFailureMessage(s, s).c_str()); // wchar_t* wchar_t ch = L'a'; EXPECT_EQ(PrintPointer(&ch), FormatForComparisonFailureMessage(&ch, &ch).c_str()); } // Tests formatting a char pointer when it's compared to a string object. // In this case we want to print the char pointer as a C string. #if GTEST_HAS_GLOBAL_STRING // char pointer vs ::string TEST(FormatForComparisonFailureMessageTest, WorksForCharPointerVsString) { const char* s = "hello \"world"; EXPECT_STREQ("\"hello \\\"world\"", // The string content should be escaped. FormatForComparisonFailureMessage(s, ::string()).c_str()); // char* char str[] = "hi\1"; char* p = str; EXPECT_STREQ("\"hi\\x1\"", // The string content should be escaped. FormatForComparisonFailureMessage(p, ::string()).c_str()); } #endif // char pointer vs std::string TEST(FormatForComparisonFailureMessageTest, WorksForCharPointerVsStdString) { const char* s = "hello \"world"; EXPECT_STREQ("\"hello \\\"world\"", // The string content should be escaped. FormatForComparisonFailureMessage(s, ::std::string()).c_str()); // char* char str[] = "hi\1"; char* p = str; EXPECT_STREQ("\"hi\\x1\"", // The string content should be escaped. FormatForComparisonFailureMessage(p, ::std::string()).c_str()); } #if GTEST_HAS_GLOBAL_WSTRING // wchar_t pointer vs ::wstring TEST(FormatForComparisonFailureMessageTest, WorksForWCharPointerVsWString) { const wchar_t* s = L"hi \"world"; EXPECT_STREQ("L\"hi \\\"world\"", // The string content should be escaped. FormatForComparisonFailureMessage(s, ::wstring()).c_str()); // wchar_t* wchar_t str[] = L"hi\1"; wchar_t* p = str; EXPECT_STREQ("L\"hi\\x1\"", // The string content should be escaped. FormatForComparisonFailureMessage(p, ::wstring()).c_str()); } #endif #if GTEST_HAS_STD_WSTRING // wchar_t pointer vs std::wstring TEST(FormatForComparisonFailureMessageTest, WorksForWCharPointerVsStdWString) { const wchar_t* s = L"hi \"world"; EXPECT_STREQ("L\"hi \\\"world\"", // The string content should be escaped. FormatForComparisonFailureMessage(s, ::std::wstring()).c_str()); // wchar_t* wchar_t str[] = L"hi\1"; wchar_t* p = str; EXPECT_STREQ("L\"hi\\x1\"", // The string content should be escaped. FormatForComparisonFailureMessage(p, ::std::wstring()).c_str()); } #endif // Tests formatting a char array when it's compared with a pointer or array. // In this case we want to print the array as a row pointer, as the comparison // is by pointer. // char array vs pointer TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsPointer) { char str[] = "hi \"world\""; char* p = NULL; EXPECT_EQ(PrintPointer(str), FormatForComparisonFailureMessage(str, p).c_str()); } // char array vs char array TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsCharArray) { const char str[] = "hi \"world\""; EXPECT_EQ(PrintPointer(str), FormatForComparisonFailureMessage(str, str).c_str()); } // wchar_t array vs pointer TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsPointer) { wchar_t str[] = L"hi \"world\""; wchar_t* p = NULL; EXPECT_EQ(PrintPointer(str), FormatForComparisonFailureMessage(str, p).c_str()); } // wchar_t array vs wchar_t array TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsWCharArray) { const wchar_t str[] = L"hi \"world\""; EXPECT_EQ(PrintPointer(str), FormatForComparisonFailureMessage(str, str).c_str()); } // Tests formatting a char array when it's compared with a string object. // In this case we want to print the array as a C string. #if GTEST_HAS_GLOBAL_STRING // char array vs string TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsString) { const char str[] = "hi \"w\0rld\""; EXPECT_STREQ("\"hi \\\"w\"", // The content should be escaped. // Embedded NUL terminates the string. FormatForComparisonFailureMessage(str, ::string()).c_str()); } #endif // char array vs std::string TEST(FormatForComparisonFailureMessageTest, WorksForCharArrayVsStdString) { const char str[] = "hi \"world\""; EXPECT_STREQ("\"hi \\\"world\\\"\"", // The content should be escaped. FormatForComparisonFailureMessage(str, ::std::string()).c_str()); } #if GTEST_HAS_GLOBAL_WSTRING // wchar_t array vs wstring TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsWString) { const wchar_t str[] = L"hi \"world\""; EXPECT_STREQ("L\"hi \\\"world\\\"\"", // The content should be escaped. FormatForComparisonFailureMessage(str, ::wstring()).c_str()); } #endif #if GTEST_HAS_STD_WSTRING // wchar_t array vs std::wstring TEST(FormatForComparisonFailureMessageTest, WorksForWCharArrayVsStdWString) { const wchar_t str[] = L"hi \"w\0rld\""; EXPECT_STREQ( "L\"hi \\\"w\"", // The content should be escaped. // Embedded NUL terminates the string. FormatForComparisonFailureMessage(str, ::std::wstring()).c_str()); } #endif // Useful for testing PrintToString(). We cannot use EXPECT_EQ() // there as its implementation uses PrintToString(). The caller must // ensure that 'value' has no side effect. #define EXPECT_PRINT_TO_STRING_(value, expected_string) \ EXPECT_TRUE(PrintToString(value) == (expected_string)) \ << " where " #value " prints as " << (PrintToString(value)) TEST(PrintToStringTest, WorksForScalar) { EXPECT_PRINT_TO_STRING_(123, "123"); } TEST(PrintToStringTest, WorksForPointerToConstChar) { const char* p = "hello"; EXPECT_PRINT_TO_STRING_(p, "\"hello\""); } TEST(PrintToStringTest, WorksForPointerToNonConstChar) { char s[] = "hello"; char* p = s; EXPECT_PRINT_TO_STRING_(p, "\"hello\""); } TEST(PrintToStringTest, EscapesForPointerToConstChar) { const char* p = "hello\n"; EXPECT_PRINT_TO_STRING_(p, "\"hello\\n\""); } TEST(PrintToStringTest, EscapesForPointerToNonConstChar) { char s[] = "hello\1"; char* p = s; EXPECT_PRINT_TO_STRING_(p, "\"hello\\x1\""); } TEST(PrintToStringTest, WorksForArray) { int n[3] = { 1, 2, 3 }; EXPECT_PRINT_TO_STRING_(n, "{ 1, 2, 3 }"); } TEST(PrintToStringTest, WorksForCharArray) { char s[] = "hello"; EXPECT_PRINT_TO_STRING_(s, "\"hello\""); } TEST(PrintToStringTest, WorksForCharArrayWithEmbeddedNul) { const char str_with_nul[] = "hello\0 world"; EXPECT_PRINT_TO_STRING_(str_with_nul, "\"hello\\0 world\""); char mutable_str_with_nul[] = "hello\0 world"; EXPECT_PRINT_TO_STRING_(mutable_str_with_nul, "\"hello\\0 world\""); } #undef EXPECT_PRINT_TO_STRING_ TEST(UniversalTersePrintTest, WorksForNonReference) { ::std::stringstream ss; UniversalTersePrint(123, &ss); EXPECT_EQ("123", ss.str()); } TEST(UniversalTersePrintTest, WorksForReference) { const int& n = 123; ::std::stringstream ss; UniversalTersePrint(n, &ss); EXPECT_EQ("123", ss.str()); } TEST(UniversalTersePrintTest, WorksForCString) { const char* s1 = "abc"; ::std::stringstream ss1; UniversalTersePrint(s1, &ss1); EXPECT_EQ("\"abc\"", ss1.str()); char* s2 = const_cast(s1); ::std::stringstream ss2; UniversalTersePrint(s2, &ss2); EXPECT_EQ("\"abc\"", ss2.str()); const char* s3 = NULL; ::std::stringstream ss3; UniversalTersePrint(s3, &ss3); EXPECT_EQ("NULL", ss3.str()); } TEST(UniversalPrintTest, WorksForNonReference) { ::std::stringstream ss; UniversalPrint(123, &ss); EXPECT_EQ("123", ss.str()); } TEST(UniversalPrintTest, WorksForReference) { const int& n = 123; ::std::stringstream ss; UniversalPrint(n, &ss); EXPECT_EQ("123", ss.str()); } TEST(UniversalPrintTest, WorksForCString) { const char* s1 = "abc"; ::std::stringstream ss1; UniversalPrint(s1, &ss1); EXPECT_EQ(PrintPointer(s1) + " pointing to \"abc\"", string(ss1.str())); char* s2 = const_cast(s1); ::std::stringstream ss2; UniversalPrint(s2, &ss2); EXPECT_EQ(PrintPointer(s2) + " pointing to \"abc\"", string(ss2.str())); const char* s3 = NULL; ::std::stringstream ss3; UniversalPrint(s3, &ss3); EXPECT_EQ("NULL", ss3.str()); } TEST(UniversalPrintTest, WorksForCharArray) { const char str[] = "\"Line\0 1\"\nLine 2"; ::std::stringstream ss1; UniversalPrint(str, &ss1); EXPECT_EQ("\"\\\"Line\\0 1\\\"\\nLine 2\"", ss1.str()); const char mutable_str[] = "\"Line\0 1\"\nLine 2"; ::std::stringstream ss2; UniversalPrint(mutable_str, &ss2); EXPECT_EQ("\"\\\"Line\\0 1\\\"\\nLine 2\"", ss2.str()); } #if GTEST_HAS_TR1_TUPLE TEST(UniversalTersePrintTupleFieldsToStringsTestWithTr1, PrintsEmptyTuple) { Strings result = UniversalTersePrintTupleFieldsToStrings( ::std::tr1::make_tuple()); EXPECT_EQ(0u, result.size()); } TEST(UniversalTersePrintTupleFieldsToStringsTestWithTr1, PrintsOneTuple) { Strings result = UniversalTersePrintTupleFieldsToStrings( ::std::tr1::make_tuple(1)); ASSERT_EQ(1u, result.size()); EXPECT_EQ("1", result[0]); } TEST(UniversalTersePrintTupleFieldsToStringsTestWithTr1, PrintsTwoTuple) { Strings result = UniversalTersePrintTupleFieldsToStrings( ::std::tr1::make_tuple(1, 'a')); ASSERT_EQ(2u, result.size()); EXPECT_EQ("1", result[0]); EXPECT_EQ("'a' (97, 0x61)", result[1]); } TEST(UniversalTersePrintTupleFieldsToStringsTestWithTr1, PrintsTersely) { const int n = 1; Strings result = UniversalTersePrintTupleFieldsToStrings( ::std::tr1::tuple(n, "a")); ASSERT_EQ(2u, result.size()); EXPECT_EQ("1", result[0]); EXPECT_EQ("\"a\"", result[1]); } #endif // GTEST_HAS_TR1_TUPLE #if GTEST_HAS_STD_TUPLE_ TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsEmptyTuple) { Strings result = UniversalTersePrintTupleFieldsToStrings(::std::make_tuple()); EXPECT_EQ(0u, result.size()); } TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsOneTuple) { Strings result = UniversalTersePrintTupleFieldsToStrings( ::std::make_tuple(1)); ASSERT_EQ(1u, result.size()); EXPECT_EQ("1", result[0]); } TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsTwoTuple) { Strings result = UniversalTersePrintTupleFieldsToStrings( ::std::make_tuple(1, 'a')); ASSERT_EQ(2u, result.size()); EXPECT_EQ("1", result[0]); EXPECT_EQ("'a' (97, 0x61)", result[1]); } TEST(UniversalTersePrintTupleFieldsToStringsTestWithStd, PrintsTersely) { const int n = 1; Strings result = UniversalTersePrintTupleFieldsToStrings( ::std::tuple(n, "a")); ASSERT_EQ(2u, result.size()); EXPECT_EQ("1", result[0]); EXPECT_EQ("\"a\"", result[1]); } #endif // GTEST_HAS_STD_TUPLE_ } // namespace gtest_printers_test } // namespace testing assimp-4.1.0/contrib/gtest/test/gtest_filter_unittest_.cc0000644002537200234200000000675413213503245024135 0ustar zmoelnigiemusers// 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 { }; 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(); } assimp-4.1.0/contrib/gtest/test/gtest_test_utils.py0000644002537200234200000002510713213503245023005 0ustar zmoelnigiemusers#!/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] # The environment variable for specifying the path to the premature-exit file. PREMATURE_EXIT_FILE_ENV_VAR = 'TEST_PREMATURE_EXIT_FILE' environ = os.environ.copy() def SetEnvVar(env_var, value): """Sets/unsets an environment variable to a given value.""" if value is not None: environ[env_var] = value elif env_var in environ: del environ[env_var] # 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 = {'source_dir': os.path.dirname(sys.argv[0]), '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('source_dir')) def GetBuildDir(): """Returns the absolute path of the directory where the test binaries are.""" return os.path.abspath(GetFlag('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 "%s". Please make sure to provide\n' 'a path to the binary via the --build_dir flag or the BUILD_DIR\n' 'environment variable.' % path) sys.stdout.write(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.keys(): 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() assimp-4.1.0/contrib/gtest/test/gtest_output_test.py0000644002537200234200000002774313213503245023215 0ustar zmoelnigiemusers#!/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 --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 difflib 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' # TODO(vladl@google.com): remove the _lin suffix. 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 # 'internal_skip_environment_and_ad_hoc_tests' argument. COMMAND_LIST_TESTS = ({}, [PROGRAM_PATH, '--gtest_list_tests']) COMMAND_WITH_COLOR = ({}, [PROGRAM_PATH, '--gtest_color=yes']) COMMAND_WITH_TIME = ({}, [PROGRAM_PATH, '--gtest_print_time', 'internal_skip_environment_and_ad_hoc_tests', '--gtest_filter=FatalFailureTest.*:LoggingTest.*']) COMMAND_WITH_DISABLED = ( {}, [PROGRAM_PATH, '--gtest_also_run_disabled_tests', 'internal_skip_environment_and_ad_hoc_tests', '--gtest_filter=*DISABLED_*']) COMMAND_WITH_SHARDING = ( {'GTEST_SHARD_INDEX': '1', 'GTEST_TOTAL_SHARDS': '2'}, [PROGRAM_PATH, '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 NormalizeToCurrentPlatform(test_output): """Normalizes platform specific output details for easier comparison.""" if IS_WINDOWS: # Removes the color information that is not present on Windows. test_output = re.sub('\x1b\\[(0;3\d)?m', '', test_output) # Changes failure message headers into the Windows format. test_output = re.sub(r': Failure\n', r': error: ', test_output) # Changes file(line_number) to file:line_number. test_output = re.sub(r'((\w|\.)+)\((\d+)\):', r'\1:\3:', test_output) return 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 and not IS_WINDOWS) 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, 'r') # 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, '\n'.join(difflib.unified_diff( normalized_golden.split('\n'), normalized_actual.split('\n'), 'golden', 'actual'))) else: normalized_actual = NormalizeToCurrentPlatform( RemoveTestCounts(normalized_actual)) normalized_golden = NormalizeToCurrentPlatform( 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, typed tests, and multiple 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() assimp-4.1.0/contrib/gtest/test/gtest_prod_test.cc0000644002537200234200000000424113213503245022542 0ustar zmoelnigiemusers// 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_); } assimp-4.1.0/contrib/gtest/test/gtest-param-test_test.cc0000644002537200234200000011345013213503245023574 0ustar zmoelnigiemusers// 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 # include # include # include # include # include // 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 ::testing::get; using ::testing::make_tuple; using ::testing::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 ::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 ::std::string PrintValue(const tuple& value) { ::std::stringstream stream; stream << "(" << get<0>(value) << ", " << get<1>(value) << ")"; return stream.str(); } template ::std::string PrintValue(const tuple& value) { ::std::stringstream stream; stream << "(" << get<0>(value) << ", " << get<1>(value) << ", "<< get<2>(value) << ")"; return stream.str(); } template ::std::string PrintValue( const tuple& 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 void VerifyGenerator(const ParamGenerator& generator, const T (&expected_values)[N]) { typename ParamGenerator::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 void VerifyGeneratorIsEmpty(const ParamGenerator& generator) { typename ParamGenerator::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 gen = Range(0, 10); ParamGenerator::iterator it = gen.begin(); // Verifies that iterator initialization works as expected. ParamGenerator::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 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 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 gen = Range(0, 0); VerifyGeneratorIsEmpty(gen); } // Tests that Range() with custom step (greater then one) generates // the expected sequence. TEST(RangeTest, IntRangeWithCustomStep) { const ParamGenerator 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 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 std::string& value() const { return value_; } private: std::string value_; }; TEST(RangeTest, WorksWithACustomType) { const ParamGenerator gen = Range(DogAdder("cat"), DogAdder("catdogdog"), DogAdder("dog")); ParamGenerator::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 gen = Range(IntWrapper(0), IntWrapper(2)); ParamGenerator::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 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 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 gen = ValuesIn(array); VerifyGenerator(gen, array); } // Tests that ValuesIn() generates the expected sequence for an STL // container (vector). TEST(ValuesInTest, ValuesInVector) { typedef ::std::vector ContainerType; ContainerType values; values.push_back(3); values.push_back(5); values.push_back(8); const ParamGenerator 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 ContainerType; ContainerType values; values.push_back(3); values.push_back(5); values.push_back(8); const ParamGenerator 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 ContainerType; ContainerType values; values.push_back(42); const ParamGenerator 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 ContainerType; ContainerType values; const ParamGenerator gen = ValuesIn(values.begin(), values.end()); VerifyGeneratorIsEmpty(gen); } // Tests that the Values() generates the expected sequence. TEST(ValuesTest, ValuesWorks) { const ParamGenerator 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 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 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 gen = Values(42); const int expected_values[] = {42}; VerifyGenerator(gen, expected_values); } // Tests that Bool() generates sequence (false, true). TEST(BoolTest, BoolWorks) { const ParamGenerator 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 > gen = Combine(Values(foo, bar), Values(3, 4)); tuple 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 > gen = Combine(Values(0, 1), Values(3, 4), Values(5, 6)); tuple 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 > gen = Combine(Values(42), Values(0, 1)); tuple 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 > gen = Combine(Values(0, 1), Values(42)); tuple 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 > 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 > 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 > gen = Combine(Values(foo, bar), Values(1), Values(2), Values(3), Values(4), Values(5), Values(6), Values(7), Values(8), Values(9)); tuple 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 gen = Values(1, 2); const ParamGenerator 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 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 { public: enum { PARAMETER_COUNT = sizeof(test_generation_params)/sizeof(test_generation_params[0]) }; typedef TestGenerationEnvironment 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 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 collected_parameters_; private: GTEST_DISALLOW_COPY_AND_ASSIGN_(TestGenerationTest); }; vector 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 { 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 extern_gen; class ExternalGeneratorTest : public TestWithParam {}; 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 {}; 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 { 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 {}; TEST_P(NamingTest, TestsReportCorrectNamesAndParameters) { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); EXPECT_STREQ("ZeroToFiveSequence/NamingTest", test_info->test_case_name()); Message index_stream; index_stream << "TestsReportCorrectNamesAndParameters/" << GetParam(); EXPECT_STREQ(index_stream.GetString().c_str(), test_info->name()); EXPECT_EQ(::testing::PrintToString(GetParam()), test_info->value_param()); } INSTANTIATE_TEST_CASE_P(ZeroToFiveSequence, NamingTest, Range(0, 5)); // Tests that user supplied custom parameter names are working correctly. // Runs the test with a builtin helper method which uses PrintToString, // as well as a custom function and custom functor to ensure all possible // uses work correctly. class CustomFunctorNamingTest : public TestWithParam {}; TEST_P(CustomFunctorNamingTest, CustomTestNames) {} struct CustomParamNameFunctor { std::string operator()(const ::testing::TestParamInfo& info) { return info.param; } }; INSTANTIATE_TEST_CASE_P(CustomParamNameFunctor, CustomFunctorNamingTest, Values(std::string("FunctorName")), CustomParamNameFunctor()); INSTANTIATE_TEST_CASE_P(AllAllowedCharacters, CustomFunctorNamingTest, Values("abcdefghijklmnopqrstuvwxyz", "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "01234567890_"), CustomParamNameFunctor()); inline std::string CustomParamNameFunction( const ::testing::TestParamInfo& info) { return info.param; } class CustomFunctionNamingTest : public TestWithParam {}; TEST_P(CustomFunctionNamingTest, CustomTestNames) {} INSTANTIATE_TEST_CASE_P(CustomParamNameFunction, CustomFunctionNamingTest, Values(std::string("FunctionName")), CustomParamNameFunction); #if GTEST_LANG_CXX11 // Test custom naming with a lambda class CustomLambdaNamingTest : public TestWithParam {}; TEST_P(CustomLambdaNamingTest, CustomTestNames) {} INSTANTIATE_TEST_CASE_P(CustomParamNameLambda, CustomLambdaNamingTest, Values(std::string("LambdaName")), [](const ::testing::TestParamInfo& info) { return info.param; }); #endif // GTEST_LANG_CXX11 TEST(CustomNamingTest, CheckNameRegistry) { ::testing::UnitTest* unit_test = ::testing::UnitTest::GetInstance(); std::set test_names; for (int case_num = 0; case_num < unit_test->total_test_case_count(); ++case_num) { const ::testing::TestCase* test_case = unit_test->GetTestCase(case_num); for (int test_num = 0; test_num < test_case->total_test_count(); ++test_num) { const ::testing::TestInfo* test_info = test_case->GetTestInfo(test_num); test_names.insert(std::string(test_info->name())); } } EXPECT_EQ(1u, test_names.count("CustomTestNames/FunctorName")); EXPECT_EQ(1u, test_names.count("CustomTestNames/FunctionName")); #if GTEST_LANG_CXX11 EXPECT_EQ(1u, test_names.count("CustomTestNames/LambdaName")); #endif // GTEST_LANG_CXX11 } // Test a numeric name to ensure PrintToStringParamName works correctly. class CustomIntegerNamingTest : public TestWithParam {}; TEST_P(CustomIntegerNamingTest, TestsReportCorrectNames) { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); Message test_name_stream; test_name_stream << "TestsReportCorrectNames/" << GetParam(); EXPECT_STREQ(test_name_stream.GetString().c_str(), test_info->name()); } INSTANTIATE_TEST_CASE_P(PrintToString, CustomIntegerNamingTest, Range(0, 5), ::testing::PrintToStringParamName()); // Test a custom struct with PrintToString. struct CustomStruct { explicit CustomStruct(int value) : x(value) {} int x; }; std::ostream& operator<<(std::ostream& stream, const CustomStruct& val) { stream << val.x; return stream; } class CustomStructNamingTest : public TestWithParam {}; TEST_P(CustomStructNamingTest, TestsReportCorrectNames) { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); Message test_name_stream; test_name_stream << "TestsReportCorrectNames/" << GetParam(); EXPECT_STREQ(test_name_stream.GetString().c_str(), test_info->name()); } INSTANTIATE_TEST_CASE_P(PrintToString, CustomStructNamingTest, Values(CustomStruct(0), CustomStruct(1)), ::testing::PrintToStringParamName()); // Test that using a stateful parameter naming function works as expected. struct StatefulNamingFunctor { StatefulNamingFunctor() : sum(0) {} std::string operator()(const ::testing::TestParamInfo& info) { int value = info.param + sum; sum += info.param; return ::testing::PrintToString(value); } int sum; }; class StatefulNamingTest : public ::testing::TestWithParam { protected: StatefulNamingTest() : sum_(0) {} int sum_; }; TEST_P(StatefulNamingTest, TestsReportCorrectNames) { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); sum_ += GetParam(); Message test_name_stream; test_name_stream << "TestsReportCorrectNames/" << sum_; EXPECT_STREQ(test_name_stream.GetString().c_str(), test_info->name()); } INSTANTIATE_TEST_CASE_P(StatefulNamingFunctor, StatefulNamingTest, Range(0, 5), StatefulNamingFunctor()); // Class that cannot be streamed into an ostream. It needs to be copyable // (and, in case of MSVC, also assignable) in order to be a test parameter // type. Its default copy constructor and assignment operator do exactly // what we need. class Unstreamable { public: explicit Unstreamable(int value) : value_(value) {} private: int value_; }; class CommentTest : public TestWithParam {}; TEST_P(CommentTest, TestsCorrectlyReportUnstreamableParams) { const ::testing::TestInfo* const test_info = ::testing::UnitTest::GetInstance()->current_test_info(); EXPECT_EQ(::testing::PrintToString(GetParam()), test_info->value_param()); } INSTANTIATE_TEST_CASE_P(InstantiationWithComments, CommentTest, Values(Unstreamable(1))); // Verify that we can create a hierarchy of test fixtures, where the base // class fixture is not parameterized and the derived class is. In this case // ParameterizedDerivedTest inherits from NonParameterizedBaseTest. We // perform simple tests on both. class NonParameterizedBaseTest : public ::testing::Test { public: NonParameterizedBaseTest() : n_(17) { } protected: int n_; }; class ParameterizedDerivedTest : public NonParameterizedBaseTest, public ::testing::WithParamInterface { protected: ParameterizedDerivedTest() : count_(0) { } int count_; static int global_count_; }; int ParameterizedDerivedTest::global_count_ = 0; TEST_F(NonParameterizedBaseTest, FixtureIsInitialized) { EXPECT_EQ(17, n_); } TEST_P(ParameterizedDerivedTest, SeesSequence) { EXPECT_EQ(17, n_); EXPECT_EQ(0, count_++); EXPECT_EQ(GetParam(), global_count_++); } class ParameterizedDeathTest : public ::testing::TestWithParam { }; TEST_F(ParameterizedDeathTest, GetParamDiesFromTestF) { EXPECT_DEATH_IF_SUPPORTED(GetParam(), ".* value-parameterized test .*"); } INSTANTIATE_TEST_CASE_P(RangeZeroToFive, ParameterizedDerivedTest, 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(); } assimp-4.1.0/contrib/gtest/test/gtest_env_var_test_.cc0000644002537200234200000000677013213503245023406 0ustar zmoelnigiemusers// 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 #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; } assimp-4.1.0/contrib/gtest/test/gtest_main_unittest.cc0000644002537200234200000000354013213503245023423 0ustar zmoelnigiemusers// 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. assimp-4.1.0/contrib/gtest/test/gtest_xml_outfile1_test_.cc0000644002537200234200000000373313213503245024352 0ustar zmoelnigiemusers// 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); } assimp-4.1.0/contrib/gtest/test/gtest_xml_output_unittest.py0000644002537200234200000003452513213503245024771 0ustar zmoelnigiemusers#!/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 datetime import errno import os import re import sys from xml.dom import minidom, Node import gtest_test_utils import gtest_xml_test_utils GTEST_FILTER_FLAG = '--gtest_filter' GTEST_LIST_TESTS_FLAG = '--gtest_list_tests' 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 = """ ]]>%(stack)s]]> """ % {'stack': STACK_TRACE_TEMPLATE} EXPECTED_FILTERED_TEST_XML = """ """ EXPECTED_EMPTY_XML = """ """ GTEST_PROGRAM_PATH = gtest_test_utils.GetTestExecutablePath(GTEST_PROGRAM_NAME) SUPPORTS_TYPED_TESTS = 'TypedTest' in gtest_test_utils.Subprocess( [GTEST_PROGRAM_PATH, GTEST_LIST_TESTS_FLAG], capture_stderr=False).output class GTestXMLOutputUnitTest(gtest_xml_test_utils.GTestXMLTestCase): """ Unit test for Google Test's XML output functionality. """ # This test currently breaks on platforms that do not support typed and # type-parameterized tests, so we don't run it under them. if SUPPORTS_TYPED_TESTS: 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): """Verifies XML output for a Google Test binary without actual tests. 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 testTimestampValue(self): """Checks whether the timestamp attribute in the XML output is valid. Runs a test program that generates an empty XML output, and checks if the timestamp attribute in the testsuites tag is valid. """ actual = self._GetXmlOutput('gtest_no_test_unittest', [], 0) date_time_str = actual.documentElement.getAttributeNode('timestamp').value # datetime.strptime() is only available in Python 2.5+ so we have to # parse the expected datetime manually. match = re.match(r'(\d+)-(\d\d)-(\d\d)T(\d\d):(\d\d):(\d\d)', date_time_str) self.assertTrue( re.match, 'XML datettime string %s has incorrect format' % date_time_str) date_time_from_xml = datetime.datetime( year=int(match.group(1)), month=int(match.group(2)), day=int(match.group(3)), hour=int(match.group(4)), minute=int(match.group(5)), second=int(match.group(6))) time_delta = abs(datetime.datetime.now() - date_time_from_xml) # timestamp value should be near the current local time self.assertTrue(time_delta < datetime.timedelta(seconds=600), 'time_delta is %s' % time_delta) actual.unlink() 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 = sys.exc_info()[1] 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) command = [GTEST_PROGRAM_PATH, '%s=xml:%s' % (GTEST_OUTPUT_FLAG, xml_path), '--shut_down_xml'] p = gtest_test_utils.Subprocess(command) if p.terminated_by_signal: # p.signal is avalable only if p.terminated_by_signal is True. self.assertFalse( p.terminated_by_signal, '%s was killed by signal %d' % (GTEST_PROGRAM_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 testFilteredTestXmlOutput(self): """Verifies XML output when a filter is applied. Runs a test program that executes only some tests and verifies that non-selected tests do not show up in the XML output. """ self._TestXmlOutput(GTEST_PROGRAM_NAME, EXPECTED_FILTERED_TEST_XML, 0, extra_args=['%s=SuccessfulTest.*' % GTEST_FILTER_FLAG]) def _GetXmlOutput(self, gtest_prog_name, extra_args, expected_exit_code): """ Returns the xml output generated by running the program gtest_prog_name. 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)] + extra_args) 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)) actual = minidom.parse(xml_path) return actual def _TestXmlOutput(self, gtest_prog_name, expected_xml, expected_exit_code, extra_args=None): """ 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. """ actual = self._GetXmlOutput(gtest_prog_name, extra_args or [], expected_exit_code) expected = minidom.parseString(expected_xml) 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() assimp-4.1.0/contrib/gtest/test/gtest_output_test_.cc0000644002537200234200000010052213213503245023274 0ustar zmoelnigiemusers// 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. // // The purpose of this file is to generate Google Test output under // various conditions. The output will then be verified by // gtest_output_test.py to ensure that Google Test generates the // desired messages. Therefore, most tests in this file are MEANT TO // FAIL. // // 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 #if GTEST_IS_THREADSAFE using testing::ScopedFakeTestPartResultReporter; using testing::TestPartResultArray; using testing::internal::Notification; using testing::internal::ThreadWithParam; #endif namespace posix = ::testing::internal::posix; // 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 that parameters of failing parameterized tests are printed in the // failing test summary. class FailingParamTest : public testing::TestWithParam {}; TEST_P(FailingParamTest, Fails) { EXPECT_EQ(1, GetParam()); } // This generates a test which will fail. Google Test is expected to print // its parameter when it outputs the list of all failed tests. INSTANTIATE_TEST_CASE_P(PrintingFailingParams, FailingParamTest, testing::Values(2)); static const char kGoldenString[] = "\"Line\0 1\"\nLine 2"; TEST(NonfatalFailureTest, EscapesStringOperands) { std::string actual = "actual \"string\""; EXPECT_EQ(kGoldenString, actual); const char* golden = kGoldenString; EXPECT_EQ(golden, actual); } TEST(NonfatalFailureTest, DiffForLongStrings) { std::string golden_str(kGoldenString, sizeof(kGoldenString) - 1); EXPECT_EQ(golden_str, "Line 2"); } // 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(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 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."; } TEST(AddFailureAtTest, MessageContainsSpecifiedFileAndLineNumber) { ADD_FAILURE_AT("foo.cc", 42) << "Expected failure in foo.cc"; } #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( &ThreadRoutine, ¬ifications_, 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_; testing::internal::scoped_ptr > 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 value-parameterized tests. #if GTEST_HAS_PARAM_TEST std::string ParamNameFunc(const testing::TestParamInfo& info) { return info.param; } class ParamTest : public testing::TestWithParam { }; TEST_P(ParamTest, Success) { EXPECT_EQ("a", GetParam()); } TEST_P(ParamTest, Failure) { EXPECT_EQ("b", GetParam()) << "Expected failure"; } INSTANTIATE_TEST_CASE_P(PrintingStrings, ParamTest, testing::Values(std::string("a")), ParamNameFunc); #endif // GTEST_HAS_PARAM_TEST // This #ifdef block tests the output of typed tests. #if GTEST_HAS_TYPED_TEST template class TypedTest : public testing::Test { }; TYPED_TEST_CASE(TypedTest, testing::Types); 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 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 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 class ATypedDeathTest : public testing::Test { }; typedef testing::Types 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 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 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."; } }; // 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); bool internal_skip_environment_and_ad_hoc_tests = std::count(argv, argv + argc, std::string("internal_skip_environment_and_ad_hoc_tests")) > 0; #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 (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(); } assimp-4.1.0/contrib/gtest/test/gtest_catch_exceptions_test_.cc0000644002537200234200000002132713213503245025264 0ustar zmoelnigiemusers// 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. // // Author: vladl@google.com (Vlad Losev) // // Tests for Google Test itself. Tests in this file throw C++ or SEH // exceptions, and the output is verified by gtest_catch_exceptions_test.py. #include "gtest/gtest.h" #include // NOLINT #include // For exit(). #if GTEST_HAS_SEH # include #endif #if GTEST_HAS_EXCEPTIONS # include // For set_terminate(). # include #endif using testing::Test; #if GTEST_HAS_SEH class SehExceptionInConstructorTest : public Test { public: SehExceptionInConstructorTest() { RaiseException(42, 0, 0, NULL); } }; TEST_F(SehExceptionInConstructorTest, ThrowsExceptionInConstructor) {} class SehExceptionInDestructorTest : public Test { public: ~SehExceptionInDestructorTest() { RaiseException(42, 0, 0, NULL); } }; TEST_F(SehExceptionInDestructorTest, ThrowsExceptionInDestructor) {} class SehExceptionInSetUpTestCaseTest : public Test { public: static void SetUpTestCase() { RaiseException(42, 0, 0, NULL); } }; TEST_F(SehExceptionInSetUpTestCaseTest, ThrowsExceptionInSetUpTestCase) {} class SehExceptionInTearDownTestCaseTest : public Test { public: static void TearDownTestCase() { RaiseException(42, 0, 0, NULL); } }; TEST_F(SehExceptionInTearDownTestCaseTest, ThrowsExceptionInTearDownTestCase) {} class SehExceptionInSetUpTest : public Test { protected: virtual void SetUp() { RaiseException(42, 0, 0, NULL); } }; TEST_F(SehExceptionInSetUpTest, ThrowsExceptionInSetUp) {} class SehExceptionInTearDownTest : public Test { protected: virtual void TearDown() { RaiseException(42, 0, 0, NULL); } }; TEST_F(SehExceptionInTearDownTest, ThrowsExceptionInTearDown) {} TEST(SehExceptionTest, ThrowsSehException) { RaiseException(42, 0, 0, NULL); } #endif // GTEST_HAS_SEH #if GTEST_HAS_EXCEPTIONS class CxxExceptionInConstructorTest : public Test { public: CxxExceptionInConstructorTest() { // Without this macro VC++ complains about unreachable code at the end of // the constructor. GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_( throw std::runtime_error("Standard C++ exception")); } static void TearDownTestCase() { printf("%s", "CxxExceptionInConstructorTest::TearDownTestCase() " "called as expected.\n"); } protected: ~CxxExceptionInConstructorTest() { ADD_FAILURE() << "CxxExceptionInConstructorTest destructor " << "called unexpectedly."; } virtual void SetUp() { ADD_FAILURE() << "CxxExceptionInConstructorTest::SetUp() " << "called unexpectedly."; } virtual void TearDown() { ADD_FAILURE() << "CxxExceptionInConstructorTest::TearDown() " << "called unexpectedly."; } }; TEST_F(CxxExceptionInConstructorTest, ThrowsExceptionInConstructor) { ADD_FAILURE() << "CxxExceptionInConstructorTest test body " << "called unexpectedly."; } // Exceptions in destructors are not supported in C++11. #if !defined(__GXX_EXPERIMENTAL_CXX0X__) && __cplusplus < 201103L class CxxExceptionInDestructorTest : public Test { public: static void TearDownTestCase() { printf("%s", "CxxExceptionInDestructorTest::TearDownTestCase() " "called as expected.\n"); } protected: ~CxxExceptionInDestructorTest() { GTEST_SUPPRESS_UNREACHABLE_CODE_WARNING_BELOW_( throw std::runtime_error("Standard C++ exception")); } }; TEST_F(CxxExceptionInDestructorTest, ThrowsExceptionInDestructor) {} #endif // C++11 mode class CxxExceptionInSetUpTestCaseTest : public Test { public: CxxExceptionInSetUpTestCaseTest() { printf("%s", "CxxExceptionInSetUpTestCaseTest constructor " "called as expected.\n"); } static void SetUpTestCase() { throw std::runtime_error("Standard C++ exception"); } static void TearDownTestCase() { printf("%s", "CxxExceptionInSetUpTestCaseTest::TearDownTestCase() " "called as expected.\n"); } protected: ~CxxExceptionInSetUpTestCaseTest() { printf("%s", "CxxExceptionInSetUpTestCaseTest destructor " "called as expected.\n"); } virtual void SetUp() { printf("%s", "CxxExceptionInSetUpTestCaseTest::SetUp() " "called as expected.\n"); } virtual void TearDown() { printf("%s", "CxxExceptionInSetUpTestCaseTest::TearDown() " "called as expected.\n"); } }; TEST_F(CxxExceptionInSetUpTestCaseTest, ThrowsExceptionInSetUpTestCase) { printf("%s", "CxxExceptionInSetUpTestCaseTest test body " "called as expected.\n"); } class CxxExceptionInTearDownTestCaseTest : public Test { public: static void TearDownTestCase() { throw std::runtime_error("Standard C++ exception"); } }; TEST_F(CxxExceptionInTearDownTestCaseTest, ThrowsExceptionInTearDownTestCase) {} class CxxExceptionInSetUpTest : public Test { public: static void TearDownTestCase() { printf("%s", "CxxExceptionInSetUpTest::TearDownTestCase() " "called as expected.\n"); } protected: ~CxxExceptionInSetUpTest() { printf("%s", "CxxExceptionInSetUpTest destructor " "called as expected.\n"); } virtual void SetUp() { throw std::runtime_error("Standard C++ exception"); } virtual void TearDown() { printf("%s", "CxxExceptionInSetUpTest::TearDown() " "called as expected.\n"); } }; TEST_F(CxxExceptionInSetUpTest, ThrowsExceptionInSetUp) { ADD_FAILURE() << "CxxExceptionInSetUpTest test body " << "called unexpectedly."; } class CxxExceptionInTearDownTest : public Test { public: static void TearDownTestCase() { printf("%s", "CxxExceptionInTearDownTest::TearDownTestCase() " "called as expected.\n"); } protected: ~CxxExceptionInTearDownTest() { printf("%s", "CxxExceptionInTearDownTest destructor " "called as expected.\n"); } virtual void TearDown() { throw std::runtime_error("Standard C++ exception"); } }; TEST_F(CxxExceptionInTearDownTest, ThrowsExceptionInTearDown) {} class CxxExceptionInTestBodyTest : public Test { public: static void TearDownTestCase() { printf("%s", "CxxExceptionInTestBodyTest::TearDownTestCase() " "called as expected.\n"); } protected: ~CxxExceptionInTestBodyTest() { printf("%s", "CxxExceptionInTestBodyTest destructor " "called as expected.\n"); } virtual void TearDown() { printf("%s", "CxxExceptionInTestBodyTest::TearDown() " "called as expected.\n"); } }; TEST_F(CxxExceptionInTestBodyTest, ThrowsStdCxxException) { throw std::runtime_error("Standard C++ exception"); } TEST(CxxExceptionTest, ThrowsNonStdCxxException) { throw "C-string"; } // This terminate handler aborts the program using exit() rather than abort(). // This avoids showing pop-ups on Windows systems and core dumps on Unix-like // ones. void TerminateHandler() { fprintf(stderr, "%s\n", "Unhandled C++ exception terminating the program."); fflush(NULL); exit(3); } #endif // GTEST_HAS_EXCEPTIONS int main(int argc, char** argv) { #if GTEST_HAS_EXCEPTIONS std::set_terminate(&TerminateHandler); #endif testing::InitGoogleTest(&argc, argv); return RUN_ALL_TESTS(); } assimp-4.1.0/contrib/gtest/test/production.cc0000644002537200234200000000330413213503245021516 0ustar zmoelnigiemusers// 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) {} assimp-4.1.0/contrib/gtest/test/gtest_repeat_test.cc0000644002537200234200000002000113213503245023046 0ustar zmoelnigiemusers// 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 #include #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";\ ::testing::internal::posix::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(::testing::internal::posix::Abort(), ""); GTEST_FLAG(death_test_style) = "fast"; EXPECT_DEATH_IF_SUPPORTED(::testing::internal::posix::Abort(), ""); } #if GTEST_HAS_PARAM_TEST int g_param_test_count = 0; const int kNumberOfParamTests = 10; class MyParamTest : public testing::TestWithParam {}; 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; } assimp-4.1.0/contrib/gtest/test/gtest-typed-test_test.cc0000644002537200234200000003005713213503245023622 0ustar zmoelnigiemusers// 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 "test/gtest-typed-test_test.h" #include #include #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 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 doesn't compile cleanly with /W4. typedef std::vector Vector; typedef std::set 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 T* CommonTest::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 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(2), this->value_); } // Tests that multiple TYPED_TEST_CASE's can be defined in the same // translation unit. template 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 class TypedTest2 : public Test { }; // Verifies that the second argument of TYPED_TEST_CASE can be a // Types<...> type list. TYPED_TEST_CASE(TypedTest2, Types); // 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 class NumericTest : public Test { }; typedef Types 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 class DerivedTest : public CommonTest { }; 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 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 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 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); // 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); // 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::set > 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 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 NumericTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, NumericTest, NumericTypes); static const char* GetTestName() { return testing::UnitTest::GetInstance()->current_test_info()->name(); } // Test the stripping of space from test names template class TrimmedTest : public Test { }; TYPED_TEST_CASE_P(TrimmedTest); TYPED_TEST_P(TrimmedTest, Test1) { EXPECT_STREQ("Test1", GetTestName()); } TYPED_TEST_P(TrimmedTest, Test2) { EXPECT_STREQ("Test2", GetTestName()); } TYPED_TEST_P(TrimmedTest, Test3) { EXPECT_STREQ("Test3", GetTestName()); } TYPED_TEST_P(TrimmedTest, Test4) { EXPECT_STREQ("Test4", GetTestName()); } TYPED_TEST_P(TrimmedTest, Test5) { EXPECT_STREQ("Test5", GetTestName()); } REGISTER_TYPED_TEST_CASE_P( TrimmedTest, Test1, Test2,Test3 , Test4 ,Test5 ); // NOLINT template struct MyPair {}; // Be sure to try a type with a comma in its name just in case it matters. typedef Types > TrimTypes; INSTANTIATE_TYPED_TEST_CASE_P(My, TrimmedTest, TrimTypes); } // 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) assimp-4.1.0/contrib/gtest/test/gtest-options_test.cc0000644002537200234200000001740213213503245023212 0ustar zmoelnigiemusers// 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 #elif GTEST_OS_WINDOWS # include #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_EQ(GetAbsolutePathOf(FilePath("test_detail.xml")).string(), UnitTestOptions::GetAbsolutePathToOutputFile()); } TEST(XmlOutputTest, GetOutputFileSingleFile) { GTEST_FLAG(output) = "xml:filename.abc"; EXPECT_EQ(GetAbsolutePathOf(FilePath("filename.abc")).string(), UnitTestOptions::GetAbsolutePathToOutputFile()); } 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().string() + ".xml")).string(); const std::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().string(); #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_NE(original_working_dir_.string(), FilePath::GetCurrentDir().string()); } virtual void TearDown() { posix::ChDir(original_working_dir_.string().c_str()); } FilePath original_working_dir_; }; TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefault) { GTEST_FLAG(output) = ""; EXPECT_EQ(FilePath::ConcatPaths(original_working_dir_, FilePath("test_detail.xml")).string(), UnitTestOptions::GetAbsolutePathToOutputFile()); } TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithDefaultXML) { GTEST_FLAG(output) = "xml"; EXPECT_EQ(FilePath::ConcatPaths(original_working_dir_, FilePath("test_detail.xml")).string(), UnitTestOptions::GetAbsolutePathToOutputFile()); } TEST_F(XmlOutputChangeDirTest, PreserveOriginalWorkingDirWithRelativeFile) { GTEST_FLAG(output) = "xml:filename.abc"; EXPECT_EQ(FilePath::ConcatPaths(original_working_dir_, FilePath("filename.abc")).string(), UnitTestOptions::GetAbsolutePathToOutputFile()); } 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().string() + ".xml")).string(); const std::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_EQ(FilePath("c:\\tmp\\filename.abc").string(), UnitTestOptions::GetAbsolutePathToOutputFile()); #else GTEST_FLAG(output) ="xml:/tmp/filename.abc"; EXPECT_EQ(FilePath("/tmp/filename.abc").string(), UnitTestOptions::GetAbsolutePathToOutputFile()); #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().string() + ".xml"; const std::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 assimp-4.1.0/contrib/gtest/LICENSE0000644002537200234200000000270313213503245017051 0ustar zmoelnigiemusersCopyright 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. assimp-4.1.0/contrib/gtest/CMakeLists.txt0000644002537200234200000002436113213503245020610 0ustar zmoelnigiemusers######################################################################## # CMake build script for Google Test. # # 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'. # BUILD_SHARED_LIBS is a standard CMake variable, but we declare it here to # make it prominent in the GUI. option(BUILD_SHARED_LIBS "Build shared libraries (DLLs)." OFF) # When other libraries are using a shared version of runtime libraries, # Google Test also has to use one. option( gtest_force_shared_crt "Use shared (DLL) run-time lib even when Google Test is built as static lib." OFF) option(gtest_build_tests "Build all of gtest's own tests." OFF) option(gtest_build_samples "Build gtest's sample programs." OFF) option(gtest_disable_pthreads "Disable uses of pthreads in gtest." OFF) option( gtest_hide_internal_symbols "Build gtest with internal symbols hidden in shared libraries." OFF) # Defines pre_project_set_up_hermetic_build() and set_up_hermetic_build(). include(cmake/hermetic_build.cmake OPTIONAL) if (COMMAND pre_project_set_up_hermetic_build) pre_project_set_up_hermetic_build() 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.2) if (COMMAND set_up_hermetic_build) set_up_hermetic_build() endif() if (gtest_hide_internal_symbols) set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) endif() # Define helper functions and macros used by Google Test. include(cmake/internal_utils.cmake) config_compiler_and_linker() # Defined in internal_utils.cmake. # Where Google Test's .h files can be found. include_directories( ${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) # Where Google Test's libraries can be found. link_directories(${gtest_BINARY_DIR}/src) # Summary of tuple support for Microsoft Visual Studio: # Compiler version(MS) version(cmake) Support # ---------- ----------- -------------- ----------------------------- # <= VS 2010 <= 10 <= 1600 Use Google Tests's own tuple. # VS 2012 11 1700 std::tr1::tuple + _VARIADIC_MAX=10 # VS 2013 12 1800 std::tr1::tuple if (MSVC AND MSVC_VERSION EQUAL 1700) add_definitions(/D _VARIADIC_MAX=10) endif() ######################################################################## # # Defines the gtest & gtest_main libraries. User tests should link # with one of them. # 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_library(gtest "${cxx_strict}" src/gtest-all.cc) cxx_library(gtest_main "${cxx_strict}" src/gtest_main.cc) target_link_libraries(gtest_main gtest) # If the CMake version supports it, attach header directory information # to the targets for when we are part of a parent build (ie being pulled # in via add_subdirectory() rather than being a standalone build). if (DEFINED CMAKE_VERSION AND NOT "${CMAKE_VERSION}" VERSION_LESS "2.8.11") target_include_directories(gtest INTERFACE "${gtest_SOURCE_DIR}/include") target_include_directories(gtest_main INTERFACE "${gtest_SOURCE_DIR}/include") endif() ######################################################################## # # Install rules install(TARGETS gtest gtest_main DESTINATION lib) install(DIRECTORY ${gtest_SOURCE_DIR}/include/gtest DESTINATION include) ######################################################################## # # Samples on how to link user tests with gtest or gtest_main. # # They are not built by default. To build them, set the # gtest_build_samples option to ON. You can do it by running ccmake # or specifying the -Dgtest_build_samples=ON flag when running cmake. if (gtest_build_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. # # The tests are not built by default. To build them, set the # gtest_build_tests option to ON. You can do it by running ccmake # or specifying the -Dgtest_build_tests=ON flag when running cmake. if (gtest_build_tests) # This must be set in the root directory for the tests to be run by # 'make test' or ctest. enable_testing() ############################################################ # C++ tests built with standard compiler flags. 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_premature_exit_test gtest test/gtest_premature_exit_test.cc) cxx_test(gtest-printers_test 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 gtest_main) cxx_test(gtest-unittest-api_test gtest) ############################################################ # C++ tests built with non-standard compiler flags. # MSVC 7.1 does not support STL with exceptions disabled. if (NOT MSVC OR MSVC_VERSION GREATER 1310) cxx_library(gtest_no_exception "${cxx_no_exception}" src/gtest-all.cc) cxx_library(gtest_main_no_exception "${cxx_no_exception}" src/gtest-all.cc src/gtest_main.cc) endif() cxx_library(gtest_main_no_rtti "${cxx_no_rtti}" src/gtest-all.cc src/gtest_main.cc) cxx_test_with_flags(gtest-death-test_ex_nocatch_test "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=0" gtest test/gtest-death-test_ex_test.cc) cxx_test_with_flags(gtest-death-test_ex_catch_test "${cxx_exception} -DGTEST_ENABLE_CATCH_EXCEPTIONS_=1" gtest test/gtest-death-test_ex_test.cc) cxx_test_with_flags(gtest_no_rtti_unittest "${cxx_no_rtti}" gtest_main_no_rtti test/gtest_unittest.cc) cxx_shared_library(gtest_dll "${cxx_default}" src/gtest-all.cc src/gtest_main.cc) cxx_executable_with_flags(gtest_dll_test_ "${cxx_default}" gtest_dll test/gtest_all_test.cc) set_target_properties(gtest_dll_test_ PROPERTIES COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") if (NOT MSVC OR MSVC_VERSION LESS 1600) # 1600 is Visual Studio 2010. # Visual Studio 2010, 2012, and 2013 define symbols in std::tr1 that # conflict with our own definitions. Therefore using our own tuple does not # work on those compilers. 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() ############################################################ # Python tests. cxx_executable(gtest_break_on_failure_unittest_ test gtest) py_test(gtest_break_on_failure_unittest) # Visual Studio .NET 2003 does not support STL with exceptions disabled. if (NOT MSVC OR MSVC_VERSION GREATER 1310) # 1310 is Visual Studio .NET 2003 cxx_executable_with_flags( gtest_catch_exceptions_no_ex_test_ "${cxx_no_exception}" gtest_main_no_exception test/gtest_catch_exceptions_test_.cc) endif() cxx_executable_with_flags( gtest_catch_exceptions_ex_test_ "${cxx_exception}" gtest_main test/gtest_catch_exceptions_test_.cc) py_test(gtest_catch_exceptions_test) 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) # MSVC 7.1 does not support STL with exceptions disabled. if (NOT MSVC OR MSVC_VERSION GREATER 1310) 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) endif() 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() assimp-4.1.0/contrib/gtest/CONTRIBUTORS0000644002537200234200000000251613213503245017726 0ustar zmoelnigiemusers# 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 Balázs Dán Bharat Mediratta Chandler Carruth Chris Prince Chris Taylor Dan Egnor Eric Roman Hady Zalek Jeffrey Yasskin Jói Sigurðsson Keir Mierle Keith Ray Kenton Varda Manuel Klimek Markus Heule Mika Raento Miklós Fazekas Pasi Valminen Patrick Hanna Patrick Riley Peter Kaminski Preston Jackson Rainer Klaffenboeck Russ Cox Russ Rufer Sean Mcafee Sigurður Ásgeirsson Tracy Bialik Vadim Berman Vlad Losev Zhanyong Wan assimp-4.1.0/contrib/gtest/Makefile.am0000644002537200234200000002330413213503245020100 0ustar zmoelnigiemusers# Automake file ACLOCAL_AMFLAGS = -I m4 # Nonstandard package files for distribution EXTRA_DIST = \ CHANGES \ CONTRIBUTORS \ LICENSE \ include/gtest/gtest-param-test.h.pump \ include/gtest/internal/gtest-param-util-generated.h.pump \ include/gtest/internal/gtest-tuple.h.pump \ include/gtest/internal/gtest-type-util.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-death-test.cc \ src/gtest-filepath.cc \ src/gtest-internal-inl.h \ src/gtest-port.cc \ src/gtest-printers.cc \ src/gtest-test-part.cc \ src/gtest-typed-test.cc \ src/gtest.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_ex_test.cc \ test/gtest-death-test_test.cc \ test/gtest-filepath_test.cc \ test/gtest-linked_ptr_test.cc \ test/gtest-listener_test.cc \ test/gtest-message_test.cc \ test/gtest-options_test.cc \ test/gtest-param-test2_test.cc \ test/gtest-param-test2_test.cc \ test/gtest-param-test_test.cc \ test/gtest-param-test_test.cc \ test/gtest-param-test_test.h \ test/gtest-port_test.cc \ test/gtest_premature_exit_test.cc \ test/gtest-printers_test.cc \ test/gtest-test-part_test.cc \ test/gtest-tuple_test.cc \ test/gtest-typed-test2_test.cc \ test/gtest-typed-test_test.cc \ test/gtest-typed-test_test.h \ test/gtest-unittest-api_test.cc \ test/gtest_break_on_failure_unittest_.cc \ test/gtest_catch_exceptions_test_.cc \ test/gtest_color_test_.cc \ test/gtest_env_var_test_.cc \ test/gtest_environment_test.cc \ test/gtest_filter_unittest_.cc \ test/gtest_help_test_.cc \ test/gtest_list_tests_unittest_.cc \ test/gtest_main_unittest.cc \ test/gtest_no_test_unittest.cc \ test/gtest_output_test_.cc \ test/gtest_pred_impl_unittest.cc \ test/gtest_prod_test.cc \ test/gtest_repeat_test.cc \ test/gtest_shuffle_test_.cc \ test/gtest_sole_header_test.cc \ test/gtest_stress_test.cc \ test/gtest_throw_on_failure_ex_test.cc \ test/gtest_throw_on_failure_test_.cc \ test/gtest_uninitialized_test_.cc \ test/gtest_unittest.cc \ test/gtest_unittest.cc \ test/gtest_xml_outfile1_test_.cc \ test/gtest_xml_outfile2_test_.cc \ test/gtest_xml_output_unittest_.cc \ test/production.cc \ test/production.h # Python tests that we don't run. EXTRA_DIST += \ test/gtest_break_on_failure_unittest.py \ test/gtest_catch_exceptions_test.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_shuffle_test.py \ test/gtest_test_utils.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/gtest_xml_test_utils.py # CMake script EXTRA_DIST += \ CMakeLists.txt \ cmake/internal_utils.cmake # MSVC project files EXTRA_DIST += \ msvc/gtest-md.sln \ msvc/gtest-md.vcproj \ msvc/gtest.sln \ 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/runtests.sh \ xcode/Scripts/versiongenerate.py \ xcode/gtest.xcodeproj/project.pbxproj # xcode sample files EXTRA_DIST += \ xcode/Samples/FrameworkSample/Info.plist \ xcode/Samples/FrameworkSample/WidgetFramework.xcodeproj/project.pbxproj \ xcode/Samples/FrameworkSample/runtests.sh \ xcode/Samples/FrameworkSample/widget.cc \ xcode/Samples/FrameworkSample/widget.h \ xcode/Samples/FrameworkSample/widget_test.cc # C++Builder project files EXTRA_DIST += \ codegear/gtest.cbproj \ codegear/gtest.groupproj \ codegear/gtest_all.cc \ codegear/gtest_link.cc \ codegear/gtest_main.cbproj \ codegear/gtest_unittest.cbproj # 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-death-test.h \ include/gtest/gtest-message.h \ include/gtest/gtest-param-test.h \ include/gtest/gtest-printers.h \ include/gtest/gtest-spi.h \ include/gtest/gtest-test-part.h \ include/gtest/gtest-typed-test.h \ include/gtest/gtest.h \ include/gtest/gtest_pred_impl.h \ include/gtest/gtest_prod.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-port-arch.h \ include/gtest/internal/gtest-string.h \ include/gtest/internal/gtest-tuple.h \ include/gtest/internal/gtest-type-util.h \ include/gtest/internal/custom/gtest.h \ include/gtest/internal/custom/gtest-port.h \ include/gtest/internal/custom/gtest-printers.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 \ lib/libgtest.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 # and libgtest work. 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 \ lib/libgtest.la # Tests that fused gtest files compile and work. FUSED_GTEST_SRC = \ fused-src/gtest/gtest-all.cc \ fused-src/gtest/gtest.h \ fused-src/gtest/gtest_main.cc if HAVE_PYTHON 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" endif # Death tests may produce core dumps in the build directory. In case # this happens, clean them to keep distcleancheck happy. CLEANFILES = core # Disables 'make install' as installing a compiled version of Google # Test can lead to undefined behavior due to violation of the # One-Definition Rule. install-exec-local: echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system." false install-data-local: echo "'make install' is dangerous and not supported. Instead, see README for how to integrate Google Test into your build system." false assimp-4.1.0/contrib/gtest/cmake/0000755002537200234200000000000013213503245017122 5ustar zmoelnigiemusersassimp-4.1.0/contrib/gtest/cmake/internal_utils.cmake0000644002537200234200000002526613213503245023173 0ustar zmoelnigiemusers# Defines functions and macros useful for building Google Test and # Google Mock. # # Note: # # - This file will be run twice when building Google Mock (once via # Google Test's CMakeLists.txt, and once via Google Mock's). # Therefore it shouldn't have any side effects other than defining # the functions and macros. # # - The functions/macros defined in this file may depend on Google # Test and Google Mock's option() definitions, and thus must be # called *after* the options have been defined. # Tweaks CMake's default compiler/linker settings to suit Google Test's needs. # # This must be a macro(), as inside a function string() can only # update variables in the function scope. macro(fix_default_compiler_settings_) 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) if (NOT BUILD_SHARED_LIBS AND NOT gtest_force_shared_crt) # When Google Test is built as a shared library, it should also use # shared runtime libraries. Otherwise, it may end up with multiple # copies of runtime library data in different modules, resulting in # hard-to-find crashes. When it is built as a static library, it is # preferable to use CRT as static libraries, as we don't have to rely # on CRT DLLs being available. CMake always defaults to using shared # CRT libraries, so we override that default here. string(REPLACE "/MD" "-MT" ${flag_var} "${${flag_var}}") endif() # 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() endmacro() # Defines the compiler/linker flags used to build Google Test and # Google Mock. You can tweak these definitions to suit your need. A # variable's value is empty before it's explicitly assigned to. macro(config_compiler_and_linker) if (NOT gtest_disable_pthreads) # Defines CMAKE_USE_PTHREADS_INIT and CMAKE_THREAD_LIBS_INIT. find_package(Threads) endif() fix_default_compiler_settings_() if (MSVC) # Newlines inside flags variables break CMake's NMake generator. # TODO(vladl@google.com): Add -RTCs and -RTCu to debug builds. set(cxx_base_flags "-GS -W4 -WX -wd4251 -wd4275 -nologo -J -Zi") if (MSVC_VERSION LESS 1400) # 1400 is Visual Studio 2005 # Suppress spurious warnings MSVC 7.1 sometimes issues. # Forcing value to bool. set(cxx_base_flags "${cxx_base_flags} -wd4800") # Copy constructor and assignment operator could not be generated. set(cxx_base_flags "${cxx_base_flags} -wd4511 -wd4512") # Compatibility warnings not applicable to Google Test. # Resolved overload was found by argument-dependent lookup. set(cxx_base_flags "${cxx_base_flags} -wd4675") endif() if (MSVC_VERSION LESS 1500) # 1500 is Visual Studio 2008 # Conditional expression is constant. # When compiling with /W4, we get several instances of C4127 # (Conditional expression is constant). In our code, we disable that # warning on a case-by-case basis. However, on Visual Studio 2005, # the warning fires on std::list. Therefore on that compiler and earlier, # we disable the warning project-wide. set(cxx_base_flags "${cxx_base_flags} -wd4127") endif() if (NOT (MSVC_VERSION LESS 1700)) # 1700 is Visual Studio 2012. # Suppress "unreachable code" warning on VS 2012 and later. # http://stackoverflow.com/questions/3232669 explains the issue. set(cxx_base_flags "${cxx_base_flags} -wd4702") endif() if (NOT (MSVC_VERSION GREATER 1900)) # 1900 is Visual Studio 2015 # BigObj required for tests. set(cxx_base_flags "${cxx_base_flags} -bigobj") endif() 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 -Wno-unused-parameter -Wno-missing-field-initializers") 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") elseif (CMAKE_CXX_COMPILER_ID STREQUAL "HP") set(cxx_base_flags "-AA -mt") set(cxx_exception_flags "-DGTEST_HAS_EXCEPTIONS=1") set(cxx_no_exception_flags "+noeh -DGTEST_HAS_EXCEPTIONS=0") # RTTI can not be disabled in HP aCC compiler. set(cxx_no_rtti_flags "") endif() if (CMAKE_USE_PTHREADS_INIT) # The pthreads library is available and allowed. set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=1") else() set(cxx_base_flags "${cxx_base_flags} -DGTEST_HAS_PTHREAD=0") 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}") endmacro() # 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 (BUILD_SHARED_LIBS OR type STREQUAL "SHARED") set_target_properties(${name} PROPERTIES COMPILE_DEFINITIONS "GTEST_CREATE_SHARED_LIBRARY=1") endif() if (CMAKE_USE_PTHREADS_INIT) target_link_libraries(${name} ${CMAKE_THREAD_LIBS_INIT}) endif() endfunction() ######################################################################## # # Helper functions for creating build targets. function(cxx_shared_library name cxx_flags) cxx_library_with_type(${name} SHARED "${cxx_flags}" ${ARGN}) endfunction() function(cxx_library name cxx_flags) cxx_library_with_type(${name} "" "${cxx_flags}" ${ARGN}) endfunction() # cxx_executable_with_flags(name cxx_flags libs srcs...) # # creates a named C++ executable that depends on the given libraries and # is built from the given source files with the given compiler flags. function(cxx_executable_with_flags name cxx_flags libs) add_executable(${name} ${ARGN}) if (cxx_flags) set_target_properties(${name} PROPERTIES COMPILE_FLAGS "${cxx_flags}") endif() if (BUILD_SHARED_LIBS) set_target_properties(${name} PROPERTIES COMPILE_DEFINITIONS "GTEST_LINKED_AS_SHARED_LIBRARY=1") endif() # 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() endfunction() # cxx_executable(name dir lib srcs...) # # creates a named target that depends on the given libs and is built # from the given source files. dir/name.cc is implicitly included in # the source file list. function(cxx_executable name dir libs) cxx_executable_with_flags( ${name} "${cxx_default}" "${libs}" "${dir}/${name}.cc" ${ARGN}) endfunction() # Sets PYTHONINTERP_FOUND and PYTHON_EXECUTABLE. find_package(PythonInterp) # 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) cxx_executable_with_flags(${name} "${cxx_flags}" "${libs}" ${ARGN}) 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() # 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) # We are not supporting Python tests on Linux yet as they consider # all Linux environments to be google3 and try to use google3 features. if (PYTHONINTERP_FOUND) # ${CMAKE_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 ), so # we have to escape $ to delay variable substitution here. if (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.1) add_test( NAME ${name} COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py --build_dir=${CMAKE_CURRENT_BINARY_DIR}/$) else (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.1) add_test( ${name} ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/test/${name}.py --build_dir=${CMAKE_CURRENT_BINARY_DIR}/\${CTEST_CONFIGURATION_TYPE}) endif (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 3.1) endif() endfunction() assimp-4.1.0/contrib/utf8cpp/0000755002537200234200000000000013213503245016305 5ustar zmoelnigiemusersassimp-4.1.0/contrib/utf8cpp/source/0000755002537200234200000000000013213503245017605 5ustar zmoelnigiemusersassimp-4.1.0/contrib/utf8cpp/source/utf8.h0000644002537200234200000000276113213503245020652 0ustar zmoelnigiemusers// Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include "utf8/checked.h" #include "utf8/unchecked.h" #endif // header guard assimp-4.1.0/contrib/utf8cpp/source/utf8/0000755002537200234200000000000013213503245020473 5ustar zmoelnigiemusersassimp-4.1.0/contrib/utf8cpp/source/utf8/core.h0000644002537200234200000002471113213503245021601 0ustar zmoelnigiemusers// Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include namespace utf8 { // The typedefs for 8-bit, 16-bit and 32-bit unsigned integers // You may need to change them to match your system. // These typedefs have the same names as ones from cstdint, or boost/cstdint typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; // Helper code - not intended to be directly called by the library users. May be changed at any time namespace internal { // Unicode constants // Leading (high) surrogates: 0xd800 - 0xdbff // Trailing (low) surrogates: 0xdc00 - 0xdfff const uint16_t LEAD_SURROGATE_MIN = 0xd800u; const uint16_t LEAD_SURROGATE_MAX = 0xdbffu; const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u; const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu; const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10); const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN; // Maximum valid value for a Unicode code point const uint32_t CODE_POINT_MAX = 0x0010ffffu; template inline uint8_t mask8(octet_type oc) { return static_cast(0xff & oc); } template inline uint16_t mask16(u16_type oc) { return static_cast(0xffff & oc); } template inline bool is_trail(octet_type oc) { return ((utf8::internal::mask8(oc) >> 6) == 0x2); } template inline bool is_lead_surrogate(u16 cp) { return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); } template inline bool is_trail_surrogate(u16 cp) { return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); } template inline bool is_surrogate(u16 cp) { return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); } template inline bool is_code_point_valid(u32 cp) { return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); } template inline typename std::iterator_traits::difference_type sequence_length(octet_iterator lead_it) { uint8_t lead = utf8::internal::mask8(*lead_it); if (lead < 0x80) return 1; else if ((lead >> 5) == 0x6) return 2; else if ((lead >> 4) == 0xe) return 3; else if ((lead >> 3) == 0x1e) return 4; else return 0; } template inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length) { if (cp < 0x80) { if (length != 1) return true; } else if (cp < 0x800) { if (length != 2) return true; } else if (cp < 0x10000) { if (length != 3) return true; } return false; } enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT}; /// Helper for get_sequence_x template utf_error increase_safely(octet_iterator& it, octet_iterator end) { if (++it == end) return NOT_ENOUGH_ROOM; if (!utf8::internal::is_trail(*it)) return INCOMPLETE_SEQUENCE; return UTF8_OK; } #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;} /// get_sequence_x functions decode utf-8 sequences of the length x template utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; code_point = utf8::internal::mask8(*it); return UTF8_OK; } template utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; code_point = utf8::internal::mask8(*it); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f); return UTF8_OK; } template utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; code_point = utf8::internal::mask8(*it); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point += (*it) & 0x3f; return UTF8_OK; } template utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point) { if (it == end) return NOT_ENOUGH_ROOM; code_point = utf8::internal::mask8(*it); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point += (utf8::internal::mask8(*it) << 6) & 0xfff; UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end) code_point += (*it) & 0x3f; return UTF8_OK; } #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR template utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point) { // Save the original value of it so we can go back in case of failure // Of course, it does not make much sense with i.e. stream iterators octet_iterator original_it = it; uint32_t cp = 0; // Determine the sequence length based on the lead octet typedef typename std::iterator_traits::difference_type octet_difference_type; const octet_difference_type length = utf8::internal::sequence_length(it); // Get trail octets and calculate the code point utf_error err = UTF8_OK; switch (length) { case 0: return INVALID_LEAD; case 1: err = utf8::internal::get_sequence_1(it, end, cp); break; case 2: err = utf8::internal::get_sequence_2(it, end, cp); break; case 3: err = utf8::internal::get_sequence_3(it, end, cp); break; case 4: err = utf8::internal::get_sequence_4(it, end, cp); break; } if (err == UTF8_OK) { // Decoding succeeded. Now, security checks... if (utf8::internal::is_code_point_valid(cp)) { if (!utf8::internal::is_overlong_sequence(cp, length)){ // Passed! Return here. code_point = cp; ++it; return UTF8_OK; } else err = OVERLONG_SEQUENCE; } else err = INVALID_CODE_POINT; } // Failure branch - restore the original value of the iterator it = original_it; return err; } template inline utf_error validate_next(octet_iterator& it, octet_iterator end) { uint32_t ignored; return utf8::internal::validate_next(it, end, ignored); } } // namespace internal /// The library API - functions intended to be called by the users // Byte order mark const uint8_t bom[] = {0xef, 0xbb, 0xbf}; template octet_iterator find_invalid(octet_iterator start, octet_iterator end) { octet_iterator result = start; while (result != end) { utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end); if (err_code != internal::UTF8_OK) return result; } return result; } template inline bool is_valid(octet_iterator start, octet_iterator end) { return (utf8::find_invalid(start, end) == end); } template inline bool starts_with_bom (octet_iterator it, octet_iterator end) { return ( ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) && ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) && ((it != end) && (utf8::internal::mask8(*it)) == bom[2]) ); } //Deprecated in release 2.3 template inline bool is_bom (octet_iterator it) { return ( (utf8::internal::mask8(*it++)) == bom[0] && (utf8::internal::mask8(*it++)) == bom[1] && (utf8::internal::mask8(*it)) == bom[2] ); } } // namespace utf8 #endif // header guard assimp-4.1.0/contrib/utf8cpp/source/utf8/checked.h0000644002537200234200000002761413213503245022244 0ustar zmoelnigiemusers// Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include "core.h" #include namespace utf8 { // Base for the exceptions that may be thrown from the library class exception : public ::std::exception { }; // Exceptions that may be thrown from the library functions. class invalid_code_point : public exception { uint32_t cp; public: invalid_code_point(uint32_t cp) : cp(cp) {} virtual const char* what() const throw() { return "Invalid code point"; } uint32_t code_point() const {return cp;} }; class invalid_utf8 : public exception { uint8_t u8; public: invalid_utf8 (uint8_t u) : u8(u) {} virtual const char* what() const throw() { return "Invalid UTF-8"; } uint8_t utf8_octet() const {return u8;} }; class invalid_utf16 : public exception { uint16_t u16; public: invalid_utf16 (uint16_t u) : u16(u) {} virtual const char* what() const throw() { return "Invalid UTF-16"; } uint16_t utf16_word() const {return u16;} }; class not_enough_room : public exception { public: virtual const char* what() const throw() { return "Not enough space"; } }; /// The library API - functions intended to be called by the users template octet_iterator append(uint32_t cp, octet_iterator result) { if (!utf8::internal::is_code_point_valid(cp)) throw invalid_code_point(cp); if (cp < 0x80) // one octet *(result++) = static_cast(cp); else if (cp < 0x800) { // two octets *(result++) = static_cast((cp >> 6) | 0xc0); *(result++) = static_cast((cp & 0x3f) | 0x80); } else if (cp < 0x10000) { // three octets *(result++) = static_cast((cp >> 12) | 0xe0); *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast((cp & 0x3f) | 0x80); } else { // four octets *(result++) = static_cast((cp >> 18) | 0xf0); *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast((cp & 0x3f) | 0x80); } return result; } template output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement) { while (start != end) { octet_iterator sequence_start = start; internal::utf_error err_code = utf8::internal::validate_next(start, end); switch (err_code) { case internal::UTF8_OK : for (octet_iterator it = sequence_start; it != start; ++it) *out++ = *it; break; case internal::NOT_ENOUGH_ROOM: throw not_enough_room(); case internal::INVALID_LEAD: out = utf8::append (replacement, out); ++start; break; case internal::INCOMPLETE_SEQUENCE: case internal::OVERLONG_SEQUENCE: case internal::INVALID_CODE_POINT: out = utf8::append (replacement, out); ++start; // just one replacement mark for the sequence while (start != end && utf8::internal::is_trail(*start)) ++start; break; } } return out; } template inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out) { static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd); return utf8::replace_invalid(start, end, out, replacement_marker); } template uint32_t next(octet_iterator& it, octet_iterator end) { uint32_t cp = 0; internal::utf_error err_code = utf8::internal::validate_next(it, end, cp); switch (err_code) { case internal::UTF8_OK : break; case internal::NOT_ENOUGH_ROOM : throw not_enough_room(); case internal::INVALID_LEAD : case internal::INCOMPLETE_SEQUENCE : case internal::OVERLONG_SEQUENCE : throw invalid_utf8(*it); case internal::INVALID_CODE_POINT : throw invalid_code_point(cp); } return cp; } template uint32_t peek_next(octet_iterator it, octet_iterator end) { return utf8::next(it, end); } template uint32_t prior(octet_iterator& it, octet_iterator start) { // can't do much if it == start if (it == start) throw not_enough_room(); octet_iterator end = it; // Go back until we hit either a lead octet or start while (utf8::internal::is_trail(*(--it))) if (it == start) throw invalid_utf8(*it); // error - no lead byte in the sequence return utf8::peek_next(it, end); } /// Deprecated in versions that include "prior" template uint32_t previous(octet_iterator& it, octet_iterator pass_start) { octet_iterator end = it; while (utf8::internal::is_trail(*(--it))) if (it == pass_start) throw invalid_utf8(*it); // error - no lead byte in the sequence octet_iterator temp = it; return utf8::next(temp, end); } template void advance (octet_iterator& it, distance_type n, octet_iterator end) { for (distance_type i = 0; i < n; ++i) utf8::next(it, end); } template typename std::iterator_traits::difference_type distance (octet_iterator first, octet_iterator last) { typename std::iterator_traits::difference_type dist; for (dist = 0; first < last; ++dist) utf8::next(first, last); return dist; } template octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) { while (start != end) { uint32_t cp = utf8::internal::mask16(*start++); // Take care of surrogate pairs first if (utf8::internal::is_lead_surrogate(cp)) { if (start != end) { uint32_t trail_surrogate = utf8::internal::mask16(*start++); if (utf8::internal::is_trail_surrogate(trail_surrogate)) cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; else throw invalid_utf16(static_cast(trail_surrogate)); } else throw invalid_utf16(static_cast(cp)); } // Lone trail surrogate else if (utf8::internal::is_trail_surrogate(cp)) throw invalid_utf16(static_cast(cp)); result = utf8::append(cp, result); } return result; } template u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) { while (start != end) { uint32_t cp = utf8::next(start, end); if (cp > 0xffff) { //make a surrogate pair *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); } else *result++ = static_cast(cp); } return result; } template octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) { while (start != end) result = utf8::append(*(start++), result); return result; } template u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) { while (start != end) (*result++) = utf8::next(start, end); return result; } // The iterator class template class iterator : public std::iterator { octet_iterator it; octet_iterator range_start; octet_iterator range_end; public: iterator () {} explicit iterator (const octet_iterator& octet_it, const octet_iterator& range_start, const octet_iterator& range_end) : it(octet_it), range_start(range_start), range_end(range_end) { if (it < range_start || it > range_end) throw std::out_of_range("Invalid utf-8 iterator position"); } // the default "big three" are OK octet_iterator base () const { return it; } uint32_t operator * () const { octet_iterator temp = it; return utf8::next(temp, range_end); } bool operator == (const iterator& rhs) const { if (range_start != rhs.range_start || range_end != rhs.range_end) throw std::logic_error("Comparing utf-8 iterators defined with different ranges"); return (it == rhs.it); } bool operator != (const iterator& rhs) const { return !(operator == (rhs)); } iterator& operator ++ () { utf8::next(it, range_end); return *this; } iterator operator ++ (int) { iterator temp = *this; utf8::next(it, range_end); return temp; } iterator& operator -- () { utf8::prior(it, range_start); return *this; } iterator operator -- (int) { iterator temp = *this; utf8::prior(it, range_start); return temp; } }; // class iterator } // namespace utf8 #endif //header guard assimp-4.1.0/contrib/utf8cpp/source/utf8/unchecked.h0000644002537200234200000002131313213503245022575 0ustar zmoelnigiemusers// Copyright 2006 Nemanja Trifunovic /* Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731 #include "core.h" namespace utf8 { namespace unchecked { template octet_iterator append(uint32_t cp, octet_iterator result) { if (cp < 0x80) // one octet *(result++) = static_cast(cp); else if (cp < 0x800) { // two octets *(result++) = static_cast((cp >> 6) | 0xc0); *(result++) = static_cast((cp & 0x3f) | 0x80); } else if (cp < 0x10000) { // three octets *(result++) = static_cast((cp >> 12) | 0xe0); *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast((cp & 0x3f) | 0x80); } else { // four octets *(result++) = static_cast((cp >> 18) | 0xf0); *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); *(result++) = static_cast((cp & 0x3f) | 0x80); } return result; } template uint32_t next(octet_iterator& it) { uint32_t cp = utf8::internal::mask8(*it); typename std::iterator_traits::difference_type length = utf8::internal::sequence_length(it); switch (length) { case 1: break; case 2: it++; cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f); break; case 3: ++it; cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff); ++it; cp += (*it) & 0x3f; break; case 4: ++it; cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff); ++it; cp += (utf8::internal::mask8(*it) << 6) & 0xfff; ++it; cp += (*it) & 0x3f; break; } ++it; return cp; } template uint32_t peek_next(octet_iterator it) { return utf8::unchecked::next(it); } template uint32_t prior(octet_iterator& it) { while (utf8::internal::is_trail(*(--it))) ; octet_iterator temp = it; return utf8::unchecked::next(temp); } // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous) template inline uint32_t previous(octet_iterator& it) { return utf8::unchecked::prior(it); } template void advance (octet_iterator& it, distance_type n) { for (distance_type i = 0; i < n; ++i) utf8::unchecked::next(it); } template typename std::iterator_traits::difference_type distance (octet_iterator first, octet_iterator last) { typename std::iterator_traits::difference_type dist; for (dist = 0; first < last; ++dist) utf8::unchecked::next(first); return dist; } template octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result) { while (start != end) { uint32_t cp = utf8::internal::mask16(*start++); // Take care of surrogate pairs first if (utf8::internal::is_lead_surrogate(cp)) { uint32_t trail_surrogate = utf8::internal::mask16(*start++); cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET; } result = utf8::unchecked::append(cp, result); } return result; } template u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result) { while (start < end) { uint32_t cp = utf8::unchecked::next(start); if (cp > 0xffff) { //make a surrogate pair *result++ = static_cast((cp >> 10) + internal::LEAD_OFFSET); *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); } else *result++ = static_cast(cp); } return result; } template octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) { while (start != end) result = utf8::unchecked::append(*(start++), result); return result; } template u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result) { while (start < end) (*result++) = utf8::unchecked::next(start); return result; } // The iterator class template class iterator : public std::iterator { octet_iterator it; public: iterator () {} explicit iterator (const octet_iterator& octet_it): it(octet_it) {} // the default "big three" are OK octet_iterator base () const { return it; } uint32_t operator * () const { octet_iterator temp = it; return utf8::unchecked::next(temp); } bool operator == (const iterator& rhs) const { return (it == rhs.it); } bool operator != (const iterator& rhs) const { return !(operator == (rhs)); } iterator& operator ++ () { ::std::advance(it, utf8::internal::sequence_length(it)); return *this; } iterator operator ++ (int) { iterator temp = *this; ::std::advance(it, utf8::internal::sequence_length(it)); return temp; } iterator& operator -- () { utf8::unchecked::prior(it); return *this; } iterator operator -- (int) { iterator temp = *this; utf8::unchecked::prior(it); return temp; } }; // class iterator } // namespace utf8::unchecked } // namespace utf8 #endif // header guard assimp-4.1.0/contrib/utf8cpp/doc/0000755002537200234200000000000013213503245017052 5ustar zmoelnigiemusersassimp-4.1.0/contrib/utf8cpp/doc/ReleaseNotes0000644002537200234200000000066013213503245021370 0ustar zmoelnigiemusersutf8 cpp library Release 2.3.4 A minor bug fix release. Thanks to all who reported bugs. Note: Version 2.3.3 contained a regression, and therefore was removed. Changes from version 2.3.2 - Bug fix [39]: checked.h Line 273 and unchecked.h Line 182 have an extra ';' - Bug fix [36]: replace_invalid() only works with back_inserter Files included in the release: utf8.h, core.h, checked.h, unchecked.h, utf8cpp.html, ReleaseNotes assimp-4.1.0/contrib/utf8cpp/doc/utf8cpp.html0000644002537200234200000021513413213503245021337 0ustar zmoelnigiemusers UTF8-CPP: UTF-8 with C++ in a Portable Way

UTF8-CPP: UTF-8 with C++ in a Portable Way

The Sourceforge project page

Introduction

Many C++ developers miss an easy and portable way of handling Unicode encoded strings. The original C++ Standard (known as C++98 or C++03) is Unicode agnostic. C++11 provides some support for Unicode on core language and library level: u8, u, and U character and string literals, char16_t and char32_t character types, u16string and u32string library classes, and codecvt support for conversions between Unicode encoding forms. In the meantime, developers use third party libraries like ICU, OS specific capabilities, or simply roll out their own solutions.

In order to easily handle UTF-8 encoded Unicode strings, I came up with a small generic library. For anybody used to work with STL algorithms and iterators, it should be easy and natural to use. The code is freely available for any purpose - check out the license at the beginning of the utf8.h file. If you run into bugs or performance issues, please let me know and I'll do my best to address them.

The purpose of this article is not to offer an introduction to Unicode in general, and UTF-8 in particular. If you are not familiar with Unicode, be sure to check out Unicode Home Page or some other source of information for Unicode. Also, it is not my aim to advocate the use of UTF-8 encoded strings in C++ programs; if you want to handle UTF-8 encoded strings from C++, I am sure you have good reasons for it.

Examples of use

Introductionary Sample

To illustrate the use of the library, let's start with a small but complete program that opens a file containing UTF-8 encoded text, reads it line by line, checks each line for invalid UTF-8 byte sequences, and converts it to UTF-16 encoding and back to UTF-8:

#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include "utf8.h"
using namespace std;
int main(int argc, char** argv)
{
    if (argc != 2) {
        cout << "\nUsage: docsample filename\n";
        return 0;
    }

    const char* test_file_path = argv[1];
    // Open the test file (contains UTF-8 encoded text)
    ifstream fs8(test_file_path);
    if (!fs8.is_open()) {
    cout << "Could not open " << test_file_path << endl;
    return 0;
    }

    unsigned line_count = 1;
    string line;
    // Play with all the lines in the file
    while (getline(fs8, line)) {
       // check for invalid utf-8 (for a simple yes/no check, there is also utf8::is_valid function)
        string::iterator end_it = utf8::find_invalid(line.begin(), line.end());
        if (end_it != line.end()) {
            cout << "Invalid UTF-8 encoding detected at line " << line_count << "\n";
            cout << "This part is fine: " << string(line.begin(), end_it) << "\n";
        }

        // Get the line length (at least for the valid part)
        int length = utf8::distance(line.begin(), end_it);
        cout << "Length of line " << line_count << " is " << length <<  "\n";

        // Convert it to utf-16
        vector<unsigned short> utf16line;
        utf8::utf8to16(line.begin(), end_it, back_inserter(utf16line));

        // And back to utf-8
        string utf8line; 
        utf8::utf16to8(utf16line.begin(), utf16line.end(), back_inserter(utf8line));

        // Confirm that the conversion went OK:
        if (utf8line != string(line.begin(), end_it))
            cout << "Error in UTF-16 conversion at line: " << line_count << "\n";        

        line_count++;
    }
    return 0;
}

In the previous code sample, for each line we performed a detection of invalid UTF-8 sequences with find_invalid; the number of characters (more precisely - the number of Unicode code points, including the end of line and even BOM if there is one) in each line was determined with a use of utf8::distance; finally, we have converted each line to UTF-16 encoding with utf8to16 and back to UTF-8 with utf16to8.

Checking if a file contains valid UTF-8 text

Here is a function that checks whether the content of a file is valid UTF-8 encoded text without reading the content into the memory:

    
bool valid_utf8_file(iconst char* file_name)
{
    ifstream ifs(file_name);
    if (!ifs)
        return false; // even better, throw here

    istreambuf_iterator<char> it(ifs.rdbuf());
    istreambuf_iterator<char> eos;

    return utf8::is_valid(it, eos);
}

Because the function utf8::is_valid() works with input iterators, we were able to pass an istreambuf_iterator to it and read the content of the file directly without loading it to the memory first.

Note that other functions that take input iterator arguments can be used in a similar way. For instance, to read the content of a UTF-8 encoded text file and convert the text to UTF-16, just do something like:

    utf8::utf8to16(it, eos, back_inserter(u16string));

Ensure that a string contains valid UTF-8 text

If we have some text that "probably" contains UTF-8 encoded text and we want to replace any invalid UTF-8 sequence with a replacement character, something like the following function may be used:

void fix_utf8_string(std::string& str)
{
    std::string temp;
    utf8::replace_invalid(str.begin(), str.end(), back_inserter(temp));
    str = temp;
}

The function will replace any invalid UTF-8 sequence with a Unicode replacement character. There is an overloaded function that enables the caller to supply their own replacement character.

Reference

Functions From utf8 Namespace

utf8::append

Available in version 1.0 and later.

Encodes a 32 bit code point as a UTF-8 sequence of octets and appends the sequence to a UTF-8 string.

template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result);
   

octet_iterator: an output iterator.
cp: a 32 bit integer representing a code point to append to the sequence.
result: an output iterator to the place in the sequence where to append the code point.
Return value: an iterator pointing to the place after the newly appended sequence.

Example of use:

unsigned char u[5] = {0,0,0,0,0};
unsigned char* end = append(0x0448, u);
assert (u[0] == 0xd1 && u[1] == 0x88 && u[2] == 0 && u[3] == 0 && u[4] == 0);

Note that append does not allocate any memory - it is the burden of the caller to make sure there is enough memory allocated for the operation. To make things more interesting, append can add anywhere between 1 and 4 octets to the sequence. In practice, you would most often want to use std::back_inserter to ensure that the necessary memory is allocated.

In case of an invalid code point, a utf8::invalid_code_point exception is thrown.

utf8::next

Available in version 1.0 and later.

Given the iterator to the beginning of the UTF-8 sequence, it returns the code point and moves the iterator to the next position.

template <typename octet_iterator> 
uint32_t next(octet_iterator& it, octet_iterator end);
   

octet_iterator: an input iterator.
it: a reference to an iterator pointing to the beginning of an UTF-8 encoded code point. After the function returns, it is incremented to point to the beginning of the next code point.
end: end of the UTF-8 sequence to be processed. If it gets equal to end during the extraction of a code point, an utf8::not_enough_room exception is thrown.
Return value: the 32 bit representation of the processed UTF-8 code point.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
char* w = twochars;
int cp = next(w, twochars + 6);
assert (cp == 0x65e5);
assert (w == twochars + 3);

This function is typically used to iterate through a UTF-8 encoded string.

In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is thrown.

utf8::peek_next

Available in version 2.1 and later.

Given the iterator to the beginning of the UTF-8 sequence, it returns the code point for the following sequence without changing the value of the iterator.

template <typename octet_iterator> 
uint32_t peek_next(octet_iterator it, octet_iterator end);
   

octet_iterator: an input iterator.
it: an iterator pointing to the beginning of an UTF-8 encoded code point.
end: end of the UTF-8 sequence to be processed. If it gets equal to end during the extraction of a code point, an utf8::not_enough_room exception is thrown.
Return value: the 32 bit representation of the processed UTF-8 code point.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
char* w = twochars;
int cp = peek_next(w, twochars + 6);
assert (cp == 0x65e5);
assert (w == twochars);

In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is thrown.

utf8::prior

Available in version 1.02 and later.

Given a reference to an iterator pointing to an octet in a UTF-8 sequence, it decreases the iterator until it hits the beginning of the previous UTF-8 encoded code point and returns the 32 bits representation of the code point.

template <typename octet_iterator> 
uint32_t prior(octet_iterator& it, octet_iterator start);
   

octet_iterator: a bidirectional iterator.
it: a reference pointing to an octet within a UTF-8 encoded string. After the function returns, it is decremented to point to the beginning of the previous code point.
start: an iterator to the beginning of the sequence where the search for the beginning of a code point is performed. It is a safety measure to prevent passing the beginning of the string in the search for a UTF-8 lead octet.
Return value: the 32 bit representation of the previous code point.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
unsigned char* w = twochars + 3;
int cp = prior (w, twochars);
assert (cp == 0x65e5);
assert (w == twochars);

This function has two purposes: one is two iterate backwards through a UTF-8 encoded string. Note that it is usually a better idea to iterate forward instead, since utf8::next is faster. The second purpose is to find a beginning of a UTF-8 sequence if we have a random position within a string. Note that in that case utf8::prior may not detect an invalid UTF-8 sequence in some scenarios: for instance if there are superfluous trail octets, it will just skip them.

it will typically point to the beginning of a code point, and start will point to the beginning of the string to ensure we don't go backwards too far. it is decreased until it points to a lead UTF-8 octet, and then the UTF-8 sequence beginning with that octet is decoded to a 32 bit representation and returned.

In case start is reached before a UTF-8 lead octet is hit, or if an invalid UTF-8 sequence is started by the lead octet, an invalid_utf8 exception is thrown.

In case start equals it, a not_enough_room exception is thrown.

utf8::previous

Deprecated in version 1.02 and later.

Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it decreases the iterator until it hits the beginning of the previous UTF-8 encoded code point and returns the 32 bits representation of the code point.

template <typename octet_iterator> 
uint32_t previous(octet_iterator& it, octet_iterator pass_start);
   

octet_iterator: a random access iterator.
it: a reference pointing to an octet within a UTF-8 encoded string. After the function returns, it is decremented to point to the beginning of the previous code point.
pass_start: an iterator to the point in the sequence where the search for the beginning of a code point is aborted if no result was reached. It is a safety measure to prevent passing the beginning of the string in the search for a UTF-8 lead octet.
Return value: the 32 bit representation of the previous code point.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
unsigned char* w = twochars + 3;
int cp = previous (w, twochars - 1);
assert (cp == 0x65e5);
assert (w == twochars);

utf8::previous is deprecated, and utf8::prior should be used instead, although the existing code can continue using this function. The problem is the parameter pass_start that points to the position just before the beginning of the sequence. Standard containers don't have the concept of "pass start" and the function can not be used with their iterators.

it will typically point to the beginning of a code point, and pass_start will point to the octet just before the beginning of the string to ensure we don't go backwards too far. it is decreased until it points to a lead UTF-8 octet, and then the UTF-8 sequence beginning with that octet is decoded to a 32 bit representation and returned.

In case pass_start is reached before a UTF-8 lead octet is hit, or if an invalid UTF-8 sequence is started by the lead octet, an invalid_utf8 exception is thrown

utf8::advance

Available in version 1.0 and later.

Advances an iterator by the specified number of code points within an UTF-8 sequence.

template <typename octet_iterator, typename distance_type> 
void advance (octet_iterator& it, distance_type n, octet_iterator end);
   

octet_iterator: an input iterator.
distance_type: an integral type convertible to octet_iterator's difference type.
it: a reference to an iterator pointing to the beginning of an UTF-8 encoded code point. After the function returns, it is incremented to point to the nth following code point.
n: a positive integer that shows how many code points we want to advance.
end: end of the UTF-8 sequence to be processed. If it gets equal to end during the extraction of a code point, an utf8::not_enough_room exception is thrown.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
unsigned char* w = twochars;
advance (w, 2, twochars + 6);
assert (w == twochars + 5);

This function works only "forward". In case of a negative n, there is no effect.

In case of an invalid code point, a utf8::invalid_code_point exception is thrown.

utf8::distance

Available in version 1.0 and later.

Given the iterators to two UTF-8 encoded code points in a seqence, returns the number of code points between them.

template <typename octet_iterator> 
typename std::iterator_traits<octet_iterator>::difference_type distance (octet_iterator first, octet_iterator last);
   

octet_iterator: an input iterator.
first: an iterator to a beginning of a UTF-8 encoded code point.
last: an iterator to a "post-end" of the last UTF-8 encoded code point in the sequence we are trying to determine the length. It can be the beginning of a new code point, or not.
Return value the distance between the iterators, in code points.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
size_t dist = utf8::distance(twochars, twochars + 5);
assert (dist == 2);

This function is used to find the length (in code points) of a UTF-8 encoded string. The reason it is called distance, rather than, say, length is mainly because developers are used that length is an O(1) function. Computing the length of an UTF-8 string is a linear operation, and it looked better to model it after std::distance algorithm.

In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is thrown. If last does not point to the past-of-end of a UTF-8 seqence, a utf8::not_enough_room exception is thrown.

utf8::utf16to8

Available in version 1.0 and later.

Converts a UTF-16 encoded string to UTF-8.

template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result);
   

u16bit_iterator: an input iterator.
octet_iterator: an output iterator.
start: an iterator pointing to the beginning of the UTF-16 encoded string to convert.
end: an iterator pointing to pass-the-end of the UTF-16 encoded string to convert.
result: an output iterator to the place in the UTF-8 string where to append the result of conversion.
Return value: An iterator pointing to the place after the appended UTF-8 string.

Example of use:

unsigned short utf16string[] = {0x41, 0x0448, 0x65e5, 0xd834, 0xdd1e};
vector<unsigned char> utf8result;
utf16to8(utf16string, utf16string + 5, back_inserter(utf8result));
assert (utf8result.size() == 10);    

In case of invalid UTF-16 sequence, a utf8::invalid_utf16 exception is thrown.

utf8::utf8to16

Available in version 1.0 and later.

Converts an UTF-8 encoded string to UTF-16

template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result);
   

octet_iterator: an input iterator.
u16bit_iterator: an output iterator.
start: an iterator pointing to the beginning of the UTF-8 encoded string to convert. < br /> end: an iterator pointing to pass-the-end of the UTF-8 encoded string to convert.
result: an output iterator to the place in the UTF-16 string where to append the result of conversion.
Return value: An iterator pointing to the place after the appended UTF-16 string.

Example of use:

char utf8_with_surrogates[] = "\xe6\x97\xa5\xd1\x88\xf0\x9d\x84\x9e";
vector <unsigned short> utf16result;
utf8to16(utf8_with_surrogates, utf8_with_surrogates + 9, back_inserter(utf16result));
assert (utf16result.size() == 4);
assert (utf16result[2] == 0xd834);
assert (utf16result[3] == 0xdd1e);

In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is thrown. If end does not point to the past-of-end of a UTF-8 seqence, a utf8::not_enough_room exception is thrown.

utf8::utf32to8

Available in version 1.0 and later.

Converts a UTF-32 encoded string to UTF-8.

template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result);
   

octet_iterator: an output iterator.
u32bit_iterator: an input iterator.
start: an iterator pointing to the beginning of the UTF-32 encoded string to convert.
end: an iterator pointing to pass-the-end of the UTF-32 encoded string to convert.
result: an output iterator to the place in the UTF-8 string where to append the result of conversion.
Return value: An iterator pointing to the place after the appended UTF-8 string.

Example of use:

int utf32string[] = {0x448, 0x65E5, 0x10346, 0};
vector<unsigned char> utf8result;
utf32to8(utf32string, utf32string + 3, back_inserter(utf8result));
assert (utf8result.size() == 9);

In case of invalid UTF-32 string, a utf8::invalid_code_point exception is thrown.

utf8::utf8to32

Available in version 1.0 and later.

Converts a UTF-8 encoded string to UTF-32.

template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result);
   

octet_iterator: an input iterator.
u32bit_iterator: an output iterator.
start: an iterator pointing to the beginning of the UTF-8 encoded string to convert.
end: an iterator pointing to pass-the-end of the UTF-8 encoded string to convert.
result: an output iterator to the place in the UTF-32 string where to append the result of conversion.
Return value: An iterator pointing to the place after the appended UTF-32 string.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
vector<int> utf32result;
utf8to32(twochars, twochars + 5, back_inserter(utf32result));
assert (utf32result.size() == 2);

In case of an invalid UTF-8 seqence, a utf8::invalid_utf8 exception is thrown. If end does not point to the past-of-end of a UTF-8 seqence, a utf8::not_enough_room exception is thrown.

utf8::find_invalid

Available in version 1.0 and later.

Detects an invalid sequence within a UTF-8 string.

template <typename octet_iterator> 
octet_iterator find_invalid(octet_iterator start, octet_iterator end);

octet_iterator: an input iterator.
start: an iterator pointing to the beginning of the UTF-8 string to test for validity.
end: an iterator pointing to pass-the-end of the UTF-8 string to test for validity.
Return value: an iterator pointing to the first invalid octet in the UTF-8 string. In case none were found, equals end.

Example of use:

char utf_invalid[] = "\xe6\x97\xa5\xd1\x88\xfa";
char* invalid = find_invalid(utf_invalid, utf_invalid + 6);
assert (invalid == utf_invalid + 5);

This function is typically used to make sure a UTF-8 string is valid before processing it with other functions. It is especially important to call it if before doing any of the unchecked operations on it.

utf8::is_valid

Available in version 1.0 and later.

Checks whether a sequence of octets is a valid UTF-8 string.

template <typename octet_iterator> 
bool is_valid(octet_iterator start, octet_iterator end);
   

octet_iterator: an input iterator.
start: an iterator pointing to the beginning of the UTF-8 string to test for validity.
end: an iterator pointing to pass-the-end of the UTF-8 string to test for validity.
Return value: true if the sequence is a valid UTF-8 string; false if not.

Example of use:
char utf_invalid[] = "\xe6\x97\xa5\xd1\x88\xfa";
bool bvalid = is_valid(utf_invalid, utf_invalid + 6);
assert (bvalid == false);

is_valid is a shorthand for find_invalid(start, end) == end;. You may want to use it to make sure that a byte seqence is a valid UTF-8 string without the need to know where it fails if it is not valid.

utf8::replace_invalid

Available in version 2.0 and later.

Replaces all invalid UTF-8 sequences within a string with a replacement marker.

template <typename octet_iterator, typename output_iterator>
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement);
template <typename octet_iterator, typename output_iterator>
output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out);
   

octet_iterator: an input iterator.
output_iterator: an output iterator.
start: an iterator pointing to the beginning of the UTF-8 string to look for invalid UTF-8 sequences.
end: an iterator pointing to pass-the-end of the UTF-8 string to look for invalid UTF-8 sequences.
out: An output iterator to the range where the result of replacement is stored.
replacement: A Unicode code point for the replacement marker. The version without this parameter assumes the value 0xfffd
Return value: An iterator pointing to the place after the UTF-8 string with replaced invalid sequences.

Example of use:

char invalid_sequence[] = "a\x80\xe0\xa0\xc0\xaf\xed\xa0\x80z";
vector<char> replace_invalid_result;
replace_invalid (invalid_sequence, invalid_sequence + sizeof(invalid_sequence), back_inserter(replace_invalid_result), '?');
bvalid = is_valid(replace_invalid_result.begin(), replace_invalid_result.end());
assert (bvalid);
char* fixed_invalid_sequence = "a????z";
assert (std::equal(replace_invalid_result.begin(), replace_invalid_result.end(), fixed_invalid_sequence));

replace_invalid does not perform in-place replacement of invalid sequences. Rather, it produces a copy of the original string with the invalid sequences replaced with a replacement marker. Therefore, out must not be in the [start, end] range.

If end does not point to the past-of-end of a UTF-8 sequence, a utf8::not_enough_room exception is thrown.

utf8::starts_with_bom

Available in version 2.3 and later. Relaces deprecated is_bom() function.

Checks whether an octet sequence starts with a UTF-8 byte order mark (BOM)

template <typename octet_iterator> 
bool starts_with_bom (octet_iterator it, octet_iterator end);

octet_iterator: an input iterator.
it: beginning of the octet sequence to check
end: pass-end of the sequence to check
Return value: true if the sequence starts with a UTF-8 byte order mark; false if not.

Example of use:

unsigned char byte_order_mark[] = {0xef, 0xbb, 0xbf};
bool bbom = starts_with_bom(byte_order_mark, byte_order_mark + sizeof(byte_order_mark));
assert (bbom == true);

The typical use of this function is to check the first three bytes of a file. If they form the UTF-8 BOM, we want to skip them before processing the actual UTF-8 encoded text.

utf8::is_bom

Available in version 1.0 and later. Deprecated in version 2.3. starts_with_bom() should be used instead.

Checks whether a sequence of three octets is a UTF-8 byte order mark (BOM)

template <typename octet_iterator> 
bool is_bom (octet_iterator it);  // Deprecated

octet_iterator: an input iterator.
it: beginning of the 3-octet sequence to check
Return value: true if the sequence is UTF-8 byte order mark; false if not.

Example of use:

unsigned char byte_order_mark[] = {0xef, 0xbb, 0xbf};
bool bbom = is_bom(byte_order_mark);
assert (bbom == true);

The typical use of this function is to check the first three bytes of a file. If they form the UTF-8 BOM, we want to skip them before processing the actual UTF-8 encoded text.

If a sequence is shorter than three bytes, an invalid iterator will be dereferenced. Therefore, this function is deprecated in favor of starts_with_bom()that takes the end of sequence as an argument.

Types From utf8 Namespace

utf8::exception

Available in version 2.3 and later.

Base class for the exceptions thrown by UTF CPP library functions.

class exception : public std::exception {};

Example of use:

try {
  code_that_uses_utf_cpp_library();
}
catch(const utf8::exception& utfcpp_ex) {
  cerr << utfcpp_ex.what();
}

utf8::invalid_code_point

Available in version 1.0 and later.

Thrown by UTF8 CPP functions such as advance and next if an UTF-8 sequence represents and invalid code point.

class invalid_code_point : public exception {
public: 
    uint32_t code_point() const;
};

Member function code_point() can be used to determine the invalid code point that caused the exception to be thrown.

utf8::invalid_utf8

Available in version 1.0 and later.

Thrown by UTF8 CPP functions such as next and prior if an invalid UTF-8 sequence is detected during decoding.

class invalid_utf8 : public exception {
public: 
    uint8_t utf8_octet() const;
};

Member function utf8_octet() can be used to determine the beginning of the byte sequence that caused the exception to be thrown.

utf8::invalid_utf16

Available in version 1.0 and later.

Thrown by UTF8 CPP function utf16to8 if an invalid UTF-16 sequence is detected during decoding.

class invalid_utf16 : public exception {
public: 
    uint16_t utf16_word() const;
};

Member function utf16_word() can be used to determine the UTF-16 code unit that caused the exception to be thrown.

utf8::not_enough_room

Available in version 1.0 and later.

Thrown by UTF8 CPP functions such as next if the end of the decoded UTF-8 sequence was reached before the code point was decoded.

class not_enough_room : public exception {};

utf8::iterator

Available in version 2.0 and later.

Adapts the underlying octet iterator to iterate over the sequence of code points, rather than raw octets.

template <typename octet_iterator>
class iterator;
Member functions
iterator();
the deafult constructor; the underlying octet_iterator is constructed with its default constructor.
explicit iterator (const octet_iterator& octet_it, const octet_iterator& range_start, const octet_iterator& range_end);
a constructor that initializes the underlying octet_iterator with octet_it and sets the range in which the iterator is considered valid.
octet_iterator base () const;
returns the underlying octet_iterator.
uint32_t operator * () const;
decodes the utf-8 sequence the underlying octet_iterator is pointing to and returns the code point.
bool operator == (const iterator& rhs) const;
returns true if the two underlaying iterators are equal.
bool operator != (const iterator& rhs) const;
returns true if the two underlaying iterators are not equal.
iterator& operator ++ ();
the prefix increment - moves the iterator to the next UTF-8 encoded code point.
iterator operator ++ (int);
the postfix increment - moves the iterator to the next UTF-8 encoded code point and returns the current one.
iterator& operator -- ();
the prefix decrement - moves the iterator to the previous UTF-8 encoded code point.
iterator operator -- (int);
the postfix decrement - moves the iterator to the previous UTF-8 encoded code point and returns the current one.

Example of use:

char* threechars = "\xf0\x90\x8d\x86\xe6\x97\xa5\xd1\x88";
utf8::iterator<char*> it(threechars, threechars, threechars + 9);
utf8::iterator<char*> it2 = it;
assert (it2 == it);
assert (*it == 0x10346);
assert (*(++it) == 0x65e5);
assert ((*it++) == 0x65e5);
assert (*it == 0x0448);
assert (it != it2);
utf8::iterator<char*> endit (threechars + 9, threechars, threechars + 9);  
assert (++it == endit);
assert (*(--it) == 0x0448);
assert ((*it--) == 0x0448);
assert (*it == 0x65e5);
assert (--it == utf8::iterator<char*>(threechars, threechars, threechars + 9));
assert (*it == 0x10346);

The purpose of utf8::iterator adapter is to enable easy iteration as well as the use of STL algorithms with UTF-8 encoded strings. Increment and decrement operators are implemented in terms of utf8::next() and utf8::prior() functions.

Note that utf8::iterator adapter is a checked iterator. It operates on the range specified in the constructor; any attempt to go out of that range will result in an exception. Even the comparison operators require both iterator object to be constructed against the same range - otherwise an exception is thrown. Typically, the range will be determined by sequence container functions begin and end, i.e.:

std::string s = "example";
utf8::iterator i (s.begin(), s.begin(), s.end());

Functions From utf8::unchecked Namespace

utf8::unchecked::append

Available in version 1.0 and later.

Encodes a 32 bit code point as a UTF-8 sequence of octets and appends the sequence to a UTF-8 string.

template <typename octet_iterator>
octet_iterator append(uint32_t cp, octet_iterator result);
   

cp: A 32 bit integer representing a code point to append to the sequence.
result: An output iterator to the place in the sequence where to append the code point.
Return value: An iterator pointing to the place after the newly appended sequence.

Example of use:

unsigned char u[5] = {0,0,0,0,0};
unsigned char* end = unchecked::append(0x0448, u);
assert (u[0] == 0xd1 && u[1] == 0x88 && u[2] == 0 && u[3] == 0 && u[4] == 0);

This is a faster but less safe version of utf8::append. It does not check for validity of the supplied code point, and may produce an invalid UTF-8 sequence.

utf8::unchecked::next

Available in version 1.0 and later.

Given the iterator to the beginning of a UTF-8 sequence, it returns the code point and moves the iterator to the next position.

template <typename octet_iterator>
uint32_t next(octet_iterator& it);
   

it: a reference to an iterator pointing to the beginning of an UTF-8 encoded code point. After the function returns, it is incremented to point to the beginning of the next code point.
Return value: the 32 bit representation of the processed UTF-8 code point.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
char* w = twochars;
int cp = unchecked::next(w);
assert (cp == 0x65e5);
assert (w == twochars + 3);

This is a faster but less safe version of utf8::next. It does not check for validity of the supplied UTF-8 sequence.

utf8::unchecked::peek_next

Available in version 2.1 and later.

Given the iterator to the beginning of a UTF-8 sequence, it returns the code point.

template <typename octet_iterator>
uint32_t peek_next(octet_iterator it);
   

it: an iterator pointing to the beginning of an UTF-8 encoded code point.
Return value: the 32 bit representation of the processed UTF-8 code point.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
char* w = twochars;
int cp = unchecked::peek_next(w);
assert (cp == 0x65e5);
assert (w == twochars);

This is a faster but less safe version of utf8::peek_next. It does not check for validity of the supplied UTF-8 sequence.

utf8::unchecked::prior

Available in version 1.02 and later.

Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it decreases the iterator until it hits the beginning of the previous UTF-8 encoded code point and returns the 32 bits representation of the code point.

template <typename octet_iterator>
uint32_t prior(octet_iterator& it);
   

it: a reference pointing to an octet within a UTF-8 encoded string. After the function returns, it is decremented to point to the beginning of the previous code point.
Return value: the 32 bit representation of the previous code point.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
char* w = twochars + 3;
int cp = unchecked::prior (w);
assert (cp == 0x65e5);
assert (w == twochars);

This is a faster but less safe version of utf8::prior. It does not check for validity of the supplied UTF-8 sequence and offers no boundary checking.

utf8::unchecked::previous (deprecated, see utf8::unchecked::prior)

Deprecated in version 1.02 and later.

Given a reference to an iterator pointing to an octet in a UTF-8 seqence, it decreases the iterator until it hits the beginning of the previous UTF-8 encoded code point and returns the 32 bits representation of the code point.

template <typename octet_iterator>
uint32_t previous(octet_iterator& it);
   

it: a reference pointing to an octet within a UTF-8 encoded string. After the function returns, it is decremented to point to the beginning of the previous code point.
Return value: the 32 bit representation of the previous code point.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
char* w = twochars + 3;
int cp = unchecked::previous (w);
assert (cp == 0x65e5);
assert (w == twochars);

The reason this function is deprecated is just the consistency with the "checked" versions, where prior should be used instead of previous. In fact, unchecked::previous behaves exactly the same as unchecked::prior

This is a faster but less safe version of utf8::previous. It does not check for validity of the supplied UTF-8 sequence and offers no boundary checking.

utf8::unchecked::advance

Available in version 1.0 and later.

Advances an iterator by the specified number of code points within an UTF-8 sequence.

template <typename octet_iterator, typename distance_type>
void advance (octet_iterator& it, distance_type n);
   

it: a reference to an iterator pointing to the beginning of an UTF-8 encoded code point. After the function returns, it is incremented to point to the nth following code point.
n: a positive integer that shows how many code points we want to advance.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
char* w = twochars;
unchecked::advance (w, 2);
assert (w == twochars + 5);

This function works only "forward". In case of a negative n, there is no effect.

This is a faster but less safe version of utf8::advance. It does not check for validity of the supplied UTF-8 sequence and offers no boundary checking.

utf8::unchecked::distance

Available in version 1.0 and later.

Given the iterators to two UTF-8 encoded code points in a seqence, returns the number of code points between them.

template <typename octet_iterator>
typename std::iterator_traits<octet_iterator>::difference_type distance (octet_iterator first, octet_iterator last);

first: an iterator to a beginning of a UTF-8 encoded code point.
last: an iterator to a "post-end" of the last UTF-8 encoded code point in the sequence we are trying to determine the length. It can be the beginning of a new code point, or not.
Return value the distance between the iterators, in code points.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
size_t dist = utf8::unchecked::distance(twochars, twochars + 5);
assert (dist == 2);

This is a faster but less safe version of utf8::distance. It does not check for validity of the supplied UTF-8 sequence.

utf8::unchecked::utf16to8

Available in version 1.0 and later.

Converts a UTF-16 encoded string to UTF-8.

template <typename u16bit_iterator, typename octet_iterator>
octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result);
   

start: an iterator pointing to the beginning of the UTF-16 encoded string to convert.
end: an iterator pointing to pass-the-end of the UTF-16 encoded string to convert.
result: an output iterator to the place in the UTF-8 string where to append the result of conversion.
Return value: An iterator pointing to the place after the appended UTF-8 string.

Example of use:

unsigned short utf16string[] = {0x41, 0x0448, 0x65e5, 0xd834, 0xdd1e};
vector<unsigned char> utf8result;
unchecked::utf16to8(utf16string, utf16string + 5, back_inserter(utf8result));
assert (utf8result.size() == 10);    

This is a faster but less safe version of utf8::utf16to8. It does not check for validity of the supplied UTF-16 sequence.

utf8::unchecked::utf8to16

Available in version 1.0 and later.

Converts an UTF-8 encoded string to UTF-16

template <typename u16bit_iterator, typename octet_iterator>
u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result);
   

start: an iterator pointing to the beginning of the UTF-8 encoded string to convert. < br /> end: an iterator pointing to pass-the-end of the UTF-8 encoded string to convert.
result: an output iterator to the place in the UTF-16 string where to append the result of conversion.
Return value: An iterator pointing to the place after the appended UTF-16 string.

Example of use:

char utf8_with_surrogates[] = "\xe6\x97\xa5\xd1\x88\xf0\x9d\x84\x9e";
vector <unsigned short> utf16result;
unchecked::utf8to16(utf8_with_surrogates, utf8_with_surrogates + 9, back_inserter(utf16result));
assert (utf16result.size() == 4);
assert (utf16result[2] == 0xd834);
assert (utf16result[3] == 0xdd1e);

This is a faster but less safe version of utf8::utf8to16. It does not check for validity of the supplied UTF-8 sequence.

utf8::unchecked::utf32to8

Available in version 1.0 and later.

Converts a UTF-32 encoded string to UTF-8.

template <typename octet_iterator, typename u32bit_iterator>
octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result);
   

start: an iterator pointing to the beginning of the UTF-32 encoded string to convert.
end: an iterator pointing to pass-the-end of the UTF-32 encoded string to convert.
result: an output iterator to the place in the UTF-8 string where to append the result of conversion.
Return value: An iterator pointing to the place after the appended UTF-8 string.

Example of use:

int utf32string[] = {0x448, 0x65e5, 0x10346, 0};
vector<unsigned char> utf8result;
utf32to8(utf32string, utf32string + 3, back_inserter(utf8result));
assert (utf8result.size() == 9);

This is a faster but less safe version of utf8::utf32to8. It does not check for validity of the supplied UTF-32 sequence.

utf8::unchecked::utf8to32

Available in version 1.0 and later.

Converts a UTF-8 encoded string to UTF-32.

template <typename octet_iterator, typename u32bit_iterator>
u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result);
   

start: an iterator pointing to the beginning of the UTF-8 encoded string to convert.
end: an iterator pointing to pass-the-end of the UTF-8 encoded string to convert.
result: an output iterator to the place in the UTF-32 string where to append the result of conversion.
Return value: An iterator pointing to the place after the appended UTF-32 string.

Example of use:

char* twochars = "\xe6\x97\xa5\xd1\x88";
vector<int> utf32result;
unchecked::utf8to32(twochars, twochars + 5, back_inserter(utf32result));
assert (utf32result.size() == 2);

This is a faster but less safe version of utf8::utf8to32. It does not check for validity of the supplied UTF-8 sequence.

Types From utf8::unchecked Namespace

utf8::iterator

Available in version 2.0 and later.

Adapts the underlying octet iterator to iterate over the sequence of code points, rather than raw octets.

template <typename octet_iterator>
class iterator;
Member functions
iterator();
the deafult constructor; the underlying octet_iterator is constructed with its default constructor.
explicit iterator (const octet_iterator& octet_it);
a constructor that initializes the underlying octet_iterator with octet_it
octet_iterator base () const;
returns the underlying octet_iterator.
uint32_t operator * () const;
decodes the utf-8 sequence the underlying octet_iterator is pointing to and returns the code point.
bool operator == (const iterator& rhs) const;
returns true if the two underlaying iterators are equal.
bool operator != (const iterator& rhs) const;
returns true if the two underlaying iterators are not equal.
iterator& operator ++ ();
the prefix increment - moves the iterator to the next UTF-8 encoded code point.
iterator operator ++ (int);
the postfix increment - moves the iterator to the next UTF-8 encoded code point and returns the current one.
iterator& operator -- ();
the prefix decrement - moves the iterator to the previous UTF-8 encoded code point.
iterator operator -- (int);
the postfix decrement - moves the iterator to the previous UTF-8 encoded code point and returns the current one.

Example of use:

char* threechars = "\xf0\x90\x8d\x86\xe6\x97\xa5\xd1\x88";
utf8::unchecked::iterator<char*> un_it(threechars);
utf8::unchecked::iterator<char*> un_it2 = un_it;
assert (un_it2 == un_it);
assert (*un_it == 0x10346);
assert (*(++un_it) == 0x65e5);
assert ((*un_it++) == 0x65e5);
assert (*un_it == 0x0448);
assert (un_it != un_it2);
utf8::::unchecked::iterator<char*> un_endit (threechars + 9);  
assert (++un_it == un_endit);
assert (*(--un_it) == 0x0448);
assert ((*un_it--) == 0x0448);
assert (*un_it == 0x65e5);
assert (--un_it == utf8::unchecked::iterator<char*>(threechars));
assert (*un_it == 0x10346);

This is an unchecked version of utf8::iterator. It is faster in many cases, but offers no validity or range checks.

Points of interest

Design goals and decisions

The library was designed to be:

  1. Generic: for better or worse, there are many C++ string classes out there, and the library should work with as many of them as possible.
  2. Portable: the library should be portable both accross different platforms and compilers. The only non-portable code is a small section that declares unsigned integers of different sizes: three typedefs. They can be changed by the users of the library if they don't match their platform. The default setting should work for Windows (both 32 and 64 bit), and most 32 bit and 64 bit Unix derivatives.
  3. Lightweight: follow the "pay only for what you use" guideline.
  4. Unintrusive: avoid forcing any particular design or even programming style on the user. This is a library, not a framework.

Alternatives

In case you want to look into other means of working with UTF-8 strings from C++, here is the list of solutions I am aware of:

  1. ICU Library. It is very powerful, complete, feature-rich, mature, and widely used. Also big, intrusive, non-generic, and doesn't play well with the Standard Library. I definitelly recommend looking at ICU even if you don't plan to use it.
  2. C++11 language and library features. Still far from complete, and not widely supported by compiler vendors.
  3. Glib::ustring. A class specifically made to work with UTF-8 strings, and also feel like std::string. If you prefer to have yet another string class in your code, it may be worth a look. Be aware of the licensing issues, though.
  4. Platform dependent solutions: Windows and POSIX have functions to convert strings from one encoding to another. That is only a subset of what my library offers, but if that is all you need it may be good enough.
  1. The Unicode Consortium.
  2. ICU Library.
  3. UTF-8 at Wikipedia
  4. UTF-8 and Unicode FAQ for Unix/Linux
assimp-4.1.0/contrib/irrXML/0000755002537200234200000000000013213503245016071 5ustar zmoelnigiemusersassimp-4.1.0/contrib/irrXML/heapsort.h0000644002537200234200000000257513213503245020100 0ustar zmoelnigiemusers// Copyright (C) 2002-2005 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #ifndef __IRR_HEAPSORT_H_INCLUDED__ #define __IRR_HEAPSORT_H_INCLUDED__ #include "irrTypes.h" namespace irr { namespace core { //! Sinks an element into the heap. template inline void heapsink(T*array, s32 element, s32 max) { while ((element<<1) < max) // there is a left child { s32 j = (element<<1); if (j+1 < max && array[j] < array[j+1]) j = j+1; // take right child if (array[element] < array[j]) { T t = array[j]; // swap elements array[j] = array[element]; array[element] = t; element = j; } else return; } } //! Sorts an array with size 'size' using heapsort. template inline void heapsort(T* array_, s32 size) { // for heapsink we pretent this is not c++, where // arrays start with index 0. So we decrease the array pointer, // the maximum always +2 and the element always +1 T* virtualArray = array_ - 1; s32 virtualSize = size + 2; s32 i; // build heap for (i=((size-1)/2); i>=0; --i) heapsink(virtualArray, i+1, virtualSize-1); // sort array for (i=size-1; i>=0; --i) { T t = array_[0]; array_[0] = array_[i]; array_[i] = t; heapsink(virtualArray, 1, i + 1); } } } // end namespace core } // end namespace irr #endif assimp-4.1.0/contrib/irrXML/irrXML.h0000644002537200234200000005337613213503245017435 0ustar zmoelnigiemusers// Copyright (C) 2002-2005 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine" and the "irrXML" project. // For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h #ifndef __IRR_XML_H_INCLUDED__ #define __IRR_XML_H_INCLUDED__ #include /** \mainpage irrXML 1.2 API documentation
\section intro Introduction Welcome to the irrXML API documentation. Here you'll find any information you'll need to develop applications with irrXML. If you look for a tutorial on how to start, take a look at the \ref irrxmlexample, at the homepage of irrXML at xml.irrlicht3d.org or into the SDK in the directory \example. irrXML is intended to be a high speed and easy-to-use XML Parser for C++, and this documentation is an important part of it. If you have any questions or suggestions, just send a email to the author of the engine, Nikolaus Gebhardt (niko (at) irrlicht3d.org). For more informations about this parser, see \ref history. \section features Features irrXML provides forward-only, read-only access to a stream of non validated XML data. It was fully implemented by Nikolaus Gebhardt. Its current features are: - It it fast as lighting and has very low memory usage. It was developed with the intention of being used in 3D games, as it already has been. - irrXML is very small: It only consists of 60 KB of code and can be added easily to your existing project. - Of course, it is platform independent and works with lots of compilers. - It is able to parse ASCII, UTF-8, UTF-16 and UTF-32 text files, both in little and big endian format. - Independent of the input file format, the parser can return all strings in ASCII, UTF-8, UTF-16 and UTF-32 format. - With its optional file access abstraction it has the advantage that it can read not only from files but from any type of data (memory, network, ...). For example when used with the Irrlicht Engine, it directly reads from compressed .zip files. - Just like the Irrlicht Engine for which it was originally created, it is extremely easy to use. - It has no external dependencies, it does not even need the STL. Although irrXML has some strenghts, it currently also has the following limitations: - The input xml file is not validated and assumed to be correct. \section irrxmlexample Example The following code demonstrates the basic usage of irrXML. A simple xml file like this is parsed: \code Welcome to the Mesh Viewer of the "Irrlicht Engine". \endcode The code for parsing this file would look like this: \code #include using namespace irr; // irrXML is located in the namespace irr::io using namespace io; #include // we use STL strings to store data in this example void main() { // create the reader using one of the factory functions IrrXMLReader* xml = createIrrXMLReader("config.xml"); // strings for storing the data we want to get out of the file std::string modelFile; std::string messageText; std::string caption; // parse the file until end reached while(xml && xml->read()) { switch(xml->getNodeType()) { case EXN_TEXT: // in this xml file, the only text which occurs is the messageText messageText = xml->getNodeData(); break; case EXN_ELEMENT: { if (!strcmp("model", xml->getNodeName())) modelFile = xml->getAttributeValue("file"); else if (!strcmp("messageText", xml->getNodeName())) caption = xml->getAttributeValue("caption"); } break; } } // delete the xml parser after usage delete xml; } \endcode \section howto How to use Simply add the source files in the /src directory of irrXML to your project. Done. \section license License The irrXML license is based on the zlib license. Basicly, this means you can do with irrXML whatever you want: Copyright (C) 2002-2005 Nikolaus Gebhardt This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. Permission is granted to anyone to use this software for any purpose, including commercial applications, and to alter it and redistribute it freely, subject to the following restrictions: 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required. 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software. 3. This notice may not be removed or altered from any source distribution. \section history History As lots of references in this documentation and the source show, this xml parser has originally been a part of the Irrlicht Engine. But because the parser has become very useful with the latest release, people asked for a separate version of it, to be able to use it in non Irrlicht projects. With irrXML 1.0, this has now been done. */ namespace irr { namespace io { //! Enumeration of all supported source text file formats enum ETEXT_FORMAT { //! ASCII, file without byte order mark, or not a text file ETF_ASCII, //! UTF-8 format ETF_UTF8, //! UTF-16 format, big endian ETF_UTF16_BE, //! UTF-16 format, little endian ETF_UTF16_LE, //! UTF-32 format, big endian ETF_UTF32_BE, //! UTF-32 format, little endian ETF_UTF32_LE }; //! Enumeration for all xml nodes which are parsed by IrrXMLReader enum EXML_NODE { //! No xml node. This is usually the node if you did not read anything yet. EXN_NONE, //! A xml element, like EXN_ELEMENT, //! End of an xml element, like EXN_ELEMENT_END, //! Text within a xml element: this is the text. EXN_TEXT, //! An xml comment like <!-- I am a comment --> or a DTD definition. EXN_COMMENT, //! An xml cdata section like <![CDATA[ this is some CDATA ]]> EXN_CDATA, //! Unknown element. EXN_UNKNOWN }; //! Callback class for file read abstraction. /** With this, it is possible to make the xml parser read in other things than just files. The Irrlicht engine is using this for example to read xml from compressed .zip files. To make the parser read in any other data, derive a class from this interface, implement the two methods to read your data and give a pointer to an instance of your implementation when calling createIrrXMLReader(), createIrrXMLReaderUTF16() or createIrrXMLReaderUTF32() */ class IFileReadCallBack { public: //! virtual destructor virtual ~IFileReadCallBack() {}; //! Reads an amount of bytes from the file. /** \param buffer: Pointer to buffer where to read bytes will be written to. \param sizeToRead: Amount of bytes to read from the file. \return Returns how much bytes were read. */ virtual int read(void* buffer, int sizeToRead) = 0; //! Returns size of file in bytes virtual int getSize() = 0; }; //! Empty class to be used as parent class for IrrXMLReader. /** If you need another class as base class for the xml reader, you can do this by creating the reader using for example new CXMLReaderImpl(yourcallback); The Irrlicht Engine for example needs IUnknown as base class for every object to let it automaticly reference countend, hence it replaces IXMLBase with IUnknown. See irrXML.cpp on how this can be done in detail. */ class IXMLBase { }; //! Interface providing easy read access to a XML file. /** You can create an instance of this reader using one of the factory functions createIrrXMLReader(), createIrrXMLReaderUTF16() and createIrrXMLReaderUTF32(). If using the parser from the Irrlicht Engine, please use IFileSystem::createXMLReader() instead. For a detailed intro how to use the parser, see \ref irrxmlexample and \ref features. The typical usage of this parser looks like this: \code #include using namespace irr; // irrXML is located in the namespace irr::io using namespace io; void main() { // create the reader using one of the factory functions IrrXMLReader* xml = createIrrXMLReader("config.xml"); if (xml == 0) return; // file could not be opened // parse the file until end reached while(xml->read()) { // based on xml->getNodeType(), do something. } // delete the xml parser after usage delete xml; } \endcode See \ref irrxmlexample for a more detailed example. */ template class IIrrXMLReader : public super_class { public: //! Destructor virtual ~IIrrXMLReader() {}; //! Reads forward to the next xml node. /** \return Returns false, if there was no further node. */ virtual bool read() = 0; //! Returns the type of the current XML node. virtual EXML_NODE getNodeType() const = 0; //! Returns attribute count of the current XML node. /** This is usually non null if the current node is EXN_ELEMENT, and the element has attributes. \return Returns amount of attributes of this xml node. */ virtual int getAttributeCount() const = 0; //! Returns name of an attribute. /** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1. \return Name of the attribute, 0 if an attribute with this index does not exist. */ virtual const char_type* getAttributeName(int idx) const = 0; //! Returns the value of an attribute. /** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1. \return Value of the attribute, 0 if an attribute with this index does not exist. */ virtual const char_type* getAttributeValue(int idx) const = 0; //! Returns the value of an attribute. /** \param name: Name of the attribute. \return Value of the attribute, 0 if an attribute with this name does not exist. */ virtual const char_type* getAttributeValue(const char_type* name) const = 0; //! Returns the value of an attribute in a safe way. /** Like getAttributeValue(), but does not return 0 if the attribute does not exist. An empty string ("") is returned then. \param name: Name of the attribute. \return Value of the attribute, and "" if an attribute with this name does not exist */ virtual const char_type* getAttributeValueSafe(const char_type* name) const = 0; //! Returns the value of an attribute as integer. /** \param name Name of the attribute. \return Value of the attribute as integer, and 0 if an attribute with this name does not exist or the value could not be interpreted as integer. */ virtual int getAttributeValueAsInt(const char_type* name) const = 0; //! Returns the value of an attribute as integer. /** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1. \return Value of the attribute as integer, and 0 if an attribute with this index does not exist or the value could not be interpreted as integer. */ virtual int getAttributeValueAsInt(int idx) const = 0; //! Returns the value of an attribute as float. /** \param name: Name of the attribute. \return Value of the attribute as float, and 0 if an attribute with this name does not exist or the value could not be interpreted as float. */ virtual float getAttributeValueAsFloat(const char_type* name) const = 0; //! Returns the value of an attribute as float. /** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1. \return Value of the attribute as float, and 0 if an attribute with this index does not exist or the value could not be interpreted as float. */ virtual float getAttributeValueAsFloat(int idx) const = 0; //! Returns the name of the current node. /** Only non null, if the node type is EXN_ELEMENT. \return Name of the current node or 0 if the node has no name. */ virtual const char_type* getNodeName() const = 0; //! Returns data of the current node. /** Only non null if the node has some data and it is of type EXN_TEXT or EXN_UNKNOWN. */ virtual const char_type* getNodeData() const = 0; //! Returns if an element is an empty element, like virtual bool isEmptyElement() const = 0; //! Returns format of the source xml file. /** It is not necessary to use this method because the parser will convert the input file format to the format wanted by the user when creating the parser. This method is useful to get/display additional informations. */ virtual ETEXT_FORMAT getSourceFormat() const = 0; //! Returns format of the strings returned by the parser. /** This will be UTF8 for example when you created a parser with IrrXMLReaderUTF8() and UTF32 when it has been created using IrrXMLReaderUTF32. It should not be necessary to call this method and only exists for informational purposes. */ virtual ETEXT_FORMAT getParserFormat() const = 0; }; //! defines the utf-16 type. /** Not using wchar_t for this because wchar_t has 16 bit on windows and 32 bit on other operating systems. */ typedef unsigned short char16; //! defines the utf-32 type. /** Not using wchar_t for this because wchar_t has 16 bit on windows and 32 bit on other operating systems. */ typedef unsigned long char32; //! A UTF-8 or ASCII character xml parser. /** This means that all character data will be returned in 8 bit ASCII or UTF-8 by this parser. The file to read can be in any format, it will be converted to UTF-8 if it is not in this format. Create an instance of this with createIrrXMLReader(); See IIrrXMLReader for description on how to use it. */ typedef IIrrXMLReader IrrXMLReader; //! A UTF-16 xml parser. /** This means that all character data will be returned in UTF-16 by this parser. The file to read can be in any format, it will be converted to UTF-16 if it is not in this format. Create an instance of this with createIrrXMLReaderUTF16(); See IIrrXMLReader for description on how to use it. */ typedef IIrrXMLReader IrrXMLReaderUTF16; //! A UTF-32 xml parser. /** This means that all character data will be returned in UTF-32 by this parser. The file to read can be in any format, it will be converted to UTF-32 if it is not in this format. Create an instance of this with createIrrXMLReaderUTF32(); See IIrrXMLReader for description on how to use it. */ typedef IIrrXMLReader IrrXMLReaderUTF32; //! Creates an instance of an UFT-8 or ASCII character xml parser. /** This means that all character data will be returned in 8 bit ASCII or UTF-8. The file to read can be in any format, it will be converted to UTF-8 if it is not in this format. If you are using the Irrlicht Engine, it is better not to use this function but IFileSystem::createXMLReaderUTF8() instead. \param filename: Name of file to be opened. \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ IrrXMLReader* createIrrXMLReader(const char* filename); //! Creates an instance of an UFT-8 or ASCII character xml parser. /** This means that all character data will be returned in 8 bit ASCII or UTF-8. The file to read can be in any format, it will be converted to UTF-8 if it is not in this format. If you are using the Irrlicht Engine, it is better not to use this function but IFileSystem::createXMLReaderUTF8() instead. \param file: Pointer to opened file, must have been opened in binary mode, e.g. using fopen("foo.bar", "wb"); The file will not be closed after it has been read. \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ IrrXMLReader* createIrrXMLReader(FILE* file); //! Creates an instance of an UFT-8 or ASCII character xml parser. /** This means that all character data will be returned in 8 bit ASCII or UTF-8. The file to read can be in any format, it will be converted to UTF-8 if it is not in this format. If you are using the Irrlicht Engine, it is better not to use this function but IFileSystem::createXMLReaderUTF8() instead. \param callback: Callback for file read abstraction. Implement your own callback to make the xml parser read in other things than just files. See IFileReadCallBack for more information about this. \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ IrrXMLReader* createIrrXMLReader(IFileReadCallBack* callback); //! Creates an instance of an UFT-16 xml parser. /** This means that all character data will be returned in UTF-16. The file to read can be in any format, it will be converted to UTF-16 if it is not in this format. If you are using the Irrlicht Engine, it is better not to use this function but IFileSystem::createXMLReader() instead. \param filename: Name of file to be opened. \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ IrrXMLReaderUTF16* createIrrXMLReaderUTF16(const char* filename); //! Creates an instance of an UFT-16 xml parser. /** This means that all character data will be returned in UTF-16. The file to read can be in any format, it will be converted to UTF-16 if it is not in this format. If you are using the Irrlicht Engine, it is better not to use this function but IFileSystem::createXMLReader() instead. \param file: Pointer to opened file, must have been opened in binary mode, e.g. using fopen("foo.bar", "wb"); The file will not be closed after it has been read. \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ IrrXMLReaderUTF16* createIrrXMLReaderUTF16(FILE* file); //! Creates an instance of an UFT-16 xml parser. /** This means that all character data will be returned in UTF-16. The file to read can be in any format, it will be converted to UTF-16 if it is not in this format. If you are using the Irrlicht Engine, it is better not to use this function but IFileSystem::createXMLReader() instead. \param callback: Callback for file read abstraction. Implement your own callback to make the xml parser read in other things than just files. See IFileReadCallBack for more information about this. \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ IrrXMLReaderUTF16* createIrrXMLReaderUTF16(IFileReadCallBack* callback); //! Creates an instance of an UFT-32 xml parser. /** This means that all character data will be returned in UTF-32. The file to read can be in any format, it will be converted to UTF-32 if it is not in this format. If you are using the Irrlicht Engine, it is better not to use this function but IFileSystem::createXMLReader() instead. \param filename: Name of file to be opened. \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ IrrXMLReaderUTF32* createIrrXMLReaderUTF32(const char* filename); //! Creates an instance of an UFT-32 xml parser. /** This means that all character data will be returned in UTF-32. The file to read can be in any format, it will be converted to UTF-32 if it is not in this format. if you are using the Irrlicht Engine, it is better not to use this function but IFileSystem::createXMLReader() instead. \param file: Pointer to opened file, must have been opened in binary mode, e.g. using fopen("foo.bar", "wb"); The file will not be closed after it has been read. \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ IrrXMLReaderUTF32* createIrrXMLReaderUTF32(FILE* file); //! Creates an instance of an UFT-32 xml parser. /** This means that all character data will be returned in UTF-32. The file to read can be in any format, it will be converted to UTF-32 if it is not in this format. If you are using the Irrlicht Engine, it is better not to use this function but IFileSystem::createXMLReader() instead. \param callback: Callback for file read abstraction. Implement your own callback to make the xml parser read in other things than just files. See IFileReadCallBack for more information about this. \return Returns a pointer to the created xml parser. This pointer should be deleted using 'delete' after no longer needed. Returns 0 if an error occured and the file could not be opened. */ IrrXMLReaderUTF32* createIrrXMLReaderUTF32(IFileReadCallBack* callback); /*! \file irrxml.h \brief Header file of the irrXML, the Irrlicht XML parser. This file includes everything needed for using irrXML, the XML parser of the Irrlicht Engine. To use irrXML, you only need to include this file in your project: \code #include \endcode It is also common to use the two namespaces in which irrXML is included, directly after #including irrXML.h: \code #include using namespace irr; using namespace io; \endcode */ } // end namespace io } // end namespace irr #endif // __IRR_XML_H_INCLUDED__ assimp-4.1.0/contrib/irrXML/irrArray.h0000644002537200234200000002235013213503245020037 0ustar zmoelnigiemusers// Copyright (C) 2002-2005 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine" and the "irrXML" project. // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h #ifndef __IRR_ARRAY_H_INCLUDED__ #define __IRR_ARRAY_H_INCLUDED__ #include "irrTypes.h" #include "heapsort.h" namespace irr { namespace core { //! Self reallocating template array (like stl vector) with additional features. /** Some features are: Heap sorting, binary search methods, easier debugging. */ template class array { public: array() : data(0), allocated(0), used(0), free_when_destroyed(true), is_sorted(true) { } //! Constructs a array and allocates an initial chunk of memory. //! \param start_count: Amount of elements to allocate. array(u32 start_count) : data(0), allocated(0), used(0), free_when_destroyed(true), is_sorted(true) { reallocate(start_count); } //! Copy constructor array(const array& other) : data(0) { *this = other; } //! Destructor. Frees allocated memory, if set_free_when_destroyed //! was not set to false by the user before. ~array() { if (free_when_destroyed) delete [] data; } //! Reallocates the array, make it bigger or smaller. //! \param new_size: New size of array. void reallocate(u32 new_size) { T* old_data = data; data = new T[new_size]; allocated = new_size; s32 end = used < new_size ? used : new_size; for (s32 i=0; i allocated) { // reallocate(used * 2 +1); // this doesn't work if the element is in the same array. So // we'll copy the element first to be sure we'll get no data // corruption T e; e = element; // copy element reallocate(used * 2 +1); // increase data block data[used++] = e; // push_back is_sorted = false; return; } data[used++] = element; is_sorted = false; } //! Adds an element at the front of the array. If the array is to small to //! add this new element, the array is made bigger. Please note that this //! is slow, because the whole array needs to be copied for this. //! \param element: Element to add at the back of the array. void push_front(const T& element) { if (used + 1 > allocated) reallocate(used * 2 +1); for (int i=(int)used; i>0; --i) data[i] = data[i-1]; data[0] = element; is_sorted = false; ++used; } //! Insert item into array at specified position. Please use this //! only if you know what you are doing (possible performance loss). //! The preferred method of adding elements should be push_back(). //! \param element: Element to be inserted //! \param index: Where position to insert the new element. void insert(const T& element, u32 index=0) { _IRR_DEBUG_BREAK_IF(index>used) // access violation if (used + 1 > allocated) reallocate(used * 2 +1); for (u32 i=used++; i>index; i--) data[i] = data[i-1]; data[index] = element; is_sorted = false; } //! Clears the array and deletes all allocated memory. void clear() { delete [] data; data = 0; used = 0; allocated = 0; is_sorted = true; } //! Sets pointer to new array, using this as new workspace. //! \param newPointer: Pointer to new array of elements. //! \param size: Size of the new array. void set_pointer(T* newPointer, u32 size) { delete [] data; data = newPointer; allocated = size; used = size; is_sorted = false; } //! Sets if the array should delete the memory it used. //! \param f: If true, the array frees the allocated memory in its //! destructor, otherwise not. The default is true. void set_free_when_destroyed(bool f) { free_when_destroyed = f; } //! Sets the size of the array. //! \param usedNow: Amount of elements now used. void set_used(u32 usedNow) { if (allocated < usedNow) reallocate(usedNow); used = usedNow; } //! Assignement operator void operator=(const array& other) { if (data) delete [] data; //if (allocated < other.allocated) if (other.allocated == 0) data = 0; else data = new T[other.allocated]; used = other.used; free_when_destroyed = other.free_when_destroyed; is_sorted = other.is_sorted; allocated = other.allocated; for (u32 i=0; i=used) // access violation return data[index]; } //! Direct access operator const T& operator [](u32 index) const { _IRR_DEBUG_BREAK_IF(index>=used) // access violation return data[index]; } //! Gets last frame const T& getLast() const { _IRR_DEBUG_BREAK_IF(!used) // access violation return data[used-1]; } //! Gets last frame T& getLast() { _IRR_DEBUG_BREAK_IF(!used) // access violation return data[used-1]; } //! Returns a pointer to the array. //! \return Pointer to the array. T* pointer() { return data; } //! Returns a const pointer to the array. //! \return Pointer to the array. const T* const_pointer() const { return data; } //! Returns size of used array. //! \return Size of elements in the array. u32 size() const { return used; } //! Returns amount memory allocated. //! \return Returns amount of memory allocated. The amount of bytes //! allocated would be allocated_size() * sizeof(ElementsUsed); u32 allocated_size() const { return allocated; } //! Returns true if array is empty //! \return True if the array is empty, false if not. bool empty() const { return used == 0; } //! Sorts the array using heapsort. There is no additional memory waste and //! the algorithm performs (O) n log n in worst case. void sort() { if (is_sorted || used<2) return; heapsort(data, used); is_sorted = true; } //! Performs a binary search for an element, returns -1 if not found. //! The array will be sorted before the binary search if it is not //! already sorted. //! \param element: Element to search for. //! \return Returns position of the searched element if it was found, //! otherwise -1 is returned. s32 binary_search(const T& element) { return binary_search(element, 0, used-1); } //! Performs a binary search for an element, returns -1 if not found. //! The array will be sorted before the binary search if it is not //! already sorted. //! \param element: Element to search for. //! \param left: First left index //! \param right: Last right index. //! \return Returns position of the searched element if it was found, //! otherwise -1 is returned. s32 binary_search(const T& element, s32 left, s32 right) { if (!used) return -1; sort(); s32 m; do { m = (left+right)>>1; if (element < data[m]) right = m - 1; else left = m + 1; } while((element < data[m] || data[m] < element) && left<=right); // this last line equals to: // " while((element != array[m]) && left<=right);" // but we only want to use the '<' operator. // the same in next line, it is "(element == array[m])" if (!(element < data[m]) && !(data[m] < element)) return m; return -1; } //! Finds an element in linear time, which is very slow. Use //! binary_search for faster finding. Only works if =operator is implemented. //! \param element: Element to search for. //! \return Returns position of the searched element if it was found, //! otherwise -1 is returned. s32 linear_search(T& element) { for (u32 i=0; i=0; --i) if (data[i] == element) return (s32)i; return -1; } //! Erases an element from the array. May be slow, because all elements //! following after the erased element have to be copied. //! \param index: Index of element to be erased. void erase(u32 index) { _IRR_DEBUG_BREAK_IF(index>=used || index<0) // access violation for (u32 i=index+1; i=used || index<0 || count<1 || index+count>used) // access violation for (u32 i=index+count; i and string work both with unicode AND ascii, so you can assign unicode to string and ascii to string (and the other way round) if your ever would want to. Note that the conversation between both is not done using an encoding. Known bugs: Special characters like '', '' and '' are ignored in the methods make_upper, make_lower and equals_ignore_case. */ template class string { public: //! Default constructor string() : array(0), allocated(1), used(1) { array = new T[1]; array[0] = 0x0; } //! Constructor string(const string& other) : array(0), allocated(0), used(0) { *this = other; } //! Constructs a string from an int string(int number) : array(0), allocated(0), used(0) { // store if negative and make positive bool negative = false; if (number < 0) { number *= -1; negative = true; } // temporary buffer for 16 numbers c8 tmpbuf[16]; tmpbuf[15] = 0; s32 idx = 15; // special case '0' if (!number) { tmpbuf[14] = '0'; *this = &tmpbuf[14]; return; } // add numbers while(number && idx) { idx--; tmpbuf[idx] = (c8)('0' + (number % 10)); number = number / 10; } // add sign if (negative) { idx--; tmpbuf[idx] = '-'; } *this = &tmpbuf[idx]; } //! Constructor for copying a string from a pointer with a given lenght template string(const B* c, s32 lenght) : array(0), allocated(0), used(0) { if (!c) return; allocated = used = lenght+1; array = new T[used]; for (s32 l = 0; l string(const B* c) : array(0),allocated(0), used(0) { *this = c; } //! destructor ~string() { delete [] array; } //! Assignment operator string& operator=(const string& other) { if (this == &other) return *this; delete [] array; allocated = used = other.size()+1; array = new T[used]; const T* p = other.c_str(); for (s32 i=0; i string& operator=(const B* c) { if (!c) { if (!array) { array = new T[1]; allocated = 1; used = 1; } array[0] = 0x0; return *this; } if ((void*)c == (void*)array) return *this; s32 len = 0; const B* p = c; while(*p) { ++len; ++p; } // we'll take the old string for a while, because the new string could be // a part of the current string. T* oldArray = array; allocated = used = len+1; array = new T[used]; for (s32 l = 0; l operator+(const string& other) { string str(*this); str.append(other); return str; } //! Add operator for strings, ascii and unicode template string operator+(const B* c) { string str(*this); str.append(c); return str; } //! Direct access operator T& operator [](const s32 index) const { _IRR_DEBUG_BREAK_IF(index>=used) // bad index return array[index]; } //! Comparison operator bool operator ==(const T* str) const { int i; for(i=0; array[i] && str[i]; ++i) if (array[i] != str[i]) return false; return !array[i] && !str[i]; } //! Comparison operator bool operator ==(const string& other) const { for(s32 i=0; array[i] && other.array[i]; ++i) if (array[i] != other.array[i]) return false; return used == other.used; } //! Is smaller operator bool operator <(const string& other) const { for(s32 i=0; array[i] && other.array[i]; ++i) if (array[i] != other.array[i]) return (array[i] < other.array[i]); return used < other.used; } //! Equals not operator bool operator !=(const string& other) const { return !(*this == other); } //! Returns length of string /** \return Returns length of the string in characters. */ s32 size() const { return used-1; } //! Returns character string /** \return Returns pointer to C-style zero terminated string. */ const T* c_str() const { return array; } //! Makes the string lower case. void make_lower() { const T A = (T)'A'; const T Z = (T)'Z'; const T diff = (T)'a' - A; for (s32 i=0; i=A && array[i]<=Z) array[i] += diff; } } //! Makes the string upper case. void make_upper() { const T a = (T)'a'; const T z = (T)'z'; const T diff = (T)'A' - a; for (s32 i=0; i=a && array[i]<=z) array[i] += diff; } } //! Compares the string ignoring case. /** \param other: Other string to compare. \return Returns true if the string are equal ignoring case. */ bool equals_ignore_case(const string& other) const { for(s32 i=0; array[i] && other[i]; ++i) if (toLower(array[i]) != toLower(other[i])) return false; return used == other.used; } //! compares the first n characters of the strings bool equalsn(const string& other, int len) { int i; for(i=0; array[i] && other[i] && i < len; ++i) if (array[i] != other[i]) return false; // if one (or both) of the strings was smaller then they // are only equal if they have the same lenght return (i == len) || (used == other.used); } //! compares the first n characters of the strings bool equalsn(const T* str, int len) { int i; for(i=0; array[i] && str[i] && i < len; ++i) if (array[i] != str[i]) return false; // if one (or both) of the strings was smaller then they // are only equal if they have the same lenght return (i == len) || (array[i] == 0 && str[i] == 0); } //! Appends a character to this string /** \param character: Character to append. */ void append(T character) { if (used + 1 > allocated) reallocate((s32)used + 1); used += 1; array[used-2] = character; array[used-1] = 0; } //! Appends a string to this string /** \param other: String to append. */ void append(const string& other) { --used; s32 len = other.size(); if (used + len + 1 > allocated) reallocate((s32)used + (s32)len + 1); for (s32 l=0; l& other, s32 length) { s32 len = other.size(); if (len < length) { append(other); return; } len = length; --used; if (used + len > allocated) reallocate((s32)used + (s32)len); for (s32 l=0; l s32 findFirstCharNotInList(B* c, int count) const { for (int i=0; i s32 findLastCharNotInList(B* c, int count) const { for (int i=used-2; i>=0; --i) { int j; for (j=0; j=0; --i) if (array[i] == c) return i; return -1; } //! Returns a substring //! \param begin: Start of substring. //! \param length: Length of substring. string subString(s32 begin, s32 length) { if (length <= 0) return string(""); string o; o.reserve(length+1); for (s32 i=0; i& other) { append(other); } void operator += (int i) { append(string(i)); } //! replaces all characters of a special type with another one void replace(T toReplace, T replaceWith) { for (s32 i=0; i=used || index<0) // access violation for (int i=index+1; i=(T)'A' && t<=(T)'Z') return t + ((T)'a' - (T)'A'); else return t; } //! Reallocate the array, make it bigger or smaler void reallocate(s32 new_size) { T* old_array = array; array = new T[new_size]; allocated = new_size; s32 amount = used < new_size ? used : new_size; for (s32 i=0; i stringc; //! Typedef for wide character strings typedef string stringw; } // end namespace core } // end namespace irr #endif assimp-4.1.0/contrib/irrXML/irrXML.cpp0000644002537200234200000000642713213503245017763 0ustar zmoelnigiemusers// Copyright (C) 2002-2005 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine" and the "irrXML" project. // For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h // Need to include Assimp, too. We're using Assimp's version of fast_atof // so we need stdint.h. But no PCH. #include "irrXML.h" #include "irrString.h" #include "irrArray.h" #include "./../../code/fast_atof.h" #include "CXMLReaderImpl.h" namespace irr { namespace io { //! Implementation of the file read callback for ordinary files class CFileReadCallBack : public IFileReadCallBack { public: //! construct from filename CFileReadCallBack(const char* filename) : File(0), Size(0), Close(true) { // open file File = fopen(filename, "rb"); if (File) getFileSize(); } //! construct from FILE pointer CFileReadCallBack(FILE* file) : File(file), Size(0), Close(false) { if (File) getFileSize(); } //! destructor virtual ~CFileReadCallBack() { if (Close && File) fclose(File); } //! Reads an amount of bytes from the file. virtual int read(void* buffer, int sizeToRead) { if (!File) return 0; return (int)fread(buffer, 1, sizeToRead, File); } //! Returns size of file in bytes virtual int getSize() { return Size; } private: //! retrieves the file size of the open file void getFileSize() { fseek(File, 0, SEEK_END); Size = ftell(File); fseek(File, 0, SEEK_SET); } FILE* File; int Size; bool Close; }; // end class CFileReadCallBack // FACTORY FUNCTIONS: //! Creates an instance of an UFT-8 or ASCII character xml parser. IrrXMLReader* createIrrXMLReader(const char* filename) { return new CXMLReaderImpl(new CFileReadCallBack(filename)); } //! Creates an instance of an UFT-8 or ASCII character xml parser. IrrXMLReader* createIrrXMLReader(FILE* file) { return new CXMLReaderImpl(new CFileReadCallBack(file)); } //! Creates an instance of an UFT-8 or ASCII character xml parser. IrrXMLReader* createIrrXMLReader(IFileReadCallBack* callback) { return new CXMLReaderImpl(callback, false); } //! Creates an instance of an UTF-16 xml parser. IrrXMLReaderUTF16* createIrrXMLReaderUTF16(const char* filename) { return new CXMLReaderImpl(new CFileReadCallBack(filename)); } //! Creates an instance of an UTF-16 xml parser. IrrXMLReaderUTF16* createIrrXMLReaderUTF16(FILE* file) { return new CXMLReaderImpl(new CFileReadCallBack(file)); } //! Creates an instance of an UTF-16 xml parser. IrrXMLReaderUTF16* createIrrXMLReaderUTF16(IFileReadCallBack* callback) { return new CXMLReaderImpl(callback, false); } //! Creates an instance of an UTF-32 xml parser. IrrXMLReaderUTF32* createIrrXMLReaderUTF32(const char* filename) { return new CXMLReaderImpl(new CFileReadCallBack(filename)); } //! Creates an instance of an UTF-32 xml parser. IrrXMLReaderUTF32* createIrrXMLReaderUTF32(FILE* file) { return new CXMLReaderImpl(new CFileReadCallBack(file)); } //! Creates an instance of an UTF-32 xml parser. IrrXMLReaderUTF32* createIrrXMLReaderUTF32(IFileReadCallBack* callback) { return new CXMLReaderImpl(callback, false); } } // end namespace io } // end namespace irr assimp-4.1.0/contrib/irrXML/CXMLReaderImpl.h0000644002537200234200000004231713213503245020761 0ustar zmoelnigiemusers// Copyright (C) 2002-2005 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine" and the "irrXML" project. // For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h #ifndef __ICXML_READER_IMPL_H_INCLUDED__ #define __ICXML_READER_IMPL_H_INCLUDED__ #include "irrXML.h" #include "irrString.h" #include "irrArray.h" using namespace Assimp; #ifdef _DEBUG #define IRR_DEBUGPRINT(x) printf((x)); #else // _DEBUG #define IRR_DEBUGPRINT(x) #endif // _DEBUG namespace irr { namespace io { //! implementation of the IrrXMLReader template class CXMLReaderImpl : public IIrrXMLReader { public: //! Constructor CXMLReaderImpl(IFileReadCallBack* callback, bool deleteCallBack = true) : TextData(0), P(0), TextBegin(0), TextSize(0), CurrentNodeType(EXN_NONE), SourceFormat(ETF_ASCII), TargetFormat(ETF_ASCII) { if (!callback) return; storeTargetFormat(); // read whole xml file readFile(callback); // clean up if (deleteCallBack) delete callback; // create list with special characters createSpecialCharacterList(); // set pointer to text begin P = TextBegin; } //! Destructor virtual ~CXMLReaderImpl() { delete [] TextData; } //! Reads forward to the next xml node. //! \return Returns false, if there was no further node. virtual bool read() { // if not end reached, parse the node if (P && (unsigned int)(P - TextBegin) < TextSize - 1 && *P != 0) { parseCurrentNode(); return true; } _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; return false; } //! Returns the type of the current XML node. virtual EXML_NODE getNodeType() const { return CurrentNodeType; } //! Returns attribute count of the current XML node. virtual int getAttributeCount() const { return Attributes.size(); } //! Returns name of an attribute. virtual const char_type* getAttributeName(int idx) const { if (idx < 0 || idx >= (int)Attributes.size()) return 0; return Attributes[idx].Name.c_str(); } //! Returns the value of an attribute. virtual const char_type* getAttributeValue(int idx) const { if (idx < 0 || idx >= (int)Attributes.size()) return 0; return Attributes[idx].Value.c_str(); } //! Returns the value of an attribute. virtual const char_type* getAttributeValue(const char_type* name) const { const SAttribute* attr = getAttributeByName(name); if (!attr) return 0; return attr->Value.c_str(); } //! Returns the value of an attribute virtual const char_type* getAttributeValueSafe(const char_type* name) const { const SAttribute* attr = getAttributeByName(name); if (!attr) return EmptyString.c_str(); return attr->Value.c_str(); } //! Returns the value of an attribute as integer. int getAttributeValueAsInt(const char_type* name) const { return (int)getAttributeValueAsFloat(name); } //! Returns the value of an attribute as integer. int getAttributeValueAsInt(int idx) const { return (int)getAttributeValueAsFloat(idx); } //! Returns the value of an attribute as float. float getAttributeValueAsFloat(const char_type* name) const { const SAttribute* attr = getAttributeByName(name); if (!attr) return 0; core::stringc c = attr->Value.c_str(); return fast_atof(c.c_str()); } //! Returns the value of an attribute as float. float getAttributeValueAsFloat(int idx) const { const char_type* attrvalue = getAttributeValue(idx); if (!attrvalue) return 0; core::stringc c = attrvalue; return fast_atof(c.c_str()); } //! Returns the name of the current node. virtual const char_type* getNodeName() const { return NodeName.c_str(); } //! Returns data of the current node. virtual const char_type* getNodeData() const { return NodeName.c_str(); } //! Returns if an element is an empty element, like virtual bool isEmptyElement() const { return IsEmptyElement; } //! Returns format of the source xml file. virtual ETEXT_FORMAT getSourceFormat() const { return SourceFormat; } //! Returns format of the strings returned by the parser. virtual ETEXT_FORMAT getParserFormat() const { return TargetFormat; } private: // Reads the current xml node void parseCurrentNode() { char_type* start = P; // move forward until '<' found while(*P != L'<' && *P) ++P; if (!*P) return; if (P - start > 0) { // we found some text, store it if (setText(start, P)) return; } ++P; // based on current token, parse and report next element switch(*P) { case L'/': parseClosingXMLElement(); break; case L'?': ignoreDefinition(); break; case L'!': if (!parseCDATA()) parseComment(); break; default: parseOpeningXMLElement(); break; } } //! sets the state that text was found. Returns true if set should be set bool setText(char_type* start, char_type* end) { // check if text is more than 2 characters, and if not, check if there is // only white space, so that this text won't be reported if (end - start < 3) { char_type* p = start; for(; p != end; ++p) if (!isWhiteSpace(*p)) break; if (p == end) return false; } // set current text to the parsed text, and replace xml special characters core::string s(start, (int)(end - start)); NodeName = replaceSpecialCharacters(s); // current XML node type is text CurrentNodeType = EXN_TEXT; return true; } //! ignores an xml definition like void ignoreDefinition() { CurrentNodeType = EXN_UNKNOWN; // move until end marked with '>' reached while(*P != L'>') ++P; ++P; } //! parses a comment void parseComment() { CurrentNodeType = EXN_COMMENT; P += 1; char_type *pCommentBegin = P; int count = 1; // move until end of comment reached while(count) { if (*P == L'>') --count; else if (*P == L'<') ++count; ++P; } P -= 3; NodeName = core::string(pCommentBegin+2, (int)(P - pCommentBegin-2)); P += 3; } //! parses an opening xml element and reads attributes void parseOpeningXMLElement() { CurrentNodeType = EXN_ELEMENT; IsEmptyElement = false; Attributes.clear(); // find name const char_type* startName = P; // find end of element while(*P != L'>' && !isWhiteSpace(*P)) ++P; const char_type* endName = P; // find Attributes while(*P != L'>') { if (isWhiteSpace(*P)) ++P; else { if (*P != L'/') { // we've got an attribute // read the attribute names const char_type* attributeNameBegin = P; while(!isWhiteSpace(*P) && *P != L'=') ++P; const char_type* attributeNameEnd = P; ++P; // read the attribute value // check for quotes and single quotes, thx to murphy while( (*P != L'\"') && (*P != L'\'') && *P) ++P; if (!*P) // malformatted xml file return; const char_type attributeQuoteChar = *P; ++P; const char_type* attributeValueBegin = P; while(*P != attributeQuoteChar && *P) ++P; if (!*P) // malformatted xml file return; const char_type* attributeValueEnd = P; ++P; SAttribute attr; attr.Name = core::string(attributeNameBegin, (int)(attributeNameEnd - attributeNameBegin)); core::string s(attributeValueBegin, (int)(attributeValueEnd - attributeValueBegin)); attr.Value = replaceSpecialCharacters(s); Attributes.push_back(attr); } else { // tag is closed directly ++P; IsEmptyElement = true; break; } } } // check if this tag is closing directly if (endName > startName && *(endName-1) == L'/') { // directly closing tag IsEmptyElement = true; endName--; } NodeName = core::string(startName, (int)(endName - startName)); ++P; } //! parses an closing xml tag void parseClosingXMLElement() { CurrentNodeType = EXN_ELEMENT_END; IsEmptyElement = false; Attributes.clear(); ++P; const char_type* pBeginClose = P; while(*P != L'>') ++P; // remove trailing whitespace, if any while( isspace( P[-1])) --P; NodeName = core::string(pBeginClose, (int)(P - pBeginClose)); ++P; } //! parses a possible CDATA section, returns false if begin was not a CDATA section bool parseCDATA() { if (*(P+1) != L'[') return false; CurrentNodeType = EXN_CDATA; // skip '' && (*(P-1) == L']') && (*(P-2) == L']')) { cDataEnd = P - 2; } ++P; } if ( cDataEnd ) NodeName = core::string(cDataBegin, (int)(cDataEnd - cDataBegin)); else NodeName = ""; return true; } // structure for storing attribute-name pairs struct SAttribute { core::string Name; core::string Value; }; // finds a current attribute by name, returns 0 if not found const SAttribute* getAttributeByName(const char_type* name) const { if (!name) return 0; core::string n = name; for (int i=0; i<(int)Attributes.size(); ++i) if (Attributes[i].Name == n) return &Attributes[i]; return 0; } // replaces xml special characters in a string and creates a new one core::string replaceSpecialCharacters( core::string& origstr) { int pos = origstr.findFirst(L'&'); int oldPos = 0; if (pos == -1) return origstr; core::string newstr; while(pos != -1 && pos < origstr.size()-2) { // check if it is one of the special characters int specialChar = -1; for (int i=0; i<(int)SpecialCharacters.size(); ++i) { const char_type* p = &origstr.c_str()[pos]+1; if (equalsn(&SpecialCharacters[i][1], p, SpecialCharacters[i].size()-1)) { specialChar = i; break; } } if (specialChar != -1) { newstr.append(origstr.subString(oldPos, pos - oldPos)); newstr.append(SpecialCharacters[specialChar][0]); pos += SpecialCharacters[specialChar].size(); } else { newstr.append(origstr.subString(oldPos, pos - oldPos + 1)); pos += 1; } // find next & oldPos = pos; pos = origstr.findNext(L'&', pos); } if (oldPos < origstr.size()-1) newstr.append(origstr.subString(oldPos, origstr.size()-oldPos)); return newstr; } //! reads the xml file and converts it into the wanted character format. bool readFile(IFileReadCallBack* callback) { int size = callback->getSize(); size += 4; // We need two terminating 0's at the end. // For ASCII we need 1 0's, for UTF-16 2, for UTF-32 4. char* data8 = new char[size]; if (!callback->read(data8, size-4)) { delete [] data8; return false; } // add zeros at end data8[size-1] = 0; data8[size-2] = 0; data8[size-3] = 0; data8[size-4] = 0; char16* data16 = reinterpret_cast(data8); char32* data32 = reinterpret_cast(data8); // now we need to convert the data to the desired target format // based on the byte order mark. const unsigned char UTF8[] = {0xEF, 0xBB, 0xBF}; // 0xEFBBBF; const int UTF16_BE = 0xFFFE; const int UTF16_LE = 0xFEFF; const int UTF32_BE = 0xFFFE0000; const int UTF32_LE = 0x0000FEFF; // check source for all utf versions and convert to target data format if (size >= 4 && data32[0] == (char32)UTF32_BE) { // UTF-32, big endian SourceFormat = ETF_UTF32_BE; convertTextData(data32+1, data8, (size/4)); // data32+1 because we need to skip the header } else if (size >= 4 && data32[0] == (char32)UTF32_LE) { // UTF-32, little endian SourceFormat = ETF_UTF32_LE; convertTextData(data32+1, data8, (size/4)); // data32+1 because we need to skip the header } else if (size >= 2 && data16[0] == UTF16_BE) { // UTF-16, big endian SourceFormat = ETF_UTF16_BE; convertTextData(data16+1, data8, (size/2)); // data16+1 because we need to skip the header } else if (size >= 2 && data16[0] == UTF16_LE) { // UTF-16, little endian SourceFormat = ETF_UTF16_LE; convertTextData(data16+1, data8, (size/2)); // data16+1 because we need to skip the header } else if (size >= 3 && data8[0] == UTF8[0] && data8[1] == UTF8[1] && data8[2] == UTF8[2]) { // UTF-8 SourceFormat = ETF_UTF8; convertTextData(data8+3, data8, size); // data8+3 because we need to skip the header } else { // ASCII SourceFormat = ETF_ASCII; convertTextData(data8, data8, size); } return true; } //! converts the text file into the desired format. //! \param source: begin of the text (without byte order mark) //! \param pointerToStore: pointer to text data block which can be //! stored or deleted based on the nesessary conversion. //! \param sizeWithoutHeader: Text size in characters without header template void convertTextData(src_char_type* source, char* pointerToStore, int sizeWithoutHeader) { // convert little to big endian if necessary if (sizeof(src_char_type) > 1 && isLittleEndian(TargetFormat) != isLittleEndian(SourceFormat)) convertToLittleEndian(source); // check if conversion is necessary: if (sizeof(src_char_type) == sizeof(char_type)) { // no need to convert TextBegin = (char_type*)source; TextData = (char_type*)pointerToStore; TextSize = sizeWithoutHeader; } else { // convert source into target data format. // TODO: implement a real conversion. This one just // copies bytes. This is a problem when there are // unicode symbols using more than one character. TextData = new char_type[sizeWithoutHeader]; // MSVC debugger complains here about loss of data ... // FIXME - gcc complains about 'shift width larger than width of type' // for T == unsigned long. Avoid it by messing around volatile .. volatile unsigned int c = 3; const src_char_type cc = (src_char_type)((((uint64_t)1u << (sizeof( char_type)< void convertToLittleEndian(src_char_type* t) { if (sizeof(src_char_type) == 4) { // 32 bit while(*t) { *t = ((*t & 0xff000000) >> 24) | ((*t & 0x00ff0000) >> 8) | ((*t & 0x0000ff00) << 8) | ((*t & 0x000000ff) << 24); ++t; } } else { // 16 bit while(*t) { *t = (*t >> 8) | (*t << 8); ++t; } } } //! returns if a format is little endian inline bool isLittleEndian(ETEXT_FORMAT f) { return f == ETF_ASCII || f == ETF_UTF8 || f == ETF_UTF16_LE || f == ETF_UTF32_LE; } //! returns true if a character is whitespace inline bool isWhiteSpace(char_type c) { return (c==' ' || c=='\t' || c=='\n' || c=='\r'); } //! generates a list with xml special characters void createSpecialCharacterList() { // list of strings containing special symbols, // the first character is the special character, // the following is the symbol string without trailing &. SpecialCharacters.push_back("&"); SpecialCharacters.push_back("gt;"); SpecialCharacters.push_back("\"quot;"); SpecialCharacters.push_back("'apos;"); } //! compares the first n characters of the strings bool equalsn(const char_type* str1, const char_type* str2, int len) { int i; for(i=0; str1[i] && str2[i] && i < len; ++i) if (str1[i] != str2[i]) return false; // if one (or both) of the strings was smaller then they // are only equal if they have the same lenght return (i == len) || (str1[i] == 0 && str2[i] == 0); } //! stores the target text format void storeTargetFormat() { // get target format. We could have done this using template specialization, // but VisualStudio 6 don't like it and we want to support it. switch(sizeof(char_type)) { case 1: TargetFormat = ETF_UTF8; break; case 2: TargetFormat = ETF_UTF16_LE; break; case 4: TargetFormat = ETF_UTF32_LE; break; default: TargetFormat = ETF_ASCII; // should never happen. } } // instance variables: char_type* TextData; // data block of the text file char_type* P; // current point in text to parse char_type* TextBegin; // start of text to parse unsigned int TextSize; // size of text to parse in characters, not bytes EXML_NODE CurrentNodeType; // type of the currently parsed node ETEXT_FORMAT SourceFormat; // source format of the xml file ETEXT_FORMAT TargetFormat; // output format of this parser core::string NodeName; // name of the node currently in core::string EmptyString; // empty string to be returned by getSafe() methods bool IsEmptyElement; // is the currently parsed node empty? core::array< core::string > SpecialCharacters; // see createSpecialCharacterList() core::array Attributes; // attributes of current element }; // end CXMLReaderImpl } // end namespace } // end namespace #endif assimp-4.1.0/contrib/irrXML/CMakeLists.txt0000644002537200234200000000102113213503245020623 0ustar zmoelnigiemusersset( IrrXML_SRCS CXMLReaderImpl.h heapsort.h irrArray.h irrString.h irrTypes.h irrXML.cpp irrXML.h ) if ( MSVC ) ADD_DEFINITIONS( -D_SCL_SECURE_NO_WARNINGS ) ADD_DEFINITIONS( -D_CRT_SECURE_NO_WARNINGS ) endif ( MSVC ) add_library(IrrXML STATIC ${IrrXML_SRCS}) set(IRRXML_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}" CACHE INTERNAL "IrrXML_Include" ) set(IRRXML_LIBRARY "IrrXML" CACHE INTERNAL "IrrXML" ) install(TARGETS IrrXML ARCHIVE DESTINATION ${ASSIMP_LIB_INSTALL_DIR} COMPONENT ${LIBASSIMP_COMPONENT}) assimp-4.1.0/contrib/irrXML/irrTypes.h0000644002537200234200000000641513213503245020071 0ustar zmoelnigiemusers// Copyright (C) 2002-2005 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #ifndef __IRR_TYPES_H_INCLUDED__ #define __IRR_TYPES_H_INCLUDED__ namespace irr { //! 8 bit unsigned variable. /** This is a typedef for unsigned char, it ensures portability of the engine. */ typedef unsigned char u8; //! 8 bit signed variable. /** This is a typedef for signed char, it ensures portability of the engine. */ typedef signed char s8; //! 8 bit character variable. /** This is a typedef for char, it ensures portability of the engine. */ typedef char c8; //! 16 bit unsigned variable. /** This is a typedef for unsigned short, it ensures portability of the engine. */ typedef unsigned short u16; //! 16 bit signed variable. /** This is a typedef for signed short, it ensures portability of the engine. */ typedef signed short s16; //! 32 bit unsigned variable. /** This is a typedef for unsigned int, it ensures portability of the engine. */ typedef unsigned int u32; //! 32 bit signed variable. /** This is a typedef for signed int, it ensures portability of the engine. */ typedef signed int s32; // 64 bit signed variable. // This is a typedef for __int64, it ensures portability of the engine. // This type is currently not used by the engine and not supported by compilers // other than Microsoft Compilers, so it is outcommented. //typedef __int64 s64; //! 32 bit floating point variable. /** This is a typedef for float, it ensures portability of the engine. */ typedef float f32; //! 64 bit floating point variable. /** This is a typedef for double, it ensures portability of the engine. */ typedef double f64; } // end namespace // define the wchar_t type if not already built in. #ifdef _MSC_VER #ifndef _WCHAR_T_DEFINED //! A 16 bit wide character type. /** Defines the wchar_t-type. In VS6, its not possible to tell the standard compiler to treat wchar_t as a built-in type, and sometimes we just don't want to include the huge stdlib.h or wchar.h, so we'll use this. */ typedef unsigned short wchar_t; #define _WCHAR_T_DEFINED #endif // wchar is not defined #endif // microsoft compiler //! define a break macro for debugging only in Win32 mode. // WORKAROUND (assimp): remove __asm #if defined(WIN32) && defined(_MSC_VER) && defined(_DEBUG) #if defined(_M_IX86) #define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) /*if (_CONDITION_) {_asm int 3}*/ #else #define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) #endif #else #define _IRR_DEBUG_BREAK_IF( _CONDITION_ ) #endif //! Defines a small statement to work around a microsoft compiler bug. /** The microsft compiler 7.0 - 7.1 has a bug: When you call unmanaged code that returns a bool type value of false from managed code, the return value may appear as true. See http://support.microsoft.com/default.aspx?kbid=823071 for details. Compiler version defines: VC6.0 : 1200, VC7.0 : 1300, VC7.1 : 1310, VC8.0 : 1400*/ // WORKAROUND (assimp): remove __asm #if defined(WIN32) && defined(_MSC_VER) && (_MSC_VER > 1299) && (_MSC_VER < 1400) #define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX /*__asm mov eax,100*/ #else #define _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX #endif // _IRR_MANAGED_MARSHALLING_BUGFIX #endif // __IRR_TYPES_H_INCLUDED__ assimp-4.1.0/contrib/rapidjson/0000755002537200234200000000000013213503245016705 5ustar zmoelnigiemusersassimp-4.1.0/contrib/rapidjson/readme.md0000644002537200234200000002146413213503245020473 0ustar zmoelnigiemusers![RapidJSON logo](doc/logo/rapidjson.png) ![Release version](https://img.shields.io/badge/release-v1.1.0-blue.svg) ## A fast JSON parser/generator for C++ with both SAX/DOM style API Tencent is pleased to support the open source community by making RapidJSON available. Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. * [RapidJSON GitHub](https://github.com/Tencent/rapidjson/) * RapidJSON Documentation * [English](http://rapidjson.org/) * [简体中文](http://rapidjson.org/zh-cn/) * [GitBook](https://www.gitbook.com/book/miloyip/rapidjson/) with downloadable PDF/EPUB/MOBI, without API reference. ## Build status | [Linux][lin-link] | [Windows][win-link] | [Coveralls][cov-link] | | :---------------: | :-----------------: | :-------------------: | | ![lin-badge] | ![win-badge] | ![cov-badge] | [lin-badge]: https://travis-ci.org/Tencent/rapidjson.svg?branch=master "Travis build status" [lin-link]: https://travis-ci.org/Tencent/rapidjson "Travis build status" [win-badge]: https://ci.appveyor.com/api/projects/status/l6qulgqahcayidrf/branch/master?svg=true "AppVeyor build status" [win-link]: https://ci.appveyor.com/project/miloyip/rapidjson-0fdqj/branch/master "AppVeyor build status" [cov-badge]: https://coveralls.io/repos/Tencent/rapidjson/badge.svg?branch=master "Coveralls coverage" [cov-link]: https://coveralls.io/r/Tencent/rapidjson?branch=master "Coveralls coverage" ## Introduction RapidJSON is a JSON parser and generator for C++. It was inspired by [RapidXml](http://rapidxml.sourceforge.net/). * RapidJSON is **small** but **complete**. It supports both SAX and DOM style API. The SAX parser is only a half thousand lines of code. * RapidJSON is **fast**. Its performance can be comparable to `strlen()`. It also optionally supports SSE2/SSE4.2 for acceleration. * RapidJSON is **self-contained** and **header-only**. It does not depend on external libraries such as BOOST. It even does not depend on STL. * RapidJSON is **memory-friendly**. Each JSON value occupies exactly 16 bytes for most 32/64-bit machines (excluding text string). By default it uses a fast memory allocator, and the parser allocates memory compactly during parsing. * RapidJSON is **Unicode-friendly**. It supports UTF-8, UTF-16, UTF-32 (LE & BE), and their detection, validation and transcoding internally. For example, you can read a UTF-8 file and let RapidJSON transcode the JSON strings into UTF-16 in the DOM. It also supports surrogates and "\u0000" (null character). More features can be read [here](doc/features.md). JSON(JavaScript Object Notation) is a light-weight data exchange format. RapidJSON should be in fully compliance with RFC7159/ECMA-404, with optional support of relaxed syntax. More information about JSON can be obtained at * [Introducing JSON](http://json.org/) * [RFC7159: The JavaScript Object Notation (JSON) Data Interchange Format](https://tools.ietf.org/html/rfc7159) * [Standard ECMA-404: The JSON Data Interchange Format](https://www.ecma-international.org/publications/standards/Ecma-404.htm) ## Highlights in v1.1 (2016-8-25) * Added [JSON Pointer](doc/pointer.md) * Added [JSON Schema](doc/schema.md) * Added [relaxed JSON syntax](doc/dom.md) (comment, trailing comma, NaN/Infinity) * Iterating array/object with [C++11 Range-based for loop](doc/tutorial.md) * Reduce memory overhead of each `Value` from 24 bytes to 16 bytes in x86-64 architecture. For other changes please refer to [change log](CHANGELOG.md). ## Compatibility RapidJSON is cross-platform. Some platform/compiler combinations which have been tested are shown as follows. * Visual C++ 2008/2010/2013 on Windows (32/64-bit) * GNU C++ 3.8.x on Cygwin * Clang 3.4 on Mac OS X (32/64-bit) and iOS * Clang 3.4 on Android NDK Users can build and run the unit tests on their platform/compiler. ## Installation RapidJSON is a header-only C++ library. Just copy the `include/rapidjson` folder to system or project's include path. RapidJSON uses following software as its dependencies: * [CMake](https://cmake.org/) as a general build tool * (optional) [Doxygen](http://www.doxygen.org) to build documentation * (optional) [googletest](https://github.com/google/googletest) for unit and performance testing To generate user documentation and run tests please proceed with the steps below: 1. Execute `git submodule update --init` to get the files of thirdparty submodules (google test). 2. Create directory called `build` in rapidjson source directory. 3. Change to `build` directory and run `cmake ..` command to configure your build. Windows users can do the same with cmake-gui application. 4. On Windows, build the solution found in the build directory. On Linux, run `make` from the build directory. On successful build you will find compiled test and example binaries in `bin` directory. The generated documentation will be available in `doc/html` directory of the build tree. To run tests after finished build please run `make test` or `ctest` from your build tree. You can get detailed output using `ctest -V` command. It is possible to install library system-wide by running `make install` command from the build tree with administrative privileges. This will install all files according to system preferences. Once RapidJSON is installed, it is possible to use it from other CMake projects by adding `find_package(RapidJSON)` line to your CMakeLists.txt. ## Usage at a glance This simple example parses a JSON string into a document (DOM), make a simple modification of the DOM, and finally stringify the DOM to a JSON string. ~~~~~~~~~~cpp // rapidjson/example/simpledom/simpledom.cpp` #include "rapidjson/document.h" #include "rapidjson/writer.h" #include "rapidjson/stringbuffer.h" #include using namespace rapidjson; int main() { // 1. Parse a JSON string into DOM. const char* json = "{\"project\":\"rapidjson\",\"stars\":10}"; Document d; d.Parse(json); // 2. Modify it by DOM. Value& s = d["stars"]; s.SetInt(s.GetInt() + 1); // 3. Stringify the DOM StringBuffer buffer; Writer writer(buffer); d.Accept(writer); // Output {"project":"rapidjson","stars":11} std::cout << buffer.GetString() << std::endl; return 0; } ~~~~~~~~~~ Note that this example did not handle potential errors. The following diagram shows the process. ![simpledom](doc/diagram/simpledom.png) More [examples](https://github.com/Tencent/rapidjson/tree/master/example) are available: * DOM API * [tutorial](https://github.com/Tencent/rapidjson/blob/master/example/tutorial/tutorial.cpp): Basic usage of DOM API. * SAX API * [simplereader](https://github.com/Tencent/rapidjson/blob/master/example/simplereader/simplereader.cpp): Dumps all SAX events while parsing a JSON by `Reader`. * [condense](https://github.com/Tencent/rapidjson/blob/master/example/condense/condense.cpp): A command line tool to rewrite a JSON, with all whitespaces removed. * [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp): A command line tool to rewrite a JSON with indents and newlines by `PrettyWriter`. * [capitalize](https://github.com/Tencent/rapidjson/blob/master/example/capitalize/capitalize.cpp): A command line tool to capitalize strings in JSON. * [messagereader](https://github.com/Tencent/rapidjson/blob/master/example/messagereader/messagereader.cpp): Parse a JSON message with SAX API. * [serialize](https://github.com/Tencent/rapidjson/blob/master/example/serialize/serialize.cpp): Serialize a C++ object into JSON with SAX API. * [jsonx](https://github.com/Tencent/rapidjson/blob/master/example/jsonx/jsonx.cpp): Implements a `JsonxWriter` which stringify SAX events into [JSONx](https://www-01.ibm.com/support/knowledgecenter/SS9H2Y_7.1.0/com.ibm.dp.doc/json_jsonx.html) (a kind of XML) format. The example is a command line tool which converts input JSON into JSONx format. * Schema * [schemavalidator](https://github.com/Tencent/rapidjson/blob/master/example/schemavalidator/schemavalidator.cpp) : A command line tool to validate a JSON with a JSON schema. * Advanced * [prettyauto](https://github.com/Tencent/rapidjson/blob/master/example/prettyauto/prettyauto.cpp): A modified version of [pretty](https://github.com/Tencent/rapidjson/blob/master/example/pretty/pretty.cpp) to automatically handle JSON with any UTF encodings. * [parsebyparts](https://github.com/Tencent/rapidjson/blob/master/example/parsebyparts/parsebyparts.cpp): Implements an `AsyncDocumentParser` which can parse JSON in parts, using C++11 thread. * [filterkey](https://github.com/Tencent/rapidjson/blob/master/example/filterkey/filterkey.cpp): A command line tool to remove all values with user-specified key. * [filterkeydom](https://github.com/Tencent/rapidjson/blob/master/example/filterkeydom/filterkeydom.cpp): Same tool as above, but it demonstrates how to use a generator to populate a `Document`. assimp-4.1.0/contrib/rapidjson/include/0000755002537200234200000000000013213503245020330 5ustar zmoelnigiemusersassimp-4.1.0/contrib/rapidjson/include/rapidjson/0000755002537200234200000000000013213503245022321 5ustar zmoelnigiemusersassimp-4.1.0/contrib/rapidjson/include/rapidjson/ostreamwrapper.h0000644002537200234200000000443313213503245025551 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_OSTREAMWRAPPER_H_ #define RAPIDJSON_OSTREAMWRAPPER_H_ #include "stream.h" #include #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept. /*! The classes can be wrapped including but not limited to: - \c std::ostringstream - \c std::stringstream - \c std::wpstringstream - \c std::wstringstream - \c std::ifstream - \c std::fstream - \c std::wofstream - \c std::wfstream \tparam StreamType Class derived from \c std::basic_ostream. */ template class BasicOStreamWrapper { public: typedef typename StreamType::char_type Ch; BasicOStreamWrapper(StreamType& stream) : stream_(stream) {} void Put(Ch c) { stream_.put(c); } void Flush() { stream_.flush(); } // Not implemented char Peek() const { RAPIDJSON_ASSERT(false); return 0; } char Take() { RAPIDJSON_ASSERT(false); return 0; } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } private: BasicOStreamWrapper(const BasicOStreamWrapper&); BasicOStreamWrapper& operator=(const BasicOStreamWrapper&); StreamType& stream_; }; typedef BasicOStreamWrapper OStreamWrapper; typedef BasicOStreamWrapper WOStreamWrapper; #ifdef __clang__ RAPIDJSON_DIAG_POP #endif RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_OSTREAMWRAPPER_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/0000755002537200234200000000000013213503245024135 5ustar zmoelnigiemusersassimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/diyfp.h0000644002537200234200000002642613213503245025433 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. // This is a C++ header-only implementation of Grisu2 algorithm from the publication: // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with // integers." ACM Sigplan Notices 45.6 (2010): 233-243. #ifndef RAPIDJSON_DIYFP_H_ #define RAPIDJSON_DIYFP_H_ #include "../rapidjson.h" #if defined(_MSC_VER) && defined(_M_AMD64) && !defined(__INTEL_COMPILER) #include #pragma intrinsic(_BitScanReverse64) #pragma intrinsic(_umul128) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif struct DiyFp { DiyFp() : f(), e() {} DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {} explicit DiyFp(double d) { union { double d; uint64_t u64; } u = { d }; int biased_e = static_cast((u.u64 & kDpExponentMask) >> kDpSignificandSize); uint64_t significand = (u.u64 & kDpSignificandMask); if (biased_e != 0) { f = significand + kDpHiddenBit; e = biased_e - kDpExponentBias; } else { f = significand; e = kDpMinExponent + 1; } } DiyFp operator-(const DiyFp& rhs) const { return DiyFp(f - rhs.f, e); } DiyFp operator*(const DiyFp& rhs) const { #if defined(_MSC_VER) && defined(_M_AMD64) uint64_t h; uint64_t l = _umul128(f, rhs.f, &h); if (l & (uint64_t(1) << 63)) // rounding h++; return DiyFp(h, e + rhs.e + 64); #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) __extension__ typedef unsigned __int128 uint128; uint128 p = static_cast(f) * static_cast(rhs.f); uint64_t h = static_cast(p >> 64); uint64_t l = static_cast(p); if (l & (uint64_t(1) << 63)) // rounding h++; return DiyFp(h, e + rhs.e + 64); #else const uint64_t M32 = 0xFFFFFFFF; const uint64_t a = f >> 32; const uint64_t b = f & M32; const uint64_t c = rhs.f >> 32; const uint64_t d = rhs.f & M32; const uint64_t ac = a * c; const uint64_t bc = b * c; const uint64_t ad = a * d; const uint64_t bd = b * d; uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); tmp += 1U << 31; /// mult_round return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); #endif } DiyFp Normalize() const { #if defined(_MSC_VER) && defined(_M_AMD64) unsigned long index; _BitScanReverse64(&index, f); return DiyFp(f << (63 - index), e - (63 - index)); #elif defined(__GNUC__) && __GNUC__ >= 4 int s = __builtin_clzll(f); return DiyFp(f << s, e - s); #else DiyFp res = *this; while (!(res.f & (static_cast(1) << 63))) { res.f <<= 1; res.e--; } return res; #endif } DiyFp NormalizeBoundary() const { DiyFp res = *this; while (!(res.f & (kDpHiddenBit << 1))) { res.f <<= 1; res.e--; } res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); return res; } void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); mi.f <<= mi.e - pl.e; mi.e = pl.e; *plus = pl; *minus = mi; } double ToDouble() const { union { double d; uint64_t u64; }u; const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : static_cast(e + kDpExponentBias); u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize); return u.d; } static const int kDiySignificandSize = 64; static const int kDpSignificandSize = 52; static const int kDpExponentBias = 0x3FF + kDpSignificandSize; static const int kDpMaxExponent = 0x7FF - kDpExponentBias; static const int kDpMinExponent = -kDpExponentBias; static const int kDpDenormalExponent = -kDpExponentBias + 1; static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); uint64_t f; int e; }; inline DiyFp GetCachedPowerByIndex(size_t index) { // 10^-348, 10^-340, ..., 10^340 static const uint64_t kCachedPowers_F[] = { RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76), RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea), RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df), RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f), RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c), RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5), RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d), RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637), RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7), RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5), RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b), RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996), RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6), RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8), RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053), RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd), RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94), RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b), RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac), RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3), RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb), RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c), RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000), RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984), RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70), RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245), RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8), RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a), RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea), RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85), RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2), RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3), RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25), RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece), RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5), RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a), RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c), RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a), RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129), RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429), RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d), RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841), RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9), RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b) }; static const int16_t kCachedPowers_E[] = { -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066 }; return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); } inline DiyFp GetCachedPower(int e, int* K) { //int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive int k = static_cast(dk); if (dk - k > 0.0) k++; unsigned index = static_cast((k >> 3) + 1); *K = -(-348 + static_cast(index << 3)); // decimal exponent no need lookup table return GetCachedPowerByIndex(index); } inline DiyFp GetCachedPower10(int exp, int *outExp) { unsigned index = (static_cast(exp) + 348u) / 8u; *outExp = -348 + static_cast(index) * 8; return GetCachedPowerByIndex(index); } #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #ifdef __clang__ RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_OFF(padded) #endif } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_DIYFP_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/ieee754.h0000644002537200234200000000566213213503245025466 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_IEEE754_ #define RAPIDJSON_IEEE754_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { class Double { public: Double() {} Double(double d) : d_(d) {} Double(uint64_t u) : u_(u) {} double Value() const { return d_; } uint64_t Uint64Value() const { return u_; } double NextPositiveDouble() const { RAPIDJSON_ASSERT(!Sign()); return Double(u_ + 1).Value(); } bool Sign() const { return (u_ & kSignMask) != 0; } uint64_t Significand() const { return u_ & kSignificandMask; } int Exponent() const { return static_cast(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); } bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; } bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; } bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; } bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; } bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; } uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); } int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; } uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; } static int EffectiveSignificandSize(int order) { if (order >= -1021) return 53; else if (order <= -1074) return 0; else return order + 1074; } private: static const int kSignificandSize = 52; static const int kExponentBias = 0x3FF; static const int kDenormalExponent = 1 - kExponentBias; static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000); static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000); static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF); static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000); union { double d_; uint64_t u_; }; }; } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_IEEE754_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/itoa.h0000644002537200234200000002410213213503245025241 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_ITOA_ #define RAPIDJSON_ITOA_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { inline const char* GetDigitsLut() { static const char cDigitsLut[200] = { '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9', '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9', '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9', '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9', '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9', '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9', '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9', '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9', '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9', '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9' }; return cDigitsLut; } inline char* u32toa(uint32_t value, char* buffer) { const char* cDigitsLut = GetDigitsLut(); if (value < 10000) { const uint32_t d1 = (value / 100) << 1; const uint32_t d2 = (value % 100) << 1; if (value >= 1000) *buffer++ = cDigitsLut[d1]; if (value >= 100) *buffer++ = cDigitsLut[d1 + 1]; if (value >= 10) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; } else if (value < 100000000) { // value = bbbbcccc const uint32_t b = value / 10000; const uint32_t c = value % 10000; const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; if (value >= 10000000) *buffer++ = cDigitsLut[d1]; if (value >= 1000000) *buffer++ = cDigitsLut[d1 + 1]; if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; } else { // value = aabbbbcccc in decimal const uint32_t a = value / 100000000; // 1 to 42 value %= 100000000; if (a >= 10) { const unsigned i = a << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; } else *buffer++ = static_cast('0' + static_cast(a)); const uint32_t b = value / 10000; // 0 to 9999 const uint32_t c = value % 10000; // 0 to 9999 const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; *buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; } return buffer; } inline char* i32toa(int32_t value, char* buffer) { uint32_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; u = ~u + 1; } return u32toa(u, buffer); } inline char* u64toa(uint64_t value, char* buffer) { const char* cDigitsLut = GetDigitsLut(); const uint64_t kTen8 = 100000000; const uint64_t kTen9 = kTen8 * 10; const uint64_t kTen10 = kTen8 * 100; const uint64_t kTen11 = kTen8 * 1000; const uint64_t kTen12 = kTen8 * 10000; const uint64_t kTen13 = kTen8 * 100000; const uint64_t kTen14 = kTen8 * 1000000; const uint64_t kTen15 = kTen8 * 10000000; const uint64_t kTen16 = kTen8 * kTen8; if (value < kTen8) { uint32_t v = static_cast(value); if (v < 10000) { const uint32_t d1 = (v / 100) << 1; const uint32_t d2 = (v % 100) << 1; if (v >= 1000) *buffer++ = cDigitsLut[d1]; if (v >= 100) *buffer++ = cDigitsLut[d1 + 1]; if (v >= 10) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; } else { // value = bbbbcccc const uint32_t b = v / 10000; const uint32_t c = v % 10000; const uint32_t d1 = (b / 100) << 1; const uint32_t d2 = (b % 100) << 1; const uint32_t d3 = (c / 100) << 1; const uint32_t d4 = (c % 100) << 1; if (value >= 10000000) *buffer++ = cDigitsLut[d1]; if (value >= 1000000) *buffer++ = cDigitsLut[d1 + 1]; if (value >= 100000) *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; } } else if (value < kTen16) { const uint32_t v0 = static_cast(value / kTen8); const uint32_t v1 = static_cast(value % kTen8); const uint32_t b0 = v0 / 10000; const uint32_t c0 = v0 % 10000; const uint32_t d1 = (b0 / 100) << 1; const uint32_t d2 = (b0 % 100) << 1; const uint32_t d3 = (c0 / 100) << 1; const uint32_t d4 = (c0 % 100) << 1; const uint32_t b1 = v1 / 10000; const uint32_t c1 = v1 % 10000; const uint32_t d5 = (b1 / 100) << 1; const uint32_t d6 = (b1 % 100) << 1; const uint32_t d7 = (c1 / 100) << 1; const uint32_t d8 = (c1 % 100) << 1; if (value >= kTen15) *buffer++ = cDigitsLut[d1]; if (value >= kTen14) *buffer++ = cDigitsLut[d1 + 1]; if (value >= kTen13) *buffer++ = cDigitsLut[d2]; if (value >= kTen12) *buffer++ = cDigitsLut[d2 + 1]; if (value >= kTen11) *buffer++ = cDigitsLut[d3]; if (value >= kTen10) *buffer++ = cDigitsLut[d3 + 1]; if (value >= kTen9) *buffer++ = cDigitsLut[d4]; if (value >= kTen8) *buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d6]; *buffer++ = cDigitsLut[d6 + 1]; *buffer++ = cDigitsLut[d7]; *buffer++ = cDigitsLut[d7 + 1]; *buffer++ = cDigitsLut[d8]; *buffer++ = cDigitsLut[d8 + 1]; } else { const uint32_t a = static_cast(value / kTen16); // 1 to 1844 value %= kTen16; if (a < 10) *buffer++ = static_cast('0' + static_cast(a)); else if (a < 100) { const uint32_t i = a << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; } else if (a < 1000) { *buffer++ = static_cast('0' + static_cast(a / 100)); const uint32_t i = (a % 100) << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; } else { const uint32_t i = (a / 100) << 1; const uint32_t j = (a % 100) << 1; *buffer++ = cDigitsLut[i]; *buffer++ = cDigitsLut[i + 1]; *buffer++ = cDigitsLut[j]; *buffer++ = cDigitsLut[j + 1]; } const uint32_t v0 = static_cast(value / kTen8); const uint32_t v1 = static_cast(value % kTen8); const uint32_t b0 = v0 / 10000; const uint32_t c0 = v0 % 10000; const uint32_t d1 = (b0 / 100) << 1; const uint32_t d2 = (b0 % 100) << 1; const uint32_t d3 = (c0 / 100) << 1; const uint32_t d4 = (c0 % 100) << 1; const uint32_t b1 = v1 / 10000; const uint32_t c1 = v1 % 10000; const uint32_t d5 = (b1 / 100) << 1; const uint32_t d6 = (b1 % 100) << 1; const uint32_t d7 = (c1 / 100) << 1; const uint32_t d8 = (c1 % 100) << 1; *buffer++ = cDigitsLut[d1]; *buffer++ = cDigitsLut[d1 + 1]; *buffer++ = cDigitsLut[d2]; *buffer++ = cDigitsLut[d2 + 1]; *buffer++ = cDigitsLut[d3]; *buffer++ = cDigitsLut[d3 + 1]; *buffer++ = cDigitsLut[d4]; *buffer++ = cDigitsLut[d4 + 1]; *buffer++ = cDigitsLut[d5]; *buffer++ = cDigitsLut[d5 + 1]; *buffer++ = cDigitsLut[d6]; *buffer++ = cDigitsLut[d6 + 1]; *buffer++ = cDigitsLut[d7]; *buffer++ = cDigitsLut[d7 + 1]; *buffer++ = cDigitsLut[d8]; *buffer++ = cDigitsLut[d8 + 1]; } return buffer; } inline char* i64toa(int64_t value, char* buffer) { uint64_t u = static_cast(value); if (value < 0) { *buffer++ = '-'; u = ~u + 1; } return u64toa(u, buffer); } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ITOA_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/dtoa.h0000644002537200234200000001767513213503245025255 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. // This is a C++ header-only implementation of Grisu2 algorithm from the publication: // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with // integers." ACM Sigplan Notices 45.6 (2010): 233-243. #ifndef RAPIDJSON_DTOA_ #define RAPIDJSON_DTOA_ #include "itoa.h" // GetDigitsLut() #include "diyfp.h" #include "ieee754.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 #endif inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { while (rest < wp_w && delta - rest >= ten_kappa && (rest + ten_kappa < wp_w || /// closer wp_w - rest > rest + ten_kappa - wp_w)) { buffer[len - 1]--; rest += ten_kappa; } } inline int CountDecimalDigit32(uint32_t n) { // Simple pure C++ implementation was faster than __builtin_clz version in this situation. if (n < 10) return 1; if (n < 100) return 2; if (n < 1000) return 3; if (n < 10000) return 4; if (n < 100000) return 5; if (n < 1000000) return 6; if (n < 10000000) return 7; if (n < 100000000) return 8; // Will not reach 10 digits in DigitGen() //if (n < 1000000000) return 9; //return 10; return 9; } inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); const DiyFp wp_w = Mp - W; uint32_t p1 = static_cast(Mp.f >> -one.e); uint64_t p2 = Mp.f & (one.f - 1); int kappa = CountDecimalDigit32(p1); // kappa in [0, 9] *len = 0; while (kappa > 0) { uint32_t d = 0; switch (kappa) { case 9: d = p1 / 100000000; p1 %= 100000000; break; case 8: d = p1 / 10000000; p1 %= 10000000; break; case 7: d = p1 / 1000000; p1 %= 1000000; break; case 6: d = p1 / 100000; p1 %= 100000; break; case 5: d = p1 / 10000; p1 %= 10000; break; case 4: d = p1 / 1000; p1 %= 1000; break; case 3: d = p1 / 100; p1 %= 100; break; case 2: d = p1 / 10; p1 %= 10; break; case 1: d = p1; p1 = 0; break; default:; } if (d || *len) buffer[(*len)++] = static_cast('0' + static_cast(d)); kappa--; uint64_t tmp = (static_cast(p1) << -one.e) + p2; if (tmp <= delta) { *K += kappa; GrisuRound(buffer, *len, delta, tmp, static_cast(kPow10[kappa]) << -one.e, wp_w.f); return; } } // kappa = 0 for (;;) { p2 *= 10; delta *= 10; char d = static_cast(p2 >> -one.e); if (d || *len) buffer[(*len)++] = static_cast('0' + d); p2 &= one.f - 1; kappa--; if (p2 < delta) { *K += kappa; int index = -kappa; GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[index] : 0)); return; } } } inline void Grisu2(double value, char* buffer, int* length, int* K) { const DiyFp v(value); DiyFp w_m, w_p; v.NormalizedBoundaries(&w_m, &w_p); const DiyFp c_mk = GetCachedPower(w_p.e, K); const DiyFp W = v.Normalize() * c_mk; DiyFp Wp = w_p * c_mk; DiyFp Wm = w_m * c_mk; Wm.f++; Wp.f--; DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); } inline char* WriteExponent(int K, char* buffer) { if (K < 0) { *buffer++ = '-'; K = -K; } if (K >= 100) { *buffer++ = static_cast('0' + static_cast(K / 100)); K %= 100; const char* d = GetDigitsLut() + K * 2; *buffer++ = d[0]; *buffer++ = d[1]; } else if (K >= 10) { const char* d = GetDigitsLut() + K * 2; *buffer++ = d[0]; *buffer++ = d[1]; } else *buffer++ = static_cast('0' + static_cast(K)); return buffer; } inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { const int kk = length + k; // 10^(kk-1) <= v < 10^kk if (0 <= k && kk <= 21) { // 1234e7 -> 12340000000 for (int i = length; i < kk; i++) buffer[i] = '0'; buffer[kk] = '.'; buffer[kk + 1] = '0'; return &buffer[kk + 2]; } else if (0 < kk && kk <= 21) { // 1234e-2 -> 12.34 std::memmove(&buffer[kk + 1], &buffer[kk], static_cast(length - kk)); buffer[kk] = '.'; if (0 > k + maxDecimalPlaces) { // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 // Remove extra trailing zeros (at least one) after truncation. for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) if (buffer[i] != '0') return &buffer[i + 1]; return &buffer[kk + 2]; // Reserve one zero } else return &buffer[length + 1]; } else if (-6 < kk && kk <= 0) { // 1234e-6 -> 0.001234 const int offset = 2 - kk; std::memmove(&buffer[offset], &buffer[0], static_cast(length)); buffer[0] = '0'; buffer[1] = '.'; for (int i = 2; i < offset; i++) buffer[i] = '0'; if (length - kk > maxDecimalPlaces) { // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 // Remove extra trailing zeros (at least one) after truncation. for (int i = maxDecimalPlaces + 1; i > 2; i--) if (buffer[i] != '0') return &buffer[i + 1]; return &buffer[3]; // Reserve one zero } else return &buffer[length + offset]; } else if (kk < -maxDecimalPlaces) { // Truncate to zero buffer[0] = '0'; buffer[1] = '.'; buffer[2] = '0'; return &buffer[3]; } else if (length == 1) { // 1e30 buffer[1] = 'e'; return WriteExponent(kk - 1, &buffer[2]); } else { // 1234e30 -> 1.234e33 std::memmove(&buffer[2], &buffer[1], static_cast(length - 1)); buffer[1] = '.'; buffer[length + 1] = 'e'; return WriteExponent(kk - 1, &buffer[0 + length + 2]); } } inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); Double d(value); if (d.IsZero()) { if (d.Sign()) *buffer++ = '-'; // -0.0, Issue #289 buffer[0] = '0'; buffer[1] = '.'; buffer[2] = '0'; return &buffer[3]; } else { if (value < 0) { *buffer++ = '-'; value = -value; } int length, K; Grisu2(value, buffer, &length, &K); return Prettify(buffer, length, K, maxDecimalPlaces); } } #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_DTOA_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/strfunc.h0000644002537200234200000000422713213503245025777 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_INTERNAL_STRFUNC_H_ #define RAPIDJSON_INTERNAL_STRFUNC_H_ #include "../stream.h" #include RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Custom strlen() which works on different character types. /*! \tparam Ch Character type (e.g. char, wchar_t, short) \param s Null-terminated input string. \return Number of characters in the string. \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints. */ template inline SizeType StrLen(const Ch* s) { RAPIDJSON_ASSERT(s != 0); const Ch* p = s; while (*p) ++p; return SizeType(p - s); } template <> inline SizeType StrLen(const char* s) { return SizeType(std::strlen(s)); } template <> inline SizeType StrLen(const wchar_t* s) { return SizeType(std::wcslen(s)); } //! Returns number of code points in a encoded string. template bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) { RAPIDJSON_ASSERT(s != 0); RAPIDJSON_ASSERT(outCount != 0); GenericStringStream is(s); const typename Encoding::Ch* end = s + length; SizeType count = 0; while (is.src_ < end) { unsigned codepoint; if (!Encoding::Decode(is, &codepoint)) return false; count++; } *outCount = count; return true; } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_INTERNAL_STRFUNC_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/regex.h0000644002537200234200000006230213213503245025423 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_INTERNAL_REGEX_H_ #define RAPIDJSON_INTERNAL_REGEX_H_ #include "../allocators.h" #include "../stream.h" #include "stack.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(implicit-fallthrough) #endif #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #if __GNUC__ >= 7 RAPIDJSON_DIAG_OFF(implicit-fallthrough) #endif #endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif #ifndef RAPIDJSON_REGEX_VERBOSE #define RAPIDJSON_REGEX_VERBOSE 0 #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { /////////////////////////////////////////////////////////////////////////////// // DecodedStream template class DecodedStream { public: DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); } unsigned Peek() { return codepoint_; } unsigned Take() { unsigned c = codepoint_; if (c) // No further decoding when '\0' Decode(); return c; } private: void Decode() { if (!Encoding::Decode(ss_, &codepoint_)) codepoint_ = 0; } SourceStream& ss_; unsigned codepoint_; }; /////////////////////////////////////////////////////////////////////////////// // GenericRegex static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1 static const SizeType kRegexInvalidRange = ~SizeType(0); template class GenericRegexSearch; //! Regular expression engine with subset of ECMAscript grammar. /*! Supported regular expression syntax: - \c ab Concatenation - \c a|b Alternation - \c a? Zero or one - \c a* Zero or more - \c a+ One or more - \c a{3} Exactly 3 times - \c a{3,} At least 3 times - \c a{3,5} 3 to 5 times - \c (ab) Grouping - \c ^a At the beginning - \c a$ At the end - \c . Any character - \c [abc] Character classes - \c [a-c] Character class range - \c [a-z0-9_] Character class combination - \c [^abc] Negated character classes - \c [^a-c] Negated character class range - \c [\b] Backspace (U+0008) - \c \\| \\\\ ... Escape characters - \c \\f Form feed (U+000C) - \c \\n Line feed (U+000A) - \c \\r Carriage return (U+000D) - \c \\t Tab (U+0009) - \c \\v Vertical tab (U+000B) \note This is a Thompson NFA engine, implemented with reference to Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", https://swtch.com/~rsc/regexp/regexp1.html */ template class GenericRegex { public: typedef Encoding EncodingType; typedef typename Encoding::Ch Ch; template friend class GenericRegexSearch; GenericRegex(const Ch* source, Allocator* allocator = 0) : states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), anchorBegin_(), anchorEnd_() { GenericStringStream ss(source); DecodedStream, Encoding> ds(ss); Parse(ds); } ~GenericRegex() {} bool IsValid() const { return root_ != kRegexInvalidState; } private: enum Operator { kZeroOrOne, kZeroOrMore, kOneOrMore, kConcatenation, kAlternation, kLeftParenthesis }; static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.' static const unsigned kRangeCharacterClass = 0xFFFFFFFE; static const unsigned kRangeNegationFlag = 0x80000000; struct Range { unsigned start; // unsigned end; SizeType next; }; struct State { SizeType out; //!< Equals to kInvalid for matching state SizeType out1; //!< Equals to non-kInvalid for split SizeType rangeStart; unsigned codepoint; }; struct Frag { Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {} SizeType start; SizeType out; //!< link-list of all output states SizeType minIndex; }; State& GetState(SizeType index) { RAPIDJSON_ASSERT(index < stateCount_); return states_.template Bottom()[index]; } const State& GetState(SizeType index) const { RAPIDJSON_ASSERT(index < stateCount_); return states_.template Bottom()[index]; } Range& GetRange(SizeType index) { RAPIDJSON_ASSERT(index < rangeCount_); return ranges_.template Bottom()[index]; } const Range& GetRange(SizeType index) const { RAPIDJSON_ASSERT(index < rangeCount_); return ranges_.template Bottom()[index]; } template void Parse(DecodedStream& ds) { Allocator allocator; Stack operandStack(&allocator, 256); // Frag Stack operatorStack(&allocator, 256); // Operator Stack atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis) *atomCountStack.template Push() = 0; unsigned codepoint; while (ds.Peek() != 0) { switch (codepoint = ds.Take()) { case '^': anchorBegin_ = true; break; case '$': anchorEnd_ = true; break; case '|': while (!operatorStack.Empty() && *operatorStack.template Top() < kAlternation) if (!Eval(operandStack, *operatorStack.template Pop(1))) return; *operatorStack.template Push() = kAlternation; *atomCountStack.template Top() = 0; break; case '(': *operatorStack.template Push() = kLeftParenthesis; *atomCountStack.template Push() = 0; break; case ')': while (!operatorStack.Empty() && *operatorStack.template Top() != kLeftParenthesis) if (!Eval(operandStack, *operatorStack.template Pop(1))) return; if (operatorStack.Empty()) return; operatorStack.template Pop(1); atomCountStack.template Pop(1); ImplicitConcatenation(atomCountStack, operatorStack); break; case '?': if (!Eval(operandStack, kZeroOrOne)) return; break; case '*': if (!Eval(operandStack, kZeroOrMore)) return; break; case '+': if (!Eval(operandStack, kOneOrMore)) return; break; case '{': { unsigned n, m; if (!ParseUnsigned(ds, &n)) return; if (ds.Peek() == ',') { ds.Take(); if (ds.Peek() == '}') m = kInfinityQuantifier; else if (!ParseUnsigned(ds, &m) || m < n) return; } else m = n; if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}') return; ds.Take(); } break; case '.': PushOperand(operandStack, kAnyCharacterClass); ImplicitConcatenation(atomCountStack, operatorStack); break; case '[': { SizeType range; if (!ParseRange(ds, &range)) return; SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass); GetState(s).rangeStart = range; *operandStack.template Push() = Frag(s, s, s); } ImplicitConcatenation(atomCountStack, operatorStack); break; case '\\': // Escape character if (!CharacterEscape(ds, &codepoint)) return; // Unsupported escape character // fall through to default default: // Pattern character PushOperand(operandStack, codepoint); ImplicitConcatenation(atomCountStack, operatorStack); } } while (!operatorStack.Empty()) if (!Eval(operandStack, *operatorStack.template Pop(1))) return; // Link the operand to matching state. if (operandStack.GetSize() == sizeof(Frag)) { Frag* e = operandStack.template Pop(1); Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0)); root_ = e->start; #if RAPIDJSON_REGEX_VERBOSE printf("root: %d\n", root_); for (SizeType i = 0; i < stateCount_ ; i++) { State& s = GetState(i); printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint); } printf("\n"); #endif } } SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) { State* s = states_.template Push(); s->out = out; s->out1 = out1; s->codepoint = codepoint; s->rangeStart = kRegexInvalidRange; return stateCount_++; } void PushOperand(Stack& operandStack, unsigned codepoint) { SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint); *operandStack.template Push() = Frag(s, s, s); } void ImplicitConcatenation(Stack& atomCountStack, Stack& operatorStack) { if (*atomCountStack.template Top()) *operatorStack.template Push() = kConcatenation; (*atomCountStack.template Top())++; } SizeType Append(SizeType l1, SizeType l2) { SizeType old = l1; while (GetState(l1).out != kRegexInvalidState) l1 = GetState(l1).out; GetState(l1).out = l2; return old; } void Patch(SizeType l, SizeType s) { for (SizeType next; l != kRegexInvalidState; l = next) { next = GetState(l).out; GetState(l).out = s; } } bool Eval(Stack& operandStack, Operator op) { switch (op) { case kConcatenation: RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2); { Frag e2 = *operandStack.template Pop(1); Frag e1 = *operandStack.template Pop(1); Patch(e1.out, e2.start); *operandStack.template Push() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex)); } return true; case kAlternation: if (operandStack.GetSize() >= sizeof(Frag) * 2) { Frag e2 = *operandStack.template Pop(1); Frag e1 = *operandStack.template Pop(1); SizeType s = NewState(e1.start, e2.start, 0); *operandStack.template Push() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex)); return true; } return false; case kZeroOrOne: if (operandStack.GetSize() >= sizeof(Frag)) { Frag e = *operandStack.template Pop(1); SizeType s = NewState(kRegexInvalidState, e.start, 0); *operandStack.template Push() = Frag(s, Append(e.out, s), e.minIndex); return true; } return false; case kZeroOrMore: if (operandStack.GetSize() >= sizeof(Frag)) { Frag e = *operandStack.template Pop(1); SizeType s = NewState(kRegexInvalidState, e.start, 0); Patch(e.out, s); *operandStack.template Push() = Frag(s, s, e.minIndex); return true; } return false; default: RAPIDJSON_ASSERT(op == kOneOrMore); if (operandStack.GetSize() >= sizeof(Frag)) { Frag e = *operandStack.template Pop(1); SizeType s = NewState(kRegexInvalidState, e.start, 0); Patch(e.out, s); *operandStack.template Push() = Frag(e.start, s, e.minIndex); return true; } return false; } } bool EvalQuantifier(Stack& operandStack, unsigned n, unsigned m) { RAPIDJSON_ASSERT(n <= m); RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag)); if (n == 0) { if (m == 0) // a{0} not support return false; else if (m == kInfinityQuantifier) Eval(operandStack, kZeroOrMore); // a{0,} -> a* else { Eval(operandStack, kZeroOrOne); // a{0,5} -> a? for (unsigned i = 0; i < m - 1; i++) CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a? for (unsigned i = 0; i < m - 1; i++) Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a? } return true; } for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a CloneTopOperand(operandStack); if (m == kInfinityQuantifier) Eval(operandStack, kOneOrMore); // a{3,} -> a a a+ else if (m > n) { CloneTopOperand(operandStack); // a{3,5} -> a a a a Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a? for (unsigned i = n; i < m - 1; i++) CloneTopOperand(operandStack); // a{3,5} -> a a a a? a? for (unsigned i = n; i < m; i++) Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a? } for (unsigned i = 0; i < n - 1; i++) Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a? return true; } static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; } void CloneTopOperand(Stack& operandStack) { const Frag src = *operandStack.template Top(); // Copy constructor to prevent invalidation SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_) State* s = states_.template Push(count); memcpy(s, &GetState(src.minIndex), count * sizeof(State)); for (SizeType j = 0; j < count; j++) { if (s[j].out != kRegexInvalidState) s[j].out += count; if (s[j].out1 != kRegexInvalidState) s[j].out1 += count; } *operandStack.template Push() = Frag(src.start + count, src.out + count, src.minIndex + count); stateCount_ += count; } template bool ParseUnsigned(DecodedStream& ds, unsigned* u) { unsigned r = 0; if (ds.Peek() < '0' || ds.Peek() > '9') return false; while (ds.Peek() >= '0' && ds.Peek() <= '9') { if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295 return false; // overflow r = r * 10 + (ds.Take() - '0'); } *u = r; return true; } template bool ParseRange(DecodedStream& ds, SizeType* range) { bool isBegin = true; bool negate = false; int step = 0; SizeType start = kRegexInvalidRange; SizeType current = kRegexInvalidRange; unsigned codepoint; while ((codepoint = ds.Take()) != 0) { if (isBegin) { isBegin = false; if (codepoint == '^') { negate = true; continue; } } switch (codepoint) { case ']': if (start == kRegexInvalidRange) return false; // Error: nothing inside [] if (step == 2) { // Add trailing '-' SizeType r = NewRange('-'); RAPIDJSON_ASSERT(current != kRegexInvalidRange); GetRange(current).next = r; } if (negate) GetRange(start).start |= kRangeNegationFlag; *range = start; return true; case '\\': if (ds.Peek() == 'b') { ds.Take(); codepoint = 0x0008; // Escape backspace character } else if (!CharacterEscape(ds, &codepoint)) return false; // fall through to default default: switch (step) { case 1: if (codepoint == '-') { step++; break; } // fall through to step 0 for other characters case 0: { SizeType r = NewRange(codepoint); if (current != kRegexInvalidRange) GetRange(current).next = r; if (start == kRegexInvalidRange) start = r; current = r; } step = 1; break; default: RAPIDJSON_ASSERT(step == 2); GetRange(current).end = codepoint; step = 0; } } } return false; } SizeType NewRange(unsigned codepoint) { Range* r = ranges_.template Push(); r->start = r->end = codepoint; r->next = kRegexInvalidRange; return rangeCount_++; } template bool CharacterEscape(DecodedStream& ds, unsigned* escapedCodepoint) { unsigned codepoint; switch (codepoint = ds.Take()) { case '^': case '$': case '|': case '(': case ')': case '?': case '*': case '+': case '.': case '[': case ']': case '{': case '}': case '\\': *escapedCodepoint = codepoint; return true; case 'f': *escapedCodepoint = 0x000C; return true; case 'n': *escapedCodepoint = 0x000A; return true; case 'r': *escapedCodepoint = 0x000D; return true; case 't': *escapedCodepoint = 0x0009; return true; case 'v': *escapedCodepoint = 0x000B; return true; default: return false; // Unsupported escape character } } Stack states_; Stack ranges_; SizeType root_; SizeType stateCount_; SizeType rangeCount_; static const unsigned kInfinityQuantifier = ~0u; // For SearchWithAnchoring() bool anchorBegin_; bool anchorEnd_; }; template class GenericRegexSearch { public: typedef typename RegexType::EncodingType Encoding; typedef typename Encoding::Ch Ch; GenericRegexSearch(const RegexType& regex, Allocator* allocator = 0) : regex_(regex), allocator_(allocator), ownAllocator_(0), state0_(allocator, 0), state1_(allocator, 0), stateSet_() { RAPIDJSON_ASSERT(regex_.IsValid()); if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); stateSet_ = static_cast(allocator_->Malloc(GetStateSetSize())); state0_.template Reserve(regex_.stateCount_); state1_.template Reserve(regex_.stateCount_); } ~GenericRegexSearch() { Allocator::Free(stateSet_); RAPIDJSON_DELETE(ownAllocator_); } template bool Match(InputStream& is) { return SearchWithAnchoring(is, true, true); } bool Match(const Ch* s) { GenericStringStream is(s); return Match(is); } template bool Search(InputStream& is) { return SearchWithAnchoring(is, regex_.anchorBegin_, regex_.anchorEnd_); } bool Search(const Ch* s) { GenericStringStream is(s); return Search(is); } private: typedef typename RegexType::State State; typedef typename RegexType::Range Range; template bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) { DecodedStream ds(is); state0_.Clear(); Stack *current = &state0_, *next = &state1_; const size_t stateSetSize = GetStateSetSize(); std::memset(stateSet_, 0, stateSetSize); bool matched = AddState(*current, regex_.root_); unsigned codepoint; while (!current->Empty() && (codepoint = ds.Take()) != 0) { std::memset(stateSet_, 0, stateSetSize); next->Clear(); matched = false; for (const SizeType* s = current->template Bottom(); s != current->template End(); ++s) { const State& sr = regex_.GetState(*s); if (sr.codepoint == codepoint || sr.codepoint == RegexType::kAnyCharacterClass || (sr.codepoint == RegexType::kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint))) { matched = AddState(*next, sr.out) || matched; if (!anchorEnd && matched) return true; } if (!anchorBegin) AddState(*next, regex_.root_); } internal::Swap(current, next); } return matched; } size_t GetStateSetSize() const { return (regex_.stateCount_ + 31) / 32 * 4; } // Return whether the added states is a match state bool AddState(Stack& l, SizeType index) { RAPIDJSON_ASSERT(index != kRegexInvalidState); const State& s = regex_.GetState(index); if (s.out1 != kRegexInvalidState) { // Split bool matched = AddState(l, s.out); return AddState(l, s.out1) || matched; } else if (!(stateSet_[index >> 5] & (1u << (index & 31)))) { stateSet_[index >> 5] |= (1u << (index & 31)); *l.template PushUnsafe() = index; } return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation. } bool MatchRange(SizeType rangeIndex, unsigned codepoint) const { bool yes = (regex_.GetRange(rangeIndex).start & RegexType::kRangeNegationFlag) == 0; while (rangeIndex != kRegexInvalidRange) { const Range& r = regex_.GetRange(rangeIndex); if (codepoint >= (r.start & ~RegexType::kRangeNegationFlag) && codepoint <= r.end) return yes; rangeIndex = r.next; } return !yes; } const RegexType& regex_; Allocator* allocator_; Allocator* ownAllocator_; Stack state0_; Stack state1_; uint32_t* stateSet_; }; typedef GenericRegex > Regex; typedef GenericRegexSearch RegexSearch; } // namespace internal RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #ifdef _MSC_VER RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_INTERNAL_REGEX_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/stack.h0000644002537200234200000001562713213503245025426 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_INTERNAL_STACK_H_ #define RAPIDJSON_INTERNAL_STACK_H_ #include "../allocators.h" #include "swap.h" #if defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { /////////////////////////////////////////////////////////////////////////////// // Stack //! A type-unsafe stack for storing different types of data. /*! \tparam Allocator Allocator for allocating stack memory. */ template class Stack { public: // Optimization note: Do not allocate memory for stack_ in constructor. // Do it lazily when first Push() -> Expand() -> Resize(). Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) { } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS Stack(Stack&& rhs) : allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), stack_(rhs.stack_), stackTop_(rhs.stackTop_), stackEnd_(rhs.stackEnd_), initialCapacity_(rhs.initialCapacity_) { rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.stack_ = 0; rhs.stackTop_ = 0; rhs.stackEnd_ = 0; rhs.initialCapacity_ = 0; } #endif ~Stack() { Destroy(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS Stack& operator=(Stack&& rhs) { if (&rhs != this) { Destroy(); allocator_ = rhs.allocator_; ownAllocator_ = rhs.ownAllocator_; stack_ = rhs.stack_; stackTop_ = rhs.stackTop_; stackEnd_ = rhs.stackEnd_; initialCapacity_ = rhs.initialCapacity_; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.stack_ = 0; rhs.stackTop_ = 0; rhs.stackEnd_ = 0; rhs.initialCapacity_ = 0; } return *this; } #endif void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT { internal::Swap(allocator_, rhs.allocator_); internal::Swap(ownAllocator_, rhs.ownAllocator_); internal::Swap(stack_, rhs.stack_); internal::Swap(stackTop_, rhs.stackTop_); internal::Swap(stackEnd_, rhs.stackEnd_); internal::Swap(initialCapacity_, rhs.initialCapacity_); } void Clear() { stackTop_ = stack_; } void ShrinkToFit() { if (Empty()) { // If the stack is empty, completely deallocate the memory. Allocator::Free(stack_); stack_ = 0; stackTop_ = 0; stackEnd_ = 0; } else Resize(GetSize()); } // Optimization note: try to minimize the size of this function for force inline. // Expansion is run very infrequently, so it is moved to another (probably non-inline) function. template RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) { // Expand the stack if needed if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_)) Expand(count); } template RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) { Reserve(count); return PushUnsafe(count); } template RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) { RAPIDJSON_ASSERT(stackTop_); RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_); T* ret = reinterpret_cast(stackTop_); stackTop_ += sizeof(T) * count; return ret; } template T* Pop(size_t count) { RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T)); stackTop_ -= count * sizeof(T); return reinterpret_cast(stackTop_); } template T* Top() { RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); return reinterpret_cast(stackTop_ - sizeof(T)); } template const T* Top() const { RAPIDJSON_ASSERT(GetSize() >= sizeof(T)); return reinterpret_cast(stackTop_ - sizeof(T)); } template T* End() { return reinterpret_cast(stackTop_); } template const T* End() const { return reinterpret_cast(stackTop_); } template T* Bottom() { return reinterpret_cast(stack_); } template const T* Bottom() const { return reinterpret_cast(stack_); } bool HasAllocator() const { return allocator_ != 0; } Allocator& GetAllocator() { RAPIDJSON_ASSERT(allocator_); return *allocator_; } bool Empty() const { return stackTop_ == stack_; } size_t GetSize() const { return static_cast(stackTop_ - stack_); } size_t GetCapacity() const { return static_cast(stackEnd_ - stack_); } private: template void Expand(size_t count) { // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity. size_t newCapacity; if (stack_ == 0) { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); newCapacity = initialCapacity_; } else { newCapacity = GetCapacity(); newCapacity += (newCapacity + 1) / 2; } size_t newSize = GetSize() + sizeof(T) * count; if (newCapacity < newSize) newCapacity = newSize; Resize(newCapacity); } void Resize(size_t newCapacity) { const size_t size = GetSize(); // Backup the current size stack_ = static_cast(allocator_->Realloc(stack_, GetCapacity(), newCapacity)); stackTop_ = stack_ + size; stackEnd_ = stack_ + newCapacity; } void Destroy() { Allocator::Free(stack_); RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack } // Prohibit copy constructor & assignment operator. Stack(const Stack&); Stack& operator=(const Stack&); Allocator* allocator_; Allocator* ownAllocator_; char *stack_; char *stackTop_; char *stackEnd_; size_t initialCapacity_; }; } // namespace internal RAPIDJSON_NAMESPACE_END #if defined(__clang__) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_STACK_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/strtod.h0000644002537200234200000002064313213503245025632 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_STRTOD_ #define RAPIDJSON_STRTOD_ #include "ieee754.h" #include "biginteger.h" #include "diyfp.h" #include "pow10.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { inline double FastPath(double significand, int exp) { if (exp < -308) return 0.0; else if (exp >= 0) return significand * internal::Pow10(exp); else return significand / internal::Pow10(-exp); } inline double StrtodNormalPrecision(double d, int p) { if (p < -308) { // Prevent expSum < -308, making Pow10(p) = 0 d = FastPath(d, -308); d = FastPath(d, p + 308); } else d = FastPath(d, p); return d; } template inline T Min3(T a, T b, T c) { T m = a; if (m > b) m = b; if (m > c) m = c; return m; } inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { const Double db(b); const uint64_t bInt = db.IntegerSignificand(); const int bExp = db.IntegerExponent(); const int hExp = bExp - 1; int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; // Adjust for decimal exponent if (dExp >= 0) { dS_Exp2 += dExp; dS_Exp5 += dExp; } else { bS_Exp2 -= dExp; bS_Exp5 -= dExp; hS_Exp2 -= dExp; hS_Exp5 -= dExp; } // Adjust for binary exponent if (bExp >= 0) bS_Exp2 += bExp; else { dS_Exp2 -= bExp; hS_Exp2 -= bExp; } // Adjust for half ulp exponent if (hExp >= 0) hS_Exp2 += hExp; else { dS_Exp2 -= hExp; bS_Exp2 -= hExp; } // Remove common power of two factor from all three scaled values int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); dS_Exp2 -= common_Exp2; bS_Exp2 -= common_Exp2; hS_Exp2 -= common_Exp2; BigInteger dS = d; dS.MultiplyPow5(static_cast(dS_Exp5)) <<= static_cast(dS_Exp2); BigInteger bS(bInt); bS.MultiplyPow5(static_cast(bS_Exp5)) <<= static_cast(bS_Exp2); BigInteger hS(1); hS.MultiplyPow5(static_cast(hS_Exp5)) <<= static_cast(hS_Exp2); BigInteger delta(0); dS.Difference(bS, &delta); return delta.Compare(hS); } inline bool StrtodFast(double d, int p, double* result) { // Use fast path for string-to-double conversion if possible // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ if (p > 22 && p < 22 + 16) { // Fast Path Cases In Disguise d *= internal::Pow10(p - 22); p = 22; } if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 *result = FastPath(d, p); return true; } else return false; } // Compute an approximation and see if it is within 1/2 ULP inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { uint64_t significand = 0; size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 for (; i < length; i++) { if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) break; significand = significand * 10u + static_cast(decimals[i] - '0'); } if (i < length && decimals[i] >= '5') // Rounding significand++; size_t remaining = length - i; const int kUlpShift = 3; const int kUlp = 1 << kUlpShift; int64_t error = (remaining == 0) ? 0 : kUlp / 2; DiyFp v(significand, 0); v = v.Normalize(); error <<= -v.e; const int dExp = static_cast(decimalPosition) - static_cast(i) + exp; int actualExp; DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); if (actualExp != dExp) { static const DiyFp kPow10[] = { DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 }; int adjustment = dExp - actualExp - 1; RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); v = v * kPow10[adjustment]; if (length + static_cast(adjustment)> 19u) // has more digits than decimal digits in 64-bit error += kUlp / 2; } v = v * cachedPower; error += kUlp + (error == 0 ? 0 : 1); const int oldExp = v.e; v = v.Normalize(); error <<= oldExp - v.e; const int effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); int precisionSize = 64 - effectiveSignificandSize; if (precisionSize + kUlpShift >= 64) { int scaleExp = (precisionSize + kUlpShift) - 63; v.f >>= scaleExp; v.e += scaleExp; error = (error >> scaleExp) + 1 + kUlp; precisionSize -= scaleExp; } DiyFp rounded(v.f >> precisionSize, v.e + precisionSize); const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; if (precisionBits >= halfWay + static_cast(error)) { rounded.f++; if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) rounded.f >>= 1; rounded.e++; } } *result = rounded.ToDouble(); return halfWay - static_cast(error) >= precisionBits || precisionBits >= halfWay + static_cast(error); } inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { const BigInteger dInt(decimals, length); const int dExp = static_cast(decimalPosition) - static_cast(length) + exp; Double a(approx); int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); if (cmp < 0) return a.Value(); // within half ULP else if (cmp == 0) { // Round towards even if (a.Significand() & 1) return a.NextPositiveDouble(); else return a.Value(); } else // adjustment return a.NextPositiveDouble(); } inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { RAPIDJSON_ASSERT(d >= 0.0); RAPIDJSON_ASSERT(length >= 1); double result; if (StrtodFast(d, p, &result)) return result; // Trim leading zeros while (*decimals == '0' && length > 1) { length--; decimals++; decimalPosition--; } // Trim trailing zeros while (decimals[length - 1] == '0' && length > 1) { length--; decimalPosition--; exp++; } // Trim right-most digits const int kMaxDecimalDigit = 780; if (static_cast(length) > kMaxDecimalDigit) { int delta = (static_cast(length) - kMaxDecimalDigit); exp += delta; decimalPosition -= static_cast(delta); length = kMaxDecimalDigit; } // If too small, underflow to zero if (int(length) + exp < -324) return 0.0; if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) return result; // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison return StrtodBigInteger(result, decimals, length, decimalPosition, exp); } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_STRTOD_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/pow10.h0000644002537200234200000000701313213503245025255 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_POW10_ #define RAPIDJSON_POW10_ #include "../rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Computes integer powers of 10 in double (10.0^n). /*! This function uses lookup table for fast and accurate results. \param n non-negative exponent. Must <= 308. \return 10.0^n */ inline double Pow10(int n) { static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80, 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100, 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120, 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140, 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160, 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180, 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200, 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220, 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240, 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260, 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280, 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300, 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308 }; RAPIDJSON_ASSERT(n >= 0 && n <= 308); return e[n]; } } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_POW10_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/swap.h0000644002537200234200000000261313213503245025262 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_INTERNAL_SWAP_H_ #define RAPIDJSON_INTERNAL_SWAP_H_ #include "../rapidjson.h" #if defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { //! Custom swap() to avoid dependency on C++ header /*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only. \note This has the same semantics as std::swap(). */ template inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT { T tmp = a; a = b; b = tmp; } } // namespace internal RAPIDJSON_NAMESPACE_END #if defined(__clang__) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_INTERNAL_SWAP_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/biginteger.h0000644002537200234200000002166313213503245026435 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_BIGINTEGER_H_ #define RAPIDJSON_BIGINTEGER_H_ #include "../rapidjson.h" #if defined(_MSC_VER) && defined(_M_AMD64) #include // for _umul128 #pragma intrinsic(_umul128) #endif RAPIDJSON_NAMESPACE_BEGIN namespace internal { class BigInteger { public: typedef uint64_t Type; BigInteger(const BigInteger& rhs) : count_(rhs.count_) { std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); } explicit BigInteger(uint64_t u) : count_(1) { digits_[0] = u; } BigInteger(const char* decimals, size_t length) : count_(1) { RAPIDJSON_ASSERT(length > 0); digits_[0] = 0; size_t i = 0; const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19 while (length >= kMaxDigitPerIteration) { AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration); length -= kMaxDigitPerIteration; i += kMaxDigitPerIteration; } if (length > 0) AppendDecimal64(decimals + i, decimals + i + length); } BigInteger& operator=(const BigInteger &rhs) { if (this != &rhs) { count_ = rhs.count_; std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type)); } return *this; } BigInteger& operator=(uint64_t u) { digits_[0] = u; count_ = 1; return *this; } BigInteger& operator+=(uint64_t u) { Type backup = digits_[0]; digits_[0] += u; for (size_t i = 0; i < count_ - 1; i++) { if (digits_[i] >= backup) return *this; // no carry backup = digits_[i + 1]; digits_[i + 1] += 1; } // Last carry if (digits_[count_ - 1] < backup) PushBack(1); return *this; } BigInteger& operator*=(uint64_t u) { if (u == 0) return *this = 0; if (u == 1) return *this; if (*this == 1) return *this = u; uint64_t k = 0; for (size_t i = 0; i < count_; i++) { uint64_t hi; digits_[i] = MulAdd64(digits_[i], u, k, &hi); k = hi; } if (k > 0) PushBack(k); return *this; } BigInteger& operator*=(uint32_t u) { if (u == 0) return *this = 0; if (u == 1) return *this; if (*this == 1) return *this = u; uint64_t k = 0; for (size_t i = 0; i < count_; i++) { const uint64_t c = digits_[i] >> 32; const uint64_t d = digits_[i] & 0xFFFFFFFF; const uint64_t uc = u * c; const uint64_t ud = u * d; const uint64_t p0 = ud + k; const uint64_t p1 = uc + (p0 >> 32); digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32); k = p1 >> 32; } if (k > 0) PushBack(k); return *this; } BigInteger& operator<<=(size_t shift) { if (IsZero() || shift == 0) return *this; size_t offset = shift / kTypeBit; size_t interShift = shift % kTypeBit; RAPIDJSON_ASSERT(count_ + offset <= kCapacity); if (interShift == 0) { std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type)); count_ += offset; } else { digits_[count_] = 0; for (size_t i = count_; i > 0; i--) digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift)); digits_[offset] = digits_[0] << interShift; count_ += offset; if (digits_[count_]) count_++; } std::memset(digits_, 0, offset * sizeof(Type)); return *this; } bool operator==(const BigInteger& rhs) const { return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0; } bool operator==(const Type rhs) const { return count_ == 1 && digits_[0] == rhs; } BigInteger& MultiplyPow5(unsigned exp) { static const uint32_t kPow5[12] = { 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 * 5 * 5 * 5, 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 }; if (exp == 0) return *this; for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27 for (; exp >= 13; exp -= 13) *this *= static_cast(1220703125u); // 5^13 if (exp > 0) *this *= kPow5[exp - 1]; return *this; } // Compute absolute difference of this and rhs. // Assume this != rhs bool Difference(const BigInteger& rhs, BigInteger* out) const { int cmp = Compare(rhs); RAPIDJSON_ASSERT(cmp != 0); const BigInteger *a, *b; // Makes a > b bool ret; if (cmp < 0) { a = &rhs; b = this; ret = true; } else { a = this; b = &rhs; ret = false; } Type borrow = 0; for (size_t i = 0; i < a->count_; i++) { Type d = a->digits_[i] - borrow; if (i < b->count_) d -= b->digits_[i]; borrow = (d > a->digits_[i]) ? 1 : 0; out->digits_[i] = d; if (d != 0) out->count_ = i + 1; } return ret; } int Compare(const BigInteger& rhs) const { if (count_ != rhs.count_) return count_ < rhs.count_ ? -1 : 1; for (size_t i = count_; i-- > 0;) if (digits_[i] != rhs.digits_[i]) return digits_[i] < rhs.digits_[i] ? -1 : 1; return 0; } size_t GetCount() const { return count_; } Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; } bool IsZero() const { return count_ == 1 && digits_[0] == 0; } private: void AppendDecimal64(const char* begin, const char* end) { uint64_t u = ParseUint64(begin, end); if (IsZero()) *this = u; else { unsigned exp = static_cast(end - begin); (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u } } void PushBack(Type digit) { RAPIDJSON_ASSERT(count_ < kCapacity); digits_[count_++] = digit; } static uint64_t ParseUint64(const char* begin, const char* end) { uint64_t r = 0; for (const char* p = begin; p != end; ++p) { RAPIDJSON_ASSERT(*p >= '0' && *p <= '9'); r = r * 10u + static_cast(*p - '0'); } return r; } // Assume a * b + k < 2^128 static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) { #if defined(_MSC_VER) && defined(_M_AMD64) uint64_t low = _umul128(a, b, outHigh) + k; if (low < k) (*outHigh)++; return low; #elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__) __extension__ typedef unsigned __int128 uint128; uint128 p = static_cast(a) * static_cast(b); p += k; *outHigh = static_cast(p >> 64); return static_cast(p); #else const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32; uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1; x1 += (x0 >> 32); // can't give carry x1 += x2; if (x1 < x2) x3 += (static_cast(1) << 32); uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF); uint64_t hi = x3 + (x1 >> 32); lo += k; if (lo < k) hi++; *outHigh = hi; return lo; #endif } static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000 static const size_t kCapacity = kBitCount / sizeof(Type); static const size_t kTypeBit = sizeof(Type) * 8; Type digits_[kCapacity]; size_t count_; }; } // namespace internal RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_BIGINTEGER_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/internal/meta.h0000644002537200234200000001465413213503245025246 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_INTERNAL_META_H_ #define RAPIDJSON_INTERNAL_META_H_ #include "../rapidjson.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #if defined(_MSC_VER) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(6334) #endif #if RAPIDJSON_HAS_CXX11_TYPETRAITS #include #endif //@cond RAPIDJSON_INTERNAL RAPIDJSON_NAMESPACE_BEGIN namespace internal { // Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching template struct Void { typedef void Type; }; /////////////////////////////////////////////////////////////////////////////// // BoolType, TrueType, FalseType // template struct BoolType { static const bool Value = Cond; typedef BoolType Type; }; typedef BoolType TrueType; typedef BoolType FalseType; /////////////////////////////////////////////////////////////////////////////// // SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr // template struct SelectIfImpl { template struct Apply { typedef T1 Type; }; }; template <> struct SelectIfImpl { template struct Apply { typedef T2 Type; }; }; template struct SelectIfCond : SelectIfImpl::template Apply {}; template struct SelectIf : SelectIfCond {}; template struct AndExprCond : FalseType {}; template <> struct AndExprCond : TrueType {}; template struct OrExprCond : TrueType {}; template <> struct OrExprCond : FalseType {}; template struct BoolExpr : SelectIf::Type {}; template struct NotExpr : SelectIf::Type {}; template struct AndExpr : AndExprCond::Type {}; template struct OrExpr : OrExprCond::Type {}; /////////////////////////////////////////////////////////////////////////////// // AddConst, MaybeAddConst, RemoveConst template struct AddConst { typedef const T Type; }; template struct MaybeAddConst : SelectIfCond {}; template struct RemoveConst { typedef T Type; }; template struct RemoveConst { typedef T Type; }; /////////////////////////////////////////////////////////////////////////////// // IsSame, IsConst, IsMoreConst, IsPointer // template struct IsSame : FalseType {}; template struct IsSame : TrueType {}; template struct IsConst : FalseType {}; template struct IsConst : TrueType {}; template struct IsMoreConst : AndExpr::Type, typename RemoveConst::Type>, BoolType::Value >= IsConst::Value> >::Type {}; template struct IsPointer : FalseType {}; template struct IsPointer : TrueType {}; /////////////////////////////////////////////////////////////////////////////// // IsBaseOf // #if RAPIDJSON_HAS_CXX11_TYPETRAITS template struct IsBaseOf : BoolType< ::std::is_base_of::value> {}; #else // simplified version adopted from Boost template struct IsBaseOfImpl { RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0); RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0); typedef char (&Yes)[1]; typedef char (&No) [2]; template static Yes Check(const D*, T); static No Check(const B*, int); struct Host { operator const B*() const; operator const D*(); }; enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) }; }; template struct IsBaseOf : OrExpr, BoolExpr > >::Type {}; #endif // RAPIDJSON_HAS_CXX11_TYPETRAITS ////////////////////////////////////////////////////////////////////////// // EnableIf / DisableIf // template struct EnableIfCond { typedef T Type; }; template struct EnableIfCond { /* empty */ }; template struct DisableIfCond { typedef T Type; }; template struct DisableIfCond { /* empty */ }; template struct EnableIf : EnableIfCond {}; template struct DisableIf : DisableIfCond {}; // SFINAE helpers struct SfinaeTag {}; template struct RemoveSfinaeTag; template struct RemoveSfinaeTag { typedef T Type; }; #define RAPIDJSON_REMOVEFPTR_(type) \ typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \ < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type #define RAPIDJSON_ENABLEIF(cond) \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ ::Type * = NULL #define RAPIDJSON_DISABLEIF(cond) \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ ::Type * = NULL #define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \ ::Type #define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \ ::Type } // namespace internal RAPIDJSON_NAMESPACE_END //@endcond #if defined(__GNUC__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_INTERNAL_META_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/filereadstream.h0000644002537200234200000000565413213503245025473 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_FILEREADSTREAM_H_ #define RAPIDJSON_FILEREADSTREAM_H_ #include "stream.h" #include #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(missing-noreturn) #endif RAPIDJSON_NAMESPACE_BEGIN //! File byte stream for input using fread(). /*! \note implements Stream concept */ class FileReadStream { public: typedef char Ch; //!< Character type (byte). //! Constructor. /*! \param fp File pointer opened for read. \param buffer user-supplied buffer. \param bufferSize size of buffer in bytes. Must >=4 bytes. */ FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { RAPIDJSON_ASSERT(fp_ != 0); RAPIDJSON_ASSERT(bufferSize >= 4); Read(); } Ch Peek() const { return *current_; } Ch Take() { Ch c = *current_; Read(); return c; } size_t Tell() const { return count_ + static_cast(current_ - buffer_); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. const Ch* Peek4() const { return (current_ + 4 <= bufferLast_) ? current_ : 0; } private: void Read() { if (current_ < bufferLast_) ++current_; else if (!eof_) { count_ += readCount_; readCount_ = fread(buffer_, 1, bufferSize_, fp_); bufferLast_ = buffer_ + readCount_ - 1; current_ = buffer_; if (readCount_ < bufferSize_) { buffer_[readCount_] = '\0'; ++bufferLast_; eof_ = true; } } } std::FILE* fp_; Ch *buffer_; size_t bufferSize_; Ch *bufferLast_; Ch *current_; size_t readCount_; size_t count_; //!< Number of characters read bool eof_; }; RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_FILESTREAM_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/schema.h0000644002537200234200000023516613213503245023747 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available-> // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved-> // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License-> You may obtain a copy of the License at // // http://opensource->org/licenses/MIT // // 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-> #ifndef RAPIDJSON_SCHEMA_H_ #define RAPIDJSON_SCHEMA_H_ #include "document.h" #include "pointer.h" #include // abs, floor #if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX) #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1 #else #define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0 #endif #if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800)) #define RAPIDJSON_SCHEMA_USE_STDREGEX 1 #else #define RAPIDJSON_SCHEMA_USE_STDREGEX 0 #endif #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX #include "internal/regex.h" #elif RAPIDJSON_SCHEMA_USE_STDREGEX #include #endif #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX #define RAPIDJSON_SCHEMA_HAS_REGEX 1 #else #define RAPIDJSON_SCHEMA_HAS_REGEX 0 #endif #ifndef RAPIDJSON_SCHEMA_VERBOSE #define RAPIDJSON_SCHEMA_VERBOSE 0 #endif #if RAPIDJSON_SCHEMA_VERBOSE #include "stringbuffer.h" #endif RAPIDJSON_DIAG_PUSH #if defined(__GNUC__) RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef __clang__ RAPIDJSON_DIAG_OFF(weak-vtables) RAPIDJSON_DIAG_OFF(exit-time-destructors) RAPIDJSON_DIAG_OFF(c++98-compat-pedantic) RAPIDJSON_DIAG_OFF(variadic-macros) #endif #ifdef _MSC_VER RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Verbose Utilities #if RAPIDJSON_SCHEMA_VERBOSE namespace internal { inline void PrintInvalidKeyword(const char* keyword) { printf("Fail keyword: %s\n", keyword); } inline void PrintInvalidKeyword(const wchar_t* keyword) { wprintf(L"Fail keyword: %ls\n", keyword); } inline void PrintInvalidDocument(const char* document) { printf("Fail document: %s\n\n", document); } inline void PrintInvalidDocument(const wchar_t* document) { wprintf(L"Fail document: %ls\n\n", document); } inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) { printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d); } inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) { wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d); } } // namespace internal #endif // RAPIDJSON_SCHEMA_VERBOSE /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_INVALID_KEYWORD_RETURN #if RAPIDJSON_SCHEMA_VERBOSE #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword) #else #define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) #endif #define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\ RAPIDJSON_MULTILINEMACRO_BEGIN\ context.invalidKeyword = keyword.GetString();\ RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\ return false;\ RAPIDJSON_MULTILINEMACRO_END /////////////////////////////////////////////////////////////////////////////// // Forward declarations template class GenericSchemaDocument; namespace internal { template class Schema; /////////////////////////////////////////////////////////////////////////////// // ISchemaValidator class ISchemaValidator { public: virtual ~ISchemaValidator() {} virtual bool IsValid() const = 0; }; /////////////////////////////////////////////////////////////////////////////// // ISchemaStateFactory template class ISchemaStateFactory { public: virtual ~ISchemaStateFactory() {} virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0; virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0; virtual void* CreateHasher() = 0; virtual uint64_t GetHashCode(void* hasher) = 0; virtual void DestroryHasher(void* hasher) = 0; virtual void* MallocState(size_t size) = 0; virtual void FreeState(void* p) = 0; }; /////////////////////////////////////////////////////////////////////////////// // Hasher // For comparison of compound value template class Hasher { public: typedef typename Encoding::Ch Ch; Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {} bool Null() { return WriteType(kNullType); } bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); } bool Int(int i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast(i); return WriteNumber(n); } bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast(u); return WriteNumber(n); } bool Double(double d) { Number n; if (d < 0) n.u.i = static_cast(d); else n.u.u = static_cast(d); n.d = d; return WriteNumber(n); } bool RawNumber(const Ch* str, SizeType len, bool) { WriteBuffer(kNumberType, str, len * sizeof(Ch)); return true; } bool String(const Ch* str, SizeType len, bool) { WriteBuffer(kStringType, str, len * sizeof(Ch)); return true; } bool StartObject() { return true; } bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); } bool EndObject(SizeType memberCount) { uint64_t h = Hash(0, kObjectType); uint64_t* kv = stack_.template Pop(memberCount * 2); for (SizeType i = 0; i < memberCount; i++) h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive *stack_.template Push() = h; return true; } bool StartArray() { return true; } bool EndArray(SizeType elementCount) { uint64_t h = Hash(0, kArrayType); uint64_t* e = stack_.template Pop(elementCount); for (SizeType i = 0; i < elementCount; i++) h = Hash(h, e[i]); // Use hash to achieve element order sensitive *stack_.template Push() = h; return true; } bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); } uint64_t GetHashCode() const { RAPIDJSON_ASSERT(IsValid()); return *stack_.template Top(); } private: static const size_t kDefaultSize = 256; struct Number { union U { uint64_t u; int64_t i; }u; double d; }; bool WriteType(Type type) { return WriteBuffer(type, 0, 0); } bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); } bool WriteBuffer(Type type, const void* data, size_t len) { // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/ uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type); const unsigned char* d = static_cast(data); for (size_t i = 0; i < len; i++) h = Hash(h, d[i]); *stack_.template Push() = h; return true; } static uint64_t Hash(uint64_t h, uint64_t d) { static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3); h ^= d; h *= kPrime; return h; } Stack stack_; }; /////////////////////////////////////////////////////////////////////////////// // SchemaValidationContext template struct SchemaValidationContext { typedef Schema SchemaType; typedef ISchemaStateFactory SchemaValidatorFactoryType; typedef typename SchemaType::ValueType ValueType; typedef typename ValueType::Ch Ch; enum PatternValidatorType { kPatternValidatorOnly, kPatternValidatorWithProperty, kPatternValidatorWithAdditionalProperty }; SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) : factory(f), schema(s), valueSchema(), invalidKeyword(), hasher(), arrayElementHashCodes(), validators(), validatorCount(), patternPropertiesValidators(), patternPropertiesValidatorCount(), patternPropertiesSchemas(), patternPropertiesSchemaCount(), valuePatternValidatorType(kPatternValidatorOnly), propertyExist(), inArray(false), valueUniqueness(false), arrayUniqueness(false) { } ~SchemaValidationContext() { if (hasher) factory.DestroryHasher(hasher); if (validators) { for (SizeType i = 0; i < validatorCount; i++) factory.DestroySchemaValidator(validators[i]); factory.FreeState(validators); } if (patternPropertiesValidators) { for (SizeType i = 0; i < patternPropertiesValidatorCount; i++) factory.DestroySchemaValidator(patternPropertiesValidators[i]); factory.FreeState(patternPropertiesValidators); } if (patternPropertiesSchemas) factory.FreeState(patternPropertiesSchemas); if (propertyExist) factory.FreeState(propertyExist); } SchemaValidatorFactoryType& factory; const SchemaType* schema; const SchemaType* valueSchema; const Ch* invalidKeyword; void* hasher; // Only validator access void* arrayElementHashCodes; // Only validator access this ISchemaValidator** validators; SizeType validatorCount; ISchemaValidator** patternPropertiesValidators; SizeType patternPropertiesValidatorCount; const SchemaType** patternPropertiesSchemas; SizeType patternPropertiesSchemaCount; PatternValidatorType valuePatternValidatorType; PatternValidatorType objectPatternValidatorType; SizeType arrayElementIndex; bool* propertyExist; bool inArray; bool valueUniqueness; bool arrayUniqueness; }; /////////////////////////////////////////////////////////////////////////////// // Schema template class Schema { public: typedef typename SchemaDocumentType::ValueType ValueType; typedef typename SchemaDocumentType::AllocatorType AllocatorType; typedef typename SchemaDocumentType::PointerType PointerType; typedef typename ValueType::EncodingType EncodingType; typedef typename EncodingType::Ch Ch; typedef SchemaValidationContext Context; typedef Schema SchemaType; typedef GenericValue SValue; friend class GenericSchemaDocument; Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) : allocator_(allocator), typeless_(schemaDocument->GetTypeless()), enum_(), enumCount_(), not_(), type_((1 << kTotalSchemaType) - 1), // typeless validatorCount_(), properties_(), additionalPropertiesSchema_(), patternProperties_(), patternPropertyCount_(), propertyCount_(), minProperties_(), maxProperties_(SizeType(~0)), additionalProperties_(true), hasDependencies_(), hasRequired_(), hasSchemaDependencies_(), additionalItemsSchema_(), itemsList_(), itemsTuple_(), itemsTupleCount_(), minItems_(), maxItems_(SizeType(~0)), additionalItems_(true), uniqueItems_(false), pattern_(), minLength_(0), maxLength_(~SizeType(0)), exclusiveMinimum_(false), exclusiveMaximum_(false) { typedef typename SchemaDocumentType::ValueType ValueType; typedef typename ValueType::ConstValueIterator ConstValueIterator; typedef typename ValueType::ConstMemberIterator ConstMemberIterator; if (!value.IsObject()) return; if (const ValueType* v = GetMember(value, GetTypeString())) { type_ = 0; if (v->IsString()) AddType(*v); else if (v->IsArray()) for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) AddType(*itr); } if (const ValueType* v = GetMember(value, GetEnumString())) if (v->IsArray() && v->Size() > 0) { enum_ = static_cast(allocator_->Malloc(sizeof(uint64_t) * v->Size())); for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) { typedef Hasher > EnumHasherType; char buffer[256 + 24]; MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer)); EnumHasherType h(&hasherAllocator, 256); itr->Accept(h); enum_[enumCount_++] = h.GetHashCode(); } } if (schemaDocument) { AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document); AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document); AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document); } if (const ValueType* v = GetMember(value, GetNotString())) { schemaDocument->CreateSchema(¬_, p.Append(GetNotString(), allocator_), *v, document); notValidatorIndex_ = validatorCount_; validatorCount_++; } // Object const ValueType* properties = GetMember(value, GetPropertiesString()); const ValueType* required = GetMember(value, GetRequiredString()); const ValueType* dependencies = GetMember(value, GetDependenciesString()); { // Gather properties from properties/required/dependencies SValue allProperties(kArrayType); if (properties && properties->IsObject()) for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) AddUniqueElement(allProperties, itr->name); if (required && required->IsArray()) for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) if (itr->IsString()) AddUniqueElement(allProperties, *itr); if (dependencies && dependencies->IsObject()) for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { AddUniqueElement(allProperties, itr->name); if (itr->value.IsArray()) for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i) if (i->IsString()) AddUniqueElement(allProperties, *i); } if (allProperties.Size() > 0) { propertyCount_ = allProperties.Size(); properties_ = static_cast(allocator_->Malloc(sizeof(Property) * propertyCount_)); for (SizeType i = 0; i < propertyCount_; i++) { new (&properties_[i]) Property(); properties_[i].name = allProperties[i]; properties_[i].schema = typeless_; } } } if (properties && properties->IsObject()) { PointerType q = p.Append(GetPropertiesString(), allocator_); for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) { SizeType index; if (FindPropertyIndex(itr->name, &index)) schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document); } } if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) { PointerType q = p.Append(GetPatternPropertiesString(), allocator_); patternProperties_ = static_cast(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount())); patternPropertyCount_ = 0; for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) { new (&patternProperties_[patternPropertyCount_]) PatternProperty(); patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name); schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document); patternPropertyCount_++; } } if (required && required->IsArray()) for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr) if (itr->IsString()) { SizeType index; if (FindPropertyIndex(*itr, &index)) { properties_[index].required = true; hasRequired_ = true; } } if (dependencies && dependencies->IsObject()) { PointerType q = p.Append(GetDependenciesString(), allocator_); hasDependencies_ = true; for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) { SizeType sourceIndex; if (FindPropertyIndex(itr->name, &sourceIndex)) { if (itr->value.IsArray()) { properties_[sourceIndex].dependencies = static_cast(allocator_->Malloc(sizeof(bool) * propertyCount_)); std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_); for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) { SizeType targetIndex; if (FindPropertyIndex(*targetItr, &targetIndex)) properties_[sourceIndex].dependencies[targetIndex] = true; } } else if (itr->value.IsObject()) { hasSchemaDependencies_ = true; schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document); properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_; validatorCount_++; } } } } if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) { if (v->IsBool()) additionalProperties_ = v->GetBool(); else if (v->IsObject()) schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document); } AssignIfExist(minProperties_, value, GetMinPropertiesString()); AssignIfExist(maxProperties_, value, GetMaxPropertiesString()); // Array if (const ValueType* v = GetMember(value, GetItemsString())) { PointerType q = p.Append(GetItemsString(), allocator_); if (v->IsObject()) // List validation schemaDocument->CreateSchema(&itemsList_, q, *v, document); else if (v->IsArray()) { // Tuple validation itemsTuple_ = static_cast(allocator_->Malloc(sizeof(const Schema*) * v->Size())); SizeType index = 0; for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++) schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document); } } AssignIfExist(minItems_, value, GetMinItemsString()); AssignIfExist(maxItems_, value, GetMaxItemsString()); if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) { if (v->IsBool()) additionalItems_ = v->GetBool(); else if (v->IsObject()) schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document); } AssignIfExist(uniqueItems_, value, GetUniqueItemsString()); // String AssignIfExist(minLength_, value, GetMinLengthString()); AssignIfExist(maxLength_, value, GetMaxLengthString()); if (const ValueType* v = GetMember(value, GetPatternString())) pattern_ = CreatePattern(*v); // Number if (const ValueType* v = GetMember(value, GetMinimumString())) if (v->IsNumber()) minimum_.CopyFrom(*v, *allocator_); if (const ValueType* v = GetMember(value, GetMaximumString())) if (v->IsNumber()) maximum_.CopyFrom(*v, *allocator_); AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString()); AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString()); if (const ValueType* v = GetMember(value, GetMultipleOfString())) if (v->IsNumber() && v->GetDouble() > 0.0) multipleOf_.CopyFrom(*v, *allocator_); } ~Schema() { AllocatorType::Free(enum_); if (properties_) { for (SizeType i = 0; i < propertyCount_; i++) properties_[i].~Property(); AllocatorType::Free(properties_); } if (patternProperties_) { for (SizeType i = 0; i < patternPropertyCount_; i++) patternProperties_[i].~PatternProperty(); AllocatorType::Free(patternProperties_); } AllocatorType::Free(itemsTuple_); #if RAPIDJSON_SCHEMA_HAS_REGEX if (pattern_) { pattern_->~RegexType(); AllocatorType::Free(pattern_); } #endif } bool BeginValue(Context& context) const { if (context.inArray) { if (uniqueItems_) context.valueUniqueness = true; if (itemsList_) context.valueSchema = itemsList_; else if (itemsTuple_) { if (context.arrayElementIndex < itemsTupleCount_) context.valueSchema = itemsTuple_[context.arrayElementIndex]; else if (additionalItemsSchema_) context.valueSchema = additionalItemsSchema_; else if (additionalItems_) context.valueSchema = typeless_; else RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString()); } else context.valueSchema = typeless_; context.arrayElementIndex++; } return true; } RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const { if (context.patternPropertiesValidatorCount > 0) { bool otherValid = false; SizeType count = context.patternPropertiesValidatorCount; if (context.objectPatternValidatorType != Context::kPatternValidatorOnly) otherValid = context.patternPropertiesValidators[--count]->IsValid(); bool patternValid = true; for (SizeType i = 0; i < count; i++) if (!context.patternPropertiesValidators[i]->IsValid()) { patternValid = false; break; } if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) { if (!patternValid) RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); } else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) { if (!patternValid || !otherValid) RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); } else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty) RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString()); } if (enum_) { const uint64_t h = context.factory.GetHashCode(context.hasher); for (SizeType i = 0; i < enumCount_; i++) if (enum_[i] == h) goto foundEnum; RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString()); foundEnum:; } if (allOf_.schemas) for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++) if (!context.validators[i]->IsValid()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString()); if (anyOf_.schemas) { for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++) if (context.validators[i]->IsValid()) goto foundAny; RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString()); foundAny:; } if (oneOf_.schemas) { bool oneValid = false; for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++) if (context.validators[i]->IsValid()) { if (oneValid) RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); else oneValid = true; } if (!oneValid) RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString()); } if (not_ && context.validators[notValidatorIndex_]->IsValid()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString()); return true; } bool Null(Context& context) const { if (!(type_ & (1 << kNullSchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); return CreateParallelValidator(context); } bool Bool(Context& context, bool) const { if (!(type_ & (1 << kBooleanSchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); return CreateParallelValidator(context); } bool Int(Context& context, int i) const { if (!CheckInt(context, i)) return false; return CreateParallelValidator(context); } bool Uint(Context& context, unsigned u) const { if (!CheckUint(context, u)) return false; return CreateParallelValidator(context); } bool Int64(Context& context, int64_t i) const { if (!CheckInt(context, i)) return false; return CreateParallelValidator(context); } bool Uint64(Context& context, uint64_t u) const { if (!CheckUint(context, u)) return false; return CreateParallelValidator(context); } bool Double(Context& context, double d) const { if (!(type_ & (1 << kNumberSchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d)) return false; if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d)) return false; if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d)) return false; return CreateParallelValidator(context); } bool String(Context& context, const Ch* str, SizeType length, bool) const { if (!(type_ & (1 << kStringSchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); if (minLength_ != 0 || maxLength_ != SizeType(~0)) { SizeType count; if (internal::CountStringCodePoint(str, length, &count)) { if (count < minLength_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString()); if (count > maxLength_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString()); } } if (pattern_ && !IsPatternMatch(pattern_, str, length)) RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString()); return CreateParallelValidator(context); } bool StartObject(Context& context) const { if (!(type_ & (1 << kObjectSchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); if (hasDependencies_ || hasRequired_) { context.propertyExist = static_cast(context.factory.MallocState(sizeof(bool) * propertyCount_)); std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_); } if (patternProperties_) { // pre-allocate schema array SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType context.patternPropertiesSchemas = static_cast(context.factory.MallocState(sizeof(const SchemaType*) * count)); context.patternPropertiesSchemaCount = 0; std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count); } return CreateParallelValidator(context); } bool Key(Context& context, const Ch* str, SizeType len, bool) const { if (patternProperties_) { context.patternPropertiesSchemaCount = 0; for (SizeType i = 0; i < patternPropertyCount_; i++) if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len)) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema; context.valueSchema = typeless_; } } SizeType index; if (FindPropertyIndex(ValueType(str, len).Move(), &index)) { if (context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema; context.valueSchema = typeless_; context.valuePatternValidatorType = Context::kPatternValidatorWithProperty; } else context.valueSchema = properties_[index].schema; if (context.propertyExist) context.propertyExist[index] = true; return true; } if (additionalPropertiesSchema_) { if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) { context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_; context.valueSchema = typeless_; context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty; } else context.valueSchema = additionalPropertiesSchema_; return true; } else if (additionalProperties_) { context.valueSchema = typeless_; return true; } if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString()); return true; } bool EndObject(Context& context, SizeType memberCount) const { if (hasRequired_) for (SizeType index = 0; index < propertyCount_; index++) if (properties_[index].required) if (!context.propertyExist[index]) RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString()); if (memberCount < minProperties_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString()); if (memberCount > maxProperties_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString()); if (hasDependencies_) { for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++) if (context.propertyExist[sourceIndex]) { if (properties_[sourceIndex].dependencies) { for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++) if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex]) RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); } else if (properties_[sourceIndex].dependenciesSchema) if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString()); } } return true; } bool StartArray(Context& context) const { if (!(type_ & (1 << kArraySchemaType))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); context.arrayElementIndex = 0; context.inArray = true; return CreateParallelValidator(context); } bool EndArray(Context& context, SizeType elementCount) const { context.inArray = false; if (elementCount < minItems_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString()); if (elementCount > maxItems_) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString()); return true; } // Generate functions for string literal according to Ch #define RAPIDJSON_STRING_(name, ...) \ static const ValueType& Get##name##String() {\ static const Ch s[] = { __VA_ARGS__, '\0' };\ static const ValueType v(s, static_cast(sizeof(s) / sizeof(Ch) - 1));\ return v;\ } RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l') RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n') RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't') RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y') RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g') RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r') RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r') RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e') RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm') RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f') RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f') RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f') RAPIDJSON_STRING_(Not, 'n', 'o', 't') RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd') RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's') RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's') RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's') RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's') RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's') RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's') RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's') RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h') RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h') RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n') RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm') RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f') #undef RAPIDJSON_STRING_ private: enum SchemaValueType { kNullSchemaType, kBooleanSchemaType, kObjectSchemaType, kArraySchemaType, kStringSchemaType, kNumberSchemaType, kIntegerSchemaType, kTotalSchemaType }; #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX typedef internal::GenericRegex RegexType; #elif RAPIDJSON_SCHEMA_USE_STDREGEX typedef std::basic_regex RegexType; #else typedef char RegexType; #endif struct SchemaArray { SchemaArray() : schemas(), count() {} ~SchemaArray() { AllocatorType::Free(schemas); } const SchemaType** schemas; SizeType begin; // begin index of context.validators SizeType count; }; template void AddUniqueElement(V1& a, const V2& v) { for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr) if (*itr == v) return; V1 c(v, *allocator_); a.PushBack(c, *allocator_); } static const ValueType* GetMember(const ValueType& value, const ValueType& name) { typename ValueType::ConstMemberIterator itr = value.FindMember(name); return itr != value.MemberEnd() ? &(itr->value) : 0; } static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) { if (const ValueType* v = GetMember(value, name)) if (v->IsBool()) out = v->GetBool(); } static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) { if (const ValueType* v = GetMember(value, name)) if (v->IsUint64() && v->GetUint64() <= SizeType(~0)) out = static_cast(v->GetUint64()); } void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) { if (const ValueType* v = GetMember(value, name)) { if (v->IsArray() && v->Size() > 0) { PointerType q = p.Append(name, allocator_); out.count = v->Size(); out.schemas = static_cast(allocator_->Malloc(out.count * sizeof(const Schema*))); memset(out.schemas, 0, sizeof(Schema*)* out.count); for (SizeType i = 0; i < out.count; i++) schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document); out.begin = validatorCount_; validatorCount_ += out.count; } } } #if RAPIDJSON_SCHEMA_USE_INTERNALREGEX template RegexType* CreatePattern(const ValueType& value) { if (value.IsString()) { RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString()); if (!r->IsValid()) { r->~RegexType(); AllocatorType::Free(r); r = 0; } return r; } return 0; } static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) { GenericRegexSearch rs(*pattern); return rs.Search(str); } #elif RAPIDJSON_SCHEMA_USE_STDREGEX template RegexType* CreatePattern(const ValueType& value) { if (value.IsString()) try { return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript); } catch (const std::regex_error&) { } return 0; } static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) { std::match_results r; return std::regex_search(str, str + length, r, *pattern); } #else template RegexType* CreatePattern(const ValueType&) { return 0; } static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; } #endif // RAPIDJSON_SCHEMA_USE_STDREGEX void AddType(const ValueType& type) { if (type == GetNullString() ) type_ |= 1 << kNullSchemaType; else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType; else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType; else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType; else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType; else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType; else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType); } bool CreateParallelValidator(Context& context) const { if (enum_ || context.arrayUniqueness) context.hasher = context.factory.CreateHasher(); if (validatorCount_) { RAPIDJSON_ASSERT(context.validators == 0); context.validators = static_cast(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_)); context.validatorCount = validatorCount_; if (allOf_.schemas) CreateSchemaValidators(context, allOf_); if (anyOf_.schemas) CreateSchemaValidators(context, anyOf_); if (oneOf_.schemas) CreateSchemaValidators(context, oneOf_); if (not_) context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_); if (hasSchemaDependencies_) { for (SizeType i = 0; i < propertyCount_; i++) if (properties_[i].dependenciesSchema) context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema); } } return true; } void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const { for (SizeType i = 0; i < schemas.count; i++) context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]); } // O(n) bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const { SizeType len = name.GetStringLength(); const Ch* str = name.GetString(); for (SizeType index = 0; index < propertyCount_; index++) if (properties_[index].name.GetStringLength() == len && (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0)) { *outIndex = index; return true; } return false; } bool CheckInt(Context& context, int64_t i) const { if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); if (!minimum_.IsNull()) { if (minimum_.IsInt64()) { if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); } else if (minimum_.IsUint64()) { RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64() } else if (!CheckDoubleMinimum(context, static_cast(i))) return false; } if (!maximum_.IsNull()) { if (maximum_.IsInt64()) { if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); } else if (maximum_.IsUint64()) { } /* do nothing */ // i <= max(int64_t) < maximum_.GetUint64() else if (!CheckDoubleMaximum(context, static_cast(i))) return false; } if (!multipleOf_.IsNull()) { if (multipleOf_.IsUint64()) { if (static_cast(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); } else if (!CheckDoubleMultipleOf(context, static_cast(i))) return false; } return true; } bool CheckUint(Context& context, uint64_t i) const { if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType)))) RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString()); if (!minimum_.IsNull()) { if (minimum_.IsUint64()) { if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); } else if (minimum_.IsInt64()) /* do nothing */; // i >= 0 > minimum.Getint64() else if (!CheckDoubleMinimum(context, static_cast(i))) return false; } if (!maximum_.IsNull()) { if (maximum_.IsUint64()) { if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); } else if (maximum_.IsInt64()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_ else if (!CheckDoubleMaximum(context, static_cast(i))) return false; } if (!multipleOf_.IsNull()) { if (multipleOf_.IsUint64()) { if (i % multipleOf_.GetUint64() != 0) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); } else if (!CheckDoubleMultipleOf(context, static_cast(i))) return false; } return true; } bool CheckDoubleMinimum(Context& context, double d) const { if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); return true; } bool CheckDoubleMaximum(Context& context, double d) const { if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble()) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); return true; } bool CheckDoubleMultipleOf(Context& context, double d) const { double a = std::abs(d), b = std::abs(multipleOf_.GetDouble()); double q = std::floor(a / b); double r = a - q * b; if (r > 0.0) RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString()); return true; } struct Property { Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {} ~Property() { AllocatorType::Free(dependencies); } SValue name; const SchemaType* schema; const SchemaType* dependenciesSchema; SizeType dependenciesValidatorIndex; bool* dependencies; bool required; }; struct PatternProperty { PatternProperty() : schema(), pattern() {} ~PatternProperty() { if (pattern) { pattern->~RegexType(); AllocatorType::Free(pattern); } } const SchemaType* schema; RegexType* pattern; }; AllocatorType* allocator_; const SchemaType* typeless_; uint64_t* enum_; SizeType enumCount_; SchemaArray allOf_; SchemaArray anyOf_; SchemaArray oneOf_; const SchemaType* not_; unsigned type_; // bitmask of kSchemaType SizeType validatorCount_; SizeType notValidatorIndex_; Property* properties_; const SchemaType* additionalPropertiesSchema_; PatternProperty* patternProperties_; SizeType patternPropertyCount_; SizeType propertyCount_; SizeType minProperties_; SizeType maxProperties_; bool additionalProperties_; bool hasDependencies_; bool hasRequired_; bool hasSchemaDependencies_; const SchemaType* additionalItemsSchema_; const SchemaType* itemsList_; const SchemaType** itemsTuple_; SizeType itemsTupleCount_; SizeType minItems_; SizeType maxItems_; bool additionalItems_; bool uniqueItems_; RegexType* pattern_; SizeType minLength_; SizeType maxLength_; SValue minimum_; SValue maximum_; SValue multipleOf_; bool exclusiveMinimum_; bool exclusiveMaximum_; }; template struct TokenHelper { RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { *documentStack.template Push() = '/'; char buffer[21]; size_t length = static_cast((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer); for (size_t i = 0; i < length; i++) *documentStack.template Push() = static_cast(buffer[i]); } }; // Partial specialized version for char to prevent buffer copying. template struct TokenHelper { RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) { if (sizeof(SizeType) == 4) { char *buffer = documentStack.template Push(1 + 10); // '/' + uint *buffer++ = '/'; const char* end = internal::u32toa(index, buffer); documentStack.template Pop(static_cast(10 - (end - buffer))); } else { char *buffer = documentStack.template Push(1 + 20); // '/' + uint64 *buffer++ = '/'; const char* end = internal::u64toa(index, buffer); documentStack.template Pop(static_cast(20 - (end - buffer))); } } }; } // namespace internal /////////////////////////////////////////////////////////////////////////////// // IGenericRemoteSchemaDocumentProvider template class IGenericRemoteSchemaDocumentProvider { public: typedef typename SchemaDocumentType::Ch Ch; virtual ~IGenericRemoteSchemaDocumentProvider() {} virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0; }; /////////////////////////////////////////////////////////////////////////////// // GenericSchemaDocument //! JSON schema document. /*! A JSON schema document is a compiled version of a JSON schema. It is basically a tree of internal::Schema. \note This is an immutable class (i.e. its instance cannot be modified after construction). \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding. \tparam Allocator Allocator type for allocating memory of this document. */ template class GenericSchemaDocument { public: typedef ValueT ValueType; typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProviderType; typedef Allocator AllocatorType; typedef typename ValueType::EncodingType EncodingType; typedef typename EncodingType::Ch Ch; typedef internal::Schema SchemaType; typedef GenericPointer PointerType; friend class internal::Schema; template friend class GenericSchemaValidator; //! Constructor. /*! Compile a JSON document into schema document. \param document A JSON document as source. \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null. \param allocator An optional allocator instance for allocating memory. Can be null. */ explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) : remoteProvider_(remoteProvider), allocator_(allocator), ownAllocator_(), root_(), typeless_(), schemaMap_(allocator, kInitialSchemaMapSize), schemaRef_(allocator, kInitialSchemaRefSize) { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); typeless_ = static_cast(allocator_->Malloc(sizeof(SchemaType))); new (typeless_) SchemaType(this, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0); // Generate root schema, it will call CreateSchema() to create sub-schemas, // And call AddRefSchema() if there are $ref. CreateSchemaRecursive(&root_, PointerType(), document, document); // Resolve $ref while (!schemaRef_.Empty()) { SchemaRefEntry* refEntry = schemaRef_.template Pop(1); if (const SchemaType* s = GetSchema(refEntry->target)) { if (refEntry->schema) *refEntry->schema = s; // Create entry in map if not exist if (!GetSchema(refEntry->source)) { new (schemaMap_.template Push()) SchemaEntry(refEntry->source, const_cast(s), false, allocator_); } } else if (refEntry->schema) *refEntry->schema = typeless_; refEntry->~SchemaRefEntry(); } RAPIDJSON_ASSERT(root_ != 0); schemaRef_.ShrinkToFit(); // Deallocate all memory for ref } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT : remoteProvider_(rhs.remoteProvider_), allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), root_(rhs.root_), typeless_(rhs.typeless_), schemaMap_(std::move(rhs.schemaMap_)), schemaRef_(std::move(rhs.schemaRef_)) { rhs.remoteProvider_ = 0; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.typeless_ = 0; } #endif //! Destructor ~GenericSchemaDocument() { while (!schemaMap_.Empty()) schemaMap_.template Pop(1)->~SchemaEntry(); if (typeless_) { typeless_->~SchemaType(); Allocator::Free(typeless_); } RAPIDJSON_DELETE(ownAllocator_); } //! Get the root schema. const SchemaType& GetRoot() const { return *root_; } private: //! Prohibit copying GenericSchemaDocument(const GenericSchemaDocument&); //! Prohibit assignment GenericSchemaDocument& operator=(const GenericSchemaDocument&); struct SchemaRefEntry { SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {} PointerType source; PointerType target; const SchemaType** schema; }; struct SchemaEntry { SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {} ~SchemaEntry() { if (owned) { schema->~SchemaType(); Allocator::Free(schema); } } PointerType pointer; SchemaType* schema; bool owned; }; void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { if (schema) *schema = typeless_; if (v.GetType() == kObjectType) { const SchemaType* s = GetSchema(pointer); if (!s) CreateSchema(schema, pointer, v, document); for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr) CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document); } else if (v.GetType() == kArrayType) for (SizeType i = 0; i < v.Size(); i++) CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document); } void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) { RAPIDJSON_ASSERT(pointer.IsValid()); if (v.IsObject()) { if (!HandleRefSchema(pointer, schema, v, document)) { SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_); new (schemaMap_.template Push()) SchemaEntry(pointer, s, true, allocator_); if (schema) *schema = s; } } } bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) { static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' }; static const ValueType kRefValue(kRefString, 4); typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue); if (itr == v.MemberEnd()) return false; if (itr->value.IsString()) { SizeType len = itr->value.GetStringLength(); if (len > 0) { const Ch* s = itr->value.GetString(); SizeType i = 0; while (i < len && s[i] != '#') // Find the first # i++; if (i > 0) { // Remote reference, resolve immediately if (remoteProvider_) { if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i)) { PointerType pointer(&s[i], len - i, allocator_); if (pointer.IsValid()) { if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) { if (schema) *schema = sc; return true; } } } } } else if (s[i] == '#') { // Local reference, defer resolution PointerType pointer(&s[i], len - i, allocator_); if (pointer.IsValid()) { if (const ValueType* nv = pointer.Get(document)) if (HandleRefSchema(source, schema, *nv, document)) return true; new (schemaRef_.template Push()) SchemaRefEntry(source, pointer, schema, allocator_); return true; } } } } return false; } const SchemaType* GetSchema(const PointerType& pointer) const { for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) if (pointer == target->pointer) return target->schema; return 0; } PointerType GetPointer(const SchemaType* schema) const { for (const SchemaEntry* target = schemaMap_.template Bottom(); target != schemaMap_.template End(); ++target) if (schema == target->schema) return target->pointer; return PointerType(); } const SchemaType* GetTypeless() const { return typeless_; } static const size_t kInitialSchemaMapSize = 64; static const size_t kInitialSchemaRefSize = 64; IRemoteSchemaDocumentProviderType* remoteProvider_; Allocator *allocator_; Allocator *ownAllocator_; const SchemaType* root_; //!< Root schema. SchemaType* typeless_; internal::Stack schemaMap_; // Stores created Pointer -> Schemas internal::Stack schemaRef_; // Stores Pointer from $ref and schema which holds the $ref }; //! GenericSchemaDocument using Value type. typedef GenericSchemaDocument SchemaDocument; //! IGenericRemoteSchemaDocumentProvider using SchemaDocument. typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; /////////////////////////////////////////////////////////////////////////////// // GenericSchemaValidator //! JSON Schema Validator. /*! A SAX style JSON schema validator. It uses a \c GenericSchemaDocument to validate SAX events. It delegates the incoming SAX events to an output handler. The default output handler does nothing. It can be reused multiple times by calling \c Reset(). \tparam SchemaDocumentType Type of schema document. \tparam OutputHandler Type of output handler. Default handler does nothing. \tparam StateAllocator Allocator for storing the internal validation states. */ template < typename SchemaDocumentType, typename OutputHandler = BaseReaderHandler, typename StateAllocator = CrtAllocator> class GenericSchemaValidator : public internal::ISchemaStateFactory, public internal::ISchemaValidator { public: typedef typename SchemaDocumentType::SchemaType SchemaType; typedef typename SchemaDocumentType::PointerType PointerType; typedef typename SchemaType::EncodingType EncodingType; typedef typename EncodingType::Ch Ch; //! Constructor without output handler. /*! \param schemaDocument The schema document to conform to. \param allocator Optional allocator for storing internal validation states. \param schemaStackCapacity Optional initial capacity of schema path stack. \param documentStackCapacity Optional initial capacity of document path stack. */ GenericSchemaValidator( const SchemaDocumentType& schemaDocument, StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity, size_t documentStackCapacity = kDefaultDocumentStackCapacity) : schemaDocument_(&schemaDocument), root_(schemaDocument.GetRoot()), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), outputHandler_(0), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) #endif { } //! Constructor with output handler. /*! \param schemaDocument The schema document to conform to. \param allocator Optional allocator for storing internal validation states. \param schemaStackCapacity Optional initial capacity of schema path stack. \param documentStackCapacity Optional initial capacity of document path stack. */ GenericSchemaValidator( const SchemaDocumentType& schemaDocument, OutputHandler& outputHandler, StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity, size_t documentStackCapacity = kDefaultDocumentStackCapacity) : schemaDocument_(&schemaDocument), root_(schemaDocument.GetRoot()), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), outputHandler_(&outputHandler), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(0) #endif { } //! Destructor. ~GenericSchemaValidator() { Reset(); RAPIDJSON_DELETE(ownStateAllocator_); } //! Reset the internal states. void Reset() { while (!schemaStack_.Empty()) PopSchema(); documentStack_.Clear(); valid_ = true; } //! Checks whether the current state is valid. // Implementation of ISchemaValidator virtual bool IsValid() const { return valid_; } //! Gets the JSON pointer pointed to the invalid schema. PointerType GetInvalidSchemaPointer() const { return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema()); } //! Gets the keyword of invalid schema. const Ch* GetInvalidSchemaKeyword() const { return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword; } //! Gets the JSON pointer pointed to the invalid value. PointerType GetInvalidDocumentPointer() const { return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom(), documentStack_.GetSize() / sizeof(Ch)); } #if RAPIDJSON_SCHEMA_VERBOSE #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \ RAPIDJSON_MULTILINEMACRO_BEGIN\ *documentStack_.template Push() = '\0';\ documentStack_.template Pop(1);\ internal::PrintInvalidDocument(documentStack_.template Bottom());\ RAPIDJSON_MULTILINEMACRO_END #else #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() #endif #define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\ if (!valid_) return false; \ if (!BeginValue() || !CurrentSchema().method arg1) {\ RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\ return valid_ = false;\ } #define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\ for (Context* context = schemaStack_.template Bottom(); context != schemaStack_.template End(); context++) {\ if (context->hasher)\ static_cast(context->hasher)->method arg2;\ if (context->validators)\ for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\ static_cast(context->validators[i_])->method arg2;\ if (context->patternPropertiesValidators)\ for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\ static_cast(context->patternPropertiesValidators[i_])->method arg2;\ } #define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\ return valid_ = EndValue() && (!outputHandler_ || outputHandler_->method arg2) #define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \ RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\ RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2) bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); } bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); } bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); } bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); } bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); } bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); } bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); } bool RawNumber(const Ch* str, SizeType length, bool copy) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } bool String(const Ch* str, SizeType length, bool copy) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); } bool StartObject() { RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ()); return valid_ = !outputHandler_ || outputHandler_->StartObject(); } bool Key(const Ch* str, SizeType len, bool copy) { if (!valid_) return false; AppendToken(str, len); if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy)); return valid_ = !outputHandler_ || outputHandler_->Key(str, len, copy); } bool EndObject(SizeType memberCount) { if (!valid_) return false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount)); if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount)); } bool StartArray() { RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext())); RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ()); return valid_ = !outputHandler_ || outputHandler_->StartArray(); } bool EndArray(SizeType elementCount) { if (!valid_) return false; RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount)); if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false; RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount)); } #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_ #undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_ #undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_ #undef RAPIDJSON_SCHEMA_HANDLE_VALUE_ // Implementation of ISchemaStateFactory virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) { return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root, #if RAPIDJSON_SCHEMA_VERBOSE depth_ + 1, #endif &GetStateAllocator()); } virtual void DestroySchemaValidator(ISchemaValidator* validator) { GenericSchemaValidator* v = static_cast(validator); v->~GenericSchemaValidator(); StateAllocator::Free(v); } virtual void* CreateHasher() { return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator()); } virtual uint64_t GetHashCode(void* hasher) { return static_cast(hasher)->GetHashCode(); } virtual void DestroryHasher(void* hasher) { HasherType* h = static_cast(hasher); h->~HasherType(); StateAllocator::Free(h); } virtual void* MallocState(size_t size) { return GetStateAllocator().Malloc(size); } virtual void FreeState(void* p) { StateAllocator::Free(p); } private: typedef typename SchemaType::Context Context; typedef GenericValue, StateAllocator> HashCodeArray; typedef internal::Hasher HasherType; GenericSchemaValidator( const SchemaDocumentType& schemaDocument, const SchemaType& root, #if RAPIDJSON_SCHEMA_VERBOSE unsigned depth, #endif StateAllocator* allocator = 0, size_t schemaStackCapacity = kDefaultSchemaStackCapacity, size_t documentStackCapacity = kDefaultDocumentStackCapacity) : schemaDocument_(&schemaDocument), root_(root), stateAllocator_(allocator), ownStateAllocator_(0), schemaStack_(allocator, schemaStackCapacity), documentStack_(allocator, documentStackCapacity), outputHandler_(0), valid_(true) #if RAPIDJSON_SCHEMA_VERBOSE , depth_(depth) #endif { } StateAllocator& GetStateAllocator() { if (!stateAllocator_) stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator)(); return *stateAllocator_; } bool BeginValue() { if (schemaStack_.Empty()) PushSchema(root_); else { if (CurrentContext().inArray) internal::TokenHelper, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex); if (!CurrentSchema().BeginValue(CurrentContext())) return false; SizeType count = CurrentContext().patternPropertiesSchemaCount; const SchemaType** sa = CurrentContext().patternPropertiesSchemas; typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType; bool valueUniqueness = CurrentContext().valueUniqueness; RAPIDJSON_ASSERT(CurrentContext().valueSchema); PushSchema(*CurrentContext().valueSchema); if (count > 0) { CurrentContext().objectPatternValidatorType = patternValidatorType; ISchemaValidator**& va = CurrentContext().patternPropertiesValidators; SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount; va = static_cast(MallocState(sizeof(ISchemaValidator*) * count)); for (SizeType i = 0; i < count; i++) va[validatorCount++] = CreateSchemaValidator(*sa[i]); } CurrentContext().arrayUniqueness = valueUniqueness; } return true; } bool EndValue() { if (!CurrentSchema().EndValue(CurrentContext())) return false; #if RAPIDJSON_SCHEMA_VERBOSE GenericStringBuffer sb; schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb); *documentStack_.template Push() = '\0'; documentStack_.template Pop(1); internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom()); #endif uint64_t h = CurrentContext().arrayUniqueness ? static_cast(CurrentContext().hasher)->GetHashCode() : 0; PopSchema(); if (!schemaStack_.Empty()) { Context& context = CurrentContext(); if (context.valueUniqueness) { HashCodeArray* a = static_cast(context.arrayElementHashCodes); if (!a) CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType); for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr) if (itr->GetUint64() == h) RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString()); a->PushBack(h, GetStateAllocator()); } } // Remove the last token of document pointer while (!documentStack_.Empty() && *documentStack_.template Pop(1) != '/') ; return true; } void AppendToken(const Ch* str, SizeType len) { documentStack_.template Reserve(1 + len * 2); // worst case all characters are escaped as two characters *documentStack_.template PushUnsafe() = '/'; for (SizeType i = 0; i < len; i++) { if (str[i] == '~') { *documentStack_.template PushUnsafe() = '~'; *documentStack_.template PushUnsafe() = '0'; } else if (str[i] == '/') { *documentStack_.template PushUnsafe() = '~'; *documentStack_.template PushUnsafe() = '1'; } else *documentStack_.template PushUnsafe() = str[i]; } } RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push()) Context(*this, &schema); } RAPIDJSON_FORCEINLINE void PopSchema() { Context* c = schemaStack_.template Pop(1); if (HashCodeArray* a = static_cast(c->arrayElementHashCodes)) { a->~HashCodeArray(); StateAllocator::Free(a); } c->~Context(); } const SchemaType& CurrentSchema() const { return *schemaStack_.template Top()->schema; } Context& CurrentContext() { return *schemaStack_.template Top(); } const Context& CurrentContext() const { return *schemaStack_.template Top(); } static const size_t kDefaultSchemaStackCapacity = 1024; static const size_t kDefaultDocumentStackCapacity = 256; const SchemaDocumentType* schemaDocument_; const SchemaType& root_; StateAllocator* stateAllocator_; StateAllocator* ownStateAllocator_; internal::Stack schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *) internal::Stack documentStack_; //!< stack to store the current path of validating document (Ch) OutputHandler* outputHandler_; bool valid_; #if RAPIDJSON_SCHEMA_VERBOSE unsigned depth_; #endif }; typedef GenericSchemaValidator SchemaValidator; /////////////////////////////////////////////////////////////////////////////// // SchemaValidatingReader //! A helper class for parsing with validation. /*! This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate(). \tparam parseFlags Combination of \ref ParseFlag. \tparam InputStream Type of input stream, implementing Stream concept. \tparam SourceEncoding Encoding of the input stream. \tparam SchemaDocumentType Type of schema document. \tparam StackAllocator Allocator type for stack. */ template < unsigned parseFlags, typename InputStream, typename SourceEncoding, typename SchemaDocumentType = SchemaDocument, typename StackAllocator = CrtAllocator> class SchemaValidatingReader { public: typedef typename SchemaDocumentType::PointerType PointerType; typedef typename InputStream::Ch Ch; //! Constructor /*! \param is Input stream. \param sd Schema document. */ SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {} template bool operator()(Handler& handler) { GenericReader reader; GenericSchemaValidator validator(sd_, handler); parseResult_ = reader.template Parse(is_, validator); isValid_ = validator.IsValid(); if (isValid_) { invalidSchemaPointer_ = PointerType(); invalidSchemaKeyword_ = 0; invalidDocumentPointer_ = PointerType(); } else { invalidSchemaPointer_ = validator.GetInvalidSchemaPointer(); invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword(); invalidDocumentPointer_ = validator.GetInvalidDocumentPointer(); } return parseResult_; } const ParseResult& GetParseResult() const { return parseResult_; } bool IsValid() const { return isValid_; } const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; } const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; } const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; } private: InputStream& is_; const SchemaDocumentType& sd_; ParseResult parseResult_; PointerType invalidSchemaPointer_; const Ch* invalidSchemaKeyword_; PointerType invalidDocumentPointer_; bool isValid_; }; RAPIDJSON_NAMESPACE_END RAPIDJSON_DIAG_POP #endif // RAPIDJSON_SCHEMA_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/fwd.h0000644002537200234200000000770313213503245023261 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_FWD_H_ #define RAPIDJSON_FWD_H_ #include "rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN // encodings.h template struct UTF8; template struct UTF16; template struct UTF16BE; template struct UTF16LE; template struct UTF32; template struct UTF32BE; template struct UTF32LE; template struct ASCII; template struct AutoUTF; template struct Transcoder; // allocators.h class CrtAllocator; template class MemoryPoolAllocator; // stream.h template struct GenericStringStream; typedef GenericStringStream > StringStream; template struct GenericInsituStringStream; typedef GenericInsituStringStream > InsituStringStream; // stringbuffer.h template class GenericStringBuffer; typedef GenericStringBuffer, CrtAllocator> StringBuffer; // filereadstream.h class FileReadStream; // filewritestream.h class FileWriteStream; // memorybuffer.h template struct GenericMemoryBuffer; typedef GenericMemoryBuffer MemoryBuffer; // memorystream.h struct MemoryStream; // reader.h template struct BaseReaderHandler; template class GenericReader; typedef GenericReader, UTF8, CrtAllocator> Reader; // writer.h template class Writer; // prettywriter.h template class PrettyWriter; // document.h template struct GenericMember; template class GenericMemberIterator; template struct GenericStringRef; template class GenericValue; typedef GenericValue, MemoryPoolAllocator > Value; template class GenericDocument; typedef GenericDocument, MemoryPoolAllocator, CrtAllocator> Document; // pointer.h template class GenericPointer; typedef GenericPointer Pointer; // schema.h template class IGenericRemoteSchemaDocumentProvider; template class GenericSchemaDocument; typedef GenericSchemaDocument SchemaDocument; typedef IGenericRemoteSchemaDocumentProvider IRemoteSchemaDocumentProvider; template < typename SchemaDocumentType, typename OutputHandler, typename StateAllocator> class GenericSchemaValidator; typedef GenericSchemaValidator, void>, CrtAllocator> SchemaValidator; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_RAPIDJSONFWD_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/allocators.h0000644002537200234200000002410713213503245024641 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_ALLOCATORS_H_ #define RAPIDJSON_ALLOCATORS_H_ #include "rapidjson.h" RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Allocator /*! \class rapidjson::Allocator \brief Concept for allocating, resizing and freeing memory block. Note that Malloc() and Realloc() are non-static but Free() is static. So if an allocator need to support Free(), it needs to put its pointer in the header of memory block. \code concept Allocator { static const bool kNeedFree; //!< Whether this allocator needs to call Free(). // Allocate a memory block. // \param size of the memory block in bytes. // \returns pointer to the memory block. void* Malloc(size_t size); // Resize a memory block. // \param originalPtr The pointer to current memory block. Null pointer is permitted. // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.) // \param newSize the new size in bytes. void* Realloc(void* originalPtr, size_t originalSize, size_t newSize); // Free a memory block. // \param pointer to the memory block. Null pointer is permitted. static void Free(void *ptr); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // CrtAllocator //! C-runtime library allocator. /*! This class is just wrapper for standard C library memory routines. \note implements Allocator concept */ class CrtAllocator { public: static const bool kNeedFree = true; void* Malloc(size_t size) { if (size) // behavior of malloc(0) is implementation defined. return std::malloc(size); else return NULL; // standardize to returning NULL. } void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { (void)originalSize; if (newSize == 0) { std::free(originalPtr); return NULL; } return std::realloc(originalPtr, newSize); } static void Free(void *ptr) { std::free(ptr); } }; /////////////////////////////////////////////////////////////////////////////// // MemoryPoolAllocator //! Default memory allocator used by the parser and DOM. /*! This allocator allocate memory blocks from pre-allocated memory chunks. It does not free memory blocks. And Realloc() only allocate new memory. The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default. User may also supply a buffer as the first chunk. If the user-buffer is full then additional chunks are allocated by BaseAllocator. The user-buffer is not deallocated by this allocator. \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator. \note implements Allocator concept */ template class MemoryPoolAllocator { public: static const bool kNeedFree = false; //!< Tell users that no need to call Free() with this allocator. (concept Allocator) //! Constructor with chunkSize. /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param baseAllocator The allocator for allocating memory chunks. */ MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0) { } //! Constructor with user-supplied buffer. /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size. The user buffer will not be deallocated when this allocator is destructed. \param buffer User supplied buffer. \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader). \param chunkSize The size of memory chunk. The default is kDefaultChunkSize. \param baseAllocator The allocator for allocating memory chunks. */ MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0) { RAPIDJSON_ASSERT(buffer != 0); RAPIDJSON_ASSERT(size > sizeof(ChunkHeader)); chunkHead_ = reinterpret_cast(buffer); chunkHead_->capacity = size - sizeof(ChunkHeader); chunkHead_->size = 0; chunkHead_->next = 0; } //! Destructor. /*! This deallocates all memory chunks, excluding the user-supplied buffer. */ ~MemoryPoolAllocator() { Clear(); RAPIDJSON_DELETE(ownBaseAllocator_); } //! Deallocates all memory chunks, excluding the user-supplied buffer. void Clear() { while (chunkHead_ && chunkHead_ != userBuffer_) { ChunkHeader* next = chunkHead_->next; baseAllocator_->Free(chunkHead_); chunkHead_ = next; } if (chunkHead_ && chunkHead_ == userBuffer_) chunkHead_->size = 0; // Clear user buffer } //! Computes the total capacity of allocated memory chunks. /*! \return total capacity in bytes. */ size_t Capacity() const { size_t capacity = 0; for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) capacity += c->capacity; return capacity; } //! Computes the memory blocks allocated. /*! \return total used bytes. */ size_t Size() const { size_t size = 0; for (ChunkHeader* c = chunkHead_; c != 0; c = c->next) size += c->size; return size; } //! Allocates a memory block. (concept Allocator) void* Malloc(size_t size) { if (!size) return NULL; size = RAPIDJSON_ALIGN(size); if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity) if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size)) return NULL; void *buffer = reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size; chunkHead_->size += size; return buffer; } //! Resizes a memory block (concept Allocator) void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) { if (originalPtr == 0) return Malloc(newSize); if (newSize == 0) return NULL; originalSize = RAPIDJSON_ALIGN(originalSize); newSize = RAPIDJSON_ALIGN(newSize); // Do not shrink if new size is smaller than original if (originalSize >= newSize) return originalPtr; // Simply expand it if it is the last allocation and there is sufficient space if (originalPtr == reinterpret_cast(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) { size_t increment = static_cast(newSize - originalSize); if (chunkHead_->size + increment <= chunkHead_->capacity) { chunkHead_->size += increment; return originalPtr; } } // Realloc process: allocate and copy memory, do not free original buffer. if (void* newBuffer = Malloc(newSize)) { if (originalSize) std::memcpy(newBuffer, originalPtr, originalSize); return newBuffer; } else return NULL; } //! Frees a memory block (concept Allocator) static void Free(void *ptr) { (void)ptr; } // Do nothing private: //! Copy constructor is not permitted. MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */; //! Copy assignment operator is not permitted. MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */; //! Creates a new chunk. /*! \param capacity Capacity of the chunk in bytes. \return true if success. */ bool AddChunk(size_t capacity) { if (!baseAllocator_) ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator)(); if (ChunkHeader* chunk = reinterpret_cast(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) { chunk->capacity = capacity; chunk->size = 0; chunk->next = chunkHead_; chunkHead_ = chunk; return true; } else return false; } static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity. //! Chunk header for perpending to each chunk. /*! Chunks are stored as a singly linked list. */ struct ChunkHeader { size_t capacity; //!< Capacity of the chunk in bytes (excluding the header itself). size_t size; //!< Current size of allocated memory in bytes. ChunkHeader *next; //!< Next chunk in the linked list. }; ChunkHeader *chunkHead_; //!< Head of the chunk linked-list. Only the head chunk serves allocation. size_t chunk_capacity_; //!< The minimum capacity of chunk when they are allocated. void *userBuffer_; //!< User supplied buffer. BaseAllocator* baseAllocator_; //!< base allocator for allocating memory chunks. BaseAllocator* ownBaseAllocator_; //!< base allocator created by this object. }; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ENCODINGS_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/encodings.h0000644002537200234200000006773213213503245024462 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_ENCODINGS_H_ #define RAPIDJSON_ENCODINGS_H_ #include "rapidjson.h" #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data RAPIDJSON_DIAG_OFF(4702) // unreachable code #elif defined(__GNUC__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) RAPIDJSON_DIAG_OFF(overflow) #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Encoding /*! \class rapidjson::Encoding \brief Concept for encoding of Unicode characters. \code concept Encoding { typename Ch; //! Type of character. A "character" is actually a code unit in unicode's definition. enum { supportUnicode = 1 }; // or 0 if not supporting unicode //! \brief Encode a Unicode codepoint to an output stream. //! \param os Output stream. //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively. template static void Encode(OutputStream& os, unsigned codepoint); //! \brief Decode a Unicode codepoint from an input stream. //! \param is Input stream. //! \param codepoint Output of the unicode codepoint. //! \return true if a valid codepoint can be decoded from the stream. template static bool Decode(InputStream& is, unsigned* codepoint); //! \brief Validate one Unicode codepoint from an encoded stream. //! \param is Input stream to obtain codepoint. //! \param os Output for copying one codepoint. //! \return true if it is valid. //! \note This function just validating and copying the codepoint without actually decode it. template static bool Validate(InputStream& is, OutputStream& os); // The following functions are deal with byte streams. //! Take a character from input byte stream, skip BOM if exist. template static CharType TakeBOM(InputByteStream& is); //! Take a character from input byte stream. template static Ch Take(InputByteStream& is); //! Put BOM to output byte stream. template static void PutBOM(OutputByteStream& os); //! Put a character to output byte stream. template static void Put(OutputByteStream& os, Ch c); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // UTF8 //! UTF-8 encoding. /*! http://en.wikipedia.org/wiki/UTF-8 http://tools.ietf.org/html/rfc3629 \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char. \note implements Encoding concept */ template struct UTF8 { typedef CharType Ch; enum { supportUnicode = 1 }; template static void Encode(OutputStream& os, unsigned codepoint) { if (codepoint <= 0x7F) os.Put(static_cast(codepoint & 0xFF)); else if (codepoint <= 0x7FF) { os.Put(static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); os.Put(static_cast(0x80 | ((codepoint & 0x3F)))); } else if (codepoint <= 0xFFFF) { os.Put(static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); os.Put(static_cast(0x80 | (codepoint & 0x3F))); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); os.Put(static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); os.Put(static_cast(0x80 | ((codepoint >> 12) & 0x3F))); os.Put(static_cast(0x80 | ((codepoint >> 6) & 0x3F))); os.Put(static_cast(0x80 | (codepoint & 0x3F))); } } template static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { if (codepoint <= 0x7F) PutUnsafe(os, static_cast(codepoint & 0xFF)); else if (codepoint <= 0x7FF) { PutUnsafe(os, static_cast(0xC0 | ((codepoint >> 6) & 0xFF))); PutUnsafe(os, static_cast(0x80 | ((codepoint & 0x3F)))); } else if (codepoint <= 0xFFFF) { PutUnsafe(os, static_cast(0xE0 | ((codepoint >> 12) & 0xFF))); PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); PutUnsafe(os, static_cast(0xF0 | ((codepoint >> 18) & 0xFF))); PutUnsafe(os, static_cast(0x80 | ((codepoint >> 12) & 0x3F))); PutUnsafe(os, static_cast(0x80 | ((codepoint >> 6) & 0x3F))); PutUnsafe(os, static_cast(0x80 | (codepoint & 0x3F))); } } template static bool Decode(InputStream& is, unsigned* codepoint) { #define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast(c) & 0x3Fu) #define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) #define TAIL() COPY(); TRANS(0x70) typename InputStream::Ch c = is.Take(); if (!(c & 0x80)) { *codepoint = static_cast(c); return true; } unsigned char type = GetRange(static_cast(c)); if (type >= 32) { *codepoint = 0; } else { *codepoint = (0xFFu >> type) & static_cast(c); } bool result = true; switch (type) { case 2: TAIL(); return result; case 3: TAIL(); TAIL(); return result; case 4: COPY(); TRANS(0x50); TAIL(); return result; case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; case 6: TAIL(); TAIL(); TAIL(); return result; case 10: COPY(); TRANS(0x20); TAIL(); return result; case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; default: return false; } #undef COPY #undef TRANS #undef TAIL } template static bool Validate(InputStream& is, OutputStream& os) { #define COPY() os.Put(c = is.Take()) #define TRANS(mask) result &= ((GetRange(static_cast(c)) & mask) != 0) #define TAIL() COPY(); TRANS(0x70) Ch c; COPY(); if (!(c & 0x80)) return true; bool result = true; switch (GetRange(static_cast(c))) { case 2: TAIL(); return result; case 3: TAIL(); TAIL(); return result; case 4: COPY(); TRANS(0x50); TAIL(); return result; case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result; case 6: TAIL(); TAIL(); TAIL(); return result; case 10: COPY(); TRANS(0x20); TAIL(); return result; case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result; default: return false; } #undef COPY #undef TRANS #undef TAIL } static unsigned char GetRange(unsigned char c) { // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types. static const unsigned char type[] = { 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, 0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, 0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20, 8,8,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, 10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8, }; return type[c]; } template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); typename InputByteStream::Ch c = Take(is); if (static_cast(c) != 0xEFu) return c; c = is.Take(); if (static_cast(c) != 0xBBu) return c; c = is.Take(); if (static_cast(c) != 0xBFu) return c; c = is.Take(); return c; } template static Ch Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); return static_cast(is.Take()); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0xEFu)); os.Put(static_cast(0xBBu)); os.Put(static_cast(0xBFu)); } template static void Put(OutputByteStream& os, Ch c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(c)); } }; /////////////////////////////////////////////////////////////////////////////// // UTF16 //! UTF-16 encoding. /*! http://en.wikipedia.org/wiki/UTF-16 http://tools.ietf.org/html/rfc2781 \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead. \note implements Encoding concept \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. For streaming, use UTF16LE and UTF16BE, which handle endianness. */ template struct UTF16 { typedef CharType Ch; RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2); enum { supportUnicode = 1 }; template static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); if (codepoint <= 0xFFFF) { RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair os.Put(static_cast(codepoint)); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; os.Put(static_cast((v >> 10) | 0xD800)); os.Put(static_cast((v & 0x3FF) | 0xDC00)); } } template static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); if (codepoint <= 0xFFFF) { RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair PutUnsafe(os, static_cast(codepoint)); } else { RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); unsigned v = codepoint - 0x10000; PutUnsafe(os, static_cast((v >> 10) | 0xD800)); PutUnsafe(os, static_cast((v & 0x3FF) | 0xDC00)); } } template static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); typename InputStream::Ch c = is.Take(); if (c < 0xD800 || c > 0xDFFF) { *codepoint = static_cast(c); return true; } else if (c <= 0xDBFF) { *codepoint = (static_cast(c) & 0x3FF) << 10; c = is.Take(); *codepoint |= (static_cast(c) & 0x3FF); *codepoint += 0x10000; return c >= 0xDC00 && c <= 0xDFFF; } return false; } template static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2); RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2); typename InputStream::Ch c; os.Put(static_cast(c = is.Take())); if (c < 0xD800 || c > 0xDFFF) return true; else if (c <= 0xDBFF) { os.Put(c = is.Take()); return c >= 0xDC00 && c <= 0xDFFF; } return false; } }; //! UTF-16 little endian encoding. template struct UTF16LE : UTF16 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return static_cast(c) == 0xFEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(is.Take()); c |= static_cast(static_cast(is.Take())) << 8; return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0xFFu)); os.Put(static_cast(0xFEu)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(static_cast(c) & 0xFFu)); os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); } }; //! UTF-16 big endian encoding. template struct UTF16BE : UTF16 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return static_cast(c) == 0xFEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(static_cast(is.Take())) << 8; c |= static_cast(is.Take()); return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0xFEu)); os.Put(static_cast(0xFFu)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast((static_cast(c) >> 8) & 0xFFu)); os.Put(static_cast(static_cast(c) & 0xFFu)); } }; /////////////////////////////////////////////////////////////////////////////// // UTF32 //! UTF-32 encoding. /*! http://en.wikipedia.org/wiki/UTF-32 \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead. \note implements Encoding concept \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness. For streaming, use UTF32LE and UTF32BE, which handle endianness. */ template struct UTF32 { typedef CharType Ch; RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4); enum { supportUnicode = 1 }; template static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); os.Put(codepoint); } template static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4); RAPIDJSON_ASSERT(codepoint <= 0x10FFFF); PutUnsafe(os, codepoint); } template static bool Decode(InputStream& is, unsigned* codepoint) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); Ch c = is.Take(); *codepoint = c; return c <= 0x10FFFF; } template static bool Validate(InputStream& is, OutputStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4); Ch c; os.Put(c = is.Take()); return c <= 0x10FFFF; } }; //! UTF-32 little endian enocoding. template struct UTF32LE : UTF32 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return static_cast(c) == 0x0000FEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(is.Take()); c |= static_cast(static_cast(is.Take())) << 8; c |= static_cast(static_cast(is.Take())) << 16; c |= static_cast(static_cast(is.Take())) << 24; return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0xFFu)); os.Put(static_cast(0xFEu)); os.Put(static_cast(0x00u)); os.Put(static_cast(0x00u)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(c & 0xFFu)); os.Put(static_cast((c >> 8) & 0xFFu)); os.Put(static_cast((c >> 16) & 0xFFu)); os.Put(static_cast((c >> 24) & 0xFFu)); } }; //! UTF-32 big endian encoding. template struct UTF32BE : UTF32 { template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); CharType c = Take(is); return static_cast(c) == 0x0000FEFFu ? Take(is) : c; } template static CharType Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); unsigned c = static_cast(static_cast(is.Take())) << 24; c |= static_cast(static_cast(is.Take())) << 16; c |= static_cast(static_cast(is.Take())) << 8; c |= static_cast(static_cast(is.Take())); return static_cast(c); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(0x00u)); os.Put(static_cast(0x00u)); os.Put(static_cast(0xFEu)); os.Put(static_cast(0xFFu)); } template static void Put(OutputByteStream& os, CharType c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast((c >> 24) & 0xFFu)); os.Put(static_cast((c >> 16) & 0xFFu)); os.Put(static_cast((c >> 8) & 0xFFu)); os.Put(static_cast(c & 0xFFu)); } }; /////////////////////////////////////////////////////////////////////////////// // ASCII //! ASCII encoding. /*! http://en.wikipedia.org/wiki/ASCII \tparam CharType Code unit for storing 7-bit ASCII data. Default is char. \note implements Encoding concept */ template struct ASCII { typedef CharType Ch; enum { supportUnicode = 0 }; template static void Encode(OutputStream& os, unsigned codepoint) { RAPIDJSON_ASSERT(codepoint <= 0x7F); os.Put(static_cast(codepoint & 0xFF)); } template static void EncodeUnsafe(OutputStream& os, unsigned codepoint) { RAPIDJSON_ASSERT(codepoint <= 0x7F); PutUnsafe(os, static_cast(codepoint & 0xFF)); } template static bool Decode(InputStream& is, unsigned* codepoint) { uint8_t c = static_cast(is.Take()); *codepoint = c; return c <= 0X7F; } template static bool Validate(InputStream& is, OutputStream& os) { uint8_t c = static_cast(is.Take()); os.Put(static_cast(c)); return c <= 0x7F; } template static CharType TakeBOM(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); uint8_t c = static_cast(Take(is)); return static_cast(c); } template static Ch Take(InputByteStream& is) { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); return static_cast(is.Take()); } template static void PutBOM(OutputByteStream& os) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); (void)os; } template static void Put(OutputByteStream& os, Ch c) { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); os.Put(static_cast(c)); } }; /////////////////////////////////////////////////////////////////////////////// // AutoUTF //! Runtime-specified UTF encoding type of a stream. enum UTFType { kUTF8 = 0, //!< UTF-8. kUTF16LE = 1, //!< UTF-16 little endian. kUTF16BE = 2, //!< UTF-16 big endian. kUTF32LE = 3, //!< UTF-32 little endian. kUTF32BE = 4 //!< UTF-32 big endian. }; //! Dynamically select encoding according to stream's runtime-specified UTF encoding type. /*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType(). */ template struct AutoUTF { typedef CharType Ch; enum { supportUnicode = 1 }; #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x template static RAPIDJSON_FORCEINLINE void Encode(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) }; (*f[os.GetType()])(os, codepoint); } template static RAPIDJSON_FORCEINLINE void EncodeUnsafe(OutputStream& os, unsigned codepoint) { typedef void (*EncodeFunc)(OutputStream&, unsigned); static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) }; (*f[os.GetType()])(os, codepoint); } template static RAPIDJSON_FORCEINLINE bool Decode(InputStream& is, unsigned* codepoint) { typedef bool (*DecodeFunc)(InputStream&, unsigned*); static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) }; return (*f[is.GetType()])(is, codepoint); } template static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { typedef bool (*ValidateFunc)(InputStream&, OutputStream&); static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) }; return (*f[is.GetType()])(is, os); } #undef RAPIDJSON_ENCODINGS_FUNC }; /////////////////////////////////////////////////////////////////////////////// // Transcoder //! Encoding conversion. template struct Transcoder { //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream. template static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; TargetEncoding::Encode(os, codepoint); return true; } template static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { unsigned codepoint; if (!SourceEncoding::Decode(is, &codepoint)) return false; TargetEncoding::EncodeUnsafe(os, codepoint); return true; } //! Validate one Unicode codepoint from an encoded stream. template static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Transcode(is, os); // Since source/target encoding is different, must transcode. } }; // Forward declaration. template inline void PutUnsafe(Stream& stream, typename Stream::Ch c); //! Specialization of Transcoder with same source and target encoding. template struct Transcoder { template static RAPIDJSON_FORCEINLINE bool Transcode(InputStream& is, OutputStream& os) { os.Put(is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template static RAPIDJSON_FORCEINLINE bool TranscodeUnsafe(InputStream& is, OutputStream& os) { PutUnsafe(os, is.Take()); // Just copy one code unit. This semantic is different from primary template class. return true; } template static RAPIDJSON_FORCEINLINE bool Validate(InputStream& is, OutputStream& os) { return Encoding::Validate(is, os); // source/target encoding are the same } }; RAPIDJSON_NAMESPACE_END #if defined(__GNUC__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_ENCODINGS_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/reader.h0000644002537200234200000026475713213503245023761 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_READER_H_ #define RAPIDJSON_READER_H_ /*! \file reader.h */ #include "allocators.h" #include "stream.h" #include "encodedstream.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strtod.h" #include #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #include #pragma intrinsic(_BitScanForward) #endif #ifdef RAPIDJSON_SSE42 #include #elif defined(RAPIDJSON_SSE2) #include #elif defined(RAPIDJSON_NEON) #include #endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4702) // unreachable code #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(old-style-cast) RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) #endif #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define RAPIDJSON_NOTHING /* deliberately empty */ #ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \ RAPIDJSON_MULTILINEMACRO_END #endif #define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING) //!@endcond /*! \def RAPIDJSON_PARSE_ERROR_NORETURN \ingroup RAPIDJSON_ERRORS \brief Macro to indicate a parse error. \param parseErrorCode \ref rapidjson::ParseErrorCode of the error \param offset position of the error in JSON input (\c size_t) This macros can be used as a customization point for the internal error handling mechanism of RapidJSON. A common usage model is to throw an exception instead of requiring the caller to explicitly check the \ref rapidjson::GenericReader::Parse's return value: \code #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \ throw ParseException(parseErrorCode, #parseErrorCode, offset) #include // std::runtime_error #include "rapidjson/error/error.h" // rapidjson::ParseResult struct ParseException : std::runtime_error, rapidjson::ParseResult { ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset) : std::runtime_error(msg), ParseResult(code, offset) {} }; #include "rapidjson/reader.h" \endcode \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse */ #ifndef RAPIDJSON_PARSE_ERROR_NORETURN #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \ SetParseError(parseErrorCode, offset); \ RAPIDJSON_MULTILINEMACRO_END #endif /*! \def RAPIDJSON_PARSE_ERROR \ingroup RAPIDJSON_ERRORS \brief (Internal) macro to indicate and handle a parse error. \param parseErrorCode \ref rapidjson::ParseErrorCode of the error \param offset position of the error in JSON input (\c size_t) Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing. \see RAPIDJSON_PARSE_ERROR_NORETURN \hideinitializer */ #ifndef RAPIDJSON_PARSE_ERROR #define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \ RAPIDJSON_MULTILINEMACRO_BEGIN \ RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \ RAPIDJSON_MULTILINEMACRO_END #endif #include "error/error.h" // ParseErrorCode, ParseResult RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // ParseFlag /*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS \ingroup RAPIDJSON_CONFIG \brief User-defined kParseDefaultFlags definition. User can define this as any \c ParseFlag combinations. */ #ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS #define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags #endif //! Combination of parseFlags /*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream */ enum ParseFlag { kParseNoFlags = 0, //!< No flags are set. kParseInsituFlag = 1, //!< In-situ(destructive) parsing. kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings. kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing. kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error. kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower). kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments. kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings. kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays. kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles. kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS }; /////////////////////////////////////////////////////////////////////////////// // Handler /*! \class rapidjson::Handler \brief Concept for receiving events from GenericReader upon parsing. The functions return true if no error occurs. If they return false, the event publisher should terminate the process. \code concept Handler { typename Ch; bool Null(); bool Bool(bool b); bool Int(int i); bool Uint(unsigned i); bool Int64(int64_t i); bool Uint64(uint64_t i); bool Double(double d); /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) bool RawNumber(const Ch* str, SizeType length, bool copy); bool String(const Ch* str, SizeType length, bool copy); bool StartObject(); bool Key(const Ch* str, SizeType length, bool copy); bool EndObject(SizeType memberCount); bool StartArray(); bool EndArray(SizeType elementCount); }; \endcode */ /////////////////////////////////////////////////////////////////////////////// // BaseReaderHandler //! Default implementation of Handler. /*! This can be used as base class of any reader handler. \note implements Handler concept */ template, typename Derived = void> struct BaseReaderHandler { typedef typename Encoding::Ch Ch; typedef typename internal::SelectIf, BaseReaderHandler, Derived>::Type Override; bool Default() { return true; } bool Null() { return static_cast(*this).Default(); } bool Bool(bool) { return static_cast(*this).Default(); } bool Int(int) { return static_cast(*this).Default(); } bool Uint(unsigned) { return static_cast(*this).Default(); } bool Int64(int64_t) { return static_cast(*this).Default(); } bool Uint64(uint64_t) { return static_cast(*this).Default(); } bool Double(double) { return static_cast(*this).Default(); } /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length) bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } bool String(const Ch*, SizeType, bool) { return static_cast(*this).Default(); } bool StartObject() { return static_cast(*this).Default(); } bool Key(const Ch* str, SizeType len, bool copy) { return static_cast(*this).String(str, len, copy); } bool EndObject(SizeType) { return static_cast(*this).Default(); } bool StartArray() { return static_cast(*this).Default(); } bool EndArray(SizeType) { return static_cast(*this).Default(); } }; /////////////////////////////////////////////////////////////////////////////// // StreamLocalCopy namespace internal { template::copyOptimization> class StreamLocalCopy; //! Do copy optimization. template class StreamLocalCopy { public: StreamLocalCopy(Stream& original) : s(original), original_(original) {} ~StreamLocalCopy() { original_ = s; } Stream s; private: StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; Stream& original_; }; //! Keep reference. template class StreamLocalCopy { public: StreamLocalCopy(Stream& original) : s(original) {} Stream& s; private: StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */; }; } // namespace internal /////////////////////////////////////////////////////////////////////////////// // SkipWhitespace //! Skip the JSON white spaces in a stream. /*! \param is A input stream for skipping white spaces. \note This function has SSE2/SSE4.2 specialization. */ template void SkipWhitespace(InputStream& is) { internal::StreamLocalCopy copy(is); InputStream& s(copy.s); typename InputStream::Ch c; while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t') s.Take(); } inline const char* SkipWhitespace(const char* p, const char* end) { while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) ++p; return p; } #ifdef RAPIDJSON_SSE42 //! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { // Fast return for single non-whitespace if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // 16-byte align to the next boundary const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // The rest of string using SIMD static const char whitespace[16] = " \n\r\t"; const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); if (r != 16) // some of characters is non-whitespace return p + r; } } inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { // Fast return for single non-whitespace if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) ++p; else return p; // The middle of string using SIMD static const char whitespace[16] = " \n\r\t"; const __m128i w = _mm_loadu_si128(reinterpret_cast(&whitespace[0])); for (; p <= end - 16; p += 16) { const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); const int r = _mm_cmpistri(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY); if (r != 16) // some of characters is non-whitespace return p + r; } return SkipWhitespace(p, end); } #elif defined(RAPIDJSON_SSE2) //! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { // Fast return for single non-whitespace if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // 16-byte align to the next boundary const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // The rest of string #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; #undef C16 const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); __m128i x = _mm_cmpeq_epi8(s, w0); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); unsigned short r = static_cast(~_mm_movemask_epi8(x)); if (r != 0) { // some of characters may be non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; _BitScanForward(&offset, r); return p + offset; #else return p + __builtin_ffs(r) - 1; #endif } } } inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { // Fast return for single non-whitespace if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) ++p; else return p; // The rest of string #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c } static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') }; #undef C16 const __m128i w0 = _mm_loadu_si128(reinterpret_cast(&whitespaces[0][0])); const __m128i w1 = _mm_loadu_si128(reinterpret_cast(&whitespaces[1][0])); const __m128i w2 = _mm_loadu_si128(reinterpret_cast(&whitespaces[2][0])); const __m128i w3 = _mm_loadu_si128(reinterpret_cast(&whitespaces[3][0])); for (; p <= end - 16; p += 16) { const __m128i s = _mm_loadu_si128(reinterpret_cast(p)); __m128i x = _mm_cmpeq_epi8(s, w0); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2)); x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3)); unsigned short r = static_cast(~_mm_movemask_epi8(x)); if (r != 0) { // some of characters may be non-whitespace #ifdef _MSC_VER // Find the index of first non-whitespace unsigned long offset; _BitScanForward(&offset, r); return p + offset; #else return p + __builtin_ffs(r) - 1; #endif } } return SkipWhitespace(p, end); } #elif defined(RAPIDJSON_NEON) //! Skip whitespace with ARM Neon instructions, testing 16 8-byte characters at once. inline const char *SkipWhitespace_SIMD(const char* p) { // Fast return for single non-whitespace if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; // 16-byte align to the next boundary const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t') ++p; else return p; const uint8x16_t w0 = vmovq_n_u8(' '); const uint8x16_t w1 = vmovq_n_u8('\n'); const uint8x16_t w2 = vmovq_n_u8('\r'); const uint8x16_t w3 = vmovq_n_u8('\t'); for (;; p += 16) { const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); uint8x16_t x = vceqq_u8(s, w0); x = vorrq_u8(x, vceqq_u8(s, w1)); x = vorrq_u8(x, vceqq_u8(s, w2)); x = vorrq_u8(x, vceqq_u8(s, w3)); x = vmvnq_u8(x); // Negate x = vrev64q_u8(x); // Rev in 64 uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract if (low == 0) { if (high != 0) { int lz =__builtin_clzll(high);; return p + 8 + (lz >> 3); } } else { int lz = __builtin_clzll(low);; return p + (lz >> 3); } } } inline const char *SkipWhitespace_SIMD(const char* p, const char* end) { // Fast return for single non-whitespace if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')) ++p; else return p; const uint8x16_t w0 = vmovq_n_u8(' '); const uint8x16_t w1 = vmovq_n_u8('\n'); const uint8x16_t w2 = vmovq_n_u8('\r'); const uint8x16_t w3 = vmovq_n_u8('\t'); for (; p <= end - 16; p += 16) { const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); uint8x16_t x = vceqq_u8(s, w0); x = vorrq_u8(x, vceqq_u8(s, w1)); x = vorrq_u8(x, vceqq_u8(s, w2)); x = vorrq_u8(x, vceqq_u8(s, w3)); x = vmvnq_u8(x); // Negate x = vrev64q_u8(x); // Rev in 64 uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract if (low == 0) { if (high != 0) { int lz = __builtin_clzll(high); return p + 8 + (lz >> 3); } } else { int lz = __builtin_clzll(low); return p + (lz >> 3); } } return SkipWhitespace(p, end); } #endif // RAPIDJSON_NEON #ifdef RAPIDJSON_SIMD //! Template function specialization for InsituStringStream template<> inline void SkipWhitespace(InsituStringStream& is) { is.src_ = const_cast(SkipWhitespace_SIMD(is.src_)); } //! Template function specialization for StringStream template<> inline void SkipWhitespace(StringStream& is) { is.src_ = SkipWhitespace_SIMD(is.src_); } template<> inline void SkipWhitespace(EncodedInputStream, MemoryStream>& is) { is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_); } #endif // RAPIDJSON_SIMD /////////////////////////////////////////////////////////////////////////////// // GenericReader //! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator. /*! GenericReader parses JSON text from a stream, and send events synchronously to an object implementing Handler concept. It needs to allocate a stack for storing a single decoded string during non-destructive parsing. For in-situ parsing, the decoded string is directly written to the source text string, no temporary buffer is required. A GenericReader object can be reused for parsing multiple JSON text. \tparam SourceEncoding Encoding of the input stream. \tparam TargetEncoding Encoding of the parse output. \tparam StackAllocator Allocator type for stack. */ template class GenericReader { public: typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type //! Constructor. /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing) \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing) */ GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {} //! Parse JSON text. /*! \tparam parseFlags Combination of \ref ParseFlag. \tparam InputStream Type of input stream, implementing Stream concept. \tparam Handler Type of handler, implementing Handler concept. \param is Input stream to be parsed. \param handler The handler to receive events. \return Whether the parsing is successful. */ template ParseResult Parse(InputStream& is, Handler& handler) { if (parseFlags & kParseIterativeFlag) return IterativeParse(is, handler); parseResult_.Clear(); ClearStackOnExit scope(*this); SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell()); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } else { ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (!(parseFlags & kParseStopWhenDoneFlag)) { SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell()); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } } } return parseResult_; } //! Parse JSON text (with \ref kParseDefaultFlags) /*! \tparam InputStream Type of input stream, implementing Stream concept \tparam Handler Type of handler, implementing Handler concept. \param is Input stream to be parsed. \param handler The handler to receive events. \return Whether the parsing is successful. */ template ParseResult Parse(InputStream& is, Handler& handler) { return Parse(is, handler); } //! Initialize JSON text token-by-token parsing /*! */ void IterativeParseInit() { parseResult_.Clear(); state_ = IterativeParsingStartState; } //! Parse one token from JSON text /*! \tparam InputStream Type of input stream, implementing Stream concept \tparam Handler Type of handler, implementing Handler concept. \param is Input stream to be parsed. \param handler The handler to receive events. \return Whether the parsing is successful. */ template bool IterativeParseNext(InputStream& is, Handler& handler) { while (RAPIDJSON_LIKELY(is.Peek() != '\0')) { SkipWhitespaceAndComments(is); Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state_, t); IterativeParsingState d = Transit(state_, t, n, is, handler); // If we've finished or hit an error... if (RAPIDJSON_UNLIKELY(IsIterativeParsingCompleteState(d))) { // Report errors. if (d == IterativeParsingErrorState) { HandleError(state_, is); return false; } // Transition to the finish state. RAPIDJSON_ASSERT(d == IterativeParsingFinishState); state_ = d; // If StopWhenDone is not set... if (!(parseFlags & kParseStopWhenDoneFlag)) { // ... and extra non-whitespace data is found... SkipWhitespaceAndComments(is); if (is.Peek() != '\0') { // ... this is considered an error. HandleError(state_, is); return false; } } // Success! We are done! return true; } // Transition to the new state. state_ = d; // If we parsed anything other than a delimiter, we invoked the handler, so we can return true now. if (!IsIterativeParsingDelimiterState(n)) return true; } // We reached the end of file. stack_.Clear(); if (state_ != IterativeParsingFinishState) { HandleError(state_, is); return false; } return true; } //! Check if token-by-token parsing JSON text is complete /*! \return Whether the JSON has been fully decoded. */ RAPIDJSON_FORCEINLINE bool IterativeParseComplete() { return IsIterativeParsingCompleteState(state_); } //! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); } //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } protected: void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); } private: // Prohibit copy constructor & assignment operator. GenericReader(const GenericReader&); GenericReader& operator=(const GenericReader&); void ClearStack() { stack_.Clear(); } // clear stack on any exit from ParseStream, e.g. due to exception struct ClearStackOnExit { explicit ClearStackOnExit(GenericReader& r) : r_(r) {} ~ClearStackOnExit() { r_.ClearStack(); } private: GenericReader& r_; ClearStackOnExit(const ClearStackOnExit&); ClearStackOnExit& operator=(const ClearStackOnExit&); }; template void SkipWhitespaceAndComments(InputStream& is) { SkipWhitespace(is); if (parseFlags & kParseCommentsFlag) { while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) { if (Consume(is, '*')) { while (true) { if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); else if (Consume(is, '*')) { if (Consume(is, '/')) break; } else is.Take(); } } else if (RAPIDJSON_LIKELY(Consume(is, '/'))) while (is.Peek() != '\0' && is.Take() != '\n') {} else RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell()); SkipWhitespace(is); } } } // Parse object: { string : value, ... } template void ParseObject(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '{'); is.Take(); // Skip '{' if (RAPIDJSON_UNLIKELY(!handler.StartObject())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (Consume(is, '}')) { if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } for (SizeType memberCount = 0;;) { if (RAPIDJSON_UNLIKELY(is.Peek() != '"')) RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); ParseString(is, handler, true); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (RAPIDJSON_UNLIKELY(!Consume(is, ':'))) RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++memberCount; switch (is.Peek()) { case ',': is.Take(); SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; break; case '}': is.Take(); if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; default: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy } if (parseFlags & kParseTrailingCommasFlag) { if (is.Peek() == '}') { if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); is.Take(); return; } } } } // Parse array: [ value, ... ] template void ParseArray(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == '['); is.Take(); // Skip '[' if (RAPIDJSON_UNLIKELY(!handler.StartArray())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (Consume(is, ']')) { if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } for (SizeType elementCount = 0;;) { ParseValue(is, handler); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; ++elementCount; SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (Consume(is, ',')) { SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; } else if (Consume(is, ']')) { if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); return; } else RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); if (parseFlags & kParseTrailingCommasFlag) { if (is.Peek() == ']') { if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); is.Take(); return; } } } } template void ParseNull(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == 'n'); is.Take(); if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) { if (RAPIDJSON_UNLIKELY(!handler.Null())) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template void ParseTrue(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == 't'); is.Take(); if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) { if (RAPIDJSON_UNLIKELY(!handler.Bool(true))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template void ParseFalse(InputStream& is, Handler& handler) { RAPIDJSON_ASSERT(is.Peek() == 'f'); is.Take(); if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) { if (RAPIDJSON_UNLIKELY(!handler.Bool(false))) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell()); } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); } template RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) { if (RAPIDJSON_LIKELY(is.Peek() == expect)) { is.Take(); return true; } else return false; } // Helper function to parse four hexidecimal digits in \uXXXX in ParseString(). template unsigned ParseHex4(InputStream& is, size_t escapeOffset) { unsigned codepoint = 0; for (int i = 0; i < 4; i++) { Ch c = is.Peek(); codepoint <<= 4; codepoint += static_cast(c); if (c >= '0' && c <= '9') codepoint -= '0'; else if (c >= 'A' && c <= 'F') codepoint -= 'A' - 10; else if (c >= 'a' && c <= 'f') codepoint -= 'a' - 10; else { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0); } is.Take(); } return codepoint; } template class StackStream { public: typedef CharType Ch; StackStream(internal::Stack& stack) : stack_(stack), length_(0) {} RAPIDJSON_FORCEINLINE void Put(Ch c) { *stack_.template Push() = c; ++length_; } RAPIDJSON_FORCEINLINE void* Push(SizeType count) { length_ += count; return stack_.template Push(count); } size_t Length() const { return length_; } Ch* Pop() { return stack_.template Pop(length_); } private: StackStream(const StackStream&); StackStream& operator=(const StackStream&); internal::Stack& stack_; SizeType length_; }; // Parse string and generate String event. Different code paths for kParseInsituFlag. template void ParseString(InputStream& is, Handler& handler, bool isKey = false) { internal::StreamLocalCopy copy(is); InputStream& s(copy.s); RAPIDJSON_ASSERT(s.Peek() == '\"'); s.Take(); // Skip '\"' bool success = false; if (parseFlags & kParseInsituFlag) { typename InputStream::Ch *head = s.PutBegin(); ParseStringToStream(s, s); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; size_t length = s.PutEnd(head) - 1; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); const typename TargetEncoding::Ch* const str = reinterpret_cast(head); success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false)); } else { StackStream stackStream(stack_); ParseStringToStream(s, stackStream); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; SizeType length = static_cast(stackStream.Length()) - 1; const typename TargetEncoding::Ch* const str = stackStream.Pop(); success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true)); } if (RAPIDJSON_UNLIKELY(!success)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell()); } // Parse string to an output is // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation. template RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) { //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 static const char escape[256] = { Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/', Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0, 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 }; #undef Z16 //!@endcond for (;;) { // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation. if (!(parseFlags & kParseValidateEncodingFlag)) ScanCopyUnescapedString(is, os); Ch c = is.Peek(); if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset is.Take(); Ch e = is.Peek(); if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast(e)])) { is.Take(); os.Put(static_cast(escape[static_cast(e)])); } else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode is.Take(); unsigned codepoint = ParseHex4(is, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) { // Handle UTF-16 surrogate pair if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u'))) RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); unsigned codepoint2 = ParseHex4(is, escapeOffset); RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF)) RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset); codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000; } TEncoding::Encode(os, codepoint); } else RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset); } else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote is.Take(); os.Put('\0'); // null-terminate the string return; } else if (RAPIDJSON_UNLIKELY(static_cast(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF if (c == '\0') RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell()); else RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, is.Tell()); } else { size_t offset = is.Tell(); if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ? !Transcoder::Validate(is, os) : !Transcoder::Transcode(is, os)))) RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset); } } } template static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) { // Do nothing for generic version } #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) // StringStream -> StackStream static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { const char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = p; return; } else os.Put(*p++); // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped SizeType length; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); length = offset; #else length = static_cast(__builtin_ffs(r) - 1); #endif if (length != 0) { char* q = reinterpret_cast(os.Push(length)); for (size_t i = 0; i < length; i++) q[i] = p[i]; p += length; } break; } _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s); } is.src_ = p; } // InsituStringStream -> InsituStringStream static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { RAPIDJSON_ASSERT(&is == &os); (void)os; if (is.src_ == is.dst_) { SkipUnescapedString(is); return; } char* p = is.src_; char *q = is.dst_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = p; is.dst_ = q; return; } else *q++ = *p++; // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); for (;; p += 16, q += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped size_t length; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); length = offset; #else length = static_cast(__builtin_ffs(r) - 1); #endif for (const char* pend = p + length; p != pend; ) *q++ = *p++; break; } _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s); } is.src_ = p; is.dst_ = q; } // When read/write pointers are the same for insitu stream, just skip unescaped characters static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { RAPIDJSON_ASSERT(is.src_ == is.dst_); char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); for (; p != nextAligned; p++) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = is.dst_ = p; return; } // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); for (;; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped size_t length; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); length = offset; #else length = static_cast(__builtin_ffs(r) - 1); #endif p += length; break; } } is.src_ = is.dst_ = p; } #elif defined(RAPIDJSON_NEON) // StringStream -> StackStream static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream& os) { const char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = p; return; } else os.Put(*p++); // The rest of string using SIMD const uint8x16_t s0 = vmovq_n_u8('"'); const uint8x16_t s1 = vmovq_n_u8('\\'); const uint8x16_t s2 = vmovq_n_u8('\b'); const uint8x16_t s3 = vmovq_n_u8(32); for (;; p += 16) { const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); uint8x16_t x = vceqq_u8(s, s0); x = vorrq_u8(x, vceqq_u8(s, s1)); x = vorrq_u8(x, vceqq_u8(s, s2)); x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract SizeType length = 0; bool escaped = false; if (low == 0) { if (high != 0) { unsigned lz = (unsigned)__builtin_clzll(high);; length = 8 + (lz >> 3); escaped = true; } } else { unsigned lz = (unsigned)__builtin_clzll(low);; length = lz >> 3; escaped = true; } if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped if (length != 0) { char* q = reinterpret_cast(os.Push(length)); for (size_t i = 0; i < length; i++) q[i] = p[i]; p += length; } break; } vst1q_u8(reinterpret_cast(os.Push(16)), s); } is.src_ = p; } // InsituStringStream -> InsituStringStream static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) { RAPIDJSON_ASSERT(&is == &os); (void)os; if (is.src_ == is.dst_) { SkipUnescapedString(is); return; } char* p = is.src_; char *q = is.dst_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); while (p != nextAligned) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = p; is.dst_ = q; return; } else *q++ = *p++; // The rest of string using SIMD const uint8x16_t s0 = vmovq_n_u8('"'); const uint8x16_t s1 = vmovq_n_u8('\\'); const uint8x16_t s2 = vmovq_n_u8('\b'); const uint8x16_t s3 = vmovq_n_u8(32); for (;; p += 16, q += 16) { const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); uint8x16_t x = vceqq_u8(s, s0); x = vorrq_u8(x, vceqq_u8(s, s1)); x = vorrq_u8(x, vceqq_u8(s, s2)); x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract SizeType length = 0; bool escaped = false; if (low == 0) { if (high != 0) { unsigned lz = (unsigned)__builtin_clzll(high); length = 8 + (lz >> 3); escaped = true; } } else { unsigned lz = (unsigned)__builtin_clzll(low); length = lz >> 3; escaped = true; } if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped for (const char* pend = p + length; p != pend; ) { *q++ = *p++; } break; } vst1q_u8(reinterpret_cast(q), s); } is.src_ = p; is.dst_ = q; } // When read/write pointers are the same for insitu stream, just skip unescaped characters static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) { RAPIDJSON_ASSERT(is.src_ == is.dst_); char* p = is.src_; // Scan one by one until alignment (unaligned load may cross page boundary and cause crash) const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); for (; p != nextAligned; p++) if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast(*p) < 0x20)) { is.src_ = is.dst_ = p; return; } // The rest of string using SIMD const uint8x16_t s0 = vmovq_n_u8('"'); const uint8x16_t s1 = vmovq_n_u8('\\'); const uint8x16_t s2 = vmovq_n_u8('\b'); const uint8x16_t s3 = vmovq_n_u8(32); for (;; p += 16) { const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); uint8x16_t x = vceqq_u8(s, s0); x = vorrq_u8(x, vceqq_u8(s, s1)); x = vorrq_u8(x, vceqq_u8(s, s2)); x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract if (low == 0) { if (high != 0) { int lz = __builtin_clzll(high); p += 8 + (lz >> 3); break; } } else { int lz = __builtin_clzll(low); p += lz >> 3; break; } } is.src_ = is.dst_ = p; } #endif // RAPIDJSON_NEON template class NumberStream; template class NumberStream { public: typedef typename InputStream::Ch Ch; NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; } RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); } RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); } RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); } RAPIDJSON_FORCEINLINE void Push(char) {} size_t Tell() { return is.Tell(); } size_t Length() { return 0; } const char* Pop() { return 0; } protected: NumberStream& operator=(const NumberStream&); InputStream& is; }; template class NumberStream : public NumberStream { typedef NumberStream Base; public: NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {} RAPIDJSON_FORCEINLINE Ch TakePush() { stackStream.Put(static_cast(Base::is.Peek())); return Base::is.Take(); } RAPIDJSON_FORCEINLINE void Push(char c) { stackStream.Put(c); } size_t Length() { return stackStream.Length(); } const char* Pop() { stackStream.Put('\0'); return stackStream.Pop(); } private: StackStream stackStream; }; template class NumberStream : public NumberStream { typedef NumberStream Base; public: NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {} RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); } }; template void ParseNumber(InputStream& is, Handler& handler) { internal::StreamLocalCopy copy(is); NumberStream s(*this, copy.s); size_t startOffset = s.Tell(); double d = 0.0; bool useNanOrInf = false; // Parse minus bool minus = Consume(s, '-'); // Parse int: zero / ( digit1-9 *DIGIT ) unsigned i = 0; uint64_t i64 = 0; bool use64bit = false; int significandDigit = 0; if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) { i = 0; s.TakePush(); } else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) { i = static_cast(s.TakePush() - '0'); if (minus) while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648 if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) { i64 = i; use64bit = true; break; } } i = i * 10 + static_cast(s.TakePush() - '0'); significandDigit++; } else while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295 if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) { i64 = i; use64bit = true; break; } } i = i * 10 + static_cast(s.TakePush() - '0'); significandDigit++; } } // Parse NaN or Infinity here else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) { if (Consume(s, 'N')) { if (Consume(s, 'a') && Consume(s, 'N')) { d = std::numeric_limits::quiet_NaN(); useNanOrInf = true; } } else if (RAPIDJSON_LIKELY(Consume(s, 'I'))) { if (Consume(s, 'n') && Consume(s, 'f')) { d = (minus ? -std::numeric_limits::infinity() : std::numeric_limits::infinity()); useNanOrInf = true; if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n') && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y')))) { RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); } } } if (RAPIDJSON_UNLIKELY(!useNanOrInf)) { RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); } } else RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell()); // Parse 64bit int bool useDouble = false; if (use64bit) { if (minus) while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808 if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) { d = static_cast(i64); useDouble = true; break; } i64 = i64 * 10 + static_cast(s.TakePush() - '0'); significandDigit++; } else while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615 if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) { d = static_cast(i64); useDouble = true; break; } i64 = i64 * 10 + static_cast(s.TakePush() - '0'); significandDigit++; } } // Force double for big integer if (useDouble) { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0 RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); d = d * 10 + (s.TakePush() - '0'); } } // Parse frac = decimal-point 1*DIGIT int expFrac = 0; size_t decimalPosition; if (Consume(s, '.')) { decimalPosition = s.Length(); if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9'))) RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell()); if (!useDouble) { #if RAPIDJSON_64BIT // Use i64 to store significand in 64-bit architecture if (!use64bit) i64 = i; while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path break; else { i64 = i64 * 10 + static_cast(s.TakePush() - '0'); --expFrac; if (i64 != 0) significandDigit++; } } d = static_cast(i64); #else // Use double to store significand in 32-bit architecture d = static_cast(use64bit ? i64 : i); #endif useDouble = true; } while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { if (significandDigit < 17) { d = d * 10.0 + (s.TakePush() - '0'); --expFrac; if (RAPIDJSON_LIKELY(d > 0.0)) significandDigit++; } else s.TakePush(); } } else decimalPosition = s.Length(); // decimal position at the end of integer. // Parse exp = e [ minus / plus ] 1*DIGIT int exp = 0; if (Consume(s, 'e') || Consume(s, 'E')) { if (!useDouble) { d = static_cast(use64bit ? i64 : i); useDouble = true; } bool expMinus = false; if (Consume(s, '+')) ; else if (Consume(s, '-')) expMinus = true; if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = static_cast(s.Take() - '0'); if (expMinus) { while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = exp * 10 + static_cast(s.Take() - '0'); if (exp >= 214748364) { // Issue #313: prevent overflow exponent while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent s.Take(); } } } else { // positive exp int maxExp = 308 - expFrac; while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) { exp = exp * 10 + static_cast(s.Take() - '0'); if (RAPIDJSON_UNLIKELY(exp > maxExp)) RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset); } } } else RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell()); if (expMinus) exp = -exp; } // Finish parsing, call event according to the type of number. bool cont = true; if (parseFlags & kParseNumbersAsStringsFlag) { if (parseFlags & kParseInsituFlag) { s.Pop(); // Pop stack no matter if it will be used or not. typename InputStream::Ch* head = is.PutBegin(); const size_t length = s.Tell() - startOffset; RAPIDJSON_ASSERT(length <= 0xFFFFFFFF); // unable to insert the \0 character here, it will erase the comma after this number const typename TargetEncoding::Ch* const str = reinterpret_cast(head); cont = handler.RawNumber(str, SizeType(length), false); } else { SizeType numCharsToCopy = static_cast(s.Length()); StringStream srcStream(s.Pop()); StackStream dstStream(stack_); while (numCharsToCopy--) { Transcoder, TargetEncoding>::Transcode(srcStream, dstStream); } dstStream.Put('\0'); const typename TargetEncoding::Ch* str = dstStream.Pop(); const SizeType length = static_cast(dstStream.Length()) - 1; cont = handler.RawNumber(str, SizeType(length), true); } } else { size_t length = s.Length(); const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not. if (useDouble) { int p = exp + expFrac; if (parseFlags & kParseFullPrecisionFlag) d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp); else d = internal::StrtodNormalPrecision(d, p); cont = handler.Double(minus ? -d : d); } else if (useNanOrInf) { cont = handler.Double(d); } else { if (use64bit) { if (minus) cont = handler.Int64(static_cast(~i64 + 1)); else cont = handler.Uint64(i64); } else { if (minus) cont = handler.Int(static_cast(~i + 1)); else cont = handler.Uint(i); } } } if (RAPIDJSON_UNLIKELY(!cont)) RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset); } // Parse any JSON value template void ParseValue(InputStream& is, Handler& handler) { switch (is.Peek()) { case 'n': ParseNull (is, handler); break; case 't': ParseTrue (is, handler); break; case 'f': ParseFalse (is, handler); break; case '"': ParseString(is, handler); break; case '{': ParseObject(is, handler); break; case '[': ParseArray (is, handler); break; default : ParseNumber(is, handler); break; } } // Iterative Parsing // States enum IterativeParsingState { IterativeParsingFinishState = 0, // sink states at top IterativeParsingErrorState, // sink states at top IterativeParsingStartState, // Object states IterativeParsingObjectInitialState, IterativeParsingMemberKeyState, IterativeParsingMemberValueState, IterativeParsingObjectFinishState, // Array states IterativeParsingArrayInitialState, IterativeParsingElementState, IterativeParsingArrayFinishState, // Single value state IterativeParsingValueState, // Delimiter states (at bottom) IterativeParsingElementDelimiterState, IterativeParsingMemberDelimiterState, IterativeParsingKeyValueDelimiterState, cIterativeParsingStateCount }; // Tokens enum Token { LeftBracketToken = 0, RightBracketToken, LeftCurlyBracketToken, RightCurlyBracketToken, CommaToken, ColonToken, StringToken, FalseToken, TrueToken, NullToken, NumberToken, kTokenCount }; RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) { //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define N NumberToken #define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N // Maps from ASCII to Token static const unsigned char tokenMap[256] = { N16, // 00~0F N16, // 10~1F N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F N16, // 40~4F N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF }; #undef N #undef N16 //!@endcond if (sizeof(Ch) == 1 || static_cast(c) < 256) return static_cast(tokenMap[static_cast(c)]); else return NumberToken; } RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) { // current state x one lookahead token -> new state static const char G[cIterativeParsingStateCount][kTokenCount] = { // Finish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // Error(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // Start { IterativeParsingArrayInitialState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingValueState, // String IterativeParsingValueState, // False IterativeParsingValueState, // True IterativeParsingValueState, // Null IterativeParsingValueState // Number }, // ObjectInitial { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingObjectFinishState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingMemberKeyState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // MemberKey { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingKeyValueDelimiterState, // Colon IterativeParsingErrorState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // MemberValue { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingObjectFinishState, // Right curly bracket IterativeParsingMemberDelimiterState, // Comma IterativeParsingErrorState, // Colon IterativeParsingErrorState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // ObjectFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // ArrayInitial { IterativeParsingArrayInitialState, // Left bracket(push Element state) IterativeParsingArrayFinishState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket(push Element state) IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingElementState, // String IterativeParsingElementState, // False IterativeParsingElementState, // True IterativeParsingElementState, // Null IterativeParsingElementState // Number }, // Element { IterativeParsingErrorState, // Left bracket IterativeParsingArrayFinishState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingErrorState, // Right curly bracket IterativeParsingElementDelimiterState, // Comma IterativeParsingErrorState, // Colon IterativeParsingErrorState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // ArrayFinish(sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // Single Value (sink state) { IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState }, // ElementDelimiter { IterativeParsingArrayInitialState, // Left bracket(push Element state) IterativeParsingArrayFinishState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket(push Element state) IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingElementState, // String IterativeParsingElementState, // False IterativeParsingElementState, // True IterativeParsingElementState, // Null IterativeParsingElementState // Number }, // MemberDelimiter { IterativeParsingErrorState, // Left bracket IterativeParsingErrorState, // Right bracket IterativeParsingErrorState, // Left curly bracket IterativeParsingObjectFinishState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingMemberKeyState, // String IterativeParsingErrorState, // False IterativeParsingErrorState, // True IterativeParsingErrorState, // Null IterativeParsingErrorState // Number }, // KeyValueDelimiter { IterativeParsingArrayInitialState, // Left bracket(push MemberValue state) IterativeParsingErrorState, // Right bracket IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state) IterativeParsingErrorState, // Right curly bracket IterativeParsingErrorState, // Comma IterativeParsingErrorState, // Colon IterativeParsingMemberValueState, // String IterativeParsingMemberValueState, // False IterativeParsingMemberValueState, // True IterativeParsingMemberValueState, // Null IterativeParsingMemberValueState // Number }, }; // End of G return static_cast(G[state][token]); } // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit(). // May return a new state on state pop. template RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) { (void)token; switch (dst) { case IterativeParsingErrorState: return dst; case IterativeParsingObjectInitialState: case IterativeParsingArrayInitialState: { // Push the state(Element or MemeberValue) if we are nested in another array or value of member. // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop. IterativeParsingState n = src; if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState) n = IterativeParsingElementState; else if (src == IterativeParsingKeyValueDelimiterState) n = IterativeParsingMemberValueState; // Push current state. *stack_.template Push(1) = n; // Initialize and push the member/element count. *stack_.template Push(1) = 0; // Call handler bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray(); // On handler short circuits the parsing. if (!hr) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { is.Take(); return dst; } } case IterativeParsingMemberKeyState: ParseString(is, handler, true); if (HasParseError()) return IterativeParsingErrorState; else return dst; case IterativeParsingKeyValueDelimiterState: RAPIDJSON_ASSERT(token == ColonToken); is.Take(); return dst; case IterativeParsingMemberValueState: // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue(is, handler); if (HasParseError()) { return IterativeParsingErrorState; } return dst; case IterativeParsingElementState: // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue(is, handler); if (HasParseError()) { return IterativeParsingErrorState; } return dst; case IterativeParsingMemberDelimiterState: case IterativeParsingElementDelimiterState: is.Take(); // Update member/element count. *stack_.template Top() = *stack_.template Top() + 1; return dst; case IterativeParsingObjectFinishState: { // Transit from delimiter is only allowed when trailing commas are enabled if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell()); return IterativeParsingErrorState; } // Get member count. SizeType c = *stack_.template Pop(1); // If the object is not empty, count the last member. if (src == IterativeParsingMemberValueState) ++c; // Restore the state. IterativeParsingState n = static_cast(*stack_.template Pop(1)); // Transit to Finish state if this is the topmost scope. if (n == IterativeParsingStartState) n = IterativeParsingFinishState; // Call handler bool hr = handler.EndObject(c); // On handler short circuits the parsing. if (!hr) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { is.Take(); return n; } } case IterativeParsingArrayFinishState: { // Transit from delimiter is only allowed when trailing commas are enabled if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell()); return IterativeParsingErrorState; } // Get element count. SizeType c = *stack_.template Pop(1); // If the array is not empty, count the last element. if (src == IterativeParsingElementState) ++c; // Restore the state. IterativeParsingState n = static_cast(*stack_.template Pop(1)); // Transit to Finish state if this is the topmost scope. if (n == IterativeParsingStartState) n = IterativeParsingFinishState; // Call handler bool hr = handler.EndArray(c); // On handler short circuits the parsing. if (!hr) { RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell()); return IterativeParsingErrorState; } else { is.Take(); return n; } } default: // This branch is for IterativeParsingValueState actually. // Use `default:` rather than // `case IterativeParsingValueState:` is for code coverage. // The IterativeParsingStartState is not enumerated in this switch-case. // It is impossible for that case. And it can be caught by following assertion. // The IterativeParsingFinishState is not enumerated in this switch-case either. // It is a "derivative" state which cannot triggered from Predict() directly. // Therefore it cannot happen here. And it can be caught by following assertion. RAPIDJSON_ASSERT(dst == IterativeParsingValueState); // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state. ParseValue(is, handler); if (HasParseError()) { return IterativeParsingErrorState; } return IterativeParsingFinishState; } } template void HandleError(IterativeParsingState src, InputStream& is) { if (HasParseError()) { // Error flag has been set. return; } switch (src) { case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return; case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return; case IterativeParsingObjectInitialState: case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return; case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return; case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return; case IterativeParsingKeyValueDelimiterState: case IterativeParsingArrayInitialState: case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return; default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return; } } RAPIDJSON_FORCEINLINE bool IsIterativeParsingDelimiterState(IterativeParsingState s) { return s >= IterativeParsingElementDelimiterState; } RAPIDJSON_FORCEINLINE bool IsIterativeParsingCompleteState(IterativeParsingState s) { return s <= IterativeParsingErrorState; } template ParseResult IterativeParse(InputStream& is, Handler& handler) { parseResult_.Clear(); ClearStackOnExit scope(*this); IterativeParsingState state = IterativeParsingStartState; SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); while (is.Peek() != '\0') { Token t = Tokenize(is.Peek()); IterativeParsingState n = Predict(state, t); IterativeParsingState d = Transit(state, t, n, is, handler); if (d == IterativeParsingErrorState) { HandleError(state, is); break; } state = d; // Do not further consume streams if a root JSON has been parsed. if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState) break; SkipWhitespaceAndComments(is); RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_); } // Handle the end of file. if (state != IterativeParsingFinishState) HandleError(state, is); return parseResult_; } static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string. internal::Stack stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing. ParseResult parseResult_; IterativeParsingState state_; }; // class GenericReader //! Reader with UTF8 encoding and default allocator. typedef GenericReader, UTF8<> > Reader; RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #ifdef _MSC_VER RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_READER_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/rapidjson.h0000644002537200234200000005276313213503245024500 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_RAPIDJSON_H_ #define RAPIDJSON_RAPIDJSON_H_ /*!\file rapidjson.h \brief common definitions and configuration \see RAPIDJSON_CONFIG */ /*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration \brief Configuration macros for library features Some RapidJSON features are configurable to adapt the library to a wide variety of platforms, environments and usage scenarios. Most of the features can be configured in terms of overriden or predefined preprocessor macros at compile-time. Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs. \note These macros should be given on the compiler command-line (where applicable) to avoid inconsistent values when compiling different translation units of a single application. */ #include // malloc(), realloc(), free(), size_t #include // memset(), memcpy(), memmove(), memcmp() /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_VERSION_STRING // // ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt. // //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN // token stringification #define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x) #define RAPIDJSON_DO_STRINGIFY(x) #x // token concatenation #define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y) #define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y) #define RAPIDJSON_DO_JOIN2(X, Y) X##Y //!@endcond /*! \def RAPIDJSON_MAJOR_VERSION \ingroup RAPIDJSON_CONFIG \brief Major version of RapidJSON in integer. */ /*! \def RAPIDJSON_MINOR_VERSION \ingroup RAPIDJSON_CONFIG \brief Minor version of RapidJSON in integer. */ /*! \def RAPIDJSON_PATCH_VERSION \ingroup RAPIDJSON_CONFIG \brief Patch version of RapidJSON in integer. */ /*! \def RAPIDJSON_VERSION_STRING \ingroup RAPIDJSON_CONFIG \brief Version of RapidJSON in ".." string format. */ #define RAPIDJSON_MAJOR_VERSION 1 #define RAPIDJSON_MINOR_VERSION 1 #define RAPIDJSON_PATCH_VERSION 0 #define RAPIDJSON_VERSION_STRING \ RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION) /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NAMESPACE_(BEGIN|END) /*! \def RAPIDJSON_NAMESPACE \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace In order to avoid symbol clashes and/or "One Definition Rule" errors between multiple inclusions of (different versions of) RapidJSON in a single binary, users can customize the name of the main RapidJSON namespace. In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE to a custom name (e.g. \c MyRapidJSON) is sufficient. If multiple levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref RAPIDJSON_NAMESPACE_END need to be defined as well: \code // in some .cpp file #define RAPIDJSON_NAMESPACE my::rapidjson #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson { #define RAPIDJSON_NAMESPACE_END } } #include "rapidjson/..." \endcode \see rapidjson */ /*! \def RAPIDJSON_NAMESPACE_BEGIN \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace (opening expression) \see RAPIDJSON_NAMESPACE */ /*! \def RAPIDJSON_NAMESPACE_END \ingroup RAPIDJSON_CONFIG \brief provide custom rapidjson namespace (closing expression) \see RAPIDJSON_NAMESPACE */ #ifndef RAPIDJSON_NAMESPACE #define RAPIDJSON_NAMESPACE rapidjson #endif #ifndef RAPIDJSON_NAMESPACE_BEGIN #define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE { #endif #ifndef RAPIDJSON_NAMESPACE_END #define RAPIDJSON_NAMESPACE_END } #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_HAS_STDSTRING #ifndef RAPIDJSON_HAS_STDSTRING #ifdef RAPIDJSON_DOXYGEN_RUNNING #define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation #else #define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default #endif /*! \def RAPIDJSON_HAS_STDSTRING \ingroup RAPIDJSON_CONFIG \brief Enable RapidJSON support for \c std::string By defining this preprocessor symbol to \c 1, several convenience functions for using \ref rapidjson::GenericValue with \c std::string are enabled, especially for construction and comparison. \hideinitializer */ #endif // !defined(RAPIDJSON_HAS_STDSTRING) #if RAPIDJSON_HAS_STDSTRING #include #endif // RAPIDJSON_HAS_STDSTRING /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_INT64DEFINE /*! \def RAPIDJSON_NO_INT64DEFINE \ingroup RAPIDJSON_CONFIG \brief Use external 64-bit integer types. RapidJSON requires the 64-bit integer types \c int64_t and \c uint64_t types to be available at global scope. If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to prevent RapidJSON from defining its own types. */ #ifndef RAPIDJSON_NO_INT64DEFINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #if defined(_MSC_VER) && (_MSC_VER < 1800) // Visual Studio 2013 #include "msinttypes/stdint.h" #include "msinttypes/inttypes.h" #else // Other compilers should have this. #include #include #endif //!@endcond #ifdef RAPIDJSON_DOXYGEN_RUNNING #define RAPIDJSON_NO_INT64DEFINE #endif #endif // RAPIDJSON_NO_INT64TYPEDEF /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_FORCEINLINE #ifndef RAPIDJSON_FORCEINLINE //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #if defined(_MSC_VER) && defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __forceinline #elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG) #define RAPIDJSON_FORCEINLINE __attribute__((always_inline)) #else #define RAPIDJSON_FORCEINLINE #endif //!@endcond #endif // RAPIDJSON_FORCEINLINE /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ENDIAN #define RAPIDJSON_LITTLEENDIAN 0 //!< Little endian machine #define RAPIDJSON_BIGENDIAN 1 //!< Big endian machine //! Endianness of the machine. /*! \def RAPIDJSON_ENDIAN \ingroup RAPIDJSON_CONFIG GCC 4.6 provided macro for detecting endianness of the target machine. But other compilers may not have this. User can define RAPIDJSON_ENDIAN to either \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN. Default detection implemented with reference to \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp */ #ifndef RAPIDJSON_ENDIAN // Detect with GCC 4.6's macro # ifdef __BYTE_ORDER__ # if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else # error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. # endif // __BYTE_ORDER__ // Detect with GLIBC's endian.h # elif defined(__GLIBC__) # include # if (__BYTE_ORDER == __LITTLE_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif (__BYTE_ORDER == __BIG_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # else # error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. # endif // __GLIBC__ // Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro # elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN // Detect with architecture macros # elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__) # define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN # elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(_MSC_VER) && (defined(_M_ARM) || defined(_M_ARM64)) # define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN # elif defined(RAPIDJSON_DOXYGEN_RUNNING) # define RAPIDJSON_ENDIAN # else # error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN. # endif #endif // RAPIDJSON_ENDIAN /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_64BIT //! Whether using 64-bit architecture #ifndef RAPIDJSON_64BIT #if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__) #define RAPIDJSON_64BIT 1 #else #define RAPIDJSON_64BIT 0 #endif #endif // RAPIDJSON_64BIT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ALIGN //! Data alignment of the machine. /*! \ingroup RAPIDJSON_CONFIG \param x pointer to align Some machines require strict data alignment. Currently the default uses 4 bytes alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms. User can customize by defining the RAPIDJSON_ALIGN function macro. */ #ifndef RAPIDJSON_ALIGN #if RAPIDJSON_64BIT == 1 #define RAPIDJSON_ALIGN(x) (((x) + static_cast(7u)) & ~static_cast(7u)) #else #define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u) #endif #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_UINT64_C2 //! Construct a 64-bit literal by a pair of 32-bit integer. /*! 64-bit literal with or without ULL suffix is prone to compiler warnings. UINT64_C() is C macro which cause compilation problems. Use this macro to define 64-bit constants by a pair of 32-bit integer. */ #ifndef RAPIDJSON_UINT64_C2 #define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast(high32) << 32) | static_cast(low32)) #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_48BITPOINTER_OPTIMIZATION //! Use only lower 48-bit address for some pointers. /*! \ingroup RAPIDJSON_CONFIG This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address. The higher 16-bit can be used for storing other data. \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture. */ #ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION #if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64) #define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1 #else #define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0 #endif #endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION #if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1 #if RAPIDJSON_64BIT != 1 #error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1 #endif #define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast((reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast(reinterpret_cast(x)))) #define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast(reinterpret_cast(p) & static_cast(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF)))) #else #define RAPIDJSON_SETPOINTER(type, p, x) (p = (x)) #define RAPIDJSON_GETPOINTER(type, p) (p) #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_NEON/RAPIDJSON_SIMD /*! \def RAPIDJSON_SIMD \ingroup RAPIDJSON_CONFIG \brief Enable SSE2/SSE4.2/Neon optimization. RapidJSON supports optimized implementations for some parsing operations based on the SSE2, SSE4.2 or NEon SIMD extensions on modern Intel or ARM compatible processors. To enable these optimizations, three different symbols can be defined; \code // Enable SSE2 optimization. #define RAPIDJSON_SSE2 // Enable SSE4.2 optimization. #define RAPIDJSON_SSE42 \endcode // Enable ARM Neon optimization. #define RAPIDJSON_NEON \endcode \c RAPIDJSON_SSE42 takes precedence over SSE2, if both are defined. If any of these symbols is defined, RapidJSON defines the macro \c RAPIDJSON_SIMD to indicate the availability of the optimized code. */ #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \ || defined(RAPIDJSON_NEON) || defined(RAPIDJSON_DOXYGEN_RUNNING) #define RAPIDJSON_SIMD #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_NO_SIZETYPEDEFINE #ifndef RAPIDJSON_NO_SIZETYPEDEFINE /*! \def RAPIDJSON_NO_SIZETYPEDEFINE \ingroup RAPIDJSON_CONFIG \brief User-provided \c SizeType definition. In order to avoid using 32-bit size types for indexing strings and arrays, define this preprocessor symbol and provide the type rapidjson::SizeType before including RapidJSON: \code #define RAPIDJSON_NO_SIZETYPEDEFINE namespace rapidjson { typedef ::std::size_t SizeType; } #include "rapidjson/..." \endcode \see rapidjson::SizeType */ #ifdef RAPIDJSON_DOXYGEN_RUNNING #define RAPIDJSON_NO_SIZETYPEDEFINE #endif RAPIDJSON_NAMESPACE_BEGIN //! Size type (for string lengths, array sizes, etc.) /*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms, instead of using \c size_t. Users may override the SizeType by defining \ref RAPIDJSON_NO_SIZETYPEDEFINE. */ typedef unsigned SizeType; RAPIDJSON_NAMESPACE_END #endif // always import std::size_t to rapidjson namespace RAPIDJSON_NAMESPACE_BEGIN using std::size_t; RAPIDJSON_NAMESPACE_END /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ASSERT //! Assertion. /*! \ingroup RAPIDJSON_CONFIG By default, rapidjson uses C \c assert() for internal assertions. User can override it by defining RAPIDJSON_ASSERT(x) macro. \note Parsing errors are handled and can be customized by the \ref RAPIDJSON_ERRORS APIs. */ #ifndef RAPIDJSON_ASSERT #include #define RAPIDJSON_ASSERT(x) assert(x) #endif // RAPIDJSON_ASSERT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_STATIC_ASSERT // Prefer C++11 static_assert, if available #ifndef RAPIDJSON_STATIC_ASSERT #if __cplusplus >= 201103L || ( defined(_MSC_VER) && _MSC_VER >= 1800 ) #define RAPIDJSON_STATIC_ASSERT(x) \ static_assert(x, RAPIDJSON_STRINGIFY(x)) #endif // C++11 #endif // RAPIDJSON_STATIC_ASSERT // Adopt C++03 implementation from boost #ifndef RAPIDJSON_STATIC_ASSERT #ifndef __clang__ //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #endif RAPIDJSON_NAMESPACE_BEGIN template struct STATIC_ASSERTION_FAILURE; template <> struct STATIC_ASSERTION_FAILURE { enum { value = 1 }; }; template struct StaticAssertTest {}; RAPIDJSON_NAMESPACE_END #if defined(__GNUC__) #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused)) #else #define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif #ifndef __clang__ //!@endcond #endif /*! \def RAPIDJSON_STATIC_ASSERT \brief (Internal) macro to check for conditions at compile-time \param x compile-time condition \hideinitializer */ #define RAPIDJSON_STATIC_ASSERT(x) \ typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \ sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE)> \ RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE #endif // RAPIDJSON_STATIC_ASSERT /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY //! Compiler branching hint for expression with high probability to be true. /*! \ingroup RAPIDJSON_CONFIG \param x Boolean expression likely to be true. */ #ifndef RAPIDJSON_LIKELY #if defined(__GNUC__) || defined(__clang__) #define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1) #else #define RAPIDJSON_LIKELY(x) (x) #endif #endif //! Compiler branching hint for expression with low probability to be true. /*! \ingroup RAPIDJSON_CONFIG \param x Boolean expression unlikely to be true. */ #ifndef RAPIDJSON_UNLIKELY #if defined(__GNUC__) || defined(__clang__) #define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0) #else #define RAPIDJSON_UNLIKELY(x) (x) #endif #endif /////////////////////////////////////////////////////////////////////////////// // Helpers //!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN #define RAPIDJSON_MULTILINEMACRO_BEGIN do { #define RAPIDJSON_MULTILINEMACRO_END \ } while((void)0, 0) // adopted from Boost #define RAPIDJSON_VERSION_CODE(x,y,z) \ (((x)*100000) + ((y)*100) + (z)) /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF #if defined(__GNUC__) #define RAPIDJSON_GNUC \ RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__) #endif #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0)) #define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x)) #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x) #define RAPIDJSON_DIAG_OFF(x) \ RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x))) // push/pop support in Clang and GCC>=4.6 #if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) #define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) #define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) #else // GCC >= 4.2, < 4.6 #define RAPIDJSON_DIAG_PUSH /* ignored */ #define RAPIDJSON_DIAG_POP /* ignored */ #endif #elif defined(_MSC_VER) // pragma (MSVC specific) #define RAPIDJSON_PRAGMA(x) __pragma(x) #define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x)) #define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x) #define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push) #define RAPIDJSON_DIAG_POP RAPIDJSON_DIAG_PRAGMA(pop) #else #define RAPIDJSON_DIAG_OFF(x) /* ignored */ #define RAPIDJSON_DIAG_PUSH /* ignored */ #define RAPIDJSON_DIAG_POP /* ignored */ #endif // RAPIDJSON_DIAG_* /////////////////////////////////////////////////////////////////////////////// // C++11 features #ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS #if defined(__clang__) #if __has_feature(cxx_rvalue_references) && \ (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 #endif #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1600) #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1 #else #define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0 #endif #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS #ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT #if defined(__clang__) #define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept) #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) // (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported #define RAPIDJSON_HAS_CXX11_NOEXCEPT 1 #else #define RAPIDJSON_HAS_CXX11_NOEXCEPT 0 #endif #endif #if RAPIDJSON_HAS_CXX11_NOEXCEPT #define RAPIDJSON_NOEXCEPT noexcept #else #define RAPIDJSON_NOEXCEPT /* noexcept */ #endif // RAPIDJSON_HAS_CXX11_NOEXCEPT // no automatic detection, yet #ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS #define RAPIDJSON_HAS_CXX11_TYPETRAITS 0 #endif #ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR #if defined(__clang__) #define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for) #elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \ (defined(_MSC_VER) && _MSC_VER >= 1700) #define RAPIDJSON_HAS_CXX11_RANGE_FOR 1 #else #define RAPIDJSON_HAS_CXX11_RANGE_FOR 0 #endif #endif // RAPIDJSON_HAS_CXX11_RANGE_FOR //!@endcond /////////////////////////////////////////////////////////////////////////////// // new/delete #ifndef RAPIDJSON_NEW ///! customization point for global \c new #define RAPIDJSON_NEW(TypeName) new TypeName #endif #ifndef RAPIDJSON_DELETE ///! customization point for global \c delete #define RAPIDJSON_DELETE(x) delete x #endif /////////////////////////////////////////////////////////////////////////////// // Type /*! \namespace rapidjson \brief main RapidJSON namespace \see RAPIDJSON_NAMESPACE */ RAPIDJSON_NAMESPACE_BEGIN //! Type of JSON value enum Type { kNullType = 0, //!< null kFalseType = 1, //!< false kTrueType = 2, //!< true kObjectType = 3, //!< object kArrayType = 4, //!< array kStringType = 5, //!< string kNumberType = 6 //!< number }; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_RAPIDJSON_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/memorybuffer.h0000644002537200234200000000500013213503245025167 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_MEMORYBUFFER_H_ #define RAPIDJSON_MEMORYBUFFER_H_ #include "stream.h" #include "internal/stack.h" RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory output byte stream. /*! This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream. It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file. Differences between MemoryBuffer and StringBuffer: 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator. \tparam Allocator type for allocating memory buffer. \note implements Stream concept */ template struct GenericMemoryBuffer { typedef char Ch; // byte GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} void Put(Ch c) { *stack_.template Push() = c; } void Flush() {} void Clear() { stack_.Clear(); } void ShrinkToFit() { stack_.ShrinkToFit(); } Ch* Push(size_t count) { return stack_.template Push(count); } void Pop(size_t count) { stack_.template Pop(count); } const Ch* GetBuffer() const { return stack_.template Bottom(); } size_t GetSize() const { return stack_.GetSize(); } static const size_t kDefaultCapacity = 256; mutable internal::Stack stack_; }; typedef GenericMemoryBuffer<> MemoryBuffer; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) { std::memset(memoryBuffer.stack_.Push(n), c, n * sizeof(c)); } RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_MEMORYBUFFER_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/stringbuffer.h0000644002537200234200000000763113213503245025201 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_STRINGBUFFER_H_ #define RAPIDJSON_STRINGBUFFER_H_ #include "stream.h" #include "internal/stack.h" #if RAPIDJSON_HAS_CXX11_RVALUE_REFS #include // std::move #endif #include "internal/stack.h" #if defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory output stream. /*! \tparam Encoding Encoding of the stream. \tparam Allocator type for allocating memory buffer. \note implements Stream concept */ template class GenericStringBuffer { public: typedef typename Encoding::Ch Ch; GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {} #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {} GenericStringBuffer& operator=(GenericStringBuffer&& rhs) { if (&rhs != this) stack_ = std::move(rhs.stack_); return *this; } #endif void Put(Ch c) { *stack_.template Push() = c; } void PutUnsafe(Ch c) { *stack_.template PushUnsafe() = c; } void Flush() {} void Clear() { stack_.Clear(); } void ShrinkToFit() { // Push and pop a null terminator. This is safe. *stack_.template Push() = '\0'; stack_.ShrinkToFit(); stack_.template Pop(1); } void Reserve(size_t count) { stack_.template Reserve(count); } Ch* Push(size_t count) { return stack_.template Push(count); } Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe(count); } void Pop(size_t count) { stack_.template Pop(count); } const Ch* GetString() const { // Push and pop a null terminator. This is safe. *stack_.template Push() = '\0'; stack_.template Pop(1); return stack_.template Bottom(); } //! Get the size of string in bytes in the string buffer. size_t GetSize() const { return stack_.GetSize(); } //! Get the length of string in Ch in the string buffer. size_t GetLength() const { return stack_.GetSize() / sizeof(Ch); } static const size_t kDefaultCapacity = 256; mutable internal::Stack stack_; private: // Prohibit copy constructor & assignment operator. GenericStringBuffer(const GenericStringBuffer&); GenericStringBuffer& operator=(const GenericStringBuffer&); }; //! String buffer with UTF8 encoding typedef GenericStringBuffer > StringBuffer; template inline void PutReserve(GenericStringBuffer& stream, size_t count) { stream.Reserve(count); } template inline void PutUnsafe(GenericStringBuffer& stream, typename Encoding::Ch c) { stream.PutUnsafe(c); } //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(GenericStringBuffer >& stream, char c, size_t n) { std::memset(stream.stack_.Push(n), c, n * sizeof(c)); } RAPIDJSON_NAMESPACE_END #if defined(__clang__) RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_STRINGBUFFER_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/msinttypes/0000755002537200234200000000000013213503245024540 5ustar zmoelnigiemusersassimp-4.1.0/contrib/rapidjson/include/rapidjson/msinttypes/stdint.h0000644002537200234200000002225213213503245026221 0ustar zmoelnigiemusers// ISO C9x compliant stdint.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2013 Alexander Chemeris // // 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. Neither the name of the product 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 AUTHOR ``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 AUTHOR 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. // /////////////////////////////////////////////////////////////////////////////// // The above software in this distribution may have been modified by // THL A29 Limited ("Tencent Modifications"). // All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_STDINT_H_ // [ #define _MSC_STDINT_H_ #if _MSC_VER > 1000 #pragma once #endif // miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010. #if _MSC_VER >= 1600 // [ #include #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 #undef INT8_C #undef INT16_C #undef INT32_C #undef INT64_C #undef UINT8_C #undef UINT16_C #undef UINT32_C #undef UINT64_C // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants // These #ifndef's are needed to prevent collisions with . // Check out Issue 9 for the details. #ifndef INTMAX_C // [ # define INTMAX_C INT64_C #endif // INTMAX_C ] #ifndef UINTMAX_C // [ # define UINTMAX_C UINT64_C #endif // UINTMAX_C ] #endif // __STDC_CONSTANT_MACROS ] #else // ] _MSC_VER >= 1700 [ #include // For Visual Studio 6 in C++ mode and for many Visual Studio versions when // compiling for ARM we have to wrap include with 'extern "C++" {}' // or compiler would give many errors like this: // error C2733: second C linkage of overloaded function 'wmemchr' not allowed #if defined(__cplusplus) && !defined(_M_ARM) extern "C" { #endif # include #if defined(__cplusplus) && !defined(_M_ARM) } #endif // Define _W64 macros to mark types changing their size, like intptr_t. #ifndef _W64 # if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300 # define _W64 __w64 # else # define _W64 # endif #endif // 7.18.1 Integer types // 7.18.1.1 Exact-width integer types // Visual Studio 6 and Embedded Visual C++ 4 doesn't // realize that, e.g. char has the same size as __int8 // so we give up on __intX for them. #if (_MSC_VER < 1300) typedef signed char int8_t; typedef signed short int16_t; typedef signed int int32_t; typedef unsigned char uint8_t; typedef unsigned short uint16_t; typedef unsigned int uint32_t; #else typedef signed __int8 int8_t; typedef signed __int16 int16_t; typedef signed __int32 int32_t; typedef unsigned __int8 uint8_t; typedef unsigned __int16 uint16_t; typedef unsigned __int32 uint32_t; #endif typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; // 7.18.1.2 Minimum-width integer types typedef int8_t int_least8_t; typedef int16_t int_least16_t; typedef int32_t int_least32_t; typedef int64_t int_least64_t; typedef uint8_t uint_least8_t; typedef uint16_t uint_least16_t; typedef uint32_t uint_least32_t; typedef uint64_t uint_least64_t; // 7.18.1.3 Fastest minimum-width integer types typedef int8_t int_fast8_t; typedef int16_t int_fast16_t; typedef int32_t int_fast32_t; typedef int64_t int_fast64_t; typedef uint8_t uint_fast8_t; typedef uint16_t uint_fast16_t; typedef uint32_t uint_fast32_t; typedef uint64_t uint_fast64_t; // 7.18.1.4 Integer types capable of holding object pointers #ifdef _WIN64 // [ typedef signed __int64 intptr_t; typedef unsigned __int64 uintptr_t; #else // _WIN64 ][ typedef _W64 signed int intptr_t; typedef _W64 unsigned int uintptr_t; #endif // _WIN64 ] // 7.18.1.5 Greatest-width integer types typedef int64_t intmax_t; typedef uint64_t uintmax_t; // 7.18.2 Limits of specified-width integer types #if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259 // 7.18.2.1 Limits of exact-width integer types #define INT8_MIN ((int8_t)_I8_MIN) #define INT8_MAX _I8_MAX #define INT16_MIN ((int16_t)_I16_MIN) #define INT16_MAX _I16_MAX #define INT32_MIN ((int32_t)_I32_MIN) #define INT32_MAX _I32_MAX #define INT64_MIN ((int64_t)_I64_MIN) #define INT64_MAX _I64_MAX #define UINT8_MAX _UI8_MAX #define UINT16_MAX _UI16_MAX #define UINT32_MAX _UI32_MAX #define UINT64_MAX _UI64_MAX // 7.18.2.2 Limits of minimum-width integer types #define INT_LEAST8_MIN INT8_MIN #define INT_LEAST8_MAX INT8_MAX #define INT_LEAST16_MIN INT16_MIN #define INT_LEAST16_MAX INT16_MAX #define INT_LEAST32_MIN INT32_MIN #define INT_LEAST32_MAX INT32_MAX #define INT_LEAST64_MIN INT64_MIN #define INT_LEAST64_MAX INT64_MAX #define UINT_LEAST8_MAX UINT8_MAX #define UINT_LEAST16_MAX UINT16_MAX #define UINT_LEAST32_MAX UINT32_MAX #define UINT_LEAST64_MAX UINT64_MAX // 7.18.2.3 Limits of fastest minimum-width integer types #define INT_FAST8_MIN INT8_MIN #define INT_FAST8_MAX INT8_MAX #define INT_FAST16_MIN INT16_MIN #define INT_FAST16_MAX INT16_MAX #define INT_FAST32_MIN INT32_MIN #define INT_FAST32_MAX INT32_MAX #define INT_FAST64_MIN INT64_MIN #define INT_FAST64_MAX INT64_MAX #define UINT_FAST8_MAX UINT8_MAX #define UINT_FAST16_MAX UINT16_MAX #define UINT_FAST32_MAX UINT32_MAX #define UINT_FAST64_MAX UINT64_MAX // 7.18.2.4 Limits of integer types capable of holding object pointers #ifdef _WIN64 // [ # define INTPTR_MIN INT64_MIN # define INTPTR_MAX INT64_MAX # define UINTPTR_MAX UINT64_MAX #else // _WIN64 ][ # define INTPTR_MIN INT32_MIN # define INTPTR_MAX INT32_MAX # define UINTPTR_MAX UINT32_MAX #endif // _WIN64 ] // 7.18.2.5 Limits of greatest-width integer types #define INTMAX_MIN INT64_MIN #define INTMAX_MAX INT64_MAX #define UINTMAX_MAX UINT64_MAX // 7.18.3 Limits of other integer types #ifdef _WIN64 // [ # define PTRDIFF_MIN _I64_MIN # define PTRDIFF_MAX _I64_MAX #else // _WIN64 ][ # define PTRDIFF_MIN _I32_MIN # define PTRDIFF_MAX _I32_MAX #endif // _WIN64 ] #define SIG_ATOMIC_MIN INT_MIN #define SIG_ATOMIC_MAX INT_MAX #ifndef SIZE_MAX // [ # ifdef _WIN64 // [ # define SIZE_MAX _UI64_MAX # else // _WIN64 ][ # define SIZE_MAX _UI32_MAX # endif // _WIN64 ] #endif // SIZE_MAX ] // WCHAR_MIN and WCHAR_MAX are also defined in #ifndef WCHAR_MIN // [ # define WCHAR_MIN 0 #endif // WCHAR_MIN ] #ifndef WCHAR_MAX // [ # define WCHAR_MAX _UI16_MAX #endif // WCHAR_MAX ] #define WINT_MIN 0 #define WINT_MAX _UI16_MAX #endif // __STDC_LIMIT_MACROS ] // 7.18.4 Limits of other integer types #if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260 // 7.18.4.1 Macros for minimum-width integer constants #define INT8_C(val) val##i8 #define INT16_C(val) val##i16 #define INT32_C(val) val##i32 #define INT64_C(val) val##i64 #define UINT8_C(val) val##ui8 #define UINT16_C(val) val##ui16 #define UINT32_C(val) val##ui32 #define UINT64_C(val) val##ui64 // 7.18.4.2 Macros for greatest-width integer constants // These #ifndef's are needed to prevent collisions with . // Check out Issue 9 for the details. #ifndef INTMAX_C // [ # define INTMAX_C INT64_C #endif // INTMAX_C ] #ifndef UINTMAX_C // [ # define UINTMAX_C UINT64_C #endif // UINTMAX_C ] #endif // __STDC_CONSTANT_MACROS ] #endif // _MSC_VER >= 1600 ] #endif // _MSC_STDINT_H_ ] assimp-4.1.0/contrib/rapidjson/include/rapidjson/msinttypes/inttypes.h0000644002537200234200000002026413213503245026574 0ustar zmoelnigiemusers// ISO C9x compliant inttypes.h for Microsoft Visual Studio // Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 // // Copyright (c) 2006-2013 Alexander Chemeris // // 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. Neither the name of the product 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 AUTHOR ``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 AUTHOR 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. // /////////////////////////////////////////////////////////////////////////////// // The above software in this distribution may have been modified by // THL A29 Limited ("Tencent Modifications"). // All Tencent Modifications are Copyright (C) 2015 THL A29 Limited. #ifndef _MSC_VER // [ #error "Use this header only with Microsoft Visual C++ compilers!" #endif // _MSC_VER ] #ifndef _MSC_INTTYPES_H_ // [ #define _MSC_INTTYPES_H_ #if _MSC_VER > 1000 #pragma once #endif #include "stdint.h" // miloyip: VC supports inttypes.h since VC2013 #if _MSC_VER >= 1800 #include #else // 7.8 Format conversion of integer types typedef struct { intmax_t quot; intmax_t rem; } imaxdiv_t; // 7.8.1 Macros for format specifiers #if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [ See footnote 185 at page 198 // The fprintf macros for signed integers are: #define PRId8 "d" #define PRIi8 "i" #define PRIdLEAST8 "d" #define PRIiLEAST8 "i" #define PRIdFAST8 "d" #define PRIiFAST8 "i" #define PRId16 "hd" #define PRIi16 "hi" #define PRIdLEAST16 "hd" #define PRIiLEAST16 "hi" #define PRIdFAST16 "hd" #define PRIiFAST16 "hi" #define PRId32 "I32d" #define PRIi32 "I32i" #define PRIdLEAST32 "I32d" #define PRIiLEAST32 "I32i" #define PRIdFAST32 "I32d" #define PRIiFAST32 "I32i" #define PRId64 "I64d" #define PRIi64 "I64i" #define PRIdLEAST64 "I64d" #define PRIiLEAST64 "I64i" #define PRIdFAST64 "I64d" #define PRIiFAST64 "I64i" #define PRIdMAX "I64d" #define PRIiMAX "I64i" #define PRIdPTR "Id" #define PRIiPTR "Ii" // The fprintf macros for unsigned integers are: #define PRIo8 "o" #define PRIu8 "u" #define PRIx8 "x" #define PRIX8 "X" #define PRIoLEAST8 "o" #define PRIuLEAST8 "u" #define PRIxLEAST8 "x" #define PRIXLEAST8 "X" #define PRIoFAST8 "o" #define PRIuFAST8 "u" #define PRIxFAST8 "x" #define PRIXFAST8 "X" #define PRIo16 "ho" #define PRIu16 "hu" #define PRIx16 "hx" #define PRIX16 "hX" #define PRIoLEAST16 "ho" #define PRIuLEAST16 "hu" #define PRIxLEAST16 "hx" #define PRIXLEAST16 "hX" #define PRIoFAST16 "ho" #define PRIuFAST16 "hu" #define PRIxFAST16 "hx" #define PRIXFAST16 "hX" #define PRIo32 "I32o" #define PRIu32 "I32u" #define PRIx32 "I32x" #define PRIX32 "I32X" #define PRIoLEAST32 "I32o" #define PRIuLEAST32 "I32u" #define PRIxLEAST32 "I32x" #define PRIXLEAST32 "I32X" #define PRIoFAST32 "I32o" #define PRIuFAST32 "I32u" #define PRIxFAST32 "I32x" #define PRIXFAST32 "I32X" #define PRIo64 "I64o" #define PRIu64 "I64u" #define PRIx64 "I64x" #define PRIX64 "I64X" #define PRIoLEAST64 "I64o" #define PRIuLEAST64 "I64u" #define PRIxLEAST64 "I64x" #define PRIXLEAST64 "I64X" #define PRIoFAST64 "I64o" #define PRIuFAST64 "I64u" #define PRIxFAST64 "I64x" #define PRIXFAST64 "I64X" #define PRIoMAX "I64o" #define PRIuMAX "I64u" #define PRIxMAX "I64x" #define PRIXMAX "I64X" #define PRIoPTR "Io" #define PRIuPTR "Iu" #define PRIxPTR "Ix" #define PRIXPTR "IX" // The fscanf macros for signed integers are: #define SCNd8 "d" #define SCNi8 "i" #define SCNdLEAST8 "d" #define SCNiLEAST8 "i" #define SCNdFAST8 "d" #define SCNiFAST8 "i" #define SCNd16 "hd" #define SCNi16 "hi" #define SCNdLEAST16 "hd" #define SCNiLEAST16 "hi" #define SCNdFAST16 "hd" #define SCNiFAST16 "hi" #define SCNd32 "ld" #define SCNi32 "li" #define SCNdLEAST32 "ld" #define SCNiLEAST32 "li" #define SCNdFAST32 "ld" #define SCNiFAST32 "li" #define SCNd64 "I64d" #define SCNi64 "I64i" #define SCNdLEAST64 "I64d" #define SCNiLEAST64 "I64i" #define SCNdFAST64 "I64d" #define SCNiFAST64 "I64i" #define SCNdMAX "I64d" #define SCNiMAX "I64i" #ifdef _WIN64 // [ # define SCNdPTR "I64d" # define SCNiPTR "I64i" #else // _WIN64 ][ # define SCNdPTR "ld" # define SCNiPTR "li" #endif // _WIN64 ] // The fscanf macros for unsigned integers are: #define SCNo8 "o" #define SCNu8 "u" #define SCNx8 "x" #define SCNX8 "X" #define SCNoLEAST8 "o" #define SCNuLEAST8 "u" #define SCNxLEAST8 "x" #define SCNXLEAST8 "X" #define SCNoFAST8 "o" #define SCNuFAST8 "u" #define SCNxFAST8 "x" #define SCNXFAST8 "X" #define SCNo16 "ho" #define SCNu16 "hu" #define SCNx16 "hx" #define SCNX16 "hX" #define SCNoLEAST16 "ho" #define SCNuLEAST16 "hu" #define SCNxLEAST16 "hx" #define SCNXLEAST16 "hX" #define SCNoFAST16 "ho" #define SCNuFAST16 "hu" #define SCNxFAST16 "hx" #define SCNXFAST16 "hX" #define SCNo32 "lo" #define SCNu32 "lu" #define SCNx32 "lx" #define SCNX32 "lX" #define SCNoLEAST32 "lo" #define SCNuLEAST32 "lu" #define SCNxLEAST32 "lx" #define SCNXLEAST32 "lX" #define SCNoFAST32 "lo" #define SCNuFAST32 "lu" #define SCNxFAST32 "lx" #define SCNXFAST32 "lX" #define SCNo64 "I64o" #define SCNu64 "I64u" #define SCNx64 "I64x" #define SCNX64 "I64X" #define SCNoLEAST64 "I64o" #define SCNuLEAST64 "I64u" #define SCNxLEAST64 "I64x" #define SCNXLEAST64 "I64X" #define SCNoFAST64 "I64o" #define SCNuFAST64 "I64u" #define SCNxFAST64 "I64x" #define SCNXFAST64 "I64X" #define SCNoMAX "I64o" #define SCNuMAX "I64u" #define SCNxMAX "I64x" #define SCNXMAX "I64X" #ifdef _WIN64 // [ # define SCNoPTR "I64o" # define SCNuPTR "I64u" # define SCNxPTR "I64x" # define SCNXPTR "I64X" #else // _WIN64 ][ # define SCNoPTR "lo" # define SCNuPTR "lu" # define SCNxPTR "lx" # define SCNXPTR "lX" #endif // _WIN64 ] #endif // __STDC_FORMAT_MACROS ] // 7.8.2 Functions for greatest-width integer types // 7.8.2.1 The imaxabs function #define imaxabs _abs64 // 7.8.2.2 The imaxdiv function // This is modified version of div() function from Microsoft's div.c found // in %MSVC.NET%\crt\src\div.c #ifdef STATIC_IMAXDIV // [ static #else // STATIC_IMAXDIV ][ _inline #endif // STATIC_IMAXDIV ] imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom) { imaxdiv_t result; result.quot = numer / denom; result.rem = numer % denom; if (numer < 0 && result.rem > 0) { // did division wrong; must fix up ++result.quot; result.rem -= denom; } return result; } // 7.8.2.3 The strtoimax and strtoumax functions #define strtoimax _strtoi64 #define strtoumax _strtoui64 // 7.8.2.4 The wcstoimax and wcstoumax functions #define wcstoimax _wcstoi64 #define wcstoumax _wcstoui64 #endif // _MSC_VER >= 1800 #endif // _MSC_INTTYPES_H_ ] assimp-4.1.0/contrib/rapidjson/include/rapidjson/stream.h0000644002537200234200000001253213213503245023770 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #include "rapidjson.h" #ifndef RAPIDJSON_STREAM_H_ #define RAPIDJSON_STREAM_H_ #include "encodings.h" RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // Stream /*! \class rapidjson::Stream \brief Concept for reading and writing characters. For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd(). For write-only stream, only need to implement Put() and Flush(). \code concept Stream { typename Ch; //!< Character type of the stream. //! Read the current character from stream without moving the read cursor. Ch Peek() const; //! Read the current character from stream and moving the read cursor to next character. Ch Take(); //! Get the current read cursor. //! \return Number of characters read from start. size_t Tell(); //! Begin writing operation at the current read pointer. //! \return The begin writer pointer. Ch* PutBegin(); //! Write a character. void Put(Ch c); //! Flush the buffer. void Flush(); //! End the writing operation. //! \param begin The begin write pointer returned by PutBegin(). //! \return Number of characters written. size_t PutEnd(Ch* begin); } \endcode */ //! Provides additional information for stream. /*! By using traits pattern, this type provides a default configuration for stream. For custom stream, this type can be specialized for other configuration. See TEST(Reader, CustomStringStream) in readertest.cpp for example. */ template struct StreamTraits { //! Whether to make local copy of stream for optimization during parsing. /*! By default, for safety, streams do not use local copy optimization. Stream that can be copied fast should specialize this, like StreamTraits. */ enum { copyOptimization = 0 }; }; //! Reserve n characters for writing to a stream. template inline void PutReserve(Stream& stream, size_t count) { (void)stream; (void)count; } //! Write character to a stream, presuming buffer is reserved. template inline void PutUnsafe(Stream& stream, typename Stream::Ch c) { stream.Put(c); } //! Put N copies of a character to a stream. template inline void PutN(Stream& stream, Ch c, size_t n) { PutReserve(stream, n); for (size_t i = 0; i < n; i++) PutUnsafe(stream, c); } /////////////////////////////////////////////////////////////////////////////// // StringStream //! Read-only string stream. /*! \note implements Stream concept */ template struct GenericStringStream { typedef typename Encoding::Ch Ch; GenericStringStream(const Ch *src) : src_(src), head_(src) {} Ch Peek() const { return *src_; } Ch Take() { return *src_++; } size_t Tell() const { return static_cast(src_ - head_); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } const Ch* src_; //!< Current read position. const Ch* head_; //!< Original head of the string. }; template struct StreamTraits > { enum { copyOptimization = 1 }; }; //! String stream with UTF8 encoding. typedef GenericStringStream > StringStream; /////////////////////////////////////////////////////////////////////////////// // InsituStringStream //! A read-write string stream. /*! This string stream is particularly designed for in-situ parsing. \note implements Stream concept */ template struct GenericInsituStringStream { typedef typename Encoding::Ch Ch; GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {} // Read Ch Peek() { return *src_; } Ch Take() { return *src_++; } size_t Tell() { return static_cast(src_ - head_); } // Write void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; } Ch* PutBegin() { return dst_ = src_; } size_t PutEnd(Ch* begin) { return static_cast(dst_ - begin); } void Flush() {} Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; } void Pop(size_t count) { dst_ -= count; } Ch* src_; Ch* dst_; Ch* head_; }; template struct StreamTraits > { enum { copyOptimization = 1 }; }; //! Insitu string stream with UTF8 encoding. typedef GenericInsituStringStream > InsituStringStream; RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_STREAM_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/istreamwrapper.h0000644002537200234200000000701113213503245025536 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_ISTREAMWRAPPER_H_ #define RAPIDJSON_ISTREAMWRAPPER_H_ #include "stream.h" #include #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized #endif RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of \c std::basic_istream into RapidJSON's Stream concept. /*! The classes can be wrapped including but not limited to: - \c std::istringstream - \c std::stringstream - \c std::wistringstream - \c std::wstringstream - \c std::ifstream - \c std::fstream - \c std::wifstream - \c std::wfstream \tparam StreamType Class derived from \c std::basic_istream. */ template class BasicIStreamWrapper { public: typedef typename StreamType::char_type Ch; BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {} Ch Peek() const { typename StreamType::int_type c = stream_.peek(); return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast(c) : static_cast('\0'); } Ch Take() { typename StreamType::int_type c = stream_.get(); if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) { count_++; return static_cast(c); } else return '\0'; } // tellg() may return -1 when failed. So we count by ourself. size_t Tell() const { return count_; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. const Ch* Peek4() const { RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream. int i; bool hasError = false; for (i = 0; i < 4; ++i) { typename StreamType::int_type c = stream_.get(); if (c == StreamType::traits_type::eof()) { hasError = true; stream_.clear(); break; } peekBuffer_[i] = static_cast(c); } for (--i; i >= 0; --i) stream_.putback(peekBuffer_[i]); return !hasError ? peekBuffer_ : 0; } private: BasicIStreamWrapper(const BasicIStreamWrapper&); BasicIStreamWrapper& operator=(const BasicIStreamWrapper&); StreamType& stream_; size_t count_; //!< Number of characters read. Note: mutable Ch peekBuffer_[4]; }; typedef BasicIStreamWrapper IStreamWrapper; typedef BasicIStreamWrapper WIStreamWrapper; #if defined(__clang__) || defined(_MSC_VER) RAPIDJSON_DIAG_POP #endif RAPIDJSON_NAMESPACE_END #endif // RAPIDJSON_ISTREAMWRAPPER_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/document.h0000644002537200234200000034267413213503245024330 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_DOCUMENT_H_ #define RAPIDJSON_DOCUMENT_H_ /*! \file document.h */ #include "reader.h" #include "internal/meta.h" #include "internal/strfunc.h" #include "memorystream.h" #include "encodedstream.h" #include // placement new #include RAPIDJSON_DIAG_PUSH #ifdef _MSC_VER RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data #endif #ifdef __clang__ RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(c++98-compat) #endif #ifdef __GNUC__ RAPIDJSON_DIAG_OFF(effc++) #if __GNUC__ >= 6 RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions #endif #endif // __GNUC__ #ifndef RAPIDJSON_NOMEMBERITERATORCLASS #include // std::iterator, std::random_access_iterator_tag #endif #if RAPIDJSON_HAS_CXX11_RVALUE_REFS #include // std::move #endif RAPIDJSON_NAMESPACE_BEGIN // Forward declaration. template class GenericValue; template class GenericDocument; //! Name-value pair in a JSON object value. /*! This class was internal to GenericValue. It used to be a inner struct. But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct. https://code.google.com/p/rapidjson/issues/detail?id=64 */ template struct GenericMember { GenericValue name; //!< name of member (must be a string) GenericValue value; //!< value of member. }; /////////////////////////////////////////////////////////////////////////////// // GenericMemberIterator #ifndef RAPIDJSON_NOMEMBERITERATORCLASS //! (Constant) member iterator for a JSON object value /*! \tparam Const Is this a constant iterator? \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. This class implements a Random Access Iterator for GenericMember elements of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements]. \note This iterator implementation is mainly intended to avoid implicit conversions from iterator values to \c NULL, e.g. from GenericValue::FindMember. \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a pointer-based implementation, if your platform doesn't provide the C++ header. \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator */ template class GenericMemberIterator : public std::iterator >::Type> { friend class GenericValue; template friend class GenericMemberIterator; typedef GenericMember PlainType; typedef typename internal::MaybeAddConst::Type ValueType; typedef std::iterator BaseType; public: //! Iterator type itself typedef GenericMemberIterator Iterator; //! Constant iterator type typedef GenericMemberIterator ConstIterator; //! Non-constant iterator type typedef GenericMemberIterator NonConstIterator; //! Pointer to (const) GenericMember typedef typename BaseType::pointer Pointer; //! Reference to (const) GenericMember typedef typename BaseType::reference Reference; //! Signed integer type (e.g. \c ptrdiff_t) typedef typename BaseType::difference_type DifferenceType; //! Default constructor (singular value) /*! Creates an iterator pointing to no element. \note All operations, except for comparisons, are undefined on such values. */ GenericMemberIterator() : ptr_() {} //! Iterator conversions to more const /*! \param it (Non-const) iterator to copy from Allows the creation of an iterator from another GenericMemberIterator that is "less const". Especially, creating a non-constant iterator from a constant iterator are disabled: \li const -> non-const (not ok) \li const -> const (ok) \li non-const -> const (ok) \li non-const -> non-const (ok) \note If the \c Const template parameter is already \c false, this constructor effectively defines a regular copy-constructor. Otherwise, the copy constructor is implicitly defined. */ GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {} Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; } //! @name stepping //@{ Iterator& operator++(){ ++ptr_; return *this; } Iterator& operator--(){ --ptr_; return *this; } Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; } Iterator operator--(int){ Iterator old(*this); --ptr_; return old; } //@} //! @name increment/decrement //@{ Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); } Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); } Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; } Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; } //@} //! @name relations //@{ bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; } bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; } bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; } bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; } bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; } bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; } //@} //! @name dereference //@{ Reference operator*() const { return *ptr_; } Pointer operator->() const { return ptr_; } Reference operator[](DifferenceType n) const { return ptr_[n]; } //@} //! Distance DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; } private: //! Internal constructor from plain pointer explicit GenericMemberIterator(Pointer p) : ptr_(p) {} Pointer ptr_; //!< raw pointer }; #else // RAPIDJSON_NOMEMBERITERATORCLASS // class-based member iterator implementation disabled, use plain pointers template struct GenericMemberIterator; //! non-const GenericMemberIterator template struct GenericMemberIterator { //! use plain pointer as iterator type typedef GenericMember* Iterator; }; //! const GenericMemberIterator template struct GenericMemberIterator { //! use plain const pointer as iterator type typedef const GenericMember* Iterator; }; #endif // RAPIDJSON_NOMEMBERITERATORCLASS /////////////////////////////////////////////////////////////////////////////// // GenericStringRef //! Reference to a constant string (not taking a copy) /*! \tparam CharType character type of the string This helper class is used to automatically infer constant string references for string literals, especially from \c const \b (!) character arrays. The main use is for creating JSON string values without copying the source string via an \ref Allocator. This requires that the referenced string pointers have a sufficient lifetime, which exceeds the lifetime of the associated GenericValue. \b Example \code Value v("foo"); // ok, no need to copy & calculate length const char foo[] = "foo"; v.SetString(foo); // ok const char* bar = foo; // Value x(bar); // not ok, can't rely on bar's lifetime Value x(StringRef(bar)); // lifetime explicitly guaranteed by user Value y(StringRef(bar, 3)); // ok, explicitly pass length \endcode \see StringRef, GenericValue::SetString */ template struct GenericStringRef { typedef CharType Ch; //!< character type of the string //! Create string reference from \c const character array #ifndef __clang__ // -Wdocumentation /*! This constructor implicitly creates a constant string reference from a \c const character array. It has better performance than \ref StringRef(const CharType*) by inferring the string \ref length from the array length, and also supports strings containing null characters. \tparam N length of the string, automatically inferred \param str Constant character array, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \post \ref s == str \note Constant complexity. \note There is a hidden, private overload to disallow references to non-const character arrays to be created via this constructor. By this, e.g. function-scope arrays used to be filled via \c snprintf are excluded from consideration. In such cases, the referenced string should be \b copied to the GenericValue instead. */ #endif template GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT : s(str), length(N-1) {} //! Explicitly create string reference from \c const character pointer #ifndef __clang__ // -Wdocumentation /*! This constructor can be used to \b explicitly create a reference to a constant string pointer. \see StringRef(const CharType*) \param str Constant character pointer, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \post \ref s == str \note There is a hidden, private overload to disallow references to non-const character arrays to be created via this constructor. By this, e.g. function-scope arrays used to be filled via \c snprintf are excluded from consideration. In such cases, the referenced string should be \b copied to the GenericValue instead. */ #endif explicit GenericStringRef(const CharType* str) : s(str), length(NotNullStrLen(str)) {} //! Create constant string reference from pointer and length #ifndef __clang__ // -Wdocumentation /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \param len length of the string, excluding the trailing NULL terminator \post \ref s == str && \ref length == len \note Constant complexity. */ #endif GenericStringRef(const CharType* str, SizeType len) : s(RAPIDJSON_LIKELY(str) ? str : emptyString), length(len) { RAPIDJSON_ASSERT(str != 0 || len == 0u); } GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {} //! implicit conversion to plain CharType pointer operator const Ch *() const { return s; } const Ch* const s; //!< plain CharType pointer const SizeType length; //!< length of the string (excluding the trailing NULL terminator) private: SizeType NotNullStrLen(const CharType* str) { RAPIDJSON_ASSERT(str != 0); return internal::StrLen(str); } /// Empty string - used when passing in a NULL pointer static const Ch emptyString[]; //! Disallow construction from non-const array template GenericStringRef(CharType (&str)[N]) /* = delete */; //! Copy assignment operator not permitted - immutable type GenericStringRef& operator=(const GenericStringRef& rhs) /* = delete */; }; template const CharType GenericStringRef::emptyString[] = { CharType() }; //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function can be used to avoid copying a character string to be referenced as a value in a JSON GenericValue object, if the string's lifetime is known to be valid long enough. \tparam CharType Character type of the string \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \return GenericStringRef string reference object \relatesalso GenericStringRef \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember */ template inline GenericStringRef StringRef(const CharType* str) { return GenericStringRef(str); } //! Mark a character pointer as constant string /*! Mark a plain character pointer as a "string literal". This function can be used to avoid copying a character string to be referenced as a value in a JSON GenericValue object, if the string's lifetime is known to be valid long enough. This version has better performance with supplied length, and also supports string containing null characters. \tparam CharType character type of the string \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \param length The length of source string. \return GenericStringRef string reference object \relatesalso GenericStringRef */ template inline GenericStringRef StringRef(const CharType* str, size_t length) { return GenericStringRef(str, SizeType(length)); } #if RAPIDJSON_HAS_STDSTRING //! Mark a string object as constant string /*! Mark a string object (e.g. \c std::string) as a "string literal". This function can be used to avoid copying a string to be referenced as a value in a JSON GenericValue object, if the string's lifetime is known to be valid long enough. \tparam CharType character type of the string \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue \return GenericStringRef string reference object \relatesalso GenericStringRef \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ template inline GenericStringRef StringRef(const std::basic_string& str) { return GenericStringRef(str.data(), SizeType(str.size())); } #endif /////////////////////////////////////////////////////////////////////////////// // GenericValue type traits namespace internal { template struct IsGenericValueImpl : FalseType {}; // select candidates according to nested encoding and allocator types template struct IsGenericValueImpl::Type, typename Void::Type> : IsBaseOf, T>::Type {}; // helper to match arbitrary GenericValue instantiations, including derived classes template struct IsGenericValue : IsGenericValueImpl::Type {}; } // namespace internal /////////////////////////////////////////////////////////////////////////////// // TypeHelper namespace internal { template struct TypeHelper {}; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsBool(); } static bool Get(const ValueType& v) { return v.GetBool(); } static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); } static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); } }; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsInt(); } static int Get(const ValueType& v) { return v.GetInt(); } static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); } static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); } }; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsUint(); } static unsigned Get(const ValueType& v) { return v.GetUint(); } static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); } static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); } }; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsInt64(); } static int64_t Get(const ValueType& v) { return v.GetInt64(); } static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); } static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); } }; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsUint64(); } static uint64_t Get(const ValueType& v) { return v.GetUint64(); } static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); } static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); } }; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsDouble(); } static double Get(const ValueType& v) { return v.GetDouble(); } static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); } static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); } }; template struct TypeHelper { static bool Is(const ValueType& v) { return v.IsFloat(); } static float Get(const ValueType& v) { return v.GetFloat(); } static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); } static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); } }; template struct TypeHelper { typedef const typename ValueType::Ch* StringType; static bool Is(const ValueType& v) { return v.IsString(); } static StringType Get(const ValueType& v) { return v.GetString(); } static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); } static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } }; #if RAPIDJSON_HAS_STDSTRING template struct TypeHelper > { typedef std::basic_string StringType; static bool Is(const ValueType& v) { return v.IsString(); } static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); } static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); } }; #endif template struct TypeHelper { typedef typename ValueType::Array ArrayType; static bool Is(const ValueType& v) { return v.IsArray(); } static ArrayType Get(ValueType& v) { return v.GetArray(); } static ValueType& Set(ValueType& v, ArrayType data) { return v = data; } static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; } }; template struct TypeHelper { typedef typename ValueType::ConstArray ArrayType; static bool Is(const ValueType& v) { return v.IsArray(); } static ArrayType Get(const ValueType& v) { return v.GetArray(); } }; template struct TypeHelper { typedef typename ValueType::Object ObjectType; static bool Is(const ValueType& v) { return v.IsObject(); } static ObjectType Get(ValueType& v) { return v.GetObject(); } static ValueType& Set(ValueType& v, ObjectType data) { return v = data; } static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { return v = data; } }; template struct TypeHelper { typedef typename ValueType::ConstObject ObjectType; static bool Is(const ValueType& v) { return v.IsObject(); } static ObjectType Get(const ValueType& v) { return v.GetObject(); } }; } // namespace internal // Forward declarations template class GenericArray; template class GenericObject; /////////////////////////////////////////////////////////////////////////////// // GenericValue //! Represents a JSON value. Use Value for UTF8 encoding and default allocator. /*! A JSON value can be one of 7 types. This class is a variant type supporting these types. Use the Value if UTF8 and default allocator \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document) \tparam Allocator Allocator type for allocating memory of object, array and string. */ template > class GenericValue { public: //! Name-value pair in an object. typedef GenericMember Member; typedef Encoding EncodingType; //!< Encoding type from template parameter. typedef Allocator AllocatorType; //!< Allocator type from template parameter. typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericStringRef StringRefType; //!< Reference to a constant string typedef typename GenericMemberIterator::Iterator MemberIterator; //!< Member iterator for iterating in object. typedef typename GenericMemberIterator::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object. typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array. typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array. typedef GenericValue ValueType; //!< Value type of itself. typedef GenericArray Array; typedef GenericArray ConstArray; typedef GenericObject Object; typedef GenericObject ConstObject; //!@name Constructors and destructor. //@{ //! Default constructor creates a null value. GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) { rhs.data_.f.flags = kNullFlag; // give up contents } #endif private: //! Copy constructor is not permitted. GenericValue(const GenericValue& rhs); #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Moving from a GenericDocument is not permitted. template GenericValue(GenericDocument&& rhs); //! Move assignment from a GenericDocument is not permitted. template GenericValue& operator=(GenericDocument&& rhs); #endif public: //! Constructor with JSON value type. /*! This creates a Value of specified type with default content. \param type Type of the value. \note Default content for number is zero. */ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() { static const uint16_t defaultFlags[7] = { kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag, kNumberAnyFlag }; RAPIDJSON_ASSERT(type >= kNullType && type <= kNumberType); data_.f.flags = defaultFlags[type]; // Use ShortString to store empty string. if (type == kStringType) data_.ss.SetLength(0); } //! Explicit copy constructor (with allocator) /*! Creates a copy of a Value by using the given Allocator \tparam SourceAllocator allocator of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator(). \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) \see CopyFrom() */ template GenericValue(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { switch (rhs.GetType()) { case kObjectType: { SizeType count = rhs.data_.o.size; Member* lm = reinterpret_cast(allocator.Malloc(count * sizeof(Member))); const typename GenericValue::Member* rm = rhs.GetMembersPointer(); for (SizeType i = 0; i < count; i++) { new (&lm[i].name) GenericValue(rm[i].name, allocator, copyConstStrings); new (&lm[i].value) GenericValue(rm[i].value, allocator, copyConstStrings); } data_.f.flags = kObjectFlag; data_.o.size = data_.o.capacity = count; SetMembersPointer(lm); } break; case kArrayType: { SizeType count = rhs.data_.a.size; GenericValue* le = reinterpret_cast(allocator.Malloc(count * sizeof(GenericValue))); const GenericValue* re = rhs.GetElementsPointer(); for (SizeType i = 0; i < count; i++) new (&le[i]) GenericValue(re[i], allocator, copyConstStrings); data_.f.flags = kArrayFlag; data_.a.size = data_.a.capacity = count; SetElementsPointer(le); } break; case kStringType: if (rhs.data_.f.flags == kConstStringFlag && !copyConstStrings) { data_.f.flags = rhs.data_.f.flags; data_ = *reinterpret_cast(&rhs.data_); } else SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator); break; default: data_.f.flags = rhs.data_.f.flags; data_ = *reinterpret_cast(&rhs.data_); break; } } //! Constructor for boolean value. /*! \param b Boolean value \note This constructor is limited to \em real boolean values and rejects implicitly converted types like arbitrary pointers. Use an explicit cast to \c bool, if you want to construct a boolean JSON value in such cases. */ #ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen template explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame))) RAPIDJSON_NOEXCEPT // See #472 #else explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT #endif : data_() { // safe-guard against failing SFINAE RAPIDJSON_STATIC_ASSERT((internal::IsSame::Value)); data_.f.flags = b ? kTrueFlag : kFalseFlag; } //! Constructor for int value. explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() { data_.n.i64 = i; data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag; } //! Constructor for unsigned value. explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() { data_.n.u64 = u; data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag); } //! Constructor for int64_t value. explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() { data_.n.i64 = i64; data_.f.flags = kNumberInt64Flag; if (i64 >= 0) { data_.f.flags |= kNumberUint64Flag; if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) data_.f.flags |= kUintFlag; if (!(static_cast(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) data_.f.flags |= kIntFlag; } else if (i64 >= static_cast(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) data_.f.flags |= kIntFlag; } //! Constructor for uint64_t value. explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() { data_.n.u64 = u64; data_.f.flags = kNumberUint64Flag; if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000))) data_.f.flags |= kInt64Flag; if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000))) data_.f.flags |= kUintFlag; if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000))) data_.f.flags |= kIntFlag; } //! Constructor for double value. explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; } //! Constructor for float value. explicit GenericValue(float f) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = static_cast(f); data_.f.flags = kNumberDoubleFlag; } //! Constructor for constant string (i.e. do not make a copy of string) GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); } //! Constructor for constant string (i.e. do not make a copy of string) explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); } //! Constructor for copy-string (i.e. do make a copy of string) GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); } //! Constructor for copy-string (i.e. do make a copy of string) GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } #if RAPIDJSON_HAS_STDSTRING //! Constructor for copy-string from a string object (i.e. do make a copy of string) /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ GenericValue(const std::basic_string& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); } #endif //! Constructor for Array. /*! \param a An array obtained by \c GetArray(). \note \c Array is always pass-by-value. \note the source array is moved into this value and the sourec array becomes empty. */ GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) { a.value_.data_ = Data(); a.value_.data_.f.flags = kArrayFlag; } //! Constructor for Object. /*! \param o An object obtained by \c GetObject(). \note \c Object is always pass-by-value. \note the source object is moved into this value and the sourec object becomes empty. */ GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) { o.value_.data_ = Data(); o.value_.data_.f.flags = kObjectFlag; } //! Destructor. /*! Need to destruct elements of array, members of object, or copy-string. */ ~GenericValue() { if (Allocator::kNeedFree) { // Shortcut by Allocator's trait switch(data_.f.flags) { case kArrayFlag: { GenericValue* e = GetElementsPointer(); for (GenericValue* v = e; v != e + data_.a.size; ++v) v->~GenericValue(); Allocator::Free(e); } break; case kObjectFlag: for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) m->~Member(); Allocator::Free(GetMembersPointer()); break; case kCopyStringFlag: Allocator::Free(const_cast(GetStringPointer())); break; default: break; // Do nothing for other types. } } } //@} //!@name Assignment operators //@{ //! Assignment with move semantics. /*! \param rhs Source of the assignment. It will become a null value after assignment. */ GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT { RAPIDJSON_ASSERT(this != &rhs); this->~GenericValue(); RawAssign(rhs); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move assignment in C++11 GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT { return *this = rhs.Move(); } #endif //! Assignment of constant string reference (no copy) /*! \param str Constant string reference to be assigned \note This overload is needed to avoid clashes with the generic primitive type assignment overload below. \see GenericStringRef, operator=(T) */ GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT { GenericValue s(str); return *this = s; } //! Assignment with primitive types. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param value The value to be assigned. \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref SetString(const Ch*, Allocator&) (for copying) or \ref StringRef() (to explicitly mark the pointer as constant) instead. All other pointer types would implicitly convert to \c bool, use \ref SetBool() instead. */ template RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer), (GenericValue&)) operator=(T value) { GenericValue v(value); return *this = v; } //! Deep-copy assignment from Value /*! Assigns a \b copy of the Value to the current Value object \tparam SourceAllocator Allocator type of \c rhs \param rhs Value to copy from (read-only) \param allocator Allocator to use for copying \param copyConstStrings Force copying of constant strings (e.g. referencing an in-situ buffer) */ template GenericValue& CopyFrom(const GenericValue& rhs, Allocator& allocator, bool copyConstStrings = false) { RAPIDJSON_ASSERT(static_cast(this) != static_cast(&rhs)); this->~GenericValue(); new (this) GenericValue(rhs, allocator, copyConstStrings); return *this; } //! Exchange the contents of this value with those of other. /*! \param other Another value. \note Constant complexity. */ GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT { GenericValue temp; temp.RawAssign(*this); RawAssign(other); other.RawAssign(temp); return *this; } //! free-standing swap function helper /*! Helper function to enable support for common swap implementation pattern based on \c std::swap: \code void swap(MyClass& a, MyClass& b) { using std::swap; swap(a.value, b.value); // ... } \endcode \see Swap() */ friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } //! Prepare Value for move semantics /*! \return *this */ GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; } //@} //!@name Equal-to and not-equal-to operators //@{ //! Equal-to operator /*! \note If an object contains duplicated named member, comparing equality with any object is always \c false. \note Linear time complexity (number of all values in the subtree and total lengths of all strings). */ template bool operator==(const GenericValue& rhs) const { typedef GenericValue RhsType; if (GetType() != rhs.GetType()) return false; switch (GetType()) { case kObjectType: // Warning: O(n^2) inner-loop if (data_.o.size != rhs.data_.o.size) return false; for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) { typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name); if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value) return false; } return true; case kArrayType: if (data_.a.size != rhs.data_.a.size) return false; for (SizeType i = 0; i < data_.a.size; i++) if ((*this)[i] != rhs[i]) return false; return true; case kStringType: return StringEqual(rhs); case kNumberType: if (IsDouble() || rhs.IsDouble()) { double a = GetDouble(); // May convert from integer to double. double b = rhs.GetDouble(); // Ditto return a >= b && a <= b; // Prevent -Wfloat-equal } else return data_.n.u64 == rhs.data_.n.u64; default: return true; } } //! Equal-to operator with const C-string pointer bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); } #if RAPIDJSON_HAS_STDSTRING //! Equal-to operator with string object /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ bool operator==(const std::basic_string& rhs) const { return *this == GenericValue(StringRef(rhs)); } #endif //! Equal-to operator with primitive types /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr,internal::IsGenericValue >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); } //! Not-equal-to operator /*! \return !(*this == rhs) */ template bool operator!=(const GenericValue& rhs) const { return !(*this == rhs); } //! Not-equal-to operator with const C-string pointer bool operator!=(const Ch* rhs) const { return !(*this == rhs); } //! Not-equal-to operator with arbitrary types /*! \return !(*this == rhs) */ template RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); } //! Equal-to operator with arbitrary types (symmetric version) /*! \return (rhs == lhs) */ template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; } //! Not-Equal-to operator with arbitrary types (symmetric version) /*! \return !(rhs == lhs) */ template friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); } //@} //!@name Type //@{ Type GetType() const { return static_cast(data_.f.flags & kTypeMask); } bool IsNull() const { return data_.f.flags == kNullFlag; } bool IsFalse() const { return data_.f.flags == kFalseFlag; } bool IsTrue() const { return data_.f.flags == kTrueFlag; } bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; } bool IsObject() const { return data_.f.flags == kObjectFlag; } bool IsArray() const { return data_.f.flags == kArrayFlag; } bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; } bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; } bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; } bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; } bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; } bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; } bool IsString() const { return (data_.f.flags & kStringFlag) != 0; } // Checks whether a number can be losslessly converted to a double. bool IsLosslessDouble() const { if (!IsNumber()) return false; if (IsUint64()) { uint64_t u = GetUint64(); volatile double d = static_cast(u); return (d >= 0.0) && (d < static_cast((std::numeric_limits::max)())) && (u == static_cast(d)); } if (IsInt64()) { int64_t i = GetInt64(); volatile double d = static_cast(i); return (d >= static_cast((std::numeric_limits::min)())) && (d < static_cast((std::numeric_limits::max)())) && (i == static_cast(d)); } return true; // double, int, uint are always lossless } // Checks whether a number is a float (possible lossy). bool IsFloat() const { if ((data_.f.flags & kDoubleFlag) == 0) return false; double d = GetDouble(); return d >= -3.4028234e38 && d <= 3.4028234e38; } // Checks whether a number can be losslessly converted to a float. bool IsLosslessFloat() const { if (!IsNumber()) return false; double a = GetDouble(); if (a < static_cast(-(std::numeric_limits::max)()) || a > static_cast((std::numeric_limits::max)())) return false; double b = static_cast(static_cast(a)); return a >= b && a <= b; // Prevent -Wfloat-equal } //@} //!@name Null //@{ GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; } //@} //!@name Bool //@{ bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; } //!< Set boolean value /*! \post IsBool() == true */ GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; } //@} //!@name Object //@{ //! Set this value as an empty object. /*! \post IsObject() == true */ GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; } //! Get the number of members in the object. SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; } //! Check whether the object is empty. bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; } //! Get a value from an object associated with the name. /*! \pre IsObject() == true \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType)) \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7. Since 0.2, if the name is not correct, it will assert. If user is unsure whether a member exists, user should use HasMember() first. A better approach is to use FindMember(). \note Linear time complexity. */ template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(GenericValue&)) operator[](T* name) { GenericValue n(StringRef(name)); return (*this)[n]; } template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast(*this)[name]; } //! Get a value from an object associated with the name. /*! \pre IsObject() == true \tparam SourceAllocator Allocator of the \c name value \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen(). And it can also handle strings with embedded null characters. \note Linear time complexity. */ template GenericValue& operator[](const GenericValue& name) { MemberIterator member = FindMember(name); if (member != MemberEnd()) return member->value; else { RAPIDJSON_ASSERT(false); // see above note // This will generate -Wexit-time-destructors in clang // static GenericValue NullValue; // return NullValue; // Use static buffer and placement-new to prevent destruction static char buffer[sizeof(GenericValue)]; return *new (buffer) GenericValue(); } } template const GenericValue& operator[](const GenericValue& name) const { return const_cast(*this)[name]; } #if RAPIDJSON_HAS_STDSTRING //! Get a value from an object associated with name (string object). GenericValue& operator[](const std::basic_string& name) { return (*this)[GenericValue(StringRef(name))]; } const GenericValue& operator[](const std::basic_string& name) const { return (*this)[GenericValue(StringRef(name))]; } #endif //! Const member iterator /*! \pre IsObject() == true */ ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); } //! Const \em past-the-end member iterator /*! \pre IsObject() == true */ ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); } //! Member iterator /*! \pre IsObject() == true */ MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); } //! \em Past-the-end member iterator /*! \pre IsObject() == true */ MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); } //! Check whether a member exists in the object. /*! \param name Member name to be searched. \pre IsObject() == true \return Whether a member with that name exists. \note It is better to use FindMember() directly if you need the obtain the value as well. \note Linear time complexity. */ bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); } #if RAPIDJSON_HAS_STDSTRING //! Check whether a member exists in the object with string object. /*! \param name Member name to be searched. \pre IsObject() == true \return Whether a member with that name exists. \note It is better to use FindMember() directly if you need the obtain the value as well. \note Linear time complexity. */ bool HasMember(const std::basic_string& name) const { return FindMember(name) != MemberEnd(); } #endif //! Check whether a member exists in the object with GenericValue name. /*! This version is faster because it does not need a StrLen(). It can also handle string with null character. \param name Member name to be searched. \pre IsObject() == true \return Whether a member with that name exists. \note It is better to use FindMember() directly if you need the obtain the value as well. \note Linear time complexity. */ template bool HasMember(const GenericValue& name) const { return FindMember(name) != MemberEnd(); } //! Find member by name. /*! \param name Member name to be searched. \pre IsObject() == true \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). \note Earlier versions of Rapidjson returned a \c NULL pointer, in case the requested member doesn't exist. For consistency with e.g. \c std::map, this has been changed to MemberEnd() now. \note Linear time complexity. */ MemberIterator FindMember(const Ch* name) { GenericValue n(StringRef(name)); return FindMember(n); } ConstMemberIterator FindMember(const Ch* name) const { return const_cast(*this).FindMember(name); } //! Find member by name. /*! This version is faster because it does not need a StrLen(). It can also handle string with null character. \param name Member name to be searched. \pre IsObject() == true \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). \note Earlier versions of Rapidjson returned a \c NULL pointer, in case the requested member doesn't exist. For consistency with e.g. \c std::map, this has been changed to MemberEnd() now. \note Linear time complexity. */ template MemberIterator FindMember(const GenericValue& name) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); MemberIterator member = MemberBegin(); for ( ; member != MemberEnd(); ++member) if (name.StringEqual(member->name)) break; return member; } template ConstMemberIterator FindMember(const GenericValue& name) const { return const_cast(*this).FindMember(name); } #if RAPIDJSON_HAS_STDSTRING //! Find member by string object name. /*! \param name Member name to be searched. \pre IsObject() == true \return Iterator to member, if it exists. Otherwise returns \ref MemberEnd(). */ MemberIterator FindMember(const std::basic_string& name) { return FindMember(GenericValue(StringRef(name))); } ConstMemberIterator FindMember(const std::basic_string& name) const { return FindMember(GenericValue(StringRef(name))); } #endif //! Add a member (name-value pair) to the object. /*! \param name A string value as name of member. \param value Value of any type. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note The ownership of \c name and \c value will be transferred to this object on success. \pre IsObject() && name.IsString() \post name.IsNull() && value.IsNull() \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(name.IsString()); ObjectData& o = data_.o; if (o.size >= o.capacity) { if (o.capacity == 0) { o.capacity = kDefaultObjectCapacity; SetMembersPointer(reinterpret_cast(allocator.Malloc(o.capacity * sizeof(Member)))); } else { SizeType oldCapacity = o.capacity; o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5 SetMembersPointer(reinterpret_cast(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member)))); } } Member* members = GetMembersPointer(); members[o.size].name.RawAssign(name); members[o.size].value.RawAssign(value); o.size++; return *this; } //! Add a constant string value as member (name-value pair) to the object. /*! \param name A string value as name of member. \param value constant string reference as value of member. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } #if RAPIDJSON_HAS_STDSTRING //! Add a string object as member (name-value pair) to the object. /*! \param name A string value as name of member. \param value constant string reference as value of member. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below. \note Amortized Constant time complexity. */ GenericValue& AddMember(GenericValue& name, std::basic_string& value, Allocator& allocator) { GenericValue v(value, allocator); return AddMember(name, v, allocator); } #endif //! Add any primitive value as member (name-value pair) to the object. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param name A string value as name of member. \param value Value of primitive type \c T as value of member \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref AddMember(StringRefType, StringRefType, Allocator&). All other pointer types would implicitly convert to \c bool, use an explicit cast instead, if needed. \note Amortized Constant time complexity. */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) AddMember(GenericValue& name, T value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) { return AddMember(name, value, allocator); } GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) { return AddMember(name, value, allocator); } GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) { return AddMember(name, value, allocator); } GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Add a member (name-value pair) to the object. /*! \param name A constant string reference as name of member. \param value Value of any type. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note The ownership of \c value will be transferred to this object on success. \pre IsObject() \post value.IsNull() \note Amortized Constant time complexity. */ GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); } //! Add a constant string value as member (name-value pair) to the object. /*! \param name A constant string reference as name of member. \param value constant string reference as value of member. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below. \note Amortized Constant time complexity. */ GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) { GenericValue v(value); return AddMember(name, v, allocator); } //! Add any primitive value as member (name-value pair) to the object. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param name A constant string reference as name of member. \param value Value of primitive type \c T as value of member \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \pre IsObject() \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref AddMember(StringRefType, StringRefType, Allocator&). All other pointer types would implicitly convert to \c bool, use an explicit cast instead, if needed. \note Amortized Constant time complexity. */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) AddMember(StringRefType name, T value, Allocator& allocator) { GenericValue n(name); return AddMember(n, value, allocator); } //! Remove all members in the object. /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged. \note Linear time complexity. */ void RemoveAllMembers() { RAPIDJSON_ASSERT(IsObject()); for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m) m->~Member(); data_.o.size = 0; } //! Remove a member in object by its name. /*! \param name Name of member to be removed. \return Whether the member existed. \note This function may reorder the object members. Use \ref EraseMember(ConstMemberIterator) if you need to preserve the relative order of the remaining members. \note Linear time complexity. */ bool RemoveMember(const Ch* name) { GenericValue n(StringRef(name)); return RemoveMember(n); } #if RAPIDJSON_HAS_STDSTRING bool RemoveMember(const std::basic_string& name) { return RemoveMember(GenericValue(StringRef(name))); } #endif template bool RemoveMember(const GenericValue& name) { MemberIterator m = FindMember(name); if (m != MemberEnd()) { RemoveMember(m); return true; } else return false; } //! Remove a member in object by iterator. /*! \param m member iterator (obtained by FindMember() or MemberBegin()). \return the new iterator after removal. \note This function may reorder the object members. Use \ref EraseMember(ConstMemberIterator) if you need to preserve the relative order of the remaining members. \note Constant time complexity. */ MemberIterator RemoveMember(MemberIterator m) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(data_.o.size > 0); RAPIDJSON_ASSERT(GetMembersPointer() != 0); RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd()); MemberIterator last(GetMembersPointer() + (data_.o.size - 1)); if (data_.o.size > 1 && m != last) *m = *last; // Move the last one to this place else m->~Member(); // Only one left, just destroy --data_.o.size; return m; } //! Remove a member from an object by iterator. /*! \param pos iterator to the member to remove \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd() \return Iterator following the removed element. If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned. \note This function preserves the relative order of the remaining object members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator). \note Linear time complexity. */ MemberIterator EraseMember(ConstMemberIterator pos) { return EraseMember(pos, pos +1); } //! Remove members in the range [first, last) from an object. /*! \param first iterator to the first member to remove \param last iterator following the last member to remove \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd() \return Iterator following the last removed element. \note This function preserves the relative order of the remaining object members. \note Linear time complexity. */ MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) { RAPIDJSON_ASSERT(IsObject()); RAPIDJSON_ASSERT(data_.o.size > 0); RAPIDJSON_ASSERT(GetMembersPointer() != 0); RAPIDJSON_ASSERT(first >= MemberBegin()); RAPIDJSON_ASSERT(first <= last); RAPIDJSON_ASSERT(last <= MemberEnd()); MemberIterator pos = MemberBegin() + (first - MemberBegin()); for (MemberIterator itr = pos; itr != last; ++itr) itr->~Member(); std::memmove(&*pos, &*last, static_cast(MemberEnd() - last) * sizeof(Member)); data_.o.size -= static_cast(last - first); return pos; } //! Erase a member in object by its name. /*! \param name Name of member to be removed. \return Whether the member existed. \note Linear time complexity. */ bool EraseMember(const Ch* name) { GenericValue n(StringRef(name)); return EraseMember(n); } #if RAPIDJSON_HAS_STDSTRING bool EraseMember(const std::basic_string& name) { return EraseMember(GenericValue(StringRef(name))); } #endif template bool EraseMember(const GenericValue& name) { MemberIterator m = FindMember(name); if (m != MemberEnd()) { EraseMember(m); return true; } else return false; } Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); } ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); } //@} //!@name Array //@{ //! Set this value as an empty array. /*! \post IsArray == true */ GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; } //! Get the number of elements in array. SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; } //! Get the capacity of array. SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; } //! Check whether the array is empty. bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; } //! Remove all elements in the array. /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged. \note Linear time complexity. */ void Clear() { RAPIDJSON_ASSERT(IsArray()); GenericValue* e = GetElementsPointer(); for (GenericValue* v = e; v != e + data_.a.size; ++v) v->~GenericValue(); data_.a.size = 0; } //! Get an element from array by index. /*! \pre IsArray() == true \param index Zero-based index of element. \see operator[](T*) */ GenericValue& operator[](SizeType index) { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(index < data_.a.size); return GetElementsPointer()[index]; } const GenericValue& operator[](SizeType index) const { return const_cast(*this)[index]; } //! Element iterator /*! \pre IsArray() == true */ ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); } //! \em Past-the-end element iterator /*! \pre IsArray() == true */ ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; } //! Constant element iterator /*! \pre IsArray() == true */ ConstValueIterator Begin() const { return const_cast(*this).Begin(); } //! Constant \em past-the-end element iterator /*! \pre IsArray() == true */ ConstValueIterator End() const { return const_cast(*this).End(); } //! Request the array to have enough capacity to store elements. /*! \param newCapacity The capacity that the array at least need to have. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \note Linear time complexity. */ GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) { RAPIDJSON_ASSERT(IsArray()); if (newCapacity > data_.a.capacity) { SetElementsPointer(reinterpret_cast(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue)))); data_.a.capacity = newCapacity; } return *this; } //! Append a GenericValue at the end of the array. /*! \param value Value to be appended. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \pre IsArray() == true \post value.IsNull() == true \return The value itself for fluent API. \note The ownership of \c value will be transferred to this array on success. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. \note Amortized constant time complexity. */ GenericValue& PushBack(GenericValue& value, Allocator& allocator) { RAPIDJSON_ASSERT(IsArray()); if (data_.a.size >= data_.a.capacity) Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator); GetElementsPointer()[data_.a.size++].RawAssign(value); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericValue& PushBack(GenericValue&& value, Allocator& allocator) { return PushBack(value, allocator); } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Append a constant string reference at the end of the array. /*! \param value Constant string reference to be appended. \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator(). \pre IsArray() == true \return The value itself for fluent API. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. \note Amortized constant time complexity. \see GenericStringRef */ GenericValue& PushBack(StringRefType value, Allocator& allocator) { return (*this).template PushBack(value, allocator); } //! Append a primitive value at the end of the array. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t \param value Value of primitive type T to be appended. \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator(). \pre IsArray() == true \return The value itself for fluent API. \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient. \note The source type \c T explicitly disallows all pointer types, especially (\c const) \ref Ch*. This helps avoiding implicitly referencing character strings with insufficient lifetime, use \ref PushBack(GenericValue&, Allocator&) or \ref PushBack(StringRefType, Allocator&). All other pointer types would implicitly convert to \c bool, use an explicit cast instead, if needed. \note Amortized constant time complexity. */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericValue&)) PushBack(T value, Allocator& allocator) { GenericValue v(value); return PushBack(v, allocator); } //! Remove the last element in the array. /*! \note Constant time complexity. */ GenericValue& PopBack() { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(!Empty()); GetElementsPointer()[--data_.a.size].~GenericValue(); return *this; } //! Remove an element of array by iterator. /*! \param pos iterator to the element to remove \pre IsArray() == true && \ref Begin() <= \c pos < \ref End() \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned. \note Linear time complexity. */ ValueIterator Erase(ConstValueIterator pos) { return Erase(pos, pos + 1); } //! Remove elements in the range [first, last) of the array. /*! \param first iterator to the first element to remove \param last iterator following the last element to remove \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End() \return Iterator following the last removed element. \note Linear time complexity. */ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) { RAPIDJSON_ASSERT(IsArray()); RAPIDJSON_ASSERT(data_.a.size > 0); RAPIDJSON_ASSERT(GetElementsPointer() != 0); RAPIDJSON_ASSERT(first >= Begin()); RAPIDJSON_ASSERT(first <= last); RAPIDJSON_ASSERT(last <= End()); ValueIterator pos = Begin() + (first - Begin()); for (ValueIterator itr = pos; itr != last; ++itr) itr->~GenericValue(); std::memmove(pos, last, static_cast(End() - last) * sizeof(GenericValue)); data_.a.size -= static_cast(last - first); return pos; } Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); } ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); } //@} //!@name Number //@{ int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; } unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; } int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; } uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; } //! Get the value as double type. /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless. */ double GetDouble() const { RAPIDJSON_ASSERT(IsNumber()); if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion. if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double if ((data_.f.flags & kInt64Flag) != 0) return static_cast(data_.n.i64); // int64_t -> double (may lose precision) RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast(data_.n.u64); // uint64_t -> double (may lose precision) } //! Get the value as float type. /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless. */ float GetFloat() const { return static_cast(GetDouble()); } GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; } GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; } GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; } GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; } GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; } GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(static_cast(f)); return *this; } //@} //!@name String //@{ const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); } //! Get the length of string. /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength(). */ SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); } //! Set this value as a string without copying source string. /*! This version has better performance with supplied length, and also support string containing null character. \param s source string pointer. \param length The length of source string, excluding the trailing null terminator. \return The value itself for fluent API. \post IsString() == true && GetString() == s && GetStringLength() == length \see SetString(StringRefType) */ GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); } //! Set this value as a string without copying source string. /*! \param s source string reference \return The value itself for fluent API. \post IsString() == true && GetString() == s && GetStringLength() == s.length */ GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; } //! Set this value as a string by copying from source string. /*! This version has better performance with supplied length, and also support string containing null character. \param s source string. \param length The length of source string, excluding the trailing null terminator. \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { return SetString(StringRef(s, length), allocator); } //! Set this value as a string by copying from source string. /*! \param s source string. \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(StringRef(s), allocator); } //! Set this value as a string by copying from source string. /*! \param s source string reference \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s.s && strcmp(GetString(),s) == 0 && GetStringLength() == length */ GenericValue& SetString(StringRefType s, Allocator& allocator) { this->~GenericValue(); SetStringRaw(s, allocator); return *this; } #if RAPIDJSON_HAS_STDSTRING //! Set this value as a string by copying from source string. /*! \param s source string. \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator(). \return The value itself for fluent API. \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ GenericValue& SetString(const std::basic_string& s, Allocator& allocator) { return SetString(StringRef(s), allocator); } #endif //@} //!@name Array //@{ //! Templated version for checking whether this value is type T. /*! \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string */ template bool Is() const { return internal::TypeHelper::Is(*this); } template T Get() const { return internal::TypeHelper::Get(*this); } template T Get() { return internal::TypeHelper::Get(*this); } template ValueType& Set(const T& data) { return internal::TypeHelper::Set(*this, data); } template ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper::Set(*this, data, allocator); } //@} //! Generate events of this value to a Handler. /*! This function adopts the GoF visitor pattern. Typical usage is to output this JSON value as JSON text via Writer, which is a Handler. It can also be used to deep clone this value via GenericDocument, which is also a Handler. \tparam Handler type of handler. \param handler An object implementing concept Handler. */ template bool Accept(Handler& handler) const { switch(GetType()) { case kNullType: return handler.Null(); case kFalseType: return handler.Bool(false); case kTrueType: return handler.Bool(true); case kObjectType: if (RAPIDJSON_UNLIKELY(!handler.StartObject())) return false; for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) { RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator. if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0))) return false; if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler))) return false; } return handler.EndObject(data_.o.size); case kArrayType: if (RAPIDJSON_UNLIKELY(!handler.StartArray())) return false; for (const GenericValue* v = Begin(); v != End(); ++v) if (RAPIDJSON_UNLIKELY(!v->Accept(handler))) return false; return handler.EndArray(data_.a.size); case kStringType: return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0); default: RAPIDJSON_ASSERT(GetType() == kNumberType); if (IsDouble()) return handler.Double(data_.n.d); else if (IsInt()) return handler.Int(data_.n.i.i); else if (IsUint()) return handler.Uint(data_.n.u.u); else if (IsInt64()) return handler.Int64(data_.n.i64); else return handler.Uint64(data_.n.u64); } } private: template friend class GenericValue; template friend class GenericDocument; enum { kBoolFlag = 0x0008, kNumberFlag = 0x0010, kIntFlag = 0x0020, kUintFlag = 0x0040, kInt64Flag = 0x0080, kUint64Flag = 0x0100, kDoubleFlag = 0x0200, kStringFlag = 0x0400, kCopyFlag = 0x0800, kInlineStrFlag = 0x1000, // Initial flags of different types. kNullFlag = kNullType, kTrueFlag = kTrueType | kBoolFlag, kFalseFlag = kFalseType | kBoolFlag, kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag, kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag, kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag, kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag, kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag, kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag, kConstStringFlag = kStringType | kStringFlag, kCopyStringFlag = kStringType | kStringFlag | kCopyFlag, kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag, kObjectFlag = kObjectType, kArrayFlag = kArrayType, kTypeMask = 0x07 }; static const SizeType kDefaultArrayCapacity = 16; static const SizeType kDefaultObjectCapacity = 16; struct Flag { #if RAPIDJSON_48BITPOINTER_OPTIMIZATION char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer #elif RAPIDJSON_64BIT char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes #else char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes #endif uint16_t flags; }; struct String { SizeType length; SizeType hashcode; //!< reserved const Ch* str; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars // (excluding the terminating zero) and store a value to determine the length of the contained // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as // the string terminator as well. For getting the string length back from that value just use // "MaxSize - str[LenPos]". // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode, // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings). struct ShortString { enum { MaxChars = sizeof(static_cast(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize }; Ch str[MaxChars]; inline static bool Usable(SizeType len) { return (MaxSize >= len); } inline void SetLength(SizeType len) { str[LenPos] = static_cast(MaxSize - len); } inline SizeType GetLength() const { return static_cast(MaxSize - str[LenPos]); } }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode // By using proper binary layout, retrieval of different integer types do not need conversions. union Number { #if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN struct I { int i; char padding[4]; }i; struct U { unsigned u; char padding2[4]; }u; #else struct I { char padding[4]; int i; }i; struct U { char padding2[4]; unsigned u; }u; #endif int64_t i64; uint64_t u64; double d; }; // 8 bytes struct ObjectData { SizeType size; SizeType capacity; Member* members; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode struct ArrayData { SizeType size; SizeType capacity; GenericValue* elements; }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode union Data { String s; ShortString ss; Number n; ObjectData o; ArrayData a; Flag f; }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); } RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); } RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); } RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); } RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); } RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); } // Initialize this value as array with initial data, without calling destructor. void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) { data_.f.flags = kArrayFlag; if (count) { GenericValue* e = static_cast(allocator.Malloc(count * sizeof(GenericValue))); SetElementsPointer(e); std::memcpy(e, values, count * sizeof(GenericValue)); } else SetElementsPointer(0); data_.a.size = data_.a.capacity = count; } //! Initialize this value as object with initial data, without calling destructor. void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) { data_.f.flags = kObjectFlag; if (count) { Member* m = static_cast(allocator.Malloc(count * sizeof(Member))); SetMembersPointer(m); std::memcpy(m, members, count * sizeof(Member)); } else SetMembersPointer(0); data_.o.size = data_.o.capacity = count; } //! Initialize this value as constant string, without calling destructor. void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT { data_.f.flags = kConstStringFlag; SetStringPointer(s); data_.s.length = s.length; } //! Initialize this value as copy string with initial data, without calling destructor. void SetStringRaw(StringRefType s, Allocator& allocator) { Ch* str = 0; if (ShortString::Usable(s.length)) { data_.f.flags = kShortStringFlag; data_.ss.SetLength(s.length); str = data_.ss.str; } else { data_.f.flags = kCopyStringFlag; data_.s.length = s.length; str = static_cast(allocator.Malloc((s.length + 1) * sizeof(Ch))); SetStringPointer(str); } std::memcpy(str, s, s.length * sizeof(Ch)); str[s.length] = '\0'; } //! Assignment without calling destructor void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT { data_ = rhs.data_; // data_.f.flags = rhs.data_.f.flags; rhs.data_.f.flags = kNullFlag; } template bool StringEqual(const GenericValue& rhs) const { RAPIDJSON_ASSERT(IsString()); RAPIDJSON_ASSERT(rhs.IsString()); const SizeType len1 = GetStringLength(); const SizeType len2 = rhs.GetStringLength(); if(len1 != len2) { return false; } const Ch* const str1 = GetString(); const Ch* const str2 = rhs.GetString(); if(str1 == str2) { return true; } // fast path for constant string return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0); } Data data_; }; //! GenericValue with UTF8 encoding typedef GenericValue > Value; /////////////////////////////////////////////////////////////////////////////// // GenericDocument //! A document for parsing JSON text as DOM. /*! \note implements Handler concept \tparam Encoding Encoding for both parsing and string storage. \tparam Allocator Allocator for allocating memory for the DOM \tparam StackAllocator Allocator for allocating memory for stack during parsing. \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue. */ template , typename StackAllocator = CrtAllocator> class GenericDocument : public GenericValue { public: typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding. typedef GenericValue ValueType; //!< Value type of the document. typedef Allocator AllocatorType; //!< Allocator type from template parameter. //! Constructor /*! Creates an empty document of specified type. \param type Mandatory type of object to create. \param allocator Optional allocator for allocating memory. \param stackCapacity Optional initial capacity of stack in bytes. \param stackAllocator Optional allocator for allocating memory for stack. */ explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : GenericValue(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); } //! Constructor /*! Creates an empty document which type is Null. \param allocator Optional allocator for allocating memory. \param stackCapacity Optional initial capacity of stack in bytes. \param stackAllocator Optional allocator for allocating memory for stack. */ GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_() { if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move constructor in C++11 GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT : ValueType(std::forward(rhs)), // explicit cast to avoid prohibited move from Document allocator_(rhs.allocator_), ownAllocator_(rhs.ownAllocator_), stack_(std::move(rhs.stack_)), parseResult_(rhs.parseResult_) { rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.parseResult_ = ParseResult(); } #endif ~GenericDocument() { Destroy(); } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS //! Move assignment in C++11 GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT { // The cast to ValueType is necessary here, because otherwise it would // attempt to call GenericValue's templated assignment operator. ValueType::operator=(std::forward(rhs)); // Calling the destructor here would prematurely call stack_'s destructor Destroy(); allocator_ = rhs.allocator_; ownAllocator_ = rhs.ownAllocator_; stack_ = std::move(rhs.stack_); parseResult_ = rhs.parseResult_; rhs.allocator_ = 0; rhs.ownAllocator_ = 0; rhs.parseResult_ = ParseResult(); return *this; } #endif //! Exchange the contents of this document with those of another. /*! \param rhs Another document. \note Constant complexity. \see GenericValue::Swap */ GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT { ValueType::Swap(rhs); stack_.Swap(rhs.stack_); internal::Swap(allocator_, rhs.allocator_); internal::Swap(ownAllocator_, rhs.ownAllocator_); internal::Swap(parseResult_, rhs.parseResult_); return *this; } // Allow Swap with ValueType. // Refer to Effective C++ 3rd Edition/Item 33: Avoid hiding inherited names. using ValueType::Swap; //! free-standing swap function helper /*! Helper function to enable support for common swap implementation pattern based on \c std::swap: \code void swap(MyClass& a, MyClass& b) { using std::swap; swap(a.doc, b.doc); // ... } \endcode \see Swap() */ friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); } //! Populate this document by a generator which produces SAX events. /*! \tparam Generator A functor with bool f(Handler) prototype. \param g Generator functor which sends SAX events to the parameter. \return The document itself for fluent API. */ template GenericDocument& Populate(Generator& g) { ClearStackOnExit scope(*this); if (g(*this)) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document } return *this; } //!@name Parse from stream //!@{ //! Parse JSON text from an input stream (with Encoding conversion) /*! \tparam parseFlags Combination of \ref ParseFlag. \tparam SourceEncoding Encoding of input stream \tparam InputStream Type of input stream, implementing Stream concept \param is Input stream to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseStream(InputStream& is) { GenericReader reader( stack_.HasAllocator() ? &stack_.GetAllocator() : 0); ClearStackOnExit scope(*this); parseResult_ = reader.template Parse(is, *this); if (parseResult_) { RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object ValueType::operator=(*stack_.template Pop(1));// Move value from stack to document } return *this; } //! Parse JSON text from an input stream /*! \tparam parseFlags Combination of \ref ParseFlag. \tparam InputStream Type of input stream, implementing Stream concept \param is Input stream to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseStream(InputStream& is) { return ParseStream(is); } //! Parse JSON text from an input stream (with \ref kParseDefaultFlags) /*! \tparam InputStream Type of input stream, implementing Stream concept \param is Input stream to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseStream(InputStream& is) { return ParseStream(is); } //!@} //!@name Parse in-place from mutable string //!@{ //! Parse JSON text from a mutable string /*! \tparam parseFlags Combination of \ref ParseFlag. \param str Mutable zero-terminated string to be parsed. \return The document itself for fluent API. */ template GenericDocument& ParseInsitu(Ch* str) { GenericInsituStringStream s(str); return ParseStream(s); } //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags) /*! \param str Mutable zero-terminated string to be parsed. \return The document itself for fluent API. */ GenericDocument& ParseInsitu(Ch* str) { return ParseInsitu(str); } //!@} //!@name Parse from read-only string //!@{ //! Parse JSON text from a read-only string (with Encoding conversion) /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). \tparam SourceEncoding Transcoding from input Encoding \param str Read-only zero-terminated string to be parsed. */ template GenericDocument& Parse(const typename SourceEncoding::Ch* str) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); GenericStringStream s(str); return ParseStream(s); } //! Parse JSON text from a read-only string /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag). \param str Read-only zero-terminated string to be parsed. */ template GenericDocument& Parse(const Ch* str) { return Parse(str); } //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags) /*! \param str Read-only zero-terminated string to be parsed. */ GenericDocument& Parse(const Ch* str) { return Parse(str); } template GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) { RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag)); MemoryStream ms(reinterpret_cast(str), length * sizeof(typename SourceEncoding::Ch)); EncodedInputStream is(ms); ParseStream(is); return *this; } template GenericDocument& Parse(const Ch* str, size_t length) { return Parse(str, length); } GenericDocument& Parse(const Ch* str, size_t length) { return Parse(str, length); } #if RAPIDJSON_HAS_STDSTRING template GenericDocument& Parse(const std::basic_string& str) { // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t) return Parse(str.c_str()); } template GenericDocument& Parse(const std::basic_string& str) { return Parse(str.c_str()); } GenericDocument& Parse(const std::basic_string& str) { return Parse(str); } #endif // RAPIDJSON_HAS_STDSTRING //!@} //!@name Handling parse errors //!@{ //! Whether a parse error has occured in the last parsing. bool HasParseError() const { return parseResult_.IsError(); } //! Get the \ref ParseErrorCode of last parsing. ParseErrorCode GetParseError() const { return parseResult_.Code(); } //! Get the position of last parsing error in input, 0 otherwise. size_t GetErrorOffset() const { return parseResult_.Offset(); } //! Implicit conversion to get the last parse result #ifndef __clang // -Wdocumentation /*! \return \ref ParseResult of the last parse operation \code Document doc; ParseResult ok = doc.Parse(json); if (!ok) printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset()); \endcode */ #endif operator ParseResult() const { return parseResult_; } //!@} //! Get the allocator of this document. Allocator& GetAllocator() { RAPIDJSON_ASSERT(allocator_); return *allocator_; } //! Get the capacity of stack in bytes. size_t GetStackCapacity() const { return stack_.GetCapacity(); } private: // clear stack on any exit from ParseStream, e.g. due to exception struct ClearStackOnExit { explicit ClearStackOnExit(GenericDocument& d) : d_(d) {} ~ClearStackOnExit() { d_.ClearStack(); } private: ClearStackOnExit(const ClearStackOnExit&); ClearStackOnExit& operator=(const ClearStackOnExit&); GenericDocument& d_; }; // callers of the following private Handler functions // template friend class GenericReader; // for parsing template friend class GenericValue; // for deep copying public: // Implementation of Handler bool Null() { new (stack_.template Push()) ValueType(); return true; } bool Bool(bool b) { new (stack_.template Push()) ValueType(b); return true; } bool Int(int i) { new (stack_.template Push()) ValueType(i); return true; } bool Uint(unsigned i) { new (stack_.template Push()) ValueType(i); return true; } bool Int64(int64_t i) { new (stack_.template Push()) ValueType(i); return true; } bool Uint64(uint64_t i) { new (stack_.template Push()) ValueType(i); return true; } bool Double(double d) { new (stack_.template Push()) ValueType(d); return true; } bool RawNumber(const Ch* str, SizeType length, bool copy) { if (copy) new (stack_.template Push()) ValueType(str, length, GetAllocator()); else new (stack_.template Push()) ValueType(str, length); return true; } bool String(const Ch* str, SizeType length, bool copy) { if (copy) new (stack_.template Push()) ValueType(str, length, GetAllocator()); else new (stack_.template Push()) ValueType(str, length); return true; } bool StartObject() { new (stack_.template Push()) ValueType(kObjectType); return true; } bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); } bool EndObject(SizeType memberCount) { typename ValueType::Member* members = stack_.template Pop(memberCount); stack_.template Top()->SetObjectRaw(members, memberCount, GetAllocator()); return true; } bool StartArray() { new (stack_.template Push()) ValueType(kArrayType); return true; } bool EndArray(SizeType elementCount) { ValueType* elements = stack_.template Pop(elementCount); stack_.template Top()->SetArrayRaw(elements, elementCount, GetAllocator()); return true; } private: //! Prohibit copying GenericDocument(const GenericDocument&); //! Prohibit assignment GenericDocument& operator=(const GenericDocument&); void ClearStack() { if (Allocator::kNeedFree) while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects) (stack_.template Pop(1))->~ValueType(); else stack_.Clear(); stack_.ShrinkToFit(); } void Destroy() { RAPIDJSON_DELETE(ownAllocator_); } static const size_t kDefaultStackCapacity = 1024; Allocator* allocator_; Allocator* ownAllocator_; internal::Stack stack_; ParseResult parseResult_; }; //! GenericDocument with UTF8 encoding typedef GenericDocument > Document; //! Helper class for accessing Value of array type. /*! Instance of this helper class is obtained by \c GenericValue::GetArray(). In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. */ template class GenericArray { public: typedef GenericArray ConstArray; typedef GenericArray Array; typedef ValueT PlainType; typedef typename internal::MaybeAddConst::Type ValueType; typedef ValueType* ValueIterator; // This may be const or non-const iterator typedef const ValueT* ConstValueIterator; typedef typename ValueType::AllocatorType AllocatorType; typedef typename ValueType::StringRefType StringRefType; template friend class GenericValue; GenericArray(const GenericArray& rhs) : value_(rhs.value_) {} GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; } ~GenericArray() {} SizeType Size() const { return value_.Size(); } SizeType Capacity() const { return value_.Capacity(); } bool Empty() const { return value_.Empty(); } void Clear() const { value_.Clear(); } ValueType& operator[](SizeType index) const { return value_[index]; } ValueIterator Begin() const { return value_.Begin(); } ValueIterator End() const { return value_.End(); } GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; } GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; } GenericArray PopBack() const { value_.PopBack(); return *this; } ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); } ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); } #if RAPIDJSON_HAS_CXX11_RANGE_FOR ValueIterator begin() const { return value_.Begin(); } ValueIterator end() const { return value_.End(); } #endif private: GenericArray(); GenericArray(ValueType& value) : value_(value) {} ValueType& value_; }; //! Helper class for accessing Value of object type. /*! Instance of this helper class is obtained by \c GenericValue::GetObject(). In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1. */ template class GenericObject { public: typedef GenericObject ConstObject; typedef GenericObject Object; typedef ValueT PlainType; typedef typename internal::MaybeAddConst::Type ValueType; typedef GenericMemberIterator MemberIterator; // This may be const or non-const iterator typedef GenericMemberIterator ConstMemberIterator; typedef typename ValueType::AllocatorType AllocatorType; typedef typename ValueType::StringRefType StringRefType; typedef typename ValueType::EncodingType EncodingType; typedef typename ValueType::Ch Ch; template friend class GenericValue; GenericObject(const GenericObject& rhs) : value_(rhs.value_) {} GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; } ~GenericObject() {} SizeType MemberCount() const { return value_.MemberCount(); } bool ObjectEmpty() const { return value_.ObjectEmpty(); } template ValueType& operator[](T* name) const { return value_[name]; } template ValueType& operator[](const GenericValue& name) const { return value_[name]; } #if RAPIDJSON_HAS_STDSTRING ValueType& operator[](const std::basic_string& name) const { return value_[name]; } #endif MemberIterator MemberBegin() const { return value_.MemberBegin(); } MemberIterator MemberEnd() const { return value_.MemberEnd(); } bool HasMember(const Ch* name) const { return value_.HasMember(name); } #if RAPIDJSON_HAS_STDSTRING bool HasMember(const std::basic_string& name) const { return value_.HasMember(name); } #endif template bool HasMember(const GenericValue& name) const { return value_.HasMember(name); } MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); } template MemberIterator FindMember(const GenericValue& name) const { return value_.FindMember(name); } #if RAPIDJSON_HAS_STDSTRING MemberIterator FindMember(const std::basic_string& name) const { return value_.FindMember(name); } #endif GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #if RAPIDJSON_HAS_STDSTRING GenericObject AddMember(ValueType& name, std::basic_string& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #if RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } #endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; } void RemoveAllMembers() { value_.RemoveAllMembers(); } bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); } #if RAPIDJSON_HAS_STDSTRING bool RemoveMember(const std::basic_string& name) const { return value_.RemoveMember(name); } #endif template bool RemoveMember(const GenericValue& name) const { return value_.RemoveMember(name); } MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); } MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); } MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); } bool EraseMember(const Ch* name) const { return value_.EraseMember(name); } #if RAPIDJSON_HAS_STDSTRING bool EraseMember(const std::basic_string& name) const { return EraseMember(ValueType(StringRef(name))); } #endif template bool EraseMember(const GenericValue& name) const { return value_.EraseMember(name); } #if RAPIDJSON_HAS_CXX11_RANGE_FOR MemberIterator begin() const { return value_.MemberBegin(); } MemberIterator end() const { return value_.MemberEnd(); } #endif private: GenericObject(); GenericObject(ValueType& value) : value_(value) {} ValueType& value_; }; RAPIDJSON_NAMESPACE_END RAPIDJSON_DIAG_POP #endif // RAPIDJSON_DOCUMENT_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/encodedstream.h0000644002537200234200000002467113213503245025321 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_ENCODEDSTREAM_H_ #define RAPIDJSON_ENCODEDSTREAM_H_ #include "stream.h" #include "memorystream.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif RAPIDJSON_NAMESPACE_BEGIN //! Input byte stream wrapper with a statically bound encoding. /*! \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. \tparam InputByteStream Type of input byte stream. For example, FileReadStream. */ template class EncodedInputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); public: typedef typename Encoding::Ch Ch; EncodedInputStream(InputByteStream& is) : is_(is) { current_ = Encoding::TakeBOM(is_); } Ch Peek() const { return current_; } Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; } size_t Tell() const { return is_.Tell(); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: EncodedInputStream(const EncodedInputStream&); EncodedInputStream& operator=(const EncodedInputStream&); InputByteStream& is_; Ch current_; }; //! Specialized for UTF8 MemoryStream. template <> class EncodedInputStream, MemoryStream> { public: typedef UTF8<>::Ch Ch; EncodedInputStream(MemoryStream& is) : is_(is) { if (static_cast(is_.Peek()) == 0xEFu) is_.Take(); if (static_cast(is_.Peek()) == 0xBBu) is_.Take(); if (static_cast(is_.Peek()) == 0xBFu) is_.Take(); } Ch Peek() const { return is_.Peek(); } Ch Take() { return is_.Take(); } size_t Tell() const { return is_.Tell(); } // Not implemented void Put(Ch) {} void Flush() {} Ch* PutBegin() { return 0; } size_t PutEnd(Ch*) { return 0; } MemoryStream& is_; private: EncodedInputStream(const EncodedInputStream&); EncodedInputStream& operator=(const EncodedInputStream&); }; //! Output byte stream wrapper with statically bound encoding. /*! \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE. \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream. */ template class EncodedOutputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); public: typedef typename Encoding::Ch Ch; EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { if (putBOM) Encoding::PutBOM(os_); } void Put(Ch c) { Encoding::Put(os_, c); } void Flush() { os_.Flush(); } // Not implemented Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} Ch Take() { RAPIDJSON_ASSERT(false); return 0;} size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: EncodedOutputStream(const EncodedOutputStream&); EncodedOutputStream& operator=(const EncodedOutputStream&); OutputByteStream& os_; }; #define RAPIDJSON_ENCODINGS_FUNC(x) UTF8::x, UTF16LE::x, UTF16BE::x, UTF32LE::x, UTF32BE::x //! Input stream wrapper with dynamically bound encoding and automatic encoding detection. /*! \tparam CharType Type of character for reading. \tparam InputByteStream type of input byte stream to be wrapped. */ template class AutoUTFInputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1); public: typedef CharType Ch; //! Constructor. /*! \param is input stream to be wrapped. \param type UTF encoding type if it is not detected from the stream. */ AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) { RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); DetectType(); static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) }; takeFunc_ = f[type_]; current_ = takeFunc_(*is_); } UTFType GetType() const { return type_; } bool HasBOM() const { return hasBOM_; } Ch Peek() const { return current_; } Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; } size_t Tell() const { return is_->Tell(); } // Not implemented void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: AutoUTFInputStream(const AutoUTFInputStream&); AutoUTFInputStream& operator=(const AutoUTFInputStream&); // Detect encoding type with BOM or RFC 4627 void DetectType() { // BOM (Byte Order Mark): // 00 00 FE FF UTF-32BE // FF FE 00 00 UTF-32LE // FE FF UTF-16BE // FF FE UTF-16LE // EF BB BF UTF-8 const unsigned char* c = reinterpret_cast(is_->Peek4()); if (!c) return; unsigned bom = static_cast(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24)); hasBOM_ = false; if (bom == 0xFFFE0000) { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } else if (bom == 0x0000FEFF) { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); } else if ((bom & 0xFFFF) == 0xFFFE) { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take(); } else if ((bom & 0xFFFF) == 0xFEFF) { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take(); } else if ((bom & 0xFFFFFF) == 0xBFBBEF) { type_ = kUTF8; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); } // RFC 4627: Section 3 // "Since the first two characters of a JSON text will always be ASCII // characters [RFC0020], it is possible to determine whether an octet // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking // at the pattern of nulls in the first four octets." // 00 00 00 xx UTF-32BE // 00 xx 00 xx UTF-16BE // xx 00 00 00 UTF-32LE // xx 00 xx 00 UTF-16LE // xx xx xx xx UTF-8 if (!hasBOM_) { int pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0); switch (pattern) { case 0x08: type_ = kUTF32BE; break; case 0x0A: type_ = kUTF16BE; break; case 0x01: type_ = kUTF32LE; break; case 0x05: type_ = kUTF16LE; break; case 0x0F: type_ = kUTF8; break; default: break; // Use type defined by user. } } // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); } typedef Ch (*TakeFunc)(InputByteStream& is); InputByteStream* is_; UTFType type_; Ch current_; TakeFunc takeFunc_; bool hasBOM_; }; //! Output stream wrapper with dynamically bound encoding and automatic encoding detection. /*! \tparam CharType Type of character for writing. \tparam OutputByteStream type of output byte stream to be wrapped. */ template class AutoUTFOutputStream { RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1); public: typedef CharType Ch; //! Constructor. /*! \param os output stream to be wrapped. \param type UTF encoding type. \param putBOM Whether to write BOM at the beginning of the stream. */ AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) { RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE); // Runtime check whether the size of character type is sufficient. It only perform checks with assertion. if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2); if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4); static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) }; putFunc_ = f[type_]; if (putBOM) PutBOM(); } UTFType GetType() const { return type_; } void Put(Ch c) { putFunc_(*os_, c); } void Flush() { os_->Flush(); } // Not implemented Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;} Ch Take() { RAPIDJSON_ASSERT(false); return 0;} size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } private: AutoUTFOutputStream(const AutoUTFOutputStream&); AutoUTFOutputStream& operator=(const AutoUTFOutputStream&); void PutBOM() { typedef void (*PutBOMFunc)(OutputByteStream&); static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) }; f[type_](*os_); } typedef void (*PutFunc)(OutputByteStream&, Ch); OutputByteStream* os_; UTFType type_; PutFunc putFunc_; }; #undef RAPIDJSON_ENCODINGS_FUNC RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_FILESTREAM_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/pointer.h0000644002537200234200000016231413213503245024161 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_POINTER_H_ #define RAPIDJSON_POINTER_H_ #include "document.h" #include "internal/itoa.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(switch-enum) #endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated #endif RAPIDJSON_NAMESPACE_BEGIN static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token //! Error code of parsing. /*! \ingroup RAPIDJSON_ERRORS \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode */ enum PointerParseErrorCode { kPointerParseErrorNone = 0, //!< The parse is successful kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/' kPointerParseErrorInvalidEscape, //!< Invalid escape kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment }; /////////////////////////////////////////////////////////////////////////////// // GenericPointer //! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator. /*! This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" (https://tools.ietf.org/html/rfc6901). A JSON pointer is for identifying a specific value in a JSON document (GenericDocument). It can simplify coding of DOM tree manipulation, because it can access multiple-level depth of DOM tree with single API call. After it parses a string representation (e.g. "/foo/0" or URI fragment representation (e.g. "#/foo/0") into its internal representation (tokens), it can be used to resolve a specific value in multiple documents, or sub-tree of documents. Contrary to GenericValue, Pointer can be copy constructed and copy assigned. Apart from assignment, a Pointer cannot be modified after construction. Although Pointer is very convenient, please aware that constructing Pointer involves parsing and dynamic memory allocation. A special constructor with user- supplied tokens eliminates these. GenericPointer depends on GenericDocument and GenericValue. \tparam ValueType The value type of the DOM tree. E.g. GenericValue > \tparam Allocator The allocator type for allocating memory for internal representation. \note GenericPointer uses same encoding of ValueType. However, Allocator of GenericPointer is independent of Allocator of Value. */ template class GenericPointer { public: typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value typedef typename ValueType::Ch Ch; //!< Character type from Value //! A token is the basic units of internal representation. /*! A JSON pointer string representation "/foo/123" is parsed to two tokens: "foo" and 123. 123 will be represented in both numeric form and string form. They are resolved according to the actual value type (object or array). For token that are not numbers, or the numeric value is out of bound (greater than limits of SizeType), they are only treated as string form (i.e. the token's index will be equal to kPointerInvalidIndex). This struct is public so that user can create a Pointer without parsing and allocation, using a special constructor. */ struct Token { const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character. SizeType length; //!< Length of the name. SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex. }; //!@name Constructors and destructor. //@{ //! Default constructor. GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Constructor that parses a string or URI fragment representation. /*! \param source A null-terminated, string or URI fragment representation of JSON pointer. \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. */ explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { Parse(source, internal::StrLen(source)); } #if RAPIDJSON_HAS_STDSTRING //! Constructor that parses a string or URI fragment representation. /*! \param source A string or URI fragment representation of JSON pointer. \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING. */ explicit GenericPointer(const std::basic_string& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { Parse(source.c_str(), source.size()); } #endif //! Constructor that parses a string or URI fragment representation, with length of the source string. /*! \param source A string or URI fragment representation of JSON pointer. \param length Length of source. \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one. \note Slightly faster than the overload without length. */ GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { Parse(source, length); } //! Constructor with user-supplied tokens. /*! This constructor let user supplies const array of tokens. This prevents the parsing process and eliminates allocation. This is preferred for memory constrained environments. \param tokens An constant array of tokens representing the JSON pointer. \param tokenCount Number of tokens. \b Example \code #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex } #define INDEX(i) { #i, sizeof(#i) - 1, i } static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) }; static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0])); // Equivalent to static const Pointer p("/foo/123"); #undef NAME #undef INDEX \endcode */ GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {} //! Copy constructor. GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) { *this = rhs; } //! Destructor. ~GenericPointer() { if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated. Allocator::Free(tokens_); RAPIDJSON_DELETE(ownAllocator_); } //! Assignment operator. GenericPointer& operator=(const GenericPointer& rhs) { if (this != &rhs) { // Do not delete ownAllcator if (nameBuffer_) Allocator::Free(tokens_); tokenCount_ = rhs.tokenCount_; parseErrorOffset_ = rhs.parseErrorOffset_; parseErrorCode_ = rhs.parseErrorCode_; if (rhs.nameBuffer_) CopyFromRaw(rhs); // Normally parsed tokens. else { tokens_ = rhs.tokens_; // User supplied const tokens. nameBuffer_ = 0; } } return *this; } //@} //!@name Append token //@{ //! Append a token and return a new Pointer /*! \param token Token to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const Token& token, Allocator* allocator = 0) const { GenericPointer r; r.allocator_ = allocator; Ch *p = r.CopyFromRaw(*this, 1, token.length + 1); std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch)); r.tokens_[tokenCount_].name = p; r.tokens_[tokenCount_].length = token.length; r.tokens_[tokenCount_].index = token.index; return r; } //! Append a name token with length, and return a new Pointer /*! \param name Name to be appended. \param length Length of name. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const { Token token = { name, length, kPointerInvalidIndex }; return Append(token, allocator); } //! Append a name token without length, and return a new Pointer /*! \param name Name (const Ch*) to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ template RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr::Type, Ch> >), (GenericPointer)) Append(T* name, Allocator* allocator = 0) const { return Append(name, internal::StrLen(name), allocator); } #if RAPIDJSON_HAS_STDSTRING //! Append a name token, and return a new Pointer /*! \param name Name to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const std::basic_string& name, Allocator* allocator = 0) const { return Append(name.c_str(), static_cast(name.size()), allocator); } #endif //! Append a index token, and return a new Pointer /*! \param index Index to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(SizeType index, Allocator* allocator = 0) const { char buffer[21]; char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer); SizeType length = static_cast(end - buffer); buffer[length] = '\0'; if (sizeof(Ch) == 1) { Token token = { reinterpret_cast(buffer), length, index }; return Append(token, allocator); } else { Ch name[21]; for (size_t i = 0; i <= length; i++) name[i] = static_cast(buffer[i]); Token token = { name, length, index }; return Append(token, allocator); } } //! Append a token by value, and return a new Pointer /*! \param token token to be appended. \param allocator Allocator for the newly return Pointer. \return A new Pointer with appended token. */ GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const { if (token.IsString()) return Append(token.GetString(), token.GetStringLength(), allocator); else { RAPIDJSON_ASSERT(token.IsUint64()); RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0)); return Append(static_cast(token.GetUint64()), allocator); } } //!@name Handling Parse Error //@{ //! Check whether this is a valid pointer. bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; } //! Get the parsing error offset in code unit. size_t GetParseErrorOffset() const { return parseErrorOffset_; } //! Get the parsing error code. PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; } //@} //! Get the allocator of this pointer. Allocator& GetAllocator() { return *allocator_; } //!@name Tokens //@{ //! Get the token array (const version only). const Token* GetTokens() const { return tokens_; } //! Get the number of tokens. size_t GetTokenCount() const { return tokenCount_; } //@} //!@name Equality/inequality operators //@{ //! Equality operator. /*! \note When any pointers are invalid, always returns false. */ bool operator==(const GenericPointer& rhs) const { if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_) return false; for (size_t i = 0; i < tokenCount_; i++) { if (tokens_[i].index != rhs.tokens_[i].index || tokens_[i].length != rhs.tokens_[i].length || (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0)) { return false; } } return true; } //! Inequality operator. /*! \note When any pointers are invalid, always returns true. */ bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); } //@} //!@name Stringify //@{ //! Stringify the pointer into string representation. /*! \tparam OutputStream Type of output stream. \param os The output stream. */ template bool Stringify(OutputStream& os) const { return Stringify(os); } //! Stringify the pointer into URI fragment representation. /*! \tparam OutputStream Type of output stream. \param os The output stream. */ template bool StringifyUriFragment(OutputStream& os) const { return Stringify(os); } //@} //!@name Create value //@{ //! Create a value in a subtree. /*! If the value is not exist, it creates all parent values and a JSON Null value. So it always succeed and return the newly created or existing value. Remind that it may change types of parents according to tokens, so it potentially removes previously stored values. For example, if a document was an array, and "/foo" is used to create a value, then the document will be changed to an object, and all existing array elements are lost. \param root Root value of a DOM subtree to be resolved. It can be any value other than document root. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \param alreadyExist If non-null, it stores whether the resolved value is already exist. \return The resolved newly created (a JSON Null value), or already exists value. */ ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const { RAPIDJSON_ASSERT(IsValid()); ValueType* v = &root; bool exist = true; for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { if (v->IsArray() && t->name[0] == '-' && t->length == 1) { v->PushBack(ValueType().Move(), allocator); v = &((*v)[v->Size() - 1]); exist = false; } else { if (t->index == kPointerInvalidIndex) { // must be object name if (!v->IsObject()) v->SetObject(); // Change to Object } else { // object name or array index if (!v->IsArray() && !v->IsObject()) v->SetArray(); // Change to Array } if (v->IsArray()) { if (t->index >= v->Size()) { v->Reserve(t->index + 1, allocator); while (t->index >= v->Size()) v->PushBack(ValueType().Move(), allocator); exist = false; } v = &((*v)[t->index]); } else { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) { v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator); v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end exist = false; } else v = &m->value; } } } if (alreadyExist) *alreadyExist = exist; return *v; } //! Creates a value in a document. /*! \param document A document to be resolved. \param alreadyExist If non-null, it stores whether the resolved value is already exist. \return The resolved newly created, or already exists value. */ template ValueType& Create(GenericDocument& document, bool* alreadyExist = 0) const { return Create(document, document.GetAllocator(), alreadyExist); } //@} //!@name Query value //@{ //! Query a value in a subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token. \return Pointer to the value if it can be resolved. Otherwise null. \note There are only 3 situations when a value cannot be resolved: 1. A value in the path is not an array nor object. 2. An object value does not contain the token. 3. A token is out of range of an array value. Use unresolvedTokenIndex to retrieve the token index. */ ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const { RAPIDJSON_ASSERT(IsValid()); ValueType* v = &root; for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { switch (v->GetType()) { case kObjectType: { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) break; v = &m->value; } continue; case kArrayType: if (t->index == kPointerInvalidIndex || t->index >= v->Size()) break; v = &((*v)[t->index]); continue; default: break; } // Error: unresolved token if (unresolvedTokenIndex) *unresolvedTokenIndex = static_cast(t - tokens_); return 0; } return v; } //! Query a const value in a const subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \return Pointer to the value if it can be resolved. Otherwise null. */ const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { return Get(const_cast(root), unresolvedTokenIndex); } //@} //!@name Query a value with default //@{ //! Query a value in a subtree with default value. /*! Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value. So that this function always succeed. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param defaultValue Default value to be cloned if the value was not exists. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \see Create() */ ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; Value& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.CopyFrom(defaultValue, allocator); } //! Query a value in a subtree with default null-terminated string. ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; Value& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } #if RAPIDJSON_HAS_STDSTRING //! Query a value in a subtree with default std::basic_string. ValueType& GetWithDefault(ValueType& root, const std::basic_string& defaultValue, typename ValueType::AllocatorType& allocator) const { bool alreadyExist; Value& v = Create(root, allocator, &alreadyExist); return alreadyExist ? v : v.SetString(defaultValue, allocator); } #endif //! Query a value in a subtree with default primitive value. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const { return GetWithDefault(root, ValueType(defaultValue).Move(), allocator); } //! Query a value in a document with default value. template ValueType& GetWithDefault(GenericDocument& document, const ValueType& defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } //! Query a value in a document with default null-terminated string. template ValueType& GetWithDefault(GenericDocument& document, const Ch* defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } #if RAPIDJSON_HAS_STDSTRING //! Query a value in a document with default std::basic_string. template ValueType& GetWithDefault(GenericDocument& document, const std::basic_string& defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } #endif //! Query a value in a document with default primitive value. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) GetWithDefault(GenericDocument& document, T defaultValue) const { return GetWithDefault(document, defaultValue, document.GetAllocator()); } //@} //!@name Set a value //@{ //! Set a value in a subtree, with move semantics. /*! It creates all parents if they are not exist or types are different to the tokens. So this function always succeeds but potentially remove existing values. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param value Value to be set. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \see Create() */ ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = value; } //! Set a value in a subtree, with copy semantics. ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator).CopyFrom(value, allocator); } //! Set a null-terminated string in a subtree. ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = ValueType(value, allocator).Move(); } #if RAPIDJSON_HAS_STDSTRING //! Set a std::basic_string in a subtree. ValueType& Set(ValueType& root, const std::basic_string& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = ValueType(value, allocator).Move(); } #endif //! Set a primitive value in a subtree. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator) = ValueType(value).Move(); } //! Set a value in a document, with move semantics. template ValueType& Set(GenericDocument& document, ValueType& value) const { return Create(document) = value; } //! Set a value in a document, with copy semantics. template ValueType& Set(GenericDocument& document, const ValueType& value) const { return Create(document).CopyFrom(value, document.GetAllocator()); } //! Set a null-terminated string in a document. template ValueType& Set(GenericDocument& document, const Ch* value) const { return Create(document) = ValueType(value, document.GetAllocator()).Move(); } #if RAPIDJSON_HAS_STDSTRING //! Sets a std::basic_string in a document. template ValueType& Set(GenericDocument& document, const std::basic_string& value) const { return Create(document) = ValueType(value, document.GetAllocator()).Move(); } #endif //! Set a primitive value in a document. /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool */ template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (ValueType&)) Set(GenericDocument& document, T value) const { return Create(document) = value; } //@} //!@name Swap a value //@{ //! Swap a value with a value in a subtree. /*! It creates all parents if they are not exist or types are different to the tokens. So this function always succeeds but potentially remove existing values. \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \param value Value to be swapped. \param allocator Allocator for creating the values if the specified value or its parents are not exist. \see Create() */ ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const { return Create(root, allocator).Swap(value); } //! Swap a value with a value in a document. template ValueType& Swap(GenericDocument& document, ValueType& value) const { return Create(document).Swap(value); } //@} //! Erase a value in a subtree. /*! \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root. \return Whether the resolved value is found and erased. \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false. */ bool Erase(ValueType& root) const { RAPIDJSON_ASSERT(IsValid()); if (tokenCount_ == 0) // Cannot erase the root return false; ValueType* v = &root; const Token* last = tokens_ + (tokenCount_ - 1); for (const Token *t = tokens_; t != last; ++t) { switch (v->GetType()) { case kObjectType: { typename ValueType::MemberIterator m = v->FindMember(GenericStringRef(t->name, t->length)); if (m == v->MemberEnd()) return false; v = &m->value; } break; case kArrayType: if (t->index == kPointerInvalidIndex || t->index >= v->Size()) return false; v = &((*v)[t->index]); break; default: return false; } } switch (v->GetType()) { case kObjectType: return v->EraseMember(GenericStringRef(last->name, last->length)); case kArrayType: if (last->index == kPointerInvalidIndex || last->index >= v->Size()) return false; v->Erase(v->Begin() + last->index); return true; default: return false; } } private: //! Clone the content from rhs to this. /*! \param rhs Source pointer. \param extraToken Extra tokens to be allocated. \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated. \return Start of non-occupied name buffer, for storing extra names. */ Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) { if (!allocator_) // allocator is independently owned. ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t) nameBufferSize += t->length; tokenCount_ = rhs.tokenCount_ + extraToken; tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch))); nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); if (rhs.tokenCount_ > 0) { std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token)); } if (nameBufferSize > 0) { std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch)); } // Adjust pointers to name buffer std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_; for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t) t->name += diff; return nameBuffer_ + nameBufferSize; } //! Check whether a character should be percent-encoded. /*! According to RFC 3986 2.3 Unreserved Characters. \param c The character (code unit) to be tested. */ bool NeedPercentEncode(Ch c) const { return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~'); } //! Parse a JSON String or its URI fragment representation into tokens. #ifndef __clang__ // -Wdocumentation /*! \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated. \param length Length of the source string. \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped. */ #endif void Parse(const Ch* source, size_t length) { RAPIDJSON_ASSERT(source != NULL); RAPIDJSON_ASSERT(nameBuffer_ == 0); RAPIDJSON_ASSERT(tokens_ == 0); // Create own allocator if user did not supply. if (!allocator_) ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator)(); // Count number of '/' as tokenCount tokenCount_ = 0; for (const Ch* s = source; s != source + length; s++) if (*s == '/') tokenCount_++; Token* token = tokens_ = static_cast(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch))); Ch* name = nameBuffer_ = reinterpret_cast(tokens_ + tokenCount_); size_t i = 0; // Detect if it is a URI fragment bool uriFragment = false; if (source[i] == '#') { uriFragment = true; i++; } if (i != length && source[i] != '/') { parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus; goto error; } while (i < length) { RAPIDJSON_ASSERT(source[i] == '/'); i++; // consumes '/' token->name = name; bool isNumber = true; while (i < length && source[i] != '/') { Ch c = source[i]; if (uriFragment) { // Decoding percent-encoding for URI fragment if (c == '%') { PercentDecodeStream is(&source[i], source + length); GenericInsituStringStream os(name); Ch* begin = os.PutBegin(); if (!Transcoder, EncodingType>().Validate(is, os) || !is.IsValid()) { parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding; goto error; } size_t len = os.PutEnd(begin); i += is.Tell() - 1; if (len == 1) c = *name; else { name += len; isNumber = false; i++; continue; } } else if (NeedPercentEncode(c)) { parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode; goto error; } } i++; // Escaping "~0" -> '~', "~1" -> '/' if (c == '~') { if (i < length) { c = source[i]; if (c == '0') c = '~'; else if (c == '1') c = '/'; else { parseErrorCode_ = kPointerParseErrorInvalidEscape; goto error; } i++; } else { parseErrorCode_ = kPointerParseErrorInvalidEscape; goto error; } } // First check for index: all of characters are digit if (c < '0' || c > '9') isNumber = false; *name++ = c; } token->length = static_cast(name - token->name); if (token->length == 0) isNumber = false; *name++ = '\0'; // Null terminator // Second check for index: more than one digit cannot have leading zero if (isNumber && token->length > 1 && token->name[0] == '0') isNumber = false; // String to SizeType conversion SizeType n = 0; if (isNumber) { for (size_t j = 0; j < token->length; j++) { SizeType m = n * 10 + static_cast(token->name[j] - '0'); if (m < n) { // overflow detection isNumber = false; break; } n = m; } } token->index = isNumber ? n : kPointerInvalidIndex; token++; } RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer parseErrorCode_ = kPointerParseErrorNone; return; error: Allocator::Free(tokens_); nameBuffer_ = 0; tokens_ = 0; tokenCount_ = 0; parseErrorOffset_ = i; return; } //! Stringify to string or URI fragment representation. /*! \tparam uriFragment True for stringifying to URI fragment representation. False for string representation. \tparam OutputStream type of output stream. \param os The output stream. */ template bool Stringify(OutputStream& os) const { RAPIDJSON_ASSERT(IsValid()); if (uriFragment) os.Put('#'); for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) { os.Put('/'); for (size_t j = 0; j < t->length; j++) { Ch c = t->name[j]; if (c == '~') { os.Put('~'); os.Put('0'); } else if (c == '/') { os.Put('~'); os.Put('1'); } else if (uriFragment && NeedPercentEncode(c)) { // Transcode to UTF8 sequence GenericStringStream source(&t->name[j]); PercentEncodeStream target(os); if (!Transcoder >().Validate(source, target)) return false; j += source.Tell() - 1; } else os.Put(c); } } return true; } //! A helper stream for decoding a percent-encoded sequence into code unit. /*! This stream decodes %XY triplet into code unit (0-255). If it encounters invalid characters, it sets output code unit as 0 and mark invalid, and to be checked by IsValid(). */ class PercentDecodeStream { public: typedef typename ValueType::Ch Ch; //! Constructor /*! \param source Start of the stream \param end Past-the-end of the stream. */ PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {} Ch Take() { if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet valid_ = false; return 0; } src_++; Ch c = 0; for (int j = 0; j < 2; j++) { c = static_cast(c << 4); Ch h = *src_; if (h >= '0' && h <= '9') c = static_cast(c + h - '0'); else if (h >= 'A' && h <= 'F') c = static_cast(c + h - 'A' + 10); else if (h >= 'a' && h <= 'f') c = static_cast(c + h - 'a' + 10); else { valid_ = false; return 0; } src_++; } return c; } size_t Tell() const { return static_cast(src_ - head_); } bool IsValid() const { return valid_; } private: const Ch* src_; //!< Current read position. const Ch* head_; //!< Original head of the string. const Ch* end_; //!< Past-the-end position. bool valid_; //!< Whether the parsing is valid. }; //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence. template class PercentEncodeStream { public: PercentEncodeStream(OutputStream& os) : os_(os) {} void Put(char c) { // UTF-8 must be byte unsigned char u = static_cast(c); static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; os_.Put('%'); os_.Put(static_cast(hexDigits[u >> 4])); os_.Put(static_cast(hexDigits[u & 15])); } private: OutputStream& os_; }; Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_. Allocator* ownAllocator_; //!< Allocator owned by this Pointer. Ch* nameBuffer_; //!< A buffer containing all names in tokens. Token* tokens_; //!< A list of tokens. size_t tokenCount_; //!< Number of tokens in tokens_. size_t parseErrorOffset_; //!< Offset in code unit when parsing fail. PointerParseErrorCode parseErrorCode_; //!< Parsing error code. }; //! GenericPointer for Value (UTF-8, default allocator). typedef GenericPointer Pointer; //!@name Helper functions for GenericPointer //@{ ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer& pointer, typename T::AllocatorType& a) { return pointer.Create(root, a); } template typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Create(root, a); } // No allocator parameter template typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer& pointer) { return pointer.Create(document); } template typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) { return GenericPointer(source, N - 1).Create(document); } ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType* GetValueByPointer(T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { return pointer.Get(root, unresolvedTokenIndex); } template const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer& pointer, size_t* unresolvedTokenIndex = 0) { return pointer.Get(root, unresolvedTokenIndex); } template typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) { return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); } template const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) { return GenericPointer(source, N - 1).Get(root, unresolvedTokenIndex); } ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } template typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } #if RAPIDJSON_HAS_STDSTRING template typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, const std::basic_string& defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) GetValueByPointerWithDefault(T& root, const GenericPointer& pointer, T2 defaultValue, typename T::AllocatorType& a) { return pointer.GetWithDefault(root, defaultValue, a); } template typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } template typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } #if RAPIDJSON_HAS_STDSTRING template typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string& defaultValue, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).GetWithDefault(root, defaultValue, a); } // No allocator parameter template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& defaultValue) { return pointer.GetWithDefault(document, defaultValue); } template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* defaultValue) { return pointer.GetWithDefault(document, defaultValue); } #if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, const std::basic_string& defaultValue) { return pointer.GetWithDefault(document, defaultValue); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) GetValueByPointerWithDefault(DocumentType& document, const GenericPointer& pointer, T2 defaultValue) { return pointer.GetWithDefault(document, defaultValue); } template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) { return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) { return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } #if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string& defaultValue) { return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) { return GenericPointer(source, N - 1).GetWithDefault(document, defaultValue); } ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const typename T::Ch* value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } #if RAPIDJSON_HAS_STDSTRING template typename T::ValueType& SetValueByPointer(T& root, const GenericPointer& pointer, const std::basic_string& value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) SetValueByPointer(T& root, const GenericPointer& pointer, T2 value, typename T::AllocatorType& a) { return pointer.Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } template typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } #if RAPIDJSON_HAS_STDSTRING template typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string& value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename T::ValueType&)) SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Set(root, value, a); } // No allocator parameter template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { return pointer.Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::ValueType& value) { return pointer.Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const typename DocumentType::Ch* value) { return pointer.Set(document, value); } #if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer& pointer, const std::basic_string& value) { return pointer.Set(document, value); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) SetValueByPointer(DocumentType& document, const GenericPointer& pointer, T2 value) { return pointer.Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { return GenericPointer(source, N - 1).Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) { return GenericPointer(source, N - 1).Set(document, value); } template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) { return GenericPointer(source, N - 1).Set(document, value); } #if RAPIDJSON_HAS_STDSTRING template typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string& value) { return GenericPointer(source, N - 1).Set(document, value); } #endif template RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr, internal::IsGenericValue >), (typename DocumentType::ValueType&)) SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) { return GenericPointer(source, N - 1).Set(document, value); } ////////////////////////////////////////////////////////////////////////////// template typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer& pointer, typename T::ValueType& value, typename T::AllocatorType& a) { return pointer.Swap(root, value, a); } template typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) { return GenericPointer(source, N - 1).Swap(root, value, a); } template typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer& pointer, typename DocumentType::ValueType& value) { return pointer.Swap(document, value); } template typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) { return GenericPointer(source, N - 1).Swap(document, value); } ////////////////////////////////////////////////////////////////////////////// template bool EraseValueByPointer(T& root, const GenericPointer& pointer) { return pointer.Erase(root); } template bool EraseValueByPointer(T& root, const CharType(&source)[N]) { return GenericPointer(source, N - 1).Erase(root); } //@} RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #ifdef _MSC_VER RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_POINTER_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/prettywriter.h0000644002537200234200000002411313213503245025257 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_PRETTYWRITER_H_ #define RAPIDJSON_PRETTYWRITER_H_ #include "writer.h" #ifdef __GNUC__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(effc++) #endif #if defined(__clang__) RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN //! Combination of PrettyWriter format flags. /*! \see PrettyWriter::SetFormatOptions */ enum PrettyFormatOptions { kFormatDefault = 0, //!< Default pretty formatting. kFormatSingleLineArray = 1 //!< Format arrays on a single line. }; //! Writer with indentation and spacing. /*! \tparam OutputStream Type of ouptut os. \tparam SourceEncoding Encoding of source string. \tparam TargetEncoding Encoding of output stream. \tparam StackAllocator Type of allocator for allocating memory of stack. */ template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> class PrettyWriter : public Writer { public: typedef Writer Base; typedef typename Base::Ch Ch; //! Constructor /*! \param os Output stream. \param allocator User supplied allocator. If it is null, it will create a private one. \param levelDepth Initial capacity of stack. */ explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {} explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {} #if RAPIDJSON_HAS_CXX11_RVALUE_REFS PrettyWriter(PrettyWriter&& rhs) : Base(std::forward(rhs)), indentChar_(rhs.indentChar_), indentCharCount_(rhs.indentCharCount_), formatOptions_(rhs.formatOptions_) {} #endif //! Set custom indentation. /*! \param indentChar Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r'). \param indentCharCount Number of indent characters for each indentation level. \note The default indentation is 4 spaces. */ PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) { RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r'); indentChar_ = indentChar; indentCharCount_ = indentCharCount; return *this; } //! Set pretty writer formatting options. /*! \param options Formatting options. */ PrettyWriter& SetFormatOptions(PrettyFormatOptions options) { formatOptions_ = options; return *this; } /*! @name Implementation of Handler \see Handler */ //@{ bool Null() { PrettyPrefix(kNullType); return Base::WriteNull(); } bool Bool(bool b) { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); } bool Int(int i) { PrettyPrefix(kNumberType); return Base::WriteInt(i); } bool Uint(unsigned u) { PrettyPrefix(kNumberType); return Base::WriteUint(u); } bool Int64(int64_t i64) { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); } bool Uint64(uint64_t u64) { PrettyPrefix(kNumberType); return Base::WriteUint64(u64); } bool Double(double d) { PrettyPrefix(kNumberType); return Base::WriteDouble(d); } bool RawNumber(const Ch* str, SizeType length, bool copy = false) { RAPIDJSON_ASSERT(str != 0); (void)copy; PrettyPrefix(kNumberType); return Base::WriteString(str, length); } bool String(const Ch* str, SizeType length, bool copy = false) { RAPIDJSON_ASSERT(str != 0); (void)copy; PrettyPrefix(kStringType); return Base::WriteString(str, length); } #if RAPIDJSON_HAS_STDSTRING bool String(const std::basic_string& str) { return String(str.data(), SizeType(str.size())); } #endif bool StartObject() { PrettyPrefix(kObjectType); new (Base::level_stack_.template Push()) typename Base::Level(false); return Base::WriteStartObject(); } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } #if RAPIDJSON_HAS_STDSTRING bool Key(const std::basic_string& str) { return Key(str.data(), SizeType(str.size())); } #endif bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); // not inside an Object RAPIDJSON_ASSERT(!Base::level_stack_.template Top()->inArray); // currently inside an Array, not Object RAPIDJSON_ASSERT(0 == Base::level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty) { Base::os_->Put('\n'); WriteIndent(); } bool ret = Base::WriteEndObject(); (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text Base::Flush(); return true; } bool StartArray() { PrettyPrefix(kArrayType); new (Base::level_stack_.template Push()) typename Base::Level(true); return Base::WriteStartArray(); } bool EndArray(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level)); RAPIDJSON_ASSERT(Base::level_stack_.template Top()->inArray); bool empty = Base::level_stack_.template Pop(1)->valueCount == 0; if (!empty && !(formatOptions_ & kFormatSingleLineArray)) { Base::os_->Put('\n'); WriteIndent(); } bool ret = Base::WriteEndArray(); (void)ret; RAPIDJSON_ASSERT(ret == true); if (Base::level_stack_.Empty()) // end of json text Base::Flush(); return true; } //@} /*! @name Convenience extensions */ //@{ //! Simpler but slower overload. bool String(const Ch* str) { return String(str, internal::StrLen(str)); } bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); } //@} //! Write a raw JSON value. /*! For user to write a stringified JSON as a value. \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. \param length Length of the json. \param type Type of the root of json. \note When using PrettyWriter::RawValue(), the result json may not be indented correctly. */ bool RawValue(const Ch* json, size_t length, Type type) { RAPIDJSON_ASSERT(json != 0); PrettyPrefix(type); return Base::WriteRawValue(json, length); } protected: void PrettyPrefix(Type type) { (void)type; if (Base::level_stack_.GetSize() != 0) { // this value is not at root typename Base::Level* level = Base::level_stack_.template Top(); if (level->inArray) { if (level->valueCount > 0) { Base::os_->Put(','); // add comma if it is not the first element in array if (formatOptions_ & kFormatSingleLineArray) Base::os_->Put(' '); } if (!(formatOptions_ & kFormatSingleLineArray)) { Base::os_->Put('\n'); WriteIndent(); } } else { // in object if (level->valueCount > 0) { if (level->valueCount % 2 == 0) { Base::os_->Put(','); Base::os_->Put('\n'); } else { Base::os_->Put(':'); Base::os_->Put(' '); } } else Base::os_->Put('\n'); if (level->valueCount % 2 == 0) WriteIndent(); } if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else { RAPIDJSON_ASSERT(!Base::hasRoot_); // Should only has one and only one root. Base::hasRoot_ = true; } } void WriteIndent() { size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_; PutN(*Base::os_, static_cast(indentChar_), count); } Ch indentChar_; unsigned indentCharCount_; PrettyFormatOptions formatOptions_; private: // Prohibit copy constructor & assignment operator. PrettyWriter(const PrettyWriter&); PrettyWriter& operator=(const PrettyWriter&); }; RAPIDJSON_NAMESPACE_END #if defined(__clang__) RAPIDJSON_DIAG_POP #endif #ifdef __GNUC__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_RAPIDJSON_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/error/0000755002537200234200000000000013213503245023452 5ustar zmoelnigiemusersassimp-4.1.0/contrib/rapidjson/include/rapidjson/error/error.h0000644002537200234200000001410513213503245024755 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_ERROR_ERROR_H_ #define RAPIDJSON_ERROR_ERROR_H_ #include "../rapidjson.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) #endif /*! \file error.h */ /*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */ /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ERROR_CHARTYPE //! Character type of error messages. /*! \ingroup RAPIDJSON_ERRORS The default character type is \c char. On Windows, user can define this macro as \c TCHAR for supporting both unicode/non-unicode settings. */ #ifndef RAPIDJSON_ERROR_CHARTYPE #define RAPIDJSON_ERROR_CHARTYPE char #endif /////////////////////////////////////////////////////////////////////////////// // RAPIDJSON_ERROR_STRING //! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[]. /*! \ingroup RAPIDJSON_ERRORS By default this conversion macro does nothing. On Windows, user can define this macro as \c _T(x) for supporting both unicode/non-unicode settings. */ #ifndef RAPIDJSON_ERROR_STRING #define RAPIDJSON_ERROR_STRING(x) x #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // ParseErrorCode //! Error code of parsing. /*! \ingroup RAPIDJSON_ERRORS \see GenericReader::Parse, GenericReader::GetParseErrorCode */ enum ParseErrorCode { kParseErrorNone = 0, //!< No error. kParseErrorDocumentEmpty, //!< The document is empty. kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values. kParseErrorValueInvalid, //!< Invalid value. kParseErrorObjectMissName, //!< Missing a name for object member. kParseErrorObjectMissColon, //!< Missing a colon after a name of object member. kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member. kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element. kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string. kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid. kParseErrorStringEscapeInvalid, //!< Invalid escape character in string. kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string. kParseErrorStringInvalidEncoding, //!< Invalid encoding in string. kParseErrorNumberTooBig, //!< Number too big to be stored in double. kParseErrorNumberMissFraction, //!< Miss fraction part in number. kParseErrorNumberMissExponent, //!< Miss exponent in number. kParseErrorTermination, //!< Parsing was terminated. kParseErrorUnspecificSyntaxError //!< Unspecific syntax error. }; //! Result of parsing (wraps ParseErrorCode) /*! \ingroup RAPIDJSON_ERRORS \code Document doc; ParseResult ok = doc.Parse("[42]"); if (!ok) { fprintf(stderr, "JSON parse error: %s (%u)", GetParseError_En(ok.Code()), ok.Offset()); exit(EXIT_FAILURE); } \endcode \see GenericReader::Parse, GenericDocument::Parse */ struct ParseResult { //!! Unspecified boolean type typedef bool (ParseResult::*BooleanType)() const; public: //! Default constructor, no error. ParseResult() : code_(kParseErrorNone), offset_(0) {} //! Constructor to set an error. ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {} //! Get the error code. ParseErrorCode Code() const { return code_; } //! Get the error offset, if \ref IsError(), 0 otherwise. size_t Offset() const { return offset_; } //! Explicit conversion to \c bool, returns \c true, iff !\ref IsError(). operator BooleanType() const { return !IsError() ? &ParseResult::IsError : NULL; } //! Whether the result is an error. bool IsError() const { return code_ != kParseErrorNone; } bool operator==(const ParseResult& that) const { return code_ == that.code_; } bool operator==(ParseErrorCode code) const { return code_ == code; } friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; } bool operator!=(const ParseResult& that) const { return !(*this == that); } bool operator!=(ParseErrorCode code) const { return !(*this == code); } friend bool operator!=(ParseErrorCode code, const ParseResult & err) { return err != code; } //! Reset error code. void Clear() { Set(kParseErrorNone); } //! Update error code and offset. void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; } private: ParseErrorCode code_; size_t offset_; }; //! Function pointer type of GetParseError(). /*! \ingroup RAPIDJSON_ERRORS This is the prototype for \c GetParseError_X(), where \c X is a locale. User can dynamically change locale in runtime, e.g.: \code GetParseErrorFunc GetParseError = GetParseError_En; // or whatever const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode()); \endcode */ typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode); RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_ERROR_ERROR_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/error/en.h0000644002537200234200000000743613213503245024237 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_ERROR_EN_H_ #define RAPIDJSON_ERROR_EN_H_ #include "error.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(switch-enum) RAPIDJSON_DIAG_OFF(covered-switch-default) #endif RAPIDJSON_NAMESPACE_BEGIN //! Maps error code of parsing into error message. /*! \ingroup RAPIDJSON_ERRORS \param parseErrorCode Error code obtained in parsing. \return the error message. \note User can make a copy of this function for localization. Using switch-case is safer for future modification of error codes. */ inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) { switch (parseErrorCode) { case kParseErrorNone: return RAPIDJSON_ERROR_STRING("No error."); case kParseErrorDocumentEmpty: return RAPIDJSON_ERROR_STRING("The document is empty."); case kParseErrorDocumentRootNotSingular: return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values."); case kParseErrorValueInvalid: return RAPIDJSON_ERROR_STRING("Invalid value."); case kParseErrorObjectMissName: return RAPIDJSON_ERROR_STRING("Missing a name for object member."); case kParseErrorObjectMissColon: return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member."); case kParseErrorObjectMissCommaOrCurlyBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member."); case kParseErrorArrayMissCommaOrSquareBracket: return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element."); case kParseErrorStringUnicodeEscapeInvalidHex: return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string."); case kParseErrorStringUnicodeSurrogateInvalid: return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid."); case kParseErrorStringEscapeInvalid: return RAPIDJSON_ERROR_STRING("Invalid escape character in string."); case kParseErrorStringMissQuotationMark: return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string."); case kParseErrorStringInvalidEncoding: return RAPIDJSON_ERROR_STRING("Invalid encoding in string."); case kParseErrorNumberTooBig: return RAPIDJSON_ERROR_STRING("Number too big to be stored in double."); case kParseErrorNumberMissFraction: return RAPIDJSON_ERROR_STRING("Miss fraction part in number."); case kParseErrorNumberMissExponent: return RAPIDJSON_ERROR_STRING("Miss exponent in number."); case kParseErrorTermination: return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error."); case kParseErrorUnspecificSyntaxError: return RAPIDJSON_ERROR_STRING("Unspecific syntax error."); default: return RAPIDJSON_ERROR_STRING("Unknown error."); } } RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_ERROR_EN_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/memorystream.h0000644002537200234200000000515313213503245025222 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_MEMORYSTREAM_H_ #define RAPIDJSON_MEMORYSTREAM_H_ #include "stream.h" #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(missing-noreturn) #endif RAPIDJSON_NAMESPACE_BEGIN //! Represents an in-memory input byte stream. /*! This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream. It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file. Differences between MemoryStream and StringStream: 1. StringStream has encoding but MemoryStream is a byte stream. 2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source. 3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4(). \note implements Stream concept */ struct MemoryStream { typedef char Ch; // byte MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {} Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; } Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; } size_t Tell() const { return static_cast(src_ - begin_); } Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } void Put(Ch) { RAPIDJSON_ASSERT(false); } void Flush() { RAPIDJSON_ASSERT(false); } size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; } // For encoding detection only. const Ch* Peek4() const { return Tell() + 4 <= size_ ? src_ : 0; } const Ch* src_; //!< Current read position. const Ch* begin_; //!< Original head of the string. const Ch* end_; //!< End of stream. size_t size_; //!< Size of the stream. }; RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_MEMORYBUFFER_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/writer.h0000644002537200234200000006374313213503245024023 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_WRITER_H_ #define RAPIDJSON_WRITER_H_ #include "stream.h" #include "internal/meta.h" #include "internal/stack.h" #include "internal/strfunc.h" #include "internal/dtoa.h" #include "internal/itoa.h" #include "stringbuffer.h" #include // placement new #if defined(RAPIDJSON_SIMD) && defined(_MSC_VER) #include #pragma intrinsic(_BitScanForward) #endif #ifdef RAPIDJSON_SSE42 #include #elif defined(RAPIDJSON_SSE2) #include #elif defined(RAPIDJSON_NEON) #include #endif #ifdef _MSC_VER RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant #endif #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(padded) RAPIDJSON_DIAG_OFF(unreachable-code) RAPIDJSON_DIAG_OFF(c++98-compat) #endif RAPIDJSON_NAMESPACE_BEGIN /////////////////////////////////////////////////////////////////////////////// // WriteFlag /*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS \ingroup RAPIDJSON_CONFIG \brief User-defined kWriteDefaultFlags definition. User can define this as any \c WriteFlag combinations. */ #ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS #define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags #endif //! Combination of writeFlags enum WriteFlag { kWriteNoFlags = 0, //!< No flags are set. kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings. kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN. kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS }; //! JSON writer /*! Writer implements the concept Handler. It generates JSON text by events to an output os. User may programmatically calls the functions of a writer to generate JSON text. On the other side, a writer can also be passed to objects that generates events, for example Reader::Parse() and Document::Accept(). \tparam OutputStream Type of output stream. \tparam SourceEncoding Encoding of source string. \tparam TargetEncoding Encoding of output stream. \tparam StackAllocator Type of allocator for allocating memory of stack. \note implements Handler concept */ template, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags> class Writer { public: typedef typename SourceEncoding::Ch Ch; static const int kDefaultMaxDecimalPlaces = 324; //! Constructor /*! \param os Output stream. \param stackAllocator User supplied allocator. If it is null, it will create a private one. \param levelDepth Initial capacity of stack. */ explicit Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} explicit Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) : os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {} #if RAPIDJSON_HAS_CXX11_RVALUE_REFS Writer(Writer&& rhs) : os_(rhs.os_), level_stack_(std::move(rhs.level_stack_)), maxDecimalPlaces_(rhs.maxDecimalPlaces_), hasRoot_(rhs.hasRoot_) { rhs.os_ = 0; } #endif //! Reset the writer with a new stream. /*! This function reset the writer with a new stream and default settings, in order to make a Writer object reusable for output multiple JSONs. \param os New output stream. \code Writer writer(os1); writer.StartObject(); // ... writer.EndObject(); writer.Reset(os2); writer.StartObject(); // ... writer.EndObject(); \endcode */ void Reset(OutputStream& os) { os_ = &os; hasRoot_ = false; level_stack_.Clear(); } //! Checks whether the output is a complete JSON. /*! A complete JSON has a complete root object or array. */ bool IsComplete() const { return hasRoot_ && level_stack_.Empty(); } int GetMaxDecimalPlaces() const { return maxDecimalPlaces_; } //! Sets the maximum number of decimal places for double output. /*! This setting truncates the output with specified number of decimal places. For example, \code writer.SetMaxDecimalPlaces(3); writer.StartArray(); writer.Double(0.12345); // "0.123" writer.Double(0.0001); // "0.0" writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent) writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent) writer.EndArray(); \endcode The default setting does not truncate any decimal places. You can restore to this setting by calling \code writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces); \endcode */ void SetMaxDecimalPlaces(int maxDecimalPlaces) { maxDecimalPlaces_ = maxDecimalPlaces; } /*!@name Implementation of Handler \see Handler */ //@{ bool Null() { Prefix(kNullType); return EndValue(WriteNull()); } bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); } bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); } bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); } bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); } bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); } //! Writes the given \c double value to the stream /*! \param d The value to be written. \return Whether it is succeed. */ bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); } bool RawNumber(const Ch* str, SizeType length, bool copy = false) { RAPIDJSON_ASSERT(str != 0); (void)copy; Prefix(kNumberType); return EndValue(WriteString(str, length)); } bool String(const Ch* str, SizeType length, bool copy = false) { RAPIDJSON_ASSERT(str != 0); (void)copy; Prefix(kStringType); return EndValue(WriteString(str, length)); } #if RAPIDJSON_HAS_STDSTRING bool String(const std::basic_string& str) { return String(str.data(), SizeType(str.size())); } #endif bool StartObject() { Prefix(kObjectType); new (level_stack_.template Push()) Level(false); return WriteStartObject(); } bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); } #if RAPIDJSON_HAS_STDSTRING bool Key(const std::basic_string& str) { return Key(str.data(), SizeType(str.size())); } #endif bool EndObject(SizeType memberCount = 0) { (void)memberCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); // not inside an Object RAPIDJSON_ASSERT(!level_stack_.template Top()->inArray); // currently inside an Array, not Object RAPIDJSON_ASSERT(0 == level_stack_.template Top()->valueCount % 2); // Object has a Key without a Value level_stack_.template Pop(1); return EndValue(WriteEndObject()); } bool StartArray() { Prefix(kArrayType); new (level_stack_.template Push()) Level(true); return WriteStartArray(); } bool EndArray(SizeType elementCount = 0) { (void)elementCount; RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level)); RAPIDJSON_ASSERT(level_stack_.template Top()->inArray); level_stack_.template Pop(1); return EndValue(WriteEndArray()); } //@} /*! @name Convenience extensions */ //@{ //! Simpler but slower overload. bool String(const Ch* const& str) { return String(str, internal::StrLen(str)); } bool Key(const Ch* const& str) { return Key(str, internal::StrLen(str)); } //@} //! Write a raw JSON value. /*! For user to write a stringified JSON as a value. \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range. \param length Length of the json. \param type Type of the root of json. */ bool RawValue(const Ch* json, size_t length, Type type) { RAPIDJSON_ASSERT(json != 0); Prefix(type); return EndValue(WriteRawValue(json, length)); } //! Flush the output stream. /*! Allows the user to flush the output stream immediately. */ void Flush() { os_->Flush(); } protected: //! Information for each nested level struct Level { Level(bool inArray_) : valueCount(0), inArray(inArray_) {} size_t valueCount; //!< number of values in this level bool inArray; //!< true if in array, otherwise in object }; static const size_t kDefaultLevelDepth = 32; bool WriteNull() { PutReserve(*os_, 4); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true; } bool WriteBool(bool b) { if (b) { PutReserve(*os_, 4); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e'); } else { PutReserve(*os_, 5); PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e'); } return true; } bool WriteInt(int i) { char buffer[11]; const char* end = internal::i32toa(i, buffer); PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteUint(unsigned u) { char buffer[10]; const char* end = internal::u32toa(u, buffer); PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteInt64(int64_t i64) { char buffer[21]; const char* end = internal::i64toa(i64, buffer); PutReserve(*os_, static_cast(end - buffer)); for (const char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteUint64(uint64_t u64) { char buffer[20]; char* end = internal::u64toa(u64, buffer); PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteDouble(double d) { if (internal::Double(d).IsNanOrInf()) { if (!(writeFlags & kWriteNanAndInfFlag)) return false; if (internal::Double(d).IsNan()) { PutReserve(*os_, 3); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); return true; } if (internal::Double(d).Sign()) { PutReserve(*os_, 9); PutUnsafe(*os_, '-'); } else PutReserve(*os_, 8); PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); return true; } char buffer[25]; char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); PutReserve(*os_, static_cast(end - buffer)); for (char* p = buffer; p != end; ++p) PutUnsafe(*os_, static_cast(*p)); return true; } bool WriteString(const Ch* str, SizeType length) { static const typename OutputStream::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; static const char escape[256] = { #define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 //0 1 2 3 4 5 6 7 8 9 A B C D E F 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20 Z16, Z16, // 30~4F 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50 Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF #undef Z16 }; if (TargetEncoding::supportUnicode) PutReserve(*os_, 2 + length * 6); // "\uxxxx..." else PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." PutUnsafe(*os_, '\"'); GenericStringStream is(str); while (ScanWriteUnescapedString(is, length)) { const Ch c = is.Peek(); if (!TargetEncoding::supportUnicode && static_cast(c) >= 0x80) { // Unicode escaping unsigned codepoint; if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint))) return false; PutUnsafe(*os_, '\\'); PutUnsafe(*os_, 'u'); if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) { PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]); PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]); PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]); PutUnsafe(*os_, hexDigits[(codepoint ) & 15]); } else { RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF); // Surrogate pair unsigned s = codepoint - 0x010000; unsigned lead = (s >> 10) + 0xD800; unsigned trail = (s & 0x3FF) + 0xDC00; PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]); PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]); PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]); PutUnsafe(*os_, hexDigits[(lead ) & 15]); PutUnsafe(*os_, '\\'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]); PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]); PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]); PutUnsafe(*os_, hexDigits[(trail ) & 15]); } } else if ((sizeof(Ch) == 1 || static_cast(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast(c)])) { is.Take(); PutUnsafe(*os_, '\\'); PutUnsafe(*os_, static_cast(escape[static_cast(c)])); if (escape[static_cast(c)] == 'u') { PutUnsafe(*os_, '0'); PutUnsafe(*os_, '0'); PutUnsafe(*os_, hexDigits[static_cast(c) >> 4]); PutUnsafe(*os_, hexDigits[static_cast(c) & 0xF]); } } else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? Transcoder::Validate(is, *os_) : Transcoder::TranscodeUnsafe(is, *os_)))) return false; } PutUnsafe(*os_, '\"'); return true; } bool ScanWriteUnescapedString(GenericStringStream& is, size_t length) { return RAPIDJSON_LIKELY(is.Tell() < length); } bool WriteStartObject() { os_->Put('{'); return true; } bool WriteEndObject() { os_->Put('}'); return true; } bool WriteStartArray() { os_->Put('['); return true; } bool WriteEndArray() { os_->Put(']'); return true; } bool WriteRawValue(const Ch* json, size_t length) { PutReserve(*os_, length); for (size_t i = 0; i < length; i++) { RAPIDJSON_ASSERT(json[i] != '\0'); PutUnsafe(*os_, json[i]); } return true; } void Prefix(Type type) { (void)type; if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root Level* level = level_stack_.template Top(); if (level->valueCount > 0) { if (level->inArray) os_->Put(','); // add comma if it is not the first element in array else // in object os_->Put((level->valueCount % 2 == 0) ? ',' : ':'); } if (!level->inArray && level->valueCount % 2 == 0) RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name level->valueCount++; } else { RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root. hasRoot_ = true; } } // Flush the value if it is the top level one. bool EndValue(bool ret) { if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text Flush(); return ret; } OutputStream* os_; internal::Stack level_stack_; int maxDecimalPlaces_; bool hasRoot_; private: // Prohibit copy constructor & assignment operator. Writer(const Writer&); Writer& operator=(const Writer&); }; // Full specialization for StringStream to prevent memory copying template<> inline bool Writer::WriteInt(int i) { char *buffer = os_->Push(11); const char* end = internal::i32toa(i, buffer); os_->Pop(static_cast(11 - (end - buffer))); return true; } template<> inline bool Writer::WriteUint(unsigned u) { char *buffer = os_->Push(10); const char* end = internal::u32toa(u, buffer); os_->Pop(static_cast(10 - (end - buffer))); return true; } template<> inline bool Writer::WriteInt64(int64_t i64) { char *buffer = os_->Push(21); const char* end = internal::i64toa(i64, buffer); os_->Pop(static_cast(21 - (end - buffer))); return true; } template<> inline bool Writer::WriteUint64(uint64_t u) { char *buffer = os_->Push(20); const char* end = internal::u64toa(u, buffer); os_->Pop(static_cast(20 - (end - buffer))); return true; } template<> inline bool Writer::WriteDouble(double d) { if (internal::Double(d).IsNanOrInf()) { // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag). if (!(kWriteDefaultFlags & kWriteNanAndInfFlag)) return false; if (internal::Double(d).IsNan()) { PutReserve(*os_, 3); PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N'); return true; } if (internal::Double(d).Sign()) { PutReserve(*os_, 9); PutUnsafe(*os_, '-'); } else PutReserve(*os_, 8); PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y'); return true; } char *buffer = os_->Push(25); char* end = internal::dtoa(d, buffer, maxDecimalPlaces_); os_->Pop(static_cast(25 - (end - buffer))); return true; } #if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) template<> inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { if (length < 16) return RAPIDJSON_LIKELY(is.Tell() < length); if (!RAPIDJSON_LIKELY(is.Tell() < length)) return false; const char* p = is.src_; const char* end = is.head_ + length; const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); if (nextAligned > end) return true; while (p != nextAligned) if (*p < 0x20 || *p == '\"' || *p == '\\') { is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } else os_->PutUnsafe(*p++); // The rest of string using SIMD static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' }; static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' }; static const char space[16] = { 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F, 0x1F }; const __m128i dq = _mm_loadu_si128(reinterpret_cast(&dquote[0])); const __m128i bs = _mm_loadu_si128(reinterpret_cast(&bslash[0])); const __m128i sp = _mm_loadu_si128(reinterpret_cast(&space[0])); for (; p != endAligned; p += 16) { const __m128i s = _mm_load_si128(reinterpret_cast(p)); const __m128i t1 = _mm_cmpeq_epi8(s, dq); const __m128i t2 = _mm_cmpeq_epi8(s, bs); const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x1F) == 0x1F const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3); unsigned short r = static_cast(_mm_movemask_epi8(x)); if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped SizeType len; #ifdef _MSC_VER // Find the index of first escaped unsigned long offset; _BitScanForward(&offset, r); len = offset; #else len = static_cast(__builtin_ffs(r) - 1); #endif char* q = reinterpret_cast(os_->PushUnsafe(len)); for (size_t i = 0; i < len; i++) q[i] = p[i]; p += len; break; } _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s); } is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } #elif defined(RAPIDJSON_NEON) template<> inline bool Writer::ScanWriteUnescapedString(StringStream& is, size_t length) { if (length < 16) return RAPIDJSON_LIKELY(is.Tell() < length); if (!RAPIDJSON_LIKELY(is.Tell() < length)) return false; const char* p = is.src_; const char* end = is.head_ + length; const char* nextAligned = reinterpret_cast((reinterpret_cast(p) + 15) & static_cast(~15)); const char* endAligned = reinterpret_cast(reinterpret_cast(end) & static_cast(~15)); if (nextAligned > end) return true; while (p != nextAligned) if (*p < 0x20 || *p == '\"' || *p == '\\') { is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } else os_->PutUnsafe(*p++); // The rest of string using SIMD const uint8x16_t s0 = vmovq_n_u8('"'); const uint8x16_t s1 = vmovq_n_u8('\\'); const uint8x16_t s2 = vmovq_n_u8('\b'); const uint8x16_t s3 = vmovq_n_u8(32); for (; p != endAligned; p += 16) { const uint8x16_t s = vld1q_u8(reinterpret_cast(p)); uint8x16_t x = vceqq_u8(s, s0); x = vorrq_u8(x, vceqq_u8(s, s1)); x = vorrq_u8(x, vceqq_u8(s, s2)); x = vorrq_u8(x, vcltq_u8(s, s3)); x = vrev64q_u8(x); // Rev in 64 uint64_t low = vgetq_lane_u64(reinterpret_cast(x), 0); // extract uint64_t high = vgetq_lane_u64(reinterpret_cast(x), 1); // extract SizeType len = 0; bool escaped = false; if (low == 0) { if (high != 0) { unsigned lz = (unsigned)__builtin_clzll(high); len = 8 + (lz >> 3); escaped = true; } } else { unsigned lz = (unsigned)__builtin_clzll(low); len = lz >> 3; escaped = true; } if (RAPIDJSON_UNLIKELY(escaped)) { // some of characters is escaped char* q = reinterpret_cast(os_->PushUnsafe(len)); for (size_t i = 0; i < len; i++) q[i] = p[i]; p += len; break; } vst1q_u8(reinterpret_cast(os_->PushUnsafe(16)), s); } is.src_ = p; return RAPIDJSON_LIKELY(is.Tell() < length); } #endif // RAPIDJSON_NEON RAPIDJSON_NAMESPACE_END #ifdef _MSC_VER RAPIDJSON_DIAG_POP #endif #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_RAPIDJSON_H_ assimp-4.1.0/contrib/rapidjson/include/rapidjson/filewritestream.h0000644002537200234200000000610313213503245025700 0ustar zmoelnigiemusers// Tencent is pleased to support the open source community by making RapidJSON available. // // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. // // Licensed under the MIT License (the "License"); you may not use this file except // in compliance with the License. You may obtain a copy of the License at // // http://opensource.org/licenses/MIT // // 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. #ifndef RAPIDJSON_FILEWRITESTREAM_H_ #define RAPIDJSON_FILEWRITESTREAM_H_ #include "stream.h" #include #ifdef __clang__ RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_OFF(unreachable-code) #endif RAPIDJSON_NAMESPACE_BEGIN //! Wrapper of C file stream for input using fread(). /*! \note implements Stream concept */ class FileWriteStream { public: typedef char Ch; //!< Character type. Only support char. FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { RAPIDJSON_ASSERT(fp_ != 0); } void Put(char c) { if (current_ >= bufferEnd_) Flush(); *current_++ = c; } void PutN(char c, size_t n) { size_t avail = static_cast(bufferEnd_ - current_); while (n > avail) { std::memset(current_, c, avail); current_ += avail; Flush(); n -= avail; avail = static_cast(bufferEnd_ - current_); } if (n > 0) { std::memset(current_, c, n); current_ += n; } } void Flush() { if (current_ != buffer_) { size_t result = fwrite(buffer_, 1, static_cast(current_ - buffer_), fp_); if (result < static_cast(current_ - buffer_)) { // failure deliberately ignored at this time // added to avoid warn_unused_result build errors } current_ = buffer_; } } // Not implemented char Peek() const { RAPIDJSON_ASSERT(false); return 0; } char Take() { RAPIDJSON_ASSERT(false); return 0; } size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; } char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; } size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; } private: // Prohibit copy constructor & assignment operator. FileWriteStream(const FileWriteStream&); FileWriteStream& operator=(const FileWriteStream&); std::FILE* fp_; char *buffer_; char *bufferEnd_; char *current_; }; //! Implement specialized version of PutN() with memset() for better performance. template<> inline void PutN(FileWriteStream& stream, char c, size_t n) { stream.PutN(c, n); } RAPIDJSON_NAMESPACE_END #ifdef __clang__ RAPIDJSON_DIAG_POP #endif #endif // RAPIDJSON_FILESTREAM_H_ assimp-4.1.0/contrib/rapidjson/license.txt0000644002537200234200000001204013213503245021065 0ustar zmoelnigiemusersTencent is pleased to support the open source community by making RapidJSON available. Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. If you have downloaded a copy of the RapidJSON binary from Tencent, please note that the RapidJSON binary is licensed under the MIT License. If you have downloaded a copy of the RapidJSON source code from Tencent, please note that RapidJSON source code is licensed under the MIT License, except for the third-party components listed below which are subject to different license terms. Your integration of RapidJSON into your own projects may require compliance with the MIT License, as well as the other licenses applicable to the third-party components included within RapidJSON. To avoid the problematic JSON license in your own projects, it's sufficient to exclude the bin/jsonchecker/ directory, as it's the only code under the JSON license. A copy of the MIT License is included in this file. Other dependencies and licenses: Open Source Software Licensed Under the BSD License: -------------------------------------------------------------------- The msinttypes r29 Copyright (c) 2006-2013 Alexander Chemeris 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 copyright holder 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 REGENTS 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 REGENTS AND 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. Open Source Software Licensed Under the JSON License: -------------------------------------------------------------------- json.org Copyright (c) 2002 JSON.org All Rights Reserved. JSON_checker Copyright (c) 2002 JSON.org All Rights Reserved. Terms of the JSON License: --------------------------------------------------- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. The Software shall be used for Good, not Evil. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Terms of the MIT License: -------------------------------------------------------------------- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. assimp-4.1.0/contrib/android-cmake/0000755002537200234200000000000013213503245017412 5ustar zmoelnigiemusersassimp-4.1.0/contrib/android-cmake/AndroidNdkGdb.cmake0000644002537200234200000001050413213503245023046 0ustar zmoelnigiemusers# Copyright (c) 2014, Pavel Rojtberg # 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. Neither the name of the copyright holder 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 HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # ------------------------------------------------------------------------------ # Usage: # 1. place AndroidNdkGdb.cmake somewhere inside ${CMAKE_MODULE_PATH} # 2. inside your project add # # include(AndroidNdkGdb) # android_ndk_gdb_enable() # # for each target # add_library(MyLibrary ...) # android_ndk_gdb_debuggable(MyLibrary) # add gdbserver and general gdb configuration to project # also create a mininal NDK skeleton so ndk-gdb finds the paths # # the optional parameter defines the path to the android project. # uses PROJECT_SOURCE_DIR by default. macro(android_ndk_gdb_enable) if(ANDROID) # create custom target that depends on the real target so it gets executed afterwards add_custom_target(NDK_GDB ALL) if(${ARGC}) set(ANDROID_PROJECT_DIR ${ARGV0}) else() set(ANDROID_PROJECT_DIR ${PROJECT_SOURCE_DIR}) endif() set(NDK_GDB_SOLIB_PATH ${ANDROID_PROJECT_DIR}/obj/local/${ANDROID_NDK_ABI_NAME}/) file(MAKE_DIRECTORY ${NDK_GDB_SOLIB_PATH}) # 1. generate essential Android Makefiles file(MAKE_DIRECTORY ${ANDROID_PROJECT_DIR}/jni) if(NOT EXISTS ${ANDROID_PROJECT_DIR}/jni/Android.mk) file(WRITE ${ANDROID_PROJECT_DIR}/jni/Android.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n") endif() if(NOT EXISTS ${ANDROID_PROJECT_DIR}/jni/Application.mk) file(WRITE ${ANDROID_PROJECT_DIR}/jni/Application.mk "APP_ABI := ${ANDROID_NDK_ABI_NAME}\n") endif() # 2. generate gdb.setup get_directory_property(PROJECT_INCLUDES DIRECTORY ${PROJECT_SOURCE_DIR} INCLUDE_DIRECTORIES) string(REGEX REPLACE ";" " " PROJECT_INCLUDES "${PROJECT_INCLUDES}") file(WRITE ${LIBRARY_OUTPUT_PATH}/gdb.setup "set solib-search-path ${NDK_GDB_SOLIB_PATH}\n") file(APPEND ${LIBRARY_OUTPUT_PATH}/gdb.setup "directory ${PROJECT_INCLUDES}\n") # 3. copy gdbserver executable file(COPY ${ANDROID_NDK}/prebuilt/android-${ANDROID_ARCH_NAME}/gdbserver/gdbserver DESTINATION ${LIBRARY_OUTPUT_PATH}) endif() endmacro() # register a target for remote debugging # copies the debug version to NDK_GDB_SOLIB_PATH then strips symbols of original macro(android_ndk_gdb_debuggable TARGET_NAME) if(ANDROID) get_property(TARGET_LOCATION TARGET ${TARGET_NAME} PROPERTY LOCATION) # create custom target that depends on the real target so it gets executed afterwards add_dependencies(NDK_GDB ${TARGET_NAME}) # 4. copy lib to obj add_custom_command(TARGET NDK_GDB POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different ${TARGET_LOCATION} ${NDK_GDB_SOLIB_PATH}) # 5. strip symbols add_custom_command(TARGET NDK_GDB POST_BUILD COMMAND ${CMAKE_STRIP} ${TARGET_LOCATION}) endif() endmacro() assimp-4.1.0/contrib/android-cmake/AndroidNdkModules.cmake0000644002537200234200000000526513213503245023772 0ustar zmoelnigiemusers# Copyright (c) 2014, Pavel Rojtberg # 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. Neither the name of the copyright holder 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 HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. macro(android_ndk_import_module_cpufeatures) if(ANDROID) include_directories(${ANDROID_NDK}/sources/android/cpufeatures) add_library(cpufeatures ${ANDROID_NDK}/sources/android/cpufeatures/cpu-features.c) target_link_libraries(cpufeatures dl) endif() endmacro() macro(android_ndk_import_module_native_app_glue) if(ANDROID) include_directories(${ANDROID_NDK}/sources/android/native_app_glue) add_library(native_app_glue ${ANDROID_NDK}/sources/android/native_app_glue/android_native_app_glue.c) target_link_libraries(native_app_glue log) endif() endmacro() macro(android_ndk_import_module_ndk_helper) if(ANDROID) android_ndk_import_module_cpufeatures() android_ndk_import_module_native_app_glue() include_directories(${ANDROID_NDK}/sources/android/ndk_helper) file(GLOB _NDK_HELPER_SRCS ${ANDROID_NDK}/sources/android/ndk_helper/*.cpp ${ANDROID_NDK}/sources/android/ndk_helper/gl3stub.c) add_library(ndk_helper ${_NDK_HELPER_SRCS}) target_link_libraries(ndk_helper log android EGL GLESv2 cpufeatures native_app_glue) unset(_NDK_HELPER_SRCS) endif() endmacro()assimp-4.1.0/contrib/android-cmake/android.toolchain.cmake0000644002537200234200000024065413213503245024026 0ustar zmoelnigiemusers# Copyright (c) 2010-2011, Ethan Rublee # Copyright (c) 2011-2014, Andrey Kamaev # 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. Neither the name of the copyright holder 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 HOLDER OR CONTRIBUTORS BE # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE # POSSIBILITY OF SUCH DAMAGE. # ------------------------------------------------------------------------------ # Android CMake toolchain file, for use with the Android NDK r5-r10d # Requires cmake 2.6.3 or newer (2.8.9 or newer is recommended). # See home page: https://github.com/taka-no-me/android-cmake # # Usage Linux: # $ export ANDROID_NDK=/absolute/path/to/the/android-ndk # $ mkdir build && cd build # $ cmake -DCMAKE_TOOLCHAIN_FILE=path/to/the/android.toolchain.cmake .. # $ make -j8 # # Usage Windows: # You need native port of make to build your project. # Android NDK r7 (and newer) already has make.exe on board. # For older NDK you have to install it separately. # For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm # # $ SET ANDROID_NDK=C:\absolute\path\to\the\android-ndk # $ mkdir build && cd build # $ cmake.exe -G"MinGW Makefiles" # -DCMAKE_TOOLCHAIN_FILE=path\to\the\android.toolchain.cmake # -DCMAKE_MAKE_PROGRAM="%ANDROID_NDK%\prebuilt\windows\bin\make.exe" .. # $ cmake.exe --build . # # # Options (can be set as cmake parameters: -D=): # ANDROID_NDK=/opt/android-ndk - path to the NDK root. # Can be set as environment variable. Can be set only at first cmake run. # # ANDROID_ABI=armeabi-v7a - specifies the target Application Binary # Interface (ABI). This option nearly matches to the APP_ABI variable # used by ndk-build tool from Android NDK. # # Possible targets are: # "armeabi" - ARMv5TE based CPU with software floating point operations # "armeabi-v7a" - ARMv7 based devices with hardware FPU instructions # this ABI target is used by default # "armeabi-v7a with NEON" - same as armeabi-v7a, but # sets NEON as floating-point unit # "armeabi-v7a with VFPV3" - same as armeabi-v7a, but # sets VFPV3 as floating-point unit (has 32 registers instead of 16) # "armeabi-v6 with VFP" - tuned for ARMv6 processors having VFP # "x86" - IA-32 instruction set # "mips" - MIPS32 instruction set # # 64-bit ABIs for NDK r10 and newer: # "arm64-v8a" - ARMv8 AArch64 instruction set # "x86_64" - Intel64 instruction set (r1) # "mips64" - MIPS64 instruction set (r6) # # ANDROID_NATIVE_API_LEVEL=android-8 - level of Android API compile for. # Option is read-only when standalone toolchain is used. # Note: building for "android-L" requires explicit configuration. # # ANDROID_TOOLCHAIN_NAME=arm-linux-androideabi-4.9 - the name of compiler # toolchain to be used. The list of possible values depends on the NDK # version. For NDK r10c the possible values are: # # * aarch64-linux-android-4.9 # * aarch64-linux-android-clang3.4 # * aarch64-linux-android-clang3.5 # * arm-linux-androideabi-4.6 # * arm-linux-androideabi-4.8 # * arm-linux-androideabi-4.9 (default) # * arm-linux-androideabi-clang3.4 # * arm-linux-androideabi-clang3.5 # * mips64el-linux-android-4.9 # * mips64el-linux-android-clang3.4 # * mips64el-linux-android-clang3.5 # * mipsel-linux-android-4.6 # * mipsel-linux-android-4.8 # * mipsel-linux-android-4.9 # * mipsel-linux-android-clang3.4 # * mipsel-linux-android-clang3.5 # * x86-4.6 # * x86-4.8 # * x86-4.9 # * x86-clang3.4 # * x86-clang3.5 # * x86_64-4.9 # * x86_64-clang3.4 # * x86_64-clang3.5 # # ANDROID_FORCE_ARM_BUILD=OFF - set ON to generate 32-bit ARM instructions # instead of Thumb. Is not available for "armeabi-v6 with VFP" # (is forced to be ON) ABI. # # ANDROID_NO_UNDEFINED=ON - set ON to show all undefined symbols as linker # errors even if they are not used. # # ANDROID_SO_UNDEFINED=OFF - set ON to allow undefined symbols in shared # libraries. Automatically turned for NDK r5x and r6x due to GLESv2 # problems. # # ANDROID_STL=gnustl_static - specify the runtime to use. # # Possible values are: # none -> Do not configure the runtime. # system -> Use the default minimal system C++ runtime library. # Implies -fno-rtti -fno-exceptions. # Is not available for standalone toolchain. # system_re -> Use the default minimal system C++ runtime library. # Implies -frtti -fexceptions. # Is not available for standalone toolchain. # gabi++_static -> Use the GAbi++ runtime as a static library. # Implies -frtti -fno-exceptions. # Available for NDK r7 and newer. # Is not available for standalone toolchain. # gabi++_shared -> Use the GAbi++ runtime as a shared library. # Implies -frtti -fno-exceptions. # Available for NDK r7 and newer. # Is not available for standalone toolchain. # stlport_static -> Use the STLport runtime as a static library. # Implies -fno-rtti -fno-exceptions for NDK before r7. # Implies -frtti -fno-exceptions for NDK r7 and newer. # Is not available for standalone toolchain. # stlport_shared -> Use the STLport runtime as a shared library. # Implies -fno-rtti -fno-exceptions for NDK before r7. # Implies -frtti -fno-exceptions for NDK r7 and newer. # Is not available for standalone toolchain. # gnustl_static -> Use the GNU STL as a static library. # Implies -frtti -fexceptions. # gnustl_shared -> Use the GNU STL as a shared library. # Implies -frtti -fno-exceptions. # Available for NDK r7b and newer. # Silently degrades to gnustl_static if not available. # # ANDROID_STL_FORCE_FEATURES=ON - turn rtti and exceptions support based on # chosen runtime. If disabled, then the user is responsible for settings # these options. # # What?: # android-cmake toolchain searches for NDK/toolchain in the following order: # ANDROID_NDK - cmake parameter # ANDROID_NDK - environment variable # ANDROID_STANDALONE_TOOLCHAIN - cmake parameter # ANDROID_STANDALONE_TOOLCHAIN - environment variable # ANDROID_NDK - default locations # ANDROID_STANDALONE_TOOLCHAIN - default locations # # Make sure to do the following in your scripts: # SET( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}" ) # SET( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}" ) # The flags will be prepopulated with critical flags, so don't loose them. # Also be aware that toolchain also sets configuration-specific compiler # flags and linker flags. # # ANDROID and BUILD_ANDROID will be set to true, you may test any of these # variables to make necessary Android-specific configuration changes. # # Also ARMEABI or ARMEABI_V7A or X86 or MIPS or ARM64_V8A or X86_64 or MIPS64 # will be set true, mutually exclusive. NEON option will be set true # if VFP is set to NEON. # # ------------------------------------------------------------------------------ cmake_minimum_required( VERSION 2.6.3 ) if( DEFINED CMAKE_CROSSCOMPILING ) # subsequent toolchain loading is not really needed return() endif() if( CMAKE_TOOLCHAIN_FILE ) # touch toolchain variable to suppress "unused variable" warning endif() # inherit settings in recursive loads get_property( _CMAKE_IN_TRY_COMPILE GLOBAL PROPERTY IN_TRY_COMPILE ) if( _CMAKE_IN_TRY_COMPILE ) include( "${CMAKE_CURRENT_SOURCE_DIR}/../android.toolchain.config.cmake" OPTIONAL ) endif() # this one is important if( CMAKE_VERSION VERSION_GREATER "3.0.99" ) set( CMAKE_SYSTEM_NAME Android ) else() set( CMAKE_SYSTEM_NAME Linux ) endif() # this one not so much set( CMAKE_SYSTEM_VERSION 1 ) # rpath makes low sense for Android set( CMAKE_SHARED_LIBRARY_RUNTIME_C_FLAG "" ) set( CMAKE_SKIP_RPATH TRUE CACHE BOOL "If set, runtime paths are not added when using shared libraries." ) # NDK search paths set( ANDROID_SUPPORTED_NDK_VERSIONS ${ANDROID_EXTRA_NDK_VERSIONS} -r10d -r10c -r10b -r10 -r9d -r9c -r9b -r9 -r8e -r8d -r8c -r8b -r8 -r7c -r7b -r7 -r6b -r6 -r5c -r5b -r5 "" ) if( NOT DEFINED ANDROID_NDK_SEARCH_PATHS ) if( CMAKE_HOST_WIN32 ) file( TO_CMAKE_PATH "$ENV{PROGRAMFILES}" ANDROID_NDK_SEARCH_PATHS ) set( ANDROID_NDK_SEARCH_PATHS "${ANDROID_NDK_SEARCH_PATHS}" "$ENV{SystemDrive}/NVPACK" ) else() file( TO_CMAKE_PATH "$ENV{HOME}" ANDROID_NDK_SEARCH_PATHS ) set( ANDROID_NDK_SEARCH_PATHS /opt "${ANDROID_NDK_SEARCH_PATHS}/NVPACK" ) endif() endif() if( NOT DEFINED ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH ) set( ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH /opt/android-toolchain ) endif() # known ABIs set( ANDROID_SUPPORTED_ABIS_arm "armeabi-v7a;armeabi;armeabi-v7a with NEON;armeabi-v7a with VFPV3;armeabi-v6 with VFP" ) set( ANDROID_SUPPORTED_ABIS_arm64 "arm64-v8a" ) set( ANDROID_SUPPORTED_ABIS_x86 "x86" ) set( ANDROID_SUPPORTED_ABIS_x86_64 "x86_64" ) set( ANDROID_SUPPORTED_ABIS_mips "mips" ) set( ANDROID_SUPPORTED_ABIS_mips64 "mips64" ) # API level defaults set( ANDROID_DEFAULT_NDK_API_LEVEL 8 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_arm64 21 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_x86 9 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_x86_64 21 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_mips 9 ) set( ANDROID_DEFAULT_NDK_API_LEVEL_mips64 21 ) macro( __LIST_FILTER listvar regex ) if( ${listvar} ) foreach( __val ${${listvar}} ) if( __val MATCHES "${regex}" ) list( REMOVE_ITEM ${listvar} "${__val}" ) endif() endforeach() endif() endmacro() macro( __INIT_VARIABLE var_name ) set( __test_path 0 ) foreach( __var ${ARGN} ) if( __var STREQUAL "PATH" ) set( __test_path 1 ) break() endif() endforeach() if( __test_path AND NOT EXISTS "${${var_name}}" ) unset( ${var_name} CACHE ) endif() if( " ${${var_name}}" STREQUAL " " ) set( __values 0 ) foreach( __var ${ARGN} ) if( __var STREQUAL "VALUES" ) set( __values 1 ) elseif( NOT __var STREQUAL "PATH" ) if( __var MATCHES "^ENV_.*$" ) string( REPLACE "ENV_" "" __var "${__var}" ) set( __value "$ENV{${__var}}" ) elseif( DEFINED ${__var} ) set( __value "${${__var}}" ) elseif( __values ) set( __value "${__var}" ) else() set( __value "" ) endif() if( NOT " ${__value}" STREQUAL " " AND (NOT __test_path OR EXISTS "${__value}") ) set( ${var_name} "${__value}" ) break() endif() endif() endforeach() unset( __value ) unset( __values ) endif() if( __test_path ) file( TO_CMAKE_PATH "${${var_name}}" ${var_name} ) endif() unset( __test_path ) endmacro() macro( __DETECT_NATIVE_API_LEVEL _var _path ) set( __ndkApiLevelRegex "^[\t ]*#define[\t ]+__ANDROID_API__[\t ]+([0-9]+)[\t ]*.*$" ) file( STRINGS ${_path} __apiFileContent REGEX "${__ndkApiLevelRegex}" ) if( NOT __apiFileContent ) message( SEND_ERROR "Could not get Android native API level. Probably you have specified invalid level value, or your copy of NDK/toolchain is broken." ) endif() string( REGEX REPLACE "${__ndkApiLevelRegex}" "\\1" ${_var} "${__apiFileContent}" ) unset( __apiFileContent ) unset( __ndkApiLevelRegex ) endmacro() macro( __DETECT_TOOLCHAIN_MACHINE_NAME _var _root ) if( EXISTS "${_root}" ) file( GLOB __gccExePath RELATIVE "${_root}/bin/" "${_root}/bin/*-gcc${TOOL_OS_SUFFIX}" ) __LIST_FILTER( __gccExePath "^[.].*" ) list( LENGTH __gccExePath __gccExePathsCount ) if( NOT __gccExePathsCount EQUAL 1 AND NOT _CMAKE_IN_TRY_COMPILE ) message( WARNING "Could not determine machine name for compiler from ${_root}" ) set( ${_var} "" ) else() get_filename_component( __gccExeName "${__gccExePath}" NAME_WE ) string( REPLACE "-gcc" "" ${_var} "${__gccExeName}" ) endif() unset( __gccExePath ) unset( __gccExePathsCount ) unset( __gccExeName ) else() set( ${_var} "" ) endif() endmacro() # fight against cygwin set( ANDROID_FORBID_SYGWIN TRUE CACHE BOOL "Prevent cmake from working under cygwin and using cygwin tools") mark_as_advanced( ANDROID_FORBID_SYGWIN ) if( ANDROID_FORBID_SYGWIN ) if( CYGWIN ) message( FATAL_ERROR "Android NDK and android-cmake toolchain are not welcome Cygwin. It is unlikely that this cmake toolchain will work under cygwin. But if you want to try then you can set cmake variable ANDROID_FORBID_SYGWIN to FALSE and rerun cmake." ) endif() if( CMAKE_HOST_WIN32 ) # remove cygwin from PATH set( __new_path "$ENV{PATH}") __LIST_FILTER( __new_path "cygwin" ) set(ENV{PATH} "${__new_path}") unset(__new_path) endif() endif() # detect current host platform if( NOT DEFINED ANDROID_NDK_HOST_X64 AND (CMAKE_HOST_SYSTEM_PROCESSOR MATCHES "amd64|x86_64|AMD64" OR CMAKE_HOST_APPLE) ) set( ANDROID_NDK_HOST_X64 1 CACHE BOOL "Try to use 64-bit compiler toolchain" ) mark_as_advanced( ANDROID_NDK_HOST_X64 ) endif() set( TOOL_OS_SUFFIX "" ) if( CMAKE_HOST_APPLE ) set( ANDROID_NDK_HOST_SYSTEM_NAME "darwin-x86_64" ) set( ANDROID_NDK_HOST_SYSTEM_NAME2 "darwin-x86" ) elseif( CMAKE_HOST_WIN32 ) set( ANDROID_NDK_HOST_SYSTEM_NAME "windows-x86_64" ) set( ANDROID_NDK_HOST_SYSTEM_NAME2 "windows" ) set( TOOL_OS_SUFFIX ".exe" ) elseif( CMAKE_HOST_UNIX ) set( ANDROID_NDK_HOST_SYSTEM_NAME "linux-x86_64" ) set( ANDROID_NDK_HOST_SYSTEM_NAME2 "linux-x86" ) else() message( FATAL_ERROR "Cross-compilation on your platform is not supported by this cmake toolchain" ) endif() if( NOT ANDROID_NDK_HOST_X64 ) set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) endif() # see if we have path to Android NDK if( NOT ANDROID_NDK AND NOT ANDROID_STANDALONE_TOOLCHAIN ) __INIT_VARIABLE( ANDROID_NDK PATH ENV_ANDROID_NDK ) endif() if( NOT ANDROID_NDK ) # see if we have path to Android standalone toolchain __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ENV_ANDROID_STANDALONE_TOOLCHAIN ) if( NOT ANDROID_STANDALONE_TOOLCHAIN ) #try to find Android NDK in one of the the default locations set( __ndkSearchPaths ) foreach( __ndkSearchPath ${ANDROID_NDK_SEARCH_PATHS} ) foreach( suffix ${ANDROID_SUPPORTED_NDK_VERSIONS} ) list( APPEND __ndkSearchPaths "${__ndkSearchPath}/android-ndk${suffix}" ) endforeach() endforeach() __INIT_VARIABLE( ANDROID_NDK PATH VALUES ${__ndkSearchPaths} ) unset( __ndkSearchPaths ) if( ANDROID_NDK ) message( STATUS "Using default path for Android NDK: ${ANDROID_NDK}" ) message( STATUS " If you prefer to use a different location, please define a cmake or environment variable: ANDROID_NDK" ) else() #try to find Android standalone toolchain in one of the the default locations __INIT_VARIABLE( ANDROID_STANDALONE_TOOLCHAIN PATH ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH ) if( ANDROID_STANDALONE_TOOLCHAIN ) message( STATUS "Using default path for standalone toolchain ${ANDROID_STANDALONE_TOOLCHAIN}" ) message( STATUS " If you prefer to use a different location, please define the variable: ANDROID_STANDALONE_TOOLCHAIN" ) endif( ANDROID_STANDALONE_TOOLCHAIN ) endif( ANDROID_NDK ) endif( NOT ANDROID_STANDALONE_TOOLCHAIN ) endif( NOT ANDROID_NDK ) # remember found paths if( ANDROID_NDK ) get_filename_component( ANDROID_NDK "${ANDROID_NDK}" ABSOLUTE ) set( ANDROID_NDK "${ANDROID_NDK}" CACHE INTERNAL "Path of the Android NDK" FORCE ) set( BUILD_WITH_ANDROID_NDK True ) if( EXISTS "${ANDROID_NDK}/RELEASE.TXT" ) file( STRINGS "${ANDROID_NDK}/RELEASE.TXT" ANDROID_NDK_RELEASE_FULL LIMIT_COUNT 1 REGEX "r[0-9]+[a-z]?" ) string( REGEX MATCH "r([0-9]+)([a-z]?)" ANDROID_NDK_RELEASE "${ANDROID_NDK_RELEASE_FULL}" ) else() set( ANDROID_NDK_RELEASE "r1x" ) set( ANDROID_NDK_RELEASE_FULL "unreleased" ) endif() string( REGEX REPLACE "r([0-9]+)([a-z]?)" "\\1*1000" ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE}" ) string( FIND " abcdefghijklmnopqastuvwxyz" "${CMAKE_MATCH_2}" __ndkReleaseLetterNum ) math( EXPR ANDROID_NDK_RELEASE_NUM "${ANDROID_NDK_RELEASE_NUM}+${__ndkReleaseLetterNum}" ) elseif( ANDROID_STANDALONE_TOOLCHAIN ) get_filename_component( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" ABSOLUTE ) # try to detect change if( CMAKE_AR ) string( LENGTH "${ANDROID_STANDALONE_TOOLCHAIN}" __length ) string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidStandaloneToolchainPreviousPath ) if( NOT __androidStandaloneToolchainPreviousPath STREQUAL ANDROID_STANDALONE_TOOLCHAIN ) message( FATAL_ERROR "It is not possible to change path to the Android standalone toolchain on subsequent run." ) endif() unset( __androidStandaloneToolchainPreviousPath ) unset( __length ) endif() set( ANDROID_STANDALONE_TOOLCHAIN "${ANDROID_STANDALONE_TOOLCHAIN}" CACHE INTERNAL "Path of the Android standalone toolchain" FORCE ) set( BUILD_WITH_STANDALONE_TOOLCHAIN True ) else() list(GET ANDROID_NDK_SEARCH_PATHS 0 ANDROID_NDK_SEARCH_PATH) message( FATAL_ERROR "Could not find neither Android NDK nor Android standalone toolchain. You should either set an environment variable: export ANDROID_NDK=~/my-android-ndk or export ANDROID_STANDALONE_TOOLCHAIN=~/my-android-toolchain or put the toolchain or NDK in the default path: sudo ln -s ~/my-android-ndk ${ANDROID_NDK_SEARCH_PATH}/android-ndk sudo ln -s ~/my-android-toolchain ${ANDROID_STANDALONE_TOOLCHAIN_SEARCH_PATH}" ) endif() # android NDK layout if( BUILD_WITH_ANDROID_NDK ) if( NOT DEFINED ANDROID_NDK_LAYOUT ) # try to automatically detect the layout if( EXISTS "${ANDROID_NDK}/RELEASE.TXT") set( ANDROID_NDK_LAYOUT "RELEASE" ) elseif( EXISTS "${ANDROID_NDK}/../../linux-x86/toolchain/" ) set( ANDROID_NDK_LAYOUT "LINARO" ) elseif( EXISTS "${ANDROID_NDK}/../../gcc/" ) set( ANDROID_NDK_LAYOUT "ANDROID" ) endif() endif() set( ANDROID_NDK_LAYOUT "${ANDROID_NDK_LAYOUT}" CACHE STRING "The inner layout of NDK" ) mark_as_advanced( ANDROID_NDK_LAYOUT ) if( ANDROID_NDK_LAYOUT STREQUAL "LINARO" ) set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../${ANDROID_NDK_HOST_SYSTEM_NAME}/toolchain" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) elseif( ANDROID_NDK_LAYOUT STREQUAL "ANDROID" ) set( ANDROID_NDK_HOST_SYSTEM_NAME ${ANDROID_NDK_HOST_SYSTEM_NAME2} ) # only 32-bit at the moment set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/../../gcc/${ANDROID_NDK_HOST_SYSTEM_NAME}/arm" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH "" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "" ) else() # ANDROID_NDK_LAYOUT STREQUAL "RELEASE" set( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK}/toolchains" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME}" ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH2 "/prebuilt/${ANDROID_NDK_HOST_SYSTEM_NAME2}" ) endif() get_filename_component( ANDROID_NDK_TOOLCHAINS_PATH "${ANDROID_NDK_TOOLCHAINS_PATH}" ABSOLUTE ) # try to detect change of NDK if( CMAKE_AR ) string( LENGTH "${ANDROID_NDK_TOOLCHAINS_PATH}" __length ) string( SUBSTRING "${CMAKE_AR}" 0 ${__length} __androidNdkPreviousPath ) if( NOT __androidNdkPreviousPath STREQUAL ANDROID_NDK_TOOLCHAINS_PATH ) message( FATAL_ERROR "It is not possible to change the path to the NDK on subsequent CMake run. You must remove all generated files from your build folder first. " ) endif() unset( __androidNdkPreviousPath ) unset( __length ) endif() endif() # get all the details about standalone toolchain if( BUILD_WITH_STANDALONE_TOOLCHAIN ) __DETECT_NATIVE_API_LEVEL( ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot/usr/include/android/api-level.h" ) set( ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) set( __availableToolchains "standalone" ) __DETECT_TOOLCHAIN_MACHINE_NAME( __availableToolchainMachines "${ANDROID_STANDALONE_TOOLCHAIN}" ) if( NOT __availableToolchainMachines ) message( FATAL_ERROR "Could not determine machine name of your toolchain. Probably your Android standalone toolchain is broken." ) endif() if( __availableToolchainMachines MATCHES x86_64 ) set( __availableToolchainArchs "x86_64" ) elseif( __availableToolchainMachines MATCHES i686 ) set( __availableToolchainArchs "x86" ) elseif( __availableToolchainMachines MATCHES aarch64 ) set( __availableToolchainArchs "arm64" ) elseif( __availableToolchainMachines MATCHES arm ) set( __availableToolchainArchs "arm" ) elseif( __availableToolchainMachines MATCHES mips64el ) set( __availableToolchainArchs "mips64" ) elseif( __availableToolchainMachines MATCHES mipsel ) set( __availableToolchainArchs "mips" ) endif() execute_process( COMMAND "${ANDROID_STANDALONE_TOOLCHAIN}/bin/${__availableToolchainMachines}-gcc${TOOL_OS_SUFFIX}" -dumpversion OUTPUT_VARIABLE __availableToolchainCompilerVersions OUTPUT_STRIP_TRAILING_WHITESPACE ) string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9]+)?" __availableToolchainCompilerVersions "${__availableToolchainCompilerVersions}" ) if( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/bin/clang${TOOL_OS_SUFFIX}" ) list( APPEND __availableToolchains "standalone-clang" ) list( APPEND __availableToolchainMachines ${__availableToolchainMachines} ) list( APPEND __availableToolchainArchs ${__availableToolchainArchs} ) list( APPEND __availableToolchainCompilerVersions ${__availableToolchainCompilerVersions} ) endif() endif() macro( __GLOB_NDK_TOOLCHAINS __availableToolchainsVar __availableToolchainsLst __toolchain_subpath ) foreach( __toolchain ${${__availableToolchainsLst}} ) if( "${__toolchain}" MATCHES "-clang3[.][0-9]$" AND NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}${__toolchain_subpath}" ) SET( __toolchainVersionRegex "^TOOLCHAIN_VERSION[\t ]+:=[\t ]+(.*)$" ) FILE( STRINGS "${ANDROID_NDK_TOOLCHAINS_PATH}/${__toolchain}/setup.mk" __toolchainVersionStr REGEX "${__toolchainVersionRegex}" ) if( __toolchainVersionStr ) string( REGEX REPLACE "${__toolchainVersionRegex}" "\\1" __toolchainVersionStr "${__toolchainVersionStr}" ) string( REGEX REPLACE "-clang3[.][0-9]$" "-${__toolchainVersionStr}" __gcc_toolchain "${__toolchain}" ) else() string( REGEX REPLACE "-clang3[.][0-9]$" "-4.6" __gcc_toolchain "${__toolchain}" ) endif() unset( __toolchainVersionStr ) unset( __toolchainVersionRegex ) else() set( __gcc_toolchain "${__toolchain}" ) endif() __DETECT_TOOLCHAIN_MACHINE_NAME( __machine "${ANDROID_NDK_TOOLCHAINS_PATH}/${__gcc_toolchain}${__toolchain_subpath}" ) if( __machine ) string( REGEX MATCH "[0-9]+[.][0-9]+([.][0-9x]+)?$" __version "${__gcc_toolchain}" ) if( __machine MATCHES x86_64 ) set( __arch "x86_64" ) elseif( __machine MATCHES i686 ) set( __arch "x86" ) elseif( __machine MATCHES aarch64 ) set( __arch "arm64" ) elseif( __machine MATCHES arm ) set( __arch "arm" ) elseif( __machine MATCHES mips64el ) set( __arch "mips64" ) elseif( __machine MATCHES mipsel ) set( __arch "mips" ) else() set( __arch "" ) endif() #message("machine: !${__machine}!\narch: !${__arch}!\nversion: !${__version}!\ntoolchain: !${__toolchain}!\n") if (__arch) list( APPEND __availableToolchainMachines "${__machine}" ) list( APPEND __availableToolchainArchs "${__arch}" ) list( APPEND __availableToolchainCompilerVersions "${__version}" ) list( APPEND ${__availableToolchainsVar} "${__toolchain}" ) endif() endif() unset( __gcc_toolchain ) endforeach() endmacro() # get all the details about NDK if( BUILD_WITH_ANDROID_NDK ) file( GLOB ANDROID_SUPPORTED_NATIVE_API_LEVELS RELATIVE "${ANDROID_NDK}/platforms" "${ANDROID_NDK}/platforms/android-*" ) string( REPLACE "android-" "" ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_SUPPORTED_NATIVE_API_LEVELS}" ) set( __availableToolchains "" ) set( __availableToolchainMachines "" ) set( __availableToolchainArchs "" ) set( __availableToolchainCompilerVersions "" ) if( ANDROID_TOOLCHAIN_NAME AND EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_TOOLCHAIN_NAME}/" ) # do not go through all toolchains if we know the name set( __availableToolchainsLst "${ANDROID_TOOLCHAIN_NAME}" ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) if( __availableToolchains ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) endif() endif() endif() if( NOT __availableToolchains ) file( GLOB __availableToolchainsLst RELATIVE "${ANDROID_NDK_TOOLCHAINS_PATH}" "${ANDROID_NDK_TOOLCHAINS_PATH}/*" ) if( __availableToolchainsLst ) list(SORT __availableToolchainsLst) # we need clang to go after gcc endif() __LIST_FILTER( __availableToolchainsLst "^[.]" ) __LIST_FILTER( __availableToolchainsLst "llvm" ) __LIST_FILTER( __availableToolchainsLst "renderscript" ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) if( NOT __availableToolchains AND NOT ANDROID_NDK_TOOLCHAINS_SUBPATH STREQUAL ANDROID_NDK_TOOLCHAINS_SUBPATH2 ) __GLOB_NDK_TOOLCHAINS( __availableToolchains __availableToolchainsLst "${ANDROID_NDK_TOOLCHAINS_SUBPATH2}" ) if( __availableToolchains ) set( ANDROID_NDK_TOOLCHAINS_SUBPATH ${ANDROID_NDK_TOOLCHAINS_SUBPATH2} ) endif() endif() endif() if( NOT __availableToolchains ) message( FATAL_ERROR "Could not find any working toolchain in the NDK. Probably your Android NDK is broken." ) endif() endif() # build list of available ABIs set( ANDROID_SUPPORTED_ABIS "" ) set( __uniqToolchainArchNames ${__availableToolchainArchs} ) list( REMOVE_DUPLICATES __uniqToolchainArchNames ) list( SORT __uniqToolchainArchNames ) foreach( __arch ${__uniqToolchainArchNames} ) list( APPEND ANDROID_SUPPORTED_ABIS ${ANDROID_SUPPORTED_ABIS_${__arch}} ) endforeach() unset( __uniqToolchainArchNames ) if( NOT ANDROID_SUPPORTED_ABIS ) message( FATAL_ERROR "No one of known Android ABIs is supported by this cmake toolchain." ) endif() # choose target ABI __INIT_VARIABLE( ANDROID_ABI VALUES ${ANDROID_SUPPORTED_ABIS} ) # verify that target ABI is supported list( FIND ANDROID_SUPPORTED_ABIS "${ANDROID_ABI}" __androidAbiIdx ) if( __androidAbiIdx EQUAL -1 ) string( REPLACE ";" "\", \"" PRINTABLE_ANDROID_SUPPORTED_ABIS "${ANDROID_SUPPORTED_ABIS}" ) message( FATAL_ERROR "Specified ANDROID_ABI = \"${ANDROID_ABI}\" is not supported by this cmake toolchain or your NDK/toolchain. Supported values are: \"${PRINTABLE_ANDROID_SUPPORTED_ABIS}\" " ) endif() unset( __androidAbiIdx ) # set target ABI options if( ANDROID_ABI STREQUAL "x86" ) set( X86 true ) set( ANDROID_NDK_ABI_NAME "x86" ) set( ANDROID_ARCH_NAME "x86" ) set( ANDROID_LLVM_TRIPLE "i686-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "i686" ) elseif( ANDROID_ABI STREQUAL "x86_64" ) set( X86 true ) set( X86_64 true ) set( ANDROID_NDK_ABI_NAME "x86_64" ) set( ANDROID_ARCH_NAME "x86_64" ) set( CMAKE_SYSTEM_PROCESSOR "x86_64" ) set( ANDROID_LLVM_TRIPLE "x86_64-none-linux-android" ) elseif( ANDROID_ABI STREQUAL "mips64" ) set( MIPS64 true ) set( ANDROID_NDK_ABI_NAME "mips64" ) set( ANDROID_ARCH_NAME "mips64" ) set( ANDROID_LLVM_TRIPLE "mips64el-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "mips64" ) elseif( ANDROID_ABI STREQUAL "mips" ) set( MIPS true ) set( ANDROID_NDK_ABI_NAME "mips" ) set( ANDROID_ARCH_NAME "mips" ) set( ANDROID_LLVM_TRIPLE "mipsel-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "mips" ) elseif( ANDROID_ABI STREQUAL "arm64-v8a" ) set( ARM64_V8A true ) set( ANDROID_NDK_ABI_NAME "arm64-v8a" ) set( ANDROID_ARCH_NAME "arm64" ) set( ANDROID_LLVM_TRIPLE "aarch64-none-linux-android" ) set( CMAKE_SYSTEM_PROCESSOR "aarch64" ) set( VFPV3 true ) set( NEON true ) elseif( ANDROID_ABI STREQUAL "armeabi" ) set( ARMEABI true ) set( ANDROID_NDK_ABI_NAME "armeabi" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv5te" ) elseif( ANDROID_ABI STREQUAL "armeabi-v6 with VFP" ) set( ARMEABI_V6 true ) set( ANDROID_NDK_ABI_NAME "armeabi" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv5te-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv6" ) # need always fallback to older platform set( ARMEABI true ) elseif( ANDROID_ABI STREQUAL "armeabi-v7a") set( ARMEABI_V7A true ) set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) elseif( ANDROID_ABI STREQUAL "armeabi-v7a with VFPV3" ) set( ARMEABI_V7A true ) set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) set( VFPV3 true ) elseif( ANDROID_ABI STREQUAL "armeabi-v7a with NEON" ) set( ARMEABI_V7A true ) set( ANDROID_NDK_ABI_NAME "armeabi-v7a" ) set( ANDROID_ARCH_NAME "arm" ) set( ANDROID_LLVM_TRIPLE "armv7-none-linux-androideabi" ) set( CMAKE_SYSTEM_PROCESSOR "armv7-a" ) set( VFPV3 true ) set( NEON true ) else() message( SEND_ERROR "Unknown ANDROID_ABI=\"${ANDROID_ABI}\" is specified." ) endif() if( CMAKE_BINARY_DIR AND EXISTS "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" ) # really dirty hack # it is not possible to change CMAKE_SYSTEM_PROCESSOR after the first run... file( APPEND "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeSystem.cmake" "SET(CMAKE_SYSTEM_PROCESSOR \"${CMAKE_SYSTEM_PROCESSOR}\")\n" ) endif() if( ANDROID_ARCH_NAME STREQUAL "arm" AND NOT ARMEABI_V6 ) __INIT_VARIABLE( ANDROID_FORCE_ARM_BUILD VALUES OFF ) set( ANDROID_FORCE_ARM_BUILD ${ANDROID_FORCE_ARM_BUILD} CACHE BOOL "Use 32-bit ARM instructions instead of Thumb-1" FORCE ) mark_as_advanced( ANDROID_FORCE_ARM_BUILD ) else() unset( ANDROID_FORCE_ARM_BUILD CACHE ) endif() # choose toolchain if( ANDROID_TOOLCHAIN_NAME ) list( FIND __availableToolchains "${ANDROID_TOOLCHAIN_NAME}" __toolchainIdx ) if( __toolchainIdx EQUAL -1 ) list( SORT __availableToolchains ) string( REPLACE ";" "\n * " toolchains_list "${__availableToolchains}" ) set( toolchains_list " * ${toolchains_list}") message( FATAL_ERROR "Specified toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is missing in your NDK or broken. Please verify that your NDK is working or select another compiler toolchain. To configure the toolchain set CMake variable ANDROID_TOOLCHAIN_NAME to one of the following values:\n${toolchains_list}\n" ) endif() list( GET __availableToolchainArchs ${__toolchainIdx} __toolchainArch ) if( NOT __toolchainArch STREQUAL ANDROID_ARCH_NAME ) message( SEND_ERROR "Selected toolchain \"${ANDROID_TOOLCHAIN_NAME}\" is not able to compile binaries for the \"${ANDROID_ARCH_NAME}\" platform." ) endif() else() set( __toolchainIdx -1 ) set( __applicableToolchains "" ) set( __toolchainMaxVersion "0.0.0" ) list( LENGTH __availableToolchains __availableToolchainsCount ) math( EXPR __availableToolchainsCount "${__availableToolchainsCount}-1" ) foreach( __idx RANGE ${__availableToolchainsCount} ) list( GET __availableToolchainArchs ${__idx} __toolchainArch ) if( __toolchainArch STREQUAL ANDROID_ARCH_NAME ) list( GET __availableToolchainCompilerVersions ${__idx} __toolchainVersion ) string( REPLACE "x" "99" __toolchainVersion "${__toolchainVersion}") if( __toolchainVersion VERSION_GREATER __toolchainMaxVersion ) set( __toolchainMaxVersion "${__toolchainVersion}" ) set( __toolchainIdx ${__idx} ) endif() endif() endforeach() unset( __availableToolchainsCount ) unset( __toolchainMaxVersion ) unset( __toolchainVersion ) endif() unset( __toolchainArch ) if( __toolchainIdx EQUAL -1 ) message( FATAL_ERROR "No one of available compiler toolchains is able to compile for ${ANDROID_ARCH_NAME} platform." ) endif() list( GET __availableToolchains ${__toolchainIdx} ANDROID_TOOLCHAIN_NAME ) list( GET __availableToolchainMachines ${__toolchainIdx} ANDROID_TOOLCHAIN_MACHINE_NAME ) list( GET __availableToolchainCompilerVersions ${__toolchainIdx} ANDROID_COMPILER_VERSION ) unset( __toolchainIdx ) unset( __availableToolchains ) unset( __availableToolchainMachines ) unset( __availableToolchainArchs ) unset( __availableToolchainCompilerVersions ) # choose native API level __INIT_VARIABLE( ANDROID_NATIVE_API_LEVEL ENV_ANDROID_NATIVE_API_LEVEL ANDROID_API_LEVEL ENV_ANDROID_API_LEVEL ANDROID_STANDALONE_TOOLCHAIN_API_LEVEL ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME} ANDROID_DEFAULT_NDK_API_LEVEL ) string( REPLACE "android-" "" ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" ) string( STRIP "${ANDROID_NATIVE_API_LEVEL}" ANDROID_NATIVE_API_LEVEL ) # adjust API level set( __real_api_level ${ANDROID_DEFAULT_NDK_API_LEVEL_${ANDROID_ARCH_NAME}} ) foreach( __level ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) if( (__level LESS ANDROID_NATIVE_API_LEVEL OR __level STREQUAL ANDROID_NATIVE_API_LEVEL) AND NOT __level LESS __real_api_level ) set( __real_api_level ${__level} ) endif() endforeach() if( __real_api_level AND NOT ANDROID_NATIVE_API_LEVEL STREQUAL __real_api_level ) message( STATUS "Adjusting Android API level 'android-${ANDROID_NATIVE_API_LEVEL}' to 'android-${__real_api_level}'") set( ANDROID_NATIVE_API_LEVEL ${__real_api_level} ) endif() unset(__real_api_level) # validate list( FIND ANDROID_SUPPORTED_NATIVE_API_LEVELS "${ANDROID_NATIVE_API_LEVEL}" __levelIdx ) if( __levelIdx EQUAL -1 ) message( SEND_ERROR "Specified Android native API level 'android-${ANDROID_NATIVE_API_LEVEL}' is not supported by your NDK/toolchain." ) else() if( BUILD_WITH_ANDROID_NDK ) __DETECT_NATIVE_API_LEVEL( __realApiLevel "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}/usr/include/android/api-level.h" ) if( NOT __realApiLevel EQUAL ANDROID_NATIVE_API_LEVEL AND NOT __realApiLevel GREATER 9000 ) message( SEND_ERROR "Specified Android API level (${ANDROID_NATIVE_API_LEVEL}) does not match to the level found (${__realApiLevel}). Probably your copy of NDK is broken." ) endif() unset( __realApiLevel ) endif() set( ANDROID_NATIVE_API_LEVEL "${ANDROID_NATIVE_API_LEVEL}" CACHE STRING "Android API level for native code" FORCE ) set( CMAKE_ANDROID_API ${ANDROID_NATIVE_API_LEVEL} ) if( CMAKE_VERSION VERSION_GREATER "2.8" ) list( SORT ANDROID_SUPPORTED_NATIVE_API_LEVELS ) set_property( CACHE ANDROID_NATIVE_API_LEVEL PROPERTY STRINGS ${ANDROID_SUPPORTED_NATIVE_API_LEVELS} ) endif() endif() unset( __levelIdx ) # remember target ABI set( ANDROID_ABI "${ANDROID_ABI}" CACHE STRING "The target ABI for Android. If arm, then armeabi-v7a is recommended for hardware floating point." FORCE ) if( CMAKE_VERSION VERSION_GREATER "2.8" ) list( SORT ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME} ) set_property( CACHE ANDROID_ABI PROPERTY STRINGS ${ANDROID_SUPPORTED_ABIS_${ANDROID_ARCH_NAME}} ) endif() # runtime choice (STL, rtti, exceptions) if( NOT ANDROID_STL ) set( ANDROID_STL gnustl_static ) endif() set( ANDROID_STL "${ANDROID_STL}" CACHE STRING "C++ runtime" ) set( ANDROID_STL_FORCE_FEATURES ON CACHE BOOL "automatically configure rtti and exceptions support based on C++ runtime" ) mark_as_advanced( ANDROID_STL ANDROID_STL_FORCE_FEATURES ) if( BUILD_WITH_ANDROID_NDK ) if( NOT "${ANDROID_STL}" MATCHES "^(none|system|system_re|gabi\\+\\+_static|gabi\\+\\+_shared|stlport_static|stlport_shared|gnustl_static|gnustl_shared)$") message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". The possible values are: none -> Do not configure the runtime. system -> Use the default minimal system C++ runtime library. system_re -> Same as system but with rtti and exceptions. gabi++_static -> Use the GAbi++ runtime as a static library. gabi++_shared -> Use the GAbi++ runtime as a shared library. stlport_static -> Use the STLport runtime as a static library. stlport_shared -> Use the STLport runtime as a shared library. gnustl_static -> (default) Use the GNU STL as a static library. gnustl_shared -> Use the GNU STL as a shared library. " ) endif() elseif( BUILD_WITH_STANDALONE_TOOLCHAIN ) if( NOT "${ANDROID_STL}" MATCHES "^(none|gnustl_static|gnustl_shared)$") message( FATAL_ERROR "ANDROID_STL is set to invalid value \"${ANDROID_STL}\". The possible values are: none -> Do not configure the runtime. gnustl_static -> (default) Use the GNU STL as a static library. gnustl_shared -> Use the GNU STL as a shared library. " ) endif() endif() unset( ANDROID_RTTI ) unset( ANDROID_EXCEPTIONS ) unset( ANDROID_STL_INCLUDE_DIRS ) unset( __libstl ) unset( __libsupcxx ) if( NOT _CMAKE_IN_TRY_COMPILE AND ANDROID_NDK_RELEASE STREQUAL "r7b" AND ARMEABI_V7A AND NOT VFPV3 AND ANDROID_STL MATCHES "gnustl" ) message( WARNING "The GNU STL armeabi-v7a binaries from NDK r7b can crash non-NEON devices. The files provided with NDK r7b were not configured properly, resulting in crashes on Tegra2-based devices and others when trying to use certain floating-point functions (e.g., cosf, sinf, expf). You are strongly recommended to switch to another NDK release. " ) endif() if( NOT _CMAKE_IN_TRY_COMPILE AND X86 AND ANDROID_STL MATCHES "gnustl" AND ANDROID_NDK_RELEASE STREQUAL "r6" ) message( WARNING "The x86 system header file from NDK r6 has incorrect definition for ptrdiff_t. You are recommended to upgrade to a newer NDK release or manually patch the header: See https://android.googlesource.com/platform/development.git f907f4f9d4e56ccc8093df6fee54454b8bcab6c2 diff --git a/ndk/platforms/android-9/arch-x86/include/machine/_types.h b/ndk/platforms/android-9/arch-x86/include/machine/_types.h index 5e28c64..65892a1 100644 --- a/ndk/platforms/android-9/arch-x86/include/machine/_types.h +++ b/ndk/platforms/android-9/arch-x86/include/machine/_types.h @@ -51,7 +51,11 @@ typedef long int ssize_t; #endif #ifndef _PTRDIFF_T #define _PTRDIFF_T -typedef long ptrdiff_t; +# ifdef __ANDROID__ + typedef int ptrdiff_t; +# else + typedef long ptrdiff_t; +# endif #endif " ) endif() # setup paths and STL for standalone toolchain if( BUILD_WITH_STANDALONE_TOOLCHAIN ) set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_STANDALONE_TOOLCHAIN}" ) set( ANDROID_SYSROOT "${ANDROID_STANDALONE_TOOLCHAIN}/sysroot" ) if( NOT ANDROID_STL STREQUAL "none" ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/include/c++/${ANDROID_COMPILER_VERSION}" ) if( NOT EXISTS "${ANDROID_STL_INCLUDE_DIRS}" ) # old location ( pre r8c ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/include/c++/${ANDROID_COMPILER_VERSION}" ) endif() if( ARMEABI_V7A AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}/bits" ) list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/${CMAKE_SYSTEM_PROCESSOR}" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb/bits" ) list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/thumb" ) else() list( APPEND ANDROID_STL_INCLUDE_DIRS "${ANDROID_STL_INCLUDE_DIRS}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" ) endif() # always search static GNU STL to get the location of libsupc++.a if( ARMEABI_V7A AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb" ) elseif( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb" ) elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libstdc++.a" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib" ) endif() if( __libstl ) set( __libsupcxx "${__libstl}/libsupc++.a" ) set( __libstl "${__libstl}/libstdc++.a" ) endif() if( NOT EXISTS "${__libsupcxx}" ) message( FATAL_ERROR "The required libstdsupc++.a is missing in your standalone toolchain. Usually it happens because of bug in make-standalone-toolchain.sh script from NDK r7, r7b and r7c. You need to either upgrade to newer NDK or manually copy $ANDROID_NDK/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a to ${__libsupcxx} " ) endif() if( ANDROID_STL STREQUAL "gnustl_shared" ) if( ARMEABI_V7A AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libgnustl_shared.so" ) elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD AND EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libgnustl_shared.so" ) elseif( EXISTS "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) set( __libstl "${ANDROID_STANDALONE_TOOLCHAIN}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libgnustl_shared.so" ) endif() endif() endif() endif() # clang if( "${ANDROID_TOOLCHAIN_NAME}" STREQUAL "standalone-clang" ) set( ANDROID_COMPILER_IS_CLANG 1 ) execute_process( COMMAND "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/clang${TOOL_OS_SUFFIX}" --version OUTPUT_VARIABLE ANDROID_CLANG_VERSION OUTPUT_STRIP_TRAILING_WHITESPACE ) string( REGEX MATCH "[0-9]+[.][0-9]+" ANDROID_CLANG_VERSION "${ANDROID_CLANG_VERSION}") elseif( "${ANDROID_TOOLCHAIN_NAME}" MATCHES "-clang3[.][0-9]?$" ) string( REGEX MATCH "3[.][0-9]$" ANDROID_CLANG_VERSION "${ANDROID_TOOLCHAIN_NAME}") string( REGEX REPLACE "-clang${ANDROID_CLANG_VERSION}$" "-${ANDROID_COMPILER_VERSION}" ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) if( NOT EXISTS "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}/bin/clang${TOOL_OS_SUFFIX}" ) message( FATAL_ERROR "Could not find the Clang compiler driver" ) endif() set( ANDROID_COMPILER_IS_CLANG 1 ) set( ANDROID_CLANG_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/llvm-${ANDROID_CLANG_VERSION}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) else() set( ANDROID_GCC_TOOLCHAIN_NAME "${ANDROID_TOOLCHAIN_NAME}" ) unset( ANDROID_COMPILER_IS_CLANG CACHE ) endif() string( REPLACE "." "" _clang_name "clang${ANDROID_CLANG_VERSION}" ) if( NOT EXISTS "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" ) set( _clang_name "clang" ) endif() # setup paths and STL for NDK if( BUILD_WITH_ANDROID_NDK ) set( ANDROID_TOOLCHAIN_ROOT "${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}${ANDROID_NDK_TOOLCHAINS_SUBPATH}" ) set( ANDROID_SYSROOT "${ANDROID_NDK}/platforms/android-${ANDROID_NATIVE_API_LEVEL}/arch-${ANDROID_ARCH_NAME}" ) if( ANDROID_STL STREQUAL "none" ) # do nothing elseif( ANDROID_STL STREQUAL "system" ) set( ANDROID_RTTI OFF ) set( ANDROID_EXCEPTIONS OFF ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) elseif( ANDROID_STL STREQUAL "system_re" ) set( ANDROID_RTTI ON ) set( ANDROID_EXCEPTIONS ON ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/system/include" ) elseif( ANDROID_STL MATCHES "gabi" ) if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 message( FATAL_ERROR "gabi++ is not available in your NDK. You have to upgrade to NDK r7 or newer to use gabi++.") endif() set( ANDROID_RTTI ON ) set( ANDROID_EXCEPTIONS OFF ) set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/gabi++/include" ) set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gabi++/libs/${ANDROID_NDK_ABI_NAME}/libgabi++_static.a" ) elseif( ANDROID_STL MATCHES "stlport" ) if( NOT ANDROID_NDK_RELEASE_NUM LESS 8004 ) # before r8d set( ANDROID_EXCEPTIONS ON ) else() set( ANDROID_EXCEPTIONS OFF ) endif() if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 set( ANDROID_RTTI OFF ) else() set( ANDROID_RTTI ON ) endif() set( ANDROID_STL_INCLUDE_DIRS "${ANDROID_NDK}/sources/cxx-stl/stlport/stlport" ) set( __libstl "${ANDROID_NDK}/sources/cxx-stl/stlport/libs/${ANDROID_NDK_ABI_NAME}/libstlport_static.a" ) elseif( ANDROID_STL MATCHES "gnustl" ) set( ANDROID_EXCEPTIONS ON ) set( ANDROID_RTTI ON ) if( EXISTS "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) if( ARMEABI_V7A AND ANDROID_COMPILER_VERSION VERSION_EQUAL "4.7" AND ANDROID_NDK_RELEASE STREQUAL "r8d" ) # gnustl binary for 4.7 compiler is buggy :( # TODO: look for right fix set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.6" ) else() set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}" ) endif() else() set( __libstl "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++" ) endif() set( ANDROID_STL_INCLUDE_DIRS "${__libstl}/include" "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/include" "${__libstl}/include/backward" ) if( EXISTS "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libgnustl_static.a" ) else() set( __libstl "${__libstl}/libs/${ANDROID_NDK_ABI_NAME}/libstdc++.a" ) endif() else() message( FATAL_ERROR "Unknown runtime: ${ANDROID_STL}" ) endif() # find libsupc++.a - rtti & exceptions if( ANDROID_STL STREQUAL "system_re" OR ANDROID_STL MATCHES "gnustl" ) set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/${ANDROID_COMPILER_VERSION}/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r8b or newer if( NOT EXISTS "${__libsupcxx}" ) set( __libsupcxx "${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/libs/${ANDROID_NDK_ABI_NAME}/libsupc++.a" ) # r7-r8 endif() if( NOT EXISTS "${__libsupcxx}" ) # before r7 if( ARMEABI_V7A ) if( ANDROID_FORCE_ARM_BUILD ) set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/libsupc++.a" ) else() set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/${CMAKE_SYSTEM_PROCESSOR}/thumb/libsupc++.a" ) endif() elseif( ARMEABI AND NOT ANDROID_FORCE_ARM_BUILD ) set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/thumb/libsupc++.a" ) else() set( __libsupcxx "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}/lib/libsupc++.a" ) endif() endif() if( NOT EXISTS "${__libsupcxx}") message( ERROR "Could not find libsupc++.a for a chosen platform. Either your NDK is not supported or is broken.") endif() endif() endif() # case of shared STL linkage if( ANDROID_STL MATCHES "shared" AND DEFINED __libstl ) string( REPLACE "_static.a" "_shared.so" __libstl "${__libstl}" ) # TODO: check if .so file exists before the renaming endif() # ccache support __INIT_VARIABLE( _ndk_ccache NDK_CCACHE ENV_NDK_CCACHE ) if( _ndk_ccache ) if( DEFINED NDK_CCACHE AND NOT EXISTS NDK_CCACHE ) unset( NDK_CCACHE CACHE ) endif() find_program( NDK_CCACHE "${_ndk_ccache}" DOC "The path to ccache binary") else() unset( NDK_CCACHE CACHE ) endif() unset( _ndk_ccache ) # setup the cross-compiler if( NOT CMAKE_C_COMPILER ) if( NDK_CCACHE AND NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) set( CMAKE_C_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C compiler" ) set( CMAKE_CXX_COMPILER "${NDK_CCACHE}" CACHE PATH "ccache as C++ compiler" ) if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_C_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") else() set( CMAKE_C_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") set( CMAKE_CXX_COMPILER_ARG1 "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") endif() else() if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_C_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}${TOOL_OS_SUFFIX}" CACHE PATH "C compiler") set( CMAKE_CXX_COMPILER "${ANDROID_CLANG_TOOLCHAIN_ROOT}/bin/${_clang_name}++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler") else() set( CMAKE_C_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "C compiler" ) set( CMAKE_CXX_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-g++${TOOL_OS_SUFFIX}" CACHE PATH "C++ compiler" ) endif() endif() set( CMAKE_ASM_COMPILER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc${TOOL_OS_SUFFIX}" CACHE PATH "assembler" ) set( CMAKE_STRIP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-strip${TOOL_OS_SUFFIX}" CACHE PATH "strip" ) if( EXISTS "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" ) # Use gcc-ar if we have it for better LTO support. set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-gcc-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) else() set( CMAKE_AR "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ar${TOOL_OS_SUFFIX}" CACHE PATH "archive" ) endif() set( CMAKE_LINKER "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ld${TOOL_OS_SUFFIX}" CACHE PATH "linker" ) set( CMAKE_NM "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-nm${TOOL_OS_SUFFIX}" CACHE PATH "nm" ) set( CMAKE_OBJCOPY "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objcopy${TOOL_OS_SUFFIX}" CACHE PATH "objcopy" ) set( CMAKE_OBJDUMP "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-objdump${TOOL_OS_SUFFIX}" CACHE PATH "objdump" ) set( CMAKE_RANLIB "${ANDROID_TOOLCHAIN_ROOT}/bin/${ANDROID_TOOLCHAIN_MACHINE_NAME}-ranlib${TOOL_OS_SUFFIX}" CACHE PATH "ranlib" ) endif() set( _CMAKE_TOOLCHAIN_PREFIX "${ANDROID_TOOLCHAIN_MACHINE_NAME}-" ) if( CMAKE_VERSION VERSION_LESS 2.8.5 ) set( CMAKE_ASM_COMPILER_ARG1 "-c" ) endif() if( APPLE ) find_program( CMAKE_INSTALL_NAME_TOOL NAMES install_name_tool ) if( NOT CMAKE_INSTALL_NAME_TOOL ) message( FATAL_ERROR "Could not find install_name_tool, please check your installation." ) endif() mark_as_advanced( CMAKE_INSTALL_NAME_TOOL ) endif() # Force set compilers because standard identification works badly for us include( CMakeForceCompiler ) CMAKE_FORCE_C_COMPILER( "${CMAKE_C_COMPILER}" GNU ) if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_C_COMPILER_ID Clang ) endif() set( CMAKE_C_PLATFORM_ID Linux ) if( X86_64 OR MIPS64 OR ARM64_V8A ) set( CMAKE_C_SIZEOF_DATA_PTR 8 ) else() set( CMAKE_C_SIZEOF_DATA_PTR 4 ) endif() set( CMAKE_C_HAS_ISYSROOT 1 ) set( CMAKE_C_COMPILER_ABI ELF ) CMAKE_FORCE_CXX_COMPILER( "${CMAKE_CXX_COMPILER}" GNU ) if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_CXX_COMPILER_ID Clang) endif() set( CMAKE_CXX_PLATFORM_ID Linux ) set( CMAKE_CXX_SIZEOF_DATA_PTR ${CMAKE_C_SIZEOF_DATA_PTR} ) set( CMAKE_CXX_HAS_ISYSROOT 1 ) set( CMAKE_CXX_COMPILER_ABI ELF ) set( CMAKE_CXX_SOURCE_FILE_EXTENSIONS cc cp cxx cpp CPP c++ C ) # force ASM compiler (required for CMake < 2.8.5) set( CMAKE_ASM_COMPILER_ID_RUN TRUE ) set( CMAKE_ASM_COMPILER_ID GNU ) set( CMAKE_ASM_COMPILER_WORKS TRUE ) set( CMAKE_ASM_COMPILER_FORCED TRUE ) set( CMAKE_COMPILER_IS_GNUASM 1) set( CMAKE_ASM_SOURCE_FILE_EXTENSIONS s S asm ) foreach( lang C CXX ASM ) if( ANDROID_COMPILER_IS_CLANG ) set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_CLANG_VERSION} ) else() set( CMAKE_${lang}_COMPILER_VERSION ${ANDROID_COMPILER_VERSION} ) endif() endforeach() # flags and definitions remove_definitions( -DANDROID ) add_definitions( -DANDROID ) if( ANDROID_SYSROOT MATCHES "[ ;\"]" ) if( CMAKE_HOST_WIN32 ) # try to convert path to 8.3 form file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "@echo %~s1" ) execute_process( COMMAND "$ENV{ComSpec}" /c "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/cvt83.cmd" "${ANDROID_SYSROOT}" OUTPUT_VARIABLE __path OUTPUT_STRIP_TRAILING_WHITESPACE RESULT_VARIABLE __result ERROR_QUIET ) if( __result EQUAL 0 ) file( TO_CMAKE_PATH "${__path}" ANDROID_SYSROOT ) set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) else() set( ANDROID_CXX_FLAGS "--sysroot=\"${ANDROID_SYSROOT}\"" ) endif() else() set( ANDROID_CXX_FLAGS "'--sysroot=${ANDROID_SYSROOT}'" ) endif() if( NOT _CMAKE_IN_TRY_COMPILE ) # quotes can break try_compile and compiler identification message(WARNING "Path to your Android NDK (or toolchain) has non-alphanumeric symbols.\nThe build might be broken.\n") endif() else() set( ANDROID_CXX_FLAGS "--sysroot=${ANDROID_SYSROOT}" ) endif() # NDK flags if (ARM64_V8A ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) endif() elseif( ARMEABI OR ARMEABI_V7A) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) if( NOT ANDROID_FORCE_ARM_BUILD AND NOT ARMEABI_V6 ) set( ANDROID_CXX_FLAGS_RELEASE "-mthumb -fomit-frame-pointer -fno-strict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -finline-limit=64" ) endif() else() # always compile ARMEABI_V6 in arm mode; otherwise there is no difference from ARMEABI set( ANDROID_CXX_FLAGS_RELEASE "-marm -fomit-frame-pointer -fstrict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-marm -fno-omit-frame-pointer -fno-strict-aliasing" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) endif() endif() elseif( X86 OR X86_64 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funwind-tables" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -funswitch-loops -finline-limit=300" ) endif() set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer -fstrict-aliasing" ) set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer -fno-strict-aliasing" ) elseif( MIPS OR MIPS64 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-strict-aliasing -finline-functions -funwind-tables -fmessage-length=0" ) set( ANDROID_CXX_FLAGS_RELEASE "-fomit-frame-pointer" ) set( ANDROID_CXX_FLAGS_DEBUG "-fno-omit-frame-pointer" ) if( NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fno-inline-functions-called-once -fgcse-after-reload -frerun-cse-after-loop -frename-registers" ) set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} -funswitch-loops -finline-limit=300" ) endif() elseif() set( ANDROID_CXX_FLAGS_RELEASE "" ) set( ANDROID_CXX_FLAGS_DEBUG "" ) endif() set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fsigned-char" ) # good/necessary when porting desktop libraries if( NOT X86 AND NOT ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "-Wno-psabi ${ANDROID_CXX_FLAGS}" ) endif() if( NOT ANDROID_COMPILER_VERSION VERSION_LESS "4.6" ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -no-canonical-prefixes" ) # see https://android-review.googlesource.com/#/c/47564/ endif() # ABI-specific flags if( ARMEABI_V7A ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv7-a -mfloat-abi=softfp" ) if( NEON ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=neon" ) elseif( VFPV3 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3" ) else() set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -mfpu=vfpv3-d16" ) endif() elseif( ARMEABI_V6 ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv6 -mfloat-abi=softfp -mfpu=vfp" ) # vfp == vfpv2 elseif( ARMEABI ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -march=armv5te -mtune=xscale -msoft-float" ) endif() if( ANDROID_STL MATCHES "gnustl" AND (EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}") ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) else() set( CMAKE_CXX_CREATE_SHARED_LIBRARY " -o " ) set( CMAKE_CXX_CREATE_SHARED_MODULE " -o " ) set( CMAKE_CXX_LINK_EXECUTABLE " -o " ) endif() # STL if( EXISTS "${__libstl}" OR EXISTS "${__libsupcxx}" ) if( EXISTS "${__libstl}" ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libstl}\"" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libstl}\"" ) set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libstl}\"" ) endif() if( EXISTS "${__libsupcxx}" ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) # C objects: set( CMAKE_C_CREATE_SHARED_LIBRARY " -o " ) set( CMAKE_C_CREATE_SHARED_MODULE " -o " ) set( CMAKE_C_LINK_EXECUTABLE " -o " ) set( CMAKE_C_CREATE_SHARED_LIBRARY "${CMAKE_C_CREATE_SHARED_LIBRARY} \"${__libsupcxx}\"" ) set( CMAKE_C_CREATE_SHARED_MODULE "${CMAKE_C_CREATE_SHARED_MODULE} \"${__libsupcxx}\"" ) set( CMAKE_C_LINK_EXECUTABLE "${CMAKE_C_LINK_EXECUTABLE} \"${__libsupcxx}\"" ) endif() if( ANDROID_STL MATCHES "gnustl" ) if( NOT EXISTS "${ANDROID_LIBM_PATH}" ) set( ANDROID_LIBM_PATH -lm ) endif() set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} ${ANDROID_LIBM_PATH}" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} ${ANDROID_LIBM_PATH}" ) set( CMAKE_CXX_LINK_EXECUTABLE "${CMAKE_CXX_LINK_EXECUTABLE} ${ANDROID_LIBM_PATH}" ) endif() endif() # variables controlling optional build flags if( ANDROID_NDK_RELEASE_NUM LESS 7000 ) # before r7 # libGLESv2.so in NDK's prior to r7 refers to missing external symbols. # So this flag option is required for all projects using OpenGL from native. __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES ON ) else() __INIT_VARIABLE( ANDROID_SO_UNDEFINED VALUES OFF ) endif() __INIT_VARIABLE( ANDROID_NO_UNDEFINED VALUES ON ) __INIT_VARIABLE( ANDROID_FUNCTION_LEVEL_LINKING VALUES ON ) __INIT_VARIABLE( ANDROID_GOLD_LINKER VALUES ON ) __INIT_VARIABLE( ANDROID_NOEXECSTACK VALUES ON ) __INIT_VARIABLE( ANDROID_RELRO VALUES ON ) set( ANDROID_NO_UNDEFINED ${ANDROID_NO_UNDEFINED} CACHE BOOL "Show all undefined symbols as linker errors" ) set( ANDROID_SO_UNDEFINED ${ANDROID_SO_UNDEFINED} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) set( ANDROID_FUNCTION_LEVEL_LINKING ${ANDROID_FUNCTION_LEVEL_LINKING} CACHE BOOL "Put each function in separate section and enable garbage collection of unused input sections at link time" ) set( ANDROID_GOLD_LINKER ${ANDROID_GOLD_LINKER} CACHE BOOL "Enables gold linker" ) set( ANDROID_NOEXECSTACK ${ANDROID_NOEXECSTACK} CACHE BOOL "Allows or disallows undefined symbols in shared libraries" ) set( ANDROID_RELRO ${ANDROID_RELRO} CACHE BOOL "Enables RELRO - a memory corruption mitigation technique" ) mark_as_advanced( ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_FUNCTION_LEVEL_LINKING ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO ) # linker flags set( ANDROID_LINKER_FLAGS "" ) if( ARMEABI_V7A ) # this is *required* to use the following linker flags that routes around # a CPU bug in some Cortex-A8 implementations: set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--fix-cortex-a8" ) endif() if( ANDROID_NO_UNDEFINED ) if( MIPS ) # there is some sysroot-related problem in mips linker... if( NOT ANDROID_SYSROOT MATCHES "[ ;\"]" ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined -Wl,-rpath-link,${ANDROID_SYSROOT}/usr/lib" ) endif() else() set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--no-undefined" ) endif() endif() if( ANDROID_SO_UNDEFINED ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-allow-shlib-undefined" ) endif() if( ANDROID_FUNCTION_LEVEL_LINKING ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -fdata-sections -ffunction-sections" ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,--gc-sections" ) endif() if( ANDROID_COMPILER_VERSION VERSION_EQUAL "4.6" ) if( ANDROID_GOLD_LINKER AND (CMAKE_HOST_UNIX OR ANDROID_NDK_RELEASE_NUM GREATER 8002) AND (ARMEABI OR ARMEABI_V7A OR X86) ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=gold" ) elseif( ANDROID_NDK_RELEASE_NUM GREATER 8002 ) # after r8b set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -fuse-ld=bfd" ) elseif( ANDROID_NDK_RELEASE STREQUAL "r8b" AND ARMEABI AND NOT _CMAKE_IN_TRY_COMPILE ) message( WARNING "The default bfd linker from arm GCC 4.6 toolchain can fail with 'unresolvable R_ARM_THM_CALL relocation' error message. See https://code.google.com/p/android/issues/detail?id=35342 On Linux and OS X host platform you can workaround this problem using gold linker (default). Rerun cmake with -DANDROID_GOLD_LINKER=ON option in case of problems. " ) endif() endif() # version 4.6 if( ANDROID_NOEXECSTACK ) if( ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Xclang -mnoexecstack" ) else() set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS} -Wa,--noexecstack" ) endif() set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,noexecstack" ) endif() if( ANDROID_RELRO ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} -Wl,-z,relro -Wl,-z,now" ) endif() if( ANDROID_COMPILER_IS_CLANG ) set( ANDROID_CXX_FLAGS "-target ${ANDROID_LLVM_TRIPLE} -Qunused-arguments ${ANDROID_CXX_FLAGS}" ) if( BUILD_WITH_ANDROID_NDK ) set( ANDROID_CXX_FLAGS "-gcc-toolchain ${ANDROID_TOOLCHAIN_ROOT} ${ANDROID_CXX_FLAGS}" ) endif() endif() # cache flags set( CMAKE_CXX_FLAGS "" CACHE STRING "c++ flags" ) set( CMAKE_C_FLAGS "" CACHE STRING "c flags" ) set( CMAKE_CXX_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c++ Release flags" ) set( CMAKE_C_FLAGS_RELEASE "-O3 -DNDEBUG" CACHE STRING "c Release flags" ) set( CMAKE_CXX_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c++ Debug flags" ) set( CMAKE_C_FLAGS_DEBUG "-O0 -g -DDEBUG -D_DEBUG" CACHE STRING "c Debug flags" ) set( CMAKE_SHARED_LINKER_FLAGS "" CACHE STRING "shared linker flags" ) set( CMAKE_MODULE_LINKER_FLAGS "" CACHE STRING "module linker flags" ) set( CMAKE_EXE_LINKER_FLAGS "-Wl,-z,nocopyreloc" CACHE STRING "executable linker flags" ) # put flags to cache (for debug purpose only) set( ANDROID_CXX_FLAGS "${ANDROID_CXX_FLAGS}" CACHE INTERNAL "Android specific c/c++ flags" ) set( ANDROID_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE}" CACHE INTERNAL "Android specific c/c++ Release flags" ) set( ANDROID_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG}" CACHE INTERNAL "Android specific c/c++ Debug flags" ) set( ANDROID_LINKER_FLAGS "${ANDROID_LINKER_FLAGS}" CACHE INTERNAL "Android specific c/c++ linker flags" ) # finish flags set( CMAKE_CXX_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "${ANDROID_CXX_FLAGS} ${CMAKE_C_FLAGS}" ) set( CMAKE_CXX_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_CXX_FLAGS_RELEASE}" ) set( CMAKE_C_FLAGS_RELEASE "${ANDROID_CXX_FLAGS_RELEASE} ${CMAKE_C_FLAGS_RELEASE}" ) set( CMAKE_CXX_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_CXX_FLAGS_DEBUG}" ) set( CMAKE_C_FLAGS_DEBUG "${ANDROID_CXX_FLAGS_DEBUG} ${CMAKE_C_FLAGS_DEBUG}" ) set( CMAKE_SHARED_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_SHARED_LINKER_FLAGS}" ) set( CMAKE_MODULE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_MODULE_LINKER_FLAGS}" ) set( CMAKE_EXE_LINKER_FLAGS "${ANDROID_LINKER_FLAGS} ${CMAKE_EXE_LINKER_FLAGS}" ) if( MIPS AND BUILD_WITH_ANDROID_NDK AND ANDROID_NDK_RELEASE STREQUAL "r8" ) set( CMAKE_SHARED_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_SHARED_LINKER_FLAGS}" ) set( CMAKE_MODULE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.xsc ${CMAKE_MODULE_LINKER_FLAGS}" ) set( CMAKE_EXE_LINKER_FLAGS "-Wl,-T,${ANDROID_NDK_TOOLCHAINS_PATH}/${ANDROID_GCC_TOOLCHAIN_NAME}/mipself.x ${CMAKE_EXE_LINKER_FLAGS}" ) endif() # pie/pic if( NOT (ANDROID_NATIVE_API_LEVEL LESS 16) AND (NOT DEFINED ANDROID_APP_PIE OR ANDROID_APP_PIE) AND (CMAKE_VERSION VERSION_GREATER 2.8.8) ) set( CMAKE_POSITION_INDEPENDENT_CODE TRUE ) set( CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fPIE -pie") else() set( CMAKE_POSITION_INDEPENDENT_CODE FALSE ) set( CMAKE_CXX_FLAGS "-fpic ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "-fpic ${CMAKE_C_FLAGS}" ) endif() # configure rtti if( DEFINED ANDROID_RTTI AND ANDROID_STL_FORCE_FEATURES ) if( ANDROID_RTTI ) set( CMAKE_CXX_FLAGS "-frtti ${CMAKE_CXX_FLAGS}" ) else() set( CMAKE_CXX_FLAGS "-fno-rtti ${CMAKE_CXX_FLAGS}" ) endif() endif() # configure exceptios if( DEFINED ANDROID_EXCEPTIONS AND ANDROID_STL_FORCE_FEATURES ) if( ANDROID_EXCEPTIONS ) set( CMAKE_CXX_FLAGS "-fexceptions ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "-fexceptions ${CMAKE_C_FLAGS}" ) else() set( CMAKE_CXX_FLAGS "-fno-exceptions ${CMAKE_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "-fno-exceptions ${CMAKE_C_FLAGS}" ) endif() endif() # global includes and link directories include_directories( SYSTEM "${ANDROID_SYSROOT}/usr/include" ${ANDROID_STL_INCLUDE_DIRS} ) get_filename_component(__android_install_path "${CMAKE_INSTALL_PREFIX}/libs/${ANDROID_NDK_ABI_NAME}" ABSOLUTE) # avoid CMP0015 policy warning link_directories( "${__android_install_path}" ) # detect if need link crtbegin_so.o explicitly if( NOT DEFINED ANDROID_EXPLICIT_CRT_LINK ) set( __cmd "${CMAKE_CXX_CREATE_SHARED_LIBRARY}" ) string( REPLACE "" "${CMAKE_CXX_COMPILER} ${CMAKE_CXX_COMPILER_ARG1}" __cmd "${__cmd}" ) string( REPLACE "" "${CMAKE_C_COMPILER} ${CMAKE_C_COMPILER_ARG1}" __cmd "${__cmd}" ) string( REPLACE "" "${CMAKE_CXX_FLAGS}" __cmd "${__cmd}" ) string( REPLACE "" "" __cmd "${__cmd}" ) string( REPLACE "" "${CMAKE_SHARED_LINKER_FLAGS}" __cmd "${__cmd}" ) string( REPLACE "" "-shared" __cmd "${__cmd}" ) string( REPLACE "" "" __cmd "${__cmd}" ) string( REPLACE "" "" __cmd "${__cmd}" ) string( REPLACE "" "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/toolchain_crtlink_test.so" __cmd "${__cmd}" ) string( REPLACE "" "\"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" __cmd "${__cmd}" ) string( REPLACE "" "" __cmd "${__cmd}" ) separate_arguments( __cmd ) foreach( __var ANDROID_NDK ANDROID_NDK_TOOLCHAINS_PATH ANDROID_STANDALONE_TOOLCHAIN ) if( ${__var} ) set( __tmp "${${__var}}" ) separate_arguments( __tmp ) string( REPLACE "${__tmp}" "${${__var}}" __cmd "${__cmd}") endif() endforeach() string( REPLACE "'" "" __cmd "${__cmd}" ) string( REPLACE "\"" "" __cmd "${__cmd}" ) execute_process( COMMAND ${__cmd} RESULT_VARIABLE __cmd_result OUTPUT_QUIET ERROR_QUIET ) if( __cmd_result EQUAL 0 ) set( ANDROID_EXPLICIT_CRT_LINK ON ) else() set( ANDROID_EXPLICIT_CRT_LINK OFF ) endif() endif() if( ANDROID_EXPLICIT_CRT_LINK ) set( CMAKE_CXX_CREATE_SHARED_LIBRARY "${CMAKE_CXX_CREATE_SHARED_LIBRARY} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) set( CMAKE_CXX_CREATE_SHARED_MODULE "${CMAKE_CXX_CREATE_SHARED_MODULE} \"${ANDROID_SYSROOT}/usr/lib/crtbegin_so.o\"" ) endif() # setup output directories set( CMAKE_INSTALL_PREFIX "${ANDROID_TOOLCHAIN_ROOT}/user" CACHE STRING "path for installing" ) if( DEFINED LIBRARY_OUTPUT_PATH_ROOT OR EXISTS "${CMAKE_SOURCE_DIR}/AndroidManifest.xml" OR (EXISTS "${CMAKE_SOURCE_DIR}/../AndroidManifest.xml" AND EXISTS "${CMAKE_SOURCE_DIR}/../jni/") ) set( LIBRARY_OUTPUT_PATH_ROOT ${CMAKE_SOURCE_DIR} CACHE PATH "Root for binaries output, set this to change where Android libs are installed to" ) if( NOT _CMAKE_IN_TRY_COMPILE ) if( EXISTS "${CMAKE_SOURCE_DIR}/jni/CMakeLists.txt" ) set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for applications" ) else() set( EXECUTABLE_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/bin" CACHE PATH "Output directory for applications" ) endif() set( LIBRARY_OUTPUT_PATH "${LIBRARY_OUTPUT_PATH_ROOT}/libs/${ANDROID_NDK_ABI_NAME}" CACHE PATH "Output directory for Android libs" ) endif() endif() # copy shaed stl library to build directory if( NOT _CMAKE_IN_TRY_COMPILE AND __libstl MATCHES "[.]so$" AND DEFINED LIBRARY_OUTPUT_PATH ) get_filename_component( __libstlname "${__libstl}" NAME ) execute_process( COMMAND "${CMAKE_COMMAND}" -E copy_if_different "${__libstl}" "${LIBRARY_OUTPUT_PATH}/${__libstlname}" RESULT_VARIABLE __fileCopyProcess ) if( NOT __fileCopyProcess EQUAL 0 OR NOT EXISTS "${LIBRARY_OUTPUT_PATH}/${__libstlname}") message( SEND_ERROR "Failed copying of ${__libstl} to the ${LIBRARY_OUTPUT_PATH}/${__libstlname}" ) endif() unset( __fileCopyProcess ) unset( __libstlname ) endif() # set these global flags for cmake client scripts to change behavior set( ANDROID True ) set( BUILD_ANDROID True ) # where is the target environment set( CMAKE_FIND_ROOT_PATH "${ANDROID_TOOLCHAIN_ROOT}/bin" "${ANDROID_TOOLCHAIN_ROOT}/${ANDROID_TOOLCHAIN_MACHINE_NAME}" "${ANDROID_SYSROOT}" "${CMAKE_INSTALL_PREFIX}" "${CMAKE_INSTALL_PREFIX}/share" ) # only search for libraries and includes in the ndk toolchain set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) # macro to find packages on the host OS macro( find_host_package ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) if( CMAKE_HOST_WIN32 ) SET( WIN32 1 ) SET( UNIX ) elseif( CMAKE_HOST_APPLE ) SET( APPLE 1 ) SET( UNIX ) endif() find_package( ${ARGN} ) SET( WIN32 ) SET( APPLE ) SET( UNIX 1 ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) endmacro() # macro to find programs on the host OS macro( find_host_program ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER ) if( CMAKE_HOST_WIN32 ) SET( WIN32 1 ) SET( UNIX ) elseif( CMAKE_HOST_APPLE ) SET( APPLE 1 ) SET( UNIX ) endif() find_program( ${ARGN} ) SET( WIN32 ) SET( APPLE ) SET( UNIX 1 ) set( CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY ) set( CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY ) endmacro() # export toolchain settings for the try_compile() command if( NOT _CMAKE_IN_TRY_COMPILE ) set( __toolchain_config "") foreach( __var NDK_CCACHE LIBRARY_OUTPUT_PATH_ROOT ANDROID_FORBID_SYGWIN ANDROID_NDK_HOST_X64 ANDROID_NDK ANDROID_NDK_LAYOUT ANDROID_STANDALONE_TOOLCHAIN ANDROID_TOOLCHAIN_NAME ANDROID_ABI ANDROID_NATIVE_API_LEVEL ANDROID_STL ANDROID_STL_FORCE_FEATURES ANDROID_FORCE_ARM_BUILD ANDROID_NO_UNDEFINED ANDROID_SO_UNDEFINED ANDROID_FUNCTION_LEVEL_LINKING ANDROID_GOLD_LINKER ANDROID_NOEXECSTACK ANDROID_RELRO ANDROID_LIBM_PATH ANDROID_EXPLICIT_CRT_LINK ANDROID_APP_PIE ) if( DEFINED ${__var} ) if( ${__var} MATCHES " ") set( __toolchain_config "${__toolchain_config}set( ${__var} \"${${__var}}\" CACHE INTERNAL \"\" )\n" ) else() set( __toolchain_config "${__toolchain_config}set( ${__var} ${${__var}} CACHE INTERNAL \"\" )\n" ) endif() endif() endforeach() file( WRITE "${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/android.toolchain.config.cmake" "${__toolchain_config}" ) unset( __toolchain_config ) endif() # force cmake to produce / instead of \ in build commands for Ninja generator if( CMAKE_GENERATOR MATCHES "Ninja" AND CMAKE_HOST_WIN32 ) # it is a bad hack after all # CMake generates Ninja makefiles with UNIX paths only if it thinks that we are going to build with MinGW set( CMAKE_COMPILER_IS_MINGW TRUE ) # tell CMake that we are MinGW set( CMAKE_CROSSCOMPILING TRUE ) # stop recursion enable_language( C ) enable_language( CXX ) # unset( CMAKE_COMPILER_IS_MINGW ) # can't unset because CMake does not convert back-slashes in response files without it unset( MINGW ) endif() # Variables controlling behavior or set by cmake toolchain: # ANDROID_ABI : "armeabi-v7a" (default), "armeabi", "armeabi-v7a with NEON", "armeabi-v7a with VFPV3", "armeabi-v6 with VFP", "x86", "mips", "arm64-v8a", "x86_64", "mips64" # ANDROID_NATIVE_API_LEVEL : 3,4,5,8,9,14,15,16,17,18,19,21 (depends on NDK version) # ANDROID_STL : gnustl_static/gnustl_shared/stlport_static/stlport_shared/gabi++_static/gabi++_shared/system_re/system/none # ANDROID_FORBID_SYGWIN : ON/OFF # ANDROID_NO_UNDEFINED : ON/OFF # ANDROID_SO_UNDEFINED : OFF/ON (default depends on NDK version) # ANDROID_FUNCTION_LEVEL_LINKING : ON/OFF # ANDROID_GOLD_LINKER : ON/OFF # ANDROID_NOEXECSTACK : ON/OFF # ANDROID_RELRO : ON/OFF # ANDROID_FORCE_ARM_BUILD : ON/OFF # ANDROID_STL_FORCE_FEATURES : ON/OFF # ANDROID_LIBM_PATH : path to libm.so (set to something like $(TOP)/out/target/product//obj/lib/libm.so) to workaround unresolved `sincos` # Can be set only at the first run: # ANDROID_NDK : path to your NDK install # NDK_CCACHE : path to your ccache executable # ANDROID_TOOLCHAIN_NAME : the NDK name of compiler toolchain # ANDROID_NDK_HOST_X64 : try to use x86_64 toolchain (default for x64 host systems) # ANDROID_NDK_LAYOUT : the inner NDK structure (RELEASE, LINARO, ANDROID) # LIBRARY_OUTPUT_PATH_ROOT : # ANDROID_STANDALONE_TOOLCHAIN # # Primary read-only variables: # ANDROID : always TRUE # ARMEABI : TRUE for arm v6 and older devices # ARMEABI_V6 : TRUE for arm v6 # ARMEABI_V7A : TRUE for arm v7a # ARM64_V8A : TRUE for arm64-v8a # NEON : TRUE if NEON unit is enabled # VFPV3 : TRUE if VFP version 3 is enabled # X86 : TRUE if configured for x86 # X86_64 : TRUE if configured for x86_64 # MIPS : TRUE if configured for mips # MIPS64 : TRUE if configured for mips64 # BUILD_WITH_ANDROID_NDK : TRUE if NDK is used # BUILD_WITH_STANDALONE_TOOLCHAIN : TRUE if standalone toolchain is used # ANDROID_NDK_HOST_SYSTEM_NAME : "windows", "linux-x86" or "darwin-x86" depending on host platform # ANDROID_NDK_ABI_NAME : "armeabi", "armeabi-v7a", "x86", "mips", "arm64-v8a", "x86_64", "mips64" depending on ANDROID_ABI # ANDROID_NDK_RELEASE : from r5 to r10d; set only for NDK # ANDROID_NDK_RELEASE_NUM : numeric ANDROID_NDK_RELEASE version (1000*major+minor) # ANDROID_ARCH_NAME : "arm", "x86", "mips", "arm64", "x86_64", "mips64" depending on ANDROID_ABI # ANDROID_SYSROOT : path to the compiler sysroot # TOOL_OS_SUFFIX : "" or ".exe" depending on host platform # ANDROID_COMPILER_IS_CLANG : TRUE if clang compiler is used # # Secondary (less stable) read-only variables: # ANDROID_COMPILER_VERSION : GCC version used (not Clang version) # ANDROID_CLANG_VERSION : version of clang compiler if clang is used # ANDROID_CXX_FLAGS : C/C++ compiler flags required by Android platform # ANDROID_SUPPORTED_ABIS : list of currently allowed values for ANDROID_ABI # ANDROID_TOOLCHAIN_MACHINE_NAME : "arm-linux-androideabi", "arm-eabi" or "i686-android-linux" # ANDROID_TOOLCHAIN_ROOT : path to the top level of toolchain (standalone or placed inside NDK) # ANDROID_CLANG_TOOLCHAIN_ROOT : path to clang tools # ANDROID_SUPPORTED_NATIVE_API_LEVELS : list of native API levels found inside NDK # ANDROID_STL_INCLUDE_DIRS : stl include paths # ANDROID_RTTI : if rtti is enabled by the runtime # ANDROID_EXCEPTIONS : if exceptions are enabled by the runtime # ANDROID_GCC_TOOLCHAIN_NAME : read-only, differs from ANDROID_TOOLCHAIN_NAME only if clang is used # # Defaults: # ANDROID_DEFAULT_NDK_API_LEVEL # ANDROID_DEFAULT_NDK_API_LEVEL_${ARCH} # ANDROID_NDK_SEARCH_PATHS # ANDROID_SUPPORTED_ABIS_${ARCH} # ANDROID_SUPPORTED_NDK_VERSIONS assimp-4.1.0/contrib/android-cmake/README.md0000644002537200234200000003157313213503245020702 0ustar zmoelnigiemusers# android-cmake CMake is great, and so is Android. This is a collection of CMake scripts that may be useful to the Android NDK community. It is based on experience from porting OpenCV library to Android: http://opencv.org/platforms/android.html Main goal is to share these scripts so that devs that use CMake as their build system may easily compile native code for Android. ## TL;DR cmake -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake \ -DANDROID_NDK= \ -DCMAKE_BUILD_TYPE=Release \ -DANDROID_ABI="armeabi-v7a with NEON" \ cmake --build . One-liner: cmake -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake -DANDROID_NDK= -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="armeabi-v7a with NEON" && cmake --build . _android-cmake_ will search for your NDK install in the following order: 1. Value of `ANDROID_NDK` CMake variable; 1. Value of `ANDROID_NDK` environment variable; 1. Search under paths from `ANDROID_NDK_SEARCH_PATHS` CMake variable; 1. Search platform specific locations (home folder, Windows "Program Files", etc). So if you have installed the NDK as `~/android-ndk-r10d` then _android-cmake_ will locate it automatically. ## Getting started To build a cmake-based C/C++ project for Android you need: * Android NDK (>= r5) http://developer.android.com/tools/sdk/ndk/index.html * CMake (>= v2.6.3, >= v2.8.9 recommended) http://www.cmake.org/download The _android-cmake_ is also capable to build with NDK from AOSP or Linaro Android source tree, but you may be required to manually specify path to `libm` binary to link with. ## Difference from traditional CMake Folowing the _ndk-build_ the _android-cmake_ supports **only two build targets**: * `-DCMAKE_BUILD_TYPE=Release` * `-DCMAKE_BUILD_TYPE=Debug` So don't even try other targets that can be found in CMake documentation and don't forget to explicitly specify `Release` or `Debug` because CMake builds without a build configuration by default. ## Difference from _ndk-build_ * Latest GCC available in NDK is used as the default compiler; * `Release` builds with `-O3` instead of `-Os`; * `Release` builds without debug info (without `-g`) (because _ndk-build_ always creates a stripped version but cmake delays this for `install/strip` target); * `-fsigned-char` is added to compiler flags to make `char` signed by default as it is on x86/x86_64; * GCC's stack protector is not used neither in `Debug` nor `Release` configurations; * No builds for multiple platforms (e.g. building for both arm and x86 require to run cmake twice with different parameters); * No file level Neon via `.neon` suffix; The following features of _ndk-build_ are not supported by the _android-cmake_ yet: * `armeabi-v7a-hard` ABI * `libc++_static`/`libc++_shared` STL runtime ## Basic options Similarly to the NDK build system _android-cmake_ allows to select between several compiler toolchains and target platforms. Most of the options can be set either as cmake arguments: `-D=` or as environment variables: * **ANDROID_NDK** - path to the Android NDK. If not set then _android-cmake_ will search for the most recent version of supported NDK in commonly used locations; * **ANDROID_ABI** - specifies the target Application Binary Interface (ABI). This option nearly matches to the APP_ABI variable used by ndk-build tool from Android NDK. If not specified then set to `armeabi-v7a`. Possible target names are: * `armeabi` - ARMv5TE based CPU with software floating point operations; * **`armeabi-v7a`** - ARMv7 based devices with hardware FPU instructions (VFPv3_D16); * `armeabi-v7a with NEON` - same as armeabi-v7a, but sets NEON as floating-point unit; * `armeabi-v7a with VFPV3` - same as armeabi-v7a, but sets VFPv3_D32 as floating-point unit; * `armeabi-v6 with VFP` - tuned for ARMv6 processors having VFP; * `x86` - IA-32 instruction set * `mips` - MIPS32 instruction set * `arm64-v8a` - ARMv8 AArch64 instruction set - only for NDK r10 and newer * `x86_64` - Intel64 instruction set (r1) - only for NDK r10 and newer * `mips64` - MIPS64 instruction set (r6) - only for NDK r10 and newer * **ANDROID_NATIVE_API_LEVEL** - level of android API to build for. Can be set either to full name (example: `android-8`) or a numeric value (example: `17`). The default API level depends on the target ABI: * `android-8` for ARM; * `android-9` for x86 and MIPS; * `android-21` for 64-bit ABIs. Building for `android-L` is possible only when it is explicitly selected. * **ANDROID_TOOLCHAIN_NAME** - the name of compiler toolchain to be used. This option allows to select between different GCC and Clang versions. The list of possible values depends on the NDK version and will be printed by toolchain file if an invalid value is set. By default _android-cmake_ selects the most recent version of GCC which can build for specified `ANDROID_ABI`. Example values are: * `aarch64-linux-android-4.9` * `aarch64-linux-android-clang3.5` * `arm-linux-androideabi-4.8` * `arm-linux-androideabi-4.9` * `arm-linux-androideabi-clang3.5` * `mips64el-linux-android-4.9` * `mipsel-linux-android-4.8` * `x86-4.9` * `x86_64-4.9` * etc. * **ANDROID_STL** - the name of C++ runtime to use. The default is `gnustl_static`. * `none` - do not configure the runtime. * `system` - use the default minimal system C++ runtime library. * Implies `-fno-rtti -fno-exceptions`. * `system_re` - use the default minimal system C++ runtime library. * Implies `-frtti -fexceptions`. * `gabi++_static` - use the GAbi++ runtime as a static library. * Implies `-frtti -fno-exceptions`. * Available for NDK r7 and newer. * `gabi++_shared` - use the GAbi++ runtime as a shared library. * Implies `-frtti -fno-exceptions`. * Available for NDK r7 and newer. * `stlport_static` - use the STLport runtime as a static library. * Implies `-fno-rtti -fno-exceptions` for NDK before r7. * Implies `-frtti -fno-exceptions` for NDK r7 and newer. * `stlport_shared` - use the STLport runtime as a shared library. * Implies `-fno-rtti -fno-exceptions` for NDK before r7. * Implies `-frtti -fno-exceptions` for NDK r7 and newer. * **`gnustl_static`** - use the GNU STL as a static library. * Implies `-frtti -fexceptions`. * `gnustl_shared` - use the GNU STL as a shared library. * Implies `-frtti -fno-exceptions`. * Available for NDK r7b and newer. * Silently degrades to `gnustl_static` if not available. * **NDK_CCACHE** - path to `ccache` executable. If not set then initialized from `NDK_CCACHE` environment variable. ## Advanced _android-cmake_ options Normally _android-cmake_ users are not supposed to touch these variables but they might be useful to workaround some build issues: * **ANDROID_FORCE_ARM_BUILD** = `OFF` - generate 32-bit ARM instructions instead of Thumb. Applicable only for arm ABIs and is forced to be `ON` for `armeabi-v6 with VFP`; * **ANDROID_NO_UNDEFINED** = `ON` - show all undefined symbols as linker errors; * **ANDROID_SO_UNDEFINED** = `OFF` - allow undefined symbols in shared libraries; * actually it is turned `ON` by default for NDK older than `r7` * **ANDROID_STL_FORCE_FEATURES** = `ON` - automatically configure rtti and exceptions support based on C++ runtime; * **ANDROID_NDK_LAYOUT** = `RELEASE` - inner layout of Android NDK, should be detected automatically. Possible values are: * `RELEASE` - public releases from Google; * `LINARO` - NDK from Linaro project; * `ANDROID` - NDK from AOSP. * **ANDROID_FUNCTION_LEVEL_LINKING** = `ON` - enables saparate putting each function and data items into separate sections and enable garbage collection of unused input sections at link time (`-fdata-sections -ffunction-sections -Wl,--gc-sections`); * **ANDROID_GOLD_LINKER** = `ON` - use gold linker with GCC 4.6 for NDK r8b and newer (only for ARM and x86); * **ANDROID_NOEXECSTACK** = `ON` - enables or disables stack execution protection code (`-Wl,-z,noexecstack`); * **ANDROID_RELRO** = `ON` - Enables RELRO - a memory corruption mitigation technique (`-Wl,-z,relro -Wl,-z,now`); * **ANDROID_LIBM_PATH** - path to `libm.so` (set to something like `$(TOP)/out/target/product//obj/lib/libm.so`) to workaround unresolved `sincos`. ## Fine-tuning `CMakeLists.txt` for _android-cmake_ ### Recognizing Android build _android-cmake_ defines `ANDROID` CMake variable which can be used to add Android-specific stuff: if (ANDROID) message(STATUS "Hello from Android build!") endif() The recommended way to identify ARM/MIPS/x86 architecture is examining `CMAKE_SYSTEM_PROCESSOR` which is set to the appropriate value: * `armv5te` - for `armeabi` ABI * `armv6` - for `armeabi-v6 with VFP` ABI * `armv7-a` - for `armeabi-v7a`, `armeabi-v7a with VFPV3` and `armeabi-v7a with NEON` ABIs * `aarch64` - for `arm64-v8a` ABI * `i686` - for `x86` ABI * `x86_64` - for `x86_64` ABI * `mips` - for `mips` ABI * `mips64` - for `mips64` ABI Other variables that are set by _android-cmake_ and can be used for the fine-grained build configuration are: * `NEON` - set if target ABI supports Neon; * `ANDROID_NATIVE_API_LEVEL` - native Android API level we are building for (note: Java part of Andoid application can be built for another API level) * `ANDROID_NDK_RELEASE` - version of the Android NDK * `ANDROID_NDK_HOST_SYSTEM_NAME` - "windows", "linux-x86" or "darwin-x86" depending on the host platform * `ANDROID_RTTI` - set if rtti is enabled by the runtime * `ANDROID_EXCEPTIONS` - set if exceptions are enabled by the runtime ### Finding packages When crosscompiling CMake `find_*` commands are normally expected to find libraries and packages belonging to the same build target. So _android-cmake_ configures CMake to search in Android-specific paths only and ignore your host system locations. So find_package(ZLIB) will surely find libz.so within the Android NDK. However sometimes you need to locate a host package even when cross-compiling. For example you can be searching for your documentation generator. The _android-cmake_ recommends you to use `find_host_package` and `find_host_program` macro defined in the `android.toolchain.cmake`: find_host_package(Doxygen) find_host_program(PDFLATEX pdflatex) However this will break regular builds so instead of wrapping package search into platform-specific logic you can copy the following snippet into your project (put it after your top-level `project()` command): # Search packages for host system instead of packages for target system # in case of cross compilation these macro should be defined by toolchain file if(NOT COMMAND find_host_package) macro(find_host_package) find_package(${ARGN}) endmacro() endif() if(NOT COMMAND find_host_program) macro(find_host_program) find_program(${ARGN}) endmacro() endif() ### Compiler flags recycling Make sure to do the following in your scripts: set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}") The flags will be prepopulated with critical flags, so don't loose them. Also be aware that _android-cmake_ also sets configuration-specific compiler and linker flags. ## Troubleshooting ### Building on Windows First of all `cygwin` builds are **NOT supported** and will not be supported by _android-cmake_. To build natively on Windows you need a port of make but I recommend http://martine.github.io/ninja/ instead. To build with Ninja you need: * Ensure you are using CMake newer than 2.8.9; * Download the latest Ninja from https://github.com/martine/ninja/releases; * Put the `ninja.exe` into your PATH (or add path to `ninja.exe` to your PATH environment variable); * Pass `-GNinja` to `cmake` alongside with other arguments (or choose Ninja generator in `cmake-gui`). * Enjoy the fast native multithreaded build :) But if you still want to stick to old make then: * Get a Windows port of GNU Make: * Android NDK r7 (and newer) already has `make.exe` on board; * `mingw-make` should work as fine; * Download some other port. For example, this one: http://gnuwin32.sourceforge.net/packages/make.htm. * Add path to your `make.exe` to system PATH or always use full path; * Pass `-G"MinGW Makefiles"` and `-DCMAKE_MAKE_PROGRAM="make.exe"` * It must be `MinGW Makefiles` and not `Unix Makefiles` even if your `make.exe` is not a MinGW's make. * Run `make.exe` or `cmake --build .` for single-threaded build. ### Projects with assembler files The _android-cmake_ should correctly handle projects with assembler sources (`*.s` or `*.S`). But if you still facing problems with assembler then try to upgrade your CMake to version newer than 2.8.5 ## Copying _android-cmake_ is distributed under the terms of [BSD 3-Clause License](http://opensource.org/licenses/BSD-3-Clause)assimp-4.1.0/contrib/android-cmake/ndk_links.md0000644002537200234200000002423313213503245021714 0ustar zmoelnigiemusers ============== r1 ============== (dead links) * http://dl.google.com/android/ndk/android-ndk-1.5_r1-windows.zip * http://dl.google.com/android/ndk/android-ndk-1.5_r1-darwin-x86.zip * http://dl.google.com/android/ndk/android-ndk-1.5_r1-linux-x86.zip ============== r2 ============== * http://dl.google.com/android/ndk/android-ndk-1.6_r1-windows.zip * http://dl.google.com/android/ndk/android-ndk-1.6_r1-darwin-x86.zip * http://dl.google.com/android/ndk/android-ndk-1.6_r1-linux-x86.zip ============== r3 ============== * http://dl.google.com/android/ndk/android-ndk-r3-windows.zip * http://dl.google.com/android/ndk/android-ndk-r3-darwin-x86.zip * http://dl.google.com/android/ndk/android-ndk-r3-linux-x86.zip ============== r4 ============== * http://dl.google.com/android/ndk/android-ndk-r4-windows.zip * http://dl.google.com/android/ndk/android-ndk-r4-darwin-x86.zip * http://dl.google.com/android/ndk/android-ndk-r4-linux-x86.zip ============== r4b ============== * http://dl.google.com/android/ndk/android-ndk-r4b-windows.zip * http://dl.google.com/android/ndk/android-ndk-r4b-darwin-x86.zip * http://dl.google.com/android/ndk/android-ndk-r4b-linux-x86.zip ============== r5 ============== * http://dl.google.com/android/ndk/android-ndk-r5-windows.zip * http://dl.google.com/android/ndk/android-ndk-r5-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r5-linux-x86.tar.bz2 ============== r5b ============== * http://dl.google.com/android/ndk/android-ndk-r5b-windows.zip * http://dl.google.com/android/ndk/android-ndk-r5b-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r5b-linux-x86.tar.bz2 ============== r5c ============== * http://dl.google.com/android/ndk/android-ndk-r5c-windows.zip * http://dl.google.com/android/ndk/android-ndk-r5c-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r5c-linux-x86.tar.bz2 ============== r6 ============== * http://dl.google.com/android/ndk/android-ndk-r6-windows.zip * http://dl.google.com/android/ndk/android-ndk-r6-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r6-linux-x86.tar.bz2 ============== r6b ============== * http://dl.google.com/android/ndk/android-ndk-r6b-windows.zip * http://dl.google.com/android/ndk/android-ndk-r6b-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r6b-linux-x86.tar.bz2 ============== r7 ============== * http://dl.google.com/android/ndk/android-ndk-r7-windows.zip * http://dl.google.com/android/ndk/android-ndk-r7-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r7-linux-x86.tar.bz2 ============== r7b ============== * http://dl.google.com/android/ndk/android-ndk-r7b-windows.zip * http://dl.google.com/android/ndk/android-ndk-r7b-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r7b-linux-x86.tar.bz2 ============== r7c ============== * http://dl.google.com/android/ndk/android-ndk-r7c-windows.zip * http://dl.google.com/android/ndk/android-ndk-r7c-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r7c-linux-x86.tar.bz2 ============== r8 ============== * http://dl.google.com/android/ndk/android-ndk-r8-windows.zip * http://dl.google.com/android/ndk/android-ndk-r8-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r8-linux-x86.tar.bz2 ============== r8b ============== * http://dl.google.com/android/ndk/android-ndk-r8b-windows.zip * http://dl.google.com/android/ndk/android-ndk-r8b-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r8b-linux-x86.tar.bz2 ============== r8c ============== * http://dl.google.com/android/ndk/android-ndk-r8c-windows.zip * http://dl.google.com/android/ndk/android-ndk-r8c-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r8c-linux-x86.tar.bz2 ============== r8d ============== * http://dl.google.com/android/ndk/android-ndk-r8d-windows.zip * http://dl.google.com/android/ndk/android-ndk-r8d-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r8d-linux-x86.tar.bz2 ============== r8e ============== * http://dl.google.com/android/ndk/android-ndk-r8e-windows-x86.zip * http://dl.google.com/android/ndk/android-ndk-r8e-windows-x86_64.zip * http://dl.google.com/android/ndk/android-ndk-r8e-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r8e-darwin-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r8e-linux-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r8e-linux-x86_64.tar.bz2 ============== r9 ============== * http://dl.google.com/android/ndk/android-ndk-r9-windows-x86.zip * http://dl.google.com/android/ndk/android-ndk-r9-windows-x86-legacy-toolchains.zip * http://dl.google.com/android/ndk/android-ndk-r9-windows-x86_64.zip * http://dl.google.com/android/ndk/android-ndk-r9-windows-x86_64-legacy-toolchains.zip * http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86-legacy-toolchains.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9-darwin-x86_64-legacy-toolchains.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9-linux-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9-linux-x86-legacy-toolchains.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9-linux-x86_64-legacy-toolchains.tar.bz2 ============== r9b ============== * http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86.zip * http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86-legacy-toolchains.zip * http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86_64.zip * http://dl.google.com/android/ndk/android-ndk-r9b-windows-x86_64-legacy-toolchains.zip * http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86-legacy-toolchains.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9b-darwin-x86_64-legacy-toolchains.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86-legacy-toolchains.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9b-linux-x86_64-legacy-toolchains.tar.bz2 ============== r9c ============== * http://dl.google.com/android/ndk/android-ndk-r9c-windows-x86.zip * http://dl.google.com/android/ndk/android-ndk-r9c-windows-x86_64.zip * http://dl.google.com/android/ndk/android-ndk-r9c-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9c-darwin-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9c-linux-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9c-linux-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9c-cxx-stl-libs-with-debugging-info.zip ============== r9d ============== * http://dl.google.com/android/ndk/android-ndk-r9d-windows-x86.zip * http://dl.google.com/android/ndk/android-ndk-r9d-windows-x86_64.zip * http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9d-darwin-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9d-linux-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r9d-cxx-stl-libs-with-debug-info.zip ============== r10 ============== * http://dl.google.com/android/ndk/android-ndk32-r10-windows-x86.zip * http://dl.google.com/android/ndk/android-ndk32-r10-windows-x86_64.zip * http://dl.google.com/android/ndk/android-ndk32-r10-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk32-r10-darwin-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk32-r10-linux-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk32-r10-linux-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk64-r10-windows-x86.zip * http://dl.google.com/android/ndk/android-ndk64-r10-windows-x86_64.zip * http://dl.google.com/android/ndk/android-ndk64-r10-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk64-r10-darwin-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk64-r10-linux-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk64-r10-linux-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r10-cxx-stl-libs-with-debug-info.zip ============== r10b ============== * http://dl.google.com/android/ndk/android-ndk32-r10b-windows-x86.zip * http://dl.google.com/android/ndk/android-ndk32-r10b-windows-x86_64.zip * http://dl.google.com/android/ndk/android-ndk32-r10b-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk32-r10b-darwin-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk32-r10b-linux-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk32-r10b-linux-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk64-r10b-windows-x86.zip * http://dl.google.com/android/ndk/android-ndk64-r10b-windows-x86_64.zip * http://dl.google.com/android/ndk/android-ndk64-r10b-darwin-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk64-r10b-darwin-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk64-r10b-linux-x86.tar.bz2 * http://dl.google.com/android/ndk/android-ndk64-r10b-linux-x86_64.tar.bz2 * http://dl.google.com/android/ndk/android-ndk-r10b-cxx-stl-libs-with-debug-info.zip ============== r10c ============== * http://dl.google.com/android/ndk/android-ndk-r10c-windows-x86.exe * http://dl.google.com/android/ndk/android-ndk-r10c-windows-x86_64.exe * http://dl.google.com/android/ndk/android-ndk-r10c-darwin-x86.bin * http://dl.google.com/android/ndk/android-ndk-r10c-darwin-x86_64.bin * http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86.bin * http://dl.google.com/android/ndk/android-ndk-r10c-linux-x86_64.bin ============== r10d ============== * http://dl.google.com/android/ndk/android-ndk-r10d-windows-x86.exe * http://dl.google.com/android/ndk/android-ndk-r10d-windows-x86_64.exe * http://dl.google.com/android/ndk/android-ndk-r10d-darwin-x86.bin * http://dl.google.com/android/ndk/android-ndk-r10d-darwin-x86_64.bin * http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86.bin * http://dl.google.com/android/ndk/android-ndk-r10d-linux-x86_64.bin assimp-4.1.0/contrib/poly2tri_patch.txt0000644002537200234200000000462213213503245020424 0ustar zmoelnigiemusersdiff -r 5de9623d6a50 poly2tri/common/shapes.h --- a/poly2tri/common/shapes.h Mon Aug 08 22:26:41 2011 -0400 +++ b/poly2tri/common/shapes.h Tue Jan 17 02:36:52 2012 +0100 @@ -35,6 +35,7 @@ #include #include +#include #include #include @@ -136,7 +137,9 @@ p = &p2; } else if (p1.x == p2.x) { // Repeat points - assert(false); + // ASSIMP_CHANGE (aramis_acg) + throw std::runtime_error("repeat points"); + //assert(false); } } diff -r 5de9623d6a50 poly2tri/sweep/sweep.cc --- a/poly2tri/sweep/sweep.cc Mon Aug 08 22:26:41 2011 -0400 +++ b/poly2tri/sweep/sweep.cc Tue Jan 17 02:36:52 2012 +0100 @@ -113,6 +113,8 @@ Point* p1 = triangle->PointCCW(point); Orientation o1 = Orient2d(eq, *p1, ep); if (o1 == COLLINEAR) { + // ASSIMP_CHANGE (aramis_acg) + throw std::runtime_error("EdgeEvent - collinear points not supported"); if( triangle->Contains(&eq, p1)) { triangle->MarkConstrainedEdge(&eq, p1 ); // We are modifying the constraint maybe it would be better to @@ -121,8 +123,8 @@ triangle = &triangle->NeighborAcross(point); EdgeEvent( tcx, ep, *p1, triangle, *p1 ); } else { + // ASSIMP_CHANGE (aramis_acg) std::runtime_error("EdgeEvent - collinear points not supported"); - assert(0); } return; } @@ -130,6 +132,9 @@ Point* p2 = triangle->PointCW(point); Orientation o2 = Orient2d(eq, *p2, ep); if (o2 == COLLINEAR) { + // ASSIMP_CHANGE (aramis_acg) + throw std::runtime_error("EdgeEvent - collinear points not supported"); + if( triangle->Contains(&eq, p2)) { triangle->MarkConstrainedEdge(&eq, p2 ); // We are modifying the constraint maybe it would be better to @@ -138,8 +143,8 @@ triangle = &triangle->NeighborAcross(point); EdgeEvent( tcx, ep, *p2, triangle, *p2 ); } else { - std::runtime_error("EdgeEvent - collinear points not supported"); - assert(0); + // ASSIMP_CHANGE (aramis_acg) + throw std::runtime_error("EdgeEvent - collinear points not supported"); } return; } @@ -712,7 +717,8 @@ return *ot.PointCW(op); } else{ //throw new RuntimeException("[Unsupported] Opposing point on constrained edge"); - assert(0); + // ASSIMP_CHANGE (aramis_acg) + throw std::runtime_error("[Unsupported] Opposing point on constrained edge"); } } assimp-4.1.0/contrib/CMakeLists.txt0000644002537200234200000000021213213503245017447 0ustar zmoelnigiemusers# Compile internal irrXML only if system is not requested if( NOT SYSTEM_IRRXML ) add_subdirectory(irrXML) endif( NOT SYSTEM_IRRXML ) assimp-4.1.0/contrib/poly2tri/0000755002537200234200000000000013213503245016500 5ustar zmoelnigiemusersassimp-4.1.0/contrib/poly2tri/README0000644002537200234200000000177113213503245017366 0ustar zmoelnigiemusers================== INSTALLATION GUIDE ================== ------------ Dependencies ------------ Core poly2tri lib: - Standard Template Library (STL) Testbed: - gcc - OpenGL - GLFW (http://glfw.sf.net) - Python Waf (http://code.google.com/p/waf/) is used to compile the testbed. A waf script (86kb) is included in the repositoty. ---------------------------------------------- Building the Testbed ---------------------------------------------- Posix/MSYS environment: ./waf configure ./waf build Windows command line: python waf configure python waf build ---------------------------------------------- Running the Examples ---------------------------------------------- Load data points from a file: p2t Random distribution of points inside a consrained box: p2t random Examples: ./p2t dude.dat 300 500 2 ./p2t nazca_monkey.dat 0 0 9 ./p2t random 10 100 5.0 ./p2t random 1000 20000 0.025assimp-4.1.0/contrib/poly2tri/AUTHORS0000644002537200234200000000022113213503245017543 0ustar zmoelnigiemusersPrimary Contributors: Mason Green (C++, Python) Thomas hln (Java) Other Contributors: assimp-4.1.0/contrib/poly2tri/LICENSE0000644002537200234200000000277513213503245017520 0ustar zmoelnigiemusersPoly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors http://code.google.com/p/poly2tri/ 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 Poly2Tri 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. assimp-4.1.0/contrib/poly2tri/poly2tri/0000755002537200234200000000000013213503245020264 5ustar zmoelnigiemusersassimp-4.1.0/contrib/poly2tri/poly2tri/poly2tri.h0000644002537200234200000000326613213503245022230 0ustar zmoelnigiemusers/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * 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 Poly2Tri 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 POLY2TRI_H #define POLY2TRI_H #include "common/shapes.h" #include "sweep/cdt.h" #endifassimp-4.1.0/contrib/poly2tri/poly2tri/sweep/0000755002537200234200000000000013213503245021407 5ustar zmoelnigiemusersassimp-4.1.0/contrib/poly2tri/poly2tri/sweep/advancing_front.cc0000644002537200234200000000613613213503245025066 0ustar zmoelnigiemusers/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * 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 Poly2Tri 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 "advancing_front.h" namespace p2t { AdvancingFront::AdvancingFront(Node& head, Node& tail) { head_ = &head; tail_ = &tail; search_node_ = &head; } Node* AdvancingFront::LocateNode(double x) { Node* node = search_node_; if (x < node->value) { while ((node = node->prev) != NULL) { if (x >= node->value) { search_node_ = node; return node; } } } else { while ((node = node->next) != NULL) { if (x < node->value) { search_node_ = node->prev; return node->prev; } } } return NULL; } Node* AdvancingFront::FindSearchNode(double x) { (void)x; // suppress compiler warnings "unused parameter 'x'" // TODO: implement BST index return search_node_; } Node* AdvancingFront::LocatePoint(const Point* point) { const double px = point->x; Node* node = FindSearchNode(px); const double nx = node->point->x; if (px == nx) { if (point != node->point) { // We might have two nodes with same x value for a short time if (point == node->prev->point) { node = node->prev; } else if (point == node->next->point) { node = node->next; } else { assert(0); } } } else if (px < nx) { while ((node = node->prev) != NULL) { if (point == node->point) { break; } } } else { while ((node = node->next) != NULL) { if (point == node->point) break; } } if(node) search_node_ = node; return node; } AdvancingFront::~AdvancingFront() { } }assimp-4.1.0/contrib/poly2tri/poly2tri/sweep/sweep_context.cc0000644002537200234200000001252613213503245024613 0ustar zmoelnigiemusers/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * 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 Poly2Tri 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 "sweep_context.h" #include #include "advancing_front.h" namespace p2t { SweepContext::SweepContext(const std::vector& polyline) : points_(polyline), front_(0), head_(0), tail_(0), af_head_(0), af_middle_(0), af_tail_(0) { InitEdges(points_); } void SweepContext::AddHole(const std::vector& polyline) { InitEdges(polyline); for(unsigned int i = 0; i < polyline.size(); i++) { points_.push_back(polyline[i]); } } void SweepContext::AddPoint(Point* point) { points_.push_back(point); } std::vector &SweepContext::GetTriangles() { return triangles_; } std::list &SweepContext::GetMap() { return map_; } void SweepContext::InitTriangulation() { double xmax(points_[0]->x), xmin(points_[0]->x); double ymax(points_[0]->y), ymin(points_[0]->y); // Calculate bounds. for (unsigned int i = 0; i < points_.size(); i++) { Point& p = *points_[i]; if (p.x > xmax) xmax = p.x; if (p.x < xmin) xmin = p.x; if (p.y > ymax) ymax = p.y; if (p.y < ymin) ymin = p.y; } double dx = kAlpha * (xmax - xmin); double dy = kAlpha * (ymax - ymin); head_ = new Point(xmax + dx, ymin - dy); tail_ = new Point(xmin - dx, ymin - dy); // Sort points along y-axis std::sort(points_.begin(), points_.end(), cmp); } void SweepContext::InitEdges(const std::vector& polyline) { size_t num_points = polyline.size(); for (size_t i = 0; i < num_points; i++) { size_t j = i < num_points - 1 ? i + 1 : 0; edge_list.push_back(new Edge(*polyline[i], *polyline[j])); } } Point* SweepContext::GetPoint(size_t index) { return points_[index]; } void SweepContext::AddToMap(Triangle* triangle) { map_.push_back(triangle); } Node& SweepContext::LocateNode(const Point& point) { // TODO implement search tree return *front_->LocateNode(point.x); } void SweepContext::CreateAdvancingFront(const std::vector& nodes) { (void) nodes; // Initial triangle Triangle* triangle = new Triangle(*points_[0], *tail_, *head_); map_.push_back(triangle); af_head_ = new Node(*triangle->GetPoint(1), *triangle); af_middle_ = new Node(*triangle->GetPoint(0), *triangle); af_tail_ = new Node(*triangle->GetPoint(2)); front_ = new AdvancingFront(*af_head_, *af_tail_); // TODO: More intuitive if head is middles next and not previous? // so swap head and tail af_head_->next = af_middle_; af_middle_->next = af_tail_; af_middle_->prev = af_head_; af_tail_->prev = af_middle_; } void SweepContext::RemoveNode(Node* node) { delete node; } void SweepContext::MapTriangleToNodes(Triangle& t) { for (int i = 0; i < 3; i++) { if (!t.GetNeighbor(i)) { Node* n = front_->LocatePoint(t.PointCW(*t.GetPoint(i))); if (n) n->triangle = &t; } } } void SweepContext::RemoveFromMap(Triangle* triangle) { map_.remove(triangle); } void SweepContext::MeshClean(Triangle& triangle) { std::vector triangles; triangles.push_back(&triangle); while(!triangles.empty()){ Triangle *t = triangles.back(); triangles.pop_back(); if (t != NULL && !t->IsInterior()) { t->IsInterior(true); triangles_.push_back(t); for (int i = 0; i < 3; i++) { if (!t->constrained_edge[i]) triangles.push_back(t->GetNeighbor(i)); } } } } SweepContext::~SweepContext() { // Clean up memory delete head_; delete tail_; delete front_; delete af_head_; delete af_middle_; delete af_tail_; typedef std::list type_list; for(type_list::iterator iter = map_.begin(); iter != map_.end(); ++iter) { Triangle* ptr = *iter; delete ptr; } for(unsigned int i = 0; i < edge_list.size(); i++) { delete edge_list[i]; } } } assimp-4.1.0/contrib/poly2tri/poly2tri/sweep/sweep.h0000644002537200234200000002106113213503245022703 0ustar zmoelnigiemusers/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * 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 Poly2Tri 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. */ /** * Sweep-line, Constrained Delauney Triangulation (CDT) See: Domiter, V. and * Zalik, B.(2008)'Sweep-line algorithm for constrained Delaunay triangulation', * International Journal of Geographical Information Science * * "FlipScan" Constrained Edge Algorithm invented by Thomas ?hl?n, thahlen@gmail.com */ #ifndef SWEEP_H #define SWEEP_H #include namespace p2t { class SweepContext; struct Node; struct Point; struct Edge; class Triangle; class Sweep { public: /** * Triangulate * * @param tcx */ void Triangulate(SweepContext& tcx); /** * Destructor - clean up memory */ ~Sweep(); private: /** * Start sweeping the Y-sorted point set from bottom to top * * @param tcx */ void SweepPoints(SweepContext& tcx); /** * Find closes node to the left of the new point and * create a new triangle. If needed new holes and basins * will be filled to. * * @param tcx * @param point * @return */ Node& PointEvent(SweepContext& tcx, Point& point); /** * * * @param tcx * @param edge * @param node */ void EdgeEvent(SweepContext& tcx, Edge* edge, Node* node); void EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangle, Point& point); /** * Creates a new front triangle and legalize it * * @param tcx * @param point * @param node * @return */ Node& NewFrontTriangle(SweepContext& tcx, Point& point, Node& node); /** * Adds a triangle to the advancing front to fill a hole. * @param tcx * @param node - middle node, that is the bottom of the hole */ void Fill(SweepContext& tcx, Node& node); /** * Returns true if triangle was legalized */ bool Legalize(SweepContext& tcx, Triangle& t); /** * Requirement:
* 1. a,b and c form a triangle.
* 2. a and d is know to be on opposite side of bc
*
   *                a
   *                +
   *               / \
   *              /   \
   *            b/     \c
   *            +-------+
   *           /    d    \
   *          /           \
   * 
* Fact: d has to be in area B to have a chance to be inside the circle formed by * a,b and c
* d is outside B if orient2d(a,b,d) or orient2d(c,a,d) is CW
* This preknowledge gives us a way to optimize the incircle test * @param a - triangle point, opposite d * @param b - triangle point * @param c - triangle point * @param d - point opposite a * @return true if d is inside circle, false if on circle edge */ bool Incircle(const Point& pa, const Point& pb, const Point& pc, const Point& pd) const; /** * Rotates a triangle pair one vertex CW *
   *       n2                    n2
   *  P +-----+             P +-----+
   *    | t  /|               |\  t |
   *    |   / |               | \   |
   *  n1|  /  |n3           n1|  \  |n3
   *    | /   |    after CW   |   \ |
   *    |/ oT |               | oT \|
   *    +-----+ oP            +-----+
   *       n4                    n4
   * 
*/ void RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) const; /** * Fills holes in the Advancing Front * * * @param tcx * @param n */ void FillAdvancingFront(SweepContext& tcx, Node& n); // Decision-making about when to Fill hole. // Contributed by ToolmakerSteve2 bool LargeHole_DontFill(const Node* node) const; bool AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const; bool AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const; double Angle(const Point* origin, const Point* pa, const Point* pb) const; /** * * @param node - middle node * @return the angle between 3 front nodes */ double HoleAngle(const Node& node) const; /** * The basin angle is decided against the horizontal line [1,0] */ double BasinAngle(const Node& node) const; /** * Fills a basin that has formed on the Advancing Front to the right * of given node.
* First we decide a left,bottom and right node that forms the * boundaries of the basin. Then we do a reqursive fill. * * @param tcx * @param node - starting node, this or next node will be left node */ void FillBasin(SweepContext& tcx, Node& node); /** * Recursive algorithm to fill a Basin with triangles * * @param tcx * @param node - bottom_node * @param cnt - counter used to alternate on even and odd numbers */ void FillBasinReq(SweepContext& tcx, Node* node); bool IsShallow(SweepContext& tcx, Node& node); bool IsEdgeSideOfTriangle(Triangle& triangle, Point& ep, Point& eq); void FillEdgeEvent(SweepContext& tcx, Edge* edge, Node* node); void FillRightAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node); void FillRightBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); void FillRightConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); void FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); void FillLeftAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node); void FillLeftBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); void FillLeftConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); void FillLeftConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node); void FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t, Point& p); /** * After a flip we have two triangles and know that only one will still be * intersecting the edge. So decide which to contiune with and legalize the other * * @param tcx * @param o - should be the result of an orient2d( eq, op, ep ) * @param t - triangle 1 * @param ot - triangle 2 * @param p - a point shared by both triangles * @param op - another point shared by both triangles * @return returns the triangle still intersecting the edge */ Triangle& NextFlipTriangle(SweepContext& tcx, int o, Triangle& t, Triangle& ot, Point& p, Point& op); /** * When we need to traverse from one triangle to the next we need * the point in current triangle that is the opposite point to the next * triangle. * * @param ep * @param eq * @param ot * @param op * @return */ Point& NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op); /** * Scan part of the FlipScan algorithm
* When a triangle pair isn't flippable we will scan for the next * point that is inside the flip triangle scan area. When found * we generate a new flipEdgeEvent * * @param tcx * @param ep - last point on the edge we are traversing * @param eq - first point on the edge we are traversing * @param flipTriangle - the current triangle sharing the point eq with edge * @param t * @param p */ void FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle, Triangle& t, Point& p); void FinalizationPolygon(SweepContext& tcx); std::vector nodes_; }; } #endifassimp-4.1.0/contrib/poly2tri/poly2tri/sweep/sweep_context.h0000644002537200234200000001012013213503245024441 0ustar zmoelnigiemusers/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * 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 Poly2Tri 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 SWEEP_CONTEXT_H #define SWEEP_CONTEXT_H #include #include #include namespace p2t { // Inital triangle factor, seed triangle will extend 30% of // PointSet width to both left and right. const double kAlpha = 0.3; struct Point; class Triangle; struct Node; struct Edge; class AdvancingFront; class SweepContext { public: /// Constructor SweepContext(const std::vector& polyline); /// Destructor ~SweepContext(); void set_head(Point* p1); Point* head() const; void set_tail(Point* p1); Point* tail() const; size_t point_count() const; Node& LocateNode(const Point& point); void RemoveNode(Node* node); void CreateAdvancingFront(const std::vector& nodes); /// Try to map a node to all sides of this triangle that don't have a neighbor void MapTriangleToNodes(Triangle& t); void AddToMap(Triangle* triangle); Point* GetPoint(size_t index); Point* GetPoints(); void RemoveFromMap(Triangle* triangle); void AddHole(const std::vector& polyline); void AddPoint(Point* point); AdvancingFront* front() const; void MeshClean(Triangle& triangle); std::vector &GetTriangles(); std::list &GetMap(); std::vector edge_list; struct Basin { Node* left_node; Node* bottom_node; Node* right_node; double width; bool left_highest; Basin() : left_node(NULL), bottom_node(NULL), right_node(NULL), width(0.0), left_highest(false) { } void Clear() { left_node = NULL; bottom_node = NULL; right_node = NULL; width = 0.0; left_highest = false; } }; struct EdgeEvent { Edge* constrained_edge; bool right; EdgeEvent() : constrained_edge(NULL), right(false) { } }; Basin basin; EdgeEvent edge_event; private: friend class Sweep; std::vector triangles_; std::list map_; std::vector points_; // Advancing front AdvancingFront* front_; // head point used with advancing front Point* head_; // tail point used with advancing front Point* tail_; Node *af_head_, *af_middle_, *af_tail_; void InitTriangulation(); void InitEdges(const std::vector& polyline); }; inline AdvancingFront* SweepContext::front() const { return front_; } inline size_t SweepContext::point_count() const { return points_.size(); } inline void SweepContext::set_head(Point* p1) { head_ = p1; } inline Point* SweepContext::head() const { return head_; } inline void SweepContext::set_tail(Point* p1) { tail_ = p1; } inline Point* SweepContext::tail() const { return tail_; } } #endif assimp-4.1.0/contrib/poly2tri/poly2tri/sweep/cdt.cc0000644002537200234200000000431113213503245022467 0ustar zmoelnigiemusers/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * 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 Poly2Tri 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 "cdt.h" namespace p2t { CDT::CDT(const std::vector& polyline) { sweep_context_ = new SweepContext(polyline); sweep_ = new Sweep; } void CDT::AddHole(const std::vector& polyline) { sweep_context_->AddHole(polyline); } void CDT::AddPoint(Point* point) { sweep_context_->AddPoint(point); } void CDT::Triangulate() { sweep_->Triangulate(*sweep_context_); } std::vector CDT::GetTriangles() { return sweep_context_->GetTriangles(); } std::list CDT::GetMap() { return sweep_context_->GetMap(); } CDT::~CDT() { delete sweep_context_; delete sweep_; } }assimp-4.1.0/contrib/poly2tri/poly2tri/sweep/cdt.h0000644002537200234200000000504313213503245022334 0ustar zmoelnigiemusers/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * 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 Poly2Tri 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 CDT_H #define CDT_H #include "advancing_front.h" #include "sweep_context.h" #include "sweep.h" /** * * @author Mason Green * */ namespace p2t { class CDT { public: /** * Constructor - add polyline with non repeating points * * @param polyline */ CDT(const std::vector& polyline); /** * Destructor - clean up memory */ ~CDT(); /** * Add a hole * * @param polyline */ void AddHole(const std::vector& polyline); /** * Add a steiner point * * @param point */ void AddPoint(Point* point); /** * Triangulate - do this AFTER you've added the polyline, holes, and Steiner points */ void Triangulate(); /** * Get CDT triangles */ std::vector GetTriangles(); /** * Get triangle map */ std::list GetMap(); private: /** * Internals */ SweepContext* sweep_context_; Sweep* sweep_; }; } #endifassimp-4.1.0/contrib/poly2tri/poly2tri/sweep/advancing_front.h0000644002537200234200000000554113213503245024727 0ustar zmoelnigiemusers/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * 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 Poly2Tri 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 ADVANCED_FRONT_H #define ADVANCED_FRONT_H #include "../common/shapes.h" namespace p2t { struct Node; // Advancing front node struct Node { Point* point; Triangle* triangle; Node* next; Node* prev; double value; Node(Point& p) : point(&p), triangle(NULL), next(NULL), prev(NULL), value(p.x) { } Node(Point& p, Triangle& t) : point(&p), triangle(&t), next(NULL), prev(NULL), value(p.x) { } }; // Advancing front class AdvancingFront { public: AdvancingFront(Node& head, Node& tail); // Destructor ~AdvancingFront(); Node* head(); void set_head(Node* node); Node* tail(); void set_tail(Node* node); Node* search(); void set_search(Node* node); /// Locate insertion point along advancing front Node* LocateNode(double x); Node* LocatePoint(const Point* point); private: Node* head_, *tail_, *search_node_; Node* FindSearchNode(double x); }; inline Node* AdvancingFront::head() { return head_; } inline void AdvancingFront::set_head(Node* node) { head_ = node; } inline Node* AdvancingFront::tail() { return tail_; } inline void AdvancingFront::set_tail(Node* node) { tail_ = node; } inline Node* AdvancingFront::search() { return search_node_; } inline void AdvancingFront::set_search(Node* node) { search_node_ = node; } } #endifassimp-4.1.0/contrib/poly2tri/poly2tri/sweep/sweep.cc0000644002537200234200000005662313213503245023055 0ustar zmoelnigiemusers/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * 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 Poly2Tri 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 #include "sweep.h" #include "sweep_context.h" #include "advancing_front.h" #include "../common/utils.h" namespace p2t { // Triangulate simple polygon with holes void Sweep::Triangulate(SweepContext& tcx) { tcx.InitTriangulation(); tcx.CreateAdvancingFront(nodes_); // Sweep points; build mesh SweepPoints(tcx); // Clean up FinalizationPolygon(tcx); } void Sweep::SweepPoints(SweepContext& tcx) { for (size_t i = 1; i < tcx.point_count(); i++) { Point& point = *tcx.GetPoint(i); Node* node = &PointEvent(tcx, point); for (unsigned int i = 0; i < point.edge_list.size(); i++) { EdgeEvent(tcx, point.edge_list[i], node); } } } void Sweep::FinalizationPolygon(SweepContext& tcx) { // Get an Internal triangle to start with Triangle* t = tcx.front()->head()->next->triangle; Point* p = tcx.front()->head()->next->point; while (!t->GetConstrainedEdgeCW(*p)) { t = t->NeighborCCW(*p); } // Collect interior triangles constrained by edges tcx.MeshClean(*t); } Node& Sweep::PointEvent(SweepContext& tcx, Point& point) { Node& node = tcx.LocateNode(point); Node& new_node = NewFrontTriangle(tcx, point, node); // Only need to check +epsilon since point never have smaller // x value than node due to how we fetch nodes from the front if (point.x <= node.point->x + EPSILON) { Fill(tcx, node); } //tcx.AddNode(new_node); FillAdvancingFront(tcx, new_node); return new_node; } void Sweep::EdgeEvent(SweepContext& tcx, Edge* edge, Node* node) { tcx.edge_event.constrained_edge = edge; tcx.edge_event.right = (edge->p->x > edge->q->x); if (IsEdgeSideOfTriangle(*node->triangle, *edge->p, *edge->q)) { return; } // For now we will do all needed filling // TODO: integrate with flip process might give some better performance // but for now this avoid the issue with cases that needs both flips and fills FillEdgeEvent(tcx, edge, node); EdgeEvent(tcx, *edge->p, *edge->q, node->triangle, *edge->q); } void Sweep::EdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* triangle, Point& point) { if (IsEdgeSideOfTriangle(*triangle, ep, eq)) { return; } Point* p1 = triangle->PointCCW(point); Orientation o1 = Orient2d(eq, *p1, ep); if (o1 == COLLINEAR) { // ASSIMP_CHANGE (aramis_acg) throw std::runtime_error("EdgeEvent - collinear points not supported"); if( triangle->Contains(&eq, p1)) { triangle->MarkConstrainedEdge(&eq, p1 ); // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.edge_event.constrained_edge->q = p1; triangle = &triangle->NeighborAcross(point); EdgeEvent( tcx, ep, *p1, triangle, *p1 ); } else { // ASSIMP_CHANGE (aramis_acg) std::runtime_error("EdgeEvent - collinear points not supported"); } return; } Point* p2 = triangle->PointCW(point); Orientation o2 = Orient2d(eq, *p2, ep); if (o2 == COLLINEAR) { // ASSIMP_CHANGE (aramis_acg) throw std::runtime_error("EdgeEvent - collinear points not supported"); if( triangle->Contains(&eq, p2)) { triangle->MarkConstrainedEdge(&eq, p2 ); // We are modifying the constraint maybe it would be better to // not change the given constraint and just keep a variable for the new constraint tcx.edge_event.constrained_edge->q = p2; triangle = &triangle->NeighborAcross(point); EdgeEvent( tcx, ep, *p2, triangle, *p2 ); } else { // ASSIMP_CHANGE (aramis_acg) throw std::runtime_error("EdgeEvent - collinear points not supported"); } return; } if (o1 == o2) { // Need to decide if we are rotating CW or CCW to get to a triangle // that will cross edge if (o1 == CW) { triangle = triangle->NeighborCCW(point); } else{ triangle = triangle->NeighborCW(point); } EdgeEvent(tcx, ep, eq, triangle, point); } else { // This triangle crosses constraint so lets flippin start! FlipEdgeEvent(tcx, ep, eq, triangle, point); } } bool Sweep::IsEdgeSideOfTriangle(Triangle& triangle, Point& ep, Point& eq) { const int index = triangle.EdgeIndex(&ep, &eq); if (index != -1) { triangle.MarkConstrainedEdge(index); Triangle* t = triangle.GetNeighbor(index); if (t) { t->MarkConstrainedEdge(&ep, &eq); } return true; } return false; } Node& Sweep::NewFrontTriangle(SweepContext& tcx, Point& point, Node& node) { Triangle* triangle = new Triangle(point, *node.point, *node.next->point); triangle->MarkNeighbor(*node.triangle); tcx.AddToMap(triangle); Node* new_node = new Node(point); nodes_.push_back(new_node); new_node->next = node.next; new_node->prev = &node; node.next->prev = new_node; node.next = new_node; if (!Legalize(tcx, *triangle)) { tcx.MapTriangleToNodes(*triangle); } return *new_node; } void Sweep::Fill(SweepContext& tcx, Node& node) { Triangle* triangle = new Triangle(*node.prev->point, *node.point, *node.next->point); // TODO: should copy the constrained_edge value from neighbor triangles // for now constrained_edge values are copied during the legalize triangle->MarkNeighbor(*node.prev->triangle); triangle->MarkNeighbor(*node.triangle); tcx.AddToMap(triangle); // Update the advancing front node.prev->next = node.next; node.next->prev = node.prev; // If it was legalized the triangle has already been mapped if (!Legalize(tcx, *triangle)) { tcx.MapTriangleToNodes(*triangle); } } void Sweep::FillAdvancingFront(SweepContext& tcx, Node& n) { // Fill right holes Node* node = n.next; while (node->next) { // if HoleAngle exceeds 90 degrees then break. if (LargeHole_DontFill(node)) break; Fill(tcx, *node); node = node->next; } // Fill left holes node = n.prev; while (node->prev) { // if HoleAngle exceeds 90 degrees then break. if (LargeHole_DontFill(node)) break; Fill(tcx, *node); node = node->prev; } // Fill right basins if (n.next && n.next->next) { const double angle = BasinAngle(n); if (angle < PI_3div4) { FillBasin(tcx, n); } } } // True if HoleAngle exceeds 90 degrees. bool Sweep::LargeHole_DontFill(const Node* node) const { const Node* nextNode = node->next; const Node* prevNode = node->prev; if (!AngleExceeds90Degrees(node->point, nextNode->point, prevNode->point)) return false; // Check additional points on front. const Node* next2Node = nextNode->next; // "..Plus.." because only want angles on same side as point being added. if ((next2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, next2Node->point, prevNode->point)) return false; const Node* prev2Node = prevNode->prev; // "..Plus.." because only want angles on same side as point being added. if ((prev2Node != NULL) && !AngleExceedsPlus90DegreesOrIsNegative(node->point, nextNode->point, prev2Node->point)) return false; return true; } bool Sweep::AngleExceeds90Degrees(const Point* origin, const Point* pa, const Point* pb) const { const double angle = Angle(origin, pa, pb); return ((angle > PI_div2) || (angle < -PI_div2)); } bool Sweep::AngleExceedsPlus90DegreesOrIsNegative(const Point* origin, const Point* pa, const Point* pb) const { const double angle = Angle(origin, pa, pb); return (angle > PI_div2) || (angle < 0); } double Sweep::Angle(const Point* origin, const Point* pa, const Point* pb) const { /* Complex plane * ab = cosA +i*sinA * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx) * atan2(y,x) computes the principal value of the argument function * applied to the complex number x+iy * Where x = ax*bx + ay*by * y = ax*by - ay*bx */ const double px = origin->x; const double py = origin->y; const double ax = pa->x- px; const double ay = pa->y - py; const double bx = pb->x - px; const double by = pb->y - py; const double x = ax * by - ay * bx; const double y = ax * bx + ay * by; return atan2(x, y); } double Sweep::BasinAngle(const Node& node) const { const double ax = node.point->x - node.next->next->point->x; const double ay = node.point->y - node.next->next->point->y; return atan2(ay, ax); } double Sweep::HoleAngle(const Node& node) const { /* Complex plane * ab = cosA +i*sinA * ab = (ax + ay*i)(bx + by*i) = (ax*bx + ay*by) + i(ax*by-ay*bx) * atan2(y,x) computes the principal value of the argument function * applied to the complex number x+iy * Where x = ax*bx + ay*by * y = ax*by - ay*bx */ const double ax = node.next->point->x - node.point->x; const double ay = node.next->point->y - node.point->y; const double bx = node.prev->point->x - node.point->x; const double by = node.prev->point->y - node.point->y; return atan2(ax * by - ay * bx, ax * bx + ay * by); } bool Sweep::Legalize(SweepContext& tcx, Triangle& t) { // To legalize a triangle we start by finding if any of the three edges // violate the Delaunay condition for (int i = 0; i < 3; i++) { if (t.delaunay_edge[i]) continue; Triangle* ot = t.GetNeighbor(i); if (ot) { Point* p = t.GetPoint(i); Point* op = ot->OppositePoint(t, *p); int oi = ot->Index(op); // If this is a Constrained Edge or a Delaunay Edge(only during recursive legalization) // then we should not try to legalize if (ot->constrained_edge[oi] || ot->delaunay_edge[oi]) { t.constrained_edge[i] = ot->constrained_edge[oi]; continue; } bool inside = Incircle(*p, *t.PointCCW(*p), *t.PointCW(*p), *op); if (inside) { // Lets mark this shared edge as Delaunay t.delaunay_edge[i] = true; ot->delaunay_edge[oi] = true; // Lets rotate shared edge one vertex CW to legalize it RotateTrianglePair(t, *p, *ot, *op); // We now got one valid Delaunay Edge shared by two triangles // This gives us 4 new edges to check for Delaunay // Make sure that triangle to node mapping is done only one time for a specific triangle bool not_legalized = !Legalize(tcx, t); if (not_legalized) { tcx.MapTriangleToNodes(t); } not_legalized = !Legalize(tcx, *ot); if (not_legalized) tcx.MapTriangleToNodes(*ot); // Reset the Delaunay edges, since they only are valid Delaunay edges // until we add a new triangle or point. // XXX: need to think about this. Can these edges be tried after we // return to previous recursive level? t.delaunay_edge[i] = false; ot->delaunay_edge[oi] = false; // If triangle have been legalized no need to check the other edges since // the recursive legalization will handles those so we can end here. return true; } } } return false; } bool Sweep::Incircle(const Point& pa, const Point& pb, const Point& pc, const Point& pd) const { const double adx = pa.x - pd.x; const double ady = pa.y - pd.y; const double bdx = pb.x - pd.x; const double bdy = pb.y - pd.y; const double adxbdy = adx * bdy; const double bdxady = bdx * ady; const double oabd = adxbdy - bdxady; if (oabd <= 0) return false; const double cdx = pc.x - pd.x; const double cdy = pc.y - pd.y; const double cdxady = cdx * ady; const double adxcdy = adx * cdy; const double ocad = cdxady - adxcdy; if (ocad <= 0) return false; const double bdxcdy = bdx * cdy; const double cdxbdy = cdx * bdy; const double alift = adx * adx + ady * ady; const double blift = bdx * bdx + bdy * bdy; const double clift = cdx * cdx + cdy * cdy; const double det = alift * (bdxcdy - cdxbdy) + blift * ocad + clift * oabd; return det > 0; } void Sweep::RotateTrianglePair(Triangle& t, Point& p, Triangle& ot, Point& op) const { Triangle* n1, *n2, *n3, *n4; n1 = t.NeighborCCW(p); n2 = t.NeighborCW(p); n3 = ot.NeighborCCW(op); n4 = ot.NeighborCW(op); bool ce1, ce2, ce3, ce4; ce1 = t.GetConstrainedEdgeCCW(p); ce2 = t.GetConstrainedEdgeCW(p); ce3 = ot.GetConstrainedEdgeCCW(op); ce4 = ot.GetConstrainedEdgeCW(op); bool de1, de2, de3, de4; de1 = t.GetDelunayEdgeCCW(p); de2 = t.GetDelunayEdgeCW(p); de3 = ot.GetDelunayEdgeCCW(op); de4 = ot.GetDelunayEdgeCW(op); t.Legalize(p, op); ot.Legalize(op, p); // Remap delaunay_edge ot.SetDelunayEdgeCCW(p, de1); t.SetDelunayEdgeCW(p, de2); t.SetDelunayEdgeCCW(op, de3); ot.SetDelunayEdgeCW(op, de4); // Remap constrained_edge ot.SetConstrainedEdgeCCW(p, ce1); t.SetConstrainedEdgeCW(p, ce2); t.SetConstrainedEdgeCCW(op, ce3); ot.SetConstrainedEdgeCW(op, ce4); // Remap neighbors // XXX: might optimize the markNeighbor by keeping track of // what side should be assigned to what neighbor after the // rotation. Now mark neighbor does lots of testing to find // the right side. t.ClearNeighbors(); ot.ClearNeighbors(); if (n1) ot.MarkNeighbor(*n1); if (n2) t.MarkNeighbor(*n2); if (n3) t.MarkNeighbor(*n3); if (n4) ot.MarkNeighbor(*n4); t.MarkNeighbor(ot); } void Sweep::FillBasin(SweepContext& tcx, Node& node) { if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) { tcx.basin.left_node = node.next->next; } else { tcx.basin.left_node = node.next; } // Find the bottom and right node tcx.basin.bottom_node = tcx.basin.left_node; while (tcx.basin.bottom_node->next && tcx.basin.bottom_node->point->y >= tcx.basin.bottom_node->next->point->y) { tcx.basin.bottom_node = tcx.basin.bottom_node->next; } if (tcx.basin.bottom_node == tcx.basin.left_node) { // No valid basin return; } tcx.basin.right_node = tcx.basin.bottom_node; while (tcx.basin.right_node->next && tcx.basin.right_node->point->y < tcx.basin.right_node->next->point->y) { tcx.basin.right_node = tcx.basin.right_node->next; } if (tcx.basin.right_node == tcx.basin.bottom_node) { // No valid basins return; } tcx.basin.width = tcx.basin.right_node->point->x - tcx.basin.left_node->point->x; tcx.basin.left_highest = tcx.basin.left_node->point->y > tcx.basin.right_node->point->y; FillBasinReq(tcx, tcx.basin.bottom_node); } void Sweep::FillBasinReq(SweepContext& tcx, Node* node) { // if shallow stop filling if (IsShallow(tcx, *node)) { return; } Fill(tcx, *node); if (node->prev == tcx.basin.left_node && node->next == tcx.basin.right_node) { return; } else if (node->prev == tcx.basin.left_node) { Orientation o = Orient2d(*node->point, *node->next->point, *node->next->next->point); if (o == CW) { return; } node = node->next; } else if (node->next == tcx.basin.right_node) { Orientation o = Orient2d(*node->point, *node->prev->point, *node->prev->prev->point); if (o == CCW) { return; } node = node->prev; } else { // Continue with the neighbor node with lowest Y value if (node->prev->point->y < node->next->point->y) { node = node->prev; } else { node = node->next; } } FillBasinReq(tcx, node); } bool Sweep::IsShallow(SweepContext& tcx, Node& node) { double height; if (tcx.basin.left_highest) { height = tcx.basin.left_node->point->y - node.point->y; } else { height = tcx.basin.right_node->point->y - node.point->y; } // if shallow stop filling if (tcx.basin.width > height) { return true; } return false; } void Sweep::FillEdgeEvent(SweepContext& tcx, Edge* edge, Node* node) { if (tcx.edge_event.right) { FillRightAboveEdgeEvent(tcx, edge, node); } else { FillLeftAboveEdgeEvent(tcx, edge, node); } } void Sweep::FillRightAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node) { while (node->next->point->x < edge->p->x) { // Check if next node is below the edge if (Orient2d(*edge->q, *node->next->point, *edge->p) == CCW) { FillRightBelowEdgeEvent(tcx, edge, *node); } else { node = node->next; } } } void Sweep::FillRightBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { if (node.point->x < edge->p->x) { if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) { // Concave FillRightConcaveEdgeEvent(tcx, edge, node); } else{ // Convex FillRightConvexEdgeEvent(tcx, edge, node); // Retry this one FillRightBelowEdgeEvent(tcx, edge, node); } } } void Sweep::FillRightConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { Fill(tcx, *node.next); if (node.next->point != edge->p) { // Next above or below edge? if (Orient2d(*edge->q, *node.next->point, *edge->p) == CCW) { // Below if (Orient2d(*node.point, *node.next->point, *node.next->next->point) == CCW) { // Next is concave FillRightConcaveEdgeEvent(tcx, edge, node); } else { // Next is convex } } } } void Sweep::FillRightConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { // Next concave or convex? if (Orient2d(*node.next->point, *node.next->next->point, *node.next->next->next->point) == CCW) { // Concave FillRightConcaveEdgeEvent(tcx, edge, *node.next); } else{ // Convex // Next above or below edge? if (Orient2d(*edge->q, *node.next->next->point, *edge->p) == CCW) { // Below FillRightConvexEdgeEvent(tcx, edge, *node.next); } else{ // Above } } } void Sweep::FillLeftAboveEdgeEvent(SweepContext& tcx, Edge* edge, Node* node) { while (node->prev->point->x > edge->p->x) { // Check if next node is below the edge if (Orient2d(*edge->q, *node->prev->point, *edge->p) == CW) { FillLeftBelowEdgeEvent(tcx, edge, *node); } else { node = node->prev; } } } void Sweep::FillLeftBelowEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { if (node.point->x > edge->p->x) { if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) { // Concave FillLeftConcaveEdgeEvent(tcx, edge, node); } else { // Convex FillLeftConvexEdgeEvent(tcx, edge, node); // Retry this one FillLeftBelowEdgeEvent(tcx, edge, node); } } } void Sweep::FillLeftConvexEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { // Next concave or convex? if (Orient2d(*node.prev->point, *node.prev->prev->point, *node.prev->prev->prev->point) == CW) { // Concave FillLeftConcaveEdgeEvent(tcx, edge, *node.prev); } else{ // Convex // Next above or below edge? if (Orient2d(*edge->q, *node.prev->prev->point, *edge->p) == CW) { // Below FillLeftConvexEdgeEvent(tcx, edge, *node.prev); } else{ // Above } } } void Sweep::FillLeftConcaveEdgeEvent(SweepContext& tcx, Edge* edge, Node& node) { Fill(tcx, *node.prev); if (node.prev->point != edge->p) { // Next above or below edge? if (Orient2d(*edge->q, *node.prev->point, *edge->p) == CW) { // Below if (Orient2d(*node.point, *node.prev->point, *node.prev->prev->point) == CW) { // Next is concave FillLeftConcaveEdgeEvent(tcx, edge, node); } else{ // Next is convex } } } } void Sweep::FlipEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle* t, Point& p) { Triangle& ot = t->NeighborAcross(p); Point& op = *ot.OppositePoint(*t, p); if (InScanArea(p, *t->PointCCW(p), *t->PointCW(p), op)) { // Lets rotate shared edge one vertex CW RotateTrianglePair(*t, p, ot, op); tcx.MapTriangleToNodes(*t); tcx.MapTriangleToNodes(ot); if (p == eq && op == ep) { if (eq == *tcx.edge_event.constrained_edge->q && ep == *tcx.edge_event.constrained_edge->p) { t->MarkConstrainedEdge(&ep, &eq); ot.MarkConstrainedEdge(&ep, &eq); Legalize(tcx, *t); Legalize(tcx, ot); } else { // XXX: I think one of the triangles should be legalized here? } } else { Orientation o = Orient2d(eq, op, ep); t = &NextFlipTriangle(tcx, (int)o, *t, ot, p, op); FlipEdgeEvent(tcx, ep, eq, t, p); } } else { Point& newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, *t, ot, newP); EdgeEvent(tcx, ep, eq, t, p); } } Triangle& Sweep::NextFlipTriangle(SweepContext& tcx, int o, Triangle& t, Triangle& ot, Point& p, Point& op) { if (o == CCW) { // ot is not crossing edge after flip int edge_index = ot.EdgeIndex(&p, &op); ot.delaunay_edge[edge_index] = true; Legalize(tcx, ot); ot.ClearDelunayEdges(); return t; } // t is not crossing edge after flip int edge_index = t.EdgeIndex(&p, &op); t.delaunay_edge[edge_index] = true; Legalize(tcx, t); t.ClearDelunayEdges(); return ot; } Point& Sweep::NextFlipPoint(Point& ep, Point& eq, Triangle& ot, Point& op) { Orientation o2d = Orient2d(eq, op, ep); if (o2d == CW) { // Right return *ot.PointCCW(op); } else if (o2d == CCW) { // Left return *ot.PointCW(op); } throw std::runtime_error("[Unsupported] Opposing point on constrained edge"); } void Sweep::FlipScanEdgeEvent(SweepContext& tcx, Point& ep, Point& eq, Triangle& flip_triangle, Triangle& t, Point& p) { Triangle& ot = t.NeighborAcross(p); Point& op = *ot.OppositePoint(t, p); if (InScanArea(eq, *flip_triangle.PointCCW(eq), *flip_triangle.PointCW(eq), op)) { // flip with new edge op->eq FlipEdgeEvent(tcx, eq, op, &ot, op); // TODO: Actually I just figured out that it should be possible to // improve this by getting the next ot and op before the the above // flip and continue the flipScanEdgeEvent here // set new ot and op here and loop back to inScanArea test // also need to set a new flip_triangle first // Turns out at first glance that this is somewhat complicated // so it will have to wait. } else{ Point& newP = NextFlipPoint(ep, eq, ot, op); FlipScanEdgeEvent(tcx, ep, eq, flip_triangle, ot, newP); } } Sweep::~Sweep() { // Clean up memory for(size_t i = 0; i < nodes_.size(); i++) { delete nodes_[i]; } } } assimp-4.1.0/contrib/poly2tri/poly2tri/common/0000755002537200234200000000000013213503245021554 5ustar zmoelnigiemusersassimp-4.1.0/contrib/poly2tri/poly2tri/common/shapes.h0000644002537200234200000001701513213503245023214 0ustar zmoelnigiemusers/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * 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 Poly2Tri 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 guard #ifndef SHAPES_H #define SHAPES_H #include #include #include #include #include #include namespace p2t { struct Edge; struct Point { double x, y; /// Default constructor does nothing (for performance). Point() { x = 0.0; y = 0.0; } /// The edges this point constitutes an upper ending point std::vector edge_list; /// Construct using coordinates. Point(double x, double y) : x(x), y(y) {} /// Set this point to all zeros. void set_zero() { x = 0.0; y = 0.0; } /// Set this point to some specified coordinates. void set(double x_, double y_) { x = x_; y = y_; } /// Negate this point. Point operator -() const { Point v; v.set(-x, -y); return v; } /// Add a point to this point. void operator +=(const Point& v) { x += v.x; y += v.y; } /// Subtract a point from this point. void operator -=(const Point& v) { x -= v.x; y -= v.y; } /// Multiply this point by a scalar. void operator *=(double a) { x *= a; y *= a; } /// Get the length of this point (the norm). double Length() const { return sqrt(x * x + y * y); } /// Convert this point into a unit point. Returns the Length. double Normalize() { const double len = Length(); x /= len; y /= len; return len; } }; // Represents a simple polygon's edge struct Edge { Point* p, *q; /// Constructor Edge(Point& p1, Point& p2) : p(&p1), q(&p2) { if (p1.y > p2.y) { q = &p1; p = &p2; } else if (p1.y == p2.y) { if (p1.x > p2.x) { q = &p1; p = &p2; } else if (p1.x == p2.x) { // Repeat points // ASSIMP_CHANGE (aramis_acg) throw std::runtime_error(std::string("repeat points")); //assert(false); } } q->edge_list.push_back(this); } }; // Triangle-based data structures are know to have better performance than quad-edge structures // See: J. Shewchuk, "Triangle: Engineering a 2D Quality Mesh Generator and Delaunay Triangulator" // "Triangulations in CGAL" class Triangle { public: /// Constructor Triangle(Point& a, Point& b, Point& c); /// Flags to determine if an edge is a Constrained edge bool constrained_edge[3]; /// Flags to determine if an edge is a Delauney edge bool delaunay_edge[3]; Point* GetPoint(int index); Point* PointCW(const Point& point); Point* PointCCW(const Point& point); Point* OppositePoint(Triangle& t, const Point& p); Triangle* GetNeighbor(int index); void MarkNeighbor(Point* p1, Point* p2, Triangle* t); void MarkNeighbor(Triangle& t); void MarkConstrainedEdge(int index); void MarkConstrainedEdge(Edge& edge); void MarkConstrainedEdge(Point* p, Point* q); int Index(const Point* p); int EdgeIndex(const Point* p1, const Point* p2); Triangle* NeighborCW(const Point& point); Triangle* NeighborCCW(const Point& point); bool GetConstrainedEdgeCCW(const Point& p); bool GetConstrainedEdgeCW(const Point& p); void SetConstrainedEdgeCCW(const Point& p, bool ce); void SetConstrainedEdgeCW(const Point& p, bool ce); bool GetDelunayEdgeCCW(const Point& p); bool GetDelunayEdgeCW(const Point& p); void SetDelunayEdgeCCW(const Point& p, bool e); void SetDelunayEdgeCW(const Point& p, bool e); bool Contains(const Point* p); bool Contains(const Edge& e); bool Contains(const Point* p, const Point* q); void Legalize(Point& point); void Legalize(Point& opoint, Point& npoint); /** * Clears all references to all other triangles and points */ void Clear(); void ClearNeighbor(const Triangle *triangle); void ClearNeighbors(); void ClearDelunayEdges(); inline bool IsInterior(); inline void IsInterior(bool b); Triangle& NeighborAcross(const Point& opoint); void DebugPrint(); private: /// Triangle points Point* points_[3]; /// Neighbor list Triangle* neighbors_[3]; /// Has this triangle been marked as an interior triangle? bool interior_; }; inline bool cmp(const Point* a, const Point* b) { if (a->y < b->y) { return true; } else if (a->y == b->y) { // Make sure q is point with greater x value if (a->x < b->x) { return true; } } return false; } /// Add two points_ component-wise. inline Point operator +(const Point& a, const Point& b) { return Point(a.x + b.x, a.y + b.y); } /// Subtract two points_ component-wise. inline Point operator -(const Point& a, const Point& b) { return Point(a.x - b.x, a.y - b.y); } /// Multiply point by scalar inline Point operator *(double s, const Point& a) { return Point(s * a.x, s * a.y); } inline bool operator ==(const Point& a, const Point& b) { return a.x == b.x && a.y == b.y; } inline bool operator !=(const Point& a, const Point& b) { return !(a.x == b.x) && !(a.y == b.y); } /// Peform the dot product on two vectors. inline double Dot(const Point& a, const Point& b) { return a.x * b.x + a.y * b.y; } /// Perform the cross product on two vectors. In 2D this produces a scalar. inline double Cross(const Point& a, const Point& b) { return a.x * b.y - a.y * b.x; } /// Perform the cross product on a point and a scalar. In 2D this produces /// a point. inline Point Cross(const Point& a, double s) { return Point(s * a.y, -s * a.x); } /// Perform the cross product on a scalar and a point. In 2D this produces /// a point. inline Point Cross(double s, const Point& a) { return Point(-s * a.y, s * a.x); } inline Point* Triangle::GetPoint(int index) { return points_[index]; } inline Triangle* Triangle::GetNeighbor(int index) { return neighbors_[index]; } inline bool Triangle::Contains(const Point* p) { return p == points_[0] || p == points_[1] || p == points_[2]; } inline bool Triangle::Contains(const Edge& e) { return Contains(e.p) && Contains(e.q); } inline bool Triangle::Contains(const Point* p, const Point* q) { return Contains(p) && Contains(q); } inline bool Triangle::IsInterior() { return interior_; } inline void Triangle::IsInterior(bool b) { interior_ = b; } } #endifassimp-4.1.0/contrib/poly2tri/poly2tri/common/utils.h0000644002537200234200000000700213213503245023064 0ustar zmoelnigiemusers/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * 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 Poly2Tri 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 UTILS_H #define UTILS_H // Otherwise #defines like M_PI are undeclared under Visual Studio #define _USE_MATH_DEFINES #include #include // C99 removes M_PI from math.h #ifndef M_PI #define M_PI 3.14159265358979323846264338327 #endif namespace p2t { const double PI_3div4 = 3 * M_PI / 4; const double PI_div2 = 1.57079632679489661923; const double EPSILON = 1e-12; enum Orientation { CW, CCW, COLLINEAR }; /** * Forumla to calculate signed area
* Positive if CCW
* Negative if CW
* 0 if collinear
*
 * A[P1,P2,P3]  =  (x1*y2 - y1*x2) + (x2*y3 - y2*x3) + (x3*y1 - y3*x1)
 *              =  (x1-x3)*(y2-y3) - (y1-y3)*(x2-x3)
 * 
*/ Orientation Orient2d(const Point& pa, const Point& pb, const Point& pc) { double detleft = (pa.x - pc.x) * (pb.y - pc.y); double detright = (pa.y - pc.y) * (pb.x - pc.x); double val = detleft - detright; if (val > -EPSILON && val < EPSILON) { return COLLINEAR; } else if (val > 0) { return CCW; } return CW; } /* bool InScanArea(Point& pa, Point& pb, Point& pc, Point& pd) { double pdx = pd.x; double pdy = pd.y; double adx = pa.x - pdx; double ady = pa.y - pdy; double bdx = pb.x - pdx; double bdy = pb.y - pdy; double adxbdy = adx * bdy; double bdxady = bdx * ady; double oabd = adxbdy - bdxady; if (oabd <= EPSILON) { return false; } double cdx = pc.x - pdx; double cdy = pc.y - pdy; double cdxady = cdx * ady; double adxcdy = adx * cdy; double ocad = cdxady - adxcdy; if (ocad <= EPSILON) { return false; } return true; } */ bool InScanArea(const Point& pa, const Point& pb, const Point& pc, const Point& pd) { double oadb = (pa.x - pb.x)*(pd.y - pb.y) - (pd.x - pb.x)*(pa.y - pb.y); if (oadb >= -EPSILON) { return false; } double oadc = (pa.x - pc.x)*(pd.y - pc.y) - (pd.x - pc.x)*(pa.y - pc.y); if (oadc <= EPSILON) { return false; } return true; } } #endif assimp-4.1.0/contrib/poly2tri/poly2tri/common/shapes.cc0000644002537200234200000002172413213503245023354 0ustar zmoelnigiemusers/* * Poly2Tri Copyright (c) 2009-2010, Poly2Tri Contributors * http://code.google.com/p/poly2tri/ * * 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 Poly2Tri 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 "shapes.h" #include namespace p2t { Triangle::Triangle(Point& a, Point& b, Point& c) { points_[0] = &a; points_[1] = &b; points_[2] = &c; neighbors_[0] = NULL; neighbors_[1] = NULL; neighbors_[2] = NULL; constrained_edge[0] = constrained_edge[1] = constrained_edge[2] = false; delaunay_edge[0] = delaunay_edge[1] = delaunay_edge[2] = false; interior_ = false; } // Update neighbor pointers void Triangle::MarkNeighbor(Point* p1, Point* p2, Triangle* t) { if ((p1 == points_[2] && p2 == points_[1]) || (p1 == points_[1] && p2 == points_[2])) neighbors_[0] = t; else if ((p1 == points_[0] && p2 == points_[2]) || (p1 == points_[2] && p2 == points_[0])) neighbors_[1] = t; else if ((p1 == points_[0] && p2 == points_[1]) || (p1 == points_[1] && p2 == points_[0])) neighbors_[2] = t; else assert(0); } // Exhaustive search to update neighbor pointers void Triangle::MarkNeighbor(Triangle& t) { if (t.Contains(points_[1], points_[2])) { neighbors_[0] = &t; t.MarkNeighbor(points_[1], points_[2], this); } else if (t.Contains(points_[0], points_[2])) { neighbors_[1] = &t; t.MarkNeighbor(points_[0], points_[2], this); } else if (t.Contains(points_[0], points_[1])) { neighbors_[2] = &t; t.MarkNeighbor(points_[0], points_[1], this); } } /** * Clears all references to all other triangles and points */ void Triangle::Clear() { Triangle *t; for( int i=0; i<3; i++ ) { t = neighbors_[i]; if( t != NULL ) { t->ClearNeighbor( this ); } } ClearNeighbors(); points_[0]=points_[1]=points_[2] = NULL; } void Triangle::ClearNeighbor(const Triangle *triangle ) { if( neighbors_[0] == triangle ) { neighbors_[0] = NULL; } else if( neighbors_[1] == triangle ) { neighbors_[1] = NULL; } else { neighbors_[2] = NULL; } } void Triangle::ClearNeighbors() { neighbors_[0] = NULL; neighbors_[1] = NULL; neighbors_[2] = NULL; } void Triangle::ClearDelunayEdges() { delaunay_edge[0] = delaunay_edge[1] = delaunay_edge[2] = false; } Point* Triangle::OppositePoint(Triangle& t, const Point& p) { Point *cw = t.PointCW(p); return PointCW(*cw); } // Legalized triangle by rotating clockwise around point(0) void Triangle::Legalize(Point& point) { points_[1] = points_[0]; points_[0] = points_[2]; points_[2] = &point; } // Legalize triagnle by rotating clockwise around oPoint void Triangle::Legalize(Point& opoint, Point& npoint) { if (&opoint == points_[0]) { points_[1] = points_[0]; points_[0] = points_[2]; points_[2] = &npoint; } else if (&opoint == points_[1]) { points_[2] = points_[1]; points_[1] = points_[0]; points_[0] = &npoint; } else if (&opoint == points_[2]) { points_[0] = points_[2]; points_[2] = points_[1]; points_[1] = &npoint; } else { assert(0); } } int Triangle::Index(const Point* p) { if (p == points_[0]) { return 0; } else if (p == points_[1]) { return 1; } else if (p == points_[2]) { return 2; } assert(0); return -1; } int Triangle::EdgeIndex(const Point* p1, const Point* p2) { if (points_[0] == p1) { if (points_[1] == p2) { return 2; } else if (points_[2] == p2) { return 1; } } else if (points_[1] == p1) { if (points_[2] == p2) { return 0; } else if (points_[0] == p2) { return 2; } } else if (points_[2] == p1) { if (points_[0] == p2) { return 1; } else if (points_[1] == p2) { return 0; } } return -1; } void Triangle::MarkConstrainedEdge(int index) { constrained_edge[index] = true; } void Triangle::MarkConstrainedEdge(Edge& edge) { MarkConstrainedEdge(edge.p, edge.q); } // Mark edge as constrained void Triangle::MarkConstrainedEdge(Point* p, Point* q) { if ((q == points_[0] && p == points_[1]) || (q == points_[1] && p == points_[0])) { constrained_edge[2] = true; } else if ((q == points_[0] && p == points_[2]) || (q == points_[2] && p == points_[0])) { constrained_edge[1] = true; } else if ((q == points_[1] && p == points_[2]) || (q == points_[2] && p == points_[1])) { constrained_edge[0] = true; } } // The point counter-clockwise to given point Point* Triangle::PointCW(const Point& point) { if (&point == points_[0]) { return points_[2]; } else if (&point == points_[1]) { return points_[0]; } else if (&point == points_[2]) { return points_[1]; } assert(0); return NULL; } // The point counter-clockwise to given point Point* Triangle::PointCCW(const Point& point) { if (&point == points_[0]) { return points_[1]; } else if (&point == points_[1]) { return points_[2]; } else if (&point == points_[2]) { return points_[0]; } assert(0); return NULL; } // The neighbor clockwise to given point Triangle* Triangle::NeighborCW(const Point& point) { if (&point == points_[0]) { return neighbors_[1]; } else if (&point == points_[1]) { return neighbors_[2]; } return neighbors_[0]; } // The neighbor counter-clockwise to given point Triangle* Triangle::NeighborCCW(const Point& point) { if (&point == points_[0]) { return neighbors_[2]; } else if (&point == points_[1]) { return neighbors_[0]; } return neighbors_[1]; } bool Triangle::GetConstrainedEdgeCCW(const Point& p) { if (&p == points_[0]) { return constrained_edge[2]; } else if (&p == points_[1]) { return constrained_edge[0]; } return constrained_edge[1]; } bool Triangle::GetConstrainedEdgeCW(const Point& p) { if (&p == points_[0]) { return constrained_edge[1]; } else if (&p == points_[1]) { return constrained_edge[2]; } return constrained_edge[0]; } void Triangle::SetConstrainedEdgeCCW(const Point& p, bool ce) { if (&p == points_[0]) { constrained_edge[2] = ce; } else if (&p == points_[1]) { constrained_edge[0] = ce; } else { constrained_edge[1] = ce; } } void Triangle::SetConstrainedEdgeCW(const Point& p, bool ce) { if (&p == points_[0]) { constrained_edge[1] = ce; } else if (&p == points_[1]) { constrained_edge[2] = ce; } else { constrained_edge[0] = ce; } } bool Triangle::GetDelunayEdgeCCW(const Point& p) { if (&p == points_[0]) { return delaunay_edge[2]; } else if (&p == points_[1]) { return delaunay_edge[0]; } return delaunay_edge[1]; } bool Triangle::GetDelunayEdgeCW(const Point& p) { if (&p == points_[0]) { return delaunay_edge[1]; } else if (&p == points_[1]) { return delaunay_edge[2]; } return delaunay_edge[0]; } void Triangle::SetDelunayEdgeCCW(const Point& p, bool e) { if (&p == points_[0]) { delaunay_edge[2] = e; } else if (&p == points_[1]) { delaunay_edge[0] = e; } else { delaunay_edge[1] = e; } } void Triangle::SetDelunayEdgeCW(const Point& p, bool e) { if (&p == points_[0]) { delaunay_edge[1] = e; } else if (&p == points_[1]) { delaunay_edge[2] = e; } else { delaunay_edge[0] = e; } } // The neighbor across to given point Triangle& Triangle::NeighborAcross(const Point& opoint) { if (&opoint == points_[0]) { return *neighbors_[0]; } else if (&opoint == points_[1]) { return *neighbors_[1]; } return *neighbors_[2]; } void Triangle::DebugPrint() { using namespace std; cout << points_[0]->x << "," << points_[0]->y << " "; cout << points_[1]->x << "," << points_[1]->y << " "; cout << points_[2]->x << "," << points_[2]->y << endl; } }assimp-4.1.0/contrib/clipper/0000755002537200234200000000000013213503245016352 5ustar zmoelnigiemusersassimp-4.1.0/contrib/clipper/License.txt0000644002537200234200000000304713213503245020501 0ustar zmoelnigiemusersThe Clipper code library, the "Software" (that includes Delphi, C++ & C# source code, accompanying samples and documentation), has been released under the following license, terms and conditions: Boost Software License - Version 1.0 - August 17th, 2003 http://www.boost.org/LICENSE_1_0.txt Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following: The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor. 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. assimp-4.1.0/contrib/clipper/clipper.hpp0000644002537200234200000002475713213503245020540 0ustar zmoelnigiemusers/******************************************************************************* * * * Author : Angus Johnson * * Version : 4.8.8 * * Date : 30 August 2012 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2012 * * * * License: * * Use, modification & distribution is subject to Boost Software License Ver 1. * * http://www.boost.org/LICENSE_1_0.txt * * * * Attributions: * * The code in this library is an extension of Bala Vatti's clipping algorithm: * * "A generic solution to polygon clipping" * * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * * http://portal.acm.org/citation.cfm?id=129906 * * * * Computer graphics and geometric modeling: implementation and algorithms * * By Max K. Agoston * * Springer; 1 edition (January 4, 2005) * * http://books.google.com/books?q=vatti+clipping+agoston * * * * See also: * * "Polygon Offsetting by Computing Winding Numbers" * * Paper no. DETC2005-85513 pp. 565-575 * * ASME 2005 International Design Engineering Technical Conferences * * and Computers and Information in Engineering Conference (IDETC/CIE2005) * * September 24-28, 2005 , Long Beach, California, USA * * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * * * *******************************************************************************/ #ifndef clipper_hpp #define clipper_hpp #include #include #include #include #include namespace ClipperLib { enum ClipType { ctIntersection, ctUnion, ctDifference, ctXor }; enum PolyType { ptSubject, ptClip }; //By far the most widely used winding rules for polygon filling are //EvenOdd & NonZero (GDI, GDI+, XLib, OpenGL, Cairo, AGG, Quartz, SVG, Gr32) //Others rules include Positive, Negative and ABS_GTR_EQ_TWO (only in OpenGL) //see http://glprogramming.com/red/chapter11.html enum PolyFillType { pftEvenOdd, pftNonZero, pftPositive, pftNegative }; typedef signed long long long64; typedef unsigned long long ulong64; struct IntPoint { public: long64 X; long64 Y; IntPoint(long64 x = 0, long64 y = 0): X(x), Y(y) {}; friend std::ostream& operator <<(std::ostream &s, IntPoint &p); }; typedef std::vector< IntPoint > Polygon; typedef std::vector< Polygon > Polygons; std::ostream& operator <<(std::ostream &s, Polygon &p); std::ostream& operator <<(std::ostream &s, Polygons &p); struct ExPolygon { Polygon outer; Polygons holes; }; typedef std::vector< ExPolygon > ExPolygons; enum JoinType { jtSquare, jtRound, jtMiter }; bool Orientation(const Polygon &poly); double Area(const Polygon &poly); void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys, double delta, JoinType jointype = jtSquare, double MiterLimit = 2); void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType = pftEvenOdd); void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType = pftEvenOdd); void SimplifyPolygons(Polygons &polys, PolyFillType fillType = pftEvenOdd); void ReversePolygon(Polygon& p); void ReversePolygons(Polygons& p); //used internally ... enum EdgeSide { esNeither = 0, esLeft = 1, esRight = 2, esBoth = 3 }; enum IntersectProtects { ipNone = 0, ipLeft = 1, ipRight = 2, ipBoth = 3 }; struct TEdge { long64 xbot; long64 ybot; long64 xcurr; long64 ycurr; long64 xtop; long64 ytop; double dx; long64 tmpX; PolyType polyType; EdgeSide side; int windDelta; //1 or -1 depending on winding direction int windCnt; int windCnt2; //winding count of the opposite polytype int outIdx; TEdge *next; TEdge *prev; TEdge *nextInLML; TEdge *nextInAEL; TEdge *prevInAEL; TEdge *nextInSEL; TEdge *prevInSEL; }; struct IntersectNode { TEdge *edge1; TEdge *edge2; IntPoint pt; IntersectNode *next; }; struct LocalMinima { long64 Y; TEdge *leftBound; TEdge *rightBound; LocalMinima *next; }; struct Scanbeam { long64 Y; Scanbeam *next; }; struct OutPt; //forward declaration struct OutRec { int idx; bool isHole; OutRec *FirstLeft; OutRec *AppendLink; OutPt *pts; OutPt *bottomPt; OutPt *bottomFlag; EdgeSide sides; }; struct OutPt { int idx; IntPoint pt; OutPt *next; OutPt *prev; }; struct JoinRec { IntPoint pt1a; IntPoint pt1b; int poly1Idx; IntPoint pt2a; IntPoint pt2b; int poly2Idx; }; struct HorzJoinRec { TEdge *edge; int savedIdx; }; struct IntRect { long64 left; long64 top; long64 right; long64 bottom; }; typedef std::vector < OutRec* > PolyOutList; typedef std::vector < TEdge* > EdgeList; typedef std::vector < JoinRec* > JoinList; typedef std::vector < HorzJoinRec* > HorzJoinList; //ClipperBase is the ancestor to the Clipper class. It should not be //instantiated directly. This class simply abstracts the conversion of sets of //polygon coordinates into edge objects that are stored in a LocalMinima list. class ClipperBase { public: ClipperBase(); virtual ~ClipperBase(); bool AddPolygon(const Polygon &pg, PolyType polyType); bool AddPolygons( const Polygons &ppg, PolyType polyType); virtual void Clear(); IntRect GetBounds(); protected: void DisposeLocalMinimaList(); TEdge* AddBoundsToLML(TEdge *e); void PopLocalMinima(); virtual void Reset(); void InsertLocalMinima(LocalMinima *newLm); LocalMinima *m_CurrentLM; LocalMinima *m_MinimaList; bool m_UseFullRange; EdgeList m_edges; }; class Clipper : public virtual ClipperBase { public: Clipper(); ~Clipper(); bool Execute(ClipType clipType, Polygons &solution, PolyFillType subjFillType = pftEvenOdd, PolyFillType clipFillType = pftEvenOdd); bool Execute(ClipType clipType, ExPolygons &solution, PolyFillType subjFillType = pftEvenOdd, PolyFillType clipFillType = pftEvenOdd); void Clear(); bool ReverseSolution() {return m_ReverseOutput;}; void ReverseSolution(bool value) {m_ReverseOutput = value;}; protected: void Reset(); virtual bool ExecuteInternal(bool fixHoleLinkages); private: PolyOutList m_PolyOuts; JoinList m_Joins; HorzJoinList m_HorizJoins; ClipType m_ClipType; Scanbeam *m_Scanbeam; TEdge *m_ActiveEdges; TEdge *m_SortedEdges; IntersectNode *m_IntersectNodes; bool m_ExecuteLocked; PolyFillType m_ClipFillType; PolyFillType m_SubjFillType; bool m_ReverseOutput; void DisposeScanbeamList(); void SetWindingCount(TEdge& edge); bool IsEvenOddFillType(const TEdge& edge) const; bool IsEvenOddAltFillType(const TEdge& edge) const; void InsertScanbeam(const long64 Y); long64 PopScanbeam(); void InsertLocalMinimaIntoAEL(const long64 botY); void InsertEdgeIntoAEL(TEdge *edge); void AddEdgeToSEL(TEdge *edge); void CopyAELToSEL(); void DeleteFromSEL(TEdge *e); void DeleteFromAEL(TEdge *e); void UpdateEdgeIntoAEL(TEdge *&e); void SwapPositionsInSEL(TEdge *edge1, TEdge *edge2); bool IsContributing(const TEdge& edge) const; bool IsTopHorz(const long64 XPos); void SwapPositionsInAEL(TEdge *edge1, TEdge *edge2); void DoMaxima(TEdge *e, long64 topY); void ProcessHorizontals(); void ProcessHorizontal(TEdge *horzEdge); void AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); void AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt); void AppendPolygon(TEdge *e1, TEdge *e2); void DoEdge1(TEdge *edge1, TEdge *edge2, const IntPoint &pt); void DoEdge2(TEdge *edge1, TEdge *edge2, const IntPoint &pt); void DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt); void IntersectEdges(TEdge *e1, TEdge *e2, const IntPoint &pt, IntersectProtects protects); OutRec* CreateOutRec(); void AddOutPt(TEdge *e, const IntPoint &pt); void DisposeBottomPt(OutRec &outRec); void DisposeAllPolyPts(); void DisposeOutRec(PolyOutList::size_type index); bool ProcessIntersections(const long64 botY, const long64 topY); void AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt); void BuildIntersectList(const long64 botY, const long64 topY); void ProcessIntersectList(); void ProcessEdgesAtTopOfScanbeam(const long64 topY); void BuildResult(Polygons& polys); void BuildResultEx(ExPolygons& polys); void SetHoleState(TEdge *e, OutRec *OutRec); void DisposeIntersectNodes(); bool FixupIntersections(); void FixupOutPolygon(OutRec &outRec); bool IsHole(TEdge *e); void FixHoleLinkage(OutRec *outRec); void CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2); void CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2); void AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx = -1, int e2OutIdx = -1); void ClearJoins(); void AddHorzJoin(TEdge *e, int idx); void ClearHorzJoins(); void JoinCommonEdges(bool fixHoleLinkages); }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ class clipperException : public std::exception { public: clipperException(const char* description): m_descr(description) {} virtual ~clipperException() throw() {} virtual const char* what() const throw() {return m_descr.c_str();} private: std::string m_descr; }; //------------------------------------------------------------------------------ } //ClipperLib namespace #endif //clipper_hpp assimp-4.1.0/contrib/clipper/clipper.cpp0000644002537200234200000031162013213503245020517 0ustar zmoelnigiemusers/******************************************************************************* * * * Author : Angus Johnson * * Version : 4.8.8 * * Date : 30 August 2012 * * Website : http://www.angusj.com * * Copyright : Angus Johnson 2010-2012 * * * * License: * * Use, modification & distribution is subject to Boost Software License Ver 1. * * http://www.boost.org/LICENSE_1_0.txt * * * * Attributions: * * The code in this library is an extension of Bala Vatti's clipping algorithm: * * "A generic solution to polygon clipping" * * Communications of the ACM, Vol 35, Issue 7 (July 1992) pp 56-63. * * http://portal.acm.org/citation.cfm?id=129906 * * * * Computer graphics and geometric modeling: implementation and algorithms * * By Max K. Agoston * * Springer; 1 edition (January 4, 2005) * * http://books.google.com/books?q=vatti+clipping+agoston * * * * See also: * * "Polygon Offsetting by Computing Winding Numbers" * * Paper no. DETC2005-85513 pp. 565-575 * * ASME 2005 International Design Engineering Technical Conferences * * and Computers and Information in Engineering Conference (IDETC/CIE2005) * * September 24-28, 2005 , Long Beach, California, USA * * http://www.me.berkeley.edu/~mcmains/pubs/DAC05OffsetPolygon.pdf * * * *******************************************************************************/ /******************************************************************************* * * * This is a translation of the Delphi Clipper library and the naming style * * used has retained a Delphi flavour. * * * *******************************************************************************/ #include "clipper.hpp" #include #include #include #include #include #include #include #include namespace ClipperLib { static long64 const loRange = 0x3FFFFFFF; static long64 const hiRange = 0x3FFFFFFFFFFFFFFFLL; static double const pi = 3.141592653589793238; enum Direction { dRightToLeft, dLeftToRight }; #define HORIZONTAL (-1.0E+40) #define TOLERANCE (1.0e-20) #define NEAR_ZERO(val) (((val) > -TOLERANCE) && ((val) < TOLERANCE)) #define NEAR_EQUAL(a, b) NEAR_ZERO((a) - (b)) inline long64 Abs(long64 val) { return val < 0 ? -val : val; } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ // Int128 class (enables safe math on signed 64bit integers) // eg Int128 val1((long64)9223372036854775807); //ie 2^63 -1 // Int128 val2((long64)9223372036854775807); // Int128 val3 = val1 * val2; // val3.AsString => "85070591730234615847396907784232501249" (8.5e+37) //------------------------------------------------------------------------------ class Int128 { public: Int128(long64 _lo = 0) { lo = _lo; if (lo < 0) hi = -1; else hi = 0; } Int128(const Int128 &val): hi(val.hi), lo(val.lo){} long64 operator = (const long64 &val) { lo = val; if (lo < 0) hi = -1; else hi = 0; return val; } bool operator == (const Int128 &val) const {return (hi == val.hi && lo == val.lo);} bool operator != (const Int128 &val) const { return !(*this == val);} bool operator > (const Int128 &val) const { if (hi != val.hi) return hi > val.hi; else return lo > val.lo; } bool operator < (const Int128 &val) const { if (hi != val.hi) return hi < val.hi; else return lo < val.lo; } bool operator >= (const Int128 &val) const { return !(*this < val);} bool operator <= (const Int128 &val) const { return !(*this > val);} Int128& operator += (const Int128 &rhs) { hi += rhs.hi; lo += rhs.lo; if (ulong64(lo) < ulong64(rhs.lo)) hi++; return *this; } Int128 operator + (const Int128 &rhs) const { Int128 result(*this); result+= rhs; return result; } Int128& operator -= (const Int128 &rhs) { Int128 tmp(rhs); Negate(tmp); *this += tmp; return *this; } //Int128 operator -() const //{ // Int128 result(*this); // if (result.lo == 0) { // if (result.hi != 0) result.hi = -1; // } // else { // result.lo = -result.lo; // result.hi = ~result.hi; // } // return result; //} Int128 operator - (const Int128 &rhs) const { Int128 result(*this); result -= rhs; return result; } Int128 operator * (const Int128 &rhs) const { if ( !(hi == 0 || hi == -1) || !(rhs.hi == 0 || rhs.hi == -1)) throw "Int128 operator*: overflow error"; bool negate = (hi < 0) != (rhs.hi < 0); Int128 tmp(*this); if (tmp.hi < 0) Negate(tmp); ulong64 int1Hi = ulong64(tmp.lo) >> 32; ulong64 int1Lo = ulong64(tmp.lo & 0xFFFFFFFF); tmp = rhs; if (tmp.hi < 0) Negate(tmp); ulong64 int2Hi = ulong64(tmp.lo) >> 32; ulong64 int2Lo = ulong64(tmp.lo & 0xFFFFFFFF); //nb: see comments in clipper.pas ulong64 a = int1Hi * int2Hi; ulong64 b = int1Lo * int2Lo; ulong64 c = int1Hi * int2Lo + int1Lo * int2Hi; tmp.hi = long64(a + (c >> 32)); tmp.lo = long64(c << 32); tmp.lo += long64(b); if (ulong64(tmp.lo) < b) tmp.hi++; if (negate) Negate(tmp); return tmp; } Int128 operator/ (const Int128 &rhs) const { if (rhs.lo == 0 && rhs.hi == 0) throw "Int128 operator/: divide by zero"; bool negate = (rhs.hi < 0) != (hi < 0); Int128 result(*this), denom(rhs); if (result.hi < 0) Negate(result); if (denom.hi < 0) Negate(denom); if (denom > result) return Int128(0); //result is only a fraction of 1 Negate(denom); Int128 p(0); for (int i = 0; i < 128; ++i) { p.hi = p.hi << 1; if (p.lo < 0) p.hi++; p.lo = long64(p.lo) << 1; if (result.hi < 0) p.lo++; result.hi = result.hi << 1; if (result.lo < 0) result.hi++; result.lo = long64(result.lo) << 1; Int128 p2(p); p += denom; if (p.hi < 0) p = p2; else result.lo++; } if (negate) Negate(result); return result; } double AsDouble() const { const double shift64 = 18446744073709551616.0; //2^64 const double bit64 = 9223372036854775808.0; if (hi < 0) { Int128 tmp(*this); Negate(tmp); if (tmp.lo < 0) return (double)tmp.lo - bit64 - tmp.hi * shift64; else return -(double)tmp.lo - tmp.hi * shift64; } else if (lo < 0) return -(double)lo + bit64 + hi * shift64; else return (double)lo + (double)hi * shift64; } //for bug testing ... //std::string AsString() const //{ // std::string result; // unsigned char r = 0; // Int128 tmp(0), val(*this); // if (hi < 0) Negate(val); // result.resize(50); // std::string::size_type i = result.size() -1; // while (val.hi != 0 || val.lo != 0) // { // Div10(val, tmp, r); // result[i--] = char('0' + r); // val = tmp; // } // if (hi < 0) result[i--] = '-'; // result.erase(0,i+1); // if (result.size() == 0) result = "0"; // return result; //} private: long64 hi; long64 lo; static void Negate(Int128 &val) { if (val.lo == 0) { if (val.hi != 0) val.hi = -val.hi;; } else { val.lo = -val.lo; val.hi = ~val.hi; } } //debugging only ... //void Div10(const Int128 val, Int128& result, unsigned char & remainder) const //{ // remainder = 0; // result = 0; // for (int i = 63; i >= 0; --i) // { // if ((val.hi & ((long64)1 << i)) != 0) // remainder = char((remainder * 2) + 1); else // remainder *= char(2); // if (remainder >= 10) // { // result.hi += ((long64)1 << i); // remainder -= char(10); // } // } // for (int i = 63; i >= 0; --i) // { // if ((val.lo & ((long64)1 << i)) != 0) // remainder = char((remainder * 2) + 1); else // remainder *= char(2); // if (remainder >= 10) // { // result.lo += ((long64)1 << i); // remainder -= char(10); // } // } //} }; //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ bool FullRangeNeeded(const Polygon &pts) { bool result = false; for (Polygon::size_type i = 0; i < pts.size(); ++i) { if (Abs(pts[i].X) > hiRange || Abs(pts[i].Y) > hiRange) throw "Coordinate exceeds range bounds."; else if (Abs(pts[i].X) > loRange || Abs(pts[i].Y) > loRange) result = true; } return result; } //------------------------------------------------------------------------------ bool Orientation(const Polygon &poly) { int highI = (int)poly.size() -1; if (highI < 2) return false; int j = 0, jplus, jminus; for (int i = 0; i <= highI; ++i) { if (poly[i].Y < poly[j].Y) continue; if ((poly[i].Y > poly[j].Y || poly[i].X < poly[j].X)) j = i; }; if (j == highI) jplus = 0; else jplus = j +1; if (j == 0) jminus = highI; else jminus = j -1; IntPoint vec1, vec2; //get cross product of vectors of the edges adjacent to highest point ... vec1.X = poly[j].X - poly[jminus].X; vec1.Y = poly[j].Y - poly[jminus].Y; vec2.X = poly[jplus].X - poly[j].X; vec2.Y = poly[jplus].Y - poly[j].Y; if (Abs(vec1.X) > loRange || Abs(vec1.Y) > loRange || Abs(vec2.X) > loRange || Abs(vec2.Y) > loRange) { if (Abs(vec1.X) > hiRange || Abs(vec1.Y) > hiRange || Abs(vec2.X) > hiRange || Abs(vec2.Y) > hiRange) throw "Coordinate exceeds range bounds."; Int128 cross = Int128(vec1.X) * Int128(vec2.Y) - Int128(vec2.X) * Int128(vec1.Y); return cross >= 0; } else return (vec1.X * vec2.Y - vec2.X * vec1.Y) >= 0; } //------------------------------------------------------------------------------ inline bool PointsEqual( const IntPoint &pt1, const IntPoint &pt2) { return ( pt1.X == pt2.X && pt1.Y == pt2.Y ); } //------------------------------------------------------------------------------ bool Orientation(OutRec *outRec, bool UseFullInt64Range) { //first make sure bottomPt is correctly assigned ... OutPt *opBottom = outRec->pts, *op = outRec->pts->next; while (op != outRec->pts) { if (op->pt.Y >= opBottom->pt.Y) { if (op->pt.Y > opBottom->pt.Y || op->pt.X < opBottom->pt.X) opBottom = op; } op = op->next; } outRec->bottomPt = opBottom; opBottom->idx = outRec->idx; op = opBottom; //find vertices either side of bottomPt (skipping duplicate points) .... OutPt *opPrev = op->prev; OutPt *opNext = op->next; while (op != opPrev && PointsEqual(op->pt, opPrev->pt)) opPrev = opPrev->prev; while (op != opNext && PointsEqual(op->pt, opNext->pt)) opNext = opNext->next; IntPoint ip1, ip2; ip1.X = op->pt.X - opPrev->pt.X; ip1.Y = op->pt.Y - opPrev->pt.Y; ip2.X = opNext->pt.X - op->pt.X; ip2.Y = opNext->pt.Y - op->pt.Y; if (UseFullInt64Range) return Int128(ip1.X) * Int128(ip2.Y) - Int128(ip2.X) * Int128(ip1.Y) >= 0; else return (ip1.X * ip2.Y - ip2.X * ip1.Y) >= 0; } //------------------------------------------------------------------------------ double Area(const Polygon &poly) { int highI = (int)poly.size() -1; if (highI < 2) return 0; if (FullRangeNeeded(poly)) { Int128 a; a = (Int128(poly[highI].X) * Int128(poly[0].Y)) - Int128(poly[0].X) * Int128(poly[highI].Y); for (int i = 0; i < highI; ++i) a += Int128(poly[i].X) * Int128(poly[i+1].Y) - Int128(poly[i+1].X) * Int128(poly[i].Y); return a.AsDouble() / 2; } else { double a; a = (double)poly[highI].X * poly[0].Y - (double)poly[0].X * poly[highI].Y; for (int i = 0; i < highI; ++i) a += (double)poly[i].X * poly[i+1].Y - (double)poly[i+1].X * poly[i].Y; return a/2; } } //------------------------------------------------------------------------------ double Area(const OutRec &outRec, bool UseFullInt64Range) { OutPt *op = outRec.pts; if (UseFullInt64Range) { Int128 a(0); do { a += (Int128(op->prev->pt.X) * Int128(op->pt.Y)) - Int128(op->pt.X) * Int128(op->prev->pt.Y); op = op->next; } while (op != outRec.pts); return a.AsDouble() / 2; } else { double a = 0; do { a += (op->prev->pt.X * op->pt.Y) - (op->pt.X * op->prev->pt.Y); op = op->next; } while (op != outRec.pts); return a/2; } } //------------------------------------------------------------------------------ bool PointIsVertex(const IntPoint &pt, OutPt *pp) { OutPt *pp2 = pp; do { if (PointsEqual(pp2->pt, pt)) return true; pp2 = pp2->next; } while (pp2 != pp); return false; } //------------------------------------------------------------------------------ bool PointInPolygon(const IntPoint &pt, OutPt *pp, bool UseFullInt64Range) { OutPt *pp2 = pp; bool result = false; if (UseFullInt64Range) { do { if ((((pp2->pt.Y <= pt.Y) && (pt.Y < pp2->prev->pt.Y)) || ((pp2->prev->pt.Y <= pt.Y) && (pt.Y < pp2->pt.Y))) && Int128(pt.X - pp2->pt.X) < (Int128(pp2->prev->pt.X - pp2->pt.X) * Int128(pt.Y - pp2->pt.Y)) / Int128(pp2->prev->pt.Y - pp2->pt.Y)) result = !result; pp2 = pp2->next; } while (pp2 != pp); } else { do { if ((((pp2->pt.Y <= pt.Y) && (pt.Y < pp2->prev->pt.Y)) || ((pp2->prev->pt.Y <= pt.Y) && (pt.Y < pp2->pt.Y))) && (pt.X < (pp2->prev->pt.X - pp2->pt.X) * (pt.Y - pp2->pt.Y) / (pp2->prev->pt.Y - pp2->pt.Y) + pp2->pt.X )) result = !result; pp2 = pp2->next; } while (pp2 != pp); } return result; } //------------------------------------------------------------------------------ bool SlopesEqual(TEdge &e1, TEdge &e2, bool UseFullInt64Range) { if (UseFullInt64Range) return Int128(e1.ytop - e1.ybot) * Int128(e2.xtop - e2.xbot) == Int128(e1.xtop - e1.xbot) * Int128(e2.ytop - e2.ybot); else return (e1.ytop - e1.ybot)*(e2.xtop - e2.xbot) == (e1.xtop - e1.xbot)*(e2.ytop - e2.ybot); } //------------------------------------------------------------------------------ bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, const IntPoint pt3, bool UseFullInt64Range) { if (UseFullInt64Range) return Int128(pt1.Y-pt2.Y) * Int128(pt2.X-pt3.X) == Int128(pt1.X-pt2.X) * Int128(pt2.Y-pt3.Y); else return (pt1.Y-pt2.Y)*(pt2.X-pt3.X) == (pt1.X-pt2.X)*(pt2.Y-pt3.Y); } //------------------------------------------------------------------------------ bool SlopesEqual(const IntPoint pt1, const IntPoint pt2, const IntPoint pt3, const IntPoint pt4, bool UseFullInt64Range) { if (UseFullInt64Range) return Int128(pt1.Y-pt2.Y) * Int128(pt3.X-pt4.X) == Int128(pt1.X-pt2.X) * Int128(pt3.Y-pt4.Y); else return (pt1.Y-pt2.Y)*(pt3.X-pt4.X) == (pt1.X-pt2.X)*(pt3.Y-pt4.Y); } //------------------------------------------------------------------------------ double GetDx(const IntPoint pt1, const IntPoint pt2) { return (pt1.Y == pt2.Y) ? HORIZONTAL : (double)(pt2.X - pt1.X) / (double)(pt2.Y - pt1.Y); } //--------------------------------------------------------------------------- void SetDx(TEdge &e) { if (e.ybot == e.ytop) e.dx = HORIZONTAL; else e.dx = (double)(e.xtop - e.xbot) / (double)(e.ytop - e.ybot); } //--------------------------------------------------------------------------- void SwapSides(TEdge &edge1, TEdge &edge2) { EdgeSide side = edge1.side; edge1.side = edge2.side; edge2.side = side; } //------------------------------------------------------------------------------ void SwapPolyIndexes(TEdge &edge1, TEdge &edge2) { int outIdx = edge1.outIdx; edge1.outIdx = edge2.outIdx; edge2.outIdx = outIdx; } //------------------------------------------------------------------------------ inline long64 Round(double val) { return (val < 0) ? static_cast(val - 0.5) : static_cast(val + 0.5); } //------------------------------------------------------------------------------ long64 TopX(TEdge &edge, const long64 currentY) { return ( currentY == edge.ytop ) ? edge.xtop : edge.xbot + Round(edge.dx *(currentY - edge.ybot)); } //------------------------------------------------------------------------------ long64 TopX(const IntPoint pt1, const IntPoint pt2, const long64 currentY) { //preconditions: pt1.Y <> pt2.Y and pt1.Y > pt2.Y if (currentY >= pt1.Y) return pt1.X; else if (currentY == pt2.Y) return pt2.X; else if (pt1.X == pt2.X) return pt1.X; else { double q = (double)(pt1.X-pt2.X)/(double)(pt1.Y-pt2.Y); return Round(pt1.X + (currentY - pt1.Y) *q); } } //------------------------------------------------------------------------------ bool IntersectPoint(TEdge &edge1, TEdge &edge2, IntPoint &ip, bool UseFullInt64Range) { double b1, b2; if (SlopesEqual(edge1, edge2, UseFullInt64Range)) return false; else if (NEAR_ZERO(edge1.dx)) { ip.X = edge1.xbot; if (NEAR_EQUAL(edge2.dx, HORIZONTAL)) { ip.Y = edge2.ybot; } else { b2 = edge2.ybot - (edge2.xbot/edge2.dx); ip.Y = Round(ip.X/edge2.dx + b2); } } else if (NEAR_ZERO(edge2.dx)) { ip.X = edge2.xbot; if (NEAR_EQUAL(edge1.dx, HORIZONTAL)) { ip.Y = edge1.ybot; } else { b1 = edge1.ybot - (edge1.xbot/edge1.dx); ip.Y = Round(ip.X/edge1.dx + b1); } } else { b1 = edge1.xbot - edge1.ybot * edge1.dx; b2 = edge2.xbot - edge2.ybot * edge2.dx; b2 = (b2-b1)/(edge1.dx - edge2.dx); ip.Y = Round(b2); ip.X = Round(edge1.dx * b2 + b1); } return //can be *so close* to the top of one edge that the rounded Y equals one ytop ... (ip.Y == edge1.ytop && ip.Y >= edge2.ytop && edge1.tmpX > edge2.tmpX) || (ip.Y == edge2.ytop && ip.Y >= edge1.ytop && edge1.tmpX > edge2.tmpX) || (ip.Y > edge1.ytop && ip.Y > edge2.ytop); } //------------------------------------------------------------------------------ void ReversePolyPtLinks(OutPt &pp) { OutPt *pp1, *pp2; pp1 = &pp; do { pp2 = pp1->next; pp1->next = pp1->prev; pp1->prev = pp2; pp1 = pp2; } while( pp1 != &pp ); } //------------------------------------------------------------------------------ void DisposeOutPts(OutPt*& pp) { if (pp == 0) return; pp->prev->next = 0; while( pp ) { OutPt *tmpPp = pp; pp = pp->next; delete tmpPp ; } } //------------------------------------------------------------------------------ void InitEdge(TEdge *e, TEdge *eNext, TEdge *ePrev, const IntPoint &pt, PolyType polyType) { std::memset( e, 0, sizeof( TEdge )); e->next = eNext; e->prev = ePrev; e->xcurr = pt.X; e->ycurr = pt.Y; if (e->ycurr >= e->next->ycurr) { e->xbot = e->xcurr; e->ybot = e->ycurr; e->xtop = e->next->xcurr; e->ytop = e->next->ycurr; e->windDelta = 1; } else { e->xtop = e->xcurr; e->ytop = e->ycurr; e->xbot = e->next->xcurr; e->ybot = e->next->ycurr; e->windDelta = -1; } SetDx(*e); e->polyType = polyType; e->outIdx = -1; } //------------------------------------------------------------------------------ inline void SwapX(TEdge &e) { //swap horizontal edges' top and bottom x's so they follow the natural //progression of the bounds - ie so their xbots will align with the //adjoining lower edge. [Helpful in the ProcessHorizontal() method.] e.xcurr = e.xtop; e.xtop = e.xbot; e.xbot = e.xcurr; } //------------------------------------------------------------------------------ void SwapPoints(IntPoint &pt1, IntPoint &pt2) { IntPoint tmp = pt1; pt1 = pt2; pt2 = tmp; } //------------------------------------------------------------------------------ bool GetOverlapSegment(IntPoint pt1a, IntPoint pt1b, IntPoint pt2a, IntPoint pt2b, IntPoint &pt1, IntPoint &pt2) { //precondition: segments are colinear. if ( pt1a.Y == pt1b.Y || Abs((pt1a.X - pt1b.X)/(pt1a.Y - pt1b.Y)) > 1 ) { if (pt1a.X > pt1b.X) SwapPoints(pt1a, pt1b); if (pt2a.X > pt2b.X) SwapPoints(pt2a, pt2b); if (pt1a.X > pt2a.X) pt1 = pt1a; else pt1 = pt2a; if (pt1b.X < pt2b.X) pt2 = pt1b; else pt2 = pt2b; return pt1.X < pt2.X; } else { if (pt1a.Y < pt1b.Y) SwapPoints(pt1a, pt1b); if (pt2a.Y < pt2b.Y) SwapPoints(pt2a, pt2b); if (pt1a.Y < pt2a.Y) pt1 = pt1a; else pt1 = pt2a; if (pt1b.Y > pt2b.Y) pt2 = pt1b; else pt2 = pt2b; return pt1.Y > pt2.Y; } } //------------------------------------------------------------------------------ bool FirstIsBottomPt(const OutPt* btmPt1, const OutPt* btmPt2) { OutPt *p = btmPt1->prev; while (PointsEqual(p->pt, btmPt1->pt) && (p != btmPt1)) p = p->prev; double dx1p = std::fabs(GetDx(btmPt1->pt, p->pt)); p = btmPt1->next; while (PointsEqual(p->pt, btmPt1->pt) && (p != btmPt1)) p = p->next; double dx1n = std::fabs(GetDx(btmPt1->pt, p->pt)); p = btmPt2->prev; while (PointsEqual(p->pt, btmPt2->pt) && (p != btmPt2)) p = p->prev; double dx2p = std::fabs(GetDx(btmPt2->pt, p->pt)); p = btmPt2->next; while (PointsEqual(p->pt, btmPt2->pt) && (p != btmPt2)) p = p->next; double dx2n = std::fabs(GetDx(btmPt2->pt, p->pt)); return (dx1p >= dx2p && dx1p >= dx2n) || (dx1n >= dx2p && dx1n >= dx2n); } //------------------------------------------------------------------------------ OutPt* GetBottomPt(OutPt *pp) { OutPt* dups = 0; OutPt* p = pp->next; while (p != pp) { if (p->pt.Y > pp->pt.Y) { pp = p; dups = 0; } else if (p->pt.Y == pp->pt.Y && p->pt.X <= pp->pt.X) { if (p->pt.X < pp->pt.X) { dups = 0; pp = p; } else { if (p->next != pp && p->prev != pp) dups = p; } } p = p->next; } if (dups) { //there appears to be at least 2 vertices at bottomPt so ... while (dups != p) { if (!FirstIsBottomPt(p, dups)) pp = dups; dups = dups->next; while (!PointsEqual(dups->pt, pp->pt)) dups = dups->next; } } return pp; } //------------------------------------------------------------------------------ bool FindSegment(OutPt* &pp, IntPoint &pt1, IntPoint &pt2) { //outPt1 & outPt2 => the overlap segment (if the function returns true) if (!pp) return false; OutPt* pp2 = pp; IntPoint pt1a = pt1, pt2a = pt2; do { if (SlopesEqual(pt1a, pt2a, pp->pt, pp->prev->pt, true) && SlopesEqual(pt1a, pt2a, pp->pt, true) && GetOverlapSegment(pt1a, pt2a, pp->pt, pp->prev->pt, pt1, pt2)) return true; pp = pp->next; } while (pp != pp2); return false; } //------------------------------------------------------------------------------ bool Pt3IsBetweenPt1AndPt2(const IntPoint pt1, const IntPoint pt2, const IntPoint pt3) { if (PointsEqual(pt1, pt3) || PointsEqual(pt2, pt3)) return true; else if (pt1.X != pt2.X) return (pt1.X < pt3.X) == (pt3.X < pt2.X); else return (pt1.Y < pt3.Y) == (pt3.Y < pt2.Y); } //------------------------------------------------------------------------------ OutPt* InsertPolyPtBetween(OutPt* p1, OutPt* p2, const IntPoint pt) { if (p1 == p2) throw "JoinError"; OutPt* result = new OutPt; result->pt = pt; if (p2 == p1->next) { p1->next = result; p2->prev = result; result->next = p2; result->prev = p1; } else { p2->next = result; p1->prev = result; result->next = p1; result->prev = p2; } return result; } //------------------------------------------------------------------------------ // ClipperBase class methods ... //------------------------------------------------------------------------------ ClipperBase::ClipperBase() //constructor { m_MinimaList = 0; m_CurrentLM = 0; m_UseFullRange = true; } //------------------------------------------------------------------------------ ClipperBase::~ClipperBase() //destructor { Clear(); } //------------------------------------------------------------------------------ bool ClipperBase::AddPolygon( const Polygon &pg, PolyType polyType) { int len = (int)pg.size(); if (len < 3) return false; Polygon p(len); p[0] = pg[0]; int j = 0; long64 maxVal; if (m_UseFullRange) maxVal = hiRange; else maxVal = loRange; for (int i = 0; i < len; ++i) { if (Abs(pg[i].X) > maxVal || Abs(pg[i].Y) > maxVal) { if (Abs(pg[i].X) > hiRange || Abs(pg[i].Y) > hiRange) throw "Coordinate exceeds range bounds"; maxVal = hiRange; m_UseFullRange = true; } if (i == 0 || PointsEqual(p[j], pg[i])) continue; else if (j > 0 && SlopesEqual(p[j-1], p[j], pg[i], m_UseFullRange)) { if (PointsEqual(p[j-1], pg[i])) j--; } else j++; p[j] = pg[i]; } if (j < 2) return false; len = j+1; while (len > 2) { //nb: test for point equality before testing slopes ... if (PointsEqual(p[j], p[0])) j--; else if (PointsEqual(p[0], p[1]) || SlopesEqual(p[j], p[0], p[1], m_UseFullRange)) p[0] = p[j--]; else if (SlopesEqual(p[j-1], p[j], p[0], m_UseFullRange)) j--; else if (SlopesEqual(p[0], p[1], p[2], m_UseFullRange)) { for (int i = 2; i <= j; ++i) p[i-1] = p[i]; j--; } else break; len--; } if (len < 3) return false; //create a new edge array ... TEdge *edges = new TEdge [len]; m_edges.push_back(edges); //convert vertices to a double-linked-list of edges and initialize ... edges[0].xcurr = p[0].X; edges[0].ycurr = p[0].Y; InitEdge(&edges[len-1], &edges[0], &edges[len-2], p[len-1], polyType); for (int i = len-2; i > 0; --i) InitEdge(&edges[i], &edges[i+1], &edges[i-1], p[i], polyType); InitEdge(&edges[0], &edges[1], &edges[len-1], p[0], polyType); //reset xcurr & ycurr and find 'eHighest' (given the Y axis coordinates //increase downward so the 'highest' edge will have the smallest ytop) ... TEdge *e = &edges[0]; TEdge *eHighest = e; do { e->xcurr = e->xbot; e->ycurr = e->ybot; if (e->ytop < eHighest->ytop) eHighest = e; e = e->next; } while ( e != &edges[0]); //make sure eHighest is positioned so the following loop works safely ... if (eHighest->windDelta > 0) eHighest = eHighest->next; if (NEAR_EQUAL(eHighest->dx, HORIZONTAL)) eHighest = eHighest->next; //finally insert each local minima ... e = eHighest; do { e = AddBoundsToLML(e); } while( e != eHighest ); return true; } //------------------------------------------------------------------------------ void ClipperBase::InsertLocalMinima(LocalMinima *newLm) { if( ! m_MinimaList ) { m_MinimaList = newLm; } else if( newLm->Y >= m_MinimaList->Y ) { newLm->next = m_MinimaList; m_MinimaList = newLm; } else { LocalMinima* tmpLm = m_MinimaList; while( tmpLm->next && ( newLm->Y < tmpLm->next->Y ) ) tmpLm = tmpLm->next; newLm->next = tmpLm->next; tmpLm->next = newLm; } } //------------------------------------------------------------------------------ TEdge* ClipperBase::AddBoundsToLML(TEdge *e) { //Starting at the top of one bound we progress to the bottom where there's //a local minima. We then go to the top of the next bound. These two bounds //form the left and right (or right and left) bounds of the local minima. e->nextInLML = 0; e = e->next; for (;;) { if (NEAR_EQUAL(e->dx, HORIZONTAL)) { //nb: proceed through horizontals when approaching from their right, // but break on horizontal minima if approaching from their left. // This ensures 'local minima' are always on the left of horizontals. if (e->next->ytop < e->ytop && e->next->xbot > e->prev->xbot) break; if (e->xtop != e->prev->xbot) SwapX(*e); e->nextInLML = e->prev; } else if (e->ycurr == e->prev->ycurr) break; else e->nextInLML = e->prev; e = e->next; } //e and e.prev are now at a local minima ... LocalMinima* newLm = new LocalMinima; newLm->next = 0; newLm->Y = e->prev->ybot; if ( NEAR_EQUAL(e->dx, HORIZONTAL) ) //horizontal edges never start a left bound { if (e->xbot != e->prev->xbot) SwapX(*e); newLm->leftBound = e->prev; newLm->rightBound = e; } else if (e->dx < e->prev->dx) { newLm->leftBound = e->prev; newLm->rightBound = e; } else { newLm->leftBound = e; newLm->rightBound = e->prev; } newLm->leftBound->side = esLeft; newLm->rightBound->side = esRight; InsertLocalMinima( newLm ); for (;;) { if ( e->next->ytop == e->ytop && !NEAR_EQUAL(e->next->dx, HORIZONTAL) ) break; e->nextInLML = e->next; e = e->next; if ( NEAR_EQUAL(e->dx, HORIZONTAL) && e->xbot != e->prev->xtop) SwapX(*e); } return e->next; } //------------------------------------------------------------------------------ bool ClipperBase::AddPolygons(const Polygons &ppg, PolyType polyType) { bool result = false; for (Polygons::size_type i = 0; i < ppg.size(); ++i) if (AddPolygon(ppg[i], polyType)) result = true; return result; } //------------------------------------------------------------------------------ void ClipperBase::Clear() { DisposeLocalMinimaList(); for (EdgeList::size_type i = 0; i < m_edges.size(); ++i) delete [] m_edges[i]; m_edges.clear(); m_UseFullRange = false; } //------------------------------------------------------------------------------ void ClipperBase::Reset() { m_CurrentLM = m_MinimaList; if( !m_CurrentLM ) return; //ie nothing to process //reset all edges ... LocalMinima* lm = m_MinimaList; while( lm ) { TEdge* e = lm->leftBound; while( e ) { e->xcurr = e->xbot; e->ycurr = e->ybot; e->side = esLeft; e->outIdx = -1; e = e->nextInLML; } e = lm->rightBound; while( e ) { e->xcurr = e->xbot; e->ycurr = e->ybot; e->side = esRight; e->outIdx = -1; e = e->nextInLML; } lm = lm->next; } } //------------------------------------------------------------------------------ void ClipperBase::DisposeLocalMinimaList() { while( m_MinimaList ) { LocalMinima* tmpLm = m_MinimaList->next; delete m_MinimaList; m_MinimaList = tmpLm; } m_CurrentLM = 0; } //------------------------------------------------------------------------------ void ClipperBase::PopLocalMinima() { if( ! m_CurrentLM ) return; m_CurrentLM = m_CurrentLM->next; } //------------------------------------------------------------------------------ IntRect ClipperBase::GetBounds() { IntRect result; LocalMinima* lm = m_MinimaList; if (!lm) { result.left = result.top = result.right = result.bottom = 0; return result; } result.left = lm->leftBound->xbot; result.top = lm->leftBound->ybot; result.right = lm->leftBound->xbot; result.bottom = lm->leftBound->ybot; while (lm) { if (lm->leftBound->ybot > result.bottom) result.bottom = lm->leftBound->ybot; TEdge* e = lm->leftBound; for (;;) { TEdge* bottomE = e; while (e->nextInLML) { if (e->xbot < result.left) result.left = e->xbot; if (e->xbot > result.right) result.right = e->xbot; e = e->nextInLML; } if (e->xbot < result.left) result.left = e->xbot; if (e->xbot > result.right) result.right = e->xbot; if (e->xtop < result.left) result.left = e->xtop; if (e->xtop > result.right) result.right = e->xtop; if (e->ytop < result.top) result.top = e->ytop; if (bottomE == lm->leftBound) e = lm->rightBound; else break; } lm = lm->next; } return result; } //------------------------------------------------------------------------------ // TClipper methods ... //------------------------------------------------------------------------------ Clipper::Clipper() : ClipperBase() //constructor { m_Scanbeam = 0; m_ActiveEdges = 0; m_SortedEdges = 0; m_IntersectNodes = 0; m_ExecuteLocked = false; m_UseFullRange = false; m_ReverseOutput = false; } //------------------------------------------------------------------------------ Clipper::~Clipper() //destructor { Clear(); DisposeScanbeamList(); } //------------------------------------------------------------------------------ void Clipper::Clear() { if (m_edges.size() == 0) return; //avoids problems with ClipperBase destructor DisposeAllPolyPts(); ClipperBase::Clear(); } //------------------------------------------------------------------------------ void Clipper::DisposeScanbeamList() { while ( m_Scanbeam ) { Scanbeam* sb2 = m_Scanbeam->next; delete m_Scanbeam; m_Scanbeam = sb2; } } //------------------------------------------------------------------------------ void Clipper::Reset() { ClipperBase::Reset(); m_Scanbeam = 0; m_ActiveEdges = 0; m_SortedEdges = 0; DisposeAllPolyPts(); LocalMinima* lm = m_MinimaList; while (lm) { InsertScanbeam(lm->Y); InsertScanbeam(lm->leftBound->ytop); lm = lm->next; } } //------------------------------------------------------------------------------ bool Clipper::Execute(ClipType clipType, Polygons &solution, PolyFillType subjFillType, PolyFillType clipFillType) { if( m_ExecuteLocked ) return false; m_ExecuteLocked = true; solution.resize(0); m_SubjFillType = subjFillType; m_ClipFillType = clipFillType; m_ClipType = clipType; bool succeeded = ExecuteInternal(false); if (succeeded) BuildResult(solution); m_ExecuteLocked = false; return succeeded; } //------------------------------------------------------------------------------ bool Clipper::Execute(ClipType clipType, ExPolygons &solution, PolyFillType subjFillType, PolyFillType clipFillType) { if( m_ExecuteLocked ) return false; m_ExecuteLocked = true; solution.resize(0); m_SubjFillType = subjFillType; m_ClipFillType = clipFillType; m_ClipType = clipType; bool succeeded = ExecuteInternal(true); if (succeeded) BuildResultEx(solution); m_ExecuteLocked = false; return succeeded; } //------------------------------------------------------------------------------ bool PolySort(OutRec *or1, OutRec *or2) { if (or1 == or2) return false; if (!or1->pts || !or2->pts) { if (or1->pts != or2->pts) { return or1->pts ? true : false; } else return false; } int i1, i2; if (or1->isHole) i1 = or1->FirstLeft->idx; else i1 = or1->idx; if (or2->isHole) i2 = or2->FirstLeft->idx; else i2 = or2->idx; int result = i1 - i2; if (result == 0 && (or1->isHole != or2->isHole)) { return or1->isHole ? false : true; } else return result < 0; } //------------------------------------------------------------------------------ OutRec* FindAppendLinkEnd(OutRec *outRec) { while (outRec->AppendLink) outRec = outRec->AppendLink; return outRec; } //------------------------------------------------------------------------------ void Clipper::FixHoleLinkage(OutRec *outRec) { OutRec *tmp; if (outRec->bottomPt) tmp = m_PolyOuts[outRec->bottomPt->idx]->FirstLeft; else tmp = outRec->FirstLeft; if (outRec == tmp) throw clipperException("HoleLinkage error"); if (tmp) { if (tmp->AppendLink) tmp = FindAppendLinkEnd(tmp); if (tmp == outRec) tmp = 0; else if (tmp->isHole) { FixHoleLinkage(tmp); tmp = tmp->FirstLeft; } } outRec->FirstLeft = tmp; if (!tmp) outRec->isHole = false; outRec->AppendLink = 0; } //------------------------------------------------------------------------------ bool Clipper::ExecuteInternal(bool fixHoleLinkages) { bool succeeded; try { Reset(); if (!m_CurrentLM ) return true; long64 botY = PopScanbeam(); do { InsertLocalMinimaIntoAEL(botY); ClearHorzJoins(); ProcessHorizontals(); long64 topY = PopScanbeam(); succeeded = ProcessIntersections(botY, topY); if (!succeeded) break; ProcessEdgesAtTopOfScanbeam(topY); botY = topY; } while( m_Scanbeam ); } catch(...) { succeeded = false; } if (succeeded) { //tidy up output polygons and fix orientations where necessary ... for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) { OutRec *outRec = m_PolyOuts[i]; if (!outRec->pts) continue; FixupOutPolygon(*outRec); if (!outRec->pts) continue; if (outRec->isHole && fixHoleLinkages) FixHoleLinkage(outRec); if (outRec->bottomPt == outRec->bottomFlag && (Orientation(outRec, m_UseFullRange) != (Area(*outRec, m_UseFullRange) > 0))) DisposeBottomPt(*outRec); if (outRec->isHole == (m_ReverseOutput ^ Orientation(outRec, m_UseFullRange))) ReversePolyPtLinks(*outRec->pts); } JoinCommonEdges(fixHoleLinkages); if (fixHoleLinkages) std::sort(m_PolyOuts.begin(), m_PolyOuts.end(), PolySort); } ClearJoins(); ClearHorzJoins(); return succeeded; } //------------------------------------------------------------------------------ void Clipper::InsertScanbeam(const long64 Y) { if( !m_Scanbeam ) { m_Scanbeam = new Scanbeam; m_Scanbeam->next = 0; m_Scanbeam->Y = Y; } else if( Y > m_Scanbeam->Y ) { Scanbeam* newSb = new Scanbeam; newSb->Y = Y; newSb->next = m_Scanbeam; m_Scanbeam = newSb; } else { Scanbeam* sb2 = m_Scanbeam; while( sb2->next && ( Y <= sb2->next->Y ) ) sb2 = sb2->next; if( Y == sb2->Y ) return; //ie ignores duplicates Scanbeam* newSb = new Scanbeam; newSb->Y = Y; newSb->next = sb2->next; sb2->next = newSb; } } //------------------------------------------------------------------------------ long64 Clipper::PopScanbeam() { long64 Y = m_Scanbeam->Y; Scanbeam* sb2 = m_Scanbeam; m_Scanbeam = m_Scanbeam->next; delete sb2; return Y; } //------------------------------------------------------------------------------ void Clipper::DisposeAllPolyPts(){ for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) DisposeOutRec(i); m_PolyOuts.clear(); } //------------------------------------------------------------------------------ void Clipper::DisposeOutRec(PolyOutList::size_type index) { OutRec *outRec = m_PolyOuts[index]; if (outRec->pts) DisposeOutPts(outRec->pts); delete outRec; m_PolyOuts[index] = 0; } //------------------------------------------------------------------------------ void Clipper::SetWindingCount(TEdge &edge) { TEdge *e = edge.prevInAEL; //find the edge of the same polytype that immediately preceeds 'edge' in AEL while ( e && e->polyType != edge.polyType ) e = e->prevInAEL; if ( !e ) { edge.windCnt = edge.windDelta; edge.windCnt2 = 0; e = m_ActiveEdges; //ie get ready to calc windCnt2 } else if ( IsEvenOddFillType(edge) ) { //EvenOdd filling ... edge.windCnt = 1; edge.windCnt2 = e->windCnt2; e = e->nextInAEL; //ie get ready to calc windCnt2 } else { //nonZero, Positive or Negative filling ... if ( e->windCnt * e->windDelta < 0 ) { if (Abs(e->windCnt) > 1) { if (e->windDelta * edge.windDelta < 0) edge.windCnt = e->windCnt; else edge.windCnt = e->windCnt + edge.windDelta; } else edge.windCnt = e->windCnt + e->windDelta + edge.windDelta; } else { if ( Abs(e->windCnt) > 1 && e->windDelta * edge.windDelta < 0) edge.windCnt = e->windCnt; else if ( e->windCnt + edge.windDelta == 0 ) edge.windCnt = e->windCnt; else edge.windCnt = e->windCnt + edge.windDelta; } edge.windCnt2 = e->windCnt2; e = e->nextInAEL; //ie get ready to calc windCnt2 } //update windCnt2 ... if ( IsEvenOddAltFillType(edge) ) { //EvenOdd filling ... while ( e != &edge ) { edge.windCnt2 = (edge.windCnt2 == 0) ? 1 : 0; e = e->nextInAEL; } } else { //nonZero, Positive or Negative filling ... while ( e != &edge ) { edge.windCnt2 += e->windDelta; e = e->nextInAEL; } } } //------------------------------------------------------------------------------ bool Clipper::IsEvenOddFillType(const TEdge& edge) const { if (edge.polyType == ptSubject) return m_SubjFillType == pftEvenOdd; else return m_ClipFillType == pftEvenOdd; } //------------------------------------------------------------------------------ bool Clipper::IsEvenOddAltFillType(const TEdge& edge) const { if (edge.polyType == ptSubject) return m_ClipFillType == pftEvenOdd; else return m_SubjFillType == pftEvenOdd; } //------------------------------------------------------------------------------ bool Clipper::IsContributing(const TEdge& edge) const { PolyFillType pft, pft2; if (edge.polyType == ptSubject) { pft = m_SubjFillType; pft2 = m_ClipFillType; } else { pft = m_ClipFillType; pft2 = m_SubjFillType; } switch(pft) { case pftEvenOdd: case pftNonZero: if (Abs(edge.windCnt) != 1) return false; break; case pftPositive: if (edge.windCnt != 1) return false; break; default: //pftNegative if (edge.windCnt != -1) return false; } switch(m_ClipType) { case ctIntersection: switch(pft2) { case pftEvenOdd: case pftNonZero: return (edge.windCnt2 != 0); case pftPositive: return (edge.windCnt2 > 0); default: return (edge.windCnt2 < 0); } case ctUnion: switch(pft2) { case pftEvenOdd: case pftNonZero: return (edge.windCnt2 == 0); case pftPositive: return (edge.windCnt2 <= 0); default: return (edge.windCnt2 >= 0); } case ctDifference: if (edge.polyType == ptSubject) switch(pft2) { case pftEvenOdd: case pftNonZero: return (edge.windCnt2 == 0); case pftPositive: return (edge.windCnt2 <= 0); default: return (edge.windCnt2 >= 0); } else switch(pft2) { case pftEvenOdd: case pftNonZero: return (edge.windCnt2 != 0); case pftPositive: return (edge.windCnt2 > 0); default: return (edge.windCnt2 < 0); } default: return true; } } //------------------------------------------------------------------------------ void Clipper::AddLocalMinPoly(TEdge *e1, TEdge *e2, const IntPoint &pt) { TEdge *e, *prevE; if( NEAR_EQUAL(e2->dx, HORIZONTAL) || ( e1->dx > e2->dx ) ) { AddOutPt( e1, pt ); e2->outIdx = e1->outIdx; e1->side = esLeft; e2->side = esRight; e = e1; if (e->prevInAEL == e2) prevE = e2->prevInAEL; else prevE = e->prevInAEL; } else { AddOutPt( e2, pt ); e1->outIdx = e2->outIdx; e1->side = esRight; e2->side = esLeft; e = e2; if (e->prevInAEL == e1) prevE = e1->prevInAEL; else prevE = e->prevInAEL; } if (prevE && prevE->outIdx >= 0 && (TopX(*prevE, pt.Y) == TopX(*e, pt.Y)) && SlopesEqual(*e, *prevE, m_UseFullRange)) AddJoin(e, prevE, -1, -1); } //------------------------------------------------------------------------------ void Clipper::AddLocalMaxPoly(TEdge *e1, TEdge *e2, const IntPoint &pt) { AddOutPt( e1, pt ); if( e1->outIdx == e2->outIdx ) { e1->outIdx = -1; e2->outIdx = -1; } else if (e1->outIdx < e2->outIdx) AppendPolygon(e1, e2); else AppendPolygon(e2, e1); } //------------------------------------------------------------------------------ void Clipper::AddEdgeToSEL(TEdge *edge) { //SEL pointers in PEdge are reused to build a list of horizontal edges. //However, we don't need to worry about order with horizontal edge processing. if( !m_SortedEdges ) { m_SortedEdges = edge; edge->prevInSEL = 0; edge->nextInSEL = 0; } else { edge->nextInSEL = m_SortedEdges; edge->prevInSEL = 0; m_SortedEdges->prevInSEL = edge; m_SortedEdges = edge; } } //------------------------------------------------------------------------------ void Clipper::CopyAELToSEL() { TEdge* e = m_ActiveEdges; m_SortedEdges = e; if (!m_ActiveEdges) return; m_SortedEdges->prevInSEL = 0; e = e->nextInAEL; while ( e ) { e->prevInSEL = e->prevInAEL; e->prevInSEL->nextInSEL = e; e->nextInSEL = 0; e = e->nextInAEL; } } //------------------------------------------------------------------------------ void Clipper::AddJoin(TEdge *e1, TEdge *e2, int e1OutIdx, int e2OutIdx) { JoinRec* jr = new JoinRec; if (e1OutIdx >= 0) jr->poly1Idx = e1OutIdx; else jr->poly1Idx = e1->outIdx; jr->pt1a = IntPoint(e1->xcurr, e1->ycurr); jr->pt1b = IntPoint(e1->xtop, e1->ytop); if (e2OutIdx >= 0) jr->poly2Idx = e2OutIdx; else jr->poly2Idx = e2->outIdx; jr->pt2a = IntPoint(e2->xcurr, e2->ycurr); jr->pt2b = IntPoint(e2->xtop, e2->ytop); m_Joins.push_back(jr); } //------------------------------------------------------------------------------ void Clipper::ClearJoins() { for (JoinList::size_type i = 0; i < m_Joins.size(); i++) delete m_Joins[i]; m_Joins.resize(0); } //------------------------------------------------------------------------------ void Clipper::AddHorzJoin(TEdge *e, int idx) { HorzJoinRec* hj = new HorzJoinRec; hj->edge = e; hj->savedIdx = idx; m_HorizJoins.push_back(hj); } //------------------------------------------------------------------------------ void Clipper::ClearHorzJoins() { for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); i++) delete m_HorizJoins[i]; m_HorizJoins.resize(0); } //------------------------------------------------------------------------------ void Clipper::InsertLocalMinimaIntoAEL( const long64 botY) { while( m_CurrentLM && ( m_CurrentLM->Y == botY ) ) { TEdge* lb = m_CurrentLM->leftBound; TEdge* rb = m_CurrentLM->rightBound; InsertEdgeIntoAEL( lb ); InsertScanbeam( lb->ytop ); InsertEdgeIntoAEL( rb ); if (IsEvenOddFillType(*lb)) { lb->windDelta = 1; rb->windDelta = 1; } else { rb->windDelta = -lb->windDelta; } SetWindingCount( *lb ); rb->windCnt = lb->windCnt; rb->windCnt2 = lb->windCnt2; if( NEAR_EQUAL(rb->dx, HORIZONTAL) ) { //nb: only rightbounds can have a horizontal bottom edge AddEdgeToSEL( rb ); InsertScanbeam( rb->nextInLML->ytop ); } else InsertScanbeam( rb->ytop ); if( IsContributing(*lb) ) AddLocalMinPoly( lb, rb, IntPoint(lb->xcurr, m_CurrentLM->Y) ); //if any output polygons share an edge, they'll need joining later ... if (rb->outIdx >= 0) { if (NEAR_EQUAL(rb->dx, HORIZONTAL)) { for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i) { IntPoint pt, pt2; //returned by GetOverlapSegment() but unused here. HorzJoinRec* hj = m_HorizJoins[i]; //if horizontals rb and hj.edge overlap, flag for joining later ... if (GetOverlapSegment(IntPoint(hj->edge->xbot, hj->edge->ybot), IntPoint(hj->edge->xtop, hj->edge->ytop), IntPoint(rb->xbot, rb->ybot), IntPoint(rb->xtop, rb->ytop), pt, pt2)) AddJoin(hj->edge, rb, hj->savedIdx); } } } if( lb->nextInAEL != rb ) { if (rb->outIdx >= 0 && rb->prevInAEL->outIdx >= 0 && SlopesEqual(*rb->prevInAEL, *rb, m_UseFullRange)) AddJoin(rb, rb->prevInAEL); TEdge* e = lb->nextInAEL; IntPoint pt = IntPoint(lb->xcurr, lb->ycurr); while( e != rb ) { if(!e) throw clipperException("InsertLocalMinimaIntoAEL: missing rightbound!"); //nb: For calculating winding counts etc, IntersectEdges() assumes //that param1 will be to the right of param2 ABOVE the intersection ... IntersectEdges( rb , e , pt , ipNone); //order important here e = e->nextInAEL; } } PopLocalMinima(); } } //------------------------------------------------------------------------------ void Clipper::DeleteFromAEL(TEdge *e) { TEdge* AelPrev = e->prevInAEL; TEdge* AelNext = e->nextInAEL; if( !AelPrev && !AelNext && (e != m_ActiveEdges) ) return; //already deleted if( AelPrev ) AelPrev->nextInAEL = AelNext; else m_ActiveEdges = AelNext; if( AelNext ) AelNext->prevInAEL = AelPrev; e->nextInAEL = 0; e->prevInAEL = 0; } //------------------------------------------------------------------------------ void Clipper::DeleteFromSEL(TEdge *e) { TEdge* SelPrev = e->prevInSEL; TEdge* SelNext = e->nextInSEL; if( !SelPrev && !SelNext && (e != m_SortedEdges) ) return; //already deleted if( SelPrev ) SelPrev->nextInSEL = SelNext; else m_SortedEdges = SelNext; if( SelNext ) SelNext->prevInSEL = SelPrev; e->nextInSEL = 0; e->prevInSEL = 0; } //------------------------------------------------------------------------------ void Clipper::IntersectEdges(TEdge *e1, TEdge *e2, const IntPoint &pt, IntersectProtects protects) { //e1 will be to the left of e2 BELOW the intersection. Therefore e1 is before //e2 in AEL except when e1 is being inserted at the intersection point ... bool e1stops = !(ipLeft & protects) && !e1->nextInLML && e1->xtop == pt.X && e1->ytop == pt.Y; bool e2stops = !(ipRight & protects) && !e2->nextInLML && e2->xtop == pt.X && e2->ytop == pt.Y; bool e1Contributing = ( e1->outIdx >= 0 ); bool e2contributing = ( e2->outIdx >= 0 ); //update winding counts... //assumes that e1 will be to the right of e2 ABOVE the intersection if ( e1->polyType == e2->polyType ) { if ( IsEvenOddFillType( *e1) ) { int oldE1WindCnt = e1->windCnt; e1->windCnt = e2->windCnt; e2->windCnt = oldE1WindCnt; } else { if (e1->windCnt + e2->windDelta == 0 ) e1->windCnt = -e1->windCnt; else e1->windCnt += e2->windDelta; if ( e2->windCnt - e1->windDelta == 0 ) e2->windCnt = -e2->windCnt; else e2->windCnt -= e1->windDelta; } } else { if (!IsEvenOddFillType(*e2)) e1->windCnt2 += e2->windDelta; else e1->windCnt2 = ( e1->windCnt2 == 0 ) ? 1 : 0; if (!IsEvenOddFillType(*e1)) e2->windCnt2 -= e1->windDelta; else e2->windCnt2 = ( e2->windCnt2 == 0 ) ? 1 : 0; } PolyFillType e1FillType, e2FillType, e1FillType2, e2FillType2; if (e1->polyType == ptSubject) { e1FillType = m_SubjFillType; e1FillType2 = m_ClipFillType; } else { e1FillType = m_ClipFillType; e1FillType2 = m_SubjFillType; } if (e2->polyType == ptSubject) { e2FillType = m_SubjFillType; e2FillType2 = m_ClipFillType; } else { e2FillType = m_ClipFillType; e2FillType2 = m_SubjFillType; } long64 e1Wc, e2Wc; switch (e1FillType) { case pftPositive: e1Wc = e1->windCnt; break; case pftNegative: e1Wc = -e1->windCnt; break; default: e1Wc = Abs(e1->windCnt); } switch(e2FillType) { case pftPositive: e2Wc = e2->windCnt; break; case pftNegative: e2Wc = -e2->windCnt; break; default: e2Wc = Abs(e2->windCnt); } if ( e1Contributing && e2contributing ) { if ( e1stops || e2stops || (e1Wc != 0 && e1Wc != 1) || (e2Wc != 0 && e2Wc != 1) || (e1->polyType != e2->polyType && m_ClipType != ctXor) ) AddLocalMaxPoly(e1, e2, pt); else DoBothEdges( e1, e2, pt ); } else if ( e1Contributing ) { if ((e2Wc == 0 || e2Wc == 1) && (m_ClipType != ctIntersection || e2->polyType == ptSubject || (e2->windCnt2 != 0))) DoEdge1(e1, e2, pt); } else if ( e2contributing ) { if ((e1Wc == 0 || e1Wc == 1) && (m_ClipType != ctIntersection || e1->polyType == ptSubject || (e1->windCnt2 != 0))) DoEdge2(e1, e2, pt); } else if ( (e1Wc == 0 || e1Wc == 1) && (e2Wc == 0 || e2Wc == 1) && !e1stops && !e2stops ) { //neither edge is currently contributing ... long64 e1Wc2, e2Wc2; switch (e1FillType2) { case pftPositive: e1Wc2 = e1->windCnt2; break; case pftNegative : e1Wc2 = -e1->windCnt2; break; default: e1Wc2 = Abs(e1->windCnt2); } switch (e2FillType2) { case pftPositive: e2Wc2 = e2->windCnt2; break; case pftNegative: e2Wc2 = -e2->windCnt2; break; default: e2Wc2 = Abs(e2->windCnt2); } if (e1->polyType != e2->polyType) AddLocalMinPoly(e1, e2, pt); else if (e1Wc == 1 && e2Wc == 1) switch( m_ClipType ) { case ctIntersection: if (e1Wc2 > 0 && e2Wc2 > 0) AddLocalMinPoly(e1, e2, pt); break; case ctUnion: if ( e1Wc2 <= 0 && e2Wc2 <= 0 ) AddLocalMinPoly(e1, e2, pt); break; case ctDifference: if (((e1->polyType == ptClip) && (e1Wc2 > 0) && (e2Wc2 > 0)) || ((e1->polyType == ptSubject) && (e1Wc2 <= 0) && (e2Wc2 <= 0))) AddLocalMinPoly(e1, e2, pt); break; case ctXor: AddLocalMinPoly(e1, e2, pt); } else SwapSides( *e1, *e2 ); } if( (e1stops != e2stops) && ( (e1stops && (e1->outIdx >= 0)) || (e2stops && (e2->outIdx >= 0)) ) ) { SwapSides( *e1, *e2 ); SwapPolyIndexes( *e1, *e2 ); } //finally, delete any non-contributing maxima edges ... if( e1stops ) DeleteFromAEL( e1 ); if( e2stops ) DeleteFromAEL( e2 ); } //------------------------------------------------------------------------------ void Clipper::SetHoleState(TEdge *e, OutRec *outRec) { bool isHole = false; TEdge *e2 = e->prevInAEL; while (e2) { if (e2->outIdx >= 0) { isHole = !isHole; if (! outRec->FirstLeft) outRec->FirstLeft = m_PolyOuts[e2->outIdx]; } e2 = e2->prevInAEL; } if (isHole) outRec->isHole = true; } //------------------------------------------------------------------------------ OutRec* GetLowermostRec(OutRec *outRec1, OutRec *outRec2) { //work out which polygon fragment has the correct hole state ... OutPt *outPt1 = outRec1->bottomPt; OutPt *outPt2 = outRec2->bottomPt; if (outPt1->pt.Y > outPt2->pt.Y) return outRec1; else if (outPt1->pt.Y < outPt2->pt.Y) return outRec2; else if (outPt1->pt.X < outPt2->pt.X) return outRec1; else if (outPt1->pt.X > outPt2->pt.X) return outRec2; else if (outPt1->next == outPt1) return outRec2; else if (outPt2->next == outPt2) return outRec1; else if (FirstIsBottomPt(outPt1, outPt2)) return outRec1; else return outRec2; } //------------------------------------------------------------------------------ bool Param1RightOfParam2(OutRec* outRec1, OutRec* outRec2) { do { outRec1 = outRec1->FirstLeft; if (outRec1 == outRec2) return true; } while (outRec1); return false; } //------------------------------------------------------------------------------ void Clipper::AppendPolygon(TEdge *e1, TEdge *e2) { //get the start and ends of both output polygons ... OutRec *outRec1 = m_PolyOuts[e1->outIdx]; OutRec *outRec2 = m_PolyOuts[e2->outIdx]; OutRec *holeStateRec; if (Param1RightOfParam2(outRec1, outRec2)) holeStateRec = outRec2; else if (Param1RightOfParam2(outRec2, outRec1)) holeStateRec = outRec1; else holeStateRec = GetLowermostRec(outRec1, outRec2); OutPt* p1_lft = outRec1->pts; OutPt* p1_rt = p1_lft->prev; OutPt* p2_lft = outRec2->pts; OutPt* p2_rt = p2_lft->prev; EdgeSide side; //join e2 poly onto e1 poly and delete pointers to e2 ... if( e1->side == esLeft ) { if( e2->side == esLeft ) { //z y x a b c ReversePolyPtLinks(*p2_lft); p2_lft->next = p1_lft; p1_lft->prev = p2_lft; p1_rt->next = p2_rt; p2_rt->prev = p1_rt; outRec1->pts = p2_rt; } else { //x y z a b c p2_rt->next = p1_lft; p1_lft->prev = p2_rt; p2_lft->prev = p1_rt; p1_rt->next = p2_lft; outRec1->pts = p2_lft; } side = esLeft; } else { if( e2->side == esRight ) { //a b c z y x ReversePolyPtLinks( *p2_lft ); p1_rt->next = p2_rt; p2_rt->prev = p1_rt; p2_lft->next = p1_lft; p1_lft->prev = p2_lft; } else { //a b c x y z p1_rt->next = p2_lft; p2_lft->prev = p1_rt; p1_lft->prev = p2_rt; p2_rt->next = p1_lft; } side = esRight; } if (holeStateRec == outRec2) { outRec1->bottomPt = outRec2->bottomPt; outRec1->bottomPt->idx = outRec1->idx; if (outRec2->FirstLeft != outRec1) outRec1->FirstLeft = outRec2->FirstLeft; outRec1->isHole = outRec2->isHole; } outRec2->pts = 0; outRec2->bottomPt = 0; outRec2->AppendLink = outRec1; int OKIdx = e1->outIdx; int ObsoleteIdx = e2->outIdx; e1->outIdx = -1; //nb: safe because we only get here via AddLocalMaxPoly e2->outIdx = -1; TEdge* e = m_ActiveEdges; while( e ) { if( e->outIdx == ObsoleteIdx ) { e->outIdx = OKIdx; e->side = side; break; } e = e->nextInAEL; } for (JoinList::size_type i = 0; i < m_Joins.size(); ++i) { if (m_Joins[i]->poly1Idx == ObsoleteIdx) m_Joins[i]->poly1Idx = OKIdx; if (m_Joins[i]->poly2Idx == ObsoleteIdx) m_Joins[i]->poly2Idx = OKIdx; } for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i) { if (m_HorizJoins[i]->savedIdx == ObsoleteIdx) m_HorizJoins[i]->savedIdx = OKIdx; } } //------------------------------------------------------------------------------ OutRec* Clipper::CreateOutRec() { OutRec* result = new OutRec; result->isHole = false; result->FirstLeft = 0; result->AppendLink = 0; result->pts = 0; result->bottomPt = 0; result->sides = esNeither; result->bottomFlag = 0; return result; } //------------------------------------------------------------------------------ void Clipper::DisposeBottomPt(OutRec &outRec) { OutPt* next = outRec.bottomPt->next; OutPt* prev = outRec.bottomPt->prev; if (outRec.pts == outRec.bottomPt) outRec.pts = next; delete outRec.bottomPt; next->prev = prev; prev->next = next; outRec.bottomPt = next; FixupOutPolygon(outRec); } //------------------------------------------------------------------------------ void Clipper::AddOutPt(TEdge *e, const IntPoint &pt) { bool ToFront = (e->side == esLeft); if( e->outIdx < 0 ) { OutRec *outRec = CreateOutRec(); m_PolyOuts.push_back(outRec); outRec->idx = (int)m_PolyOuts.size()-1; e->outIdx = outRec->idx; OutPt* op = new OutPt; outRec->pts = op; outRec->bottomPt = op; op->pt = pt; op->idx = outRec->idx; op->next = op; op->prev = op; SetHoleState(e, outRec); } else { OutRec *outRec = m_PolyOuts[e->outIdx]; OutPt* op = outRec->pts; if ((ToFront && PointsEqual(pt, op->pt)) || (!ToFront && PointsEqual(pt, op->prev->pt))) return; if ((e->side | outRec->sides) != outRec->sides) { //check for 'rounding' artefacts ... if (outRec->sides == esNeither && pt.Y == op->pt.Y) { if (ToFront) { if (pt.X == op->pt.X +1) return; //ie wrong side of bottomPt } else if (pt.X == op->pt.X -1) return; //ie wrong side of bottomPt } outRec->sides = (EdgeSide)(outRec->sides | e->side); if (outRec->sides == esBoth) { //A vertex from each side has now been added. //Vertices of one side of an output polygon are quite commonly close to //or even 'touching' edges of the other side of the output polygon. //Very occasionally vertices from one side can 'cross' an edge on the //the other side. The distance 'crossed' is always less that a unit //and is purely an artefact of coordinate rounding. Nevertheless, this //results in very tiny self-intersections. Because of the way //orientation is calculated, even tiny self-intersections can cause //the Orientation function to return the wrong result. Therefore, it's //important to ensure that any self-intersections close to BottomPt are //detected and removed before orientation is assigned. OutPt *opBot, *op2; if (ToFront) { opBot = outRec->pts; op2 = opBot->next; //op2 == right side if (opBot->pt.Y != op2->pt.Y && opBot->pt.Y != pt.Y && ((opBot->pt.X - pt.X)/(opBot->pt.Y - pt.Y) < (opBot->pt.X - op2->pt.X)/(opBot->pt.Y - op2->pt.Y))) outRec->bottomFlag = opBot; } else { opBot = outRec->pts->prev; op2 = opBot->prev; //op2 == left side if (opBot->pt.Y != op2->pt.Y && opBot->pt.Y != pt.Y && ((opBot->pt.X - pt.X)/(opBot->pt.Y - pt.Y) > (opBot->pt.X - op2->pt.X)/(opBot->pt.Y - op2->pt.Y))) outRec->bottomFlag = opBot; } } } OutPt* op2 = new OutPt; op2->pt = pt; op2->idx = outRec->idx; if (op2->pt.Y == outRec->bottomPt->pt.Y && op2->pt.X < outRec->bottomPt->pt.X) outRec->bottomPt = op2; op2->next = op; op2->prev = op->prev; op2->prev->next = op2; op->prev = op2; if (ToFront) outRec->pts = op2; } } //------------------------------------------------------------------------------ void Clipper::ProcessHorizontals() { TEdge* horzEdge = m_SortedEdges; while( horzEdge ) { DeleteFromSEL( horzEdge ); ProcessHorizontal( horzEdge ); horzEdge = m_SortedEdges; } } //------------------------------------------------------------------------------ bool Clipper::IsTopHorz(const long64 XPos) { TEdge* e = m_SortedEdges; while( e ) { if( ( XPos >= std::min(e->xcurr, e->xtop) ) && ( XPos <= std::max(e->xcurr, e->xtop) ) ) return false; e = e->nextInSEL; } return true; } //------------------------------------------------------------------------------ bool IsMinima(TEdge *e) { return e && (e->prev->nextInLML != e) && (e->next->nextInLML != e); } //------------------------------------------------------------------------------ bool IsMaxima(TEdge *e, const long64 Y) { return e && e->ytop == Y && !e->nextInLML; } //------------------------------------------------------------------------------ bool IsIntermediate(TEdge *e, const long64 Y) { return e->ytop == Y && e->nextInLML; } //------------------------------------------------------------------------------ TEdge *GetMaximaPair(TEdge *e) { if( !IsMaxima(e->next, e->ytop) || e->next->xtop != e->xtop ) return e->prev; else return e->next; } //------------------------------------------------------------------------------ void Clipper::SwapPositionsInAEL(TEdge *edge1, TEdge *edge2) { if( !edge1->nextInAEL && !edge1->prevInAEL ) return; if( !edge2->nextInAEL && !edge2->prevInAEL ) return; if( edge1->nextInAEL == edge2 ) { TEdge* next = edge2->nextInAEL; if( next ) next->prevInAEL = edge1; TEdge* prev = edge1->prevInAEL; if( prev ) prev->nextInAEL = edge2; edge2->prevInAEL = prev; edge2->nextInAEL = edge1; edge1->prevInAEL = edge2; edge1->nextInAEL = next; } else if( edge2->nextInAEL == edge1 ) { TEdge* next = edge1->nextInAEL; if( next ) next->prevInAEL = edge2; TEdge* prev = edge2->prevInAEL; if( prev ) prev->nextInAEL = edge1; edge1->prevInAEL = prev; edge1->nextInAEL = edge2; edge2->prevInAEL = edge1; edge2->nextInAEL = next; } else { TEdge* next = edge1->nextInAEL; TEdge* prev = edge1->prevInAEL; edge1->nextInAEL = edge2->nextInAEL; if( edge1->nextInAEL ) edge1->nextInAEL->prevInAEL = edge1; edge1->prevInAEL = edge2->prevInAEL; if( edge1->prevInAEL ) edge1->prevInAEL->nextInAEL = edge1; edge2->nextInAEL = next; if( edge2->nextInAEL ) edge2->nextInAEL->prevInAEL = edge2; edge2->prevInAEL = prev; if( edge2->prevInAEL ) edge2->prevInAEL->nextInAEL = edge2; } if( !edge1->prevInAEL ) m_ActiveEdges = edge1; else if( !edge2->prevInAEL ) m_ActiveEdges = edge2; } //------------------------------------------------------------------------------ void Clipper::SwapPositionsInSEL(TEdge *edge1, TEdge *edge2) { if( !( edge1->nextInSEL ) && !( edge1->prevInSEL ) ) return; if( !( edge2->nextInSEL ) && !( edge2->prevInSEL ) ) return; if( edge1->nextInSEL == edge2 ) { TEdge* next = edge2->nextInSEL; if( next ) next->prevInSEL = edge1; TEdge* prev = edge1->prevInSEL; if( prev ) prev->nextInSEL = edge2; edge2->prevInSEL = prev; edge2->nextInSEL = edge1; edge1->prevInSEL = edge2; edge1->nextInSEL = next; } else if( edge2->nextInSEL == edge1 ) { TEdge* next = edge1->nextInSEL; if( next ) next->prevInSEL = edge2; TEdge* prev = edge2->prevInSEL; if( prev ) prev->nextInSEL = edge1; edge1->prevInSEL = prev; edge1->nextInSEL = edge2; edge2->prevInSEL = edge1; edge2->nextInSEL = next; } else { TEdge* next = edge1->nextInSEL; TEdge* prev = edge1->prevInSEL; edge1->nextInSEL = edge2->nextInSEL; if( edge1->nextInSEL ) edge1->nextInSEL->prevInSEL = edge1; edge1->prevInSEL = edge2->prevInSEL; if( edge1->prevInSEL ) edge1->prevInSEL->nextInSEL = edge1; edge2->nextInSEL = next; if( edge2->nextInSEL ) edge2->nextInSEL->prevInSEL = edge2; edge2->prevInSEL = prev; if( edge2->prevInSEL ) edge2->prevInSEL->nextInSEL = edge2; } if( !edge1->prevInSEL ) m_SortedEdges = edge1; else if( !edge2->prevInSEL ) m_SortedEdges = edge2; } //------------------------------------------------------------------------------ TEdge* GetNextInAEL(TEdge *e, Direction dir) { return dir == dLeftToRight ? e->nextInAEL : e->prevInAEL; } //------------------------------------------------------------------------------ void Clipper::ProcessHorizontal(TEdge *horzEdge) { Direction dir; long64 horzLeft, horzRight; if( horzEdge->xcurr < horzEdge->xtop ) { horzLeft = horzEdge->xcurr; horzRight = horzEdge->xtop; dir = dLeftToRight; } else { horzLeft = horzEdge->xtop; horzRight = horzEdge->xcurr; dir = dRightToLeft; } TEdge* eMaxPair; if( horzEdge->nextInLML ) eMaxPair = 0; else eMaxPair = GetMaximaPair(horzEdge); TEdge* e = GetNextInAEL( horzEdge , dir ); while( e ) { TEdge* eNext = GetNextInAEL( e, dir ); if (eMaxPair || ((dir == dLeftToRight) && (e->xcurr <= horzRight)) || ((dir == dRightToLeft) && (e->xcurr >= horzLeft))) { //ok, so far it looks like we're still in range of the horizontal edge if ( e->xcurr == horzEdge->xtop && !eMaxPair ) { assert(horzEdge->nextInLML); if (SlopesEqual(*e, *horzEdge->nextInLML, m_UseFullRange)) { //if output polygons share an edge, they'll need joining later ... if (horzEdge->outIdx >= 0 && e->outIdx >= 0) AddJoin(horzEdge->nextInLML, e, horzEdge->outIdx); break; //we've reached the end of the horizontal line } else if (e->dx < horzEdge->nextInLML->dx) //we really have got to the end of the intermediate horz edge so quit. //nb: More -ve slopes follow more +ve slopes ABOVE the horizontal. break; } if( e == eMaxPair ) { //horzEdge is evidently a maxima horizontal and we've arrived at its end. if (dir == dLeftToRight) IntersectEdges(horzEdge, e, IntPoint(e->xcurr, horzEdge->ycurr), ipNone); else IntersectEdges(e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr), ipNone); if (eMaxPair->outIdx >= 0) throw clipperException("ProcessHorizontal error"); return; } else if( NEAR_EQUAL(e->dx, HORIZONTAL) && !IsMinima(e) && !(e->xcurr > e->xtop) ) { //An overlapping horizontal edge. Overlapping horizontal edges are //processed as if layered with the current horizontal edge (horizEdge) //being infinitesimally lower that the next (e). Therfore, we //intersect with e only if e.xcurr is within the bounds of horzEdge ... if( dir == dLeftToRight ) IntersectEdges( horzEdge , e, IntPoint(e->xcurr, horzEdge->ycurr), (IsTopHorz( e->xcurr ))? ipLeft : ipBoth ); else IntersectEdges( e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr), (IsTopHorz( e->xcurr ))? ipRight : ipBoth ); } else if( dir == dLeftToRight ) { IntersectEdges( horzEdge, e, IntPoint(e->xcurr, horzEdge->ycurr), (IsTopHorz( e->xcurr ))? ipLeft : ipBoth ); } else { IntersectEdges( e, horzEdge, IntPoint(e->xcurr, horzEdge->ycurr), (IsTopHorz( e->xcurr ))? ipRight : ipBoth ); } SwapPositionsInAEL( horzEdge, e ); } else if( (dir == dLeftToRight && e->xcurr > horzRight && m_SortedEdges) || (dir == dRightToLeft && e->xcurr < horzLeft && m_SortedEdges) ) break; e = eNext; } //end while if( horzEdge->nextInLML ) { if( horzEdge->outIdx >= 0 ) AddOutPt( horzEdge, IntPoint(horzEdge->xtop, horzEdge->ytop)); UpdateEdgeIntoAEL( horzEdge ); } else { if ( horzEdge->outIdx >= 0 ) IntersectEdges( horzEdge, eMaxPair, IntPoint(horzEdge->xtop, horzEdge->ycurr), ipBoth); assert(eMaxPair); if (eMaxPair->outIdx >= 0) throw clipperException("ProcessHorizontal error"); DeleteFromAEL(eMaxPair); DeleteFromAEL(horzEdge); } } //------------------------------------------------------------------------------ void Clipper::UpdateEdgeIntoAEL(TEdge *&e) { if( !e->nextInLML ) throw clipperException("UpdateEdgeIntoAEL: invalid call"); TEdge* AelPrev = e->prevInAEL; TEdge* AelNext = e->nextInAEL; e->nextInLML->outIdx = e->outIdx; if( AelPrev ) AelPrev->nextInAEL = e->nextInLML; else m_ActiveEdges = e->nextInLML; if( AelNext ) AelNext->prevInAEL = e->nextInLML; e->nextInLML->side = e->side; e->nextInLML->windDelta = e->windDelta; e->nextInLML->windCnt = e->windCnt; e->nextInLML->windCnt2 = e->windCnt2; e = e->nextInLML; e->prevInAEL = AelPrev; e->nextInAEL = AelNext; if( !NEAR_EQUAL(e->dx, HORIZONTAL) ) InsertScanbeam( e->ytop ); } //------------------------------------------------------------------------------ bool Clipper::ProcessIntersections(const long64 botY, const long64 topY) { if( !m_ActiveEdges ) return true; try { BuildIntersectList(botY, topY); if ( !m_IntersectNodes) return true; if ( FixupIntersections() ) ProcessIntersectList(); else return false; } catch(...) { m_SortedEdges = 0; DisposeIntersectNodes(); throw clipperException("ProcessIntersections error"); } return true; } //------------------------------------------------------------------------------ void Clipper::DisposeIntersectNodes() { while ( m_IntersectNodes ) { IntersectNode* iNode = m_IntersectNodes->next; delete m_IntersectNodes; m_IntersectNodes = iNode; } } //------------------------------------------------------------------------------ void Clipper::BuildIntersectList(const long64 botY, const long64 topY) { if ( !m_ActiveEdges ) return; //prepare for sorting ... TEdge* e = m_ActiveEdges; e->tmpX = TopX( *e, topY ); m_SortedEdges = e; m_SortedEdges->prevInSEL = 0; e = e->nextInAEL; while( e ) { e->prevInSEL = e->prevInAEL; e->prevInSEL->nextInSEL = e; e->nextInSEL = 0; e->tmpX = TopX( *e, topY ); e = e->nextInAEL; } //bubblesort ... bool isModified = true; while( isModified && m_SortedEdges ) { isModified = false; e = m_SortedEdges; while( e->nextInSEL ) { TEdge *eNext = e->nextInSEL; IntPoint pt; if(e->tmpX > eNext->tmpX && IntersectPoint(*e, *eNext, pt, m_UseFullRange)) { if (pt.Y > botY) { pt.Y = botY; pt.X = TopX(*e, pt.Y); } AddIntersectNode( e, eNext, pt ); SwapPositionsInSEL(e, eNext); isModified = true; } else e = eNext; } if( e->prevInSEL ) e->prevInSEL->nextInSEL = 0; else break; } m_SortedEdges = 0; } //------------------------------------------------------------------------------ bool ProcessParam1BeforeParam2(IntersectNode &node1, IntersectNode &node2) { bool result; if (node1.pt.Y == node2.pt.Y) { if (node1.edge1 == node2.edge1 || node1.edge2 == node2.edge1) { result = node2.pt.X > node1.pt.X; return node2.edge1->dx > 0 ? !result : result; } else if (node1.edge1 == node2.edge2 || node1.edge2 == node2.edge2) { result = node2.pt.X > node1.pt.X; return node2.edge2->dx > 0 ? !result : result; } else return node2.pt.X > node1.pt.X; } else return node1.pt.Y > node2.pt.Y; } //------------------------------------------------------------------------------ void Clipper::AddIntersectNode(TEdge *e1, TEdge *e2, const IntPoint &pt) { IntersectNode* newNode = new IntersectNode; newNode->edge1 = e1; newNode->edge2 = e2; newNode->pt = pt; newNode->next = 0; if( !m_IntersectNodes ) m_IntersectNodes = newNode; else if( ProcessParam1BeforeParam2(*newNode, *m_IntersectNodes) ) { newNode->next = m_IntersectNodes; m_IntersectNodes = newNode; } else { IntersectNode* iNode = m_IntersectNodes; while( iNode->next && ProcessParam1BeforeParam2(*iNode->next, *newNode) ) iNode = iNode->next; newNode->next = iNode->next; iNode->next = newNode; } } //------------------------------------------------------------------------------ void Clipper::ProcessIntersectList() { while( m_IntersectNodes ) { IntersectNode* iNode = m_IntersectNodes->next; { IntersectEdges( m_IntersectNodes->edge1 , m_IntersectNodes->edge2 , m_IntersectNodes->pt, ipBoth ); SwapPositionsInAEL( m_IntersectNodes->edge1 , m_IntersectNodes->edge2 ); } delete m_IntersectNodes; m_IntersectNodes = iNode; } } //------------------------------------------------------------------------------ void Clipper::DoMaxima(TEdge *e, long64 topY) { TEdge* eMaxPair = GetMaximaPair(e); long64 X = e->xtop; TEdge* eNext = e->nextInAEL; while( eNext != eMaxPair ) { if (!eNext) throw clipperException("DoMaxima error"); IntersectEdges( e, eNext, IntPoint(X, topY), ipBoth ); eNext = eNext->nextInAEL; } if( e->outIdx < 0 && eMaxPair->outIdx < 0 ) { DeleteFromAEL( e ); DeleteFromAEL( eMaxPair ); } else if( e->outIdx >= 0 && eMaxPair->outIdx >= 0 ) { IntersectEdges( e, eMaxPair, IntPoint(X, topY), ipNone ); } else throw clipperException("DoMaxima error"); } //------------------------------------------------------------------------------ void Clipper::ProcessEdgesAtTopOfScanbeam(const long64 topY) { TEdge* e = m_ActiveEdges; while( e ) { //1. process maxima, treating them as if they're 'bent' horizontal edges, // but exclude maxima with horizontal edges. nb: e can't be a horizontal. if( IsMaxima(e, topY) && !NEAR_EQUAL(GetMaximaPair(e)->dx, HORIZONTAL) ) { //'e' might be removed from AEL, as may any following edges so ... TEdge* ePrior = e->prevInAEL; DoMaxima(e, topY); if( !ePrior ) e = m_ActiveEdges; else e = ePrior->nextInAEL; } else { //2. promote horizontal edges, otherwise update xcurr and ycurr ... if( IsIntermediate(e, topY) && NEAR_EQUAL(e->nextInLML->dx, HORIZONTAL) ) { if (e->outIdx >= 0) { AddOutPt(e, IntPoint(e->xtop, e->ytop)); for (HorzJoinList::size_type i = 0; i < m_HorizJoins.size(); ++i) { IntPoint pt, pt2; HorzJoinRec* hj = m_HorizJoins[i]; if (GetOverlapSegment(IntPoint(hj->edge->xbot, hj->edge->ybot), IntPoint(hj->edge->xtop, hj->edge->ytop), IntPoint(e->nextInLML->xbot, e->nextInLML->ybot), IntPoint(e->nextInLML->xtop, e->nextInLML->ytop), pt, pt2)) AddJoin(hj->edge, e->nextInLML, hj->savedIdx, e->outIdx); } AddHorzJoin(e->nextInLML, e->outIdx); } UpdateEdgeIntoAEL(e); AddEdgeToSEL(e); } else { //this just simplifies horizontal processing ... e->xcurr = TopX( *e, topY ); e->ycurr = topY; } e = e->nextInAEL; } } //3. Process horizontals at the top of the scanbeam ... ProcessHorizontals(); //4. Promote intermediate vertices ... e = m_ActiveEdges; while( e ) { if( IsIntermediate( e, topY ) ) { if( e->outIdx >= 0 ) AddOutPt(e, IntPoint(e->xtop,e->ytop)); UpdateEdgeIntoAEL(e); //if output polygons share an edge, they'll need joining later ... if (e->outIdx >= 0 && e->prevInAEL && e->prevInAEL->outIdx >= 0 && e->prevInAEL->xcurr == e->xbot && e->prevInAEL->ycurr == e->ybot && SlopesEqual(IntPoint(e->xbot,e->ybot), IntPoint(e->xtop, e->ytop), IntPoint(e->xbot,e->ybot), IntPoint(e->prevInAEL->xtop, e->prevInAEL->ytop), m_UseFullRange)) { AddOutPt(e->prevInAEL, IntPoint(e->xbot, e->ybot)); AddJoin(e, e->prevInAEL); } else if (e->outIdx >= 0 && e->nextInAEL && e->nextInAEL->outIdx >= 0 && e->nextInAEL->ycurr > e->nextInAEL->ytop && e->nextInAEL->ycurr <= e->nextInAEL->ybot && e->nextInAEL->xcurr == e->xbot && e->nextInAEL->ycurr == e->ybot && SlopesEqual(IntPoint(e->xbot,e->ybot), IntPoint(e->xtop, e->ytop), IntPoint(e->xbot,e->ybot), IntPoint(e->nextInAEL->xtop, e->nextInAEL->ytop), m_UseFullRange)) { AddOutPt(e->nextInAEL, IntPoint(e->xbot, e->ybot)); AddJoin(e, e->nextInAEL); } } e = e->nextInAEL; } } //------------------------------------------------------------------------------ void Clipper::FixupOutPolygon(OutRec &outRec) { //FixupOutPolygon() - removes duplicate points and simplifies consecutive //parallel edges by removing the middle vertex. OutPt *lastOK = 0; outRec.pts = outRec.bottomPt; OutPt *pp = outRec.bottomPt; for (;;) { if (pp->prev == pp || pp->prev == pp->next ) { DisposeOutPts(pp); outRec.pts = 0; outRec.bottomPt = 0; return; } //test for duplicate points and for same slope (cross-product) ... if ( PointsEqual(pp->pt, pp->next->pt) || SlopesEqual(pp->prev->pt, pp->pt, pp->next->pt, m_UseFullRange) ) { lastOK = 0; OutPt *tmp = pp; if (pp == outRec.bottomPt) outRec.bottomPt = 0; //flags need for updating pp->prev->next = pp->next; pp->next->prev = pp->prev; pp = pp->prev; delete tmp; } else if (pp == lastOK) break; else { if (!lastOK) lastOK = pp; pp = pp->next; } } if (!outRec.bottomPt) { outRec.bottomPt = GetBottomPt(pp); outRec.bottomPt->idx = outRec.idx; outRec.pts = outRec.bottomPt; } } //------------------------------------------------------------------------------ void Clipper::BuildResult(Polygons &polys) { int k = 0; polys.resize(m_PolyOuts.size()); for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) { if (m_PolyOuts[i]->pts) { Polygon* pg = &polys[k]; pg->clear(); OutPt* p = m_PolyOuts[i]->pts; do { pg->push_back(p->pt); p = p->next; } while (p != m_PolyOuts[i]->pts); //make sure each polygon has at least 3 vertices ... if (pg->size() < 3) pg->clear(); else k++; } } polys.resize(k); } //------------------------------------------------------------------------------ void Clipper::BuildResultEx(ExPolygons &polys) { PolyOutList::size_type i = 0; int k = 0; polys.resize(0); polys.reserve(m_PolyOuts.size()); while (i < m_PolyOuts.size() && m_PolyOuts[i]->pts) { ExPolygon epg; OutPt* p = m_PolyOuts[i]->pts; do { epg.outer.push_back(p->pt); p = p->next; } while (p != m_PolyOuts[i]->pts); i++; //make sure polygons have at least 3 vertices ... if (epg.outer.size() < 3) continue; while (i < m_PolyOuts.size() && m_PolyOuts[i]->pts && m_PolyOuts[i]->isHole) { Polygon pg; p = m_PolyOuts[i]->pts; do { pg.push_back(p->pt); p = p->next; } while (p != m_PolyOuts[i]->pts); epg.holes.push_back(pg); i++; } polys.push_back(epg); k++; } polys.resize(k); } //------------------------------------------------------------------------------ void SwapIntersectNodes(IntersectNode &int1, IntersectNode &int2) { TEdge *e1 = int1.edge1; TEdge *e2 = int1.edge2; IntPoint p = int1.pt; int1.edge1 = int2.edge1; int1.edge2 = int2.edge2; int1.pt = int2.pt; int2.edge1 = e1; int2.edge2 = e2; int2.pt = p; } //------------------------------------------------------------------------------ bool Clipper::FixupIntersections() { if ( !m_IntersectNodes->next ) return true; CopyAELToSEL(); IntersectNode *int1 = m_IntersectNodes; IntersectNode *int2 = m_IntersectNodes->next; while (int2) { TEdge *e1 = int1->edge1; TEdge *e2; if (e1->prevInSEL == int1->edge2) e2 = e1->prevInSEL; else if (e1->nextInSEL == int1->edge2) e2 = e1->nextInSEL; else { //The current intersection is out of order, so try and swap it with //a subsequent intersection ... while (int2) { if (int2->edge1->nextInSEL == int2->edge2 || int2->edge1->prevInSEL == int2->edge2) break; else int2 = int2->next; } if ( !int2 ) return false; //oops!!! //found an intersect node that can be swapped ... SwapIntersectNodes(*int1, *int2); e1 = int1->edge1; e2 = int1->edge2; } SwapPositionsInSEL(e1, e2); int1 = int1->next; int2 = int1->next; } m_SortedEdges = 0; //finally, check the last intersection too ... return (int1->edge1->prevInSEL == int1->edge2 || int1->edge1->nextInSEL == int1->edge2); } //------------------------------------------------------------------------------ bool E2InsertsBeforeE1(TEdge &e1, TEdge &e2) { return e2.xcurr == e1.xcurr ? e2.dx > e1.dx : e2.xcurr < e1.xcurr; } //------------------------------------------------------------------------------ void Clipper::InsertEdgeIntoAEL(TEdge *edge) { edge->prevInAEL = 0; edge->nextInAEL = 0; if( !m_ActiveEdges ) { m_ActiveEdges = edge; } else if( E2InsertsBeforeE1(*m_ActiveEdges, *edge) ) { edge->nextInAEL = m_ActiveEdges; m_ActiveEdges->prevInAEL = edge; m_ActiveEdges = edge; } else { TEdge* e = m_ActiveEdges; while( e->nextInAEL && !E2InsertsBeforeE1(*e->nextInAEL , *edge) ) e = e->nextInAEL; edge->nextInAEL = e->nextInAEL; if( e->nextInAEL ) e->nextInAEL->prevInAEL = edge; edge->prevInAEL = e; e->nextInAEL = edge; } } //---------------------------------------------------------------------- void Clipper::DoEdge1(TEdge *edge1, TEdge *edge2, const IntPoint &pt) { AddOutPt(edge1, pt); SwapSides(*edge1, *edge2); SwapPolyIndexes(*edge1, *edge2); } //---------------------------------------------------------------------- void Clipper::DoEdge2(TEdge *edge1, TEdge *edge2, const IntPoint &pt) { AddOutPt(edge2, pt); SwapSides(*edge1, *edge2); SwapPolyIndexes(*edge1, *edge2); } //---------------------------------------------------------------------- void Clipper::DoBothEdges(TEdge *edge1, TEdge *edge2, const IntPoint &pt) { AddOutPt(edge1, pt); AddOutPt(edge2, pt); SwapSides( *edge1 , *edge2 ); SwapPolyIndexes( *edge1 , *edge2 ); } //---------------------------------------------------------------------- void Clipper::CheckHoleLinkages1(OutRec *outRec1, OutRec *outRec2) { //when a polygon is split into 2 polygons, make sure any holes the original //polygon contained link to the correct polygon ... for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) { OutRec *orec = m_PolyOuts[i]; if (orec->isHole && orec->bottomPt && orec->FirstLeft == outRec1 && !PointInPolygon(orec->bottomPt->pt, outRec1->pts, m_UseFullRange)) orec->FirstLeft = outRec2; } } //---------------------------------------------------------------------- void Clipper::CheckHoleLinkages2(OutRec *outRec1, OutRec *outRec2) { //if a hole is owned by outRec2 then make it owned by outRec1 ... for (PolyOutList::size_type i = 0; i < m_PolyOuts.size(); ++i) if (m_PolyOuts[i]->isHole && m_PolyOuts[i]->bottomPt && m_PolyOuts[i]->FirstLeft == outRec2) m_PolyOuts[i]->FirstLeft = outRec1; } //---------------------------------------------------------------------- void Clipper::JoinCommonEdges(bool fixHoleLinkages) { for (JoinList::size_type i = 0; i < m_Joins.size(); i++) { JoinRec* j = m_Joins[i]; OutRec *outRec1 = m_PolyOuts[j->poly1Idx]; OutPt *pp1a = outRec1->pts; OutRec *outRec2 = m_PolyOuts[j->poly2Idx]; OutPt *pp2a = outRec2->pts; IntPoint pt1 = j->pt2a, pt2 = j->pt2b; IntPoint pt3 = j->pt1a, pt4 = j->pt1b; if (!FindSegment(pp1a, pt1, pt2)) continue; if (j->poly1Idx == j->poly2Idx) { //we're searching the same polygon for overlapping segments so //segment 2 mustn't be the same as segment 1 ... pp2a = pp1a->next; if (!FindSegment(pp2a, pt3, pt4) || (pp2a == pp1a)) continue; } else if (!FindSegment(pp2a, pt3, pt4)) continue; if (!GetOverlapSegment(pt1, pt2, pt3, pt4, pt1, pt2)) continue; OutPt *p1, *p2, *p3, *p4; OutPt *prev = pp1a->prev; //get p1 & p2 polypts - the overlap start & endpoints on poly1 if (PointsEqual(pp1a->pt, pt1)) p1 = pp1a; else if (PointsEqual(prev->pt, pt1)) p1 = prev; else p1 = InsertPolyPtBetween(pp1a, prev, pt1); if (PointsEqual(pp1a->pt, pt2)) p2 = pp1a; else if (PointsEqual(prev->pt, pt2)) p2 = prev; else if ((p1 == pp1a) || (p1 == prev)) p2 = InsertPolyPtBetween(pp1a, prev, pt2); else if (Pt3IsBetweenPt1AndPt2(pp1a->pt, p1->pt, pt2)) p2 = InsertPolyPtBetween(pp1a, p1, pt2); else p2 = InsertPolyPtBetween(p1, prev, pt2); //get p3 & p4 polypts - the overlap start & endpoints on poly2 prev = pp2a->prev; if (PointsEqual(pp2a->pt, pt1)) p3 = pp2a; else if (PointsEqual(prev->pt, pt1)) p3 = prev; else p3 = InsertPolyPtBetween(pp2a, prev, pt1); if (PointsEqual(pp2a->pt, pt2)) p4 = pp2a; else if (PointsEqual(prev->pt, pt2)) p4 = prev; else if ((p3 == pp2a) || (p3 == prev)) p4 = InsertPolyPtBetween(pp2a, prev, pt2); else if (Pt3IsBetweenPt1AndPt2(pp2a->pt, p3->pt, pt2)) p4 = InsertPolyPtBetween(pp2a, p3, pt2); else p4 = InsertPolyPtBetween(p3, prev, pt2); //p1.pt == p3.pt and p2.pt == p4.pt so join p1 to p3 and p2 to p4 ... if (p1->next == p2 && p3->prev == p4) { p1->next = p3; p3->prev = p1; p2->prev = p4; p4->next = p2; } else if (p1->prev == p2 && p3->next == p4) { p1->prev = p3; p3->next = p1; p2->next = p4; p4->prev = p2; } else continue; //an orientation is probably wrong if (j->poly2Idx == j->poly1Idx) { //instead of joining two polygons, we've just created a new one by //splitting one polygon into two. outRec1->pts = GetBottomPt(p1); outRec1->bottomPt = outRec1->pts; outRec1->bottomPt->idx = outRec1->idx; outRec2 = CreateOutRec(); m_PolyOuts.push_back(outRec2); outRec2->idx = (int)m_PolyOuts.size()-1; j->poly2Idx = outRec2->idx; outRec2->pts = GetBottomPt(p2); outRec2->bottomPt = outRec2->pts; outRec2->bottomPt->idx = outRec2->idx; if (PointInPolygon(outRec2->pts->pt, outRec1->pts, m_UseFullRange)) { //outRec2 is contained by outRec1 ... outRec2->isHole = !outRec1->isHole; outRec2->FirstLeft = outRec1; if (outRec2->isHole == (m_ReverseOutput ^ Orientation(outRec2, m_UseFullRange))) ReversePolyPtLinks(*outRec2->pts); } else if (PointInPolygon(outRec1->pts->pt, outRec2->pts, m_UseFullRange)) { //outRec1 is contained by outRec2 ... outRec2->isHole = outRec1->isHole; outRec1->isHole = !outRec2->isHole; outRec2->FirstLeft = outRec1->FirstLeft; outRec1->FirstLeft = outRec2; if (outRec1->isHole == (m_ReverseOutput ^ Orientation(outRec1, m_UseFullRange))) ReversePolyPtLinks(*outRec1->pts); //make sure any contained holes now link to the correct polygon ... if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2); } else { outRec2->isHole = outRec1->isHole; outRec2->FirstLeft = outRec1->FirstLeft; //make sure any contained holes now link to the correct polygon ... if (fixHoleLinkages) CheckHoleLinkages1(outRec1, outRec2); } //now fixup any subsequent joins that match this polygon for (JoinList::size_type k = i+1; k < m_Joins.size(); k++) { JoinRec* j2 = m_Joins[k]; if (j2->poly1Idx == j->poly1Idx && PointIsVertex(j2->pt1a, p2)) j2->poly1Idx = j->poly2Idx; if (j2->poly2Idx == j->poly1Idx && PointIsVertex(j2->pt2a, p2)) j2->poly2Idx = j->poly2Idx; } //now cleanup redundant edges too ... FixupOutPolygon(*outRec1); FixupOutPolygon(*outRec2); if (Orientation(outRec1, m_UseFullRange) != (Area(*outRec1, m_UseFullRange) > 0)) DisposeBottomPt(*outRec1); if (Orientation(outRec2, m_UseFullRange) != (Area(*outRec2, m_UseFullRange) > 0)) DisposeBottomPt(*outRec2); } else { //joined 2 polygons together ... //make sure any holes contained by outRec2 now link to outRec1 ... if (fixHoleLinkages) CheckHoleLinkages2(outRec1, outRec2); //now cleanup redundant edges too ... FixupOutPolygon(*outRec1); if (outRec1->pts) { outRec1->isHole = !Orientation(outRec1, m_UseFullRange); if (outRec1->isHole && !outRec1->FirstLeft) outRec1->FirstLeft = outRec2->FirstLeft; } //delete the obsolete pointer ... int OKIdx = outRec1->idx; int ObsoleteIdx = outRec2->idx; outRec2->pts = 0; outRec2->bottomPt = 0; outRec2->AppendLink = outRec1; //now fixup any subsequent Joins that match this polygon for (JoinList::size_type k = i+1; k < m_Joins.size(); k++) { JoinRec* j2 = m_Joins[k]; if (j2->poly1Idx == ObsoleteIdx) j2->poly1Idx = OKIdx; if (j2->poly2Idx == ObsoleteIdx) j2->poly2Idx = OKIdx; } } } } //------------------------------------------------------------------------------ void ReversePolygon(Polygon& p) { std::reverse(p.begin(), p.end()); } //------------------------------------------------------------------------------ void ReversePolygons(Polygons& p) { for (Polygons::size_type i = 0; i < p.size(); ++i) ReversePolygon(p[i]); } //------------------------------------------------------------------------------ // OffsetPolygon functions ... //------------------------------------------------------------------------------ struct DoublePoint { double X; double Y; DoublePoint(double x = 0, double y = 0) : X(x), Y(y) {} }; //------------------------------------------------------------------------------ Polygon BuildArc(const IntPoint &pt, const double a1, const double a2, const double r) { long64 steps = std::max(6, int(std::sqrt(std::fabs(r)) * std::fabs(a2 - a1))); if (steps > 0x100000) steps = 0x100000; int n = (unsigned)steps; Polygon result(n); double da = (a2 - a1) / (n -1); double a = a1; for (int i = 0; i < n; ++i) { result[i].X = pt.X + Round(std::cos(a)*r); result[i].Y = pt.Y + Round(std::sin(a)*r); a += da; } return result; } //------------------------------------------------------------------------------ DoublePoint GetUnitNormal( const IntPoint &pt1, const IntPoint &pt2) { if(pt2.X == pt1.X && pt2.Y == pt1.Y) return DoublePoint(0, 0); double dx = (double)(pt2.X - pt1.X); double dy = (double)(pt2.Y - pt1.Y); double f = 1 *1.0/ std::sqrt( dx*dx + dy*dy ); dx *= f; dy *= f; return DoublePoint(dy, -dx); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ class PolyOffsetBuilder { private: Polygons m_p; Polygon* m_curr_poly; std::vector normals; double m_delta, m_RMin, m_R; size_t m_i, m_j, m_k; static const int buffLength = 128; JoinType m_jointype; public: PolyOffsetBuilder(const Polygons& in_polys, Polygons& out_polys, double delta, JoinType jointype, double MiterLimit) { //nb precondition - out_polys != ptsin_polys if (NEAR_ZERO(delta)) { out_polys = in_polys; return; } this->m_p = in_polys; this->m_delta = delta; this->m_jointype = jointype; if (MiterLimit <= 1) MiterLimit = 1; m_RMin = 2/(MiterLimit*MiterLimit); double deltaSq = delta*delta; out_polys.clear(); out_polys.resize(in_polys.size()); for (m_i = 0; m_i < in_polys.size(); m_i++) { m_curr_poly = &out_polys[m_i]; size_t len = in_polys[m_i].size(); if (len > 1 && m_p[m_i][0].X == m_p[m_i][len - 1].X && m_p[m_i][0].Y == m_p[m_i][len-1].Y) len--; //when 'shrinking' polygons - to minimize artefacts //strip those polygons that have an area < pi * delta^2 ... double a1 = Area(in_polys[m_i]); if (delta < 0) { if (a1 > 0 && a1 < deltaSq *pi) len = 0; } else if (a1 < 0 && -a1 < deltaSq *pi) len = 0; //holes have neg. area if (len == 0 || (len < 3 && delta <= 0)) continue; else if (len == 1) { Polygon arc; arc = BuildArc(in_polys[m_i][len-1], 0, 2 * pi, delta); out_polys[m_i] = arc; continue; } //build normals ... normals.clear(); normals.resize(len); normals[len-1] = GetUnitNormal(in_polys[m_i][len-1], in_polys[m_i][0]); for (m_j = 0; m_j < len -1; ++m_j) normals[m_j] = GetUnitNormal(in_polys[m_i][m_j], in_polys[m_i][m_j+1]); m_k = len -1; for (m_j = 0; m_j < len; ++m_j) { switch (jointype) { case jtMiter: { m_R = 1 + (normals[m_j].X*normals[m_k].X + normals[m_j].Y*normals[m_k].Y); if (m_R >= m_RMin) DoMiter(); else DoSquare(MiterLimit); break; } case jtSquare: DoSquare(); break; case jtRound: DoRound(); break; } m_k = m_j; } } //finally, clean up untidy corners using Clipper ... Clipper clpr; clpr.AddPolygons(out_polys, ptSubject); if (delta > 0) { if (!clpr.Execute(ctUnion, out_polys, pftPositive, pftPositive)) out_polys.clear(); } else { IntRect r = clpr.GetBounds(); Polygon outer(4); outer[0] = IntPoint(r.left - 10, r.bottom + 10); outer[1] = IntPoint(r.right + 10, r.bottom + 10); outer[2] = IntPoint(r.right + 10, r.top - 10); outer[3] = IntPoint(r.left - 10, r.top - 10); clpr.AddPolygon(outer, ptSubject); if (clpr.Execute(ctUnion, out_polys, pftNegative, pftNegative)) { out_polys.erase(out_polys.begin()); ReversePolygons(out_polys); } else out_polys.clear(); } } //------------------------------------------------------------------------------ private: void AddPoint(const IntPoint& pt) { Polygon::size_type len = m_curr_poly->size(); if (len == m_curr_poly->capacity()) m_curr_poly->reserve(len + buffLength); m_curr_poly->push_back(pt); } //------------------------------------------------------------------------------ void DoSquare(double mul = 1.0) { IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta)); IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta)); if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0) { double a1 = std::atan2(normals[m_k].Y, normals[m_k].X); double a2 = std::atan2(-normals[m_j].Y, -normals[m_j].X); a1 = std::fabs(a2 - a1); if (a1 > pi) a1 = pi * 2 - a1; double dx = std::tan((pi - a1)/4) * std::fabs(m_delta * mul); pt1 = IntPoint((long64)(pt1.X -normals[m_k].Y * dx), (long64)(pt1.Y + normals[m_k].X * dx)); AddPoint(pt1); pt2 = IntPoint((long64)(pt2.X + normals[m_j].Y * dx), (long64)(pt2.Y -normals[m_j].X * dx)); AddPoint(pt2); } else { AddPoint(pt1); AddPoint(m_p[m_i][m_j]); AddPoint(pt2); } } //------------------------------------------------------------------------------ void DoMiter() { if ((normals[m_k].X * normals[m_j].Y - normals[m_j].X * normals[m_k].Y) * m_delta >= 0) { double q = m_delta / m_R; AddPoint(IntPoint((long64)Round(m_p[m_i][m_j].X + (normals[m_k].X + normals[m_j].X) * q), (long64)Round(m_p[m_i][m_j].Y + (normals[m_k].Y + normals[m_j].Y) * q))); } else { IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta)); IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta)); AddPoint(pt1); AddPoint(m_p[m_i][m_j]); AddPoint(pt2); } } //------------------------------------------------------------------------------ void DoRound() { IntPoint pt1 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_k].X * m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_k].Y * m_delta)); IntPoint pt2 = IntPoint((long64)Round(m_p[m_i][m_j].X + normals[m_j].X * m_delta), (long64)Round(m_p[m_i][m_j].Y + normals[m_j].Y * m_delta)); AddPoint(pt1); //round off reflex angles (ie > 180 deg) unless almost flat (ie < ~10deg). if ((normals[m_k].X*normals[m_j].Y - normals[m_j].X*normals[m_k].Y) * m_delta >= 0) { if (normals[m_j].X * normals[m_k].X + normals[m_j].Y * normals[m_k].Y < 0.985) { double a1 = std::atan2(normals[m_k].Y, normals[m_k].X); double a2 = std::atan2(normals[m_j].Y, normals[m_j].X); if (m_delta > 0 && a2 < a1) a2 += pi *2; else if (m_delta < 0 && a2 > a1) a2 -= pi *2; Polygon arc = BuildArc(m_p[m_i][m_j], a1, a2, m_delta); for (Polygon::size_type m = 0; m < arc.size(); m++) AddPoint(arc[m]); } } else AddPoint(m_p[m_i][m_j]); AddPoint(pt2); } //-------------------------------------------------------------------------- }; //end PolyOffsetBuilder //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ void OffsetPolygons(const Polygons &in_polys, Polygons &out_polys, double delta, JoinType jointype, double MiterLimit) { if (&out_polys == &in_polys) { Polygons poly2(in_polys); PolyOffsetBuilder(poly2, out_polys, delta, jointype, MiterLimit); } else PolyOffsetBuilder(in_polys, out_polys, delta, jointype, MiterLimit); } //------------------------------------------------------------------------------ void SimplifyPolygon(const Polygon &in_poly, Polygons &out_polys, PolyFillType fillType) { Clipper c; c.AddPolygon(in_poly, ptSubject); c.Execute(ctUnion, out_polys, fillType, fillType); } //------------------------------------------------------------------------------ void SimplifyPolygons(const Polygons &in_polys, Polygons &out_polys, PolyFillType fillType) { Clipper c; c.AddPolygons(in_polys, ptSubject); c.Execute(ctUnion, out_polys, fillType, fillType); } //------------------------------------------------------------------------------ void SimplifyPolygons(Polygons &polys, PolyFillType fillType) { SimplifyPolygons(polys, polys, fillType); } //------------------------------------------------------------------------------ std::ostream& operator <<(std::ostream &s, IntPoint& p) { s << p.X << ' ' << p.Y << "\n"; return s; } //------------------------------------------------------------------------------ std::ostream& operator <<(std::ostream &s, Polygon &p) { for (Polygon::size_type i = 0; i < p.size(); i++) s << p[i]; s << "\n"; return s; } //------------------------------------------------------------------------------ std::ostream& operator <<(std::ostream &s, Polygons &p) { for (Polygons::size_type i = 0; i < p.size(); i++) s << p[i]; s << "\n"; return s; } //------------------------------------------------------------------------------ } //ClipperLib namespace assimp-4.1.0/AssimpBuildTreeSettings.cmake.in0000644002537200234200000000011313213503245021433 0ustar zmoelnigiemusersset(ASSIMP_INCLUDE_DIRS "@PROJECT_SOURCE_DIR@" "@PROJECT_BINARY_DIR@") assimp-4.1.0/assimp.pc.in0000644002537200234200000000070313213503245015501 0ustar zmoelnigiemusersprefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=@CMAKE_INSTALL_PREFIX@/ libdir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_LIB_INSTALL_DIR@ includedir=@CMAKE_INSTALL_PREFIX@/@ASSIMP_INCLUDE_INSTALL_DIR@ Name: @CMAKE_PROJECT_NAME@ Description: Import various well-known 3D model formats in an uniform manner. Version: @PROJECT_VERSION@ Libs: -L${libdir} -lassimp@ASSIMP_LIBRARY_SUFFIX@ Libs.private: @LIBSTDC++_LIBRARIES@ @ZLIB_LIBRARIES_LINKED@ Cflags: -I${includedir} assimp-4.1.0/CHANGES0000644002537200234200000003500213213503245014247 0ustar zmoelnigiemusers---------------------------------------------------------------------- CHANGELOG ---------------------------------------------------------------------- 4.0.1 (2017-07-28) - FIXES/HOUSEKEEPING: - fix version test. - Not compiling when using ASSIMP_DOUBLE_PRECISION - Added support for python3 - Check if cmake is installed with brew - Low performance in OptimizeMeshesProcess::ProcessNode with huge numbers of meshes - Elapsed seconds not shown correctly - StreamReader: fix out-of-range exception - PPdPmdParser: fix compilation for clang 4.0.0 (2017-07-18) FEATURES: - Double precision support provided ( available via cmake option ) - QT-Widget based assimp-viewer ( works for windows, linux, osx ) - Open3DGC codec supported by glFT-importer - glTF: Read and write transparency values - Add Triangulate post-processing step to glTF exporters - Update rapidjson to v1.0.2 - Added method to append new metadata to structure - Unittests: intoduce a prototype model differ - X3D support - AMF support - Lugdunum3D support - Obj-Importer: obj-homogeneous_coords support - Obj-Importer: new streaming handling - Added support for 64 bit version header introduced in FbxSdk2016 - Travis: enable coverall support. - PyAssimp: New version of the pyASSIMP 3D viewer, with much improved 3D controls - Morph animation support for collada - Added support for parameters Ni and Tf in OBJ/MTL file format - aiScene: add method to add children - Added new option to IFC importer to control tessellation angle + removed unused IFC option - aiMetaData: introduce aiMetaData::Dealloc - Samples: add a DX11 example - travis ci: test on OXS ( XCode 6.3 ) as well - travis ci: enable sudo support. - openddlparser: integrate release v0.4.0 - aiMetaData: Added support for metadata in assbin format FIXES/HOUSEKEEPING: - Introduce usage of #pragma statement - Put cmake-scripts into their own folder - Fix install pathes ( issue 938 ) - Fix object_compare in blender importer( issue 946 ) - Fix OSX compilation error - Fix unzip path when no other version was found ( issue 967 ) - Set _FILE_OFFSET_BITS=64 for 32-bit linux ( issue 975 ) - Fix constructor for radjson on OSX - Use Assimp namespace to fix build for big-endian architectures - Add -fPIC to C Flags for 64bit linux Shared Object builds - MDLLoader: fix resource leak. - MakeVerboseFormat: fix invalid delete statement - IFC: fix possible use after free access bug - ComputeUVMappingprocess: add missing initialization for scalar value - Fix invalid release of mat + mesh - IrrImporter: Fix release functions - Split mesh before exporting gltf ( issue 995 ) - 3MFImporter: add source group for visual studio - IFC: Switch generated file to 2 files to fix issue related to and ( issue 1084 ) - OBJParser: set material index when changing current material - OBJ: check for null mesh before updating material index - add vertex color export support ( issue 809 ) - Fix memory leak in Collada importer ( issue 1169 ) - add stp to the list of supported extensions for step-files ( issue 1183 ) - fix clang build ( Issue-1169 ) - fix for FreeBSD - Import FindPkgMacros to main CMake Configuration - Extended support for tessellation parameter to more IFC shapes - defensice handling of utf-8 decode issues ( issue 1211 ) - Fixed compiler error on clang 4.0 running on OSX - use test extension for exported test files ( issue 1228 ) - Set UVW index material properties for OBJ files - Fixed no member named 'atop' in global namespace issue for Android NDK compilation - Apply mechanism to decide use for IrrXML external or internal - Fix static init ordering bug in OpenGEX importer - GLTF exporter: ensure animation accessors have same count - GLTF exporter: convert animation time from ticks to seconds - Add support for reading texture coordinates from PLY meshes with properties named 'texture_u' and 'texture_v' - Added TokensForSearch in BlenderLoader to allow CanRead return true for in-memory files. - fix wrong delete ( issue 1266 ) - OpenGEX: fix invalid handling with color4 token ( issue 1262 ) - LWOLoader: fix link in loader description - Fix error when custom CMAKE_C_FLAGS is specified - Fast-atof: log overflow errors - Obj-Importer: do not break when detecting an overflow ( issue 1244 ) - Obj-Importer: fix parsing of multible line data definitions - Fixed bug where IFC models with multiple IFCSite only loaded 1 site instead of the complete model - PLYImporter: - optimize memory and speed on ply importer / change parser to use a file stream - manage texture path in ply import - manage texture coords on faces in ply import - correction on point cloud faces generation - Utf8: integrate new lib ( issue 1158 ) - fixed CMAKE_MODULE_PATH overwriting previous values - OpenGEX: Fixed bug in material color processing ( issue 1271 ) - SceneCombiner: move header for scenecombiner to public folder. - GLTF exporter: ensure buffer view byte offsets are correctly aligned - X3D importer: Added EXPORT and IMPORT to the list of ignored XML tags - X3D Exporter: fixed missing attributes - X3D importer: Fixed import of normals for the single index / normal per vertex case - X3D importer: Fixed handling of inlined files - X3D importer: fixed whitespace handling (issue 1202) - X3D importer: Fixed iterator on MSVC 2015 - X3D importer: Fixed problems with auto, override and regex on older compilers - X3D importer: Fixed missing header file - X3D importer: Fixed path handling - X3D importer: Implemented support for binary X3D files - fix build without 3DS ( issue 1319 ) - pyassimp: Fixed indices for IndexedTriangleFanSet, IndexedTriangleSet and IndexedTriangleStripSet - Fixes parameters to pyassimp.load - Obj-Importe: Fixed texture bug due simultaneously using 'usemtl' and 'usemap' attributes - check if all exporters are disabled ( issue 1320 ) - Remove std functions deprecated by C++11. - X-Importer: make it deal with lines - use correct path for compilers ( issue 1335 ) - Collada: add workaround to deal with polygon with holes - update python readme - Use unique node names when loading Collada files - Fixed many FBX bugs API COMPATIBILITY: - Changed ABI-compatibility to v3.3.1, please rebuild your precompiled libraries ( see issue 1182 ) - VS2010 outdated 3.3.1 (2016-07-08) FIXES/HOUSEKEEPING: - Setup of default precision for 17 exporters - Fix xcode project files - Fix BlenderTesselator: offsetof operator - Invalid version in cmake file - Update pstdint.h to latest greatest 3.3.0 (2016-07-05) FEATURES: - C++11 support enabled - New regression-test-UI - Experimental glTF-importer support - OpenGEX: add support for cameras and lights - C4D: update to latest Melange-SDK - Add a gitter channel - Coverity check enabled - Switch to <...> include brackets for public headers - Enable export by pyAssimp - CI: check windows build - Add functionality to perform a singlepost-processing step - many more, just check the history FIXES/HOUSEKEEPING: - Fix of many resource leaks in unittests and main lib - Fix iOS-buildfor X64 - Choosing zlib manually for cmake - many more, just check the history 3.2.1 (2016-010-10) FEATURES: - Updated glTF exporter to meet 1.0 specification. FIXES/HOUSEKEEPING: - Fixed glTF Validator errors for exported glTF format. ISSUES: - Hard coded sampler setting for - magFilter - minFilter - void* in ExportData for accessor max and min. 3.2.0 (2015-11-03) FEATURES: - OpenDDL-Parser is part of contrib-source. - Experimental OpenGEX-support - CI-check for linux and windows - Coverity check added - New regression testsuite. FIXES/HOUSEKEEPING: - Hundreds of bugfixes in all parts of the library - Unified line endings API COMPATIBILITY: - Removed precompiled header to increase build speed for linux 3.1.1 (2014-06-15) FEATURES: - Support for FBX 2013 and newer, binary and ASCII (this is partly work from Google Summer of Code 2012) - Support for OGRE binary mesh and skeleton format - Updated BLEND support for newer Blender versions - Support for arbitrary meta data, used to hold FBX and DAE metadata - OBJ Export now produces smaller files - Meshes can now have names, this is supported by the major importers - Improved IFC geometry generation - M3 support has been removed FIXES/HOUSEKEEPING: - Hundreds of bugfixes in all parts of the library - CMake is now the primary build system API COMPATIBILITY: - 3.1.1 is not binary compatible to 3.0 due to aiNode::mMetaData and aiMesh::mName - Export interface has been cleaned up and unified - Other than that no relevant changes 3.0 (2012-07-07) FEATURES: - new export interface similar to the import API. - Supported export formats: Collada, OBJ, PLY and STL - added new import formats: XGL/ZGL, M3 (experimental) - new postprocessing steps: Debone - vastly improved IFC (Industry Foundation Classes) support - introduced API to query importer meta information (such as supported format versions, full name, maintainer info). - reworked Ogre XML import - C-API now supports per-import properties FIXES/HOUSEKEEPING: - hundreds of bugfixes in all parts of the library - unified naming and cleanup of public headers - improved CMake build system - templatized math library - reduce dependency on boost.thread, only remaining spot is synchronization for the C logging API API COMPATIBILITY: - renamed headers, export interface, C API properties and meta data prevent compatibility with code written for 2.0, but in most cases these can be easily resolved - Note: 3.0 is not binary compatible with 2.0 2.0 (2010-11-21) FEATURES: - Add support for static Blender (*.blend) scenes - Add support for Q3BSP scenes - Add a windows-based OpenGL sample featuring texturing & basic materials - Add an experimental progress feedback interface. - Vastly improved performance (up to 500%, depending on mesh size and spatial structure) in some expensive postprocessing steps - AssimpView now uses a reworked layout which leaves more space to the scene hierarchy window - Add C# bindings ('Assimp.NET') - Keep BSD-licensed and otherwise free test files in separate folders (./test/models and ./test/models-nonbsd). FIXES: - Many Collada bugfixes, improve fault tolerance - Fix possible crashes in the Obj loader - Improve the Ogre XML loader - OpenGL-sample now works with MinGW - Fix Importer::FindLoader failing on uppercase file extensions - Fix flawed path handling when locating external files - Limit the maximum number of vertices, faces, face indices and weights that Assimp is able to handle. This is to avoid crashes due to overflowing counters. - Updated XCode project files - Further CMAKE build improvements API CHANGES: - Add data structures for vertex-based animations (These are not currently used, however ...) - Some Assimp::Importer methods are const now. 1.1 (2010-04-17) This is the list of relevant changes from the 1.0 (r412) release to 1.1 (r700). FEATURES: - Vastly improved Collada support - Add MS3D (Milkshape 3D) support - Add support for Ogre XML static meshes - Add experimental COB (TrueSpace) support - Automatic test suite to quickly locate regressions - D bindings (`dAssimp`) - Python 2.n bindings (`PyAssimp`) - Add basic support for Unicode input files (utf8, utf16 and utf32) - Add further utilities to the `assimp` tool (xml/binary dumps, quick file stats) - Switch to a CMAKE-based build system including an install target for unix'es - Automatic evaluation of subdivision surfaces for some formats. - Add `Importer::ReadFileFromMemory` and the corresponding C-API `aiReadFileFromMemory` - Expose further math utilities via the C-API (i.e. `aiMultiplyMatrix4`) - Move noboost files away from the public include directory - Many, many bugfixes and improvements in existing loaders and postprocessing steps - Documentation improved and clarified in many places. - Add a sample on using Assimp in conjunction with OpenGL - Distribution/packaging: comfortable SDK installer for Windows - Distribution/packaging: improved release packages for other architectures CRITICAL FIXES: - Resolve problems with clashing heap managers, STL ABIs and runtime libraries (win32) - Fix automatic detection of file type if no file extension is given - Improved exception safety and robustness, prevent leaking of exceptions through the C interface - Fix possible heap corruption due to material properties pulled in incorrectly - Avoid leaking in certain error scenarios - Fix 64 bit compatibility problems in some loaders (i.e. MDL) BREAKING API CHANGES: - None - MINOR API BEHAVIOUR CHANGES: - Change quaternion orientation to suit to the more common convention (-w). - aiString is utf8 now. Not yet consistent, however. assimp-4.1.0/INSTALL0000644002537200234200000000264613213503245014315 0ustar zmoelnigiemusers ======================================================================== Open Asset Import Library (assimp) INSTALL ======================================================================== ------------------------------ Getting the documentation ------------------------------ A regularly-updated copy is available at http://assimp.sourceforge.net/lib_html/index.html A CHM file is included in the SVN repos: ./doc/AssimpDoc_Html/AssimpDoc.chm. To build the doxygen documentation on your own, follow these steps: a) download & install latest doxygen b) make sure doxygen is in the executable search path c) navigate to ./doc d) and run 'doxygen' Open the generated HTML (AssimpDoc_Html/index.html) in the browser of your choice. Windows only: To generate the CHM doc, install 'Microsoft HTML Workshop' and configure the path to it in the DOXYFILE first. ------------------------------ Building Assimp ------------------------------ More detailed build instructions can be found in the documentation, this section is just for the inpatient among you. CMake is the preferred build system for Assimp. The minimum required version is 2.6. If you don't have it yet, downloads for CMake can be found on http://www.cmake.org/. For Unix: 1. cmake CMakeLists.txt -G 'Unix Makefiles' 2. make For Windows: 1. Open a command prompt 2. cmake CMakeLists.txt 2. Open your default IDE and build it assimp-4.1.0/port/0000755002537200234200000000000013213503245014240 5ustar zmoelnigiemusersassimp-4.1.0/port/AssimpNET/0000755002537200234200000000000013213503245016043 5ustar zmoelnigiemusersassimp-4.1.0/port/AssimpNET/Readme.md0000644002537200234200000000014713213503245017564 0ustar zmoelnigiemusersSee https://code.google.com/p/assimp-net/ and https://github.com/assimp/assimp-net for a Github mirror.assimp-4.1.0/port/AssimpDelphi/0000755002537200234200000000000013213503245016622 5ustar zmoelnigiemusersassimp-4.1.0/port/AssimpDelphi/Readme.txt0000644002537200234200000000103013213503245020552 0ustar zmoelnigiemusersThis is a set of Delphi units for using the Assimp C DLL. This was created for use with Delphi 7, but should be usable as-is or with minimal modifications with later Delphi versions. This set of headers is enough to load and display a model with external textures. Since I'm not familiar with animated models and some of the other functionality of the assimp library, I did not convert the headers for those features. See http://sourceforge.net/tracker/?func=detail&aid=3212646&group_id=226462&atid=1067634 for the original patch assimp-4.1.0/port/AssimpDelphi/assimp.pas0000644002537200234200000000655413213503245020635 0ustar zmoelnigiemusersunit assimp; interface uses aiTypes, aiMatrix4x4, aiMatrix3x3, aiMesh, aiScene, aiMaterial, aiColor4d, aiVector3D; const ASSIMP_DLL = 'assimp32.dll'; function aiImportFile(filename: pchar; pFlags: integer): PaiScene; cdecl; external ASSIMP_DLL; procedure aiReleaseImport( pScene: pointer); cdecl; external ASSIMP_DLL; function aiGetErrorString(): PChar; cdecl; external ASSIMP_DLL; //procedure aiDecomposeMatrix( var mat: TaiMatrix4x4; var scaling: TaiVector3D; var rotation: TaiQuaternion; var position: TaiVector3D); cdecl; external ASSIMP_DLL; procedure aiTransposeMatrix4( var mat: TaiMatrix4x4); cdecl; external ASSIMP_DLL; procedure aiTransposeMatrix3( var mat: TaiMatrix3x3); cdecl; external ASSIMP_DLL; procedure aiTransformVecByMatrix3( var vec: TaiVector3D; var mat: TaiMatrix3x3); cdecl; external ASSIMP_DLL; procedure aiTransformVecByMatrix4( var vec: TaiVector3D; var mat: TaiMatrix4x4); cdecl; external ASSIMP_DLL; procedure aiMultiplyMatrix4(var dst: TaiMatrix4x4; var src: TaiMatrix4x4); cdecl; external ASSIMP_DLL; procedure aiMultiplyMatrix3(var dst: TaiMatrix3x3; var src: TaiMatrix3x3); cdecl; external ASSIMP_DLL; procedure aiIdentityMatrix3(var mat: TaiMatrix3x3); cdecl; external ASSIMP_DLL; procedure aiIdentityMatrix4(var mat: TaiMatrix4x4); cdecl; external ASSIMP_DLL; //----- from aiMaterial.h function aiGetMaterialProperty( pMat: PaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; pPropOut: pointer): aiReturn; cdecl; external ASSIMP_DLL; function aiGetMaterialFloatArray( var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: Single; var pMax: Cardinal): aiReturn; cdecl; external ASSIMP_DLL; function aiGetMaterialFloat( var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: Single): aiReturn; function aiGetMaterialIntegerArray(var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: Integer; var pMax: Cardinal): aiReturn; cdecl; external ASSIMP_DLL; function aiGetMaterialInteger(var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: Integer): aiReturn; function aiGetMaterialColor(var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: TaiColor4d): aiReturn; cdecl; external ASSIMP_DLL; function aiGetMaterialString(var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: aiString): aiReturn; cdecl; external ASSIMP_DLL; function aiGetMaterialTextureCount(var pMat: TaiMaterial; nType: TaiTextureType): Cardinal; cdecl; external ASSIMP_DLL; function aiGetMaterialTexture(var mat: TaiMaterial; nType: TaiTextureType; nIndex: Cardinal; var path: aiString; var mapping: TaiTextureMapping; var uvindex: Cardinal; var blend: single; var op: TaiTextureOp; var mapmode: TaiTextureMapMode; var flags: Cardinal): aiReturn; cdecl; external ASSIMP_DLL; implementation function aiGetMaterialFloat( var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: Single): aiReturn; var n: cardinal; begin n := 0; result := aiGetMaterialFloatArray( pMat, pKey, nType, nIndex, pOut, n); end; function aiGetMaterialInteger(var pMat: TaiMaterial; pKey: PChar; nType: Cardinal; nIndex: Cardinal; var pOut: integer): aiReturn; var n: cardinal; begin n := 0; result := aiGetMaterialIntegerArray( pMat, pKey, nType, nIndex, pOut, n); end; end. assimp-4.1.0/port/AssimpDelphi/aiMatrix3x3.pas0000644002537200234200000000033413213503245021443 0ustar zmoelnigiemusersunit aiMatrix3x3; interface type TaiMatrix3x3 = packed record a1, a2, a3, a4: single; b1, b2, b3, b4: single; c1, c2, c3, c4: single; end; PaiMatrix3x3 = ^TaiMatrix3x3; implementation end. assimp-4.1.0/port/AssimpDelphi/aiColor4D.pas0000644002537200234200000000044513213503245021112 0ustar zmoelnigiemusersunit aiColor4D; interface const AI_MAX_NUMBER_OF_COLOR_SETS = $04; type TaiColor4D = packed record r, g, b, a: single; end; type PaiColor4D = ^TaiColor4D; type TaiColor4DArray = array[0..0] of TaiColor4D; type PTaiColor4DArray = ^TaiColor4DArray; implementation end. assimp-4.1.0/port/AssimpDelphi/aiTypes.pas0000644002537200234200000000175613213503245020756 0ustar zmoelnigiemusersunit aiTypes; interface //added for Delphi interface type TCardinalArray = array [0..0] of Cardinal; PCardinalArray = ^TCardinalArray; TSingleArray = array[0..0] of Single; PSingleArray = ^TSingleArray; type aiString = packed record length: Cardinal; data: array [0..1023] of char; end; type PaiString = ^aiString; type aiReturn = ( aiReturn_SUCCESS = $0, aiReturn_FAILURE = -$1, aiReturn_OUTOFMEMORY = -$3, _AI_ENFORCE_ENUM_SIZE = $7fffffff ); const AI_SUCCESS = aiReturn_SUCCESS; const AI_FAILURE = aiReturn_FAILURE; const AI_OUTOFMEMORY = aiReturn_OUTOFMEMORY; function aiStringToDelphiString( a: aiString): AnsiString; implementation function aiStringToDelphiString( a: aiString): AnsiString; var i: integer; begin result := ''; if a.length > 0 then begin SetLength( result, a.length); for i := 1 to a.length do begin result[i] := a.data[i-1]; end; end; end; end. assimp-4.1.0/port/AssimpDelphi/aiVector3D.pas0000644002537200234200000000046413213503245021276 0ustar zmoelnigiemusersunit aiVector3D; interface type TaiVector3D = packed record x, y, z: single; end; type PaiVector3D = ^TaiVector3D; type PaiVector3DArray = array [0..0] of PaiVector3D; type TaiVector3DArray = array[0..0] of TaiVector3D; type PTaiVector3DArray = ^TaiVector3DArray; implementation end. assimp-4.1.0/port/AssimpDelphi/aiMatrix4x4.pas0000644002537200234200000000036613213503245021452 0ustar zmoelnigiemusersunit aiMatrix4x4; interface type TaiMatrix4x4 = packed record a1, a2, a3, a4: single; b1, b2, b3, b4: single; c1, c2, c3, c4: single; d1, d2, d3, d4: single; end; PaiMatrix4x4 = ^TaiMatrix4x4; implementation end. assimp-4.1.0/port/AssimpDelphi/aiTexture.pas0000644002537200234200000000112213213503245021275 0ustar zmoelnigiemusersunit aiTexture; interface type TaiTexel = packed record b, g, r, a: byte; end; PaiTexel = ^TaiTexel; TaiTexelArray = array[0..0] of TaiTexel; PaiTexelArray = ^TaiTexelArray; type TaiTexture = packed record mWidth: Cardinal; //width in pixels, OR total embedded file size if texture is a jpg/png/etc mHeight: Cardinal; //0 if texture is an embedded file achFormatHint: array[0..3] of byte; pcData: PaiTexelArray; end; PaiTexture = ^TaiTexture; PaiTextureArray = array [0..0] of PaiTexture; PPaiTextureArray = ^PaiTextureArray; implementation end. assimp-4.1.0/port/AssimpDelphi/aiVector2D.pas0000644002537200234200000000023113213503245021265 0ustar zmoelnigiemusersunit aiVector2D; interface type TaiVector2D = packed record x, y: single; end; type PaiVector2D = ^TaiVector2D; implementation end. assimp-4.1.0/port/AssimpDelphi/aiMaterial.pas0000644002537200234200000001052113213503245021376 0ustar zmoelnigiemusersunit aiMaterial; interface uses aiTypes, aiVector2D, aiVector3D; {This following directive causes enums to be stored as double words (32bit), to be compatible with the assimp C Dll} {$Z4} type TaiTextureOp = ( aiTextureOp_Multiply = $0, aiTextureOp_Add = $1, aiTextureOp_Subtract = $2, aiTextureOp_Divide = $3, aiTextureOp_SmoothAdd = $4, aiTextureOp_SignedAdd = $5 //_aiTextureOp_Force32Bit = 0x9fffffff ); type TaiTextureMapMode = ( aiTextureMapMode_Wrap = $0, aiTextureMapMode_Clamp = $1, aiTextureMapMode_Decal = $3, aiTextureMapMode_Mirror = $2 //_aiTextureMapMode_Force32Bit = 0x9fffffff ); type TaiTextureMapping = ( aiTextureMapping_UV = $0, aiTextureMapping_SPHERE = $1, aiTextureMapping_CYLINDER = $2, aiTextureMapping_BOX = $3, aiTextureMapping_PLANE = $4, aiTextureMapping_OTHER = $5 //_aiTextureMapping_Force32Bit = 0x9fffffff ); type TaiTextureType = ( aiTextureType_NONE = $0, aiTextureType_DIFFUSE = $1, aiTextureType_SPECULAR = $2, aiTextureType_AMBIENT = $3, aiTextureType_EMISSIVE = $4, aiTextureType_HEIGHT = $5, aiTextureType_NORMALS = $6, aiTextureType_SHININESS = $7, aiTextureType_OPACITY = $8, aiTextureType_DISPLACEMENT = $9, aiTextureType_LIGHTMAP = $A, aiTextureType_REFLECTION = $B, aiTextureType_UNKNOWN = $C //_aiTextureType_Force32Bit = 0x9fffffff ); const AI_TEXTURE_TYPE_MAX = aiTextureType_UNKNOWN; type TaiShadingMode = ( aiShadingMode_Flat = $1, aiShadingMode_Gouraud = $2, aiShadingMode_Phong = $3, aiShadingMode_Blinn = $4, aiShadingMode_Toon = $5, aiShadingMode_OrenNayar = $6, aiShadingMode_Minnaert = $7, aiShadingMode_CookTorrance = $8, aiShadingMode_NoShading = $9, aiShadingMode_Fresnel = $A //_aiShadingMode_Force32Bit = 0x9fffffff ); type TaiTextureFlags = ( aiTextureFlags_Invert = $1, aiTextureFlags_UseAlpha = $2, aiTextureFlags_IgnoreAlpha = $4 //_aiTextureFlags_Force32Bit = 0x9fffffff ); type TaiBlendMode = ( aiBlendMode_Default = $0, aiBlendMode_Additive = $1 //_aiBlendMode_Force32Bit = 0x9fffffff ); type TaiUVTransform = packed record mTranslation: TaiVector2D; mScaling: TaiVector2D; mRotation: single; end; type TaiPropertyTypeInfo = ( aiPTI_Float = $1, aiPTI_String = $3, aiPTI_Integer = $4, aiPTI_Buffer = $5 // _aiPTI_Force32Bit = 0x9fffffff ); type TaiMaterialProperty = packed record mKey: aiString; mSemantic: Cardinal; mIndex: Cardinal; mDataLength: Cardinal; mType: TaiPropertyTypeInfo; mData: PChar; end; type PaiMaterialProperty = ^TaiMaterialProperty; type TaiMaterial = packed record mProperties: pointer; mNumProperties: Cardinal; mNumAllocated: Cardinal; end; type PaiMaterial = ^TaiMaterial; type PaiMaterialArray = array[0..0] of PaiMaterial; type PPaiMaterialArray = ^PaiMaterialArray; const AI_MATKEY_NAME = '?mat.name'; const AI_MATKEY_TWOSIDED = '$mat.twosided'; const AI_MATKEY_SHADING_MODEL = '$mat.shadingm'; const AI_MATKEY_ENABLE_WIREFRAME = '$mat.wireframe'; const AI_MATKEY_BLEND_FUNC = '$mat.blend'; const AI_MATKEY_OPACITY = '$mat.opacity'; const AI_MATKEY_BUMPSCALING = '$mat.bumpscaling'; const AI_MATKEY_SHININESS = '$mat.shininess'; const AI_MATKEY_REFLECTIVITY = '$mat.reflectivity'; const AI_MATKEY_SHININESS_STRENGTH = '$mat.shinpercent'; const AI_MATKEY_REFRACTI = '$mat.refracti'; const AI_MATKEY_COLOR_DIFFUSE = '$clr.diffuse'; const AI_MATKEY_COLOR_AMBIENT = '$clr.ambient'; const AI_MATKEY_COLOR_SPECULAR = '$clr.specular'; const AI_MATKEY_COLOR_EMISSIVE = '$clr.emissive'; const AI_MATKEY_COLOR_TRANSPARENT = '$clr.transparent'; const AI_MATKEY_COLOR_REFLECTIVE = '$clr.reflective'; const AI_MATKEY_GLOBAL_BACKGROUND_IMAGE = '?bg.global'; const _AI_MATKEY_TEXTURE_BASE = '$tex.file'; const _AI_MATKEY_UVWSRC_BASE = '$tex.uvwsrc'; const _AI_MATKEY_TEXOP_BASE = '$tex.op'; const _AI_MATKEY_MAPPING_BASE = '$tex.mapping'; const _AI_MATKEY_TEXBLEND_BASE = '$tex.blend'; const _AI_MATKEY_MAPPINGMODE_U_BASE = '$tex.mapmodeu'; const _AI_MATKEY_MAPPINGMODE_V_BASE = '$tex.mapmodev'; const _AI_MATKEY_TEXMAP_AXIS_BASE = '$tex.mapaxis'; const _AI_MATKEY_UVTRANSFORM_BASE = '$tex.uvtrafo'; const _AI_MATKEY_TEXFLAGS_BASE = '$tex.flags'; implementation end. assimp-4.1.0/port/AssimpDelphi/aiScene.pas0000644002537200234200000000164313213503245020702 0ustar zmoelnigiemusersunit aiScene; interface uses aiTypes, aiMatrix4x4, aiMesh, aiMaterial, aiTexture; type PaiNode = ^TaiNode; PPaiNode = ^PaiNode; PaiNodeArray = array[0..0] of PaiNode; PPaiNodeArray = ^PaiNodeArray; TaiNode = packed record mName: aiString; mTransformation: TaiMatrix4x4; mParent: PPaiNode; mNumChildren: cardinal; mChildren: PPaiNodeArray; mNumMeshes: cardinal; mMeshes: PCardinalArray; end; type TaiScene = packed record mFlags: cardinal; mRootNode: PaiNode; mNumMeshes: Cardinal; mMeshes: PPaiMeshArray; //? mNumMaterials: Cardinal; mMaterials: PPaiMaterialArray; mNumAnimations: Cardinal; mAnimations: Pointer; mNumTextures: Cardinal; mTextures: PPaiTextureArray; mNumLights: Cardinal; mLights: Pointer; mNumCameras: Cardinal; mCameras: Pointer; end; type PaiScene = ^TaiScene; implementation end. assimp-4.1.0/port/AssimpDelphi/aiQuaternion.pas0000644002537200234200000000024513213503245021767 0ustar zmoelnigiemusersunit aiQuaternion; interface type TaiQuaternion = packed record w, x, y, z: single; end; type PaiQuaternion = ^TaiQuaternion; implementation end. assimp-4.1.0/port/AssimpDelphi/aiMesh.pas0000644002537200234200000000334613213503245020543 0ustar zmoelnigiemusersunit aiMesh; interface uses aiTypes, aiMatrix4x4, aiVector3D, aiColor4D; const AI_MAX_NUMBER_OF_COLOR_SETS = $4; AI_MAX_NUMBER_OF_TEXTURECOORDS = $4; type TaiFace = packed record mNumIndicies: cardinal; mIndices: PCardinalArray; end; type PaiFace = ^TaiFace; type PaiFaceArray = array [0..0] of PaiFace; type TaiFaceArray = array [0..0] of TaiFace; type PTaiFaceArray = ^TaiFaceArray; type TaiVertexWeight = packed record mVertexId: cardinal; mWeight: single; end; type TaiBone = packed record mName: aiString; mNumWeights: cardinal; mWeights: Pointer; mOffsetMatrix: TaiMatrix4x4; end; type PaiBone = ^TaiBone; type TaiPrimitiveType = ( aiPrimitiveType_POINT = $1, aiPrimitiveType_LINE = $2, aiPrimitiveType_TRIANGLE = $4, aiPrimitiveType_POLYGON = $8 //,_aiPrimitiveType_Force32Bit = $9fffffff ); type TaiMesh = packed record mPrimitiveTypes: cardinal; mNumVertices: cardinal; mNumFaces: cardinal; mVertices: PTaiVector3DArray; mNormals: PTaiVector3DArray; mTangents: PaiVector3DArray; mBitangents: PaiVector3DArray; mColors: array[0..3] of PTaiColor4Darray; //array [0..3] of PaiColor4DArray; //array of 4 mTextureCoords: array [0..3] of PTaiVector3DArray; //array of 4 mNumUVComponents: array[0..AI_MAX_NUMBER_OF_TEXTURECOORDS -1] of cardinal; mFaces: PTaiFaceArray; mNumBones: cardinal; mBones: PaiBone; mMaterialIndex: cardinal; mName: aiString; mNumAniMeshes: cardinal; mAniMeshes: pointer; end; type PaiMesh = ^TaiMesh; type PPaiMesh = ^PaiMesh; type PaiMeshArray = array [0..0] of PaiMesh; type PPaiMeshArray = ^PaiMeshArray; implementation end. assimp-4.1.0/port/dAssimp/0000755002537200234200000000000013213503245015640 5ustar zmoelnigiemusersassimp-4.1.0/port/dAssimp/README0000644002537200234200000000103713213503245016521 0ustar zmoelnigiemusersD bindings for the Assimp library (http://assimp.sf.net). --- These bindings provide access to Assimp's C API. They were directly created from the C header files. You should be able to create sufficient DDoc documentation for the bindings using your favourite build tool (such as Rebuild). Please refer to the main (Doxygen-generated) documentation for general topics. Please note that the bindings have only been tested on 32 bit systems, they have yet to be adapted for the different size of the integer types in 64 bit builds of Assimp. assimp-4.1.0/port/dAssimp/assimp/0000755002537200234200000000000013213503245017134 5ustar zmoelnigiemusersassimp-4.1.0/port/dAssimp/assimp/texture.d0000644002537200234200000001110413213503245020776 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * Contains helper structures to handle textures in Assimp. * * Used for file formats which embed their textures into the model file. * Supported are both normal textures, which are stored as uncompressed pixels, * and "compressed" textures, which are stored in a file format such as PNG or * TGA. */ module assimp.texture; extern ( C ) { /** * Helper structure to represent a texel in a ARGB8888 format. * * Used by aiTexture. */ struct aiTexel { align ( 1 ): ubyte b, g, r, a; } /** * Helper structure to describe an embedded texture. * * Usually textures are contained in external files but some file formats * embed them directly in the model file. There are two types of * embedded textures: * * 1. Uncompressed textures: The color data is given in an * uncompressed format. * * 2. Compressed textures stored in a file format like PNG or JPEG. * The raw file bytes are given so the application must utilize an image * decoder (e.g. DevIL) to get access to the actual color data. */ struct aiTexture { /** * Width of the texture, in pixels. * * If mHeight is zero the texture is compressed in a format * like JPEG. In this case, this value specifies the size of the memory * area pcData is pointing to, in bytes. */ uint mWidth; /** * Height of the texture, in pixels. * * If this value is zero, pcData points to an compressed * texture in any format (e.g. JPEG). */ uint mHeight; /** * A hint from the loader to make it easier for applications to determine * the type of embedded compressed textures. * * If mHeight is not 0, this member is undefined. Otherwise * it is set set to '\0\0\0\0' if the loader has no additional * information about the texture file format used, or the file extension * of the format without a trailing dot. If there are multiple file * extensions for a format, the shortest extension is chosen (JPEG maps * to 'jpg', not to 'jpeg'). E.g. 'dds\0', 'pcx\0', 'jpg\0'. All * characters are lower-case. The fourth byte will always be '\0'. */ char achFormatHint[4]; /** * Data of the texture. * * Points to an array of mWidth * mHeight * aiTexels. The format of the texture data is always * ARGB8888 to make the implementation for user of the library as easy as * possible. * * If mHeight is 0, this is a pointer to a memory buffer of * size mWidth containing the compressed texture data. */ aiTexel* pcData; } } assimp-4.1.0/port/dAssimp/assimp/math.d0000644002537200234200000001001113213503245020223 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * Mathematical structures in which the imported data is stored. */ module assimp.math; extern( C ) { /** * Represents a two-dimensional vector. */ struct aiVector2D { align ( 1 ): float x, y; } /** * Represents a three-dimensional vector. */ struct aiVector3D { align ( 1 ): float x, y, z; } /** * Represents a quaternion. */ struct aiQuaternion { float w, x, y, z; } /** * Represents a row-major 3x3 matrix * * There is much confusion about matrix layouts (column vs. row order). This * is always a row-major matrix, even when using the * ConvertToLeftHanded post processing step. */ struct aiMatrix3x3 { float a1, a2, a3; float b1, b2, b3; float c1, c2, c3; } /** * Represents a row-major 3x3 matrix * * There is much confusion about matrix layouts (column vs. row order). This * is always a row-major matrix, even when using the * ConvertToLeftHanded post processing step. */ struct aiMatrix4x4 { align ( 1 ): float a1, a2, a3, a4; float b1, b2, b3, b4; float c1, c2, c3, c4; float d1, d2, d3, d4; } /** * Represents a plane in a three-dimensional, euclidean space */ struct aiPlane { align ( 1 ): /** * Coefficients of the plane equation (ax + by + cz = d). */ float a; float b; /// ditto float c; /// ditto float d; /// ditto } /** * Represents a ray. */ struct aiRay { align ( 1 ): /** * Origin of the ray. */ aiVector3D pos; /** * Direction of the ray. */ aiVector3D dir; } /** * Represents a color in RGB space. */ struct aiColor3D { align ( 1 ): /** * Red, green and blue values. */ float r; float g; /// ditto float b; /// ditto } /** * Represents a color in RGB space including an alpha component. */ struct aiColor4D { align ( 1 ): /** * Red, green, blue and alpha values. */ float r; float g; /// ditto float b; /// ditto float a; /// ditto } } assimp-4.1.0/port/dAssimp/assimp/scene.d0000644002537200234200000002371313213503245020404 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * Contains the data structures which store the hierarchy fo the imported data. */ module assimp.scene; import assimp.animation; import assimp.camera; import assimp.light; import assimp.math; import assimp.mesh; import assimp.material; import assimp.texture; import assimp.types; extern ( C ) { /** * A node in the imported hierarchy. * * Each node has name, a parent node (except for the root node), a * transformation relative to its parent and possibly several child nodes. * Simple file formats don't support hierarchical structures, for these * formats the imported scene does consist of only a single root node with * no childs. */ struct aiNode { /** * The name of the node. * * The name might be empty (length of zero) but all nodes which need to * be accessed afterwards by bones or animations are usually named. * Multiple nodes may have the same name, but nodes which are accessed * by bones (see aiBone and aiMesh.mBones) * must be unique. * * Cameras and lights are assigned to a specific node name – if there are * multiple nodes with this name, they are assigned to each of them. * * There are no limitations regarding the characters contained in this * string. You should be able to handle stuff like whitespace, tabs, * linefeeds, quotation marks, ampersands, … */ aiString mName; /** * The transformation relative to the node's parent. */ aiMatrix4x4 mTransformation; /** * Parent node. * * null if this node is the root node. */ aiNode* mParent; /** * The number of child nodes of this node. */ uint mNumChildren; /** * The child nodes of this node. * * null if mNumChildren is 0. */ aiNode** mChildren; /** * The number of meshes of this node. */ int mNumMeshes; /** * The meshes of this node. * * Each entry is an index for aiScene.mMeshes. */ uint* mMeshes; } /** * Flags which are combinated in aiScene.mFlags to store * auxiliary information about the imported scene. */ enum aiSceneFlags : uint { /** * Specifies that the scene data structure that was imported is not * complete. * * This flag bypasses some internal validations and allows the import of * animation skeletons, material libraries or camera animation paths * using Assimp. Most applications won't support such data. */ INCOMPLETE = 0x1, /** * This flag is set by the validation post-processing step * (aiProcess.ValidateDS) if the validation was successful. * * In a validated scene you can be sure that any cross references in the * data structure (e.g. vertex indices) are valid. */ VALIDATED = 0x2, /** * This flag is set by the validation post-processing step * (aiProcess.ValidateDS) if the validation is successful * but some issues have been found. * * This can for example mean that a texture that does not exist is * referenced by a material or that the bone weights for a vertex don't * sum to 1. In most cases you should still be able to use the import. * * This flag could be useful for applications which don't capture * Assimp's log output. */ VALIDATION_WARNING = 0x4, /** * This flag is currently only set by the * aiProcess.JoinIdenticalVertices post-processing step. It * indicates that the vertices of the output meshes aren't in the * internal verbose format anymore. In the verbose format all vertices * are unique, no vertex is ever referenced by more than one face. */ NON_VERBOSE_FORMAT = 0x8, /** * Denotes pure height-map terrain data. Pure terrains usually consist of * quads, sometimes triangles, in a regular grid. The x,y coordinates of * all vertex positions refer to the x,y coordinates on the terrain * height map, the z-axis stores the elevation at a specific point. * * TER (Terragen) and HMP (3D Game Studio) are height map formats. * * Note: Assimp is probably not the best choice for loading huge * terrains – fully triangulated data takes extremely much storage * space and should be avoided as long as possible (typically you will * perform the triangulation when you actually need to render it). */ FLAGS_TERRAIN = 0x10 } /** * The root structure of the imported data. * * Everything that was imported from the given file can be accessed from here. * Objects of this class are generally maintained and owned by Assimp, not * by the caller. You shouldn't want to instance it, nor should you ever try to * delete a given scene on your own. */ struct aiScene { /** * Any combination of the aiSceneFlags. By default, this * value is 0, no flags are set. * * Most applications will want to reject all scenes with the * aiSceneFlags.INCOMPLETE bit set. */ uint mFlags; /** * The root node of the hierarchy. * * There will always be at least the root node if the import was * successful (and no special flags have been set). Presence of further * nodes depends on the format and contents of the imported file. */ aiNode* mRootNode; /** * The number of meshes in the scene. */ uint mNumMeshes; /** * The array of meshes. * * Use the indices given in the aiNode structure to access * this array. The array is mNumMeshes in size. * * If the aiSceneFlags.INCOMPLETE flag is not set, there * will always be at least one mesh. */ aiMesh** mMeshes; /** * The number of materials in the scene. */ uint mNumMaterials; /** * The array of meshes. * * Use the indices given in the aiMesh structure to access * this array. The array is mNumMaterials in size. * * If the aiSceneFlags.INCOMPLETE flag is not set, there * will always be at least one material. */ aiMaterial** mMaterials; /** * The number of animations in the scene. */ uint mNumAnimations; /** * The array of animations. * * All animations imported from the given file are listed here. The array * is mNumAnimations in size. */ aiAnimation** mAnimations; /** * The number of textures embedded into the file. */ uint mNumTextures; /** * The array of embedded textures. * * Not many file formats embed their textures into the file. An example * is Quake's MDL format (which is also used by some * GameStudio versions). */ aiTexture** mTextures; /** * The number of light sources in the scene. * * Light sources are fully optional, in most cases this attribute will be * 0. */ uint mNumLights; /** * The array of light sources. * * All light sources imported from the given file are listed here. The * array is mNumLights in size. */ aiLight** mLights; /** * The number of cameras in the scene. * * Cameras are fully optional, in most cases this attribute * will be 0. */ uint mNumCameras; /** * The array of cameras. * * All cameras imported from the given file are listed here. The array is * mNumCameras in size. * * The first camera in the array (if existing) is the default camera view * at the scene. */ aiCamera** mCameras; } } assimp-4.1.0/port/dAssimp/assimp/api.d0000644002537200234200000005660213213503245020063 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * The C-style interface to the Open Asset import library. * * All functions of the C API have been collected in this module as function * pointers, which are set by the dynamic library loader * (assimp.loader). */ module assimp.api; import assimp.fileIO; import assimp.material; import assimp.math; import assimp.scene; import assimp.types; extern ( C ) { /** * Reads the given file and returns its content. * * If the call succeeds, the imported data is returned in an aiScene * structure. The data is intended to be read-only, it stays property of the * Assimp library and will be stable until aiReleaseImport() is * called. After you're done with it, call aiReleaseImport() to * free the resources associated with this file. * * If an error is encountered, null is returned instead. Call * aiGetErrorString() to retrieve a human-readable error * description. * * Params: * pFile = Path and filename of the file to be imported, * expected to be a null-terminated C-string. null is not a valid value. * pFlags = Optional post processing steps to be executed after a * successful import. Provide a bitwise combination of the * aiPostProcessSteps flags. If you wish to inspect the * imported scene first in order to fine-tune your post-processing * setup, consider to use aiApplyPostProcessing(). * * Returns: * A pointer to the imported data, null if the import failed. */ aiScene* function( char* pFile, uint pFile ) aiImportFile; /** * Reads the given file using user-defined I/O functions and returns its * content. * * If the call succeeds, the imported data is returned in an aiScene * structure. The data is intended to be read-only, it stays property of the * Assimp library and will be stable until aiReleaseImport() is * called. After you're done with it, call aiReleaseImport() to * free the resources associated with this file. * * If an error is encountered, null is returned instead. Call * aiGetErrorString() to retrieve a human-readable error * description. * * Params: * pFile = Path and filename of the file to be imported, * expected to be a null-terminated C-string. null is not a valid value. * pFlags = Optional post processing steps to be executed after a * successful import. Provide a bitwise combination of the * aiPostProcessSteps flags. If you wish to inspect the * imported scene first in order to fine-tune your post-processing * setup, consider to use aiApplyPostProcessing(). * pFS = An aiFileIO which will be used to open the model file itself * and any other files the loader needs to open. * * Returns: * A pointer to the imported data, null if the import failed. */ aiScene* function( char* pFile, uint pFlags, aiFileIO* pFS ) aiImportFileEx; /** * Reads the scene from the given memory buffer. * * Reads the given file using user-defined I/O functions and returns its * content. * * If the call succeeds, the imported data is returned in an aiScene * structure. The data is intended to be read-only, it stays property of the * Assimp library and will be stable until aiReleaseImport() is * called. After you're done with it, call aiReleaseImport() to * free the resources associated with this file. * * If an error is encountered, null is returned instead. Call * aiGetErrorString() to retrieve a human-readable error * description. * * Params: * pBuffer = Pointer to the scene data. * pLength = Size of pBuffer in bytes. * pFlags = Optional post processing steps to be executed after a * successful import. Provide a bitwise combination of the * aiPostProcessSteps flags. If you wish to inspect the * imported scene first in order to fine-tune your post-processing * setup, consider to use aiApplyPostProcessing(). * pHint = An additional hint to the library. If this is a non empty * string, the library looks for a loader to support the file * extension specified and passes the file to the first matching * loader. If this loader is unable to complete the request, the * library continues and tries to determine the file format on its * own, a task that may or may not be successful. * * Returns: * A pointer to the imported data, null if the import failed. * * Note: * This is a straightforward way to decode models from memory buffers, * but it doesn't handle model formats spreading their data across * multiple files or even directories. Examples include OBJ or MD3, which * outsource parts of their material stuff into external scripts. If you * need the full functionality, provide a custom IOSystem to make Assimp * find these files. */ aiScene* function( char* pBuffer, uint pLength, uint pFlags, char* pHint ) aiImportFileFromMemory; /** * Apply post-processing to an already-imported scene. * * This is strictly equivalent to calling aiImportFile() or * aiImportFileEx() with the same flags. However, you can use * this separate function to inspect the imported scene first to fine-tune * your post-processing setup. * * Params: * pScene = Scene to work on. * pFlags = Provide a bitwise combination of the * aiPostProcessSteps flags. * * Returns: * A pointer to the post-processed data. Post processing is done in-place, * meaning this is still the same aiScene which you passed * for pScene. However, if post-processing failed, the scene could now be * null. That's quite a rare case, post processing steps are not really * designed to fail. To be exact, aiProcess.ValidateDS is * currently the only post processing step which can actually cause the * scene to be reset to null. */ aiScene* function( aiScene* pScene, uint pFlags ) aiApplyPostProcessing; /** * Get one of the predefined log streams. This is the quick'n'easy solution * to access Assimp's log system. Attaching a log stream can slightly reduce * Assimp's overall import performance. * * Examples: * --- * aiLogStream stream = aiGetPredefinedLogStream( * aiDefaultLogStream.FILE, "assimp.log.txt" ); * if ( stream.callback !is null ) { * aiAttachLogStream( &stream ); * } * --- * * Params: * pStreams = The log stream destination. * file = Solely for the aiDefaultLogStream.FILE flag: * specifies the file to write to. Pass null for all other flags. * * Returns: * The log stream, null if something went wrong. */ aiLogStream function( aiDefaultLogStream pStreams, char* file ) aiGetPredefinedLogStream; /** * Attach a custom log stream to the libraries' logging system. * * Attaching a log stream can slightly reduce Assimp's overall import * performance. Multiple log-streams can be attached. * * Params: * stream = Describes the new log stream. * * Note: To ensure proper destruction of the logging system, you need to * manually call aiDetachLogStream() on every single log * stream you attach. Alternatively, aiDetachAllLogStreams() * is provided. */ void function( aiLogStream* stream ) aiAttachLogStream; /** * Enable verbose logging. * * Verbose logging includes debug-related stuff and detailed import * statistics. This can have severe impact on import performance and memory * consumption. However, it might be useful to find out why a file is not * read correctly. * * Param: * d = Whether verbose logging should be enabled. */ void function( aiBool d ) aiEnableVerboseLogging; /** * Detach a custom log stream from the libraries' logging system. * * This is the counterpart of #aiAttachPredefinedLogStream. If you attached a stream, * don't forget to detach it again. * * Params: * stream = The log stream to be detached. * * Returns: * aiReturn.SUCCESS if the log stream has been detached * successfully. * * See: aiDetachAllLogStreams */ aiReturn function( aiLogStream* stream ) aiDetachLogStream; /** * Detach all active log streams from the libraries' logging system. * * This ensures that the logging system is terminated properly and all * resources allocated by it are actually freed. If you attached a stream, * don't forget to detach it again. * * See: aiAttachLogStream, aiDetachLogStream */ void function() aiDetachAllLogStreams; /** * Releases all resources associated with the given import process. * * Call this function after you're done with the imported data. * * Params: * pScene = The imported data to release. null is a valid value. */ void function( aiScene* pScene ) aiReleaseImport; /** * Returns the error text of the last failed import process. * * Returns: * A textual description of the error that occurred at the last importing * process. null if there was no error. There can't be an error if you * got a non-null aiScene from * aiImportFile()/aiImportFileEx()/aiApplyPostProcessing(). */ char* function() aiGetErrorString; /** * Returns whether a given file extension is supported by this Assimp build. * * Params: * szExtension = Extension for which to query support. Must include a * leading dot '.'. Example: ".3ds", ".md3" * * Returns: * TRUE if the file extension is supported. */ aiBool function( char* szExtension ) aiIsExtensionSupported; /** * Gets a list of all file extensions supported by ASSIMP. * * Format of the list: "*.3ds;*.obj;*.dae". * * If a file extension is contained in the list this does, of course, not * mean that Assimp is able to load all files with this extension. * * Params: * szOut = String to receive the extension list. null is not a valid * parameter. */ void function( aiString* szOut ) aiGetExtensionList; /** * Gets the storage required by an imported asset * * Params: * pIn = Asset to query storage size for. * info = Data structure to be filled. */ void function( aiScene* pIn, aiMemoryInfo* info ) aiGetMemoryRequirements; /** * Sets an integer property. * * Properties are always shared by all imports. It is not possible to * specify them per import. * * Params: * szName = Name of the configuration property to be set. All supported * public properties are defined in the config module. * value = New value for the property. */ void function( char* szName, int value ) aiSetImportPropertyInteger; /** * Sets a floating-point property. * * Properties are always shared by all imports. It is not possible to * specify them per import. * * Params: * szName = Name of the configuration property to be set. All supported * public properties are defined in the config module. * value = New value for the property. */ void function( char* szName, float value ) aiSetImportPropertyFloat; /** * Sets a string property. * * Properties are always shared by all imports. It is not possible to * specify them per import. * * Params: * szName = Name of the configuration property to be set. All supported * public properties are defined in the config module. * st = New value for the property. */ void function( char* szName, aiString* st ) aiSetImportPropertyString; /* * Mathematical helper functions. */ /** * Constructs a quaternion from a 3x3 rotation matrix. * * Params: * quat = Receives the output quaternion. * mat = Matrix to 'quaternionize'. */ void function( aiQuaternion* quat, aiMatrix3x3* mat ) aiCreateQuaternionFromMatrix; /** * Decomposes a transformation matrix into its rotational, translational and * scaling components. * * Params: * mat = Matrix to decompose. * scaling = Receives the scaling component. * rotation = Receives the rotational component. * position = Receives the translational component. */ void function( aiMatrix4x4* mat, aiVector3D* scaling, aiQuaternion* rotation, aiVector3D* position ) aiDecomposeMatrix; /** * Transposes a 4x4 matrix (in-place). * * Params: * mat = The matrix to be transposed. */ void function( aiMatrix4x4* mat ) aiTransposeMatrix4; /** * Transposes a 3x3 matrix (in-place). * * Params: * mat = The matrix to be transposed. */ void function( aiMatrix3x3* mat ) aiTransposeMatrix3; /** * Transforms a vector by a 3x3 matrix (in-place). * * Params: * vec = Vector to be transformed. * mat = Matrix to transform the vector with. */ void function( aiVector3D* vec, aiMatrix3x3* mat ) aiTransformVecByMatrix3; /** * Transforms a vector by a 4x4 matrix (in-place). * * Params: * vec = Vector to be transformed. * mat = Matrix to transform the vector with. */ void function( aiVector3D* vec, aiMatrix4x4* mat ) aiTransformVecByMatrix4; /** * Multiplies two 4x4 matrices. * * Params: * dst = First factor, receives result. * src = Matrix to be multiplied with 'dst'. */ void function( aiMatrix4x4* dst, aiMatrix4x4* src ) aiMultiplyMatrix4; /** * Multiplies two 3x3 matrices. * * Params: * dst = First factor, receives result. * src = Matrix to be multiplied with 'dst'. */ void function( aiMatrix3x3* dst, aiMatrix3x3* src ) aiMultiplyMatrix3; /** * Constructs a 3x3 identity matrix. * * Params: * mat = Matrix to receive its personal identity. */ void function( aiMatrix3x3* mat ) aiIdentityMatrix3; /** * Constructs a 4x4 identity matrix. * * Params: * mat = Matrix to receive its personal identity. */ void function( aiMatrix4x4* mat ) aiIdentityMatrix4; /* * Material system functions. */ /** * Retrieves a material property with a specific key from the material. * * Params: * pMat = Pointer to the input material. May not be null. * pKey = Key to search for. One of the AI_MATKEY_XXX * constants. * type = Specifies the aiTextureType of the texture to be * retrieved, 0 for non-texture properties. * index = Index of the texture to be retrieved, * 0 for non-texture properties. * pPropOut = Pointer to receive a pointer to a valid * aiMaterialProperty structure or null if the key has * not been found. */ aiReturn function( aiMaterial* pMat, char* pKey, uint type, uint index, aiMaterialProperty** pPropOut ) aiGetMaterialProperty; /** * Retrieves a single float value or an array of float values from the * material. * * Examples: * --- * const FLOATS_IN_UV_TRANSFORM = ( aiUVTransform.sizeof / float.sizeof ); * uint valuesRead = FLOATS_IN_UV_TRANSFORM; * bool success = * ( aiGetMaterialFloatArray( &material, AI_MATKEY_UVTRANSFORM, * aiTextureType.DIFFUSE, 0, cast( float* ) &trafo, &valuesRead ) == * aiReturn.SUCCESS ) && * ( valuesRead == FLOATS_IN_UV_TRANSFORM ); * --- * * Params: * pMat = Pointer to the input material. May not be null. * pKey = Key to search for. One of the AI_MATKEY_XXX constants. * type = Specifies the aiTextureType of the texture to be * retrieved, 0 for non-texture properties. * index = Index of the texture to be retrieved, * 0 for non-texture properties. * pOut = Pointer to a buffer to receive the result. * pMax = Specifies the size of the given buffer in floats. Receives the * number of values (not bytes!) read. null to read a scalar property. * * Returns: * Specifies whether the key has been found. If not, the output arrays * remains unmodified and pMax is set to 0. */ aiReturn function( aiMaterial* pMat, char* pKey, uint type, uint index, float* pOut, uint* pMax = null ) aiGetMaterialFloatArray; /** * Convenience alias for aiGetMaterialFloatArray(). */ alias aiGetMaterialFloatArray aiGetMaterialFloat; /** * Retrieves a single integer value or an array of integer values from the * material. * * See: aiGetMaterialFloatArray() */ aiReturn function( aiMaterial* pMat, char* pKey, uint type, uint index, int* pOut, uint* pMax = null ) aiGetMaterialIntegerArray; /** * Convenience alias for aiGetMaterialIntegerArray(). */ alias aiGetMaterialIntegerArray aiGetMaterialInteger; /** * Retrieves a color value from the material. * * See: aiGetMaterialFloatArray() */ aiReturn function( aiMaterial* pMat, char* pKey, uint type, uint index, aiColor4D* pOut ) aiGetMaterialColor; /** * Retrieves a string value from the material. * * See: aiGetMaterialFloatArray() */ aiReturn function( aiMaterial* pMat, char* pKey, uint type, uint index, aiString* pOut ) aiGetMaterialString; /** * Get the number of textures for a particular texture type. * * Params: * pMat = Pointer to the input material. May not be NULL * type = Texture type to check for * * Returns: * Number of textures for this type. */ uint function( aiMaterial* pMat, aiTextureType type ) aiGetMaterialTextureCount; /** * Helper function to get all values pertaining to a particular texture slot * from a material structure. * * This function is provided just for convenience. You could also read the * texture by parsing all of its properties manually. This function bundles * all of them in a huge function monster. * * Params: * mat = Pointer to the input material. May not be null. * type = Specifies the texture stack (aiTextureType) to * read from. * index = Index of the texture. The function fails if the requested * index is not available for this texture type. * aiGetMaterialTextureCount() can be used to determine * the number of textures in a particular texture stack. * path = Receives the output path. null is not a valid value. * mapping = Receives the texture mapping mode to be used. * Pass null if you are not interested in this information. * uvindex = For UV-mapped textures: receives the index of the UV source * channel. Unmodified otherwise. Pass null if you are not interested * in this information. * blend = Receives the blend factor for the texture. * Pass null if you are not interested in this information. * op = Receives the texture blend operation to be perform between this * texture and the previous texture. Pass null if you are not * interested in this information. * mapmode = Receives the mapping modes to be used for the texture. Pass * a pointer to an array of two aiTextureMapMode's (one for each axis, * UV order) or null if you are not interested in this information. * * Returns: * aiReturn.SUCCESS on success, otherwise something else. */ aiReturn function( aiMaterial* mat, aiTextureType type, uint index, aiString* path, aiTextureMapping* mapping = null, uint* uvindex = null, float* blend = null, aiTextureOp* op = null, aiTextureMapMode* mapmode = null ) aiGetMaterialTexture; /* * Versioning functions. */ /** * Returns a string with legal copyright and licensing information about * Assimp. * * The string may include multiple lines. * * Returns: * Pointer to static string. */ char* function() aiGetLegalString; /** * Returns the current minor version number of the Assimp library. * * Returns: * Minor version of the Assimp library. */ uint function() aiGetVersionMinor; /** * Returns the current major version number of the Assimp library. * * Returns: * Major version of the Assimp library. */ uint function() aiGetVersionMajor; /** * Returns the repository revision of the Assimp library. * * Returns: * SVN Repository revision number of the Assimp library. */ uint function() aiGetVersionRevision; /** * Returns the flags Assimp was compiled with. * * Returns: * Any bitwise combination of the ASSIMP_CFLAGS_xxx constants. */ uint function() aiGetCompileFlags; } assimp-4.1.0/port/dAssimp/assimp/loader.d0000644002537200234200000001555513213503245020562 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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 dynamically loading the Assimp library. * * Currently requires Tango, but there is no reason why Phobos could not be * supported too. */ module assimp.loader; import assimp.api; import tango.io.Stdout; import tango.sys.SharedLib; const uint ASSIMP_BINDINGS_MAJOR = 2; const uint ASSIMP_BINDINGS_MINOR = 0; /** * Loader class for dynamically loading the Assimp library. * * The library is »reference-counted«, meaning that the library is not * unloaded on a call to unload() if there are still other * references to it. */ struct Assimp { public: /** * Loads the library if it is not already loaded and increases the * reference counter. * * The library file (libassimp.so on POSIX systems, * Assimp32.dll on Win32) is loaded via Tango's SharedLib * class. */ static void load() { if ( m_sRefCount == 0 ) { version ( Posix ) { version ( OSX ) { m_sLibrary = SharedLib.load( "libassimp.dylib" ); } else { m_sLibrary = SharedLib.load( "libassimp.so" ); } } version ( Win32 ) { m_sLibrary = SharedLib.load( "Assimp32.dll" ); } // Versioning mixin( bindCode( "aiGetLegalString" ) ); mixin( bindCode( "aiGetVersionMinor" ) ); mixin( bindCode( "aiGetVersionMajor" ) ); mixin( bindCode( "aiGetVersionRevision" ) ); mixin( bindCode( "aiGetCompileFlags" ) ); // Check for version mismatch between the external, dynamically loaded // library and the version the bindings were created against. uint libMajor = aiGetVersionMajor(); uint libMinor = aiGetVersionMinor(); if ( ( libMajor < ASSIMP_BINDINGS_MAJOR ) || ( libMinor < ASSIMP_BINDINGS_MINOR ) ) { Stdout.format( "WARNING: Assimp version too old (loaded library: {}.{}, " ~ "bindings: {}.{})!", libMajor, libMinor, ASSIMP_BINDINGS_MAJOR, ASSIMP_BINDINGS_MINOR ).newline; } if ( libMajor > ASSIMP_BINDINGS_MAJOR ) { Stdout.format( "WARNING: Assimp version too new (loaded library: {}.{}, " ~ "bindings: {}.{})!", libMajor, libMinor, ASSIMP_BINDINGS_MAJOR, ASSIMP_BINDINGS_MINOR ).newline; } // General API mixin( bindCode( "aiImportFile" ) ); mixin( bindCode( "aiImportFileEx" ) ); mixin( bindCode( "aiImportFileFromMemory" ) ); mixin( bindCode( "aiApplyPostProcessing" ) ); mixin( bindCode( "aiGetPredefinedLogStream" ) ); mixin( bindCode( "aiAttachLogStream" ) ); mixin( bindCode( "aiEnableVerboseLogging" ) ); mixin( bindCode( "aiDetachLogStream" ) ); mixin( bindCode( "aiDetachAllLogStreams" ) ); mixin( bindCode( "aiReleaseImport" ) ); mixin( bindCode( "aiGetErrorString" ) ); mixin( bindCode( "aiIsExtensionSupported" ) ); mixin( bindCode( "aiGetExtensionList" ) ); mixin( bindCode( "aiGetMemoryRequirements" ) ); mixin( bindCode( "aiSetImportPropertyInteger" ) ); mixin( bindCode( "aiSetImportPropertyFloat" ) ); mixin( bindCode( "aiSetImportPropertyString" ) ); // Mathematical functions mixin( bindCode( "aiCreateQuaternionFromMatrix" ) ); mixin( bindCode( "aiDecomposeMatrix" ) ); mixin( bindCode( "aiTransposeMatrix4" ) ); mixin( bindCode( "aiTransposeMatrix3" ) ); mixin( bindCode( "aiTransformVecByMatrix3" ) ); mixin( bindCode( "aiTransformVecByMatrix4" ) ); mixin( bindCode( "aiMultiplyMatrix4" ) ); mixin( bindCode( "aiMultiplyMatrix3" ) ); mixin( bindCode( "aiIdentityMatrix3" ) ); mixin( bindCode( "aiIdentityMatrix4" ) ); // Material system mixin( bindCode( "aiGetMaterialProperty" ) ); mixin( bindCode( "aiGetMaterialFloatArray" ) ); mixin( bindCode( "aiGetMaterialIntegerArray" ) ); mixin( bindCode( "aiGetMaterialColor" ) ); mixin( bindCode( "aiGetMaterialString" ) ); mixin( bindCode( "aiGetMaterialTextureCount" ) ); mixin( bindCode( "aiGetMaterialTexture" ) ); } ++m_sRefCount; } /** * Decreases the reference counter and unloads the library if this was the * last reference. */ static void unload() { assert( m_sRefCount > 0 ); --m_sRefCount; if ( m_sRefCount == 0 ) { m_sLibrary.unload(); } } private: /// Current number of references to the library. static uint m_sRefCount; /// Library handle. static SharedLib m_sLibrary; } /** * Private helper function which constructs the bind command for a symbol to * keep the code DRY. */ private char[] bindCode( char[] symbol ) { return symbol ~ " = cast( typeof( " ~ symbol ~ " ) )m_sLibrary.getSymbol( `" ~ symbol ~ "` );"; } assimp-4.1.0/port/dAssimp/assimp/camera.d0000644002537200234200000001474213213503245020541 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * Contains the data structure which is used to store the imported information * about the virtual cameras in the scene. */ module assimp.camera; import assimp.math; import assimp.types; extern ( C ) { /** * Helper structure to describe a virtual camera. * * Cameras have a representation in the node graph and can be animated. * An important aspect is that the camera itself is also part of the * scenegraph. This means, any values such as the look-at vector are not * absolute, they're relative to the coordinate system defined * by the node which corresponds to the camera. This allows for camera * animations. Static cameras parameters like the look-at or up vectors are * usually specified directly in the class members, but beware, they could * also be encoded in the node transformation. The following (pseudo)code * sample shows how to do it. * * Examples: * --- * // Get the camera matrix for a camera at a specific time * // if the node hierarchy for the camera does not contain * // at least one animated node this is a static computation * get-camera-matrix (node sceneRoot, camera cam) : matrix * { * node cnd = find-node-for-camera(cam) * matrix cmt = identity() * * // as usual - get the absolute camera transformation for this frame * for each node nd in hierarchy from sceneRoot to cnd * matrix cur * if (is-animated(nd)) * cur = eval-animation(nd) * else cur = nd->mTransformation; * cmt = mult-matrices( cmt, cur ) * end for * * // now multiply with the camera's own local transform * cam = mult-matrices (cam, get-camera-matrix(cmt) ) * } * --- * * Note: Some file formats (such as 3DS, ASE) export a "target point" – the * point the camera is looking at (it can even be animated). Assimp * writes the target point as a subnode of the camera's main node, called * ".Target". However, this is just additional information; the * transformation applied to the main camera node already makes the * camera face the right direction. */ struct aiCamera { /** * The name of the camera. * * There must be a node in the scenegraph with the same name. This node * specifies the position of the camera in the scene hierarchy and can * be animated. */ aiString mName; /** * Position of the camera relative to the coordinate space defined by the * corresponding node. * * The default value is 0|0|0. */ aiVector3D mPosition; /** * Up vector of the camera coordinate system relative to the * coordinate space defined by the corresponding node. * * The right vector of the camera coordinate system is the cross * product of the up and lookAt vectors. * * The default value is 0|1|0. The vector may be normalized, but it * needn't. */ aiVector3D mUp; /** * Look-at vector of the camera coordinate system relative to the * coordinate space defined by the corresponding node. * * This is the viewing direction of the user. * * The default value is 0|0|1. The vector may be normalized, but it * needn't. */ aiVector3D mLookAt; /** * Half horizontal field of view angle, in radians. * * The field of view angle is the angle between the center line of the * screen and the left or right border. * * The default value is PI/4. */ float mHorizontalFOV; /** * Distance of the near clipping plane from the camera. * * The value may not be 0.f (for arithmetic reasons to prevent * a division through zero). * * The default value is 0.1f. */ float mClipPlaneNear; /** * Distance of the far clipping plane from the camera. * * The far clipping plane must, of course, be further away than the * near clipping plane. The ratio between the near and the far plane * should not be too large (between 1000-10000 should be ok) to avoid * floating-point inaccuracies which could lead to z-fighting. * * The default value is 1000.f. */ float mClipPlaneFar; /** * Screen aspect ratio. * * This is the ration between the width and the height of the * screen. Typical values are 4/3, 1/2 or 1/1. This value is * 0 if the aspect ratio is not defined in the source file. * * 0 is also the default value. */ float mAspect; } } assimp-4.1.0/port/dAssimp/assimp/config.d0000644002537200234200000006051313213503245020553 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * Defines constants for configurable properties for the library. * * These are set via aiSetImportPropertyInteger(), * aiSetImportPropertyFloat() and * aiSetImportPropertyString(). */ module assimp.config; extern ( C ) { /* * Library settings. * * General, global settings. */ /** * Enables time measurements. * * If enabled, measures the time needed for each part of the loading * process (i.e. IO time, importing, postprocessing, ..) and dumps these * timings to the DefaultLogger. See the performance page in the main * Assimp docs information on this topic. * * Property type: bool. Default value: false. */ const char* AI_CONFIG_GLOB_MEASURE_TIME = "GLOB_MEASURE_TIME"; version( none ) { // not implemented yet /** * Set Assimp's multithreading policy. * * This setting is ignored if Assimp was built without boost.thread support * (ASSIMP_BUILD_NO_THREADING, which is implied by * ASSIMP_BUILD_BOOST_WORKAROUND). * * Possible values are: -1 to let Assimp decide what to do, 0 to disable * multithreading entirely and any number larger than 0 to force a specific * number of threads. Assimp is always free to ignore this settings, which * is merely a hint. Usually, the default value (-1) will be fine. However, * if Assimp is used concurrently from multiple user threads, it might be * useful to limit each Importer instance to a specific number of cores. * * For more information, see the threading page in the main Assimp docs. * * Property type: int, default value: -1. */ const char* AI_CONFIG_GLOB_MULTITHREADING = "GLOB_MULTITHREADING"; } /* * Post processing settings. * * Various options to fine-tune the behavior of a specific post processing step. */ /** * Specifies the maximum angle that may be between two vertex tangents that * their tangents and bitangents are smoothed. * * This applies to the CalcTangentSpace step. The angle is * specified in degrees, so 180 corresponds to PI radians. * * The default value is 45, the maximum value is 175. * * Property type: float. */ const char* AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE = "PP_CT_MAX_SMOOTHING_ANGLE"; /** * Specifies the maximum angle that may be between two face normals at the * same vertex position that their are smoothed together. Sometimes referred * to as 'crease angle'. * * This applies to the GenSmoothNormals step. The angle is * specified in degrees, so 180 corresponds to PI radians. * * The default value is 175 degrees (all vertex normals are smoothed), the * maximum value is 175, too. * * Property type: float. * * Warning: * Setting this option may cause a severe loss of performance. The * performance is unaffected if the AI_CONFIG_FAVOUR_SPEED * flag is set but the output quality may be reduced. */ const char* AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE = "PP_GSN_MAX_SMOOTHING_ANGLE"; /** * Sets the colormap (= palette) to be used to decode embedded textures in * MDL (Quake or 3DGS) files. * * This must be a valid path to a file. The file is 768 (256*3) bytes large * and contains RGB triplets for each of the 256 palette entries. The * default value is colormap.lmp. If the file is not found, a default * palette (from Quake 1) is used. * * Property type: string. */ const char* AI_CONFIG_IMPORT_MDL_COLORMAP = "IMPORT_MDL_COLORMAP"; /** * Configures the RemoveRedundantMaterials step to keep * materials matching a name in a given list. * * This is a list of 1 to n strings, ' ' serves as delimiter character. * Identifiers containing whitespaces must be enclosed in single * quotation marks. For example: * "keep-me and_me_to anotherMaterialToBeKept \'name with whitespace\'". * Linefeeds, tabs or carriage returns are treated as whitespace. * * If a material matches on of these names, it will not be modified or * removed by the postprocessing step nor will other materials be replaced * by a reference to it. * * This option might be useful if you are using some magic material names * to pass additional semantics through the content pipeline. This ensures * they won't be optimized away, but a general optimization is still * performed for materials not contained in the list. * * Default value: n/a * * Property type: string. * * Note: Material names are case sensitive. */ const char* AI_CONFIG_PP_RRM_EXCLUDE_LIST = "PP_RRM_EXCLUDE_LIST"; /** * Configures the PretransformVertices step to keep the scene * hierarchy. Meshes are moved to worldspace, but no optimization is * performed (meshes with equal materials are not joined, the total number * of meshes will not change). * * This option could be of use for you if the scene hierarchy contains * important additional information which you intend to parse. * For rendering, you can still render all meshes in the scene without * any transformations. * * Default value: false. * * Property type: bool. */ const char* AI_CONFIG_PP_PTV_KEEP_HIERARCHY = "PP_PTV_KEEP_HIERARCHY"; /** * Configures the PretransformVertices step to normalize all * vertex components into the -1...1 range. That is, a bounding box for the * whole scene is computed, the maximum component is taken and all meshes * are scaled appropriately (uniformly of course!). * * This might be useful if you don't know the spatial dimension of the input * data. */ const char* AI_CONFIG_PP_PTV_NORMALIZE = "PP_PTV_NORMALIZE"; /** * Configures the FindDegenerates step to remove degenerated * primitives from the import – immediately. * * The default behaviour converts degenerated triangles to lines and * degenerated lines to points. See the documentation to the * FindDegenerates step for a detailed example of the various * ways to get rid of these lines and points if you don't want them. * * Default value: false. * * Property type: bool. */ const char* AI_CONFIG_PP_FD_REMOVE = "PP_FD_REMOVE"; /** * Configures the OptimizeGraph step to preserve nodes matching * a name in a given list. * * This is a list of 1 to n strings, ' ' serves as delimiter character. * Identifiers containing whitespaces must be enclosed in single * quotation marks. For example: * "keep-me and_me_to anotherMaterialToBeKept \'name with whitespace\'". * Linefeeds, tabs or carriage returns are treated as whitespace. * * If a node matches on of these names, it will not be modified or * removed by the postprocessing step. * * This option might be useful if you are using some magic node names * to pass additional semantics through the content pipeline. This ensures * they won't be optimized away, but a general optimization is still * performed for nodes not contained in the list. * * Default value: n/a * * Property type: string. * * Note: Node names are case sensitive. */ const char* AI_CONFIG_PP_OG_EXCLUDE_LIST = "PP_OG_EXCLUDE_LIST"; /** * Sets the maximum number of triangles in a mesh. * * This is used by the SplitLargeMeshes step to determine * whether a mesh must be split or not. * * Default value: AI_SLM_DEFAULT_MAX_TRIANGLES. * * Property type: integer. */ const char* AI_CONFIG_PP_SLM_TRIANGLE_LIMIT = "PP_SLM_TRIANGLE_LIMIT"; /** * The default value for the AI_CONFIG_PP_SLM_TRIANGLE_LIMIT setting. */ const AI_SLM_DEFAULT_MAX_TRIANGLES = 1000000; /** * Sets the maximum number of vertices in a mesh. * * This is used by the SplitLargeMeshes step to determine * whether a mesh must be split or not. * * Default value: AI_SLM_DEFAULT_MAX_VERTICES * * Property type: integer. */ const char* AI_CONFIG_PP_SLM_VERTEX_LIMIT = "PP_SLM_VERTEX_LIMIT"; /** * The default value for the AI_CONFIG_PP_SLM_VERTEX_LIMIT setting. */ const AI_SLM_DEFAULT_MAX_VERTICES = 1000000; /** * Sets the maximum number of bones affecting a single vertex. * * This is used by the LimitBoneWeights step. * * Default value: AI_LBW_MAX_WEIGHTS * * Property type: integer. */ const char* AI_CONFIG_PP_LBW_MAX_WEIGHTS = "PP_LBW_MAX_WEIGHTS"; /** * The default value for the AI_CONFIG_PP_LBW_MAX_WEIGHTS setting. */ const AI_LMW_MAX_WEIGHTS = 0x4; /** * Sets the size of the post-transform vertex cache to optimize the * vertices for. This configures the ImproveCacheLocality step. * * The size is given in vertices. Of course you can't know how the vertex * format will exactly look like after the import returns, but you can still * guess what your meshes will probably have. * * The default value results in slight performance improvements for most * nVidia/AMD cards since 2002. * * Default value: PP_ICL_PTCACHE_SIZE * * Property type: integer. */ const char* AI_CONFIG_PP_ICL_PTCACHE_SIZE = "PP_ICL_PTCACHE_SIZE"; /** * The default value for the AI_CONFIG_PP_ICL_PTCACHE_SIZE config option. */ const PP_ICL_PTCACHE_SIZE = 12; /** * Components of the aiScene and aiMesh data * structures that can be excluded from the import by using the * RemoveComponent step. * * See the documentation to RemoveComponent for more details. */ enum aiComponent : uint { /** * Normal vectors. */ NORMALS = 0x2, /** * Tangents and bitangents. */ TANGENTS_AND_BITANGENTS = 0x4, /** * All color sets. * * Use aiComponent_COLORSn( N ) to specify the N'th set. */ COLORS = 0x8, /** * All texture UV coordinate sets. * * Use aiComponent_TEXCOORDn( N ) to specify the N'th set. */ TEXCOORDS = 0x10, /** * Bone weights from all meshes. * * The corresponding scenegraph nodes are not removed. Use the * OptimizeGraph step to do this. */ BONEWEIGHTS = 0x20, /** * Node animations (aiScene.mAnimations). * * The corresponding scenegraph nodes are not removed. Use the * OptimizeGraph step to do this. */ ANIMATIONS = 0x40, /** * Embedded textures (aiScene.mTextures). */ TEXTURES = 0x80, /** * Light sources (aiScene.mLights). * * The corresponding scenegraph nodes are not removed. Use the * OptimizeGraph step to do this. */ LIGHTS = 0x100, /** * Cameras (aiScene.mCameras). * * The corresponding scenegraph nodes are not removed. Use the * OptimizeGraph step to do this. */ CAMERAS = 0x200, /** * Meshes (aiScene.mMeshes). */ MESHES = 0x400, /** Materials. * * One default material will be generated, so * aiScene.mNumMaterials will be 1. */ MATERIALS = 0x800 } /** * Specifies a certain color channel to remove. */ uint aiComponent_COLORSn( uint n ) { return 1u << ( n + 20u ); } /** * Specifies a certain UV coordinate channel to remove. */ uint aiComponent_TEXCOORDSn( uint n ) { return 1u << ( n + 25u ); } /** * Input parameter to the RemoveComponent step: * Specifies the parts of the data structure to be removed. * * See the documentation to this step for further details. * * Default value: 0 * * Property type: integer (bitwise combination of aiComponent * flags). * * Note: If no valid mesh is remaining after the step has been executed, the * import fails, because there is no data to work on anymore. */ const char* AI_CONFIG_PP_RVC_FLAGS = "PP_RVC_FLAGS"; /** * Input parameter to the SortByPType step: * Specifies which primitive types are removed by the step. * * This is a bitwise combination of the aiPrimitiveType flags. * Specifying all of them is illegal, of course. A typical use would be to * exclude all line and point meshes from the import. * * Default value: 0 * * Property type: integer. */ const char* AI_CONFIG_PP_SBP_REMOVE = "PP_SBP_REMOVE"; /** * Input parameter to the FindInvalidData step: * Specifies the floating-point accuracy for animation values. * * The step checks for animation tracks where all frame values are * absolutely equal and removes them. This tweakable controls the epsilon * for floating-point comparisons – two keys are considered equal if the * invariant abs(n0-n1) > epsilon holds true for all vector respectively * quaternion components. * * Default value: 0 (exact comparison). * * Property type: float. */ const char* AI_CONFIG_PP_FID_ANIM_ACCURACY = "PP_FID_ANIM_ACCURACY"; /** * The TransformUVCoords step evaluates UV scalings. */ const AI_UVTRAFO_SCALING = 0x1; /** * The TransformUVCoords step evaluates UV rotations. */ const AI_UVTRAFO_ROTATION = 0x2; /** * The TransformUVCoords step evaluates UV translation. */ const AI_UVTRAFO_TRANSLATION = 0x4; /** * The TransformUVCoords step evaluates all UV translations. */ const AI_UVTRAFO_ALL = AI_UVTRAFO_SCALING | AI_UVTRAFO_ROTATION | AI_UVTRAFO_TRANSLATION; /** * Input parameter to the TransformUVCoords step: Specifies * which UV transformations are evaluated. * * Default value: AI_UVTRAFO_ALL. * * Property type: integer (bitwise combination of the * AI_UVTRAFO_XXX flag). */ const char* AI_CONFIG_PP_TUV_EVALUATE = "PP_TUV_EVALUATE"; /** * A hint to assimp to favour speed against import quality. * * Enabling this option may result in faster loading, but it needn't. * It represents just a hint to loaders and post-processing steps to use * faster code paths, if possible. * * Default value: false. * * Property type: bool. */ const char* AI_CONFIG_FAVOUR_SPEED = "FAVOUR_SPEED"; /* * Importer settings. * * Various stuff to fine-tune the behaviour of specific importer plugins. */ /** * Set the vertex animation keyframe to be imported. * * Assimp does not support vertex keyframes (only bone animation is * supported). The library reads only one frame of models with vertex * animations. * * Default value: 0 (first frame). * * Property type: integer. * * Note: This option applies to all importers. However, it is also possible * to override the global setting for a specific loader. You can use the * AI_CONFIG_IMPORT_XXX_KEYFRAME options (where XXX is a placeholder for * the file format for which you want to override the global setting). */ const char* AI_CONFIG_IMPORT_GLOBAL_KEYFRAME = "IMPORT_GLOBAL_KEYFRAME"; const char* AI_CONFIG_IMPORT_MD3_KEYFRAME = "IMPORT_MD3_KEYFRAME"; const char* AI_CONFIG_IMPORT_MD2_KEYFRAME = "IMPORT_MD2_KEYFRAME"; const char* AI_CONFIG_IMPORT_MDL_KEYFRAME = "IMPORT_MDL_KEYFRAME"; const char* AI_CONFIG_IMPORT_MDC_KEYFRAME = "IMPORT_MDC_KEYFRAME"; const char* AI_CONFIG_IMPORT_SMD_KEYFRAME = "IMPORT_SMD_KEYFRAME"; const char* AI_CONFIG_IMPORT_UNREAL_KEYFRAME = "IMPORT_UNREAL_KEYFRAME"; /** * Configures the AC loader to collect all surfaces which have the * "Backface cull" flag set in separate meshes. * * Default value: true. * * Property type: bool. */ const char* AI_CONFIG_IMPORT_AC_SEPARATE_BFCULL = "IMPORT_AC_SEPARATE_BFCULL"; /** * Configures the UNREAL 3D loader to separate faces with different surface * flags (e.g. two-sided vs. single-sided). * * Default value: true. * * Property type: bool. */ const char* AI_CONFIG_IMPORT_UNREAL_HANDLE_FLAGS = "UNREAL_HANDLE_FLAGS"; /** * Configures the terragen import plugin to compute uv's for terrains, if * not given. Furthermore, a default texture is assigned. * * UV coordinates for terrains are so simple to compute that you'll usually * want to compute them on your own, if you need them. This option is intended * for model viewers which want to offer an easy way to apply textures to * terrains. * * Default value: false. * * Property type: bool. */ const char* AI_CONFIG_IMPORT_TER_MAKE_UVS = "IMPORT_TER_MAKE_UVS"; /** * Configures the ASE loader to always reconstruct normal vectors basing on * the smoothing groups loaded from the file. * * Many ASE files have invalid normals (they're not orthonormal). * * Default value: true. * * Property type: bool. */ const char* AI_CONFIG_IMPORT_ASE_RECONSTRUCT_NORMALS = "IMPORT_ASE_RECONSTRUCT_NORMALS"; /** * Configures the M3D loader to detect and process multi-part Quake player * models. * * These models usually consist of three files, lower.md3, * upper.md3 and head.md3. If this property is set * to true, Assimp will try to load and combine all three files if one of * them is loaded. * * Default value: true. * * Property type: bool. */ const char* AI_CONFIG_IMPORT_MD3_HANDLE_MULTIPART = "IMPORT_MD3_HANDLE_MULTIPART"; /** * Tells the MD3 loader which skin files to load. * * When loading MD3 files, Assimp checks whether a file * _.skin is existing. These files * are used by Quake 3 to be able to assign different skins (e.g. red and * blue team) to models. 'default', 'red', 'blue' are typical skin names. * * Default value: "default". * * Property type: string. */ const char* AI_CONFIG_IMPORT_MD3_SKIN_NAME = "IMPORT_MD3_SKIN_NAME"; /** * Specify the Quake 3 shader file to be used for a particular MD3 file. * This can also be a search path. * * By default Assimp's behaviour is as follows: If a MD3 file * [any_path]/models/[any_q3_subdir]/[model_name]/[file_name].md3 * is loaded, the library tries to locate the corresponding shader file in * [any_path]/scripts/[model_name].shader. This property * overrides this behaviour. It can either specify a full path to the shader * to be loaded or alternatively the path (relative or absolute) to the * directory where the shaders for all MD3s to be loaded reside. Assimp * attempts to open [dir]/[model_name].shader first, * [dir]/[file_name].shader is the fallback file. Note that * [dir] should have a terminal (back)slash. * * Default value: n/a. * * Property type: string. */ const char* AI_CONFIG_IMPORT_MD3_SHADER_SRC = "IMPORT_MD3_SHADER_SRC"; /** * Configures the LWO loader to load just one layer from the model. * * LWO files consist of layers and in some cases it could be useful to load * only one of them. This property can be either a string – which specifies * the name of the layer – or an integer – the index of the layer. If the * property is not set the whole LWO model is loaded. Loading fails if the * requested layer is not available. The layer index is zero-based and the * layer name may not be empty. * * Default value: all layers are loaded. * * Property type: integer/string. */ const char* AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY = "IMPORT_LWO_ONE_LAYER_ONLY"; /** * Configures the MD5 loader to not load the MD5ANIM file for a MD5MESH file * automatically. * * The default strategy is to look for a file with the same name but the * MD5ANIM extension in the same directory. If it is found, it is loaded * and combined with the MD5MESH file. This configuration option can be * used to disable this behaviour. * * Default value: false. * * Property type: bool. */ const char* AI_CONFIG_IMPORT_MD5_NO_ANIM_AUTOLOAD = "IMPORT_MD5_NO_ANIM_AUTOLOAD"; /** * Defines the begin of the time range for which the LWS loader evaluates * animations and computes aiNodeAnims. * * Assimp provides full conversion of LightWave's envelope system, including * pre and post conditions. The loader computes linearly subsampled animation * chanels with the frame rate given in the LWS file. This property defines * the start time. Note: animation channels are only generated if a node * has at least one envelope with more tan one key assigned. This property. * is given in frames, '0' is the first frame. By default, if this property * is not set, the importer takes the animation start from the input LWS * file ('FirstFrame' line). * * Default value: read from file. * * Property type: integer. * * See: AI_CONFIG_IMPORT_LWS_ANIM_END – end of the imported * time range */ const char* AI_CONFIG_IMPORT_LWS_ANIM_START = "IMPORT_LWS_ANIM_START"; const char* AI_CONFIG_IMPORT_LWS_ANIM_END = "IMPORT_LWS_ANIM_END"; /** * Defines the output frame rate of the IRR loader. * * IRR animations are difficult to convert for Assimp and there will always * be a loss of quality. This setting defines how many keys per second are * returned by the converter. * * Default value: 100. * * Property type: integer. */ const char* AI_CONFIG_IMPORT_IRR_ANIM_FPS = "IMPORT_IRR_ANIM_FPS"; /** * Ogre Importer will try to load this material file. * * Ogre Mehs contain only the material name, not the material file. If there * is no material file with the same name as the material, Ogre Importer * will try to load this file and search the material in it. * * Property type: string. Default value: "Scene.material". */ const char* AI_CONFIG_IMPORT_OGRE_MATERIAL_FILE = "IMPORT_OGRE_MATERIAL_FILE"; } assimp-4.1.0/port/dAssimp/assimp/assimp.d0000644002537200234200000000437513213503245020606 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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-all module provided for convenience. */ module assimp.assimp; public { import assimp.animation; import assimp.api; import assimp.camera; import assimp.config; import assimp.fileIO; import assimp.light; import assimp.loader; import assimp.material; import assimp.math; import assimp.mesh; import assimp.postprocess; import assimp.scene; import assimp.texture; import assimp.types; import assimp.versionInfo; } assimp-4.1.0/port/dAssimp/assimp/material.d0000644002537200234200000004637513213503245021116 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * Contains the material system which stores the imported material information. */ module assimp.material; import assimp.math; import assimp.types; extern ( C ) { /** * Default material names for meshes without UV coordinates. */ const char* AI_DEFAULT_MATERIAL_NAME = "aiDefaultMat"; /** * Default material names for meshes with UV coordinates. */ const char* AI_DEFAULT_TEXTURED_MATERIAL_NAME = "TexturedDefaultMaterial"; /** * Defines how the Nth texture of a specific type is combined with the * result of all previous layers. * * Example (left: key, right: value): *
 DiffColor0     - gray
    * DiffTextureOp0 - aiTextureOpMultiply
    * DiffTexture0   - tex1.png
    * DiffTextureOp0 - aiTextureOpAdd
    * DiffTexture1   - tex2.png
* Written as equation, the final diffuse term for a specific pixel would be: *
diffFinal = DiffColor0 * sampleTex( DiffTexture0, UV0 ) +
    *     sampleTex( DiffTexture1, UV0 ) * diffContrib;
* where diffContrib is the intensity of the incoming light for * that pixel. */ enum aiTextureOp : uint { /** * T = T1 * T2 */ Multiply = 0x0, /** * T = T1 + T2 */ Add = 0x1, /** * T = T1 - T2 */ Subtract = 0x2, /** * T = T1 / T2 */ Divide = 0x3, /** * T = ( T1 + T2 ) - ( T1 * T2 ) */ SmoothAdd = 0x4, /** * T = T1 + ( T2 - 0.5 ) */ SignedAdd = 0x5 } /** * Defines how UV coordinates outside the [0..1] range are * handled. * * Commonly referred to as 'wrapping mode'. */ enum aiTextureMapMode : uint { /** * A texture coordinate u | v is translated to * (u%1) | (v%1). */ Wrap = 0x0, /** * Texture coordinates are clamped to the nearest valid value. */ Clamp = 0x1, /** * If the texture coordinates for a pixel are outside * [0..1], the texture is not applied to that pixel. */ Decal = 0x3, /** * A texture coordinate u | v becomes * (u%1) | (v%1) if (u-(u%1))%2 is * zero and (1-(u%1)) | (1-(v%1)) otherwise. */ Mirror = 0x2 } /** * Defines how the mapping coords for a texture are generated. * * Real-time applications typically require full UV coordinates, so the use of * the aiProcess.GenUVCoords step is highly recommended. It * generates proper UV channels for non-UV mapped objects, as long as an * accurate description how the mapping should look like (e.g spherical) is * given. See the AI_MATKEY_MAPPING property for more details. */ enum aiTextureMapping : uint { /** * The mapping coordinates are taken from an UV channel. * * The AI_MATKEY_UVSRC key specifies from which (remember, * meshes can have more than one UV channel). */ UV = 0x0, /** * Spherical mapping. */ SPHERE = 0x1, /** * Cylindrical mapping. */ CYLINDER = 0x2, /** * Cubic mapping. */ BOX = 0x3, /** * Planar mapping. */ PLANE = 0x4, /** * Undefined mapping. */ OTHER = 0x5 } /** * Defines the purpose of a texture * * This is a very difficult topic. Different 3D packages support different * kinds of textures. For very common texture types, such as bumpmaps, the * rendering results depend on implementation details in the rendering * pipelines of these applications. Assimp loads all texture references from * the model file and tries to determine which of the predefined texture * types below is the best choice to match the original use of the texture * as closely as possible. * * In content pipelines you'll usually define how textures have to be * handled, and the artists working on models have to conform to this * specification, regardless which 3D tool they're using. */ enum aiTextureType : uint { /** * No texture, but the value to be used for * aiMaterialProperty.mSemantic for all material properties * not related to textures. */ NONE = 0x0, /** * The texture is combined with the result of the diffuse lighting * equation. */ DIFFUSE = 0x1, /** * The texture is combined with the result of the specular lighting * equation. */ SPECULAR = 0x2, /** * The texture is combined with the result of the ambient lighting * equation. */ AMBIENT = 0x3, /** * The texture is added to the result of the lighting calculation. It * isn't influenced by incoming light. */ EMISSIVE = 0x4, /** * The texture is a height map. * * By convention, higher grey-scale values stand for higher elevations * from the base height. */ HEIGHT = 0x5, /** * The texture is a (tangent space) normal-map. * * Again, there are several conventions for tangent-space normal maps. * Assimp does (intentionally) not differenciate here. */ NORMALS = 0x6, /** * The texture defines the glossiness of the material. * * The glossiness is in fact the exponent of the specular (phong) * lighting equation. Usually there is a conversion function defined to * map the linear color values in the texture to a suitable exponent. */ SHININESS = 0x7, /** * The texture defines per-pixel opacity. * * Usually white means opaque and black means transparent. */ OPACITY = 0x8, /** * Displacement texture. * * The exact purpose and format is application-dependent. Higher color * values stand for higher vertex displacements. */ DISPLACEMENT = 0x9, /** * Lightmap or ambient occlusion texture. * * Both lightmaps and dedicated ambient occlusion maps are covered by * this material property. The texture contains a scaling value for the * final color value of a pixel. Its intensity is not affected by * incoming light. */ LIGHTMAP = 0xA, /** * Reflection texture. * * Contains the color of a perfect mirror reflection. Rarely used, almost * never for real-time applications. */ REFLECTION = 0xB, /** * Unknown texture. * * A texture reference that does not match any of the definitions above is * considered to be 'unknown'. It is still imported, but is excluded from * any further postprocessing. */ UNKNOWN = 0xC } /** * Defines all shading models supported by the library * * The list of shading modes has been taken from Blender. See Blender * documentation for more information. The API does not distinguish between * "specular" and "diffuse" shaders (thus the specular term for diffuse * shading models like Oren-Nayar remains undefined). * * Again, this value is just a hint. Assimp tries to select the shader whose * most common implementation matches the original rendering results of the * 3D modeller which wrote a particular model as closely as possible. */ enum aiShadingMode : uint { /** * Flat shading. * * Shading is done on per-face base diffuse only. Also known as * »faceted shading«. */ Flat = 0x1, /** * Simple Gouraud shading. */ Gouraud = 0x2, /** * Phong-Shading. */ Phong = 0x3, /** * Phong-Blinn-Shading. */ Blinn = 0x4, /** * Per-pixel toon shading. * * Often referred to as »comic shading«. */ Toon = 0x5, /** * Per-pixel Oren-Nayar shading. * * Extension to standard Lambertian shading, taking the roughness of the * material into account. */ OrenNayar = 0x6, /** * Per-pixel Minnaert shading. * * Extension to standard Lambertian shading, taking the "darkness" of the * material into account. */ Minnaert = 0x7, /** * Per-pixel Cook-Torrance shading. * * Special shader for metallic surfaces. */ CookTorrance = 0x8, /** * No shading at all. * * Constant light influence of 1. */ NoShading = 0x9, /** * Fresnel shading. */ Fresnel = 0xa } /** * Defines some mixed flags for a particular texture. * * Usually you'll instruct your cg artists how textures have to look like * and how they will be processed in your application. However, if you use * Assimp for completely generic loading purposes you might also need to * process these flags in order to display as many 'unknown' 3D models as * possible correctly. * * This corresponds to the AI_MATKEY_TEXFLAGS property. */ enum aiTextureFlags : uint { /** * The texture's color values have to be inverted (i.e. 1-n * component-wise). */ Invert = 0x1, /** * Explicit request to the application to process the alpha channel of the * texture. * * Mutually exclusive with IgnoreAlpha. These flags are * set if the library can say for sure that the alpha channel is used/is * not used. If the model format does not define this, it is left to the * application to decide whether the texture alpha channel – if any – is * evaluated or not. */ UseAlpha = 0x2, /** * Explicit request to the application to ignore the alpha channel of the * texture. * * Mutually exclusive with UseAlpha. */ IgnoreAlpha = 0x4 } /** * Defines alpha-blend flags. * * If you're familiar with OpenGL or D3D, these flags aren't new to you. * They define how the final color value of a pixel is computed, based on * the previous color at that pixel and the new color value from the * material. * * The basic blending formula is * SourceColor * SourceBlend + DestColor * DestBlend, * where DestColor is the previous color in the framebuffer at * this position and SourceColor is the material color before * the transparency calculation. * * This corresponds to the AI_MATKEY_BLEND_FUNC property. */ enum aiBlendMode :uint { /** * Formula: * SourceColor * SourceAlpha + DestColor * (1 - SourceAlpha) */ Default = 0x0, /** * Additive blending. * * Formula: SourceColor*1 + DestColor*1 */ Additive = 0x1 } /** * Defines how an UV channel is transformed. * * This is just a helper structure for the AI_MATKEY_UVTRANSFORM * key. See its documentation for more details. */ struct aiUVTransform { align ( 1 ) : /** * Translation on the u and v axes. * * The default value is (0|0). */ aiVector2D mTranslation; /** * Scaling on the u and v axes. * * The default value is (1|1). */ aiVector2D mScaling; /** * Rotation - in counter-clockwise direction. * * The rotation angle is specified in radians. The rotation center is * 0.5|0.5. The default value is 0. */ float mRotation; } /** * A very primitive RTTI system to store the data type of a material * property. */ enum aiPropertyTypeInfo : uint { /** * Array of single-precision (32 bit) floats. * * It is possible to use aiGetMaterialInteger[Array]() to * query properties stored in floating-point format. The material system * performs the type conversion automatically. */ Float = 0x1, /** * aiString property. * * Arrays of strings aren't possible, aiGetMaterialString() * must be used to query a string property. */ String = 0x3, /** * Array of (32 bit) integers. * * It is possible to use aiGetMaterialFloat[Array]() to * query properties stored in integer format. The material system * performs the type conversion automatically. */ Integer = 0x4, /** * Simple binary buffer, content undefined. Not convertible to anything. */ Buffer = 0x5 } /** * Data structure for a single material property. * * As an user, you'll probably never need to deal with this data structure. * Just use the provided aiGetMaterialXXX() functions to query * material properties easily. Processing them manually is faster, but it is * not the recommended way. It isn't worth the effort. * * Material property names follow a simple scheme: * * $[name]: A public property, there must be a corresponding * AI_MATKEY_XXX constant. * * ?[name]: Also public, but ignored by the * aiProcess.RemoveRedundantMaterials post-processing step. * * ~[name]: A temporary property for internal use. */ struct aiMaterialProperty { /** * Specifies the name of the property (key). * * Keys are generally case insensitive. */ aiString mKey; /** * For texture properties, this specifies the exact usage semantic. * * For non-texture properties, this member is always 0 (or rather * aiTextureType.NONE). */ uint mSemantic; /** * For texture properties, this specifies the index of the texture. * * For non-texture properties, this member is always 0. */ uint mIndex; /** * Size of the buffer mData is pointing to (in bytes). * * This value may not be 0. */ uint mDataLength; /** * Type information for the property. * * Defines the data layout inside the data buffer. This is used by the * library internally to perform debug checks and to utilize proper type * conversions. */ aiPropertyTypeInfo mType; /** * Binary buffer to hold the property's value. * * The size of the buffer is always mDataLength. */ char* mData; } /** * Data structure for a material * * Material data is stored using a key-value structure. A single key-value * pair is called a material property. The properties can be * queried using the aiMaterialGetXXX family of functions. The * library defines a set of standard keys (AI_MATKEY_XXX). */ struct aiMaterial { /** * List of all material properties loaded. */ aiMaterialProperty** mProperties; /** * Number of properties loaded. */ uint mNumProperties; uint mNumAllocated; /// ditto } /** * Standard material property keys. Always pass 0 for texture type and index * when querying these keys. */ const char* AI_MATKEY_NAME = "?mat.name"; const char* AI_MATKEY_TWOSIDED = "$mat.twosided"; /// ditto const char* AI_MATKEY_SHADING_MODEL = "$mat.shadingm"; /// ditto const char* AI_MATKEY_ENABLE_WIREFRAME = "$mat.wireframe"; /// ditto const char* AI_MATKEY_BLEND_FUNC = "$mat.blend"; /// ditto const char* AI_MATKEY_OPACITY = "$mat.opacity"; /// ditto const char* AI_MATKEY_BUMPSCALING = "$mat.bumpscaling"; /// ditto const char* AI_MATKEY_SHININESS = "$mat.shininess"; /// ditto const char* AI_MATKEY_REFLECTIVITY = "$mat.reflectivity"; /// ditto const char* AI_MATKEY_SHININESS_STRENGTH = "$mat.shinpercent"; /// ditto const char* AI_MATKEY_REFRACTI = "$mat.refracti"; /// ditto const char* AI_MATKEY_COLOR_DIFFUSE = "$clr.diffuse"; /// ditto const char* AI_MATKEY_COLOR_AMBIENT = "$clr.ambient"; /// ditto const char* AI_MATKEY_COLOR_SPECULAR = "$clr.specular"; /// ditto const char* AI_MATKEY_COLOR_EMISSIVE = "$clr.emissive"; /// ditto const char* AI_MATKEY_COLOR_TRANSPARENT = "$clr.transparent"; /// ditto const char* AI_MATKEY_COLOR_REFLECTIVE = "$clr.reflective"; /// ditto const char* AI_MATKEY_GLOBAL_BACKGROUND_IMAGE = "?bg.global"; /// ditto /** * Texture material property keys. Do not forget to specify texture type and * index for these keys. */ const char* AI_MATKEY_TEXTURE = "$tex.file"; const char* AI_MATKEY_UVWSRC = "$tex.uvwsrc"; /// ditto const char* AI_MATKEY_TEXOP = "$tex.op"; /// ditto const char* AI_MATKEY_MAPPING = "$tex.mapping"; /// ditto const char* AI_MATKEY_TEXBLEND = "$tex.blend"; /// ditto const char* AI_MATKEY_MAPPINGMODE_U = "$tex.mapmodeu"; /// ditto const char* AI_MATKEY_MAPPINGMODE_V = "$tex.mapmodev"; /// ditto const char* AI_MATKEY_TEXMAP_AXIS = "$tex.mapaxis"; /// ditto const char* AI_MATKEY_UVTRANSFORM = "$tex.uvtrafo"; /// ditto const char* AI_MATKEY_TEXFLAGS = "$tex.flags"; /// ditto } assimp-4.1.0/port/dAssimp/assimp/fileIO.d0000644002537200234200000001057513213503245020460 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * The data structures necessary to use Assimip with a custom IO system. */ module assimp.fileIO; import assimp.types; extern ( C ) { // aiFile callbacks alias size_t function( aiFile*, char*, size_t, size_t ) aiFileWriteProc; alias size_t function( aiFile*, char*, size_t, size_t ) aiFileReadProc; alias size_t function( aiFile* ) aiFileTellProc; alias void function( aiFile* ) aiFileFlushProc; alias aiReturn function( aiFile*, size_t, aiOrigin ) aiFileSeek; // aiFileIO callbacks alias aiFile* function( aiFileIO*, char*, char* ) aiFileOpenProc; alias void function( aiFileIO*, aiFile* ) aiFileCloseProc; /** * Represents user-defined data. */ alias char* aiUserData; /** * File system callbacks. * * Provided are functions to open and close files. Supply a custom structure * to the import function. If you don't, a default implementation is used. * Use custom file systems to enable reading from other sources, such as * ZIPs or memory locations. */ struct aiFileIO { /** * Function used to open a new file */ aiFileOpenProc OpenProc; /** * Function used to close an existing file */ aiFileCloseProc CloseProc; /** * User-defined, opaque data. */ aiUserData UserData; } /** * File callbacks. * * Actually, it's a data structure to wrap a set of fXXXX * (e.g fopen()) replacement functions. * * The default implementation of the functions utilizes the fXXX * functions from the CRT. However, you can supply a custom implementation * to Assimp by passing a custom aiFileIO. Use this to enable * reading from other sources such as ZIP archives or memory locations. */ struct aiFile { /** * Callback to read from a file. */ aiFileReadProc ReadProc; /** * Callback to write to a file. */ aiFileWriteProc WriteProc; /** * Callback to retrieve the current position of the file cursor * (ftell()). */ aiFileTellProc TellProc; /** * Callback to retrieve the size of the file, in bytes. */ aiFileTellProc FileSizeProc; /** * Callback to set the current position of the file cursor * (fseek()). */ aiFileSeek SeekProc; /** * Callback to flush the file contents. */ aiFileFlushProc FlushProc; /** * User-defined, opaque data. */ aiUserData UserData; } } assimp-4.1.0/port/dAssimp/assimp/versionInfo.d0000644002537200234200000000472613213503245021613 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * Flags returned by aiGetCompileFlags(). */ module assimp.versionInfo; extern ( C ) { /** * Assimp was compiled as a shared object (Windows: DLL). */ const uint ASSIMP_CFLAGS_SHARED = 0x1; /** * Assimp was compiled against STLport. */ const uint ASSIMP_CFLAGS_STLPORT = 0x2; /** * Assimp was compiled as a debug build. */ const uint ASSIMP_CFLAGS_DEBUG = 0x4; /** * Assimp was compiled with ASSIMP_BUILD_BOOST_WORKAROUND defined. */ const uint ASSIMP_CFLAGS_NOBOOST = 0x8; /** * Assimp was compiled with ASSIMP_BUILD_SINGLETHREADED defined. */ const uint ASSIMP_CFLAGS_SINGLETHREADED = 0x10; } assimp-4.1.0/port/dAssimp/assimp/types.d0000644002537200234200000001477713213503245020465 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * Contains miscellaneous types used in Assimp's C API. */ module assimp.types; extern ( C ) { /** * Our own C boolean type. */ enum aiBool : int { FALSE = 0, TRUE = 1 } /** * Type definition for log stream callback function pointers. */ alias void function( char* message, char* user ) aiLogStreamCallback; /** * Represents a log stream. A log stream receives all log messages and * streams them somewhere. * * See: aiGetPredefinedLogStream, * aiAttachLogStream and aiDetachLogStream. */ struct aiLogStream { /** * Callback function to be called when a new message arrives. */ aiLogStreamCallback callback; /** * User data to be passed to the callback. */ char* user; } /** * Maximum dimension for aiStrings. * * Assimp strings are zero terminated. */ const size_t MAXLEN = 1024; /** * Represents an UTF-8 string, zero byte terminated. * * The length of such a string is limited to MAXLEN bytes * (excluding the terminal \0). * * The character set of an aiString is explicitly defined to be UTF-8. This * Unicode transformation was chosen in the belief that most strings in 3d * model files are limited to ASCII characters, thus the character set * needed to be ASCII compatible. * * Most text file loaders provide proper Unicode input file handling, * special unicode characters are correctly transcoded to UTF-8 and are kept * throughout the libraries' import pipeline. * * For most applications, it will be absolutely sufficient to interpret the * aiString as ASCII data and work with it as one would work with a plain * char[]. * * To access an aiString from D you might want to use something like the * following piece of code: * --- * char[] importAiString( aiString* s ) { * return s.data[ 0 .. s.length ]; * } * --- */ struct aiString { /** * Length of the string (excluding the terminal \0). * * This is not the logical length of strings containing UTF-8 * multibyte sequences, but the number of bytes from the beginning of the * string to its end. */ size_t length; /** * String buffer. * * Size limit is MAXLEN. */ char data[ MAXLEN ]; } /** * Standard return type for some library functions. */ enum aiReturn : uint { /** * Indicates that a function was successful. */ SUCCESS = 0x0, /** * Indicates that a function failed. */ FAILURE = -0x1, /** * Indicates that not enough memory was available to perform the * requested operation. */ OUTOFMEMORY = -0x3 } /** * Seek origins (for the virtual file system API). */ enum aiOrigin : uint { /** * Beginning of the file. */ SET = 0x0, /** * Current position of the file pointer. */ CUR = 0x1, /** * End of the file. * * Offsets must be negative. */ END = 0x2 } /** * Enumerates predefined log streaming destinations. * * Logging to these streams can be enabled with a single call to * aiAttachPredefinedLogStream(). */ enum aiDefaultLogStream :uint { /** * Stream the log to a file. */ FILE = 0x1, /** * Stream the log to standard output. */ STDOUT = 0x2, /** * Stream the log to standard error. */ STDERR = 0x4, /** * MSVC only: Stream the log the the debugger (this relies on * OutputDebugString from the Win32 SDK). */ DEBUGGER = 0x8 } /** * Stores the memory requirements for different components (e.g. meshes, * materials, animations) of an import. All sizes are in bytes. */ struct aiMemoryInfo { /** * Storage allocated for texture data. */ uint textures; /** * Storage allocated for material data. */ uint materials; /** * Storage allocated for mesh data. */ uint meshes; /** * Storage allocated for node data. */ uint nodes; /** * Storage allocated for animation data. */ uint animations; /** * Storage allocated for camera data. */ uint cameras; /** * Storage allocated for light data. */ uint lights; /** * Total storage allocated for the full import. */ uint total; } } assimp-4.1.0/port/dAssimp/assimp/light.d0000644002537200234200000001674013213503245020420 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * Contains the data structures which are used to store the imported information * about the light sources in the scene. */ module assimp.light; import assimp.math; import assimp.types; extern ( C ) { /** * Enumerates all supported types of light sources. */ enum aiLightSourceType : uint { UNDEFINED = 0x0, /** * A directional light source has a well-defined direction but is * infinitely far away. That's quite a good approximation for sun light. */ DIRECTIONAL = 0x1, /** * A point light source has a well-defined position in space but no * direction – it emits light in all directions. A normal bulb is a point * light. */ POINT = 0x2, /** * A spot light source emits light in a specific angle. It has a position * and a direction it is pointing to. A good example for a spot light is * a light spot in sport arenas. */ SPOT = 0x3 } /** * Helper structure to describe a light source. * * Assimp supports multiple sorts of light sources, including directional, * point and spot lights. All of them are defined with just a single * structure and distinguished by their parameters. * * Note: Some file formats (such as 3DS, ASE) export a "target point" – the * point a spot light is looking at (it can even be animated). Assimp * writes the target point as a subnode of a spotlights's main node, called * [spotName].Target. However, this is just additional * information then, the transformation tracks of the main node make the * spot light already point in the right direction. */ struct aiLight { /** * The name of the light source. * * There must be a node in the scenegraph with the same name. This node * specifies the position of the light in the scenehierarchy and can be * animated. */ aiString mName; /** * The type of the light source. * * aiLightSource.UNDEFINED is not a valid value for this * member. */ aiLightSourceType mType; /** * Position of the light source in space. Relative to the transformation * of the node corresponding to the light. * * The position is undefined for directional lights. */ aiVector3D mPosition; /** * Direction of the light source in space. Relative to the transformation * of the node corresponding to the light. * * The direction is undefined for point lights. The vector may be * normalized, but it needn't. */ aiVector3D mDirection; /** * Constant light attenuation factor. * * The intensity of the light source at a given distance * d from the light's position is * 1/( att0 + att1 * d + att2 * d * d ). This member * corresponds to the att0 variable in the equation. * * Naturally undefined for directional lights. */ float mAttenuationConstant; /** * Linear light attenuation factor. * * The intensity of the light source at a given distance * d from the light's position is * 1/( att0 + att1 * d + att2 * d * d ). This member * corresponds to the att1 variable in the equation. * * Naturally undefined for directional lights. */ float mAttenuationLinear; /** * Quadratic light attenuation factor. * * The intensity of the light source at a given distance * d from the light's position is * 1/( att0 + att1 * d + att2 * d * d ). This member * corresponds to the att2 variable in the equation. * * Naturally undefined for directional lights. */ float mAttenuationQuadratic; /** * Diffuse color of the light source * * The diffuse light color is multiplied with the diffuse material color * to obtain the final color that contributes to the diffuse shading term. */ aiColor3D mColorDiffuse; /** * Specular color of the light source * * The specular light color is multiplied with the specular material * color to obtain the final color that contributes to the specular * shading term. */ aiColor3D mColorSpecular; /** * Ambient color of the light source * * The ambient light color is multiplied with the ambient material color * to obtain the final color that contributes to the ambient shading term. * * Most renderers will ignore this value it, is just a remaining of the * fixed-function pipeline that is still supported by quite many file * formats. */ aiColor3D mColorAmbient; /** * Inner angle of a spot light's light cone. * * The spot light has maximum influence on objects inside this angle. The * angle is given in radians. It is 2PI for point lights and undefined * for directional lights. */ float mAngleInnerCone; /** * Outer angle of a spot light's light cone. * * The spot light does not affect objects outside this angle. The angle * is given in radians. It is 2PI for point lights and undefined for * directional lights. The outer angle must be greater than or equal to * the inner angle. * * It is assumed that the application uses a smooth interpolation between * the inner and the outer cone of the spot light. */ float mAngleOuterCone; } } assimp-4.1.0/port/dAssimp/assimp/mesh.d0000644002537200234200000003763513213503245020253 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * Contains the data structures in which the imported geometry is returned by * Assimp. */ module assimp.mesh; import assimp.math; import assimp.types; extern ( C ) { /* * These limits are required to match the settings Assimp was compiled * against. Therefore, do not redefine them unless you build the library * from source using the same definitions. */ /** * Maximum number of indices per face (polygon). */ const AI_MAX_FACE_INDICES = 0x7fff; /** * Maximum number of indices per face (polygon). */ const AI_MAX_BONE_WEIGHTS = 0x7fffffff; /** * Maximum number of vertices per mesh. */ const AI_MAX_VERTICES = 0x7fffffff; /** * Maximum number of faces per mesh. */ const AI_MAX_FACES = 0x7fffffff; /** * Supported number of vertex color sets per mesh. */ const AI_MAX_NUMBER_OF_COLOR_SETS = 0x4; /** * Supported number of texture coord sets (UV(W) channels) per mesh. */ const AI_MAX_NUMBER_OF_TEXTURECOORDS = 0x4; /** * A single face in a mesh, referring to multiple vertices. * * If mNumIndices is 3, we call the face triangle, for * for mNumIndices > 3 it's called polygon. * * aiMesh.mPrimitiveTypes can be queried to quickly examine * which types of primitive are actually present in a mesh. The * aiProcess.SortByPType flag post-processing step splits * meshes containing different primitive types (e.g. lines and triangles) in * several "clean" submeshes. * * Furthermore, there is a configuration option * (AI_CONFIG_PP_SBP_REMOVE) to force SortByPType * to completely remove specific kinds of primitives from the imported scene. * In many cases you'll probably want to set this setting to * aiPrimitiveType.LINE | aiPrimitiveType.POINT. Together with * the aiProcess.Triangulate flag you can then be sure that * mNumIndices is always 3. */ struct aiFace { /** * Number of indices defining this face. * * The maximum value for this member is AI_MAX_FACE_INDICES. */ uint mNumIndices; /** * Array of the indices defining the face. * * The size is given in mNumIndices. */ uint* mIndices; } /** * A single influence of a bone on a vertex. */ struct aiVertexWeight { /** * Index of the vertex which is influenced by the bone. */ uint mVertexId; /** * The strength of the influence in the range [0..1]. * * The influence from all bones at one vertex sums up to 1. */ float mWeight; } /** * A single bone of a mesh. * * A bone has a name by which it can be found in the frame hierarchy and by * which it can be addressed by animations. In addition it has a number of * influences on vertices. */ struct aiBone { /** * The name of the bone. */ aiString mName; /** * The number of vertices affected by this bone. * * The maximum value for this member is AI_MAX_BONE_WEIGHTS. */ uint mNumWeights; /** * The vertices affected by this bone. * * This array is mNumWeights entries in size. */ aiVertexWeight* mWeights; /** * Matrix that transforms from mesh space to bone space (in the bind * pose). */ aiMatrix4x4 mOffsetMatrix; } /** * Enumerates the types of geometric primitives supported by Assimp. * * See: aiFace, aiProcess.SortByPType, * aiProcess.Triangulate, * AI_CONFIG_PP_SBP_REMOVE. */ enum aiPrimitiveType : uint { /** A point primitive. * * This is just a single vertex in the virtual world, * aiFace contains just one index for such a primitive. */ POINT = 0x1, /** A line primitive. * * This is a line defined through a start and an end position. * aiFace contains exactly two indices for such a primitive. */ LINE = 0x2, /** A triangular primitive. * * A triangle consists of three indices. */ TRIANGLE = 0x4, /** A higher-level polygon with more than 3 edges. * * A triangle is a polygon, but in this context, polygon means * "all polygons that are not triangles". The Triangulate * post processing step is provided for your convenience, it splits all * polygons in triangles (which are much easier to handle). */ POLYGON = 0x8 } // Note: The AI_PRIMITIVE_TYPE_FOR_N_INDICES(n) macro from the C headers is // missing since there is probably not much use for it when just reading // scene files. /** * NOT CURRENTLY IN USE. An AnimMesh is an attachment to an #aiMesh stores * per-vertex animations for a particular frame. * * You may think of an aiAnimMesh as a `patch` for the host * mesh, which replaces only certain vertex data streams at a particular * time. * * Each mesh stores n attached attached meshes (aiMesh.mAnimMeshes). * The actual relationship between the time line and anim meshes is * established by #aiMeshAnim, which references singular mesh attachments * by their ID and binds them to a time offset. */ struct aiAnimMesh { /** * Replacement for aiMesh.mVertices. * * If this array is non-null, it *must* contain mNumVertices entries. * The corresponding array in the host mesh must be non-null as well - * animation meshes may neither add or nor remove vertex components (if * a replacement array is NULL and the corresponding source array is * not, the source data is taken instead). */ aiVector3D* mVertices; /// Replacement for aiMesh.mNormals. aiVector3D* mNormals; /// Replacement for aiMesh.mTangents. aiVector3D* mTangents; /// Replacement for aiMesh.mBitangents. aiVector3D* mBitangents; /// Replacement for aiMesh.mColors. aiColor4D* mColors[ AI_MAX_NUMBER_OF_COLOR_SETS ]; /// Replacement for aiMesh.mTextureCoords. aiVector3D* mTextureCoords[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; /** * The number of vertices in the aiAnimMesh, and thus the length of all * the member arrays. * * This has always the same value as the mNumVertices property in the * corresponding aiMesh. It is duplicated here merely to make the length * of the member arrays accessible even if the aiMesh is not known, e.g. * from language bindings. */ uint mNumVertices; } /** * A mesh represents a geometry or model with a single material. * * It usually consists of a number of vertices and a series * primitives/faces referencing the vertices. In addition there might be a * series of bones, each of them addressing a number of vertices with a * certain weight. Vertex data is presented in channels with each channel * containing a single per-vertex information such as a set of texture * coords or a normal vector. If a data pointer is non-null, the * corresponding data stream is present. * * A mesh uses only a single material which is referenced by a material ID. * * Note: The mPositions member is usually not optional. * However, vertex positions could be missing if the * AI_SCENE_FLAGS_INCOMPLETE flag is set in * aiScene.mFlags. */ struct aiMesh { /** * Bitwise combination of aiPrimitiveType members. * * This specifies which types of primitives are present in the mesh. * The SortByPrimitiveType post processing step can be used * to make sure the output meshes consist of one primitive type each. */ uint mPrimitiveTypes; /** * The number of vertices in this mesh. * * This is also the size of all of the per-vertex data arrays. The * maximum value for this member is AI_MAX_VERTICES. */ uint mNumVertices; /** * The number of primitives (triangles, polygons, lines) in this mesh. * * This is also the size of the mFaces array. The maximum * value for this member is AI_MAX_FACES. */ uint mNumFaces; /** * Vertex positions. * * This array is always present in a mesh. The array is * mNumVertices in size. */ aiVector3D* mVertices; /** * Vertex normals. * * The array contains normalized vectors, null if not present. * The array is mNumVertices in size. * * Normals are undefined for point and line primitives. A mesh * consisting of points and lines only may not have normal vectors. * Meshes with mixed primitive types (i.e. lines and triangles) may have * normals, but the normals for vertices that are only referenced by * point or line primitives are undefined and set to QNAN. * * Note: Normal vectors computed by Assimp are always unit-length. * However, this needn't apply for normals that have been taken * directly from the model file. */ aiVector3D* mNormals; /** * Vertex tangents. * * The tangent of a vertex points in the direction of the positive x * texture axis. The array contains normalized vectors, null if * not present. The array is mNumVertices in size. * * A mesh consisting of points and lines only may not have normal * vectors. Meshes with mixed primitive types (i.e. lines and triangles) * may have normals, but the normals for vertices that are only * referenced by point or line primitives are undefined and set to * QNAN. * * Note: If the mesh contains tangents, it automatically also contains * bitangents (the bitangent is just the cross product of tangent and * normal vectors). */ aiVector3D* mTangents; /** * Vertex bitangents. * * The bitangent of a vertex points in the direction of the positive Y * texture axis. The array contains normalized vectors, null if not * present. The array is mNumVertices in size. * * Note: If the mesh contains tangents, it automatically also contains * bitangents. */ aiVector3D* mBitangents; /** * Vertex color sets. * * A mesh may contain 0 to AI_MAX_NUMBER_OF_COLOR_SETS * vertex colors per vertex. null if not present. * * Each array is mNumVertices in size if present. */ aiColor4D* mColors[ AI_MAX_NUMBER_OF_COLOR_SETS ]; /** * Vertex texture coords, also known as UV channels. * A mesh may contain 0 to AI_MAX_NUMBER_OF_TEXTURECOORDS * per vertex. null if not present. * * Each array is mNumVertices in size. */ aiVector3D* mTextureCoords[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; /** * Specifies the number of components for a given UV channel. * * Up to three channels are supported (UVW, for accessing volume or cube * maps). If the value is 2 for a given channel n, the * component p.z of mTextureCoords[n][p] is set * to 0. If the value is 1 for a given channel, p.y is set * to 0, too. If this value is 0, 2 should be assumed. * * Note: 4D coords are not supported. */ uint mNumUVComponents[ AI_MAX_NUMBER_OF_TEXTURECOORDS ]; /** * The faces the mesh is contstructed from. * * Each face refers to a number of vertices by their indices. * This array is always present in a mesh, its size is given * in mNumFaces. If the * AI_SCENE_FLAGS_NON_VERBOSE_FORMAT is not set, * each face references an unique set of vertices. */ aiFace* mFaces; /** * The number of bones this mesh contains. * * Can be 0, in which case the mBones array is null. */ uint mNumBones; /** * The bones of this mesh. * * A bone consists of a name by which it can be found in the frame * hierarchy and a set of vertex weights. */ aiBone** mBones; /** * The material used by this mesh. * * A mesh does use only a single material. If an imported model uses * multiple materials, the import splits up the mesh. Use this value as * index into the scene's material list. */ uint mMaterialIndex; /** * Name of the mesh. * * Meshes can be named, but this is not a requirement and leaving this * field empty is totally fine. * * There are mainly three uses for mesh names: * - Some formats name nodes and meshes independently. * - Importers tend to split meshes up to meet the one-material-per-mesh * requirement. Assigning the same (dummy) name to each of the result * meshes aids the caller at recovering the original mesh partitioning. * - Vertex animations refer to meshes by their names. */ aiString mName; /// NOT CURRENTLY IN USE. The number of attachment meshes. uint mNumAnimMeshes; /** * NOT CURRENTLY IN USE. Attachment meshes for this mesh, for vertex- * based animation. * * Attachment meshes carry replacement data for some of the mesh's * vertex components (usually positions, normals). */ aiAnimMesh** mAnimMeshes; } } assimp-4.1.0/port/dAssimp/assimp/animation.d0000644002537200234200000001620013213503245021257 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * The data structures which are used to store the imported animation data. */ module assimp.animation; import assimp.math; import assimp.types; extern ( C ) { /** * A time-value pair specifying a certain 3D vector for the given time. */ struct aiVectorKey { /** * The time of this key. */ double mTime; /** * The value of this key. */ aiVector3D mValue; } /** * A time-value pair specifying a rotation for the given time. For joint * animations, the rotation is usually expressed using a quaternion. */ struct aiQuatKey { /** * The time of this key. */ double mTime; /** * The value of this key. */ aiQuaternion mValue; } /** * Defines how an animation channel behaves outside the defined time * range. This corresponds to aiNodeAnim.mPreState and * aiNodeAnim.mPostState. */ enum aiAnimBehaviour : uint { /** * The value from the default node transformation is used. */ DEFAULT = 0x0, /** * The nearest key value is used without interpolation. */ CONSTANT = 0x1, /** * The value of the nearest two keys is linearly extrapolated for the * current time value. */ LINEAR = 0x2, /** * The animation is repeated. * * If the animation key go from n to m and the current time is t, use the * value at (t-n) % (|m-n|). */ REPEAT = 0x3 } /** * Describes the animation of a single node. * * The name specifies the bone/node which is affected by this animation * channel. The keyframes are given in three separate series of values, one * each for position, rotation and scaling. The transformation matrix * computed from these values replaces the node's original transformation * matrix at a specific time. This means all keys are absolute and not * relative to the bone default pose. * * The order in which the transformations are applied is – * as usual – scaling, rotation, translation. * * Note: All keys are returned in their correct, chronological order. * Duplicate keys don't pass the validation step. Most likely there will * be no negative time values, but they are not forbidden (so * implementations need to cope with them!). */ struct aiNodeAnim { /** * The name of the node affected by this animation. The node must exist * and it must be unique. */ aiString mNodeName; /** * The number of position keys. */ uint mNumPositionKeys; /** * The position keys of this animation channel. Positions are specified * as 3D vectors. The array is mNumPositionKeys in size. * * If there are position keys, there will also be at least one scaling * and one rotation key. */ aiVectorKey* mPositionKeys; /** * The number of rotation keys. */ uint mNumRotationKeys; /** * The rotation keys of this animation channel. Rotations are given as * quaternions. The array is mNumRotationKeys in size. * * If there are rotation keys, there will also be at least one scaling * and one position key. */ aiQuatKey* mRotationKeys; /** * The number of scaling keys. */ uint mNumScalingKeys; /** * The scaling keys of this animation channel. Scalings are specified as * 3D vectors. The array is mNumScalingKeys in size. * * If there are scaling keys, there will also be at least one position * and one rotation key. */ aiVectorKey* mScalingKeys; /** * Defines how the animation behaves before the first key is encountered. * * The default value is aiAnimBehaviour.DEFAULT (the original * transformation matrix of the affected node is used). */ aiAnimBehaviour mPreState; /** * Defines how the animation behaves after the last key was processed. * * The default value is aiAnimBehaviour.DEFAULT (the original * transformation matrix of the affected node is used). */ aiAnimBehaviour mPostState; } /** * An animation consists of keyframe data for a number of nodes. * * For each node affected by the animation, a separate series of data is * given. */ struct aiAnimation { /** * The name of the animation. * * If the modeling package this data was * exported from does support only a single animation channel, this * name is usually empty (length is zero). */ aiString mName; /** * Duration of the animation in ticks. */ double mDuration; /** * Ticks per second. 0 if not specified in the imported file. */ double mTicksPerSecond; /** * The number of bone animation channels. * * Each channel affects a single node. */ uint mNumChannels; /** * The node animation channels. The array is mNumChannels * in size. * * Each channel affects a single node. */ aiNodeAnim** mChannels; } }assimp-4.1.0/port/dAssimp/assimp/postprocess.d0000644002537200234200000006466013213503245021701 0ustar zmoelnigiemusers/* --------------------------------------------------------------------------- Open Asset Import Library (ASSIMP) --------------------------------------------------------------------------- Copyright (c) 2006-2009, ASSIMP Development Team All rights reserved. Redistribution and use of this software 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 the ASSIMP team, nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission of the ASSIMP Development Team. 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. --------------------------------------------------------------------------- */ /** * Definitions for import post processing steps. */ module assimp.postprocess; extern ( C ) { /** * Defines the flags for all possible post processing steps. * * See: aiImportFile, aiImportFileEx */ enum aiPostProcessSteps { /** * Calculates the tangents and bitangents for the imported meshes. * * Does nothing if a mesh does not have normals. You might want this post * processing step to be executed if you plan to use tangent space * calculations such as normal mapping applied to the meshes. There is a * config setting, AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, * which allows you to specify a maximum smoothing angle for the * algorithm. However, usually you will want to use the default value. */ CalcTangentSpace = 0x1, /** * Identifies and joins identical vertex data sets within all imported * meshes. * * After this step is run each mesh does contain only unique vertices * anymore, so a vertex is possibly used by multiple faces. You usually * want to use this post processing step. If your application deals with * indexed geometry, this step is compulsory or you will just waste * rendering time. If this flag is not specified, no vertices * are referenced by more than one face and no index buffer is * required for rendering. */ JoinIdenticalVertices = 0x2, /** * Converts all the imported data to a left-handed coordinate space. * * By default the data is returned in a right-handed coordinate space * which for example OpenGL prefers. In this space, +X points to the * right, +Z points towards the viewer and and +Y points upwards. In the * DirectX coordinate space +X points to the right, +Y points upwards and * +Z points away from the viewer. * * You will probably want to consider this flag if you use Direct3D for * rendering. The ConvertToLeftHanded flag supersedes this * setting and bundles all conversions typically required for D3D-based * applications. */ MakeLeftHanded = 0x4, /** * Triangulates all faces of all meshes. * * By default the imported mesh data might contain faces with more than 3 * indices. For rendering you'll usually want all faces to be triangles. * This post processing step splits up all higher faces to triangles. * Line and point primitives are not modified!. * * If you want »triangles only« with no other kinds of primitives, * specify both Triangulate and SortByPType and * ignore all point and line meshes when you process Assimp's output. */ Triangulate = 0x8, /** * Removes some parts of the data structure (animations, materials, light * sources, cameras, textures, vertex components). * * The components to be removed are specified in a separate configuration * option, AI_CONFIG_PP_RVC_FLAGS. This is quite useful if * you don't need all parts of the output structure. Especially vertex * colors are rarely used today. * * Calling this step to remove unrequired stuff from the pipeline as * early as possible results in an increased performance and a better * optimized output data structure. * * This step is also useful if you want to force Assimp to recompute * normals or tangents since the corresponding steps don't recompute them * if they have already been loaded from the source asset. * * This flag is a poor one, mainly because its purpose is usually * misunderstood. Consider the following case: a 3d model has been exported * from a CAD app, it has per-face vertex colors. Because of the vertex * colors (which are not even used by most apps), * JoinIdenticalVertices cannot join vertices at the same * position. By using this step, unneeded components are excluded as * early as possible thus opening more room for internal optimzations. */ RemoveComponent = 0x10, /** * Generates normals for all faces of all meshes. * * This is ignored if normals are already there at the time where this * flag is evaluated. Model importers try to load them from the source * file, so they are usually already there. Face normals are shared * between all points of a single face, so a single point can have * multiple normals, which, in other words, enforces the library to * duplicate vertices in some cases. JoinIdenticalVertices * is useless then. * * This flag may not be specified together with * GenSmoothNormals. */ GenNormals = 0x20, /** * Generates smooth normals for all vertices in the mesh. * * This is ignored if normals are already there at the time where this * flag is evaluated. Model importers try to load them from the source file, so * they are usually already there. * * There is a configuration option, * AI_CONFIG_PP_GSN_MAX_SMOOTHING_ANGLE which allows you to * specify an angle maximum for the normal smoothing algorithm. Normals * exceeding this limit are not smoothed, resulting in a »hard« seam * between two faces. Using a decent angle here (e.g. 80°) results in * very good visual appearance. */ GenSmoothNormals = 0x40, /** * Splits large meshes into smaller submeshes. * * This is quite useful for realtime rendering where the number of triangles * which can be maximally processed in a single draw-call is usually limited * by the video driver/hardware. The maximum vertex buffer is usually limited, * too. Both requirements can be met with this step: you may specify both a * triangle and vertex limit for a single mesh. * * The split limits can (and should!) be set through the * AI_CONFIG_PP_SLM_VERTEX_LIMIT and * AI_CONFIG_PP_SLM_TRIANGLE_LIMIT settings. The default * values are AI_SLM_DEFAULT_MAX_VERTICES and * AI_SLM_DEFAULT_MAX_TRIANGLES. * * Note that splitting is generally a time-consuming task, but not if * there's nothing to split. The use of this step is recommended for most * users. */ SplitLargeMeshes = 0x80, /** * Removes the node graph and pre-transforms all vertices with the local * transformation matrices of their nodes. * * The output scene does still contain nodes, however, there is only a * root node with children, each one referencing only one mesh, each * mesh referencing one material. For rendering, you can simply render * all meshes in order, you don't need to pay attention to local * transformations and the node hierarchy. Animations are removed during * this step. * * This step is intended for applications that have no scenegraph. * * The step can cause some problems: if e.g. a mesh of the asset * contains normals and another, using the same material index, does not, * they will be brought together, but the first meshes's part of the * normal list is zeroed. However, these artifacts are rare. * * Note: The AI_CONFIG_PP_PTV_NORMALIZE configuration * property can be set to normalize the scene's spatial dimension * to the -1...1 range. */ PreTransformVertices = 0x100, /** * Limits the number of bones simultaneously affecting a single vertex to * a maximum value. * * If any vertex is affected by more than that number of bones, the least * important vertex weights are removed and the remaining vertex weights * are renormalized so that the weights still sum up to 1. * * The default bone weight limit is 4 (AI_LMW_MAX_WEIGHTS), * but you can use the #AI_CONFIG_PP_LBW_MAX_WEIGHTS setting * to supply your own limit to the post processing step. * * If you intend to perform the skinning in hardware, this post processing * step might be of interest for you. */ LimitBoneWeights = 0x200, /** * Validates the imported scene data structure. * * This makes sure that all indices are valid, all animations and * bones are linked correctly, all material references are correct, etc. * * It is recommended to capture Assimp's log output if you use this flag, * so you can easily find ot what's actually wrong if a file fails the * validation. The validator is quite rude and will find all * inconsistencies in the data structure. * * Plugin developers are recommended to use it to debug their loaders. * * There are two types of validation failures: *
    *
  • Error: There's something wrong with the imported data. Further * postprocessing is not possible and the data is not usable at all. * The import fails, see aiGetErrorString() for the * error message.
  • *
  • Warning: There are some minor issues (e.g. 1000000 animation * keyframes with the same time), but further postprocessing and use * of the data structure is still safe. Warning details are written * to the log file, AI_SCENE_FLAGS_VALIDATION_WARNING is * set in aiScene::mFlags
  • *
* * This post-processing step is not time-consuming. It's use is not * compulsory, but recommended. */ ValidateDataStructure = 0x400, /** * Reorders triangles for better vertex cache locality. * * The step tries to improve the ACMR (average post-transform vertex cache * miss ratio) for all meshes. The implementation runs in O(n) and is * roughly based on the 'tipsify' algorithm (see * http://www.cs.princeton.edu/gfx/pubs/Sander_2007_%3ETR/tipsy.pdf). * * If you intend to render huge models in hardware, this step might * be of interest for you. The AI_CONFIG_PP_ICL_PTCACHE_SIZE * config setting can be used to fine-tune the cache optimization. */ ImproveCacheLocality = 0x800, /** * Searches for redundant/unreferenced materials and removes them. * * This is especially useful in combination with the * PretransformVertices and OptimizeMeshes * flags. Both join small meshes with equal characteristics, but they * can't do their work if two meshes have different materials. Because * several material settings are always lost during Assimp's import * filters, (and because many exporters don't check for redundant * materials), huge models often have materials which are are defined * several times with exactly the same settings. * * Several material settings not contributing to the final appearance of * a surface are ignored in all comparisons; the material name is one of * them. So, if you are passing additional information through the * content pipeline (probably using »magic« material names), don't * specify this flag. Alternatively take a look at the * AI_CONFIG_PP_RRM_EXCLUDE_LIST setting. */ RemoveRedundantMaterials = 0x1000, /** * This step tries to determine which meshes have normal vectors that are * acing inwards. * * The algorithm is simple but effective: The bounding box of all * vertices and their normals is compared against the volume of the * bounding box of all vertices without their normals. This works well * for most objects, problems might occur with planar surfaces. However, * the step tries to filter such cases. * * The step inverts all in-facing normals. Generally it is recommended to * enable this step, although the result is not always correct. */ FixInfacingNormals = 0x2000, /** * This step splits meshes with more than one primitive type in * homogeneous submeshes. * * The step is executed after the triangulation step. After the step * returns, just one bit is set in aiMesh.mPrimitiveTypes. * This is especially useful for real-time rendering where point and line * primitives are often ignored or rendered separately. * * You can use the AI_CONFIG_PP_SBP_REMOVE option to * specify which primitive types you need. This can be used to easily * exclude lines and points, which are rarely used, from the import. */ SortByPType = 0x8000, /** * This step searches all meshes for degenerated primitives and converts * them to proper lines or points. * * A face is »degenerated« if one or more of its points are identical. * To have the degenerated stuff not only detected and collapsed but also * removed, try one of the following procedures: * * 1. (if you support lines and points for rendering but don't * want the degenerates) *
    *
  • Specify the FindDegenerates flag.
  • *
  • Set the AI_CONFIG_PP_FD_REMOVE option to 1. This will * cause the step to remove degenerated triangles from the import * as soon as they're detected. They won't pass any further * pipeline steps.
  • *
* * 2.(if you don't support lines and points at all ...) *
    *
  • Specify the FindDegenerates flag.
  • *
  • Specify the SortByPType flag. This moves line and * point primitives to separate meshes.
  • *
  • Set the AI_CONFIG_PP_SBP_REMOVE option to * aiPrimitiveType_POINTS | aiPrimitiveType_LINES * to cause SortByPType to reject point and line meshes from the * scene.
  • *
* * Note: Degenerated polygons are not necessarily bad and that's why * they're not removed by default. There are several file formats * which don't support lines or points. Some exporters bypass the * format specification and write them as degenerated triangle * instead. */ FindDegenerates = 0x10000, /** * This step searches all meshes for invalid data, such as zeroed normal * vectors or invalid UV coords and removes/fixes them. This is intended * to get rid of some common exporter errors. * * This is especially useful for normals. If they are invalid, and the * step recognizes this, they will be removed and can later be * recomputed, e.g. by the GenSmoothNormals step. * * The step will also remove meshes that are infinitely small and reduce * animation tracks consisting of hundreds if redundant keys to a single * key. The AI_CONFIG_PP_FID_ANIM_ACCURACY config property * decides the accuracy of the check for duplicate animation tracks. */ FindInvalidData = 0x20000, /** * This step converts non-UV mappings (such as spherical or cylindrical * mapping) to proper texture coordinate channels. * * Most applications will support UV mapping only, so you will probably * want to specify this step in every case. Note tha Assimp is not always * able to match the original mapping implementation of the 3d app which * produced a model perfectly. It's always better to let the father app * compute the UV channels, at least 3ds max, maja, blender, lightwave, * modo, ... are able to achieve this. * * Note: If this step is not requested, you'll need to process the * AI_MATKEY_MAPPING material property in order to * display all assets properly. */ GenUVCoords = 0x40000, /** * This step applies per-texture UV transformations and bakes them to * stand-alone vtexture coordinate channelss. * * UV transformations are specified per-texture – see the * AI_MATKEY_UVTRANSFORM material key for more information. * This step processes all textures with transformed input UV coordinates * and generates new (pretransformed) UV channel which replace the old * channel. Most applications won't support UV transformations, so you * will probably want to specify this step. * * Note: UV transformations are usually implemented in realtime apps by * transforming texture coordinates at vertex shader stage with a 3x3 * (homogenous) transformation matrix. */ TransformUVCoords = 0x80000, /** * This step searches for duplicate meshes and replaces duplicates with * references to the first mesh. * * This step takes a while, don't use it if you have no time. Its main * purpose is to workaround the limitation that many export file formats * don't support instanced meshes, so exporters need to duplicate meshes. * This step removes the duplicates again. Please note that Assimp does * currently not support per-node material assignment to meshes, which * means that identical meshes with differnent materials are currently * not joined, although this is planned for future versions. */ FindInstances = 0x100000, /** * A postprocessing step to reduce the number of meshes. * * In fact, it will reduce the number of drawcalls. * * This is a very effective optimization and is recommended to be used * together with OptimizeGraph, if possible. The flag is * fully compatible with both SplitLargeMeshes and * SortByPType. */ OptimizeMeshes = 0x200000, /** * A postprocessing step to optimize the scene hierarchy. * * Nodes with no animations, bones, lights or cameras assigned are * collapsed and joined. * * Node names can be lost during this step. If you use special tag nodes * to pass additional information through your content pipeline, use the * AI_CONFIG_PP_OG_EXCLUDE_LIST setting to specify a list of * node names you want to be kept. Nodes matching one of the names in * this list won't be touched or modified. * * Use this flag with caution. Most simple files will be collapsed to a * single node, complex hierarchies are usually completely lost. That's * note the right choice for editor environments, but probably a very * effective optimization if you just want to get the model data, convert * it to your own format and render it as fast as possible. * * This flag is designed to be used with OptimizeMeshes for * best results. * * Note: »Crappy« scenes with thousands of extremely small meshes packed * in deeply nested nodes exist for almost all file formats. * OptimizeMeshes in combination with * OptimizeGraph usually fixes them all and makes them * renderable. */ OptimizeGraph = 0x400000, /** This step flips all UV coordinates along the y-axis and adjusts * material settings and bitangents accordingly. * * Output UV coordinate system: *
 0y|0y ---------- 1x|0y
       * |                 |
       * |                 |
       * |                 |
       * 0x|1y ---------- 1x|1y
* You'll probably want to consider this flag if you use Direct3D for * rendering. The AI_PROCESS_CONVERT_TO_LEFT_HANDED flag * supersedes this setting and bundles all conversions typically required * for D3D-based applications. */ FlipUVs = 0x800000, /** * This step adjusts the output face winding order to be clockwise. * * The default face winding order is counter clockwise. * * Output face order: *
       x2
       *
       *                         x0
       *  x1
*/ FlipWindingOrder = 0x1000000 } /** * Abbrevation for convenience. */ alias aiPostProcessSteps aiProcess; /** * Shortcut flag for Direct3D-based applications. * * Combines the MakeLeftHanded, FlipUVs and * FlipWindingOrder flags. The output data matches Direct3D's * conventions: left-handed geometry, upper-left origin for UV coordinates * and clockwise face order, suitable for CCW culling. */ const aiPostProcessSteps AI_PROCESS_CONVERT_TO_LEFT_HANDED = aiProcess.MakeLeftHanded | aiProcess.FlipUVs | aiProcess.FlipWindingOrder; /** * Default postprocess configuration optimizing the data for real-time rendering. * * Applications would want to use this preset to load models on end-user * PCs, maybe for direct use in game. * * If you're using DirectX, don't forget to combine this value with * the ConvertToLeftHanded step. If you don't support UV * transformations in your application, apply the * TransformUVCoords step, too. * * Note: Please take the time to read the doc for the steps enabled by this * preset. Some of them offer further configurable properties, some of * them might not be of use for you so it might be better to not specify * them. */ const aiPostProcessSteps AI_PROCESS_PRESET_TARGET_REALTIME_FAST = aiProcess.CalcTangentSpace | aiProcess.GenNormals | aiProcess.JoinIdenticalVertices | aiProcess.Triangulate | aiProcess.GenUVCoords | aiProcess.SortByPType; /** * Default postprocess configuration optimizing the data for real-time * rendering. * * Unlike AI_PROCESS_PRESET_TARGET_REALTIME_FAST, this * configuration performs some extra optimizations to improve rendering * speed and to minimize memory usage. It could be a good choice for a * level editor environment where import speed is not so important. * * If you're using DirectX, don't forget to combine this value with * the ConvertToLeftHanded step. If you don't support UV * transformations in your application, apply the * TransformUVCoords step, too. * * Note: Please take the time to read the doc for the steps enabled by this * preset. Some of them offer further configurable properties, some of * them might not be of use for you so it might be better to not specify * them. */ const aiPostProcessSteps AI_PROCESS_PRESET_TARGET_REALTIME_QUALITY = aiProcess.CalcTangentSpace | aiProcess.GenSmoothNormals | aiProcess.JoinIdenticalVertices | aiProcess.ImproveCacheLocality | aiProcess.LimitBoneWeights | aiProcess.RemoveRedundantMaterials | aiProcess.SplitLargeMeshes | aiProcess.Triangulate | aiProcess.GenUVCoords | aiProcess.SortByPType | aiProcess.FindDegenerates | aiProcess.FindInvalidData; /** * Default postprocess configuration optimizing the data for real-time * rendering. * * This preset enables almost every optimization step to achieve perfectly * optimized data. It's your choice for level editor environments where * import speed is not important. * * If you're using DirectX, don't forget to combine this value with * the ConvertToLeftHanded step. If you don't support UV * transformations in your application, apply the * TransformUVCoords step, too. * * Note: Please take the time to read the doc for the steps enabled by this * preset. Some of them offer further configurable properties, some of * them might not be of use for you so it might be better to not specify * them. */ const aiPostProcessSteps AI_PROCESS_PRESET_TARGET_REALTIME_MAX_QUALITY = AI_PROCESS_PRESET_TARGET_REALTIME_QUALITY | aiProcess.FindInstances | aiProcess.ValidateDataStructure | aiProcess.OptimizeMeshes; } assimp-4.1.0/port/swig/0000755002537200234200000000000013213503245015211 5ustar zmoelnigiemusersassimp-4.1.0/port/swig/assimp.i0000644002537200234200000001033113213503245016655 0ustar zmoelnigiemusers%module assimp // SWIG helpers for std::string and std::vector wrapping. %include %include // Globally enable enum prefix stripping. %dstripprefix; // PACK_STRUCT is a no-op for SWIG – it does not matter for the generated // bindings how the underlying C++ code manages its memory. #define PACK_STRUCT // Helper macros for wrapping the pointer-and-length arrays used in the // Assimp API. %define ASSIMP_ARRAY(CLASS, TYPE, NAME, LENGTH) %newobject CLASS::NAME; %extend CLASS { std::vector *NAME() const { std::vector *result = new std::vector; result->reserve(LENGTH); for (unsigned int i = 0; i < LENGTH; ++i) { result->push_back($self->NAME[i]); } return result; } } %ignore CLASS::NAME; %enddef %define ASSIMP_POINTER_ARRAY(CLASS, TYPE, NAME, LENGTH) %newobject CLASS::NAME; %extend CLASS { std::vector *NAME() const { std::vector *result = new std::vector; result->reserve(LENGTH); TYPE *currentValue = $self->NAME; TYPE *valueLimit = $self->NAME + LENGTH; while (currentValue < valueLimit) { result->push_back(currentValue); ++currentValue; } return result; } } %ignore CLASS::NAME; %enddef %define ASSIMP_POINTER_ARRAY_ARRAY(CLASS, TYPE, NAME, OUTER_LENGTH, INNER_LENGTH) %newobject CLASS::NAME; %extend CLASS { std::vector > *NAME() const { std::vector > *result = new std::vector >; result->reserve(OUTER_LENGTH); for (unsigned int i = 0; i < OUTER_LENGTH; ++i) { std::vector currentElements; if ($self->NAME[i] != 0) { currentElements.reserve(INNER_LENGTH); TYPE *currentValue = $self->NAME[i]; TYPE *valueLimit = $self->NAME[i] + INNER_LENGTH; while (currentValue < valueLimit) { currentElements.push_back(currentValue); ++currentValue; } } result->push_back(currentElements); } return result; } } %ignore CLASS::NAME; %enddef %include "interface/aiDefines.i" %include "interface/aiTypes.i" %include "interface/assimp.i" %include "interface/aiTexture.i" %include "interface/aiMatrix4x4.i" %include "interface/aiMatrix3x3.i" %include "interface/aiVector3D.i" %include "interface/aiVector2D.i" %include "interface/aiColor4D.i" %include "interface/aiLight.i" %include "interface/aiCamera.i" %include "interface/aiFileIO.i" %include "interface/aiAssert.i" %include "interface/aiVersion.i" %include "interface/aiAnim.i" %include "interface/aiMaterial.i" %include "interface/aiMesh.i" %include "interface/aiPostProcess.i" %include "interface/aiConfig.i" %include "interface/assimp.i" %include "interface/aiQuaternion.i" %include "interface/aiScene.i" %include "interface/Logger.i" %include "interface/DefaultLogger.i" %include "interface/NullLogger.i" %include "interface/LogStream.i" %include "interface/IOStream.i" %include "interface/IOSystem.i" // We have to "instantiate" the templates used by the ASSSIMP_*_ARRAY macros // here at the end to avoid running into forward reference issues (SWIG would // spit out the helper functions before the header includes for the element // types otherwise). %template(UintVector) std::vector; %template(aiAnimationVector) std::vector; %template(aiAnimMeshVector) std::vector; %template(aiBonesVector) std::vector; %template(aiCameraVector) std::vector; %template(aiColor4DVector) std::vector; %template(aiColor4DVectorVector) std::vector >; %template(aiFaceVector) std::vector; %template(aiLightVector) std::vector; %template(aiMaterialVector) std::vector; %template(aiMaterialPropertyVector) std::vector; %template(aiMeshAnimVector) std::vector; %template(aiMeshVector) std::vector; %template(aiNodeVector) std::vector; %template(aiNodeAnimVector) std::vector; %template(aiTextureVector) std::vector; %template(aiVector3DVector) std::vector; %template(aiVector3DVectorVector) std::vector >; %template(aiVertexWeightVector) std::vector; assimp-4.1.0/port/swig/DONOTUSEYET0000644002537200234200000000030513213503245016754 0ustar zmoelnigiemusersThe interface files are by no means complete yet and only work with the not-yet-released D SWIG backend, although adding support for other languages should not be too much of problem via #ifdefs. assimp-4.1.0/port/swig/d/0000755002537200234200000000000013213503245015434 5ustar zmoelnigiemusersassimp-4.1.0/port/swig/d/generate.sh0000755002537200234200000000020013213503245017555 0ustar zmoelnigiemusers#!/bin/sh rm -rf assimp/ mkdir assimp swig -c++ -d -outcurrentdir -I../../../include -splitproxy -package assimp $@ ../assimp.i assimp-4.1.0/port/swig/d/build.sh0000755002537200234200000000014113213503245017066 0ustar zmoelnigiemusers#!/bin/sh gcc -shared -fPIC -g3 -I../../../include/ -lassimp -olibassimp_wrap.so assimp_wrap.cxx assimp-4.1.0/port/swig/interface/0000755002537200234200000000000013213503245017151 5ustar zmoelnigiemusersassimp-4.1.0/port/swig/interface/aiColor4D.i0000644002537200234200000000006513213503245021104 0ustar zmoelnigiemusers%{ #include "aiColor4D.h" %} %include "aiColor4D.h" assimp-4.1.0/port/swig/interface/assimp.i0000644002537200234200000000253713213503245020626 0ustar zmoelnigiemusers%{ #include "assimp.hpp" %} namespace Assimp { // See docs in assimp.hpp. %ignore Importer::ReadFile(const std::string& pFile, unsigned int pFlags); %ignore Importer::GetExtensionList(std::string& szOut); %ignore Importer::IsExtensionSupported(const std::string& szExtension); // These are only necessary for extending Assimp with custom importers or post // processing steps, which would require wrapping the internal BaseImporter and // BaseProcess classes. %ignore Importer::RegisterLoader(BaseImporter* pImp); %ignore Importer::UnregisterLoader(BaseImporter* pImp); %ignore Importer::RegisterPPStep(BaseProcess* pImp); %ignore Importer::UnregisterPPStep(BaseProcess* pImp); %ignore Importer::FindLoader(const char* szExtension); } // Each aiScene has to keep a reference to the Importer to prevent it from // being garbage collected, whose destructor would release the underlying // C++ memory the scene is stored in. %typemap(dcode) aiScene "package Object m_importer;" %typemap(dout) aiScene* GetScene, aiScene* ReadFile, aiScene* ApplyPostProcessing, aiScene* ReadFileFromMemory { void* cPtr = $wcall; $dclassname ret = (cPtr is null) ? null : new $dclassname(cPtr, $owner);$excode ret.m_importer = this; return ret; } %include %apply bool *OUTPUT { bool *bWasExisting }; %include "assimp.hpp" %clear bool *bWasExisting; assimp-4.1.0/port/swig/interface/aiAnim.i0000644002537200234200000000031013213503245020513 0ustar zmoelnigiemusers%{ #include "aiAnim.h" %} ASSIMP_ARRAY(aiAnimation, aiNodeAnim*, mChannels, $self->mNumChannels); ASSIMP_ARRAY(aiAnimation, aiMeshAnim*, mMeshChannels, $self->mNumMeshChannels); %include "aiAnim.h" assimp-4.1.0/port/swig/interface/aiVector3D.i0000644002537200234200000000006713213503245021271 0ustar zmoelnigiemusers%{ #include "aiVector3D.h" %} %include "aiVector3D.h" assimp-4.1.0/port/swig/interface/aiTexture.i0000644002537200234200000000006513213503245021276 0ustar zmoelnigiemusers%{ #include "aiTexture.h" %} %include "aiTexture.h" assimp-4.1.0/port/swig/interface/aiVersion.i0000644002537200234200000000006513213503245021263 0ustar zmoelnigiemusers%{ #include "aiVersion.h" %} %include "aiVersion.h" assimp-4.1.0/port/swig/interface/aiPostProcess.i0000644002537200234200000000017213213503245022121 0ustar zmoelnigiemusers%{ #include "aiPostProcess.h" %} %feature("d:stripprefix", "aiProcess_") aiPostProcessSteps; %include "aiPostProcess.h" assimp-4.1.0/port/swig/interface/IOSystem.i0000644002537200234200000000061413213503245021040 0ustar zmoelnigiemusers%{ #include "IOSystem.h" %} // The const char* overload is used instead. %ignore Assimp::IOSystem::Exists(const std::string&) const; %ignore Assimp::IOSystem::Open(const std::string& pFile); %ignore Assimp::IOSystem::Open(const std::string& pFile, const std::string& pMode); %ignore Assimp::IOSystem::ComparePaths(const std::string& one, const std::string& second) const; %include "IOSystem.h" assimp-4.1.0/port/swig/interface/aiMatrix3x3.i0000644002537200234200000000007113213503245021435 0ustar zmoelnigiemusers%{ #include "aiMatrix3x3.h" %} %include "aiMatrix3x3.h" assimp-4.1.0/port/swig/interface/Logger.i0000644002537200234200000000005713213503245020544 0ustar zmoelnigiemusers%{ #include "Logger.h" %} %include "Logger.h" assimp-4.1.0/port/swig/interface/aiQuaternion.i0000644002537200234200000000007313213503245021762 0ustar zmoelnigiemusers%{ #include "aiQuaternion.h" %} %include "aiQuaternion.h" assimp-4.1.0/port/swig/interface/aiVector2D.i0000644002537200234200000000006713213503245021270 0ustar zmoelnigiemusers%{ #include "aiVector2D.h" %} %include "aiVector2D.h" assimp-4.1.0/port/swig/interface/aiTypes.i0000644002537200234200000000022213213503245020735 0ustar zmoelnigiemusers%{ #include "aiTypes.h" %} // The const char* overload is used instead. %ignore aiString::Set(const std::string& pString); %include "aiTypes.h" assimp-4.1.0/port/swig/interface/NullLogger.i0000644002537200234200000000006713213503245021400 0ustar zmoelnigiemusers%{ #include "NullLogger.h" %} %include "NullLogger.h" assimp-4.1.0/port/swig/interface/aiConfig.i0000644002537200234200000000006313213503245021041 0ustar zmoelnigiemusers%{ #include "aiConfig.h" %} %include "aiConfig.h" assimp-4.1.0/port/swig/interface/aiLight.i0000644002537200234200000000006113213503245020701 0ustar zmoelnigiemusers%{ #include "aiLight.h" %} %include "aiLight.h" assimp-4.1.0/port/swig/interface/aiDefines.i0000644002537200234200000000006513213503245021213 0ustar zmoelnigiemusers%{ #include "aiDefines.h" %} %include "aiDefines.h" assimp-4.1.0/port/swig/interface/aiScene.i0000644002537200234200000000107713213503245020677 0ustar zmoelnigiemusers%{ #include "aiScene.h" %} ASSIMP_ARRAY(aiScene, aiAnimation*, mAnimations, $self->mNumAnimations); ASSIMP_ARRAY(aiScene, aiCamera*, mCameras, $self->mNumCameras); ASSIMP_ARRAY(aiScene, aiLight*, mLights, $self->mNumLights); ASSIMP_ARRAY(aiScene, aiMaterial*, mMaterials, $self->mNumMaterials); ASSIMP_ARRAY(aiScene, aiMesh*, mMeshes, $self->mNumMeshes); ASSIMP_ARRAY(aiScene, aiTexture*, mTextures, $self->mNumTextures); ASSIMP_ARRAY(aiNode, aiNode*, mChildren, $self->mNumChildren); ASSIMP_ARRAY(aiNode, unsigned int, mMeshes, $self->mNumMeshes); %include "aiScene.h" assimp-4.1.0/port/swig/interface/aiFileIO.i0000644002537200234200000000006313213503245020743 0ustar zmoelnigiemusers%{ #include "aiFileIO.h" %} %include "aiFileIO.h" assimp-4.1.0/port/swig/interface/aiMesh.i0000644002537200234200000000300113213503245020523 0ustar zmoelnigiemusers%{ #include "aiMesh.h" %} ASSIMP_ARRAY(aiFace, unsigned int, mIndices, $self->mNumIndices); ASSIMP_POINTER_ARRAY(aiBone, aiVertexWeight, mWeights, $self->mNumWeights); ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mVertices, $self->mNumVertices); ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mNormals, $self->mNumVertices); ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mTangents, $self->mNumVertices); ASSIMP_POINTER_ARRAY(aiAnimMesh, aiVector3D, mBitangents, $self->mNumVertices); ASSIMP_POINTER_ARRAY_ARRAY(aiAnimMesh, aiVector3D, mTextureCoords, AI_MAX_NUMBER_OF_TEXTURECOORDS, $self->mNumVertices); ASSIMP_POINTER_ARRAY_ARRAY(aiAnimMesh, aiColor4D, mColors, AI_MAX_NUMBER_OF_COLOR_SETS, $self->mNumVertices); ASSIMP_ARRAY(aiMesh, aiAnimMesh*, mAnimMeshes, $self->mNumAnimMeshes); ASSIMP_ARRAY(aiMesh, aiBone*, mBones, $self->mNumBones); ASSIMP_ARRAY(aiMesh, unsigned int, mNumUVComponents, AI_MAX_NUMBER_OF_TEXTURECOORDS); ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mVertices, $self->mNumVertices); ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mNormals, $self->mNumVertices); ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mTangents, $self->mNumVertices); ASSIMP_POINTER_ARRAY(aiMesh, aiVector3D, mBitangents, $self->mNumVertices); ASSIMP_POINTER_ARRAY(aiMesh, aiFace, mFaces, $self->mNumFaces); ASSIMP_POINTER_ARRAY_ARRAY(aiMesh, aiVector3D, mTextureCoords, AI_MAX_NUMBER_OF_TEXTURECOORDS, $self->mNumVertices); ASSIMP_POINTER_ARRAY_ARRAY(aiMesh, aiColor4D, mColors, AI_MAX_NUMBER_OF_COLOR_SETS, $self->mNumVertices); %include "aiMesh.h" assimp-4.1.0/port/swig/interface/aiCamera.i0000644002537200234200000000006313213503245021024 0ustar zmoelnigiemusers%{ #include "aiCamera.h" %} %include "aiCamera.h" assimp-4.1.0/port/swig/interface/DefaultLogger.i0000644002537200234200000000007513213503245022051 0ustar zmoelnigiemusers%{ #include "DefaultLogger.h" %} %include "DefaultLogger.h" assimp-4.1.0/port/swig/interface/aiAssert.i0000644002537200234200000000006313213503245021075 0ustar zmoelnigiemusers%{ #include "aiAssert.h" %} %include "aiAssert.h" assimp-4.1.0/port/swig/interface/IOStream.i0000644002537200234200000000006313213503245021005 0ustar zmoelnigiemusers%{ #include "IOStream.h" %} %include "IOStream.h" assimp-4.1.0/port/swig/interface/aiMatrix4x4.i0000644002537200234200000000007113213503245021437 0ustar zmoelnigiemusers%{ #include "aiMatrix4x4.h" %} %include "aiMatrix4x4.h" assimp-4.1.0/port/swig/interface/LogStream.i0000644002537200234200000000006513213503245021221 0ustar zmoelnigiemusers%{ #include "LogStream.h" %} %include "LogStream.h" assimp-4.1.0/port/swig/interface/aiMaterial.i0000644002537200234200000000161213213503245021373 0ustar zmoelnigiemusers%{ #include "aiMaterial.h" %} ASSIMP_ARRAY(aiMaterial, aiMaterialProperty*, mProperties, $self->mNumProperties) %include %apply enum SWIGTYPE *OUTPUT { aiTextureMapping* mapping }; %apply unsigned int *OUTPUT { unsigned int* uvindex }; %apply float *OUTPUT { float* blend }; %apply enum SWIGTYPE *OUTPUT { aiTextureOp* op }; %apply unsigned int *OUTPUT { unsigned int* flags }; %include "aiMaterial.h" %clear unsigned int* flags; %clear aiTextureOp* op; %clear float *blend; %clear unsigned int* uvindex; %clear aiTextureMapping* mapping; %apply int &OUTPUT { int &pOut }; %apply float &OUTPUT { float &pOut }; %template(GetInteger) aiMaterial::Get; %template(GetFloat) aiMaterial::Get; %template(GetColor4D) aiMaterial::Get; %template(GetColor3D) aiMaterial::Get; %template(GetString) aiMaterial::Get; %clear int &pOut; %clear float &pOut; assimp-4.1.0/port/PyAssimp/0000755002537200234200000000000013213503245016005 5ustar zmoelnigiemusersassimp-4.1.0/port/PyAssimp/3d_viewer_screenshot.png0000644002537200234200000014463213213503245022651 0ustar zmoelnigiemusersPNG  IHDR5؂Z pHYs+tIME "2tEXtCommentCreated with GIMPW IDATxwU{skzIHTn4"(OJfEAE_bylO bEPLB"{w<9aNۙݻ3s|Fgg@`0 ` IA àR3uDqĉ~^nݺu9K===Fޮ5kTՓLf҉4{{{CCC/_3rȶ6zYg˖-BѣG?_@@S.G!믿f)O'L0vXzYr\,egERͿuWW׶mJRSSӸqx !ڵkNK/555M:uڵ===SNmjjZjUKKɓ7n6 cn-477 69bĈ &466ݍ1aܸq[nklli9QkwwW_}0iӦYo===;zhԩSQmCWI4G2000<$} mmmj`BaҤIaeikk+ cƌ3 C rhG>㸗#F7o۶mJ744B^zIV/.R(/ ZwZdqM6ݞidf1 {xxUjRT.eL{R,lٲeLȏox챡AJ%yx?M \.q!BX,iF__=^޾}͛7e5\, ®*E l[\~W7?_eώbn)~&}i7===ivttd>2\&ؼyիo.5jTP(Jݖb](TnP 6lhjj2M0JҦMj=Jn|E׮][*ݑ^ׯ_ǭWN  Ꙗ#.h̘1cǎ-J۶mkjj4i 7Ms۶mOkoo7MUU3f\y榦ɓ'E˻2a„b0443x#Gd#ǽ?Gv nNN O,*]Ra0y `0 ` `0 `0 `0 0 `00 `00 `00 `0 ``0 ` ] `0 `0 `0 0 `00 `00 `00 `0 ``0 ` `0 ` `0 ` `0 `0 `.̝;+o6 e}ȷ@B?Vn Zq$!@9~TuL# @N~rZ-S?+ 0h(`Pa 0y6Im?j%}$`ҫèUb"a @~2[&S_'p`X @BB3 7kj:0y5̳G Ex`YK D` 'd09k;G?Pc(S cc0nR;a%WqAme:ǿSdU[b&KP zwG<[Lk[ r`+qHf>w1#v)pSCX@ }H}#LhKs:.@( ԑ!Ɍ*e48:?$=ʛ@V~J#t#qh1& k9=밫)0./R@m*|2U̵qFQRAL@JFS9𮓌b0B;:?Oa/skӼd RB/R9WVL|'R,)k!&x 6〫Uvo$&-pWbK'U0" jxdHZڒ]aD`qǩ @5.shYQEcȑ_nTO3a5! YWk2:mW lmKѮfΜS ߓi=@p Kɰȧjt\Lc[fvx,%jy;w.)ƒ70jKE'%87̙3Ž j juEM$i;Mg` Ed#]nL1!s3N]XkH?U>*q۷oH&X=DGk+ Yd.m9Bi \djI+a ![+170nI`AXU`?_ ~AwwY"V PS59h&`jލ+6bڦ1QȞOગpTmI^LG՜$ ֜>/Pn;:CDս$@j撺̘9ߑWӪJ%d:hj*z*..S<"TX @fdJt H9Iz/s^#  X<{tQoO8zTT? |m9 9[HaӢ:j޴X 1QΗ%3,UqF2Zc%G5xN`hhHz؀n7oI $22 P^WřgΖ?Q4g:?V䠖O:k*6a%dRTҙr׈ LdJ|UP_8cׯdQo i|z@ 0ڱB@׿^ՆghrY9Mn J:ͮ&' />jZ?)R>0R -%조~ @r9Z :5kVOO|#>pg(8$su򔲳:PX :2I2ay3OEG'`iRQpqvo7a6$@Ygd^b5'N*2X+8)裏<ݘyMYxJvg3xb 2`[54*m6FeT9?ׄ`qޢ5v<*BYygqFP SO='O,2MT*Hj?N;M3 @w5Sg L#wgj"e|~$8$)Uaocj3vٛ_Wn#G+Os$v3XF~@&ju%^6m֭[eI_8sŎFi^r%=BSO=U?OCT+3w]4CѯOajzX/6@tDU -QB;ND7_Gv ؀j-0?i׿e7Jn˧>)!DPp1jy%K~ Tܨ43Wȳۜ~ g-ʜ |b4Ʉ(dVdk& < )@͇rrJoō>rߧPKRT"5›4 r㢋.Zn]CCE_zzO|j>MH! q`IQD7fYDԳ[33KWs/ ͸ }zsEu2z{3cQi)F{N:I!ÄƌSQa@ `bQ yR _X~}X(j=?qW:.!4GNG?PLZdqLNx|[Uvp9*~Ne57&L3gn??1 ?n7CZlYX\ze*7c-u|Q-[V}+̀d{f!9._@oicY]mRV2׹ɩmӢHx`8fF;I.yS 8umܖ[j IDAT>g"'O\2I`*AbyCzV^=N9i#U~m׿u mN@ַ%{zGk!KbXr`nlsfx˃WЬg[%f|?O@;V 5ij;I'0v؊Z? @@ 'se+>1 ndz|իW ! ̟?|bb ֭[-ɒ%],c#5ii]Wci2&O&&WSf&fl^|Eȑ# !e v܁@2$*п '2rx$j8h8Ţ4|h}*3 &5»GG^WraUTN *K0n8:Z6  HIr B x '*'/YX,떩.L-oQrY-/+r7eͷ~%]髯r-_dH~!3b>'}rj O $3T`N,M>)"ଫ~ڌ7#a_8HLKz`1Qܹs АlW^yE˖-{ׅ6` nN*-Rvjժj M7׿U˗G3^2=vb*N6lbJy4>VA7co&տ?> G ('* @ >+o6?a̟?_W7pWmi?h4֭6>Տp1NxE`a-ZCc=Va}588\pj_-v̧4b]Q)礍I?_WF4oz[29UA$hiiQ+B`1@1%<ꨣ`vP퐧d6Q(岽Je |3*Ʒ̝;78K5x49Uo=xz3~ژucoi4 䉒Q-~j ={}_{__xsu!ǘN`ĉk}7/34ޏ .pˎkLßd 0e]իW;sUW]<@`ៅ Z& R uwtt'x"9`yxxyŅ ~-T1$<&<,75Q7A&Wmb2)!k ԃϑz#]WƔ8hĉq=/kY./p3RQ1{b>9J%7n XXՁk֬q{>94F ŋdz˘O~/'Dw޵^+v?HԿ'Ϸ u5זV0 gfBL` A]?rvusFq.b~뮻(ܜ$ !Z[[-8@.80PmߴiSxpG\vkO:gLmsWI[Oj~|rXbE`Ƈ>!!2X_)qy-Z0 =RH P%gNi @J*jհV_ܭNR.U!r}Y=,;vOVq2i^qӦM 3U~E[[N@EUeJgxںukP,ؼysHOBBuEb"U_~=iWg}Ď~:r'*9¶g8^ [ZZh_nW4z|.JAX{;wYDǛvG/\؀'@U9s -[ao/;Z@;/;#GwSƎGa΢~|0 ccUR)Y͙<:9ڮA-Ҝ1s֤lWmK3n8_yh7ZE*N"4i$?Z35_m{Ê8d8\3[nգb?\7zɿHTG˯`v {ﭻg}6V/9ꨣWCxPs$&s 4Hݣkx0tE:h @$s=yn%TvΡ~Jm|K_fp*/awwd4ɓ'Qe_2?@JXyf!4۶mS裏Vive-5nxajpeo{Z>ГN:iҥJ+gp BaѢEV̠Zu 6 h8@")ں4Lx+ܬ&38~`)l~בz4M6>l<~fK]|o߾ݢ*LӼ⋕s=_&"q|}GGw| c@@g϶޾}{ ?S='b̍< 7M{Փ5J=\LB__,U_Ս~ /)twcW ̗E >NgoDؤ:(EQQ;YY^ 9cza\; hkkϟ|_2իՒ&MOѯ3rHc ,CϤUEC=()elN:I{ `^*+=i[a?ILyq SXrٺM$Tt8<]~/XbP䮘bd"$p3S_v:ѣG{Tt %(`z{ޣMuHooVzn۶'pxtG#Ʈ_,7ZZZ>_xd^+#ěҤI%ժ:`]B'RoﰎU{CsY'$!ޞ['Wz|Rg|_Ǐh  0>ϸ{onݺ&9*wWW +#]FnKՠ_xz!aYgOScTRG.I7ɗ/\>>+3rh"GoO.H8#jByHp>V;6.Hb11lyNSsoJg| _pSN.P( %=TIK&!R2eJG(}@yj D~K~z-ɇj@!$ |AXreIkF_vvLoU>[ԧ @&⸞m:RǁӦMe]&~,_|W-R _K9.*]wc̘1.Uy56RΜ9cn:::Μ9S~oIOWk^cʳGfWەב~Uܿ^X4Y4ͦX=@:^{EPnqUaI<@bUuS~RF9/ 7V>]ʁW>9|=Q'Z[[.9* `7NzY*zR?|Ge P`[h.QWO~!#Gy^žx'ִCCPX, .w߰aC@ bU~4q@w %O8J*U=)`)핀ř^,NW$l{d)8묳TlW\qHG-I%BW^7!v6WL<묳(f52gPq`Nj?4 6k]}ΐ^Y#G=6o<8[#\sw6mLm3?wީ*i|,-;\Nlܸ1ؾ?p!rUVЅ_YV3mk0mr;T@Fc姶C7RB ?.O/ Gw0ŋwtty,ZP=~gչ% ( i&L GQM?xw۱QF=#Oї_~nKKaŘa-[_>S̙8 .5ܕW^տÁ_f#W io1)R5 BS!cC2oTm^z0?jԿ]K!WgBK/tpp1ǮehPCCCE,ӛ ӧs=Hk]Z"-wtc~_=ԹCȥBlǘ/RK :ŢB/ZH&g}_kii9S-K,qO=Kۅ=|2G]]]u//pQ@k*nܹsnP/Pˑ{zz,=̞=[p0%Gr~W\7ol={T[?5I: tO:EaI] G穀.'c j5//^,~Ix,R0 wSl^{wcގ}sOꭥEDI>aŊnj`^dP~F[n4Mﵿ/J/Аҗ> v)wJ(us[[[`ѯ*gAK044tGy/E 8ܚvm_ax7j׿Vbl0ƤPѴ8r![G3FxO V UDh:)+kwu>~P'W -DsBjR٥8F(ow]{BaÆ gϮ%@,ϲTIROJQ@>39ڂLY IDATi' uI|FKc UW]U)dJ%mpBٯtPPҿڑ~7WIGPDF;ڀ_7!.vT}6MSz}J-4T8 rCUDX#,˯TJJ @73`m{$nko"΁ 0WoSfu~uYI,^Xr@u믿P(mo(,/YMMVkH<>6l<5V0eϨvvyg1?۷oVJ+W 7 %{%_[[[u/7׏hT*ݯoI$3ox}r&%j0ޒƏ-K}Yc[5kBՎ$JCnPV%qD w&m]ɖ O7QI %R+o%/oB{gd'tҶ6u䯿i?RzP"{Tevyg6?V+W_q!տlig}J1l6ӿ}FEV$We,ue)UW]5z[nE~̙37uV?}4m۶U)_ KܿpۣO_I;*\åJj'P40gQ]M$azj=@}驀br|-P=#w̏=-hjj#t=oy[_ ,[!Ց[,IH}Q409eʔ^?+[ZZd`_^~unbsQ~r)J]$O.\O~mMpPo;444v[n嗿t]۷o8SN9e```jƧԿHTBg?ŋ 4%o(#wGyvT~mejJDahFģҢ[X 4uU*=؇~n3SL:uj$*_z^{mҥL v{9GC5P?Ju|\pPu{ѣGˮ{ PÁ|P"uMy%EUIBoѧ>Pݥ`]NUɁނjp6#glF%TmN%i__wmEih!To, N>d7z~t7z衖}NCzc*@z}$͌Rӟ"_`Ɣ)SdsTпfFb+K/T!ź=]'|X,s13+߲{7Os=Z pr^%?$%jH/pByGBnɏ8Z3τ/!Rʸ 2~%"Qe $%)Ձ3f[nzc_dkk%n0?ꙓN:ɬTJPy0ӟZZZ6* P T@f *U{c B7Qr]_|B[XX,Zt1i$ #<"J:bGME_6l(6lp,2D'-4͎Rer%|衇 E]Р"ěbYPq7Ǚ Y;Tϵ٨dQy.'[$#1˾oY8.գ}l馛 ­O<1TT0o{!%0nmmյin|>.8.rP3\i>Ԥ}ɓ'5.] A3L߾ ݸqׯ_fLӔV֮ȑ#eO*Gਃo !z!Xg?YB1#(1`ʂAT1"8?ڛW.3q7#`9ty\D#b1G?J[b~nB`qBB+eG~fE =]u4e|ꩧWj*!?_R$j*MeX ?|{SA#~tB)SHw4Y` ն[/ 99'G^zɏ4 ej}D3LP?vo%&%\吲]>J׏MHSNzE￿ė?JەSr-BOq*gM(4{18?_X I ˗ۅԩS|23mX:ݯ?9eʔnQ:vI?Z4JyApjcӦMp֯_hĎx6{,2?Y-[=D̕o~S.GQSO~q6W+￀+pkrN'4@j'Ilܾ|3zIWLNԿ][z2֨'·'z7n|\>яV*`? cPKKWZeB:KW];eͮH `ty hmp7 C={/X@|?C+@ 6md7H` ̀8R^\.o޼Yd5 x޼yr@Fzꩪԗ\ɼ4qVol@0?04H%#ww1 çw <ψ=ʷ<#FaUAO~yk 9-%Tkц;ߩ_Wbqw.;gv }M髢J{$\H  _6by"k===?s=X,9M= &T)Y[GF5=9j'i154FuTCғXSO=U+鯿LJs=/ 7xc9{S?(vDFu]w0~_xG]wՏJ5ʿtR>=u rwr[۟- Pˬ>z}wɅRoܸ\.,-]T rc4j宻JR DӤd 7qkS[Z>gv( c~e[oX>W3;kΜ9Q-[CnK ſTAhy') ${~ouo9_uD/#袋6nܸxZbR8 38NĪ~FgggCYI!4UbDV_z{c*}w~!0xGSOw wUCї]vQ]F:NH&ExM0gOE6WyZ_nllt|ל9sa o[,ki5JI|?z^LzGr#[VngeUX h/bwK `Rz9ޗ 3|$ub1ٝI^R;|wwe߮u;vXGYWy睿zq8NX̙3=E˷[)US|t, ~N;'槢x,33x`žO* ֮]+G%"ޜ9GԩS_{gy/ Uʲ{=ܓ*)ɱZjPDE3o @ᛳ χ<(07'z~R[#ǍX'cn{ P >X S_XdG>}@~)DC~Dط'NVӧOI}h4<*཈q*`ԨQ O>[o-oYreTs=k/hJML}[B{kbI^m%W{tw1% KKcc]wp i2Ʊa䝌NYfX4~=T޼yM&?ӟ>BG'poSS{챇]?Wwe7V-^xɓ'W_ffX \ YvѣUhe+[r裏IpKxy͍ڞDs* -|] Zw}ըRQ2B?Cy睅BOMr;c)"$^H71|r]a8儀.COxtI=G֣wq|,~+_Q/ P %EK \rݺu^{6m]%#)~E]dN;_;̾o`7b"&dx']GVbiXdItp)IL=U]-cխz밾]D.;!3gδKuR*٥/^Od,}{IiG$KyFQA9`'|bZ4sO*oͺrJ!ĺuz{{?xۮj￿_7A 3o>QGUT6~5Q :~ ]&2Eu=Zo #cR1hSSiK,_w޼yrk_\>XT>1YFBOo/u|_ݱo}[8h+n\G]GSKΟ}G&S IFAW.UR1 I8MP2Eۏ$ǒ7rl'Rɘ˨$ZH VLӑ3p*E7)ҥKe'dʼn'Jev饗=av` ?.v,t,##{_Z|!r7[mo{ /U"͍68Dtuu쳏|rxx8ȟw]iJ%Y'T*Jm۶Iu{߭9sY|yobIi YMԧɓ0QUס%fQ~} pJ.ZȻFOθ*߾l.7ŎBe˖a?GuOKZb|5k_|GyW^yE'#Fx>MӔUiu=馛ԿϘ1#Ioy`?ZkkۗbjI_.wi;쳏WTz[[[vss+ }rxM<|;QRG^d o31M2, d2wrqCg+&ƤI<_x2ngTRJ!GH %_=VҿmŊjj=ϻXВ^nˡߞb"X}я}cJ;7a2GS,g@n(`1}{oF8ͷTp{ &Nh톌g<2g+wIF].+.B\.G>%㗿z({HaMd?b/eԼ3bM]{H#?|֏ a3bm_!/_oܸqڴiPoTzr;{KRLTi8Mq7ZDE$md7~7h4eh)S}B~zŊu /Ի"-4-_ha?ƍS/i,@w'Pr+_/~ 0Tԍi5J>?|O?j*H=nA~w| JɓMkUM|CC,tHo]'OV@>j^؃>{N MfVm3C2)&b7}jY /T0n"f]v]wg!~i9_'˦_ZzLohhpץB**3ej۶]|t_w}x󒀡!P@-cOk ̚5K/={_/ ~]K+e?^W,?3g !{Ri="smmmR1n8:|!ĉ>#=~_T _ȄHBj@3 r )QLD<#3z^0<o<+~;/{x!xXT%DJ0O;4 (JJ%հ|n  y+W9R5k|Oh!Ĵi<}CI&IO @ttnVޚfUD+r&JI#KntcՆa;a>wݜx!b,{H4jEK;z9G K,B6nܨdڵk:,}Qnv*(ezi痾766:;^XԿ`瞲8bƌW_}uS]/qv9*`j|O 0)ss_56>LTb_|Qwg}bߌK{?_eϡ)~ꩧZl\(|>ҥKtqF.ej!=PK9s,ZH>|;l;+b '~'SW4ͥKmYḯ3f Vaƌ . |Yrvƍ'O,z:kEkuLI@o(-U$++ޗGYUe[(bl !nETY(dRmV[k(;fJV:vgX;ݚ֕2DDi@D*p}w?XEQw}sN4$;>c ??;<6y8,=ܚ>G5,R ' $Y?~Ox.Zr,0r@*̍F]w|5-@wDd`ҥ .H|]GK@zR466߿_Q^z@v]Ao߾cg!c (O+hwqGV^$)56m'N)W_}utOD~)?~z7E?ewCDW\)/  D4c uqS~}=[n9Htѫ^/njp$>*۱c ] ~._[J/R?sʷRxA⭣,P/ c_>(o~ǗIb P6aVF `!%k 8v⸶]ĝޠMГ/b` gs8Nc"kyS:[nvA|JO^ZlX5?3޴iӵ^+w:o߾o=pm< P477Iw^\_~_&=u7e쒽1`Ru 1FoNEuMv8I_PN[+5'lODR@J,ӦMh۶m,FY9gz#Xf=Oɓ'<Cȋ*.,o{꥾?ˀ?_Y/Ex/;U3aÆxބ(KRx@ʫFR,L ;vlrL/ >~/ g!ԟRN8r" [nmll(ʧ13?(Iu G- / S/mmmFpW$KU7޽Ci.uёU>\J";slƕm`~.ZG`˽KX,=Ϳѓy8sb^M[/=S(ޔO&壼qٿ+{@GY~1a6mb ?|"zjU4J!CO9qD"pW?*Xх(yӗ,xcܸqikaccc:cn޼~I%Nӂctr+sy;sK4@",c_ ܹR.r4ϟȴƐ|(ʉ'T#N*н{wY뺫WggU%KYg??߿Կǎ෮]]cLVB! $6_'PTg[#~KP%Qy;ͦUܒJ#V=#F޽WXގm?%L[awU䱐rRi&뺼8Η_~)z) sp_ꯢe>9y$=?P''#=Ƥ-vk׮\r%5gMb&F T_qi|ge φvplVwM;PX\r__ΝcǏ'W_}uW 吏2_V=&Z85˾VP !@}ذa$yz饗4nӮ*o~km۶-[0Q#7F Ujpl 8PH !&Mڻw/+Cn;C{4 *e8'ˆ8K:8̍Df=ɑ y$$:oo)?Cիw,m ku> SY S) h']~_;lٲk׮_~SM#Aeo.]HJwe{b;vD4R;_=Xh5K{2եsu+I3Sz3Ff{.5~ݻY}ٮ1̙3G FO~V ]eXG_~%CnR߻wo(y-tvve=z$ė}-uÇH\L:`߾}roX+D7q|ɗ8$iӦ(H \\Tx4}!ދXKΫv،(y5yR,/_Ǚ :u].3a z m!_<>\n>|p"z'MU'Oছnh>}͸ ͟?Ï)Zgg'c/#*DtvvrC?%eɓ={GD~RW^ Nb4hP<P H02ޫt@"KVSXU^ b;g&jCeB֧O:z8E}zrUgMM͉'mW]u,8{UaPUB~?Oյy3Blԩ2 ѱ5cS??ʷrlƍD#֣G'N[DСCv)q {e^U)N % R | TQ?Aid" nJƦGp]R[p!p? "v$hڴi~}Y]`߼W\oҲbŊ'voȭ5k_<O-@\p ,0e:DDnL;dyS=:MMMZ y5Þ \RQ*b )'B/_@d K[n?~|˘O_SC\/#x3fx>|/#͕Yu/~+޶m&wҧOy^Ha:%oRWkLG\`a""ki(.%Du6lؐM%Ջ+h*… ǍG]q'ɓ'98,lΞ=0x3qDqXyP2e+]t+z *{dI O?/CM #G~_SˁdDB#de~ׯ?N<,e'⡵M/!Džy$R=](\}s$ٕrT82wKP*Pzb KuYf=hwu?Sz:_+q׮]J?)&*qO12@q Xlv+v-dkY*yK.Dw;ª(0q Pʫǒ5u pQQ\o\7X\;XR \Yx ڵ-_Kc3y4UCn  r,am~7B 0Gd{+"3gvvv_w!:sO9sfc;7N/@?p@|;QHDhѢRꬳ""nz\| D6Z={Ҁ1l5 J6eÁiJXSA[PǏi5"2)ommVmոTP.әG! ' 4(-)TEB`'˫@%XrOݺɪ*=8@*QhH5w\O?ޯ//.Of,a+ }'L@?=8NJukEcr87Pk&bbVďJ@nl"ʨ(_R+-bqܹtfOu=8;Ccƌi4,L0#bq U#(Ǐ?uDŽ q]w͚5R:ry*˞k*R06 &(D|{ۣδj3gz s?[qo /T {exܕLVD.gX;Ya[Z EvJREk].>yU.5#5UW0GqyuNu?=WU!ɍO4NC(Ɇ#-,`tT MPU dypVm PJ FLc=)ϛ7 Uv/k׮3 BDӧO͡r_BJc1n8zgСB "p< 裏b?Lyկ~UޫJٿFS\Evk+֙B^6:thU2X۰e6G4Z(PH KdFacc͛W{_&gk׮X4d?ccET?~˷Cdю#yj0Ii"4e3祸 eM^H &9vx`[oر#Ea!IPSe_,2KJn@@{rAQ\ j$,C{\Vd |[,gϞMgmѱc~_ю;.:nT}{%0[K Hfg} )5:gC/93l0y۷?6y?:ތmW*TȈ RxJx.,Zx,뮻CJm9 ꇜjKr﯈f@|bCL9U-&CS-p$nb߿`7@=tП'07'RM!m~aB]%Z/֭[2cnE(]~f?~xUɖb'-qO u'ܹS<>y'ztgmXDb gꝌH .QILZXܶm?=-OO\]~8G&jiG.Jj'׊'Ut Re lH$L1sTTNU)"R3R$N~9CR9?zjn߾{8ԩS%\¼ܸqt݅=裦*ٕGѐ!C\׽=b`[jjjx }ZW_O L%H0p\4':<̫[0euqd…2!8NW礠(=<5~'Mg*?Pfsm!Lyš@^Y% C?}Z\,__k]vu7|3y;؜9s<$s%"pƍ׾&sEFPEċSYgRcǎ%1cݵkWMM͆ l&)F].?L/@~x bq?3WW9nKH/^U:[nD$?1/+xKK nh.mYF ً( ^v@1W\T qOv͚5D~"7o^`ϴiӌdt]ҷm y5k޽guV`KաCė,ڵ?ږsykHj]/@H^ FT}'ɒ%K<\|f666~2w]0Vgp#gD¿UJxh);x s  J eY QT5T?ɓ?A:D<%SR?Bё^ÀH/ jPy 462QgD{_׶{n"[oUfc践(/;\KL5j#V4p&>Hz;]vDvhPtKJ |*V @7M~fuуN8j*"[6m566:ӣG)SD=5>4S 3W@ӧO'SV ӨƈjJ,F}Qj *$41yJ!{;<쟈f͚ed/kÇå^<0|U3yȐ W6piŒ:@u(E?jϞ=6`?nM붴۷ѣŗ`?|РAW)? zWX7B_VA(H?T>{ij\h۳gO"jkk[r%^jϞ=+VsLug!巾^cƌH8a 3f@L:6 WiCȝݙ#v4@@Ow}.]_MEOXzdϋxm߾}رryy>쬩.Lr84hivhXBbgL ^i%F'XTNk?m6~b(ؿ]y޽{c\NA?v t!4 (,2%gno_{8Ή'o"7s/;oY՘1cė(Wo GM0|;yGP9֔!pǒؙ Q($yiE!qs֯_uS/={ٳ|rMb!۶m8sPOB6B:J5ۧPRGh^zԴ$ ۼysIO`X2?q3>ݕ5 D$ N*uu-[_":yx޳gB0h~.HӧU|,Y[ZZ@UQF}TJlf ~k5;1<&߳лwoqo+X'L)˞ݻ^{TX6ֳgǏ͸ Q([,߰#V>뮻3M|ޥhю'5hyO…^8΄ }]gЎ+ )s@67 lذpi =׮]+ .{ .+Wܽ{7JD d9E]Dgޔ̒%ӯk̔ o֭D4p@1/ܳADA@ NI^&`hj"Z|,˺:rѢEDbŊ={\R_eF.bϟf,oY^hI<|"gE!䛀'3` F G)A )|B]mllTgR~/ga# *2@y!"G2EzF(+ Ge@#i~ Nefn&ShQg>Q' /q]W XQzIvb' ,x &̂1c0RI,E+d<O5Zq?[,`kKEsjA ?Eܩ'ֈ DeX&_ VTv9;C|(uuuZ??wG |ׯpرc xQxk>}cǎym.]BbԨ`D,pC sy.Q`'x'lٲrJ[__w1Tz쟤>AY`y^&-Xرc-H/*axmZ&O %g4@^-R!_'򿵼_رc=1!;t"Ai10qD0"0Y6T"DrJY %`~D_ߟJ"Ղf&эhfRk1@P"Ef `=S,;*:"28pV*E[U+l:8c?8<oP CO w@:&mk`*+46[; n6!jܸqB) y?gFOO޽'N[TPq^n6SV!.R{@\?YF<7tSMM믿.4@}}=ؿ.Jt3?+Ǐ(Nf ӧO?z\- SeƠ2 ǙAkB (2Whф D _={6544Q{{{ss3x5xɛXH*]vu'^6}&,BhT3@ ح*Y*?|T7|ƿ8cƌ7 ?wl S,%z5cƌVWݺuF8{G5lX 4`{Y$ (=JVLnrȜIV,ȿ `64 3AhNc@K 2q/wEO8V\ٿL.gޙnjT9zh޽S ;&ȌAÂwEh O Y$"㏯ ?g:[9F&AoPg#ySn޼9S6*}}&0WVg IDAT&=|o?qDBҵ㴷/Y$^18}py_^ziJ?٤~9"'Otf̙3[[[eћ` 4f!5U.D0yW^yCfD?*!9n?_-&wG .˶yݪ;zM,\ dcVDXHV^-sI&Pcc#͟??bP bœK/Tz'yYt=-Hh0@4PV0!@)٩S E(X<_e]o`:lhhȖjcT / *oEl 9 Tf5S:s/}}A15Y2pA4_!V4CZe2+6m' 0yBjg\DԨQ=?&L{vA$O _\ϳiRϠfʪ fJF^ A WCS|8`.c V ֺ{++0Ԝ?'k@0u:4l<߲VYm}YJU4l2?'ǏQ=&yE֮5=)ؿjaxωmyUWWwRPW<@q"2>etU*X>X|HB^4FeE)_wuB\VқA'a%n1rb b?4@@ &0a0o޼n "VN\?맅HdaZa[2l4RV`WK nFu]AhܹLacKB#, ~7Db؉"g}Bll#96+  ,=o>*~ X2K(x_)՞y9UY)Z0&]hg'r[e;/bu=?AoCxs%+Rj-Ϟ=Ss "#!8f  F|>??qoj"H}k_OO4?QfgXNmY̞=;aK Vci/dYdO׮]h߾}2gV'$AK~{ʏV 1j;P@3:~FGOTf=~/]u/b޼yccH^tk=m+â #=zT-3X &a,Tep (v~7/ Z_AO:f(9~d}a;x¶L^aC1 (umX22cƌٷoVEؿ9r\3ES+d!r<7uS iaIE!ӔSV2(=k@Пb=,.^?8644urԩSYTYBQDy Z288vsBfLI9Ά @ X, ,Oj7 RL"mm5\ׯ70<#(  @TC;_Dr%P͌Ynx'zS{+eZ=5xz48N@ٖvoHLS'pՉ` p4 RG?M1,I͌\2:-ؿʄRÇCMM͌3hݺuOۺLo~  UP? %4p4z1zsJ {f8#Θ1% "ӧOׯ߽k?ԟi3[ $;BNpZIR aÆCMM̙3r6 8p@ Z5?@eH%x.-&CXDS]ם>}:fY& =8,H_ Lv֗܇܆(xQn< &*_֭C蕍Z8Q>}<,X_` .;ݎ $$AEy F lRCìY6mڄkGG@no|PI}]YI Ow$$;!Ȱhy-Y__ĩ\s]w݅(.J/d "ADv §{A3 @B"Aȟ`SmTR %K;?8qb|?DDwc/S5 tHF @6zLb555Ѹq?ܹs= fxݓHDfLj1u0lbyLٺvZWWGDk׮E,td!t-Zh;?#dH2AE ahYnݺdx"jkkc_WWF0G4M1i Cn-O2%Kx ?ihhh .߀Ba 4K`/_B ȱvz2O߼iݫW/u!CԩS rxe q4fgqCџ+h7i~& 7ܰ~UrhC `҄фHqT@3 K oD+6yݻ#.>BN!07oe0f^z_|s$wǂR+;IŋƬ =E^UD](8Z%Jux}Q &x("14%PmDԳgO~^/ \ L 44=I`(}_ ^xꩧcH?J@;`ECAammmD$?Ve;Pyfɓ'uFq7)FRBb #ޏE3G?Gߘ\ٓy?/- L ^0rgV`B3tB(c^kXK@.]뺃Јށ[cfǀ2e)Nd c p­[Q,]?nEF VVn)^([nmjjP})()3h K5&B@̋%N<GH0_K鿭??.2_k`$rg8 ĉb@88T xVc>4HGРr/*dODuuu6BBVI{$xDw^駟F,Lv dLߘCIDY˜9s˾}C=hjP 8Ƴ0a;Q_&a#ϱ @[Ha Y@X]p  E#`Eo+V-[+nܸLЋ(-l ʨ ,_}}}#fã "ڳgAXC`z1EP\R@ta-z U֭[7Eq`g`\8PQhZޏ,cFLDHBU+g}u8@BA(t@|Hx "$Jd=Pߵ˗C(An㋉>ޏc<<'Luo` 2N0lB`sT^h e!"k*HB"[V;tPe%"m@La̞@Lr`jɝe+OX=3Pȵd?A603(1HYyk׮$-Xv T`@hf 97\q(Lwȁ0b\}0,$`V2r@g=HX0-6bDٞA`*M G+W- 6`Q9pDZe֭B+rݻw"pb0 ^삤-ߋ5A$"6'Z*bDD[nҥZ~ߎ1bڵ Z0CK`@[8=/Ѭ=ȞyWv)8r hYږ ޏel"655cT@ ڞTE09D~IOteĈLes=!`{B`~ HU0d|^ `F؎;jkk k.xlmO"cWf9̎20+UÆ #iӦax^h\pۃg:5p8^| eQx`PXdLοCRĴ ӧOѴiz-xKDeRq QX@dŘɋ555ov'X~UMwM[X-s&s= 0݈['WĄLp9yVL͍:QܱY9H SmKS X|"ZHm!l B2RXnHRmH ^>#xWBp0٠#8uB`xԂiS V^MD},L%:U(«az.V̰{0'qCYtHq`Ka(#sfr8[ouݩPx_ţ`I=PFnbsw'k=\ }@@d ;v ½yX &3ީƐ0h'5kDa ^6e-RP@DFÌ ZukJAj#) kBtB[N) XAJ)6`c:2K@.]nv]6P0<=i0$Hs''vmD}^xAIp +{` d*@_۴ cJ"79L7BX"za9*U)޺x?j* W4+_P @zcBE &~IB@n{+=(չ@7 G!N hK'rD6 x94 8 YK. XTq 0~m!p 4' bӧ +@H0).VvR`@M~ B gH&}}c%b~  P\ٓ\%ŋQ=2 @[R0bhB+f jii|xĉTS k iL_0h8Lg V8^ r7i*>|0U $>~1S1 l'P0M -@~ll0&H<(뀴4 +V~  HWOID`+IH;@0$ %K$+*&WX Q6~"X8@ggC=$ <"b eF A1 SNXRfVFa0k1ޏ-^/P!R`*`ERI L^@c P "d4@i `%(~ ahll-@?"l iQX0C0x26. 6!., i_4 +,J(Ů@0#4RfI`{@PaoPoRK`MVI0P @X@ gFAx *iޯr7[6#YWKaRKwL0L fDv߿?xtэD >0D`ZCCB`)`zHyE_~D4q(0ʲ;?x&rHM`xDD}7xC aB`L"]<6_"oB`o;LRV1 0L?x[n%@;::= R x?f PNəZ[[XC,XJSpb@Ac0>1c&!\ם={6Y ZaF wC|*Mi  @`kB.F)z3c?@PP:PJ3 f `2F˕ٰa<}#-fS 8.#r,IhdV(!0+C6$(2?cLmyfr `V;,1%Cu-r̊D &C FG K5 #Ô0$c d@69`0>J^@څ6@h  DHj@LI  o#m!S*}` NƘÀ A0`V1%r " V1ԙi0< 0?K+E&,KV=GZ$ @zi" X@,Y8iBp 7"e?ZO>H`oA8ņ2r)@( `a7|XxLd! ţR0-Ko6ހR /^SM`i$LDR~` Bt H`0"0$" Q 8 @Cà`&pBi"- ?L;nltc~` f$XPpDҁ)":S, 0-YIDAT PZ`0+ҰD!HlvBB +=* ~ R0L0@UR=ڡD"K$KSPNUYC iWnaXY8!*E IHP_&bXG>iW 834p h% $ecO8fD8C 0Me#TX@xC`*˹)Ђ0E0'Q0d @2*eZ*YT/8@LebQ\aX(Lcb8'S,y@) +z 83[?@SL |ªXyYB@`ZLx*c_zK5kK$za)7T.p!H0E,K$E?LW t(c 3oWLSH+"<``a`i@rdauOKpЋWi.X6 A8b.@ wL0 `Ʃ "%n ͅ79?.g @0sÀa 1XX%bhmVzXxFS,lpdžỲL}i0p&3` !`vAYihat@1ϙ 6gXaRp; ̈ $ CS&< 1tLD  Θ9U`3,ܰT 0+RfL0@fE"?L0Dކg` `@ ^pɐ>0K2RhxdB00{%P@@0ap7!0 &Zm0Ÿ0$ fo| <F4 h+ ̆LD1"C&8#Xb H^0 y:XF1 4  0E{c. +Hx8Gl ʙH10ErwR8D)E0a 8 3#|шTM^ ш(jbnVr|1~`r  7 ` 1`:&t&ap2 Ac 450I50Q(A`Z'|0g5YRaÆ4<S<#,'0@d&`R r!6RNEf9@f$0? fd "Sm aNf? XFA,$6Ri` >a03` 0 2xK3" 9>F> +XzZ`@nXYJLdLCzLAdLX` XH0ĈA  S*сeOQA- ?~k,_ /DՄr; 2 ܲhPFNF' Ƹ1SJ`PG)HLAڜ9с? )k059 >:20' "wӋd@3haL`4j9,V Lu_` P C2GEտ]v `!(!c8$!Y$dfIENDB`assimp-4.1.0/port/PyAssimp/gen/0000755002537200234200000000000013213503245016556 5ustar zmoelnigiemusersassimp-4.1.0/port/PyAssimp/gen/structsgen.py0000644002537200234200000002250713213503245021337 0ustar zmoelnigiemusers#!/usr/bin/env python # -*- Coding: UTF-8 -*- # --------------------------------------------------------------------------- # Open Asset Import Library (ASSIMP) # --------------------------------------------------------------------------- # # Copyright (c) 2006-2010, ASSIMP Development Team # # All rights reserved. # # Redistribution and use of this software 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 the ASSIMP team, nor the names of its # contributors may be used to endorse or promote products # derived from this software without specific prior # written permission of the ASSIMP Development Team. # # 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. # --------------------------------------------------------------------------- """Update PyAssimp's data structures to keep up with the C/C++ headers. This script is meant to be executed in the source tree, directly from port/PyAssimp/gen """ import os import re #==[regexps]================================================= # Clean desc REdefine = re.compile(r'' r'(?P)' # /** *desc */ r'#\s*define\s(?P[^(\n]+?)\s(?P.+)$' # #define name value , re.MULTILINE) # Get structs REstructs = re.compile(r'' #r'//\s?[\-]*\s(?P.*?)\*/\s' # /** *desc */ #r'//\s?[\-]*(?P.*?)\*/(?:.*?)' # garbage r'//\s?[\-]*\s(?P.*?)\*/\W*?' # /** *desc */ r'struct\s(?:ASSIMP_API\s)?(?P[a-z][a-z0-9_]\w+\b)' # struct name r'[^{]*?\{' # { r'(?P.*?)' # code r'\}\s*(PACK_STRUCT)?;' # }; , re.IGNORECASE + re.DOTALL + re.MULTILINE) # Clean desc REdesc = re.compile(r'' r'^\s*?([*]|/\*\*)(?P.*?)' # * line , re.IGNORECASE + re.DOTALL + re.MULTILINE) # Remove #ifdef __cplusplus RErmifdef = re.compile(r'' r'#ifdef __cplusplus' # #ifdef __cplusplus r'(?P.*)' # code r'#endif(\s*//\s*!?\s*__cplusplus)*' # #endif , re.IGNORECASE + re.DOTALL) # Replace comments RErpcom = re.compile(r'' r'\s*(/\*+\s|\*+/|\B\*\s|///?!?)' # /** r'(?P.*?)' # * line , re.IGNORECASE + re.DOTALL) # Restructure def GetType(type, prefix='c_'): t = type while t.endswith('*'): t = t[:-1] if t[:5] == 'const': t = t[5:] # skip some types if t in skiplist: return None t = t.strip() types = {'unsigned int':'uint', 'unsigned char':'ubyte',} if t in types: t = types[t] t = prefix + t while type.endswith('*'): t = "POINTER(" + t + ")" type = type[:-1] return t def restructure( match ): type = match.group("type") if match.group("struct") == "": type = GetType(type) elif match.group("struct") == "C_ENUM ": type = "c_uint" else: type = GetType(type[2:], '') if type is None: return '' if match.group("index"): type = type + "*" + match.group("index") result = "" for name in match.group("name").split(','): result += "(\"" + name.strip() + "\", "+ type + ")," return result RErestruc = re.compile(r'' r'(?PC_STRUCT\s|C_ENUM\s|)' # [C_STRUCT] r'(?P\w+\s?\w+?[*]*)\s' # type #r'(?P\w+)' # name r'(?P\w+|[a-z0-9_, ]+)' # name r'(:?\[(?P\w+)\])?;' # []; (optional) , re.DOTALL) #==[template]================================================ template = """ class $NAME$(Structure): \"\"\" $DESCRIPTION$ \"\"\" $DEFINES$ _fields_ = [ $FIELDS$ ] """ templateSR = """ class $NAME$(Structure): \"\"\" $DESCRIPTION$ \"\"\" $DEFINES$ $NAME$._fields_ = [ $FIELDS$ ] """ skiplist = ("FileIO", "File", "locateFromAssimpHeap",'LogStream','MeshAnim','AnimMesh') #============================================================ def Structify(fileName): file = open(fileName, 'r') text = file.read() result = [] # Get defines. defs = REdefine.findall(text) # Create defines defines = "\n" for define in defs: # Clean desc desc = REdesc.sub('', define[0]) # Replace comments desc = RErpcom.sub('#\g', desc) defines += desc if len(define[2].strip()): # skip non-integral defines, we can support them right now try: int(define[2],0) except: continue defines += " "*4 + define[1] + " = " + define[2] + "\n" # Get structs rs = REstructs.finditer(text) fileName = os.path.basename(fileName) print fileName for r in rs: name = r.group('name')[2:] desc = r.group('desc') # Skip some structs if name in skiplist: continue text = r.group('code') # Clean desc desc = REdesc.sub('', desc) desc = "See '"+ fileName +"' for details." #TODO # Remove #ifdef __cplusplus text = RErmifdef.sub('', text) # Whether the struct contains more than just POD primitive = text.find('C_STRUCT') == -1 # Restructure text = RErestruc.sub(restructure, text) # Replace comments text = RErpcom.sub('# \g', text) text = text.replace("),#", "),\n#") text = text.replace("#", "\n#") text = "".join([l for l in text.splitlines(True) if not l.strip().endswith("#")]) # remove empty comment lines # Whether it's selfreferencing: ex. struct Node { Node* parent; }; selfreferencing = text.find('POINTER('+name+')') != -1 complex = name == "Scene" # Create description description = "" for line in desc.split('\n'): description += " "*4 + line.strip() + "\n" description = description.rstrip() # Create fields fields = "" for line in text.split('\n'): fields += " "*12 + line.strip() + "\n" fields = fields.strip() if selfreferencing: templ = templateSR else: templ = template # Put it all together text = templ.replace('$NAME$', name) text = text.replace('$DESCRIPTION$', description) text = text.replace('$FIELDS$', fields) if ((name.lower() == fileName.split('.')[0][2:].lower()) and (name != 'Material')) or name == "String": text = text.replace('$DEFINES$', defines) else: text = text.replace('$DEFINES$', '') result.append((primitive, selfreferencing, complex, text)) return result text = "#-*- coding: UTF-8 -*-\n\n" text += "from ctypes import POINTER, c_int, c_uint, c_size_t, c_char, c_float, Structure, c_char_p, c_double, c_ubyte\n\n" structs1 = "" structs2 = "" structs3 = "" structs4 = "" path = '../../../include/assimp' files = os.listdir (path) #files = ["aiScene.h", "aiTypes.h"] for fileName in files: if fileName.endswith('.h'): for struct in Structify(os.path.join(path, fileName)): primitive, sr, complex, struct = struct if primitive: structs1 += struct elif sr: structs2 += struct elif complex: structs4 += struct else: structs3 += struct text += structs1 + structs2 + structs3 + structs4 file = open('structs.py', 'w') file.write(text) file.close() print("Generation done. You can now review the file 'structs.py' and merge it.") assimp-4.1.0/port/PyAssimp/README.md0000644002537200234200000000421713213503245017270 0ustar zmoelnigiemusersPyAssimp Readme =============== A simple Python wrapper for Assimp using `ctypes` to access the library. Requires Python >= 2.6. Python 3 support is mostly here, but not well tested. Note that pyassimp is not complete. Many ASSIMP features are missing. USAGE ----- ### Complete example: 3D viewer `pyassimp` comes with a simple 3D viewer that shows how to load and display a 3D model using a shader-based OpenGL pipeline. ![Screenshot](3d_viewer_screenshot.png) To use it, from within `/port/PyAssimp`: ``` $ cd scripts $ python ./3D-viewer ``` You can use this code as starting point in your applications. ### Writing your own code To get started with `pyassimp`, examine the simpler `sample.py` script in `scripts/`, which illustrates the basic usage. All Assimp data structures are wrapped using `ctypes`. All the data+length fields in Assimp's data structures (such as `aiMesh::mNumVertices`, `aiMesh::mVertices`) are replaced by simple python lists, so you can call `len()` on them to get their respective size and access members using `[]`. For example, to load a file named `hello.3ds` and print the first vertex of the first mesh, you would do (proper error handling substituted by assertions ...): ```python from pyassimp import * scene = load('hello.3ds') assert len(scene.meshes) mesh = scene.meshes[0] assert len(mesh.vertices) print(mesh.vertices[0]) # don't forget this one, or you will leak! release(scene) ``` Another example to list the 'top nodes' in a scene: ```python from pyassimp import * scene = load('hello.3ds') for c in scene.rootnode.children: print(str(c)) release(scene) ``` INSTALL ------- Install `pyassimp` by running: ``` $ python setup.py install ``` PyAssimp requires a assimp dynamic library (`DLL` on windows, `.so` on linux, `.dynlib` on macOS) in order to work. The default search directories are: - the current directory - on linux additionally: `/usr/lib`, `/usr/local/lib`, `/usr/lib/x86_64-linux-gnu` To build that library, refer to the Assimp master `INSTALL` instructions. To look in more places, edit `./pyassimp/helper.py`. There's an `additional_dirs` list waiting for your entries. assimp-4.1.0/port/PyAssimp/scripts/0000755002537200234200000000000013213503245017474 5ustar zmoelnigiemusersassimp-4.1.0/port/PyAssimp/scripts/fixed_pipeline_3d_viewer.py0000755002537200234200000002611213213503245025006 0ustar zmoelnigiemusers#!/usr/bin/env python #-*- coding: UTF-8 -*- """ This program demonstrates the use of pyassimp to load and render objects with OpenGL. 'c' cycles between cameras (if any available) 'q' to quit This example mixes 'old' OpenGL fixed-function pipeline with Vertex Buffer Objects. Materials are supported but textures are currently ignored. For a more advanced example (with shaders + keyboard/mouse controls), check scripts/sdl_viewer.py Author: Séverin Lemaignan, 2012 This sample is based on several sources, including: - http://www.lighthouse3d.com/tutorials - http://www.songho.ca/opengl/gl_transform.html - http://code.activestate.com/recipes/325391/ - ASSIMP's C++ SimpleOpenGL viewer """ import os, sys from OpenGL.GLUT import * from OpenGL.GLU import * from OpenGL.GL import * import logging;logger = logging.getLogger("pyassimp_opengl") logging.basicConfig(level=logging.INFO) import math import numpy import pyassimp from pyassimp.postprocess import * from pyassimp.helper import * name = 'pyassimp OpenGL viewer' height = 600 width = 900 class GLRenderer(): def __init__(self): self.scene = None self.using_fixed_cam = False self.current_cam_index = 0 # store the global scene rotation self.angle = 0. # for FPS calculation self.prev_time = 0 self.prev_fps_time = 0 self.frames = 0 def prepare_gl_buffers(self, mesh): """ Creates 3 buffer objets for each mesh, to store the vertices, the normals, and the faces indices. """ mesh.gl = {} # Fill the buffer for vertex positions mesh.gl["vertices"] = glGenBuffers(1) glBindBuffer(GL_ARRAY_BUFFER, mesh.gl["vertices"]) glBufferData(GL_ARRAY_BUFFER, mesh.vertices, GL_STATIC_DRAW) # Fill the buffer for normals mesh.gl["normals"] = glGenBuffers(1) glBindBuffer(GL_ARRAY_BUFFER, mesh.gl["normals"]) glBufferData(GL_ARRAY_BUFFER, mesh.normals, GL_STATIC_DRAW) # Fill the buffer for vertex positions mesh.gl["triangles"] = glGenBuffers(1) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["triangles"]) glBufferData(GL_ELEMENT_ARRAY_BUFFER, mesh.faces, GL_STATIC_DRAW) # Unbind buffers glBindBuffer(GL_ARRAY_BUFFER,0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,0) def load_model(self, path, postprocess = None): logger.info("Loading model:" + path + "...") if postprocess: self.scene = pyassimp.load(path, processing=postprocess) else: self.scene = pyassimp.load(path) logger.info("Done.") scene = self.scene #log some statistics logger.info(" meshes: %d" % len(scene.meshes)) logger.info(" total faces: %d" % sum([len(mesh.faces) for mesh in scene.meshes])) logger.info(" materials: %d" % len(scene.materials)) self.bb_min, self.bb_max = get_bounding_box(self.scene) logger.info(" bounding box:" + str(self.bb_min) + " - " + str(self.bb_max)) self.scene_center = [(a + b) / 2. for a, b in zip(self.bb_min, self.bb_max)] for index, mesh in enumerate(scene.meshes): self.prepare_gl_buffers(mesh) # Finally release the model pyassimp.release(scene) def cycle_cameras(self): self.current_cam_index if not self.scene.cameras: return None self.current_cam_index = (self.current_cam_index + 1) % len(self.scene.cameras) cam = self.scene.cameras[self.current_cam_index] logger.info("Switched to camera " + str(cam)) return cam def set_default_camera(self): if not self.using_fixed_cam: glLoadIdentity() gluLookAt(0.,0.,3., 0.,0.,-5., 0.,1.,0.) def set_camera(self, camera): if not camera: return self.using_fixed_cam = True znear = camera.clipplanenear zfar = camera.clipplanefar aspect = camera.aspect fov = camera.horizontalfov glMatrixMode(GL_PROJECTION) glLoadIdentity() # Compute gl frustrum tangent = math.tan(fov/2.) h = znear * tangent w = h * aspect # params: left, right, bottom, top, near, far glFrustum(-w, w, -h, h, znear, zfar) # equivalent to: #gluPerspective(fov * 180/math.pi, aspect, znear, zfar) glMatrixMode(GL_MODELVIEW) glLoadIdentity() cam = transform(camera.position, camera.transformation) at = transform(camera.lookat, camera.transformation) gluLookAt(cam[0], cam[2], -cam[1], at[0], at[2], -at[1], 0, 1, 0) def fit_scene(self, restore = False): """ Compute a scale factor and a translation to fit and center the whole geometry on the screen. """ x_max = self.bb_max[0] - self.bb_min[0] y_max = self.bb_max[1] - self.bb_min[1] tmp = max(x_max, y_max) z_max = self.bb_max[2] - self.bb_min[2] tmp = max(z_max, tmp) if not restore: tmp = 1. / tmp logger.info("Scaling the scene by %.03f" % tmp) glScalef(tmp, tmp, tmp) # center the model direction = -1 if not restore else 1 glTranslatef( direction * self.scene_center[0], direction * self.scene_center[1], direction * self.scene_center[2] ) return x_max, y_max, z_max def apply_material(self, mat): """ Apply an OpenGL, using one OpenGL display list per material to cache the operation. """ if not hasattr(mat, "gl_mat"): # evaluate once the mat properties, and cache the values in a glDisplayList. diffuse = numpy.array(mat.properties.get("diffuse", [0.8, 0.8, 0.8, 1.0])) specular = numpy.array(mat.properties.get("specular", [0., 0., 0., 1.0])) ambient = numpy.array(mat.properties.get("ambient", [0.2, 0.2, 0.2, 1.0])) emissive = numpy.array(mat.properties.get("emissive", [0., 0., 0., 1.0])) shininess = min(mat.properties.get("shininess", 1.0), 128) wireframe = mat.properties.get("wireframe", 0) twosided = mat.properties.get("twosided", 1) setattr(mat, "gl_mat", glGenLists(1)) glNewList(mat.gl_mat, GL_COMPILE) glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, diffuse) glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular) glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, ambient) glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, emissive) glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, shininess) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE if wireframe else GL_FILL) glDisable(GL_CULL_FACE) if twosided else glEnable(GL_CULL_FACE) glEndList() glCallList(mat.gl_mat) def do_motion(self): gl_time = glutGet(GLUT_ELAPSED_TIME) self.angle = (gl_time - self.prev_time) * 0.1 self.prev_time = gl_time # Compute FPS self.frames += 1 if gl_time - self.prev_fps_time >= 1000: current_fps = self.frames * 1000 / (gl_time - self.prev_fps_time) logger.info('%.0f fps' % current_fps) self.frames = 0 self.prev_fps_time = gl_time glutPostRedisplay() def recursive_render(self, node): """ Main recursive rendering method. """ # save model matrix and apply node transformation glPushMatrix() m = node.transformation.transpose() # OpenGL row major glMultMatrixf(m) for mesh in node.meshes: self.apply_material(mesh.material) glBindBuffer(GL_ARRAY_BUFFER, mesh.gl["vertices"]) glEnableClientState(GL_VERTEX_ARRAY) glVertexPointer(3, GL_FLOAT, 0, None) glBindBuffer(GL_ARRAY_BUFFER, mesh.gl["normals"]) glEnableClientState(GL_NORMAL_ARRAY) glNormalPointer(GL_FLOAT, 0, None) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["triangles"]) glDrawElements(GL_TRIANGLES,len(mesh.faces) * 3, GL_UNSIGNED_INT, None) glDisableClientState(GL_VERTEX_ARRAY) glDisableClientState(GL_NORMAL_ARRAY) glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) for child in node.children: self.recursive_render(child) glPopMatrix() def display(self): """ GLUT callback to redraw OpenGL surface """ glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT) glRotatef(self.angle,0.,1.,0.) self.recursive_render(self.scene.rootnode) glutSwapBuffers() self.do_motion() return #################################################################### ## GLUT keyboard and mouse callbacks ## #################################################################### def onkeypress(self, key, x, y): if key == 'c': self.fit_scene(restore = True) self.set_camera(self.cycle_cameras()) if key == 'q': sys.exit(0) def render(self, filename=None, fullscreen = False, autofit = True, postprocess = None): """ :param autofit: if true, scale the scene to fit the whole geometry in the viewport. """ # First initialize the openGL context glutInit(sys.argv) glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH) if not fullscreen: glutInitWindowSize(width, height) glutCreateWindow(name) else: glutGameModeString("1024x768") if glutGameModeGet(GLUT_GAME_MODE_POSSIBLE): glutEnterGameMode() else: print("Fullscreen mode not available!") sys.exit(1) self.load_model(filename, postprocess = postprocess) glClearColor(0.1,0.1,0.1,1.) #glShadeModel(GL_SMOOTH) glEnable(GL_LIGHTING) glEnable(GL_CULL_FACE) glEnable(GL_DEPTH_TEST) glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE) glEnable(GL_NORMALIZE) glEnable(GL_LIGHT0) glutDisplayFunc(self.display) glMatrixMode(GL_PROJECTION) glLoadIdentity() gluPerspective(35.0, width/float(height) , 0.10, 100.0) glMatrixMode(GL_MODELVIEW) self.set_default_camera() if autofit: # scale the whole asset to fit into our view frustum· self.fit_scene() glPushMatrix() glutKeyboardFunc(self.onkeypress) glutIgnoreKeyRepeat(1) glutMainLoop() if __name__ == '__main__': if not len(sys.argv) > 1: print("Usage: " + __file__ + " ") sys.exit(0) glrender = GLRenderer() glrender.render(sys.argv[1], fullscreen = False, postprocess = aiProcessPreset_TargetRealtime_MaxQuality) assimp-4.1.0/port/PyAssimp/scripts/sample.py0000755002537200234200000000524713213503245021342 0ustar zmoelnigiemusers#!/usr/bin/env python #-*- coding: UTF-8 -*- """ This module demonstrates the functionality of PyAssimp. """ import os, sys import logging logging.basicConfig(level=logging.INFO) import pyassimp import pyassimp.postprocess def recur_node(node,level = 0): print(" " + "\t" * level + "- " + str(node)) for child in node.children: recur_node(child, level + 1) def main(filename=None): scene = pyassimp.load(filename, processing=pyassimp.postprocess.aiProcess_Triangulate) #the model we load print("MODEL:" + filename) print #write some statistics print("SCENE:") print(" meshes:" + str(len(scene.meshes))) print(" materials:" + str(len(scene.materials))) print(" textures:" + str(len(scene.textures))) print print("NODES:") recur_node(scene.rootnode) print print("MESHES:") for index, mesh in enumerate(scene.meshes): print(" MESH" + str(index+1)) print(" material id:" + str(mesh.materialindex+1)) print(" vertices:" + str(len(mesh.vertices))) print(" first 3 verts:\n" + str(mesh.vertices[:3])) if mesh.normals.any(): print(" first 3 normals:\n" + str(mesh.normals[:3])) else: print(" no normals") print(" colors:" + str(len(mesh.colors))) tcs = mesh.texturecoords if tcs.any(): for index, tc in enumerate(tcs): print(" texture-coords "+ str(index) + ":" + str(len(tcs[index])) + "first3:" + str(tcs[index][:3])) else: print(" no texture coordinates") print(" uv-component-count:" + str(len(mesh.numuvcomponents))) print(" faces:" + str(len(mesh.faces)) + " -> first:\n" + str(mesh.faces[:3])) print(" bones:" + str(len(mesh.bones)) + " -> first:" + str([str(b) for b in mesh.bones[:3]])) print print("MATERIALS:") for index, material in enumerate(scene.materials): print(" MATERIAL (id:" + str(index+1) + ")") for key, value in material.properties.items(): print(" %s: %s" % (key, value)) print print("TEXTURES:") for index, texture in enumerate(scene.textures): print(" TEXTURE" + str(index+1)) print(" width:" + str(texture.width)) print(" height:" + str(texture.height)) print(" hint:" + str(texture.achformathint)) print(" data (size):" + str(len(texture.data))) # Finally release the model pyassimp.release(scene) def usage(): print("Usage: sample.py <3d model>") if __name__ == "__main__": if len(sys.argv) != 2: usage() else: main(sys.argv[1]) assimp-4.1.0/port/PyAssimp/scripts/3d_viewer.py0000755002537200234200000012116513213503245021746 0ustar zmoelnigiemusers#!/usr/bin/env python # -*- coding: UTF-8 -*- """ This program loads a model with PyASSIMP, and display it. Based on: - pygame code from http://3dengine.org/Spectator_%28PyOpenGL%29 - http://www.lighthouse3d.com/tutorials - http://www.songho.ca/opengl/gl_transform.html - http://code.activestate.com/recipes/325391/ - ASSIMP's C++ SimpleOpenGL viewer Authors: Séverin Lemaignan, 2012-2016 """ import sys import logging logger = logging.getLogger("pyassimp") gllogger = logging.getLogger("OpenGL") gllogger.setLevel(logging.WARNING) logging.basicConfig(level=logging.INFO) import OpenGL OpenGL.ERROR_CHECKING = False OpenGL.ERROR_LOGGING = False # OpenGL.ERROR_ON_COPY = True # OpenGL.FULL_LOGGING = True from OpenGL.GL import * from OpenGL.arrays import vbo from OpenGL.GL import shaders import pygame import pygame.font import pygame.image import math, random from numpy import linalg import pyassimp from pyassimp.postprocess import * from pyassimp.helper import * import transformations ROTATION_180_X = numpy.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], dtype=numpy.float32) # rendering mode BASE = "BASE" COLORS = "COLORS" SILHOUETTE = "SILHOUETTE" HELPERS = "HELPERS" # Entities type ENTITY = "entity" CAMERA = "camera" MESH = "mesh" FLAT_VERTEX_SHADER_120 = """ #version 120 uniform mat4 u_viewProjectionMatrix; uniform mat4 u_modelMatrix; uniform vec4 u_materialDiffuse; attribute vec3 a_vertex; varying vec4 v_color; void main(void) { v_color = u_materialDiffuse; gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); } """ FLAT_VERTEX_SHADER_130 = """ #version 130 uniform mat4 u_viewProjectionMatrix; uniform mat4 u_modelMatrix; uniform vec4 u_materialDiffuse; in vec3 a_vertex; out vec4 v_color; void main(void) { v_color = u_materialDiffuse; gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); } """ BASIC_VERTEX_SHADER_120 = """ #version 120 uniform mat4 u_viewProjectionMatrix; uniform mat4 u_modelMatrix; uniform mat3 u_normalMatrix; uniform vec3 u_lightPos; uniform vec4 u_materialDiffuse; attribute vec3 a_vertex; attribute vec3 a_normal; varying vec4 v_color; void main(void) { // Now the normal is in world space, as we pass the light in world space. vec3 normal = u_normalMatrix * a_normal; float dist = distance(a_vertex, u_lightPos); // go to https://www.desmos.com/calculator/nmnaud1hrw to play with the parameters // att is not used for now float att=1.0/(1.0+0.8*dist*dist); vec3 surf2light = normalize(u_lightPos - a_vertex); vec3 norm = normalize(normal); float dcont=max(0.0,dot(norm,surf2light)); float ambient = 0.3; float intensity = dcont + 0.3 + ambient; v_color = u_materialDiffuse * intensity; gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); } """ BASIC_VERTEX_SHADER_130 = """ #version 130 uniform mat4 u_viewProjectionMatrix; uniform mat4 u_modelMatrix; uniform mat3 u_normalMatrix; uniform vec3 u_lightPos; uniform vec4 u_materialDiffuse; in vec3 a_vertex; in vec3 a_normal; out vec4 v_color; void main(void) { // Now the normal is in world space, as we pass the light in world space. vec3 normal = u_normalMatrix * a_normal; float dist = distance(a_vertex, u_lightPos); // go to https://www.desmos.com/calculator/nmnaud1hrw to play with the parameters // att is not used for now float att=1.0/(1.0+0.8*dist*dist); vec3 surf2light = normalize(u_lightPos - a_vertex); vec3 norm = normalize(normal); float dcont=max(0.0,dot(norm,surf2light)); float ambient = 0.3; float intensity = dcont + 0.3 + ambient; v_color = u_materialDiffuse * intensity; gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); } """ BASIC_FRAGMENT_SHADER_120 = """ #version 120 varying vec4 v_color; void main() { gl_FragColor = v_color; } """ BASIC_FRAGMENT_SHADER_130 = """ #version 130 in vec4 v_color; void main() { gl_FragColor = v_color; } """ GOOCH_VERTEX_SHADER_120 = """ #version 120 // attributes attribute vec3 a_vertex; // xyz - position attribute vec3 a_normal; // xyz - normal // uniforms uniform mat4 u_modelMatrix; uniform mat4 u_viewProjectionMatrix; uniform mat3 u_normalMatrix; uniform vec3 u_lightPos; uniform vec3 u_camPos; // output data from vertex to fragment shader varying vec3 o_normal; varying vec3 o_lightVector; /////////////////////////////////////////////////////////////////// void main(void) { // transform position and normal to world space vec4 positionWorld = u_modelMatrix * vec4(a_vertex, 1.0); vec3 normalWorld = u_normalMatrix * a_normal; // calculate and pass vectors required for lighting o_lightVector = u_lightPos - positionWorld.xyz; o_normal = normalWorld; // project world space position to the screen and output it gl_Position = u_viewProjectionMatrix * positionWorld; } """ GOOCH_VERTEX_SHADER_130 = """ #version 130 // attributes in vec3 a_vertex; // xyz - position in vec3 a_normal; // xyz - normal // uniforms uniform mat4 u_modelMatrix; uniform mat4 u_viewProjectionMatrix; uniform mat3 u_normalMatrix; uniform vec3 u_lightPos; uniform vec3 u_camPos; // output data from vertex to fragment shader out vec3 o_normal; out vec3 o_lightVector; /////////////////////////////////////////////////////////////////// void main(void) { // transform position and normal to world space vec4 positionWorld = u_modelMatrix * vec4(a_vertex, 1.0); vec3 normalWorld = u_normalMatrix * a_normal; // calculate and pass vectors required for lighting o_lightVector = u_lightPos - positionWorld.xyz; o_normal = normalWorld; // project world space position to the screen and output it gl_Position = u_viewProjectionMatrix * positionWorld; } """ GOOCH_FRAGMENT_SHADER_120 = """ #version 120 // data from vertex shader varying vec3 o_normal; varying vec3 o_lightVector; // diffuse color of the object uniform vec4 u_materialDiffuse; // cool color of gooch shading uniform vec3 u_coolColor; // warm color of gooch shading uniform vec3 u_warmColor; // how much to take from object color in final cool color uniform float u_alpha; // how much to take from object color in final warm color uniform float u_beta; /////////////////////////////////////////////////////////// void main(void) { // normlize vectors for lighting vec3 normalVector = normalize(o_normal); vec3 lightVector = normalize(o_lightVector); // intensity of diffuse lighting [-1, 1] float diffuseLighting = dot(lightVector, normalVector); // map intensity of lighting from range [-1; 1] to [0, 1] float interpolationValue = (1.0 + diffuseLighting)/2; ////////////////////////////////////////////////////////////////// // cool color mixed with color of the object vec3 coolColorMod = u_coolColor + vec3(u_materialDiffuse) * u_alpha; // warm color mixed with color of the object vec3 warmColorMod = u_warmColor + vec3(u_materialDiffuse) * u_beta; // interpolation of cool and warm colors according // to lighting intensity. The lower the light intensity, // the larger part of the cool color is used vec3 colorOut = mix(coolColorMod, warmColorMod, interpolationValue); ////////////////////////////////////////////////////////////////// // save color gl_FragColor.rgb = colorOut; gl_FragColor.a = 1; } """ GOOCH_FRAGMENT_SHADER_130 = """ #version 130 // data from vertex shader in vec3 o_normal; in vec3 o_lightVector; // diffuse color of the object uniform vec4 u_materialDiffuse; // cool color of gooch shading uniform vec3 u_coolColor; // warm color of gooch shading uniform vec3 u_warmColor; // how much to take from object color in final cool color uniform float u_alpha; // how much to take from object color in final warm color uniform float u_beta; // output to framebuffer out vec4 resultingColor; /////////////////////////////////////////////////////////// void main(void) { // normlize vectors for lighting vec3 normalVector = normalize(o_normal); vec3 lightVector = normalize(o_lightVector); // intensity of diffuse lighting [-1, 1] float diffuseLighting = dot(lightVector, normalVector); // map intensity of lighting from range [-1; 1] to [0, 1] float interpolationValue = (1.0 + diffuseLighting)/2; ////////////////////////////////////////////////////////////////// // cool color mixed with color of the object vec3 coolColorMod = u_coolColor + vec3(u_materialDiffuse) * u_alpha; // warm color mixed with color of the object vec3 warmColorMod = u_warmColor + vec3(u_materialDiffuse) * u_beta; // interpolation of cool and warm colors according // to lighting intensity. The lower the light intensity, // the larger part of the cool color is used vec3 colorOut = mix(coolColorMod, warmColorMod, interpolationValue); ////////////////////////////////////////////////////////////////// // save color resultingColor.rgb = colorOut; resultingColor.a = 1; } """ SILHOUETTE_VERTEX_SHADER_120 = """ #version 120 attribute vec3 a_vertex; // xyz - position attribute vec3 a_normal; // xyz - normal uniform mat4 u_modelMatrix; uniform mat4 u_viewProjectionMatrix; uniform mat4 u_modelViewMatrix; uniform vec4 u_materialDiffuse; uniform float u_bordersize; // width of the border varying vec4 v_color; void main(void){ v_color = u_materialDiffuse; float distToCamera = -(u_modelViewMatrix * vec4(a_vertex, 1.0)).z; vec4 tPos = vec4(a_vertex + a_normal * u_bordersize * distToCamera, 1.0); gl_Position = u_viewProjectionMatrix * u_modelMatrix * tPos; } """ SILHOUETTE_VERTEX_SHADER_130 = """ #version 130 in vec3 a_vertex; // xyz - position in vec3 a_normal; // xyz - normal uniform mat4 u_modelMatrix; uniform mat4 u_viewProjectionMatrix; uniform mat4 u_modelViewMatrix; uniform vec4 u_materialDiffuse; uniform float u_bordersize; // width of the border out vec4 v_color; void main(void){ v_color = u_materialDiffuse; float distToCamera = -(u_modelViewMatrix * vec4(a_vertex, 1.0)).z; vec4 tPos = vec4(a_vertex + a_normal * u_bordersize * distToCamera, 1.0); gl_Position = u_viewProjectionMatrix * u_modelMatrix * tPos; } """ DEFAULT_CLIP_PLANE_NEAR = 0.001 DEFAULT_CLIP_PLANE_FAR = 1000.0 def get_world_transform(scene, node): if node == scene.rootnode: return numpy.identity(4, dtype=numpy.float32) parents = reversed(_get_parent_chain(scene, node, [])) parent_transform = reduce(numpy.dot, [p.transformation for p in parents]) return numpy.dot(parent_transform, node.transformation) def _get_parent_chain(scene, node, parents): parent = node.parent parents.append(parent) if parent == scene.rootnode: return parents return _get_parent_chain(scene, parent, parents) class DefaultCamera: def __init__(self, w, h, fov): self.name = "default camera" self.type = CAMERA self.clipplanenear = DEFAULT_CLIP_PLANE_NEAR self.clipplanefar = DEFAULT_CLIP_PLANE_FAR self.aspect = w / h self.horizontalfov = fov * math.pi / 180 self.transformation = numpy.array([[0.68, -0.32, 0.65, 7.48], [0.73, 0.31, -0.61, -6.51], [-0.01, 0.89, 0.44, 5.34], [0., 0., 0., 1.]], dtype=numpy.float32) self.transformation = numpy.dot(self.transformation, ROTATION_180_X) def __str__(self): return self.name class PyAssimp3DViewer: base_name = "PyASSIMP 3D viewer" def __init__(self, model, w=1024, h=768): self.w = w self.h = h pygame.init() pygame.display.set_caption(self.base_name) pygame.display.set_mode((w, h), pygame.OPENGL | pygame.DOUBLEBUF) glClearColor(0.18, 0.18, 0.18, 1.0) shader_compilation_succeeded = False try: self.set_shaders_v130() self.prepare_shaders() except RuntimeError, message: sys.stderr.write("%s\n" % message) sys.stdout.write("Could not compile shaders in version 1.30, trying version 1.20\n") if not shader_compilation_succeeded: self.set_shaders_v120() self.prepare_shaders() self.scene = None self.meshes = {} # stores the OpenGL vertex/faces/normals buffers pointers self.node2colorid = {} # stores a color ID for each node. Useful for mouse picking and visibility checking self.colorid2node = {} # reverse dict of node2colorid self.currently_selected = None self.moving = False self.moving_situation = None self.default_camera = DefaultCamera(self.w, self.h, fov=70) self.cameras = [self.default_camera] self.current_cam_index = 0 self.current_cam = self.default_camera self.set_camera_projection() self.load_model(model) # user interactions self.focal_point = [0, 0, 0] self.is_rotating = False self.is_panning = False self.is_zooming = False def set_shaders_v120(self): self.BASIC_VERTEX_SHADER = BASIC_VERTEX_SHADER_120 self.FLAT_VERTEX_SHADER = FLAT_VERTEX_SHADER_120 self.SILHOUETTE_VERTEX_SHADER = SILHOUETTE_VERTEX_SHADER_120 self.GOOCH_VERTEX_SHADER = GOOCH_VERTEX_SHADER_120 self.BASIC_FRAGMENT_SHADER = BASIC_FRAGMENT_SHADER_120 self.GOOCH_FRAGMENT_SHADER = GOOCH_FRAGMENT_SHADER_120 def set_shaders_v130(self): self.BASIC_VERTEX_SHADER = BASIC_VERTEX_SHADER_130 self.FLAT_VERTEX_SHADER = FLAT_VERTEX_SHADER_130 self.SILHOUETTE_VERTEX_SHADER = SILHOUETTE_VERTEX_SHADER_130 self.GOOCH_VERTEX_SHADER = GOOCH_VERTEX_SHADER_130 self.BASIC_FRAGMENT_SHADER = BASIC_FRAGMENT_SHADER_130 self.GOOCH_FRAGMENT_SHADER = GOOCH_FRAGMENT_SHADER_130 def prepare_shaders(self): ### Base shader vertex = shaders.compileShader(self.BASIC_VERTEX_SHADER, GL_VERTEX_SHADER) fragment = shaders.compileShader(self.BASIC_FRAGMENT_SHADER, GL_FRAGMENT_SHADER) self.shader = shaders.compileProgram(vertex, fragment) self.set_shader_accessors(('u_modelMatrix', 'u_viewProjectionMatrix', 'u_normalMatrix', 'u_lightPos', 'u_materialDiffuse'), ('a_vertex', 'a_normal'), self.shader) ### Flat shader flatvertex = shaders.compileShader(self.FLAT_VERTEX_SHADER, GL_VERTEX_SHADER) self.flatshader = shaders.compileProgram(flatvertex, fragment) self.set_shader_accessors(('u_modelMatrix', 'u_viewProjectionMatrix', 'u_materialDiffuse',), ('a_vertex',), self.flatshader) ### Silhouette shader silh_vertex = shaders.compileShader(self.SILHOUETTE_VERTEX_SHADER, GL_VERTEX_SHADER) self.silhouette_shader = shaders.compileProgram(silh_vertex, fragment) self.set_shader_accessors(('u_modelMatrix', 'u_viewProjectionMatrix', 'u_modelViewMatrix', 'u_materialDiffuse', 'u_bordersize' # width of the silhouette ), ('a_vertex', 'a_normal'), self.silhouette_shader) ### Gooch shader gooch_vertex = shaders.compileShader(self.GOOCH_VERTEX_SHADER, GL_VERTEX_SHADER) gooch_fragment = shaders.compileShader(self.GOOCH_FRAGMENT_SHADER, GL_FRAGMENT_SHADER) self.gooch_shader = shaders.compileProgram(gooch_vertex, gooch_fragment) self.set_shader_accessors(('u_modelMatrix', 'u_viewProjectionMatrix', 'u_normalMatrix', 'u_lightPos', 'u_materialDiffuse', 'u_coolColor', 'u_warmColor', 'u_alpha', 'u_beta' ), ('a_vertex', 'a_normal'), self.gooch_shader) @staticmethod def set_shader_accessors(uniforms, attributes, shader): # add accessors to the shaders uniforms and attributes for uniform in uniforms: location = glGetUniformLocation(shader, uniform) if location in (None, -1): raise RuntimeError('No uniform: %s (maybe it is not used ' 'anymore and has been optimized out by' ' the shader compiler)' % uniform) setattr(shader, uniform, location) for attribute in attributes: location = glGetAttribLocation(shader, attribute) if location in (None, -1): raise RuntimeError('No attribute: %s' % attribute) setattr(shader, attribute, location) @staticmethod def prepare_gl_buffers(mesh): mesh.gl = {} # Fill the buffer for vertex and normals positions v = numpy.array(mesh.vertices, 'f') n = numpy.array(mesh.normals, 'f') mesh.gl["vbo"] = vbo.VBO(numpy.hstack((v, n))) # Fill the buffer for vertex positions mesh.gl["faces"] = glGenBuffers(1) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) glBufferData(GL_ELEMENT_ARRAY_BUFFER, numpy.array(mesh.faces, dtype=numpy.int32), GL_STATIC_DRAW) mesh.gl["nbfaces"] = len(mesh.faces) # Unbind buffers glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) @staticmethod def get_rgb_from_colorid(colorid): r = (colorid >> 0) & 0xff g = (colorid >> 8) & 0xff b = (colorid >> 16) & 0xff return r, g, b def get_color_id(self): id = random.randint(0, 256 * 256 * 256) if id not in self.colorid2node: return id else: return self.get_color_id() def glize(self, scene, node): logger.info("Loading node <%s>" % node) node.selected = True if self.currently_selected and self.currently_selected == node else False node.transformation = node.transformation.astype(numpy.float32) if node.meshes: node.type = MESH colorid = self.get_color_id() self.colorid2node[colorid] = node self.node2colorid[node.name] = colorid elif node.name in [c.name for c in scene.cameras]: # retrieve the ASSIMP camera object [cam] = [c for c in scene.cameras if c.name == node.name] node.type = CAMERA logger.info("Added camera <%s>" % node.name) logger.info("Camera position: %.3f, %.3f, %.3f" % tuple(node.transformation[:, 3][:3].tolist())) self.cameras.append(node) node.clipplanenear = cam.clipplanenear node.clipplanefar = cam.clipplanefar if numpy.allclose(cam.lookat, [0, 0, -1]) and numpy.allclose(cam.up, [0, 1, 0]): # Cameras in .blend files # Rotate by 180deg around X to have Z pointing forward node.transformation = numpy.dot(node.transformation, ROTATION_180_X) else: raise RuntimeError( "I do not know how to normalize this camera orientation: lookat=%s, up=%s" % (cam.lookat, cam.up)) if cam.aspect == 0.0: logger.warning("Camera aspect not set. Setting to default 4:3") node.aspect = 1.333 else: node.aspect = cam.aspect node.horizontalfov = cam.horizontalfov else: node.type = ENTITY for child in node.children: self.glize(scene, child) def load_model(self, path, postprocess=aiProcessPreset_TargetRealtime_MaxQuality): logger.info("Loading model:" + path + "...") if postprocess: self.scene = pyassimp.load(path, processing=postprocess) else: self.scene = pyassimp.load(path) logger.info("Done.") scene = self.scene # log some statistics logger.info(" meshes: %d" % len(scene.meshes)) logger.info(" total faces: %d" % sum([len(mesh.faces) for mesh in scene.meshes])) logger.info(" materials: %d" % len(scene.materials)) self.bb_min, self.bb_max = get_bounding_box(self.scene) logger.info(" bounding box:" + str(self.bb_min) + " - " + str(self.bb_max)) self.scene_center = [(a + b) / 2. for a, b in zip(self.bb_min, self.bb_max)] for index, mesh in enumerate(scene.meshes): self.prepare_gl_buffers(mesh) self.glize(scene, scene.rootnode) # Finally release the model pyassimp.release(scene) logger.info("Ready for 3D rendering!") def cycle_cameras(self): self.current_cam_index = (self.current_cam_index + 1) % len(self.cameras) self.current_cam = self.cameras[self.current_cam_index] self.set_camera_projection(self.current_cam) logger.info("Switched to camera <%s>" % self.current_cam) def set_overlay_projection(self): glViewport(0, 0, self.w, self.h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0.0, self.w - 1.0, 0.0, self.h - 1.0, -1.0, 1.0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() def set_camera_projection(self, camera=None): if not camera: camera = self.current_cam znear = camera.clipplanenear or DEFAULT_CLIP_PLANE_NEAR zfar = camera.clipplanefar or DEFAULT_CLIP_PLANE_FAR aspect = camera.aspect fov = camera.horizontalfov glMatrixMode(GL_PROJECTION) glLoadIdentity() # Compute gl frustrum tangent = math.tan(fov / 2.) h = znear * tangent w = h * aspect # params: left, right, bottom, top, near, far glFrustum(-w, w, -h, h, znear, zfar) # equivalent to: # gluPerspective(fov * 180/math.pi, aspect, znear, zfar) self.projection_matrix = glGetFloatv(GL_PROJECTION_MATRIX).transpose() glMatrixMode(GL_MODELVIEW) glLoadIdentity() def render_colors(self): glEnable(GL_DEPTH_TEST) glDepthFunc(GL_LEQUAL) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glEnable(GL_CULL_FACE) glUseProgram(self.flatshader) glUniformMatrix4fv(self.flatshader.u_viewProjectionMatrix, 1, GL_TRUE, numpy.dot(self.projection_matrix, self.view_matrix)) self.recursive_render(self.scene.rootnode, self.flatshader, mode=COLORS) glUseProgram(0) def get_hovered_node(self, mousex, mousey): """ Attention: The performances of this method relies heavily on the size of the display! """ # mouse out of the window? if mousex < 0 or mousex >= self.w or mousey < 0 or mousey >= self.h: return None self.render_colors() # Capture image from the OpenGL buffer buf = (GLubyte * (3 * self.w * self.h))(0) glReadPixels(0, 0, self.w, self.h, GL_RGB, GL_UNSIGNED_BYTE, buf) # Reinterpret the RGB pixel buffer as a 1-D array of 24bits colors a = numpy.ndarray(len(buf), numpy.dtype('>u1'), buf) colors = numpy.zeros(len(buf) / 3, numpy.dtype('u1')[i::3] colorid = colors[mousex + mousey * self.w] glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) if colorid in self.colorid2node: return self.colorid2node[colorid] def render(self, wireframe=False, twosided=False): glEnable(GL_DEPTH_TEST) glDepthFunc(GL_LEQUAL) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE if wireframe else GL_FILL) glDisable(GL_CULL_FACE) if twosided else glEnable(GL_CULL_FACE) self.render_grid() self.recursive_render(self.scene.rootnode, None, mode=HELPERS) ### First, the silhouette if False: shader = self.silhouette_shader # glDepthMask(GL_FALSE) glCullFace(GL_FRONT) # cull front faces glUseProgram(shader) glUniform1f(shader.u_bordersize, 0.01) glUniformMatrix4fv(shader.u_viewProjectionMatrix, 1, GL_TRUE, numpy.dot(self.projection_matrix, self.view_matrix)) self.recursive_render(self.scene.rootnode, shader, mode=SILHOUETTE) glUseProgram(0) ### Then, inner shading # glDepthMask(GL_TRUE) glCullFace(GL_BACK) use_gooch = False if use_gooch: shader = self.gooch_shader glUseProgram(shader) glUniform3f(shader.u_lightPos, -.5, -.5, .5) ##### GOOCH specific glUniform3f(shader.u_coolColor, 159.0 / 255, 148.0 / 255, 255.0 / 255) glUniform3f(shader.u_warmColor, 255.0 / 255, 75.0 / 255, 75.0 / 255) glUniform1f(shader.u_alpha, .25) glUniform1f(shader.u_beta, .25) ######### else: shader = self.shader glUseProgram(shader) glUniform3f(shader.u_lightPos, -.5, -.5, .5) glUniformMatrix4fv(shader.u_viewProjectionMatrix, 1, GL_TRUE, numpy.dot(self.projection_matrix, self.view_matrix)) self.recursive_render(self.scene.rootnode, shader) glUseProgram(0) def render_axis(self, transformation=numpy.identity(4, dtype=numpy.float32), label=None, size=0.2, selected=False): m = transformation.transpose() # OpenGL row major glPushMatrix() glMultMatrixf(m) glLineWidth(3 if selected else 1) size = 2 * size if selected else size glBegin(GL_LINES) # draw line for x axis glColor3f(1.0, 0.0, 0.0) glVertex3f(0.0, 0.0, 0.0) glVertex3f(size, 0.0, 0.0) # draw line for y axis glColor3f(0.0, 1.0, 0.0) glVertex3f(0.0, 0.0, 0.0) glVertex3f(0.0, size, 0.0) # draw line for Z axis glColor3f(0.0, 0.0, 1.0) glVertex3f(0.0, 0.0, 0.0) glVertex3f(0.0, 0.0, size) glEnd() if label: self.showtext(label) glPopMatrix() @staticmethod def render_camera(camera, transformation): m = transformation.transpose() # OpenGL row major aspect = camera.aspect u = 0.1 # unit size (in m) l = 3 * u # length of the camera cone f = 3 * u # aperture of the camera cone glPushMatrix() glMultMatrixf(m) glLineWidth(2) glBegin(GL_LINE_STRIP) glColor3f(.2, .2, .2) glVertex3f(u, u, -u) glVertex3f(u, -u, -u) glVertex3f(-u, -u, -u) glVertex3f(-u, u, -u) glVertex3f(u, u, -u) glVertex3f(u, u, 0.0) glVertex3f(u, -u, 0.0) glVertex3f(-u, -u, 0.0) glVertex3f(-u, u, 0.0) glVertex3f(u, u, 0.0) glVertex3f(f * aspect, f, l) glVertex3f(f * aspect, -f, l) glVertex3f(-f * aspect, -f, l) glVertex3f(-f * aspect, f, l) glVertex3f(f * aspect, f, l) glEnd() glBegin(GL_LINE_STRIP) glVertex3f(u, -u, -u) glVertex3f(u, -u, 0.0) glVertex3f(f * aspect, -f, l) glEnd() glBegin(GL_LINE_STRIP) glVertex3f(-u, -u, -u) glVertex3f(-u, -u, 0.0) glVertex3f(-f * aspect, -f, l) glEnd() glBegin(GL_LINE_STRIP) glVertex3f(-u, u, -u) glVertex3f(-u, u, 0.0) glVertex3f(-f * aspect, f, l) glEnd() glPopMatrix() @staticmethod def render_grid(): glLineWidth(1) glColor3f(0.5, 0.5, 0.5) glBegin(GL_LINES) for i in range(-10, 11): glVertex3f(i, -10.0, 0.0) glVertex3f(i, 10.0, 0.0) for i in range(-10, 11): glVertex3f(-10.0, i, 0.0) glVertex3f(10.0, i, 0.0) glEnd() def recursive_render(self, node, shader, mode=BASE, with_normals=True): """ Main recursive rendering method. """ normals = with_normals if mode == COLORS: normals = False if not hasattr(node, "selected"): node.selected = False m = get_world_transform(self.scene, node) # HELPERS mode ### if mode == HELPERS: # if node.type == ENTITY: self.render_axis(m, label=node.name if node != self.scene.rootnode else None, selected=node.selected if hasattr(node, "selected") else False) if node.type == CAMERA: self.render_camera(node, m) for child in node.children: self.recursive_render(child, shader, mode) return # Mesh rendering modes ### if node.type == MESH: for mesh in node.meshes: stride = 24 # 6 * 4 bytes if node.selected and mode == SILHOUETTE: glUniform4f(shader.u_materialDiffuse, 1.0, 0.0, 0.0, 1.0) glUniformMatrix4fv(shader.u_modelViewMatrix, 1, GL_TRUE, numpy.dot(self.view_matrix, m)) else: if mode == COLORS: colorid = self.node2colorid[node.name] r, g, b = self.get_rgb_from_colorid(colorid) glUniform4f(shader.u_materialDiffuse, r / 255.0, g / 255.0, b / 255.0, 1.0) elif mode == SILHOUETTE: glUniform4f(shader.u_materialDiffuse, .0, .0, .0, 1.0) else: if node.selected: diffuse = (1.0, 0.0, 0.0, 1.0) # selected nodes in red else: diffuse = mesh.material.properties["diffuse"] if len(diffuse) == 3: # RGB instead of expected RGBA diffuse.append(1.0) glUniform4f(shader.u_materialDiffuse, *diffuse) # if ambient: # glUniform4f( shader.Material_ambient, *mat["ambient"] ) if mode == BASE: # not in COLORS or SILHOUETTE normal_matrix = linalg.inv(numpy.dot(self.view_matrix, m)[0:3, 0:3]).transpose() glUniformMatrix3fv(shader.u_normalMatrix, 1, GL_TRUE, normal_matrix) glUniformMatrix4fv(shader.u_modelMatrix, 1, GL_TRUE, m) vbo = mesh.gl["vbo"] vbo.bind() glEnableVertexAttribArray(shader.a_vertex) if normals: glEnableVertexAttribArray(shader.a_normal) glVertexAttribPointer( shader.a_vertex, 3, GL_FLOAT, False, stride, vbo ) if normals: glVertexAttribPointer( shader.a_normal, 3, GL_FLOAT, False, stride, vbo + 12 ) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) glDrawElements(GL_TRIANGLES, mesh.gl["nbfaces"] * 3, GL_UNSIGNED_INT, None) vbo.unbind() glDisableVertexAttribArray(shader.a_vertex) if normals: glDisableVertexAttribArray(shader.a_normal) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) for child in node.children: self.recursive_render(child, shader, mode) def switch_to_overlay(self): glPushMatrix() self.set_overlay_projection() def switch_from_overlay(self): self.set_camera_projection() glPopMatrix() def select_node(self, node): self.currently_selected = node self.update_node_select(self.scene.rootnode) def update_node_select(self, node): if node is self.currently_selected: node.selected = True else: node.selected = False for child in node.children: self.update_node_select(child) def loop(self): pygame.display.flip() if not self.process_events(): return False # ESC has been pressed glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) return True def process_events(self): LEFT_BUTTON = 1 MIDDLE_BUTTON = 2 RIGHT_BUTTON = 3 WHEEL_UP = 4 WHEEL_DOWN = 5 dx, dy = pygame.mouse.get_rel() mousex, mousey = pygame.mouse.get_pos() zooming_one_shot = False ok = True for evt in pygame.event.get(): if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == LEFT_BUTTON: hovered = self.get_hovered_node(mousex, self.h - mousey) if hovered: if self.currently_selected and self.currently_selected == hovered: self.select_node(None) else: logger.info("Node %s selected" % hovered) self.select_node(hovered) else: self.is_rotating = True if evt.type == pygame.MOUSEBUTTONUP and evt.button == LEFT_BUTTON: self.is_rotating = False if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == MIDDLE_BUTTON: self.is_panning = True if evt.type == pygame.MOUSEBUTTONUP and evt.button == MIDDLE_BUTTON: self.is_panning = False if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == RIGHT_BUTTON: self.is_zooming = True if evt.type == pygame.MOUSEBUTTONUP and evt.button == RIGHT_BUTTON: self.is_zooming = False if evt.type == pygame.MOUSEBUTTONDOWN and evt.button in [WHEEL_UP, WHEEL_DOWN]: zooming_one_shot = True self.is_zooming = True dy = -10 if evt.button == WHEEL_UP else 10 if evt.type == pygame.KEYDOWN: ok = (ok and self.process_keystroke(evt.key, evt.mod)) self.controls_3d(dx, dy, zooming_one_shot) return ok def process_keystroke(self, key, mod): # process arrow keys if an object is selected if self.currently_selected: up = 0 strafe = 0 if key == pygame.K_UP: up = 1 if key == pygame.K_DOWN: up = -1 if key == pygame.K_LEFT: strafe = -1 if key == pygame.K_RIGHT: strafe = 1 self.move_selected_node(up, strafe) if key == pygame.K_f: pygame.display.toggle_fullscreen() if key == pygame.K_TAB: self.cycle_cameras() if key in [pygame.K_ESCAPE, pygame.K_q]: return False return True def controls_3d(self, dx, dy, zooming_one_shot=False): CAMERA_TRANSLATION_FACTOR = 0.01 CAMERA_ROTATION_FACTOR = 0.01 if not (self.is_rotating or self.is_panning or self.is_zooming): return current_pos = self.current_cam.transformation[:3, 3].copy() distance = numpy.linalg.norm(self.focal_point - current_pos) if self.is_rotating: """ Orbiting the camera is implemented the following way: - the rotation is split into a rotation around the *world* Z axis (controlled by the horizontal mouse motion along X) and a rotation around the *X* axis of the camera (pitch) *shifted to the focal origin* (the world origin for now). This is controlled by the vertical motion of the mouse (Y axis). - as a result, the resulting transformation of the camera in the world frame C' is: C' = (T · Rx · T⁻¹ · (Rz · C)⁻¹)⁻¹ where: - C is the original camera transformation in the world frame, - Rz is the rotation along the Z axis (in the world frame) - T is the translation camera -> world (ie, the inverse of the translation part of C - Rx is the rotation around X in the (translated) camera frame """ rotation_camera_x = dy * CAMERA_ROTATION_FACTOR rotation_world_z = dx * CAMERA_ROTATION_FACTOR world_z_rotation = transformations.euler_matrix(0, 0, rotation_world_z) cam_x_rotation = transformations.euler_matrix(rotation_camera_x, 0, 0) after_world_z_rotation = numpy.dot(world_z_rotation, self.current_cam.transformation) inverse_transformation = transformations.inverse_matrix(after_world_z_rotation) translation = transformations.translation_matrix( transformations.decompose_matrix(inverse_transformation)[3]) inverse_translation = transformations.inverse_matrix(translation) new_inverse = numpy.dot(inverse_translation, inverse_transformation) new_inverse = numpy.dot(cam_x_rotation, new_inverse) new_inverse = numpy.dot(translation, new_inverse) self.current_cam.transformation = transformations.inverse_matrix(new_inverse).astype(numpy.float32) if self.is_panning: tx = -dx * CAMERA_TRANSLATION_FACTOR * distance ty = dy * CAMERA_TRANSLATION_FACTOR * distance cam_transform = transformations.translation_matrix((tx, ty, 0)).astype(numpy.float32) self.current_cam.transformation = numpy.dot(self.current_cam.transformation, cam_transform) if self.is_zooming: tz = dy * CAMERA_TRANSLATION_FACTOR * distance cam_transform = transformations.translation_matrix((0, 0, tz)).astype(numpy.float32) self.current_cam.transformation = numpy.dot(self.current_cam.transformation, cam_transform) if zooming_one_shot: self.is_zooming = False self.update_view_camera() def update_view_camera(self): self.view_matrix = linalg.inv(self.current_cam.transformation) # Rotate by 180deg around X to have Z pointing backward (OpenGL convention) self.view_matrix = numpy.dot(ROTATION_180_X, self.view_matrix) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glMultMatrixf(self.view_matrix.transpose()) def move_selected_node(self, up, strafe): self.currently_selected.transformation[0][3] += strafe self.currently_selected.transformation[2][3] += up @staticmethod def showtext(text, x=0, y=0, z=0, size=20): # TODO: alpha blending does not work... # glEnable(GL_BLEND) # glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) font = pygame.font.Font(None, size) text_surface = font.render(text, True, (10, 10, 10, 255), (255 * 0.18, 255 * 0.18, 255 * 0.18, 0)) text_data = pygame.image.tostring(text_surface, "RGBA", True) glRasterPos3d(x, y, z) glDrawPixels(text_surface.get_width(), text_surface.get_height(), GL_RGBA, GL_UNSIGNED_BYTE, text_data) # glDisable(GL_BLEND) def main(model, width, height): app = PyAssimp3DViewer(model, w=width, h=height) clock = pygame.time.Clock() while app.loop(): app.update_view_camera() ## Main rendering app.render() ## GUI text display app.switch_to_overlay() app.showtext("Active camera: %s" % str(app.current_cam), 10, app.h - 30) if app.currently_selected: app.showtext("Selected node: %s" % app.currently_selected, 10, app.h - 50) pos = app.h - 70 app.showtext("(%sm, %sm, %sm)" % (app.currently_selected.transformation[0, 3], app.currently_selected.transformation[1, 3], app.currently_selected.transformation[2, 3]), 30, pos) app.switch_from_overlay() # Make sure we do not go over 30fps clock.tick(30) logger.info("Quitting! Bye bye!") ######################################################################### ######################################################################### if __name__ == '__main__': if not len(sys.argv) > 1: print("Usage: " + __file__ + " ") sys.exit(2) main(model=sys.argv[1], width=1024, height=768) assimp-4.1.0/port/PyAssimp/scripts/README.md0000644002537200234200000000077213213503245020761 0ustar zmoelnigiemuserspyassimp examples ================= - `sample.py`: shows how to load a model with pyassimp, and display some statistics. - `3d_viewer.py`: an OpenGL 3D viewer that requires shaders - `fixed_pipeline_3d_viewer`: an OpenGL 3D viewer using the old fixed-pipeline. Only for illustration example. Base new projects on `3d_viewer.py`. Requirements for the 3D viewers: - `pyopengl` (on Ubuntu/Debian, `sudo apt-get install python-opengl`) - `pygame` (on Ubuntu/Debian, `sudo apt-get install python-pygame`) assimp-4.1.0/port/PyAssimp/scripts/quicktest.py0000755002537200234200000000332213213503245022065 0ustar zmoelnigiemusers#!/usr/bin/env python #-*- coding: UTF-8 -*- """ This module uses the sample.py script to load all test models it finds. Note: this is not an exhaustive test suite, it does not check the data structures in detail. It just verifies whether basic loading and querying of 3d models using pyassimp works. """ import os import sys # Make the development (ie. GIT repo) version of PyAssimp available for import. sys.path.insert(0, '..') import sample from pyassimp import errors # Paths to model files. basepaths = [os.path.join('..', '..', '..', 'test', 'models'), os.path.join('..', '..', '..', 'test', 'models-nonbsd')] # Valid extensions for 3D model files. extensions = ['.3ds', '.x', '.lwo', '.obj', '.md5mesh', '.dxf', '.ply', '.stl', '.dae', '.md5anim', '.lws', '.irrmesh', '.nff', '.off', '.blend'] def run_tests(): ok, err = 0, 0 for path in basepaths: print("Looking for models in %s..." % path) for root, dirs, files in os.walk(path): for afile in files: base, ext = os.path.splitext(afile) if ext in extensions: try: sample.main(os.path.join(root, afile)) ok += 1 except errors.AssimpError as error: # Assimp error is fine; this is a controlled case. print(error) err += 1 except Exception: print("Error encountered while loading <%s>" % os.path.join(root, afile)) print('** Loaded %s models, got controlled errors for %s files' % (ok, err)) if __name__ == '__main__': run_tests() assimp-4.1.0/port/PyAssimp/scripts/3d_viewer_py3.py0000755002537200234200000012122413213503245022535 0ustar zmoelnigiemusers#!/usr/bin/env python # -*- coding: UTF-8 -*- """ This program loads a model with PyASSIMP, and display it. Based on: - pygame code from http://3dengine.org/Spectator_%28PyOpenGL%29 - http://www.lighthouse3d.com/tutorials - http://www.songho.ca/opengl/gl_transform.html - http://code.activestate.com/recipes/325391/ - ASSIMP's C++ SimpleOpenGL viewer Authors: Séverin Lemaignan, 2012-2016 """ import sys import logging from functools import reduce logger = logging.getLogger("pyassimp") gllogger = logging.getLogger("OpenGL") gllogger.setLevel(logging.WARNING) logging.basicConfig(level=logging.INFO) import OpenGL OpenGL.ERROR_CHECKING = False OpenGL.ERROR_LOGGING = False # OpenGL.ERROR_ON_COPY = True # OpenGL.FULL_LOGGING = True from OpenGL.GL import * from OpenGL.arrays import vbo from OpenGL.GL import shaders import pygame import pygame.font import pygame.image import math, random from numpy import linalg import pyassimp from pyassimp.postprocess import * from pyassimp.helper import * import transformations ROTATION_180_X = numpy.array([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]], dtype=numpy.float32) # rendering mode BASE = "BASE" COLORS = "COLORS" SILHOUETTE = "SILHOUETTE" HELPERS = "HELPERS" # Entities type ENTITY = "entity" CAMERA = "camera" MESH = "mesh" FLAT_VERTEX_SHADER_120 = """ #version 120 uniform mat4 u_viewProjectionMatrix; uniform mat4 u_modelMatrix; uniform vec4 u_materialDiffuse; attribute vec3 a_vertex; varying vec4 v_color; void main(void) { v_color = u_materialDiffuse; gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); } """ FLAT_VERTEX_SHADER_130 = """ #version 130 uniform mat4 u_viewProjectionMatrix; uniform mat4 u_modelMatrix; uniform vec4 u_materialDiffuse; in vec3 a_vertex; out vec4 v_color; void main(void) { v_color = u_materialDiffuse; gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); } """ BASIC_VERTEX_SHADER_120 = """ #version 120 uniform mat4 u_viewProjectionMatrix; uniform mat4 u_modelMatrix; uniform mat3 u_normalMatrix; uniform vec3 u_lightPos; uniform vec4 u_materialDiffuse; attribute vec3 a_vertex; attribute vec3 a_normal; varying vec4 v_color; void main(void) { // Now the normal is in world space, as we pass the light in world space. vec3 normal = u_normalMatrix * a_normal; float dist = distance(a_vertex, u_lightPos); // go to https://www.desmos.com/calculator/nmnaud1hrw to play with the parameters // att is not used for now float att=1.0/(1.0+0.8*dist*dist); vec3 surf2light = normalize(u_lightPos - a_vertex); vec3 norm = normalize(normal); float dcont=max(0.0,dot(norm,surf2light)); float ambient = 0.3; float intensity = dcont + 0.3 + ambient; v_color = u_materialDiffuse * intensity; gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); } """ BASIC_VERTEX_SHADER_130 = """ #version 130 uniform mat4 u_viewProjectionMatrix; uniform mat4 u_modelMatrix; uniform mat3 u_normalMatrix; uniform vec3 u_lightPos; uniform vec4 u_materialDiffuse; in vec3 a_vertex; in vec3 a_normal; out vec4 v_color; void main(void) { // Now the normal is in world space, as we pass the light in world space. vec3 normal = u_normalMatrix * a_normal; float dist = distance(a_vertex, u_lightPos); // go to https://www.desmos.com/calculator/nmnaud1hrw to play with the parameters // att is not used for now float att=1.0/(1.0+0.8*dist*dist); vec3 surf2light = normalize(u_lightPos - a_vertex); vec3 norm = normalize(normal); float dcont=max(0.0,dot(norm,surf2light)); float ambient = 0.3; float intensity = dcont + 0.3 + ambient; v_color = u_materialDiffuse * intensity; gl_Position = u_viewProjectionMatrix * u_modelMatrix * vec4(a_vertex, 1.0); } """ BASIC_FRAGMENT_SHADER_120 = """ #version 120 varying vec4 v_color; void main() { gl_FragColor = v_color; } """ BASIC_FRAGMENT_SHADER_130 = """ #version 130 in vec4 v_color; void main() { gl_FragColor = v_color; } """ GOOCH_VERTEX_SHADER_120 = """ #version 120 // attributes attribute vec3 a_vertex; // xyz - position attribute vec3 a_normal; // xyz - normal // uniforms uniform mat4 u_modelMatrix; uniform mat4 u_viewProjectionMatrix; uniform mat3 u_normalMatrix; uniform vec3 u_lightPos; uniform vec3 u_camPos; // output data from vertex to fragment shader varying vec3 o_normal; varying vec3 o_lightVector; /////////////////////////////////////////////////////////////////// void main(void) { // transform position and normal to world space vec4 positionWorld = u_modelMatrix * vec4(a_vertex, 1.0); vec3 normalWorld = u_normalMatrix * a_normal; // calculate and pass vectors required for lighting o_lightVector = u_lightPos - positionWorld.xyz; o_normal = normalWorld; // project world space position to the screen and output it gl_Position = u_viewProjectionMatrix * positionWorld; } """ GOOCH_VERTEX_SHADER_130 = """ #version 130 // attributes in vec3 a_vertex; // xyz - position in vec3 a_normal; // xyz - normal // uniforms uniform mat4 u_modelMatrix; uniform mat4 u_viewProjectionMatrix; uniform mat3 u_normalMatrix; uniform vec3 u_lightPos; uniform vec3 u_camPos; // output data from vertex to fragment shader out vec3 o_normal; out vec3 o_lightVector; /////////////////////////////////////////////////////////////////// void main(void) { // transform position and normal to world space vec4 positionWorld = u_modelMatrix * vec4(a_vertex, 1.0); vec3 normalWorld = u_normalMatrix * a_normal; // calculate and pass vectors required for lighting o_lightVector = u_lightPos - positionWorld.xyz; o_normal = normalWorld; // project world space position to the screen and output it gl_Position = u_viewProjectionMatrix * positionWorld; } """ GOOCH_FRAGMENT_SHADER_120 = """ #version 120 // data from vertex shader varying vec3 o_normal; varying vec3 o_lightVector; // diffuse color of the object uniform vec4 u_materialDiffuse; // cool color of gooch shading uniform vec3 u_coolColor; // warm color of gooch shading uniform vec3 u_warmColor; // how much to take from object color in final cool color uniform float u_alpha; // how much to take from object color in final warm color uniform float u_beta; /////////////////////////////////////////////////////////// void main(void) { // normlize vectors for lighting vec3 normalVector = normalize(o_normal); vec3 lightVector = normalize(o_lightVector); // intensity of diffuse lighting [-1, 1] float diffuseLighting = dot(lightVector, normalVector); // map intensity of lighting from range [-1; 1] to [0, 1] float interpolationValue = (1.0 + diffuseLighting)/2; ////////////////////////////////////////////////////////////////// // cool color mixed with color of the object vec3 coolColorMod = u_coolColor + vec3(u_materialDiffuse) * u_alpha; // warm color mixed with color of the object vec3 warmColorMod = u_warmColor + vec3(u_materialDiffuse) * u_beta; // interpolation of cool and warm colors according // to lighting intensity. The lower the light intensity, // the larger part of the cool color is used vec3 colorOut = mix(coolColorMod, warmColorMod, interpolationValue); ////////////////////////////////////////////////////////////////// // save color gl_FragColor.rgb = colorOut; gl_FragColor.a = 1; } """ GOOCH_FRAGMENT_SHADER_130 = """ #version 130 // data from vertex shader in vec3 o_normal; in vec3 o_lightVector; // diffuse color of the object uniform vec4 u_materialDiffuse; // cool color of gooch shading uniform vec3 u_coolColor; // warm color of gooch shading uniform vec3 u_warmColor; // how much to take from object color in final cool color uniform float u_alpha; // how much to take from object color in final warm color uniform float u_beta; // output to framebuffer out vec4 resultingColor; /////////////////////////////////////////////////////////// void main(void) { // normlize vectors for lighting vec3 normalVector = normalize(o_normal); vec3 lightVector = normalize(o_lightVector); // intensity of diffuse lighting [-1, 1] float diffuseLighting = dot(lightVector, normalVector); // map intensity of lighting from range [-1; 1] to [0, 1] float interpolationValue = (1.0 + diffuseLighting)/2; ////////////////////////////////////////////////////////////////// // cool color mixed with color of the object vec3 coolColorMod = u_coolColor + vec3(u_materialDiffuse) * u_alpha; // warm color mixed with color of the object vec3 warmColorMod = u_warmColor + vec3(u_materialDiffuse) * u_beta; // interpolation of cool and warm colors according // to lighting intensity. The lower the light intensity, // the larger part of the cool color is used vec3 colorOut = mix(coolColorMod, warmColorMod, interpolationValue); ////////////////////////////////////////////////////////////////// // save color resultingColor.rgb = colorOut; resultingColor.a = 1; } """ SILHOUETTE_VERTEX_SHADER_120 = """ #version 120 attribute vec3 a_vertex; // xyz - position attribute vec3 a_normal; // xyz - normal uniform mat4 u_modelMatrix; uniform mat4 u_viewProjectionMatrix; uniform mat4 u_modelViewMatrix; uniform vec4 u_materialDiffuse; uniform float u_bordersize; // width of the border varying vec4 v_color; void main(void){ v_color = u_materialDiffuse; float distToCamera = -(u_modelViewMatrix * vec4(a_vertex, 1.0)).z; vec4 tPos = vec4(a_vertex + a_normal * u_bordersize * distToCamera, 1.0); gl_Position = u_viewProjectionMatrix * u_modelMatrix * tPos; } """ SILHOUETTE_VERTEX_SHADER_130 = """ #version 130 in vec3 a_vertex; // xyz - position in vec3 a_normal; // xyz - normal uniform mat4 u_modelMatrix; uniform mat4 u_viewProjectionMatrix; uniform mat4 u_modelViewMatrix; uniform vec4 u_materialDiffuse; uniform float u_bordersize; // width of the border out vec4 v_color; void main(void){ v_color = u_materialDiffuse; float distToCamera = -(u_modelViewMatrix * vec4(a_vertex, 1.0)).z; vec4 tPos = vec4(a_vertex + a_normal * u_bordersize * distToCamera, 1.0); gl_Position = u_viewProjectionMatrix * u_modelMatrix * tPos; } """ DEFAULT_CLIP_PLANE_NEAR = 0.001 DEFAULT_CLIP_PLANE_FAR = 1000.0 def get_world_transform(scene, node): if node == scene.rootnode: return numpy.identity(4, dtype=numpy.float32) parents = reversed(_get_parent_chain(scene, node, [])) parent_transform = reduce(numpy.dot, [p.transformation for p in parents]) return numpy.dot(parent_transform, node.transformation) def _get_parent_chain(scene, node, parents): parent = node.parent parents.append(parent) if parent == scene.rootnode: return parents return _get_parent_chain(scene, parent, parents) class DefaultCamera: def __init__(self, w, h, fov): self.name = "default camera" self.type = CAMERA self.clipplanenear = DEFAULT_CLIP_PLANE_NEAR self.clipplanefar = DEFAULT_CLIP_PLANE_FAR self.aspect = w / h self.horizontalfov = fov * math.pi / 180 self.transformation = numpy.array([[0.68, -0.32, 0.65, 7.48], [0.73, 0.31, -0.61, -6.51], [-0.01, 0.89, 0.44, 5.34], [0., 0., 0., 1.]], dtype=numpy.float32) self.transformation = numpy.dot(self.transformation, ROTATION_180_X) def __str__(self): return self.name class PyAssimp3DViewer: base_name = "PyASSIMP 3D viewer" def __init__(self, model, w=1024, h=768): self.w = w self.h = h pygame.init() pygame.display.set_caption(self.base_name) pygame.display.set_mode((w, h), pygame.OPENGL | pygame.DOUBLEBUF) glClearColor(0.18, 0.18, 0.18, 1.0) shader_compilation_succeeded = False try: self.set_shaders_v130() self.prepare_shaders() except RuntimeError, message: sys.stderr.write("%s\n" % message) sys.stdout.write("Could not compile shaders in version 1.30, trying version 1.20\n") if not shader_compilation_succeeded: self.set_shaders_v120() self.prepare_shaders() self.scene = None self.meshes = {} # stores the OpenGL vertex/faces/normals buffers pointers self.node2colorid = {} # stores a color ID for each node. Useful for mouse picking and visibility checking self.colorid2node = {} # reverse dict of node2colorid self.currently_selected = None self.moving = False self.moving_situation = None self.default_camera = DefaultCamera(self.w, self.h, fov=70) self.cameras = [self.default_camera] self.current_cam_index = 0 self.current_cam = self.default_camera self.set_camera_projection() self.load_model(model) # user interactions self.focal_point = [0, 0, 0] self.is_rotating = False self.is_panning = False self.is_zooming = False def set_shaders_v120(self): self.BASIC_VERTEX_SHADER = BASIC_VERTEX_SHADER_120 self.FLAT_VERTEX_SHADER = FLAT_VERTEX_SHADER_120 self.SILHOUETTE_VERTEX_SHADER = SILHOUETTE_VERTEX_SHADER_120 self.GOOCH_VERTEX_SHADER = GOOCH_VERTEX_SHADER_120 self.BASIC_FRAGMENT_SHADER = BASIC_FRAGMENT_SHADER_120 self.GOOCH_FRAGMENT_SHADER = GOOCH_FRAGMENT_SHADER_120 def set_shaders_v130(self): self.BASIC_VERTEX_SHADER = BASIC_VERTEX_SHADER_130 self.FLAT_VERTEX_SHADER = FLAT_VERTEX_SHADER_130 self.SILHOUETTE_VERTEX_SHADER = SILHOUETTE_VERTEX_SHADER_130 self.GOOCH_VERTEX_SHADER = GOOCH_VERTEX_SHADER_130 self.BASIC_FRAGMENT_SHADER = BASIC_FRAGMENT_SHADER_130 self.GOOCH_FRAGMENT_SHADER = GOOCH_FRAGMENT_SHADER_130 def prepare_shaders(self): ### Base shader vertex = shaders.compileShader(self.BASIC_VERTEX_SHADER, GL_VERTEX_SHADER) fragment = shaders.compileShader(self.BASIC_FRAGMENT_SHADER, GL_FRAGMENT_SHADER) self.shader = shaders.compileProgram(vertex, fragment) self.set_shader_accessors(('u_modelMatrix', 'u_viewProjectionMatrix', 'u_normalMatrix', 'u_lightPos', 'u_materialDiffuse'), ('a_vertex', 'a_normal'), self.shader) ### Flat shader flatvertex = shaders.compileShader(self.FLAT_VERTEX_SHADER, GL_VERTEX_SHADER) self.flatshader = shaders.compileProgram(flatvertex, fragment) self.set_shader_accessors(('u_modelMatrix', 'u_viewProjectionMatrix', 'u_materialDiffuse',), ('a_vertex',), self.flatshader) ### Silhouette shader silh_vertex = shaders.compileShader(self.SILHOUETTE_VERTEX_SHADER, GL_VERTEX_SHADER) self.silhouette_shader = shaders.compileProgram(silh_vertex, fragment) self.set_shader_accessors(('u_modelMatrix', 'u_viewProjectionMatrix', 'u_modelViewMatrix', 'u_materialDiffuse', 'u_bordersize' # width of the silhouette ), ('a_vertex', 'a_normal'), self.silhouette_shader) ### Gooch shader gooch_vertex = shaders.compileShader(self.GOOCH_VERTEX_SHADER, GL_VERTEX_SHADER) gooch_fragment = shaders.compileShader(self.GOOCH_FRAGMENT_SHADER, GL_FRAGMENT_SHADER) self.gooch_shader = shaders.compileProgram(gooch_vertex, gooch_fragment) self.set_shader_accessors(('u_modelMatrix', 'u_viewProjectionMatrix', 'u_normalMatrix', 'u_lightPos', 'u_materialDiffuse', 'u_coolColor', 'u_warmColor', 'u_alpha', 'u_beta' ), ('a_vertex', 'a_normal'), self.gooch_shader) @staticmethod def set_shader_accessors(uniforms, attributes, shader): # add accessors to the shaders uniforms and attributes for uniform in uniforms: location = glGetUniformLocation(shader, uniform) if location in (None, -1): raise RuntimeError('No uniform: %s (maybe it is not used ' 'anymore and has been optimized out by' ' the shader compiler)' % uniform) setattr(shader, uniform, location) for attribute in attributes: location = glGetAttribLocation(shader, attribute) if location in (None, -1): raise RuntimeError('No attribute: %s' % attribute) setattr(shader, attribute, location) @staticmethod def prepare_gl_buffers(mesh): mesh.gl = {} # Fill the buffer for vertex and normals positions v = numpy.array(mesh.vertices, 'f') n = numpy.array(mesh.normals, 'f') mesh.gl["vbo"] = vbo.VBO(numpy.hstack((v, n))) # Fill the buffer for vertex positions mesh.gl["faces"] = glGenBuffers(1) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) glBufferData(GL_ELEMENT_ARRAY_BUFFER, numpy.array(mesh.faces, dtype=numpy.int32), GL_STATIC_DRAW) mesh.gl["nbfaces"] = len(mesh.faces) # Unbind buffers glBindBuffer(GL_ARRAY_BUFFER, 0) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) @staticmethod def get_rgb_from_colorid(colorid): r = (colorid >> 0) & 0xff g = (colorid >> 8) & 0xff b = (colorid >> 16) & 0xff return r, g, b def get_color_id(self): id = random.randint(0, 256 * 256 * 256) if id not in self.colorid2node: return id else: return self.get_color_id() def glize(self, scene, node): logger.info("Loading node <%s>" % node) node.selected = True if self.currently_selected and self.currently_selected == node else False node.transformation = node.transformation.astype(numpy.float32) if node.meshes: node.type = MESH colorid = self.get_color_id() self.colorid2node[colorid] = node self.node2colorid[node.name] = colorid elif node.name in [c.name for c in scene.cameras]: # retrieve the ASSIMP camera object [cam] = [c for c in scene.cameras if c.name == node.name] node.type = CAMERA logger.info("Added camera <%s>" % node.name) logger.info("Camera position: %.3f, %.3f, %.3f" % tuple(node.transformation[:, 3][:3].tolist())) self.cameras.append(node) node.clipplanenear = cam.clipplanenear node.clipplanefar = cam.clipplanefar if numpy.allclose(cam.lookat, [0, 0, -1]) and numpy.allclose(cam.up, [0, 1, 0]): # Cameras in .blend files # Rotate by 180deg around X to have Z pointing forward node.transformation = numpy.dot(node.transformation, ROTATION_180_X) else: raise RuntimeError( "I do not know how to normalize this camera orientation: lookat=%s, up=%s" % (cam.lookat, cam.up)) if cam.aspect == 0.0: logger.warning("Camera aspect not set. Setting to default 4:3") node.aspect = 1.333 else: node.aspect = cam.aspect node.horizontalfov = cam.horizontalfov else: node.type = ENTITY for child in node.children: self.glize(scene, child) def load_model(self, path, postprocess=aiProcessPreset_TargetRealtime_MaxQuality): logger.info("Loading model:" + path + "...") if postprocess: self.scene = pyassimp.load(path, processing=postprocess) else: self.scene = pyassimp.load(path) logger.info("Done.") scene = self.scene # log some statistics logger.info(" meshes: %d" % len(scene.meshes)) logger.info(" total faces: %d" % sum([len(mesh.faces) for mesh in scene.meshes])) logger.info(" materials: %d" % len(scene.materials)) self.bb_min, self.bb_max = get_bounding_box(self.scene) logger.info(" bounding box:" + str(self.bb_min) + " - " + str(self.bb_max)) self.scene_center = [(a + b) / 2. for a, b in zip(self.bb_min, self.bb_max)] for index, mesh in enumerate(scene.meshes): self.prepare_gl_buffers(mesh) self.glize(scene, scene.rootnode) # Finally release the model pyassimp.release(scene) logger.info("Ready for 3D rendering!") def cycle_cameras(self): self.current_cam_index = (self.current_cam_index + 1) % len(self.cameras) self.current_cam = self.cameras[self.current_cam_index] self.set_camera_projection(self.current_cam) logger.info("Switched to camera <%s>" % self.current_cam) def set_overlay_projection(self): glViewport(0, 0, self.w, self.h) glMatrixMode(GL_PROJECTION) glLoadIdentity() glOrtho(0.0, self.w - 1.0, 0.0, self.h - 1.0, -1.0, 1.0) glMatrixMode(GL_MODELVIEW) glLoadIdentity() def set_camera_projection(self, camera=None): if not camera: camera = self.current_cam znear = camera.clipplanenear or DEFAULT_CLIP_PLANE_NEAR zfar = camera.clipplanefar or DEFAULT_CLIP_PLANE_FAR aspect = camera.aspect fov = camera.horizontalfov glMatrixMode(GL_PROJECTION) glLoadIdentity() # Compute gl frustrum tangent = math.tan(fov / 2.) h = znear * tangent w = h * aspect # params: left, right, bottom, top, near, far glFrustum(-w, w, -h, h, znear, zfar) # equivalent to: # gluPerspective(fov * 180/math.pi, aspect, znear, zfar) self.projection_matrix = glGetFloatv(GL_PROJECTION_MATRIX).transpose() glMatrixMode(GL_MODELVIEW) glLoadIdentity() def render_colors(self): glEnable(GL_DEPTH_TEST) glDepthFunc(GL_LEQUAL) glPolygonMode(GL_FRONT_AND_BACK, GL_FILL) glEnable(GL_CULL_FACE) glUseProgram(self.flatshader) glUniformMatrix4fv(self.flatshader.u_viewProjectionMatrix, 1, GL_TRUE, numpy.dot(self.projection_matrix, self.view_matrix)) self.recursive_render(self.scene.rootnode, self.flatshader, mode=COLORS) glUseProgram(0) def get_hovered_node(self, mousex, mousey): """ Attention: The performances of this method relies heavily on the size of the display! """ # mouse out of the window? if mousex < 0 or mousex >= self.w or mousey < 0 or mousey >= self.h: return None self.render_colors() # Capture image from the OpenGL buffer buf = (GLubyte * (3 * self.w * self.h))(0) glReadPixels(0, 0, self.w, self.h, GL_RGB, GL_UNSIGNED_BYTE, buf) # Reinterpret the RGB pixel buffer as a 1-D array of 24bits colors a = numpy.ndarray(len(buf), numpy.dtype('>u1'), buf) colors = numpy.zeros(len(buf) // 3, numpy.dtype('u1')[i::3] colorid = colors[mousex + mousey * self.w] glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) if colorid in self.colorid2node: return self.colorid2node[colorid] def render(self, wireframe=False, twosided=False): glEnable(GL_DEPTH_TEST) glDepthFunc(GL_LEQUAL) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE if wireframe else GL_FILL) glDisable(GL_CULL_FACE) if twosided else glEnable(GL_CULL_FACE) self.render_grid() self.recursive_render(self.scene.rootnode, None, mode=HELPERS) ### First, the silhouette if False: shader = self.silhouette_shader # glDepthMask(GL_FALSE) glCullFace(GL_FRONT) # cull front faces glUseProgram(shader) glUniform1f(shader.u_bordersize, 0.01) glUniformMatrix4fv(shader.u_viewProjectionMatrix, 1, GL_TRUE, numpy.dot(self.projection_matrix, self.view_matrix)) self.recursive_render(self.scene.rootnode, shader, mode=SILHOUETTE) glUseProgram(0) ### Then, inner shading # glDepthMask(GL_TRUE) glCullFace(GL_BACK) use_gooch = False if use_gooch: shader = self.gooch_shader glUseProgram(shader) glUniform3f(shader.u_lightPos, -.5, -.5, .5) ##### GOOCH specific glUniform3f(shader.u_coolColor, 159.0 / 255, 148.0 / 255, 255.0 / 255) glUniform3f(shader.u_warmColor, 255.0 / 255, 75.0 / 255, 75.0 / 255) glUniform1f(shader.u_alpha, .25) glUniform1f(shader.u_beta, .25) ######### else: shader = self.shader glUseProgram(shader) glUniform3f(shader.u_lightPos, -.5, -.5, .5) glUniformMatrix4fv(shader.u_viewProjectionMatrix, 1, GL_TRUE, numpy.dot(self.projection_matrix, self.view_matrix)) self.recursive_render(self.scene.rootnode, shader) glUseProgram(0) def render_axis(self, transformation=numpy.identity(4, dtype=numpy.float32), label=None, size=0.2, selected=False): m = transformation.transpose() # OpenGL row major glPushMatrix() glMultMatrixf(m) glLineWidth(3 if selected else 1) size = 2 * size if selected else size glBegin(GL_LINES) # draw line for x axis glColor3f(1.0, 0.0, 0.0) glVertex3f(0.0, 0.0, 0.0) glVertex3f(size, 0.0, 0.0) # draw line for y axis glColor3f(0.0, 1.0, 0.0) glVertex3f(0.0, 0.0, 0.0) glVertex3f(0.0, size, 0.0) # draw line for Z axis glColor3f(0.0, 0.0, 1.0) glVertex3f(0.0, 0.0, 0.0) glVertex3f(0.0, 0.0, size) glEnd() if label: self.showtext(label) glPopMatrix() @staticmethod def render_camera(camera, transformation): m = transformation.transpose() # OpenGL row major aspect = camera.aspect u = 0.1 # unit size (in m) l = 3 * u # length of the camera cone f = 3 * u # aperture of the camera cone glPushMatrix() glMultMatrixf(m) glLineWidth(2) glBegin(GL_LINE_STRIP) glColor3f(.2, .2, .2) glVertex3f(u, u, -u) glVertex3f(u, -u, -u) glVertex3f(-u, -u, -u) glVertex3f(-u, u, -u) glVertex3f(u, u, -u) glVertex3f(u, u, 0.0) glVertex3f(u, -u, 0.0) glVertex3f(-u, -u, 0.0) glVertex3f(-u, u, 0.0) glVertex3f(u, u, 0.0) glVertex3f(f * aspect, f, l) glVertex3f(f * aspect, -f, l) glVertex3f(-f * aspect, -f, l) glVertex3f(-f * aspect, f, l) glVertex3f(f * aspect, f, l) glEnd() glBegin(GL_LINE_STRIP) glVertex3f(u, -u, -u) glVertex3f(u, -u, 0.0) glVertex3f(f * aspect, -f, l) glEnd() glBegin(GL_LINE_STRIP) glVertex3f(-u, -u, -u) glVertex3f(-u, -u, 0.0) glVertex3f(-f * aspect, -f, l) glEnd() glBegin(GL_LINE_STRIP) glVertex3f(-u, u, -u) glVertex3f(-u, u, 0.0) glVertex3f(-f * aspect, f, l) glEnd() glPopMatrix() @staticmethod def render_grid(): glLineWidth(1) glColor3f(0.5, 0.5, 0.5) glBegin(GL_LINES) for i in range(-10, 11): glVertex3f(i, -10.0, 0.0) glVertex3f(i, 10.0, 0.0) for i in range(-10, 11): glVertex3f(-10.0, i, 0.0) glVertex3f(10.0, i, 0.0) glEnd() def recursive_render(self, node, shader, mode=BASE, with_normals=True): """ Main recursive rendering method. """ normals = with_normals if mode == COLORS: normals = False if not hasattr(node, "selected"): node.selected = False m = get_world_transform(self.scene, node) # HELPERS mode ### if mode == HELPERS: # if node.type == ENTITY: self.render_axis(m, label=node.name if node != self.scene.rootnode else None, selected=node.selected if hasattr(node, "selected") else False) if node.type == CAMERA: self.render_camera(node, m) for child in node.children: self.recursive_render(child, shader, mode) return # Mesh rendering modes ### if node.type == MESH: for mesh in node.meshes: stride = 24 # 6 * 4 bytes if node.selected and mode == SILHOUETTE: glUniform4f(shader.u_materialDiffuse, 1.0, 0.0, 0.0, 1.0) glUniformMatrix4fv(shader.u_modelViewMatrix, 1, GL_TRUE, numpy.dot(self.view_matrix, m)) else: if mode == COLORS: colorid = self.node2colorid[node.name] r, g, b = self.get_rgb_from_colorid(colorid) glUniform4f(shader.u_materialDiffuse, r / 255.0, g / 255.0, b / 255.0, 1.0) elif mode == SILHOUETTE: glUniform4f(shader.u_materialDiffuse, .0, .0, .0, 1.0) else: if node.selected: diffuse = (1.0, 0.0, 0.0, 1.0) # selected nodes in red else: diffuse = mesh.material.properties["diffuse"] if len(diffuse) == 3: # RGB instead of expected RGBA diffuse.append(1.0) glUniform4f(shader.u_materialDiffuse, *diffuse) # if ambient: # glUniform4f( shader.Material_ambient, *mat["ambient"] ) if mode == BASE: # not in COLORS or SILHOUETTE normal_matrix = linalg.inv(numpy.dot(self.view_matrix, m)[0:3, 0:3]).transpose() glUniformMatrix3fv(shader.u_normalMatrix, 1, GL_TRUE, normal_matrix) glUniformMatrix4fv(shader.u_modelMatrix, 1, GL_TRUE, m) vbo = mesh.gl["vbo"] vbo.bind() glEnableVertexAttribArray(shader.a_vertex) if normals: glEnableVertexAttribArray(shader.a_normal) glVertexAttribPointer( shader.a_vertex, 3, GL_FLOAT, False, stride, vbo ) if normals: glVertexAttribPointer( shader.a_normal, 3, GL_FLOAT, False, stride, vbo + 12 ) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh.gl["faces"]) glDrawElements(GL_TRIANGLES, mesh.gl["nbfaces"] * 3, GL_UNSIGNED_INT, None) vbo.unbind() glDisableVertexAttribArray(shader.a_vertex) if normals: glDisableVertexAttribArray(shader.a_normal) glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0) for child in node.children: self.recursive_render(child, shader, mode) def switch_to_overlay(self): glPushMatrix() self.set_overlay_projection() def switch_from_overlay(self): self.set_camera_projection() glPopMatrix() def select_node(self, node): self.currently_selected = node self.update_node_select(self.scene.rootnode) def update_node_select(self, node): if node is self.currently_selected: node.selected = True else: node.selected = False for child in node.children: self.update_node_select(child) def loop(self): pygame.display.flip() if not self.process_events(): return False # ESC has been pressed glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) return True def process_events(self): LEFT_BUTTON = 1 MIDDLE_BUTTON = 2 RIGHT_BUTTON = 3 WHEEL_UP = 4 WHEEL_DOWN = 5 dx, dy = pygame.mouse.get_rel() mousex, mousey = pygame.mouse.get_pos() zooming_one_shot = False ok = True for evt in pygame.event.get(): if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == LEFT_BUTTON: hovered = self.get_hovered_node(mousex, self.h - mousey) if hovered: if self.currently_selected and self.currently_selected == hovered: self.select_node(None) else: logger.info("Node %s selected" % hovered) self.select_node(hovered) else: self.is_rotating = True if evt.type == pygame.MOUSEBUTTONUP and evt.button == LEFT_BUTTON: self.is_rotating = False if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == MIDDLE_BUTTON: self.is_panning = True if evt.type == pygame.MOUSEBUTTONUP and evt.button == MIDDLE_BUTTON: self.is_panning = False if evt.type == pygame.MOUSEBUTTONDOWN and evt.button == RIGHT_BUTTON: self.is_zooming = True if evt.type == pygame.MOUSEBUTTONUP and evt.button == RIGHT_BUTTON: self.is_zooming = False if evt.type == pygame.MOUSEBUTTONDOWN and evt.button in [WHEEL_UP, WHEEL_DOWN]: zooming_one_shot = True self.is_zooming = True dy = -10 if evt.button == WHEEL_UP else 10 if evt.type == pygame.KEYDOWN: ok = (ok and self.process_keystroke(evt.key, evt.mod)) self.controls_3d(dx, dy, zooming_one_shot) return ok def process_keystroke(self, key, mod): # process arrow keys if an object is selected if self.currently_selected: up = 0 strafe = 0 if key == pygame.K_UP: up = 1 if key == pygame.K_DOWN: up = -1 if key == pygame.K_LEFT: strafe = -1 if key == pygame.K_RIGHT: strafe = 1 self.move_selected_node(up, strafe) if key == pygame.K_f: pygame.display.toggle_fullscreen() if key == pygame.K_TAB: self.cycle_cameras() if key in [pygame.K_ESCAPE, pygame.K_q]: return False return True def controls_3d(self, dx, dy, zooming_one_shot=False): CAMERA_TRANSLATION_FACTOR = 0.01 CAMERA_ROTATION_FACTOR = 0.01 if not (self.is_rotating or self.is_panning or self.is_zooming): return current_pos = self.current_cam.transformation[:3, 3].copy() distance = numpy.linalg.norm(self.focal_point - current_pos) if self.is_rotating: """ Orbiting the camera is implemented the following way: - the rotation is split into a rotation around the *world* Z axis (controlled by the horizontal mouse motion along X) and a rotation around the *X* axis of the camera (pitch) *shifted to the focal origin* (the world origin for now). This is controlled by the vertical motion of the mouse (Y axis). - as a result, the resulting transformation of the camera in the world frame C' is: C' = (T · Rx · T⁻¹ · (Rz · C)⁻¹)⁻¹ where: - C is the original camera transformation in the world frame, - Rz is the rotation along the Z axis (in the world frame) - T is the translation camera -> world (ie, the inverse of the translation part of C - Rx is the rotation around X in the (translated) camera frame """ rotation_camera_x = dy * CAMERA_ROTATION_FACTOR rotation_world_z = dx * CAMERA_ROTATION_FACTOR world_z_rotation = transformations.euler_matrix(0, 0, rotation_world_z) cam_x_rotation = transformations.euler_matrix(rotation_camera_x, 0, 0) after_world_z_rotation = numpy.dot(world_z_rotation, self.current_cam.transformation) inverse_transformation = transformations.inverse_matrix(after_world_z_rotation) translation = transformations.translation_matrix( transformations.decompose_matrix(inverse_transformation)[3]) inverse_translation = transformations.inverse_matrix(translation) new_inverse = numpy.dot(inverse_translation, inverse_transformation) new_inverse = numpy.dot(cam_x_rotation, new_inverse) new_inverse = numpy.dot(translation, new_inverse) self.current_cam.transformation = transformations.inverse_matrix(new_inverse).astype(numpy.float32) if self.is_panning: tx = -dx * CAMERA_TRANSLATION_FACTOR * distance ty = dy * CAMERA_TRANSLATION_FACTOR * distance cam_transform = transformations.translation_matrix((tx, ty, 0)).astype(numpy.float32) self.current_cam.transformation = numpy.dot(self.current_cam.transformation, cam_transform) if self.is_zooming: tz = dy * CAMERA_TRANSLATION_FACTOR * distance cam_transform = transformations.translation_matrix((0, 0, tz)).astype(numpy.float32) self.current_cam.transformation = numpy.dot(self.current_cam.transformation, cam_transform) if zooming_one_shot: self.is_zooming = False self.update_view_camera() def update_view_camera(self): self.view_matrix = linalg.inv(self.current_cam.transformation) # Rotate by 180deg around X to have Z pointing backward (OpenGL convention) self.view_matrix = numpy.dot(ROTATION_180_X, self.view_matrix) glMatrixMode(GL_MODELVIEW) glLoadIdentity() glMultMatrixf(self.view_matrix.transpose()) def move_selected_node(self, up, strafe): self.currently_selected.transformation[0][3] += strafe self.currently_selected.transformation[2][3] += up @staticmethod def showtext(text, x=0, y=0, z=0, size=20): # TODO: alpha blending does not work... # glEnable(GL_BLEND) # glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA) font = pygame.font.Font(None, size) text_surface = font.render(text, True, (10, 10, 10, 255), (255 * 0.18, 255 * 0.18, 255 * 0.18, 0)) text_data = pygame.image.tostring(text_surface, "RGBA", True) glRasterPos3d(x, y, z) glDrawPixels(text_surface.get_width(), text_surface.get_height(), GL_RGBA, GL_UNSIGNED_BYTE, text_data) # glDisable(GL_BLEND) def main(model, width, height): app = PyAssimp3DViewer(model, w=width, h=height) clock = pygame.time.Clock() while app.loop(): app.update_view_camera() ## Main rendering app.render() ## GUI text display app.switch_to_overlay() app.showtext("Active camera: %s" % str(app.current_cam), 10, app.h - 30) if app.currently_selected: app.showtext("Selected node: %s" % app.currently_selected, 10, app.h - 50) pos = app.h - 70 app.showtext("(%sm, %sm, %sm)" % (app.currently_selected.transformation[0, 3], app.currently_selected.transformation[1, 3], app.currently_selected.transformation[2, 3]), 30, pos) app.switch_from_overlay() # Make sure we do not go over 30fps clock.tick(30) logger.info("Quitting! Bye bye!") ######################################################################### ######################################################################### if __name__ == '__main__': if not len(sys.argv) > 1: print("Usage: " + __file__ + " ") sys.exit(2) main(model=sys.argv[1], width=1024, height=768) assimp-4.1.0/port/PyAssimp/scripts/transformations.py0000644002537200234200000016053713213503245023313 0ustar zmoelnigiemusers# -*- coding: utf-8 -*- # transformations.py # Copyright (c) 2006, Christoph Gohlke # Copyright (c) 2006-2009, The Regents of the University of California # 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 the copyright holders nor the names of any # 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. """Homogeneous Transformation Matrices and Quaternions. A library for calculating 4x4 matrices for translating, rotating, reflecting, scaling, shearing, projecting, orthogonalizing, and superimposing arrays of 3D homogeneous coordinates as well as for converting between rotation matrices, Euler angles, and quaternions. Also includes an Arcball control object and functions to decompose transformation matrices. :Authors: `Christoph Gohlke `__, Laboratory for Fluorescence Dynamics, University of California, Irvine :Version: 20090418 Requirements ------------ * `Python 2.6 `__ * `Numpy 1.3 `__ * `transformations.c 20090418 `__ (optional implementation of some functions in C) Notes ----- Matrices (M) can be inverted using numpy.linalg.inv(M), concatenated using numpy.dot(M0, M1), or used to transform homogeneous coordinates (v) using numpy.dot(M, v) for shape (4, \*) "point of arrays", respectively numpy.dot(v, M.T) for shape (\*, 4) "array of points". Calculations are carried out with numpy.float64 precision. This Python implementation is not optimized for speed. Vector, point, quaternion, and matrix function arguments are expected to be "array like", i.e. tuple, list, or numpy arrays. Return types are numpy arrays unless specified otherwise. Angles are in radians unless specified otherwise. Quaternions ix+jy+kz+w are represented as [x, y, z, w]. Use the transpose of transformation matrices for OpenGL glMultMatrixd(). A triple of Euler angles can be applied/interpreted in 24 ways, which can be specified using a 4 character string or encoded 4-tuple: *Axes 4-string*: e.g. 'sxyz' or 'ryxy' - first character : rotations are applied to 's'tatic or 'r'otating frame - remaining characters : successive rotation axis 'x', 'y', or 'z' *Axes 4-tuple*: e.g. (0, 0, 0, 0) or (1, 1, 1, 1) - inner axis: code of axis ('x':0, 'y':1, 'z':2) of rightmost matrix. - parity : even (0) if inner axis 'x' is followed by 'y', 'y' is followed by 'z', or 'z' is followed by 'x'. Otherwise odd (1). - repetition : first and last axis are same (1) or different (0). - frame : rotations are applied to static (0) or rotating (1) frame. References ---------- (1) Matrices and transformations. Ronald Goldman. In "Graphics Gems I", pp 472-475. Morgan Kaufmann, 1990. (2) More matrices and transformations: shear and pseudo-perspective. Ronald Goldman. In "Graphics Gems II", pp 320-323. Morgan Kaufmann, 1991. (3) Decomposing a matrix into simple transformations. Spencer Thomas. In "Graphics Gems II", pp 320-323. Morgan Kaufmann, 1991. (4) Recovering the data from the transformation matrix. Ronald Goldman. In "Graphics Gems II", pp 324-331. Morgan Kaufmann, 1991. (5) Euler angle conversion. Ken Shoemake. In "Graphics Gems IV", pp 222-229. Morgan Kaufmann, 1994. (6) Arcball rotation control. Ken Shoemake. In "Graphics Gems IV", pp 175-192. Morgan Kaufmann, 1994. (7) Representing attitude: Euler angles, unit quaternions, and rotation vectors. James Diebel. 2006. (8) A discussion of the solution for the best rotation to relate two sets of vectors. W Kabsch. Acta Cryst. 1978. A34, 827-828. (9) Closed-form solution of absolute orientation using unit quaternions. BKP Horn. J Opt Soc Am A. 1987. 4(4), 629-642. (10) Quaternions. Ken Shoemake. http://www.sfu.ca/~jwa3/cmpt461/files/quatut.pdf (11) From quaternion to matrix and back. JMP van Waveren. 2005. http://www.intel.com/cd/ids/developer/asmo-na/eng/293748.htm (12) Uniform random rotations. Ken Shoemake. In "Graphics Gems III", pp 124-132. Morgan Kaufmann, 1992. Examples -------- >>> alpha, beta, gamma = 0.123, -1.234, 2.345 >>> origin, xaxis, yaxis, zaxis = (0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1) >>> I = identity_matrix() >>> Rx = rotation_matrix(alpha, xaxis) >>> Ry = rotation_matrix(beta, yaxis) >>> Rz = rotation_matrix(gamma, zaxis) >>> R = concatenate_matrices(Rx, Ry, Rz) >>> euler = euler_from_matrix(R, 'rxyz') >>> numpy.allclose([alpha, beta, gamma], euler) True >>> Re = euler_matrix(alpha, beta, gamma, 'rxyz') >>> is_same_transform(R, Re) True >>> al, be, ga = euler_from_matrix(Re, 'rxyz') >>> is_same_transform(Re, euler_matrix(al, be, ga, 'rxyz')) True >>> qx = quaternion_about_axis(alpha, xaxis) >>> qy = quaternion_about_axis(beta, yaxis) >>> qz = quaternion_about_axis(gamma, zaxis) >>> q = quaternion_multiply(qx, qy) >>> q = quaternion_multiply(q, qz) >>> Rq = quaternion_matrix(q) >>> is_same_transform(R, Rq) True >>> S = scale_matrix(1.23, origin) >>> T = translation_matrix((1, 2, 3)) >>> Z = shear_matrix(beta, xaxis, origin, zaxis) >>> R = random_rotation_matrix(numpy.random.rand(3)) >>> M = concatenate_matrices(T, R, Z, S) >>> scale, shear, angles, trans, persp = decompose_matrix(M) >>> numpy.allclose(scale, 1.23) True >>> numpy.allclose(trans, (1, 2, 3)) True >>> numpy.allclose(shear, (0, math.tan(beta), 0)) True >>> is_same_transform(R, euler_matrix(axes='sxyz', *angles)) True >>> M1 = compose_matrix(scale, shear, angles, trans, persp) >>> is_same_transform(M, M1) True """ from __future__ import division import warnings import math import numpy # Documentation in HTML format can be generated with Epydoc __docformat__ = "restructuredtext en" def identity_matrix(): """Return 4x4 identity/unit matrix. >>> I = identity_matrix() >>> numpy.allclose(I, numpy.dot(I, I)) True >>> numpy.sum(I), numpy.trace(I) (4.0, 4.0) >>> numpy.allclose(I, numpy.identity(4, dtype=numpy.float64)) True """ return numpy.identity(4, dtype=numpy.float64) def translation_matrix(direction): """Return matrix to translate by direction vector. >>> v = numpy.random.random(3) - 0.5 >>> numpy.allclose(v, translation_matrix(v)[:3, 3]) True """ M = numpy.identity(4) M[:3, 3] = direction[:3] return M def translation_from_matrix(matrix): """Return translation vector from translation matrix. >>> v0 = numpy.random.random(3) - 0.5 >>> v1 = translation_from_matrix(translation_matrix(v0)) >>> numpy.allclose(v0, v1) True """ return numpy.array(matrix, copy=False)[:3, 3].copy() def reflection_matrix(point, normal): """Return matrix to mirror at plane defined by point and normal vector. >>> v0 = numpy.random.random(4) - 0.5 >>> v0[3] = 1.0 >>> v1 = numpy.random.random(3) - 0.5 >>> R = reflection_matrix(v0, v1) >>> numpy.allclose(2., numpy.trace(R)) True >>> numpy.allclose(v0, numpy.dot(R, v0)) True >>> v2 = v0.copy() >>> v2[:3] += v1 >>> v3 = v0.copy() >>> v2[:3] -= v1 >>> numpy.allclose(v2, numpy.dot(R, v3)) True """ normal = unit_vector(normal[:3]) M = numpy.identity(4) M[:3, :3] -= 2.0 * numpy.outer(normal, normal) M[:3, 3] = (2.0 * numpy.dot(point[:3], normal)) * normal return M def reflection_from_matrix(matrix): """Return mirror plane point and normal vector from reflection matrix. >>> v0 = numpy.random.random(3) - 0.5 >>> v1 = numpy.random.random(3) - 0.5 >>> M0 = reflection_matrix(v0, v1) >>> point, normal = reflection_from_matrix(M0) >>> M1 = reflection_matrix(point, normal) >>> is_same_transform(M0, M1) True """ M = numpy.array(matrix, dtype=numpy.float64, copy=False) # normal: unit eigenvector corresponding to eigenvalue -1 l, V = numpy.linalg.eig(M[:3, :3]) i = numpy.where(abs(numpy.real(l) + 1.0) < 1e-8)[0] if not len(i): raise ValueError("no unit eigenvector corresponding to eigenvalue -1") normal = numpy.real(V[:, i[0]]).squeeze() # point: any unit eigenvector corresponding to eigenvalue 1 l, V = numpy.linalg.eig(M) i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0] if not len(i): raise ValueError("no unit eigenvector corresponding to eigenvalue 1") point = numpy.real(V[:, i[-1]]).squeeze() point /= point[3] return point, normal def rotation_matrix(angle, direction, point=None): """Return matrix to rotate about axis defined by point and direction. >>> angle = (random.random() - 0.5) * (2*math.pi) >>> direc = numpy.random.random(3) - 0.5 >>> point = numpy.random.random(3) - 0.5 >>> R0 = rotation_matrix(angle, direc, point) >>> R1 = rotation_matrix(angle-2*math.pi, direc, point) >>> is_same_transform(R0, R1) True >>> R0 = rotation_matrix(angle, direc, point) >>> R1 = rotation_matrix(-angle, -direc, point) >>> is_same_transform(R0, R1) True >>> I = numpy.identity(4, numpy.float64) >>> numpy.allclose(I, rotation_matrix(math.pi*2, direc)) True >>> numpy.allclose(2., numpy.trace(rotation_matrix(math.pi/2, ... direc, point))) True """ sina = math.sin(angle) cosa = math.cos(angle) direction = unit_vector(direction[:3]) # rotation matrix around unit vector R = numpy.array(((cosa, 0.0, 0.0), (0.0, cosa, 0.0), (0.0, 0.0, cosa)), dtype=numpy.float64) R += numpy.outer(direction, direction) * (1.0 - cosa) direction *= sina R += numpy.array((( 0.0, -direction[2], direction[1]), ( direction[2], 0.0, -direction[0]), (-direction[1], direction[0], 0.0)), dtype=numpy.float64) M = numpy.identity(4) M[:3, :3] = R if point is not None: # rotation not around origin point = numpy.array(point[:3], dtype=numpy.float64, copy=False) M[:3, 3] = point - numpy.dot(R, point) return M def rotation_from_matrix(matrix): """Return rotation angle and axis from rotation matrix. >>> angle = (random.random() - 0.5) * (2*math.pi) >>> direc = numpy.random.random(3) - 0.5 >>> point = numpy.random.random(3) - 0.5 >>> R0 = rotation_matrix(angle, direc, point) >>> angle, direc, point = rotation_from_matrix(R0) >>> R1 = rotation_matrix(angle, direc, point) >>> is_same_transform(R0, R1) True """ R = numpy.array(matrix, dtype=numpy.float64, copy=False) R33 = R[:3, :3] # direction: unit eigenvector of R33 corresponding to eigenvalue of 1 l, W = numpy.linalg.eig(R33.T) i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0] if not len(i): raise ValueError("no unit eigenvector corresponding to eigenvalue 1") direction = numpy.real(W[:, i[-1]]).squeeze() # point: unit eigenvector of R33 corresponding to eigenvalue of 1 l, Q = numpy.linalg.eig(R) i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0] if not len(i): raise ValueError("no unit eigenvector corresponding to eigenvalue 1") point = numpy.real(Q[:, i[-1]]).squeeze() point /= point[3] # rotation angle depending on direction cosa = (numpy.trace(R33) - 1.0) / 2.0 if abs(direction[2]) > 1e-8: sina = (R[1, 0] + (cosa-1.0)*direction[0]*direction[1]) / direction[2] elif abs(direction[1]) > 1e-8: sina = (R[0, 2] + (cosa-1.0)*direction[0]*direction[2]) / direction[1] else: sina = (R[2, 1] + (cosa-1.0)*direction[1]*direction[2]) / direction[0] angle = math.atan2(sina, cosa) return angle, direction, point def scale_matrix(factor, origin=None, direction=None): """Return matrix to scale by factor around origin in direction. Use factor -1 for point symmetry. >>> v = (numpy.random.rand(4, 5) - 0.5) * 20.0 >>> v[3] = 1.0 >>> S = scale_matrix(-1.234) >>> numpy.allclose(numpy.dot(S, v)[:3], -1.234*v[:3]) True >>> factor = random.random() * 10 - 5 >>> origin = numpy.random.random(3) - 0.5 >>> direct = numpy.random.random(3) - 0.5 >>> S = scale_matrix(factor, origin) >>> S = scale_matrix(factor, origin, direct) """ if direction is None: # uniform scaling M = numpy.array(((factor, 0.0, 0.0, 0.0), (0.0, factor, 0.0, 0.0), (0.0, 0.0, factor, 0.0), (0.0, 0.0, 0.0, 1.0)), dtype=numpy.float64) if origin is not None: M[:3, 3] = origin[:3] M[:3, 3] *= 1.0 - factor else: # nonuniform scaling direction = unit_vector(direction[:3]) factor = 1.0 - factor M = numpy.identity(4) M[:3, :3] -= factor * numpy.outer(direction, direction) if origin is not None: M[:3, 3] = (factor * numpy.dot(origin[:3], direction)) * direction return M def scale_from_matrix(matrix): """Return scaling factor, origin and direction from scaling matrix. >>> factor = random.random() * 10 - 5 >>> origin = numpy.random.random(3) - 0.5 >>> direct = numpy.random.random(3) - 0.5 >>> S0 = scale_matrix(factor, origin) >>> factor, origin, direction = scale_from_matrix(S0) >>> S1 = scale_matrix(factor, origin, direction) >>> is_same_transform(S0, S1) True >>> S0 = scale_matrix(factor, origin, direct) >>> factor, origin, direction = scale_from_matrix(S0) >>> S1 = scale_matrix(factor, origin, direction) >>> is_same_transform(S0, S1) True """ M = numpy.array(matrix, dtype=numpy.float64, copy=False) M33 = M[:3, :3] factor = numpy.trace(M33) - 2.0 try: # direction: unit eigenvector corresponding to eigenvalue factor l, V = numpy.linalg.eig(M33) i = numpy.where(abs(numpy.real(l) - factor) < 1e-8)[0][0] direction = numpy.real(V[:, i]).squeeze() direction /= vector_norm(direction) except IndexError: # uniform scaling factor = (factor + 2.0) / 3.0 direction = None # origin: any eigenvector corresponding to eigenvalue 1 l, V = numpy.linalg.eig(M) i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0] if not len(i): raise ValueError("no eigenvector corresponding to eigenvalue 1") origin = numpy.real(V[:, i[-1]]).squeeze() origin /= origin[3] return factor, origin, direction def projection_matrix(point, normal, direction=None, perspective=None, pseudo=False): """Return matrix to project onto plane defined by point and normal. Using either perspective point, projection direction, or none of both. If pseudo is True, perspective projections will preserve relative depth such that Perspective = dot(Orthogonal, PseudoPerspective). >>> P = projection_matrix((0, 0, 0), (1, 0, 0)) >>> numpy.allclose(P[1:, 1:], numpy.identity(4)[1:, 1:]) True >>> point = numpy.random.random(3) - 0.5 >>> normal = numpy.random.random(3) - 0.5 >>> direct = numpy.random.random(3) - 0.5 >>> persp = numpy.random.random(3) - 0.5 >>> P0 = projection_matrix(point, normal) >>> P1 = projection_matrix(point, normal, direction=direct) >>> P2 = projection_matrix(point, normal, perspective=persp) >>> P3 = projection_matrix(point, normal, perspective=persp, pseudo=True) >>> is_same_transform(P2, numpy.dot(P0, P3)) True >>> P = projection_matrix((3, 0, 0), (1, 1, 0), (1, 0, 0)) >>> v0 = (numpy.random.rand(4, 5) - 0.5) * 20.0 >>> v0[3] = 1.0 >>> v1 = numpy.dot(P, v0) >>> numpy.allclose(v1[1], v0[1]) True >>> numpy.allclose(v1[0], 3.0-v1[1]) True """ M = numpy.identity(4) point = numpy.array(point[:3], dtype=numpy.float64, copy=False) normal = unit_vector(normal[:3]) if perspective is not None: # perspective projection perspective = numpy.array(perspective[:3], dtype=numpy.float64, copy=False) M[0, 0] = M[1, 1] = M[2, 2] = numpy.dot(perspective-point, normal) M[:3, :3] -= numpy.outer(perspective, normal) if pseudo: # preserve relative depth M[:3, :3] -= numpy.outer(normal, normal) M[:3, 3] = numpy.dot(point, normal) * (perspective+normal) else: M[:3, 3] = numpy.dot(point, normal) * perspective M[3, :3] = -normal M[3, 3] = numpy.dot(perspective, normal) elif direction is not None: # parallel projection direction = numpy.array(direction[:3], dtype=numpy.float64, copy=False) scale = numpy.dot(direction, normal) M[:3, :3] -= numpy.outer(direction, normal) / scale M[:3, 3] = direction * (numpy.dot(point, normal) / scale) else: # orthogonal projection M[:3, :3] -= numpy.outer(normal, normal) M[:3, 3] = numpy.dot(point, normal) * normal return M def projection_from_matrix(matrix, pseudo=False): """Return projection plane and perspective point from projection matrix. Return values are same as arguments for projection_matrix function: point, normal, direction, perspective, and pseudo. >>> point = numpy.random.random(3) - 0.5 >>> normal = numpy.random.random(3) - 0.5 >>> direct = numpy.random.random(3) - 0.5 >>> persp = numpy.random.random(3) - 0.5 >>> P0 = projection_matrix(point, normal) >>> result = projection_from_matrix(P0) >>> P1 = projection_matrix(*result) >>> is_same_transform(P0, P1) True >>> P0 = projection_matrix(point, normal, direct) >>> result = projection_from_matrix(P0) >>> P1 = projection_matrix(*result) >>> is_same_transform(P0, P1) True >>> P0 = projection_matrix(point, normal, perspective=persp, pseudo=False) >>> result = projection_from_matrix(P0, pseudo=False) >>> P1 = projection_matrix(*result) >>> is_same_transform(P0, P1) True >>> P0 = projection_matrix(point, normal, perspective=persp, pseudo=True) >>> result = projection_from_matrix(P0, pseudo=True) >>> P1 = projection_matrix(*result) >>> is_same_transform(P0, P1) True """ M = numpy.array(matrix, dtype=numpy.float64, copy=False) M33 = M[:3, :3] l, V = numpy.linalg.eig(M) i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0] if not pseudo and len(i): # point: any eigenvector corresponding to eigenvalue 1 point = numpy.real(V[:, i[-1]]).squeeze() point /= point[3] # direction: unit eigenvector corresponding to eigenvalue 0 l, V = numpy.linalg.eig(M33) i = numpy.where(abs(numpy.real(l)) < 1e-8)[0] if not len(i): raise ValueError("no eigenvector corresponding to eigenvalue 0") direction = numpy.real(V[:, i[0]]).squeeze() direction /= vector_norm(direction) # normal: unit eigenvector of M33.T corresponding to eigenvalue 0 l, V = numpy.linalg.eig(M33.T) i = numpy.where(abs(numpy.real(l)) < 1e-8)[0] if len(i): # parallel projection normal = numpy.real(V[:, i[0]]).squeeze() normal /= vector_norm(normal) return point, normal, direction, None, False else: # orthogonal projection, where normal equals direction vector return point, direction, None, None, False else: # perspective projection i = numpy.where(abs(numpy.real(l)) > 1e-8)[0] if not len(i): raise ValueError( "no eigenvector not corresponding to eigenvalue 0") point = numpy.real(V[:, i[-1]]).squeeze() point /= point[3] normal = - M[3, :3] perspective = M[:3, 3] / numpy.dot(point[:3], normal) if pseudo: perspective -= normal return point, normal, None, perspective, pseudo def clip_matrix(left, right, bottom, top, near, far, perspective=False): """Return matrix to obtain normalized device coordinates from frustrum. The frustrum bounds are axis-aligned along x (left, right), y (bottom, top) and z (near, far). Normalized device coordinates are in range [-1, 1] if coordinates are inside the frustrum. If perspective is True the frustrum is a truncated pyramid with the perspective point at origin and direction along z axis, otherwise an orthographic canonical view volume (a box). Homogeneous coordinates transformed by the perspective clip matrix need to be dehomogenized (divided by w coordinate). >>> frustrum = numpy.random.rand(6) >>> frustrum[1] += frustrum[0] >>> frustrum[3] += frustrum[2] >>> frustrum[5] += frustrum[4] >>> M = clip_matrix(*frustrum, perspective=False) >>> numpy.dot(M, [frustrum[0], frustrum[2], frustrum[4], 1.0]) array([-1., -1., -1., 1.]) >>> numpy.dot(M, [frustrum[1], frustrum[3], frustrum[5], 1.0]) array([ 1., 1., 1., 1.]) >>> M = clip_matrix(*frustrum, perspective=True) >>> v = numpy.dot(M, [frustrum[0], frustrum[2], frustrum[4], 1.0]) >>> v / v[3] array([-1., -1., -1., 1.]) >>> v = numpy.dot(M, [frustrum[1], frustrum[3], frustrum[4], 1.0]) >>> v / v[3] array([ 1., 1., -1., 1.]) """ if left >= right or bottom >= top or near >= far: raise ValueError("invalid frustrum") if perspective: if near <= _EPS: raise ValueError("invalid frustrum: near <= 0") t = 2.0 * near M = ((-t/(right-left), 0.0, (right+left)/(right-left), 0.0), (0.0, -t/(top-bottom), (top+bottom)/(top-bottom), 0.0), (0.0, 0.0, -(far+near)/(far-near), t*far/(far-near)), (0.0, 0.0, -1.0, 0.0)) else: M = ((2.0/(right-left), 0.0, 0.0, (right+left)/(left-right)), (0.0, 2.0/(top-bottom), 0.0, (top+bottom)/(bottom-top)), (0.0, 0.0, 2.0/(far-near), (far+near)/(near-far)), (0.0, 0.0, 0.0, 1.0)) return numpy.array(M, dtype=numpy.float64) def shear_matrix(angle, direction, point, normal): """Return matrix to shear by angle along direction vector on shear plane. The shear plane is defined by a point and normal vector. The direction vector must be orthogonal to the plane's normal vector. A point P is transformed by the shear matrix into P" such that the vector P-P" is parallel to the direction vector and its extent is given by the angle of P-P'-P", where P' is the orthogonal projection of P onto the shear plane. >>> angle = (random.random() - 0.5) * 4*math.pi >>> direct = numpy.random.random(3) - 0.5 >>> point = numpy.random.random(3) - 0.5 >>> normal = numpy.cross(direct, numpy.random.random(3)) >>> S = shear_matrix(angle, direct, point, normal) >>> numpy.allclose(1.0, numpy.linalg.det(S)) True """ normal = unit_vector(normal[:3]) direction = unit_vector(direction[:3]) if abs(numpy.dot(normal, direction)) > 1e-6: raise ValueError("direction and normal vectors are not orthogonal") angle = math.tan(angle) M = numpy.identity(4) M[:3, :3] += angle * numpy.outer(direction, normal) M[:3, 3] = -angle * numpy.dot(point[:3], normal) * direction return M def shear_from_matrix(matrix): """Return shear angle, direction and plane from shear matrix. >>> angle = (random.random() - 0.5) * 4*math.pi >>> direct = numpy.random.random(3) - 0.5 >>> point = numpy.random.random(3) - 0.5 >>> normal = numpy.cross(direct, numpy.random.random(3)) >>> S0 = shear_matrix(angle, direct, point, normal) >>> angle, direct, point, normal = shear_from_matrix(S0) >>> S1 = shear_matrix(angle, direct, point, normal) >>> is_same_transform(S0, S1) True """ M = numpy.array(matrix, dtype=numpy.float64, copy=False) M33 = M[:3, :3] # normal: cross independent eigenvectors corresponding to the eigenvalue 1 l, V = numpy.linalg.eig(M33) i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-4)[0] if len(i) < 2: raise ValueError("No two linear independent eigenvectors found %s" % l) V = numpy.real(V[:, i]).squeeze().T lenorm = -1.0 for i0, i1 in ((0, 1), (0, 2), (1, 2)): n = numpy.cross(V[i0], V[i1]) l = vector_norm(n) if l > lenorm: lenorm = l normal = n normal /= lenorm # direction and angle direction = numpy.dot(M33 - numpy.identity(3), normal) angle = vector_norm(direction) direction /= angle angle = math.atan(angle) # point: eigenvector corresponding to eigenvalue 1 l, V = numpy.linalg.eig(M) i = numpy.where(abs(numpy.real(l) - 1.0) < 1e-8)[0] if not len(i): raise ValueError("no eigenvector corresponding to eigenvalue 1") point = numpy.real(V[:, i[-1]]).squeeze() point /= point[3] return angle, direction, point, normal def decompose_matrix(matrix): """Return sequence of transformations from transformation matrix. matrix : array_like Non-degenerative homogeneous transformation matrix Return tuple of: scale : vector of 3 scaling factors shear : list of shear factors for x-y, x-z, y-z axes angles : list of Euler angles about static x, y, z axes translate : translation vector along x, y, z axes perspective : perspective partition of matrix Raise ValueError if matrix is of wrong type or degenerative. >>> T0 = translation_matrix((1, 2, 3)) >>> scale, shear, angles, trans, persp = decompose_matrix(T0) >>> T1 = translation_matrix(trans) >>> numpy.allclose(T0, T1) True >>> S = scale_matrix(0.123) >>> scale, shear, angles, trans, persp = decompose_matrix(S) >>> scale[0] 0.123 >>> R0 = euler_matrix(1, 2, 3) >>> scale, shear, angles, trans, persp = decompose_matrix(R0) >>> R1 = euler_matrix(*angles) >>> numpy.allclose(R0, R1) True """ M = numpy.array(matrix, dtype=numpy.float64, copy=True).T if abs(M[3, 3]) < _EPS: raise ValueError("M[3, 3] is zero") M /= M[3, 3] P = M.copy() P[:, 3] = 0, 0, 0, 1 if not numpy.linalg.det(P): raise ValueError("Matrix is singular") scale = numpy.zeros((3, ), dtype=numpy.float64) shear = [0, 0, 0] angles = [0, 0, 0] if any(abs(M[:3, 3]) > _EPS): perspective = numpy.dot(M[:, 3], numpy.linalg.inv(P.T)) M[:, 3] = 0, 0, 0, 1 else: perspective = numpy.array((0, 0, 0, 1), dtype=numpy.float64) translate = M[3, :3].copy() M[3, :3] = 0 row = M[:3, :3].copy() scale[0] = vector_norm(row[0]) row[0] /= scale[0] shear[0] = numpy.dot(row[0], row[1]) row[1] -= row[0] * shear[0] scale[1] = vector_norm(row[1]) row[1] /= scale[1] shear[0] /= scale[1] shear[1] = numpy.dot(row[0], row[2]) row[2] -= row[0] * shear[1] shear[2] = numpy.dot(row[1], row[2]) row[2] -= row[1] * shear[2] scale[2] = vector_norm(row[2]) row[2] /= scale[2] shear[1:] /= scale[2] if numpy.dot(row[0], numpy.cross(row[1], row[2])) < 0: scale *= -1 row *= -1 angles[1] = math.asin(-row[0, 2]) if math.cos(angles[1]): angles[0] = math.atan2(row[1, 2], row[2, 2]) angles[2] = math.atan2(row[0, 1], row[0, 0]) else: #angles[0] = math.atan2(row[1, 0], row[1, 1]) angles[0] = math.atan2(-row[2, 1], row[1, 1]) angles[2] = 0.0 return scale, shear, angles, translate, perspective def compose_matrix(scale=None, shear=None, angles=None, translate=None, perspective=None): """Return transformation matrix from sequence of transformations. This is the inverse of the decompose_matrix function. Sequence of transformations: scale : vector of 3 scaling factors shear : list of shear factors for x-y, x-z, y-z axes angles : list of Euler angles about static x, y, z axes translate : translation vector along x, y, z axes perspective : perspective partition of matrix >>> scale = numpy.random.random(3) - 0.5 >>> shear = numpy.random.random(3) - 0.5 >>> angles = (numpy.random.random(3) - 0.5) * (2*math.pi) >>> trans = numpy.random.random(3) - 0.5 >>> persp = numpy.random.random(4) - 0.5 >>> M0 = compose_matrix(scale, shear, angles, trans, persp) >>> result = decompose_matrix(M0) >>> M1 = compose_matrix(*result) >>> is_same_transform(M0, M1) True """ M = numpy.identity(4) if perspective is not None: P = numpy.identity(4) P[3, :] = perspective[:4] M = numpy.dot(M, P) if translate is not None: T = numpy.identity(4) T[:3, 3] = translate[:3] M = numpy.dot(M, T) if angles is not None: R = euler_matrix(angles[0], angles[1], angles[2], 'sxyz') M = numpy.dot(M, R) if shear is not None: Z = numpy.identity(4) Z[1, 2] = shear[2] Z[0, 2] = shear[1] Z[0, 1] = shear[0] M = numpy.dot(M, Z) if scale is not None: S = numpy.identity(4) S[0, 0] = scale[0] S[1, 1] = scale[1] S[2, 2] = scale[2] M = numpy.dot(M, S) M /= M[3, 3] return M def orthogonalization_matrix(lengths, angles): """Return orthogonalization matrix for crystallographic cell coordinates. Angles are expected in degrees. The de-orthogonalization matrix is the inverse. >>> O = orthogonalization_matrix((10., 10., 10.), (90., 90., 90.)) >>> numpy.allclose(O[:3, :3], numpy.identity(3, float) * 10) True >>> O = orthogonalization_matrix([9.8, 12.0, 15.5], [87.2, 80.7, 69.7]) >>> numpy.allclose(numpy.sum(O), 43.063229) True """ a, b, c = lengths angles = numpy.radians(angles) sina, sinb, _ = numpy.sin(angles) cosa, cosb, cosg = numpy.cos(angles) co = (cosa * cosb - cosg) / (sina * sinb) return numpy.array(( ( a*sinb*math.sqrt(1.0-co*co), 0.0, 0.0, 0.0), (-a*sinb*co, b*sina, 0.0, 0.0), ( a*cosb, b*cosa, c, 0.0), ( 0.0, 0.0, 0.0, 1.0)), dtype=numpy.float64) def superimposition_matrix(v0, v1, scaling=False, usesvd=True): """Return matrix to transform given vector set into second vector set. v0 and v1 are shape (3, \*) or (4, \*) arrays of at least 3 vectors. If usesvd is True, the weighted sum of squared deviations (RMSD) is minimized according to the algorithm by W. Kabsch [8]. Otherwise the quaternion based algorithm by B. Horn [9] is used (slower when using this Python implementation). The returned matrix performs rotation, translation and uniform scaling (if specified). >>> v0 = numpy.random.rand(3, 10) >>> M = superimposition_matrix(v0, v0) >>> numpy.allclose(M, numpy.identity(4)) True >>> R = random_rotation_matrix(numpy.random.random(3)) >>> v0 = ((1,0,0), (0,1,0), (0,0,1), (1,1,1)) >>> v1 = numpy.dot(R, v0) >>> M = superimposition_matrix(v0, v1) >>> numpy.allclose(v1, numpy.dot(M, v0)) True >>> v0 = (numpy.random.rand(4, 100) - 0.5) * 20.0 >>> v0[3] = 1.0 >>> v1 = numpy.dot(R, v0) >>> M = superimposition_matrix(v0, v1) >>> numpy.allclose(v1, numpy.dot(M, v0)) True >>> S = scale_matrix(random.random()) >>> T = translation_matrix(numpy.random.random(3)-0.5) >>> M = concatenate_matrices(T, R, S) >>> v1 = numpy.dot(M, v0) >>> v0[:3] += numpy.random.normal(0.0, 1e-9, 300).reshape(3, -1) >>> M = superimposition_matrix(v0, v1, scaling=True) >>> numpy.allclose(v1, numpy.dot(M, v0)) True >>> M = superimposition_matrix(v0, v1, scaling=True, usesvd=False) >>> numpy.allclose(v1, numpy.dot(M, v0)) True >>> v = numpy.empty((4, 100, 3), dtype=numpy.float64) >>> v[:, :, 0] = v0 >>> M = superimposition_matrix(v0, v1, scaling=True, usesvd=False) >>> numpy.allclose(v1, numpy.dot(M, v[:, :, 0])) True """ v0 = numpy.array(v0, dtype=numpy.float64, copy=False)[:3] v1 = numpy.array(v1, dtype=numpy.float64, copy=False)[:3] if v0.shape != v1.shape or v0.shape[1] < 3: raise ValueError("Vector sets are of wrong shape or type.") # move centroids to origin t0 = numpy.mean(v0, axis=1) t1 = numpy.mean(v1, axis=1) v0 = v0 - t0.reshape(3, 1) v1 = v1 - t1.reshape(3, 1) if usesvd: # Singular Value Decomposition of covariance matrix u, s, vh = numpy.linalg.svd(numpy.dot(v1, v0.T)) # rotation matrix from SVD orthonormal bases R = numpy.dot(u, vh) if numpy.linalg.det(R) < 0.0: # R does not constitute right handed system R -= numpy.outer(u[:, 2], vh[2, :]*2.0) s[-1] *= -1.0 # homogeneous transformation matrix M = numpy.identity(4) M[:3, :3] = R else: # compute symmetric matrix N xx, yy, zz = numpy.sum(v0 * v1, axis=1) xy, yz, zx = numpy.sum(v0 * numpy.roll(v1, -1, axis=0), axis=1) xz, yx, zy = numpy.sum(v0 * numpy.roll(v1, -2, axis=0), axis=1) N = ((xx+yy+zz, yz-zy, zx-xz, xy-yx), (yz-zy, xx-yy-zz, xy+yx, zx+xz), (zx-xz, xy+yx, -xx+yy-zz, yz+zy), (xy-yx, zx+xz, yz+zy, -xx-yy+zz)) # quaternion: eigenvector corresponding to most positive eigenvalue l, V = numpy.linalg.eig(N) q = V[:, numpy.argmax(l)] q /= vector_norm(q) # unit quaternion q = numpy.roll(q, -1) # move w component to end # homogeneous transformation matrix M = quaternion_matrix(q) # scale: ratio of rms deviations from centroid if scaling: v0 *= v0 v1 *= v1 M[:3, :3] *= math.sqrt(numpy.sum(v1) / numpy.sum(v0)) # translation M[:3, 3] = t1 T = numpy.identity(4) T[:3, 3] = -t0 M = numpy.dot(M, T) return M def euler_matrix(ai, aj, ak, axes='sxyz'): """Return homogeneous rotation matrix from Euler angles and axis sequence. ai, aj, ak : Euler's roll, pitch and yaw angles axes : One of 24 axis sequences as string or encoded tuple >>> R = euler_matrix(1, 2, 3, 'syxz') >>> numpy.allclose(numpy.sum(R[0]), -1.34786452) True >>> R = euler_matrix(1, 2, 3, (0, 1, 0, 1)) >>> numpy.allclose(numpy.sum(R[0]), -0.383436184) True >>> ai, aj, ak = (4.0*math.pi) * (numpy.random.random(3) - 0.5) >>> for axes in _AXES2TUPLE.keys(): ... R = euler_matrix(ai, aj, ak, axes) >>> for axes in _TUPLE2AXES.keys(): ... R = euler_matrix(ai, aj, ak, axes) """ try: firstaxis, parity, repetition, frame = _AXES2TUPLE[axes] except (AttributeError, KeyError): _ = _TUPLE2AXES[axes] firstaxis, parity, repetition, frame = axes i = firstaxis j = _NEXT_AXIS[i+parity] k = _NEXT_AXIS[i-parity+1] if frame: ai, ak = ak, ai if parity: ai, aj, ak = -ai, -aj, -ak si, sj, sk = math.sin(ai), math.sin(aj), math.sin(ak) ci, cj, ck = math.cos(ai), math.cos(aj), math.cos(ak) cc, cs = ci*ck, ci*sk sc, ss = si*ck, si*sk M = numpy.identity(4) if repetition: M[i, i] = cj M[i, j] = sj*si M[i, k] = sj*ci M[j, i] = sj*sk M[j, j] = -cj*ss+cc M[j, k] = -cj*cs-sc M[k, i] = -sj*ck M[k, j] = cj*sc+cs M[k, k] = cj*cc-ss else: M[i, i] = cj*ck M[i, j] = sj*sc-cs M[i, k] = sj*cc+ss M[j, i] = cj*sk M[j, j] = sj*ss+cc M[j, k] = sj*cs-sc M[k, i] = -sj M[k, j] = cj*si M[k, k] = cj*ci return M def euler_from_matrix(matrix, axes='sxyz'): """Return Euler angles from rotation matrix for specified axis sequence. axes : One of 24 axis sequences as string or encoded tuple Note that many Euler angle triplets can describe one matrix. >>> R0 = euler_matrix(1, 2, 3, 'syxz') >>> al, be, ga = euler_from_matrix(R0, 'syxz') >>> R1 = euler_matrix(al, be, ga, 'syxz') >>> numpy.allclose(R0, R1) True >>> angles = (4.0*math.pi) * (numpy.random.random(3) - 0.5) >>> for axes in _AXES2TUPLE.keys(): ... R0 = euler_matrix(axes=axes, *angles) ... R1 = euler_matrix(axes=axes, *euler_from_matrix(R0, axes)) ... if not numpy.allclose(R0, R1): print axes, "failed" """ try: firstaxis, parity, repetition, frame = _AXES2TUPLE[axes.lower()] except (AttributeError, KeyError): _ = _TUPLE2AXES[axes] firstaxis, parity, repetition, frame = axes i = firstaxis j = _NEXT_AXIS[i+parity] k = _NEXT_AXIS[i-parity+1] M = numpy.array(matrix, dtype=numpy.float64, copy=False)[:3, :3] if repetition: sy = math.sqrt(M[i, j]*M[i, j] + M[i, k]*M[i, k]) if sy > _EPS: ax = math.atan2( M[i, j], M[i, k]) ay = math.atan2( sy, M[i, i]) az = math.atan2( M[j, i], -M[k, i]) else: ax = math.atan2(-M[j, k], M[j, j]) ay = math.atan2( sy, M[i, i]) az = 0.0 else: cy = math.sqrt(M[i, i]*M[i, i] + M[j, i]*M[j, i]) if cy > _EPS: ax = math.atan2( M[k, j], M[k, k]) ay = math.atan2(-M[k, i], cy) az = math.atan2( M[j, i], M[i, i]) else: ax = math.atan2(-M[j, k], M[j, j]) ay = math.atan2(-M[k, i], cy) az = 0.0 if parity: ax, ay, az = -ax, -ay, -az if frame: ax, az = az, ax return ax, ay, az def euler_from_quaternion(quaternion, axes='sxyz'): """Return Euler angles from quaternion for specified axis sequence. >>> angles = euler_from_quaternion([0.06146124, 0, 0, 0.99810947]) >>> numpy.allclose(angles, [0.123, 0, 0]) True """ return euler_from_matrix(quaternion_matrix(quaternion), axes) def quaternion_from_euler(ai, aj, ak, axes='sxyz'): """Return quaternion from Euler angles and axis sequence. ai, aj, ak : Euler's roll, pitch and yaw angles axes : One of 24 axis sequences as string or encoded tuple >>> q = quaternion_from_euler(1, 2, 3, 'ryxz') >>> numpy.allclose(q, [0.310622, -0.718287, 0.444435, 0.435953]) True """ try: firstaxis, parity, repetition, frame = _AXES2TUPLE[axes.lower()] except (AttributeError, KeyError): _ = _TUPLE2AXES[axes] firstaxis, parity, repetition, frame = axes i = firstaxis j = _NEXT_AXIS[i+parity] k = _NEXT_AXIS[i-parity+1] if frame: ai, ak = ak, ai if parity: aj = -aj ai /= 2.0 aj /= 2.0 ak /= 2.0 ci = math.cos(ai) si = math.sin(ai) cj = math.cos(aj) sj = math.sin(aj) ck = math.cos(ak) sk = math.sin(ak) cc = ci*ck cs = ci*sk sc = si*ck ss = si*sk quaternion = numpy.empty((4, ), dtype=numpy.float64) if repetition: quaternion[i] = cj*(cs + sc) quaternion[j] = sj*(cc + ss) quaternion[k] = sj*(cs - sc) quaternion[3] = cj*(cc - ss) else: quaternion[i] = cj*sc - sj*cs quaternion[j] = cj*ss + sj*cc quaternion[k] = cj*cs - sj*sc quaternion[3] = cj*cc + sj*ss if parity: quaternion[j] *= -1 return quaternion def quaternion_about_axis(angle, axis): """Return quaternion for rotation about axis. >>> q = quaternion_about_axis(0.123, (1, 0, 0)) >>> numpy.allclose(q, [0.06146124, 0, 0, 0.99810947]) True """ quaternion = numpy.zeros((4, ), dtype=numpy.float64) quaternion[:3] = axis[:3] qlen = vector_norm(quaternion) if qlen > _EPS: quaternion *= math.sin(angle/2.0) / qlen quaternion[3] = math.cos(angle/2.0) return quaternion def quaternion_matrix(quaternion): """Return homogeneous rotation matrix from quaternion. >>> R = quaternion_matrix([0.06146124, 0, 0, 0.99810947]) >>> numpy.allclose(R, rotation_matrix(0.123, (1, 0, 0))) True """ q = numpy.array(quaternion[:4], dtype=numpy.float64, copy=True) nq = numpy.dot(q, q) if nq < _EPS: return numpy.identity(4) q *= math.sqrt(2.0 / nq) q = numpy.outer(q, q) return numpy.array(( (1.0-q[1, 1]-q[2, 2], q[0, 1]-q[2, 3], q[0, 2]+q[1, 3], 0.0), ( q[0, 1]+q[2, 3], 1.0-q[0, 0]-q[2, 2], q[1, 2]-q[0, 3], 0.0), ( q[0, 2]-q[1, 3], q[1, 2]+q[0, 3], 1.0-q[0, 0]-q[1, 1], 0.0), ( 0.0, 0.0, 0.0, 1.0) ), dtype=numpy.float64) def quaternion_from_matrix(matrix): """Return quaternion from rotation matrix. >>> R = rotation_matrix(0.123, (1, 2, 3)) >>> q = quaternion_from_matrix(R) >>> numpy.allclose(q, [0.0164262, 0.0328524, 0.0492786, 0.9981095]) True """ q = numpy.empty((4, ), dtype=numpy.float64) M = numpy.array(matrix, dtype=numpy.float64, copy=False)[:4, :4] t = numpy.trace(M) if t > M[3, 3]: q[3] = t q[2] = M[1, 0] - M[0, 1] q[1] = M[0, 2] - M[2, 0] q[0] = M[2, 1] - M[1, 2] else: i, j, k = 0, 1, 2 if M[1, 1] > M[0, 0]: i, j, k = 1, 2, 0 if M[2, 2] > M[i, i]: i, j, k = 2, 0, 1 t = M[i, i] - (M[j, j] + M[k, k]) + M[3, 3] q[i] = t q[j] = M[i, j] + M[j, i] q[k] = M[k, i] + M[i, k] q[3] = M[k, j] - M[j, k] q *= 0.5 / math.sqrt(t * M[3, 3]) return q def quaternion_multiply(quaternion1, quaternion0): """Return multiplication of two quaternions. >>> q = quaternion_multiply([1, -2, 3, 4], [-5, 6, 7, 8]) >>> numpy.allclose(q, [-44, -14, 48, 28]) True """ x0, y0, z0, w0 = quaternion0 x1, y1, z1, w1 = quaternion1 return numpy.array(( x1*w0 + y1*z0 - z1*y0 + w1*x0, -x1*z0 + y1*w0 + z1*x0 + w1*y0, x1*y0 - y1*x0 + z1*w0 + w1*z0, -x1*x0 - y1*y0 - z1*z0 + w1*w0), dtype=numpy.float64) def quaternion_conjugate(quaternion): """Return conjugate of quaternion. >>> q0 = random_quaternion() >>> q1 = quaternion_conjugate(q0) >>> q1[3] == q0[3] and all(q1[:3] == -q0[:3]) True """ return numpy.array((-quaternion[0], -quaternion[1], -quaternion[2], quaternion[3]), dtype=numpy.float64) def quaternion_inverse(quaternion): """Return inverse of quaternion. >>> q0 = random_quaternion() >>> q1 = quaternion_inverse(q0) >>> numpy.allclose(quaternion_multiply(q0, q1), [0, 0, 0, 1]) True """ return quaternion_conjugate(quaternion) / numpy.dot(quaternion, quaternion) def quaternion_slerp(quat0, quat1, fraction, spin=0, shortestpath=True): """Return spherical linear interpolation between two quaternions. >>> q0 = random_quaternion() >>> q1 = random_quaternion() >>> q = quaternion_slerp(q0, q1, 0.0) >>> numpy.allclose(q, q0) True >>> q = quaternion_slerp(q0, q1, 1.0, 1) >>> numpy.allclose(q, q1) True >>> q = quaternion_slerp(q0, q1, 0.5) >>> angle = math.acos(numpy.dot(q0, q)) >>> numpy.allclose(2.0, math.acos(numpy.dot(q0, q1)) / angle) or \ numpy.allclose(2.0, math.acos(-numpy.dot(q0, q1)) / angle) True """ q0 = unit_vector(quat0[:4]) q1 = unit_vector(quat1[:4]) if fraction == 0.0: return q0 elif fraction == 1.0: return q1 d = numpy.dot(q0, q1) if abs(abs(d) - 1.0) < _EPS: return q0 if shortestpath and d < 0.0: # invert rotation d = -d q1 *= -1.0 angle = math.acos(d) + spin * math.pi if abs(angle) < _EPS: return q0 isin = 1.0 / math.sin(angle) q0 *= math.sin((1.0 - fraction) * angle) * isin q1 *= math.sin(fraction * angle) * isin q0 += q1 return q0 def random_quaternion(rand=None): """Return uniform random unit quaternion. rand: array like or None Three independent random variables that are uniformly distributed between 0 and 1. >>> q = random_quaternion() >>> numpy.allclose(1.0, vector_norm(q)) True >>> q = random_quaternion(numpy.random.random(3)) >>> q.shape (4,) """ if rand is None: rand = numpy.random.rand(3) else: assert len(rand) == 3 r1 = numpy.sqrt(1.0 - rand[0]) r2 = numpy.sqrt(rand[0]) pi2 = math.pi * 2.0 t1 = pi2 * rand[1] t2 = pi2 * rand[2] return numpy.array((numpy.sin(t1)*r1, numpy.cos(t1)*r1, numpy.sin(t2)*r2, numpy.cos(t2)*r2), dtype=numpy.float64) def random_rotation_matrix(rand=None): """Return uniform random rotation matrix. rnd: array like Three independent random variables that are uniformly distributed between 0 and 1 for each returned quaternion. >>> R = random_rotation_matrix() >>> numpy.allclose(numpy.dot(R.T, R), numpy.identity(4)) True """ return quaternion_matrix(random_quaternion(rand)) class Arcball(object): """Virtual Trackball Control. >>> ball = Arcball() >>> ball = Arcball(initial=numpy.identity(4)) >>> ball.place([320, 320], 320) >>> ball.down([500, 250]) >>> ball.drag([475, 275]) >>> R = ball.matrix() >>> numpy.allclose(numpy.sum(R), 3.90583455) True >>> ball = Arcball(initial=[0, 0, 0, 1]) >>> ball.place([320, 320], 320) >>> ball.setaxes([1,1,0], [-1, 1, 0]) >>> ball.setconstrain(True) >>> ball.down([400, 200]) >>> ball.drag([200, 400]) >>> R = ball.matrix() >>> numpy.allclose(numpy.sum(R), 0.2055924) True >>> ball.next() """ def __init__(self, initial=None): """Initialize virtual trackball control. initial : quaternion or rotation matrix """ self._axis = None self._axes = None self._radius = 1.0 self._center = [0.0, 0.0] self._vdown = numpy.array([0, 0, 1], dtype=numpy.float64) self._constrain = False if initial is None: self._qdown = numpy.array([0, 0, 0, 1], dtype=numpy.float64) else: initial = numpy.array(initial, dtype=numpy.float64) if initial.shape == (4, 4): self._qdown = quaternion_from_matrix(initial) elif initial.shape == (4, ): initial /= vector_norm(initial) self._qdown = initial else: raise ValueError("initial not a quaternion or matrix.") self._qnow = self._qpre = self._qdown def place(self, center, radius): """Place Arcball, e.g. when window size changes. center : sequence[2] Window coordinates of trackball center. radius : float Radius of trackball in window coordinates. """ self._radius = float(radius) self._center[0] = center[0] self._center[1] = center[1] def setaxes(self, *axes): """Set axes to constrain rotations.""" if axes is None: self._axes = None else: self._axes = [unit_vector(axis) for axis in axes] def setconstrain(self, constrain): """Set state of constrain to axis mode.""" self._constrain = constrain == True def getconstrain(self): """Return state of constrain to axis mode.""" return self._constrain def down(self, point): """Set initial cursor window coordinates and pick constrain-axis.""" self._vdown = arcball_map_to_sphere(point, self._center, self._radius) self._qdown = self._qpre = self._qnow if self._constrain and self._axes is not None: self._axis = arcball_nearest_axis(self._vdown, self._axes) self._vdown = arcball_constrain_to_axis(self._vdown, self._axis) else: self._axis = None def drag(self, point): """Update current cursor window coordinates.""" vnow = arcball_map_to_sphere(point, self._center, self._radius) if self._axis is not None: vnow = arcball_constrain_to_axis(vnow, self._axis) self._qpre = self._qnow t = numpy.cross(self._vdown, vnow) if numpy.dot(t, t) < _EPS: self._qnow = self._qdown else: q = [t[0], t[1], t[2], numpy.dot(self._vdown, vnow)] self._qnow = quaternion_multiply(q, self._qdown) def next(self, acceleration=0.0): """Continue rotation in direction of last drag.""" q = quaternion_slerp(self._qpre, self._qnow, 2.0+acceleration, False) self._qpre, self._qnow = self._qnow, q def matrix(self): """Return homogeneous rotation matrix.""" return quaternion_matrix(self._qnow) def arcball_map_to_sphere(point, center, radius): """Return unit sphere coordinates from window coordinates.""" v = numpy.array(((point[0] - center[0]) / radius, (center[1] - point[1]) / radius, 0.0), dtype=numpy.float64) n = v[0]*v[0] + v[1]*v[1] if n > 1.0: v /= math.sqrt(n) # position outside of sphere else: v[2] = math.sqrt(1.0 - n) return v def arcball_constrain_to_axis(point, axis): """Return sphere point perpendicular to axis.""" v = numpy.array(point, dtype=numpy.float64, copy=True) a = numpy.array(axis, dtype=numpy.float64, copy=True) v -= a * numpy.dot(a, v) # on plane n = vector_norm(v) if n > _EPS: if v[2] < 0.0: v *= -1.0 v /= n return v if a[2] == 1.0: return numpy.array([1, 0, 0], dtype=numpy.float64) return unit_vector([-a[1], a[0], 0]) def arcball_nearest_axis(point, axes): """Return axis, which arc is nearest to point.""" point = numpy.array(point, dtype=numpy.float64, copy=False) nearest = None mx = -1.0 for axis in axes: t = numpy.dot(arcball_constrain_to_axis(point, axis), point) if t > mx: nearest = axis mx = t return nearest # epsilon for testing whether a number is close to zero _EPS = numpy.finfo(float).eps * 4.0 # axis sequences for Euler angles _NEXT_AXIS = [1, 2, 0, 1] # map axes strings to/from tuples of inner axis, parity, repetition, frame _AXES2TUPLE = { 'sxyz': (0, 0, 0, 0), 'sxyx': (0, 0, 1, 0), 'sxzy': (0, 1, 0, 0), 'sxzx': (0, 1, 1, 0), 'syzx': (1, 0, 0, 0), 'syzy': (1, 0, 1, 0), 'syxz': (1, 1, 0, 0), 'syxy': (1, 1, 1, 0), 'szxy': (2, 0, 0, 0), 'szxz': (2, 0, 1, 0), 'szyx': (2, 1, 0, 0), 'szyz': (2, 1, 1, 0), 'rzyx': (0, 0, 0, 1), 'rxyx': (0, 0, 1, 1), 'ryzx': (0, 1, 0, 1), 'rxzx': (0, 1, 1, 1), 'rxzy': (1, 0, 0, 1), 'ryzy': (1, 0, 1, 1), 'rzxy': (1, 1, 0, 1), 'ryxy': (1, 1, 1, 1), 'ryxz': (2, 0, 0, 1), 'rzxz': (2, 0, 1, 1), 'rxyz': (2, 1, 0, 1), 'rzyz': (2, 1, 1, 1)} _TUPLE2AXES = dict((v, k) for k, v in _AXES2TUPLE.items()) # helper functions def vector_norm(data, axis=None, out=None): """Return length, i.e. eucledian norm, of ndarray along axis. >>> v = numpy.random.random(3) >>> n = vector_norm(v) >>> numpy.allclose(n, numpy.linalg.norm(v)) True >>> v = numpy.random.rand(6, 5, 3) >>> n = vector_norm(v, axis=-1) >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=2))) True >>> n = vector_norm(v, axis=1) >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=1))) True >>> v = numpy.random.rand(5, 4, 3) >>> n = numpy.empty((5, 3), dtype=numpy.float64) >>> vector_norm(v, axis=1, out=n) >>> numpy.allclose(n, numpy.sqrt(numpy.sum(v*v, axis=1))) True >>> vector_norm([]) 0.0 >>> vector_norm([1.0]) 1.0 """ data = numpy.array(data, dtype=numpy.float64, copy=True) if out is None: if data.ndim == 1: return math.sqrt(numpy.dot(data, data)) data *= data out = numpy.atleast_1d(numpy.sum(data, axis=axis)) numpy.sqrt(out, out) return out else: data *= data numpy.sum(data, axis=axis, out=out) numpy.sqrt(out, out) def unit_vector(data, axis=None, out=None): """Return ndarray normalized by length, i.e. eucledian norm, along axis. >>> v0 = numpy.random.random(3) >>> v1 = unit_vector(v0) >>> numpy.allclose(v1, v0 / numpy.linalg.norm(v0)) True >>> v0 = numpy.random.rand(5, 4, 3) >>> v1 = unit_vector(v0, axis=-1) >>> v2 = v0 / numpy.expand_dims(numpy.sqrt(numpy.sum(v0*v0, axis=2)), 2) >>> numpy.allclose(v1, v2) True >>> v1 = unit_vector(v0, axis=1) >>> v2 = v0 / numpy.expand_dims(numpy.sqrt(numpy.sum(v0*v0, axis=1)), 1) >>> numpy.allclose(v1, v2) True >>> v1 = numpy.empty((5, 4, 3), dtype=numpy.float64) >>> unit_vector(v0, axis=1, out=v1) >>> numpy.allclose(v1, v2) True >>> list(unit_vector([])) [] >>> list(unit_vector([1.0])) [1.0] """ if out is None: data = numpy.array(data, dtype=numpy.float64, copy=True) if data.ndim == 1: data /= math.sqrt(numpy.dot(data, data)) return data else: if out is not data: out[:] = numpy.array(data, copy=False) data = out length = numpy.atleast_1d(numpy.sum(data*data, axis)) numpy.sqrt(length, length) if axis is not None: length = numpy.expand_dims(length, axis) data /= length if out is None: return data def random_vector(size): """Return array of random doubles in the half-open interval [0.0, 1.0). >>> v = random_vector(10000) >>> numpy.all(v >= 0.0) and numpy.all(v < 1.0) True >>> v0 = random_vector(10) >>> v1 = random_vector(10) >>> numpy.any(v0 == v1) False """ return numpy.random.random(size) def inverse_matrix(matrix): """Return inverse of square transformation matrix. >>> M0 = random_rotation_matrix() >>> M1 = inverse_matrix(M0.T) >>> numpy.allclose(M1, numpy.linalg.inv(M0.T)) True >>> for size in range(1, 7): ... M0 = numpy.random.rand(size, size) ... M1 = inverse_matrix(M0) ... if not numpy.allclose(M1, numpy.linalg.inv(M0)): print size """ return numpy.linalg.inv(matrix) def concatenate_matrices(*matrices): """Return concatenation of series of transformation matrices. >>> M = numpy.random.rand(16).reshape((4, 4)) - 0.5 >>> numpy.allclose(M, concatenate_matrices(M)) True >>> numpy.allclose(numpy.dot(M, M.T), concatenate_matrices(M, M.T)) True """ M = numpy.identity(4) for i in matrices: M = numpy.dot(M, i) return M def is_same_transform(matrix0, matrix1): """Return True if two matrices perform same transformation. >>> is_same_transform(numpy.identity(4), numpy.identity(4)) True >>> is_same_transform(numpy.identity(4), random_rotation_matrix()) False """ matrix0 = numpy.array(matrix0, dtype=numpy.float64, copy=True) matrix0 /= matrix0[3, 3] matrix1 = numpy.array(matrix1, dtype=numpy.float64, copy=True) matrix1 /= matrix1[3, 3] return numpy.allclose(matrix0, matrix1) def _import_module(module_name, warn=True, prefix='_py_', ignore='_'): """Try import all public attributes from module into global namespace. Existing attributes with name clashes are renamed with prefix. Attributes starting with underscore are ignored by default. Return True on successful import. """ try: module = __import__(module_name) except ImportError: if warn: warnings.warn("Failed to import module " + module_name) else: for attr in dir(module): if ignore and attr.startswith(ignore): continue if prefix: if attr in globals(): globals()[prefix + attr] = globals()[attr] elif warn: warnings.warn("No Python implementation of " + attr) globals()[attr] = getattr(module, attr) return True assimp-4.1.0/port/PyAssimp/pyassimp/0000755002537200234200000000000013213503245017652 5ustar zmoelnigiemusersassimp-4.1.0/port/PyAssimp/pyassimp/structs.py0000644002537200234200000010342313213503245021736 0ustar zmoelnigiemusers#-*- coding: UTF-8 -*- from ctypes import POINTER, c_void_p, c_int, c_uint, c_char, c_float, Structure, c_char_p, c_double, c_ubyte, c_size_t, c_uint32 class Vector2D(Structure): """ See 'aiVector2D.h' for details. """ _fields_ = [ ("x", c_float),("y", c_float), ] class Matrix3x3(Structure): """ See 'aiMatrix3x3.h' for details. """ _fields_ = [ ("a1", c_float),("a2", c_float),("a3", c_float), ("b1", c_float),("b2", c_float),("b3", c_float), ("c1", c_float),("c2", c_float),("c3", c_float), ] class Texel(Structure): """ See 'aiTexture.h' for details. """ _fields_ = [ ("b", c_ubyte),("g", c_ubyte),("r", c_ubyte),("a", c_ubyte), ] class Color4D(Structure): """ See 'aiColor4D.h' for details. """ _fields_ = [ # Red, green, blue and alpha color values ("r", c_float),("g", c_float),("b", c_float),("a", c_float), ] class Plane(Structure): """ See 'aiTypes.h' for details. """ _fields_ = [ # Plane equation ("a", c_float),("b", c_float),("c", c_float),("d", c_float), ] class Color3D(Structure): """ See 'aiTypes.h' for details. """ _fields_ = [ # Red, green and blue color values ("r", c_float),("g", c_float),("b", c_float), ] class String(Structure): """ See 'aiTypes.h' for details. """ MAXLEN = 1024 _fields_ = [ # Binary length of the string excluding the terminal 0. This is NOT the # logical length of strings containing UTF-8 multibyte sequences! It's # the number of bytes from the beginning of the string to its end. ("length", c_size_t), # String buffer. Size limit is MAXLEN ("data", c_char*MAXLEN), ] class MaterialPropertyString(Structure): """ See 'aiTypes.h' for details. The size of length is truncated to 4 bytes on 64-bit platforms when used as a material property (see MaterialSystem.cpp aiMaterial::AddProperty() for details). """ MAXLEN = 1024 _fields_ = [ # Binary length of the string excluding the terminal 0. This is NOT the # logical length of strings containing UTF-8 multibyte sequences! It's # the number of bytes from the beginning of the string to its end. ("length", c_uint32), # String buffer. Size limit is MAXLEN ("data", c_char*MAXLEN), ] class MemoryInfo(Structure): """ See 'aiTypes.h' for details. """ _fields_ = [ # Storage allocated for texture data ("textures", c_uint), # Storage allocated for material data ("materials", c_uint), # Storage allocated for mesh data ("meshes", c_uint), # Storage allocated for node data ("nodes", c_uint), # Storage allocated for animation data ("animations", c_uint), # Storage allocated for camera data ("cameras", c_uint), # Storage allocated for light data ("lights", c_uint), # Total storage allocated for the full import. ("total", c_uint), ] class Quaternion(Structure): """ See 'aiQuaternion.h' for details. """ _fields_ = [ # w,x,y,z components of the quaternion ("w", c_float),("x", c_float),("y", c_float),("z", c_float), ] class Face(Structure): """ See 'aiMesh.h' for details. """ _fields_ = [ # Number of indices defining this face. # The maximum value for this member is #AI_MAX_FACE_INDICES. ("mNumIndices", c_uint), # Pointer to the indices array. Size of the array is given in numIndices. ("mIndices", POINTER(c_uint)), ] class VertexWeight(Structure): """ See 'aiMesh.h' for details. """ _fields_ = [ # Index of the vertex which is influenced by the bone. ("mVertexId", c_uint), # The strength of the influence in the range (0...1). # The influence from all bones at one vertex amounts to 1. ("mWeight", c_float), ] class Matrix4x4(Structure): """ See 'aiMatrix4x4.h' for details. """ _fields_ = [ ("a1", c_float),("a2", c_float),("a3", c_float),("a4", c_float), ("b1", c_float),("b2", c_float),("b3", c_float),("b4", c_float), ("c1", c_float),("c2", c_float),("c3", c_float),("c4", c_float), ("d1", c_float),("d2", c_float),("d3", c_float),("d4", c_float), ] class Vector3D(Structure): """ See 'aiVector3D.h' for details. """ _fields_ = [ ("x", c_float),("y", c_float),("z", c_float), ] class MeshKey(Structure): """ See 'aiAnim.h' for details. """ _fields_ = [ # The time of this key ("mTime", c_double), # Index into the aiMesh::mAnimMeshes array of the # mesh corresponding to the #aiMeshAnim hosting this # key frame. The referenced anim mesh is evaluated # according to the rules defined in the docs for #aiAnimMesh. ("mValue", c_uint), ] class Node(Structure): """ See 'aiScene.h' for details. """ Node._fields_ = [ # The name of the node. # The name might be empty (length of zero) but all nodes which # need to be accessed afterwards by bones or anims are usually named. # Multiple nodes may have the same name, but nodes which are accessed # by bones (see #aiBone and #aiMesh::mBones) *must* be unique. # Cameras and lights are assigned to a specific node name - if there # are multiple nodes with this name, they're assigned to each of them. #
# There are no limitations regarding the characters contained in # this text. You should be able to handle stuff like whitespace, tabs, # linefeeds, quotation marks, ampersands, ... . ("mName", String), # The transformation relative to the node's parent. ("mTransformation", Matrix4x4), # Parent node. NULL if this node is the root node. ("mParent", POINTER(Node)), # The number of child nodes of this node. ("mNumChildren", c_uint), # The child nodes of this node. NULL if mNumChildren is 0. ("mChildren", POINTER(POINTER(Node))), # The number of meshes of this node. ("mNumMeshes", c_uint), # The meshes of this node. Each entry is an index into the mesh ("mMeshes", POINTER(c_uint)), ] class Light(Structure): """ See 'aiLight.h' for details. """ _fields_ = [ # The name of the light source. # There must be a node in the scenegraph with the same name. # This node specifies the position of the light in the scene # hierarchy and can be animated. ("mName", String), # The type of the light source. # aiLightSource_UNDEFINED is not a valid value for this member. ("mType", c_uint), # Position of the light source in space. Relative to the # transformation of the node corresponding to the light. # The position is undefined for directional lights. ("mPosition", Vector3D), # Direction of the light source in space. Relative to the # transformation of the node corresponding to the light. # The direction is undefined for point lights. The vector # may be normalized, but it needn't. ("mDirection", Vector3D), # Constant light attenuation factor. # The intensity of the light source at a given distance 'd' from # the light's position is # @code # Atten = 1/( att0 + att1 # d + att2 # d*d) # @endcode # This member corresponds to the att0 variable in the equation. # Naturally undefined for directional lights. ("mAttenuationConstant", c_float), # Linear light attenuation factor. # The intensity of the light source at a given distance 'd' from # the light's position is # @code # Atten = 1/( att0 + att1 # d + att2 # d*d) # @endcode # This member corresponds to the att1 variable in the equation. # Naturally undefined for directional lights. ("mAttenuationLinear", c_float), # Quadratic light attenuation factor. # The intensity of the light source at a given distance 'd' from # the light's position is # @code # Atten = 1/( att0 + att1 # d + att2 # d*d) # @endcode # This member corresponds to the att2 variable in the equation. # Naturally undefined for directional lights. ("mAttenuationQuadratic", c_float), # Diffuse color of the light source # The diffuse light color is multiplied with the diffuse # material color to obtain the final color that contributes # to the diffuse shading term. ("mColorDiffuse", Color3D), # Specular color of the light source # The specular light color is multiplied with the specular # material color to obtain the final color that contributes # to the specular shading term. ("mColorSpecular", Color3D), # Ambient color of the light source # The ambient light color is multiplied with the ambient # material color to obtain the final color that contributes # to the ambient shading term. Most renderers will ignore # this value it, is just a remaining of the fixed-function pipeline # that is still supported by quite many file formats. ("mColorAmbient", Color3D), # Inner angle of a spot light's light cone. # The spot light has maximum influence on objects inside this # angle. The angle is given in radians. It is 2PI for point # lights and undefined for directional lights. ("mAngleInnerCone", c_float), # Outer angle of a spot light's light cone. # The spot light does not affect objects outside this angle. # The angle is given in radians. It is 2PI for point lights and # undefined for directional lights. The outer angle must be # greater than or equal to the inner angle. # It is assumed that the application uses a smooth # interpolation between the inner and the outer cone of the # spot light. ("mAngleOuterCone", c_float), ] class Texture(Structure): """ See 'aiTexture.h' for details. """ _fields_ = [ # Width of the texture, in pixels # If mHeight is zero the texture is compressed in a format # like JPEG. In this case mWidth specifies the size of the # memory area pcData is pointing to, in bytes. ("mWidth", c_uint), # Height of the texture, in pixels # If this value is zero, pcData points to an compressed texture # in any format (e.g. JPEG). ("mHeight", c_uint), # A hint from the loader to make it easier for applications # to determine the type of embedded compressed textures. # If mHeight != 0 this member is undefined. Otherwise it # is set set to '\\0\\0\\0\\0' if the loader has no additional # information about the texture file format used OR the # file extension of the format without a trailing dot. If there # are multiple file extensions for a format, the shortest # extension is chosen (JPEG maps to 'jpg', not to 'jpeg'). # E.g. 'dds\\0', 'pcx\\0', 'jpg\\0'. All characters are lower-case. # The fourth character will always be '\\0'. ("achFormatHint", c_char*4), # Data of the texture. # Points to an array of mWidth # mHeight aiTexel's. # The format of the texture data is always ARGB8888 to # make the implementation for user of the library as easy # as possible. If mHeight = 0 this is a pointer to a memory # buffer of size mWidth containing the compressed texture # data. Good luck, have fun! ("pcData", POINTER(Texel)), ] class Ray(Structure): """ See 'aiTypes.h' for details. """ _fields_ = [ # Position and direction of the ray ("pos", Vector3D),("dir", Vector3D), ] class UVTransform(Structure): """ See 'aiMaterial.h' for details. """ _fields_ = [ # Translation on the u and v axes. # The default value is (0|0). ("mTranslation", Vector2D), # Scaling on the u and v axes. # The default value is (1|1). ("mScaling", Vector2D), # Rotation - in counter-clockwise direction. # The rotation angle is specified in radians. The # rotation center is 0.5f|0.5f. The default value # 0.f. ("mRotation", c_float), ] class MaterialProperty(Structure): """ See 'aiMaterial.h' for details. """ _fields_ = [ # Specifies the name of the property (key) # Keys are generally case insensitive. ("mKey", String), # Textures: Specifies their exact usage semantic. # For non-texture properties, this member is always 0 # (or, better-said, #aiTextureType_NONE). ("mSemantic", c_uint), # Textures: Specifies the index of the texture. # For non-texture properties, this member is always 0. ("mIndex", c_uint), # Size of the buffer mData is pointing to, in bytes. # This value may not be 0. ("mDataLength", c_uint), # Type information for the property. # Defines the data layout inside the data buffer. This is used # by the library internally to perform debug checks and to # utilize proper type conversions. # (It's probably a hacky solution, but it works.) ("mType", c_uint), # Binary buffer to hold the property's value. # The size of the buffer is always mDataLength. ("mData", POINTER(c_char)), ] class Material(Structure): """ See 'aiMaterial.h' for details. """ _fields_ = [ # List of all material properties loaded. ("mProperties", POINTER(POINTER(MaterialProperty))), # Number of properties in the data base ("mNumProperties", c_uint), # Storage allocated ("mNumAllocated", c_uint), ] class Bone(Structure): """ See 'aiMesh.h' for details. """ _fields_ = [ # The name of the bone. ("mName", String), # The number of vertices affected by this bone # The maximum value for this member is #AI_MAX_BONE_WEIGHTS. ("mNumWeights", c_uint), # The vertices affected by this bone ("mWeights", POINTER(VertexWeight)), # Matrix that transforms from mesh space to bone space in bind pose ("mOffsetMatrix", Matrix4x4), ] class Mesh(Structure): """ See 'aiMesh.h' for details. """ AI_MAX_FACE_INDICES = 0x7fff AI_MAX_BONE_WEIGHTS = 0x7fffffff AI_MAX_VERTICES = 0x7fffffff AI_MAX_FACES = 0x7fffffff AI_MAX_NUMBER_OF_COLOR_SETS = 0x8 AI_MAX_NUMBER_OF_TEXTURECOORDS = 0x8 _fields_ = [ # Bitwise combination of the members of the #aiPrimitiveType enum. # This specifies which types of primitives are present in the mesh. # The "SortByPrimitiveType"-Step can be used to make sure the # output meshes consist of one primitive type each. ("mPrimitiveTypes", c_uint), # The number of vertices in this mesh. # This is also the size of all of the per-vertex data arrays. # The maximum value for this member is #AI_MAX_VERTICES. ("mNumVertices", c_uint), # The number of primitives (triangles, polygons, lines) in this mesh. # This is also the size of the mFaces array. # The maximum value for this member is #AI_MAX_FACES. ("mNumFaces", c_uint), # Vertex positions. # This array is always present in a mesh. The array is # mNumVertices in size. ("mVertices", POINTER(Vector3D)), # Vertex normals. # The array contains normalized vectors, NULL if not present. # The array is mNumVertices in size. Normals are undefined for # point and line primitives. A mesh consisting of points and # lines only may not have normal vectors. Meshes with mixed # primitive types (i.e. lines and triangles) may have normals, # but the normals for vertices that are only referenced by # point or line primitives are undefined and set to QNaN (WARN: # qNaN compares to inequal to *everything*, even to qNaN itself. # Using code like this to check whether a field is qnan is: # @code #define IS_QNAN(f) (f != f) # @endcode # still dangerous because even 1.f == 1.f could evaluate to false! ( # remember the subtleties of IEEE754 artithmetics). Use stuff like # @c fpclassify instead. # @note Normal vectors computed by Assimp are always unit-length. # However, this needn't apply for normals that have been taken # directly from the model file. ("mNormals", POINTER(Vector3D)), # Vertex tangents. # The tangent of a vertex points in the direction of the positive # X texture axis. The array contains normalized vectors, NULL if # not present. The array is mNumVertices in size. A mesh consisting # of points and lines only may not have normal vectors. Meshes with # mixed primitive types (i.e. lines and triangles) may have # normals, but the normals for vertices that are only referenced by # point or line primitives are undefined and set to qNaN. See # the #mNormals member for a detailed discussion of qNaNs. # @note If the mesh contains tangents, it automatically also # contains bitangents (the bitangent is just the cross product of # tangent and normal vectors). ("mTangents", POINTER(Vector3D)), # Vertex bitangents. # The bitangent of a vertex points in the direction of the positive # Y texture axis. The array contains normalized vectors, NULL if not # present. The array is mNumVertices in size. # @note If the mesh contains tangents, it automatically also contains # bitangents. ("mBitangents", POINTER(Vector3D)), # Vertex color sets. # A mesh may contain 0 to #AI_MAX_NUMBER_OF_COLOR_SETS vertex # colors per vertex. NULL if not present. Each array is # mNumVertices in size if present. ("mColors", POINTER(Color4D)*AI_MAX_NUMBER_OF_COLOR_SETS), # Vertex texture coords, also known as UV channels. # A mesh may contain 0 to AI_MAX_NUMBER_OF_TEXTURECOORDS per # vertex. NULL if not present. The array is mNumVertices in size. ("mTextureCoords", POINTER(Vector3D)*AI_MAX_NUMBER_OF_TEXTURECOORDS), # Specifies the number of components for a given UV channel. # Up to three channels are supported (UVW, for accessing volume # or cube maps). If the value is 2 for a given channel n, the # component p.z of mTextureCoords[n][p] is set to 0.0f. # If the value is 1 for a given channel, p.y is set to 0.0f, too. # @note 4D coords are not supported ("mNumUVComponents", c_uint*AI_MAX_NUMBER_OF_TEXTURECOORDS), # The faces the mesh is constructed from. # Each face refers to a number of vertices by their indices. # This array is always present in a mesh, its size is given # in mNumFaces. If the #AI_SCENE_FLAGS_NON_VERBOSE_FORMAT # is NOT set each face references an unique set of vertices. ("mFaces", POINTER(Face)), # The number of bones this mesh contains. # Can be 0, in which case the mBones array is NULL. ("mNumBones", c_uint), # The bones of this mesh. # A bone consists of a name by which it can be found in the # frame hierarchy and a set of vertex weights. ("mBones", POINTER(POINTER(Bone))), # The material used by this mesh. # A mesh does use only a single material. If an imported model uses # multiple materials, the import splits up the mesh. Use this value # as index into the scene's material list. ("mMaterialIndex", c_uint), # Name of the mesh. Meshes can be named, but this is not a # requirement and leaving this field empty is totally fine. # There are mainly three uses for mesh names: # - some formats name nodes and meshes independently. # - importers tend to split meshes up to meet the # one-material-per-mesh requirement. Assigning # the same (dummy) name to each of the result meshes # aids the caller at recovering the original mesh # partitioning. # - Vertex animations refer to meshes by their names. ("mName", String), # NOT CURRENTLY IN USE. The number of attachment meshes ("mNumAnimMeshes", c_uint), # NOT CURRENTLY IN USE. Attachment meshes for this mesh, for vertex-based animation. # Attachment meshes carry replacement data for some of the # mesh'es vertex components (usually positions, normals). ] class Camera(Structure): """ See 'aiCamera.h' for details. """ _fields_ = [ # The name of the camera. # There must be a node in the scenegraph with the same name. # This node specifies the position of the camera in the scene # hierarchy and can be animated. ("mName", String), # Position of the camera relative to the coordinate space # defined by the corresponding node. # The default value is 0|0|0. ("mPosition", Vector3D), # 'Up' - vector of the camera coordinate system relative to # the coordinate space defined by the corresponding node. # The 'right' vector of the camera coordinate system is # the cross product of the up and lookAt vectors. # The default value is 0|1|0. The vector # may be normalized, but it needn't. ("mUp", Vector3D), # 'LookAt' - vector of the camera coordinate system relative to # the coordinate space defined by the corresponding node. # This is the viewing direction of the user. # The default value is 0|0|1. The vector # may be normalized, but it needn't. ("mLookAt", Vector3D), # Half horizontal field of view angle, in radians. # The field of view angle is the angle between the center # line of the screen and the left or right border. # The default value is 1/4PI. ("mHorizontalFOV", c_float), # Distance of the near clipping plane from the camera. # The value may not be 0.f (for arithmetic reasons to prevent # a division through zero). The default value is 0.1f. ("mClipPlaneNear", c_float), # Distance of the far clipping plane from the camera. # The far clipping plane must, of course, be further away than the # near clipping plane. The default value is 1000.f. The ratio # between the near and the far plane should not be too # large (between 1000-10000 should be ok) to avoid floating-point # inaccuracies which could lead to z-fighting. ("mClipPlaneFar", c_float), # Screen aspect ratio. # This is the ration between the width and the height of the # screen. Typical values are 4/3, 1/2 or 1/1. This value is # 0 if the aspect ratio is not defined in the source file. # 0 is also the default value. ("mAspect", c_float), ] class VectorKey(Structure): """ See 'aiAnim.h' for details. """ _fields_ = [ # The time of this key ("mTime", c_double), # The value of this key ("mValue", Vector3D), ] class QuatKey(Structure): """ See 'aiAnim.h' for details. """ _fields_ = [ # The time of this key ("mTime", c_double), # The value of this key ("mValue", Quaternion), ] class NodeAnim(Structure): """ See 'aiAnim.h' for details. """ _fields_ = [ # The name of the node affected by this animation. The node # must exist and it must be unique. ("mNodeName", String), # The number of position keys ("mNumPositionKeys", c_uint), # The position keys of this animation channel. Positions are # specified as 3D vector. The array is mNumPositionKeys in size. # If there are position keys, there will also be at least one # scaling and one rotation key. ("mPositionKeys", POINTER(VectorKey)), # The number of rotation keys ("mNumRotationKeys", c_uint), # The rotation keys of this animation channel. Rotations are # given as quaternions, which are 4D vectors. The array is # mNumRotationKeys in size. # If there are rotation keys, there will also be at least one # scaling and one position key. ("mRotationKeys", POINTER(QuatKey)), # The number of scaling keys ("mNumScalingKeys", c_uint), # The scaling keys of this animation channel. Scalings are # specified as 3D vector. The array is mNumScalingKeys in size. # If there are scaling keys, there will also be at least one # position and one rotation key. ("mScalingKeys", POINTER(VectorKey)), # Defines how the animation behaves before the first # key is encountered. # The default value is aiAnimBehaviour_DEFAULT (the original # transformation matrix of the affected node is used). ("mPreState", c_uint), # Defines how the animation behaves after the last # key was processed. # The default value is aiAnimBehaviour_DEFAULT (the original # transformation matrix of the affected node is taken). ("mPostState", c_uint), ] class Animation(Structure): """ See 'aiAnim.h' for details. """ _fields_ = [ # The name of the animation. If the modeling package this data was # exported from does support only a single animation channel, this # name is usually empty (length is zero). ("mName", String), # Duration of the animation in ticks. ("mDuration", c_double), # Ticks per second. 0 if not specified in the imported file ("mTicksPerSecond", c_double), # The number of bone animation channels. Each channel affects # a single node. ("mNumChannels", c_uint), # The node animation channels. Each channel affects a single node. # The array is mNumChannels in size. ("mChannels", POINTER(POINTER(NodeAnim))), # The number of mesh animation channels. Each channel affects # a single mesh and defines vertex-based animation. ("mNumMeshChannels", c_uint), # The mesh animation channels. Each channel affects a single mesh. # The array is mNumMeshChannels in size. ] class Scene(Structure): """ See 'aiScene.h' for details. """ AI_SCENE_FLAGS_INCOMPLETE = 0x1 AI_SCENE_FLAGS_VALIDATED = 0x2 AI_SCENE_FLAGS_VALIDATION_WARNING = 0x4 AI_SCENE_FLAGS_NON_VERBOSE_FORMAT = 0x8 AI_SCENE_FLAGS_TERRAIN = 0x10 _fields_ = [ # Any combination of the AI_SCENE_FLAGS_XXX flags. By default # this value is 0, no flags are set. Most applications will # want to reject all scenes with the AI_SCENE_FLAGS_INCOMPLETE # bit set. ("mFlags", c_uint), # The root node of the hierarchy. # There will always be at least the root node if the import # was successful (and no special flags have been set). # Presence of further nodes depends on the format and content # of the imported file. ("mRootNode", POINTER(Node)), # The number of meshes in the scene. ("mNumMeshes", c_uint), # The array of meshes. # Use the indices given in the aiNode structure to access # this array. The array is mNumMeshes in size. If the # AI_SCENE_FLAGS_INCOMPLETE flag is not set there will always # be at least ONE material. ("mMeshes", POINTER(POINTER(Mesh))), # The number of materials in the scene. ("mNumMaterials", c_uint), # The array of materials. # Use the index given in each aiMesh structure to access this # array. The array is mNumMaterials in size. If the # AI_SCENE_FLAGS_INCOMPLETE flag is not set there will always # be at least ONE material. ("mMaterials", POINTER(POINTER(Material))), # The number of animations in the scene. ("mNumAnimations", c_uint), # The array of animations. # All animations imported from the given file are listed here. # The array is mNumAnimations in size. ("mAnimations", POINTER(POINTER(Animation))), # The number of textures embedded into the file ("mNumTextures", c_uint), # The array of embedded textures. # Not many file formats embed their textures into the file. # An example is Quake's MDL format (which is also used by # some GameStudio versions) ("mTextures", POINTER(POINTER(Texture))), # The number of light sources in the scene. Light sources # are fully optional, in most cases this attribute will be 0 ("mNumLights", c_uint), # The array of light sources. # All light sources imported from the given file are # listed here. The array is mNumLights in size. ("mLights", POINTER(POINTER(Light))), # The number of cameras in the scene. Cameras # are fully optional, in most cases this attribute will be 0 ("mNumCameras", c_uint), # The array of cameras. # All cameras imported from the given file are listed here. # The array is mNumCameras in size. The first camera in the # array (if existing) is the default camera view into # the scene. ("mCameras", POINTER(POINTER(Camera))), ] assimp_structs_as_tuple = (Matrix4x4, Matrix3x3, Vector2D, Vector3D, Color3D, Color4D, Quaternion, Plane, Texel) assimp-4.1.0/port/PyAssimp/pyassimp/formats.py0000644002537200234200000000144613213503245021704 0ustar zmoelnigiemusersFORMATS = ["CSM", "LWS", "B3D", "COB", "PLY", "IFC", "OFF", "SMD", "IRRMESH", "3D", "DAE", "MDL", "HMP", "TER", "WRL", "XML", "NFF", "AC", "OBJ", "3DS", "STL", "IRR", "Q3O", "Q3D" "MS3D", "Q3S", "ZGL", "MD2", "X", "BLEND", "XGL", "MD5MESH", "MAX", "LXO", "DXF", "BVH", "LWO", "NDO"] def available_formats(): return FORMATS assimp-4.1.0/port/PyAssimp/pyassimp/postprocess.py0000644002537200234200000005572513213503245022626 0ustar zmoelnigiemusers#
Calculates the tangents and bitangents for the imported meshes. # # Does nothing if a mesh does not have normals. You might want this post # processing step to be executed if you plan to use tangent space calculations # such as normal mapping applied to the meshes. There's a config setting, # #AI_CONFIG_PP_CT_MAX_SMOOTHING_ANGLE, which allows you to specify # a maximum smoothing angle for the algorithm. However, usually you'll # want to leave it at the default value. # aiProcess_CalcTangentSpace = 0x1 ##
Identifies and joins identical vertex data sets within all # imported meshes. # # After this step is run, each mesh contains unique vertices, # so a vertex may be used by multiple faces. You usually want # to use this post processing step. If your application deals with # indexed geometry, this step is compulsory or you'll just waste rendering # time. If this flag is not specified, no vertices are referenced by # more than one face and no index buffer is required for rendering. # aiProcess_JoinIdenticalVertices = 0x2 ##
Converts all the imported data to a left-handed coordinate space. # # By default the data is returned in a right-handed coordinate space (which # OpenGL prefers). In this space, +X points to the right, # +Z points towards the viewer, and +Y points upwards. In the DirectX # coordinate space +X points to the right, +Y points upwards, and +Z points # away from the viewer. # # You'll probably want to consider this flag if you use Direct3D for # rendering. The #aiProcess_ConvertToLeftHanded flag supersedes this # setting and bundles all conversions typically required for D3D-based # applications. # aiProcess_MakeLeftHanded = 0x4 ##
Triangulates all faces of all meshes. # # By default the imported mesh data might contain faces with more than 3 # indices. For rendering you'll usually want all faces to be triangles. # This post processing step splits up faces with more than 3 indices into # triangles. Line and point primitives are #not# modified! If you want # 'triangles only' with no other kinds of primitives, try the following # solution: #