diff --git a/Windows_Libs/Dev/Input/Input.vcxproj b/Windows_Libs/Dev/Input/Input.vcxproj index ad24d91..3188e2b 100644 --- a/Windows_Libs/Dev/Input/Input.vcxproj +++ b/Windows_Libs/Dev/Input/Input.vcxproj @@ -49,7 +49,7 @@ StaticLibrary false - v110 + v145 true Unicode diff --git a/Windows_Libs/Dev/Input/Input.vcxproj.filters b/Windows_Libs/Dev/Input/Input.vcxproj.filters index 644602f..53711b9 100644 --- a/Windows_Libs/Dev/Input/Input.vcxproj.filters +++ b/Windows_Libs/Dev/Input/Input.vcxproj.filters @@ -9,10 +9,6 @@ {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;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 - diff --git a/Windows_Libs/Dev/Profile/Profile.vcxproj b/Windows_Libs/Dev/Profile/Profile.vcxproj index 11e6d42..ec99799 100644 --- a/Windows_Libs/Dev/Profile/Profile.vcxproj +++ b/Windows_Libs/Dev/Profile/Profile.vcxproj @@ -49,7 +49,7 @@ StaticLibrary false - v110 + v145 true Unicode diff --git a/Windows_Libs/Dev/Profile/Profile.vcxproj.filters b/Windows_Libs/Dev/Profile/Profile.vcxproj.filters index 857584d..ddd612f 100644 --- a/Windows_Libs/Dev/Profile/Profile.vcxproj.filters +++ b/Windows_Libs/Dev/Profile/Profile.vcxproj.filters @@ -9,10 +9,6 @@ {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;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 - diff --git a/Windows_Libs/Dev/Render/4J_Render.cpp b/Windows_Libs/Dev/Render/4J_Render.cpp index 38fe1da..0695b09 100644 --- a/Windows_Libs/Dev/Render/4J_Render.cpp +++ b/Windows_Libs/Dev/Render/4J_Render.cpp @@ -6,7 +6,9 @@ C4JRender RenderManager; void C4JRender::Tick() { +#if _DEBUG InternalRenderManager.CBuffTick(); +#endif } void C4JRender::UpdateGamma(unsigned short usGamma) diff --git a/Windows_Libs/Dev/Render/Profiler.h b/Windows_Libs/Dev/Render/Profiler.h new file mode 100644 index 0000000..e78cd52 --- /dev/null +++ b/Windows_Libs/Dev/Render/Profiler.h @@ -0,0 +1,14 @@ +#pragma once + +// enable only if you know what you're doing +// requires linking Minecraft.Client against Ws2_32.lib +// stats are available at http://127.0.0.1:1338/ + +//#define ENABLE_PROFILING + +#ifdef ENABLE_PROFILING +#include "microprofile/microprofile.h" +#define PROFILER_SCOPE(group, name, color) MICROPROFILE_SCOPEI(group, name, color); +#else +#define PROFILER_SCOPE(group, name, color) ((void)0); +#endif \ No newline at end of file diff --git a/Windows_Libs/Dev/Render/Render.vcxproj b/Windows_Libs/Dev/Render/Render.vcxproj index f0127eb..e7af720 100644 --- a/Windows_Libs/Dev/Render/Render.vcxproj +++ b/Windows_Libs/Dev/Render/Render.vcxproj @@ -49,7 +49,7 @@ StaticLibrary false - v110 + v145 true Unicode @@ -123,7 +123,7 @@ true stdafx.h MultiThreadedDebug - libpng\;zlib\;%(AdditionalIncludeDirectories) + libpng\;zlib\;microprofile\;%(AdditionalIncludeDirectories) Default true @@ -148,7 +148,7 @@ true stdafx.h MultiThreaded - libpng\;zlib\;%(AdditionalIncludeDirectories) + libpng\;zlib\;microprofile\;%(AdditionalIncludeDirectories) @@ -167,6 +167,10 @@ + + + + @@ -329,6 +333,7 @@ + diff --git a/Windows_Libs/Dev/Render/Render.vcxproj.filters b/Windows_Libs/Dev/Render/Render.vcxproj.filters index 77d14ca..a54788a 100644 --- a/Windows_Libs/Dev/Render/Render.vcxproj.filters +++ b/Windows_Libs/Dev/Render/Render.vcxproj.filters @@ -9,9 +9,20 @@ {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;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 + + {e5716c14-38f4-49f7-bf1a-916fbc7613a8} + + + {0681221a-1efa-43e4-b0f7-0b525172e486} + + + {0629c87a-576d-4163-8c60-dad190ee97d0} + + + {8be558c7-c6e6-4ef7-bfcb-83d29f079240} + + + {6cbd8b95-ff51-42d2-a66f-282d3a11c042} @@ -21,33 +32,6 @@ Header Files - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - Header Files @@ -87,6 +71,45 @@ Header Files + + Header Files\zlib + + + Header Files\zlib + + + Header Files\libpng + + + Header Files\libpng + + + Header Files\libpng + + + Header Files\libpng + + + Header Files\libpng + + + Header Files\libpng + + + Header Files\libpng + + + Header Files\microprofile + + + Header Files\microprofile + + + Header Files\microprofile + + + Header Files + @@ -114,52 +137,55 @@ Source Files - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng - Source Files + Source Files\libpng + + + Source Files\microprofile \ No newline at end of file diff --git a/Windows_Libs/Dev/Render/Renderer.h b/Windows_Libs/Dev/Render/Renderer.h index 9f6ae23..24a4fc2 100644 --- a/Windows_Libs/Dev/Render/Renderer.h +++ b/Windows_Libs/Dev/Render/Renderer.h @@ -1,5 +1,6 @@ #pragma once #include "4J_Render.h" +#include "Profiler.h" #include #include #include @@ -13,6 +14,7 @@ #define STACK_TYPES 4 #define STACK_SIZE 16 #define MAX_MIP_LEVELS 5 +#define MAX_TEXTURES 512 #define NUM_COMMAND_HANDLES 0x800000 #define MAX_COMMAND_BUFFERS 16000 @@ -137,8 +139,6 @@ private: ID3D11SamplerState *GetManagedSamplerState(); void DeleteInternalBuffer(int index); Renderer::Context &getContext(); - static D3D11_PRIMITIVE_TOPOLOGY *m_Topologies; - static DXGI_FORMAT textureFormats[C4JRender::MAX_TEXTURE_FORMATS]; public: struct Texture { @@ -332,12 +332,12 @@ public: DWORD stackPos[MATRIX_MODE_MODELVIEW_MAX]; DWORD stackType; DWORD textureIdx; - BYTE faceCullEnabled; - BYTE depthTestEnabled; - BYTE alphaTestEnabled; + bool faceCullEnabled; + bool depthTestEnabled; + bool alphaTestEnabled; float alphaReference; - BYTE depthWriteEnabled; - BYTE fogEnabled; + bool depthWriteEnabled; + bool fogEnabled; float fogNearDistance; float fogFarDistance; float fogDensity; @@ -345,9 +345,9 @@ public: float fogColourBlue; float fogColourGreen; DWORD fogMode; - BYTE lightingEnabled; - BYTE lightEnabled[2]; - BYTE lightingDirty; + bool lightingEnabled; + bool lightEnabled[2]; + bool lightingDirty; DWORD forcedLOD; BYTE paddingAfterForceLOD[4]; DirectX::XMFLOAT4 lightDirection[2]; @@ -377,7 +377,7 @@ public: DWORD recordingBufferIndex; DWORD recordingVertexType; DWORD recordingPrimitiveType; - BYTE deferredModeEnabled; + bool deferredModeEnabled; std::vector deferredBuffers; D3D11_BLEND_DESC blendDesc; D3D11_DEPTH_STENCIL_DESC depthStencilDesc; @@ -386,13 +386,12 @@ public: }; static DWORD tlsIdx; - static unsigned int s_auiWidths[MAX_MIP_LEVELS + 1]; - static unsigned int s_auiHeights[MAX_MIP_LEVELS + 1]; - static D3D11_INPUT_ELEMENT_DESC g_vertex_PTN_Elements_PF3_TF2_CB4_NB4_XW1[5]; - static D3D11_INPUT_ELEMENT_DESC g_vertex_PTN_Elements_Compressed[2]; - static D3D11_PRIMITIVE_TOPOLOGY g_topologies[C4JRender::PRIMITIVE_TYPE_COUNT]; - static int totalAlloc; static _RTL_CRITICAL_SECTION totalAllocCS; + static DWORD s_auiWidths[]; + static DWORD s_auiHeights[]; + static DXGI_FORMAT textureFormats[]; + static D3D_PRIMITIVE_TOPOLOGY g_topologies[]; + static int totalAlloc; float m_fClearColor[4]; ID3D11Device *m_pDevice; @@ -444,8 +443,8 @@ public: std::unordered_map managedDepthStencilStates; std::unordered_map managedSamplerStates; std::unordered_map managedRasterizerStates; - BYTE shouldScreenGrabNextFrame; - BYTE suspended; + bool m_bShouldScreenGrabNextFrame; + bool m_bSuspended; BYTE paddingAfterSuspendState[2]; }; diff --git a/Windows_Libs/Dev/Render/RendererCBuff.cpp b/Windows_Libs/Dev/Render/RendererCBuff.cpp index de1922a..b1fc591 100644 --- a/Windows_Libs/Dev/Render/RendererCBuff.cpp +++ b/Windows_Libs/Dev/Render/RendererCBuff.cpp @@ -1,17 +1,19 @@ -#pragma once +#include "stdafx.h" #include "Renderer.h" -#include -#include #include -#include #include #include Renderer::CommandBuffer::CommandBuffer(bool full) - : m_vertexBuffer(nullptr), m_vertexData(nullptr), m_vertexDataLength(0), m_commands(), m_allocated(0x1000), isActive(full ? 1 : 0) + : m_vertexBuffer(NULL) + , m_vertexData(NULL) + , m_vertexDataLength(0) + , m_commands() + , m_allocated(0x1000) + , isActive(full ? 1 : 0) { - m_vertexData = std::malloc(m_allocated); + m_vertexData = malloc(m_allocated); EnterCriticalSection(&Renderer::totalAllocCS); Renderer::totalAlloc += static_cast(m_allocated); LeaveCriticalSection(&Renderer::totalAllocCS); @@ -20,11 +22,9 @@ Renderer::CommandBuffer::CommandBuffer(bool full) Renderer::CommandBuffer::~CommandBuffer() { if (m_vertexBuffer) - { m_vertexBuffer->Release(); - } - std::free(m_vertexData); + free(m_vertexData); EnterCriticalSection(&Renderer::totalAllocCS); Renderer::totalAlloc -= static_cast(m_allocated); @@ -38,7 +38,7 @@ void Renderer::CommandBuffer::EndRecording(ID3D11Device *device) if (m_vertexDataLength != 0) { D3D11_BUFFER_DESC desc = {}; - desc.ByteWidth = m_vertexDataLength; + desc.ByteWidth = static_cast(m_vertexDataLength); desc.Usage = D3D11_USAGE_IMMUTABLE; desc.BindFlags = D3D11_BIND_VERTEX_BUFFER; @@ -47,8 +47,8 @@ void Renderer::CommandBuffer::EndRecording(ID3D11Device *device) device->CreateBuffer(&desc, &data, &m_vertexBuffer); } - std::free(m_vertexData); - m_vertexData = nullptr; + free(m_vertexData); + m_vertexData = NULL; } std::uint64_t Renderer::CommandBuffer::GetAllocated() @@ -65,15 +65,17 @@ void Renderer::CommandBuffer::AddMatrix(const float *matrix) { Command command = {}; command.m_command_type = COMMAND_ADD_MATRIX; - std::memcpy(command.add_matrix.m_matrix, matrix, sizeof(command.add_matrix.m_matrix)); + memcpy(command.add_matrix.m_matrix, matrix, sizeof(command.add_matrix.m_matrix)); m_commands.push_back(command); } void Renderer::CommandBuffer::AddVertices(unsigned int stride, unsigned int count, void *dataIn, Renderer::Context &c) { + PROFILER_SCOPE("Renderer::CommandBuffer::AddVertices", "AddVertices", MP_ORANGE) + if (c.matrixDirty[MATRIX_MODE_MODELVIEW_CBUFF]) { - this->AddMatrix(InternalRenderManager.MatrixGet(MATRIX_MODE_MODELVIEW_CBUFF)); + AddMatrix(InternalRenderManager.MatrixGet(MATRIX_MODE_MODELVIEW_CBUFF)); c.matrixDirty[MATRIX_MODE_MODELVIEW_CBUFF] = false; } @@ -92,7 +94,7 @@ void Renderer::CommandBuffer::AddVertices(unsigned int stride, unsigned int coun Renderer::totalAlloc -= static_cast(m_allocated); LeaveCriticalSection(&Renderer::totalAllocCS); - m_allocated = ((m_vertexDataLength + (0x1000u - 1u)) & ~(0x1000u - 1u)); + m_allocated = ((m_vertexDataLength + (0x1000 - 1)) & ~(0x1000 - 1)); m_vertexData = std::realloc(m_vertexData, m_allocated); EnterCriticalSection(&Renderer::totalAllocCS); @@ -101,7 +103,7 @@ void Renderer::CommandBuffer::AddVertices(unsigned int stride, unsigned int coun } const std::size_t byteCount = std::size_t(stride) * std::size_t(count); - std::memcpy(static_cast(m_vertexData) + vertexOffset, dataIn, byteCount); + memcpy(static_cast(m_vertexData) + vertexOffset, dataIn, byteCount); m_commands.push_back(command); } @@ -243,36 +245,39 @@ void Renderer::CommandBuffer::SetFaceCull(bool enable) void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Context &c, int primitiveType) { + PROFILER_SCOPE("Renderer::CommandBuffer::Render", "Render", MP_ORANGE) + if (!m_vertexBuffer) - { return; - } int drawVertexType = vType; int shaderVertexType = drawVertexType; bool matrixOverride = false; - for (std::vector::const_iterator it = m_commands.begin(); it != m_commands.end(); ++it) + for (const Command &command : m_commands) { - const Command &command = *it; + PROFILER_SCOPE("Renderer::CommandBuffer::Render", "ProcessCommand", MP_ORANGE) + switch (command.m_command_type) { case COMMAND_ADD_MATRIX: { if (drawVertexType == C4JRender::VERTEX_TYPE_COMPRESSED) { - const float row[4] = {command.add_matrix.m_matrix[12], command.add_matrix.m_matrix[13], command.add_matrix.m_matrix[14], - command.add_matrix.m_matrix[15]}; + const float row[4] = { + command.add_matrix.m_matrix[12], command.add_matrix.m_matrix[13], + command.add_matrix.m_matrix[14], command.add_matrix.m_matrix[15] + }; D3D11_MAPPED_SUBRESOURCE mappedAux0 = {}; c.m_pDeviceContext->Map(c.m_compressedTranslationBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedAux0); - std::memcpy(mappedAux0.pData, row, sizeof(row)); + memcpy(mappedAux0.pData, row, sizeof(row)); c.m_pDeviceContext->Unmap(c.m_compressedTranslationBuffer, 0); } else { D3D11_MAPPED_SUBRESOURCE mappedMatrix1 = {}; c.m_pDeviceContext->Map(c.m_localTransformMatrix, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedMatrix1); - std::memcpy(mappedMatrix1.pData, command.add_matrix.m_matrix, sizeof(command.add_matrix.m_matrix)); + memcpy(mappedMatrix1.pData, command.add_matrix.m_matrix, sizeof(command.add_matrix.m_matrix)); c.m_pDeviceContext->Unmap(c.m_localTransformMatrix, 0); matrixOverride = true; } @@ -300,7 +305,7 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con if (static_cast(drawVertexType) != InternalRenderManager.activeVertexType) { - c.m_pDeviceContext->VSSetShader(InternalRenderManager.vertexShaderTable[shaderVertexType], nullptr, 0); + c.m_pDeviceContext->VSSetShader(InternalRenderManager.vertexShaderTable[shaderVertexType], NULL, 0); c.m_pDeviceContext->IASetInputLayout(InternalRenderManager.inputLayoutTable[shaderVertexType]); InternalRenderManager.activeVertexType = drawVertexType; } @@ -310,12 +315,12 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con bool drawIndexed = false; if (primitiveType == C4JRender::PRIMITIVE_TYPE_QUAD_LIST) { - drawCount = (drawCount * 6u) / 4u; + drawCount = (drawCount * 6) / 4; drawIndexed = true; } else if (primitiveType == C4JRender::PRIMITIVE_TYPE_TRIANGLE_FAN) { - drawCount = (drawCount - 2u) * 3u; + drawCount = (drawCount - 2) * 3; drawIndexed = true; } @@ -325,13 +330,9 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con c.m_pDeviceContext->IASetVertexBuffers(0, 1, &buffer, &stride, &offset); if (drawIndexed) - { c.m_pDeviceContext->DrawIndexed(drawCount, 0, 0); - } else - { c.m_pDeviceContext->Draw(drawCount, 0); - } break; } case COMMAND_BIND_TEXTURE: @@ -346,7 +347,7 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con { D3D11_MAPPED_SUBRESOURCE mappedColour = {}; c.m_pDeviceContext->Map(c.m_tintColorBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedColour); - std::memcpy(mappedColour.pData, command.set_color.m_color, sizeof(command.set_color.m_color)); + memcpy(mappedColour.pData, command.set_color.m_color, sizeof(command.set_color.m_color)); c.m_pDeviceContext->Unmap(c.m_tintColorBuffer, 0); break; } @@ -358,21 +359,21 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con } case COMMAND_SET_DEPTH_MASK: { - c.depthWriteEnabled = command.set_depth_mask.m_enable ? 1 : 0; + c.depthWriteEnabled = command.set_depth_mask.m_enable; c.depthStencilDesc.DepthWriteMask = command.set_depth_mask.m_enable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; c.m_pDeviceContext->OMSetDepthStencilState(InternalRenderManager.GetManagedDepthStencilState(), 0); break; } case COMMAND_SET_DEPTH_TEST: { - c.depthTestEnabled = command.set_depth_test.m_enable ? 1 : 0; - c.depthStencilDesc.DepthEnable = command.set_depth_test.m_enable ? TRUE : FALSE; + c.depthTestEnabled = command.set_depth_test.m_enable; + c.depthStencilDesc.DepthEnable = command.set_depth_test.m_enable; c.m_pDeviceContext->OMSetDepthStencilState(InternalRenderManager.GetManagedDepthStencilState(), 0); break; } case COMMAND_SET_LIGHTING_ENABLE: { - c.lightingEnabled = command.set_lighting_enable.m_enable ? 1 : 0; + c.lightingEnabled = command.set_lighting_enable.m_enable; break; } case COMMAND_SET_LIGHT_ENABLE: @@ -380,8 +381,8 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con const int light = command.set_light_enable.m_light_index; if (light >= 0 && light < 2) { - c.lightEnabled[light] = command.set_light_enable.m_enable ? 1 : 0; - c.lightingDirty = 1; + c.lightEnabled[light] = command.set_light_enable.m_enable; + c.lightingDirty = true; } break; } @@ -394,7 +395,7 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con c.lightDirection[light].y = command.set_light_direction.m_direction[1]; c.lightDirection[light].z = command.set_light_direction.m_direction[2]; c.lightDirection[light].w = command.set_light_direction.m_direction[3]; - c.lightingDirty = 1; + c.lightingDirty = true; } break; } @@ -407,7 +408,7 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con c.lightColour[light].y = command.set_light_colour.m_color[1]; c.lightColour[light].z = command.set_light_colour.m_color[2]; c.lightColour[light].w = 1.0f; - c.lightingDirty = 1; + c.lightingDirty = true; } break; } @@ -417,36 +418,36 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con c.lightAmbientColour.y = command.set_light_ambient_colour.m_color[1]; c.lightAmbientColour.z = command.set_light_ambient_colour.m_color[2]; c.lightAmbientColour.w = 1.0f; - c.lightingDirty = 1; + c.lightingDirty = true; break; } case COMMAND_SET_BLEND_ENABLE: { - c.blendDesc.RenderTarget[0].BlendEnable = command.set_blend_enable.m_enable ? TRUE : FALSE; + c.blendDesc.RenderTarget[0].BlendEnable = command.set_blend_enable.m_enable; break; } case COMMAND_SET_BLEND_FUNC: { c.blendDesc.RenderTarget[0].SrcBlend = static_cast(command.set_blend_func.m_src); c.blendDesc.RenderTarget[0].DestBlend = static_cast(command.set_blend_func.m_dst); - c.m_pDeviceContext->OMSetBlendState(InternalRenderManager.GetManagedBlendState(), c.blendFactor, 0xFFFFFFFFu); + c.m_pDeviceContext->OMSetBlendState(InternalRenderManager.GetManagedBlendState(), c.blendFactor, 0xFFFFFFFF); break; } case COMMAND_SET_BLEND_FACTOR: { const unsigned int factor = command.set_blend_factor.m_blend_factor; - c.blendFactor[0] = float((factor >> 0) & 0xFFu) / 255.0f; - c.blendFactor[1] = float((factor >> 8) & 0xFFu) / 255.0f; - c.blendFactor[2] = float((factor >> 16) & 0xFFu) / 255.0f; - c.blendFactor[3] = float((factor >> 24) & 0xFFu) / 255.0f; - c.m_pDeviceContext->OMSetBlendState(InternalRenderManager.GetManagedBlendState(), c.blendFactor, 0xFFFFFFFFu); + c.blendFactor[0] = float((factor >> 0) & 0xFF) / 255.0f; + c.blendFactor[1] = float((factor >> 8) & 0xFF) / 255.0f; + c.blendFactor[2] = float((factor >> 16) & 0xFF) / 255.0f; + c.blendFactor[3] = float((factor >> 24) & 0xFF) / 255.0f; + c.m_pDeviceContext->OMSetBlendState(InternalRenderManager.GetManagedBlendState(), c.blendFactor, 0xFFFFFFFF); break; } case COMMAND_SET_FACE_CULL: { c.rasterizerDesc.CullMode = command.set_face_cull.m_enable ? D3D11_CULL_BACK : D3D11_CULL_NONE; c.m_pDeviceContext->RSSetState(InternalRenderManager.GetManagedRasterizerState()); - c.faceCullEnabled = command.set_face_cull.m_enable ? 1 : 0; + c.faceCullEnabled = command.set_face_cull.m_enable; break; } default: @@ -459,7 +460,7 @@ void Renderer::CommandBuffer::Render(C4JRender::eVertexType vType, Renderer::Con const DirectX::XMMATRIX identity = DirectX::XMMatrixIdentity(); D3D11_MAPPED_SUBRESOURCE mappedIdentity = {}; c.m_pDeviceContext->Map(c.m_localTransformMatrix, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedIdentity); - std::memcpy(mappedIdentity.pData, &identity, sizeof(identity)); + memcpy(mappedIdentity.pData, &identity, sizeof(identity)); c.m_pDeviceContext->Unmap(c.m_localTransformMatrix, 0); } } @@ -472,7 +473,7 @@ bool Renderer::CBuffCall(int index, bool full) const int commandIndex = m_commandHandleToIndex[index]; if (commandIndex >= 0) { - Renderer::Context &c = this->getContext(); + Renderer::Context &c = getContext(); const std::uint8_t vertexType = m_commandVertexTypes[commandIndex]; const std::uint8_t primitiveType = m_commandPrimitiveTypes[commandIndex]; @@ -482,7 +483,7 @@ bool Renderer::CBuffCall(int index, bool full) { D3D11_MAPPED_SUBRESOURCE mappedMatrix0 = {}; c.m_pDeviceContext->Map(c.m_modelViewMatrix, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedMatrix0); - std::memcpy(mappedMatrix0.pData, this->MatrixGet(MATRIX_MODE_MODELVIEW), sizeof(DirectX::XMMATRIX)); + memcpy(mappedMatrix0.pData, MatrixGet(MATRIX_MODE_MODELVIEW), sizeof(DirectX::XMMATRIX)); c.m_pDeviceContext->Unmap(c.m_modelViewMatrix, 0); c.matrixDirty[MATRIX_MODE_MODELVIEW] = false; } @@ -491,7 +492,7 @@ bool Renderer::CBuffCall(int index, bool full) { D3D11_MAPPED_SUBRESOURCE mappedMatrix2 = {}; c.m_pDeviceContext->Map(c.m_projectionMatrix, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedMatrix2); - std::memcpy(mappedMatrix2.pData, this->MatrixGet(MATRIX_MODE_MODELVIEW_PROJECTION), sizeof(DirectX::XMMATRIX)); + memcpy(mappedMatrix2.pData, MatrixGet(MATRIX_MODE_MODELVIEW_PROJECTION), sizeof(DirectX::XMMATRIX)); c.m_pDeviceContext->Unmap(c.m_projectionMatrix, 0); c.matrixDirty[MATRIX_MODE_MODELVIEW_PROJECTION] = false; } @@ -500,19 +501,19 @@ bool Renderer::CBuffCall(int index, bool full) { D3D11_MAPPED_SUBRESOURCE mappedMatrix3 = {}; c.m_pDeviceContext->Map(c.m_textureMatrix, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedMatrix3); - std::memcpy(mappedMatrix3.pData, this->MatrixGet(MATRIX_MODE_MODELVIEW_TEXTURE), sizeof(DirectX::XMMATRIX)); + memcpy(mappedMatrix3.pData, MatrixGet(MATRIX_MODE_MODELVIEW_TEXTURE), sizeof(DirectX::XMMATRIX)); c.m_pDeviceContext->Unmap(c.m_textureMatrix, 0); c.matrixDirty[MATRIX_MODE_MODELVIEW_TEXTURE] = false; } - this->UpdateFogState(); - this->UpdateLightingState(); - this->UpdateViewportState(); - this->UpdateTexGenState(); + UpdateFogState(); + UpdateLightingState(); + UpdateViewportState(); + UpdateTexGenState(); if (vertexType != activeVertexType) { - c.m_pDeviceContext->VSSetShader(vertexShaderTable[vertexType], nullptr, 0); + c.m_pDeviceContext->VSSetShader(vertexShaderTable[vertexType], NULL, 0); c.m_pDeviceContext->IASetInputLayout(inputLayoutTable[vertexType]); activeVertexType = vertexType; } @@ -523,28 +524,24 @@ bool Renderer::CBuffCall(int index, bool full) const float forcedLod[4] = {static_cast(static_cast(c.forcedLOD)), 0.0f, 0.0f, 0.0f}; D3D11_MAPPED_SUBRESOURCE mappedAux4 = {}; c.m_pDeviceContext->Map(c.m_forcedLODBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedAux4); - std::memcpy(mappedAux4.pData, forcedLod, sizeof(forcedLod)); + memcpy(mappedAux4.pData, forcedLod, sizeof(forcedLod)); c.m_pDeviceContext->Unmap(c.m_forcedLODBuffer, 0); pixelType = C4JRender::PIXEL_SHADER_TYPE_FORCELOD; } if (static_cast(pixelType) != activePixelType) { - c.m_pDeviceContext->PSSetShader(pixelShaderTable[pixelType], nullptr, 0); + c.m_pDeviceContext->PSSetShader(pixelShaderTable[pixelType], NULL, 0); activePixelType = pixelType; } - c.m_pDeviceContext->IASetPrimitiveTopology(m_Topologies[primitiveType]); + c.m_pDeviceContext->IASetPrimitiveTopology(g_topologies[primitiveType]); - ID3D11Buffer *indexBuffer = nullptr; + ID3D11Buffer *indexBuffer = NULL; if (primitiveType == C4JRender::PRIMITIVE_TYPE_QUAD_LIST) - { indexBuffer = quadIndexBuffer; - } else if (primitiveType == C4JRender::PRIMITIVE_TYPE_TRIANGLE_FAN) - { indexBuffer = fanIndexBuffer; - } c.m_pDeviceContext->IASetIndexBuffer(indexBuffer, DXGI_FORMAT_R16_UINT, 0); } @@ -553,7 +550,7 @@ bool Renderer::CBuffCall(int index, bool full) if (full) { - this->MultWithStack(m_commandMatrices[commandIndex]); + MultWithStack(m_commandMatrices[commandIndex]); c.matrixStacks[MATRIX_MODE_MODELVIEW_CBUFF][0] = DirectX::XMMatrixIdentity(); c.matrixDirty[MATRIX_MODE_MODELVIEW_CBUFF] = true; } @@ -573,7 +570,7 @@ void Renderer::CBuffClear(int index) const int internalIndex = externalToInternal[index]; if (internalIndex >= 0) { - this->DeleteInternalBuffer(internalIndex); + DeleteInternalBuffer(internalIndex); externalToInternal[index] = static_cast(-2); } @@ -600,9 +597,7 @@ int Renderer::CBuffCreate(int count) } if (cursor >= end) - { break; - } ++first; ++probe; @@ -618,14 +613,10 @@ int Renderer::CBuffCreate(int count) { const int allocationEnd = first + count; for (int i = first; i < allocationEnd; ++i) - { m_commandHandleToIndex[i] = static_cast(-2); - } if (reservedRendererByte1) - { reservedRendererDword1 = allocationEnd; - } } } else @@ -639,28 +630,22 @@ int Renderer::CBuffCreate(int count) void Renderer::CBuffDeferredModeEnd() { - Renderer::Context &c = this->getContext(); + Renderer::Context &c = getContext(); if (!c.deferredModeEnabled) - { return; - } EnterCriticalSection(&rtl_critical_section100); - c.deferredModeEnabled = 0; + c.deferredModeEnabled = false; for (std::vector::const_iterator it = c.deferredBuffers.begin(); it != c.deferredBuffers.end(); ++it) { const Renderer::DeferredCBuff &deferred = *it; const int existingIndex = m_commandHandleToIndex[deferred.m_vertex_index]; if (existingIndex >= 0) - { - this->DeleteInternalBuffer(existingIndex); - } + DeleteInternalBuffer(existingIndex); - if (static_cast(reservedRendererDword2 + reservedRendererDword3 + 10u) > MAX_COMMAND_BUFFERS) - { + if (static_cast(reservedRendererDword2 + reservedRendererDword3 + 10) > MAX_COMMAND_BUFFERS) DebugBreak(); - } const int internalSlot = reservedRendererDword2; ++reservedRendererDword2; @@ -679,7 +664,7 @@ void Renderer::CBuffDeferredModeEnd() void Renderer::CBuffDeferredModeStart() { - this->getContext().deferredModeEnabled = 1; + getContext().deferredModeEnabled = true; } void Renderer::CBuffDelete(int first, int count) @@ -691,9 +676,7 @@ void Renderer::CBuffDelete(int first, int count) { const int internalIndex = m_commandHandleToIndex[i]; if (internalIndex >= 0) - { - this->DeleteInternalBuffer(internalIndex); - } + DeleteInternalBuffer(internalIndex); m_commandHandleToIndex[i] = static_cast(-1); } @@ -703,7 +686,7 @@ void Renderer::CBuffDelete(int first, int count) void Renderer::CBuffEnd() { - Renderer::Context &c = this->getContext(); + Renderer::Context &c = getContext(); assert(c.stackType == MATRIX_MODE_MODELVIEW_CBUFF); assert(c.stackPos[MATRIX_MODE_MODELVIEW_CBUFF] == 0); @@ -724,14 +707,10 @@ void Renderer::CBuffEnd() { const int existingIndex = m_commandHandleToIndex[c.recordingBufferIndex]; if (existingIndex >= 0) - { - this->DeleteInternalBuffer(existingIndex); - } + DeleteInternalBuffer(existingIndex); - if (static_cast(reservedRendererDword2 + reservedRendererDword3 + 10u) > MAX_COMMAND_BUFFERS) - { + if (static_cast(reservedRendererDword2 + reservedRendererDword3 + 10) > MAX_COMMAND_BUFFERS) DebugBreak(); - } const int internalSlot = reservedRendererDword2; ++reservedRendererDword2; @@ -746,7 +725,7 @@ void Renderer::CBuffEnd() c.stackType = MATRIX_MODE_MODELVIEW; c.commandBuffer->EndRecording(m_pDevice); - c.commandBuffer = nullptr; + c.commandBuffer = NULL; LeaveCriticalSection(&rtl_critical_section100); } @@ -759,24 +738,20 @@ void Renderer::CBuffLockStaticCreations() int Renderer::CBuffSize(int index) { if (index == -1) - { return totalAlloc < 0 ? 0 : totalAlloc; - } unsigned int size = 0; EnterCriticalSection(&rtl_critical_section100); const int commandIndex = m_commandHandleToIndex[index]; if (commandIndex >= 0) - { - size = m_commandBuffers[commandIndex]->GetAllocated(); - } + size = static_cast(m_commandBuffers[commandIndex]->GetAllocated()); LeaveCriticalSection(&rtl_critical_section100); return size; } void Renderer::CBuffStart(int index, bool full) { - Renderer::Context &c = this->getContext(); + Renderer::Context &c = getContext(); c.commandBuffer = new (std::nothrow) Renderer::CommandBuffer(full); c.recordingBufferIndex = index; @@ -797,10 +772,8 @@ void Renderer::CBuffTick() { Renderer::CommandBuffer *buffer = m_commandBuffers[i]; if (buffer) - { delete buffer; - } - m_commandBuffers[i] = nullptr; + m_commandBuffers[i] = NULL; } reservedRendererDword3 = 0; @@ -832,4 +805,4 @@ void Renderer::DeleteInternalBuffer(int index) } LeaveCriticalSection(&rtl_critical_section100); -} +} \ No newline at end of file diff --git a/Windows_Libs/Dev/Render/RendererCore.cpp b/Windows_Libs/Dev/Render/RendererCore.cpp index c472f74..1cd8139 100644 --- a/Windows_Libs/Dev/Render/RendererCore.cpp +++ b/Windows_Libs/Dev/Render/RendererCore.cpp @@ -1,41 +1,25 @@ -#pragma once -#include "CompiledShaders.h" +#include "stdafx.h" #include "Renderer.h" - -#include -#include -#include -#include -#include -#include +#include "CompiledShaders.h" Renderer InternalRenderManager; DWORD Renderer::tlsIdx = TlsAlloc(); +_RTL_CRITICAL_SECTION Renderer::totalAllocCS; + +DWORD Renderer::s_auiWidths[] = { 1920, 512, 256, 128, 64, 0 }; +DWORD Renderer::s_auiHeights[] = { 1080, 512, 256, 128, 64 }; int Renderer::totalAlloc = 0; -_RTL_CRITICAL_SECTION Renderer::totalAllocCS = {0}; -static const unsigned int kVertexBufferSize = 0x100000u; -static const float kAspectRatio = 1.7777778f; -static const unsigned int kScreenGrabWidth = 1920u; -static const unsigned int kScreenGrabHeight = 1080u; -static const unsigned int kThumbnailSize = 64u; - -static const unsigned int g_vertexStrides[C4JRender::VERTEX_TYPE_COUNT] = {32u, 16u, 32u, 32u}; - -unsigned int Renderer::s_auiWidths[MAX_MIP_LEVELS + 1] = {1920u, 512u, 256u, 128u, 64u, 0u}; - -unsigned int Renderer::s_auiHeights[MAX_MIP_LEVELS + 1] = {1080u, 512u, 256u, 128u, 64u, 0xFFFFFFFFu}; - -D3D11_INPUT_ELEMENT_DESC Renderer::g_vertex_PTN_Elements_PF3_TF2_CB4_NB4_XW1[5] = { - {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"NORMAL", 0, DXGI_FORMAT_R8G8B8A8_SNORM, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, - {"TEXCOORD", 1, DXGI_FORMAT_R16G16_SINT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0}, +D3D11_INPUT_ELEMENT_DESC g_vertex_PTN_Elements_PF3_TF2_CB4_NB4_XW1[] = { + {"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"COLOR", 0, DXGI_FORMAT_R8G8B8A8_UNORM, 0, 20, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"NORMAL", 0, DXGI_FORMAT_R8G8B8A8_SNORM, 0, 24, D3D11_INPUT_PER_VERTEX_DATA, 0}, + {"TEXCOORD", 1, DXGI_FORMAT_R16G16_SINT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0}, }; -D3D11_INPUT_ELEMENT_DESC Renderer::g_vertex_PTN_Elements_Compressed[2] = { +D3D11_INPUT_ELEMENT_DESC g_vertex_PTN_Elements_Compressed[] = { {"POSITION", 0, DXGI_FORMAT_R16G16B16A16_SINT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0}, {"TEXCOORD", 0, DXGI_FORMAT_R16G16B16A16_SINT, 0, 8, D3D11_INPUT_PER_VERTEX_DATA, 0}, }; @@ -45,43 +29,88 @@ D3D11_PRIMITIVE_TOPOLOGY Renderer::g_topologies[C4JRender::PRIMITIVE_TYPE_COUNT] D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST, D3D11_PRIMITIVE_TOPOLOGY_LINELIST, D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, }; -Renderer::Context::Context(ID3D11Device *device, ID3D11DeviceContext *deviceContext) - : m_pDeviceContext(deviceContext), userAnnotation(nullptr), annotateDepth(0), stackType(0), textureIdx(0), faceCullEnabled(1), - depthTestEnabled(1), alphaTestEnabled(0), alphaReference(1.0f), depthWriteEnabled(1), fogEnabled(0), fogNearDistance(0.0f), - fogFarDistance(0.0f), fogDensity(0.0f), fogColourRed(0.0f), fogColourBlue(0.0f), fogColourGreen(0.0f), fogMode(0), lightingEnabled(0), - lightingDirty(0), forcedLOD(0xFFFFFFFFu), m_modelViewMatrix(nullptr), m_localTransformMatrix(nullptr), m_projectionMatrix(nullptr), - m_textureMatrix(nullptr), m_vertexTexcoordBuffer(nullptr), m_fogParamsBuffer(nullptr), m_lightingStateBuffer(nullptr), m_texGenMatricesBuffer(nullptr), - m_compressedTranslationBuffer(nullptr), m_thumbnailBoundsBuffer(nullptr), m_tintColorBuffer(nullptr), m_fogColourBuffer(nullptr), m_unkColorBuffer(nullptr), m_alphaTestBuffer(nullptr), - m_clearColorBuffer(nullptr), m_forcedLODBuffer(nullptr), dynamicVertexBase(0), dynamicVertexOffset(0), dynamicVertexBuffer(nullptr), - commandBuffer(nullptr), recordingBufferIndex(0), recordingVertexType(0), recordingPrimitiveType(0), deferredModeEnabled(0), deferredBuffers() +static const unsigned int kVertexBufferSize = 0x100000; +static const unsigned int kScreenGrabWidth = 1920; +static const unsigned int kScreenGrabHeight = 1080; +static const unsigned int kThumbnailSize = 64; + +static const unsigned int g_vertexStrides[C4JRender::VERTEX_TYPE_COUNT] = { 32, 16, 32, 32 }; + +Renderer::Context::Context(ID3D11Device* device, ID3D11DeviceContext* deviceContext) + : m_pDeviceContext(deviceContext) + , userAnnotation(NULL) + , annotateDepth(0) + , stackType(0) + , textureIdx(0) + , faceCullEnabled(true) + , depthTestEnabled(true) + , depthWriteEnabled(true) + , alphaTestEnabled(false) + , alphaReference(1.0f) + , fogEnabled(false) + , fogNearDistance(0.0f) + , fogFarDistance(0.0f) + , fogDensity(0.0f) + , fogColourRed(0.0f) + , fogColourGreen(0.0f) + , fogColourBlue(0.0f) + , fogMode(0) + , lightingEnabled(false) + , lightingDirty(false) + , forcedLOD(-1) + , m_modelViewMatrix(NULL) + , m_localTransformMatrix(NULL) + , m_projectionMatrix(NULL) + , m_textureMatrix(NULL) + , m_vertexTexcoordBuffer(NULL) + , m_fogParamsBuffer(NULL) + , m_lightingStateBuffer(NULL) + , m_texGenMatricesBuffer(NULL) + , m_compressedTranslationBuffer(NULL) + , m_thumbnailBoundsBuffer(NULL) + , m_tintColorBuffer(NULL) + , m_fogColourBuffer(NULL) + , m_unkColorBuffer(NULL) + , m_alphaTestBuffer(NULL) + , m_clearColorBuffer(NULL) + , m_forcedLODBuffer(NULL) + , dynamicVertexBase(0) + , dynamicVertexOffset(0) + , dynamicVertexBuffer(NULL) + , commandBuffer(NULL) + , recordingBufferIndex(0) + , recordingVertexType(0) + , recordingPrimitiveType(0) + , deferredModeEnabled(false) + , deferredBuffers() { deviceContext->QueryInterface(IID_PPV_ARGS(&userAnnotation)); - std::memset(matrixStacks, 0, sizeof(matrixStacks)); - std::memset(matrixDirty, 0, sizeof(matrixDirty)); - std::memset(stackPos, 0, sizeof(stackPos)); - std::memset(lightEnabled, 0, sizeof(lightEnabled)); - std::memset(lightDirection, 0, sizeof(lightDirection)); - std::memset(lightColour, 0, sizeof(lightColour)); - std::memset(&lightAmbientColour, 0, sizeof(lightAmbientColour)); - std::memset(texGenMatrices, 0, sizeof(texGenMatrices)); - std::memset(&blendDesc, 0, sizeof(blendDesc)); - std::memset(&depthStencilDesc, 0, sizeof(depthStencilDesc)); - std::memset(&rasterizerDesc, 0, sizeof(rasterizerDesc)); + memset(matrixStacks, 0, sizeof(matrixStacks)); + memset(matrixDirty, 0, sizeof(matrixDirty)); + memset(stackPos, 0, sizeof(stackPos)); + memset(lightEnabled, 0, sizeof(lightEnabled)); + memset(lightDirection, 0, sizeof(lightDirection)); + memset(lightColour, 0, sizeof(lightColour)); + memset(&lightAmbientColour, 0, sizeof(lightAmbientColour)); + memset(texGenMatrices, 0, sizeof(texGenMatrices)); + memset(&blendDesc, 0, sizeof(blendDesc)); + memset(&depthStencilDesc, 0, sizeof(depthStencilDesc)); + memset(&rasterizerDesc, 0, sizeof(rasterizerDesc)); blendFactor[0] = 0.0f; blendFactor[1] = 0.0f; blendFactor[2] = 0.0f; blendFactor[3] = 0.0f; const DirectX::XMMATRIX identity = DirectX::XMMatrixIdentity(); - for (unsigned int i = 0; i < MATRIX_MODE_MODELVIEW_MAX; ++i) + for (UINT i = 0; i < MATRIX_MODE_MODELVIEW_MAX; ++i) { matrixStacks[i][0] = identity; stackPos[i] = 0; } - blendDesc.AlphaToCoverageEnable = FALSE; - blendDesc.IndependentBlendEnable = FALSE; - blendDesc.RenderTarget[0].BlendEnable = FALSE; + blendDesc.AlphaToCoverageEnable = false; + blendDesc.IndependentBlendEnable = false; + blendDesc.RenderTarget[0].BlendEnable = false; blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; @@ -90,12 +119,12 @@ Renderer::Context::Context(ID3D11Device *device, ID3D11DeviceContext *deviceCont blendDesc.RenderTarget[0].BlendOpAlpha = D3D11_BLEND_OP_ADD; blendDesc.RenderTarget[0].RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL; - depthStencilDesc.DepthEnable = TRUE; + depthStencilDesc.DepthEnable = true; depthStencilDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL; depthStencilDesc.DepthFunc = D3D11_COMPARISON_LESS; - depthStencilDesc.StencilEnable = FALSE; - depthStencilDesc.StencilReadMask = 0xFFu; - depthStencilDesc.StencilWriteMask = 0xFFu; + depthStencilDesc.StencilEnable = false; + depthStencilDesc.StencilReadMask = 0xFF; + depthStencilDesc.StencilWriteMask = 0xFF; depthStencilDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; depthStencilDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; depthStencilDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; @@ -107,19 +136,19 @@ Renderer::Context::Context(ID3D11Device *device, ID3D11DeviceContext *deviceCont rasterizerDesc.FillMode = D3D11_FILL_SOLID; rasterizerDesc.CullMode = D3D11_CULL_BACK; - rasterizerDesc.FrontCounterClockwise = TRUE; + rasterizerDesc.FrontCounterClockwise = true; rasterizerDesc.DepthBias = 0; rasterizerDesc.DepthBiasClamp = 0.0f; rasterizerDesc.SlopeScaledDepthBias = 0.0f; - rasterizerDesc.DepthClipEnable = TRUE; - rasterizerDesc.ScissorEnable = FALSE; - rasterizerDesc.MultisampleEnable = TRUE; - rasterizerDesc.AntialiasedLineEnable = FALSE; + rasterizerDesc.DepthClipEnable = true; + rasterizerDesc.ScissorEnable = false; + rasterizerDesc.MultisampleEnable = true; + rasterizerDesc.AntialiasedLineEnable = false; - std::memset(lightDirection, 0, sizeof(lightDirection)); - std::memset(lightColour, 0, sizeof(lightColour)); - std::memset(&lightAmbientColour, 0, sizeof(lightAmbientColour)); - std::memset(texGenMatrices, 0, sizeof(texGenMatrices)); + memset(lightDirection, 0, sizeof(lightDirection)); + memset(lightColour, 0, sizeof(lightColour)); + memset(&lightAmbientColour, 0, sizeof(lightAmbientColour)); + memset(texGenMatrices, 0, sizeof(texGenMatrices)); const float zero4[4] = {0.0f, 0.0f, 0.0f, 0.0f}; const float one4[4] = {1.0f, 1.0f, 1.0f, 1.0f}; @@ -186,7 +215,7 @@ Renderer::Context::Context(ID3D11Device *device, ID3D11DeviceContext *deviceCont vbDesc.Usage = D3D11_USAGE_DYNAMIC; vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER; vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; - device->CreateBuffer(&vbDesc, nullptr, &dynamicVertexBuffer); + device->CreateBuffer(&vbDesc, NULL, &dynamicVertexBuffer); } void Renderer::BeginConditionalRendering(int) {} @@ -197,16 +226,19 @@ void Renderer::CaptureScreen(ImageFileBuffer *, XSOCIAL_PREVIEWIMAGE *) {} void Renderer::Clear(int flags, D3D11_RECT *) { - Renderer::Context &c = this->getContext(); + PROFILER_SCOPE("Renderer::Clear", "Clear", MP_MAGENTA) - ID3D11BlendState *blendState = nullptr; - ID3D11DepthStencilState *depthState = nullptr; - ID3D11RasterizerState *rasterizerState = nullptr; + Renderer::Context &c = getContext(); + ID3D11BlendState *blendState = NULL; + ID3D11DepthStencilState *depthState = NULL; + ID3D11RasterizerState *rasterizerState = NULL; + + PROFILER_SCOPE("Renderer::Clear", "Blend", MP_MAGENTA) D3D11_BLEND_DESC blendDesc = {}; - blendDesc.AlphaToCoverageEnable = FALSE; - blendDesc.IndependentBlendEnable = FALSE; - blendDesc.RenderTarget[0].BlendEnable = FALSE; + blendDesc.AlphaToCoverageEnable = false; + blendDesc.IndependentBlendEnable = false; + blendDesc.RenderTarget[0].BlendEnable = false; blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; @@ -216,13 +248,14 @@ void Renderer::Clear(int flags, D3D11_RECT *) blendDesc.RenderTarget[0].RenderTargetWriteMask = (flags & CLEAR_COLOUR_FLAG) ? D3D11_COLOR_WRITE_ENABLE_ALL : 0; m_pDevice->CreateBlendState(&blendDesc, &blendState); + PROFILER_SCOPE("Renderer::Clear", "Depth", MP_MAGENTA) D3D11_DEPTH_STENCIL_DESC depthDesc = {}; - depthDesc.DepthEnable = (flags & CLEAR_DEPTH_FLAG) ? TRUE : FALSE; + depthDesc.DepthEnable = (flags & CLEAR_DEPTH_FLAG) ? true : false; depthDesc.DepthWriteMask = depthDesc.DepthEnable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; depthDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; - depthDesc.StencilEnable = FALSE; - depthDesc.StencilReadMask = 0xFFu; - depthDesc.StencilWriteMask = 0xFFu; + depthDesc.StencilEnable = false; + depthDesc.StencilReadMask = 0xFF; + depthDesc.StencilWriteMask = 0xFF; depthDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; depthDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; depthDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; @@ -233,70 +266,79 @@ void Renderer::Clear(int flags, D3D11_RECT *) depthDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; m_pDevice->CreateDepthStencilState(&depthDesc, &depthState); + PROFILER_SCOPE("Renderer::Clear", "Rasterizer", MP_MAGENTA) D3D11_RASTERIZER_DESC rasterDesc = {}; rasterDesc.FillMode = D3D11_FILL_SOLID; rasterDesc.CullMode = D3D11_CULL_NONE; - rasterDesc.DepthClipEnable = TRUE; - rasterDesc.MultisampleEnable = TRUE; + rasterDesc.DepthClipEnable = true; + rasterDesc.MultisampleEnable = true; m_pDevice->CreateRasterizerState(&rasterDesc, &rasterizerState); - c.m_pDeviceContext->VSSetShader(screenClearVertexShader, nullptr, 0); - c.m_pDeviceContext->IASetInputLayout(nullptr); - c.m_pDeviceContext->PSSetShader(screenClearPixelShader, nullptr, 0); + PROFILER_SCOPE("Renderer::Clear", "DrawClearQuad", MP_MAGENTA) + c.m_pDeviceContext->VSSetShader(screenClearVertexShader, NULL, 0); + c.m_pDeviceContext->IASetInputLayout(NULL); + c.m_pDeviceContext->PSSetShader(screenClearPixelShader, NULL, 0); c.m_pDeviceContext->OMSetRenderTargets(1, &renderTargetView, depthStencilView); - c.m_pDeviceContext->OMSetBlendState(blendState, nullptr, 0xFFFFFFFFu); + c.m_pDeviceContext->OMSetBlendState(blendState, NULL, 0xFFFFFFFF); c.m_pDeviceContext->OMSetDepthStencilState(depthState, 0); c.m_pDeviceContext->RSSetState(rasterizerState); - c.m_pDeviceContext->PSSetShaderResources(0, 0, nullptr); + c.m_pDeviceContext->PSSetShaderResources(0, 0, NULL); c.m_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP); c.m_pDeviceContext->Draw(4, 0); if (blendState) { blendState->Release(); - blendState = nullptr; + blendState = NULL; } if (depthState) { depthState->Release(); - depthState = nullptr; + depthState = NULL; } if (rasterizerState) { rasterizerState->Release(); - rasterizerState = nullptr; + rasterizerState = NULL; } - c.m_pDeviceContext->OMSetBlendState(this->GetManagedBlendState(), c.blendFactor, 0xFFFFFFFFu); - c.m_pDeviceContext->OMSetDepthStencilState(this->GetManagedDepthStencilState(), 0); - c.m_pDeviceContext->RSSetState(this->GetManagedRasterizerState()); + c.m_pDeviceContext->OMSetBlendState(GetManagedBlendState(), c.blendFactor, 0xFFFFFFFF); + c.m_pDeviceContext->OMSetDepthStencilState(GetManagedDepthStencilState(), 0); + c.m_pDeviceContext->RSSetState(GetManagedRasterizerState()); c.m_pDeviceContext->OMSetRenderTargets(1, &renderTargetView, depthStencilView); - activeVertexType = 0xFFFFFFFFu; - activePixelType = 0xFFFFFFFFu; + + activeVertexType = -1; + activePixelType = -1; } void Renderer::ConvertLinearToPng(ImageFileBuffer *pngOut, unsigned char *linearData, unsigned int width, unsigned int height) { - const size_t dataSize = size_t(width) * size_t(height) * 4u; - const size_t outputCapacity = ((dataSize * 24u) / 20u) + 256u; - const int outputCapacityInt = int(outputCapacity); - const int widthInt = int(width); - const int heightInt = int(height); - void *outputBuffer = std::malloc(outputCapacity); + const size_t dataSize = static_cast(width) * static_cast(height) * 4; + const size_t outputCapacity = (dataSize * 24) / 20 + 256; + + void *outputBuffer = malloc(outputCapacity); int outputLength = 0; - this->SaveTextureDataToMemory(outputBuffer, outputCapacityInt, &outputLength, widthInt, heightInt, reinterpret_cast(linearData)); + + SaveTextureDataToMemory( + outputBuffer, + static_cast(outputCapacity), + &outputLength, + static_cast(width), + static_cast(height), + reinterpret_cast(linearData) + ); + pngOut->m_type = ImageFileBuffer::e_typePNG; pngOut->m_pBuffer = outputBuffer; pngOut->m_bufferSize = outputLength; } -void Renderer::DoScreenGrabOnNextPresent() -{ - shouldScreenGrabNextFrame = 1; +void Renderer::DoScreenGrabOnNextPresent() +{ + m_bShouldScreenGrabNextFrame = true; } void Renderer::EndConditionalRendering() {} - void Renderer::EndConditionalSurvey() {} void Renderer::BeginEvent(LPCWSTR eventName) @@ -315,7 +357,6 @@ void Renderer::EndEvent() if (c.m_pDeviceContext->GetType() != D3D11_DEVICE_CONTEXT_DEFERRED && c.userAnnotation) { c.userAnnotation->EndEvent(); - --c.annotateDepth; assert(c.annotateDepth >= 0); } @@ -324,9 +365,14 @@ void Renderer::EndEvent() void Renderer::Initialise(ID3D11Device *pDevice, IDXGISwapChain *pSwapChain) { m_pDevice = pDevice; - m_pDeviceContext = this->InitialiseContext(true); + m_pDeviceContext = InitialiseContext(true); m_pSwapChain = pSwapChain; + #ifdef ENABLE_PROFILING + MicroProfileOnThreadCreate("MainRenderThread"); + MicroProfileSetEnableAllGroups(true); + #endif + m_commandHandleToIndex = new int16_t[NUM_COMMAND_HANDLES]; m_commandBuffers = new CommandBuffer *[MAX_COMMAND_BUFFERS]; m_commandMatrices = new DirectX::XMMATRIX[MAX_COMMAND_BUFFERS]; @@ -334,24 +380,24 @@ void Renderer::Initialise(ID3D11Device *pDevice, IDXGISwapChain *pSwapChain) m_commandVertexTypes = new uint8_t[MAX_COMMAND_BUFFERS]; m_commandPrimitiveTypes = new uint8_t[MAX_COMMAND_BUFFERS]; - std::memset(m_commandHandleToIndex, 0xFF, NUM_COMMAND_HANDLES); - std::memset(m_commandBuffers, 0, MAX_COMMAND_BUFFERS); - std::memset(m_commandIndexToHandle, 0, MAX_COMMAND_BUFFERS); - std::memset(m_commandVertexTypes, 0, MAX_COMMAND_BUFFERS); - std::memset(m_commandPrimitiveTypes, 0, MAX_COMMAND_BUFFERS); + memset(m_commandHandleToIndex, 0xFF, NUM_COMMAND_HANDLES * sizeof(int16_t)); + memset(m_commandBuffers, 0, MAX_COMMAND_BUFFERS * sizeof(CommandBuffer*)); + memset(m_commandIndexToHandle, 0, MAX_COMMAND_BUFFERS * sizeof(int)); + memset(m_commandVertexTypes, 0, MAX_COMMAND_BUFFERS * sizeof(uint8_t)); + memset(m_commandPrimitiveTypes, 0, MAX_COMMAND_BUFFERS * sizeof(uint8_t)); reservedRendererDword3 = 0; + m_bShouldScreenGrabNextFrame = false; + m_bSuspended = false; - shouldScreenGrabNextFrame = 0; - suspended = 0; - - this->SetupShaders(); + SetupShaders(); const float clearColour[4] = {0.0f, 0.0f, 0.0f, 0.0f}; - this->SetClearColour(clearColour); + SetClearColour(clearColour); UINT backBufferSampleCount = 1; UINT backBufferSampleQuality = 0; - ID3D11Texture2D *backBuffer = nullptr; + + ID3D11Texture2D *backBuffer = NULL; pSwapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer)); if (backBuffer) { @@ -361,17 +407,24 @@ void Renderer::Initialise(ID3D11Device *pDevice, IDXGISwapChain *pSwapChain) backBufferHeight = backDesc.Height; backBufferSampleCount = backDesc.SampleDesc.Count; backBufferSampleQuality = backDesc.SampleDesc.Quality; - m_pDevice->CreateRenderTargetView(backBuffer, nullptr, &renderTargetView); - m_pDevice->CreateShaderResourceView(backBuffer, nullptr, &renderTargetShaderResourceView); + + m_pDevice->CreateRenderTargetView(backBuffer, NULL, &renderTargetView); + + D3D11_TEXTURE2D_DESC srvDesc = backDesc; + srvDesc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; + srvDesc.MiscFlags = 0; + + ID3D11Texture2D *srvTexture = NULL; + m_pDevice->CreateTexture2D(&srvDesc, NULL, &srvTexture); + m_pDevice->CreateShaderResourceView(srvTexture, NULL, &renderTargetShaderResourceView); + + srvTexture->Release(); backBuffer->Release(); } - ID3D11RenderTargetView *boundRTV = nullptr; + ID3D11RenderTargetView *boundRTV = NULL; m_pDeviceContext->OMGetRenderTargets(1, &boundRTV, &depthStencilView); - if (boundRTV) - { - boundRTV->Release(); - } + if (boundRTV) boundRTV->Release(); if (!depthStencilView && backBufferWidth != 0 && backBufferHeight != 0) { @@ -386,15 +439,15 @@ void Renderer::Initialise(ID3D11Device *pDevice, IDXGISwapChain *pSwapChain) depthDesc.Usage = D3D11_USAGE_DEFAULT; depthDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL; - ID3D11Texture2D *depthTexture = nullptr; - if (SUCCEEDED(m_pDevice->CreateTexture2D(&depthDesc, nullptr, &depthTexture))) + ID3D11Texture2D *depthTexture = NULL; + if (SUCCEEDED(m_pDevice->CreateTexture2D(&depthDesc, NULL, &depthTexture))) { - m_pDevice->CreateDepthStencilView(depthTexture, nullptr, &depthStencilView); + m_pDevice->CreateDepthStencilView(depthTexture, NULL, &depthStencilView); depthTexture->Release(); } } - for (unsigned int i = 0; i < MAX_MIP_LEVELS - 1; ++i) + for (UINT i = 0; i < MAX_MIP_LEVELS - 1; ++i) { D3D11_TEXTURE2D_DESC desc = {}; desc.Width = s_auiWidths[i + 1]; @@ -406,98 +459,97 @@ void Renderer::Initialise(ID3D11Device *pDevice, IDXGISwapChain *pSwapChain) desc.Usage = D3D11_USAGE_DEFAULT; desc.BindFlags = D3D11_BIND_RENDER_TARGET | D3D11_BIND_SHADER_RESOURCE; - HRESULT hr = 0; - hr = m_pDevice->CreateTexture2D(&desc, nullptr, &renderTargetTextures[i]); + HRESULT hr = m_pDevice->CreateTexture2D(&desc, NULL, &renderTargetTextures[i]); assert(hr == S_OK); - hr = m_pDevice->CreateRenderTargetView(renderTargetTextures[i], nullptr, &renderTargetViews[i]); + hr = m_pDevice->CreateRenderTargetView(renderTargetTextures[i], NULL, &renderTargetViews[i]); assert(hr == S_OK); - hr = m_pDevice->CreateShaderResourceView(renderTargetTextures[i], nullptr, &renderTargetShaderResourceViews[i]); + hr = m_pDevice->CreateShaderResourceView(renderTargetTextures[i], NULL, &renderTargetShaderResourceViews[i]); assert(hr == S_OK); } - std::memset(m_textures, 0, sizeof(m_textures)); - defaultTextureIndex = this->TextureCreate(); - this->TextureBind(defaultTextureIndex); + memset(m_textures, 0, sizeof(m_textures)); + defaultTextureIndex = TextureCreate(); + TextureBind(defaultTextureIndex); - unsigned char *defaultTextureData = new unsigned char[0x400u]; - std::memset(defaultTextureData, 0xFF, 0x400u); - this->TextureData(16, 16, defaultTextureData, 0, C4JRender::TEXTURE_FORMAT_RxGyBzAw); + unsigned char *defaultTextureData = new unsigned char[0x400]; + memset(defaultTextureData, 0xFF, 0x400); + TextureData(16, 16, defaultTextureData, 0, C4JRender::TEXTURE_FORMAT_RxGyBzAw); delete[] defaultTextureData; presentCount = 0; rendererFlag0 = 0; reservedRendererWord0 = 10922; - this->StateSetViewport(C4JRender::VIEWPORT_TYPE_FULLSCREEN); - this->StateSetVertexTextureUV(0.0f, 0.0f); - this->TextureBindVertex(-1); + StateSetViewport(C4JRender::VIEWPORT_TYPE_FULLSCREEN); + StateSetVertexTextureUV(0.0f, 0.0f); + TextureBindVertex(-1); + InitializeCriticalSection(&rtl_critical_section100); + InitializeCriticalSection(&Renderer::totalAllocCS); + reservedRendererDword1 = 0; - activeVertexType = 0xFFFFFFFFu; - activePixelType = 0xFFFFFFFFu; + activeVertexType = -1; + activePixelType = -1; reservedRendererByte1 = 1; reservedRendererByte0 = 0; - unsigned short *quadIndices = new unsigned short[0x18000u]; - for (unsigned int i = 0; i < 0x4000u; ++i) + unsigned short *quadIndices = new unsigned short[0x18000]; + for (UINT i = 0; i < 0x4000; ++i) { - const unsigned short base = (unsigned short)(i * 4u); - const unsigned int offset = i * 6u; + unsigned short base = static_cast(i * 4); + unsigned int offset = i * 6; quadIndices[offset + 0] = base; - quadIndices[offset + 1] = (unsigned short)(base + 1u); - quadIndices[offset + 2] = (unsigned short)(base + 3u); - quadIndices[offset + 3] = (unsigned short)(base + 1u); - quadIndices[offset + 4] = (unsigned short)(base + 2u); - quadIndices[offset + 5] = (unsigned short)(base + 3u); + quadIndices[offset + 1] = base + 1; + quadIndices[offset + 2] = base + 3; + quadIndices[offset + 3] = base + 1; + quadIndices[offset + 4] = base + 2; + quadIndices[offset + 5] = base + 3; } + D3D11_BUFFER_DESC quadIndexDesc = {}; - quadIndexDesc.ByteWidth = 0x30000u; + quadIndexDesc.ByteWidth = 0x30000; quadIndexDesc.Usage = D3D11_USAGE_IMMUTABLE; quadIndexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + D3D11_SUBRESOURCE_DATA quadIndexData = {}; quadIndexData.pSysMem = quadIndices; - HRESULT hr = m_pDevice->CreateBuffer(&quadIndexDesc, &quadIndexData, &quadIndexBuffer); assert(hr >= 0); - delete[] quadIndices; - unsigned short *fanIndices = new unsigned short[0x2FFFAu]; - for (unsigned int i = 0; i < 65534u; ++i) + unsigned short *fanIndices = new unsigned short[0x2FFFA]; + for (UINT i = 0; i < 65534; ++i) { - const unsigned int offset = i * 3u; - fanIndices[offset + 0] = 0u; - fanIndices[offset + 1] = (unsigned short)(i + 1u); - fanIndices[offset + 2] = (unsigned short)(i + 2u); + unsigned int offset = i * 3; + fanIndices[offset + 0] = 0; + fanIndices[offset + 1] = static_cast(i + 1); + fanIndices[offset + 2] = static_cast(i + 2); } + D3D11_BUFFER_DESC fanIndexDesc = {}; - fanIndexDesc.ByteWidth = 0x5FFF4u; + fanIndexDesc.ByteWidth = 0x5FFF4; fanIndexDesc.Usage = D3D11_USAGE_IMMUTABLE; fanIndexDesc.BindFlags = D3D11_BIND_INDEX_BUFFER; + D3D11_SUBRESOURCE_DATA fanIndexData = {}; fanIndexData.pSysMem = fanIndices; m_pDevice->CreateBuffer(&fanIndexDesc, &fanIndexData, &fanIndexBuffer); delete[] fanIndices; - - InitializeCriticalSection(&Renderer::totalAllocCS); - m_Topologies = g_topologies; } ID3D11DeviceContext *Renderer::InitialiseContext(bool fromPresent) { - ID3D11DeviceContext *deviceContext = nullptr; + ID3D11DeviceContext *deviceContext = NULL; + if (fromPresent) - { m_pDevice->GetImmediateContext(&deviceContext); - } else - { m_pDevice->CreateDeferredContext(0, &deviceContext); - } Renderer::Context *c = new (std::nothrow) Renderer::Context(m_pDevice, deviceContext); TlsSetValue(Renderer::tlsIdx, c); + return deviceContext; } @@ -513,11 +565,16 @@ bool Renderer::IsWidescreen() void Renderer::Present() { - if (shouldScreenGrabNextFrame) + PROFILER_SCOPE("Renderer::Present", "Present", MP_MAGENTA) + + if (m_bShouldScreenGrabNextFrame) { - int *linearData = new int[kScreenGrabWidth * kScreenGrabHeight]; - ID3D11Texture2D *backBuffer = nullptr; - ID3D11Texture2D *stagingTexture = nullptr; + PROFILER_SCOPE("Renderer::Present", "ScreenGrab", MP_MAGENTA) + + unsigned char *linearData = new unsigned char[kScreenGrabWidth * kScreenGrabHeight * 4]; + + ID3D11Texture2D *backBuffer = NULL; + ID3D11Texture2D *stagingTexture = NULL; m_pSwapChain->GetBuffer(0, IID_PPV_ARGS(&backBuffer)); if (backBuffer) @@ -528,27 +585,29 @@ void Renderer::Present() desc.BindFlags = 0; desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; desc.MiscFlags = 0; - m_pDevice->CreateTexture2D(&desc, nullptr, &stagingTexture); + m_pDevice->CreateTexture2D(&desc, NULL, &stagingTexture); } if (stagingTexture && backBuffer) { + PROFILER_SCOPE("Renderer::Present", "CopyResource", MP_MAGENTA) m_pDeviceContext->CopyResource(stagingTexture, backBuffer); + D3D11_MAPPED_SUBRESOURCE mapped = {}; if (SUCCEEDED(m_pDeviceContext->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mapped))) { - unsigned char *dst = reinterpret_cast(linearData); const unsigned char *src = reinterpret_cast(mapped.pData); - for (unsigned int y = 0; y < kScreenGrabHeight; ++y) + + for (UINT y = 0; y < kScreenGrabHeight; ++y) { - unsigned char *dstRow = dst + y * (kScreenGrabWidth * 4u); + unsigned char *dstRow = linearData + y * kScreenGrabWidth * 4; const unsigned char *srcRow = src + y * mapped.RowPitch; - std::memcpy(dstRow, srcRow, kScreenGrabWidth * 4u); - for (unsigned int x = 0; x < kScreenGrabWidth; ++x) - { - dstRow[x * 4u + 3u] = 0xFF; - } + memcpy(dstRow, srcRow, kScreenGrabWidth * 4); + + for (UINT x = 0; x < kScreenGrabWidth; ++x) + dstRow[x * 4 + 3] = 0xFF; } + m_pDeviceContext->Unmap(stagingTexture, 0); } } @@ -556,23 +615,26 @@ void Renderer::Present() static int count = 0; char fileName[304]; sprintf_s(fileName, "d:\\screen%d.png", count++); + D3DXIMAGE_INFO info; info.Width = kScreenGrabWidth; info.Height = kScreenGrabHeight; - this->SaveTextureData(fileName, &info, linearData); + SaveTextureData(fileName, &info, reinterpret_cast(linearData)); + delete[] linearData; if (stagingTexture) { stagingTexture->Release(); - stagingTexture = nullptr; + stagingTexture = NULL; } if (backBuffer) { backBuffer->Release(); - backBuffer = nullptr; + backBuffer = NULL; } - shouldScreenGrabNextFrame = 0; + + m_bShouldScreenGrabNextFrame = false; } m_pSwapChain->Present(1, 0); @@ -581,20 +643,23 @@ void Renderer::Present() void Renderer::Resume() { - suspended = 0; + m_bSuspended = false; } void Renderer::SetClearColour(const float colourRGBA[4]) { - std::memcpy(m_fClearColor, colourRGBA, sizeof(m_fClearColor)); + for (int i = 0; i < 4; ++i) + m_fClearColor[i] = colourRGBA[i]; - Renderer::Context *c = static_cast(TlsGetValue(Renderer::tlsIdx)); - if (c) + Renderer::Context &c = getContext(); + if (&c) { D3D11_MAPPED_SUBRESOURCE mapped = {}; - c->m_pDeviceContext->Map(c->m_clearColorBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); - std::memcpy(mapped.pData, colourRGBA, sizeof(float) * 4); - c->m_pDeviceContext->Unmap(c->m_clearColorBuffer, 0); + if (SUCCEEDED(c.m_pDeviceContext->Map(c.m_clearColorBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped))) + { + *(DirectX::XMVECTOR*)mapped.pData = DirectX::XMVectorSet(colourRGBA[0], colourRGBA[1], colourRGBA[2], colourRGBA[3]); + c.m_pDeviceContext->Unmap(c.m_clearColorBuffer, 0); + } } } @@ -605,71 +670,68 @@ void Renderer::SetupShaders() vertexStrideTable = new unsigned int[C4JRender::VERTEX_TYPE_COUNT]; inputLayoutTable = new ID3D11InputLayout *[C4JRender::VERTEX_TYPE_COUNT]; - for (unsigned int i = 0; i < C4JRender::VERTEX_TYPE_COUNT; ++i) + for (UINT i = 0; i < C4JRender::VERTEX_TYPE_COUNT; ++i) { - vertexShaderTable[i] = nullptr; - inputLayoutTable[i] = nullptr; + vertexShaderTable[i] = NULL; + inputLayoutTable[i] = NULL; vertexStrideTable[i] = g_vertexStrides[i]; } - for (unsigned int i = 0; i < C4JRender::PIXEL_SHADER_COUNT; ++i) + for (UINT i = 0; i < C4JRender::PIXEL_SHADER_COUNT; ++i) { - pixelShaderTable[i] = nullptr; + pixelShaderTable[i] = NULL; } - screenSpaceVertexShader = nullptr; - screenClearVertexShader = nullptr; - screenSpacePixelShader = nullptr; - screenClearPixelShader = nullptr; + screenSpaceVertexShader = NULL; + screenClearVertexShader = NULL; + screenSpacePixelShader = NULL; + screenClearPixelShader = NULL; - m_pDevice->CreateVertexShader(g_main_VS_PF3_TF2_CB4_NB4_XW1, sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1), nullptr, - &vertexShaderTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1]); - m_pDevice->CreateVertexShader(g_main_VS_Compressed, sizeof(g_main_VS_Compressed), nullptr, &vertexShaderTable[C4JRender::VERTEX_TYPE_COMPRESSED]); - m_pDevice->CreateVertexShader(g_main_VS_PF3_TF2_CB4_NB4_XW1_LIGHTING, sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1_LIGHTING), nullptr, - &vertexShaderTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_LIT]); - m_pDevice->CreateVertexShader(g_main_VS_PF3_TF2_CB4_NB4_XW1_TEXGEN, sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1_TEXGEN), nullptr, - &vertexShaderTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TEXGEN]); - m_pDevice->CreateVertexShader(g_main_VS_ScreenSpace, sizeof(g_main_VS_ScreenSpace), nullptr, &screenSpaceVertexShader); - m_pDevice->CreateVertexShader(g_main_VS_ScreenClear, sizeof(g_main_VS_ScreenClear), nullptr, &screenClearVertexShader); + m_pDevice->CreateVertexShader(g_main_VS_PF3_TF2_CB4_NB4_XW1, sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1), NULL, &vertexShaderTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1]); + m_pDevice->CreateVertexShader(g_main_VS_Compressed, sizeof(g_main_VS_Compressed), NULL, &vertexShaderTable[C4JRender::VERTEX_TYPE_COMPRESSED]); + m_pDevice->CreateVertexShader(g_main_VS_PF3_TF2_CB4_NB4_XW1_LIGHTING, sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1_LIGHTING), NULL, &vertexShaderTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_LIT]); + m_pDevice->CreateVertexShader(g_main_VS_PF3_TF2_CB4_NB4_XW1_TEXGEN, sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1_TEXGEN), NULL, &vertexShaderTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TEXGEN]); + m_pDevice->CreateVertexShader(g_main_VS_ScreenSpace, sizeof(g_main_VS_ScreenSpace), NULL, &screenSpaceVertexShader); + m_pDevice->CreateVertexShader(g_main_VS_ScreenClear, sizeof(g_main_VS_ScreenClear), NULL, &screenClearVertexShader); - m_pDevice->CreatePixelShader(g_main_PS_Standard, sizeof(g_main_PS_Standard), nullptr, &pixelShaderTable[C4JRender::PIXEL_SHADER_TYPE_STANDARD]); - m_pDevice->CreatePixelShader(g_main_PS_TextureProjection, sizeof(g_main_PS_TextureProjection), nullptr, - &pixelShaderTable[C4JRender::PIXEL_SHADER_TYPE_PROJECTION]); - m_pDevice->CreatePixelShader(g_main_PS_ForceLOD, sizeof(g_main_PS_ForceLOD), nullptr, &pixelShaderTable[C4JRender::PIXEL_SHADER_TYPE_FORCELOD]); - m_pDevice->CreatePixelShader(g_main_PS_ScreenSpace, sizeof(g_main_PS_ScreenSpace), nullptr, &screenSpacePixelShader); - m_pDevice->CreatePixelShader(g_main_PS_ScreenClear, sizeof(g_main_PS_ScreenClear), nullptr, &screenClearPixelShader); + m_pDevice->CreatePixelShader(g_main_PS_Standard, sizeof(g_main_PS_Standard), NULL, &pixelShaderTable[C4JRender::PIXEL_SHADER_TYPE_STANDARD]); + m_pDevice->CreatePixelShader(g_main_PS_TextureProjection, sizeof(g_main_PS_TextureProjection), NULL, &pixelShaderTable[C4JRender::PIXEL_SHADER_TYPE_PROJECTION]); + m_pDevice->CreatePixelShader(g_main_PS_ForceLOD, sizeof(g_main_PS_ForceLOD), NULL, &pixelShaderTable[C4JRender::PIXEL_SHADER_TYPE_FORCELOD]); + m_pDevice->CreatePixelShader(g_main_PS_ScreenSpace, sizeof(g_main_PS_ScreenSpace), NULL, &screenSpacePixelShader); + m_pDevice->CreatePixelShader(g_main_PS_ScreenClear, sizeof(g_main_PS_ScreenClear), NULL, &screenClearPixelShader); - m_pDevice->CreateInputLayout(g_vertex_PTN_Elements_PF3_TF2_CB4_NB4_XW1, 5, g_main_VS_PF3_TF2_CB4_NB4_XW1, sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1), - &inputLayoutTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1]); - m_pDevice->CreateInputLayout(g_vertex_PTN_Elements_Compressed, 2, g_main_VS_Compressed, sizeof(g_main_VS_Compressed), - &inputLayoutTable[C4JRender::VERTEX_TYPE_COMPRESSED]); - m_pDevice->CreateInputLayout(g_vertex_PTN_Elements_PF3_TF2_CB4_NB4_XW1, 5, g_main_VS_PF3_TF2_CB4_NB4_XW1_LIGHTING, - sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1_LIGHTING), &inputLayoutTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_LIT]); - m_pDevice->CreateInputLayout(g_vertex_PTN_Elements_PF3_TF2_CB4_NB4_XW1, 5, g_main_VS_PF3_TF2_CB4_NB4_XW1_TEXGEN, - sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1_TEXGEN), &inputLayoutTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TEXGEN]); + m_pDevice->CreateInputLayout(g_vertex_PTN_Elements_PF3_TF2_CB4_NB4_XW1, 5, g_main_VS_PF3_TF2_CB4_NB4_XW1, sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1), &inputLayoutTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1]); + m_pDevice->CreateInputLayout(g_vertex_PTN_Elements_Compressed, 2, g_main_VS_Compressed, sizeof(g_main_VS_Compressed), &inputLayoutTable[C4JRender::VERTEX_TYPE_COMPRESSED]); + m_pDevice->CreateInputLayout(g_vertex_PTN_Elements_PF3_TF2_CB4_NB4_XW1, 5, g_main_VS_PF3_TF2_CB4_NB4_XW1_LIGHTING, sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1_LIGHTING), &inputLayoutTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_LIT]); + m_pDevice->CreateInputLayout(g_vertex_PTN_Elements_PF3_TF2_CB4_NB4_XW1, 5, g_main_VS_PF3_TF2_CB4_NB4_XW1_TEXGEN, sizeof(g_main_VS_PF3_TF2_CB4_NB4_XW1_TEXGEN), &inputLayoutTable[C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_TEXGEN]); } void Renderer::StartFrame() { - Renderer::Context &c = this->getContext(); + PROFILER_SCOPE("Renderer::StartFrame", "StartFrame", MP_MAGENTA) - activeVertexType = 0xFFFFFFFFu; - activePixelType = 0xFFFFFFFFu; + Renderer::Context &c = getContext(); - this->TextureBindVertex(-1); - this->TextureBind(-1); - this->StateSetColour(1.0f, 1.0f, 1.0f, 1.0f); - this->StateSetDepthMask(true); - this->StateSetBlendEnable(true); - this->StateSetBlendFunc(D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA); - this->StateSetBlendFactor(0xFFFFFFFFu); - this->StateSetAlphaFunc(D3D11_COMPARISON_GREATER, 0.1f); - this->StateSetDepthFunc(D3D11_COMPARISON_LESS_EQUAL); - this->StateSetFaceCull(true); - this->StateSetLineWidth(1.0f); - this->StateSetWriteEnable(true, true, true, true); - this->StateSetDepthTestEnable(false); - this->StateSetAlphaTestEnable(true); + activeVertexType = -1; + activePixelType = -1; + + TextureBindVertex(-1); + TextureBind(-1); + + PROFILER_SCOPE("Renderer::StartFrame", "State", MP_MAGENTA) + + StateSetColour(1.0f, 1.0f, 1.0f, 1.0f); + StateSetDepthMask(true); + StateSetBlendEnable(true); + StateSetBlendFunc(D3D11_BLEND_SRC_ALPHA, D3D11_BLEND_INV_SRC_ALPHA); + StateSetBlendFactor(0xFFFFFFFF); + StateSetAlphaFunc(D3D11_COMPARISON_GREATER, 0.1f); + StateSetDepthFunc(D3D11_COMPARISON_LESS_EQUAL); + StateSetFaceCull(true); + StateSetLineWidth(1.0f); + StateSetWriteEnable(true, true, true, true); + StateSetDepthTestEnable(false); + StateSetAlphaTestEnable(true); c.m_pDeviceContext->VSSetConstantBuffers(0, 10, &c.m_modelViewMatrix); c.m_pDeviceContext->PSSetConstantBuffers(0, 6, &c.m_tintColorBuffer); @@ -683,16 +745,20 @@ void Renderer::StartFrame() viewport.MaxDepth = 1.0f; c.m_pDeviceContext->RSSetViewports(1, &viewport); c.m_pDeviceContext->OMSetRenderTargets(1, &renderTargetView, depthStencilView); + + #ifdef ENABLE_PROFILING + MicroProfileFlip(nullptr); + #endif } void Renderer::Suspend() { - suspended = 1; + m_bSuspended = true; } bool Renderer::Suspended() { - return suspended != 0; + return m_bSuspended; } void Renderer::UpdateGamma(unsigned short) {} @@ -704,16 +770,13 @@ Renderer::Context &Renderer::getContext() void Renderer::CaptureThumbnail(ImageFileBuffer *pngOut) { - Renderer::Context &c = this->getContext(); + Renderer::Context &c = getContext(); - float left; - float bottom; - float right; - float top; - left = 0.0f; - bottom = 0.0f; - right = 1.0f; - top = 1.0f; + float left = 0.0f; + float bottom = 0.0f; + float right = 1.0f; + float top = 1.0f; + switch (m_ViewportType) { case C4JRender::VIEWPORT_TYPE_SPLIT_TOP: @@ -748,36 +811,38 @@ void Renderer::CaptureThumbnail(ImageFileBuffer *pngOut) break; } - float leftScaled = left * kAspectRatio; - float rightScaled = right * kAspectRatio; - const float viewportHeight = top - bottom; - const float viewportScaledWidth = rightScaled - leftScaled; + float aspectRatio = IsWidescreen() ? (16.0f / 9.0f) : (4.0f / 3.0f); - if (viewportHeight <= viewportScaledWidth) + right *= aspectRatio; + left *= aspectRatio; + + float width = right - left; + float height = top - bottom; + + if (height > width) { - const float pad = (viewportScaledWidth - viewportHeight) * 0.5f; - leftScaled += pad; - rightScaled -= pad; + float diff = (height - width) * 0.5f; + bottom += diff; + top -= diff; } else { - const float pad = (viewportHeight - viewportScaledWidth) * 0.5f; - bottom += pad; - top -= pad; + float diff = (width - height) * 0.5f; + left += diff; + right -= diff; } - const float sampleLeft = leftScaled / kAspectRatio; - const float sampleWidth = (rightScaled - leftScaled) / kAspectRatio; - const float sampleHeight = top - bottom; + left /= aspectRatio; + right /= aspectRatio; - ID3D11BlendState *blendState = nullptr; - ID3D11DepthStencilState *depthState = nullptr; - ID3D11RasterizerState *rasterizerState = nullptr; - ID3D11SamplerState *samplerState = nullptr; - ID3D11Texture2D *stagingTexture = nullptr; + ID3D11BlendState *blendState = NULL; + ID3D11DepthStencilState *depthState = NULL; + ID3D11RasterizerState *rasterizerState = NULL; + ID3D11SamplerState *samplerState = NULL; + ID3D11Texture2D *stagingTexture = NULL; D3D11_BLEND_DESC blendDesc = {}; - blendDesc.RenderTarget[0].BlendEnable = FALSE; + blendDesc.RenderTarget[0].BlendEnable = false; blendDesc.RenderTarget[0].SrcBlend = D3D11_BLEND_ONE; blendDesc.RenderTarget[0].DestBlend = D3D11_BLEND_ZERO; blendDesc.RenderTarget[0].BlendOp = D3D11_BLEND_OP_ADD; @@ -788,27 +853,24 @@ void Renderer::CaptureThumbnail(ImageFileBuffer *pngOut) m_pDevice->CreateBlendState(&blendDesc, &blendState); D3D11_DEPTH_STENCIL_DESC depthDesc = {}; - depthDesc.DepthEnable = FALSE; + depthDesc.DepthEnable = false; depthDesc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ZERO; depthDesc.DepthFunc = D3D11_COMPARISON_ALWAYS; - depthDesc.StencilEnable = FALSE; - depthDesc.StencilReadMask = 0xFFu; - depthDesc.StencilWriteMask = 0xFFu; + depthDesc.StencilEnable = false; + depthDesc.StencilReadMask = 0xFF; + depthDesc.StencilWriteMask = 0xFF; depthDesc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; depthDesc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; depthDesc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; depthDesc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS; - depthDesc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP; - depthDesc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP; - depthDesc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP; - depthDesc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS; + depthDesc.BackFace = depthDesc.FrontFace; m_pDevice->CreateDepthStencilState(&depthDesc, &depthState); D3D11_RASTERIZER_DESC rasterDesc = {}; rasterDesc.FillMode = D3D11_FILL_SOLID; rasterDesc.CullMode = D3D11_CULL_NONE; - rasterDesc.DepthClipEnable = TRUE; - rasterDesc.MultisampleEnable = TRUE; + rasterDesc.DepthClipEnable = true; + rasterDesc.MultisampleEnable = true; m_pDevice->CreateRasterizerState(&rasterDesc, &rasterizerState); D3D11_SAMPLER_DESC samplerDesc = {}; @@ -822,14 +884,14 @@ void Renderer::CaptureThumbnail(ImageFileBuffer *pngOut) samplerDesc.MaxLOD = (std::numeric_limits::max)(); m_pDevice->CreateSamplerState(&samplerDesc, &samplerState); - c.m_pDeviceContext->VSSetShader(screenSpaceVertexShader, nullptr, 0); - c.m_pDeviceContext->IASetInputLayout(nullptr); - c.m_pDeviceContext->PSSetShader(screenSpacePixelShader, nullptr, 0); - c.m_pDeviceContext->OMSetBlendState(blendState, nullptr, 0xFFFFFFFFu); + c.m_pDeviceContext->VSSetShader(screenSpaceVertexShader, NULL, 0); + c.m_pDeviceContext->IASetInputLayout(NULL); + c.m_pDeviceContext->PSSetShader(screenSpacePixelShader, NULL, 0); + c.m_pDeviceContext->OMSetBlendState(blendState, NULL, -1); c.m_pDeviceContext->OMSetDepthStencilState(depthState, 0); c.m_pDeviceContext->RSSetState(rasterizerState); - for (unsigned int i = 0; i < MAX_MIP_LEVELS - 1; ++i) + for (UINT i = 0; i < MAX_MIP_LEVELS - 1; ++i) { D3D11_VIEWPORT viewport = {}; viewport.TopLeftX = 0.0f; @@ -839,7 +901,7 @@ void Renderer::CaptureThumbnail(ImageFileBuffer *pngOut) viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; - c.m_pDeviceContext->OMSetRenderTargets(1, &renderTargetViews[i], nullptr); + c.m_pDeviceContext->OMSetRenderTargets(1, &renderTargetViews[i], NULL); c.m_pDeviceContext->RSSetViewports(1, &viewport); ID3D11ShaderResourceView *inputTexture = (i == 0) ? renderTargetShaderResourceView : renderTargetShaderResourceViews[i - 1]; @@ -849,13 +911,14 @@ void Renderer::CaptureThumbnail(ImageFileBuffer *pngOut) D3D11_MAPPED_SUBRESOURCE mapped = {}; c.m_pDeviceContext->Map(c.m_thumbnailBoundsBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); - float *constants = static_cast(mapped.pData); + + float *constants = (float *)mapped.pData; if (i == 0) { - constants[0] = sampleLeft; + constants[0] = left; constants[1] = bottom; - constants[2] = sampleWidth; - constants[3] = sampleHeight; + constants[2] = right - left; + constants[3] = top - bottom; } else { @@ -864,73 +927,83 @@ void Renderer::CaptureThumbnail(ImageFileBuffer *pngOut) constants[2] = 1.0f; constants[3] = 1.0f; } + c.m_pDeviceContext->Unmap(c.m_thumbnailBoundsBuffer, 0); c.m_pDeviceContext->Draw(4, 0); } - D3D11_TEXTURE2D_DESC desc = {}; - renderTargetTextures[MAX_MIP_LEVELS - 2]->GetDesc(&desc); - desc.Usage = D3D11_USAGE_STAGING; - desc.BindFlags = 0; - desc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; - desc.MiscFlags = 0; - m_pDevice->CreateTexture2D(&desc, nullptr, &stagingTexture); + D3D11_TEXTURE2D_DESC texDesc = {}; + renderTargetTextures[MAX_MIP_LEVELS - 2]->GetDesc(&texDesc); + texDesc.Usage = D3D11_USAGE_STAGING; + texDesc.BindFlags = 0; + texDesc.CPUAccessFlags = D3D11_CPU_ACCESS_READ; + texDesc.MiscFlags = 0; + m_pDevice->CreateTexture2D(&texDesc, NULL, &stagingTexture); + + const unsigned int stride = kThumbnailSize * 4; + unsigned char *linearData = new unsigned char[kThumbnailSize * stride]; - unsigned char *linearData = new unsigned char[kThumbnailSize * kThumbnailSize * 4u]; if (stagingTexture) { c.m_pDeviceContext->CopyResource(stagingTexture, renderTargetTextures[MAX_MIP_LEVELS - 2]); + D3D11_MAPPED_SUBRESOURCE mapped = {}; if (SUCCEEDED(c.m_pDeviceContext->Map(stagingTexture, 0, D3D11_MAP_READ, 0, &mapped))) { const unsigned char *src = static_cast(mapped.pData); unsigned char *dst = linearData; - for (unsigned int y = 0; y < kThumbnailSize; ++y) + + for (UINT y = 0; y < kThumbnailSize; ++y) { - std::memcpy(dst, src, kThumbnailSize * 4u); - for (unsigned int x = 0; x < kThumbnailSize; ++x) + memcpy(dst, src, stride); + + unsigned char *alpha = dst + 3; + for (UINT x = 0; x < kThumbnailSize; ++x) { - dst[x * 4u + 3u] = 0xFF; + *alpha = 0xFF; + alpha += 4; } + src += mapped.RowPitch; - dst += kThumbnailSize * 4u; + dst += stride; } + c.m_pDeviceContext->Unmap(stagingTexture, 0); } } - this->ConvertLinearToPng(pngOut, linearData, kThumbnailSize, kThumbnailSize); + ConvertLinearToPng(pngOut, linearData, kThumbnailSize, kThumbnailSize); delete[] linearData; if (stagingTexture) { stagingTexture->Release(); - stagingTexture = nullptr; + stagingTexture = NULL; } if (samplerState) { samplerState->Release(); - samplerState = nullptr; + samplerState = NULL; } if (rasterizerState) { rasterizerState->Release(); - rasterizerState = nullptr; + rasterizerState = NULL; } if (depthState) { depthState->Release(); - depthState = nullptr; + depthState = NULL; } if (blendState) { blendState->Release(); - blendState = nullptr; + blendState = NULL; } - c.m_pDeviceContext->OMSetBlendState(this->GetManagedBlendState(), c.blendFactor, 0xFFFFFFFFu); - c.m_pDeviceContext->OMSetDepthStencilState(this->GetManagedDepthStencilState(), 0); - c.m_pDeviceContext->RSSetState(this->GetManagedRasterizerState()); + c.m_pDeviceContext->OMSetBlendState(GetManagedBlendState(), c.blendFactor, -1); + c.m_pDeviceContext->OMSetDepthStencilState(GetManagedDepthStencilState(), 0); + c.m_pDeviceContext->RSSetState(GetManagedRasterizerState()); D3D11_VIEWPORT viewport = {}; viewport.TopLeftX = 0.0f; @@ -939,8 +1012,10 @@ void Renderer::CaptureThumbnail(ImageFileBuffer *pngOut) viewport.Height = (float)backBufferHeight; viewport.MinDepth = 0.0f; viewport.MaxDepth = 1.0f; + c.m_pDeviceContext->RSSetViewports(1, &viewport); c.m_pDeviceContext->OMSetRenderTargets(1, &renderTargetView, depthStencilView); - activeVertexType = 0xFFFFFFFFu; - activePixelType = 0xFFFFFFFFu; + + activeVertexType = -1; + activePixelType = -1; } diff --git a/Windows_Libs/Dev/Render/RendererMatrix.cpp b/Windows_Libs/Dev/Render/RendererMatrix.cpp index fbd7c53..b33c142 100644 --- a/Windows_Libs/Dev/Render/RendererMatrix.cpp +++ b/Windows_Libs/Dev/Render/RendererMatrix.cpp @@ -1,18 +1,18 @@ -#pragma once +#include "stdafx.h" #include "Renderer.h" #include const float *Renderer::MatrixGet(int type) { - Context &c = this->getContext(); + Context &c = getContext(); const int depth = c.stackPos[type]; return reinterpret_cast(&c.matrixStacks[type][depth]); } void Renderer::MatrixMode(int type) { - Context &c = this->getContext(); + Context &c = getContext(); assert(type >= 0); assert(type < STACK_TYPES); c.stackType = type; @@ -22,25 +22,25 @@ void Renderer::MatrixMult(float *mat) { DirectX::XMMATRIX matrix; std::memcpy(&matrix, mat, sizeof(matrix)); - this->MultWithStack(matrix); + MultWithStack(matrix); } void Renderer::MatrixOrthogonal(float left, float right, float bottom, float top, float zNear, float zFar) { const DirectX::XMMATRIX matrix = DirectX::XMMatrixOrthographicOffCenterRH(left, right, bottom, top, zNear, zFar); - this->MultWithStack(matrix); + MultWithStack(matrix); } void Renderer::MatrixPerspective(float fovy, float aspect, float zNear, float zFar) { const float fovRadians = fovy * (3.14159274f / 180.0f); const DirectX::XMMATRIX matrix = DirectX::XMMatrixPerspectiveFovRH(fovRadians, aspect, zNear, zFar); - this->MultWithStack(matrix); + MultWithStack(matrix); } void Renderer::MatrixPop() { - Context &c = this->getContext(); + Context &c = getContext(); assert(c.stackPos[c.stackType] > 0); @@ -51,7 +51,7 @@ void Renderer::MatrixPop() void Renderer::MatrixPush() { - Context &c = this->getContext(); + Context &c = getContext(); assert(c.stackPos[c.stackType] < (STACK_SIZE - 1)); @@ -65,18 +65,18 @@ void Renderer::MatrixRotate(float angle, float x, float y, float z) { const DirectX::XMVECTOR axis = DirectX::XMVectorSet(x, y, z, 0.0f); const DirectX::XMMATRIX matrix = DirectX::XMMatrixRotationAxis(axis, angle); - this->MultWithStack(matrix); + MultWithStack(matrix); } void Renderer::MatrixScale(float x, float y, float z) { const DirectX::XMMATRIX matrix = DirectX::XMMatrixScaling(x, y, z); - this->MultWithStack(matrix); + MultWithStack(matrix); } void Renderer::MatrixSetIdentity() { - Context &c = this->getContext(); + Context &c = getContext(); const int mode = c.stackType; const int depth = c.stackPos[mode]; c.matrixStacks[mode][depth] = DirectX::XMMatrixIdentity(); @@ -86,12 +86,12 @@ void Renderer::MatrixSetIdentity() void Renderer::MatrixTranslate(float x, float y, float z) { const DirectX::XMMATRIX matrix = DirectX::XMMatrixTranslation(x, y, z); - this->MultWithStack(matrix); + MultWithStack(matrix); } void Renderer::MultWithStack(DirectX::XMMATRIX matrix) { - Context &c = this->getContext(); + Context &c = getContext(); const int mode = c.stackType; const int depth = c.stackPos[mode]; DirectX::XMMATRIX ¤t = c.matrixStacks[mode][depth]; @@ -101,7 +101,7 @@ void Renderer::MultWithStack(DirectX::XMMATRIX matrix) void Renderer::Set_matrixDirty() { - Context &c = this->getContext(); + Context &c = getContext(); const DirectX::XMMATRIX identity = DirectX::XMMatrixIdentity(); c.matrixStacks[MATRIX_MODE_MODELVIEW][0] = identity; @@ -114,6 +114,6 @@ void Renderer::Set_matrixDirty() c.matrixDirty[MATRIX_MODE_MODELVIEW_TEXTURE] = true; c.matrixDirty[MATRIX_MODE_MODELVIEW_CBUFF] = true; - activeVertexType = 0xFFFFFFFFu; - activePixelType = 0xFFFFFFFFu; + activeVertexType = -1; + activePixelType = -1; } diff --git a/Windows_Libs/Dev/Render/RendererState.cpp b/Windows_Libs/Dev/Render/RendererState.cpp index 70e9bfe..3cef1a0 100644 --- a/Windows_Libs/Dev/Render/RendererState.cpp +++ b/Windows_Libs/Dev/Render/RendererState.cpp @@ -1,13 +1,13 @@ -#pragma once +#include "stdafx.h" #include "Renderer.h" -#include #include #include ID3D11BlendState *Renderer::GetManagedBlendState() { - Context &c = this->getContext(); + PROFILER_SCOPE("Renderer::GetManagedBlendState", "GetManagedBlendState", MP_ORCHID1) + Context &c = getContext(); const D3D11_RENDER_TARGET_BLEND_DESC &rtBlend = c.blendDesc.RenderTarget[0]; const int key = (rtBlend.BlendEnable ? 1 : 0) | ((static_cast(rtBlend.SrcBlend) & 0x1F) << 1) | @@ -15,11 +15,9 @@ ID3D11BlendState *Renderer::GetManagedBlendState() auto it = managedBlendStates.find(key); if (it != managedBlendStates.end()) - { return it->second; - } - ID3D11BlendState *state = nullptr; + ID3D11BlendState *state = NULL; m_pDevice->CreateBlendState(&c.blendDesc, &state); managedBlendStates.emplace(key, state); return state; @@ -27,18 +25,17 @@ ID3D11BlendState *Renderer::GetManagedBlendState() ID3D11DepthStencilState *Renderer::GetManagedDepthStencilState() { - Context &c = this->getContext(); + PROFILER_SCOPE("Renderer::GetManagedBlendState", "GetManagedDepthStencilState", MP_ORCHID1) + Context &c = getContext(); const int key = (c.depthStencilDesc.DepthEnable ? 2 : 0) | ((static_cast(c.depthStencilDesc.DepthFunc) & 0x0F) << 2) | (c.depthStencilDesc.DepthWriteMask == D3D11_DEPTH_WRITE_MASK_ALL ? 1 : 0); auto it = managedDepthStencilStates.find(key); if (it != managedDepthStencilStates.end()) - { return it->second; - } - ID3D11DepthStencilState *state = nullptr; + ID3D11DepthStencilState *state = NULL; m_pDevice->CreateDepthStencilState(&c.depthStencilDesc, &state); managedDepthStencilStates.emplace(key, state); return state; @@ -46,7 +43,8 @@ ID3D11DepthStencilState *Renderer::GetManagedDepthStencilState() ID3D11RasterizerState *Renderer::GetManagedRasterizerState() { - Context &c = this->getContext(); + PROFILER_SCOPE("Renderer::GetManagedRasterizerState", "GetManagedRasterizerState", MP_ORCHID1) + Context &c = getContext(); const int key = (static_cast(c.rasterizerDesc.DepthBias)) | (static_cast(static_cast(c.rasterizerDesc.SlopeScaledDepthBias)) << 8) | @@ -54,11 +52,9 @@ ID3D11RasterizerState *Renderer::GetManagedRasterizerState() auto it = managedRasterizerStates.find(key); if (it != managedRasterizerStates.end()) - { return it->second; - } - ID3D11RasterizerState *state = nullptr; + ID3D11RasterizerState *state = NULL; m_pDevice->CreateRasterizerState(&c.rasterizerDesc, &state); managedRasterizerStates.emplace(key, state); return state; @@ -66,14 +62,13 @@ ID3D11RasterizerState *Renderer::GetManagedRasterizerState() ID3D11SamplerState *Renderer::GetManagedSamplerState() { - Context &c = this->getContext(); + PROFILER_SCOPE("Renderer::GetManagedSamplerState", "GetManagedSamplerState", MP_ORCHID1) + Context &c = getContext(); const int key = m_textures[c.textureIdx].samplerParams; auto it = managedSamplerStates.find(key); if (it != managedSamplerStates.end()) - { return it->second; - } const bool clampU = (key & 0x01) != 0; const bool clampV = (key & 0x02) != 0; @@ -96,7 +91,7 @@ ID3D11SamplerState *Renderer::GetManagedSamplerState() desc.MinLOD = -(std::numeric_limits::max)(); desc.MaxLOD = (std::numeric_limits::max)(); - ID3D11SamplerState *state = nullptr; + ID3D11SamplerState *state = NULL; m_pDevice->CreateSamplerState(&desc, &state); managedSamplerStates.emplace(key, state); return state; @@ -104,37 +99,37 @@ ID3D11SamplerState *Renderer::GetManagedSamplerState() void Renderer::StateSetFogEnable(bool enable) { - Context &c = this->getContext(); - c.fogEnabled = enable ? 1 : 0; + Context &c = getContext(); + c.fogEnabled = enable; } void Renderer::StateSetFogMode(int mode) { - Context &c = this->getContext(); + Context &c = getContext(); c.fogMode = mode; } void Renderer::StateSetFogNearDistance(float dist) { - Context &c = this->getContext(); + Context &c = getContext(); c.fogNearDistance = dist; } void Renderer::StateSetFogFarDistance(float dist) { - Context &c = this->getContext(); + Context &c = getContext(); c.fogFarDistance = dist; } void Renderer::StateSetFogDensity(float density) { - Context &c = this->getContext(); + Context &c = getContext(); c.fogDensity = density; } void Renderer::StateSetFogColour(float red, float green, float blue) { - Context &c = this->getContext(); + Context &c = getContext(); c.fogColourRed = red; c.fogColourBlue = blue; c.fogColourGreen = green; @@ -144,25 +139,23 @@ void Renderer::UpdateViewportState() {} void Renderer::StateSetLightingEnable(bool enable) { - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetLightingEnable(enable); return; } - c.lightingEnabled = enable ? 1 : 0; + c.lightingEnabled = enable; } void Renderer::StateSetLightColour(int light, float red, float green, float blue) { if (light >= 2) - { return; - } - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetLightColour(light, red, green, blue); return; @@ -172,13 +165,13 @@ void Renderer::StateSetLightColour(int light, float red, float green, float blue c.lightColour[light].y = green; c.lightColour[light].z = blue; c.lightColour[light].w = 1.0f; - c.lightingDirty = 1; + c.lightingDirty = true; } void Renderer::StateSetLightAmbientColour(float red, float green, float blue) { - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetLightAmbientColour(red, green, blue); return; @@ -188,31 +181,29 @@ void Renderer::StateSetLightAmbientColour(float red, float green, float blue) c.lightAmbientColour.y = green; c.lightAmbientColour.z = blue; c.lightAmbientColour.w = 1.0f; - c.lightingDirty = 1; + c.lightingDirty = true; } void Renderer::StateSetLightEnable(int light, bool enable) { if (light >= 2) - { return; - } - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetLightEnable(light, enable); return; } - c.lightEnabled[light] = enable ? 1 : 0; - c.lightingDirty = 1; + c.lightEnabled[light] = enable; + c.lightingDirty = true; } void Renderer::StateSetColour(float r, float g, float b, float a) { - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetColor(r, g, b, a); return; @@ -229,35 +220,35 @@ void Renderer::StateSetColour(float r, float g, float b, float a) void Renderer::StateSetDepthMask(bool enable) { - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetDepthMask(enable); return; } c.depthStencilDesc.DepthWriteMask = enable ? D3D11_DEPTH_WRITE_MASK_ALL : D3D11_DEPTH_WRITE_MASK_ZERO; - c.m_pDeviceContext->OMSetDepthStencilState(this->GetManagedDepthStencilState(), 0); - c.depthWriteEnabled = enable ? 1 : 0; + c.m_pDeviceContext->OMSetDepthStencilState(GetManagedDepthStencilState(), 0); + c.depthWriteEnabled = enable; } void Renderer::StateSetBlendEnable(bool enable) { - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetBlendEnable(enable); return; } - c.blendDesc.RenderTarget[0].BlendEnable = enable ? TRUE : FALSE; - c.m_pDeviceContext->OMSetBlendState(this->GetManagedBlendState(), c.blendFactor, 0xFFFFFFFFu); + c.blendDesc.RenderTarget[0].BlendEnable = enable; + c.m_pDeviceContext->OMSetBlendState(GetManagedBlendState(), c.blendFactor, 0xFFFFFFFF); } void Renderer::StateSetBlendFunc(int src, int dst) { - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetBlendFunc(src, dst); return; @@ -265,29 +256,29 @@ void Renderer::StateSetBlendFunc(int src, int dst) c.blendDesc.RenderTarget[0].SrcBlend = static_cast(src); c.blendDesc.RenderTarget[0].DestBlend = static_cast(dst); - c.m_pDeviceContext->OMSetBlendState(this->GetManagedBlendState(), c.blendFactor, 0xFFFFFFFFu); + c.m_pDeviceContext->OMSetBlendState(GetManagedBlendState(), c.blendFactor, 0xFFFFFFFF); } void Renderer::StateSetBlendFactor(unsigned int colour) { - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetBlendFactor(colour); return; } const float scale = 255.0f; - c.blendFactor[0] = static_cast((colour >> 0) & 0xFFu) / scale; - c.blendFactor[1] = static_cast((colour >> 8) & 0xFFu) / scale; - c.blendFactor[2] = static_cast((colour >> 16) & 0xFFu) / scale; - c.blendFactor[3] = static_cast((colour >> 24) & 0xFFu) / scale; - c.m_pDeviceContext->OMSetBlendState(this->GetManagedBlendState(), c.blendFactor, 0xFFFFFFFFu); + c.blendFactor[0] = static_cast((colour >> 0) & 0xFF) / scale; + c.blendFactor[1] = static_cast((colour >> 8) & 0xFF) / scale; + c.blendFactor[2] = static_cast((colour >> 16) & 0xFF) / scale; + c.blendFactor[3] = static_cast((colour >> 24) & 0xFF) / scale; + c.m_pDeviceContext->OMSetBlendState(GetManagedBlendState(), c.blendFactor, 0xFFFFFFFF); } void Renderer::StateSetAlphaFunc(int, float param) { - Context &c = this->getContext(); + Context &c = getContext(); c.alphaReference = param; const float alpha[4] = {0.0f, 0.0f, 0.0f, c.alphaTestEnabled ? c.alphaReference : 0.0f}; @@ -299,51 +290,47 @@ void Renderer::StateSetAlphaFunc(int, float param) void Renderer::StateSetDepthFunc(int func) { - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetDepthFunc(func); return; } c.depthStencilDesc.DepthFunc = static_cast(func); - c.m_pDeviceContext->OMSetDepthStencilState(this->GetManagedDepthStencilState(), 0); + c.m_pDeviceContext->OMSetDepthStencilState(GetManagedDepthStencilState(), 0); } void Renderer::StateSetFaceCull(bool enable) { - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetFaceCull(enable); return; } c.rasterizerDesc.CullMode = enable ? D3D11_CULL_BACK : D3D11_CULL_NONE; - c.m_pDeviceContext->RSSetState(this->GetManagedRasterizerState()); - c.faceCullEnabled = enable ? 1 : 0; + c.m_pDeviceContext->RSSetState(GetManagedRasterizerState()); + c.faceCullEnabled = enable; } void Renderer::StateSetFaceCullCW(bool enable) { - Context &c = this->getContext(); + Context &c = getContext(); if (c.faceCullEnabled) - { c.rasterizerDesc.CullMode = enable ? D3D11_CULL_BACK : D3D11_CULL_FRONT; - } else - { c.rasterizerDesc.CullMode = D3D11_CULL_NONE; - } - c.m_pDeviceContext->RSSetState(this->GetManagedRasterizerState()); + c.m_pDeviceContext->RSSetState(GetManagedRasterizerState()); } void Renderer::StateSetLineWidth(float) {} void Renderer::StateSetWriteEnable(bool red, bool green, bool blue, bool alpha) { - Context &c = this->getContext(); + Context &c = getContext(); std::uint8_t mask = 0; mask |= red ? 0x1 : 0; @@ -352,27 +339,27 @@ void Renderer::StateSetWriteEnable(bool red, bool green, bool blue, bool alpha) mask |= alpha ? 0x8 : 0; c.blendDesc.RenderTarget[0].RenderTargetWriteMask = mask; - c.m_pDeviceContext->OMSetBlendState(this->GetManagedBlendState(), c.blendFactor, 0xFFFFFFFFu); + c.m_pDeviceContext->OMSetBlendState(GetManagedBlendState(), c.blendFactor, 0xFFFFFFFF); } void Renderer::StateSetDepthTestEnable(bool enable) { - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetDepthTestEnable(enable); return; } - c.depthStencilDesc.DepthEnable = enable ? TRUE : FALSE; - c.m_pDeviceContext->OMSetDepthStencilState(this->GetManagedDepthStencilState(), 0); - c.depthTestEnabled = enable ? 1 : 0; + c.depthStencilDesc.DepthEnable = enable; + c.m_pDeviceContext->OMSetDepthStencilState(GetManagedDepthStencilState(), 0); + c.depthTestEnabled = enable; } void Renderer::StateSetAlphaTestEnable(bool enable) { - Context &c = this->getContext(); - c.alphaTestEnabled = enable ? 1 : 0; + Context &c = getContext(); + c.alphaTestEnabled = enable; const float alpha[4] = {0.0f, 0.0f, 0.0f, enable ? c.alphaReference : 0.0f}; D3D11_MAPPED_SUBRESOURCE mapped = {}; @@ -383,17 +370,18 @@ void Renderer::StateSetAlphaTestEnable(bool enable) void Renderer::StateSetDepthSlopeAndBias(float slope, float bias) { - Context &c = this->getContext(); + Context &c = getContext(); const float scale = 65536.0f; c.rasterizerDesc.DepthBias = static_cast(bias * scale); c.rasterizerDesc.SlopeScaledDepthBias = slope * scale; - c.m_pDeviceContext->RSSetState(this->GetManagedRasterizerState()); + c.m_pDeviceContext->RSSetState(GetManagedRasterizerState()); } void Renderer::UpdateFogState() { - Context &c = this->getContext(); + PROFILER_SCOPE("Renderer::UpdateFogState", "UpdateFogState", MP_ORCHID1) + Context &c = getContext(); ID3D11DeviceContext *d3d11 = c.m_pDeviceContext; float fogParams[4] = {}; @@ -426,7 +414,7 @@ void Renderer::UpdateFogState() void Renderer::StateSetVertexTextureUV(float u, float v) { - Context &c = this->getContext(); + Context &c = getContext(); const float texgen[4] = {u - 1.0f, v - 1.0f, 0.0f, 0.0f}; D3D11_MAPPED_SUBRESOURCE mapped = {}; @@ -437,7 +425,8 @@ void Renderer::StateSetVertexTextureUV(float u, float v) void Renderer::UpdateTexGenState() { - Context &c = this->getContext(); + PROFILER_SCOPE("Renderer::UpdateTexGenState", "UpdateTexGenState", MP_ORCHID1) + Context &c = getContext(); D3D11_MAPPED_SUBRESOURCE mapped = {}; c.m_pDeviceContext->Map(c.m_texGenMatricesBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); @@ -447,7 +436,8 @@ void Renderer::UpdateTexGenState() void Renderer::UpdateLightingState() { - Context &c = this->getContext(); + PROFILER_SCOPE("Renderer::UpdateLightingState", "UpdateLightingState", MP_ORCHID1) + Context &c = getContext(); if (!c.lightingDirty || !c.lightingEnabled) { return; @@ -471,18 +461,16 @@ void Renderer::UpdateLightingState() std::memcpy(mapped.pData, c.lightDirection, lightingBytes); c.m_pDeviceContext->Unmap(c.m_lightingStateBuffer, 0); - c.lightingDirty = 0; + c.lightingDirty = false; } void Renderer::StateSetLightDirection(int light, float x, float y, float z) { if (light >= 2) - { return; - } - Context &c = this->getContext(); - if (c.commandBuffer != nullptr && c.commandBuffer->isActive != 0) + Context &c = getContext(); + if (c.commandBuffer != NULL && c.commandBuffer->isActive != 0) { c.commandBuffer->SetLightDirection(light, x, y, z); return; @@ -495,12 +483,12 @@ void Renderer::StateSetLightDirection(int light, float x, float y, float z) const DirectX::XMVECTOR normalized = DirectX::XMVector3Normalize(transformed); DirectX::XMStoreFloat4(&c.lightDirection[light], normalized); - c.lightingDirty = 1; + c.lightingDirty = true; } void Renderer::StateSetViewport(C4JRender::eViewportType viewportType) { - this->getContext(); + getContext(); m_ViewportType = viewportType; const float fullWidth = static_cast(backBufferWidth); @@ -569,14 +557,14 @@ void Renderer::StateSetEnableViewportClipPlanes(bool) {} void Renderer::StateSetTexGenCol(int col, float x, float y, float z, float w, bool eyeSpace) { - Context &c = this->getContext(); + Context &c = getContext(); DirectX::XMVECTOR plane = DirectX::XMVectorSet(x, y, z, w); if (eyeSpace) { DirectX::XMFLOAT4X4 modelView; std::memset(&modelView, 0, sizeof(modelView)); - std::memcpy(&modelView, this->MatrixGet(MATRIX_MODE_MODELVIEW), sizeof(modelView)); + std::memcpy(&modelView, MatrixGet(MATRIX_MODE_MODELVIEW), sizeof(modelView)); DirectX::XMVECTOR determinant = DirectX::XMVectorZero(); const DirectX::XMMATRIX inverse = DirectX::XMMatrixInverse(&determinant, DirectX::XMLoadFloat4x4(&modelView)); @@ -604,35 +592,33 @@ void Renderer::StateSetTexGenCol(int col, float x, float y, float z, float w, bo void Renderer::StateSetStencil(D3D11_COMPARISON_FUNC function, uint8_t stencil_ref, uint8_t stencil_func_mask, uint8_t stencil_write_mask) { - Context &c = this->getContext(); + Context &c = getContext(); D3D11_DEPTH_STENCIL_DESC desc = c.depthStencilDesc; - desc.StencilEnable = TRUE; + desc.StencilEnable = true; desc.StencilReadMask = stencil_func_mask; desc.StencilWriteMask = stencil_write_mask; desc.FrontFace.StencilFunc = function; desc.BackFace.StencilFunc = function; - ID3D11DepthStencilState *state = nullptr; + ID3D11DepthStencilState *state = NULL; m_pDevice->CreateDepthStencilState(&desc, &state); m_pDeviceContext->OMSetDepthStencilState(state, stencil_ref); - if (state != nullptr) - { - state->Release(); - } + if (state != NULL) state->Release(); } void Renderer::StateSetForceLOD(int LOD) { - Context &c = this->getContext(); + Context &c = getContext(); c.forcedLOD = LOD; } void Renderer::StateUpdate() { - Context &c = this->getContext(); - this->StateSetFaceCull(c.faceCullEnabled != 0); - this->StateSetDepthMask(c.depthWriteEnabled != 0); - this->StateSetDepthTestEnable(c.depthTestEnabled != 0); - this->StateSetAlphaTestEnable(c.alphaTestEnabled != 0); + PROFILER_SCOPE("Renderer::StateUpdate", "StateUpdate", MP_ORCHID1) + Context &c = getContext(); + StateSetFaceCull(c.faceCullEnabled); + StateSetDepthMask(c.depthWriteEnabled); + StateSetDepthTestEnable(c.depthTestEnabled); + StateSetAlphaTestEnable(c.alphaTestEnabled); } diff --git a/Windows_Libs/Dev/Render/RendererTexture.cpp b/Windows_Libs/Dev/Render/RendererTexture.cpp index 40c5925..f9243d9 100644 --- a/Windows_Libs/Dev/Render/RendererTexture.cpp +++ b/Windows_Libs/Dev/Render/RendererTexture.cpp @@ -1,372 +1,326 @@ -#pragma once +#include "stdafx.h" #include "Renderer.h" #include "libpng/png.h" -#include -#include -#include -#include +unsigned char* dataStart; +unsigned char *dataCurr; +unsigned char *dataEnd; -DXGI_FORMAT Renderer::textureFormats[C4JRender::MAX_TEXTURE_FORMATS] = { - DXGI_FORMAT_B8G8R8A8_UNORM, -}; +DXGI_FORMAT Renderer::textureFormats[] = { DXGI_FORMAT_B8G8R8A8_UNORM }; + +void user_write_data_init(unsigned char* pBuffer, int size) +{ + dataStart = pBuffer; + dataCurr = pBuffer; + dataEnd = pBuffer + size; +} + +int user_write_data_bytes_written() +{ + return static_cast(dataCurr - dataStart); +} + +void user_write_data(png_struct_def* png_ptr, unsigned char* src, size_t length) +{ + int bytesToWrite = static_cast(dataEnd - dataCurr); + if (static_cast(length) < bytesToWrite) + bytesToWrite = static_cast(length); + + memcpy(dataCurr, src, bytesToWrite); + dataCurr += bytesToWrite; +} + +void user_flush_data(png_struct_def* png_ptr) +{ + // TODO(3UR): this is for a different platform? it's empty in Render_PC.lib but not Render.lib +} int Renderer::TextureCreate() { - int i = 0; - for (; ; i++) + PROFILER_SCOPE("Renderer::TextureCreate", "TextureCreate", MP_PURPLE4) + for (int i = 0; i < MAX_TEXTURES; i++) { - assert(i < 512); - if (!m_textures[i].allocated) { - break; + m_textures[i].texture = NULL; + m_textures[i].allocated = true; + m_textures[i].mipLevels = 1; + m_textures[i].textureFormat = 0; + return i; } } - - m_textures[i].texture = nullptr; - m_textures[i].allocated = true; - m_textures[i].mipLevels = 1; - m_textures[i].samplerParams = 0; - return i; -} - -void Renderer::TextureSetTextureLevels(int levels) -{ - const int textureIdx = this->getContext().textureIdx; - - assert(levels <= MAX_MIP_LEVELS); - - m_textures[textureIdx].mipLevels = levels; -} - -int Renderer::TextureGetTextureLevels() -{ - const int textureIdx = this->getContext().textureIdx; - return m_textures[textureIdx].mipLevels; -} - -void Renderer::TextureSetParam(int param, int value) -{ - Texture &texture = m_textures[this->getContext().textureIdx]; - - switch (param) - { - case GL_TEXTURE_MIN_FILTER: - texture.samplerParams &= ~4u; - if (value == 1) - { - texture.samplerParams |= 4u; - } - break; - case GL_TEXTURE_MAG_FILTER: - texture.samplerParams &= ~8u; - if (value == 1) - { - texture.samplerParams |= 8u; - } - break; - case GL_TEXTURE_WRAP_S: - texture.samplerParams &= ~1u; - if (value == 0) - { - texture.samplerParams |= 1u; - } - break; - case GL_TEXTURE_WRAP_T: - case 5: // GL_TEXTURE_WRAP_R, but this renderer only supports 2D textures, so treat it as GL_TEXTURE_WRAP_T - texture.samplerParams &= ~2u; - if (value == 0) - { - texture.samplerParams |= 2u; - } - break; - default: - break; - } -} - -void Renderer::TextureDynamicUpdateStart() {} - -void Renderer::TextureDynamicUpdateEnd() {} - -void Renderer::TextureData(int width, int height, void *data, int level, C4JRender::eTextureFormat format) -{ - Renderer::Context &c = this->getContext(); - - assert(m_textures[c.textureIdx].allocated); - assert((level > 0) || (m_textures[c.textureIdx].texture == NULL)); - - Texture &texture = m_textures[c.textureIdx]; - texture.textureFormat = format; - - if (level == 0) - { - D3D11_TEXTURE2D_DESC desc = {}; - desc.Width = width; - desc.Height = height; - desc.MipLevels = texture.mipLevels; - desc.ArraySize = 1; - desc.Format = textureFormats[format]; - desc.SampleDesc.Count = 1; - desc.Usage = D3D11_USAGE_DEFAULT; - desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; - - HRESULT hr = 0; - hr = m_pDevice->CreateTexture2D(&desc, nullptr, &texture.texture); - assert(hr >= 0); - - hr = m_pDevice->CreateShaderResourceView(texture.texture, nullptr, &texture.view); - assert(hr >= 0); - } - - const UINT rowPitch = width * 4u; - const UINT depthPitch = width * height * 4u; - c.m_pDeviceContext->UpdateSubresource(texture.texture, level, nullptr, data, rowPitch, depthPitch); -} - -void Renderer::TextureDataUpdate(int xoffset, int yoffset, int width, int height, void *data, int level) -{ - Renderer::Context &c = this->getContext(); - Texture &texture = m_textures[c.textureIdx]; - - D3D11_BOX box = {}; - box.left = xoffset; - box.right = xoffset + width; - box.top = yoffset; - box.bottom = yoffset + height; - box.front = 0; - box.back = 1; - - D3D11_TEXTURE2D_DESC desc = {}; - texture.texture->GetDesc(&desc); - - const UINT rowPitch = width * 4u; - const UINT depthPitch = width * height * 4u; - c.m_pDeviceContext->UpdateSubresource(texture.texture, level, &box, data, rowPitch, depthPitch); + return -1; } void Renderer::TextureFree(int idx) { - Texture &texture = m_textures[idx]; - texture.texture->Release(); - texture.view->Release(); - texture.view = nullptr; - texture.allocated = false; - texture.texture = nullptr; -} - -void Renderer::TextureGetStats() {} - -ID3D11ShaderResourceView *Renderer::TextureGetTexture(int idx) -{ - if (idx < 0 || idx > 0x1FF) + PROFILER_SCOPE("Renderer::TextureFree", "TextureFree", MP_PURPLE4) + if (m_textures[idx].texture) { - return nullptr; + m_textures[idx].texture->Release(); + m_textures[idx].texture = NULL; } - - const Texture &texture = m_textures[idx]; - if (!texture.allocated) + if (m_textures[idx].view) { - return nullptr; + m_textures[idx].view->Release(); + m_textures[idx].view = NULL; } - - return texture.view; + m_textures[idx].allocated = false; } void Renderer::TextureBind(int idx) { - int textureIndex = idx; - if (textureIndex == -1) - { - textureIndex = defaultTextureIndex; - } + PROFILER_SCOPE("Renderer::TextureBind", "TextureBind", MP_PURPLE4) + if (idx == -1) + idx = defaultTextureIndex; - Renderer::Context &c = this->getContext(); + Context& c = getContext(); if (c.commandBuffer && c.commandBuffer->isActive) - { - c.commandBuffer->BindTexture(textureIndex); - } + c.commandBuffer->BindTexture(idx); - c.textureIdx = textureIndex; - ID3D11ShaderResourceView *const view = m_textures[textureIndex].view; - c.m_pDeviceContext->PSSetShaderResources(0, 1, &view); - this->UpdateTextureState(false); + c.textureIdx = idx; + c.m_pDeviceContext->PSSetShaderResources(0, 1, &m_textures[idx].view); + + UpdateTextureState(false); } void Renderer::TextureBindVertex(int idx) { - int textureIndex = idx; - if (textureIndex == -1) - { - textureIndex = defaultTextureIndex; - } + PROFILER_SCOPE("Renderer::TextureBindVertex", "TextureBindVertex", MP_PURPLE4) + if (idx == -1) + idx = defaultTextureIndex; - Renderer::Context &c = this->getContext(); - c.textureIdx = textureIndex; + Context& c = getContext(); - ID3D11ShaderResourceView *const view = m_textures[textureIndex].view; - c.m_pDeviceContext->VSSetShaderResources(0, 1, &view); - this->UpdateTextureState(true); + c.textureIdx = idx; + c.m_pDeviceContext->VSSetShaderResources(0, 1, &m_textures[idx].view); + + UpdateTextureState(true); } -void Renderer::UpdateTextureState(bool vertexSampler) +void Renderer::TextureSetTextureLevels(int levels) { - Renderer::Context &c = this->getContext(); - ID3D11SamplerState *sampler = this->GetManagedSamplerState(); + Context& c = getContext(); + m_textures[c.textureIdx].mipLevels = levels; +} - if (vertexSampler) +int Renderer::TextureGetTextureLevels() +{ + Context& c = getContext(); + return m_textures[c.textureIdx].mipLevels; +} + +void Renderer::TextureData(int width, int height, void* data, int level, C4JRender::eTextureFormat format) +{ + PROFILER_SCOPE("Renderer::TextureData", "TextureData", MP_PURPLE4) + Context& c = getContext(); + int idx = c.textureIdx; + + m_textures[idx].textureFormat = format; + + if (level == 0) { - c.m_pDeviceContext->VSSetSamplers(0, 1, &sampler); + D3D11_TEXTURE2D_DESC desc; + desc.Width = width; + desc.Height = height; + desc.MipLevels = m_textures[idx].mipLevels; + desc.ArraySize = 1; + desc.Format = textureFormats[format]; + desc.SampleDesc.Count = 1; + desc.SampleDesc.Quality = 0; + desc.Usage = D3D11_USAGE_DEFAULT; + desc.BindFlags = D3D11_BIND_SHADER_RESOURCE; + desc.CPUAccessFlags = 0; + desc.MiscFlags = 0; + + m_pDevice->CreateTexture2D(&desc, NULL, &m_textures[idx].texture); + m_pDevice->CreateShaderResourceView(m_textures[idx].texture, NULL, &m_textures[idx].view); } + + c.m_pDeviceContext->UpdateSubresource( + m_textures[idx].texture, + level, + NULL, + data, + static_cast(width * 4), + static_cast(width * height * 4) + ); +} + +void Renderer::TextureDataUpdate(int xoffset, int yoffset, int width, int height, void* data, int level) +{ + PROFILER_SCOPE("Renderer::TextureDataUpdate", "TextureDataUpdate", MP_PURPLE4) + Context& c = getContext(); + int idx = c.textureIdx; + + D3D11_TEXTURE2D_DESC desc; + m_textures[idx].texture->GetDesc(&desc); + + D3D11_BOX box; + box.left = xoffset; + box.top = yoffset; + box.right = xoffset + width; + box.bottom = yoffset + height; + box.front = 0; + box.back = 1; + + c.m_pDeviceContext->UpdateSubresource( + m_textures[idx].texture, + level, + &box, + data, + static_cast(width * 4), + static_cast(width * height * 4) + ); +} + +void Renderer::TextureSetParam(int param, int value) +{ + Context& c = getContext(); + int idx = c.textureIdx; + + switch (param) + { + case GL_TEXTURE_MIN_FILTER: + m_textures[idx].samplerParams &= ~4u; + if (value == GL_LINEAR) + m_textures[idx].samplerParams |= 4u; + break; + case GL_TEXTURE_MAG_FILTER: + m_textures[idx].samplerParams &= ~8u; + if (value == GL_LINEAR) + m_textures[idx].samplerParams |= 8u; + break; + case GL_TEXTURE_WRAP_S: + m_textures[idx].samplerParams &= ~1u; + if (value == GL_CLAMP) + m_textures[idx].samplerParams |= 1u; + break; + case GL_TEXTURE_WRAP_T: + m_textures[idx].samplerParams &= ~2u; + if (value == GL_CLAMP) + m_textures[idx].samplerParams |= 2u; + break; + } +} + +void Renderer::TextureDynamicUpdateStart() +{ + // TODO(3UR): this is for a different platform? it's empty in Render_PC.lib but not Render.lib +} + +void Renderer::TextureDynamicUpdateEnd() +{ + // TODO(3UR): this is for a different platform? it's empty in Render_PC.lib but not Render.lib +} + +void Renderer::UpdateTextureState(bool bVertex) +{ + Context& c = getContext(); + ID3D11SamplerState* pSampler = GetManagedSamplerState(); + + if (bVertex) + c.m_pDeviceContext->VSSetSamplers(0, 1, &pSampler); else - { - c.m_pDeviceContext->PSSetSamplers(0, 1, &sampler); - } + c.m_pDeviceContext->PSSetSamplers(0, 1, &pSampler); } -HRESULT Renderer::LoadTextureData(const char *szFilename, D3DXIMAGE_INFO *pSrcInfo, int **ppDataOut) +HRESULT Renderer::LoadTextureData(const char* szFilename, D3DXIMAGE_INFO* pSrcInfo, int** ppDataOut) { - if (!szFilename || !pSrcInfo || !ppDataOut) - { - return -1; - } - - *ppDataOut = nullptr; - + PROFILER_SCOPE("Renderer::LoadTextureData_File", "LoadTextureData_File", MP_PURPLE4) png_image image; - std::memset(&image, 0, sizeof(image)); + memset(&image, 0, sizeof(image)); image.version = PNG_IMAGE_VERSION; + if (!png_image_begin_read_from_file(&image, szFilename)) - { return -1; - } - if (image.width == 0 || image.height == 0) - { - png_image_free(&image); - return -1; - } + // TODO(3UR): why crash? + //if ((image.format & 3u) > 1) + // return -1; image.format = PNG_FORMAT_RGBA; - const png_alloc_size_t pixelCount = png_alloc_size_t(image.width) * png_alloc_size_t(image.height); - if (pixelCount == 0 || pixelCount > (std::numeric_limits::max)() / sizeof(int)) - { - png_image_free(&image); + + *ppDataOut = new int[image.width * image.height]; + if (!*ppDataOut || !png_image_finish_read(&image, NULL, *ppDataOut, 0, NULL)) return -1; - } - int *output = new (std::nothrow) int[size_t(pixelCount)]; - - if (!output) - { - png_image_free(&image); - return -1; - } - - if (!png_image_finish_read(&image, nullptr, output, 0, nullptr)) - { - delete[] output; - png_image_free(&image); - return -1; - } - - *ppDataOut = output; pSrcInfo->Width = image.width; pSrcInfo->Height = image.height; - png_image_free(&image); - return 0; + return S_OK; } -HRESULT Renderer::LoadTextureData(BYTE *pbData, DWORD dwBytes, D3DXIMAGE_INFO *pSrcInfo, int **ppDataOut) +HRESULT Renderer::LoadTextureData(BYTE* pbData, DWORD dwBytes, D3DXIMAGE_INFO* pSrcInfo, int** ppDataOut) { - if (!pbData || dwBytes == 0 || !pSrcInfo || !ppDataOut) - { - return -1; - } - - *ppDataOut = nullptr; - + PROFILER_SCOPE("Renderer::LoadTextureData_Memory", "LoadTextureData_Memory", MP_PURPLE4) png_image image; - std::memset(&image, 0, sizeof(image)); + memset(&image, 0, sizeof(image)); image.version = PNG_IMAGE_VERSION; - if (!png_image_begin_read_from_memory(&image, pbData, dwBytes)) - { - return -1; - } - if (image.width == 0 || image.height == 0) - { - png_image_free(&image); + if (!png_image_begin_read_from_memory(&image, pbData, dwBytes)) return -1; - } + + // TODO(3UR): why crash? + //if ((image.format & 3u) > 1) + // return -1; image.format = PNG_FORMAT_RGBA; - const png_alloc_size_t pixelCount = png_alloc_size_t(image.width) * png_alloc_size_t(image.height); - if (pixelCount == 0 || pixelCount > (std::numeric_limits::max)() / sizeof(int)) - { - png_image_free(&image); + + *ppDataOut = new int[image.width * image.height]; + if (!*ppDataOut || !png_image_finish_read(&image, NULL, *ppDataOut, 0, NULL)) return -1; - } - int *output = new (std::nothrow) int[size_t(pixelCount)]; - - if (!output) - { - png_image_free(&image); - return -1; - } - - if (!png_image_finish_read(&image, nullptr, output, 0, nullptr)) - { - delete[] output; - png_image_free(&image); - return -1; - } - - *ppDataOut = output; pSrcInfo->Width = image.width; pSrcInfo->Height = image.height; - png_image_free(&image); - return 0; + return S_OK; } -HRESULT Renderer::SaveTextureData(const char *szFilename, D3DXIMAGE_INFO *pSrcInfo, int *ppDataOut) +HRESULT Renderer::SaveTextureData(const char* szFilename, D3DXIMAGE_INFO* pSrcInfo, int* ppDataOut) { - png_image image = {}; - image.version = PNG_IMAGE_VERSION; + PROFILER_SCOPE("Renderer::SaveTextureData", "SaveTextureData", MP_PURPLE4) + png_image image; + memset(&image, 0, sizeof(image)); image.width = pSrcInfo->Width; image.height = pSrcInfo->Height; + image.version = PNG_IMAGE_VERSION; image.format = PNG_FORMAT_RGBA; - png_image_write_to_file(&image, szFilename, 0, ppDataOut, 0, nullptr); - return 0; + png_image_write_to_file(&image, szFilename, 0, ppDataOut, 0, NULL); + return S_OK; } -HRESULT Renderer::SaveTextureDataToMemory(void *pOutput, int outputCapacity, int *outputLength, int width, int height, int *ppDataIn) +HRESULT Renderer::SaveTextureDataToMemory(void* pOutput, int outputCapacity, int* outputLength, int width, int height, int* ppDataIn) { - if (!pOutput || outputCapacity <= 0 || !outputLength || width <= 0 || height <= 0 || !ppDataIn) - { - return -1; - } - + PROFILER_SCOPE("Renderer::SaveTextureDataToMemory", "SaveTextureDataToMemory", MP_PURPLE4) png_image image; - std::memset(&image, 0, sizeof(image)); - image.version = PNG_IMAGE_VERSION; + memset(&image, 0, sizeof(image)); image.width = width; image.height = height; + image.version = PNG_IMAGE_VERSION; image.format = PNG_FORMAT_RGBA; - png_alloc_size_t memoryBytes = static_cast(outputCapacity); - if (!png_image_write_to_memory(&image, pOutput, &memoryBytes, 0, ppDataIn, 0, nullptr)) - { - *outputLength = 0; - png_image_free(&image); - return -1; - } + dataEnd = (BYTE*)pOutput + outputCapacity; + dataStart = (BYTE*)pOutput; + dataCurr = (BYTE*)pOutput; - *outputLength = static_cast(memoryBytes); - png_image_free(&image); - return 0; + png_image_write_to_stdio(&image, NULL, 0, ppDataIn, 0, NULL, user_write_data, user_flush_data); + + *outputLength = static_cast(dataCurr - dataStart); + return S_OK; } + +void Renderer::TextureGetStats() +{ + // TODO(3UR): this is for a different platform? it's empty in Render_PC.lib but not Render.lib +} + +ID3D11ShaderResourceView* Renderer::TextureGetTexture(int idx) +{ + if ((unsigned int)idx <= 511) + { + if (m_textures[idx].allocated) + return m_textures[idx].view; + } + return NULL; +} \ No newline at end of file diff --git a/Windows_Libs/Dev/Render/RendererVertex.cpp b/Windows_Libs/Dev/Render/RendererVertex.cpp index 4fbb93d..ff806ec 100644 --- a/Windows_Libs/Dev/Render/RendererVertex.cpp +++ b/Windows_Libs/Dev/Render/RendererVertex.cpp @@ -1,59 +1,51 @@ -#pragma once +#include "stdafx.h" #include "Renderer.h" -#include -#include -#include - -D3D11_PRIMITIVE_TOPOLOGY *Renderer::m_Topologies = nullptr; - void Renderer::DrawVertexBuffer(C4JRender::ePrimitiveType PrimitiveType, int count, ID3D11Buffer *buffer, C4JRender::eVertexType vType, C4JRender::ePixelShaderType psType) { - Renderer::Context &c = this->getContext(); + PROFILER_SCOPE("Renderer::DrawVertexBuffer", "DrawVertexBuffer", MP_RED2) + Renderer::Context &c = getContext(); ID3D11DeviceContext *d3d11 = c.m_pDeviceContext; int drawCount = count; bool indexed = false; - this->DrawVertexSetup(vType, psType, PrimitiveType, &drawCount, &indexed); - this->StateUpdate(); + + PROFILER_SCOPE("Renderer::DrawVertexBuffer", "DrawVertexSetup", MP_RED2) + DrawVertexSetup(vType, psType, PrimitiveType, &drawCount, &indexed); + StateUpdate(); const UINT stride = vertexStrideTable[vType]; const UINT offset = 0; d3d11->IASetVertexBuffers(0, 1, &buffer, &stride, &offset); if (indexed) - { d3d11->DrawIndexed(drawCount, 0, 0); - } else - { d3d11->Draw(count, 0); - } } void Renderer::DrawVertexSetup(C4JRender::eVertexType vType, C4JRender::ePixelShaderType psType, C4JRender::ePrimitiveType PrimitiveType, int *count, bool *indexed) { - Renderer::Context &c = this->getContext(); + PROFILER_SCOPE("Renderer::DrawVertexSetup", "DrawVertexSetup", MP_RED2) + Renderer::Context &c = getContext(); ID3D11DeviceContext *d3d11 = c.m_pDeviceContext; C4JRender::eVertexType effectiveVertexType = vType; if (effectiveVertexType == C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1 && c.lightingEnabled) - { effectiveVertexType = C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_LIT; - } if (effectiveVertexType != activeVertexType) { - d3d11->VSSetShader(vertexShaderTable[effectiveVertexType], nullptr, 0); + d3d11->VSSetShader(vertexShaderTable[effectiveVertexType], NULL, 0); d3d11->IASetInputLayout(inputLayoutTable[effectiveVertexType]); activeVertexType = effectiveVertexType; } if (psType != activePixelType) { - d3d11->PSSetShader(pixelShaderTable[psType], nullptr, 0); + d3d11->PSSetShader(pixelShaderTable[psType], NULL, 0); activePixelType = psType; } @@ -62,7 +54,7 @@ void Renderer::DrawVertexSetup(C4JRender::eVertexType vType, C4JRender::ePixelSh if (c.matrixDirty[MATRIX_MODE_MODELVIEW]) { d3d11->Map(c.m_modelViewMatrix, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); - std::memcpy(mapped.pData, this->MatrixGet(MATRIX_MODE_MODELVIEW), sizeof(DirectX::XMMATRIX)); + memcpy(mapped.pData, MatrixGet(MATRIX_MODE_MODELVIEW), sizeof(DirectX::XMMATRIX)); d3d11->Unmap(c.m_modelViewMatrix, 0); c.matrixDirty[MATRIX_MODE_MODELVIEW] = false; } @@ -70,7 +62,7 @@ void Renderer::DrawVertexSetup(C4JRender::eVertexType vType, C4JRender::ePixelSh if (c.matrixDirty[MATRIX_MODE_MODELVIEW_PROJECTION]) { d3d11->Map(c.m_projectionMatrix, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); - std::memcpy(mapped.pData, this->MatrixGet(MATRIX_MODE_MODELVIEW_PROJECTION), sizeof(DirectX::XMMATRIX)); + memcpy(mapped.pData, MatrixGet(MATRIX_MODE_MODELVIEW_PROJECTION), sizeof(DirectX::XMMATRIX)); d3d11->Unmap(c.m_projectionMatrix, 0); c.matrixDirty[MATRIX_MODE_MODELVIEW_PROJECTION] = false; } @@ -78,17 +70,17 @@ void Renderer::DrawVertexSetup(C4JRender::eVertexType vType, C4JRender::ePixelSh if (c.matrixDirty[MATRIX_MODE_MODELVIEW_TEXTURE]) { d3d11->Map(c.m_textureMatrix, 0, D3D11_MAP_WRITE_DISCARD, 0, &mapped); - std::memcpy(mapped.pData, this->MatrixGet(MATRIX_MODE_MODELVIEW_TEXTURE), sizeof(DirectX::XMMATRIX)); + memcpy(mapped.pData, MatrixGet(MATRIX_MODE_MODELVIEW_TEXTURE), sizeof(DirectX::XMMATRIX)); d3d11->Unmap(c.m_textureMatrix, 0); c.matrixDirty[MATRIX_MODE_MODELVIEW_TEXTURE] = false; } - this->UpdateFogState(); - this->UpdateViewportState(); - this->UpdateLightingState(); - this->UpdateTexGenState(); + UpdateFogState(); + UpdateViewportState(); + UpdateLightingState(); + UpdateTexGenState(); - d3d11->IASetPrimitiveTopology(m_Topologies[PrimitiveType]); + d3d11->IASetPrimitiveTopology(g_topologies[PrimitiveType]); if (PrimitiveType == C4JRender::PRIMITIVE_TYPE_QUAD_LIST) { @@ -106,24 +98,23 @@ void Renderer::DrawVertexSetup(C4JRender::eVertexType vType, C4JRender::ePixelSh return; } - d3d11->IASetIndexBuffer(nullptr, DXGI_FORMAT_R16_UINT, 0); + d3d11->IASetIndexBuffer(NULL, DXGI_FORMAT_R16_UINT, 0); *indexed = false; } void Renderer::DrawVertices(C4JRender::ePrimitiveType PrimitiveType, int count, void *vertices, C4JRender::eVertexType vType, C4JRender::ePixelShaderType psType) { - Renderer::Context &c = this->getContext(); + PROFILER_SCOPE("Renderer::DrawVertices", "DrawVertices", MP_RED2) + Renderer::Context &c = getContext(); ID3D11DeviceContext *d3d11 = c.m_pDeviceContext; Renderer::CommandBuffer *commandBuffer = c.commandBuffer; - if (commandBuffer != nullptr) + if (commandBuffer != NULL) { C4JRender::eVertexType effectiveVertexType = vType; if (effectiveVertexType == C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1 && c.lightingEnabled) - { effectiveVertexType = C4JRender::VERTEX_TYPE_PF3_TF2_CB4_NB4_XW1_LIT; - } c.recordingPrimitiveType = PrimitiveType; c.recordingVertexType = effectiveVertexType; @@ -134,43 +125,37 @@ void Renderer::DrawVertices(C4JRender::ePrimitiveType PrimitiveType, int count, int drawCount = count; bool indexed = false; - this->DrawVertexSetup(vType, psType, PrimitiveType, &drawCount, &indexed); + + PROFILER_SCOPE("Renderer::DrawVertices", "DrawVertexSetup", MP_RED2) + DrawVertexSetup(vType, psType, PrimitiveType, &drawCount, &indexed); const UINT stride = vertexStrideTable[vType]; const UINT vertexBytes = stride * static_cast(count); assert(vertexBytes <= Context::VERTEX_BUFFER_SIZE); - if (c.dynamicVertexOffset + vertexBytes > Context::VERTEX_BUFFER_SIZE) - { - c.dynamicVertexOffset = 0; - } + UINT vertexOffset = c.dynamicVertexOffset; + if (vertexOffset + vertexBytes > Context::VERTEX_BUFFER_SIZE) + vertexOffset = 0; D3D11_MAPPED_SUBRESOURCE mapped = {}; - const D3D11_MAP mapType = c.dynamicVertexOffset == 0 ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE; + const D3D11_MAP mapType = vertexOffset == 0 ? D3D11_MAP_WRITE_DISCARD : D3D11_MAP_WRITE_NO_OVERWRITE; const HRESULT hr = d3d11->Map(c.dynamicVertexBuffer, 0, mapType, 0, &mapped); - if (hr != 0) - { - std::printf("ERROR: 0x%x\n", static_cast(hr)); - } + if (FAILED(hr)) + printf("ERROR: 0x%x\n", static_cast(hr)); - std::memcpy(static_cast(mapped.pData) + c.dynamicVertexOffset, vertices, vertexBytes); + memcpy(reinterpret_cast(mapped.pData) + vertexOffset, vertices, vertexBytes); d3d11->Unmap(c.dynamicVertexBuffer, 0); - this->StateUpdate(); + StateUpdate(); ID3D11Buffer *dynamicBuffer = c.dynamicVertexBuffer; - const UINT vertexOffset = c.dynamicVertexOffset; d3d11->IASetVertexBuffers(0, 1, &dynamicBuffer, &stride, &vertexOffset); if (indexed) - { d3d11->DrawIndexed(drawCount, 0, 0); - } else - { d3d11->Draw(count, 0); - } - c.dynamicVertexOffset += vertexBytes; + c.dynamicVertexOffset = vertexOffset + vertexBytes; } diff --git a/Windows_Libs/Dev/Render/libpng/png.c b/Windows_Libs/Dev/Render/libpng/png.c index a0cad01..d429c52 100644 --- a/Windows_Libs/Dev/Render/libpng/png.c +++ b/Windows_Libs/Dev/Render/libpng/png.c @@ -1,9 +1,10 @@ + /* png.c - location for general purpose libpng functions * - * Copyright (c) 2018-2026 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -13,34 +14,7 @@ #include "pngpriv.h" /* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_6_55 Your_png_h_is_not_version_1_6_55; - -/* Sanity check the chunks definitions - PNG_KNOWN_CHUNKS from pngpriv.h and the - * corresponding macro definitions. This causes a compile time failure if - * something is wrong but generates no code. - * - * (1) The first check is that the PNG_CHUNK(cHNK, index) 'index' values must - * increment from 0 to the last value. - */ -#define PNG_CHUNK(cHNK, index) != (index) || ((index)+1) - -#if 0 PNG_KNOWN_CHUNKS < 0 -# error PNG_KNOWN_CHUNKS chunk definitions are not in order -#endif - -#undef PNG_CHUNK - -/* (2) The chunk name macros, png_cHNK, must all be valid and defined. Since - * this is a preprocessor test undefined pp-tokens come out as zero and will - * fail this test. - */ -#define PNG_CHUNK(cHNK, index) !PNG_CHUNK_NAME_VALID(png_ ## cHNK) || - -#if PNG_KNOWN_CHUNKS 0 -# error png_cHNK not defined for some known cHNK -#endif - -#undef PNG_CHUNK +typedef png_libpng_version_1_6_2 Your_png_h_is_not_version_1_6_2; /* Tells libpng that we have already handled the first "num_bytes" bytes * of the PNG file signature. If the PNG data is embedded into another @@ -52,20 +26,15 @@ typedef png_libpng_version_1_6_55 Your_png_h_is_not_version_1_6_55; void PNGAPI png_set_sig_bytes(png_structrp png_ptr, int num_bytes) { - unsigned int nb = (unsigned int)num_bytes; - png_debug(1, "in png_set_sig_bytes"); if (png_ptr == NULL) return; - if (num_bytes < 0) - nb = 0; - - if (nb > 8) + if (num_bytes > 8) png_error(png_ptr, "Too many bytes for PNG signature"); - png_ptr->sig_bytes = (png_byte)nb; + png_ptr->sig_bytes = (png_byte)(num_bytes < 0 ? 0 : num_bytes); } /* Checks whether the supplied bytes match the PNG signature. We allow @@ -77,48 +46,41 @@ png_set_sig_bytes(png_structrp png_ptr, int num_bytes) * PNG signature (this is the same behavior as strcmp, memcmp, etc). */ int PNGAPI -png_sig_cmp(png_const_bytep sig, size_t start, size_t num_to_check) +png_sig_cmp(png_const_bytep sig, png_size_t start, png_size_t num_to_check) { - static const png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; + png_byte png_signature[8] = {137, 80, 78, 71, 13, 10, 26, 10}; if (num_to_check > 8) num_to_check = 8; else if (num_to_check < 1) - return -1; + return (-1); if (start > 7) - return -1; + return (-1); if (start + num_to_check > 8) num_to_check = 8 - start; - return memcmp(&sig[start], &png_signature[start], num_to_check); + return ((int)(memcmp(&sig[start], &png_signature[start], num_to_check))); } -#endif /* READ */ +#endif /* PNG_READ_SUPPORTED */ #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) /* Function to allocate memory for zlib */ PNG_FUNCTION(voidpf /* PRIVATE */, -png_zalloc,(voidpf png_ptr, uInt items, uInt size), - PNG_ALLOCATED) +png_zalloc,(voidpf png_ptr, uInt items, uInt size),PNG_ALLOCATED) { png_alloc_size_t num_bytes = size; if (png_ptr == NULL) return NULL; - /* This check against overflow is vestigial, dating back from - * the old times when png_zalloc used to be an exported function. - * We're still keeping it here for now, as an extra-cautious - * prevention against programming errors inside zlib, although it - * should rather be a debug-time assertion instead. - */ - if (size != 0 && items >= (~(png_alloc_size_t)0) / size) + if (items >= (~(png_alloc_size_t)0)/size) { - png_warning(png_voidcast(png_structrp, png_ptr), - "Potential overflow in png_zalloc()"); + png_warning (png_voidcast(png_structrp, png_ptr), + "Potential overflow in png_zalloc()"); return NULL; } @@ -139,7 +101,7 @@ png_zfree(voidpf png_ptr, voidpf ptr) void /* PRIVATE */ png_reset_crc(png_structrp png_ptr) { - /* The cast is safe because the crc is a 32-bit value. */ + /* The cast is safe because the crc is a 32 bit value. */ png_ptr->crc = (png_uint_32)crc32(0, Z_NULL, 0); } @@ -149,11 +111,11 @@ png_reset_crc(png_structrp png_ptr) * trouble of calculating it. */ void /* PRIVATE */ -png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, size_t length) +png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, png_size_t length) { int need_crc = 1; - if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)) { if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) @@ -162,26 +124,24 @@ png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, size_t length) else /* critical */ { - if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) need_crc = 0; } /* 'uLong' is defined in zlib.h as unsigned long; this means that on some - * systems it is a 64-bit value. crc32, however, returns 32 bits so the + * systems it is a 64 bit value. crc32, however, returns 32 bits so the * following cast is safe. 'uInt' may be no more than 16 bits, so it is * necessary to perform a loop here. */ - if (need_crc != 0 && length > 0) + if (need_crc && length > 0) { uLong crc = png_ptr->crc; /* Should never issue a warning */ do { uInt safe_length = (uInt)length; -#ifndef __COVERITY__ if (safe_length == 0) safe_length = (uInt)-1; /* evil, but safe */ -#endif crc = crc32(crc, ptr, safe_length); @@ -205,47 +165,52 @@ png_calculate_crc(png_structrp png_ptr, png_const_bytep ptr, size_t length) int png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver) { - /* Libpng versions 1.0.0 and later are binary compatible if the version - * string matches through the second '.'; we must recompile any - * applications that use any older library version. - */ - - if (user_png_ver != NULL) + if (user_png_ver) { - int i = -1; - int found_dots = 0; + int i = 0; do { - i++; - if (user_png_ver[i] != PNG_LIBPNG_VER_STRING[i]) + if (user_png_ver[i] != png_libpng_ver[i]) png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - if (user_png_ver[i] == '.') - found_dots++; - } while (found_dots < 2 && user_png_ver[i] != 0 && - PNG_LIBPNG_VER_STRING[i] != 0); + } while (png_libpng_ver[i++]); } else png_ptr->flags |= PNG_FLAG_LIBRARY_MISMATCH; - if ((png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) != 0) + if (png_ptr->flags & PNG_FLAG_LIBRARY_MISMATCH) { + /* Libpng 0.90 and later are binary incompatible with libpng 0.89, so + * we must recompile any applications that use any older library version. + * For versions after libpng 1.0, we will be compatible, so we need + * only check the first and third digits (note that when we reach version + * 1.10 we will need to check the fourth symbol, namely user_png_ver[3]). + */ + if (user_png_ver == NULL || user_png_ver[0] != png_libpng_ver[0] || + (user_png_ver[0] == '1' && (user_png_ver[2] != png_libpng_ver[2] || + user_png_ver[3] != png_libpng_ver[3])) || + (user_png_ver[0] == '0' && user_png_ver[2] < '9')) + { #ifdef PNG_WARNINGS_SUPPORTED - size_t pos = 0; - char m[128]; + size_t pos = 0; + char m[128]; - pos = png_safecat(m, (sizeof m), pos, - "Application built with libpng-"); - pos = png_safecat(m, (sizeof m), pos, user_png_ver); - pos = png_safecat(m, (sizeof m), pos, " but running with "); - pos = png_safecat(m, (sizeof m), pos, PNG_LIBPNG_VER_STRING); - PNG_UNUSED(pos) + pos = png_safecat(m, (sizeof m), pos, + "Application built with libpng-"); + pos = png_safecat(m, (sizeof m), pos, user_png_ver); + pos = png_safecat(m, (sizeof m), pos, " but running with "); + pos = png_safecat(m, (sizeof m), pos, png_libpng_ver); - png_warning(png_ptr, m); + png_warning(png_ptr, m); #endif - return 0; +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + png_ptr->flags = 0; +#endif + + return 0; + } } /* Success return. */ @@ -258,8 +223,7 @@ png_user_version_check(png_structrp png_ptr, png_const_charp user_png_ver) PNG_FUNCTION(png_structp /* PRIVATE */, png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn), - PNG_ALLOCATED) + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) { png_struct create_struct; # ifdef PNG_SETJMP_SUPPORTED @@ -272,23 +236,21 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, */ memset(&create_struct, 0, (sizeof create_struct)); + /* Added at libpng-1.2.6 */ # ifdef PNG_USER_LIMITS_SUPPORTED create_struct.user_width_max = PNG_USER_WIDTH_MAX; create_struct.user_height_max = PNG_USER_HEIGHT_MAX; # ifdef PNG_USER_CHUNK_CACHE_MAX - create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; + /* Added at libpng-1.2.43 and 1.4.0 */ + create_struct.user_chunk_cache_max = PNG_USER_CHUNK_CACHE_MAX; # endif -# if PNG_USER_CHUNK_MALLOC_MAX > 0 /* default to compile-time limit */ - create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; - - /* No compile-time limit, so initialize to the system limit: */ -# elif defined PNG_MAX_MALLOC_64K /* legacy system limit */ - create_struct.user_chunk_malloc_max = 65536U; - -# else /* modern system limit SIZE_MAX (C99) */ - create_struct.user_chunk_malloc_max = PNG_SIZE_MAX; +# ifdef PNG_USER_CHUNK_MALLOC_MAX + /* Added at libpng-1.2.43 and 1.4.1, required only for read but exists + * in png_struct regardless. + */ + create_struct.user_chunk_malloc_max = PNG_USER_CHUNK_MALLOC_MAX; # endif # endif @@ -297,10 +259,6 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, */ # ifdef PNG_USER_MEM_SUPPORTED png_set_mem_fn(&create_struct, mem_ptr, malloc_fn, free_fn); -# else - PNG_UNUSED(mem_ptr) - PNG_UNUSED(malloc_fn) - PNG_UNUSED(free_fn) # endif /* (*error_fn) can return control to the caller after the error_ptr is set, @@ -312,9 +270,7 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, # ifdef PNG_SETJMP_SUPPORTED if (!setjmp(create_jmp_buf)) -# endif { -# ifdef PNG_SETJMP_SUPPORTED /* Temporarily fake out the longjmp information until we have * successfully completed this function. This only works if we have * setjmp() support compiled in, but it is safe - this stuff should @@ -323,13 +279,15 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, create_struct.jmp_buf_ptr = &create_jmp_buf; create_struct.jmp_buf_size = 0; /*stack allocation*/ create_struct.longjmp_fn = longjmp; +# else + { # endif /* Call the general version checker (shared with read and write code): */ - if (png_user_version_check(&create_struct, user_png_ver) != 0) + if (png_user_version_check(&create_struct, user_png_ver)) { png_structrp png_ptr = png_voidcast(png_structrp, - png_malloc_warn(&create_struct, (sizeof *png_ptr))); + png_malloc_warn(&create_struct, (sizeof *png_ptr))); if (png_ptr != NULL) { @@ -341,10 +299,10 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, create_struct.zstream.opaque = png_ptr; # ifdef PNG_SETJMP_SUPPORTED - /* Eliminate the local error handling: */ - create_struct.jmp_buf_ptr = NULL; - create_struct.jmp_buf_size = 0; - create_struct.longjmp_fn = 0; + /* Eliminate the local error handling: */ + create_struct.jmp_buf_ptr = NULL; + create_struct.jmp_buf_size = 0; + create_struct.longjmp_fn = 0; # endif *png_ptr = create_struct; @@ -363,8 +321,7 @@ png_create_png_struct,(png_const_charp user_png_ver, png_voidp error_ptr, /* Allocate the memory for an info_struct for the application. */ PNG_FUNCTION(png_infop,PNGAPI -png_create_info_struct,(png_const_structrp png_ptr), - PNG_ALLOCATED) +png_create_info_struct,(png_const_structrp png_ptr),PNG_ALLOCATED) { png_inforp info_ptr; @@ -379,7 +336,7 @@ png_create_info_struct,(png_const_structrp png_ptr), * has always been done in 'example.c'. */ info_ptr = png_voidcast(png_inforp, png_malloc_base(png_ptr, - (sizeof *info_ptr))); + (sizeof *info_ptr))); if (info_ptr != NULL) memset(info_ptr, 0, (sizeof *info_ptr)); @@ -434,8 +391,8 @@ png_destroy_info_struct(png_const_structrp png_ptr, png_infopp info_ptr_ptr) * those cases where it does anything other than a memset. */ PNG_FUNCTION(void,PNGAPI -png_info_init_3,(png_infopp ptr_ptr, size_t png_info_struct_size), - PNG_DEPRECATED) +png_info_init_3,(png_infopp ptr_ptr, png_size_t png_info_struct_size), + PNG_DEPRECATED) { png_inforp info_ptr = *ptr_ptr; @@ -450,9 +407,7 @@ png_info_init_3,(png_infopp ptr_ptr, size_t png_info_struct_size), /* The following line is why this API should not be used: */ free(info_ptr); info_ptr = png_voidcast(png_inforp, png_malloc_base(NULL, - (sizeof *info_ptr))); - if (info_ptr == NULL) - return; + (sizeof *info_ptr))); *ptr_ptr = info_ptr; } @@ -460,9 +415,10 @@ png_info_init_3,(png_infopp ptr_ptr, size_t png_info_struct_size), memset(info_ptr, 0, (sizeof *info_ptr)); } +/* The following API is not called internally */ void PNGAPI png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr, - int freer, png_uint_32 mask) + int freer, png_uint_32 mask) { png_debug(1, "in png_data_freer"); @@ -481,7 +437,7 @@ png_data_freer(png_const_structrp png_ptr, png_inforp info_ptr, void PNGAPI png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, - int num) + int num) { png_debug(1, "in png_free_data"); @@ -490,44 +446,42 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, #ifdef PNG_TEXT_SUPPORTED /* Free text item num or (if num == -1) all text items */ - if (info_ptr->text != NULL && - ((mask & PNG_FREE_TEXT) & info_ptr->free_me) != 0) + if ((mask & PNG_FREE_TEXT) & info_ptr->free_me) { if (num != -1) { - png_free(png_ptr, info_ptr->text[num].key); - info_ptr->text[num].key = NULL; + if (info_ptr->text && info_ptr->text[num].key) + { + png_free(png_ptr, info_ptr->text[num].key); + info_ptr->text[num].key = NULL; + } } else { int i; - for (i = 0; i < info_ptr->num_text; i++) - png_free(png_ptr, info_ptr->text[i].key); - + png_free_data(png_ptr, info_ptr, PNG_FREE_TEXT, i); png_free(png_ptr, info_ptr->text); info_ptr->text = NULL; - info_ptr->num_text = 0; - info_ptr->max_text = 0; + info_ptr->num_text=0; } } #endif #ifdef PNG_tRNS_SUPPORTED /* Free any tRNS entry */ - if (((mask & PNG_FREE_TRNS) & info_ptr->free_me) != 0) + if ((mask & PNG_FREE_TRNS) & info_ptr->free_me) { - info_ptr->valid &= ~PNG_INFO_tRNS; png_free(png_ptr, info_ptr->trans_alpha); info_ptr->trans_alpha = NULL; - info_ptr->num_trans = 0; + info_ptr->valid &= ~PNG_INFO_tRNS; } #endif #ifdef PNG_sCAL_SUPPORTED /* Free any sCAL entry */ - if (((mask & PNG_FREE_SCAL) & info_ptr->free_me) != 0) + if ((mask & PNG_FREE_SCAL) & info_ptr->free_me) { png_free(png_ptr, info_ptr->scal_s_width); png_free(png_ptr, info_ptr->scal_s_height); @@ -539,20 +493,20 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, #ifdef PNG_pCAL_SUPPORTED /* Free any pCAL entry */ - if (((mask & PNG_FREE_PCAL) & info_ptr->free_me) != 0) + if ((mask & PNG_FREE_PCAL) & info_ptr->free_me) { png_free(png_ptr, info_ptr->pcal_purpose); png_free(png_ptr, info_ptr->pcal_units); info_ptr->pcal_purpose = NULL; info_ptr->pcal_units = NULL; - if (info_ptr->pcal_params != NULL) { - int i; - + unsigned int i; for (i = 0; i < info_ptr->pcal_nparams; i++) + { png_free(png_ptr, info_ptr->pcal_params[i]); - + info_ptr->pcal_params[i] = NULL; + } png_free(png_ptr, info_ptr->pcal_params); info_ptr->pcal_params = NULL; } @@ -562,7 +516,7 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, #ifdef PNG_iCCP_SUPPORTED /* Free any profile entry */ - if (((mask & PNG_FREE_ICCP) & info_ptr->free_me) != 0) + if ((mask & PNG_FREE_ICCP) & info_ptr->free_me) { png_free(png_ptr, info_ptr->iccp_name); png_free(png_ptr, info_ptr->iccp_profile); @@ -574,75 +528,68 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, #ifdef PNG_sPLT_SUPPORTED /* Free a given sPLT entry, or (if num == -1) all sPLT entries */ - if (info_ptr->splt_palettes != NULL && - ((mask & PNG_FREE_SPLT) & info_ptr->free_me) != 0) + if ((mask & PNG_FREE_SPLT) & info_ptr->free_me) { if (num != -1) { - png_free(png_ptr, info_ptr->splt_palettes[num].name); - png_free(png_ptr, info_ptr->splt_palettes[num].entries); - info_ptr->splt_palettes[num].name = NULL; - info_ptr->splt_palettes[num].entries = NULL; + if (info_ptr->splt_palettes) + { + png_free(png_ptr, info_ptr->splt_palettes[num].name); + png_free(png_ptr, info_ptr->splt_palettes[num].entries); + info_ptr->splt_palettes[num].name = NULL; + info_ptr->splt_palettes[num].entries = NULL; + } } else { - int i; - - for (i = 0; i < info_ptr->splt_palettes_num; i++) + if (info_ptr->splt_palettes_num) { - png_free(png_ptr, info_ptr->splt_palettes[i].name); - png_free(png_ptr, info_ptr->splt_palettes[i].entries); - } + int i; + for (i = 0; i < info_ptr->splt_palettes_num; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_SPLT, (int)i); - png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes = NULL; - info_ptr->splt_palettes_num = 0; + png_free(png_ptr, info_ptr->splt_palettes); + info_ptr->splt_palettes = NULL; + info_ptr->splt_palettes_num = 0; + } info_ptr->valid &= ~PNG_INFO_sPLT; } } #endif #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED - if (info_ptr->unknown_chunks != NULL && - ((mask & PNG_FREE_UNKN) & info_ptr->free_me) != 0) + if ((mask & PNG_FREE_UNKN) & info_ptr->free_me) { if (num != -1) { - png_free(png_ptr, info_ptr->unknown_chunks[num].data); - info_ptr->unknown_chunks[num].data = NULL; + if (info_ptr->unknown_chunks) + { + png_free(png_ptr, info_ptr->unknown_chunks[num].data); + info_ptr->unknown_chunks[num].data = NULL; + } } else { int i; - for (i = 0; i < info_ptr->unknown_chunks_num; i++) - png_free(png_ptr, info_ptr->unknown_chunks[i].data); + if (info_ptr->unknown_chunks_num) + { + for (i = 0; i < info_ptr->unknown_chunks_num; i++) + png_free_data(png_ptr, info_ptr, PNG_FREE_UNKN, (int)i); - png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = NULL; - info_ptr->unknown_chunks_num = 0; + png_free(png_ptr, info_ptr->unknown_chunks); + info_ptr->unknown_chunks = NULL; + info_ptr->unknown_chunks_num = 0; + } } } #endif -#ifdef PNG_eXIf_SUPPORTED - /* Free any eXIf entry */ - if (((mask & PNG_FREE_EXIF) & info_ptr->free_me) != 0) - { - if (info_ptr->exif) - { - png_free(png_ptr, info_ptr->exif); - info_ptr->exif = NULL; - } - info_ptr->valid &= ~PNG_INFO_eXIf; - } -#endif - #ifdef PNG_hIST_SUPPORTED /* Free any hIST entry */ - if (((mask & PNG_FREE_HIST) & info_ptr->free_me) != 0) + if ((mask & PNG_FREE_HIST) & info_ptr->free_me) { png_free(png_ptr, info_ptr->hist); info_ptr->hist = NULL; @@ -651,7 +598,7 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, #endif /* Free any PLTE entry that was internally allocated */ - if (((mask & PNG_FREE_PLTE) & info_ptr->free_me) != 0) + if ((mask & PNG_FREE_PLTE) & info_ptr->free_me) { png_free(png_ptr, info_ptr->palette); info_ptr->palette = NULL; @@ -661,14 +608,16 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, #ifdef PNG_INFO_IMAGE_SUPPORTED /* Free any image bits attached to the info structure */ - if (((mask & PNG_FREE_ROWS) & info_ptr->free_me) != 0) + if ((mask & PNG_FREE_ROWS) & info_ptr->free_me) { - if (info_ptr->row_pointers != NULL) + if (info_ptr->row_pointers) { png_uint_32 row; for (row = 0; row < info_ptr->height; row++) + { png_free(png_ptr, info_ptr->row_pointers[row]); - + info_ptr->row_pointers[row] = NULL; + } png_free(png_ptr, info_ptr->row_pointers); info_ptr->row_pointers = NULL; } @@ -681,7 +630,7 @@ png_free_data(png_const_structrp png_ptr, png_inforp info_ptr, png_uint_32 mask, info_ptr->free_me &= ~mask; } -#endif /* READ || WRITE */ +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ /* This function returns a pointer to the io_ptr associated with the user * functions. The application should free any memory associated with this @@ -691,9 +640,9 @@ png_voidp PNGAPI png_get_io_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) - return NULL; + return (NULL); - return png_ptr->io_ptr; + return (png_ptr->io_ptr); } #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) @@ -705,7 +654,7 @@ png_get_io_ptr(png_const_structrp png_ptr) * function of your own because "FILE *" isn't necessarily available. */ void PNGAPI -png_init_io(png_structrp png_ptr, FILE *fp) +png_init_io(png_structrp png_ptr, png_FILE_p fp) { png_debug(1, "in png_init_io"); @@ -716,23 +665,22 @@ png_init_io(png_structrp png_ptr, FILE *fp) } # endif -# ifdef PNG_SAVE_INT_32_SUPPORTED -/* PNG signed integers are saved in 32-bit 2's complement format. ANSI C-90 - * defines a cast of a signed integer to an unsigned integer either to preserve - * the value, if it is positive, or to calculate: - * - * (UNSIGNED_MAX+1) + integer - * - * Where UNSIGNED_MAX is the appropriate maximum unsigned value, so when the - * negative integral value is added the result will be an unsigned value - * corresponding to the 2's complement representation. +#ifdef PNG_SAVE_INT_32_SUPPORTED +/* The png_save_int_32 function assumes integers are stored in two's + * complement format. If this isn't the case, then this routine needs to + * be modified to write data in two's complement format. Note that, + * the following works correctly even if png_int_32 has more than 32 bits + * (compare the more complex code required on read for sign extension.) */ void PNGAPI png_save_int_32(png_bytep buf, png_int_32 i) { - png_save_uint_32(buf, (png_uint_32)i); + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); } -# endif +#endif # ifdef PNG_TIME_RFC1123_SUPPORTED /* Convert the supplied time into an RFC 1123 string suitable for use in @@ -741,7 +689,7 @@ png_save_int_32(png_bytep buf, png_int_32 i) int PNGAPI png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime) { - static const char short_months[12][4] = + static PNG_CONST char short_months[12][4] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; @@ -757,7 +705,7 @@ png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime) { size_t pos = 0; - char number_buf[5] = {0, 0, 0, 0, 0}; /* enough for a four-digit year */ + char number_buf[5]; /* enough for a four-digit year */ # define APPEND_STRING(string) pos = png_safecat(out, 29, pos, (string)) # define APPEND_NUMBER(format, value)\ @@ -776,7 +724,6 @@ png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime) APPEND(':'); APPEND_NUMBER(PNG_NUMBER_FORMAT_02u, (unsigned)ptime->second); APPEND_STRING(" +0000"); /* This reliably terminates the buffer */ - PNG_UNUSED (pos) # undef APPEND # undef APPEND_NUMBER @@ -786,7 +733,7 @@ png_convert_to_rfc1123_buffer(char out[29], png_const_timep ptime) return 1; } -# if PNG_LIBPNG_VER < 10700 +# if PNG_LIBPNG_VER < 10700 /* To do: remove the following from libpng-1.7 */ /* Original API that uses a private buffer in png_struct. * Deprecated because it causes png_struct to carry a spurious temporary @@ -798,7 +745,7 @@ png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime) if (png_ptr != NULL) { /* The only failure above if png_ptr != NULL is from an invalid ptime */ - if (png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime) == 0) + if (!png_convert_to_rfc1123_buffer(png_ptr->time_buffer, ptime)) png_warning(png_ptr, "Ignoring invalid time value"); else @@ -807,10 +754,10 @@ png_convert_to_rfc1123(png_structrp png_ptr, png_const_timep ptime) return NULL; } -# endif /* LIBPNG_VER < 10700 */ -# endif /* TIME_RFC1123 */ +# endif +# endif /* PNG_TIME_RFC1123_SUPPORTED */ -#endif /* READ || WRITE */ +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ png_const_charp PNGAPI png_get_copyright(png_const_structrp png_ptr) @@ -819,14 +766,19 @@ png_get_copyright(png_const_structrp png_ptr) #ifdef PNG_STRING_COPYRIGHT return PNG_STRING_COPYRIGHT #else +# ifdef __STDC__ return PNG_STRING_NEWLINE \ - "libpng version 1.6.55" PNG_STRING_NEWLINE \ - "Copyright (c) 2018-2026 Cosmin Truta" PNG_STRING_NEWLINE \ - "Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson" \ - PNG_STRING_NEWLINE \ - "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ - "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ - PNG_STRING_NEWLINE; + "libpng version 1.6.2 - April 25, 2013" PNG_STRING_NEWLINE \ + "Copyright (c) 1998-2013 Glenn Randers-Pehrson" PNG_STRING_NEWLINE \ + "Copyright (c) 1996-1997 Andreas Dilger" PNG_STRING_NEWLINE \ + "Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc." \ + PNG_STRING_NEWLINE; +# else + return "libpng version 1.6.2 - April 25, 2013\ + Copyright (c) 1998-2013 Glenn Randers-Pehrson\ + Copyright (c) 1996-1997 Andreas Dilger\ + Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc."; +# endif #endif } @@ -861,71 +813,14 @@ png_get_header_version(png_const_structrp png_ptr) #ifdef __STDC__ return PNG_HEADER_VERSION_STRING # ifndef PNG_READ_SUPPORTED - " (NO READ SUPPORT)" + " (NO READ SUPPORT)" # endif - PNG_STRING_NEWLINE; + PNG_STRING_NEWLINE; #else return PNG_HEADER_VERSION_STRING; #endif } -#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED -/* NOTE: this routine is not used internally! */ -/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth - * large of png_color. This lets grayscale images be treated as - * paletted. Most useful for gamma correction and simplification - * of code. This API is not used internally. - */ -void PNGAPI -png_build_grayscale_palette(int bit_depth, png_colorp palette) -{ - int num_palette; - int color_inc; - int i; - int v; - - png_debug(1, "in png_do_build_grayscale_palette"); - - if (palette == NULL) - return; - - switch (bit_depth) - { - case 1: - num_palette = 2; - color_inc = 0xff; - break; - - case 2: - num_palette = 4; - color_inc = 0x55; - break; - - case 4: - num_palette = 16; - color_inc = 0x11; - break; - - case 8: - num_palette = 256; - color_inc = 1; - break; - - default: - num_palette = 0; - color_inc = 0; - break; - } - - for (i = 0, v = 0; i < num_palette; i++, v += color_inc) - { - palette[i].red = (png_byte)(v & 0xff); - palette[i].green = (png_byte)(v & 0xff); - palette[i].blue = (png_byte)(v & 0xff); - } -} -#endif - #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED int PNGAPI png_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name) @@ -941,13 +836,13 @@ png_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name) /* The code is the fifth byte after each four byte string. Historically this * code was always searched from the end of the list, this is no longer - * necessary because the 'set' routine handles duplicate entries correctly. + * necessary because the 'set' routine handles duplicate entries correcty. */ do /* num_chunk_list > 0, so at least one */ { p -= 5; - if (memcmp(chunk_name, p, 4) == 0) + if (!memcmp(chunk_name, p, 4)) return p[4]; } while (p > p_end); @@ -960,8 +855,7 @@ png_handle_as_unknown(png_const_structrp png_ptr, png_const_bytep chunk_name) return PNG_HANDLE_CHUNK_AS_DEFAULT; } -#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ - defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED int /* PRIVATE */ png_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name) { @@ -970,7 +864,7 @@ png_chunk_unknown_handling(png_const_structrp png_ptr, png_uint_32 chunk_name) PNG_CSTRING_FROM_CHUNK(chunk_string, chunk_name); return png_handle_as_unknown(png_ptr, chunk_string); } -#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ +#endif /* READ_UNKNOWN_CHUNKS */ #endif /* SET_UNKNOWN_CHUNKS */ #ifdef PNG_READ_SUPPORTED @@ -982,18 +876,20 @@ png_reset_zstream(png_structrp png_ptr) return Z_STREAM_ERROR; /* WARNING: this resets the window bits to the maximum! */ - return inflateReset(&png_ptr->zstream); + return (inflateReset(&png_ptr->zstream)); } -#endif /* READ */ +#endif /* PNG_READ_SUPPORTED */ /* This function was added to libpng-1.0.7 */ png_uint_32 PNGAPI png_access_version_number(void) { /* Version of *.c files used when building libpng */ - return (png_uint_32)PNG_LIBPNG_VER; + return((png_uint_32)PNG_LIBPNG_VER); } + + #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) /* Ensure that png_ptr->zstream.msg holds some appropriate error message string. * If it doesn't 'ret' is used to set it to something appropriate, even in cases @@ -1065,169 +961,227 @@ png_zstream_error(png_structrp png_ptr, int ret) } } -#ifdef PNG_COLORSPACE_SUPPORTED -static png_int_32 -png_fp_add(png_int_32 addend0, png_int_32 addend1, int *error) -{ - /* Safely add two fixed point values setting an error flag and returning 0.5 - * on overflow. - * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore - * relying on addition of two positive values producing a negative one is not - * safe. - */ - if (addend0 > 0) - { - if (0x7fffffff - addend0 >= addend1) - return addend0+addend1; - } - else if (addend0 < 0) - { - if (-0x7fffffff - addend0 <= addend1) - return addend0+addend1; - } - else - return addend1; - - *error = 1; - return PNG_FP_1/2; -} - -static png_int_32 -png_fp_sub(png_int_32 addend0, png_int_32 addend1, int *error) -{ - /* As above but calculate addend0-addend1. */ - if (addend1 > 0) - { - if (-0x7fffffff + addend1 <= addend0) - return addend0-addend1; - } - else if (addend1 < 0) - { - if (0x7fffffff + addend1 >= addend0) - return addend0-addend1; - } - else - return addend0; - - *error = 1; - return PNG_FP_1/2; -} +/* png_convert_size: a PNGAPI but no longer in png.h, so deleted + * at libpng 1.5.5! + */ +/* Added at libpng version 1.2.34 and 1.4.0 (moved from pngset.c) */ +#ifdef PNG_GAMMA_SUPPORTED /* always set if COLORSPACE */ static int -png_safe_add(png_int_32 *addend0_and_result, png_int_32 addend1, - png_int_32 addend2) -{ - /* Safely add three integers. Returns 0 on success, 1 on overflow. Does not - * set the result on overflow. +png_colorspace_check_gamma(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA, int from) + /* This is called to check a new gamma value against an existing one. The + * routine returns false if the new gamma value should not be written. + * + * 'from' says where the new gamma value comes from: + * + * 0: the new gamma value is the libpng estimate for an ICC profile + * 1: the new gamma value comes from a gAMA chunk + * 2: the new gamma value comes from an sRGB chunk */ - int error = 0; - int result = png_fp_add(*addend0_and_result, - png_fp_add(addend1, addend2, &error), - &error); - if (!error) *addend0_and_result = result; - return error; +{ + png_fixed_point gtest; + + if ((colorspace->flags & PNG_COLORSPACE_HAVE_GAMMA) != 0 && + (!png_muldiv(>est, colorspace->gamma, PNG_FP_1, gAMA) || + png_gamma_significant(gtest))) + { + /* Either this is an sRGB image, in which case the calculated gamma + * approximation should match, or this is an image with a profile and the + * value libpng calculates for the gamma of the profile does not match the + * value recorded in the file. The former, sRGB, case is an error, the + * latter is just a warning. + */ + if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0 || from == 2) + { + png_chunk_report(png_ptr, "gamma value does not match sRGB", + PNG_CHUNK_ERROR); + /* Do not overwrite an sRGB value */ + return from == 2; + } + + else /* sRGB tag not involved */ + { + png_chunk_report(png_ptr, "gamma value does not match libpng estimate", + PNG_CHUNK_WARNING); + return from == 1; + } + } + + return 1; } +void /* PRIVATE */ +png_colorspace_set_gamma(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA) +{ + /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't + * occur. Since the fixed point representation is assymetrical it is + * possible for 1/gamma to overflow the limit of 21474 and this means the + * gamma value must be at least 5/100000 and hence at most 20000.0. For + * safety the limits here are a little narrower. The values are 0.00016 to + * 6250.0, which are truly ridiculous gamma values (and will produce + * displays that are all black or all white.) + * + * In 1.6.0 this test replaces the ones in pngrutil.c, in the gAMA chunk + * handling code, which only required the value to be >0. + */ + png_const_charp errmsg; + + if (gAMA < 16 || gAMA > 625000000) + errmsg = "gamma value out of range"; + +# ifdef PNG_READ_gAMA_SUPPORTED + /* Allow the application to set the gamma value more than once */ + else if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && + (colorspace->flags & PNG_COLORSPACE_FROM_gAMA) != 0) + errmsg = "duplicate"; +# endif + + /* Do nothing if the colorspace is already invalid */ + else if (colorspace->flags & PNG_COLORSPACE_INVALID) + return; + + else + { + if (png_colorspace_check_gamma(png_ptr, colorspace, gAMA, 1/*from gAMA*/)) + { + /* Store this gamma value. */ + colorspace->gamma = gAMA; + colorspace->flags |= + (PNG_COLORSPACE_HAVE_GAMMA | PNG_COLORSPACE_FROM_gAMA); + } + + /* At present if the check_gamma test fails the gamma of the colorspace is + * not updated however the colorspace is not invalidated. This + * corresponds to the case where the existing gamma comes from an sRGB + * chunk or profile. An error message has already been output. + */ + return; + } + + /* Error exit - errmsg has been set. */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_chunk_report(png_ptr, errmsg, PNG_CHUNK_WRITE_ERROR); +} + +void /* PRIVATE */ +png_colorspace_sync_info(png_const_structrp png_ptr, png_inforp info_ptr) +{ + if (info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) + { + /* Everything is invalid */ + info_ptr->valid &= ~(PNG_INFO_gAMA|PNG_INFO_cHRM|PNG_INFO_sRGB| + PNG_INFO_iCCP); + +# ifdef PNG_COLORSPACE_SUPPORTED + /* Clean up the iCCP profile now if it won't be used. */ + png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, -1/*not used*/); +# else + PNG_UNUSED(png_ptr) +# endif + } + + else + { +# ifdef PNG_COLORSPACE_SUPPORTED + /* Leave the INFO_iCCP flag set if the pngset.c code has already set + * it; this allows a PNG to contain a profile which matches sRGB and + * yet still have that profile retrievable by the application. + */ + if (info_ptr->colorspace.flags & PNG_COLORSPACE_MATCHES_sRGB) + info_ptr->valid |= PNG_INFO_sRGB; + + else + info_ptr->valid &= ~PNG_INFO_sRGB; + + if (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) + info_ptr->valid |= PNG_INFO_cHRM; + + else + info_ptr->valid &= ~PNG_INFO_cHRM; +# endif + + if (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) + info_ptr->valid |= PNG_INFO_gAMA; + + else + info_ptr->valid &= ~PNG_INFO_gAMA; + } +} + +#ifdef PNG_READ_SUPPORTED +void /* PRIVATE */ +png_colorspace_sync(png_const_structrp png_ptr, png_inforp info_ptr) +{ + if (info_ptr == NULL) /* reduce code size; check here not in the caller */ + return; + + info_ptr->colorspace = png_ptr->colorspace; + png_colorspace_sync_info(png_ptr, info_ptr); +} +#endif +#endif + +#ifdef PNG_COLORSPACE_SUPPORTED /* Added at libpng-1.5.5 to support read and write of true CIEXYZ values for * cHRM, as opposed to using chromaticities. These internal APIs return * non-zero on a parameter error. The X, Y and Z values are required to be * positive and less than 1.0. */ -int /* PRIVATE */ +static int png_xy_from_XYZ(png_xy *xy, const png_XYZ *XYZ) { - /* NOTE: returns 0 on success, 1 means error. */ - png_int_32 d, dred, dgreen, dblue, dwhite, whiteX, whiteY; + png_int_32 d, dwhite, whiteX, whiteY; - /* 'd' in each of the blocks below is just X+Y+Z for each component, - * x, y and z are X,Y,Z/(X+Y+Z). - */ - d = XYZ->red_X; - if (png_safe_add(&d, XYZ->red_Y, XYZ->red_Z)) - return 1; - dred = d; - if (png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, dred) == 0) - return 1; - if (png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, dred) == 0) - return 1; - - d = XYZ->green_X; - if (png_safe_add(&d, XYZ->green_Y, XYZ->green_Z)) - return 1; - dgreen = d; - if (png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, dgreen) == 0) - return 1; - if (png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, dgreen) == 0) - return 1; - - d = XYZ->blue_X; - if (png_safe_add(&d, XYZ->blue_Y, XYZ->blue_Z)) - return 1; - dblue = d; - if (png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, dblue) == 0) - return 1; - if (png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, dblue) == 0) - return 1; - - /* The reference white is simply the sum of the end-point (X,Y,Z) vectors so - * the fillowing calculates (X+Y+Z) of the reference white (media white, - * encoding white) itself: - */ - d = dblue; - if (png_safe_add(&d, dred, dgreen)) - return 1; + d = XYZ->red_X + XYZ->red_Y + XYZ->red_Z; + if (!png_muldiv(&xy->redx, XYZ->red_X, PNG_FP_1, d)) return 1; + if (!png_muldiv(&xy->redy, XYZ->red_Y, PNG_FP_1, d)) return 1; dwhite = d; + whiteX = XYZ->red_X; + whiteY = XYZ->red_Y; - /* Find the white X,Y values from the sum of the red, green and blue X,Y - * values. + d = XYZ->green_X + XYZ->green_Y + XYZ->green_Z; + if (!png_muldiv(&xy->greenx, XYZ->green_X, PNG_FP_1, d)) return 1; + if (!png_muldiv(&xy->greeny, XYZ->green_Y, PNG_FP_1, d)) return 1; + dwhite += d; + whiteX += XYZ->green_X; + whiteY += XYZ->green_Y; + + d = XYZ->blue_X + XYZ->blue_Y + XYZ->blue_Z; + if (!png_muldiv(&xy->bluex, XYZ->blue_X, PNG_FP_1, d)) return 1; + if (!png_muldiv(&xy->bluey, XYZ->blue_Y, PNG_FP_1, d)) return 1; + dwhite += d; + whiteX += XYZ->blue_X; + whiteY += XYZ->blue_Y; + + /* The reference white is simply the sum of the end-point (X,Y,Z) vectors, + * thus: */ - d = XYZ->red_X; - if (png_safe_add(&d, XYZ->green_X, XYZ->blue_X)) - return 1; - whiteX = d; - - d = XYZ->red_Y; - if (png_safe_add(&d, XYZ->green_Y, XYZ->blue_Y)) - return 1; - whiteY = d; - - if (png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite) == 0) - return 1; - if (png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite) == 0) - return 1; + if (!png_muldiv(&xy->whitex, whiteX, PNG_FP_1, dwhite)) return 1; + if (!png_muldiv(&xy->whitey, whiteY, PNG_FP_1, dwhite)) return 1; return 0; } -int /* PRIVATE */ +static int png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) { - /* NOTE: returns 0 on success, 1 means error. */ png_fixed_point red_inverse, green_inverse, blue_scale; png_fixed_point left, right, denominator; /* Check xy and, implicitly, z. Note that wide gamut color spaces typically * have end points with 0 tristimulus values (these are impossible end - * points, but they are used to cover the possible colors). We check - * xy->whitey against 5, not 0, to avoid a possible integer overflow. - * - * The limits here will *not* accept ACES AP0, where bluey is -7700 - * (-0.0770) because the PNG spec itself requires the xy values to be - * unsigned. whitey is also required to be 5 or more to avoid overflow. - * - * Instead the upper limits have been relaxed to accomodate ACES AP1 where - * redz ends up as -600 (-0.006). ProPhotoRGB was already "in range." - * The new limit accomodates the AP0 and AP1 ranges for z but not AP0 redy. + * points, but they are used to cover the possible colors.) */ - const png_fixed_point fpLimit = PNG_FP_1+(PNG_FP_1/10); - if (xy->redx < 0 || xy->redx > fpLimit) return 1; - if (xy->redy < 0 || xy->redy > fpLimit-xy->redx) return 1; - if (xy->greenx < 0 || xy->greenx > fpLimit) return 1; - if (xy->greeny < 0 || xy->greeny > fpLimit-xy->greenx) return 1; - if (xy->bluex < 0 || xy->bluex > fpLimit) return 1; - if (xy->bluey < 0 || xy->bluey > fpLimit-xy->bluex) return 1; - if (xy->whitex < 0 || xy->whitex > fpLimit) return 1; - if (xy->whitey < 5 || xy->whitey > fpLimit-xy->whitex) return 1; + if (xy->redx < 0 || xy->redx > PNG_FP_1) return 1; + if (xy->redy < 0 || xy->redy > PNG_FP_1-xy->redx) return 1; + if (xy->greenx < 0 || xy->greenx > PNG_FP_1) return 1; + if (xy->greeny < 0 || xy->greeny > PNG_FP_1-xy->greenx) return 1; + if (xy->bluex < 0 || xy->bluex > PNG_FP_1) return 1; + if (xy->bluey < 0 || xy->bluey > PNG_FP_1-xy->bluex) return 1; + if (xy->whitex < 0 || xy->whitex > PNG_FP_1) return 1; + if (xy->whitey < 0 || xy->whitey > PNG_FP_1-xy->whitex) return 1; /* The reverse calculation is more difficult because the original tristimulus * value had 9 independent values (red,green,blue)x(X,Y,Z) however only 8 @@ -1302,7 +1256,7 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) * (1/white-y), so we can immediately see that as white-y approaches 0 the * accuracy inherent in the cHRM chunk drops off substantially. * - * libpng arithmetic: a simple inversion of the above equations + * libpng arithmetic: a simple invertion of the above equations * ------------------------------------------------------------ * * white_scale = 1/white-y @@ -1372,23 +1326,18 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) * (green-x - blue-x)*(red-y - blue-y)-(green-y - blue-y)*(red-x - blue-x) * * Accuracy: - * The input values have 5 decimal digits of accuracy. - * - * In the previous implementation the values were all in the range 0 < value - * < 1, so simple products are in the same range but may need up to 10 - * decimal digits to preserve the original precision and avoid underflow. - * Because we are using a 32-bit signed representation we cannot match this; - * the best is a little over 9 decimal digits, less than 10. - * - * This range has now been extended to allow values up to 1.1, or 110,000 in - * fixed point. + * The input values have 5 decimal digits of accuracy. The values are all in + * the range 0 < value < 1, so simple products are in the same range but may + * need up to 10 decimal digits to preserve the original precision and avoid + * underflow. Because we are using a 32-bit signed representation we cannot + * match this; the best is a little over 9 decimal digits, less than 10. * * The approach used here is to preserve the maximum precision within the * signed representation. Because the red-scale calculation above uses the - * difference between two products of values that must be in the range - * -1.1..+1.1 it is sufficient to divide the product by 8; - * ceil(121,000/32767*2). The factor is irrelevant in the calculation - * because it is applied to both numerator and denominator. + * difference between two products of values that must be in the range -1..+1 + * it is sufficient to divide the product by 7; ceil(100,000/32767*2). The + * factor is irrelevant in the calculation because it is applied to both + * numerator and denominator. * * Note that the values of the differences of the products of the * chromaticities in the above equations tend to be small, for example for @@ -1410,93 +1359,297 @@ png_XYZ_from_xy(png_XYZ *XYZ, const png_xy *xy) * Adobe Wide Gamut RGB * 0.258728243040113 0.724682314948566 0.016589442011321 */ - { - int error = 0; - - /* By the argument above overflow should be impossible here, however the - * code now simply returns a failure code. The xy subtracts in the - * arguments to png_muldiv are *not* checked for overflow because the - * checks at the start guarantee they are in the range 0..110000 and - * png_fixed_point is a 32-bit signed number. - */ - if (png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 8) == 0) - return 1; - if (png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 8) == - 0) - return 1; - denominator = png_fp_sub(left, right, &error); - if (error) return 1; - - /* Now find the red numerator. */ - if (png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 8) == 0) - return 1; - if (png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 8) == - 0) - return 1; - - /* Overflow is possible here and it indicates an extreme set of PNG cHRM - * chunk values. This calculation actually returns the reciprocal of the - * scale value because this allows us to delay the multiplication of - * white-y into the denominator, which tends to produce a small number. - */ - if (png_muldiv(&red_inverse, xy->whitey, denominator, - png_fp_sub(left, right, &error)) == 0 || error || - red_inverse <= xy->whitey /* r+g+b scales = white scale */) - return 1; - - /* Similarly for green_inverse: */ - if (png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 8) == 0) - return 1; - if (png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 8) == 0) - return 1; - if (png_muldiv(&green_inverse, xy->whitey, denominator, - png_fp_sub(left, right, &error)) == 0 || error || - green_inverse <= xy->whitey) - return 1; - - /* And the blue scale, the checks above guarantee this can't overflow but - * it can still produce 0 for extreme cHRM values. - */ - blue_scale = png_fp_sub(png_fp_sub(png_reciprocal(xy->whitey), - png_reciprocal(red_inverse), &error), - png_reciprocal(green_inverse), &error); - if (error || blue_scale <= 0) - return 1; - } - - /* And fill in the png_XYZ. Again the subtracts are safe because of the - * checks on the xy values at the start (the subtracts just calculate the - * corresponding z values.) + /* By the argument, above overflow should be impossible here. The return + * value of 2 indicates an internal error to the caller. */ - if (png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse) == 0) - return 1; - if (png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse) == 0) - return 1; - if (png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1, - red_inverse) == 0) + if (!png_muldiv(&left, xy->greenx-xy->bluex, xy->redy - xy->bluey, 7)) + return 2; + if (!png_muldiv(&right, xy->greeny-xy->bluey, xy->redx - xy->bluex, 7)) + return 2; + denominator = left - right; + + /* Now find the red numerator. */ + if (!png_muldiv(&left, xy->greenx-xy->bluex, xy->whitey-xy->bluey, 7)) + return 2; + if (!png_muldiv(&right, xy->greeny-xy->bluey, xy->whitex-xy->bluex, 7)) + return 2; + + /* Overflow is possible here and it indicates an extreme set of PNG cHRM + * chunk values. This calculation actually returns the reciprocal of the + * scale value because this allows us to delay the multiplication of white-y + * into the denominator, which tends to produce a small number. + */ + if (!png_muldiv(&red_inverse, xy->whitey, denominator, left-right) || + red_inverse <= xy->whitey /* r+g+b scales = white scale */) return 1; - if (png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse) == 0) - return 1; - if (png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse) == 0) - return 1; - if (png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1, - green_inverse) == 0) + /* Similarly for green_inverse: */ + if (!png_muldiv(&left, xy->redy-xy->bluey, xy->whitex-xy->bluex, 7)) + return 2; + if (!png_muldiv(&right, xy->redx-xy->bluex, xy->whitey-xy->bluey, 7)) + return 2; + if (!png_muldiv(&green_inverse, xy->whitey, denominator, left-right) || + green_inverse <= xy->whitey) return 1; - if (png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1) == 0) + /* And the blue scale, the checks above guarantee this can't overflow but it + * can still produce 0 for extreme cHRM values. + */ + blue_scale = png_reciprocal(xy->whitey) - png_reciprocal(red_inverse) - + png_reciprocal(green_inverse); + if (blue_scale <= 0) return 1; + + + /* And fill in the png_XYZ: */ + if (!png_muldiv(&XYZ->red_X, xy->redx, PNG_FP_1, red_inverse)) return 1; + if (!png_muldiv(&XYZ->red_Y, xy->redy, PNG_FP_1, red_inverse)) return 1; + if (!png_muldiv(&XYZ->red_Z, PNG_FP_1 - xy->redx - xy->redy, PNG_FP_1, + red_inverse)) return 1; - if (png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1) == 0) + + if (!png_muldiv(&XYZ->green_X, xy->greenx, PNG_FP_1, green_inverse)) return 1; - if (png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale, - PNG_FP_1) == 0) + if (!png_muldiv(&XYZ->green_Y, xy->greeny, PNG_FP_1, green_inverse)) + return 1; + if (!png_muldiv(&XYZ->green_Z, PNG_FP_1 - xy->greenx - xy->greeny, PNG_FP_1, + green_inverse)) + return 1; + + if (!png_muldiv(&XYZ->blue_X, xy->bluex, blue_scale, PNG_FP_1)) return 1; + if (!png_muldiv(&XYZ->blue_Y, xy->bluey, blue_scale, PNG_FP_1)) return 1; + if (!png_muldiv(&XYZ->blue_Z, PNG_FP_1 - xy->bluex - xy->bluey, blue_scale, + PNG_FP_1)) return 1; return 0; /*success*/ } -#endif /* COLORSPACE */ -#ifdef PNG_READ_iCCP_SUPPORTED +static int +png_XYZ_normalize(png_XYZ *XYZ) +{ + png_int_32 Y; + + if (XYZ->red_Y < 0 || XYZ->green_Y < 0 || XYZ->blue_Y < 0 || + XYZ->red_X < 0 || XYZ->green_X < 0 || XYZ->blue_X < 0 || + XYZ->red_Z < 0 || XYZ->green_Z < 0 || XYZ->blue_Z < 0) + return 1; + + /* Normalize by scaling so the sum of the end-point Y values is PNG_FP_1. + * IMPLEMENTATION NOTE: ANSI requires signed overflow not to occur, therefore + * relying on addition of two positive values producing a negative one is not + * safe. + */ + Y = XYZ->red_Y; + if (0x7fffffff - Y < XYZ->green_X) return 1; + Y += XYZ->green_Y; + if (0x7fffffff - Y < XYZ->blue_X) return 1; + Y += XYZ->blue_Y; + + if (Y != PNG_FP_1) + { + if (!png_muldiv(&XYZ->red_X, XYZ->red_X, PNG_FP_1, Y)) return 1; + if (!png_muldiv(&XYZ->red_Y, XYZ->red_Y, PNG_FP_1, Y)) return 1; + if (!png_muldiv(&XYZ->red_Z, XYZ->red_Z, PNG_FP_1, Y)) return 1; + + if (!png_muldiv(&XYZ->green_X, XYZ->green_X, PNG_FP_1, Y)) return 1; + if (!png_muldiv(&XYZ->green_Y, XYZ->green_Y, PNG_FP_1, Y)) return 1; + if (!png_muldiv(&XYZ->green_Z, XYZ->green_Z, PNG_FP_1, Y)) return 1; + + if (!png_muldiv(&XYZ->blue_X, XYZ->blue_X, PNG_FP_1, Y)) return 1; + if (!png_muldiv(&XYZ->blue_Y, XYZ->blue_Y, PNG_FP_1, Y)) return 1; + if (!png_muldiv(&XYZ->blue_Z, XYZ->blue_Z, PNG_FP_1, Y)) return 1; + } + + return 0; +} + +static int +png_colorspace_endpoints_match(const png_xy *xy1, const png_xy *xy2, int delta) +{ + /* Allow an error of +/-0.01 (absolute value) on each chromaticity */ + return !(PNG_OUT_OF_RANGE(xy1->whitex, xy2->whitex,delta) || + PNG_OUT_OF_RANGE(xy1->whitey, xy2->whitey,delta) || + PNG_OUT_OF_RANGE(xy1->redx, xy2->redx, delta) || + PNG_OUT_OF_RANGE(xy1->redy, xy2->redy, delta) || + PNG_OUT_OF_RANGE(xy1->greenx, xy2->greenx,delta) || + PNG_OUT_OF_RANGE(xy1->greeny, xy2->greeny,delta) || + PNG_OUT_OF_RANGE(xy1->bluex, xy2->bluex, delta) || + PNG_OUT_OF_RANGE(xy1->bluey, xy2->bluey, delta)); +} + +/* Added in libpng-1.6.0, a different check for the validity of a set of cHRM + * chunk chromaticities. Earlier checks used to simply look for the overflow + * condition (where the determinant of the matrix to solve for XYZ ends up zero + * because the chromaticity values are not all distinct.) Despite this it is + * theoretically possible to produce chromaticities that are apparently valid + * but that rapidly degrade to invalid, potentially crashing, sets because of + * arithmetic inaccuracies when calculations are performed on them. The new + * check is to round-trip xy -> XYZ -> xy and then check that the result is + * within a small percentage of the original. + */ +static int +png_colorspace_check_xy(png_XYZ *XYZ, const png_xy *xy) +{ + int result; + png_xy xy_test; + + /* As a side-effect this routine also returns the XYZ endpoints. */ + result = png_XYZ_from_xy(XYZ, xy); + if (result) return result; + + result = png_xy_from_XYZ(&xy_test, XYZ); + if (result) return result; + + if (png_colorspace_endpoints_match(xy, &xy_test, + 5/*actually, the math is pretty accurate*/)) + return 0; + + /* Too much slip */ + return 1; +} + +/* This is the check going the other way. The XYZ is modified to normalize it + * (another side-effect) and the xy chromaticities are returned. + */ +static int +png_colorspace_check_XYZ(png_xy *xy, png_XYZ *XYZ) +{ + int result; + png_XYZ XYZtemp; + + result = png_XYZ_normalize(XYZ); + if (result) return result; + + result = png_xy_from_XYZ(xy, XYZ); + if (result) return result; + + XYZtemp = *XYZ; + return png_colorspace_check_xy(&XYZtemp, xy); +} + +/* Used to check for an endpoint match against sRGB */ +static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */ +{ + /* color x y */ + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000, + /* white */ 31270, 32900 +}; + +static int +png_colorspace_set_xy_and_XYZ(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_xy *xy, const png_XYZ *XYZ, + int preferred) +{ + if (colorspace->flags & PNG_COLORSPACE_INVALID) + return 0; + + /* The consistency check is performed on the chromaticities; this factors out + * variations because of the normalization (or not) of the end point Y + * values. + */ + if (preferred < 2 && (colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) + { + /* The end points must be reasonably close to any we already have. The + * following allows an error of up to +/-.001 + */ + if (!png_colorspace_endpoints_match(xy, &colorspace->end_points_xy, 100)) + { + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "inconsistent chromaticities"); + return 0; /* failed */ + } + + /* Only overwrite with preferred values */ + if (!preferred) + return 1; /* ok, but no change */ + } + + colorspace->end_points_xy = *xy; + colorspace->end_points_XYZ = *XYZ; + colorspace->flags |= PNG_COLORSPACE_HAVE_ENDPOINTS; + + /* The end points are normally quoted to two decimal digits, so allow +/-0.01 + * on this test. + */ + if (png_colorspace_endpoints_match(xy, &sRGB_xy, 1000)) + colorspace->flags |= PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB; + + else + colorspace->flags &= PNG_COLORSPACE_CANCEL( + PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); + + return 2; /* ok and changed */ +} + +int /* PRIVATE */ +png_colorspace_set_chromaticities(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_xy *xy, int preferred) +{ + /* We must check the end points to ensure they are reasonable - in the past + * color management systems have crashed as a result of getting bogus + * colorant values, while this isn't the fault of libpng it is the + * responsibility of libpng because PNG carries the bomb and libpng is in a + * position to protect against it. + */ + png_XYZ XYZ; + + switch (png_colorspace_check_xy(&XYZ, xy)) + { + case 0: /* success */ + return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, xy, &XYZ, + preferred); + + case 1: + /* We can't invert the chromaticities so we can't produce value XYZ + * values. Likely as not a color management system will fail too. + */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "invalid chromaticities"); + break; + + default: + /* libpng is broken; this should be a warning but if it happens we + * want error reports so for the moment it is an error. + */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_error(png_ptr, "internal error checking chromaticities"); + break; + } + + return 0; /* failed */ +} + +int /* PRIVATE */ +png_colorspace_set_endpoints(png_const_structrp png_ptr, + png_colorspacerp colorspace, const png_XYZ *XYZ_in, int preferred) +{ + png_XYZ XYZ = *XYZ_in; + png_xy xy; + + switch (png_colorspace_check_XYZ(&xy, &XYZ)) + { + case 0: + return png_colorspace_set_xy_and_XYZ(png_ptr, colorspace, &xy, &XYZ, + preferred); + + case 1: + /* End points are invalid. */ + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_benign_error(png_ptr, "invalid end points"); + break; + + default: + colorspace->flags |= PNG_COLORSPACE_INVALID; + png_error(png_ptr, "internal error checking chromaticities"); + break; + } + + return 0; /* failed */ +} + +#if defined(PNG_sRGB_SUPPORTED) || defined(PNG_iCCP_SUPPORTED) /* Error message generation */ static char png_icc_tag_char(png_uint_32 byte) @@ -1526,8 +1679,7 @@ is_ICC_signature_char(png_alloc_size_t it) (it >= 97 && it <= 122); } -static int -is_ICC_signature(png_alloc_size_t it) +static int is_ICC_signature(png_alloc_size_t it) { return is_ICC_signature_char(it >> 24) /* checks all the top bits */ && is_ICC_signature_char((it >> 16) & 0xff) && @@ -1536,16 +1688,19 @@ is_ICC_signature(png_alloc_size_t it) } static int -png_icc_profile_error(png_const_structrp png_ptr, png_const_charp name, - png_alloc_size_t value, png_const_charp reason) +png_icc_profile_error(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_alloc_size_t value, png_const_charp reason) { size_t pos; char message[196]; /* see below for calculation */ + if (colorspace != NULL) + colorspace->flags |= PNG_COLORSPACE_INVALID; + pos = png_safecat(message, (sizeof message), 0, "profile '"); /* 9 chars */ pos = png_safecat(message, pos+79, pos, name); /* Truncate to 79 chars */ pos = png_safecat(message, (sizeof message), pos, "': "); /* +2 = 90 */ - if (is_ICC_signature(value) != 0) + if (is_ICC_signature(value)) { /* So 'value' is at most 4 bytes and the following cast is safe */ png_icc_tag_name(message+pos, (png_uint_32)value); @@ -1555,24 +1710,121 @@ png_icc_profile_error(png_const_structrp png_ptr, png_const_charp name, } # ifdef PNG_WARNINGS_SUPPORTED else - { - char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114 */ + { + char number[PNG_NUMBER_BUFFER_SIZE]; /* +24 = 114*/ - pos = png_safecat(message, (sizeof message), pos, - png_format_number(number, number+(sizeof number), - PNG_NUMBER_FORMAT_x, value)); - pos = png_safecat(message, (sizeof message), pos, "h: "); /* +2 = 116 */ - } + pos = png_safecat(message, (sizeof message), pos, + png_format_number(number, number+(sizeof number), + PNG_NUMBER_FORMAT_x, value)); + pos = png_safecat(message, (sizeof message), pos, "h: "); /*+2 = 116*/ + } # endif /* The 'reason' is an arbitrary message, allow +79 maximum 195 */ pos = png_safecat(message, (sizeof message), pos, reason); - PNG_UNUSED(pos) - png_chunk_benign_error(png_ptr, message); + /* This is recoverable, but make it unconditionally an app_error on write to + * avoid writing invalid ICC profiles into PNG files. (I.e. we handle them + * on read, with a warning, but on write unless the app turns off + * application errors the PNG won't be written.) + */ + png_chunk_report(png_ptr, message, + (colorspace != NULL) ? PNG_CHUNK_ERROR : PNG_CHUNK_WRITE_ERROR); return 0; } +#endif /* sRGB || iCCP */ +#ifdef PNG_sRGB_SUPPORTED +int /* PRIVATE */ +png_colorspace_set_sRGB(png_const_structrp png_ptr, png_colorspacerp colorspace, + int intent) +{ + /* sRGB sets known gamma, end points and (from the chunk) intent. */ + /* IMPORTANT: these are not necessarily the values found in an ICC profile + * because ICC profiles store values adapted to a D50 environment; it is + * expected that the ICC profile mediaWhitePointTag will be D50, see the + * checks and code elsewhere to understand this better. + * + * These XYZ values, which are accurate to 5dp, produce rgb to gray + * coefficients of (6968,23435,2366), which are reduced (because they add up + * to 32769 not 32768) to (6968,23434,2366). These are the values that + * libpng has traditionally used (and are the best values given the 15bit + * algorithm used by the rgb to gray code.) + */ + static const png_XYZ sRGB_XYZ = /* D65 XYZ (*not* the D50 adapted values!) */ + { + /* color X Y Z */ + /* red */ 41239, 21264, 1933, + /* green */ 35758, 71517, 11919, + /* blue */ 18048, 7219, 95053 + }; + + /* Do nothing if the colorspace is already invalidated. */ + if (colorspace->flags & PNG_COLORSPACE_INVALID) + return 0; + + /* Check the intent, then check for existing settings. It is valid for the + * PNG file to have cHRM or gAMA chunks along with sRGB, but the values must + * be consistent with the correct values. If, however, this function is + * called below because an iCCP chunk matches sRGB then it is quite + * conceivable that an older app recorded incorrect gAMA and cHRM because of + * an incorrect calculation based on the values in the profile - this does + * *not* invalidate the profile (though it still produces an error, which can + * be ignored.) + */ + if (intent < 0 || intent >= PNG_sRGB_INTENT_LAST) + return png_icc_profile_error(png_ptr, colorspace, "sRGB", + (unsigned)intent, "invalid sRGB rendering intent"); + + if ((colorspace->flags & PNG_COLORSPACE_HAVE_INTENT) != 0 && + colorspace->rendering_intent != intent) + return png_icc_profile_error(png_ptr, colorspace, "sRGB", + (unsigned)intent, "inconsistent rendering intents"); + + if ((colorspace->flags & PNG_COLORSPACE_FROM_sRGB) != 0) + { + png_benign_error(png_ptr, "duplicate sRGB information ignored"); + return 0; + } + + /* If the standard sRGB cHRM chunk does not match the one from the PNG file + * warn but overwrite the value with the correct one. + */ + if ((colorspace->flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0 && + !png_colorspace_endpoints_match(&sRGB_xy, &colorspace->end_points_xy, + 100)) + png_chunk_report(png_ptr, "cHRM chunk does not match sRGB", + PNG_CHUNK_ERROR); + + /* This check is just done for the error reporting - the routine always + * returns true when the 'from' argument corresponds to sRGB (2). + */ + (void)png_colorspace_check_gamma(png_ptr, colorspace, PNG_GAMMA_sRGB_INVERSE, + 2/*from sRGB*/); + + /* intent: bugs in GCC force 'int' to be used as the parameter type. */ + colorspace->rendering_intent = (png_uint_16)intent; + colorspace->flags |= PNG_COLORSPACE_HAVE_INTENT; + + /* endpoints */ + colorspace->end_points_xy = sRGB_xy; + colorspace->end_points_XYZ = sRGB_XYZ; + colorspace->flags |= + (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB); + + /* gamma */ + colorspace->gamma = PNG_GAMMA_sRGB_INVERSE; + colorspace->flags |= PNG_COLORSPACE_HAVE_GAMMA; + + /* Finally record that we have an sRGB profile */ + colorspace->flags |= + (PNG_COLORSPACE_MATCHES_sRGB|PNG_COLORSPACE_FROM_sRGB); + + return 1; /* set */ +} +#endif /* sRGB */ + +#ifdef PNG_iCCP_SUPPORTED /* Encoded value of D50 as an ICC XYZNumber. From the ICC 2010 spec the value * is XYZ(0.9642,1.0,0.8249), which scales to: * @@ -1581,38 +1833,24 @@ png_icc_profile_error(png_const_structrp png_ptr, png_const_charp name, static const png_byte D50_nCIEXYZ[12] = { 0x00, 0x00, 0xf6, 0xd6, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0xd3, 0x2d }; -static int /* bool */ -icc_check_length(png_const_structrp png_ptr, png_const_charp name, - png_uint_32 profile_length) +int /* PRIVATE */ +png_icc_check_length(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length) { if (profile_length < 132) - return png_icc_profile_error(png_ptr, name, profile_length, "too short"); - return 1; -} + return png_icc_profile_error(png_ptr, colorspace, name, profile_length, + "too short"); -int /* PRIVATE */ -png_icc_check_length(png_const_structrp png_ptr, png_const_charp name, - png_uint_32 profile_length) -{ - if (!icc_check_length(png_ptr, name, profile_length)) - return 0; - - /* This needs to be here because the 'normal' check is in - * png_decompress_chunk, yet this happens after the attempt to - * png_malloc_base the required data. We only need this on read; on write - * the caller supplies the profile buffer so libpng doesn't allocate it. See - * the call to icc_check_length below (the write case). - */ - if (profile_length > png_chunk_max(png_ptr)) - return png_icc_profile_error(png_ptr, name, profile_length, - "profile too long"); + if (profile_length & 3) + return png_icc_profile_error(png_ptr, colorspace, name, profile_length, + "invalid length"); return 1; } int /* PRIVATE */ -png_icc_check_header(png_const_structrp png_ptr, png_const_charp name, - png_uint_32 profile_length, +png_icc_check_header(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, png_const_bytep profile/* first 132 bytes only */, int color_type) { png_uint_32 temp; @@ -1624,34 +1862,29 @@ png_icc_check_header(png_const_structrp png_ptr, png_const_charp name, */ temp = png_get_uint_32(profile); if (temp != profile_length) - return png_icc_profile_error(png_ptr, name, temp, - "length does not match profile"); - - temp = (png_uint_32) (*(profile+8)); - if (temp > 3 && (profile_length & 3)) - return png_icc_profile_error(png_ptr, name, profile_length, - "invalid length"); + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "length does not match profile"); temp = png_get_uint_32(profile+128); /* tag count: 12 bytes/tag */ if (temp > 357913930 || /* (2^32-4-132)/12: maximum possible tag count */ profile_length < 132+12*temp) /* truncated tag table */ - return png_icc_profile_error(png_ptr, name, temp, - "tag count too large"); + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "tag count too large"); /* The 'intent' must be valid or we can't store it, ICC limits the intent to * 16 bits. */ temp = png_get_uint_32(profile+64); if (temp >= 0xffff) /* The ICC limit */ - return png_icc_profile_error(png_ptr, name, temp, - "invalid rendering intent"); + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid rendering intent"); /* This is just a warning because the profile may be valid in future * versions. */ if (temp >= PNG_sRGB_INTENT_LAST) - (void)png_icc_profile_error(png_ptr, name, temp, - "intent outside defined range"); + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "intent outside defined range"); /* At this point the tag table can't be checked because it hasn't necessarily * been loaded; however, various header fields can be checked. These checks @@ -1661,14 +1894,14 @@ png_icc_check_header(png_const_structrp png_ptr, png_const_charp name, */ /* Data checks (could be skipped). These checks must be independent of the - * version number; however, the version number doesn't accommodate changes in + * version number; however, the version number doesn't accomodate changes in * the header fields (just the known tags and the interpretation of the * data.) */ temp = png_get_uint_32(profile+36); /* signature 'ascp' */ if (temp != 0x61637370) - return png_icc_profile_error(png_ptr, name, temp, - "invalid signature"); + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid signature"); /* Currently the PCS illuminant/adopted white point (the computational * white point) are required to be D50, @@ -1678,8 +1911,8 @@ png_icc_check_header(png_const_structrp png_ptr, png_const_charp name, * following is just a warning. */ if (memcmp(profile+68, D50_nCIEXYZ, 12) != 0) - (void)png_icc_profile_error(png_ptr, name, 0/*no tag value*/, - "PCS illuminant is not D50"); + (void)png_icc_profile_error(png_ptr, NULL, name, 0/*no tag value*/, + "PCS illuminant is not D50"); /* The PNG spec requires this: * "If the iCCP chunk is present, the image samples conform to the colour @@ -1705,20 +1938,20 @@ png_icc_check_header(png_const_structrp png_ptr, png_const_charp name, switch (temp) { case 0x52474220: /* 'RGB ' */ - if ((color_type & PNG_COLOR_MASK_COLOR) == 0) - return png_icc_profile_error(png_ptr, name, temp, - "RGB color space not permitted on grayscale PNG"); + if (!(color_type & PNG_COLOR_MASK_COLOR)) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "RGB color space not permitted on grayscale PNG"); break; case 0x47524159: /* 'GRAY' */ - if ((color_type & PNG_COLOR_MASK_COLOR) != 0) - return png_icc_profile_error(png_ptr, name, temp, - "Gray color space not permitted on RGB PNG"); + if (color_type & PNG_COLOR_MASK_COLOR) + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "Gray color space not permitted on RGB PNG"); break; default: - return png_icc_profile_error(png_ptr, name, temp, - "invalid ICC profile color space"); + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid ICC profile color space"); } /* It is up to the application to check that the profile class matches the @@ -1733,8 +1966,8 @@ png_icc_check_header(png_const_structrp png_ptr, png_const_charp name, temp = png_get_uint_32(profile+12); /* profile/device class */ switch (temp) { - case 0x73636e72: /* 'scnr' */ - case 0x6d6e7472: /* 'mntr' */ + case 0x73636E72: /* 'scnr' */ + case 0x6D6E7472: /* 'mntr' */ case 0x70727472: /* 'prtr' */ case 0x73706163: /* 'spac' */ /* All supported */ @@ -1742,26 +1975,26 @@ png_icc_check_header(png_const_structrp png_ptr, png_const_charp name, case 0x61627374: /* 'abst' */ /* May not be embedded in an image */ - return png_icc_profile_error(png_ptr, name, temp, - "invalid embedded Abstract ICC profile"); + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "invalid embedded Abstract ICC profile"); - case 0x6c696e6b: /* 'link' */ - /* DeviceLink profiles cannot be interpreted in a non-device specific + case 0x6C696E6B: /* 'link' */ + /* DeviceLink profiles cannnot be interpreted in a non-device specific * fashion, if an app uses the AToB0Tag in the profile the results are * undefined unless the result is sent to the intended device, * therefore a DeviceLink profile should not be found embedded in a * PNG. */ - return png_icc_profile_error(png_ptr, name, temp, - "unexpected DeviceLink ICC profile class"); + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "unexpected DeviceLink ICC profile class"); - case 0x6e6d636c: /* 'nmcl' */ + case 0x6E6D636C: /* 'nmcl' */ /* A NamedColor profile is also device specific, however it doesn't - * contain an AToB0 tag that is open to misinterpretation. Almost + * contain an AToB0 tag that is open to misintrepretation. Almost * certainly it will fail the tests below. */ - (void)png_icc_profile_error(png_ptr, name, temp, - "unexpected NamedColor ICC profile class"); + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "unexpected NamedColor ICC profile class"); break; default: @@ -1770,8 +2003,8 @@ png_icc_check_header(png_const_structrp png_ptr, png_const_charp name, * tag content to ensure they are backward compatible with one of the * understood profiles. */ - (void)png_icc_profile_error(png_ptr, name, temp, - "unrecognized ICC profile class"); + (void)png_icc_profile_error(png_ptr, NULL, name, temp, + "unrecognized ICC profile class"); break; } @@ -1781,21 +2014,21 @@ png_icc_check_header(png_const_structrp png_ptr, png_const_charp name, temp = png_get_uint_32(profile+20); switch (temp) { - case 0x58595a20: /* 'XYZ ' */ - case 0x4c616220: /* 'Lab ' */ + case 0x58595A20: /* 'XYZ ' */ + case 0x4C616220: /* 'Lab ' */ break; default: - return png_icc_profile_error(png_ptr, name, temp, - "unexpected ICC PCS encoding"); + return png_icc_profile_error(png_ptr, colorspace, name, temp, + "unexpected ICC PCS encoding"); } return 1; } int /* PRIVATE */ -png_icc_check_tag_table(png_const_structrp png_ptr, png_const_charp name, - png_uint_32 profile_length, +png_icc_check_tag_table(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, png_const_bytep profile /* header plus whole tag table */) { png_uint_32 tag_count = png_get_uint_32(profile+128); @@ -1817,151 +2050,316 @@ png_icc_check_tag_table(png_const_structrp png_ptr, png_const_charp name, * being in range. All defined tag types have an 8 byte header - a 4 byte * type signature then 0. */ + if ((tag_start & 3) != 0) + { + /* CNHP730S.icc shipped with Microsoft Windows 64 violates this, it is + * only a warning here because libpng does not care about the + * alignment. + */ + (void)png_icc_profile_error(png_ptr, NULL, name, tag_id, + "ICC profile tag start not a multiple of 4"); + } /* This is a hard error; potentially it can cause read outside the * profile. */ if (tag_start > profile_length || tag_length > profile_length - tag_start) - return png_icc_profile_error(png_ptr, name, tag_id, - "ICC profile tag outside profile"); - - if ((tag_start & 3) != 0) - { - /* CNHP730S.icc shipped with Microsoft Windows 64 violates this; it is - * only a warning here because libpng does not care about the - * alignment. - */ - (void)png_icc_profile_error(png_ptr, name, tag_id, - "ICC profile tag start not a multiple of 4"); - } + return png_icc_profile_error(png_ptr, colorspace, name, tag_id, + "ICC profile tag outside profile"); } return 1; /* success, maybe with warnings */ } -#endif /* READ_iCCP */ -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -#if (defined PNG_READ_mDCV_SUPPORTED) || (defined PNG_READ_cHRM_SUPPORTED) +#ifdef PNG_sRGB_SUPPORTED +/* Information about the known ICC sRGB profiles */ +static const struct +{ + png_uint_32 adler, crc, length; + png_uint_32 md5[4]; + png_byte have_md5; + png_byte is_broken; + png_uint_16 intent; + +# define PNG_MD5(a,b,c,d) { a, b, c, d }, (a!=0)||(b!=0)||(c!=0)||(d!=0) +# define PNG_ICC_CHECKSUM(adler, crc, md5, intent, broke, date, length, fname)\ + { adler, crc, length, md5, broke, intent }, + +} png_sRGB_checks[] = +{ + /* This data comes from contrib/tools/checksum-icc run on downloads of + * all four ICC sRGB profiles from www.color.org. + */ + /* adler32, crc32, MD5[4], intent, date, length, file-name */ + PNG_ICC_CHECKSUM(0x0a3fd9f6, 0x3b8772b9, + PNG_MD5(0x29f83dde, 0xaff255ae, 0x7842fae4, 0xca83390d), 0, 0, + "2009/03/27 21:36:31", 3048, "sRGB_IEC61966-2-1_black_scaled.icc") + + /* ICC sRGB v2 perceptual no black-compensation: */ + PNG_ICC_CHECKSUM(0x4909e5e1, 0x427ebb21, + PNG_MD5(0xc95bd637, 0xe95d8a3b, 0x0df38f99, 0xc1320389), 1, 0, + "2009/03/27 21:37:45", 3052, "sRGB_IEC61966-2-1_no_black_scaling.icc") + + PNG_ICC_CHECKSUM(0xfd2144a1, 0x306fd8ae, + PNG_MD5(0xfc663378, 0x37e2886b, 0xfd72e983, 0x8228f1b8), 0, 0, + "2009/08/10 17:28:01", 60988, "sRGB_v4_ICC_preference_displayclass.icc") + + /* ICC sRGB v4 perceptual */ + PNG_ICC_CHECKSUM(0x209c35d2, 0xbbef7812, + PNG_MD5(0x34562abf, 0x994ccd06, 0x6d2c5721, 0xd0d68c5d), 0, 0, + "2007/07/25 00:05:37", 60960, "sRGB_v4_ICC_preference.icc") + + /* The following profiles have no known MD5 checksum. If there is a match + * on the (empty) MD5 the other fields are used to attempt a match and + * a warning is produced. The first two of these profiles have a 'cprt' tag + * which suggests that they were also made by Hewlett Packard. + */ + PNG_ICC_CHECKSUM(0xa054d762, 0x5d5129ce, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 0, + "2004/07/21 18:57:42", 3024, "sRGB_IEC61966-2-1_noBPC.icc") + + /* This is a 'mntr' (display) profile with a mediaWhitePointTag that does not + * match the D50 PCS illuminant in the header (it is in fact the D65 values, + * so the white point is recorded as the un-adapted value.) The profiles + * below only differ in one byte - the intent - and are basically the same as + * the previous profile except for the mediaWhitePointTag error and a missing + * chromaticAdaptationTag. + */ + PNG_ICC_CHECKSUM(0xf784f3fb, 0x182ea552, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 0, 1/*broken*/, + "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 perceptual") + + PNG_ICC_CHECKSUM(0x0398f3fc, 0xf29e526d, + PNG_MD5(0x00000000, 0x00000000, 0x00000000, 0x00000000), 1, 1/*broken*/, + "1998/02/09 06:49:00", 3144, "HP-Microsoft sRGB v2 media-relative") +}; + static int -have_chromaticities(png_const_structrp png_ptr) +png_compare_ICC_profile_with_sRGB(png_const_structrp png_ptr, + png_const_bytep profile, uLong adler) { - /* Handle new PNGv3 chunks and the precedence rules to determine whether - * png_struct::chromaticities must be processed. Only required for RGB to - * gray. - * - * mDCV: this is the mastering colour space and it is independent of the - * encoding so it needs to be used regardless of the encoded space. - * - * cICP: first in priority but not yet implemented - the chromaticities come - * from the 'primaries'. - * - * iCCP: not supported by libpng (so ignored) - * - * sRGB: the defaults match sRGB - * - * cHRM: calculate the coefficients + /* The quick check is to verify just the MD5 signature and trust the + * rest of the data. Because the profile has already been verified for + * correctness this is safe. png_colorspace_set_sRGB will check the 'intent' + * field too, so if the profile has been edited with an intent not defined + * by sRGB (but maybe defined by a later ICC specification) the read of + * the profile will fail at that point. */ -# ifdef PNG_READ_mDCV_SUPPORTED - if (png_has_chunk(png_ptr, mDCV)) - return 1; -# define check_chromaticities 1 -# endif /*mDCV*/ + png_uint_32 length = 0; + png_uint_32 intent = 0x10000; /* invalid */ +#if PNG_sRGB_PROFILE_CHECKS > 1 + uLong crc = 0; /* the value for 0 length data */ +#endif + unsigned int i; -# ifdef PNG_READ_sRGB_SUPPORTED - if (png_has_chunk(png_ptr, sRGB)) - return 0; -# endif /*sRGB*/ - -# ifdef PNG_READ_cHRM_SUPPORTED - if (png_has_chunk(png_ptr, cHRM)) - return 1; -# define check_chromaticities 1 -# endif /*cHRM*/ - - return 0; /* sRGB defaults */ -} -#endif /* READ_mDCV || READ_cHRM */ - -void /* PRIVATE */ -png_set_rgb_coefficients(png_structrp png_ptr) -{ - /* Set the rgb_to_gray coefficients from the colorspace if available. Note - * that '_set' means that png_rgb_to_gray was called **and** it successfully - * set up the coefficients. - */ - if (png_ptr->rgb_to_gray_coefficients_set == 0) + for (i=0; i < (sizeof png_sRGB_checks) / (sizeof png_sRGB_checks[0]); ++i) { -# if check_chromaticities - png_XYZ xyz; - - if (have_chromaticities(png_ptr) && - png_XYZ_from_xy(&xyz, &png_ptr->chromaticities) == 0) + if (png_get_uint_32(profile+84) == png_sRGB_checks[i].md5[0] && + png_get_uint_32(profile+88) == png_sRGB_checks[i].md5[1] && + png_get_uint_32(profile+92) == png_sRGB_checks[i].md5[2] && + png_get_uint_32(profile+96) == png_sRGB_checks[i].md5[3]) { - /* png_set_rgb_to_gray has not set the coefficients, get them from the - * Y * values of the colorspace colorants. + /* This may be one of the old HP profiles without an MD5, in that + * case we can only use the length and Adler32 (note that these + * are not used by default if there is an MD5!) */ - png_fixed_point r = xyz.red_Y; - png_fixed_point g = xyz.green_Y; - png_fixed_point b = xyz.blue_Y; - png_fixed_point total = r+g+b; +# if PNG_sRGB_PROFILE_CHECKS == 0 + if (png_sRGB_checks[i].have_md5) + return 1+png_sRGB_checks[i].is_broken; +# endif - if (total > 0 && - r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 && - g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 && - b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 && - r+g+b <= 32769) + /* Profile is unsigned or more checks have been configured in. */ + if (length == 0) { - /* We allow 0 coefficients here. r+g+b may be 32769 if two or - * all of the coefficients were rounded up. Handle this by - * reducing the *largest* coefficient by 1; this matches the - * approach used for the default coefficients in pngrtran.c - */ - int add = 0; + length = png_get_uint_32(profile); + intent = png_get_uint_32(profile+64); + } - if (r+g+b > 32768) - add = -1; - else if (r+g+b < 32768) - add = 1; - - if (add != 0) + /* Length *and* intent must match */ + if (length == png_sRGB_checks[i].length && + intent == png_sRGB_checks[i].intent) + { + /* Now calculate the adler32 if not done already. */ + if (adler == 0) { - if (g >= r && g >= b) - g += add; - else if (r >= g && r >= b) - r += add; - else - b += add; + adler = adler32(0, NULL, 0); + adler = adler32(adler, profile, length); } - /* Check for an internal error. */ - if (r+g+b != 32768) - png_error(png_ptr, - "internal error handling cHRM coefficients"); - - else + if (adler == png_sRGB_checks[i].adler) { - png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r; - png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g; + /* These basic checks suggest that the data has not been + * modified, but if the check level is more than 1 perform + * our own crc32 checksum on the data. + */ +# if PNG_sRGB_PROFILE_CHECKS > 1 + if (crc == 0) + { + crc = crc32(0, NULL, 0); + crc = crc32(crc, profile, length); + } + + /* So this check must pass for the 'return' below to happen. + */ + if (crc == png_sRGB_checks[i].crc) +# endif + { + if (png_sRGB_checks[i].is_broken) + { + /* These profiles are known to have bad data that may cause + * problems if they are used, therefore attempt to + * discourage their use, skip the 'have_md5' warning below, + * which is made irrelevant by this error. + */ + png_chunk_report(png_ptr, "known incorrect sRGB profile", + PNG_CHUNK_ERROR); + } + + /* Warn that this being done; this isn't even an error since + * the profile is perfectly valid, but it would be nice if + * people used the up-to-date ones. + */ + else if (!png_sRGB_checks[i].have_md5) + { + png_chunk_report(png_ptr, + "out-of-date sRGB profile with no signature", + PNG_CHUNK_WARNING); + } + + return 1+png_sRGB_checks[i].is_broken; + } } } - } - else -# endif /* check_chromaticities */ - { - /* Use the historical REC 709 (etc) values: */ - png_ptr->rgb_to_gray_red_coeff = 6968; - png_ptr->rgb_to_gray_green_coeff = 23434; - /* png_ptr->rgb_to_gray_blue_coeff = 2366; */ + +# if PNG_sRGB_PROFILE_CHECKS > 0 + /* The signature matched, but the profile had been changed in some + * way. This is an apparent violation of the ICC terms of use and, + * anyway, probably indicates a data error or uninformed hacking. + */ + if (png_sRGB_checks[i].have_md5) + png_benign_error(png_ptr, + "copyright violation: edited ICC profile ignored"); +# endif } } + + return 0; /* no match */ } -#endif /* READ_RGB_TO_GRAY */ +#endif + +#ifdef PNG_sRGB_SUPPORTED +void /* PRIVATE */ +png_icc_set_sRGB(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_bytep profile, uLong adler) +{ + /* Is this profile one of the known ICC sRGB profiles? If it is, just set + * the sRGB information. + */ + if (png_compare_ICC_profile_with_sRGB(png_ptr, profile, adler)) + (void)png_colorspace_set_sRGB(png_ptr, colorspace, + (int)/*already checked*/png_get_uint_32(profile+64)); +} +#endif /* PNG_READ_sRGB_SUPPORTED */ + +int /* PRIVATE */ +png_colorspace_set_ICC(png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_charp name, png_uint_32 profile_length, png_const_bytep profile, + int color_type) +{ + if (colorspace->flags & PNG_COLORSPACE_INVALID) + return 0; + + if (png_icc_check_length(png_ptr, colorspace, name, profile_length) && + png_icc_check_header(png_ptr, colorspace, name, profile_length, profile, + color_type) && + png_icc_check_tag_table(png_ptr, colorspace, name, profile_length, + profile)) + { +# ifdef PNG_sRGB_SUPPORTED + /* If no sRGB support, don't try storing sRGB information */ + png_icc_set_sRGB(png_ptr, colorspace, profile, 0); +# endif + return 1; + } + + /* Failure case */ + return 0; +} +#endif /* iCCP */ + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +void /* PRIVATE */ +png_colorspace_set_rgb_coefficients(png_structrp png_ptr) +{ + /* Set the rgb_to_gray coefficients from the colorspace. */ + if (!png_ptr->rgb_to_gray_coefficients_set && + (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS) != 0) + { + /* png_set_background has not been called, get the coefficients from the Y + * values of the colorspace colorants. + */ + png_fixed_point r = png_ptr->colorspace.end_points_XYZ.red_Y; + png_fixed_point g = png_ptr->colorspace.end_points_XYZ.green_Y; + png_fixed_point b = png_ptr->colorspace.end_points_XYZ.blue_Y; + png_fixed_point total = r+g+b; + + if (total > 0 && + r >= 0 && png_muldiv(&r, r, 32768, total) && r >= 0 && r <= 32768 && + g >= 0 && png_muldiv(&g, g, 32768, total) && g >= 0 && g <= 32768 && + b >= 0 && png_muldiv(&b, b, 32768, total) && b >= 0 && b <= 32768 && + r+g+b <= 32769) + { + /* We allow 0 coefficients here. r+g+b may be 32769 if two or + * all of the coefficients were rounded up. Handle this by + * reducing the *largest* coefficient by 1; this matches the + * approach used for the default coefficients in pngrtran.c + */ + int add = 0; + + if (r+g+b > 32768) + add = -1; + else if (r+g+b < 32768) + add = 1; + + if (add != 0) + { + if (g >= r && g >= b) + g += add; + else if (r >= g && r >= b) + r += add; + else + b += add; + } + + /* Check for an internal error. */ + if (r+g+b != 32768) + png_error(png_ptr, + "internal error handling cHRM coefficients"); + + else + { + png_ptr->rgb_to_gray_red_coeff = (png_uint_16)r; + png_ptr->rgb_to_gray_green_coeff = (png_uint_16)g; + } + } + + /* This is a png_error at present even though it could be ignored - + * it should never happen, but it is important that if it does, the + * bug is fixed. + */ + else + png_error(png_ptr, "internal error handling cHRM->XYZ"); + } +} +#endif + +#endif /* COLORSPACE */ void /* PRIVATE */ png_check_IHDR(png_const_structrp png_ptr, - png_uint_32 width, png_uint_32 height, int bit_depth, - int color_type, int interlace_type, int compression_type, - int filter_type) + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type) { int error = 0; @@ -1972,55 +2370,36 @@ png_check_IHDR(png_const_structrp png_ptr, error = 1; } - if (width > PNG_UINT_31_MAX) + if (height == 0) { - png_warning(png_ptr, "Invalid image width in IHDR"); + png_warning(png_ptr, "Image height is zero in IHDR"); error = 1; } - /* The bit mask on the first line below must be at least as big as a - * png_uint_32. "~7U" is not adequate on 16-bit systems because it will - * be an unsigned 16-bit value. Casting to (png_alloc_size_t) makes the - * type of the result at least as bit (in bits) as the RHS of the > operator - * which also avoids a common warning on 64-bit systems that the comparison - * of (png_uint_32) against the constant value on the RHS will always be - * false. - */ - if (((width + 7) & ~(png_alloc_size_t)7) > - (((PNG_SIZE_MAX - - 48 /* big_row_buf hack */ - - 1) /* filter byte */ - / 8) /* 8-byte RGBA pixels */ - - 1)) /* extra max_pixel_depth pad */ - { - /* The size of the row must be within the limits of this architecture. - * Because the read code can perform arbitrary transformations the - * maximum size is checked here. Because the code in png_read_start_row - * adds extra space "for safety's sake" in several places a conservative - * limit is used here. - * - * NOTE: it would be far better to check the size that is actually used, - * but the effect in the real world is minor and the changes are more - * extensive, therefore much more dangerous and much more difficult to - * write in a way that avoids compiler warnings. - */ - png_warning(png_ptr, "Image width is too large for this architecture"); - error = 1; - } - -#ifdef PNG_SET_USER_LIMITS_SUPPORTED +# ifdef PNG_SET_USER_LIMITS_SUPPORTED if (width > png_ptr->user_width_max) -#else + +# else if (width > PNG_USER_WIDTH_MAX) -#endif +# endif { png_warning(png_ptr, "Image width exceeds user limit in IHDR"); error = 1; } - if (height == 0) +# ifdef PNG_SET_USER_LIMITS_SUPPORTED + if (height > png_ptr->user_height_max) +# else + if (height > PNG_USER_HEIGHT_MAX) +# endif { - png_warning(png_ptr, "Image height is zero in IHDR"); + png_warning(png_ptr, "Image height exceeds user limit in IHDR"); + error = 1; + } + + if (width > PNG_UINT_31_MAX) + { + png_warning(png_ptr, "Invalid image width in IHDR"); error = 1; } @@ -2030,15 +2409,13 @@ png_check_IHDR(png_const_structrp png_ptr, error = 1; } -#ifdef PNG_SET_USER_LIMITS_SUPPORTED - if (height > png_ptr->user_height_max) -#else - if (height > PNG_USER_HEIGHT_MAX) -#endif - { - png_warning(png_ptr, "Image height exceeds user limit in IHDR"); - error = 1; - } + if (width > (PNG_UINT_32_MAX + >> 3) /* 8-byte RGBA pixels */ + - 48 /* bigrowbuf hack */ + - 1 /* filter byte */ + - 7*8 /* rounding of width to multiple of 8 pixels */ + - 8) /* extra max_pixel_depth pad */ + png_warning(png_ptr, "Width is too large for libpng to process pixels"); /* Check other values */ if (bit_depth != 1 && bit_depth != 2 && bit_depth != 4 && @@ -2076,7 +2453,7 @@ png_check_IHDR(png_const_structrp png_ptr, error = 1; } -#ifdef PNG_MNG_FEATURES_SUPPORTED +# ifdef PNG_MNG_FEATURES_SUPPORTED /* Accept filter_method 64 (intrapixel differencing) only if * 1. Libpng was compiled with PNG_MNG_FEATURES_SUPPORTED and * 2. Libpng did not read a PNG signature (this filter_method is only @@ -2086,13 +2463,13 @@ png_check_IHDR(png_const_structrp png_ptr, * 4. The filter_method is 64 and * 5. The color_type is RGB or RGBA */ - if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && - png_ptr->mng_features_permitted != 0) + if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) && + png_ptr->mng_features_permitted) png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); if (filter_type != PNG_FILTER_TYPE_BASE) { - if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + if (!((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && (filter_type == PNG_INTRAPIXEL_DIFFERENCING) && ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && (color_type == PNG_COLOR_TYPE_RGB || @@ -2102,20 +2479,20 @@ png_check_IHDR(png_const_structrp png_ptr, error = 1; } - if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0) + if (png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) { png_warning(png_ptr, "Invalid filter method in IHDR"); error = 1; } } -#else +# else if (filter_type != PNG_FILTER_TYPE_BASE) { png_warning(png_ptr, "Unknown filter method in IHDR"); error = 1; } -#endif +# endif if (error == 1) png_error(png_ptr, "Invalid IHDR data"); @@ -2123,7 +2500,7 @@ png_check_IHDR(png_const_structrp png_ptr, #if defined(PNG_sCAL_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) /* ASCII to fp functions */ -/* Check an ASCII formatted floating point value, see the more detailed +/* Check an ASCII formated floating point value, see the more detailed * comments in pngpriv.h */ /* The following is used internally to preserve the sticky flags */ @@ -2131,11 +2508,11 @@ png_check_IHDR(png_const_structrp png_ptr, #define png_fp_set(state, value) ((state) = (value) | ((state) & PNG_FP_STICKY)) int /* PRIVATE */ -png_check_fp_number(png_const_charp string, size_t size, int *statep, - size_t *whereami) +png_check_fp_number(png_const_charp string, png_size_t size, int *statep, + png_size_tp whereami) { int state = *statep; - size_t i = *whereami; + png_size_t i = *whereami; while (i < size) { @@ -2162,7 +2539,7 @@ png_check_fp_number(png_const_charp string, size_t size, int *statep, switch ((state & PNG_FP_STATE) + (type & PNG_FP_SAW_ANY)) { case PNG_FP_INTEGER + PNG_FP_SAW_SIGN: - if ((state & PNG_FP_SAW_ANY) != 0) + if (state & PNG_FP_SAW_ANY) goto PNG_FP_End; /* not a part of the number */ png_fp_add(state, type); @@ -2170,10 +2547,10 @@ png_check_fp_number(png_const_charp string, size_t size, int *statep, case PNG_FP_INTEGER + PNG_FP_SAW_DOT: /* Ok as trailer, ok as lead of fraction. */ - if ((state & PNG_FP_SAW_DOT) != 0) /* two dots */ + if (state & PNG_FP_SAW_DOT) /* two dots */ goto PNG_FP_End; - else if ((state & PNG_FP_SAW_DIGIT) != 0) /* trailing dot? */ + else if (state & PNG_FP_SAW_DIGIT) /* trailing dot? */ png_fp_add(state, type); else @@ -2182,7 +2559,7 @@ png_check_fp_number(png_const_charp string, size_t size, int *statep, break; case PNG_FP_INTEGER + PNG_FP_SAW_DIGIT: - if ((state & PNG_FP_SAW_DOT) != 0) /* delayed fraction */ + if (state & PNG_FP_SAW_DOT) /* delayed fraction */ png_fp_set(state, PNG_FP_FRACTION | PNG_FP_SAW_DOT); png_fp_add(state, type | PNG_FP_WAS_VALID); @@ -2220,7 +2597,7 @@ png_check_fp_number(png_const_charp string, size_t size, int *statep, break; case PNG_FP_EXPONENT + PNG_FP_SAW_SIGN: - if ((state & PNG_FP_SAW_ANY) != 0) + if (state & PNG_FP_SAW_ANY) goto PNG_FP_End; /* not a part of the number */ png_fp_add(state, PNG_FP_SAW_SIGN); @@ -2258,18 +2635,18 @@ PNG_FP_End: /* The same but for a complete string. */ int -png_check_fp_string(png_const_charp string, size_t size) +png_check_fp_string(png_const_charp string, png_size_t size) { - int state = 0; - size_t char_index = 0; + int state=0; + png_size_t char_index=0; - if (png_check_fp_number(string, size, &state, &char_index) != 0 && + if (png_check_fp_number(string, size, &state, &char_index) && (char_index == size || string[char_index] == 0)) return state /* must be non-zero - see above */; return 0; /* i.e. fail */ } -#endif /* pCAL || sCAL */ +#endif /* pCAL or sCAL */ #ifdef PNG_sCAL_SUPPORTED # ifdef PNG_FLOATING_POINT_SUPPORTED @@ -2288,7 +2665,7 @@ png_pow10(int power) if (power < 0) { if (power < DBL_MIN_10_EXP) return 0; - recip = 1; power = -power; + recip = 1, power = -power; } if (power > 0) @@ -2303,7 +2680,7 @@ png_pow10(int power) } while (power > 0); - if (recip != 0) d = 1/d; + if (recip) d = 1/d; } /* else power is 0 and d is 1 */ @@ -2314,7 +2691,7 @@ png_pow10(int power) * precision. */ void /* PRIVATE */ -png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, +png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, png_size_t size, double fp, unsigned int precision) { /* We use standard functions from math.h, but not printf because @@ -2341,7 +2718,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, if (fp >= DBL_MIN && fp <= DBL_MAX) { - int exp_b10; /* A base 10 exponent */ + int exp_b10; /* A base 10 exponent */ double base; /* 10^exp_b10 */ /* First extract a base 10 exponent of the number, @@ -2366,9 +2743,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, double test = png_pow10(exp_b10+1); if (test <= DBL_MAX) - { - ++exp_b10; base = test; - } + ++exp_b10, base = test; else break; @@ -2382,10 +2757,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, * test on DBL_MAX above. */ fp /= base; - while (fp >= 1) - { - fp /= 10; ++exp_b10; - } + while (fp >= 1) fp /= 10, ++exp_b10; /* Because of the code above fp may, at this point, be * less than .1, this is ok because the code below can @@ -2394,7 +2766,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, */ { - unsigned int czero, clead, cdigits; + int czero, clead, cdigits; char exponent[10]; /* Allow up to two leading zeros - this will not lengthen @@ -2402,7 +2774,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, */ if (exp_b10 < 0 && exp_b10 > -3) /* PLUS 3 TOTAL 4 */ { - czero = 0U-exp_b10; /* PLUS 2 digits: TOTAL 3 */ + czero = -exp_b10; /* PLUS 2 digits: TOTAL 3 */ exp_b10 = 0; /* Dot added below before first output. */ } else @@ -2424,7 +2796,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, * of the loop don't break the number into parts so * that the final digit is rounded. */ - if (cdigits+czero+1 < precision+clead) + if (cdigits+czero-clead+1 < (int)precision) fp = modf(fp, &d); else @@ -2436,7 +2808,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, /* Rounding up to 10, handle that here. */ if (czero > 0) { - --czero; d = 1; + --czero, d = 1; if (cdigits == 0) --clead; } else @@ -2450,7 +2822,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, else if (ch == 46) { - ch = *--ascii; ++size; + ch = *--ascii, ++size; /* Advance exp_b10 to '1', so that the * decimal point happens after the * previous digit. @@ -2477,9 +2849,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, int ch = *--ascii; if (ch == 46) - { - ++size; exp_b10 = 1; - } + ++size, exp_b10 = 1; /* Else lost a leading zero, so 'exp_b10' is * still ok at (-1) @@ -2515,49 +2885,43 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, */ if (exp_b10 != (-1)) { - if (exp_b10 == 0) - { - *ascii++ = 46; --size; - } + if (exp_b10 == 0) *ascii++ = 46, --size; /* PLUS 1: TOTAL 4 */ --exp_b10; } - *ascii++ = 48; --czero; + *ascii++ = 48, --czero; } if (exp_b10 != (-1)) { - if (exp_b10 == 0) - { - *ascii++ = 46; --size; /* counted above */ - } - + if (exp_b10 == 0) *ascii++ = 46, --size; /* counted + above */ --exp_b10; } - *ascii++ = (char)(48 + (int)d); ++cdigits; + *ascii++ = (char)(48 + (int)d), ++cdigits; } } - while (cdigits+czero < precision+clead && fp > DBL_MIN); + while (cdigits+czero-clead < (int)precision && fp > DBL_MIN); /* The total output count (max) is now 4+precision */ /* Check for an exponent, if we don't need one we are - * done and just need to terminate the string. At this - * point, exp_b10==(-1) is effectively a flag: it got - * to '-1' because of the decrement, after outputting - * the decimal point above. (The exponent required is - * *not* -1.) + * done and just need to terminate the string. At + * this point exp_b10==(-1) is effectively if flag - it got + * to '-1' because of the decrement after outputing + * the decimal point above (the exponent required is + * *not* -1!) */ if (exp_b10 >= (-1) && exp_b10 <= 2) { /* The following only happens if we didn't output the * leading zeros above for negative exponent, so this - * doesn't add to the digit requirement. Note that the + * doest add to the digit requirement. Note that the * two zeros here can only be output if the two leading * zeros were *not* output, so this doesn't increase * the output count. */ - while (exp_b10-- > 0) *ascii++ = 48; + while (--exp_b10 >= 0) *ascii++ = 48; *ascii = 0; @@ -2575,7 +2939,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, */ size -= cdigits; - *ascii++ = 69; --size; /* 'E': PLUS 1 TOTAL 2+precision */ + *ascii++ = 69, --size; /* 'E': PLUS 1 TOTAL 2+precision */ /* The following use of an unsigned temporary avoids ambiguities in * the signed arithmetic on exp_b10 and permits GCC at least to do @@ -2586,12 +2950,12 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, if (exp_b10 < 0) { - *ascii++ = 45; --size; /* '-': PLUS 1 TOTAL 3+precision */ - uexp_b10 = 0U-exp_b10; + *ascii++ = 45, --size; /* '-': PLUS 1 TOTAL 3+precision */ + uexp_b10 = -exp_b10; } else - uexp_b10 = 0U+exp_b10; + uexp_b10 = exp_b10; cdigits = 0; @@ -2605,7 +2969,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, /* Need another size check here for the exponent digits, so * this need not be considered above. */ - if (size > cdigits) + if ((int)size > cdigits) { while (cdigits > 0) *ascii++ = exponent[--cdigits]; @@ -2634,6 +2998,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, /* Here on buffer too small. */ png_error(png_ptr, "ASCII conversion buffer too small"); } + # endif /* FLOATING_POINT */ # ifdef PNG_FIXED_POINT_SUPPORTED @@ -2641,7 +3006,7 @@ png_ascii_from_fp(png_const_structrp png_ptr, png_charp ascii, size_t size, */ void /* PRIVATE */ png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii, - size_t size, png_fixed_point fp) + png_size_t size, png_fixed_point fp) { /* Require space for 10 decimal digits, a decimal point, a minus sign and a * trailing \0, 13 characters: @@ -2652,16 +3017,14 @@ png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii, /* Avoid overflow here on the minimum integer. */ if (fp < 0) - { - *ascii++ = 45; num = (png_uint_32)(-fp); - } + *ascii++ = 45, --size, num = -fp; else - num = (png_uint_32)fp; + num = fp; if (num <= 0x80000000) /* else overflowed */ { unsigned int ndigits = 0, first = 16 /* flag value */; - char digits[10] = {0}; + char digits[10]; while (num) { @@ -2692,10 +3055,7 @@ png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii, * then ndigits digits to first: */ i = 5; - while (ndigits < i) - { - *ascii++ = 48; --i; - } + while (ndigits < i) *ascii++ = 48, --i; while (ndigits >= first) *ascii++ = digits[--ndigits]; /* Don't output the trailing zeros! */ } @@ -2713,7 +3073,7 @@ png_ascii_from_fixed(png_const_structrp png_ptr, png_charp ascii, png_error(png_ptr, "ASCII conversion buffer too small"); } # endif /* FIXED_POINT */ -#endif /* SCAL */ +#endif /* READ_SCAL */ #if defined(PNG_FLOATING_POINT_SUPPORTED) && \ !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ @@ -2730,35 +3090,11 @@ png_fixed(png_const_structrp png_ptr, double fp, png_const_charp text) if (r > 2147483647. || r < -2147483648.) png_fixed_error(png_ptr, text); -# ifndef PNG_ERROR_TEXT_SUPPORTED - PNG_UNUSED(text) -# endif - return (png_fixed_point)r; } #endif -#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ - !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ - (defined(PNG_cLLI_SUPPORTED) || defined(PNG_mDCV_SUPPORTED)) -png_uint_32 -png_fixed_ITU(png_const_structrp png_ptr, double fp, png_const_charp text) -{ - double r = floor(10000 * fp + .5); - - if (r > 2147483647. || r < 0) - png_fixed_error(png_ptr, text); - -# ifndef PNG_ERROR_TEXT_SUPPORTED - PNG_UNUSED(text) -# endif - - return (png_uint_32)r; -} -#endif - - -#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_COLORSPACE_SUPPORTED) ||\ +#if defined(PNG_READ_GAMMA_SUPPORTED) || \ defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) /* muldiv functions */ /* This API takes signed arguments and rounds the result to the nearest @@ -2766,7 +3102,7 @@ png_fixed_ITU(png_const_structrp png_ptr, double fp, png_const_charp text) * the nearest .00001). Overflow and divide by zero are signalled in * the result, a boolean - true on success, false on overflow. */ -int /* PRIVATE */ +int png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, png_int_32 divisor) { @@ -2863,12 +3199,11 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, if (s00 >= (D >> 1)) ++result; - if (negative != 0) + if (negative) result = -result; /* Check for overflow. */ - if ((negative != 0 && result <= 0) || - (negative == 0 && result >= 0)) + if ((negative && result <= 0) || (!negative && result >= 0)) { *res = result; return 1; @@ -2880,7 +3215,27 @@ png_muldiv(png_fixed_point_p res, png_fixed_point a, png_int_32 times, return 0; } +#endif /* READ_GAMMA || INCH_CONVERSIONS */ +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) +/* The following is for when the caller doesn't much care about the + * result. + */ +png_fixed_point +png_muldiv_warn(png_const_structrp png_ptr, png_fixed_point a, png_int_32 times, + png_int_32 divisor) +{ + png_fixed_point result; + + if (png_muldiv(&result, a, times, divisor)) + return result; + + png_warning(png_ptr, "fixed point overflow ignored"); + return 0; +} +#endif + +#ifdef PNG_GAMMA_SUPPORTED /* more fixed point functions for gamma */ /* Calculate a reciprocal, return 0 on div-by-zero or overflow. */ png_fixed_point png_reciprocal(png_fixed_point a) @@ -2893,44 +3248,31 @@ png_reciprocal(png_fixed_point a) #else png_fixed_point res; - if (png_muldiv(&res, 100000, 100000, a) != 0) + if (png_muldiv(&res, 100000, 100000, a)) return res; #endif return 0; /* error/overflow */ } -#endif /* READ_GAMMA || COLORSPACE || INCH_CONVERSIONS || READ_pHYS */ -#ifdef PNG_READ_GAMMA_SUPPORTED /* This is the shared test on whether a gamma value is 'significant' - whether * it is worth doing gamma correction. */ int /* PRIVATE */ png_gamma_significant(png_fixed_point gamma_val) { - /* sRGB: 1/2.2 == 0.4545(45) - * AdobeRGB: 1/(2+51/256) ~= 0.45471 5dp - * - * So the correction from AdobeRGB to sRGB (output) is: - * - * 2.2/(2+51/256) == 1.00035524 - * - * I.e. vanishly small (<4E-4) but still detectable in 16-bit linear (+/- - * 23). Note that the Adobe choice seems to be something intended to give an - * exact number with 8 binary fractional digits - it is the closest to 2.2 - * that is possible a base 2 .8p representation. - */ return gamma_val < PNG_FP_1 - PNG_GAMMA_THRESHOLD_FIXED || gamma_val > PNG_FP_1 + PNG_GAMMA_THRESHOLD_FIXED; } +#endif -#ifndef PNG_FLOATING_ARITHMETIC_SUPPORTED +#ifdef PNG_READ_GAMMA_SUPPORTED /* A local convenience routine. */ static png_fixed_point png_product2(png_fixed_point a, png_fixed_point b) { - /* The required result is a * b; the following preserves accuracy. */ -#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED /* Should now be unused */ + /* The required result is 1/a * 1/b; the following preserves accuracy. */ +#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED double r = a * 1E-5; r *= b; r = floor(r+.5); @@ -2940,28 +3282,25 @@ png_product2(png_fixed_point a, png_fixed_point b) #else png_fixed_point res; - if (png_muldiv(&res, a, b, 100000) != 0) + if (png_muldiv(&res, a, b, 100000)) return res; #endif return 0; /* overflow */ } -#endif /* FLOATING_ARITHMETIC */ +/* The inverse of the above. */ png_fixed_point png_reciprocal2(png_fixed_point a, png_fixed_point b) { /* The required result is 1/a * 1/b; the following preserves accuracy. */ #ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - if (a != 0 && b != 0) - { - double r = 1E15/a; - r /= b; - r = floor(r+.5); + double r = 1E15/a; + r /= b; + r = floor(r+.5); - if (r <= 2147483647. && r >= -2147483648.) - return (png_fixed_point)r; - } + if (r <= 2147483647. && r >= -2147483648.) + return (png_fixed_point)r; #else /* This may overflow because the range of png_fixed_point isn't symmetric, * but this API is only used for the product of file and screen gamma so it @@ -3100,7 +3439,6 @@ png_log8bit(unsigned int x) * Zero (257): 0 * End (258): 23499 */ -#ifdef PNG_16BIT_SUPPORTED static png_int_32 png_log16bit(png_uint_32 x) { @@ -3151,20 +3489,19 @@ png_log16bit(png_uint_32 x) /* Safe, because the result can't have more than 20 bits: */ return (png_int_32)((lg2 + 2048) >> 12); } -#endif /* 16BIT */ /* The 'exp()' case must invert the above, taking a 20-bit fixed point * logarithmic value and returning a 16 or 8-bit number as appropriate. In * each case only the low 16 bits are relevant - the fraction - since the * integer bits (the top 4) simply determine a shift. * - * The worst case is the 16-bit distinction between 65535 and 65534. This - * requires perhaps spurious accuracy in the decoding of the logarithm to + * The worst case is the 16-bit distinction between 65535 and 65534, this + * requires perhaps spurious accuracty in the decoding of the logarithm to * distinguish log2(65535/65534.5) - 10^-5 or 17 bits. There is little chance * of getting this accuracy in practice. * * To deal with this the following exp() function works out the exponent of the - * fractional part of the logarithm by using an accurate 32-bit value from the + * frational part of the logarithm by using an accurate 32-bit value from the * top four fractional bits then multiplying in the remaining bits. */ static const png_uint_32 @@ -3199,7 +3536,7 @@ png_exp(png_fixed_point x) if (x > 0 && x <= 0xfffff) /* Else overflow or zero (underflow) */ { /* Obtain a 4-bit approximation */ - png_uint_32 e = png_32bit_exp[(x >> 12) & 0x0f]; + png_uint_32 e = png_32bit_exp[(x >> 12) & 0xf]; /* Incorporate the low 12 bits - these decrease the returned value by * multiplying by a number less than 1 if the bit is set. The multiplier @@ -3247,15 +3584,14 @@ png_exp8bit(png_fixed_point lg2) /* Get a 32-bit value: */ png_uint_32 x = png_exp(lg2); - /* Convert the 32-bit value to 0..255 by multiplying by 256-1. Note that the + /* Convert the 32-bit value to 0..255 by multiplying by 256-1, note that the * second, rounding, step can't overflow because of the first, subtraction, * step. */ x -= x >> 8; - return (png_byte)(((x + 0x7fffffU) >> 24) & 0xff); + return (png_byte)((x + 0x7fffffU) >> 24); } -#ifdef PNG_16BIT_SUPPORTED static png_uint_16 png_exp16bit(png_fixed_point lg2) { @@ -3266,7 +3602,6 @@ png_exp16bit(png_fixed_point lg2) x -= x >> 16; return (png_uint_16)((x + 32767U) >> 16); } -#endif /* 16BIT */ #endif /* FLOATING_ARITHMETIC */ png_byte @@ -3275,37 +3610,13 @@ png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) if (value > 0 && value < 255) { # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - /* 'value' is unsigned, ANSI-C90 requires the compiler to correctly - * convert this to a floating point value. This includes values that - * would overflow if 'value' were to be converted to 'int'. - * - * Apparently GCC, however, does an intermediate conversion to (int) - * on some (ARM) but not all (x86) platforms, possibly because of - * hardware FP limitations. (E.g. if the hardware conversion always - * assumes the integer register contains a signed value.) This results - * in ANSI-C undefined behavior for large values. - * - * Other implementations on the same machine might actually be ANSI-C90 - * conformant and therefore compile spurious extra code for the large - * values. - * - * We can be reasonably sure that an unsigned to float conversion - * won't be faster than an int to float one. Therefore this code - * assumes responsibility for the undefined behavior, which it knows - * can't happen because of the check above. - * - * Note the argument to this routine is an (unsigned int) because, on - * 16-bit platforms, it is assigned a value which might be out of - * range for an (int); that would result in undefined behavior in the - * caller if the *argument* ('value') were to be declared (int). - */ - double r = floor(255*pow((int)/*SAFE*/value/255.,gamma_val*.00001)+.5); + double r = floor(255*pow(value/255.,gamma_val*.00001)+.5); return (png_byte)r; # else png_int_32 lg2 = png_log8bit(value); png_fixed_point res; - if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0) + if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1)) return png_exp8bit(res); /* Overflow. */ @@ -3313,39 +3624,31 @@ png_gamma_8bit_correct(unsigned int value, png_fixed_point gamma_val) # endif } - return (png_byte)(value & 0xff); + return (png_byte)value; } -#ifdef PNG_16BIT_SUPPORTED png_uint_16 png_gamma_16bit_correct(unsigned int value, png_fixed_point gamma_val) { if (value > 0 && value < 65535) { -# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - /* The same (unsigned int)->(double) constraints apply here as above, - * however in this case the (unsigned int) to (int) conversion can - * overflow on an ANSI-C90 compliant system so the cast needs to ensure - * that this is not possible. - */ - double r = floor(65535*pow((png_int_32)value/65535., - gamma_val*.00001)+.5); - return (png_uint_16)r; -# else - png_int_32 lg2 = png_log16bit(value); - png_fixed_point res; +# ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED + double r = floor(65535*pow(value/65535.,gamma_val*.00001)+.5); + return (png_uint_16)r; +# else + png_int_32 lg2 = png_log16bit(value); + png_fixed_point res; - if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1) != 0) - return png_exp16bit(res); + if (png_muldiv(&res, gamma_val, lg2, PNG_FP_1)) + return png_exp16bit(res); - /* Overflow. */ - value = 0; -# endif + /* Overflow. */ + value = 0; +# endif } return (png_uint_16)value; } -#endif /* 16BIT */ /* This does the right thing based on the bit_depth field of the * png_struct, interpreting values as 8-bit or 16-bit. While the result @@ -3359,16 +3662,10 @@ png_gamma_correct(png_structrp png_ptr, unsigned int value, if (png_ptr->bit_depth == 8) return png_gamma_8bit_correct(value, gamma_val); -#ifdef PNG_16BIT_SUPPORTED else return png_gamma_16bit_correct(value, gamma_val); -#else - /* should not reach this */ - return 0; -#endif /* 16BIT */ } -#ifdef PNG_16BIT_SUPPORTED /* Internal function to build a single 16-bit table - the table consists of * 'num' 256 entry subtables, where 'num' is determined by 'shift' - the amount * to shift the input values right (or 16-number_of_signifiant_bits). @@ -3379,18 +3676,12 @@ png_gamma_correct(png_structrp png_ptr, unsigned int value, */ static void png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable, - unsigned int shift, png_fixed_point gamma_val) + PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) { /* Various values derived from 'shift': */ - unsigned int num = 1U << (8U - shift); -#ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED - /* CSE the division and work round wacky GCC warnings (see the comments - * in png_gamma_8bit_correct for where these come from.) - */ - double fmax = 1.0 / (((png_int_32)1 << (16U - shift)) - 1); -#endif - unsigned int max = (1U << (16U - shift)) - 1U; - unsigned int max_by_2 = 1U << (15U - shift); + PNG_CONST unsigned int num = 1U << (8U - shift); + PNG_CONST unsigned int max = (1U << (16U - shift))-1U; + PNG_CONST unsigned int max_by_2 = 1U << (15U-shift); unsigned int i; png_uint_16pp table = *ptable = @@ -3404,7 +3695,7 @@ png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable, /* The 'threshold' test is repeated here because it can arise for one of * the 16-bit tables even if the others don't hit it. */ - if (png_gamma_significant(gamma_val) != 0) + if (png_gamma_significant(gamma_val)) { /* The old code would overflow at the end and this would cause the * 'pow' function to return a result >1, resulting in an @@ -3420,13 +3711,10 @@ png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable, png_uint_32 ig = (j << (8-shift)) + i; # ifdef PNG_FLOATING_ARITHMETIC_SUPPORTED /* Inline the 'max' scaling operation: */ - /* See png_gamma_8bit_correct for why the cast to (int) is - * required here. - */ - double d = floor(65535.*pow(ig*fmax, gamma_val*.00001)+.5); + double d = floor(65535*pow(ig/(double)max, gamma_val*.00001)+.5); sub_table[j] = (png_uint_16)d; # else - if (shift != 0) + if (shift) ig = (ig * 65535U + max_by_2)/max; sub_table[j] = png_gamma_16bit_correct(ig, gamma_val); @@ -3442,7 +3730,7 @@ png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable, { png_uint_32 ig = (j << (8-shift)) + i; - if (shift != 0) + if (shift) ig = (ig * 65535U + max_by_2)/max; sub_table[j] = (png_uint_16)ig; @@ -3456,10 +3744,10 @@ png_build_16bit_table(png_structrp png_ptr, png_uint_16pp *ptable, */ static void png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable, - unsigned int shift, png_fixed_point gamma_val) + PNG_CONST unsigned int shift, PNG_CONST png_fixed_point gamma_val) { - unsigned int num = 1U << (8U - shift); - unsigned int max = (1U << (16U - shift))-1U; + PNG_CONST unsigned int num = 1U << (8U - shift); + PNG_CONST unsigned int max = (1U << (16U - shift))-1U; unsigned int i; png_uint_32 last; @@ -3468,7 +3756,7 @@ png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable, /* 'num' is the number of tables and also the number of low bits of low * bits of the input 16-bit value used to select a table. Each table is - * itself indexed by the high 8 bits of the value. + * itself index by the high 8 bits of the value. */ for (i = 0; i < num; i++) table[i] = (png_uint_16p)png_malloc(png_ptr, @@ -3516,26 +3804,23 @@ png_build_16to8_table(png_structrp png_ptr, png_uint_16pp *ptable, last++; } } -#endif /* 16BIT */ /* Build a single 8-bit table: same as the 16-bit case but much simpler (and * typically much faster). Note that libpng currently does no sBIT processing - * (apparently contrary to the spec) so a 256-entry table is always generated. + * (apparently contrary to the spec) so a 256 entry table is always generated. */ static void png_build_8bit_table(png_structrp png_ptr, png_bytepp ptable, - png_fixed_point gamma_val) + PNG_CONST png_fixed_point gamma_val) { unsigned int i; png_bytep table = *ptable = (png_bytep)png_malloc(png_ptr, 256); - if (png_gamma_significant(gamma_val) != 0) - for (i=0; i<256; i++) - table[i] = png_gamma_8bit_correct(i, gamma_val); + if (png_gamma_significant(gamma_val)) for (i=0; i<256; i++) + table[i] = png_gamma_8bit_correct(i, gamma_val); - else - for (i=0; i<256; ++i) - table[i] = (png_byte)(i & 0xff); + else for (i=0; i<256; ++i) + table[i] = (png_byte)i; } /* Used from png_read_destroy and below to release the memory used by the gamma @@ -3547,7 +3832,6 @@ png_destroy_gamma_table(png_structrp png_ptr) png_free(png_ptr, png_ptr->gamma_table); png_ptr->gamma_table = NULL; -#ifdef PNG_16BIT_SUPPORTED if (png_ptr->gamma_16_table != NULL) { int i; @@ -3559,7 +3843,6 @@ png_destroy_gamma_table(png_structrp png_ptr) png_free(png_ptr, png_ptr->gamma_16_table); png_ptr->gamma_16_table = NULL; } -#endif /* 16BIT */ #if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ @@ -3569,7 +3852,6 @@ png_destroy_gamma_table(png_structrp png_ptr) png_free(png_ptr, png_ptr->gamma_to_1); png_ptr->gamma_to_1 = NULL; -#ifdef PNG_16BIT_SUPPORTED if (png_ptr->gamma_16_from_1 != NULL) { int i; @@ -3592,7 +3874,6 @@ png_destroy_gamma_table(png_structrp png_ptr) png_free(png_ptr, png_ptr->gamma_16_to_1); png_ptr->gamma_16_to_1 = NULL; } -#endif /* 16BIT */ #endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ } @@ -3600,170 +3881,141 @@ png_destroy_gamma_table(png_structrp png_ptr) * tables, we don't make a full table if we are reducing to 8-bit in * the future. Note also how the gamma_16 tables are segmented so that * we don't need to allocate > 64K chunks for a full 16-bit table. - * - * TODO: move this to pngrtran.c and make it static. Better yet create - * pngcolor.c and put all the PNG_COLORSPACE stuff in there. */ -#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ - defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) -# define GAMMA_TRANSFORMS 1 /* #ifdef CSE */ -#else -# define GAMMA_TRANSFORMS 0 -#endif - void /* PRIVATE */ png_build_gamma_table(png_structrp png_ptr, int bit_depth) { - png_fixed_point file_gamma, screen_gamma; - png_fixed_point correction; -# if GAMMA_TRANSFORMS - png_fixed_point file_to_linear, linear_to_screen; -# endif + png_debug(1, "in png_build_gamma_table"); - png_debug(1, "in png_build_gamma_table"); + /* Remove any existing table; this copes with multiple calls to + * png_read_update_info. The warning is because building the gamma tables + * multiple times is a performance hit - it's harmless but the ability to call + * png_read_update_info() multiple times is new in 1.5.6 so it seems sensible + * to warn if the app introduces such a hit. + */ + if (png_ptr->gamma_table != NULL || png_ptr->gamma_16_table != NULL) + { + png_warning(png_ptr, "gamma table being rebuilt"); + png_destroy_gamma_table(png_ptr); + } - /* Remove any existing table; this copes with multiple calls to - * png_read_update_info. The warning is because building the gamma tables - * multiple times is a performance hit - it's harmless but the ability to - * call png_read_update_info() multiple times is new in 1.5.6 so it seems - * sensible to warn if the app introduces such a hit. - */ - if (png_ptr->gamma_table != NULL || png_ptr->gamma_16_table != NULL) - { - png_warning(png_ptr, "gamma table being rebuilt"); - png_destroy_gamma_table(png_ptr); - } + if (bit_depth <= 8) + { + png_build_8bit_table(png_ptr, &png_ptr->gamma_table, + png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma) : PNG_FP_1); - /* The following fields are set, finally, in png_init_read_transformations. - * If file_gamma is 0 (unset) nothing can be done otherwise if screen_gamma - * is 0 (unset) there is no gamma correction but to/from linear is possible. - */ - file_gamma = png_ptr->file_gamma; - screen_gamma = png_ptr->screen_gamma; -# if GAMMA_TRANSFORMS - file_to_linear = png_reciprocal(file_gamma); -# endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) + { + png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1, + png_reciprocal(png_ptr->colorspace.gamma)); - if (screen_gamma > 0) - { -# if GAMMA_TRANSFORMS - linear_to_screen = png_reciprocal(screen_gamma); -# endif - correction = png_reciprocal2(screen_gamma, file_gamma); - } - else /* screen gamma unknown */ - { -# if GAMMA_TRANSFORMS - linear_to_screen = file_gamma; -# endif - correction = PNG_FP_1; - } + png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1, + png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : + png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); + } +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ + } + else + { + png_byte shift, sig_bit; - if (bit_depth <= 8) - { - png_build_8bit_table(png_ptr, &png_ptr->gamma_table, correction); + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) + { + sig_bit = png_ptr->sig_bit.red; -#if GAMMA_TRANSFORMS - if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0) - { - png_build_8bit_table(png_ptr, &png_ptr->gamma_to_1, file_to_linear); + if (png_ptr->sig_bit.green > sig_bit) + sig_bit = png_ptr->sig_bit.green; + + if (png_ptr->sig_bit.blue > sig_bit) + sig_bit = png_ptr->sig_bit.blue; + } + else + sig_bit = png_ptr->sig_bit.gray; + + /* 16-bit gamma code uses this equation: + * + * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8] + * + * Where 'iv' is the input color value and 'ov' is the output value - + * pow(iv, gamma). + * + * Thus the gamma table consists of up to 256 256 entry tables. The table + * is selected by the (8-gamma_shift) most significant of the low 8 bits of + * the color value then indexed by the upper 8 bits: + * + * table[low bits][high 8 bits] + * + * So the table 'n' corresponds to all those 'iv' of: + * + * ..<(n+1 << gamma_shift)-1> + * + */ + if (sig_bit > 0 && sig_bit < 16U) + shift = (png_byte)(16U - sig_bit); /* shift == insignificant bits */ + + else + shift = 0; /* keep all 16 bits */ + + if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) + { + /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively + * the significant bits in the *input* when the output will + * eventually be 8 bits. By default it is 11. + */ + if (shift < (16U - PNG_MAX_GAMMA_8)) + shift = (16U - PNG_MAX_GAMMA_8); + } + + if (shift > 8U) + shift = 8U; /* Guarantees at least one table! */ + + png_ptr->gamma_shift = shift; - png_build_8bit_table(png_ptr, &png_ptr->gamma_from_1, - linear_to_screen); - } -#endif /* GAMMA_TRANSFORMS */ - } #ifdef PNG_16BIT_SUPPORTED - else - { - png_byte shift, sig_bit; - - if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) - { - sig_bit = png_ptr->sig_bit.red; - - if (png_ptr->sig_bit.green > sig_bit) - sig_bit = png_ptr->sig_bit.green; - - if (png_ptr->sig_bit.blue > sig_bit) - sig_bit = png_ptr->sig_bit.blue; - } - else - sig_bit = png_ptr->sig_bit.gray; - - /* 16-bit gamma code uses this equation: - * - * ov = table[(iv & 0xff) >> gamma_shift][iv >> 8] - * - * Where 'iv' is the input color value and 'ov' is the output value - - * pow(iv, gamma). - * - * Thus the gamma table consists of up to 256 256-entry tables. The table - * is selected by the (8-gamma_shift) most significant of the low 8 bits - * of the color value then indexed by the upper 8 bits: - * - * table[low bits][high 8 bits] - * - * So the table 'n' corresponds to all those 'iv' of: - * - * ..<(n+1 << gamma_shift)-1> - * - */ - if (sig_bit > 0 && sig_bit < 16U) - /* shift == insignificant bits */ - shift = (png_byte)((16U - sig_bit) & 0xff); - - else - shift = 0; /* keep all 16 bits */ - - if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0) - { - /* PNG_MAX_GAMMA_8 is the number of bits to keep - effectively - * the significant bits in the *input* when the output will - * eventually be 8 bits. By default it is 11. - */ - if (shift < (16U - PNG_MAX_GAMMA_8)) - shift = (16U - PNG_MAX_GAMMA_8); - } - - if (shift > 8U) - shift = 8U; /* Guarantees at least one table! */ - - png_ptr->gamma_shift = shift; - - /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now - * PNG_COMPOSE). This effectively smashed the background calculation for - * 16-bit output because the 8-bit table assumes the result will be - * reduced to 8 bits. - */ - if ((png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) != 0) + /* NOTE: prior to 1.5.4 this test used to include PNG_BACKGROUND (now + * PNG_COMPOSE). This effectively smashed the background calculation for + * 16-bit output because the 8-bit table assumes the result will be reduced + * to 8 bits. + */ + if (png_ptr->transformations & (PNG_16_TO_8 | PNG_SCALE_16_TO_8)) +#endif png_build_16to8_table(png_ptr, &png_ptr->gamma_16_table, shift, - png_reciprocal(correction)); - else + png_ptr->screen_gamma > 0 ? png_product2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma) : PNG_FP_1); + +#ifdef PNG_16BIT_SUPPORTED + else png_build_16bit_table(png_ptr, &png_ptr->gamma_16_table, shift, - correction); + png_ptr->screen_gamma > 0 ? png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma) : PNG_FP_1); +#endif -# if GAMMA_TRANSFORMS - if ((png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) != 0) - { - png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift, - file_to_linear); +#if defined(PNG_READ_BACKGROUND_SUPPORTED) || \ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) || \ + defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) + if (png_ptr->transformations & (PNG_COMPOSE | PNG_RGB_TO_GRAY)) + { + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_to_1, shift, + png_reciprocal(png_ptr->colorspace.gamma)); - /* Notice that the '16 from 1' table should be full precision, however - * the lookup on this table still uses gamma_shift, so it can't be. - * TODO: fix this. - */ - png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift, - linear_to_screen); - } -#endif /* GAMMA_TRANSFORMS */ - } -#endif /* 16BIT */ + /* Notice that the '16 from 1' table should be full precision, however + * the lookup on this table still uses gamma_shift, so it can't be. + * TODO: fix this. + */ + png_build_16bit_table(png_ptr, &png_ptr->gamma_16_from_1, shift, + png_ptr->screen_gamma > 0 ? png_reciprocal(png_ptr->screen_gamma) : + png_ptr->colorspace.gamma/* Probably doing rgb_to_gray */); + } +#endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ + } } #endif /* READ_GAMMA */ -/* HARDWARE OR SOFTWARE OPTION SUPPORT */ +/* HARDWARE OPTION SUPPORT */ #ifdef PNG_SET_OPTION_SUPPORTED int PNGAPI png_set_option(png_structrp png_ptr, int option, int onoff) @@ -3771,13 +4023,13 @@ png_set_option(png_structrp png_ptr, int option, int onoff) if (png_ptr != NULL && option >= 0 && option < PNG_OPTION_NEXT && (option & 1) == 0) { - png_uint_32 mask = 3U << option; - png_uint_32 setting = (2U + (onoff != 0)) << option; - png_uint_32 current = png_ptr->options; + int mask = 3 << option; + int setting = (2 + (onoff != 0)) << option; + int current = png_ptr->options; - png_ptr->options = (png_uint_32)((current & ~mask) | setting); + png_ptr->options = (png_byte)((current & ~mask) | setting); - return (int)(current & mask) >> option; + return (current & mask) >> option; } return PNG_OPTION_INVALID; @@ -3789,9 +4041,9 @@ png_set_option(png_structrp png_ptr, int option, int onoff) defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) /* sRGB conversion tables; these are machine generated with the code in * contrib/tools/makesRGB.c. The actual sRGB transfer curve defined in the - * specification (see the article at https://en.wikipedia.org/wiki/SRGB) + * specification (see the article at http://en.wikipedia.org/wiki/SRGB) * is used, not the gamma=1/2.2 approximation use elsewhere in libpng. - * The sRGB to linear table is exact (to the nearest 16-bit linear fraction). + * The sRGB to linear table is exact (to the nearest 16 bit linear fraction). * The inverse (linear to sRGB) table has accuracies as follows: * * For all possible (255*65535+1) input values: @@ -3802,7 +4054,7 @@ png_set_option(png_structrp png_ptr, int option, int onoff) * * error: -0.513727 - 0.607759, 308 (0.469978%) of readings inexact * - * In all cases the inexact readings are only off by one. + * In all cases the inexact readings are off by one. */ #ifdef PNG_SIMPLIFIED_READ_SUPPORTED @@ -3842,7 +4094,8 @@ const png_uint_16 png_sRGB_table[256] = 57105,57646,58190,58737,59287,59840,60396,60955, 61517,62082,62650,63221,63795,64372,64952,65535 }; -#endif /* SIMPLIFIED_READ */ + +#endif /* simplified read only */ /* The base/delta tables are required for both read and write (but currently * only the simplified versions.) @@ -3970,9 +4223,9 @@ png_image_free_function(png_voidp argument) /* First free any data held in the control structure. */ # ifdef PNG_STDIO_SUPPORTED - if (cp->owned_file != 0) + if (cp->owned_file) { - FILE *fp = png_voidcast(FILE *, cp->png_ptr->io_ptr); + FILE *fp = png_voidcast(FILE*, cp->png_ptr->io_ptr); cp->owned_file = 0; /* Ignore errors here. */ @@ -3994,7 +4247,7 @@ png_image_free_function(png_voidp argument) png_free(c.png_ptr, cp); /* Then the structures, calling the correct API. */ - if (c.for_write != 0) + if (c.for_write) { # ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED png_destroy_write_struct(&c.png_ptr, &c.info_ptr); @@ -4025,7 +4278,8 @@ png_image_free(png_imagep image) if (image != NULL && image->opaque != NULL && image->opaque->error_buf == NULL) { - png_image_free_function(image); + /* Ignore errors here: */ + (void)png_safe_execute(image, png_image_free_function, image); image->opaque = NULL; } } @@ -4041,4 +4295,4 @@ png_image_error(png_imagep image, png_const_charp error_message) } #endif /* SIMPLIFIED READ/WRITE */ -#endif /* READ || WRITE */ +#endif /* defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) */ diff --git a/Windows_Libs/Dev/Render/libpng/png.h b/Windows_Libs/Dev/Render/libpng/png.h index 38fd349..68a0772 100644 --- a/Windows_Libs/Dev/Render/libpng/png.h +++ b/Windows_Libs/Dev/Render/libpng/png.h @@ -1,197 +1,26 @@ + /* png.h - header file for PNG reference library * - * libpng version 1.6.55 + * libpng version 1.6.2 - April 25, 2013 + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * - * Copyright (c) 2018-2026 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. - * - * This code is released under the libpng license. (See LICENSE, below.) + * This code is released under the libpng license (See LICENSE, below) * * Authors and maintainers: * libpng versions 0.71, May 1995, through 0.88, January 1996: Guy Schalnat - * libpng versions 0.89, June 1996, through 0.96, May 1997: Andreas Dilger - * libpng versions 0.97, January 1998, through 1.6.35, July 2018: - * Glenn Randers-Pehrson - * libpng versions 1.6.36, December 2018, through 1.6.55, February 2026: - * Cosmin Truta + * libpng versions 0.89c, June 1996, through 0.96, May 1997: Andreas Dilger + * libpng versions 0.97, January 1998, through 1.6.2 - April 25, 2013: Glenn * See also "Contributing Authors", below. - */ - -/* - * COPYRIGHT NOTICE, DISCLAIMER, and LICENSE - * ========================================= * - * PNG Reference Library License version 2 - * --------------------------------------- + * Note about libpng version numbers: * - * * Copyright (c) 1995-2026 The PNG Reference Library Authors. - * * Copyright (c) 2018-2026 Cosmin Truta. - * * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson. - * * Copyright (c) 1996-1997 Andreas Dilger. - * * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. - * - * The software is supplied "as is", without warranty of any kind, - * express or implied, including, without limitation, the warranties - * of merchantability, fitness for a particular purpose, title, and - * non-infringement. In no event shall the Copyright owners, 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, even if advised of the possibility - * of such damage. - * - * Permission is hereby granted to use, copy, modify, and distribute - * this software, or portions hereof, for any purpose, without fee, - * 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 Copyright notice may not be removed or altered from any - * source or altered source distribution. - * - * - * PNG Reference Library License version 1 (for libpng 0.5 through 1.6.35) - * ----------------------------------------------------------------------- - * - * libpng versions 1.0.7, July 1, 2000, through 1.6.35, July 15, 2018 are - * Copyright (c) 2000-2002, 2004, 2006-2018 Glenn Randers-Pehrson, are - * derived from libpng-1.0.6, and are distributed according to the same - * disclaimer and license as libpng-1.0.6 with the following individuals - * added to the list of Contributing Authors: - * - * Simon-Pierre Cadieux - * Eric S. Raymond - * Mans Rullgard - * Cosmin Truta - * Gilles Vollant - * James Yu - * Mandar Sahastrabuddhe - * Google Inc. - * Vadim Barkov - * - * and with the following additions to the disclaimer: - * - * There is no warranty against interference with your enjoyment of - * the library or against infringement. There is no warranty that our - * efforts or the library will fulfill any of your particular purposes - * or needs. This library is provided with all faults, and the entire - * risk of satisfactory quality, performance, accuracy, and effort is - * with the user. - * - * Some files in the "contrib" directory and some configure-generated - * files that are distributed with libpng have other copyright owners, and - * are released under other open source licenses. - * - * libpng versions 0.97, January 1998, through 1.0.6, March 20, 2000, are - * Copyright (c) 1998-2000 Glenn Randers-Pehrson, are derived from - * libpng-0.96, and are distributed according to the same disclaimer and - * license as libpng-0.96, with the following individuals added to the - * list of Contributing Authors: - * - * Tom Lane - * Glenn Randers-Pehrson - * Willem van Schaik - * - * libpng versions 0.89, June 1996, through 0.96, May 1997, are - * Copyright (c) 1996-1997 Andreas Dilger, are derived from libpng-0.88, - * and are distributed according to the same disclaimer and license as - * libpng-0.88, with the following individuals added to the list of - * Contributing Authors: - * - * John Bowler - * Kevin Bracey - * Sam Bushell - * Magnus Holmgren - * Greg Roelofs - * Tom Tanner - * - * Some files in the "scripts" directory have other copyright owners, - * but are released under this license. - * - * libpng versions 0.5, May 1995, through 0.88, January 1996, are - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. - * - * For the purposes of this copyright and license, "Contributing Authors" - * is defined as the following set of individuals: - * - * Andreas Dilger - * Dave Martindale - * Guy Eric Schalnat - * Paul Schmidt - * Tim Wegner - * - * The PNG Reference Library is supplied "AS IS". The Contributing - * Authors and Group 42, Inc. disclaim all warranties, expressed or - * implied, including, without limitation, the warranties of - * merchantability and of fitness for any purpose. The Contributing - * Authors and Group 42, Inc. assume no liability for direct, indirect, - * incidental, special, exemplary, or consequential damages, which may - * result from the use of the PNG Reference Library, even if advised of - * the possibility of such damage. - * - * Permission is hereby granted to use, copy, modify, and distribute this - * source code, or portions hereof, for any purpose, without fee, subject - * to the following restrictions: - * - * 1. The origin of this source code must not be misrepresented. - * - * 2. Altered versions must be plainly marked as such and must not - * be misrepresented as being the original source. - * - * 3. This Copyright notice may not be removed or altered from any - * source or altered source distribution. - * - * The Contributing Authors and Group 42, Inc. specifically permit, - * without fee, and encourage the use of this source code as a component - * to supporting the PNG file format in commercial products. If you use - * this source code in a product, acknowledgment is not required but would - * be appreciated. - * - * END OF COPYRIGHT NOTICE, DISCLAIMER, and LICENSE. - * - * TRADEMARK - * ========= - * - * The name "libpng" has not been registered by the Copyright owners - * as a trademark in any jurisdiction. However, because libpng has - * been distributed and maintained world-wide, continually since 1995, - * the Copyright owners claim "common-law trademark protection" in any - * jurisdiction where common-law trademark is recognized. - */ - -/* - * A "png_get_copyright" function is available, for convenient use in "about" - * boxes and the like: - * - * printf("%s", png_get_copyright(NULL)); - * - * Also, the PNG logo (in PNG format, of course) is supplied in the - * files "pngbar.png" and "pngbar.jpg (88x31) and "pngnow.png" (98x31). - */ - -/* - * The contributing authors would like to thank all those who helped - * with testing, bug fixes, and patience. This wouldn't have been - * possible without all of you. - * - * Thanks to Frank J. T. Wojcik for helping with the documentation. - */ - -/* Note about libpng version numbers: - * - * Due to various miscommunications, unforeseen code incompatibilities - * and occasional factors outside the authors' control, version numbering - * on the library has not always been consistent and straightforward. - * The following table summarizes matters since version 0.89c, which was - * the first widely used release: + * Due to various miscommunications, unforeseen code incompatibilities + * and occasional factors outside the authors' control, version numbering + * on the library has not always been consistent and straightforward. + * The following table summarizes matters since version 0.89c, which was + * the first widely used release: * * source png.h png.h shared-lib * version string int version @@ -229,34 +58,317 @@ * 1.0.7beta15-18 1 10007 2.1.0.7beta15-18 (binary compatible) * 1.0.7rc1-2 1 10007 2.1.0.7rc1-2 (binary compatible) * 1.0.7 1 10007 (still compatible) - * ... - * 1.0.69 10 10069 10.so.0.69[.0] - * ... - * 1.2.59 13 10259 12.so.0.59[.0] - * ... - * 1.4.20 14 10420 14.so.0.20[.0] - * ... - * 1.5.30 15 10530 15.so.15.30[.0] - * ... - * 1.6.55 16 10655 16.so.16.55[.0] + * 1.0.8beta1-4 1 10008 2.1.0.8beta1-4 + * 1.0.8rc1 1 10008 2.1.0.8rc1 + * 1.0.8 1 10008 2.1.0.8 + * 1.0.9beta1-6 1 10009 2.1.0.9beta1-6 + * 1.0.9rc1 1 10009 2.1.0.9rc1 + * 1.0.9beta7-10 1 10009 2.1.0.9beta7-10 + * 1.0.9rc2 1 10009 2.1.0.9rc2 + * 1.0.9 1 10009 2.1.0.9 + * 1.0.10beta1 1 10010 2.1.0.10beta1 + * 1.0.10rc1 1 10010 2.1.0.10rc1 + * 1.0.10 1 10010 2.1.0.10 + * 1.0.11beta1-3 1 10011 2.1.0.11beta1-3 + * 1.0.11rc1 1 10011 2.1.0.11rc1 + * 1.0.11 1 10011 2.1.0.11 + * 1.0.12beta1-2 2 10012 2.1.0.12beta1-2 + * 1.0.12rc1 2 10012 2.1.0.12rc1 + * 1.0.12 2 10012 2.1.0.12 + * 1.1.0a-f - 10100 2.1.1.0a-f (branch abandoned) + * 1.2.0beta1-2 2 10200 2.1.2.0beta1-2 + * 1.2.0beta3-5 3 10200 3.1.2.0beta3-5 + * 1.2.0rc1 3 10200 3.1.2.0rc1 + * 1.2.0 3 10200 3.1.2.0 + * 1.2.1beta1-4 3 10201 3.1.2.1beta1-4 + * 1.2.1rc1-2 3 10201 3.1.2.1rc1-2 + * 1.2.1 3 10201 3.1.2.1 + * 1.2.2beta1-6 12 10202 12.so.0.1.2.2beta1-6 + * 1.0.13beta1 10 10013 10.so.0.1.0.13beta1 + * 1.0.13rc1 10 10013 10.so.0.1.0.13rc1 + * 1.2.2rc1 12 10202 12.so.0.1.2.2rc1 + * 1.0.13 10 10013 10.so.0.1.0.13 + * 1.2.2 12 10202 12.so.0.1.2.2 + * 1.2.3rc1-6 12 10203 12.so.0.1.2.3rc1-6 + * 1.2.3 12 10203 12.so.0.1.2.3 + * 1.2.4beta1-3 13 10204 12.so.0.1.2.4beta1-3 + * 1.0.14rc1 13 10014 10.so.0.1.0.14rc1 + * 1.2.4rc1 13 10204 12.so.0.1.2.4rc1 + * 1.0.14 10 10014 10.so.0.1.0.14 + * 1.2.4 13 10204 12.so.0.1.2.4 + * 1.2.5beta1-2 13 10205 12.so.0.1.2.5beta1-2 + * 1.0.15rc1-3 10 10015 10.so.0.1.0.15rc1-3 + * 1.2.5rc1-3 13 10205 12.so.0.1.2.5rc1-3 + * 1.0.15 10 10015 10.so.0.1.0.15 + * 1.2.5 13 10205 12.so.0.1.2.5 + * 1.2.6beta1-4 13 10206 12.so.0.1.2.6beta1-4 + * 1.0.16 10 10016 10.so.0.1.0.16 + * 1.2.6 13 10206 12.so.0.1.2.6 + * 1.2.7beta1-2 13 10207 12.so.0.1.2.7beta1-2 + * 1.0.17rc1 10 10017 12.so.0.1.0.17rc1 + * 1.2.7rc1 13 10207 12.so.0.1.2.7rc1 + * 1.0.17 10 10017 12.so.0.1.0.17 + * 1.2.7 13 10207 12.so.0.1.2.7 + * 1.2.8beta1-5 13 10208 12.so.0.1.2.8beta1-5 + * 1.0.18rc1-5 10 10018 12.so.0.1.0.18rc1-5 + * 1.2.8rc1-5 13 10208 12.so.0.1.2.8rc1-5 + * 1.0.18 10 10018 12.so.0.1.0.18 + * 1.2.8 13 10208 12.so.0.1.2.8 + * 1.2.9beta1-3 13 10209 12.so.0.1.2.9beta1-3 + * 1.2.9beta4-11 13 10209 12.so.0.9[.0] + * 1.2.9rc1 13 10209 12.so.0.9[.0] + * 1.2.9 13 10209 12.so.0.9[.0] + * 1.2.10beta1-7 13 10210 12.so.0.10[.0] + * 1.2.10rc1-2 13 10210 12.so.0.10[.0] + * 1.2.10 13 10210 12.so.0.10[.0] + * 1.4.0beta1-5 14 10400 14.so.0.0[.0] + * 1.2.11beta1-4 13 10211 12.so.0.11[.0] + * 1.4.0beta7-8 14 10400 14.so.0.0[.0] + * 1.2.11 13 10211 12.so.0.11[.0] + * 1.2.12 13 10212 12.so.0.12[.0] + * 1.4.0beta9-14 14 10400 14.so.0.0[.0] + * 1.2.13 13 10213 12.so.0.13[.0] + * 1.4.0beta15-36 14 10400 14.so.0.0[.0] + * 1.4.0beta37-87 14 10400 14.so.14.0[.0] + * 1.4.0rc01 14 10400 14.so.14.0[.0] + * 1.4.0beta88-109 14 10400 14.so.14.0[.0] + * 1.4.0rc02-08 14 10400 14.so.14.0[.0] + * 1.4.0 14 10400 14.so.14.0[.0] + * 1.4.1beta01-03 14 10401 14.so.14.1[.0] + * 1.4.1rc01 14 10401 14.so.14.1[.0] + * 1.4.1beta04-12 14 10401 14.so.14.1[.0] + * 1.4.1 14 10401 14.so.14.1[.0] + * 1.4.2 14 10402 14.so.14.2[.0] + * 1.4.3 14 10403 14.so.14.3[.0] + * 1.4.4 14 10404 14.so.14.4[.0] + * 1.5.0beta01-58 15 10500 15.so.15.0[.0] + * 1.5.0rc01-07 15 10500 15.so.15.0[.0] + * 1.5.0 15 10500 15.so.15.0[.0] + * 1.5.1beta01-11 15 10501 15.so.15.1[.0] + * 1.5.1rc01-02 15 10501 15.so.15.1[.0] + * 1.5.1 15 10501 15.so.15.1[.0] + * 1.5.2beta01-03 15 10502 15.so.15.2[.0] + * 1.5.2rc01-03 15 10502 15.so.15.2[.0] + * 1.5.2 15 10502 15.so.15.2[.0] + * 1.5.3beta01-10 15 10503 15.so.15.3[.0] + * 1.5.3rc01-02 15 10503 15.so.15.3[.0] + * 1.5.3beta11 15 10503 15.so.15.3[.0] + * 1.5.3 [omitted] + * 1.5.4beta01-08 15 10504 15.so.15.4[.0] + * 1.5.4rc01 15 10504 15.so.15.4[.0] + * 1.5.4 15 10504 15.so.15.4[.0] + * 1.5.5beta01-08 15 10505 15.so.15.5[.0] + * 1.5.5rc01 15 10505 15.so.15.5[.0] + * 1.5.5 15 10505 15.so.15.5[.0] + * 1.5.6beta01-07 15 10506 15.so.15.6[.0] + * 1.5.6rc01-03 15 10506 15.so.15.6[.0] + * 1.5.6 15 10506 15.so.15.6[.0] + * 1.5.7beta01-05 15 10507 15.so.15.7[.0] + * 1.5.7rc01-03 15 10507 15.so.15.7[.0] + * 1.5.7 15 10507 15.so.15.7[.0] + * 1.6.0beta01-40 16 10600 16.so.16.0[.0] + * 1.6.0rc01-08 16 10600 16.so.16.0[.0] + * 1.6.0 16 10600 16.so.16.0[.0] + * 1.6.1beta01-09 16 10601 16.so.16.1[.0] + * 1.6.1rc01 16 10601 16.so.16.1[.0] + * 1.6.1 16 10601 16.so.16.1[.0] + * 1.6.2beta01 16 10602 16.so.16.2[.0] + * 1.6.2rc01-06 16 10602 16.so.16.2[.0] + * 1.6.2 16 10602 16.so.16.2[.0] * - * Henceforth the source version will match the shared-library major and - * minor numbers; the shared-library major version number will be used for - * changes in backward compatibility, as it is intended. - * The PNG_LIBPNG_VER macro, which is not used within libpng but is - * available for applications, is an unsigned integer of the form XYYZZ - * corresponding to the source version X.Y.Z (leading zeros in Y and Z). - * Beta versions were given the previous public release number plus a - * letter, until version 1.0.6j; from then on they were given the upcoming - * public release number plus "betaNN" or "rcNN". + * Henceforth the source version will match the shared-library major + * and minor numbers; the shared-library major version number will be + * used for changes in backward compatibility, as it is intended. The + * PNG_LIBPNG_VER macro, which is not used within libpng but is available + * for applications, is an unsigned integer of the form xyyzz corresponding + * to the source version x.y.z (leading zeros in y and z). Beta versions + * were given the previous public release number plus a letter, until + * version 1.0.6j; from then on they were given the upcoming public + * release number plus "betaNN" or "rcNN". * - * Binary incompatibility exists only when applications make direct access - * to the info_ptr or png_ptr members through png.h, and the compiled - * application is loaded with a different version of the library. + * Binary incompatibility exists only when applications make direct access + * to the info_ptr or png_ptr members through png.h, and the compiled + * application is loaded with a different version of the library. * - * See libpng.txt or libpng.3 for more information. The PNG specification - * is available as a W3C Recommendation and as an ISO/IEC Standard; see - * + * DLLNUM will change each time there are forward or backward changes + * in binary compatibility (e.g., when a new feature is added). + * + * See libpng-manual.txt or libpng.3 for more information. The PNG + * specification is available as a W3C Recommendation and as an ISO + * Specification, + * at the actual function definitions and structure components. * * If you just need to read a PNG file and don't want to read the documentation * skip to the end of this file and read the section entitled 'simplified API'. */ /* Version information for png.h - this should match the version in png.c */ -#define PNG_LIBPNG_VER_STRING "1.6.55" -#define PNG_HEADER_VERSION_STRING " libpng version " PNG_LIBPNG_VER_STRING "\n" +#define PNG_LIBPNG_VER_STRING "1.6.2" +#define PNG_HEADER_VERSION_STRING \ + " libpng version 1.6.2 - April 25, 2013\n" -/* The versions of shared library builds should stay in sync, going forward */ -#define PNG_LIBPNG_VER_SHAREDLIB 16 -#define PNG_LIBPNG_VER_SONUM PNG_LIBPNG_VER_SHAREDLIB /* [Deprecated] */ -#define PNG_LIBPNG_VER_DLLNUM PNG_LIBPNG_VER_SHAREDLIB /* [Deprecated] */ +#define PNG_LIBPNG_VER_SONUM 16 +#define PNG_LIBPNG_VER_DLLNUM 16 /* These should match the first 3 components of PNG_LIBPNG_VER_STRING: */ #define PNG_LIBPNG_VER_MAJOR 1 #define PNG_LIBPNG_VER_MINOR 6 -#define PNG_LIBPNG_VER_RELEASE 55 +#define PNG_LIBPNG_VER_RELEASE 2 -/* This should be zero for a public release, or non-zero for a - * development version. +/* This should match the numeric part of the final component of + * PNG_LIBPNG_VER_STRING, omitting any leading zero: */ -#define PNG_LIBPNG_VER_BUILD 0 + +#define PNG_LIBPNG_VER_BUILD 0 /* Release Status */ -#define PNG_LIBPNG_BUILD_ALPHA 1 -#define PNG_LIBPNG_BUILD_BETA 2 -#define PNG_LIBPNG_BUILD_RC 3 -#define PNG_LIBPNG_BUILD_STABLE 4 +#define PNG_LIBPNG_BUILD_ALPHA 1 +#define PNG_LIBPNG_BUILD_BETA 2 +#define PNG_LIBPNG_BUILD_RC 3 +#define PNG_LIBPNG_BUILD_STABLE 4 #define PNG_LIBPNG_BUILD_RELEASE_STATUS_MASK 7 /* Release-Specific Flags */ @@ -309,27 +419,26 @@ #define PNG_LIBPNG_BUILD_BASE_TYPE PNG_LIBPNG_BUILD_STABLE -/* Careful here. At one time, Guy wanted to use 082, but that - * would be octal. We must not include leading zeros. - * Versions 0.7 through 1.0.0 were in the range 0 to 100 here - * (only version 1.0.0 was mis-numbered 100 instead of 10000). - * From version 1.0.1 it is: - * XXYYZZ, where XX=major, YY=minor, ZZ=release +/* Careful here. At one time, Guy wanted to use 082, but that would be octal. + * We must not include leading zeros. + * Versions 0.7 through 1.0.0 were in the range 0 to 100 here (only + * version 1.0.0 was mis-numbered 100 instead of 10000). From + * version 1.0.1 it's xxyyzz, where x=major, y=minor, z=release */ -#define PNG_LIBPNG_VER 10655 /* 1.6.55 */ +#define PNG_LIBPNG_VER 10602 /* 1.6.2 */ /* Library configuration: these options cannot be changed after * the library has been built. */ #ifndef PNGLCONF_H -/* If pnglibconf.h is missing, you can - * copy scripts/pnglibconf.h.prebuilt to pnglibconf.h - */ + /* If pnglibconf.h is missing, you can + * copy scripts/pnglibconf.h.prebuilt to pnglibconf.h + */ # include "pnglibconf.h" #endif #ifndef PNG_VERSION_INFO_ONLY -/* Machine specific configuration. */ + /* Machine specific configuration. */ # include "pngconf.h" #endif @@ -373,22 +482,17 @@ extern "C" { /* This file is arranged in several sections: * - * 1. [omitted] - * 2. Any configuration options that can be specified by for the application + * 1. Any configuration options that can be specified by for the application * code when it is built. (Build time configuration is in pnglibconf.h) - * 3. Type definitions (base types are defined in pngconf.h), structure + * 2. Type definitions (base types are defined in pngconf.h), structure * definitions. - * 4. Exported library functions. - * 5. Simplified API. - * 6. Implementation options. + * 3. Exported library functions. + * 4. Simplified API. * * The library source code has additional files (principally pngpriv.h) that * allow configuration of the library. */ - -/* Section 1: [omitted] */ - -/* Section 2: run time configuration +/* Section 1: run time configuration * See pnglibconf.h for build time configuration * * Run time configuration allows the application to choose between @@ -418,7 +522,7 @@ extern "C" { * Otherwise the calls are mapped to png_error. */ -/* Section 3: type definitions, including structures and compile time +/* Section 2: type definitions, including structures and compile time * constants. * See pngconf.h for base types that vary by machine/system */ @@ -426,7 +530,7 @@ extern "C" { /* This triggers a compiler error in png.c, if png.c and png.h * do not agree upon the version number. */ -typedef char *png_libpng_version_1_6_55; +typedef char* png_libpng_version_1_6_2; /* Basic control structions. Read libpng-manual.txt or libpng.3 for more info. * @@ -567,8 +671,8 @@ typedef struct png_text_struct png_charp key; /* keyword, 1-79 character description of "text" */ png_charp text; /* comment, may be an empty string (ie "") or a NULL pointer */ - size_t text_length; /* length of the text string */ - size_t itxt_length; /* length of the itxt string */ + png_size_t text_length; /* length of the text string */ + png_size_t itxt_length; /* length of the itxt string */ png_charp lang; /* language code, 0-79 characters or a NULL pointer */ png_charp lang_key; /* keyword translated UTF-8 string, 0 or more @@ -608,8 +712,7 @@ typedef png_time * png_timep; typedef const png_time * png_const_timep; typedef png_time * * png_timepp; -#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) ||\ - defined(PNG_USER_CHUNKS_SUPPORTED) +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED /* png_unknown_chunk is a structure to hold queued chunks for which there is * no specific support. The idea is that we can use this to queue * up private chunks for output even though the library doesn't actually @@ -619,17 +722,17 @@ typedef png_time * * png_timepp; */ typedef struct png_unknown_chunk_t { - png_byte name[5]; /* Textual chunk name with '\0' terminator */ - png_byte *data; /* Data, should not be modified on read! */ - size_t size; + png_byte name[5]; /* Textual chunk name with '\0' terminator */ + png_byte *data; /* Data, should not be modified on read! */ + png_size_t size; - /* On write 'location' must be set using the flag values listed below. - * Notice that on read it is set by libpng however the values stored have - * more bits set than are listed below. Always treat the value as a - * bitmask. On write set only one bit - setting multiple bits may cause the - * chunk to be written in multiple places. - */ - png_byte location; /* mode of operation at read time */ + /* On write 'location' must be set using the flag values listed below. + * Notice that on read it is set by libpng however the values stored have + * more bits set than are listed below. Always treat the value as a + * bitmask. On write set only one bit - setting multiple bits may cause the + * chunk to be written in multiple places. + */ + png_byte location; /* mode of operation at read time */ } png_unknown_chunk; @@ -646,7 +749,7 @@ typedef png_unknown_chunk * * png_unknown_chunkpp; /* Maximum positive integer used in PNG is (2^31)-1 */ #define PNG_UINT_31_MAX ((png_uint_32)0x7fffffffL) #define PNG_UINT_32_MAX ((png_uint_32)(-1)) -#define PNG_SIZE_MAX ((size_t)(-1)) +#define PNG_SIZE_MAX ((png_size_t)(-1)) /* These are constants for fixed point values encoded in the * PNG specification manner (x100000) @@ -727,38 +830,22 @@ typedef png_unknown_chunk * * png_unknown_chunkpp; * data in the info_struct to be written into the output file. The values * of the PNG_INFO_ defines should NOT be changed. */ -#define PNG_INFO_gAMA 0x0001U -#define PNG_INFO_sBIT 0x0002U -#define PNG_INFO_cHRM 0x0004U -#define PNG_INFO_PLTE 0x0008U -#define PNG_INFO_tRNS 0x0010U -#define PNG_INFO_bKGD 0x0020U -#define PNG_INFO_hIST 0x0040U -#define PNG_INFO_pHYs 0x0080U -#define PNG_INFO_oFFs 0x0100U -#define PNG_INFO_tIME 0x0200U -#define PNG_INFO_pCAL 0x0400U -#define PNG_INFO_sRGB 0x0800U /* GR-P, 0.96a */ -#define PNG_INFO_iCCP 0x1000U /* ESR, 1.0.6 */ -#define PNG_INFO_sPLT 0x2000U /* ESR, 1.0.6 */ -#define PNG_INFO_sCAL 0x4000U /* ESR, 1.0.6 */ -#define PNG_INFO_IDAT 0x8000U /* ESR, 1.0.6 */ -#define PNG_INFO_eXIf 0x10000U /* GR-P, 1.6.31 */ -#define PNG_INFO_cICP 0x20000U /* PNGv3: 1.6.45 */ -#define PNG_INFO_cLLI 0x40000U /* PNGv3: 1.6.45 */ -#define PNG_INFO_mDCV 0x80000U /* PNGv3: 1.6.45 */ -/* APNG: these chunks are stored as unknown, these flags are never set - * however they are provided as a convenience for implementors of APNG and - * avoids any merge conflicts. - * - * Private chunks: these chunk names violate the chunk name recommendations - * because the chunk definitions have no signature and because the private - * chunks with these names have been reserved. Private definitions should - * avoid them. - */ -#define PNG_INFO_acTL 0x100000U /* PNGv3: 1.6.45: unknown */ -#define PNG_INFO_fcTL 0x200000U /* PNGv3: 1.6.45: unknown */ -#define PNG_INFO_fdAT 0x400000U /* PNGv3: 1.6.45: unknown */ +#define PNG_INFO_gAMA 0x0001 +#define PNG_INFO_sBIT 0x0002 +#define PNG_INFO_cHRM 0x0004 +#define PNG_INFO_PLTE 0x0008 +#define PNG_INFO_tRNS 0x0010 +#define PNG_INFO_bKGD 0x0020 +#define PNG_INFO_hIST 0x0040 +#define PNG_INFO_pHYs 0x0080 +#define PNG_INFO_oFFs 0x0100 +#define PNG_INFO_tIME 0x0200 +#define PNG_INFO_pCAL 0x0400 +#define PNG_INFO_sRGB 0x0800 /* GR-P, 0.96a */ +#define PNG_INFO_iCCP 0x1000 /* ESR, 1.0.6 */ +#define PNG_INFO_sPLT 0x2000 /* ESR, 1.0.6 */ +#define PNG_INFO_sCAL 0x4000 /* ESR, 1.0.6 */ +#define PNG_INFO_IDAT 0x8000 /* ESR, 1.0.6 */ /* This is used for the transformation routines, as some of them * change these values for the row. It also should enable using @@ -767,7 +854,7 @@ typedef png_unknown_chunk * * png_unknown_chunkpp; typedef struct png_row_info_struct { png_uint_32 width; /* width of row */ - size_t rowbytes; /* number of bytes in row */ + png_size_t rowbytes; /* number of bytes in row */ png_byte color_type; /* color type of row */ png_byte bit_depth; /* bit depth of row */ png_byte channels; /* number of channels (1, 2, 3, or 4) */ @@ -785,22 +872,17 @@ typedef png_row_info * * png_row_infopp; * modify the buffer it is passed. The 'read' function, on the other hand, is * expected to return the read data in the buffer. */ -typedef PNG_CALLBACK(void, *png_error_ptr, - (png_structp, png_const_charp)); -typedef PNG_CALLBACK(void, *png_rw_ptr, - (png_structp, png_bytep, size_t)); -typedef PNG_CALLBACK(void, *png_flush_ptr, - (png_structp)); -typedef PNG_CALLBACK(void, *png_read_status_ptr, - (png_structp, png_uint_32, int)); -typedef PNG_CALLBACK(void, *png_write_status_ptr, - (png_structp, png_uint_32, int)); +typedef PNG_CALLBACK(void, *png_error_ptr, (png_structp, png_const_charp)); +typedef PNG_CALLBACK(void, *png_rw_ptr, (png_structp, png_bytep, png_size_t)); +typedef PNG_CALLBACK(void, *png_flush_ptr, (png_structp)); +typedef PNG_CALLBACK(void, *png_read_status_ptr, (png_structp, png_uint_32, + int)); +typedef PNG_CALLBACK(void, *png_write_status_ptr, (png_structp, png_uint_32, + int)); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED -typedef PNG_CALLBACK(void, *png_progressive_info_ptr, - (png_structp, png_infop)); -typedef PNG_CALLBACK(void, *png_progressive_end_ptr, - (png_structp, png_infop)); +typedef PNG_CALLBACK(void, *png_progressive_info_ptr, (png_structp, png_infop)); +typedef PNG_CALLBACK(void, *png_progressive_end_ptr, (png_structp, png_infop)); /* The following callback receives png_uint_32 row_number, int pass for the * png_bytep data of the row. When transforming an interlaced image the @@ -812,19 +894,19 @@ typedef PNG_CALLBACK(void, *png_progressive_end_ptr, * find the output pixel (x,y) given an interlaced sub-image pixel * (row,col,pass). (See below for these macros.) */ -typedef PNG_CALLBACK(void, *png_progressive_row_ptr, - (png_structp, png_bytep, png_uint_32, int)); +typedef PNG_CALLBACK(void, *png_progressive_row_ptr, (png_structp, png_bytep, + png_uint_32, int)); #endif #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) -typedef PNG_CALLBACK(void, *png_user_transform_ptr, - (png_structp, png_row_infop, png_bytep)); +typedef PNG_CALLBACK(void, *png_user_transform_ptr, (png_structp, png_row_infop, + png_bytep)); #endif #ifdef PNG_USER_CHUNKS_SUPPORTED -typedef PNG_CALLBACK(int, *png_user_chunk_ptr, - (png_structp, png_unknown_chunkp)); +typedef PNG_CALLBACK(int, *png_user_chunk_ptr, (png_structp, + png_unknown_chunkp)); #endif #ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED /* not used anywhere */ @@ -843,7 +925,7 @@ typedef PNG_CALLBACK(int, *png_user_chunk_ptr, * your compiler. This may be very difficult - try using a different compiler * to build the library! */ -PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), (jmp_buf, int), typedef); +PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), PNGARG((jmp_buf, int)), typedef); #endif /* Transform masks for the high-level interface */ @@ -867,9 +949,7 @@ PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), (jmp_buf, int), typedef); #define PNG_TRANSFORM_GRAY_TO_RGB 0x2000 /* read only */ /* Added to libpng-1.5.4 */ #define PNG_TRANSFORM_EXPAND_16 0x4000 /* read only */ -#if ~0U > 0xffffU /* or else this might break on a 16-bit machine */ #define PNG_TRANSFORM_SCALE_16 0x8000 /* read only */ -#endif /* Flags for MNG supported features */ #define PNG_FLAG_MNG_EMPTY_PLTE 0x01 @@ -882,12 +962,11 @@ PNG_FUNCTION(void, (PNGCAPI *png_longjmp_ptr), (jmp_buf, int), typedef); * ignores the first argument) should be completely compatible with the * following. */ -typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, - (png_structp, png_alloc_size_t)); -typedef PNG_CALLBACK(void, *png_free_ptr, - (png_structp, png_voidp)); +typedef PNG_CALLBACK(png_voidp, *png_malloc_ptr, (png_structp, + png_alloc_size_t)); +typedef PNG_CALLBACK(void, *png_free_ptr, (png_structp, png_voidp)); -/* Section 4: exported functions +/* Section 3: exported functions * Here are the function definitions most commonly used. This is not * the place to find out how to use libpng. See libpng-manual.txt for the * full explanation, see example.c for the summary. This just provides @@ -917,45 +996,43 @@ typedef PNG_CALLBACK(void, *png_free_ptr, */ /* Returns the version number of the library */ -PNG_EXPORT(1, png_uint_32, png_access_version_number, - (void)); +PNG_EXPORT(1, png_uint_32, png_access_version_number, (void)); /* Tell lib we have already handled the first magic bytes. * Handling more than 8 bytes from the beginning of the file is an error. */ -PNG_EXPORT(2, void, png_set_sig_bytes, - (png_structrp png_ptr, int num_bytes)); +PNG_EXPORT(2, void, png_set_sig_bytes, (png_structrp png_ptr, int num_bytes)); /* Check sig[start] through sig[start + num_to_check - 1] to see if it's a * PNG file. Returns zero if the supplied bytes match the 8-byte PNG * signature, and non-zero otherwise. Having num_to_check == 0 or - * start > 7 will always fail (i.e. return non-zero). + * start > 7 will always fail (ie return non-zero). */ -PNG_EXPORT(3, int, png_sig_cmp, - (png_const_bytep sig, size_t start, size_t num_to_check)); +PNG_EXPORT(3, int, png_sig_cmp, (png_const_bytep sig, png_size_t start, + png_size_t num_to_check)); /* Simple signature checking function. This is the same as calling - * png_check_sig(sig, n) := (png_sig_cmp(sig, 0, n) == 0). + * png_check_sig(sig, n) := !png_sig_cmp(sig, 0, n). */ -#define png_check_sig(sig, n) (png_sig_cmp((sig), 0, (n)) == 0) /* DEPRECATED */ +#define png_check_sig(sig, n) !png_sig_cmp((sig), 0, (n)) /* Allocate and initialize png_ptr struct for reading, and any other memory. */ PNG_EXPORTA(4, png_structp, png_create_read_struct, - (png_const_charp user_png_ver, - png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn), - PNG_ALLOCATED); + (png_const_charp user_png_ver, png_voidp error_ptr, + png_error_ptr error_fn, png_error_ptr warn_fn), + PNG_ALLOCATED); /* Allocate and initialize png_ptr struct for writing, and any other memory */ PNG_EXPORTA(5, png_structp, png_create_write_struct, - (png_const_charp user_png_ver, - png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn), - PNG_ALLOCATED); + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn), + PNG_ALLOCATED); -PNG_EXPORT(6, size_t, png_get_compression_buffer_size, - (png_const_structrp png_ptr)); +PNG_EXPORT(6, png_size_t, png_get_compression_buffer_size, + (png_const_structrp png_ptr)); -PNG_EXPORT(7, void, png_set_compression_buffer_size, - (png_structrp png_ptr, size_t size)); +PNG_EXPORT(7, void, png_set_compression_buffer_size, (png_structrp png_ptr, + png_size_t size)); /* Moved from pngconf.h in 1.4.0 and modified to ensure setjmp/longjmp * match up. @@ -968,8 +1045,8 @@ PNG_EXPORT(7, void, png_set_compression_buffer_size, * allocated by the library - the call will return NULL on a mismatch * indicating an ABI mismatch. */ -PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, - (png_structrp png_ptr, png_longjmp_ptr longjmp_fn, size_t jmp_buf_size)); +PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, (png_structrp png_ptr, + png_longjmp_ptr longjmp_fn, size_t jmp_buf_size)); # define png_jmpbuf(png_ptr) \ (*png_set_longjmp_fn((png_ptr), longjmp, (sizeof (jmp_buf)))) #else @@ -981,77 +1058,67 @@ PNG_EXPORT(8, jmp_buf*, png_set_longjmp_fn, * will use it; otherwise it will call PNG_ABORT(). This function was * added in libpng-1.5.0. */ -PNG_EXPORTA(9, void, png_longjmp, - (png_const_structrp png_ptr, int val), - PNG_NORETURN); +PNG_EXPORTA(9, void, png_longjmp, (png_const_structrp png_ptr, int val), + PNG_NORETURN); #ifdef PNG_READ_SUPPORTED /* Reset the compression stream */ -PNG_EXPORTA(10, int, png_reset_zstream, - (png_structrp png_ptr), - PNG_DEPRECATED); +PNG_EXPORTA(10, int, png_reset_zstream, (png_structrp png_ptr), PNG_DEPRECATED); #endif /* New functions added in libpng-1.0.2 (not enabled by default until 1.2.0) */ #ifdef PNG_USER_MEM_SUPPORTED PNG_EXPORTA(11, png_structp, png_create_read_struct_2, - (png_const_charp user_png_ver, - png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), - PNG_ALLOCATED); + PNG_ALLOCATED); PNG_EXPORTA(12, png_structp, png_create_write_struct_2, - (png_const_charp user_png_ver, - png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), - PNG_ALLOCATED); + PNG_ALLOCATED); #endif /* Write the PNG file signature. */ -PNG_EXPORT(13, void, png_write_sig, - (png_structrp png_ptr)); +PNG_EXPORT(13, void, png_write_sig, (png_structrp png_ptr)); /* Write a PNG chunk - size, type, (optional) data, CRC. */ -PNG_EXPORT(14, void, png_write_chunk, - (png_structrp png_ptr, - png_const_bytep chunk_name, png_const_bytep data, size_t length)); +PNG_EXPORT(14, void, png_write_chunk, (png_structrp png_ptr, png_const_bytep + chunk_name, png_const_bytep data, png_size_t length)); /* Write the start of a PNG chunk - length and chunk name. */ -PNG_EXPORT(15, void, png_write_chunk_start, - (png_structrp png_ptr, +PNG_EXPORT(15, void, png_write_chunk_start, (png_structrp png_ptr, png_const_bytep chunk_name, png_uint_32 length)); /* Write the data of a PNG chunk started with png_write_chunk_start(). */ -PNG_EXPORT(16, void, png_write_chunk_data, - (png_structrp png_ptr, - png_const_bytep data, size_t length)); +PNG_EXPORT(16, void, png_write_chunk_data, (png_structrp png_ptr, + png_const_bytep data, png_size_t length)); /* Finish a chunk started with png_write_chunk_start() (includes CRC). */ -PNG_EXPORT(17, void, png_write_chunk_end, - (png_structrp png_ptr)); +PNG_EXPORT(17, void, png_write_chunk_end, (png_structrp png_ptr)); /* Allocate and initialize the info structure */ -PNG_EXPORTA(18, png_infop, png_create_info_struct, - (png_const_structrp png_ptr), - PNG_ALLOCATED); +PNG_EXPORTA(18, png_infop, png_create_info_struct, (png_const_structrp png_ptr), + PNG_ALLOCATED); /* DEPRECATED: this function allowed init structures to be created using the * default allocation method (typically malloc). Use is deprecated in 1.6.0 and * the API will be removed in the future. */ -PNG_EXPORTA(19, void, png_info_init_3, - (png_infopp info_ptr, size_t png_info_struct_size), - PNG_DEPRECATED); +PNG_EXPORTA(19, void, png_info_init_3, (png_infopp info_ptr, + png_size_t png_info_struct_size), PNG_DEPRECATED); /* Writes all the PNG information before the image. */ PNG_EXPORT(20, void, png_write_info_before_PLTE, - (png_structrp png_ptr, png_const_inforp info_ptr)); + (png_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(21, void, png_write_info, - (png_structrp png_ptr, png_const_inforp info_ptr)); + (png_structrp png_ptr, png_const_inforp info_ptr)); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the information before the actual image data. */ PNG_EXPORT(22, void, png_read_info, - (png_structrp png_ptr, png_inforp info_ptr)); + (png_structrp png_ptr, png_inforp info_ptr)); #endif #ifdef PNG_TIME_RFC1123_SUPPORTED @@ -1061,54 +1128,45 @@ PNG_EXPORT(22, void, png_read_info, */ #if PNG_LIBPNG_VER < 10700 /* To do: remove this from libpng17 (and from libpng17/png.c and pngstruct.h) */ -PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, - (png_structrp png_ptr, png_const_timep ptime), - PNG_DEPRECATED); +PNG_EXPORTA(23, png_const_charp, png_convert_to_rfc1123, (png_structrp png_ptr, + png_const_timep ptime),PNG_DEPRECATED); #endif -PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, - (char out[29], png_const_timep ptime)); +PNG_EXPORT(241, int, png_convert_to_rfc1123_buffer, (char out[29], + png_const_timep ptime)); #endif #ifdef PNG_CONVERT_tIME_SUPPORTED /* Convert from a struct tm to png_time */ -PNG_EXPORT(24, void, png_convert_from_struct_tm, - (png_timep ptime, const struct tm * ttime)); +PNG_EXPORT(24, void, png_convert_from_struct_tm, (png_timep ptime, + const struct tm * ttime)); /* Convert from time_t to png_time. Uses gmtime() */ -PNG_EXPORT(25, void, png_convert_from_time_t, - (png_timep ptime, time_t ttime)); -#endif /* CONVERT_tIME */ +PNG_EXPORT(25, void, png_convert_from_time_t, (png_timep ptime, time_t ttime)); +#endif /* PNG_CONVERT_tIME_SUPPORTED */ #ifdef PNG_READ_EXPAND_SUPPORTED /* Expand data to 24-bit RGB, or 8-bit grayscale, with alpha if available. */ -PNG_EXPORT(26, void, png_set_expand, - (png_structrp png_ptr)); -PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, - (png_structrp png_ptr)); -PNG_EXPORT(28, void, png_set_palette_to_rgb, - (png_structrp png_ptr)); -PNG_EXPORT(29, void, png_set_tRNS_to_alpha, - (png_structrp png_ptr)); +PNG_EXPORT(26, void, png_set_expand, (png_structrp png_ptr)); +PNG_EXPORT(27, void, png_set_expand_gray_1_2_4_to_8, (png_structrp png_ptr)); +PNG_EXPORT(28, void, png_set_palette_to_rgb, (png_structrp png_ptr)); +PNG_EXPORT(29, void, png_set_tRNS_to_alpha, (png_structrp png_ptr)); #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED /* Expand to 16-bit channels, forces conversion of palette to RGB and expansion * of a tRNS chunk if present. */ -PNG_EXPORT(221, void, png_set_expand_16, - (png_structrp png_ptr)); +PNG_EXPORT(221, void, png_set_expand_16, (png_structrp png_ptr)); #endif #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) /* Use blue, green, red order for pixels. */ -PNG_EXPORT(30, void, png_set_bgr, - (png_structrp png_ptr)); +PNG_EXPORT(30, void, png_set_bgr, (png_structrp png_ptr)); #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand the grayscale to 24-bit RGB if necessary. */ -PNG_EXPORT(31, void, png_set_gray_to_rgb, - (png_structrp png_ptr)); +PNG_EXPORT(31, void, png_set_gray_to_rgb, (png_structrp png_ptr)); #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED @@ -1118,26 +1176,24 @@ PNG_EXPORT(31, void, png_set_gray_to_rgb, #define PNG_ERROR_ACTION_ERROR 3 #define PNG_RGB_TO_GRAY_DEFAULT (-1)/*for red/green coefficients*/ -PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, - (png_structrp png_ptr, +PNG_FP_EXPORT(32, void, png_set_rgb_to_gray, (png_structrp png_ptr, int error_action, double red, double green)) -PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, - (png_structrp png_ptr, +PNG_FIXED_EXPORT(33, void, png_set_rgb_to_gray_fixed, (png_structrp png_ptr, int error_action, png_fixed_point red, png_fixed_point green)) -PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, - (png_const_structrp png_ptr)); +PNG_EXPORT(34, png_byte, png_get_rgb_to_gray_status, (png_const_structrp + png_ptr)); #endif #ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED -PNG_EXPORT(35, void, png_build_grayscale_palette, - (int bit_depth, png_colorp palette)); +PNG_EXPORT(35, void, png_build_grayscale_palette, (int bit_depth, + png_colorp palette)); #endif #ifdef PNG_READ_ALPHA_MODE_SUPPORTED -/* How the alpha channel is interpreted - this affects how the color channels - * of a PNG file are returned to the calling application when an alpha channel, - * or a tRNS chunk in a palette file, is present. +/* How the alpha channel is interpreted - this affects how the color channels of + * a PNG file are returned when an alpha channel, or tRNS chunk in a palette + * file, is present. * * This has no effect on the way pixels are written into a PNG output * datastream. The color samples in a PNG datastream are never premultiplied @@ -1145,19 +1201,33 @@ PNG_EXPORT(35, void, png_build_grayscale_palette, * * The default is to return data according to the PNG specification: the alpha * channel is a linear measure of the contribution of the pixel to the - * corresponding composited pixel, and the color channels are unassociated - * (not premultiplied). The gamma encoded color channels must be scaled - * according to the contribution and to do this it is necessary to undo - * the encoding, scale the color values, perform the composition and re-encode + * corresponding composited pixel. The gamma encoded color channels must be + * scaled according to the contribution and to do this it is necessary to undo + * the encoding, scale the color values, perform the composition and reencode * the values. This is the 'PNG' mode. * * The alternative is to 'associate' the alpha with the color information by - * storing color channel values that have been scaled by the alpha. - * image. These are the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' modes - * (the latter being the two common names for associated alpha color channels). + * storing color channel values that have been scaled by the alpha. The + * advantage is that the color channels can be resampled (the image can be + * scaled) in this form. The disadvantage is that normal practice is to store + * linear, not (gamma) encoded, values and this requires 16-bit channels for + * still images rather than the 8-bit channels that are just about sufficient if + * gamma encoding is used. In addition all non-transparent pixel values, + * including completely opaque ones, must be gamma encoded to produce the final + * image. This is the 'STANDARD', 'ASSOCIATED' or 'PREMULTIPLIED' mode (the + * latter being the two common names for associated alpha color channels.) * - * For the 'OPTIMIZED' mode, a pixel is treated as opaque only if the alpha - * value is equal to the maximum value. + * Since it is not necessary to perform arithmetic on opaque color values so + * long as they are not to be resampled and are in the final color space it is + * possible to optimize the handling of alpha by storing the opaque pixels in + * the PNG format (adjusted for the output color space) while storing partially + * opaque pixels in the standard, linear, format. The accuracy required for + * standard alpha composition is relatively low, because the pixels are + * isolated, therefore typically the accuracy loss in storing 8-bit linear + * values is acceptable. (This is not true if the alpha channel is used to + * simulate transparency over large areas - use 16 bits or the PNG mode in + * this case!) This is the 'OPTIMIZED' mode. For this mode a pixel is + * treated as opaque only if the alpha value is equal to the maximum value. * * The final choice is to gamma encode the alpha channel as well. This is * broken because, in practice, no implementation that uses this choice @@ -1176,15 +1246,76 @@ PNG_EXPORT(35, void, png_build_grayscale_palette, #define PNG_ALPHA_OPTIMIZED 2 /* 'PNG' for opaque pixels, else 'STANDARD' */ #define PNG_ALPHA_BROKEN 3 /* the alpha channel is gamma encoded */ -PNG_FP_EXPORT(227, void, png_set_alpha_mode, - (png_structrp png_ptr, int mode, double output_gamma)) -PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, - (png_structrp png_ptr, int mode, png_fixed_point output_gamma)) +PNG_FP_EXPORT(227, void, png_set_alpha_mode, (png_structrp png_ptr, int mode, + double output_gamma)) +PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, (png_structrp png_ptr, + int mode, png_fixed_point output_gamma)) #endif #if defined(PNG_GAMMA_SUPPORTED) || defined(PNG_READ_ALPHA_MODE_SUPPORTED) /* The output_gamma value is a screen gamma in libpng terminology: it expresses - * how to decode the output values, not how they are encoded. + * how to decode the output values, not how they are encoded. The values used + * correspond to the normal numbers used to describe the overall gamma of a + * computer display system; for example 2.2 for an sRGB conformant system. The + * values are scaled by 100000 in the _fixed version of the API (so 220000 for + * sRGB.) + * + * The inverse of the value is always used to provide a default for the PNG file + * encoding if it has no gAMA chunk and if png_set_gamma() has not been called + * to override the PNG gamma information. + * + * When the ALPHA_OPTIMIZED mode is selected the output gamma is used to encode + * opaque pixels however pixels with lower alpha values are not encoded, + * regardless of the output gamma setting. + * + * When the standard Porter Duff handling is requested with mode 1 the output + * encoding is set to be linear and the output_gamma value is only relevant + * as a default for input data that has no gamma information. The linear output + * encoding will be overridden if png_set_gamma() is called - the results may be + * highly unexpected! + * + * The following numbers are derived from the sRGB standard and the research + * behind it. sRGB is defined to be approximated by a PNG gAMA chunk value of + * 0.45455 (1/2.2) for PNG. The value implicitly includes any viewing + * correction required to take account of any differences in the color + * environment of the original scene and the intended display environment; the + * value expresses how to *decode* the image for display, not how the original + * data was *encoded*. + * + * sRGB provides a peg for the PNG standard by defining a viewing environment. + * sRGB itself, and earlier TV standards, actually use a more complex transform + * (a linear portion then a gamma 2.4 power law) than PNG can express. (PNG is + * limited to simple power laws.) By saying that an image for direct display on + * an sRGB conformant system should be stored with a gAMA chunk value of 45455 + * (11.3.3.2 and 11.3.3.5 of the ISO PNG specification) the PNG specification + * makes it possible to derive values for other display systems and + * environments. + * + * The Mac value is deduced from the sRGB based on an assumption that the actual + * extra viewing correction used in early Mac display systems was implemented as + * a power 1.45 lookup table. + * + * Any system where a programmable lookup table is used or where the behavior of + * the final display device characteristics can be changed requires system + * specific code to obtain the current characteristic. However this can be + * difficult and most PNG gamma correction only requires an approximate value. + * + * By default, if png_set_alpha_mode() is not called, libpng assumes that all + * values are unencoded, linear, values and that the output device also has a + * linear characteristic. This is only very rarely correct - it is invariably + * better to call png_set_alpha_mode() with PNG_DEFAULT_sRGB than rely on the + * default if you don't know what the right answer is! + * + * The special value PNG_GAMMA_MAC_18 indicates an older Mac system (pre Mac OS + * 10.6) which used a correction table to implement a somewhat lower gamma on an + * otherwise sRGB system. + * + * Both these values are reserved (not simple gamma values) in order to allow + * more precise correction internally in the future. + * + * NOTE: the following values can be passed to either the fixed or floating + * point APIs, but the floating point API will also accept floating point + * values. */ #define PNG_DEFAULT_sRGB -1 /* sRGB gamma and color space */ #define PNG_GAMMA_MAC_18 -2 /* Old Mac '1.8' gamma and color space */ @@ -1204,7 +1335,7 @@ PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, * * png_set_alpha_mode(pp, PNG_ALPHA_PNG, PNG_GAMMA_MAC); * In this case the output is assumed to be something like an sRGB conformant - * display preceded by a power-law lookup table of power 1.45. This is how + * display preceeded by a power-law lookup table of power 1.45. This is how * early Mac systems behaved. * * png_set_alpha_mode(pp, PNG_ALPHA_STANDARD, PNG_GAMMA_LINEAR); @@ -1251,7 +1382,7 @@ PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, * * When the default gamma of PNG files doesn't match the output gamma. * If you have PNG files with no gamma information png_set_alpha_mode allows - * you to provide a default gamma, but it also sets the output gamma to the + * you to provide a default gamma, but it also sets the ouput gamma to the * matching value. If you know your PNG files have a gamma that doesn't * match the output you can take advantage of the fact that * png_set_alpha_mode always sets the output gamma but only sets the PNG @@ -1269,57 +1400,51 @@ PNG_FIXED_EXPORT(228, void, png_set_alpha_mode_fixed, */ #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED -PNG_EXPORT(36, void, png_set_strip_alpha, - (png_structrp png_ptr)); +PNG_EXPORT(36, void, png_set_strip_alpha, (png_structrp png_ptr)); #endif #if defined(PNG_READ_SWAP_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_SWAP_ALPHA_SUPPORTED) -PNG_EXPORT(37, void, png_set_swap_alpha, - (png_structrp png_ptr)); +PNG_EXPORT(37, void, png_set_swap_alpha, (png_structrp png_ptr)); #endif #if defined(PNG_READ_INVERT_ALPHA_SUPPORTED) || \ defined(PNG_WRITE_INVERT_ALPHA_SUPPORTED) -PNG_EXPORT(38, void, png_set_invert_alpha, - (png_structrp png_ptr)); +PNG_EXPORT(38, void, png_set_invert_alpha, (png_structrp png_ptr)); #endif #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) -/* Add a filler byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */ -PNG_EXPORT(39, void, png_set_filler, - (png_structrp png_ptr, png_uint_32 filler, int flags)); +/* Add a filler byte to 8-bit Gray or 24-bit RGB images. */ +PNG_EXPORT(39, void, png_set_filler, (png_structrp png_ptr, png_uint_32 filler, + int flags)); /* The values of the PNG_FILLER_ defines should NOT be changed */ # define PNG_FILLER_BEFORE 0 # define PNG_FILLER_AFTER 1 -/* Add an alpha byte to 8-bit or 16-bit Gray or 24-bit or 48-bit RGB images. */ -PNG_EXPORT(40, void, png_set_add_alpha, - (png_structrp png_ptr, png_uint_32 filler, int flags)); -#endif /* READ_FILLER || WRITE_FILLER */ +/* Add an alpha byte to 8-bit Gray or 24-bit RGB images. */ +PNG_EXPORT(40, void, png_set_add_alpha, (png_structrp png_ptr, + png_uint_32 filler, int flags)); +#endif /* PNG_READ_FILLER_SUPPORTED || PNG_WRITE_FILLER_SUPPORTED */ #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) /* Swap bytes in 16-bit depth files. */ -PNG_EXPORT(41, void, png_set_swap, - (png_structrp png_ptr)); +PNG_EXPORT(41, void, png_set_swap, (png_structrp png_ptr)); #endif #if defined(PNG_READ_PACK_SUPPORTED) || defined(PNG_WRITE_PACK_SUPPORTED) /* Use 1 byte per pixel in 1, 2, or 4-bit depth files. */ -PNG_EXPORT(42, void, png_set_packing, - (png_structrp png_ptr)); +PNG_EXPORT(42, void, png_set_packing, (png_structrp png_ptr)); #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ defined(PNG_WRITE_PACKSWAP_SUPPORTED) /* Swap packing order of pixels in bytes. */ -PNG_EXPORT(43, void, png_set_packswap, - (png_structrp png_ptr)); +PNG_EXPORT(43, void, png_set_packswap, (png_structrp png_ptr)); #endif #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) /* Converts files to legal bit depths. */ -PNG_EXPORT(44, void, png_set_shift, - (png_structrp png_ptr, png_const_color_8p true_bits)); +PNG_EXPORT(44, void, png_set_shift, (png_structrp png_ptr, png_const_color_8p + true_bits)); #endif #if defined(PNG_READ_INTERLACING_SUPPORTED) || \ @@ -1330,14 +1455,12 @@ PNG_EXPORT(44, void, png_set_shift, * necessary to call png_read_row or png_read_rows png_get_image_height * times for each pass. */ -PNG_EXPORT(45, int, png_set_interlace_handling, - (png_structrp png_ptr)); +PNG_EXPORT(45, int, png_set_interlace_handling, (png_structrp png_ptr)); #endif #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) /* Invert monochrome files */ -PNG_EXPORT(46, void, png_set_invert_mono, - (png_structrp png_ptr)); +PNG_EXPORT(46, void, png_set_invert_mono, (png_structrp png_ptr)); #endif #ifdef PNG_READ_BACKGROUND_SUPPORTED @@ -1346,12 +1469,10 @@ PNG_EXPORT(46, void, png_set_invert_mono, * read. Doing so will result in unexpected behavior and possible warnings or * errors if the PNG file contains a bKGD chunk. */ -PNG_FP_EXPORT(47, void, png_set_background, - (png_structrp png_ptr, +PNG_FP_EXPORT(47, void, png_set_background, (png_structrp png_ptr, png_const_color_16p background_color, int background_gamma_code, int need_expand, double background_gamma)) -PNG_FIXED_EXPORT(215, void, png_set_background_fixed, - (png_structrp png_ptr, +PNG_FIXED_EXPORT(215, void, png_set_background_fixed, (png_structrp png_ptr, png_const_color_16p background_color, int background_gamma_code, int need_expand, png_fixed_point background_gamma)) #endif @@ -1364,23 +1485,20 @@ PNG_FIXED_EXPORT(215, void, png_set_background_fixed, #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Scale a 16-bit depth file down to 8-bit, accurately. */ -PNG_EXPORT(229, void, png_set_scale_16, - (png_structrp png_ptr)); +PNG_EXPORT(229, void, png_set_scale_16, (png_structrp png_ptr)); #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED -#define PNG_READ_16_TO_8_SUPPORTED /* Name prior to 1.5.4 */ +#define PNG_READ_16_TO_8 SUPPORTED /* Name prior to 1.5.4 */ /* Strip the second byte of information from a 16-bit depth file. */ -PNG_EXPORT(48, void, png_set_strip_16, - (png_structrp png_ptr)); +PNG_EXPORT(48, void, png_set_strip_16, (png_structrp png_ptr)); #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED /* Turn on quantizing, and reduce the palette to the number of colors * available. */ -PNG_EXPORT(49, void, png_set_quantize, - (png_structrp png_ptr, +PNG_EXPORT(49, void, png_set_quantize, (png_structrp png_ptr, png_colorp palette, int num_palette, int maximum_colors, png_const_uint_16p histogram, int full_quantize)); #endif @@ -1402,92 +1520,82 @@ PNG_EXPORT(49, void, png_set_quantize, * API (floating point or fixed.) Notice, however, that the 'file_gamma' value * is the inverse of a 'screen gamma' value. */ -PNG_FP_EXPORT(50, void, png_set_gamma, - (png_structrp png_ptr, +PNG_FP_EXPORT(50, void, png_set_gamma, (png_structrp png_ptr, double screen_gamma, double override_file_gamma)) -PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, - (png_structrp png_ptr, +PNG_FIXED_EXPORT(208, void, png_set_gamma_fixed, (png_structrp png_ptr, png_fixed_point screen_gamma, png_fixed_point override_file_gamma)) #endif #ifdef PNG_WRITE_FLUSH_SUPPORTED /* Set how many lines between output flushes - 0 for no flushing */ -PNG_EXPORT(51, void, png_set_flush, - (png_structrp png_ptr, int nrows)); +PNG_EXPORT(51, void, png_set_flush, (png_structrp png_ptr, int nrows)); /* Flush the current PNG output buffer */ -PNG_EXPORT(52, void, png_write_flush, - (png_structrp png_ptr)); +PNG_EXPORT(52, void, png_write_flush, (png_structrp png_ptr)); #endif /* Optional update palette with requested transformations */ -PNG_EXPORT(53, void, png_start_read_image, - (png_structrp png_ptr)); +PNG_EXPORT(53, void, png_start_read_image, (png_structrp png_ptr)); /* Optional call to update the users info structure */ -PNG_EXPORT(54, void, png_read_update_info, - (png_structrp png_ptr, png_inforp info_ptr)); +PNG_EXPORT(54, void, png_read_update_info, (png_structrp png_ptr, + png_inforp info_ptr)); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read one or more rows of image data. */ -PNG_EXPORT(55, void, png_read_rows, - (png_structrp png_ptr, png_bytepp row, +PNG_EXPORT(55, void, png_read_rows, (png_structrp png_ptr, png_bytepp row, png_bytepp display_row, png_uint_32 num_rows)); #endif #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read a row of data. */ -PNG_EXPORT(56, void, png_read_row, - (png_structrp png_ptr, png_bytep row, png_bytep display_row)); +PNG_EXPORT(56, void, png_read_row, (png_structrp png_ptr, png_bytep row, + png_bytep display_row)); #endif #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the whole image into memory at once. */ -PNG_EXPORT(57, void, png_read_image, - (png_structrp png_ptr, png_bytepp image)); +PNG_EXPORT(57, void, png_read_image, (png_structrp png_ptr, png_bytepp image)); #endif /* Write a row of image data */ -PNG_EXPORT(58, void, png_write_row, - (png_structrp png_ptr, png_const_bytep row)); +PNG_EXPORT(58, void, png_write_row, (png_structrp png_ptr, + png_const_bytep row)); /* Write a few rows of image data: (*row) is not written; however, the type * is declared as writeable to maintain compatibility with previous versions * of libpng and to allow the 'display_row' array from read_rows to be passed * unchanged to write_rows. */ -PNG_EXPORT(59, void, png_write_rows, - (png_structrp png_ptr, png_bytepp row, png_uint_32 num_rows)); +PNG_EXPORT(59, void, png_write_rows, (png_structrp png_ptr, png_bytepp row, + png_uint_32 num_rows)); /* Write the image data */ -PNG_EXPORT(60, void, png_write_image, - (png_structrp png_ptr, png_bytepp image)); +PNG_EXPORT(60, void, png_write_image, (png_structrp png_ptr, png_bytepp image)); /* Write the end of the PNG file. */ -PNG_EXPORT(61, void, png_write_end, - (png_structrp png_ptr, png_inforp info_ptr)); +PNG_EXPORT(61, void, png_write_end, (png_structrp png_ptr, + png_inforp info_ptr)); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the end of the PNG file. */ -PNG_EXPORT(62, void, png_read_end, - (png_structrp png_ptr, png_inforp info_ptr)); +PNG_EXPORT(62, void, png_read_end, (png_structrp png_ptr, png_inforp info_ptr)); #endif /* Free any memory associated with the png_info_struct */ -PNG_EXPORT(63, void, png_destroy_info_struct, - (png_const_structrp png_ptr, png_infopp info_ptr_ptr)); +PNG_EXPORT(63, void, png_destroy_info_struct, (png_const_structrp png_ptr, + png_infopp info_ptr_ptr)); /* Free any memory associated with the png_struct and the png_info_structs */ -PNG_EXPORT(64, void, png_destroy_read_struct, - (png_structpp png_ptr_ptr, +PNG_EXPORT(64, void, png_destroy_read_struct, (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr, png_infopp end_info_ptr_ptr)); /* Free any memory associated with the png_struct and the png_info_structs */ -PNG_EXPORT(65, void, png_destroy_write_struct, - (png_structpp png_ptr_ptr, png_infopp info_ptr_ptr)); +PNG_EXPORT(65, void, png_destroy_write_struct, (png_structpp png_ptr_ptr, + png_infopp info_ptr_ptr)); /* Set the libpng method of handling chunk CRC errors */ -PNG_EXPORT(66, void, png_set_crc_action, - (png_structrp png_ptr, int crit_action, int ancil_action)); +PNG_EXPORT(66, void, png_set_crc_action, (png_structrp png_ptr, int crit_action, + int ancil_action)); /* Values for png_set_crc_action() say how to handle CRC errors in * ancillary and critical chunks, and whether to use the data contained @@ -1505,21 +1613,19 @@ PNG_EXPORT(66, void, png_set_crc_action, #define PNG_CRC_QUIET_USE 4 /* quiet/use data quiet/use data */ #define PNG_CRC_NO_CHANGE 5 /* use current value use current value */ -#ifdef PNG_WRITE_SUPPORTED /* These functions give the user control over the scan-line filtering in * libpng and the compression methods used by zlib. These functions are * mainly useful for testing, as the defaults should work with most users. * Those users who are tight on memory or want faster performance at the * expense of compression can modify them. See the compression library - * header file (zlib.h) for an explanation of the compression functions. + * header file (zlib.h) for an explination of the compression functions. */ /* Set the filtering method(s) used by libpng. Currently, the only valid * value for "method" is 0. */ -PNG_EXPORT(67, void, png_set_filter, - (png_structrp png_ptr, int method, int filters)); -#endif /* WRITE */ +PNG_EXPORT(67, void, png_set_filter, (png_structrp png_ptr, int method, + int filters)); /* Flags for png_set_filter() to say which filters to use. The flags * are chosen so that they don't conflict with real filter types @@ -1532,8 +1638,8 @@ PNG_EXPORT(67, void, png_set_filter, #define PNG_FILTER_UP 0x20 #define PNG_FILTER_AVG 0x40 #define PNG_FILTER_PAETH 0x80 -#define PNG_FAST_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP) -#define PNG_ALL_FILTERS (PNG_FAST_FILTERS | PNG_FILTER_AVG | PNG_FILTER_PAETH) +#define PNG_ALL_FILTERS (PNG_FILTER_NONE | PNG_FILTER_SUB | PNG_FILTER_UP | \ + PNG_FILTER_AVG | PNG_FILTER_PAETH) /* Filter values (not flags) - used in pngwrite.c, pngwutil.c for now. * These defines should NOT be changed. @@ -1545,74 +1651,99 @@ PNG_EXPORT(67, void, png_set_filter, #define PNG_FILTER_VALUE_PAETH 4 #define PNG_FILTER_VALUE_LAST 5 -#ifdef PNG_WRITE_SUPPORTED -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */ -PNG_FP_EXPORT(68, void, png_set_filter_heuristics, - (png_structrp png_ptr, - int heuristic_method, int num_weights, - png_const_doublep filter_weights, +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* EXPERIMENTAL */ +/* The "heuristic_method" is given by one of the PNG_FILTER_HEURISTIC_ + * defines, either the default (minimum-sum-of-absolute-differences), or + * the experimental method (weighted-minimum-sum-of-absolute-differences). + * + * Weights are factors >= 1.0, indicating how important it is to keep the + * filter type consistent between rows. Larger numbers mean the current + * filter is that many times as likely to be the same as the "num_weights" + * previous filters. This is cumulative for each previous row with a weight. + * There needs to be "num_weights" values in "filter_weights", or it can be + * NULL if the weights aren't being specified. Weights have no influence on + * the selection of the first row filter. Well chosen weights can (in theory) + * improve the compression for a given image. + * + * Costs are factors >= 1.0 indicating the relative decoding costs of a + * filter type. Higher costs indicate more decoding expense, and are + * therefore less likely to be selected over a filter with lower computational + * costs. There needs to be a value in "filter_costs" for each valid filter + * type (given by PNG_FILTER_VALUE_LAST), or it can be NULL if you aren't + * setting the costs. Costs try to improve the speed of decompression without + * unduly increasing the compressed image size. + * + * A negative weight or cost indicates the default value is to be used, and + * values in the range [0.0, 1.0) indicate the value is to remain unchanged. + * The default values for both weights and costs are currently 1.0, but may + * change if good general weighting/cost heuristics can be found. If both + * the weights and costs are set to 1.0, this degenerates the WEIGHTED method + * to the UNWEIGHTED method, but with added encoding time/computation. + */ +PNG_FP_EXPORT(68, void, png_set_filter_heuristics, (png_structrp png_ptr, + int heuristic_method, int num_weights, png_const_doublep filter_weights, png_const_doublep filter_costs)) PNG_FIXED_EXPORT(209, void, png_set_filter_heuristics_fixed, - (png_structrp png_ptr, - int heuristic_method, int num_weights, + (png_structrp png_ptr, int heuristic_method, int num_weights, png_const_fixed_point_p filter_weights, png_const_fixed_point_p filter_costs)) -#endif /* WRITE_WEIGHTED_FILTER */ +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ -/* The following are no longer used and will be removed from libpng-1.7: */ +/* Heuristic used for row filter selection. These defines should NOT be + * changed. + */ #define PNG_FILTER_HEURISTIC_DEFAULT 0 /* Currently "UNWEIGHTED" */ #define PNG_FILTER_HEURISTIC_UNWEIGHTED 1 /* Used by libpng < 0.95 */ #define PNG_FILTER_HEURISTIC_WEIGHTED 2 /* Experimental feature */ #define PNG_FILTER_HEURISTIC_LAST 3 /* Not a valid value */ +#ifdef PNG_WRITE_SUPPORTED /* Set the library compression level. Currently, valid values range from * 0 - 9, corresponding directly to the zlib compression levels 0 - 9 * (0 - no compression, 9 - "maximal" compression). Note that tests have * shown that zlib compression levels 3-6 usually perform as well as level 9 - * for PNG images, and do considerably fewer calculations. In the future, + * for PNG images, and do considerably fewer caclulations. In the future, * these values may not correspond directly to the zlib compression levels. */ -#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED -PNG_EXPORT(69, void, png_set_compression_level, - (png_structrp png_ptr, int level)); +PNG_EXPORT(69, void, png_set_compression_level, (png_structrp png_ptr, + int level)); -PNG_EXPORT(70, void, png_set_compression_mem_level, - (png_structrp png_ptr, int mem_level)); +PNG_EXPORT(70, void, png_set_compression_mem_level, (png_structrp png_ptr, + int mem_level)); -PNG_EXPORT(71, void, png_set_compression_strategy, - (png_structrp png_ptr, int strategy)); +PNG_EXPORT(71, void, png_set_compression_strategy, (png_structrp png_ptr, + int strategy)); /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a * smaller value of window_bits if it can do so safely. */ -PNG_EXPORT(72, void, png_set_compression_window_bits, - (png_structrp png_ptr, int window_bits)); +PNG_EXPORT(72, void, png_set_compression_window_bits, (png_structrp png_ptr, + int window_bits)); -PNG_EXPORT(73, void, png_set_compression_method, - (png_structrp png_ptr, int method)); -#endif /* WRITE_CUSTOMIZE_COMPRESSION */ +PNG_EXPORT(73, void, png_set_compression_method, (png_structrp png_ptr, + int method)); +#endif #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED /* Also set zlib parameters for compressing non-IDAT chunks */ -PNG_EXPORT(222, void, png_set_text_compression_level, - (png_structrp png_ptr, int level)); +PNG_EXPORT(222, void, png_set_text_compression_level, (png_structrp png_ptr, + int level)); -PNG_EXPORT(223, void, png_set_text_compression_mem_level, - (png_structrp png_ptr, int mem_level)); +PNG_EXPORT(223, void, png_set_text_compression_mem_level, (png_structrp png_ptr, + int mem_level)); -PNG_EXPORT(224, void, png_set_text_compression_strategy, - (png_structrp png_ptr, int strategy)); +PNG_EXPORT(224, void, png_set_text_compression_strategy, (png_structrp png_ptr, + int strategy)); /* If PNG_WRITE_OPTIMIZE_CMF_SUPPORTED is defined, libpng will use a * smaller value of window_bits if it can do so safely. */ PNG_EXPORT(225, void, png_set_text_compression_window_bits, - (png_structrp png_ptr, int window_bits)); + (png_structrp png_ptr, int window_bits)); -PNG_EXPORT(226, void, png_set_text_compression_method, - (png_structrp png_ptr, int method)); -#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ -#endif /* WRITE */ +PNG_EXPORT(226, void, png_set_text_compression_method, (png_structrp png_ptr, + int method)); +#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ /* These next functions are called for input/output, memory, and error * handling. They are in the file pngrio.c, pngwio.c, and pngerror.c, @@ -1625,8 +1756,7 @@ PNG_EXPORT(226, void, png_set_text_compression_method, #ifdef PNG_STDIO_SUPPORTED /* Initialize the input/output for the PNG file to the default functions. */ -PNG_EXPORT(74, void, png_init_io, - (png_structrp png_ptr, FILE *fp)); +PNG_EXPORT(74, void, png_init_io, (png_structrp png_ptr, png_FILE_p fp)); #endif /* Replace the (error and abort), and warning functions with user @@ -1637,13 +1767,11 @@ PNG_EXPORT(74, void, png_init_io, * default function will be used. */ -PNG_EXPORT(75, void, png_set_error_fn, - (png_structrp png_ptr, +PNG_EXPORT(75, void, png_set_error_fn, (png_structrp png_ptr, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warning_fn)); /* Return the user pointer associated with the error functions */ -PNG_EXPORT(76, png_voidp, png_get_error_ptr, - (png_const_structrp png_ptr)); +PNG_EXPORT(76, png_voidp, png_get_error_ptr, (png_const_structrp png_ptr)); /* Replace the default data output functions with a user supplied one(s). * If buffered output is not used, then output_flush_fn can be set to NULL. @@ -1655,54 +1783,47 @@ PNG_EXPORT(76, png_voidp, png_get_error_ptr, * default flush function, which uses the standard *FILE structure, will * be used. */ -PNG_EXPORT(77, void, png_set_write_fn, - (png_structrp png_ptr, - png_voidp io_ptr, +PNG_EXPORT(77, void, png_set_write_fn, (png_structrp png_ptr, png_voidp io_ptr, png_rw_ptr write_data_fn, png_flush_ptr output_flush_fn)); /* Replace the default data input function with a user supplied one. */ -PNG_EXPORT(78, void, png_set_read_fn, - (png_structrp png_ptr, - png_voidp io_ptr, png_rw_ptr read_data_fn)); +PNG_EXPORT(78, void, png_set_read_fn, (png_structrp png_ptr, png_voidp io_ptr, + png_rw_ptr read_data_fn)); /* Return the user pointer associated with the I/O functions */ -PNG_EXPORT(79, png_voidp, png_get_io_ptr, - (png_const_structrp png_ptr)); +PNG_EXPORT(79, png_voidp, png_get_io_ptr, (png_const_structrp png_ptr)); -PNG_EXPORT(80, void, png_set_read_status_fn, - (png_structrp png_ptr, png_read_status_ptr read_row_fn)); +PNG_EXPORT(80, void, png_set_read_status_fn, (png_structrp png_ptr, + png_read_status_ptr read_row_fn)); -PNG_EXPORT(81, void, png_set_write_status_fn, - (png_structrp png_ptr, png_write_status_ptr write_row_fn)); +PNG_EXPORT(81, void, png_set_write_status_fn, (png_structrp png_ptr, + png_write_status_ptr write_row_fn)); #ifdef PNG_USER_MEM_SUPPORTED /* Replace the default memory allocation functions with user supplied one(s). */ -PNG_EXPORT(82, void, png_set_mem_fn, - (png_structrp png_ptr, - png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn)); +PNG_EXPORT(82, void, png_set_mem_fn, (png_structrp png_ptr, png_voidp mem_ptr, + png_malloc_ptr malloc_fn, png_free_ptr free_fn)); /* Return the user pointer associated with the memory functions */ -PNG_EXPORT(83, png_voidp, png_get_mem_ptr, - (png_const_structrp png_ptr)); +PNG_EXPORT(83, png_voidp, png_get_mem_ptr, (png_const_structrp png_ptr)); #endif #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED -PNG_EXPORT(84, void, png_set_read_user_transform_fn, - (png_structrp png_ptr, png_user_transform_ptr read_user_transform_fn)); +PNG_EXPORT(84, void, png_set_read_user_transform_fn, (png_structrp png_ptr, + png_user_transform_ptr read_user_transform_fn)); #endif #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED -PNG_EXPORT(85, void, png_set_write_user_transform_fn, - (png_structrp png_ptr, png_user_transform_ptr write_user_transform_fn)); +PNG_EXPORT(85, void, png_set_write_user_transform_fn, (png_structrp png_ptr, + png_user_transform_ptr write_user_transform_fn)); #endif #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED -PNG_EXPORT(86, void, png_set_user_transform_info, - (png_structrp png_ptr, - png_voidp user_transform_ptr, - int user_transform_depth, int user_transform_channels)); +PNG_EXPORT(86, void, png_set_user_transform_info, (png_structrp png_ptr, + png_voidp user_transform_ptr, int user_transform_depth, + int user_transform_channels)); /* Return the user pointer associated with the user transform functions */ PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr, - (png_const_structrp png_ptr)); + (png_const_structrp png_ptr)); #endif #ifdef PNG_USER_TRANSFORM_INFO_SUPPORTED @@ -1717,10 +1838,8 @@ PNG_EXPORT(87, png_voidp, png_get_user_transform_ptr, * find the output pixel (x,y) given an interlaced sub-image pixel * (row,col,pass). (See below for these macros.) */ -PNG_EXPORT(217, png_uint_32, png_get_current_row_number, - (png_const_structrp)); -PNG_EXPORT(218, png_byte, png_get_current_pass_number, - (png_const_structrp)); +PNG_EXPORT(217, png_uint_32, png_get_current_row_number, (png_const_structrp)); +PNG_EXPORT(218, png_byte, png_get_current_pass_number, (png_const_structrp)); #endif #ifdef PNG_READ_USER_CHUNKS_SUPPORTED @@ -1735,41 +1854,37 @@ PNG_EXPORT(218, png_byte, png_get_current_pass_number, * * The integer return from the callback function is interpreted thus: * - * negative: An error occurred; png_chunk_error will be called. + * negative: An error occured, png_chunk_error will be called. * zero: The chunk was not handled, the chunk will be saved. A critical * chunk will cause an error at this point unless it is to be saved. * positive: The chunk was handled, libpng will ignore/discard it. * - * See "INTERACTION WITH USER CHUNK CALLBACKS" below for important notes about + * See "INTERACTION WTIH USER CHUNK CALLBACKS" below for important notes about * how this behavior will change in libpng 1.7 */ -PNG_EXPORT(88, void, png_set_read_user_chunk_fn, - (png_structrp png_ptr, +PNG_EXPORT(88, void, png_set_read_user_chunk_fn, (png_structrp png_ptr, png_voidp user_chunk_ptr, png_user_chunk_ptr read_user_chunk_fn)); #endif #ifdef PNG_USER_CHUNKS_SUPPORTED -PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, - (png_const_structrp png_ptr)); +PNG_EXPORT(89, png_voidp, png_get_user_chunk_ptr, (png_const_structrp png_ptr)); #endif #ifdef PNG_PROGRESSIVE_READ_SUPPORTED /* Sets the function callbacks for the push reader, and a pointer to a * user-defined structure available to the callback functions. */ -PNG_EXPORT(90, void, png_set_progressive_read_fn, - (png_structrp png_ptr, +PNG_EXPORT(90, void, png_set_progressive_read_fn, (png_structrp png_ptr, png_voidp progressive_ptr, png_progressive_info_ptr info_fn, png_progressive_row_ptr row_fn, png_progressive_end_ptr end_fn)); /* Returns the user pointer associated with the push read functions */ PNG_EXPORT(91, png_voidp, png_get_progressive_ptr, - (png_const_structrp png_ptr)); + (png_const_structrp png_ptr)); /* Function to be called when data becomes available */ -PNG_EXPORT(92, void, png_process_data, - (png_structrp png_ptr, - png_inforp info_ptr, png_bytep buffer, size_t buffer_size)); +PNG_EXPORT(92, void, png_process_data, (png_structrp png_ptr, + png_inforp info_ptr, png_bytep buffer, png_size_t buffer_size)); /* A function which may be called *only* within png_process_data to stop the * processing of any more data. The function returns the number of bytes @@ -1778,8 +1893,7 @@ PNG_EXPORT(92, void, png_process_data, * 'save' is set to true the routine will first save all the pending data and * will always return 0. */ -PNG_EXPORT(219, size_t, png_process_data_pause, - (png_structrp, int save)); +PNG_EXPORT(219, png_size_t, png_process_data_pause, (png_structrp, int save)); /* A function which may be called *only* outside (after) a call to * png_process_data. It returns the number of bytes of data to skip in the @@ -1787,127 +1901,112 @@ PNG_EXPORT(219, size_t, png_process_data_pause, * application must skip than number of bytes of input data and pass the * following data to the next call to png_process_data. */ -PNG_EXPORT(220, png_uint_32, png_process_data_skip, - (png_structrp)); +PNG_EXPORT(220, png_uint_32, png_process_data_skip, (png_structrp)); +#ifdef PNG_READ_INTERLACING_SUPPORTED /* Function that combines rows. 'new_row' is a flag that should come from * the callback and be non-NULL if anything needs to be done; the library * stores its own version of the new data internally and ignores the passed * in value. */ -PNG_EXPORT(93, void, png_progressive_combine_row, - (png_const_structrp png_ptr, +PNG_EXPORT(93, void, png_progressive_combine_row, (png_const_structrp png_ptr, png_bytep old_row, png_const_bytep new_row)); -#endif /* PROGRESSIVE_READ */ +#endif /* PNG_READ_INTERLACING_SUPPORTED */ +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ -PNG_EXPORTA(94, png_voidp, png_malloc, - (png_const_structrp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED); +PNG_EXPORTA(94, png_voidp, png_malloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); /* Added at libpng version 1.4.0 */ -PNG_EXPORTA(95, png_voidp, png_calloc, - (png_const_structrp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED); +PNG_EXPORTA(95, png_voidp, png_calloc, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); /* Added at libpng version 1.2.4 */ -PNG_EXPORTA(96, png_voidp, png_malloc_warn, - (png_const_structrp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED); +PNG_EXPORTA(96, png_voidp, png_malloc_warn, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED); /* Frees a pointer allocated by png_malloc() */ -PNG_EXPORT(97, void, png_free, - (png_const_structrp png_ptr, png_voidp ptr)); +PNG_EXPORT(97, void, png_free, (png_const_structrp png_ptr, png_voidp ptr)); /* Free data that was allocated internally */ -PNG_EXPORT(98, void, png_free_data, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_uint_32 free_me, int num)); +PNG_EXPORT(98, void, png_free_data, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 free_me, int num)); -/* Reassign the responsibility for freeing existing data, whether allocated +/* Reassign responsibility for freeing existing data, whether allocated * by libpng or by the application; this works on the png_info structure passed - * in, without changing the state for other png_info structures. + * in, it does not change the state for other png_info structures. + * + * It is unlikely that this function works correctly as of 1.6.0 and using it + * may result either in memory leaks or double free of allocated data. */ -PNG_EXPORT(99, void, png_data_freer, - (png_const_structrp png_ptr, png_inforp info_ptr, - int freer, png_uint_32 mask)); +PNG_EXPORTA(99, void, png_data_freer, (png_const_structrp png_ptr, + png_inforp info_ptr, int freer, png_uint_32 mask), PNG_DEPRECATED); /* Assignments for png_data_freer */ #define PNG_DESTROY_WILL_FREE_DATA 1 -#define PNG_SET_WILL_FREE_DATA 1 -#define PNG_USER_WILL_FREE_DATA 2 +#define PNG_SET_WILL_FREE_DATA 1 +#define PNG_USER_WILL_FREE_DATA 2 /* Flags for png_ptr->free_me and info_ptr->free_me */ -#define PNG_FREE_HIST 0x0008U -#define PNG_FREE_ICCP 0x0010U -#define PNG_FREE_SPLT 0x0020U -#define PNG_FREE_ROWS 0x0040U -#define PNG_FREE_PCAL 0x0080U -#define PNG_FREE_SCAL 0x0100U +#define PNG_FREE_HIST 0x0008 +#define PNG_FREE_ICCP 0x0010 +#define PNG_FREE_SPLT 0x0020 +#define PNG_FREE_ROWS 0x0040 +#define PNG_FREE_PCAL 0x0080 +#define PNG_FREE_SCAL 0x0100 #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED -# define PNG_FREE_UNKN 0x0200U +# define PNG_FREE_UNKN 0x0200 #endif -/* PNG_FREE_LIST 0x0400U removed in 1.6.0 because it is ignored */ -#define PNG_FREE_PLTE 0x1000U -#define PNG_FREE_TRNS 0x2000U -#define PNG_FREE_TEXT 0x4000U -#define PNG_FREE_EXIF 0x8000U /* Added at libpng-1.6.31 */ -#define PNG_FREE_ALL 0xffffU -#define PNG_FREE_MUL 0x4220U /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ +/* PNG_FREE_LIST 0x0400 removed in 1.6.0 because it is ignored */ +#define PNG_FREE_PLTE 0x1000 +#define PNG_FREE_TRNS 0x2000 +#define PNG_FREE_TEXT 0x4000 +#define PNG_FREE_ALL 0x7fff +#define PNG_FREE_MUL 0x4220 /* PNG_FREE_SPLT|PNG_FREE_TEXT|PNG_FREE_UNKN */ #ifdef PNG_USER_MEM_SUPPORTED -PNG_EXPORTA(100, png_voidp, png_malloc_default, - (png_const_structrp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED PNG_DEPRECATED); -PNG_EXPORTA(101, void, png_free_default, - (png_const_structrp png_ptr, png_voidp ptr), - PNG_DEPRECATED); +PNG_EXPORTA(100, png_voidp, png_malloc_default, (png_const_structrp png_ptr, + png_alloc_size_t size), PNG_ALLOCATED PNG_DEPRECATED); +PNG_EXPORTA(101, void, png_free_default, (png_const_structrp png_ptr, + png_voidp ptr), PNG_DEPRECATED); #endif #ifdef PNG_ERROR_TEXT_SUPPORTED /* Fatal error in PNG image of libpng - can't continue */ -PNG_EXPORTA(102, void, png_error, - (png_const_structrp png_ptr, png_const_charp error_message), - PNG_NORETURN); +PNG_EXPORTA(102, void, png_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); /* The same, but the chunk name is prepended to the error string. */ -PNG_EXPORTA(103, void, png_chunk_error, - (png_const_structrp png_ptr, png_const_charp error_message), - PNG_NORETURN); +PNG_EXPORTA(103, void, png_chunk_error, (png_const_structrp png_ptr, + png_const_charp error_message), PNG_NORETURN); #else /* Fatal error in PNG image of libpng - can't continue */ -PNG_EXPORTA(104, void, png_err, - (png_const_structrp png_ptr), - PNG_NORETURN); -# define png_error(s1,s2) png_err(s1) -# define png_chunk_error(s1,s2) png_err(s1) +PNG_EXPORTA(104, void, png_err, (png_const_structrp png_ptr), PNG_NORETURN); #endif #ifdef PNG_WARNINGS_SUPPORTED /* Non-fatal error in libpng. Can continue, but may have a problem. */ -PNG_EXPORT(105, void, png_warning, - (png_const_structrp png_ptr, png_const_charp warning_message)); +PNG_EXPORT(105, void, png_warning, (png_const_structrp png_ptr, + png_const_charp warning_message)); /* Non-fatal error in libpng, chunk name is prepended to message. */ -PNG_EXPORT(106, void, png_chunk_warning, - (png_const_structrp png_ptr, png_const_charp warning_message)); -#else -# define png_warning(s1,s2) ((void)(s1)) -# define png_chunk_warning(s1,s2) ((void)(s1)) +PNG_EXPORT(106, void, png_chunk_warning, (png_const_structrp png_ptr, + png_const_charp warning_message)); #endif #ifdef PNG_BENIGN_ERRORS_SUPPORTED /* Benign error in libpng. Can continue, but may have a problem. * User can choose whether to handle as a fatal error or as a warning. */ -PNG_EXPORT(107, void, png_benign_error, - (png_const_structrp png_ptr, png_const_charp warning_message)); +PNG_EXPORT(107, void, png_benign_error, (png_const_structrp png_ptr, + png_const_charp warning_message)); #ifdef PNG_READ_SUPPORTED /* Same, chunk name is prepended to message (only during read) */ -PNG_EXPORT(108, void, png_chunk_benign_error, - (png_const_structrp png_ptr, png_const_charp warning_message)); +PNG_EXPORT(108, void, png_chunk_benign_error, (png_const_structrp png_ptr, + png_const_charp warning_message)); #endif PNG_EXPORT(109, void, png_set_benign_errors, - (png_structrp png_ptr, int allowed)); + (png_structrp png_ptr, int allowed)); #else # ifdef PNG_ALLOW_BENIGN_ERRORS # define png_benign_error png_warning @@ -1931,413 +2030,274 @@ PNG_EXPORT(109, void, png_set_benign_errors, * png_info_struct. */ /* Returns "flag" if chunk data is valid in info_ptr. */ -PNG_EXPORT(110, png_uint_32, png_get_valid, - (png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 flag)); +PNG_EXPORT(110, png_uint_32, png_get_valid, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 flag)); /* Returns number of bytes needed to hold a transformed row. */ -PNG_EXPORT(111, size_t, png_get_rowbytes, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(111, png_size_t, png_get_rowbytes, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); #ifdef PNG_INFO_IMAGE_SUPPORTED /* Returns row_pointers, which is an array of pointers to scanlines that was * returned from png_read_png(). */ -PNG_EXPORT(112, png_bytepp, png_get_rows, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(112, png_bytepp, png_get_rows, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Set row_pointers, which is an array of pointers to scanlines for use * by png_write_png(). */ -PNG_EXPORT(113, void, png_set_rows, - (png_const_structrp png_ptr, png_inforp info_ptr, png_bytepp row_pointers)); +PNG_EXPORT(113, void, png_set_rows, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytepp row_pointers)); #endif /* Returns number of color channels in image. */ -PNG_EXPORT(114, png_byte, png_get_channels, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(114, png_byte, png_get_channels, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); #ifdef PNG_EASY_ACCESS_SUPPORTED /* Returns image width in pixels. */ -PNG_EXPORT(115, png_uint_32, png_get_image_width, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(115, png_uint_32, png_get_image_width, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image height in pixels. */ -PNG_EXPORT(116, png_uint_32, png_get_image_height, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(116, png_uint_32, png_get_image_height, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image bit_depth. */ -PNG_EXPORT(117, png_byte, png_get_bit_depth, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(117, png_byte, png_get_bit_depth, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image color_type. */ -PNG_EXPORT(118, png_byte, png_get_color_type, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(118, png_byte, png_get_color_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image filter_type. */ -PNG_EXPORT(119, png_byte, png_get_filter_type, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(119, png_byte, png_get_filter_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image interlace_type. */ -PNG_EXPORT(120, png_byte, png_get_interlace_type, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(120, png_byte, png_get_interlace_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image compression_type. */ -PNG_EXPORT(121, png_byte, png_get_compression_type, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(121, png_byte, png_get_compression_type, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); /* Returns image resolution in pixels per meter, from pHYs chunk data. */ PNG_EXPORT(122, png_uint_32, png_get_pixels_per_meter, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(123, png_uint_32, png_get_x_pixels_per_meter, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(124, png_uint_32, png_get_y_pixels_per_meter, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); /* Returns pixel aspect ratio, computed from pHYs chunk data. */ PNG_FP_EXPORT(125, float, png_get_pixel_aspect_ratio, - (png_const_structrp png_ptr, png_const_inforp info_ptr)) + (png_const_structrp png_ptr, png_const_inforp info_ptr)) PNG_FIXED_EXPORT(210, png_fixed_point, png_get_pixel_aspect_ratio_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr)) + (png_const_structrp png_ptr, png_const_inforp info_ptr)) /* Returns image x, y offset in pixels or microns, from oFFs chunk data. */ PNG_EXPORT(126, png_int_32, png_get_x_offset_pixels, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(127, png_int_32, png_get_y_offset_pixels, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(128, png_int_32, png_get_x_offset_microns, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(129, png_int_32, png_get_y_offset_microns, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); -#endif /* EASY_ACCESS */ +#endif /* PNG_EASY_ACCESS_SUPPORTED */ #ifdef PNG_READ_SUPPORTED /* Returns pointer to signature string read from PNG header */ -PNG_EXPORT(130, png_const_bytep, png_get_signature, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); +PNG_EXPORT(130, png_const_bytep, png_get_signature, (png_const_structrp png_ptr, + png_const_inforp info_ptr)); #endif #ifdef PNG_bKGD_SUPPORTED -PNG_EXPORT(131, png_uint_32, png_get_bKGD, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_color_16p *background)); +PNG_EXPORT(131, png_uint_32, png_get_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_16p *background)); #endif #ifdef PNG_bKGD_SUPPORTED -PNG_EXPORT(132, void, png_set_bKGD, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_const_color_16p background)); +PNG_EXPORT(132, void, png_set_bKGD, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_16p background)); #endif #ifdef PNG_cHRM_SUPPORTED -PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - double *white_x, double *white_y, - double *red_x, double *red_y, - double *green_x, double *green_y, - double *blue_x, double *blue_y)) -PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - double *red_X, double *red_Y, double *red_Z, - double *green_X, double *green_Y, double *green_Z, - double *blue_X, double *blue_Y, double *blue_Z)) +PNG_FP_EXPORT(133, png_uint_32, png_get_cHRM, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *white_x, double *white_y, double *red_x, + double *red_y, double *green_x, double *green_y, double *blue_x, + double *blue_y)) +PNG_FP_EXPORT(230, png_uint_32, png_get_cHRM_XYZ, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *red_X, double *red_Y, double *red_Z, + double *green_X, double *green_Y, double *green_Z, double *blue_X, + double *blue_Y, double *blue_Z)) PNG_FIXED_EXPORT(134, png_uint_32, png_get_cHRM_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr, + (png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *int_white_x, png_fixed_point *int_white_y, png_fixed_point *int_red_x, png_fixed_point *int_red_y, png_fixed_point *int_green_x, png_fixed_point *int_green_y, png_fixed_point *int_blue_x, png_fixed_point *int_blue_y)) PNG_FIXED_EXPORT(231, png_uint_32, png_get_cHRM_XYZ_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr, + (png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *int_red_X, png_fixed_point *int_red_Y, - png_fixed_point *int_red_Z, - png_fixed_point *int_green_X, png_fixed_point *int_green_Y, - png_fixed_point *int_green_Z, + png_fixed_point *int_red_Z, png_fixed_point *int_green_X, + png_fixed_point *int_green_Y, png_fixed_point *int_green_Z, png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, png_fixed_point *int_blue_Z)) #endif #ifdef PNG_cHRM_SUPPORTED -PNG_FP_EXPORT(135, void, png_set_cHRM, - (png_const_structrp png_ptr, png_inforp info_ptr, - double white_x, double white_y, - double red_x, double red_y, - double green_x, double green_y, - double blue_x, double blue_y)) -PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, - (png_const_structrp png_ptr, png_inforp info_ptr, - double red_X, double red_Y, double red_Z, - double green_X, double green_Y, double green_Z, - double blue_X, double blue_Y, double blue_Z)) -PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_fixed_point int_white_x, png_fixed_point int_white_y, - png_fixed_point int_red_x, png_fixed_point int_red_y, - png_fixed_point int_green_x, png_fixed_point int_green_y, - png_fixed_point int_blue_x, png_fixed_point int_blue_y)) -PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_fixed_point int_red_X, png_fixed_point int_red_Y, - png_fixed_point int_red_Z, - png_fixed_point int_green_X, png_fixed_point int_green_Y, - png_fixed_point int_green_Z, +PNG_FP_EXPORT(135, void, png_set_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, + double white_x, double white_y, double red_x, double red_y, double green_x, + double green_y, double blue_x, double blue_y)) +PNG_FP_EXPORT(232, void, png_set_cHRM_XYZ, (png_const_structrp png_ptr, + png_inforp info_ptr, double red_X, double red_Y, double red_Z, + double green_X, double green_Y, double green_Z, double blue_X, + double blue_Y, double blue_Z)) +PNG_FIXED_EXPORT(136, void, png_set_cHRM_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_white_x, + png_fixed_point int_white_y, png_fixed_point int_red_x, + png_fixed_point int_red_y, png_fixed_point int_green_x, + png_fixed_point int_green_y, png_fixed_point int_blue_x, + png_fixed_point int_blue_y)) +PNG_FIXED_EXPORT(233, void, png_set_cHRM_XYZ_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_red_X, png_fixed_point int_red_Y, + png_fixed_point int_red_Z, png_fixed_point int_green_X, + png_fixed_point int_green_Y, png_fixed_point int_green_Z, png_fixed_point int_blue_X, png_fixed_point int_blue_Y, png_fixed_point int_blue_Z)) #endif -#ifdef PNG_cICP_SUPPORTED -PNG_EXPORT(250, png_uint_32, png_get_cICP, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - png_bytep colour_primaries, png_bytep transfer_function, - png_bytep matrix_coefficients, png_bytep video_full_range_flag)); -#endif - -#ifdef PNG_cICP_SUPPORTED -PNG_EXPORT(251, void, png_set_cICP, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_byte colour_primaries, png_byte transfer_function, - png_byte matrix_coefficients, png_byte video_full_range_flag)); -#endif - -#ifdef PNG_cLLI_SUPPORTED -PNG_FP_EXPORT(252, png_uint_32, png_get_cLLI, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - double *maximum_content_light_level, - double *maximum_frame_average_light_level)) -PNG_FIXED_EXPORT(253, png_uint_32, png_get_cLLI_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - /* The values below are in cd/m2 (nits) and are scaled by 10,000; not - * 100,000 as in the case of png_fixed_point. - */ - png_uint_32p maximum_content_light_level_scaled_by_10000, - png_uint_32p maximum_frame_average_light_level_scaled_by_10000)) -#endif - -#ifdef PNG_cLLI_SUPPORTED -PNG_FP_EXPORT(254, void, png_set_cLLI, - (png_const_structrp png_ptr, png_inforp info_ptr, - double maximum_content_light_level, - double maximum_frame_average_light_level)) -PNG_FIXED_EXPORT(255, void, png_set_cLLI_fixed, - (png_const_structrp png_ptr, png_inforp info_ptr, - /* The values below are in cd/m2 (nits) and are scaled by 10,000; not - * 100,000 as in the case of png_fixed_point. - */ - png_uint_32 maximum_content_light_level_scaled_by_10000, - png_uint_32 maximum_frame_average_light_level_scaled_by_10000)) -#endif - -#ifdef PNG_eXIf_SUPPORTED -PNG_EXPORT(246, png_uint_32, png_get_eXIf, - (png_const_structrp png_ptr, png_inforp info_ptr, png_bytep *exif)); -PNG_EXPORT(247, void, png_set_eXIf, - (png_const_structrp png_ptr, png_inforp info_ptr, png_bytep exif)); - -PNG_EXPORT(248, png_uint_32, png_get_eXIf_1, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - png_uint_32 *num_exif, png_bytep *exif)); -PNG_EXPORT(249, void, png_set_eXIf_1, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_uint_32 num_exif, png_bytep exif)); -#endif - #ifdef PNG_gAMA_SUPPORTED -PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - double *file_gamma)) +PNG_FP_EXPORT(137, png_uint_32, png_get_gAMA, (png_const_structrp png_ptr, + png_const_inforp info_ptr, double *file_gamma)) PNG_FIXED_EXPORT(138, png_uint_32, png_get_gAMA_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr, + (png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *int_file_gamma)) #endif #ifdef PNG_gAMA_SUPPORTED -PNG_FP_EXPORT(139, void, png_set_gAMA, - (png_const_structrp png_ptr, png_inforp info_ptr, - double file_gamma)) -PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_fixed_point int_file_gamma)) +PNG_FP_EXPORT(139, void, png_set_gAMA, (png_const_structrp png_ptr, + png_inforp info_ptr, double file_gamma)) +PNG_FIXED_EXPORT(140, void, png_set_gAMA_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, png_fixed_point int_file_gamma)) #endif #ifdef PNG_hIST_SUPPORTED -PNG_EXPORT(141, png_uint_32, png_get_hIST, - (png_const_structrp png_ptr, png_inforp info_ptr, png_uint_16p *hist)); -PNG_EXPORT(142, void, png_set_hIST, - (png_const_structrp png_ptr, png_inforp info_ptr, png_const_uint_16p hist)); +PNG_EXPORT(141, png_uint_32, png_get_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_16p *hist)); #endif -PNG_EXPORT(143, png_uint_32, png_get_IHDR, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - png_uint_32 *width, png_uint_32 *height, - int *bit_depth, int *color_type, - int *interlace_method, int *compression_method, int *filter_method)); - -PNG_EXPORT(144, void, png_set_IHDR, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_uint_32 width, png_uint_32 height, - int bit_depth, int color_type, - int interlace_method, int compression_method, int filter_method)); - -#ifdef PNG_mDCV_SUPPORTED -PNG_FP_EXPORT(256, png_uint_32, png_get_mDCV, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - /* The chromaticities of the mastering display. As cHRM, but independent of - * the encoding endpoints in cHRM, or cICP, or iCCP. These values will - * always be in the range 0 to 1.3107. - */ - double *white_x, double *white_y, - double *red_x, double *red_y, - double *green_x, double *green_y, - double *blue_x, double *blue_y, - /* Mastering display luminance in cd/m2 (nits). */ - double *mastering_display_maximum_luminance, - double *mastering_display_minimum_luminance)) - -PNG_FIXED_EXPORT(257, png_uint_32, png_get_mDCV_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - png_fixed_point *int_white_x, png_fixed_point *int_white_y, - png_fixed_point *int_red_x, png_fixed_point *int_red_y, - png_fixed_point *int_green_x, png_fixed_point *int_green_y, - png_fixed_point *int_blue_x, png_fixed_point *int_blue_y, - /* Mastering display luminance in cd/m2 (nits) multiplied (scaled) by - * 10,000. - */ - png_uint_32p mastering_display_maximum_luminance_scaled_by_10000, - png_uint_32p mastering_display_minimum_luminance_scaled_by_10000)) +#ifdef PNG_hIST_SUPPORTED +PNG_EXPORT(142, void, png_set_hIST, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_uint_16p hist)); #endif -#ifdef PNG_mDCV_SUPPORTED -PNG_FP_EXPORT(258, void, png_set_mDCV, - (png_const_structrp png_ptr, png_inforp info_ptr, - /* The chromaticities of the mastering display. As cHRM, but independent of - * the encoding endpoints in cHRM, or cICP, or iCCP. - */ - double white_x, double white_y, - double red_x, double red_y, - double green_x, double green_y, - double blue_x, double blue_y, - /* Mastering display luminance in cd/m2 (nits). */ - double mastering_display_maximum_luminance, - double mastering_display_minimum_luminance)) +PNG_EXPORT(143, png_uint_32, png_get_IHDR, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *width, png_uint_32 *height, + int *bit_depth, int *color_type, int *interlace_method, + int *compression_method, int *filter_method)); -PNG_FIXED_EXPORT(259, void, png_set_mDCV_fixed, - (png_const_structrp png_ptr, png_inforp info_ptr, - /* The admissible range of these values is not the full range of a PNG - * fixed point value. Negative values cannot be encoded and the maximum - * value is about 1.3 */ - png_fixed_point int_white_x, png_fixed_point int_white_y, - png_fixed_point int_red_x, png_fixed_point int_red_y, - png_fixed_point int_green_x, png_fixed_point int_green_y, - png_fixed_point int_blue_x, png_fixed_point int_blue_y, - /* These are PNG unsigned 4 byte values: 31-bit unsigned values. The MSB - * must be zero. - */ - png_uint_32 mastering_display_maximum_luminance_scaled_by_10000, - png_uint_32 mastering_display_minimum_luminance_scaled_by_10000)) +PNG_EXPORT(144, void, png_set_IHDR, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_method, int compression_method, + int filter_method)); + +#ifdef PNG_oFFs_SUPPORTED +PNG_EXPORT(145, png_uint_32, png_get_oFFs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_int_32 *offset_x, png_int_32 *offset_y, + int *unit_type)); #endif #ifdef PNG_oFFs_SUPPORTED -PNG_EXPORT(145, png_uint_32, png_get_oFFs, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - png_int_32 *offset_x, png_int_32 *offset_y, int *unit_type)); -#endif - -#ifdef PNG_oFFs_SUPPORTED -PNG_EXPORT(146, void, png_set_oFFs, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_int_32 offset_x, png_int_32 offset_y, int unit_type)); +PNG_EXPORT(146, void, png_set_oFFs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_int_32 offset_x, png_int_32 offset_y, + int unit_type)); #endif #ifdef PNG_pCAL_SUPPORTED -PNG_EXPORT(147, png_uint_32, png_get_pCAL, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_charp *purpose, png_int_32 *X0, png_int_32 *X1, - int *type, int *nparams, png_charp *units, png_charpp *params)); +PNG_EXPORT(147, png_uint_32, png_get_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charp *purpose, png_int_32 *X0, + png_int_32 *X1, int *type, int *nparams, png_charp *units, + png_charpp *params)); #endif #ifdef PNG_pCAL_SUPPORTED -PNG_EXPORT(148, void, png_set_pCAL, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_const_charp purpose, png_int_32 X0, png_int_32 X1, +PNG_EXPORT(148, void, png_set_pCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, png_const_charp units, png_charpp params)); #endif #ifdef PNG_pHYs_SUPPORTED -PNG_EXPORT(149, png_uint_32, png_get_pHYs, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); +PNG_EXPORT(149, png_uint_32, png_get_pHYs, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); #endif #ifdef PNG_pHYs_SUPPORTED -PNG_EXPORT(150, void, png_set_pHYs, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_uint_32 res_x, png_uint_32 res_y, int unit_type)); +PNG_EXPORT(150, void, png_set_pHYs, (png_const_structrp png_ptr, + png_inforp info_ptr, png_uint_32 res_x, png_uint_32 res_y, int unit_type)); #endif -PNG_EXPORT(151, png_uint_32, png_get_PLTE, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_colorp *palette, int *num_palette)); +PNG_EXPORT(151, png_uint_32, png_get_PLTE, (png_const_structrp png_ptr, + png_inforp info_ptr, png_colorp *palette, int *num_palette)); -PNG_EXPORT(152, void, png_set_PLTE, - (png_structrp png_ptr, png_inforp info_ptr, - png_const_colorp palette, int num_palette)); +PNG_EXPORT(152, void, png_set_PLTE, (png_structrp png_ptr, + png_inforp info_ptr, png_const_colorp palette, int num_palette)); #ifdef PNG_sBIT_SUPPORTED -PNG_EXPORT(153, png_uint_32, png_get_sBIT, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_color_8p *sig_bit)); +PNG_EXPORT(153, png_uint_32, png_get_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_color_8p *sig_bit)); #endif #ifdef PNG_sBIT_SUPPORTED -PNG_EXPORT(154, void, png_set_sBIT, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_const_color_8p sig_bit)); +PNG_EXPORT(154, void, png_set_sBIT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_color_8p sig_bit)); #endif #ifdef PNG_sRGB_SUPPORTED -PNG_EXPORT(155, png_uint_32, png_get_sRGB, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - int *file_srgb_intent)); +PNG_EXPORT(155, png_uint_32, png_get_sRGB, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *file_srgb_intent)); #endif #ifdef PNG_sRGB_SUPPORTED -PNG_EXPORT(156, void, png_set_sRGB, - (png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)); -PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, - (png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)); +PNG_EXPORT(156, void, png_set_sRGB, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); +PNG_EXPORT(157, void, png_set_sRGB_gAMA_and_cHRM, (png_const_structrp png_ptr, + png_inforp info_ptr, int srgb_intent)); #endif #ifdef PNG_iCCP_SUPPORTED -PNG_EXPORT(158, png_uint_32, png_get_iCCP, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_charpp name, int *compression_type, +PNG_EXPORT(158, png_uint_32, png_get_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_charpp name, int *compression_type, png_bytepp profile, png_uint_32 *proflen)); #endif #ifdef PNG_iCCP_SUPPORTED -PNG_EXPORT(159, void, png_set_iCCP, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_const_charp name, int compression_type, +PNG_EXPORT(159, void, png_set_iCCP, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_charp name, int compression_type, png_const_bytep profile, png_uint_32 proflen)); #endif #ifdef PNG_sPLT_SUPPORTED -PNG_EXPORT(160, int, png_get_sPLT, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_sPLT_tpp entries)); +PNG_EXPORT(160, int, png_get_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_sPLT_tpp entries)); #endif #ifdef PNG_sPLT_SUPPORTED -PNG_EXPORT(161, void, png_set_sPLT, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_const_sPLT_tp entries, int nentries)); +PNG_EXPORT(161, void, png_set_sPLT, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)); #endif #ifdef PNG_TEXT_SUPPORTED /* png_get_text also returns the number of text chunks in *num_text */ -PNG_EXPORT(162, int, png_get_text, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_textp *text_ptr, int *num_text)); +PNG_EXPORT(162, int, png_get_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_textp *text_ptr, int *num_text)); #endif /* Note while png_set_text() will accept a structure whose text, @@ -2348,41 +2308,35 @@ PNG_EXPORT(162, int, png_get_text, */ #ifdef PNG_TEXT_SUPPORTED -PNG_EXPORT(163, void, png_set_text, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_const_textp text_ptr, int num_text)); +PNG_EXPORT(163, void, png_set_text, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text)); #endif #ifdef PNG_tIME_SUPPORTED -PNG_EXPORT(164, png_uint_32, png_get_tIME, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_timep *mod_time)); +PNG_EXPORT(164, png_uint_32, png_get_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_timep *mod_time)); #endif #ifdef PNG_tIME_SUPPORTED -PNG_EXPORT(165, void, png_set_tIME, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_const_timep mod_time)); +PNG_EXPORT(165, void, png_set_tIME, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_timep mod_time)); #endif #ifdef PNG_tRNS_SUPPORTED -PNG_EXPORT(166, png_uint_32, png_get_tRNS, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_bytep *trans_alpha, int *num_trans, +PNG_EXPORT(166, png_uint_32, png_get_tRNS, (png_const_structrp png_ptr, + png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color)); #endif #ifdef PNG_tRNS_SUPPORTED -PNG_EXPORT(167, void, png_set_tRNS, - (png_structrp png_ptr, png_inforp info_ptr, - png_const_bytep trans_alpha, int num_trans, +PNG_EXPORT(167, void, png_set_tRNS, (png_structrp png_ptr, + png_inforp info_ptr, png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color)); #endif #ifdef PNG_sCAL_SUPPORTED -PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - int *unit, double *width, double *height)) +PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, (png_const_structrp png_ptr, + png_const_inforp info_ptr, int *unit, double *width, double *height)) #if defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) || \ defined(PNG_FLOATING_POINT_SUPPORTED) /* NOTE: this API is currently implemented using floating point arithmetic, @@ -2391,23 +2345,22 @@ PNG_FP_EXPORT(168, png_uint_32, png_get_sCAL, * is highly recommended that png_get_sCAL_s be used instead. */ PNG_FIXED_EXPORT(214, png_uint_32, png_get_sCAL_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - int *unit, png_fixed_point *width, png_fixed_point *height)) + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_fixed_point *width, png_fixed_point *height)) #endif PNG_EXPORT(169, png_uint_32, png_get_sCAL_s, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - int *unit, png_charpp swidth, png_charpp sheight)); + (png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, + png_charpp swidth, png_charpp sheight)); -PNG_FP_EXPORT(170, void, png_set_sCAL, - (png_const_structrp png_ptr, png_inforp info_ptr, - int unit, double width, double height)) -PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, - (png_const_structrp png_ptr, png_inforp info_ptr, - int unit, png_fixed_point width, png_fixed_point height)) -PNG_EXPORT(171, void, png_set_sCAL_s, - (png_const_structrp png_ptr, png_inforp info_ptr, - int unit, png_const_charp swidth, png_const_charp sheight)); -#endif /* sCAL */ +PNG_FP_EXPORT(170, void, png_set_sCAL, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, double width, double height)) +PNG_FIXED_EXPORT(213, void, png_set_sCAL_fixed, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, png_fixed_point width, + png_fixed_point height)) +PNG_EXPORT(171, void, png_set_sCAL_s, (png_const_structrp png_ptr, + png_inforp info_ptr, int unit, + png_const_charp swidth, png_const_charp sheight)); +#endif /* PNG_sCAL_SUPPORTED */ #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED /* Provide the default handling for all unknown chunks or, optionally, for @@ -2441,7 +2394,7 @@ PNG_EXPORT(171, void, png_set_sCAL_s, * to specifying "NEVER", however when "AS_DEFAULT" is used for specific chunks * it simply resets the behavior to the libpng default. * - * INTERACTION WITH USER CHUNK CALLBACKS: + * INTERACTION WTIH USER CHUNK CALLBACKS: * The per-chunk handling is always used when there is a png_user_chunk_ptr * callback and the callback returns 0; the chunk is then always stored *unless* * it is critical and the per-chunk setting is other than ALWAYS. Notice that @@ -2508,24 +2461,21 @@ PNG_EXPORT(171, void, png_set_sCAL_s, * except for the IHDR, PLTE, tRNS, IDAT, and IEND chunks (which continue to * be processed by libpng. */ -#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED -PNG_EXPORT(172, void, png_set_keep_unknown_chunks, - (png_structrp png_ptr, +PNG_EXPORT(172, void, png_set_keep_unknown_chunks, (png_structrp png_ptr, int keep, png_const_bytep chunk_list, int num_chunks)); -#endif /* HANDLE_AS_UNKNOWN */ /* The "keep" PNG_HANDLE_CHUNK_ parameter for the specified chunk is returned; * the result is therefore true (non-zero) if special handling is required, * false for the default handling. */ -PNG_EXPORT(173, int, png_handle_as_unknown, - (png_const_structrp png_ptr, png_const_bytep chunk_name)); -#endif /* SET_UNKNOWN_CHUNKS */ +PNG_EXPORT(173, int, png_handle_as_unknown, (png_const_structrp png_ptr, + png_const_bytep chunk_name)); +#endif #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED -PNG_EXPORT(174, void, png_set_unknown_chunks, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_const_unknown_chunkp unknowns, int num_unknowns)); +PNG_EXPORT(174, void, png_set_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_const_unknown_chunkp unknowns, + int num_unknowns)); /* NOTE: prior to 1.6.0 this routine set the 'location' field of the added * unknowns to the location currently stored in the png_struct. This is * invariably the wrong value on write. To fix this call the following API @@ -2536,47 +2486,39 @@ PNG_EXPORT(174, void, png_set_unknown_chunks, */ PNG_EXPORT(175, void, png_set_unknown_chunk_location, - (png_const_structrp png_ptr, png_inforp info_ptr, - int chunk, int location)); + (png_const_structrp png_ptr, png_inforp info_ptr, int chunk, int location)); -PNG_EXPORT(176, int, png_get_unknown_chunks, - (png_const_structrp png_ptr, png_inforp info_ptr, - png_unknown_chunkpp entries)); +PNG_EXPORT(176, int, png_get_unknown_chunks, (png_const_structrp png_ptr, + png_inforp info_ptr, png_unknown_chunkpp entries)); #endif /* Png_free_data() will turn off the "valid" flag for anything it frees. * If you need to turn it off for a chunk that your application has freed, * you can use png_set_invalid(png_ptr, info_ptr, PNG_INFO_CHNK); */ -PNG_EXPORT(177, void, png_set_invalid, - (png_const_structrp png_ptr, png_inforp info_ptr, int mask)); +PNG_EXPORT(177, void, png_set_invalid, (png_const_structrp png_ptr, + png_inforp info_ptr, int mask)); #ifdef PNG_INFO_IMAGE_SUPPORTED /* The "params" pointer is currently not used and is for future expansion. */ -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED -PNG_EXPORT(178, void, png_read_png, - (png_structrp png_ptr, png_inforp info_ptr, +PNG_EXPORT(178, void, png_read_png, (png_structrp png_ptr, png_inforp info_ptr, int transforms, png_voidp params)); -#endif -#ifdef PNG_WRITE_SUPPORTED -PNG_EXPORT(179, void, png_write_png, - (png_structrp png_ptr, png_inforp info_ptr, +PNG_EXPORT(179, void, png_write_png, (png_structrp png_ptr, png_inforp info_ptr, int transforms, png_voidp params)); #endif -#endif PNG_EXPORT(180, png_const_charp, png_get_copyright, - (png_const_structrp png_ptr)); + (png_const_structrp png_ptr)); PNG_EXPORT(181, png_const_charp, png_get_header_ver, - (png_const_structrp png_ptr)); + (png_const_structrp png_ptr)); PNG_EXPORT(182, png_const_charp, png_get_header_version, - (png_const_structrp png_ptr)); + (png_const_structrp png_ptr)); PNG_EXPORT(183, png_const_charp, png_get_libpng_ver, - (png_const_structrp png_ptr)); + (png_const_structrp png_ptr)); #ifdef PNG_MNG_FEATURES_SUPPORTED -PNG_EXPORT(184, png_uint_32, png_permit_mng_features, - (png_structrp png_ptr, png_uint_32 mng_features_permitted)); +PNG_EXPORT(184, png_uint_32, png_permit_mng_features, (png_structrp png_ptr, + png_uint_32 mng_features_permitted)); #endif /* For use in png_set_keep_unknown, added to version 1.2.6 */ @@ -2590,74 +2532,71 @@ PNG_EXPORT(184, png_uint_32, png_permit_mng_features, * messages before passing them to the error or warning handler. */ #ifdef PNG_ERROR_NUMBERS_SUPPORTED -PNG_EXPORT(185, void, png_set_strip_error_numbers, - (png_structrp png_ptr, png_uint_32 strip_mode)); +PNG_EXPORT(185, void, png_set_strip_error_numbers, (png_structrp png_ptr, + png_uint_32 strip_mode)); #endif /* Added in libpng-1.2.6 */ #ifdef PNG_SET_USER_LIMITS_SUPPORTED -PNG_EXPORT(186, void, png_set_user_limits, - (png_structrp png_ptr, +PNG_EXPORT(186, void, png_set_user_limits, (png_structrp png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max)); PNG_EXPORT(187, png_uint_32, png_get_user_width_max, - (png_const_structrp png_ptr)); + (png_const_structrp png_ptr)); PNG_EXPORT(188, png_uint_32, png_get_user_height_max, - (png_const_structrp png_ptr)); + (png_const_structrp png_ptr)); /* Added in libpng-1.4.0 */ -PNG_EXPORT(189, void, png_set_chunk_cache_max, - (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)); +PNG_EXPORT(189, void, png_set_chunk_cache_max, (png_structrp png_ptr, + png_uint_32 user_chunk_cache_max)); PNG_EXPORT(190, png_uint_32, png_get_chunk_cache_max, - (png_const_structrp png_ptr)); + (png_const_structrp png_ptr)); /* Added in libpng-1.4.1 */ -PNG_EXPORT(191, void, png_set_chunk_malloc_max, - (png_structrp png_ptr, png_alloc_size_t user_chunk_cache_max)); +PNG_EXPORT(191, void, png_set_chunk_malloc_max, (png_structrp png_ptr, + png_alloc_size_t user_chunk_cache_max)); PNG_EXPORT(192, png_alloc_size_t, png_get_chunk_malloc_max, - (png_const_structrp png_ptr)); + (png_const_structrp png_ptr)); #endif #if defined(PNG_INCH_CONVERSIONS_SUPPORTED) PNG_EXPORT(193, png_uint_32, png_get_pixels_per_inch, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(194, png_uint_32, png_get_x_pixels_per_inch, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_EXPORT(195, png_uint_32, png_get_y_pixels_per_inch, - (png_const_structrp png_ptr, png_const_inforp info_ptr)); + (png_const_structrp png_ptr, png_const_inforp info_ptr)); PNG_FP_EXPORT(196, float, png_get_x_offset_inches, - (png_const_structrp png_ptr, png_const_inforp info_ptr)) + (png_const_structrp png_ptr, png_const_inforp info_ptr)) #ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ PNG_FIXED_EXPORT(211, png_fixed_point, png_get_x_offset_inches_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr)) + (png_const_structrp png_ptr, png_const_inforp info_ptr)) #endif -PNG_FP_EXPORT(197, float, png_get_y_offset_inches, - (png_const_structrp png_ptr, png_const_inforp info_ptr)) +PNG_FP_EXPORT(197, float, png_get_y_offset_inches, (png_const_structrp png_ptr, + png_const_inforp info_ptr)) #ifdef PNG_FIXED_POINT_SUPPORTED /* otherwise not implemented. */ PNG_FIXED_EXPORT(212, png_fixed_point, png_get_y_offset_inches_fixed, - (png_const_structrp png_ptr, png_const_inforp info_ptr)) + (png_const_structrp png_ptr, png_const_inforp info_ptr)) #endif # ifdef PNG_pHYs_SUPPORTED -PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, - (png_const_structrp png_ptr, png_const_inforp info_ptr, - png_uint_32 *res_x, png_uint_32 *res_y, int *unit_type)); -# endif /* pHYs */ -#endif /* INCH_CONVERSIONS */ +PNG_EXPORT(198, png_uint_32, png_get_pHYs_dpi, (png_const_structrp png_ptr, + png_const_inforp info_ptr, png_uint_32 *res_x, png_uint_32 *res_y, + int *unit_type)); +# endif /* PNG_pHYs_SUPPORTED */ +#endif /* PNG_INCH_CONVERSIONS_SUPPORTED */ /* Added in libpng-1.4.0 */ #ifdef PNG_IO_STATE_SUPPORTED -PNG_EXPORT(199, png_uint_32, png_get_io_state, - (png_const_structrp png_ptr)); +PNG_EXPORT(199, png_uint_32, png_get_io_state, (png_const_structrp png_ptr)); /* Removed from libpng 1.6; use png_get_io_chunk_type. */ -PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, - (png_structrp png_ptr), - PNG_DEPRECATED) +PNG_REMOVED(200, png_const_bytep, png_get_io_chunk_name, (png_structrp png_ptr), + PNG_DEPRECATED) PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, - (png_const_structrp png_ptr)); + (png_const_structrp png_ptr)); /* The flags returned by png_get_io_state() are the following: */ # define PNG_IO_NONE 0x0000 /* no I/O at this moment */ @@ -2669,7 +2608,7 @@ PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, # define PNG_IO_CHUNK_CRC 0x0080 /* currently at the chunk crc */ # define PNG_IO_MASK_OP 0x000f /* current operation: reading/writing */ # define PNG_IO_MASK_LOC 0x00f0 /* current location: sig/hdr/data/crc */ -#endif /* IO_STATE */ +#endif /* ?PNG_IO_STATE_SUPPORTED */ /* Interlace support. The following macros are always defined so that if * libpng interlace handling is turned off the macros may be used to handle @@ -2748,60 +2687,49 @@ PNG_EXPORT(216, png_uint_32, png_get_io_chunk_type, /* fg and bg should be in `gamma 1.0' space; alpha is the opacity */ -# define png_composite(composite, fg, alpha, bg) \ - { \ - png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \ - * (png_uint_16)(alpha) \ - + (png_uint_16)(bg)*(png_uint_16)(255 \ - - (png_uint_16)(alpha)) + 128); \ - (composite) = (png_byte)(((temp + (temp >> 8)) >> 8) & 0xff); \ - } +# define png_composite(composite, fg, alpha, bg) \ + { png_uint_16 temp = (png_uint_16)((png_uint_16)(fg) \ + * (png_uint_16)(alpha) \ + + (png_uint_16)(bg)*(png_uint_16)(255 \ + - (png_uint_16)(alpha)) + 128); \ + (composite) = (png_byte)((temp + (temp >> 8)) >> 8); } -# define png_composite_16(composite, fg, alpha, bg) \ - { \ - png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \ - * (png_uint_32)(alpha) \ - + (png_uint_32)(bg)*(65535 \ - - (png_uint_32)(alpha)) + 32768); \ - (composite) = (png_uint_16)(0xffff & ((temp + (temp >> 16)) >> 16)); \ - } +# define png_composite_16(composite, fg, alpha, bg) \ + { png_uint_32 temp = (png_uint_32)((png_uint_32)(fg) \ + * (png_uint_32)(alpha) \ + + (png_uint_32)(bg)*(65535 \ + - (png_uint_32)(alpha)) + 32768); \ + (composite) = (png_uint_16)((temp + (temp >> 16)) >> 16); } #else /* Standard method using integer division */ -# define png_composite(composite, fg, alpha, bg) \ - (composite) = \ - (png_byte)(0xff & (((png_uint_16)(fg) * (png_uint_16)(alpha) + \ - (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ - 127) / 255)) +# define png_composite(composite, fg, alpha, bg) \ + (composite) = (png_byte)(((png_uint_16)(fg) * (png_uint_16)(alpha) + \ + (png_uint_16)(bg) * (png_uint_16)(255 - (png_uint_16)(alpha)) + \ + 127) / 255) -# define png_composite_16(composite, fg, alpha, bg) \ - (composite) = \ - (png_uint_16)(0xffff & (((png_uint_32)(fg) * (png_uint_32)(alpha) + \ - (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ - 32767) / 65535)) -#endif /* READ_COMPOSITE_NODIV */ +# define png_composite_16(composite, fg, alpha, bg) \ + (composite) = (png_uint_16)(((png_uint_32)(fg) * (png_uint_32)(alpha) + \ + (png_uint_32)(bg)*(png_uint_32)(65535 - (png_uint_32)(alpha)) + \ + 32767) / 65535) +#endif /* PNG_READ_COMPOSITE_NODIV_SUPPORTED */ #ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED -PNG_EXPORT(201, png_uint_32, png_get_uint_32, - (png_const_bytep buf)); -PNG_EXPORT(202, png_uint_16, png_get_uint_16, - (png_const_bytep buf)); -PNG_EXPORT(203, png_int_32, png_get_int_32, - (png_const_bytep buf)); +PNG_EXPORT(201, png_uint_32, png_get_uint_32, (png_const_bytep buf)); +PNG_EXPORT(202, png_uint_16, png_get_uint_16, (png_const_bytep buf)); +PNG_EXPORT(203, png_int_32, png_get_int_32, (png_const_bytep buf)); #endif -PNG_EXPORT(204, png_uint_32, png_get_uint_31, - (png_const_structrp png_ptr, png_const_bytep buf)); +PNG_EXPORT(204, png_uint_32, png_get_uint_31, (png_const_structrp png_ptr, + png_const_bytep buf)); /* No png_get_int_16 -- may be added if there's a real need for it. */ /* Place a 32-bit number into a buffer in PNG byte order (big-endian). */ #ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED -PNG_EXPORT(205, void, png_save_uint_32, - (png_bytep buf, png_uint_32 i)); +PNG_EXPORT(205, void, png_save_uint_32, (png_bytep buf, png_uint_32 i)); #endif #ifdef PNG_SAVE_INT_32_SUPPORTED -PNG_EXPORT(206, void, png_save_int_32, - (png_bytep buf, png_int_32 i)); +PNG_EXPORT(206, void, png_save_int_32, (png_bytep buf, png_int_32 i)); #endif /* Place a 16-bit number into a buffer in PNG byte order. @@ -2809,8 +2737,7 @@ PNG_EXPORT(206, void, png_save_int_32, * just to avoid potential problems on pre-ANSI C compilers. */ #ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED -PNG_EXPORT(207, void, png_save_uint_16, - (png_bytep buf, unsigned int i)); +PNG_EXPORT(207, void, png_save_uint_16, (png_bytep buf, unsigned int i)); /* No png_save_int_16 -- may be added if there's a real need for it. */ #endif @@ -2820,52 +2747,43 @@ PNG_EXPORT(207, void, png_save_uint_16, * format for negative values, which is almost certainly true. */ # define PNG_get_uint_32(buf) \ - (((png_uint_32)(*(buf)) << 24) + \ - ((png_uint_32)(*((buf) + 1)) << 16) + \ - ((png_uint_32)(*((buf) + 2)) << 8) + \ - ((png_uint_32)(*((buf) + 3)))) + (((png_uint_32)(*(buf)) << 24) + \ + ((png_uint_32)(*((buf) + 1)) << 16) + \ + ((png_uint_32)(*((buf) + 2)) << 8) + \ + ((png_uint_32)(*((buf) + 3)))) /* From libpng-1.4.0 until 1.4.4, the png_get_uint_16 macro (but not the * function) incorrectly returned a value of type png_uint_32. */ # define PNG_get_uint_16(buf) \ - ((png_uint_16) \ - (((unsigned int)(*(buf)) << 8) + \ - ((unsigned int)(*((buf) + 1))))) + ((png_uint_16) \ + (((unsigned int)(*(buf)) << 8) + \ + ((unsigned int)(*((buf) + 1))))) # define PNG_get_int_32(buf) \ - ((png_int_32)((*(buf) & 0x80) \ - ? -((png_int_32)(((png_get_uint_32(buf)^0xffffffffU)+1U)&0x7fffffffU)) \ - : (png_int_32)png_get_uint_32(buf))) + ((png_int_32)((*(buf) & 0x80) \ + ? -((png_int_32)((png_get_uint_32(buf) ^ 0xffffffffL) + 1)) \ + : (png_int_32)png_get_uint_32(buf))) -/* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h, - * but defining a macro name prefixed with PNG_PREFIX. - */ + /* If PNG_PREFIX is defined the same thing as below happens in pnglibconf.h, + * but defining a macro name prefixed with PNG_PREFIX. + */ # ifndef PNG_PREFIX -# define png_get_uint_32(buf) PNG_get_uint_32(buf) -# define png_get_uint_16(buf) PNG_get_uint_16(buf) -# define png_get_int_32(buf) PNG_get_int_32(buf) +# define png_get_uint_32(buf) PNG_get_uint_32(buf) +# define png_get_uint_16(buf) PNG_get_uint_16(buf) +# define png_get_int_32(buf) PNG_get_int_32(buf) # endif #else # ifdef PNG_PREFIX - /* No macros; revert to the (redefined) function */ -# define PNG_get_uint_32 (png_get_uint_32) -# define PNG_get_uint_16 (png_get_uint_16) -# define PNG_get_int_32 (png_get_int_32) + /* No macros; revert to the (redefined) function */ +# define PNG_get_uint_32 (png_get_uint_32) +# define PNG_get_uint_16 (png_get_uint_16) +# define PNG_get_int_32 (png_get_int_32) # endif #endif -#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED -PNG_EXPORT(242, void, png_set_check_for_invalid_index, - (png_structrp png_ptr, int allowed)); -# ifdef PNG_GET_PALETTE_MAX_SUPPORTED -PNG_EXPORT(243, int, png_get_palette_max, - (png_const_structp png_ptr, png_const_infop info_ptr)); -# endif -#endif /* CHECK_FOR_INVALID_INDEX */ - /******************************************************************************* - * Section 5: SIMPLIFIED API + * SIMPLIFIED API ******************************************************************************* * * Please read the documentation in libpng-manual.txt (TODO: write said @@ -2874,16 +2792,15 @@ PNG_EXPORT(243, int, png_get_palette_max, * The simplified API hides the details of both libpng and the PNG file format * itself. It allows PNG files to be read into a very limited number of * in-memory bitmap formats or to be written from the same formats. If these - * formats do not accommodate your needs then you can, and should, use the more + * formats do not accomodate your needs then you can, and should, use the more * sophisticated APIs above - these support a wide variety of in-memory formats * and a wide variety of sophisticated transformations to those formats as well * as a wide variety of APIs to manipulate ancillary information. * * To read a PNG file using the simplified API: * - * 1) Declare a 'png_image' structure (see below) on the stack, set the - * version field to PNG_IMAGE_VERSION and the 'opaque' pointer to NULL - * (this is REQUIRED, your program may crash if you don't do it.) + * 1) Declare a 'png_image' structure (see below) on the stack and set the + * version field to PNG_IMAGE_VERSION. * 2) Call the appropriate png_image_begin_read... function. * 3) Set the png_image 'format' member to the required sample format. * 4) Allocate a buffer for the image and, if required, the color-map. @@ -2910,9 +2827,6 @@ PNG_EXPORT(243, int, png_get_palette_max, * when it is being read or defines the in-memory format of an image that you * need to write: */ -#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) || \ - defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) - #define PNG_IMAGE_VERSION 1 typedef struct png_control *png_controlp; @@ -2939,7 +2853,7 @@ typedef struct # define PNG_IMAGE_WARNING 1 # define PNG_IMAGE_ERROR 2 /* - * The result is a two-bit code such that a value more than 1 indicates + * The result is a two bit code such that a value more than 1 indicates * a failure in the API just called: * * 0 - no warning or error @@ -2980,7 +2894,7 @@ typedef struct * * When the simplified API needs to convert between sRGB and linear colorspaces, * the actual sRGB transfer curve defined in the sRGB specification (see the - * article at ) is used, not the gamma=1/2.2 + * article at http://en.wikipedia.org/wiki/SRGB) is used, not the gamma=1/2.2 * approximation used elsewhere in libpng. * * When an alpha channel is present it is expected to denote pixel coverage @@ -3012,7 +2926,7 @@ typedef struct * called to read or write the color-map and set the format correctly for the * image data. Do not set the PNG_FORMAT_FLAG_COLORMAP bit directly! * - * NOTE: libpng can be built with particular features disabled. If you see + * NOTE: libpng can be built with particular features disabled, if you see * compiler errors because the definition of one of the following flags has been * compiled out it is because libpng does not have the required support. It is * possible, however, for the libpng configuration to enable the format on just @@ -3024,7 +2938,7 @@ typedef struct */ #define PNG_FORMAT_FLAG_ALPHA 0x01U /* format with an alpha channel */ #define PNG_FORMAT_FLAG_COLOR 0x02U /* color format: otherwise grayscale */ -#define PNG_FORMAT_FLAG_LINEAR 0x04U /* 2-byte channels else 1-byte */ +#define PNG_FORMAT_FLAG_LINEAR 0x04U /* 2 byte channels else 1 byte */ #define PNG_FORMAT_FLAG_COLORMAP 0x08U /* image data is color-mapped */ #ifdef PNG_FORMAT_BGR_SUPPORTED @@ -3035,8 +2949,6 @@ typedef struct # define PNG_FORMAT_FLAG_AFIRST 0x20U /* alpha channel comes first */ #endif -#define PNG_FORMAT_FLAG_ASSOCIATED_ALPHA 0x40U /* alpha channel is associated */ - /* Commonly used formats have predefined macros. * * First the single byte (sRGB) formats: @@ -3148,19 +3060,12 @@ typedef struct * is the minimum 'row stride', the minimum count of components between each * row. For a color-mapped image this is the minimum number of bytes in a * row. - * - * WARNING: this macro overflows for some images with more than one component - * and very large image widths. libpng will refuse to process an image where - * this macro would overflow. */ #define PNG_IMAGE_BUFFER_SIZE(image, row_stride)\ (PNG_IMAGE_PIXEL_COMPONENT_SIZE((image).format)*(image).height*(row_stride)) /* Return the size, in bytes, of an image buffer given a png_image and a row * stride - the number of components to leave space for in each row. - * - * WARNING: this macro overflows a 32-bit integer for some large PNG images, - * libpng will refuse to process an image where such an overflow would occur. */ #define PNG_IMAGE_SIZE(image)\ @@ -3183,7 +3088,7 @@ typedef struct * 'flags' field of png_image. */ #define PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB 0x01 - /* This indicates that the RGB values of the in-memory bitmap do not + /* This indicates the the RGB values of the in-memory bitmap do not * correspond to the red, green and blue end-points defined by sRGB. */ @@ -3224,25 +3129,24 @@ typedef struct * the png_controlp field 'opaque' to NULL (or, safer, memset the whole thing.) */ #ifdef PNG_STDIO_SUPPORTED -PNG_EXPORT(234, int, png_image_begin_read_from_file, - (png_imagep image, const char *file_name)); +PNG_EXPORT(234, int, png_image_begin_read_from_file, (png_imagep image, + const char *file_name)); /* The named file is opened for read and the image header is filled in * from the PNG header in the file. */ -PNG_EXPORT(235, int, png_image_begin_read_from_stdio, - (png_imagep image, FILE *file)); +PNG_EXPORT(235, int, png_image_begin_read_from_stdio, (png_imagep image, + FILE* file)); /* The PNG header is read from the stdio FILE object. */ -#endif /* STDIO */ +#endif /* PNG_STDIO_SUPPORTED */ -PNG_EXPORT(236, int, png_image_begin_read_from_memory, - (png_imagep image, png_const_voidp memory, size_t size)); +PNG_EXPORT(236, int, png_image_begin_read_from_memory, (png_imagep image, + png_const_voidp memory, png_size_t size)); /* The PNG header is read from the given memory buffer. */ -PNG_EXPORT(237, int, png_image_finish_read, - (png_imagep image, - png_const_colorp background, void *buffer, png_int_32 row_stride, - void *colormap)); +PNG_EXPORT(237, int, png_image_finish_read, (png_imagep image, + png_const_colorp background, void *buffer, png_int_32 row_stride, + void *colormap)); /* Finish reading the image into the supplied buffer and clean up the * png_image structure. * @@ -3275,12 +3179,11 @@ PNG_EXPORT(237, int, png_image_finish_read, * written to the colormap; this may be less than the original value. */ -PNG_EXPORT(238, void, png_image_free, - (png_imagep image)); +PNG_EXPORT(238, void, png_image_free, (png_imagep image)); /* Free any data allocated by libpng in image->opaque, setting the pointer to * NULL. May be called at any time after the structure is initialized. */ -#endif /* SIMPLIFIED_READ */ +#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED /* WRITE APIS @@ -3299,21 +3202,18 @@ PNG_EXPORT(238, void, png_image_free, * values do not correspond to the colors in sRGB. * colormap_entries: set to the number of entries in the color-map (0 to 256) */ -#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED -PNG_EXPORT(239, int, png_image_write_to_file, - (png_imagep image, - const char *file, int convert_to_8bit, const void *buffer, - png_int_32 row_stride, const void *colormap)); +PNG_EXPORT(239, int, png_image_write_to_file, (png_imagep image, + const char *file, int convert_to_8bit, const void *buffer, + png_int_32 row_stride, const void *colormap)); /* Write the image to the named file. */ -PNG_EXPORT(240, int, png_image_write_to_stdio, - (png_imagep image, - FILE *file, int convert_to_8_bit, const void *buffer, - png_int_32 row_stride, const void *colormap)); - /* Write the image to the given FILE object. */ -#endif /* SIMPLIFIED_WRITE_STDIO */ +// 4j studios: callback support +PNG_EXPORT(240, int, png_image_write_to_stdio, (png_imagep image, FILE *file, + int convert_to_8_bit, const void *buffer, png_int_32 row_stride, + const void *colormap, /*begin 4j change*/ png_rw_ptr write_fn, png_flush_ptr flush_fn /*end 4j change*/)); + /* Write the image to the given (FILE*). */ -/* With all write APIs if image is in one of the linear formats with 16-bit +/* With both write APIs if image is in one of the linear formats with 16-bit * data then setting convert_to_8_bit will cause the output to be an 8-bit PNG * gamma encoded according to the sRGB specification, otherwise a 16-bit linear * encoded PNG file is written. @@ -3325,113 +3225,26 @@ PNG_EXPORT(240, int, png_image_write_to_stdio, * * With all APIs row_stride is handled as in the read APIs - it is the spacing * from one row to the next in component sized units (1 or 2 bytes) and if - * negative indicates a bottom-up row layout in the buffer. If row_stride is - * zero, libpng will calculate it for you from the image width and number of - * channels. + * negative indicates a bottom-up row layout in the buffer. * - * Note that the write API does not support interlacing, sub-8-bit pixels or - * most ancillary chunks. If you need to write text chunks (e.g. for copyright - * notices) you need to use one of the other APIs. + * Note that the write API does not support interlacing or sub-8-bit pixels. */ - -PNG_EXPORT(245, int, png_image_write_to_memory, - (png_imagep image, - void *memory, png_alloc_size_t * PNG_RESTRICT memory_bytes, - int convert_to_8_bit, - const void *buffer, png_int_32 row_stride, const void *colormap)); - /* Write the image to the given memory buffer. The function both writes the - * whole PNG data stream to *memory and updates *memory_bytes with the count - * of bytes written. - * - * 'memory' may be NULL. In this case *memory_bytes is not read however on - * success the number of bytes which would have been written will still be - * stored in *memory_bytes. On failure *memory_bytes will contain 0. - * - * If 'memory' is not NULL it must point to memory[*memory_bytes] of - * writeable memory. - * - * If the function returns success memory[*memory_bytes] (if 'memory' is not - * NULL) contains the written PNG data. *memory_bytes will always be less - * than or equal to the original value. - * - * If the function returns false and *memory_bytes was not changed an error - * occurred during write. If *memory_bytes was changed, or is not 0 if - * 'memory' was NULL, the write would have succeeded but for the memory - * buffer being too small. *memory_bytes contains the required number of - * bytes and will be bigger that the original value. - */ - -#define png_image_write_get_memory_size(image, size, convert_to_8_bit, buffer,\ - row_stride, colormap)\ - png_image_write_to_memory(&(image), 0, &(size), convert_to_8_bit, buffer,\ - row_stride, colormap) - /* Return the amount of memory in 'size' required to compress this image. - * The png_image structure 'image' must be filled in as in the above - * function and must not be changed before the actual write call, the buffer - * and all other parameters must also be identical to that in the final - * write call. The 'size' variable need not be initialized. - * - * NOTE: the macro returns true/false, if false is returned 'size' will be - * set to zero and the write failed and probably will fail if tried again. - */ - -/* You can pre-allocate the buffer by making sure it is of sufficient size - * regardless of the amount of compression achieved. The buffer size will - * always be bigger than the original image and it will never be filled. The - * following macros are provided to assist in allocating the buffer. - */ -#define PNG_IMAGE_DATA_SIZE(image) (PNG_IMAGE_SIZE(image)+(image).height) - /* The number of uncompressed bytes in the PNG byte encoding of the image; - * uncompressing the PNG IDAT data will give this number of bytes. - * - * NOTE: while PNG_IMAGE_SIZE cannot overflow for an image in memory this - * macro can because of the extra bytes used in the PNG byte encoding. You - * need to avoid this macro if your image size approaches 2^30 in width or - * height. The same goes for the remainder of these macros; they all produce - * bigger numbers than the actual in-memory image size. - */ -#ifndef PNG_ZLIB_MAX_SIZE -# define PNG_ZLIB_MAX_SIZE(b) ((b)+(((b)+7U)>>3)+(((b)+63U)>>6)+11U) - /* An upper bound on the number of compressed bytes given 'b' uncompressed - * bytes. This is based on deflateBounds() in zlib; different - * implementations of zlib compression may conceivably produce more data so - * if your zlib implementation is not zlib itself redefine this macro - * appropriately. - */ -#endif - -#define PNG_IMAGE_COMPRESSED_SIZE_MAX(image)\ - PNG_ZLIB_MAX_SIZE((png_alloc_size_t)PNG_IMAGE_DATA_SIZE(image)) - /* An upper bound on the size of the data in the PNG IDAT chunks. */ - -#define PNG_IMAGE_PNG_SIZE_MAX_(image, image_size)\ - ((8U/*sig*/+25U/*IHDR*/+16U/*gAMA*/+44U/*cHRM*/+12U/*IEND*/+\ - (((image).format&PNG_FORMAT_FLAG_COLORMAP)?/*colormap: PLTE, tRNS*/\ - 12U+3U*(image).colormap_entries/*PLTE data*/+\ - (((image).format&PNG_FORMAT_FLAG_ALPHA)?\ - 12U/*tRNS*/+(image).colormap_entries:0U):0U)+\ - 12U)+(12U*((image_size)/PNG_ZBUF_SIZE))/*IDAT*/+(image_size)) - /* A helper for the following macro; if your compiler cannot handle the - * following macro use this one with the result of - * PNG_IMAGE_COMPRESSED_SIZE_MAX(image) as the second argument (most - * compilers should handle this just fine.) - */ - -#define PNG_IMAGE_PNG_SIZE_MAX(image)\ - PNG_IMAGE_PNG_SIZE_MAX_(image, PNG_IMAGE_COMPRESSED_SIZE_MAX(image)) - /* An upper bound on the total length of the PNG data stream for 'image'. - * The result is of type png_alloc_size_t, on 32-bit systems this may - * overflow even though PNG_IMAGE_DATA_SIZE does not overflow; the write will - * run out of buffer space but return a corrected size which should work. - */ -#endif /* SIMPLIFIED_WRITE */ +#endif /* PNG_SIMPLIFIED_WRITE_SUPPORTED */ /******************************************************************************* * END OF SIMPLIFIED API ******************************************************************************/ -#endif /* SIMPLIFIED_{READ|WRITE} */ + +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED +PNG_EXPORT(242, void, png_set_check_for_invalid_index, + (png_structrp png_ptr, int allowed)); +# ifdef PNG_GET_PALETTE_MAX_SUPPORTED +PNG_EXPORT(243, int, png_get_palette_max, (png_const_structp png_ptr, + png_const_infop info_ptr)); +# endif +#endif /* CHECK_FOR_INVALID_INDEX */ /******************************************************************************* - * Section 6: IMPLEMENTATION OPTIONS + * IMPLEMENTATION OPTIONS ******************************************************************************* * * Support for arbitrary implementation-specific optimizations. The API allows @@ -3439,7 +3252,7 @@ PNG_EXPORT(245, int, png_image_write_to_memory, * option and 'onoff' is 0 (off) or non-0 (on). The value returned is given * by the PNG_OPTION_ defines below. * - * HARDWARE: normally hardware capabilities, such as the Intel SSE instructions, + * HARDWARE: normally hardware capabilites, such as the Intel SSE instructions, * are detected at run time, however sometimes it may be impossible * to do this in user mode, in which case it is necessary to discover * the capabilities in an OS specific way. Such capabilities are @@ -3452,45 +3265,10 @@ PNG_EXPORT(245, int, png_image_write_to_memory, * selected at run time. */ #ifdef PNG_SET_OPTION_SUPPORTED - -/* HARDWARE: ARM Neon SIMD instructions supported */ #ifdef PNG_ARM_NEON_API_SUPPORTED -# define PNG_ARM_NEON 0 +# define PNG_ARM_NEON 0 /* HARDWARE: ARM Neon SIMD instructions supported */ #endif - -/* SOFTWARE: Force maximum window */ -#define PNG_MAXIMUM_INFLATE_WINDOW 2 - -/* SOFTWARE: Check ICC profile for sRGB */ -#define PNG_SKIP_sRGB_CHECK_PROFILE 4 - -/* HARDWARE: MIPS MSA SIMD instructions supported */ -#ifdef PNG_MIPS_MSA_API_SUPPORTED -# define PNG_MIPS_MSA 6 -#endif - -/* SOFTWARE: Disable Adler32 check on IDAT */ -#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED -# define PNG_IGNORE_ADLER32 8 -#endif - -/* HARDWARE: PowerPC VSX SIMD instructions supported */ -#ifdef PNG_POWERPC_VSX_API_SUPPORTED -# define PNG_POWERPC_VSX 10 -#endif - -/* HARDWARE: MIPS MMI SIMD instructions supported */ -#ifdef PNG_MIPS_MMI_API_SUPPORTED -# define PNG_MIPS_MMI 12 -#endif - -/* HARDWARE: RISC-V RVV SIMD instructions supported */ -#ifdef PNG_RISCV_RVV_API_SUPPORTED -# define PNG_RISCV_RVV 14 -#endif - -/* Next option - numbers must be even */ -#define PNG_OPTION_NEXT 16 +#define PNG_OPTION_NEXT 2 /* Next option - numbers must be even */ /* Return values: NOTE: there are four values and 'off' is *not* zero */ #define PNG_OPTION_UNSET 0 /* Unset - defaults to off */ @@ -3500,21 +3278,22 @@ PNG_EXPORT(245, int, png_image_write_to_memory, PNG_EXPORT(244, int, png_set_option, (png_structrp png_ptr, int option, int onoff)); -#endif /* SET_OPTION */ +#endif /******************************************************************************* - * END OF HARDWARE AND SOFTWARE OPTIONS + * END OF HARDWARE OPTIONS ******************************************************************************/ -/* Maintainer: Put new public prototypes here ^, in libpng.3, in project - * defs, and in scripts/symbols.def. +/* Maintainer: Put new public prototypes here ^, in libpng.3, and project + * defs, scripts/pnglibconf.h, and scripts/pnglibconf.h.prebuilt */ /* The last ordinal number (this is the *last* one already used; the next - * one to use is one more than this.) + * one to use is one more than this.) Maintainer, remember to add an entry to + * scripts/symbols.def as well. */ #ifdef PNG_EXPORT_LAST_ORDINAL - PNG_EXPORT_LAST_ORDINAL(259); + PNG_EXPORT_LAST_ORDINAL(244); #endif #ifdef __cplusplus diff --git a/Windows_Libs/Dev/Render/libpng/pngconf.h b/Windows_Libs/Dev/Render/libpng/pngconf.h index 4508452..31f9967 100644 --- a/Windows_Libs/Dev/Render/libpng/pngconf.h +++ b/Windows_Libs/Dev/Render/libpng/pngconf.h @@ -1,17 +1,19 @@ -/* pngconf.h - machine-configurable file for libpng + +/* pngconf.h - machine configurable file for libpng * - * libpng version 1.6.55 + * libpng version 1.6.2 - April 25, 2013 * - * Copyright (c) 2018-2026 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h * - * Any machine specific code is near the front of this file, so if you + */ + +/* Any machine specific code is near the front of this file, so if you * are configuring libpng for a machine, you may want to read the section * starting here down to where it starts to typedef png_color, png_text, * and png_info. @@ -20,6 +22,26 @@ #ifndef PNGCONF_H #define PNGCONF_H +/* To do: Do all of this in scripts/pnglibconf.dfa */ +#ifdef PNG_SAFE_LIMITS_SUPPORTED +# ifdef PNG_USER_WIDTH_MAX +# undef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 1000000L +# endif +# ifdef PNG_USER_HEIGHT_MAX +# undef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 1000000L +# endif +# ifdef PNG_USER_CHUNK_MALLOC_MAX +# undef PNG_USER_CHUNK_MALLOC_MAX +# define PNG_USER_CHUNK_MALLOC_MAX 4000000L +# endif +# ifdef PNG_USER_CHUNK_CACHE_MAX +# undef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 128 +# endif +#endif + #ifndef PNG_BUILDING_SYMBOL_TABLE /* else includes may cause problems */ /* From libpng 1.6.0 libpng requires an ANSI X3.159-1989 ("ISOC90") compliant C @@ -57,13 +79,14 @@ #endif /* PNG_BUILDING_SYMBOL_TABLE */ -/* Prior to 1.6.0, it was possible to turn off 'const' in declarations, - * using PNG_NO_CONST. This is no longer supported. +/* Prior to 1.6.0 it was possible to turn off 'const' in declarations using + * PNG_NO_CONST; this is no longer supported except for data declarations which + * apparently still cause problems in 2011 on some compilers. */ #define PNG_CONST const /* backward compatibility only */ -/* This controls optimization of the reading of 16-bit and 32-bit - * values from PNG files. It can be set on a per-app-file basis: it +/* This controls optimization of the reading of 16 and 32 bit values + * from PNG files. It can be set on a per-app-file basis - it * just changes whether a macro is used when the function is called. * The library builder sets the default; if read functions are not * built into the library the macro implementation is forced on. @@ -87,7 +110,7 @@ /* The PNGARG macro was used in versions of libpng prior to 1.6.0 to protect * against legacy (pre ISOC90) compilers that did not understand function - * prototypes. [Deprecated.] + * prototypes. It is not required for modern C compilers. */ #ifndef PNGARG # define PNGARG(arglist) arglist @@ -126,7 +149,7 @@ * * These cases only differ if the operating system does not use the C * calling convention, at present this just means the above cases - * (x86 DOS/Windows systems) and, even then, this does not apply to + * (x86 DOS/Windows sytems) and, even then, this does not apply to * Cygwin running on those systems. * * Note that the value must be defined in pnglibconf.h so that what @@ -179,35 +202,35 @@ * compiler-specific macros to the values required to change the calling * conventions of the various functions. */ -#if defined(_WIN32) || defined(__WIN32__) || defined(__NT__) || \ - defined(__CYGWIN__) +#if defined(_Windows) || defined(_WINDOWS) || defined(WIN32) ||\ + defined(_WIN32) || defined(__WIN32__) || defined(__CYGWIN__) /* Windows system (DOS doesn't support DLLs). Includes builds under Cygwin or * MinGW on any architecture currently supported by Windows. Also includes * Watcom builds but these need special treatment because they are not * compatible with GCC or Visual C because of different calling conventions. */ # if PNG_API_RULE == 2 - /* If this line results in an error, either because __watcall is not - * understood or because of a redefine just below you cannot use *this* - * build of the library with the compiler you are using. *This* build was - * build using Watcom and applications must also be built using Watcom! - */ + /* If this line results in an error, either because __watcall is not + * understood or because of a redefine just below you cannot use *this* + * build of the library with the compiler you are using. *This* build was + * build using Watcom and applications must also be built using Watcom! + */ # define PNGCAPI __watcall # endif # if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 800)) # define PNGCAPI __cdecl # if PNG_API_RULE == 1 - /* If this line results in an error __stdcall is not understood and - * PNG_API_RULE should not have been set to '1'. - */ + /* If this line results in an error __stdcall is not understood and + * PNG_API_RULE should not have been set to '1'. + */ # define PNGAPI __stdcall # endif # else - /* An older compiler, or one not detected (erroneously) above, - * if necessary override on the command line to get the correct - * variants for the compiler. - */ + /* An older compiler, or one not detected (erroneously) above, + * if necessary override on the command line to get the correct + * variants for the compiler. + */ # ifndef PNGCAPI # define PNGCAPI _cdecl # endif @@ -215,25 +238,36 @@ # define PNGAPI _stdcall # endif # endif /* compiler/api */ - /* NOTE: PNGCBAPI always defaults to PNGCAPI. */ # if defined(PNGAPI) && !defined(PNG_USER_PRIVATEBUILD) -# error PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed +# error "PNG_USER_PRIVATEBUILD must be defined if PNGAPI is changed" # endif -# define PNG_DLL_EXPORT __declspec(dllexport) -# ifndef PNG_DLL_IMPORT -# define PNG_DLL_IMPORT __declspec(dllimport) -# endif +# if (defined(_MSC_VER) && _MSC_VER < 800) ||\ + (defined(__BORLANDC__) && __BORLANDC__ < 0x500) + /* older Borland and MSC + * compilers used '__export' and required this to be after + * the type. + */ +# ifndef PNG_EXPORT_TYPE +# define PNG_EXPORT_TYPE(type) type PNG_IMPEXP +# endif +# define PNG_DLL_EXPORT __export +# else /* newer compiler */ +# define PNG_DLL_EXPORT __declspec(dllexport) +# ifndef PNG_DLL_IMPORT +# define PNG_DLL_IMPORT __declspec(dllimport) +# endif +# endif /* compiler */ #else /* !Windows */ # if (defined(__IBMC__) || defined(__IBMCPP__)) && defined(__OS2__) # define PNGAPI _System # else /* !Windows/x86 && !OS/2 */ - /* Use the defaults, or define PNG*API on the command line (but - * this will have to be done for every compile!) - */ + /* Use the defaults, or define PNG*API on the command line (but + * this will have to be done for every compile!) + */ # endif /* other system, !OS/2 */ #endif /* !Windows/x86 */ @@ -254,7 +288,7 @@ */ #ifndef PNG_IMPEXP # if defined(PNG_USE_DLL) && defined(PNG_DLL_IMPORT) - /* This forces use of a DLL, disallowing static linking */ + /* This forces use of a DLL, disallowing static linking */ # define PNG_IMPEXP PNG_DLL_IMPORT # endif @@ -282,11 +316,11 @@ * table entries, so we discard it here. See the .dfn files in the * scripts directory. */ - #ifndef PNG_EXPORTA -# define PNG_EXPORTA(ordinal, type, name, args, attributes) \ - PNG_FUNCTION(PNG_EXPORT_TYPE(type), (PNGAPI name), args, \ - PNG_LINKAGE_API attributes) + +# define PNG_EXPORTA(ordinal, type, name, args, attributes)\ + PNG_FUNCTION(PNG_EXPORT_TYPE(type),(PNGAPI name),PNGARG(args), \ + extern attributes) #endif /* ANSI-C (C90) does not permit a macro to be invoked with an empty argument, @@ -294,7 +328,7 @@ */ #define PNG_EMPTY /*empty list*/ -#define PNG_EXPORT(ordinal, type, name, args) \ +#define PNG_EXPORT(ordinal, type, name, args)\ PNG_EXPORTA(ordinal, type, name, args, PNG_EMPTY) /* Use PNG_REMOVED to comment out a removed interface. */ @@ -303,7 +337,7 @@ #endif #ifndef PNG_CALLBACK -# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) args +# define PNG_CALLBACK(type, name, args) type (PNGCBAPI name) PNGARG(args) #endif /* Support for compiler specific function attributes. These are used @@ -326,33 +360,7 @@ * version 1.2.41. Disabling these removes the warnings but may also produce * less efficient code. */ -# if defined(__clang__) && defined(__has_attribute) - /* Clang defines both __clang__ and __GNUC__. Check __clang__ first. */ -# if !defined(PNG_USE_RESULT) && __has_attribute(__warn_unused_result__) -# define PNG_USE_RESULT __attribute__((__warn_unused_result__)) -# endif -# if !defined(PNG_NORETURN) && __has_attribute(__noreturn__) -# define PNG_NORETURN __attribute__((__noreturn__)) -# endif -# if !defined(PNG_ALLOCATED) && __has_attribute(__malloc__) -# define PNG_ALLOCATED __attribute__((__malloc__)) -# endif -# if !defined(PNG_DEPRECATED) && __has_attribute(__deprecated__) -# define PNG_DEPRECATED __attribute__((__deprecated__)) -# endif -# if !defined(PNG_PRIVATE) -# ifdef __has_extension -# if __has_extension(attribute_unavailable_with_message) -# define PNG_PRIVATE __attribute__((__unavailable__(\ - "This function is not exported by libpng."))) -# endif -# endif -# endif -# ifndef PNG_RESTRICT -# define PNG_RESTRICT __restrict -# endif - -# elif defined(__GNUC__) +# if defined(__GNUC__) # ifndef PNG_USE_RESULT # define PNG_USE_RESULT __attribute__((__warn_unused_result__)) # endif @@ -375,12 +383,12 @@ __attribute__((__deprecated__)) # endif # endif -# if ((__GNUC__ > 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1)) +# if ((__GNUC__ != 3) || !defined(__GNUC_MINOR__) || (__GNUC_MINOR__ >= 1)) # ifndef PNG_RESTRICT # define PNG_RESTRICT __restrict # endif -# endif /* __GNUC__.__GNUC_MINOR__ > 3.0 */ -# endif /* __GNUC__ >= 3 */ +# endif /* __GNUC__ == 3.0 */ +# endif /* __GNUC__ >= 3 */ # elif defined(_MSC_VER) && (_MSC_VER >= 1300) # ifndef PNG_USE_RESULT @@ -410,7 +418,7 @@ # ifndef PNG_RESTRICT # define PNG_RESTRICT __restrict # endif -# endif +# endif /* _MSC_VER */ #endif /* PNG_PEDANTIC_WARNINGS */ #ifndef PNG_DEPRECATED @@ -431,7 +439,6 @@ #ifndef PNG_RESTRICT # define PNG_RESTRICT /* The C99 "restrict" feature */ #endif - #ifndef PNG_FP_EXPORT /* A floating point API. */ # ifdef PNG_FLOATING_POINT_SUPPORTED # define PNG_FP_EXPORT(ordinal, type, name, args)\ @@ -467,7 +474,7 @@ #if CHAR_BIT == 8 && UCHAR_MAX == 255 typedef unsigned char png_byte; #else -# error libpng requires 8-bit bytes +# error "libpng requires 8 bit bytes" #endif #if INT_MIN == -32768 && INT_MAX == 32767 @@ -475,7 +482,7 @@ #elif SHRT_MIN == -32768 && SHRT_MAX == 32767 typedef short png_int_16; #else -# error libpng requires a signed 16-bit integer type +# error "libpng requires a signed 16 bit type" #endif #if UINT_MAX == 65535 @@ -483,7 +490,7 @@ #elif USHRT_MAX == 65535 typedef unsigned short png_uint_16; #else -# error libpng requires an unsigned 16-bit integer type +# error "libpng requires an unsigned 16 bit type" #endif #if INT_MIN < -2147483646 && INT_MAX > 2147483646 @@ -491,21 +498,19 @@ #elif LONG_MIN < -2147483646 && LONG_MAX > 2147483646 typedef long int png_int_32; #else -# error libpng requires a signed 32-bit (or longer) integer type +# error "libpng requires a signed 32 bit (or more) type" #endif -#if UINT_MAX > 4294967294U +#if UINT_MAX > 4294967294 typedef unsigned int png_uint_32; -#elif ULONG_MAX > 4294967294U +#elif ULONG_MAX > 4294967294 typedef unsigned long int png_uint_32; #else -# error libpng requires an unsigned 32-bit (or longer) integer type +# error "libpng requires an unsigned 32 bit (or more) type" #endif -/* Prior to 1.6.0, it was possible to disable the use of size_t and ptrdiff_t. - * From 1.6.0 onwards, an ISO C90 compiler, as well as a standard-compliant - * behavior of sizeof and ptrdiff_t are required. - * The legacy typedefs are provided here for backwards compatibility. +/* Prior to 1.6.0 it was possible to disable the use of size_t, 1.6.0, however, + * requires an ISOC90 compiler and relies on consistent behavior of sizeof. */ typedef size_t png_size_t; typedef ptrdiff_t png_ptrdiff_t; @@ -526,12 +531,13 @@ typedef ptrdiff_t png_ptrdiff_t; # endif #endif -/* png_alloc_size_t is guaranteed to be no smaller than size_t, and no smaller - * than png_uint_32. Casts from size_t or png_uint_32 to png_alloc_size_t are - * not necessary; in fact, it is recommended not to use them at all, so that - * the compiler can complain when something turns out to be problematic. +/* png_alloc_size_t is guaranteed to be no smaller than png_size_t, and no + * smaller than png_uint_32. Casts from png_size_t or png_uint_32 to + * png_alloc_size_t are not necessary; in fact, it is recommended not to use + * them at all so that the compiler can complain when something turns out to be + * problematic. * - * Casts in the other direction (from png_alloc_size_t to size_t or + * Casts in the other direction (from png_alloc_size_t to png_size_t or * png_uint_32) should be explicitly applied; however, we do not expect to * encounter practical situations that require such conversions. * @@ -541,7 +547,7 @@ typedef ptrdiff_t png_ptrdiff_t; #ifdef PNG_SMALL_SIZE_T typedef png_uint_32 png_alloc_size_t; #else - typedef size_t png_alloc_size_t; + typedef png_size_t png_alloc_size_t; #endif /* Prior to 1.6.0 libpng offered limited support for Microsoft C compiler @@ -577,8 +583,12 @@ typedef char * png_charp; typedef const char * png_const_charp; typedef png_fixed_point * png_fixed_point_p; typedef const png_fixed_point * png_const_fixed_point_p; -typedef size_t * png_size_tp; -typedef const size_t * png_const_size_tp; +typedef png_size_t * png_size_tp; +typedef const png_size_t * png_const_size_tp; + +#ifdef PNG_STDIO_SUPPORTED +typedef FILE * png_FILE_p; +#endif #ifdef PNG_FLOATING_POINT_SUPPORTED typedef double * png_doublep; @@ -601,15 +611,6 @@ typedef double * * png_doublepp; /* Pointers to pointers to pointers; i.e., pointer to array */ typedef char * * * png_charppp; -#ifdef PNG_STDIO_SUPPORTED -/* With PNG_STDIO_SUPPORTED it was possible to use I/O streams that were - * not necessarily stdio FILE streams, to allow building Windows applications - * before Win32 and Windows CE applications before WinCE 3.0, but that kind - * of support has long been discontinued. - */ -typedef FILE * png_FILE_p; /* [Deprecated] */ -#endif - #endif /* PNG_BUILDING_SYMBOL_TABLE */ #endif /* PNGCONF_H */ diff --git a/Windows_Libs/Dev/Render/libpng/pngdebug.h b/Windows_Libs/Dev/Render/libpng/pngdebug.h index 0337918..16f81fd 100644 --- a/Windows_Libs/Dev/Render/libpng/pngdebug.h +++ b/Windows_Libs/Dev/Render/libpng/pngdebug.h @@ -1,19 +1,17 @@ -/* pngdebug.h - internal debugging macros for libpng + +/* pngdebug.h - Debugging macros for libpng, also used in pngtest.c * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2013 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Copyright (c) 1998-2011 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Last changed in libpng 1.5.0 [January 6, 2011] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ -#ifndef PNGPRIV_H -# error This file must not be included by applications; please include -#endif - /* Define PNG_DEBUG at compile time for debugging information. Higher * numbers for PNG_DEBUG mean more debugging information. This has * only been added since version 0.95 so it is not implemented throughout @@ -27,7 +25,7 @@ * (actually ((void)0)). * * level: level of detail of message, starting at 0. A level 'n' - * message is preceded by 'n' 3-space indentations (not implemented + * message is preceded by 'n' tab characters (not implemented * on Microsoft compilers unless PNG_DEBUG_FILE is also * defined, to allow debug DLL compilation with no standard IO). * message: a printf(3) style text string. A trailing '\n' is added @@ -38,6 +36,9 @@ #define PNGDEBUG_H /* These settings control the formatting of messages in png.c and pngerror.c */ /* Moved to pngdebug.h at 1.5.0 */ +# ifndef PNG_LITERAL_SHARP +# define PNG_LITERAL_SHARP 0x23 +# endif # ifndef PNG_LITERAL_LEFT_SQUARE_BRACKET # define PNG_LITERAL_LEFT_SQUARE_BRACKET 0x5b # endif @@ -76,29 +77,32 @@ # endif /* PNG_DEBUG_FILE */ # if (PNG_DEBUG > 1) +/* Note: ["%s"m PNG_STRING_NEWLINE] probably does not work on + * non-ISO compilers + */ # ifdef __STDC__ # ifndef png_debug # define png_debug(l,m) \ do { \ int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ - (num_tabs==2 ? " " : (num_tabs>2 ? " " : "")))); \ + fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":"")))); \ } while (0) # endif # ifndef png_debug1 # define png_debug1(l,m,p1) \ do { \ int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ - (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1); \ + fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1); \ } while (0) # endif # ifndef png_debug2 # define png_debug2(l,m,p1,p2) \ do { \ int num_tabs=l; \ - fprintf(PNG_DEBUG_FILE,"%s" m PNG_STRING_NEWLINE,(num_tabs==1 ? " " : \ - (num_tabs==2 ? " " : (num_tabs>2 ? " " : ""))),p1,p2);\ + fprintf(PNG_DEBUG_FILE,"%s"m PNG_STRING_NEWLINE,(num_tabs==1 ? "\t" : \ + (num_tabs==2 ? "\t\t":(num_tabs>2 ? "\t\t\t":""))),p1,p2); \ } while (0) # endif # else /* __STDC __ */ diff --git a/Windows_Libs/Dev/Render/libpng/pngerror.c b/Windows_Libs/Dev/Render/libpng/pngerror.c index 72dc20e..f469206 100644 --- a/Windows_Libs/Dev/Render/libpng/pngerror.c +++ b/Windows_Libs/Dev/Render/libpng/pngerror.c @@ -1,9 +1,10 @@ + /* pngerror.c - stub functions for i/o and memory allocation * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.1 [March 28, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -19,15 +20,14 @@ #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) -static PNG_FUNCTION(void /* PRIVATE */, -png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), - PNG_NORETURN); +static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr, + png_const_charp error_message)),PNG_NORETURN); #ifdef PNG_WARNINGS_SUPPORTED static void /* PRIVATE */ -png_default_warning(png_const_structrp png_ptr, - png_const_charp warning_message); -#endif /* WARNINGS */ +png_default_warning PNGARG((png_const_structrp png_ptr, + png_const_charp warning_message)); +#endif /* PNG_WARNINGS_SUPPORTED */ /* This function is called whenever there is a fatal error. This function * should not be changed. If there is a need to handle errors differently, @@ -37,8 +37,48 @@ png_default_warning(png_const_structrp png_ptr, #ifdef PNG_ERROR_TEXT_SUPPORTED PNG_FUNCTION(void,PNGAPI png_error,(png_const_structrp png_ptr, png_const_charp error_message), - PNG_NORETURN) + PNG_NORETURN) { +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + char msg[16]; + if (png_ptr != NULL) + { + if (png_ptr->flags& + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) + { + if (*error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + for (offset = 1; offset<15; offset++) + if (error_message[offset] == ' ') + break; + + if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + { + int i; + for (i = 0; i < offset - 1; i++) + msg[i] = error_message[i + 1]; + msg[i - 1] = '\0'; + error_message = msg; + } + + else + error_message += offset; + } + + else + { + if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT) + { + msg[0] = '0'; + msg[1] = '\0'; + error_message = msg; + } + } + } + } +#endif if (png_ptr != NULL && png_ptr->error_fn != NULL) (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), error_message); @@ -49,8 +89,7 @@ png_error,(png_const_structrp png_ptr, png_const_charp error_message), } #else PNG_FUNCTION(void,PNGAPI -png_err,(png_const_structrp png_ptr), - PNG_NORETURN) +png_err,(png_const_structrp png_ptr),PNG_NORETURN) { /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed * erroneously as '\0', instead of the empty string "". This was @@ -64,14 +103,14 @@ png_err,(png_const_structrp png_ptr), use the default handler, which will not return. */ png_default_error(png_ptr, ""); } -#endif /* ERROR_TEXT */ +#endif /* PNG_ERROR_TEXT_SUPPORTED */ /* Utility to safely appends strings to a buffer. This never errors out so * error checking is not required in the caller. */ size_t png_safecat(png_charp buffer, size_t bufsize, size_t pos, - png_const_charp string) + png_const_charp string) { if (buffer != NULL && pos < bufsize) { @@ -92,7 +131,7 @@ png_safecat(png_charp buffer, size_t bufsize, size_t pos, */ png_charp png_format_number(png_const_charp start, png_charp end, int format, - png_alloc_size_t number) + png_alloc_size_t number) { int count = 0; /* number of digits output */ int mincount = 1; /* minimum number required */ @@ -113,7 +152,7 @@ png_format_number(png_const_charp start, png_charp end, int format, case PNG_NUMBER_FORMAT_fixed: /* Needs five digits (the fraction) */ mincount = 5; - if (output != 0 || number % 10 != 0) + if (output || number % 10 != 0) { *--end = digits[number % 10]; output = 1; @@ -124,7 +163,7 @@ png_format_number(png_const_charp start, png_charp end, int format, case PNG_NUMBER_FORMAT_02u: /* Expects at least 2 digits. */ mincount = 2; - /* FALLTHROUGH */ + /* FALL THROUGH */ case PNG_NUMBER_FORMAT_u: *--end = digits[number % 10]; @@ -134,7 +173,7 @@ png_format_number(png_const_charp start, png_charp end, int format, case PNG_NUMBER_FORMAT_02x: /* This format expects at least two digits */ mincount = 2; - /* FALLTHROUGH */ + /* FALL THROUGH */ case PNG_NUMBER_FORMAT_x: *--end = digits[number & 0xf]; @@ -150,13 +189,13 @@ png_format_number(png_const_charp start, png_charp end, int format, ++count; /* Float a fixed number here: */ - if ((format == PNG_NUMBER_FORMAT_fixed) && (count == 5) && (end > start)) + if (format == PNG_NUMBER_FORMAT_fixed) if (count == 5) if (end > start) { /* End of the fraction, but maybe nothing was output? In that case * drop the decimal point. If the number is a true zero handle that * here. */ - if (output != 0) + if (output) *--end = '.'; else if (number == 0) /* and !output */ *--end = '0'; @@ -177,9 +216,24 @@ void PNGAPI png_warning(png_const_structrp png_ptr, png_const_charp warning_message) { int offset = 0; + if (png_ptr != NULL) + { +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (png_ptr->flags& + (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) +#endif + { + if (*warning_message == PNG_LITERAL_SHARP) + { + for (offset = 1; offset < 15; offset++) + if (warning_message[offset] == ' ') + break; + } + } + } if (png_ptr != NULL && png_ptr->warning_fn != NULL) (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr), - warning_message + offset); + warning_message + offset); else png_default_warning(png_ptr, warning_message + offset); } @@ -191,7 +245,7 @@ png_warning(png_const_structrp png_ptr, png_const_charp warning_message) */ void png_warning_parameter(png_warning_parameters p, int number, - png_const_charp string) + png_const_charp string) { if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT) (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string); @@ -199,19 +253,19 @@ png_warning_parameter(png_warning_parameters p, int number, void png_warning_parameter_unsigned(png_warning_parameters p, int number, int format, - png_alloc_size_t value) + png_alloc_size_t value) { - char buffer[PNG_NUMBER_BUFFER_SIZE] = {0}; + char buffer[PNG_NUMBER_BUFFER_SIZE]; png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value)); } void png_warning_parameter_signed(png_warning_parameters p, int number, int format, - png_int_32 value) + png_int_32 value) { png_alloc_size_t u; png_charp str; - char buffer[PNG_NUMBER_BUFFER_SIZE] = {0}; + char buffer[PNG_NUMBER_BUFFER_SIZE]; /* Avoid overflow by doing the negate in a png_alloc_size_t: */ u = (png_alloc_size_t)value; @@ -228,7 +282,7 @@ png_warning_parameter_signed(png_warning_parameters p, int number, int format, void png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p, - png_const_charp message) + png_const_charp message) { /* The internal buffer is just 192 bytes - enough for all our messages, * overflow doesn't happen because this code checks! If someone figures @@ -301,13 +355,13 @@ png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p, */ png_warning(png_ptr, msg); } -#endif /* WARNINGS */ +#endif /* PNG_WARNINGS_SUPPORTED */ #ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI png_benign_error(png_const_structrp png_ptr, png_const_charp error_message) { - if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) + if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) { # ifdef PNG_READ_SUPPORTED if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 && @@ -328,57 +382,44 @@ png_benign_error(png_const_structrp png_ptr, png_const_charp error_message) # endif png_error(png_ptr, error_message); } - -# ifndef PNG_ERROR_TEXT_SUPPORTED - PNG_UNUSED(error_message) -# endif } void /* PRIVATE */ png_app_warning(png_const_structrp png_ptr, png_const_charp error_message) { - if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0) - png_warning(png_ptr, error_message); - else - png_error(png_ptr, error_message); - -# ifndef PNG_ERROR_TEXT_SUPPORTED - PNG_UNUSED(error_message) -# endif + if (png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); } void /* PRIVATE */ png_app_error(png_const_structrp png_ptr, png_const_charp error_message) { - if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0) - png_warning(png_ptr, error_message); - else - png_error(png_ptr, error_message); - -# ifndef PNG_ERROR_TEXT_SUPPORTED - PNG_UNUSED(error_message) -# endif + if (png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) + png_warning(png_ptr, error_message); + else + png_error(png_ptr, error_message); } #endif /* BENIGN_ERRORS */ -#define PNG_MAX_ERROR_TEXT 196 /* Currently limited by profile_error in png.c */ -#if defined(PNG_WARNINGS_SUPPORTED) || \ - (defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)) /* These utilities are used internally to build an error message that relates * to the current chunk. The chunk name comes from png_ptr->chunk_name, - * which is used to prefix the message. The message is limited in length - * to 63 bytes. The name characters are output as hex digits wrapped in [] + * this is used to prefix the message. The message is limited in length + * to 63 bytes, the name characters are output as hex digits wrapped in [] * if the character is invalid. */ #define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) -static const char png_digit[16] = { +static PNG_CONST char png_digit[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' }; +#define PNG_MAX_ERROR_TEXT 196 /* Currently limited be profile_error in png.c */ +#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) static void /* PRIVATE */ -png_format_buffer(png_const_structrp png_ptr, png_charp buffer, - png_const_charp error_message) +png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp + error_message) { png_uint_32 chunk_name = png_ptr->chunk_name; int iout = 0, ishift = 24; @@ -388,7 +429,7 @@ png_format_buffer(png_const_structrp png_ptr, png_charp buffer, int c = (int)(chunk_name >> ishift) & 0xff; ishift -= 8; - if (isnonalpha(c) != 0) + if (isnonalpha(c)) { buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET; buffer[iout++] = png_digit[(c & 0xf0) >> 4]; @@ -419,12 +460,12 @@ png_format_buffer(png_const_structrp png_ptr, png_charp buffer, buffer[iout] = '\0'; } } -#endif /* WARNINGS || ERROR_TEXT */ +#endif /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */ #if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) PNG_FUNCTION(void,PNGAPI png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message), - PNG_NORETURN) + PNG_NORETURN) { char msg[18+PNG_MAX_ERROR_TEXT]; if (png_ptr == NULL) @@ -436,7 +477,7 @@ png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message), png_error(png_ptr, msg); } } -#endif /* READ && ERROR_TEXT */ +#endif /* PNG_READ_SUPPORTED && PNG_ERROR_TEXT_SUPPORTED */ #ifdef PNG_WARNINGS_SUPPORTED void PNGAPI @@ -452,39 +493,31 @@ png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message) png_warning(png_ptr, msg); } } -#endif /* WARNINGS */ +#endif /* PNG_WARNINGS_SUPPORTED */ #ifdef PNG_READ_SUPPORTED #ifdef PNG_BENIGN_ERRORS_SUPPORTED void PNGAPI -png_chunk_benign_error(png_const_structrp png_ptr, - png_const_charp error_message) +png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp + error_message) { - if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0) + if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) png_chunk_warning(png_ptr, error_message); else png_chunk_error(png_ptr, error_message); - -# ifndef PNG_ERROR_TEXT_SUPPORTED - PNG_UNUSED(error_message) -# endif } #endif -#endif /* READ */ +#endif /* PNG_READ_SUPPORTED */ void /* PRIVATE */ png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error) { -# ifndef PNG_WARNINGS_SUPPORTED - PNG_UNUSED(message) -# endif - /* This is always supported, but for just read or just write it * unconditionally does the right thing. */ # if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) - if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + if (png_ptr->mode & PNG_IS_READ_STRUCT) # endif # ifdef PNG_READ_SUPPORTED @@ -498,7 +531,7 @@ png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error) # endif # if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED) - else if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + else if (!(png_ptr->mode & PNG_IS_READ_STRUCT)) # endif # ifdef PNG_WRITE_SUPPORTED @@ -515,21 +548,19 @@ png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error) #ifdef PNG_ERROR_TEXT_SUPPORTED #ifdef PNG_FLOATING_POINT_SUPPORTED PNG_FUNCTION(void, -png_fixed_error,(png_const_structrp png_ptr, png_const_charp name), - PNG_NORETURN) +png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN) { # define fixed_message "fixed point overflow in " # define fixed_message_ln ((sizeof fixed_message)-1) - unsigned int iin; + int iin; char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT]; memcpy(msg, fixed_message, fixed_message_ln); iin = 0; - if (name != NULL) - while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0) - { - msg[fixed_message_ln + iin] = name[iin]; - ++iin; - } + if (name != NULL) while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0) + { + msg[fixed_message_ln + iin] = name[iin]; + ++iin; + } msg[fixed_message_ln + iin] = 0; png_error(png_ptr, msg); } @@ -567,7 +598,7 @@ png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn, else { png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *, - png_malloc_warn(png_ptr, jmp_buf_size)); + png_malloc_warn(png_ptr, jmp_buf_size)); if (png_ptr->jmp_buf_ptr == NULL) return NULL; /* new NULL return on OOM */ @@ -656,12 +687,45 @@ png_free_jmpbuf(png_structrp png_ptr) */ static PNG_FUNCTION(void /* PRIVATE */, png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), - PNG_NORETURN) + PNG_NORETURN) { #ifdef PNG_CONSOLE_IO_SUPPORTED - fprintf(stderr, "libpng error: %s", error_message ? error_message : - "undefined"); - fprintf(stderr, PNG_STRING_NEWLINE); +#ifdef PNG_ERROR_NUMBERS_SUPPORTED + /* Check on NULL only added in 1.5.4 */ + if (error_message != NULL && *error_message == PNG_LITERAL_SHARP) + { + /* Strip "#nnnn " from beginning of error message. */ + int offset; + char error_number[16]; + for (offset = 0; offset<15; offset++) + { + error_number[offset] = error_message[offset + 1]; + if (error_message[offset] == ' ') + break; + } + + if ((offset > 1) && (offset < 15)) + { + error_number[offset - 1] = '\0'; + fprintf(stderr, "libpng error no. %s: %s", + error_number, error_message + offset + 1); + fprintf(stderr, PNG_STRING_NEWLINE); + } + + else + { + fprintf(stderr, "libpng error: %s, offset=%d", + error_message, offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + } + else +#endif + { + fprintf(stderr, "libpng error: %s", error_message ? error_message : + "undefined"); + fprintf(stderr, PNG_STRING_NEWLINE); + } #else PNG_UNUSED(error_message) /* Make compiler happy */ #endif @@ -669,24 +733,14 @@ png_default_error,(png_const_structrp png_ptr, png_const_charp error_message), } PNG_FUNCTION(void,PNGAPI -png_longjmp,(png_const_structrp png_ptr, int val), - PNG_NORETURN) +png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN) { #ifdef PNG_SETJMP_SUPPORTED - if (png_ptr != NULL && png_ptr->longjmp_fn != NULL && - png_ptr->jmp_buf_ptr != NULL) + if (png_ptr && png_ptr->longjmp_fn && png_ptr->jmp_buf_ptr) png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val); -#else - PNG_UNUSED(png_ptr) - PNG_UNUSED(val) #endif - /* If control reaches this point, png_longjmp() must not return. The only - * choice is to terminate the whole process (or maybe the thread); to do - * this the ANSI-C abort() function is used unless a different method is - * implemented by overriding the default configuration setting for - * PNG_ABORT(). - */ + /* Here if not setjmp support or if png_ptr is null. */ PNG_ABORT(); } @@ -700,14 +754,46 @@ static void /* PRIVATE */ png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message) { #ifdef PNG_CONSOLE_IO_SUPPORTED - fprintf(stderr, "libpng warning: %s", warning_message); - fprintf(stderr, PNG_STRING_NEWLINE); +# ifdef PNG_ERROR_NUMBERS_SUPPORTED + if (*warning_message == PNG_LITERAL_SHARP) + { + int offset; + char warning_number[16]; + for (offset = 0; offset < 15; offset++) + { + warning_number[offset] = warning_message[offset + 1]; + if (warning_message[offset] == ' ') + break; + } + + if ((offset > 1) && (offset < 15)) + { + warning_number[offset + 1] = '\0'; + fprintf(stderr, "libpng warning no. %s: %s", + warning_number, warning_message + offset); + fprintf(stderr, PNG_STRING_NEWLINE); + } + + else + { + fprintf(stderr, "libpng warning: %s", + warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } + } + else +# endif + + { + fprintf(stderr, "libpng warning: %s", warning_message); + fprintf(stderr, PNG_STRING_NEWLINE); + } #else PNG_UNUSED(warning_message) /* Make compiler happy */ #endif PNG_UNUSED(png_ptr) /* Make compiler happy */ } -#endif /* WARNINGS */ +#endif /* PNG_WARNINGS_SUPPORTED */ /* This function is called when the application wants to use another method * of handling errors and warnings. Note that the error function MUST NOT @@ -741,7 +827,7 @@ png_get_error_ptr(png_const_structrp png_ptr) if (png_ptr == NULL) return NULL; - return (png_voidp)png_ptr->error_ptr; + return ((png_voidp)png_ptr->error_ptr); } @@ -749,8 +835,12 @@ png_get_error_ptr(png_const_structrp png_ptr) void PNGAPI png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode) { - PNG_UNUSED(png_ptr) - PNG_UNUSED(strip_mode) + if (png_ptr != NULL) + { + png_ptr->flags &= + ((~(PNG_FLAG_STRIP_ERROR_NUMBERS | + PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode); + } } #endif @@ -760,11 +850,11 @@ png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode) * possible to implement without setjmp support just so long as there is some * way to handle the error return here: */ -PNG_FUNCTION(void /* PRIVATE */, (PNGCBAPI -png_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message), - PNG_NORETURN) +PNG_FUNCTION(void /* PRIVATE */, +png_safe_error,(png_structp png_nonconst_ptr, png_const_charp error_message), + PNG_NORETURN) { - png_const_structrp png_ptr = png_nonconst_ptr; + const png_const_structrp png_ptr = png_nonconst_ptr; png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); /* An error is always logged here, overwriting anything (typically a warning) @@ -785,7 +875,7 @@ png_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message), /* Missing longjmp buffer, the following is to help debugging: */ { size_t pos = png_safecat(image->message, (sizeof image->message), 0, - "bad longjmp: "); + "bad longjmp: "); png_safecat(image->message, (sizeof image->message), pos, error_message); } @@ -796,10 +886,10 @@ png_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message), } #ifdef PNG_WARNINGS_SUPPORTED -void /* PRIVATE */ PNGCBAPI +void /* PRIVATE */ png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message) { - png_const_structrp png_ptr = png_nonconst_ptr; + const png_const_structrp png_ptr = png_nonconst_ptr; png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr); /* A warning is only logged if there is no prior warning or error. */ @@ -812,39 +902,31 @@ png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message) #endif int /* PRIVATE */ -png_safe_execute(png_imagep image, int (*function)(png_voidp), png_voidp arg) +png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg) { - const png_voidp saved_error_buf = image->opaque->error_buf; + volatile png_imagep image = image_in; + volatile int result; + volatile png_voidp saved_error_buf; jmp_buf safe_jmpbuf; - /* Safely execute function(arg), with png_error returning back here. */ - if (setjmp(safe_jmpbuf) == 0) + /* Safely execute function(arg) with png_error returning to this function. */ + saved_error_buf = image->opaque->error_buf; + result = setjmp(safe_jmpbuf) == 0; + + if (result) { - int result; image->opaque->error_buf = safe_jmpbuf; result = function(arg); - image->opaque->error_buf = saved_error_buf; - - if (result) - return 1; /* success */ } - /* The function failed either because of a caught png_error and a regular - * return of false above or because of an uncaught png_error from the - * function itself. Ensure that the error_buf is always set back to the - * value saved above: - */ image->opaque->error_buf = saved_error_buf; - /* On the final false return, when about to return control to the caller, the - * image is freed (png_image_free does this check but it is duplicated here - * for clarity: - */ - if (saved_error_buf == NULL) + /* And do the cleanup prior to any failure return. */ + if (!result) png_image_free(image); - return 0; /* failure */ + return result; } -#endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */ -#endif /* READ || WRITE */ +#endif /* SIMPLIFIED READ/WRITE */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pngget.c b/Windows_Libs/Dev/Render/libpng/pngget.c index 9c7e8a1..aca63a9 100644 --- a/Windows_Libs/Dev/Render/libpng/pngget.c +++ b/Windows_Libs/Dev/Render/libpng/pngget.c @@ -1,9 +1,10 @@ + /* pngget.c - retrieval of values from info struct * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.1 [March 28, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -20,29 +21,18 @@ png_get_valid(png_const_structrp png_ptr, png_const_inforp info_ptr, png_uint_32 flag) { if (png_ptr != NULL && info_ptr != NULL) - { -#ifdef PNG_READ_tRNS_SUPPORTED - /* png_handle_PLTE() may have canceled a valid tRNS chunk but left the - * 'valid' flag for the detection of duplicate chunks. Do not report a - * valid tRNS chunk in this case. - */ - if (flag == PNG_INFO_tRNS && png_ptr->num_trans == 0) - return 0; -#endif + return(info_ptr->valid & flag); - return info_ptr->valid & flag; - } - - return 0; + return(0); } -size_t PNGAPI +png_size_t PNGAPI png_get_rowbytes(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->rowbytes; + return(info_ptr->rowbytes); - return 0; + return(0); } #ifdef PNG_INFO_IMAGE_SUPPORTED @@ -50,9 +40,9 @@ png_bytepp PNGAPI png_get_rows(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->row_pointers; + return(info_ptr->row_pointers); - return 0; + return(0); } #endif @@ -64,7 +54,7 @@ png_get_image_width(png_const_structrp png_ptr, png_const_inforp info_ptr) if (png_ptr != NULL && info_ptr != NULL) return info_ptr->width; - return 0; + return (0); } png_uint_32 PNGAPI @@ -73,7 +63,7 @@ png_get_image_height(png_const_structrp png_ptr, png_const_inforp info_ptr) if (png_ptr != NULL && info_ptr != NULL) return info_ptr->height; - return 0; + return (0); } png_byte PNGAPI @@ -82,7 +72,7 @@ png_get_bit_depth(png_const_structrp png_ptr, png_const_inforp info_ptr) if (png_ptr != NULL && info_ptr != NULL) return info_ptr->bit_depth; - return 0; + return (0); } png_byte PNGAPI @@ -91,7 +81,7 @@ png_get_color_type(png_const_structrp png_ptr, png_const_inforp info_ptr) if (png_ptr != NULL && info_ptr != NULL) return info_ptr->color_type; - return 0; + return (0); } png_byte PNGAPI @@ -100,7 +90,7 @@ png_get_filter_type(png_const_structrp png_ptr, png_const_inforp info_ptr) if (png_ptr != NULL && info_ptr != NULL) return info_ptr->filter_type; - return 0; + return (0); } png_byte PNGAPI @@ -109,7 +99,7 @@ png_get_interlace_type(png_const_structrp png_ptr, png_const_inforp info_ptr) if (png_ptr != NULL && info_ptr != NULL) return info_ptr->interlace_type; - return 0; + return (0); } png_byte PNGAPI @@ -118,93 +108,82 @@ png_get_compression_type(png_const_structrp png_ptr, png_const_inforp info_ptr) if (png_ptr != NULL && info_ptr != NULL) return info_ptr->compression_type; - return 0; + return (0); } png_uint_32 PNGAPI -png_get_x_pixels_per_meter(png_const_structrp png_ptr, - png_const_inforp info_ptr) +png_get_x_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp + info_ptr) { #ifdef PNG_pHYs_SUPPORTED - png_debug(1, "in png_get_x_pixels_per_meter"); + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_debug1(1, "in %s retrieval function", + "png_get_x_pixels_per_meter"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pHYs) != 0) - { - if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) - return info_ptr->x_pixels_per_unit; - } -#else - PNG_UNUSED(png_ptr) - PNG_UNUSED(info_ptr) + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) + return (info_ptr->x_pixels_per_unit); + } #endif - return 0; + return (0); } png_uint_32 PNGAPI -png_get_y_pixels_per_meter(png_const_structrp png_ptr, - png_const_inforp info_ptr) +png_get_y_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp + info_ptr) { #ifdef PNG_pHYs_SUPPORTED - png_debug(1, "in png_get_y_pixels_per_meter"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pHYs) != 0) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) { + png_debug1(1, "in %s retrieval function", + "png_get_y_pixels_per_meter"); + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER) - return info_ptr->y_pixels_per_unit; + return (info_ptr->y_pixels_per_unit); } -#else - PNG_UNUSED(png_ptr) - PNG_UNUSED(info_ptr) #endif - return 0; + return (0); } png_uint_32 PNGAPI png_get_pixels_per_meter(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_pHYs_SUPPORTED - png_debug(1, "in png_get_pixels_per_meter"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pHYs) != 0) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) { + png_debug1(1, "in %s retrieval function", "png_get_pixels_per_meter"); + if (info_ptr->phys_unit_type == PNG_RESOLUTION_METER && info_ptr->x_pixels_per_unit == info_ptr->y_pixels_per_unit) - return info_ptr->x_pixels_per_unit; + return (info_ptr->x_pixels_per_unit); } -#else - PNG_UNUSED(png_ptr) - PNG_UNUSED(info_ptr) #endif - return 0; + return (0); } #ifdef PNG_FLOATING_POINT_SUPPORTED float PNGAPI -png_get_pixel_aspect_ratio(png_const_structrp png_ptr, - png_const_inforp info_ptr) +png_get_pixel_aspect_ratio(png_const_structrp png_ptr, png_const_inforp + info_ptr) { #ifdef PNG_READ_pHYs_SUPPORTED - png_debug(1, "in png_get_pixel_aspect_ratio"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pHYs) != 0) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) { + png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio"); + if (info_ptr->x_pixels_per_unit != 0) - return (float)info_ptr->y_pixels_per_unit - / (float)info_ptr->x_pixels_per_unit; + return ((float)((float)info_ptr->y_pixels_per_unit + /(float)info_ptr->x_pixels_per_unit)); } #else PNG_UNUSED(png_ptr) PNG_UNUSED(info_ptr) #endif - return (float)0.0; + return ((float)0.0); } #endif @@ -214,21 +193,20 @@ png_get_pixel_aspect_ratio_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_READ_pHYs_SUPPORTED - png_debug(1, "in png_get_pixel_aspect_ratio_fixed"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pHYs) != 0 && - info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 && - info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX && - info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs) + && info_ptr->x_pixels_per_unit > 0 && info_ptr->y_pixels_per_unit > 0 + && info_ptr->x_pixels_per_unit <= PNG_UINT_31_MAX + && info_ptr->y_pixels_per_unit <= PNG_UINT_31_MAX) { png_fixed_point res; + png_debug1(1, "in %s retrieval function", "png_get_aspect_ratio_fixed"); + /* The following casts work because a PNG 4 byte integer only has a valid * range of 0..2^31-1; otherwise the cast might overflow. */ if (png_muldiv(&res, (png_int_32)info_ptr->y_pixels_per_unit, PNG_FP_1, - (png_int_32)info_ptr->x_pixels_per_unit) != 0) + (png_int_32)info_ptr->x_pixels_per_unit)) return res; } #else @@ -244,80 +222,64 @@ png_int_32 PNGAPI png_get_x_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_oFFs_SUPPORTED - png_debug(1, "in png_get_x_offset_microns"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_oFFs) != 0) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) { + png_debug1(1, "in %s retrieval function", "png_get_x_offset_microns"); + if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) - return info_ptr->x_offset; + return (info_ptr->x_offset); } -#else - PNG_UNUSED(png_ptr) - PNG_UNUSED(info_ptr) #endif - return 0; + return (0); } png_int_32 PNGAPI png_get_y_offset_microns(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_oFFs_SUPPORTED - png_debug(1, "in png_get_y_offset_microns"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_oFFs) != 0) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) { + png_debug1(1, "in %s retrieval function", "png_get_y_offset_microns"); + if (info_ptr->offset_unit_type == PNG_OFFSET_MICROMETER) - return info_ptr->y_offset; + return (info_ptr->y_offset); } -#else - PNG_UNUSED(png_ptr) - PNG_UNUSED(info_ptr) #endif - return 0; + return (0); } png_int_32 PNGAPI png_get_x_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_oFFs_SUPPORTED - png_debug(1, "in png_get_x_offset_pixels"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_oFFs) != 0) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) { + png_debug1(1, "in %s retrieval function", "png_get_x_offset_pixels"); + if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) - return info_ptr->x_offset; + return (info_ptr->x_offset); } -#else - PNG_UNUSED(png_ptr) - PNG_UNUSED(info_ptr) #endif - return 0; + return (0); } png_int_32 PNGAPI png_get_y_offset_pixels(png_const_structrp png_ptr, png_const_inforp info_ptr) { #ifdef PNG_oFFs_SUPPORTED - png_debug(1, "in png_get_y_offset_pixels"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_oFFs) != 0) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) { + png_debug1(1, "in %s retrieval function", "png_get_y_offset_pixels"); + if (info_ptr->offset_unit_type == PNG_OFFSET_PIXEL) - return info_ptr->y_offset; + return (info_ptr->y_offset); } -#else - PNG_UNUSED(png_ptr) - PNG_UNUSED(info_ptr) #endif - return 0; + return (0); } #ifdef PNG_INCH_CONVERSIONS_SUPPORTED @@ -345,8 +307,8 @@ ppi_from_ppm(png_uint_32 ppm) */ png_fixed_point result; if (ppm <= PNG_UINT_31_MAX && png_muldiv(&result, (png_int_32)ppm, 127, - 5000) != 0) - return (png_uint_32)result; + 5000)) + return result; /* Overflow. */ return 0; @@ -375,18 +337,12 @@ png_get_y_pixels_per_inch(png_const_structrp png_ptr, png_const_inforp info_ptr) static png_fixed_point png_fixed_inches_from_microns(png_const_structrp png_ptr, png_int_32 microns) { - /* Convert from meters * 1,000,000 to inches * 100,000, meters to + /* Convert from metres * 1,000,000 to inches * 100,000, meters to * inches is simply *(100/2.54), so we want *(10/2.54) == 500/127. * Notice that this can overflow - a warning is output and 0 is * returned. */ - png_fixed_point result; - - if (png_muldiv(&result, microns, 500, 127) != 0) - return result; - - png_warning(png_ptr, "fixed point overflow ignored"); - return 0; + return png_muldiv_warn(png_ptr, microns, 500, 127); } png_fixed_point PNGAPI @@ -396,7 +352,7 @@ png_get_x_offset_inches_fixed(png_const_structrp png_ptr, return png_fixed_inches_from_microns(png_ptr, png_get_x_offset_microns(png_ptr, info_ptr)); } -#endif /* FIXED_POINT */ +#endif #ifdef PNG_FIXED_POINT_SUPPORTED png_fixed_point PNGAPI @@ -437,11 +393,10 @@ png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr, { png_uint_32 retval = 0; - png_debug1(1, "in %s retrieval function", "pHYs"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pHYs) != 0) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) { + png_debug1(1, "in %s retrieval function", "pHYs"); + if (res_x != NULL) { *res_x = info_ptr->x_pixels_per_unit; @@ -467,23 +422,23 @@ png_get_pHYs_dpi(png_const_structrp png_ptr, png_const_inforp info_ptr, } } - return retval; + return (retval); } -#endif /* pHYs */ -#endif /* INCH_CONVERSIONS */ +#endif /* PNG_pHYs_SUPPORTED */ +#endif /* PNG_INCH_CONVERSIONS_SUPPORTED */ /* png_get_channels really belongs in here, too, but it's been around longer */ -#endif /* EASY_ACCESS */ +#endif /* PNG_EASY_ACCESS_SUPPORTED */ png_byte PNGAPI png_get_channels(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->channels; + return(info_ptr->channels); - return 0; + return (0); } #ifdef PNG_READ_SUPPORTED @@ -491,28 +446,27 @@ png_const_bytep PNGAPI png_get_signature(png_const_structrp png_ptr, png_const_inforp info_ptr) { if (png_ptr != NULL && info_ptr != NULL) - return info_ptr->signature; + return(info_ptr->signature); - return NULL; + return (NULL); } #endif #ifdef PNG_bKGD_SUPPORTED png_uint_32 PNGAPI png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, - png_color_16p *background) + png_color_16p *background) { - png_debug1(1, "in %s retrieval function", "bKGD"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_bKGD) != 0 && - background != NULL) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) + && background != NULL) { + png_debug1(1, "in %s retrieval function", "bKGD"); + *background = &(info_ptr->background); - return PNG_INFO_bKGD; + return (PNG_INFO_bKGD); } - return 0; + return (0); } #endif @@ -524,72 +478,92 @@ png_get_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, # ifdef PNG_FLOATING_POINT_SUPPORTED png_uint_32 PNGAPI png_get_cHRM(png_const_structrp png_ptr, png_const_inforp info_ptr, - double *whitex, double *whitey, double *redx, double *redy, - double *greenx, double *greeny, double *bluex, double *bluey) + double *white_x, double *white_y, double *red_x, double *red_y, + double *green_x, double *green_y, double *blue_x, double *blue_y) { - png_debug1(1, "in %s retrieval function", "cHRM"); - - /* PNGv3: this just returns the values store from the cHRM, if any. */ + /* Quiet API change: this code used to only return the end points if a cHRM + * chunk was present, but the end points can also come from iCCP or sRGB + * chunks, so in 1.6.0 the png_get_ APIs return the end points regardless and + * the png_set_ APIs merely check that set end points are mutually + * consistent. + */ if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_cHRM) != 0) + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) { - if (whitex != NULL) - *whitex = png_float(png_ptr, info_ptr->cHRM.whitex, "cHRM wx"); - if (whitey != NULL) - *whitey = png_float(png_ptr, info_ptr->cHRM.whitey, "cHRM wy"); - if (redx != NULL) - *redx = png_float(png_ptr, info_ptr->cHRM.redx, "cHRM rx"); - if (redy != NULL) - *redy = png_float(png_ptr, info_ptr->cHRM.redy, "cHRM ry"); - if (greenx != NULL) - *greenx = png_float(png_ptr, info_ptr->cHRM.greenx, "cHRM gx"); - if (greeny != NULL) - *greeny = png_float(png_ptr, info_ptr->cHRM.greeny, "cHRM gy"); - if (bluex != NULL) - *bluex = png_float(png_ptr, info_ptr->cHRM.bluex, "cHRM bx"); - if (bluey != NULL) - *bluey = png_float(png_ptr, info_ptr->cHRM.bluey, "cHRM by"); - return PNG_INFO_cHRM; + png_debug1(1, "in %s retrieval function", "cHRM"); + + if (white_x != NULL) + *white_x = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.whitex, "cHRM white X"); + if (white_y != NULL) + *white_y = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.whitey, "cHRM white Y"); + if (red_x != NULL) + *red_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redx, + "cHRM red X"); + if (red_y != NULL) + *red_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.redy, + "cHRM red Y"); + if (green_x != NULL) + *green_x = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.greenx, "cHRM green X"); + if (green_y != NULL) + *green_y = png_float(png_ptr, + info_ptr->colorspace.end_points_xy.greeny, "cHRM green Y"); + if (blue_x != NULL) + *blue_x = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluex, + "cHRM blue X"); + if (blue_y != NULL) + *blue_y = png_float(png_ptr, info_ptr->colorspace.end_points_xy.bluey, + "cHRM blue Y"); + return (PNG_INFO_cHRM); } - return 0; + return (0); } png_uint_32 PNGAPI png_get_cHRM_XYZ(png_const_structrp png_ptr, png_const_inforp info_ptr, - double *red_X, double *red_Y, double *red_Z, double *green_X, - double *green_Y, double *green_Z, double *blue_X, double *blue_Y, - double *blue_Z) + double *red_X, double *red_Y, double *red_Z, double *green_X, + double *green_Y, double *green_Z, double *blue_X, double *blue_Y, + double *blue_Z) { - png_XYZ XYZ; - png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_cHRM) != 0 && - png_XYZ_from_xy(&XYZ, &info_ptr->cHRM) == 0) + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) { + png_debug1(1, "in %s retrieval function", "cHRM_XYZ(float)"); + if (red_X != NULL) - *red_X = png_float(png_ptr, XYZ.red_X, "cHRM red X"); + *red_X = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_X, + "cHRM red X"); if (red_Y != NULL) - *red_Y = png_float(png_ptr, XYZ.red_Y, "cHRM red Y"); + *red_Y = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Y, + "cHRM red Y"); if (red_Z != NULL) - *red_Z = png_float(png_ptr, XYZ.red_Z, "cHRM red Z"); + *red_Z = png_float(png_ptr, info_ptr->colorspace.end_points_XYZ.red_Z, + "cHRM red Z"); if (green_X != NULL) - *green_X = png_float(png_ptr, XYZ.green_X, "cHRM green X"); + *green_X = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_X, "cHRM green X"); if (green_Y != NULL) - *green_Y = png_float(png_ptr, XYZ.green_Y, "cHRM green Y"); + *green_Y = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_Y, "cHRM green Y"); if (green_Z != NULL) - *green_Z = png_float(png_ptr, XYZ.green_Z, "cHRM green Z"); + *green_Z = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.green_Z, "cHRM green Z"); if (blue_X != NULL) - *blue_X = png_float(png_ptr, XYZ.blue_X, "cHRM blue X"); + *blue_X = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_X, "cHRM blue X"); if (blue_Y != NULL) - *blue_Y = png_float(png_ptr, XYZ.blue_Y, "cHRM blue Y"); + *blue_Y = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_Y, "cHRM blue Y"); if (blue_Z != NULL) - *blue_Z = png_float(png_ptr, XYZ.blue_Z, "cHRM blue Z"); - return PNG_INFO_cHRM; + *blue_Z = png_float(png_ptr, + info_ptr->colorspace.end_points_XYZ.blue_Z, "cHRM blue Z"); + return (PNG_INFO_cHRM); } - return 0; + return (0); } # endif @@ -602,52 +576,66 @@ png_get_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, png_fixed_point *int_blue_X, png_fixed_point *int_blue_Y, png_fixed_point *int_blue_Z) { - png_XYZ XYZ; - png_debug1(1, "in %s retrieval function", "cHRM_XYZ"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_cHRM) != 0U && - png_XYZ_from_xy(&XYZ, &info_ptr->cHRM) == 0) + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) { - if (int_red_X != NULL) *int_red_X = XYZ.red_X; - if (int_red_Y != NULL) *int_red_Y = XYZ.red_Y; - if (int_red_Z != NULL) *int_red_Z = XYZ.red_Z; - if (int_green_X != NULL) *int_green_X = XYZ.green_X; - if (int_green_Y != NULL) *int_green_Y = XYZ.green_Y; - if (int_green_Z != NULL) *int_green_Z = XYZ.green_Z; - if (int_blue_X != NULL) *int_blue_X = XYZ.blue_X; - if (int_blue_Y != NULL) *int_blue_Y = XYZ.blue_Y; - if (int_blue_Z != NULL) *int_blue_Z = XYZ.blue_Z; - return PNG_INFO_cHRM; + png_debug1(1, "in %s retrieval function", "cHRM_XYZ"); + + if (int_red_X != NULL) + *int_red_X = info_ptr->colorspace.end_points_XYZ.red_X; + if (int_red_Y != NULL) + *int_red_Y = info_ptr->colorspace.end_points_XYZ.red_Y; + if (int_red_Z != NULL) + *int_red_Z = info_ptr->colorspace.end_points_XYZ.red_Z; + if (int_green_X != NULL) + *int_green_X = info_ptr->colorspace.end_points_XYZ.green_X; + if (int_green_Y != NULL) + *int_green_Y = info_ptr->colorspace.end_points_XYZ.green_Y; + if (int_green_Z != NULL) + *int_green_Z = info_ptr->colorspace.end_points_XYZ.green_Z; + if (int_blue_X != NULL) + *int_blue_X = info_ptr->colorspace.end_points_XYZ.blue_X; + if (int_blue_Y != NULL) + *int_blue_Y = info_ptr->colorspace.end_points_XYZ.blue_Y; + if (int_blue_Z != NULL) + *int_blue_Z = info_ptr->colorspace.end_points_XYZ.blue_Z; + return (PNG_INFO_cHRM); } - return 0; + return (0); } png_uint_32 PNGAPI png_get_cHRM_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, - png_fixed_point *whitex, png_fixed_point *whitey, png_fixed_point *redx, - png_fixed_point *redy, png_fixed_point *greenx, png_fixed_point *greeny, - png_fixed_point *bluex, png_fixed_point *bluey) + png_fixed_point *white_x, png_fixed_point *white_y, png_fixed_point *red_x, + png_fixed_point *red_y, png_fixed_point *green_x, png_fixed_point *green_y, + png_fixed_point *blue_x, png_fixed_point *blue_y) { png_debug1(1, "in %s retrieval function", "cHRM"); - /* PNGv3: this just returns the values store from the cHRM, if any. */ if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_cHRM) != 0) + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_ENDPOINTS)) { - if (whitex != NULL) *whitex = info_ptr->cHRM.whitex; - if (whitey != NULL) *whitey = info_ptr->cHRM.whitey; - if (redx != NULL) *redx = info_ptr->cHRM.redx; - if (redy != NULL) *redy = info_ptr->cHRM.redy; - if (greenx != NULL) *greenx = info_ptr->cHRM.greenx; - if (greeny != NULL) *greeny = info_ptr->cHRM.greeny; - if (bluex != NULL) *bluex = info_ptr->cHRM.bluex; - if (bluey != NULL) *bluey = info_ptr->cHRM.bluey; - return PNG_INFO_cHRM; + if (white_x != NULL) + *white_x = info_ptr->colorspace.end_points_xy.whitex; + if (white_y != NULL) + *white_y = info_ptr->colorspace.end_points_xy.whitey; + if (red_x != NULL) + *red_x = info_ptr->colorspace.end_points_xy.redx; + if (red_y != NULL) + *red_y = info_ptr->colorspace.end_points_xy.redy; + if (green_x != NULL) + *green_x = info_ptr->colorspace.end_points_xy.greenx; + if (green_y != NULL) + *green_y = info_ptr->colorspace.end_points_xy.greeny; + if (blue_x != NULL) + *blue_x = info_ptr->colorspace.end_points_xy.bluex; + if (blue_y != NULL) + *blue_y = info_ptr->colorspace.end_points_xy.bluey; + return (PNG_INFO_cHRM); } - return 0; + return (0); } # endif #endif @@ -660,15 +648,15 @@ png_get_gAMA_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, { png_debug1(1, "in %s retrieval function", "gAMA"); - /* PNGv3 compatibility: only report gAMA if it is really present. */ if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_gAMA) != 0) + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) && + file_gamma != NULL) { - if (file_gamma != NULL) *file_gamma = info_ptr->gamma; - return PNG_INFO_gAMA; + *file_gamma = info_ptr->colorspace.gamma; + return (PNG_INFO_gAMA); } - return 0; + return (0); } # endif @@ -679,17 +667,16 @@ png_get_gAMA(png_const_structrp png_ptr, png_const_inforp info_ptr, { png_debug1(1, "in %s retrieval function", "gAMA(float)"); - /* PNGv3 compatibility: only report gAMA if it is really present. */ if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_gAMA) != 0) + (info_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) && + file_gamma != NULL) { - if (file_gamma != NULL) - *file_gamma = png_float(png_ptr, info_ptr->gamma, "gAMA"); - - return PNG_INFO_gAMA; + *file_gamma = png_float(png_ptr, info_ptr->colorspace.gamma, + "png_get_gAMA"); + return (PNG_INFO_gAMA); } - return 0; + return (0); } # endif #endif @@ -701,15 +688,14 @@ png_get_sRGB(png_const_structrp png_ptr, png_const_inforp info_ptr, { png_debug1(1, "in %s retrieval function", "sRGB"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sRGB) != 0) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sRGB) + && file_srgb_intent != NULL) { - if (file_srgb_intent != NULL) - *file_srgb_intent = info_ptr->rendering_intent; - return PNG_INFO_sRGB; + *file_srgb_intent = info_ptr->colorspace.rendering_intent; + return (PNG_INFO_sRGB); } - return 0; + return (0); } #endif @@ -721,9 +707,9 @@ png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, { png_debug1(1, "in %s retrieval function", "iCCP"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_iCCP) != 0 && - name != NULL && profile != NULL && proflen != NULL) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_iCCP) + && name != NULL && compression_type != NULL && profile != NULL && + proflen != NULL) { *name = info_ptr->iccp_name; *profile = info_ptr->iccp_profile; @@ -731,12 +717,11 @@ png_get_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, /* This is somewhat irrelevant since the profile data returned has * actually been uncompressed. */ - if (compression_type != NULL) - *compression_type = PNG_COMPRESSION_TYPE_BASE; - return PNG_INFO_iCCP; + *compression_type = PNG_COMPRESSION_TYPE_BASE; + return (PNG_INFO_iCCP); } - return 0; + return (0); } #endif @@ -745,174 +730,13 @@ int PNGAPI png_get_sPLT(png_const_structrp png_ptr, png_inforp info_ptr, png_sPLT_tpp spalettes) { - png_debug1(1, "in %s retrieval function", "sPLT"); - if (png_ptr != NULL && info_ptr != NULL && spalettes != NULL) { *spalettes = info_ptr->splt_palettes; return info_ptr->splt_palettes_num; } - return 0; -} -#endif - -#ifdef PNG_cICP_SUPPORTED -png_uint_32 PNGAPI -png_get_cICP(png_const_structrp png_ptr, - png_const_inforp info_ptr, png_bytep colour_primaries, - png_bytep transfer_function, png_bytep matrix_coefficients, - png_bytep video_full_range_flag) -{ - png_debug1(1, "in %s retrieval function", "cICP"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_cICP) != 0 && - colour_primaries != NULL && transfer_function != NULL && - matrix_coefficients != NULL && video_full_range_flag != NULL) - { - *colour_primaries = info_ptr->cicp_colour_primaries; - *transfer_function = info_ptr->cicp_transfer_function; - *matrix_coefficients = info_ptr->cicp_matrix_coefficients; - *video_full_range_flag = info_ptr->cicp_video_full_range_flag; - return (PNG_INFO_cICP); - } - - return 0; -} -#endif - -#ifdef PNG_cLLI_SUPPORTED -# ifdef PNG_FIXED_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_cLLI_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, - png_uint_32p maxCLL, - png_uint_32p maxFALL) -{ - png_debug1(1, "in %s retrieval function", "cLLI"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_cLLI) != 0) - { - if (maxCLL != NULL) *maxCLL = info_ptr->maxCLL; - if (maxFALL != NULL) *maxFALL = info_ptr->maxFALL; - return PNG_INFO_cLLI; - } - - return 0; -} -# endif - -# ifdef PNG_FLOATING_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_cLLI(png_const_structrp png_ptr, png_const_inforp info_ptr, - double *maxCLL, double *maxFALL) -{ - png_debug1(1, "in %s retrieval function", "cLLI(float)"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_cLLI) != 0) - { - if (maxCLL != NULL) *maxCLL = info_ptr->maxCLL * .0001; - if (maxFALL != NULL) *maxFALL = info_ptr->maxFALL * .0001; - return PNG_INFO_cLLI; - } - - return 0; -} -# endif -#endif /* cLLI */ - -#ifdef PNG_mDCV_SUPPORTED -# ifdef PNG_FIXED_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_mDCV_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, - png_fixed_point *white_x, png_fixed_point *white_y, - png_fixed_point *red_x, png_fixed_point *red_y, - png_fixed_point *green_x, png_fixed_point *green_y, - png_fixed_point *blue_x, png_fixed_point *blue_y, - png_uint_32p mastering_maxDL, png_uint_32p mastering_minDL) -{ - png_debug1(1, "in %s retrieval function", "mDCV"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_mDCV) != 0) - { - if (white_x != NULL) *white_x = info_ptr->mastering_white_x * 2; - if (white_y != NULL) *white_y = info_ptr->mastering_white_y * 2; - if (red_x != NULL) *red_x = info_ptr->mastering_red_x * 2; - if (red_y != NULL) *red_y = info_ptr->mastering_red_y * 2; - if (green_x != NULL) *green_x = info_ptr->mastering_green_x * 2; - if (green_y != NULL) *green_y = info_ptr->mastering_green_y * 2; - if (blue_x != NULL) *blue_x = info_ptr->mastering_blue_x * 2; - if (blue_y != NULL) *blue_y = info_ptr->mastering_blue_y * 2; - if (mastering_maxDL != NULL) *mastering_maxDL = info_ptr->mastering_maxDL; - if (mastering_minDL != NULL) *mastering_minDL = info_ptr->mastering_minDL; - return PNG_INFO_mDCV; - } - - return 0; -} -# endif - -# ifdef PNG_FLOATING_POINT_SUPPORTED -png_uint_32 PNGAPI -png_get_mDCV(png_const_structrp png_ptr, png_const_inforp info_ptr, - double *white_x, double *white_y, double *red_x, double *red_y, - double *green_x, double *green_y, double *blue_x, double *blue_y, - double *mastering_maxDL, double *mastering_minDL) -{ - png_debug1(1, "in %s retrieval function", "mDCV(float)"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_mDCV) != 0) - { - if (white_x != NULL) *white_x = info_ptr->mastering_white_x * .00002; - if (white_y != NULL) *white_y = info_ptr->mastering_white_y * .00002; - if (red_x != NULL) *red_x = info_ptr->mastering_red_x * .00002; - if (red_y != NULL) *red_y = info_ptr->mastering_red_y * .00002; - if (green_x != NULL) *green_x = info_ptr->mastering_green_x * .00002; - if (green_y != NULL) *green_y = info_ptr->mastering_green_y * .00002; - if (blue_x != NULL) *blue_x = info_ptr->mastering_blue_x * .00002; - if (blue_y != NULL) *blue_y = info_ptr->mastering_blue_y * .00002; - if (mastering_maxDL != NULL) - *mastering_maxDL = info_ptr->mastering_maxDL * .0001; - if (mastering_minDL != NULL) - *mastering_minDL = info_ptr->mastering_minDL * .0001; - return PNG_INFO_mDCV; - } - - return 0; -} -# endif /* FLOATING_POINT */ -#endif /* mDCV */ - -#ifdef PNG_eXIf_SUPPORTED -png_uint_32 PNGAPI -png_get_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, - png_bytep *exif) -{ - png_warning(png_ptr, "png_get_eXIf does not work; use png_get_eXIf_1"); - PNG_UNUSED(info_ptr) - PNG_UNUSED(exif) - return 0; -} - -png_uint_32 PNGAPI -png_get_eXIf_1(png_const_structrp png_ptr, png_const_inforp info_ptr, - png_uint_32 *num_exif, png_bytep *exif) -{ - png_debug1(1, "in %s retrieval function", "eXIf"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_eXIf) != 0 && exif != NULL) - { - *num_exif = info_ptr->num_exif; - *exif = info_ptr->exif; - return PNG_INFO_eXIf; - } - - return 0; + return (0); } #endif @@ -923,14 +747,14 @@ png_get_hIST(png_const_structrp png_ptr, png_inforp info_ptr, { png_debug1(1, "in %s retrieval function", "hIST"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_hIST) != 0 && hist != NULL) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) + && hist != NULL) { *hist = info_ptr->hist; - return PNG_INFO_hIST; + return (PNG_INFO_hIST); } - return 0; + return (0); } #endif @@ -942,20 +766,14 @@ png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr, { png_debug1(1, "in %s retrieval function", "IHDR"); - if (png_ptr == NULL || info_ptr == NULL) - return 0; + if (png_ptr == NULL || info_ptr == NULL || width == NULL || + height == NULL || bit_depth == NULL || color_type == NULL) + return (0); - if (width != NULL) - *width = info_ptr->width; - - if (height != NULL) - *height = info_ptr->height; - - if (bit_depth != NULL) - *bit_depth = info_ptr->bit_depth; - - if (color_type != NULL) - *color_type = info_ptr->color_type; + *width = info_ptr->width; + *height = info_ptr->height; + *bit_depth = info_ptr->bit_depth; + *color_type = info_ptr->color_type; if (compression_type != NULL) *compression_type = info_ptr->compression_type; @@ -975,7 +793,7 @@ png_get_IHDR(png_const_structrp png_ptr, png_const_inforp info_ptr, info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, info_ptr->compression_type, info_ptr->filter_type); - return 1; + return (1); } #ifdef PNG_oFFs_SUPPORTED @@ -985,17 +803,16 @@ png_get_oFFs(png_const_structrp png_ptr, png_const_inforp info_ptr, { png_debug1(1, "in %s retrieval function", "oFFs"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_oFFs) != 0 && - offset_x != NULL && offset_y != NULL && unit_type != NULL) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs) + && offset_x != NULL && offset_y != NULL && unit_type != NULL) { *offset_x = info_ptr->x_offset; *offset_y = info_ptr->y_offset; *unit_type = (int)info_ptr->offset_unit_type; - return PNG_INFO_oFFs; + return (PNG_INFO_oFFs); } - return 0; + return (0); } #endif @@ -1007,9 +824,8 @@ png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, { png_debug1(1, "in %s retrieval function", "pCAL"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pCAL) != 0 && - purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL) + && purpose != NULL && X0 != NULL && X1 != NULL && type != NULL && nparams != NULL && units != NULL && params != NULL) { *purpose = info_ptr->pcal_purpose; @@ -1019,10 +835,10 @@ png_get_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, *nparams = (int)info_ptr->pcal_nparams; *units = info_ptr->pcal_units; *params = info_ptr->pcal_params; - return PNG_INFO_pCAL; + return (PNG_INFO_pCAL); } - return 0; + return (0); } #endif @@ -1034,10 +850,8 @@ png_uint_32 PNGAPI png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, png_fixed_point *width, png_fixed_point *height) { - png_debug1(1, "in %s retrieval function", "sCAL"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL) != 0) + (info_ptr->valid & PNG_INFO_sCAL)) { *unit = info_ptr->scal_unit; /*TODO: make this work without FP support; the API is currently eliminated @@ -1046,11 +860,11 @@ png_get_sCAL_fixed(png_const_structrp png_ptr, png_const_inforp info_ptr, */ *width = png_fixed(png_ptr, atof(info_ptr->scal_s_width), "sCAL width"); *height = png_fixed(png_ptr, atof(info_ptr->scal_s_height), - "sCAL height"); - return PNG_INFO_sCAL; + "sCAL height"); + return (PNG_INFO_sCAL); } - return 0; + return(0); } # endif /* FLOATING_ARITHMETIC */ # endif /* FIXED_POINT */ @@ -1059,36 +873,32 @@ png_uint_32 PNGAPI png_get_sCAL(png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, double *width, double *height) { - png_debug1(1, "in %s retrieval function", "sCAL(float)"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL) != 0) + (info_ptr->valid & PNG_INFO_sCAL)) { *unit = info_ptr->scal_unit; *width = atof(info_ptr->scal_s_width); *height = atof(info_ptr->scal_s_height); - return PNG_INFO_sCAL; + return (PNG_INFO_sCAL); } - return 0; + return(0); } # endif /* FLOATING POINT */ png_uint_32 PNGAPI png_get_sCAL_s(png_const_structrp png_ptr, png_const_inforp info_ptr, int *unit, png_charpp width, png_charpp height) { - png_debug1(1, "in %s retrieval function", "sCAL(str)"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sCAL) != 0) + (info_ptr->valid & PNG_INFO_sCAL)) { *unit = info_ptr->scal_unit; *width = info_ptr->scal_s_width; *height = info_ptr->scal_s_height; - return PNG_INFO_sCAL; + return (PNG_INFO_sCAL); } - return 0; + return(0); } #endif /* sCAL */ @@ -1102,7 +912,7 @@ png_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr, png_debug1(1, "in %s retrieval function", "pHYs"); if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_pHYs) != 0) + (info_ptr->valid & PNG_INFO_pHYs)) { if (res_x != NULL) { @@ -1123,7 +933,7 @@ png_get_pHYs(png_const_structrp png_ptr, png_const_inforp info_ptr, } } - return retval; + return (retval); } #endif /* pHYs */ @@ -1133,16 +943,16 @@ png_get_PLTE(png_const_structrp png_ptr, png_inforp info_ptr, { png_debug1(1, "in %s retrieval function", "PLTE"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_PLTE) != 0 && palette != NULL) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_PLTE) + && palette != NULL) { *palette = info_ptr->palette; *num_palette = info_ptr->num_palette; png_debug1(3, "num_palette = %d", *num_palette); - return PNG_INFO_PLTE; + return (PNG_INFO_PLTE); } - return 0; + return (0); } #ifdef PNG_sBIT_SUPPORTED @@ -1152,14 +962,14 @@ png_get_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, { png_debug1(1, "in %s retrieval function", "sBIT"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_sBIT) != 0 && sig_bit != NULL) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT) + && sig_bit != NULL) { *sig_bit = &(info_ptr->sig_bit); - return PNG_INFO_sBIT; + return (PNG_INFO_sBIT); } - return 0; + return (0); } #endif @@ -1170,7 +980,7 @@ png_get_text(png_const_structrp png_ptr, png_inforp info_ptr, { if (png_ptr != NULL && info_ptr != NULL && info_ptr->num_text > 0) { - png_debug1(1, "in text retrieval function, chunk typeid = 0x%lx", + png_debug1(1, "in 0x%lx retrieval function", (unsigned long)png_ptr->chunk_name); if (text_ptr != NULL) @@ -1185,7 +995,7 @@ png_get_text(png_const_structrp png_ptr, png_inforp info_ptr, if (num_text != NULL) *num_text = 0; - return 0; + return(0); } #endif @@ -1196,14 +1006,14 @@ png_get_tIME(png_const_structrp png_ptr, png_inforp info_ptr, { png_debug1(1, "in %s retrieval function", "tIME"); - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_tIME) != 0 && mod_time != NULL) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME) + && mod_time != NULL) { *mod_time = &(info_ptr->mod_time); - return PNG_INFO_tIME; + return (PNG_INFO_tIME); } - return 0; + return (0); } #endif @@ -1213,12 +1023,10 @@ png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr, png_bytep *trans_alpha, int *num_trans, png_color_16p *trans_color) { png_uint_32 retval = 0; - - png_debug1(1, "in %s retrieval function", "tRNS"); - - if (png_ptr != NULL && info_ptr != NULL && - (info_ptr->valid & PNG_INFO_tRNS) != 0) + if (png_ptr != NULL && info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) { + png_debug1(1, "in %s retrieval function", "tRNS"); + if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { if (trans_alpha != NULL) @@ -1250,7 +1058,7 @@ png_get_tRNS(png_const_structrp png_ptr, png_inforp info_ptr, } } - return retval; + return (retval); } #endif @@ -1265,13 +1073,13 @@ png_get_unknown_chunks(png_const_structrp png_ptr, png_inforp info_ptr, return info_ptr->unknown_chunks_num; } - return 0; + return (0); } #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED png_byte PNGAPI -png_get_rgb_to_gray_status(png_const_structrp png_ptr) +png_get_rgb_to_gray_status (png_const_structrp png_ptr) { return (png_byte)(png_ptr ? png_ptr->rgb_to_gray_status : 0); } @@ -1285,73 +1093,73 @@ png_get_user_chunk_ptr(png_const_structrp png_ptr) } #endif -size_t PNGAPI +png_size_t PNGAPI png_get_compression_buffer_size(png_const_structrp png_ptr) { if (png_ptr == NULL) return 0; -#ifdef PNG_WRITE_SUPPORTED - if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) -#endif +# ifdef PNG_WRITE_SUPPORTED + if (png_ptr->mode & PNG_IS_READ_STRUCT) +# endif { -#ifdef PNG_SEQUENTIAL_READ_SUPPORTED - return png_ptr->IDAT_read_size; -#else - return PNG_IDAT_READ_SIZE; -#endif +# ifdef PNG_SEQUENTIAL_READ_SUPPORTED + return png_ptr->IDAT_read_size; +# else + return PNG_IDAT_READ_SIZE; +# endif } -#ifdef PNG_WRITE_SUPPORTED - else - return png_ptr->zbuffer_size; -#endif +# ifdef PNG_WRITE_SUPPORTED + else + return png_ptr->zbuffer_size; +# endif } #ifdef PNG_SET_USER_LIMITS_SUPPORTED /* These functions were added to libpng 1.2.6 and were enabled * by default in libpng-1.4.0 */ png_uint_32 PNGAPI -png_get_user_width_max(png_const_structrp png_ptr) +png_get_user_width_max (png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_width_max : 0); } png_uint_32 PNGAPI -png_get_user_height_max(png_const_structrp png_ptr) +png_get_user_height_max (png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_height_max : 0); } /* This function was added to libpng 1.4.0 */ png_uint_32 PNGAPI -png_get_chunk_cache_max(png_const_structrp png_ptr) +png_get_chunk_cache_max (png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_chunk_cache_max : 0); } /* This function was added to libpng 1.4.1 */ png_alloc_size_t PNGAPI -png_get_chunk_malloc_max(png_const_structrp png_ptr) +png_get_chunk_malloc_max (png_const_structrp png_ptr) { return (png_ptr ? png_ptr->user_chunk_malloc_max : 0); } -#endif /* SET_USER_LIMITS */ +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ /* These functions were added to libpng 1.4.0 */ #ifdef PNG_IO_STATE_SUPPORTED png_uint_32 PNGAPI -png_get_io_state(png_const_structrp png_ptr) +png_get_io_state (png_const_structrp png_ptr) { return png_ptr->io_state; } png_uint_32 PNGAPI -png_get_io_chunk_type(png_const_structrp png_ptr) +png_get_io_chunk_type (png_const_structrp png_ptr) { return png_ptr->chunk_name; } -#endif /* IO_STATE */ +#endif /* ?PNG_IO_STATE_SUPPORTED */ #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED # ifdef PNG_GET_PALETTE_MAX_SUPPORTED @@ -1361,9 +1169,9 @@ png_get_palette_max(png_const_structp png_ptr, png_const_infop info_ptr) if (png_ptr != NULL && info_ptr != NULL) return png_ptr->num_palette_max; - return -1; + return (-1); } # endif #endif -#endif /* READ || WRITE */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pnginfo.h b/Windows_Libs/Dev/Render/libpng/pnginfo.h index 584a42f..26bf265 100644 --- a/Windows_Libs/Dev/Render/libpng/pnginfo.h +++ b/Windows_Libs/Dev/Render/libpng/pnginfo.h @@ -1,29 +1,54 @@ -/* pnginfo.h - internal structures for libpng + +/* pnginfo.h - header file for PNG reference library * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2013,2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Last changed in libpng 1.6.1 [March 28, 2013] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ -#ifndef PNGPRIV_H -# error This file must not be included by applications; please include -#endif - -/* INTERNAL, PRIVATE definition of a PNG. + /* png_info is a structure that holds the information in a PNG file so + * that the application can find out the characteristics of the image. + * If you are reading the file, this structure will tell you what is + * in the PNG file. If you are writing the file, fill in the information + * you want to put into the PNG file, using png_set_*() functions, then + * call png_write_info(). * - * png_info is a modifiable description of a PNG datastream. The fields inside - * this structure are accessed through png_get_() functions and modified - * using png_set_() functions. + * The names chosen should be very close to the PNG specification, so + * consult that document for information about the meaning of each field. * - * Some functions in libpng do directly access members of png_info. However, - * this should be avoided. png_struct objects contain members which hold - * caches, sometimes optimised, of the values from png_info objects, and - * png_info is not passed to the functions which read and write image data. + * With libpng < 0.95, it was only possible to directly set and read the + * the values in the png_info_struct, which meant that the contents and + * order of the values had to remain fixed. With libpng 0.95 and later, + * however, there are now functions that abstract the contents of + * png_info_struct from the application, so this makes it easier to use + * libpng with dynamic libraries, and even makes it possible to use + * libraries that don't have all of the libpng ancillary chunk-handing + * functionality. In libpng-1.5.0 this was moved into a separate private + * file that is not visible to applications. + * + * The following members may have allocated storage attached that should be + * cleaned up before the structure is discarded: palette, trans, text, + * pcal_purpose, pcal_units, pcal_params, hist, iccp_name, iccp_profile, + * splt_palettes, scal_unit, row_pointers, and unknowns. By default, these + * are automatically freed when the info structure is deallocated, if they were + * allocated internally by libpng. This behavior can be changed by means + * of the png_data_freer() function. + * + * More allocation details: all the chunk-reading functions that + * change these members go through the corresponding png_set_* + * functions. A function to clear these members is available: see + * png_free_data(). The png_set_* functions do not depend on being + * able to point info structure members to any of the storage they are + * passed (they make their own copies), EXCEPT that the png_set_text + * functions use the same storage passed to them in the text_ptr or + * itxt_ptr structure argument, and the png_set_rows and png_set_unknowns + * functions do not make their own copies. */ #ifndef PNGINFO_H #define PNGINFO_H @@ -31,10 +56,10 @@ struct png_info_def { /* The following are necessary for every PNG file */ - png_uint_32 width; /* width of image in pixels (from IHDR) */ - png_uint_32 height; /* height of image in pixels (from IHDR) */ - png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ - size_t rowbytes; /* bytes needed to hold an untransformed row */ + png_uint_32 width; /* width of image in pixels (from IHDR) */ + png_uint_32 height; /* height of image in pixels (from IHDR) */ + png_uint_32 valid; /* valid chunk data (see PNG_INFO_ below) */ + png_size_t rowbytes; /* bytes needed to hold an untransformed row */ png_colorp palette; /* array of color values (valid & PNG_INFO_PLTE) */ png_uint_16 num_palette; /* number of color entries in "palette" (PLTE) */ png_uint_16 num_trans; /* number of transparent palette color (tRNS) */ @@ -63,12 +88,18 @@ struct png_info_def * and initialize the appropriate fields below. */ -#ifdef PNG_cICP_SUPPORTED - /* cICP chunk data */ - png_byte cicp_colour_primaries; - png_byte cicp_transfer_function; - png_byte cicp_matrix_coefficients; - png_byte cicp_video_full_range_flag; +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + /* png_colorspace only contains 'flags' if neither GAMMA or COLORSPACE are + * defined. When COLORSPACE is switched on all the colorspace-defining + * chunks should be enabled, when GAMMA is switched on all the gamma-defining + * chunks should be enabled. If this is not done it becomes possible to read + * inconsistent PNG files and assign a probably incorrect interpretation to + * the information. (In other words, by carefully choosing which chunks to + * recognize the system configuration can select an interpretation for PNG + * files containing ambiguous data and this will result in inconsistent + * behavior between different libpng builds!) + */ + png_colorspace colorspace; #endif #ifdef PNG_iCCP_SUPPORTED @@ -78,24 +109,6 @@ struct png_info_def png_uint_32 iccp_proflen; /* ICC profile data length */ #endif -#ifdef PNG_cLLI_SUPPORTED - png_uint_32 maxCLL; /* cd/m2 (nits) * 10,000 */ - png_uint_32 maxFALL; -#endif - -#ifdef PNG_mDCV_SUPPORTED - png_uint_16 mastering_red_x; /* CIE (xy) x * 50,000 */ - png_uint_16 mastering_red_y; - png_uint_16 mastering_green_x; - png_uint_16 mastering_green_y; - png_uint_16 mastering_blue_x; - png_uint_16 mastering_blue_y; - png_uint_16 mastering_white_x; - png_uint_16 mastering_white_y; - png_uint_32 mastering_maxDL; /* cd/m2 (nits) * 10,000 */ - png_uint_32 mastering_minDL; -#endif - #ifdef PNG_TEXT_SUPPORTED /* The tEXt, and zTXt chunks contain human-readable textual data in * uncompressed, compressed, and optionally compressed forms, respectively. @@ -108,7 +121,7 @@ struct png_info_def int num_text; /* number of comments read or comments to write */ int max_text; /* current size of text array */ png_textp text; /* array of comments read or comments to write */ -#endif /* TEXT */ +#endif /* PNG_TEXT_SUPPORTED */ #ifdef PNG_tIME_SUPPORTED /* The tIME chunk holds the last time the displayed image data was @@ -173,11 +186,6 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) png_byte phys_unit_type; /* resolution type (see PNG_RESOLUTION_ below) */ #endif -#ifdef PNG_eXIf_SUPPORTED - png_uint_32 num_exif; /* Added at libpng-1.6.31 */ - png_bytep exif; -#endif - #ifdef PNG_hIST_SUPPORTED /* The hIST chunk contains the relative frequency or importance of the * various palette entries, so that a viewer can intelligently select a @@ -216,7 +224,7 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) /* Storage for unknown chunks that the library doesn't recognize. */ png_unknown_chunkp unknown_chunks; - /* The type of this field is limited by the type of + /* The type of this field is limited by the type of * png_struct::user_chunk_cache_max, else overflow can occur. */ int unknown_chunks_num; @@ -232,7 +240,7 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) /* The sCAL chunk describes the actual physical dimensions of the * subject matter of the graphic. The chunk contains a unit specification * a byte value, and two ASCII strings representing floating-point - * values. The values are width and height corresponding to one pixel + * values. The values are width and height corresponsing to one pixel * in the image. Data values are valid if (valid & PNG_INFO_sCAL) is * non-zero. */ @@ -248,16 +256,5 @@ defined(PNG_READ_BACKGROUND_SUPPORTED) png_bytepp row_pointers; /* the image bits */ #endif -#ifdef PNG_cHRM_SUPPORTED - png_xy cHRM; -#endif - -#ifdef PNG_gAMA_SUPPORTED - png_fixed_point gamma; -#endif - -#ifdef PNG_sRGB_SUPPORTED - int rendering_intent; -#endif }; #endif /* PNGINFO_H */ diff --git a/Windows_Libs/Dev/Render/libpng/pnglibconf.h b/Windows_Libs/Dev/Render/libpng/pnglibconf.h index e12c895..d616b57 100644 --- a/Windows_Libs/Dev/Render/libpng/pnglibconf.h +++ b/Windows_Libs/Dev/Render/libpng/pnglibconf.h @@ -1,9 +1,10 @@ +/* libpng 1.6.2 STANDARD API DEFINITION */ + /* pnglibconf.h - library build configuration */ -/* libpng version 1.6.55 */ +/* Libpng version 1.6.2 - April 25, 2013 */ -/* Copyright (c) 2018-2026 Cosmin Truta */ -/* Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson */ +/* Copyright (c) 1998-2013 Glenn Randers-Pehrson */ /* This code is released under the libpng license. */ /* For conditions of distribution and use, see the disclaimer */ @@ -19,6 +20,7 @@ #define PNG_ALIGNED_MEMORY_SUPPORTED /*#undef PNG_ARM_NEON_API_SUPPORTED*/ /*#undef PNG_ARM_NEON_CHECK_SUPPORTED*/ +/*#undef PNG_ARM_NEON_SUPPORTED*/ #define PNG_BENIGN_ERRORS_SUPPORTED #define PNG_BENIGN_READ_ERRORS_SUPPORTED /*#undef PNG_BENIGN_WRITE_ERRORS_SUPPORTED*/ @@ -27,7 +29,6 @@ #define PNG_COLORSPACE_SUPPORTED //#define PNG_CONSOLE_IO_SUPPORTED #define PNG_CONVERT_tIME_SUPPORTED -/*#undef PNG_DISABLE_ADLER32_CHECK_SUPPORTED*/ #define PNG_EASY_ACCESS_SUPPORTED /*#undef PNG_ERROR_NUMBERS_SUPPORTED*/ #define PNG_ERROR_TEXT_SUPPORTED @@ -42,14 +43,8 @@ #define PNG_INCH_CONVERSIONS_SUPPORTED #define PNG_INFO_IMAGE_SUPPORTED #define PNG_IO_STATE_SUPPORTED -/*#undef PNG_MIPS_MMI_API_SUPPORTED*/ -/*#undef PNG_MIPS_MMI_CHECK_SUPPORTED*/ -/*#undef PNG_MIPS_MSA_API_SUPPORTED*/ -/*#undef PNG_MIPS_MSA_CHECK_SUPPORTED*/ #define PNG_MNG_FEATURES_SUPPORTED #define PNG_POINTER_INDEXING_SUPPORTED -/*#undef PNG_POWERPC_VSX_API_SUPPORTED*/ -/*#undef PNG_POWERPC_VSX_CHECK_SUPPORTED*/ #define PNG_PROGRESSIVE_READ_SUPPORTED #define PNG_READ_16BIT_SUPPORTED #define PNG_READ_ALPHA_MODE_SUPPORTED @@ -88,14 +83,10 @@ #define PNG_READ_USER_TRANSFORM_SUPPORTED #define PNG_READ_bKGD_SUPPORTED #define PNG_READ_cHRM_SUPPORTED -#define PNG_READ_cICP_SUPPORTED -#define PNG_READ_cLLI_SUPPORTED -#define PNG_READ_eXIf_SUPPORTED #define PNG_READ_gAMA_SUPPORTED #define PNG_READ_hIST_SUPPORTED #define PNG_READ_iCCP_SUPPORTED #define PNG_READ_iTXt_SUPPORTED -#define PNG_READ_mDCV_SUPPORTED #define PNG_READ_oFFs_SUPPORTED #define PNG_READ_pCAL_SUPPORTED #define PNG_READ_pHYs_SUPPORTED @@ -107,11 +98,14 @@ #define PNG_READ_tIME_SUPPORTED #define PNG_READ_tRNS_SUPPORTED #define PNG_READ_zTXt_SUPPORTED +/*#undef PNG_SAFE_LIMITS_SUPPORTED*/ #define PNG_SAVE_INT_32_SUPPORTED #define PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED #define PNG_SEQUENTIAL_READ_SUPPORTED #define PNG_SETJMP_SUPPORTED -#define PNG_SET_OPTION_SUPPORTED +#define PNG_SET_CHUNK_CACHE_LIMIT_SUPPORTED +#define PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED +/*#undef PNG_SET_OPTION_SUPPORTED*/ #define PNG_SET_UNKNOWN_CHUNKS_SUPPORTED #define PNG_SET_USER_LIMITS_SUPPORTED #define PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED @@ -119,7 +113,6 @@ #define PNG_SIMPLIFIED_READ_SUPPORTED #define PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED #define PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED -#define PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED #define PNG_SIMPLIFIED_WRITE_SUPPORTED #define PNG_STDIO_SUPPORTED #define PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED @@ -137,7 +130,6 @@ #define PNG_WRITE_BGR_SUPPORTED #define PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED #define PNG_WRITE_COMPRESSED_TEXT_SUPPORTED -#define PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED #define PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED #define PNG_WRITE_FILLER_SUPPORTED #define PNG_WRITE_FILTER_SUPPORTED @@ -161,14 +153,10 @@ #define PNG_WRITE_WEIGHTED_FILTER_SUPPORTED #define PNG_WRITE_bKGD_SUPPORTED #define PNG_WRITE_cHRM_SUPPORTED -#define PNG_WRITE_cICP_SUPPORTED -#define PNG_WRITE_cLLI_SUPPORTED -#define PNG_WRITE_eXIf_SUPPORTED #define PNG_WRITE_gAMA_SUPPORTED #define PNG_WRITE_hIST_SUPPORTED #define PNG_WRITE_iCCP_SUPPORTED #define PNG_WRITE_iTXt_SUPPORTED -#define PNG_WRITE_mDCV_SUPPORTED #define PNG_WRITE_oFFs_SUPPORTED #define PNG_WRITE_pCAL_SUPPORTED #define PNG_WRITE_pHYs_SUPPORTED @@ -182,14 +170,10 @@ #define PNG_WRITE_zTXt_SUPPORTED #define PNG_bKGD_SUPPORTED #define PNG_cHRM_SUPPORTED -#define PNG_cICP_SUPPORTED -#define PNG_cLLI_SUPPORTED -#define PNG_eXIf_SUPPORTED #define PNG_gAMA_SUPPORTED #define PNG_hIST_SUPPORTED #define PNG_iCCP_SUPPORTED #define PNG_iTXt_SUPPORTED -#define PNG_mDCV_SUPPORTED #define PNG_oFFs_SUPPORTED #define PNG_pCAL_SUPPORTED #define PNG_pHYs_SUPPORTED @@ -204,30 +188,24 @@ /* end of options */ /* settings */ #define PNG_API_RULE 0 +#define PNG_CALLOC_SUPPORTED +#define PNG_COST_SHIFT 3 #define PNG_DEFAULT_READ_MACROS 1 #define PNG_GAMMA_THRESHOLD_FIXED 5000 #define PNG_IDAT_READ_SIZE PNG_ZBUF_SIZE #define PNG_INFLATE_BUF_SIZE 1024 -#define PNG_LINKAGE_API extern -#define PNG_LINKAGE_CALLBACK extern -#define PNG_LINKAGE_DATA extern -#define PNG_LINKAGE_FUNCTION extern #define PNG_MAX_GAMMA_8 11 #define PNG_QUANTIZE_BLUE_BITS 5 #define PNG_QUANTIZE_GREEN_BITS 5 #define PNG_QUANTIZE_RED_BITS 5 #define PNG_TEXT_Z_DEFAULT_COMPRESSION (-1) #define PNG_TEXT_Z_DEFAULT_STRATEGY 0 -#define PNG_USER_CHUNK_CACHE_MAX 1000 -#define PNG_USER_CHUNK_MALLOC_MAX 8000000 -#define PNG_USER_HEIGHT_MAX 1000000 -#define PNG_USER_WIDTH_MAX 1000000 +#define PNG_WEIGHT_SHIFT 8 #define PNG_ZBUF_SIZE 8192 -#define PNG_ZLIB_VERNUM 0 /* unknown */ #define PNG_Z_DEFAULT_COMPRESSION (-1) #define PNG_Z_DEFAULT_NOFILTER_STRATEGY 0 #define PNG_Z_DEFAULT_STRATEGY 1 #define PNG_sCAL_PRECISION 5 #define PNG_sRGB_PROFILE_CHECKS 2 /* end of settings */ -#endif /* PNGLCONF_H */ +#endif /* PNGLCONF_H */ \ No newline at end of file diff --git a/Windows_Libs/Dev/Render/libpng/pngmem.c b/Windows_Libs/Dev/Render/libpng/pngmem.c index b7adff8..b9b3efb 100644 --- a/Windows_Libs/Dev/Render/libpng/pngmem.c +++ b/Windows_Libs/Dev/Render/libpng/pngmem.c @@ -1,9 +1,10 @@ + /* pngmem.c - stub functions for memory allocation * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2014,2016 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.0 [February 14, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -40,14 +41,13 @@ png_destroy_png_struct(png_structrp png_ptr) } /* Allocate memory. For reasonable files, size should never exceed - * 64K. However, zlib may allocate more than 64K if you don't tell + * 64K. However, zlib may allocate more then 64K if you don't tell * it not to. See zconf.h and png.h for more information. zlib does * need to allocate exactly 64K, so whatever you call here must * have the ability to do that. */ PNG_FUNCTION(png_voidp,PNGAPI -png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED) +png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) { png_voidp ret; @@ -66,49 +66,44 @@ png_calloc,(png_const_structrp png_ptr, png_alloc_size_t size), */ PNG_FUNCTION(png_voidp /* PRIVATE */, png_malloc_base,(png_const_structrp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED) + PNG_ALLOCATED) { /* Moved to png_malloc_base from png_malloc_default in 1.6.0; the DOS * allocators have also been removed in 1.6.0, so any 16-bit system now has * to implement a user memory handler. This checks to be sure it isn't * called with big numbers. */ -# ifdef PNG_MAX_MALLOC_64K - /* This is support for legacy systems which had segmented addressing - * limiting the maximum allocation size to 65536. It takes precedence - * over PNG_SIZE_MAX which is set to 65535 on true 16-bit systems. - * - * TODO: libpng-1.8: finally remove both cases. - */ - if (size > 65536U) return NULL; -# endif - - /* This is checked too because the system malloc call below takes a (size_t). - */ - if (size > PNG_SIZE_MAX) return NULL; - -# ifdef PNG_USER_MEM_SUPPORTED +#ifdef PNG_USER_MEM_SUPPORTED + PNG_UNUSED(png_ptr) +#endif + if (size > 0 && size <= PNG_SIZE_MAX +# ifdef PNG_MAX_MALLOC_64K + && size <= 65536U +# endif + ) + { +#ifdef PNG_USER_MEM_SUPPORTED if (png_ptr != NULL && png_ptr->malloc_fn != NULL) return png_ptr->malloc_fn(png_constcast(png_structrp,png_ptr), size); -# else - PNG_UNUSED(png_ptr) -# endif - /* Use the system malloc */ - return malloc((size_t)/*SAFE*/size); /* checked for truncation above */ + else +#endif + return malloc((size_t)size); /* checked for truncation above */ + } + + else + return NULL; } -#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ - defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) /* This is really here only to work round a spurious warning in GCC 4.6 and 4.7 * that arises because of the checks in png_realloc_array that are repeated in * png_malloc_array. */ static png_voidp png_malloc_array_checked(png_const_structrp png_ptr, int nelements, - size_t element_size) + size_t element_size) { - png_alloc_size_t req = (png_alloc_size_t)nelements; /* known to be > 0 */ + png_alloc_size_t req = nelements; /* known to be > 0 */ if (req <= PNG_SIZE_MAX/element_size) return png_malloc_base(png_ptr, req * element_size); @@ -119,8 +114,7 @@ png_malloc_array_checked(png_const_structrp png_ptr, int nelements, PNG_FUNCTION(png_voidp /* PRIVATE */, png_malloc_array,(png_const_structrp png_ptr, int nelements, - size_t element_size), - PNG_ALLOCATED) + size_t element_size),PNG_ALLOCATED) { if (nelements <= 0 || element_size == 0) png_error(png_ptr, "internal error: array alloc"); @@ -130,8 +124,7 @@ png_malloc_array,(png_const_structrp png_ptr, int nelements, PNG_FUNCTION(png_voidp /* PRIVATE */, png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array, - int old_elements, int add_elements, size_t element_size), - PNG_ALLOCATED) + int old_elements, int add_elements, size_t element_size),PNG_ALLOCATED) { /* These are internal errors: */ if (add_elements <= 0 || element_size == 0 || old_elements < 0 || @@ -144,7 +137,7 @@ png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array, if (add_elements <= INT_MAX - old_elements) { png_voidp new_array = png_malloc_array_checked(png_ptr, - old_elements+add_elements, element_size); + old_elements+add_elements, element_size); if (new_array != NULL) { @@ -155,7 +148,7 @@ png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array, memcpy(new_array, old_array, element_size*(unsigned)old_elements); memset((char*)new_array + element_size*(unsigned)old_elements, 0, - element_size*(unsigned)add_elements); + element_size*(unsigned)add_elements); return new_array; } @@ -163,15 +156,13 @@ png_realloc_array,(png_const_structrp png_ptr, png_const_voidp old_array, return NULL; /* error */ } -#endif /* TEXT || sPLT || STORE_UNKNOWN_CHUNKS */ /* Various functions that have different error handling are derived from this. * png_malloc always exists, but if PNG_USER_MEM_SUPPORTED is defined a separate * function png_malloc_default is also provided. */ PNG_FUNCTION(png_voidp,PNGAPI -png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED) +png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size),PNG_ALLOCATED) { png_voidp ret; @@ -189,7 +180,7 @@ png_malloc,(png_const_structrp png_ptr, png_alloc_size_t size), #ifdef PNG_USER_MEM_SUPPORTED PNG_FUNCTION(png_voidp,PNGAPI png_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED PNG_DEPRECATED) + PNG_ALLOCATED PNG_DEPRECATED) { png_voidp ret; @@ -204,7 +195,7 @@ png_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size), return ret; } -#endif /* USER_MEM */ +#endif /* PNG_USER_MEM_SUPPORTED */ /* This function was added at libpng version 1.2.3. The png_malloc_warn() * function will issue a png_warning and return NULL instead of issuing a @@ -212,7 +203,7 @@ png_malloc_default,(png_const_structrp png_ptr, png_alloc_size_t size), */ PNG_FUNCTION(png_voidp,PNGAPI png_malloc_warn,(png_const_structrp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED) + PNG_ALLOCATED) { if (png_ptr != NULL) { @@ -245,12 +236,11 @@ png_free(png_const_structrp png_ptr, png_voidp ptr) } PNG_FUNCTION(void,PNGAPI -png_free_default,(png_const_structrp png_ptr, png_voidp ptr), - PNG_DEPRECATED) +png_free_default,(png_const_structrp png_ptr, png_voidp ptr),PNG_DEPRECATED) { if (png_ptr == NULL || ptr == NULL) return; -#endif /* USER_MEM */ +#endif /* PNG_USER_MEM_SUPPORTED */ free(ptr); } @@ -260,8 +250,8 @@ png_free_default,(png_const_structrp png_ptr, png_voidp ptr), * of allocating and freeing memory. */ void PNGAPI -png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn) +png_set_mem_fn(png_structrp png_ptr, png_voidp mem_ptr, png_malloc_ptr + malloc_fn, png_free_ptr free_fn) { if (png_ptr != NULL) { @@ -283,5 +273,5 @@ png_get_mem_ptr(png_const_structrp png_ptr) return png_ptr->mem_ptr; } -#endif /* USER_MEM */ -#endif /* READ || WRITE */ +#endif /* PNG_USER_MEM_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pngpread.c b/Windows_Libs/Dev/Render/libpng/pngpread.c index 37aa432..f132ce6 100644 --- a/Windows_Libs/Dev/Render/libpng/pngpread.c +++ b/Windows_Libs/Dev/Render/libpng/pngpread.c @@ -1,9 +1,10 @@ + /* pngpread.c - read a png file in push mode * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.0 [February 14, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -18,37 +19,16 @@ #define PNG_READ_SIG_MODE 0 #define PNG_READ_CHUNK_MODE 1 #define PNG_READ_IDAT_MODE 2 +#define PNG_SKIP_MODE 3 #define PNG_READ_tEXt_MODE 4 #define PNG_READ_zTXt_MODE 5 #define PNG_READ_DONE_MODE 6 #define PNG_READ_iTXt_MODE 7 #define PNG_ERROR_MODE 8 -#define PNG_PUSH_SAVE_BUFFER_IF_FULL \ -if (png_ptr->push_length + 4 > png_ptr->buffer_size) \ - { png_push_save_buffer(png_ptr); return; } -#define PNG_PUSH_SAVE_BUFFER_IF_LT(N) \ -if (png_ptr->buffer_size < N) \ - { png_push_save_buffer(png_ptr); return; } - -#ifdef PNG_READ_INTERLACING_SUPPORTED -/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */ - -/* Start of interlace block */ -static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; -/* Offset to next interlace block */ -static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; -/* Start of interlace block in the y direction */ -static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; -/* Offset to next interlace block in the y direction */ -static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; - -/* TODO: Move these arrays to a common utility module to avoid duplication. */ -#endif - void PNGAPI png_process_data(png_structrp png_ptr, png_inforp info_ptr, - png_bytep buffer, size_t buffer_size) + png_bytep buffer, png_size_t buffer_size) { if (png_ptr == NULL || info_ptr == NULL) return; @@ -61,20 +41,20 @@ png_process_data(png_structrp png_ptr, png_inforp info_ptr, } } -size_t PNGAPI +png_size_t PNGAPI png_process_data_pause(png_structrp png_ptr, int save) { if (png_ptr != NULL) { - /* It's easiest for the caller if we do the save; then the caller doesn't + /* It's easiest for the caller if we do the save, then the caller doesn't * have to supply the same data again: */ - if (save != 0) + if (save) png_push_save_buffer(png_ptr); else { /* This includes any pending saved bytes: */ - size_t remaining = png_ptr->buffer_size; + png_size_t remaining = png_ptr->buffer_size; png_ptr->buffer_size = 0; /* So subtract the saved buffer size, unless all the data @@ -91,14 +71,32 @@ png_process_data_pause(png_structrp png_ptr, int save) png_uint_32 PNGAPI png_process_data_skip(png_structrp png_ptr) { -/* TODO: Deprecate and remove this API. - * Somewhere the implementation of this seems to have been lost, - * or abandoned. It was only to support some internal back-door access - * to png_struct) in libpng-1.4.x. - */ - png_app_warning(png_ptr, -"png_process_data_skip is not implemented in any current version of libpng"); - return 0; + png_uint_32 remaining = 0; + + if (png_ptr != NULL && png_ptr->process_mode == PNG_SKIP_MODE && + png_ptr->skip_length > 0) + { + /* At the end of png_process_data the buffer size must be 0 (see the loop + * above) so we can detect a broken call here: + */ + if (png_ptr->buffer_size != 0) + png_error(png_ptr, + "png_process_data_skip called inside png_process_data"); + + /* If is impossible for there to be a saved buffer at this point - + * otherwise we could not be in SKIP mode. This will also happen if + * png_process_skip is called inside png_process_data (but only very + * rarely.) + */ + if (png_ptr->save_buffer_size != 0) + png_error(png_ptr, "png_process_data_skip called with saved data"); + + remaining = png_ptr->skip_length; + png_ptr->skip_length = 0; + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } + + return remaining; } /* What we do with the incoming data depends on what we were previously @@ -130,6 +128,12 @@ png_process_some_data(png_structrp png_ptr, png_inforp info_ptr) break; } + case PNG_SKIP_MODE: + { + png_push_crc_finish(png_ptr); + break; + } + default: { png_ptr->buffer_size = 0; @@ -147,8 +151,8 @@ png_process_some_data(png_structrp png_ptr, png_inforp info_ptr) void /* PRIVATE */ png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr) { - size_t num_checked = png_ptr->sig_bytes; /* SAFE, does not exceed 8 */ - size_t num_to_check = 8 - num_checked; + png_size_t num_checked = png_ptr->sig_bytes, + num_to_check = 8 - num_checked; if (png_ptr->buffer_size < num_to_check) { @@ -159,10 +163,10 @@ png_push_read_sig(png_structrp png_ptr, png_inforp info_ptr) num_to_check); png_ptr->sig_bytes = (png_byte)(png_ptr->sig_bytes + num_to_check); - if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0) + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) { if (num_checked < 4 && - png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4) != 0) + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) png_error(png_ptr, "Not a PNG file"); else @@ -185,16 +189,29 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) int keep; /* unknown handling method */ #endif - /* First we make sure we have enough data for the 4-byte chunk name - * and the 4-byte chunk length before proceeding with decoding the + /* First we make sure we have enough data for the 4 byte chunk name + * and the 4 byte chunk length before proceeding with decoding the * chunk data. To fully decode each of these chunks, we also make - * sure we have enough data in the buffer for the 4-byte CRC at the + * sure we have enough data in the buffer for the 4 byte CRC at the * end of every chunk (except IDAT, which is handled separately). */ - if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) + if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) { - PNG_PUSH_SAVE_BUFFER_IF_LT(8) - png_ptr->push_length = png_read_chunk_header(png_ptr); + png_byte chunk_length[4]; + png_byte chunk_tag[4]; + + if (png_ptr->buffer_size < 8) + { + png_push_save_buffer(png_ptr); + return; + } + + png_push_fill_buffer(png_ptr, chunk_length, 4); + png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); + png_reset_crc(png_ptr); + png_crc_read(png_ptr, chunk_tag, 4); + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(chunk_tag); + png_check_chunk_name(png_ptr, png_ptr->chunk_name); png_ptr->mode |= PNG_HAVE_CHUNK_HEADER; } @@ -202,39 +219,28 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) if (chunk_name == png_IDAT) { - if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + if (png_ptr->mode & PNG_AFTER_IDAT) png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; /* If we reach an IDAT chunk, this means we have read all of the * header chunks, and we can start reading the image (or if this * is called after the image has been read - we have an error). */ - if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_error(png_ptr, "Missing IHDR before IDAT"); else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - (png_ptr->mode & PNG_HAVE_PLTE) == 0) + !(png_ptr->mode & PNG_HAVE_PLTE)) png_error(png_ptr, "Missing PLTE before IDAT"); - png_ptr->process_mode = PNG_READ_IDAT_MODE; - - if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) - if ((png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) == 0) - if (png_ptr->push_length == 0) - return; - png_ptr->mode |= PNG_HAVE_IDAT; - if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) - png_benign_error(png_ptr, "Too many IDATs found"); - } + if (!(png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + if (png_ptr->push_length == 0) + return; - else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) - { - /* These flags must be set consistently for all non-IDAT chunks, - * including the unknown chunks. - */ - png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT; + if (png_ptr->mode & PNG_AFTER_IDAT) + png_benign_error(png_ptr, "Too many IDATs found"); } if (chunk_name == png_IHDR) @@ -242,14 +248,24 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) if (png_ptr->push_length != 13) png_error(png_ptr, "Invalid IHDR length"); - PNG_PUSH_SAVE_BUFFER_IF_FULL - png_handle_chunk(png_ptr, info_ptr, png_ptr->push_length); + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_IHDR(png_ptr, info_ptr, png_ptr->push_length); } else if (chunk_name == png_IEND) { - PNG_PUSH_SAVE_BUFFER_IF_FULL - png_handle_chunk(png_ptr, info_ptr, png_ptr->push_length); + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_IEND(png_ptr, info_ptr, png_ptr->push_length); png_ptr->process_mode = PNG_READ_DONE_MODE; png_push_have_end(png_ptr, info_ptr); @@ -258,13 +274,28 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { - PNG_PUSH_SAVE_BUFFER_IF_FULL + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, keep); if (chunk_name == png_PLTE) png_ptr->mode |= PNG_HAVE_PLTE; } + #endif + else if (chunk_name == png_PLTE) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_PLTE(png_ptr, info_ptr, png_ptr->push_length); + } else if (chunk_name == png_IDAT) { @@ -278,17 +309,311 @@ png_push_read_chunk(png_structrp png_ptr, png_inforp info_ptr) return; } +#ifdef PNG_READ_gAMA_SUPPORTED + else if (png_ptr->chunk_name == png_gAMA) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_gAMA(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sBIT_SUPPORTED + else if (png_ptr->chunk_name == png_sBIT) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sBIT(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_cHRM_SUPPORTED + else if (png_ptr->chunk_name == png_cHRM) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_cHRM(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sRGB_SUPPORTED + else if (chunk_name == png_sRGB) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sRGB(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_iCCP_SUPPORTED + else if (png_ptr->chunk_name == png_iCCP) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_iCCP(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sPLT_SUPPORTED + else if (chunk_name == png_sPLT) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sPLT(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tRNS_SUPPORTED + else if (chunk_name == png_tRNS) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tRNS(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_bKGD_SUPPORTED + else if (chunk_name == png_bKGD) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_bKGD(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_hIST_SUPPORTED + else if (chunk_name == png_hIST) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_hIST(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_pHYs_SUPPORTED + else if (chunk_name == png_pHYs) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_pHYs(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_oFFs_SUPPORTED + else if (chunk_name == png_oFFs) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_oFFs(png_ptr, info_ptr, png_ptr->push_length); + } +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED + else if (chunk_name == png_pCAL) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_pCAL(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_sCAL_SUPPORTED + else if (chunk_name == png_sCAL) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_sCAL(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tIME_SUPPORTED + else if (chunk_name == png_tIME) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tIME(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_tEXt_SUPPORTED + else if (chunk_name == png_tEXt) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_tEXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_zTXt_SUPPORTED + else if (chunk_name == png_zTXt) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_zTXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif +#ifdef PNG_READ_iTXt_SUPPORTED + else if (chunk_name == png_iTXt) + { + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + + png_handle_iTXt(png_ptr, info_ptr, png_ptr->push_length); + } + +#endif else { - PNG_PUSH_SAVE_BUFFER_IF_FULL - png_handle_chunk(png_ptr, info_ptr, png_ptr->push_length); + if (png_ptr->push_length + 4 > png_ptr->buffer_size) + { + png_push_save_buffer(png_ptr); + return; + } + png_handle_unknown(png_ptr, info_ptr, png_ptr->push_length, + PNG_HANDLE_CHUNK_AS_DEFAULT); } png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; } +void /* PRIVATE */ +png_push_crc_skip(png_structrp png_ptr, png_uint_32 skip) +{ + png_ptr->process_mode = PNG_SKIP_MODE; + png_ptr->skip_length = skip; +} + +void /* PRIVATE */ +png_push_crc_finish(png_structrp png_ptr) +{ + if (png_ptr->skip_length && png_ptr->save_buffer_size) + { + png_size_t save_size = png_ptr->save_buffer_size; + png_uint_32 skip_length = png_ptr->skip_length; + + /* We want the smaller of 'skip_length' and 'save_buffer_size', but + * they are of different types and we don't know which variable has the + * fewest bits. Carefully select the smaller and cast it to the type of + * the larger - this cannot overflow. Do not cast in the following test + * - it will break on either 16 or 64 bit platforms. + */ + if (skip_length < save_size) + save_size = (png_size_t)skip_length; + + else + skip_length = (png_uint_32)save_size; + + png_calculate_crc(png_ptr, png_ptr->save_buffer_ptr, save_size); + + png_ptr->skip_length -= skip_length; + png_ptr->buffer_size -= save_size; + png_ptr->save_buffer_size -= save_size; + png_ptr->save_buffer_ptr += save_size; + } + if (png_ptr->skip_length && png_ptr->current_buffer_size) + { + png_size_t save_size = png_ptr->current_buffer_size; + png_uint_32 skip_length = png_ptr->skip_length; + + /* We want the smaller of 'skip_length' and 'current_buffer_size', here, + * the same problem exists as above and the same solution. + */ + if (skip_length < save_size) + save_size = (png_size_t)skip_length; + + else + skip_length = (png_uint_32)save_size; + + png_calculate_crc(png_ptr, png_ptr->current_buffer_ptr, save_size); + + png_ptr->skip_length -= skip_length; + png_ptr->buffer_size -= save_size; + png_ptr->current_buffer_size -= save_size; + png_ptr->current_buffer_ptr += save_size; + } + if (!png_ptr->skip_length) + { + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + + png_crc_finish(png_ptr, 0); + png_ptr->process_mode = PNG_READ_CHUNK_MODE; + } +} + void PNGCBAPI -png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, size_t length) +png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, png_size_t length) { png_bytep ptr; @@ -296,9 +621,9 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, size_t length) return; ptr = buffer; - if (png_ptr->save_buffer_size != 0) + if (png_ptr->save_buffer_size) { - size_t save_size; + png_size_t save_size; if (length < png_ptr->save_buffer_size) save_size = length; @@ -313,9 +638,9 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, size_t length) png_ptr->save_buffer_size -= save_size; png_ptr->save_buffer_ptr += save_size; } - if (length != 0 && png_ptr->current_buffer_size != 0) + if (length && png_ptr->current_buffer_size) { - size_t save_size; + png_size_t save_size; if (length < png_ptr->current_buffer_size) save_size = length; @@ -333,11 +658,11 @@ png_push_fill_buffer(png_structp png_ptr, png_bytep buffer, size_t length) void /* PRIVATE */ png_push_save_buffer(png_structrp png_ptr) { - if (png_ptr->save_buffer_size != 0) + if (png_ptr->save_buffer_size) { if (png_ptr->save_buffer_ptr != png_ptr->save_buffer) { - size_t i, istop; + png_size_t i, istop; png_bytep sp; png_bytep dp; @@ -352,7 +677,7 @@ png_push_save_buffer(png_structrp png_ptr) if (png_ptr->save_buffer_size + png_ptr->current_buffer_size > png_ptr->save_buffer_max) { - size_t new_max; + png_size_t new_max; png_bytep old_buffer; if (png_ptr->save_buffer_size > PNG_SIZE_MAX - @@ -364,7 +689,7 @@ png_push_save_buffer(png_structrp png_ptr) new_max = png_ptr->save_buffer_size + png_ptr->current_buffer_size + 256; old_buffer = png_ptr->save_buffer; png_ptr->save_buffer = (png_bytep)png_malloc_warn(png_ptr, - (size_t)new_max); + (png_size_t)new_max); if (png_ptr->save_buffer == NULL) { @@ -372,10 +697,7 @@ png_push_save_buffer(png_structrp png_ptr) png_error(png_ptr, "Insufficient memory for save_buffer"); } - if (old_buffer) - memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); - else if (png_ptr->save_buffer_size) - png_error(png_ptr, "save_buffer error"); + memcpy(png_ptr->save_buffer, old_buffer, png_ptr->save_buffer_size); png_free(png_ptr, old_buffer); png_ptr->save_buffer_max = new_max; } @@ -392,7 +714,7 @@ png_push_save_buffer(png_structrp png_ptr) void /* PRIVATE */ png_push_restore_buffer(png_structrp png_ptr, png_bytep buffer, - size_t buffer_length) + png_size_t buffer_length) { png_ptr->current_buffer = buffer; png_ptr->current_buffer_size = buffer_length; @@ -403,13 +725,18 @@ png_push_restore_buffer(png_structrp png_ptr, png_bytep buffer, void /* PRIVATE */ png_push_read_IDAT(png_structrp png_ptr) { - if ((png_ptr->mode & PNG_HAVE_CHUNK_HEADER) == 0) + if (!(png_ptr->mode & PNG_HAVE_CHUNK_HEADER)) { png_byte chunk_length[4]; png_byte chunk_tag[4]; /* TODO: this code can be commoned up with the same code in push_read */ - PNG_PUSH_SAVE_BUFFER_IF_LT(8) + if (png_ptr->buffer_size < 8) + { + png_push_save_buffer(png_ptr); + return; + } + png_push_fill_buffer(png_ptr, chunk_length, 4); png_ptr->push_length = png_get_uint_31(png_ptr, chunk_length); png_reset_crc(png_ptr); @@ -421,7 +748,7 @@ png_push_read_IDAT(png_structrp png_ptr) { png_ptr->process_mode = PNG_READ_CHUNK_MODE; - if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) png_error(png_ptr, "Not enough compressed data"); return; @@ -430,19 +757,19 @@ png_push_read_IDAT(png_structrp png_ptr) png_ptr->idat_size = png_ptr->push_length; } - if (png_ptr->idat_size != 0 && png_ptr->save_buffer_size != 0) + if (png_ptr->idat_size && png_ptr->save_buffer_size) { - size_t save_size = png_ptr->save_buffer_size; + png_size_t save_size = png_ptr->save_buffer_size; png_uint_32 idat_size = png_ptr->idat_size; /* We want the smaller of 'idat_size' and 'current_buffer_size', but they * are of different types and we don't know which variable has the fewest * bits. Carefully select the smaller and cast it to the type of the * larger - this cannot overflow. Do not cast in the following test - it - * will break on either 16-bit or 64-bit platforms. + * will break on either 16 or 64 bit platforms. */ if (idat_size < save_size) - save_size = (size_t)idat_size; + save_size = (png_size_t)idat_size; else idat_size = (png_uint_32)save_size; @@ -457,9 +784,9 @@ png_push_read_IDAT(png_structrp png_ptr) png_ptr->save_buffer_ptr += save_size; } - if (png_ptr->idat_size != 0 && png_ptr->current_buffer_size != 0) + if (png_ptr->idat_size && png_ptr->current_buffer_size) { - size_t save_size = png_ptr->current_buffer_size; + png_size_t save_size = png_ptr->current_buffer_size; png_uint_32 idat_size = png_ptr->idat_size; /* We want the smaller of 'idat_size' and 'current_buffer_size', but they @@ -468,7 +795,7 @@ png_push_read_IDAT(png_structrp png_ptr) * larger - this cannot overflow. */ if (idat_size < save_size) - save_size = (size_t)idat_size; + save_size = (png_size_t)idat_size; else idat_size = (png_uint_32)save_size; @@ -482,10 +809,14 @@ png_push_read_IDAT(png_structrp png_ptr) png_ptr->current_buffer_size -= save_size; png_ptr->current_buffer_ptr += save_size; } - - if (png_ptr->idat_size == 0) + if (!png_ptr->idat_size) { - PNG_PUSH_SAVE_BUFFER_IF_LT(4) + if (png_ptr->buffer_size < 4) + { + png_push_save_buffer(png_ptr); + return; + } + png_crc_finish(png_ptr, 0); png_ptr->mode &= ~PNG_HAVE_CHUNK_HEADER; png_ptr->mode |= PNG_AFTER_IDAT; @@ -495,7 +826,7 @@ png_push_read_IDAT(png_structrp png_ptr) void /* PRIVATE */ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, - size_t buffer_length) + png_size_t buffer_length) { /* The caller checks for a non-zero buffer length. */ if (!(buffer_length > 0) || buffer == NULL) @@ -513,7 +844,7 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, * or the stream marked as finished. */ while (png_ptr->zstream.avail_in > 0 && - (png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) { int ret; @@ -538,7 +869,7 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, * change the current behavior (see comments in inflate.c * for why this doesn't happen at present with zlib 1.2.5). */ - ret = PNG_INFLATE(png_ptr, Z_SYNC_FLUSH); + ret = inflate(&png_ptr->zstream, Z_SYNC_FLUSH); /* Check for any failure before proceeding. */ if (ret != Z_OK && ret != Z_STREAM_END) @@ -555,12 +886,7 @@ png_process_IDAT_data(png_structrp png_ptr, png_bytep buffer, png_warning(png_ptr, "Truncated compressed data in IDAT"); else - { - if (ret == Z_DATA_ERROR) - png_benign_error(png_ptr, "IDAT: ADLER32 checksum mismatch"); - else - png_error(png_ptr, "Decompression error in IDAT"); - } + png_error(png_ptr, "Decompression error in IDAT"); /* Skip the check on unprocessed input */ return; @@ -635,7 +961,7 @@ png_push_process_row(png_structrp png_ptr) memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); #ifdef PNG_READ_TRANSFORMS_SUPPORTED - if (png_ptr->transformations != 0) + if (png_ptr->transformations) png_do_read_transformations(png_ptr, &row_info); #endif @@ -652,16 +978,15 @@ png_push_process_row(png_structrp png_ptr) #ifdef PNG_READ_INTERLACING_SUPPORTED - /* Expand interlaced rows to full size */ - if (png_ptr->interlaced != 0 && - (png_ptr->transformations & PNG_INTERLACE) != 0) + /* Blow up interlaced rows to full size */ + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) { if (png_ptr->pass < 6) png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, - png_ptr->transformations); + png_ptr->transformations); - switch (png_ptr->pass) - { + switch (png_ptr->pass) + { case 0: { int i; @@ -838,12 +1163,33 @@ png_push_process_row(png_structrp png_ptr) void /* PRIVATE */ png_read_push_finish_row(png_structrp png_ptr) { +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[] = {8, 8, 8, 4, 4, 2, 2}; + + /* Height of interlace block. This is not currently used - if you need + * it, uncomment it here and in png.h + static PNG_CONST png_byte png_pass_height[] = {8, 8, 4, 4, 2, 2, 1}; + */ +#endif + png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) return; #ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced != 0) + if (png_ptr->interlaced) { png_ptr->row_number = 0; memset(png_ptr->prev_row, 0, png_ptr->rowbytes + 1); @@ -867,7 +1213,7 @@ png_read_push_finish_row(png_structrp png_ptr) png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; - if ((png_ptr->transformations & PNG_INTERLACE) != 0) + if (png_ptr->transformations & PNG_INTERLACE) break; png_ptr->num_rows = (png_ptr->height + @@ -877,7 +1223,7 @@ png_read_push_finish_row(png_structrp png_ptr) } while (png_ptr->iwidth == 0 || png_ptr->num_rows == 0); } -#endif /* READ_INTERLACING */ +#endif /* PNG_READ_INTERLACING_SUPPORTED */ } void /* PRIVATE */ @@ -899,7 +1245,7 @@ png_push_have_row(png_structrp png_ptr, png_bytep row) { if (png_ptr->row_fn != NULL) (*(png_ptr->row_fn))(png_ptr, row, png_ptr->row_number, - (int)png_ptr->pass); + (int)png_ptr->pass); } #ifdef PNG_READ_INTERLACING_SUPPORTED @@ -915,9 +1261,9 @@ png_progressive_combine_row(png_const_structrp png_ptr, png_bytep old_row, * it must be png_ptr->row_buf+1 */ if (new_row != NULL) - png_combine_row(png_ptr, old_row, 1/*blocky display*/); + png_combine_row(png_ptr, old_row, 1/*display*/); } -#endif /* READ_INTERLACING */ +#endif /* PNG_READ_INTERLACING_SUPPORTED */ void PNGAPI png_set_progressive_read_fn(png_structrp png_ptr, png_voidp progressive_ptr, @@ -938,8 +1284,8 @@ png_voidp PNGAPI png_get_progressive_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) - return NULL; + return (NULL); return png_ptr->io_ptr; } -#endif /* PROGRESSIVE_READ */ +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pngpriv.h b/Windows_Libs/Dev/Render/libpng/pngpriv.h index f91666c..d06284d 100644 --- a/Windows_Libs/Dev/Render/libpng/pngpriv.h +++ b/Windows_Libs/Dev/Render/libpng/pngpriv.h @@ -1,9 +1,12 @@ + /* pngpriv.h - private declarations for use inside libpng * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * For conditions of distribution and use, see copyright notice in png.h + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Last changed in libpng 1.6.2 [April 25, 2013] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -19,20 +22,8 @@ * they should be well aware of the issues that may arise from doing so. */ - -/* pngpriv.h must be included first in each translation unit inside libpng. - * On the other hand, it must not be included at all, directly or indirectly, - * by any application code that uses the libpng API. - */ #ifndef PNGPRIV_H -# define PNGPRIV_H -#else -# error Duplicate inclusion of pngpriv.h; please check the libpng source files -#endif - -#if defined(PNG_H) || defined(PNGCONF_H) || defined(PNGLCONF_H) -# error This file must not be included by applications; please include -#endif +#define PNGPRIV_H /* Feature Test Macros. The following are defined here to ensure that correctly * implemented libraries reveal the APIs libpng needs to build and hide those @@ -46,9 +37,7 @@ * Windows/Visual Studio) there is no effect; the OS specific tests below are * still required (as of 2011-05-02.) */ -#ifndef _POSIX_SOURCE -# define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ -#endif +#define _POSIX_SOURCE 1 /* Just the POSIX 1003.1 and C89 APIs */ #ifndef PNG_VERSION_INFO_ONLY /* Standard library headers not required by png.h: */ @@ -69,6 +58,7 @@ */ #if defined(HAVE_CONFIG_H) && !defined(PNG_NO_CONFIG_H) # include + /* Pick up the definition of 'restrict' from config.h if it was read: */ # define PNG_RESTRICT restrict #endif @@ -78,7 +68,9 @@ * are not internal definitions may be required. This is handled below just * before png.h is included, but load the configuration now if it is available. */ -#include "pnglibconf.h" +#ifndef PNGLCONF_H +# include "pnglibconf.h" +#endif /* Local renames may change non-exported API functions from png.h */ #if defined(PNG_PREFIX) && !defined(PNGPREFIX_H) @@ -96,222 +88,6 @@ # endif #endif -/* Compile time options. - * ===================== - * In a multi-arch build the compiler may compile the code several times for the - * same object module, producing different binaries for different architectures. - * When this happens configure-time setting of the target host options cannot be - * done and this interferes with the handling of the ARM NEON optimizations, and - * possibly other similar optimizations. Put additional tests here; in general - * this is needed when the same option can be changed at both compile time and - * run time depending on the target OS (i.e. iOS vs Android.) - * - * NOTE: symbol prefixing does not pass $(CFLAGS) to the preprocessor, because - * this is not possible with certain compilers (Oracle SUN OS CC), as a result - * it is necessary to ensure that all extern functions that *might* be used - * regardless of $(CFLAGS) get declared in this file. The test on __ARM_NEON__ - * below is one example of this behavior because it is controlled by the - * presence or not of -mfpu=neon on the GCC command line, it is possible to do - * this in $(CC), e.g. "CC=gcc -mfpu=neon", but people who build libpng rarely - * do this. - */ -#ifndef PNG_ARM_NEON_OPT - /* ARM NEON optimizations are being controlled by the compiler settings, - * typically the target FPU. If the FPU has been set to NEON (-mfpu=neon - * with GCC) then the compiler will define __ARM_NEON__ and we can rely - * unconditionally on NEON instructions not crashing, otherwise we must - * disable use of NEON instructions. - * - * NOTE: at present these optimizations depend on 'ALIGNED_MEMORY', so they - * can only be turned on automatically if that is supported too. If - * PNG_ARM_NEON_OPT is set in CPPFLAGS (to >0) then arm/arm_init.c will fail - * to compile with an appropriate #error if ALIGNED_MEMORY has been turned - * off. - * - * Note that gcc-4.9 defines __ARM_NEON instead of the deprecated - * __ARM_NEON__, so we check both variants. - * - * To disable ARM_NEON optimizations entirely, and skip compiling the - * associated assembler code, pass --enable-arm-neon=no to configure - * or put -DPNG_ARM_NEON_OPT=0 in CPPFLAGS. - */ -# if (defined(__ARM_NEON__) || defined(__ARM_NEON)) && \ - defined(PNG_ALIGNED_MEMORY_SUPPORTED) -# define PNG_ARM_NEON_OPT 2 -# else -# define PNG_ARM_NEON_OPT 0 -# endif -#endif - -#ifndef PNG_RISCV_RVV_OPT - /* RISCV_RVV optimizations are being controlled by the compiler settings, - * typically the target compiler will define __riscv but the rvv extension - * availability has to be explicitly stated. This is why if no - * PNG_RISCV_RVV_OPT was defined then a runtime check will be executed. - * - * To enable RISCV_RVV optimizations unconditionally, and compile the - * associated code, pass --enable-riscv-rvv=yes or --enable-riscv-rvv=on - * to configure or put -DPNG_RISCV_RVV_OPT=2 in CPPFLAGS. - */ - -# define PNG_RISCV_RVV_OPT 0 -#endif - -#if PNG_ARM_NEON_OPT > 0 - /* NEON optimizations are to be at least considered by libpng, so enable the - * callbacks to do this. - */ -# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_neon -# ifndef PNG_ARM_NEON_IMPLEMENTATION - /* Use the intrinsics code by default. */ -# define PNG_ARM_NEON_IMPLEMENTATION 1 -# endif -#else /* PNG_ARM_NEON_OPT == 0 */ -# define PNG_ARM_NEON_IMPLEMENTATION 0 -#endif /* PNG_ARM_NEON_OPT > 0 */ - -#ifndef PNG_MIPS_MSA_OPT -# if defined(__mips_msa) && (__mips_isa_rev >= 5) && \ - defined(PNG_ALIGNED_MEMORY_SUPPORTED) -# define PNG_MIPS_MSA_OPT 2 -# else -# define PNG_MIPS_MSA_OPT 0 -# endif -#endif - -#ifndef PNG_MIPS_MMI_OPT -# ifdef PNG_MIPS_MMI -# if defined(__mips_loongson_mmi) && (_MIPS_SIM == _ABI64) && \ - defined(PNG_ALIGNED_MEMORY_SUPPORTED) -# define PNG_MIPS_MMI_OPT 1 -# else -# define PNG_MIPS_MMI_OPT 0 -# endif -# else -# define PNG_MIPS_MMI_OPT 0 -# endif -#endif - -#ifndef PNG_POWERPC_VSX_OPT -# if defined(__PPC64__) && defined(__ALTIVEC__) && defined(__VSX__) -# define PNG_POWERPC_VSX_OPT 2 -# else -# define PNG_POWERPC_VSX_OPT 0 -# endif -#endif - -#ifndef PNG_LOONGARCH_LSX_OPT -# if defined(__loongarch_sx) -# define PNG_LOONGARCH_LSX_OPT 1 -# else -# define PNG_LOONGARCH_LSX_OPT 0 -# endif -#endif - -#ifndef PNG_INTEL_SSE_OPT -# ifdef PNG_INTEL_SSE - /* Only check for SSE if the build configuration has been modified to - * enable SSE optimizations. This means that these optimizations will - * be off by default. See contrib/intel for more details. - */ -# if defined(__SSE4_1__) || defined(__AVX__) || defined(__SSSE3__) || \ - defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \ - (defined(_M_IX86_FP) && _M_IX86_FP >= 2) -# define PNG_INTEL_SSE_OPT 1 -# else -# define PNG_INTEL_SSE_OPT 0 -# endif -# else -# define PNG_INTEL_SSE_OPT 0 -# endif -#endif - -#if PNG_INTEL_SSE_OPT > 0 -# ifndef PNG_INTEL_SSE_IMPLEMENTATION -# if defined(__SSE4_1__) || defined(__AVX__) - /* We are not actually using AVX, but checking for AVX is the best - way we can detect SSE4.1 and SSSE3 on MSVC. - */ -# define PNG_INTEL_SSE_IMPLEMENTATION 3 -# elif defined(__SSSE3__) -# define PNG_INTEL_SSE_IMPLEMENTATION 2 -# elif defined(__SSE2__) || defined(_M_X64) || defined(_M_AMD64) || \ - (defined(_M_IX86_FP) && _M_IX86_FP >= 2) -# define PNG_INTEL_SSE_IMPLEMENTATION 1 -# else -# define PNG_INTEL_SSE_IMPLEMENTATION 0 -# endif -# endif - -# if PNG_INTEL_SSE_IMPLEMENTATION > 0 -# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_sse2 -# endif -#else -# define PNG_INTEL_SSE_IMPLEMENTATION 0 -#endif - -#if PNG_MIPS_MSA_OPT > 0 -# ifndef PNG_MIPS_MSA_IMPLEMENTATION -# if defined(__mips_msa) -# if defined(__clang__) -# elif defined(__GNUC__) -# if __GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 7) -# define PNG_MIPS_MSA_IMPLEMENTATION 2 -# endif /* no GNUC support */ -# endif /* __GNUC__ */ -# else /* !defined __mips_msa */ -# define PNG_MIPS_MSA_IMPLEMENTATION 2 -# endif /* __mips_msa */ -# endif /* !PNG_MIPS_MSA_IMPLEMENTATION */ - -# ifndef PNG_MIPS_MSA_IMPLEMENTATION -# define PNG_MIPS_MSA_IMPLEMENTATION 1 -# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_mips -# endif -#else -# define PNG_MIPS_MSA_IMPLEMENTATION 0 -#endif /* PNG_MIPS_MSA_OPT > 0 */ - -#if PNG_MIPS_MMI_OPT > 0 -# ifndef PNG_MIPS_MMI_IMPLEMENTATION -# if defined(__mips_loongson_mmi) && (_MIPS_SIM == _ABI64) -# define PNG_MIPS_MMI_IMPLEMENTATION 2 -# else /* !defined __mips_loongson_mmi || _MIPS_SIM != _ABI64 */ -# define PNG_MIPS_MMI_IMPLEMENTATION 0 -# endif /* __mips_loongson_mmi && _MIPS_SIM == _ABI64 */ -# endif /* !PNG_MIPS_MMI_IMPLEMENTATION */ - -# if PNG_MIPS_MMI_IMPLEMENTATION > 0 -# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_mips -# endif -#else -# define PNG_MIPS_MMI_IMPLEMENTATION 0 -#endif /* PNG_MIPS_MMI_OPT > 0 */ - -#if PNG_POWERPC_VSX_OPT > 0 -# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_vsx -# define PNG_POWERPC_VSX_IMPLEMENTATION 1 -#else -# define PNG_POWERPC_VSX_IMPLEMENTATION 0 -#endif - -#if PNG_LOONGARCH_LSX_OPT > 0 -# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_lsx -# define PNG_LOONGARCH_LSX_IMPLEMENTATION 1 -#else -# define PNG_LOONGARCH_LSX_IMPLEMENTATION 0 -#endif - -#if PNG_RISCV_RVV_OPT > 0 && __riscv_v >= 1000000 -# define PNG_FILTER_OPTIMIZATIONS png_init_filter_functions_rvv -# ifndef PNG_RISCV_RVV_IMPLEMENTATION - /* Use the intrinsics code by default. */ -# define PNG_RISCV_RVV_IMPLEMENTATION 1 -# endif -#else -# define PNG_RISCV_RVV_IMPLEMENTATION 0 -#endif /* PNG_RISCV_RVV_OPT > 0 && __riscv_v >= 1000000 */ - /* Is this a build of a DLL where compilation of the object modules requires * different preprocessor settings to those required for a simple library? If * so PNG_BUILD_DLL must be set. @@ -382,18 +158,12 @@ * always be used to declare an extern data or function object in this file. */ #ifndef PNG_INTERNAL_DATA -# define PNG_INTERNAL_DATA(type, name, array) PNG_LINKAGE_DATA type name array +# define PNG_INTERNAL_DATA(type, name, array) extern type name array #endif #ifndef PNG_INTERNAL_FUNCTION # define PNG_INTERNAL_FUNCTION(type, name, args, attributes)\ - PNG_LINKAGE_FUNCTION PNG_FUNCTION(type, name, args, PNG_EMPTY attributes) -#endif - -#ifndef PNG_INTERNAL_CALLBACK -# define PNG_INTERNAL_CALLBACK(type, name, args, attributes)\ - PNG_LINKAGE_CALLBACK PNG_FUNCTION(type, (PNGCBAPI name), args,\ - PNG_EMPTY attributes) + extern PNG_FUNCTION(type, name, args, PNG_EMPTY attributes) #endif /* If floating or fixed point APIs are disabled they may still be compiled @@ -431,27 +201,48 @@ # define PNG_DLL_EXPORT #endif -/* This is a global switch to set the compilation for an installed system - * (a release build). It can be set for testing debug builds to ensure that - * they will compile when the build type is switched to RC or STABLE, the - * default is just to use PNG_LIBPNG_BUILD_BASE_TYPE. Set this in CPPFLAGS - * with either: - * - * -DPNG_RELEASE_BUILD Turns on the release compile path - * -DPNG_RELEASE_BUILD=0 Turns it off - * or in your pngusr.h with - * #define PNG_RELEASE_BUILD=1 Turns on the release compile path - * #define PNG_RELEASE_BUILD=0 Turns it off - */ -#ifndef PNG_RELEASE_BUILD -# define PNG_RELEASE_BUILD (PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC) -#endif - /* SECURITY and SAFETY: * - * libpng is built with support for internal limits on image dimensions and - * memory usage. These are documented in scripts/pnglibconf.dfa of the - * source and recorded in the machine generated header file pnglibconf.h. + * By default libpng is built without any internal limits on image size, + * individual heap (png_malloc) allocations or the total amount of memory used. + * If PNG_SAFE_LIMITS_SUPPORTED is defined, however, the limits below are used + * (unless individually overridden). These limits are believed to be fairly + * safe, but builders of secure systems should verify the values against the + * real system capabilities. + */ +#ifdef PNG_SAFE_LIMITS_SUPPORTED + /* 'safe' limits */ +# ifndef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 1000000 +# endif +# ifndef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 1000000 +# endif +# ifndef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 128 +# endif +# ifndef PNG_USER_CHUNK_MALLOC_MAX +# define PNG_USER_CHUNK_MALLOC_MAX 8000000 +# endif +#else + /* values for no limits */ +# ifndef PNG_USER_WIDTH_MAX +# define PNG_USER_WIDTH_MAX 0x7fffffff +# endif +# ifndef PNG_USER_HEIGHT_MAX +# define PNG_USER_HEIGHT_MAX 0x7fffffff +# endif +# ifndef PNG_USER_CHUNK_CACHE_MAX +# define PNG_USER_CHUNK_CACHE_MAX 0 +# endif +# ifndef PNG_USER_CHUNK_MALLOC_MAX +# define PNG_USER_CHUNK_MALLOC_MAX 0 +# endif +#endif + +/* Moved to pngpriv.h at libpng-1.5.0 */ +/* NOTE: some of these may have been used in external applications as + * these definitions were exposed in pngconf.h prior to 1.5. */ /* If you are running on a machine where you cannot allocate more @@ -494,6 +285,8 @@ #ifdef PNG_WARNINGS_SUPPORTED # define PNG_WARNING_PARAMETERS(p) png_warning_parameters p; #else +# define png_warning(s1,s2) ((void)(s1)) +# define png_chunk_warning(s1,s2) ((void)(s1)) # define png_warning_parameter(p,number,string) ((void)0) # define png_warning_parameter_unsigned(p,number,format,value) ((void)0) # define png_warning_parameter_signed(p,number,format,value) ((void)0) @@ -501,24 +294,11 @@ # define PNG_WARNING_PARAMETERS(p) #endif #ifndef PNG_ERROR_TEXT_SUPPORTED +# define png_error(s1,s2) png_err(s1) +# define png_chunk_error(s1,s2) png_err(s1) # define png_fixed_error(s1,s2) png_err(s1) #endif -/* Some fixed point APIs are still required even if not exported because - * they get used by the corresponding floating point APIs. This magic - * deals with this: - */ -#ifdef PNG_FIXED_POINT_SUPPORTED -# define PNGFAPI PNGAPI -#else -# define PNGFAPI /* PRIVATE */ -#endif - -#ifndef PNG_VERSION_INFO_ONLY -/* Other defines specific to compilers can go here. Try to keep - * them inside an appropriate ifdef/endif pair for portability. - */ - /* C allows up-casts from (void*) to any pointer and (const void*) to any * pointer to a const object. C++ regards this as a type error and requires an * explicit, static, cast and provides the static_cast<> rune to ensure that @@ -533,11 +313,25 @@ static_cast(static_cast(value)) #else # define png_voidcast(type, value) (value) -# define png_constcast(type, value) ((type)(void*)(const void*)(value)) +# define png_constcast(type, value) ((type)(value)) # define png_aligncast(type, value) ((void*)(value)) # define png_aligncastconst(type, value) ((const void*)(value)) #endif /* __cplusplus */ +/* Some fixed point APIs are still required even if not exported because + * they get used by the corresponding floating point APIs. This magic + * deals with this: + */ +#ifdef PNG_FIXED_POINT_SUPPORTED +# define PNGFAPI PNGAPI +#else +# define PNGFAPI /* PRIVATE */ +#endif + +#ifndef PNG_VERSION_INFO_ONLY +/* Other defines specific to compilers can go here. Try to keep + * them inside an appropriate ifdef/endif pair for portability. + */ #if defined(PNG_FLOATING_POINT_SUPPORTED) ||\ defined(PNG_FLOATING_ARITHMETIC_SUPPORTED) /* png.c requires the following ANSI-C constants if the conversion of @@ -549,12 +343,22 @@ */ # include -# include - +# if (defined(__MWERKS__) && defined(macintosh)) || defined(applec) || \ + defined(THINK_C) || defined(__SC__) || defined(TARGET_OS_MAC) + /* We need to check that hasn't already been included earlier + * as it seems it doesn't agree with , yet we should really use + * if possible. + */ +# if !defined(__MATH_H__) && !defined(__MATH_H) && !defined(__cmath__) +# include +# endif +# else +# include +# endif # if defined(_AMIGA) && defined(__SASC) && defined(_M68881) - /* Amiga SAS/C: We must include builtin FPU functions when compiling using - * MATH=68881 - */ + /* Amiga SAS/C: We must include builtin FPU functions when compiling using + * MATH=68881 + */ # include # endif #endif @@ -565,8 +369,9 @@ # include #endif -#if defined(_WIN32) || defined(__WIN32__) || defined(__NT__) -# include +#if defined(WIN32) || defined(_Windows) || defined(_WINDOWS) || \ + defined(_WIN32) || defined(__WIN32__) +# include /* defines _WINDOWS_ macro */ #endif #endif /* PNG_VERSION_INFO_ONLY */ @@ -575,20 +380,24 @@ * functions that are passed far data must be model-independent. */ -/* Platform-independent functions */ +/* Memory model/platform independent fns */ #ifndef PNG_ABORT -# define PNG_ABORT() abort() +# ifdef _WINDOWS_ +# define PNG_ABORT() ExitProcess(0) +# else +# define PNG_ABORT() abort() +# endif #endif /* These macros may need to be architecture dependent. */ -#define PNG_ALIGN_NONE 0 /* do not use data alignment */ -#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */ +#define PNG_ALIGN_NONE 0 /* do not use data alignment */ +#define PNG_ALIGN_ALWAYS 1 /* assume unaligned accesses are OK */ #ifdef offsetof -# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */ +# define PNG_ALIGN_OFFSET 2 /* use offsetof to determine alignment */ #else # define PNG_ALIGN_OFFSET -1 /* prevent the use of this */ #endif -#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */ +#define PNG_ALIGN_SIZE 3 /* use sizeof to determine alignment */ #ifndef PNG_ALIGN_TYPE /* Default to using aligned access optimizations and requiring alignment to a @@ -602,25 +411,25 @@ /* This is used because in some compiler implementations non-aligned * structure members are supported, so the offsetof approach below fails. * Set PNG_ALIGN_SIZE=0 for compiler combinations where unaligned access - * is good for performance. Do not do this unless you have tested the - * result and understand it. + * is good for performance. Do not do this unless you have tested the result + * and understand it. */ -# define png_alignof(type) (sizeof(type)) +# define png_alignof(type) (sizeof (type)) #else # if PNG_ALIGN_TYPE == PNG_ALIGN_OFFSET -# define png_alignof(type) offsetof(struct{char c; type t;}, t) +# define png_alignof(type) offsetof(struct{char c; type t;}, t) # else -# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS -# define png_alignof(type) 1 -# endif - /* Else leave png_alignof undefined to prevent use thereof */ +# if PNG_ALIGN_TYPE == PNG_ALIGN_ALWAYS +# define png_alignof(type) (1) +# endif + /* Else leave png_alignof undefined to prevent use thereof */ # endif #endif -/* This implicitly assumes alignment is always a multiple of 2. */ +/* This implicitly assumes alignment is always to a power of 2. */ #ifdef png_alignof -# define png_isaligned(ptr, type) \ - (((type)(size_t)((const void*)(ptr)) & (type)(png_alignof(type)-1)) == 0) +# define png_isaligned(ptr, type)\ + ((((const char*)ptr-(const char*)0) & (png_alignof(type)-1)) == 0) #else # define png_isaligned(ptr, type) 0 #endif @@ -637,92 +446,96 @@ * are defined in png.h because they need to be visible to applications * that call png_set_unknown_chunk(). */ -/* #define PNG_HAVE_IHDR 0x01U (defined in png.h) */ -/* #define PNG_HAVE_PLTE 0x02U (defined in png.h) */ -#define PNG_HAVE_IDAT 0x04U -/* #define PNG_AFTER_IDAT 0x08U (defined in png.h) */ -#define PNG_HAVE_IEND 0x10U - /* 0x20U (unused) */ - /* 0x40U (unused) */ - /* 0x80U (unused) */ -#define PNG_HAVE_CHUNK_HEADER 0x100U -#define PNG_WROTE_tIME 0x200U -#define PNG_WROTE_INFO_BEFORE_PLTE 0x400U -#define PNG_BACKGROUND_IS_GRAY 0x800U -#define PNG_HAVE_PNG_SIGNATURE 0x1000U -#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000U /* Have another chunk after IDAT */ -#define PNG_WROTE_eXIf 0x4000U -#define PNG_IS_READ_STRUCT 0x8000U /* Else is a write struct */ +/* #define PNG_HAVE_IHDR 0x01 (defined in png.h) */ +/* #define PNG_HAVE_PLTE 0x02 (defined in png.h) */ +#define PNG_HAVE_IDAT 0x04 +/* #define PNG_AFTER_IDAT 0x08 (defined in png.h) */ +#define PNG_HAVE_IEND 0x10 + /* 0x20 (unused) */ + /* 0x40 (unused) */ + /* 0x80 (unused) */ +#define PNG_HAVE_CHUNK_HEADER 0x100 +#define PNG_WROTE_tIME 0x200 +#define PNG_WROTE_INFO_BEFORE_PLTE 0x400 +#define PNG_BACKGROUND_IS_GRAY 0x800 +#define PNG_HAVE_PNG_SIGNATURE 0x1000 +#define PNG_HAVE_CHUNK_AFTER_IDAT 0x2000 /* Have another chunk after IDAT */ + /* 0x4000 (unused) */ +#define PNG_IS_READ_STRUCT 0x8000 /* Else is a write struct */ /* Flags for the transformations the PNG library does on the image data */ -#define PNG_BGR 0x0001U -#define PNG_INTERLACE 0x0002U -#define PNG_PACK 0x0004U -#define PNG_SHIFT 0x0008U -#define PNG_SWAP_BYTES 0x0010U -#define PNG_INVERT_MONO 0x0020U -#define PNG_QUANTIZE 0x0040U -#define PNG_COMPOSE 0x0080U /* Was PNG_BACKGROUND */ -#define PNG_BACKGROUND_EXPAND 0x0100U -#define PNG_EXPAND_16 0x0200U /* Added to libpng 1.5.2 */ -#define PNG_16_TO_8 0x0400U /* Becomes 'chop' in 1.5.4 */ -#define PNG_RGBA 0x0800U -#define PNG_EXPAND 0x1000U -#define PNG_GAMMA 0x2000U -#define PNG_GRAY_TO_RGB 0x4000U -#define PNG_FILLER 0x8000U -#define PNG_PACKSWAP 0x10000U -#define PNG_SWAP_ALPHA 0x20000U -#define PNG_STRIP_ALPHA 0x40000U -#define PNG_INVERT_ALPHA 0x80000U -#define PNG_USER_TRANSFORM 0x100000U -#define PNG_RGB_TO_GRAY_ERR 0x200000U -#define PNG_RGB_TO_GRAY_WARN 0x400000U -#define PNG_RGB_TO_GRAY 0x600000U /* two bits, RGB_TO_GRAY_ERR|WARN */ -#define PNG_ENCODE_ALPHA 0x800000U /* Added to libpng-1.5.4 */ -#define PNG_ADD_ALPHA 0x1000000U /* Added to libpng-1.2.7 */ -#define PNG_EXPAND_tRNS 0x2000000U /* Added to libpng-1.2.9 */ -#define PNG_SCALE_16_TO_8 0x4000000U /* Added to libpng-1.5.4 */ - /* 0x8000000U unused */ - /* 0x10000000U unused */ - /* 0x20000000U unused */ - /* 0x40000000U unused */ +#define PNG_BGR 0x0001 +#define PNG_INTERLACE 0x0002 +#define PNG_PACK 0x0004 +#define PNG_SHIFT 0x0008 +#define PNG_SWAP_BYTES 0x0010 +#define PNG_INVERT_MONO 0x0020 +#define PNG_QUANTIZE 0x0040 +#define PNG_COMPOSE 0x0080 /* Was PNG_BACKGROUND */ +#define PNG_BACKGROUND_EXPAND 0x0100 +#define PNG_EXPAND_16 0x0200 /* Added to libpng 1.5.2 */ +#define PNG_16_TO_8 0x0400 /* Becomes 'chop' in 1.5.4 */ +#define PNG_RGBA 0x0800 +#define PNG_EXPAND 0x1000 +#define PNG_GAMMA 0x2000 +#define PNG_GRAY_TO_RGB 0x4000 +#define PNG_FILLER 0x8000 +#define PNG_PACKSWAP 0x10000 +#define PNG_SWAP_ALPHA 0x20000 +#define PNG_STRIP_ALPHA 0x40000 +#define PNG_INVERT_ALPHA 0x80000 +#define PNG_USER_TRANSFORM 0x100000 +#define PNG_RGB_TO_GRAY_ERR 0x200000 +#define PNG_RGB_TO_GRAY_WARN 0x400000 +#define PNG_RGB_TO_GRAY 0x600000 /* two bits, RGB_TO_GRAY_ERR|WARN */ +#define PNG_ENCODE_ALPHA 0x800000 /* Added to libpng-1.5.4 */ +#define PNG_ADD_ALPHA 0x1000000 /* Added to libpng-1.2.7 */ +#define PNG_EXPAND_tRNS 0x2000000 /* Added to libpng-1.2.9 */ +#define PNG_SCALE_16_TO_8 0x4000000 /* Added to libpng-1.5.4 */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ /* Flags for png_create_struct */ -#define PNG_STRUCT_PNG 0x0001U -#define PNG_STRUCT_INFO 0x0002U +#define PNG_STRUCT_PNG 0x0001 +#define PNG_STRUCT_INFO 0x0002 + +/* Scaling factor for filter heuristic weighting calculations */ +#define PNG_WEIGHT_FACTOR (1<<(PNG_WEIGHT_SHIFT)) +#define PNG_COST_FACTOR (1<<(PNG_COST_SHIFT)) /* Flags for the png_ptr->flags rather than declaring a byte for each one */ -#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001U -#define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002U /* Added to libpng-1.6.0 */ - /* 0x0004U unused */ -#define PNG_FLAG_ZSTREAM_ENDED 0x0008U /* Added to libpng-1.6.0 */ - /* 0x0010U unused */ - /* 0x0020U unused */ -#define PNG_FLAG_ROW_INIT 0x0040U -#define PNG_FLAG_FILLER_AFTER 0x0080U -#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100U -#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200U -#define PNG_FLAG_CRC_CRITICAL_USE 0x0400U -#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800U -/* PNG_FLAG_ASSUME_sRGB unused 0x1000U * Added to libpng-1.5.4 */ -#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000U /* Added to libpng-1.5.4 */ -#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000U /* Added to libpng-1.5.4 */ -/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000U */ -/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000U */ -#define PNG_FLAG_LIBRARY_MISMATCH 0x20000U - /* 0x40000U unused */ -#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000U -#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000U /* Added to libpng-1.4.0 */ -#define PNG_FLAG_APP_WARNINGS_WARN 0x200000U /* Added to libpng-1.6.0 */ -#define PNG_FLAG_APP_ERRORS_WARN 0x400000U /* Added to libpng-1.6.0 */ - /* 0x800000U unused */ - /* 0x1000000U unused */ - /* 0x2000000U unused */ - /* 0x4000000U unused */ - /* 0x8000000U unused */ - /* 0x10000000U unused */ - /* 0x20000000U unused */ - /* 0x40000000U unused */ +#define PNG_FLAG_ZLIB_CUSTOM_STRATEGY 0x0001 +#define PNG_FLAG_ZSTREAM_INITIALIZED 0x0002 /* Added to libpng-1.6.0 */ + /* 0x0004 unused */ +#define PNG_FLAG_ZSTREAM_ENDED 0x0008 /* Added to libpng-1.6.0 */ + /* 0x0010 unused */ + /* 0x0020 unused */ +#define PNG_FLAG_ROW_INIT 0x0040 +#define PNG_FLAG_FILLER_AFTER 0x0080 +#define PNG_FLAG_CRC_ANCILLARY_USE 0x0100 +#define PNG_FLAG_CRC_ANCILLARY_NOWARN 0x0200 +#define PNG_FLAG_CRC_CRITICAL_USE 0x0400 +#define PNG_FLAG_CRC_CRITICAL_IGNORE 0x0800 +#define PNG_FLAG_ASSUME_sRGB 0x1000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_OPTIMIZE_ALPHA 0x2000 /* Added to libpng-1.5.4 */ +#define PNG_FLAG_DETECT_UNINITIALIZED 0x4000 /* Added to libpng-1.5.4 */ +/* #define PNG_FLAG_KEEP_UNKNOWN_CHUNKS 0x8000 */ +/* #define PNG_FLAG_KEEP_UNSAFE_CHUNKS 0x10000 */ +#define PNG_FLAG_LIBRARY_MISMATCH 0x20000 +#define PNG_FLAG_STRIP_ERROR_NUMBERS 0x40000 +#define PNG_FLAG_STRIP_ERROR_TEXT 0x80000 +#define PNG_FLAG_BENIGN_ERRORS_WARN 0x100000 /* Added to libpng-1.4.0 */ +#define PNG_FLAG_APP_WARNINGS_WARN 0x200000 /* Added to libpng-1.6.0 */ +#define PNG_FLAG_APP_ERRORS_WARN 0x400000 /* Added to libpng-1.6.0 */ + /* 0x800000 unused */ + /* 0x1000000 unused */ + /* 0x2000000 unused */ + /* 0x4000000 unused */ + /* 0x8000000 unused */ + /* 0x10000000 unused */ + /* 0x20000000 unused */ + /* 0x40000000 unused */ #define PNG_FLAG_CRC_ANCILLARY_MASK (PNG_FLAG_CRC_ANCILLARY_USE | \ PNG_FLAG_CRC_ANCILLARY_NOWARN) @@ -753,26 +566,8 @@ /* Added to libpng-1.2.6 JB */ #define PNG_ROWBYTES(pixel_bits, width) \ ((pixel_bits) >= 8 ? \ - ((size_t)(width) * (((size_t)(pixel_bits)) >> 3)) : \ - (( ((size_t)(width) * ((size_t)(pixel_bits))) + 7) >> 3) ) - -/* This returns the number of trailing bits in the last byte of a row, 0 if the - * last byte is completely full of pixels. It is, in principle, (pixel_bits x - * width) % 8, but that would overflow for large 'width'. The second macro is - * the same except that it returns the number of unused bits in the last byte; - * (8-TRAILBITS), but 0 when TRAILBITS is 0. - * - * NOTE: these macros are intended to be self-evidently correct and never - * overflow on the assumption that pixel_bits is in the range 0..255. The - * arguments are evaluated only once and they can be signed (e.g. as a result of - * the integral promotions). The result of the expression always has type - * (png_uint_32), however the compiler always knows it is in the range 0..7. - */ -#define PNG_TRAILBITS(pixel_bits, width) \ - (((pixel_bits) * ((width) % (png_uint_32)8)) % 8) - -#define PNG_PADBITS(pixel_bits, width) \ - ((8 - PNG_TRAILBITS(pixel_bits, width)) % 8) + ((png_size_t)(width) * (((png_size_t)(pixel_bits)) >> 3)) : \ + (( ((png_size_t)(width) * ((png_size_t)(pixel_bits))) + 7) >> 3) ) /* PNG_OUT_OF_RANGE returns true if value is outside the range * ideal-delta..ideal+delta. Each argument is evaluated twice. @@ -799,7 +594,7 @@ /* The fixed point conversion performs range checking and evaluates * its argument multiple times, so must be used with care. The * range checking uses the PNG specification values for a signed - * 32-bit fixed point value except that the values are deliberately + * 32 bit fixed point value except that the values are deliberately * rounded-to-zero to an integral value - 21474 (21474.83 is roughly * (2^31-1) * 100000). 's' is a string that describes the value being * converted. @@ -815,8 +610,6 @@ #ifdef PNG_FIXED_POINT_MACRO_SUPPORTED #define png_fixed(png_ptr, fp, s) ((fp) <= 21474 && (fp) >= -21474 ?\ ((png_fixed_point)(100000 * (fp))) : (png_fixed_error(png_ptr, s),0)) -#define png_fixed_ITU(png_ptr, fp, s) ((fp) <= 214748 && (fp) >= 0 ?\ - ((png_uint_32)(10000 * (fp))) : (png_fixed_error(png_ptr, s),0)) #endif /* else the corresponding function is defined below, inside the scope of the * cplusplus test. @@ -835,103 +628,47 @@ * * PNG_32b correctly produces a value shifted by up to 24 bits, even on * architectures where (int) is only 16 bits. - * - * 1.6.47: PNG_32b was made into a preprocessor evaluable macro by replacing the - * static_cast with a promoting binary operation using a guaranteed 32-bit - * (minimum) unsigned value. */ -#define PNG_32b(b,s) (((0xFFFFFFFFU)&(b)) << (s)) -#define PNG_U32(b1,b2,b3,b4) \ +#define PNG_32b(b,s) ((png_uint_32)(b) << (s)) +#define PNG_CHUNK(b1,b2,b3,b4) \ (PNG_32b(b1,24) | PNG_32b(b2,16) | PNG_32b(b3,8) | PNG_32b(b4,0)) -/* Chunk name validation. When using these macros all the arguments should be - * constants, otherwise code bloat may well occur. The macros are provided - * primarily for use in #if checks. - * - * PNG_32to8 produces a byte value with the right shift; used to extract the - * byte value from a chunk name. - */ -#define PNG_32to8(cn,s) (((cn) >> (s)) & 0xffU) -#define PNG_CN_VALID_UPPER(b) ((b) >= 65 && (b) <= 90) /* upper-case ASCII */ -#define PNG_CN_VALID_ASCII(b) PNG_CN_VALID_UPPER((b) & ~32U) -#define PNG_CHUNK_NAME_VALID(cn) (\ - PNG_CN_VALID_ASCII(PNG_32to8(cn,24)) && /* critical, !ancillary */\ - PNG_CN_VALID_ASCII(PNG_32to8(cn,16)) && /* public, !privately defined */\ - PNG_CN_VALID_UPPER(PNG_32to8(cn, 8)) && /* VALID, !reserved */\ - PNG_CN_VALID_ASCII(PNG_32to8(cn, 0)) /* data-dependent, !copy ok */) - -/* Constants for known chunk types. - * - * MAINTAINERS: If you need to add a chunk, define the name here. - * For historical reasons these constants have the form png_; i.e. - * the prefix is lower case. Please use decimal values as the parameters to - * match the ISO PNG specification and to avoid relying on the C locale - * interpretation of character values. Please keep the list sorted. - * - * Notice that PNG_U32 is used to define a 32-bit value for the 4 byte chunk - * type. In fact the specification does not express chunk types this way, - * however using a 32-bit value means that the chunk type can be read from the - * stream using exactly the same code as used for a 32-bit unsigned value and - * can be examined far more efficiently (using one arithmetic compare). - * - * Prior to 1.5.6 the chunk type constants were expressed as C strings. The - * libpng API still uses strings for 'unknown' chunks and a macro, - * PNG_STRING_FROM_CHUNK, allows a string to be generated if required. Notice - * that for portable code numeric values must still be used; the string "IHDR" - * is not portable and neither is PNG_U32('I', 'H', 'D', 'R'). - * - * In 1.7.0 the definitions will be made public in png.h to avoid having to - * duplicate the same definitions in application code. - */ -#define png_IDAT PNG_U32( 73, 68, 65, 84) -#define png_IEND PNG_U32( 73, 69, 78, 68) -#define png_IHDR PNG_U32( 73, 72, 68, 82) -#define png_PLTE PNG_U32( 80, 76, 84, 69) -#define png_acTL PNG_U32( 97, 99, 84, 76) /* PNGv3: APNG */ -#define png_bKGD PNG_U32( 98, 75, 71, 68) -#define png_cHRM PNG_U32( 99, 72, 82, 77) -#define png_cICP PNG_U32( 99, 73, 67, 80) /* PNGv3 */ -#define png_cLLI PNG_U32( 99, 76, 76, 73) /* PNGv3 */ -#define png_eXIf PNG_U32(101, 88, 73, 102) /* registered July 2017 */ -#define png_fcTL PNG_U32(102, 99, 84, 76) /* PNGv3: APNG */ -#define png_fdAT PNG_U32(102, 100, 65, 84) /* PNGv3: APNG */ -#define png_fRAc PNG_U32(102, 82, 65, 99) /* registered, not defined */ -#define png_gAMA PNG_U32(103, 65, 77, 65) -#define png_gIFg PNG_U32(103, 73, 70, 103) -#define png_gIFt PNG_U32(103, 73, 70, 116) /* deprecated */ -#define png_gIFx PNG_U32(103, 73, 70, 120) -#define png_hIST PNG_U32(104, 73, 83, 84) -#define png_iCCP PNG_U32(105, 67, 67, 80) -#define png_iTXt PNG_U32(105, 84, 88, 116) -#define png_mDCV PNG_U32(109, 68, 67, 86) /* PNGv3 */ -#define png_oFFs PNG_U32(111, 70, 70, 115) -#define png_pCAL PNG_U32(112, 67, 65, 76) -#define png_pHYs PNG_U32(112, 72, 89, 115) -#define png_sBIT PNG_U32(115, 66, 73, 84) -#define png_sCAL PNG_U32(115, 67, 65, 76) -#define png_sPLT PNG_U32(115, 80, 76, 84) -#define png_sRGB PNG_U32(115, 82, 71, 66) -#define png_sTER PNG_U32(115, 84, 69, 82) -#define png_tEXt PNG_U32(116, 69, 88, 116) -#define png_tIME PNG_U32(116, 73, 77, 69) -#define png_tRNS PNG_U32(116, 82, 78, 83) -#define png_zTXt PNG_U32(122, 84, 88, 116) +#define png_IHDR PNG_CHUNK( 73, 72, 68, 82) +#define png_IDAT PNG_CHUNK( 73, 68, 65, 84) +#define png_IEND PNG_CHUNK( 73, 69, 78, 68) +#define png_PLTE PNG_CHUNK( 80, 76, 84, 69) +#define png_bKGD PNG_CHUNK( 98, 75, 71, 68) +#define png_cHRM PNG_CHUNK( 99, 72, 82, 77) +#define png_gAMA PNG_CHUNK(103, 65, 77, 65) +#define png_hIST PNG_CHUNK(104, 73, 83, 84) +#define png_iCCP PNG_CHUNK(105, 67, 67, 80) +#define png_iTXt PNG_CHUNK(105, 84, 88, 116) +#define png_oFFs PNG_CHUNK(111, 70, 70, 115) +#define png_pCAL PNG_CHUNK(112, 67, 65, 76) +#define png_sCAL PNG_CHUNK(115, 67, 65, 76) +#define png_pHYs PNG_CHUNK(112, 72, 89, 115) +#define png_sBIT PNG_CHUNK(115, 66, 73, 84) +#define png_sPLT PNG_CHUNK(115, 80, 76, 84) +#define png_sRGB PNG_CHUNK(115, 82, 71, 66) +#define png_sTER PNG_CHUNK(115, 84, 69, 82) +#define png_tEXt PNG_CHUNK(116, 69, 88, 116) +#define png_tIME PNG_CHUNK(116, 73, 77, 69) +#define png_tRNS PNG_CHUNK(116, 82, 78, 83) +#define png_zTXt PNG_CHUNK(122, 84, 88, 116) /* The following will work on (signed char*) strings, whereas the get_uint_32 * macro will fail on top-bit-set values because of the sign extension. */ #define PNG_CHUNK_FROM_STRING(s)\ - PNG_U32(0xff & (s)[0], 0xff & (s)[1], 0xff & (s)[2], 0xff & (s)[3]) + PNG_CHUNK(0xff&(s)[0], 0xff&(s)[1], 0xff&(s)[2], 0xff&(s)[3]) /* This uses (char), not (png_byte) to avoid warnings on systems where (char) is * signed and the argument is a (char[]) This macro will fail miserably on * systems where (char) is more than 8 bits. */ #define PNG_STRING_FROM_CHUNK(s,c)\ - (void)(((char*)(s))[0]=(char)(((c)>>24) & 0xff), \ - ((char*)(s))[1]=(char)(((c)>>16) & 0xff),\ - ((char*)(s))[2]=(char)(((c)>>8) & 0xff), \ - ((char*)(s))[3]=(char)((c & 0xff))) + (void)(((char*)(s))[0]=(char)((c)>>24), ((char*)(s))[1]=(char)((c)>>16),\ + ((char*)(s))[2]=(char)((c)>>8), ((char*)(s))[3]=(char)((c))) /* Do the same but terminate with a null character. */ #define PNG_CSTRING_FROM_CHUNK(s,c)\ @@ -944,74 +681,11 @@ #define PNG_CHUNK_RESERVED(c) (1 & ((c) >> 13)) #define PNG_CHUNK_SAFE_TO_COPY(c) (1 & ((c) >> 5)) -/* Known chunks. All supported chunks must be listed here. The macro PNG_CHUNK - * contains the four character ASCII name by which the chunk is identified. The - * macro is implemented as required to build tables or switch statements which - * require entries for every known chunk. The macro also contains an index - * value which should be in order (this is checked in png.c). - * - * Notice that "known" does not require "SUPPORTED"; tables should be built in - * such a way that chunks unsupported in a build require no more than the table - * entry (which should be small.) In particular function pointers for - * unsupported chunks should be NULL. - * - * At present these index values are not exported (not part of the public API) - * so can be changed at will. For convenience the names are in lexical sort - * order but with the critical chunks at the start in the order of occurence in - * a PNG. - * - * PNG_INFO_ values do not exist for every one of these chunk handles; for - * example PNG_INFO_{IDAT,IEND,tEXt,iTXt,zTXt} and possibly other chunks in the - * future. - */ -#define PNG_KNOWN_CHUNKS\ - PNG_CHUNK(IHDR, 0)\ - PNG_CHUNK(PLTE, 1)\ - PNG_CHUNK(IDAT, 2)\ - PNG_CHUNK(IEND, 3)\ - PNG_CHUNK(acTL, 4)\ - PNG_CHUNK(bKGD, 5)\ - PNG_CHUNK(cHRM, 6)\ - PNG_CHUNK(cICP, 7)\ - PNG_CHUNK(cLLI, 8)\ - PNG_CHUNK(eXIf, 9)\ - PNG_CHUNK(fcTL, 10)\ - PNG_CHUNK(fdAT, 11)\ - PNG_CHUNK(gAMA, 12)\ - PNG_CHUNK(hIST, 13)\ - PNG_CHUNK(iCCP, 14)\ - PNG_CHUNK(iTXt, 15)\ - PNG_CHUNK(mDCV, 16)\ - PNG_CHUNK(oFFs, 17)\ - PNG_CHUNK(pCAL, 18)\ - PNG_CHUNK(pHYs, 19)\ - PNG_CHUNK(sBIT, 20)\ - PNG_CHUNK(sCAL, 21)\ - PNG_CHUNK(sPLT, 22)\ - PNG_CHUNK(sRGB, 23)\ - PNG_CHUNK(tEXt, 24)\ - PNG_CHUNK(tIME, 25)\ - PNG_CHUNK(tRNS, 26)\ - PNG_CHUNK(zTXt, 27) - /* Gamma values (new at libpng-1.5.4): */ #define PNG_GAMMA_MAC_OLD 151724 /* Assume '1.8' is really 2.2/1.45! */ #define PNG_GAMMA_MAC_INVERSE 65909 #define PNG_GAMMA_sRGB_INVERSE 45455 -/* gamma sanity check. libpng cannot implement gamma transforms outside a - * certain limit because of its use of 16-bit fixed point intermediate values. - * Gamma values that are too large or too small will zap the 16-bit values all - * to 0 or 65535 resulting in an obvious 'bad' image. - * - * In libpng 1.6.0 the limits were changed from 0.07..3 to 0.01..100 to - * accommodate the optimal 16-bit gamma of 36 and its reciprocal. - * - * These are png_fixed_point integral values: - */ -#define PNG_LIB_GAMMA_MIN 1000 -#define PNG_LIB_GAMMA_MAX 10000000 - /* Almost everything below is C specific; the #defines above can be used in * non-C code (so long as it is C-preprocessed) the rest of this stuff cannot. */ @@ -1020,23 +694,7 @@ #include "pngstruct.h" #include "pnginfo.h" -/* Validate the include paths - the include path used to generate pnglibconf.h - * must match that used in the build, or we must be using pnglibconf.h.prebuilt: - */ -#if PNG_ZLIB_VERNUM != 0 && PNG_ZLIB_VERNUM != ZLIB_VERNUM -# error The include path of is incorrect - /* When pnglibconf.h was built, the copy of zlib.h that it used was not the - * same as the one being used here. Considering how libpng makes decisions - * to use the zlib API based on the zlib version number, the -I options must - * match. - * - * A possible cause of this mismatch is that you passed an -I option in - * CFLAGS, which is unlikely to work. All the preprocessor options, and all - * the -I options in particular, should be in CPPFLAGS. - */ -#endif - -/* This is used for 16-bit gamma tables -- only the top level pointers are +/* This is used for 16 bit gamma tables -- only the top level pointers are * const; this could be changed: */ typedef const png_uint_16p * png_const_uint_16pp; @@ -1054,13 +712,12 @@ PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_table, [256]); PNG_INTERNAL_DATA(const png_uint_16, png_sRGB_base, [512]); PNG_INTERNAL_DATA(const png_byte, png_sRGB_delta, [512]); -#define PNG_sRGB_FROM_LINEAR(linear) \ - ((png_byte)(0xff & ((png_sRGB_base[(linear)>>15] \ - + ((((linear) & 0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8))) +#define PNG_sRGB_FROM_LINEAR(linear) ((png_byte)((png_sRGB_base[(linear)>>15] +\ + ((((linear)&0x7fff)*png_sRGB_delta[(linear)>>15])>>12)) >> 8)) /* Given a value 'linear' in the range 0..255*65535 calculate the 8-bit sRGB * encoded value with maximum error 0.646365. Note that the input is not a * 16-bit value; it has been multiplied by 255! */ -#endif /* SIMPLIFIED_READ/WRITE */ +#endif /* PNG_SIMPLIFIED_READ/WRITE */ /* Inhibit C++ name-mangling for libpng functions but not for system calls. */ @@ -1073,19 +730,18 @@ extern "C" { * * All of these functions must be declared with PNG_INTERNAL_FUNCTION. */ + /* Zlib support */ #define PNG_UNEXPECTED_ZLIB_RETURN (-7) -PNG_INTERNAL_FUNCTION(void, png_zstream_error, - (png_structrp png_ptr, int ret), +PNG_INTERNAL_FUNCTION(void, png_zstream_error,(png_structrp png_ptr, int ret), PNG_EMPTY); /* Used by the zlib handling functions to ensure that z_stream::msg is always * set before they return. */ #ifdef PNG_WRITE_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_free_buffer_list, - (png_structrp png_ptr, png_compression_bufferp *list), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_free_buffer_list,(png_structrp png_ptr, + png_compression_bufferp *list),PNG_EMPTY); /* Free the buffer list used by the compressed write code. */ #endif @@ -1093,75 +749,41 @@ PNG_INTERNAL_FUNCTION(void, png_free_buffer_list, !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ (defined(PNG_gAMA_SUPPORTED) || defined(PNG_cHRM_SUPPORTED) || \ defined(PNG_sCAL_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) || \ - defined(PNG_mDCV_SUPPORTED) || \ defined(PNG_READ_RGB_TO_GRAY_SUPPORTED)) || \ (defined(PNG_sCAL_SUPPORTED) && \ defined(PNG_FLOATING_ARITHMETIC_SUPPORTED)) -PNG_INTERNAL_FUNCTION(png_fixed_point, png_fixed, - (png_const_structrp png_ptr, double fp, png_const_charp text), - PNG_EMPTY); -#endif - -#if defined(PNG_FLOATING_POINT_SUPPORTED) && \ - !defined(PNG_FIXED_POINT_MACRO_SUPPORTED) && \ - (defined(PNG_cLLI_SUPPORTED) || defined(PNG_mDCV_SUPPORTED)) -PNG_INTERNAL_FUNCTION(png_uint_32, png_fixed_ITU, - (png_const_structrp png_ptr, double fp, png_const_charp text), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_fixed_point,png_fixed,(png_const_structrp png_ptr, + double fp, png_const_charp text),PNG_EMPTY); #endif /* Check the user version string for compatibility, returns false if the version * numbers aren't compatible. */ -PNG_INTERNAL_FUNCTION(int, png_user_version_check, - (png_structrp png_ptr, png_const_charp user_png_ver), - PNG_EMPTY); - -#ifdef PNG_READ_SUPPORTED /* should only be used on read */ -/* Security: read limits on the largest allocations while reading a PNG. This - * avoids very large allocations caused by PNG files with damaged or altered - * chunk 'length' fields. - */ -#ifdef PNG_SET_USER_LIMITS_SUPPORTED /* run-time limit */ -# define png_chunk_max(png_ptr) ((png_ptr)->user_chunk_malloc_max) - -#elif PNG_USER_CHUNK_MALLOC_MAX > 0 /* compile-time limit */ -# define png_chunk_max(png_ptr) ((void)png_ptr, PNG_USER_CHUNK_MALLOC_MAX) - -#elif (defined PNG_MAX_MALLOC_64K) /* legacy system limit */ -# define png_chunk_max(png_ptr) ((void)png_ptr, 65536U) - -#else /* modern system limit SIZE_MAX (C99) */ -# define png_chunk_max(png_ptr) ((void)png_ptr, PNG_SIZE_MAX) -#endif -#endif /* READ */ +PNG_INTERNAL_FUNCTION(int,png_user_version_check,(png_structrp png_ptr, + png_const_charp user_png_ver),PNG_EMPTY); /* Internal base allocator - no messages, NULL on failure to allocate. This * does, however, call the application provided allocator and that could call * png_error (although that would be a bug in the application implementation.) */ -PNG_INTERNAL_FUNCTION(png_voidp, png_malloc_base, - (png_const_structrp png_ptr, png_alloc_size_t size), - PNG_ALLOCATED); +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_base,(png_const_structrp png_ptr, + png_alloc_size_t size),PNG_ALLOCATED); #if defined(PNG_TEXT_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) ||\ defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) /* Internal array allocator, outputs no error or warning messages on failure, - * just returns NULL. + * just returns NULL. */ -PNG_INTERNAL_FUNCTION(png_voidp, png_malloc_array, - (png_const_structrp png_ptr, int nelements, size_t element_size), - PNG_ALLOCATED); +PNG_INTERNAL_FUNCTION(png_voidp,png_malloc_array,(png_const_structrp png_ptr, + int nelements, size_t element_size),PNG_ALLOCATED); /* The same but an existing array is extended by add_elements. This function * also memsets the new elements to 0 and copies the old elements. The old * array is not freed or altered. */ -PNG_INTERNAL_FUNCTION(png_voidp, png_realloc_array, - (png_const_structrp png_ptr, - png_const_voidp array, int old_elements, int add_elements, - size_t element_size), - PNG_ALLOCATED); +PNG_INTERNAL_FUNCTION(png_voidp,png_realloc_array,(png_const_structrp png_ptr, + png_const_voidp array, int old_elements, int add_elements, + size_t element_size),PNG_ALLOCATED); #endif /* text, sPLT or unknown chunks */ /* Magic to create a struct when there is no struct to call the user supplied @@ -1170,106 +792,87 @@ PNG_INTERNAL_FUNCTION(png_voidp, png_realloc_array, * restriction so libpng has to assume that the 'free' handler, at least, might * call png_error. */ -PNG_INTERNAL_FUNCTION(png_structp, png_create_png_struct, - (png_const_charp user_png_ver, - png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, - png_voidp mem_ptr, png_malloc_ptr malloc_fn, png_free_ptr free_fn), - PNG_ALLOCATED); +PNG_INTERNAL_FUNCTION(png_structp,png_create_png_struct, + (png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, + png_error_ptr warn_fn, png_voidp mem_ptr, png_malloc_ptr malloc_fn, + png_free_ptr free_fn),PNG_ALLOCATED); /* Free memory from internal libpng struct */ -PNG_INTERNAL_FUNCTION(void, png_destroy_png_struct, - (png_structrp png_ptr), +PNG_INTERNAL_FUNCTION(void,png_destroy_png_struct,(png_structrp png_ptr), PNG_EMPTY); /* Free an allocated jmp_buf (always succeeds) */ -PNG_INTERNAL_FUNCTION(void, png_free_jmpbuf, - (png_structrp png_ptr), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_free_jmpbuf,(png_structrp png_ptr),PNG_EMPTY); /* Function to allocate memory for zlib. PNGAPI is disallowed. */ -PNG_INTERNAL_FUNCTION(voidpf, png_zalloc, - (voidpf png_ptr, uInt items, uInt size), +PNG_INTERNAL_FUNCTION(voidpf,png_zalloc,(voidpf png_ptr, uInt items, uInt size), PNG_ALLOCATED); /* Function to free memory for zlib. PNGAPI is disallowed. */ -PNG_INTERNAL_FUNCTION(void, png_zfree, - (voidpf png_ptr, voidpf ptr), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_zfree,(voidpf png_ptr, voidpf ptr),PNG_EMPTY); /* Next four functions are used internally as callbacks. PNGCBAPI is required * but not PNG_EXPORT. PNGAPI added at libpng version 1.2.3, changed to * PNGCBAPI at 1.5.0 */ -PNG_INTERNAL_FUNCTION(void PNGCBAPI, png_default_read_data, - (png_structp png_ptr, png_bytep data, size_t length), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_read_data,(png_structp png_ptr, + png_bytep data, png_size_t length),PNG_EMPTY); #ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_INTERNAL_FUNCTION(void PNGCBAPI, png_push_fill_buffer, - (png_structp png_ptr, png_bytep buffer, size_t length), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_push_fill_buffer,(png_structp png_ptr, + png_bytep buffer, png_size_t length),PNG_EMPTY); #endif -PNG_INTERNAL_FUNCTION(void PNGCBAPI, png_default_write_data, - (png_structp png_ptr, png_bytep data, size_t length), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_write_data,(png_structp png_ptr, + png_bytep data, png_size_t length),PNG_EMPTY); #ifdef PNG_WRITE_FLUSH_SUPPORTED # ifdef PNG_STDIO_SUPPORTED -PNG_INTERNAL_FUNCTION(void PNGCBAPI, png_default_flush, - (png_structp png_ptr), +PNG_INTERNAL_FUNCTION(void PNGCBAPI,png_default_flush,(png_structp png_ptr), PNG_EMPTY); # endif #endif /* Reset the CRC variable */ -PNG_INTERNAL_FUNCTION(void, png_reset_crc, - (png_structrp png_ptr), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_reset_crc,(png_structrp png_ptr),PNG_EMPTY); /* Write the "data" buffer to whatever output you are using */ -PNG_INTERNAL_FUNCTION(void, png_write_data, - (png_structrp png_ptr, png_const_bytep data, size_t length), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_data,(png_structrp png_ptr, + png_const_bytep data, png_size_t length),PNG_EMPTY); /* Read and check the PNG file signature */ -PNG_INTERNAL_FUNCTION(void, png_read_sig, - (png_structrp png_ptr, png_inforp info_ptr), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); /* Read the chunk header (length + type name) */ -PNG_INTERNAL_FUNCTION(png_uint_32, png_read_chunk_header, - (png_structrp png_ptr), +PNG_INTERNAL_FUNCTION(png_uint_32,png_read_chunk_header,(png_structrp png_ptr), PNG_EMPTY); /* Read data from whatever input you are using into the "data" buffer */ -PNG_INTERNAL_FUNCTION(void, png_read_data, - (png_structrp png_ptr, png_bytep data, size_t length), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_data,(png_structrp png_ptr, png_bytep data, + png_size_t length),PNG_EMPTY); /* Read bytes into buf, and update png_ptr->crc */ -PNG_INTERNAL_FUNCTION(void, png_crc_read, - (png_structrp png_ptr, png_bytep buf, png_uint_32 length), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_crc_read,(png_structrp png_ptr, png_bytep buf, + png_uint_32 length),PNG_EMPTY); /* Read "skip" bytes, read the file crc, and (optionally) verify png_ptr->crc */ -PNG_INTERNAL_FUNCTION(int, png_crc_finish, - (png_structrp png_ptr, png_uint_32 skip), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_crc_finish,(png_structrp png_ptr, + png_uint_32 skip),PNG_EMPTY); + +/* Read the CRC from the file and compare it to the libpng calculated CRC */ +PNG_INTERNAL_FUNCTION(int,png_crc_error,(png_structrp png_ptr),PNG_EMPTY); /* Calculate the CRC over a section of data. Note that we are only * passing a maximum of 64K on systems that have this as a memory limit, * since this is the maximum buffer size we can specify. */ -PNG_INTERNAL_FUNCTION(void, png_calculate_crc, - (png_structrp png_ptr, png_const_bytep ptr, size_t length), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_calculate_crc,(png_structrp png_ptr, + png_const_bytep ptr, png_size_t length),PNG_EMPTY); #ifdef PNG_WRITE_FLUSH_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_flush, - (png_structrp png_ptr), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_flush,(png_structrp png_ptr),PNG_EMPTY); #endif /* Write various chunks */ @@ -1277,193 +880,126 @@ PNG_INTERNAL_FUNCTION(void, png_flush, /* Write the IHDR chunk, and update the png_struct with the necessary * information. */ -PNG_INTERNAL_FUNCTION(void, png_write_IHDR, - (png_structrp png_ptr, - png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, - int compression_method, int filter_method, int interlace_method), +PNG_INTERNAL_FUNCTION(void,png_write_IHDR,(png_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, + int compression_method, int filter_method, int interlace_method),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_write_PLTE,(png_structrp png_ptr, + png_const_colorp palette, png_uint_32 num_pal),PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(void,png_compress_IDAT,(png_structrp png_ptr, + png_const_bytep row_data, png_alloc_size_t row_data_length, int flush), PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_write_PLTE, - (png_structrp png_ptr, - png_const_colorp palette, png_uint_32 num_pal), - PNG_EMPTY); - -PNG_INTERNAL_FUNCTION(void, png_compress_IDAT, - (png_structrp png_ptr, - png_const_bytep row_data, png_alloc_size_t row_data_length, int flush), - PNG_EMPTY); - -PNG_INTERNAL_FUNCTION(void, png_write_IEND, - (png_structrp png_ptr), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_IEND,(png_structrp png_ptr),PNG_EMPTY); #ifdef PNG_WRITE_gAMA_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_gAMA_fixed, - (png_structrp png_ptr, png_fixed_point file_gamma), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_gAMA_fixed,(png_structrp png_ptr, + png_fixed_point file_gamma),PNG_EMPTY); #endif #ifdef PNG_WRITE_sBIT_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_sBIT, - (png_structrp png_ptr, png_const_color_8p sbit, int color_type), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_sBIT,(png_structrp png_ptr, + png_const_color_8p sbit, int color_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_cHRM_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_cHRM_fixed, - (png_structrp png_ptr, const png_xy *xy), - PNG_EMPTY); - /* The xy value must have been previously validated */ -#endif - -#ifdef PNG_WRITE_cICP_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_cICP, - (png_structrp png_ptr, - png_byte colour_primaries, png_byte transfer_function, - png_byte matrix_coefficients, png_byte video_full_range_flag), - PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_cLLI_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_cLLI_fixed, - (png_structrp png_ptr, png_uint_32 maxCLL, png_uint_32 maxFALL), - PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_mDCV_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_mDCV_fixed, - (png_structrp png_ptr, - png_uint_16 red_x, png_uint_16 red_y, - png_uint_16 green_x, png_uint_16 green_y, - png_uint_16 blue_x, png_uint_16 blue_y, - png_uint_16 white_x, png_uint_16 white_y, - png_uint_32 maxDL, png_uint_32 minDL), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_cHRM_fixed,(png_structrp png_ptr, + const png_xy *xy), PNG_EMPTY); + /* The xy value must have been previously validated */ #endif #ifdef PNG_WRITE_sRGB_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_sRGB, - (png_structrp png_ptr, int intent), - PNG_EMPTY); -#endif - -#ifdef PNG_WRITE_eXIf_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_eXIf, - (png_structrp png_ptr, png_bytep exif, int num_exif), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_sRGB,(png_structrp png_ptr, + int intent),PNG_EMPTY); #endif #ifdef PNG_WRITE_iCCP_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_iCCP, - (png_structrp png_ptr, - png_const_charp name, png_const_bytep profile, png_uint_32 proflen), - PNG_EMPTY); - /* Writes a previously 'set' profile. The profile argument is **not** - * compressed. +PNG_INTERNAL_FUNCTION(void,png_write_iCCP,(png_structrp png_ptr, + png_const_charp name, png_const_bytep profile), PNG_EMPTY); + /* The profile must have been previously validated for correctness, the + * length comes from the first four bytes. Only the base, deflate, + * compression is supported. */ #endif #ifdef PNG_WRITE_sPLT_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_sPLT, - (png_structrp png_ptr, png_const_sPLT_tp palette), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_sPLT,(png_structrp png_ptr, + png_const_sPLT_tp palette),PNG_EMPTY); #endif #ifdef PNG_WRITE_tRNS_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_tRNS, - (png_structrp png_ptr, +PNG_INTERNAL_FUNCTION(void,png_write_tRNS,(png_structrp png_ptr, png_const_bytep trans, png_const_color_16p values, int number, - int color_type), - PNG_EMPTY); + int color_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_bKGD_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_bKGD, - (png_structrp png_ptr, png_const_color_16p values, int color_type), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_bKGD,(png_structrp png_ptr, + png_const_color_16p values, int color_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_hIST_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_hIST, - (png_structrp png_ptr, png_const_uint_16p hist, int num_hist), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_hIST,(png_structrp png_ptr, + png_const_uint_16p hist, int num_hist),PNG_EMPTY); #endif /* Chunks that have keywords */ #ifdef PNG_WRITE_tEXt_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_tEXt, - (png_structrp png_ptr, - png_const_charp key, png_const_charp text, size_t text_len), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_tEXt,(png_structrp png_ptr, + png_const_charp key, png_const_charp text, png_size_t text_len),PNG_EMPTY); #endif #ifdef PNG_WRITE_zTXt_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_zTXt, - (png_structrp png_ptr, - png_const_charp key, png_const_charp text, int compression), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_zTXt,(png_structrp png_ptr, png_const_charp + key, png_const_charp text, png_size_t text_len, int compression),PNG_EMPTY); #endif #ifdef PNG_WRITE_iTXt_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_iTXt, - (png_structrp png_ptr, +PNG_INTERNAL_FUNCTION(void,png_write_iTXt,(png_structrp png_ptr, int compression, png_const_charp key, png_const_charp lang, - png_const_charp lang_key, png_const_charp text), - PNG_EMPTY); + png_const_charp lang_key, png_const_charp text),PNG_EMPTY); #endif #ifdef PNG_TEXT_SUPPORTED /* Added at version 1.0.14 and 1.2.4 */ -PNG_INTERNAL_FUNCTION(int, png_set_text_2, - (png_const_structrp png_ptr, - png_inforp info_ptr, png_const_textp text_ptr, int num_text), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_set_text_2,(png_const_structrp png_ptr, + png_inforp info_ptr, png_const_textp text_ptr, int num_text),PNG_EMPTY); #endif #ifdef PNG_WRITE_oFFs_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_oFFs, - (png_structrp png_ptr, - png_int_32 x_offset, png_int_32 y_offset, int unit_type), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_oFFs,(png_structrp png_ptr, + png_int_32 x_offset, png_int_32 y_offset, int unit_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_pCAL_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_pCAL, - (png_structrp png_ptr, - png_charp purpose, png_int_32 X0, png_int_32 X1, - int type, int nparams, png_const_charp units, png_charpp params), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_pCAL,(png_structrp png_ptr, + png_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, + png_const_charp units, png_charpp params),PNG_EMPTY); #endif #ifdef PNG_WRITE_pHYs_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_pHYs, - (png_structrp png_ptr, +PNG_INTERNAL_FUNCTION(void,png_write_pHYs,(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, png_uint_32 y_pixels_per_unit, - int unit_type), - PNG_EMPTY); + int unit_type),PNG_EMPTY); #endif #ifdef PNG_WRITE_tIME_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_tIME, - (png_structrp png_ptr, png_const_timep mod_time), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_tIME,(png_structrp png_ptr, + png_const_timep mod_time),PNG_EMPTY); #endif #ifdef PNG_WRITE_sCAL_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_write_sCAL_s, - (png_structrp png_ptr, - int unit, png_const_charp width, png_const_charp height), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_sCAL_s,(png_structrp png_ptr, + int unit, png_const_charp width, png_const_charp height),PNG_EMPTY); #endif /* Called when finished processing a row of data */ -PNG_INTERNAL_FUNCTION(void, png_write_finish_row, - (png_structrp png_ptr), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_finish_row,(png_structrp png_ptr), + PNG_EMPTY); /* Internal use only. Called before first row of data */ -PNG_INTERNAL_FUNCTION(void, png_write_start_row, - (png_structrp png_ptr), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_start_row,(png_structrp png_ptr), + PNG_EMPTY); /* Combine a row of data, dealing with alpha, etc. if requested. 'row' is an * array of png_ptr->width pixels. If the image is not interlaced or this @@ -1491,9 +1027,8 @@ PNG_INTERNAL_FUNCTION(void, png_write_start_row, #ifndef PNG_USE_COMPILE_TIME_MASKS # define PNG_USE_COMPILE_TIME_MASKS 1 #endif -PNG_INTERNAL_FUNCTION(void, png_combine_row, - (png_const_structrp png_ptr, png_bytep row, int display), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_combine_row,(png_const_structrp png_ptr, + png_bytep row, int display),PNG_EMPTY); #ifdef PNG_READ_INTERLACING_SUPPORTED /* Expand an interlaced row: the 'row_info' describes the pass data that has @@ -1502,439 +1037,507 @@ PNG_INTERNAL_FUNCTION(void, png_combine_row, * the pixels are *replicated* to the intervening space. This is essential for * the correct operation of png_combine_row, above. */ -PNG_INTERNAL_FUNCTION(void, png_do_read_interlace, - (png_row_infop row_info, - png_bytep row, int pass, png_uint_32 transformations), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_read_interlace,(png_row_infop row_info, + png_bytep row, int pass, png_uint_32 transformations),PNG_EMPTY); #endif /* GRR TO DO (2.0 or whenever): simplify other internal calling interfaces */ #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Grab pixels out of a row for an interlaced pass */ -PNG_INTERNAL_FUNCTION(void, png_do_write_interlace, - (png_row_infop row_info, png_bytep row, int pass), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_write_interlace,(png_row_infop row_info, + png_bytep row, int pass),PNG_EMPTY); #endif /* Unfilter a row: check the filter value before calling this, there is no point * calling it for PNG_FILTER_VALUE_NONE. */ -PNG_INTERNAL_FUNCTION(void, png_read_filter_row, - (png_structrp pp, png_row_infop row_info, - png_bytep row, png_const_bytep prev_row, int filter), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row,(png_structrp pp, png_row_infop + row_info, png_bytep row, png_const_bytep prev_row, int filter),PNG_EMPTY); -#if PNG_ARM_NEON_OPT > 0 -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_up_neon, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_neon, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_neon, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_neon, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_neon, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_neon, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_neon, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -#endif - -#if PNG_MIPS_MSA_IMPLEMENTATION == 1 -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_up_msa, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_msa, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_msa, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_msa, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_msa, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_msa, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_msa, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -#endif - -#if PNG_MIPS_MMI_IMPLEMENTATION > 0 -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_up_mmi, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_mmi, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_mmi, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_mmi, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_mmi, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_mmi, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_mmi, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -#endif - -#if PNG_POWERPC_VSX_OPT > 0 -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_up_vsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_vsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_vsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_vsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_vsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_vsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_vsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -#endif - -#if PNG_INTEL_SSE_IMPLEMENTATION > 0 -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_sse2, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_sse2, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_sse2, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_sse2, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_sse2, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_sse2, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -#endif - -#if PNG_LOONGARCH_LSX_IMPLEMENTATION == 1 -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_up_lsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_lsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_lsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_lsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_lsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_lsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_lsx, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -#endif - -#if PNG_RISCV_RVV_IMPLEMENTATION == 1 -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_up_rvv, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub3_rvv, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_sub4_rvv, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg3_rvv, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_avg4_rvv, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth3_rvv, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_filter_row_paeth4_rvv, - (png_row_infop row_info, png_bytep row, png_const_bytep prev_row), - PNG_EMPTY); -#endif +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_up_neon,(png_row_infop row_info, + png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_sub4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_avg4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth3_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_filter_row_paeth4_neon,(png_row_infop + row_info, png_bytep row, png_const_bytep prev_row),PNG_EMPTY); /* Choose the best filter to use and filter the row data */ -PNG_INTERNAL_FUNCTION(void, png_write_find_filter, - (png_structrp png_ptr, png_row_infop row_info), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_write_find_filter,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); #ifdef PNG_SEQUENTIAL_READ_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_read_IDAT_data, - (png_structrp png_ptr, png_bytep output, png_alloc_size_t avail_out), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_IDAT_data,(png_structrp png_ptr, + png_bytep output, png_alloc_size_t avail_out),PNG_EMPTY); /* Read 'avail_out' bytes of data from the IDAT stream. If the output buffer * is NULL the function checks, instead, for the end of the stream. In this * case a benign error will be issued if the stream end is not found or if * extra data has to be consumed. */ -PNG_INTERNAL_FUNCTION(void, png_read_finish_IDAT, - (png_structrp png_ptr), +PNG_INTERNAL_FUNCTION(void,png_read_finish_IDAT,(png_structrp png_ptr), PNG_EMPTY); /* This cleans up when the IDAT LZ stream does not end when the last image * byte is read; there is still some pending input. */ -PNG_INTERNAL_FUNCTION(void, png_read_finish_row, - (png_structrp png_ptr), +PNG_INTERNAL_FUNCTION(void,png_read_finish_row,(png_structrp png_ptr), PNG_EMPTY); /* Finish a row while reading, dealing with interlacing passes, etc. */ -#endif /* SEQUENTIAL_READ */ +#endif /* Initialize the row buffers, etc. */ -PNG_INTERNAL_FUNCTION(void, png_read_start_row, - (png_structrp png_ptr), - PNG_EMPTY); - -#if ZLIB_VERNUM >= 0x1240 -PNG_INTERNAL_FUNCTION(int, png_zlib_inflate, - (png_structrp png_ptr, int flush), - PNG_EMPTY); -# define PNG_INFLATE(pp, flush) png_zlib_inflate(pp, flush) -#else /* Zlib < 1.2.4 */ -# define PNG_INFLATE(pp, flush) inflate(&(pp)->zstream, flush) -#endif /* Zlib < 1.2.4 */ +PNG_INTERNAL_FUNCTION(void,png_read_start_row,(png_structrp png_ptr),PNG_EMPTY); #ifdef PNG_READ_TRANSFORMS_SUPPORTED /* Optional call to update the users info structure */ -PNG_INTERNAL_FUNCTION(void, png_read_transform_info, - (png_structrp png_ptr, png_inforp info_ptr), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_transform_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +#endif + +/* These are the functions that do the transformations */ +#ifdef PNG_READ_FILLER_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_filler,(png_row_infop row_info, + png_bytep row, png_uint_32 filler, png_uint_32 flags),PNG_EMPTY); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_swap_alpha,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_write_swap_alpha,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_invert_alpha,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_write_invert_alpha,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); #endif -/* Shared transform functions, defined in pngtran.c */ #if defined(PNG_WRITE_FILLER_SUPPORTED) || \ defined(PNG_READ_STRIP_ALPHA_SUPPORTED) -PNG_INTERNAL_FUNCTION(void, png_do_strip_channel, - (png_row_infop row_info, png_bytep row, int at_start), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_strip_channel,(png_row_infop row_info, + png_bytep row, int at_start),PNG_EMPTY); #endif #ifdef PNG_16BIT_SUPPORTED #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -PNG_INTERNAL_FUNCTION(void, png_do_swap, - (png_row_infop row_info, png_bytep row), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_swap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); #endif #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED) || \ defined(PNG_WRITE_PACKSWAP_SUPPORTED) -PNG_INTERNAL_FUNCTION(void, png_do_packswap, - (png_row_infop row_info, png_bytep row), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_packswap,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_do_rgb_to_gray,(png_structrp png_ptr, + png_row_infop row_info, png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_gray_to_rgb,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_unpack,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_unshift,(png_row_infop row_info, + png_bytep row, png_const_color_8p sig_bits),PNG_EMPTY); #endif #if defined(PNG_READ_INVERT_SUPPORTED) || defined(PNG_WRITE_INVERT_SUPPORTED) -PNG_INTERNAL_FUNCTION(void, png_do_invert, - (png_row_infop row_info, png_bytep row), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_invert,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_scale_16_to_8,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_chop,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_quantize,(png_row_infop row_info, + png_bytep row, png_const_bytep palette_lookup, + png_const_bytep quantize_lookup),PNG_EMPTY); + +# ifdef PNG_CORRECT_PALETTE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_correct_palette,(png_structrp png_ptr, + png_colorp palette, int num_palette),PNG_EMPTY); +# endif #endif #if defined(PNG_READ_BGR_SUPPORTED) || defined(PNG_WRITE_BGR_SUPPORTED) -PNG_INTERNAL_FUNCTION(void, png_do_bgr, - (png_row_infop row_info, png_bytep row), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_bgr,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_PACK_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_pack,(png_row_infop row_info, + png_bytep row, png_uint_32 bit_depth),PNG_EMPTY); +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_shift,(png_row_infop row_info, + png_bytep row, png_const_color_8p bit_depth),PNG_EMPTY); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) +PNG_INTERNAL_FUNCTION(void,png_do_compose,(png_row_infop row_info, + png_bytep row, png_structrp png_ptr),PNG_EMPTY); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_gamma,(png_row_infop row_info, + png_bytep row, png_structrp png_ptr),PNG_EMPTY); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_encode_alpha,(png_row_infop row_info, + png_bytep row, png_structrp png_ptr),PNG_EMPTY); +#endif + +#ifdef PNG_READ_EXPAND_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_expand_palette,(png_row_infop row_info, + png_bytep row, png_const_colorp palette, png_const_bytep trans, + int num_trans),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_expand,(png_row_infop row_info, + png_bytep row, png_const_color_16p trans_color),PNG_EMPTY); +#endif + +#ifdef PNG_READ_EXPAND_16_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_expand_16,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); #endif /* The following decodes the appropriate chunks, and does error correction, * then calls the appropriate callback for the chunk if it is valid. */ -typedef enum -{ - /* Result of a call to png_handle_chunk made to handle the current chunk - * png_struct::chunk_name on read. Always informational, either the stream - * is read for the next chunk or the routine will call png_error. - * - * NOTE: order is important internally. handled_saved and above are regarded - * as handling the chunk. - */ - handled_error = 0, /* bad crc or known and bad format or too long */ - handled_discarded, /* not saved in the unknown chunk list */ - handled_saved, /* saved in the unknown chunk list */ - handled_ok /* known, supported and handled without error */ -} png_handle_result_code; -PNG_INTERNAL_FUNCTION(png_handle_result_code, png_handle_unknown, - (png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length, int keep), - PNG_EMPTY); +/* Decode the IHDR chunk */ +PNG_INTERNAL_FUNCTION(void,png_handle_IHDR,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_handle_PLTE,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_handle_IEND,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); + +#ifdef PNG_READ_bKGD_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_bKGD,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_cHRM,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_gAMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_gAMA,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_hIST_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_hIST,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_iCCP,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif /* PNG_READ_iCCP_SUPPORTED */ + +#ifdef PNG_READ_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_iTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_oFFs,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_pCAL,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_pHYs,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sBIT,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sCAL,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_sPLT_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sPLT,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif /* PNG_READ_sPLT_SUPPORTED */ + +#ifdef PNG_READ_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_sRGB,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_tEXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_tIME_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_tIME,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_tRNS_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_tRNS,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_zTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +#endif + +PNG_INTERNAL_FUNCTION(void,png_check_chunk_name,(png_structrp png_ptr, + png_uint_32 chunk_name),PNG_EMPTY); + +#ifdef PNG_READ_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_handle_unknown,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length, int keep),PNG_EMPTY); /* This is the function that gets called for unknown chunks. The 'keep' * argument is either non-zero for a known chunk that has been set to be * handled as unknown or zero for an unknown chunk. By default the function * just skips the chunk or errors out if it is critical. */ -PNG_INTERNAL_FUNCTION(png_handle_result_code, png_handle_chunk, - (png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length), - PNG_EMPTY); - /* This handles the current chunk png_ptr->chunk_name with unread - * data[length] and returns one of the above result codes. - */ - -#if defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) ||\ - defined(PNG_HANDLE_AS_UNKNOWN_SUPPORTED) -PNG_INTERNAL_FUNCTION(int, png_chunk_unknown_handling, - (png_const_structrp png_ptr, png_uint_32 chunk_name), - PNG_EMPTY); +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED +#ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_chunk_unknown_handling, + (png_const_structrp png_ptr, png_uint_32 chunk_name),PNG_EMPTY); /* Exactly as the API png_handle_as_unknown() except that the argument is a * 32-bit chunk name, not a string. */ -#endif /* READ_UNKNOWN_CHUNKS || HANDLE_AS_UNKNOWN */ +#endif +#endif /* PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED */ /* Handle the transformations for reading and writing */ #ifdef PNG_READ_TRANSFORMS_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_do_read_transformations, - (png_structrp png_ptr, png_row_infop row_info), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_read_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); #endif #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_do_write_transformations, - (png_structrp png_ptr, png_row_infop row_info), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_write_transformations,(png_structrp png_ptr, + png_row_infop row_info),PNG_EMPTY); #endif #ifdef PNG_READ_TRANSFORMS_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_init_read_transformations, - (png_structrp png_ptr), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_init_read_transformations,(png_structrp png_ptr), + PNG_EMPTY); #endif #ifdef PNG_PROGRESSIVE_READ_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_push_read_chunk, - (png_structrp png_ptr, png_inforp info_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_push_read_sig, - (png_structrp png_ptr, png_inforp info_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_push_check_crc, - (png_structrp png_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_push_save_buffer, - (png_structrp png_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_push_restore_buffer, - (png_structrp png_ptr, png_bytep buffer, size_t buffer_length), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_push_read_IDAT, - (png_structrp png_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_process_IDAT_data, - (png_structrp png_ptr, png_bytep buffer, size_t buffer_length), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_push_process_row, - (png_structrp png_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_push_have_info, - (png_structrp png_ptr, png_inforp info_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_push_have_end, - (png_structrp png_ptr, png_inforp info_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_push_have_row, - (png_structrp png_ptr, png_bytep row), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_push_read_end, - (png_structrp png_ptr, png_inforp info_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_process_some_data, - (png_structrp png_ptr, png_inforp info_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_read_push_finish_row, - (png_structrp png_ptr), - PNG_EMPTY); -#endif /* PROGRESSIVE_READ */ +PNG_INTERNAL_FUNCTION(void,png_push_read_chunk,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_sig,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_check_crc,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_crc_skip,(png_structrp png_ptr, + png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_crc_finish,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_save_buffer,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_restore_buffer,(png_structrp png_ptr, + png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_IDAT,(png_structrp png_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_IDAT_data,(png_structrp png_ptr, + png_bytep buffer, png_size_t buffer_length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_process_row,(png_structrp png_ptr), + PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_handle_unknown,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_info,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_have_row,(png_structrp png_ptr, + png_bytep row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_end,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_process_some_data,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_read_push_finish_row,(png_structrp png_ptr), + PNG_EMPTY); +# ifdef PNG_READ_tEXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_tEXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_tEXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif +# ifdef PNG_READ_zTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_zTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_zTXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif +# ifdef PNG_READ_iTXt_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_push_handle_iTXt,(png_structrp png_ptr, + png_inforp info_ptr, png_uint_32 length),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_push_read_iTXt,(png_structrp png_ptr, + png_inforp info_ptr),PNG_EMPTY); +# endif + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#ifdef PNG_MNG_FEATURES_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_do_read_intrapixel,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_write_intrapixel,(png_row_infop row_info, + png_bytep row),PNG_EMPTY); +#endif + +/* Added at libpng version 1.6.0 */ +#ifdef PNG_GAMMA_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_colorspace_set_gamma,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_fixed_point gAMA), PNG_EMPTY); + /* Set the colorspace gamma with a value provided by the application or by + * the gAMA chunk on read. The value will override anything set by an ICC + * profile. + */ + +PNG_INTERNAL_FUNCTION(void,png_colorspace_sync_info,(png_const_structrp png_ptr, + png_inforp info_ptr), PNG_EMPTY); + /* Synchronize the info 'valid' flags with the colorspace */ + +PNG_INTERNAL_FUNCTION(void,png_colorspace_sync,(png_const_structrp png_ptr, + png_inforp info_ptr), PNG_EMPTY); + /* Copy the png_struct colorspace to the info_struct and call the above to + * synchronize the flags. Checks for NULL info_ptr and does nothing. + */ +#endif + +/* Added at libpng version 1.4.0 */ +#ifdef PNG_COLORSPACE_SUPPORTED +/* These internal functions are for maintaining the colorspace structure within + * a png_info or png_struct (or, indeed, both). + */ +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_chromaticities, + (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_xy *xy, + int preferred), PNG_EMPTY); + +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_endpoints, + (png_const_structrp png_ptr, png_colorspacerp colorspace, const png_XYZ *XYZ, + int preferred), PNG_EMPTY); + +#ifdef PNG_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_sRGB,(png_const_structrp png_ptr, + png_colorspacerp colorspace, int intent), PNG_EMPTY); + /* This does set the colorspace gAMA and cHRM values too, but doesn't set the + * flags to write them, if it returns false there was a problem and an error + * message has already been output (but the colorspace may still need to be + * synced to record the invalid flag). + */ +#endif /* sRGB */ #ifdef PNG_iCCP_SUPPORTED +PNG_INTERNAL_FUNCTION(int,png_colorspace_set_ICC,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, png_const_bytep profile, int color_type), + PNG_EMPTY); + /* The 'name' is used for information only */ + /* Routines for checking parts of an ICC profile. */ -#ifdef PNG_READ_iCCP_SUPPORTED -PNG_INTERNAL_FUNCTION(int, png_icc_check_length, - (png_const_structrp png_ptr, - png_const_charp name, png_uint_32 profile_length), - PNG_EMPTY); -#endif /* READ_iCCP */ -PNG_INTERNAL_FUNCTION(int, png_icc_check_header, - (png_const_structrp png_ptr, - png_const_charp name, png_uint_32 profile_length, - png_const_bytep profile /* first 132 bytes only */, int color_type), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(int, png_icc_check_tag_table, - (png_const_structrp png_ptr, - png_const_charp name, png_uint_32 profile_length, - png_const_bytep profile /* header plus whole tag table */), +PNG_INTERNAL_FUNCTION(int,png_icc_check_length,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length), PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_header,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* first 132 bytes only */, int color_type), PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_icc_check_tag_table,(png_const_structrp png_ptr, + png_colorspacerp colorspace, png_const_charp name, + png_uint_32 profile_length, + png_const_bytep profile /* header plus whole tag table */), PNG_EMPTY); +#ifdef PNG_sRGB_SUPPORTED +PNG_INTERNAL_FUNCTION(void,png_icc_set_sRGB,( + png_const_structrp png_ptr, png_colorspacerp colorspace, + png_const_bytep profile, uLong adler), PNG_EMPTY); + /* 'adler' is the Adler32 checksum of the uncompressed profile data. It may + * be zero to indicate that it is not available. It is used, if provided, + * as a fast check on the profile when checking to see if it is sRGB. + */ +#endif #endif /* iCCP */ #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_set_rgb_coefficients, - (png_structrp png_ptr), - PNG_EMPTY); - /* Set the rgb_to_gray coefficients from the cHRM Y values (if unset) */ +PNG_INTERNAL_FUNCTION(void,png_colorspace_set_rgb_coefficients, + (png_structrp png_ptr), PNG_EMPTY); + /* Set the rgb_to_gray coefficients from the colorspace Y values */ #endif /* READ_RGB_TO_GRAY */ +#endif /* COLORSPACE */ /* Added at libpng version 1.4.0 */ -PNG_INTERNAL_FUNCTION(void, png_check_IHDR, - (png_const_structrp png_ptr, - png_uint_32 width, png_uint_32 height, int bit_depth, int color_type, - int interlace_type, int compression_type, int filter_type), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_check_IHDR,(png_const_structrp png_ptr, + png_uint_32 width, png_uint_32 height, int bit_depth, + int color_type, int interlace_type, int compression_type, + int filter_type),PNG_EMPTY); /* Added at libpng version 1.5.10 */ #if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) -PNG_INTERNAL_FUNCTION(void, png_do_check_palette_indexes, - (png_structrp png_ptr, png_row_infop row_info), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_do_check_palette_indexes, + (png_structrp png_ptr, png_row_infop row_info),PNG_EMPTY); #endif #if defined(PNG_FLOATING_POINT_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED) -PNG_INTERNAL_FUNCTION(void, png_fixed_error, - (png_const_structrp png_ptr, png_const_charp name), - PNG_NORETURN); +PNG_INTERNAL_FUNCTION(void,png_fixed_error,(png_const_structrp png_ptr, + png_const_charp name),PNG_NORETURN); #endif /* Puts 'string' into 'buffer' at buffer[pos], taking care never to overwrite * the end. Always leaves the buffer nul terminated. Never errors out (and * there is no error code.) */ -PNG_INTERNAL_FUNCTION(size_t, png_safecat, - (png_charp buffer, size_t bufsize, size_t pos, png_const_charp string), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(size_t,png_safecat,(png_charp buffer, size_t bufsize, + size_t pos, png_const_charp string),PNG_EMPTY); /* Various internal functions to handle formatted warning messages, currently * only implemented for warnings. @@ -1945,9 +1548,8 @@ PNG_INTERNAL_FUNCTION(size_t, png_safecat, * Returns the pointer to the start of the formatted string. This utility only * does unsigned values. */ -PNG_INTERNAL_FUNCTION(png_charp, png_format_number, - (png_const_charp start, png_charp end, int format, png_alloc_size_t number), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_charp,png_format_number,(png_const_charp start, + png_charp end, int format, png_alloc_size_t number),PNG_EMPTY); /* Convenience macro that takes an array: */ #define PNG_FORMAT_NUMBER(buffer,format,number) \ @@ -1979,26 +1581,23 @@ PNG_INTERNAL_FUNCTION(png_charp, png_format_number, typedef char png_warning_parameters[PNG_WARNING_PARAMETER_COUNT][ PNG_WARNING_PARAMETER_SIZE]; -PNG_INTERNAL_FUNCTION(void, png_warning_parameter, - (png_warning_parameters p, int number, png_const_charp string), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_warning_parameter,(png_warning_parameters p, + int number, png_const_charp string),PNG_EMPTY); /* Parameters are limited in size to PNG_WARNING_PARAMETER_SIZE characters, * including the trailing '\0'. */ -PNG_INTERNAL_FUNCTION(void, png_warning_parameter_unsigned, +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_unsigned, (png_warning_parameters p, int number, int format, png_alloc_size_t value), PNG_EMPTY); /* Use png_alloc_size_t because it is an unsigned type as big as any we * need to output. Use the following for a signed value. */ -PNG_INTERNAL_FUNCTION(void, png_warning_parameter_signed, +PNG_INTERNAL_FUNCTION(void,png_warning_parameter_signed, (png_warning_parameters p, int number, int format, png_int_32 value), PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_formatted_warning, - (png_const_structrp png_ptr, - png_warning_parameters p, png_const_charp message), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_formatted_warning,(png_const_structrp png_ptr, + png_warning_parameters p, png_const_charp message),PNG_EMPTY); /* 'message' follows the X/Open approach of using @1, @2 to insert * parameters previously supplied using the above functions. Errors in * specifying the parameters will simply result in garbage substitutions. @@ -2020,16 +1619,14 @@ PNG_INTERNAL_FUNCTION(void, png_formatted_warning, * If benign errors aren't supported they end up as the corresponding base call * (png_warning or png_error.) */ -PNG_INTERNAL_FUNCTION(void, png_app_warning, - (png_const_structrp png_ptr, png_const_charp message), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_app_warning,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); /* The application provided invalid parameters to an API function or called * an API function at the wrong time, libpng can completely recover. */ -PNG_INTERNAL_FUNCTION(void, png_app_error, - (png_const_structrp png_ptr, png_const_charp message), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_app_error,(png_const_structrp png_ptr, + png_const_charp message),PNG_EMPTY); /* As above but libpng will ignore the call, or attempt some other partial * recovery from the error. */ @@ -2038,9 +1635,8 @@ PNG_INTERNAL_FUNCTION(void, png_app_error, # define png_app_error(pp,s) png_error(pp,s) #endif -PNG_INTERNAL_FUNCTION(void, png_chunk_report, - (png_const_structrp png_ptr, png_const_charp message, int error), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_chunk_report,(png_const_structrp png_ptr, + png_const_charp message, int error),PNG_EMPTY); /* Report a recoverable issue in chunk data. On read this is used to report * a problem found while reading a particular chunk and the * png_chunk_benign_error or png_chunk_warning function is used as @@ -2066,17 +1662,14 @@ PNG_INTERNAL_FUNCTION(void, png_chunk_report, #define PNG_sCAL_MAX_DIGITS (PNG_sCAL_PRECISION+1/*.*/+1/*E*/+10/*exponent*/) #ifdef PNG_FLOATING_POINT_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_ascii_from_fp, - (png_const_structrp png_ptr, - png_charp ascii, size_t size, double fp, unsigned int precision), +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fp,(png_const_structrp png_ptr, + png_charp ascii, png_size_t size, double fp, unsigned int precision), PNG_EMPTY); #endif /* FLOATING_POINT */ #ifdef PNG_FIXED_POINT_SUPPORTED -PNG_INTERNAL_FUNCTION(void, png_ascii_from_fixed, - (png_const_structrp png_ptr, - png_charp ascii, size_t size, png_fixed_point fp), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_ascii_from_fixed,(png_const_structrp png_ptr, + png_charp ascii, png_size_t size, png_fixed_point fp),PNG_EMPTY); #endif /* FIXED_POINT */ #endif /* sCAL */ @@ -2133,7 +1726,7 @@ PNG_INTERNAL_FUNCTION(void, png_ascii_from_fixed, */ #define PNG_FP_INVALID 512 /* Available for callers as a distinct value */ -/* Result codes for the parser (boolean - true means ok, false means +/* Result codes for the parser (boolean - true meants ok, false means * not ok yet.) */ #define PNG_FP_MAYBE 0 /* The number may be valid in the future */ @@ -2168,9 +1761,8 @@ PNG_INTERNAL_FUNCTION(void, png_ascii_from_fixed, * that omits the last character (i.e. set the size to the index of * the problem character.) This has not been tested within libpng. */ -PNG_INTERNAL_FUNCTION(int, png_check_fp_number, - (png_const_charp string, size_t size, int *statep, size_t *whereami), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_check_fp_number,(png_const_charp string, + png_size_t size, int *statep, png_size_tp whereami),PNG_EMPTY); /* This is the same but it checks a complete string and returns true * only if it just contains a floating point number. As of 1.5.4 this @@ -2178,61 +1770,52 @@ PNG_INTERNAL_FUNCTION(int, png_check_fp_number, * it was valid (otherwise it returns 0.) This can be used for testing * for negative or zero values using the sticky flag. */ -PNG_INTERNAL_FUNCTION(int, png_check_fp_string, - (png_const_charp string, size_t size), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_check_fp_string,(png_const_charp string, + png_size_t size),PNG_EMPTY); #endif /* pCAL || sCAL */ #if defined(PNG_READ_GAMMA_SUPPORTED) ||\ - defined(PNG_COLORSPACE_SUPPORTED) ||\ - defined(PNG_INCH_CONVERSIONS_SUPPORTED) ||\ - defined(PNG_READ_pHYs_SUPPORTED) + defined(PNG_INCH_CONVERSIONS_SUPPORTED) || defined(PNG_READ_pHYs_SUPPORTED) /* Added at libpng version 1.5.0 */ /* This is a utility to provide a*times/div (rounded) and indicate * if there is an overflow. The result is a boolean - false (0) * for overflow, true (1) if no overflow, in which case *res * holds the result. */ -PNG_INTERNAL_FUNCTION(int, png_muldiv, - (png_fixed_point_p res, png_fixed_point a, - png_int_32 multiplied_by, png_int_32 divided_by), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_muldiv,(png_fixed_point_p res, png_fixed_point a, + png_int_32 multiplied_by, png_int_32 divided_by),PNG_EMPTY); +#endif +#if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_INCH_CONVERSIONS_SUPPORTED) +/* Same deal, but issue a warning on overflow and return 0. */ +PNG_INTERNAL_FUNCTION(png_fixed_point,png_muldiv_warn, + (png_const_structrp png_ptr, png_fixed_point a, png_int_32 multiplied_by, + png_int_32 divided_by),PNG_EMPTY); +#endif + +#ifdef PNG_GAMMA_SUPPORTED /* Calculate a reciprocal - used for gamma values. This returns * 0 if the argument is 0 in order to maintain an undefined value; * there are no warnings. */ -PNG_INTERNAL_FUNCTION(png_fixed_point, png_reciprocal, - (png_fixed_point a), +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal,(png_fixed_point a), PNG_EMPTY); -#endif #ifdef PNG_READ_GAMMA_SUPPORTED /* The same but gives a reciprocal of the product of two fixed point * values. Accuracy is suitable for gamma calculations but this is * not exact - use png_muldiv for that. Only required at present on read. */ -PNG_INTERNAL_FUNCTION(png_fixed_point, png_reciprocal2, - (png_fixed_point a, png_fixed_point b), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_fixed_point,png_reciprocal2,(png_fixed_point a, + png_fixed_point b),PNG_EMPTY); +#endif /* Return true if the gamma value is significantly different from 1.0 */ -PNG_INTERNAL_FUNCTION(int, png_gamma_significant, - (png_fixed_point gamma_value), - PNG_EMPTY); - -/* PNGv3: 'resolve' the file gamma according to the new PNGv3 rules for colour - * space information. - * - * NOTE: this uses precisely those chunks that libpng supports. For example it - * doesn't use iCCP and it can only use cICP for known and manageable - * transforms. For this reason a gamma specified by png_set_gamma always takes - * precedence. - */ -PNG_INTERNAL_FUNCTION(png_fixed_point, png_resolve_file_gamma, - (png_const_structrp png_ptr), +PNG_INTERNAL_FUNCTION(int,png_gamma_significant,(png_fixed_point gamma_value), PNG_EMPTY); +#endif +#ifdef PNG_READ_GAMMA_SUPPORTED /* Internal fixed point gamma correction. These APIs are called as * required to convert single values - they don't need to be fast, * they are not used when processing image pixel values. @@ -2240,45 +1823,21 @@ PNG_INTERNAL_FUNCTION(png_fixed_point, png_resolve_file_gamma, * While the input is an 'unsigned' value it must actually be the * correct bit value - 0..255 or 0..65535 as required. */ -PNG_INTERNAL_FUNCTION(png_uint_16, png_gamma_correct, - (png_structrp png_ptr, unsigned int value, png_fixed_point gamma_value), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(png_uint_16, png_gamma_16bit_correct, - (unsigned int value, png_fixed_point gamma_value), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(png_byte, png_gamma_8bit_correct, - (unsigned int value, png_fixed_point gamma_value), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_destroy_gamma_table, - (png_structrp png_ptr), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(void, png_build_gamma_table, - (png_structrp png_ptr, int bit_depth), - PNG_EMPTY); -#endif /* READ_GAMMA */ - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED -/* Set the RGB coefficients if not already set by png_set_rgb_to_gray */ -PNG_INTERNAL_FUNCTION(void, png_set_rgb_coefficients, - (png_structrp png_ptr), - PNG_EMPTY); -#endif - -#if defined(PNG_cHRM_SUPPORTED) || defined(PNG_READ_RGB_TO_GRAY_SUPPORTED) -PNG_INTERNAL_FUNCTION(int, png_XYZ_from_xy, - (png_XYZ *XYZ, const png_xy *xy), - PNG_EMPTY); -#endif /* cHRM || READ_RGB_TO_GRAY */ - -#ifdef PNG_COLORSPACE_SUPPORTED -PNG_INTERNAL_FUNCTION(int, png_xy_from_XYZ, - (png_xy *xy, const png_XYZ *XYZ), +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_correct,(png_structrp png_ptr, + unsigned int value, png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_uint_16,png_gamma_16bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(png_byte,png_gamma_8bit_correct,(unsigned int value, + png_fixed_point gamma_value),PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_destroy_gamma_table,(png_structrp png_ptr), PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_build_gamma_table,(png_structrp png_ptr, + int bit_depth),PNG_EMPTY); #endif /* SIMPLIFIED READ/WRITE SUPPORT */ #if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\ - defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) + defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) /* The internal structure that png_image::opaque points to. */ typedef struct png_control { @@ -2287,7 +1846,7 @@ typedef struct png_control png_voidp error_buf; /* Always a jmp_buf at present. */ png_const_bytep memory; /* Memory buffer. */ - size_t size; /* Size of the memory buffer. */ + png_size_t size; /* Size of the memory buffer. */ unsigned int for_write :1; /* Otherwise it is a read structure */ unsigned int owned_file :1; /* We own the file in io_ptr */ @@ -2306,115 +1865,40 @@ typedef struct png_control * errors that might occur. Returns true on success, false on failure (either * of the function or as a result of a png_error.) */ -PNG_INTERNAL_CALLBACK(void, png_safe_error, - (png_structp png_ptr, png_const_charp error_message), - PNG_NORETURN); +PNG_INTERNAL_FUNCTION(void,png_safe_error,(png_structp png_ptr, + png_const_charp error_message),PNG_NORETURN); #ifdef PNG_WARNINGS_SUPPORTED -PNG_INTERNAL_CALLBACK(void, png_safe_warning, - (png_structp png_ptr, png_const_charp warning_message), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void,png_safe_warning,(png_structp png_ptr, + png_const_charp warning_message),PNG_EMPTY); #else # define png_safe_warning 0/*dummy argument*/ #endif -PNG_INTERNAL_FUNCTION(int, png_safe_execute, - (png_imagep image, int (*function)(png_voidp), png_voidp arg), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_safe_execute,(png_imagep image, + int (*function)(png_voidp), png_voidp arg),PNG_EMPTY); /* Utility to log an error; this also cleans up the png_image; the function * always returns 0 (false). */ -PNG_INTERNAL_FUNCTION(int, png_image_error, - (png_imagep image, png_const_charp error_message), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(int,png_image_error,(png_imagep image, + png_const_charp error_message),PNG_EMPTY); #ifndef PNG_SIMPLIFIED_READ_SUPPORTED /* png_image_free is used by the write code but not exported */ -PNG_INTERNAL_FUNCTION(void, png_image_free, - (png_imagep image), - PNG_EMPTY); +PNG_INTERNAL_FUNCTION(void, png_image_free, (png_imagep image), PNG_EMPTY); #endif /* !SIMPLIFIED_READ */ #endif /* SIMPLIFIED READ/WRITE */ -/* These are initialization functions for hardware specific PNG filter - * optimizations; list these here then select the appropriate one at compile - * time using the macro PNG_FILTER_OPTIMIZATIONS. If the macro is not defined - * the generic code is used. - */ #ifdef PNG_FILTER_OPTIMIZATIONS -PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, - (png_structp png_ptr, unsigned int bpp), - PNG_EMPTY); - /* Just declare the optimization that will be used */ -#else - /* List *all* the possible optimizations here - this branch is required if - * the builder of libpng passes the definition of PNG_FILTER_OPTIMIZATIONS in - * CFLAGS in place of CPPFLAGS *and* uses symbol prefixing. +PNG_INTERNAL_FUNCTION(void, PNG_FILTER_OPTIMIZATIONS, (png_structp png_ptr, + unsigned int bpp), PNG_EMPTY); + /* This is the initialization function for hardware specific optimizations, + * one implementation (for ARM NEON machines) is contained in + * arm/filter_neon.c. It need not be defined - the generic code will be used + * if not. */ -# if PNG_ARM_NEON_OPT > 0 -PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_neon, - (png_structp png_ptr, unsigned int bpp), - PNG_EMPTY); -#endif - -#if PNG_MIPS_MSA_IMPLEMENTATION == 1 -PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_mips, - (png_structp png_ptr, unsigned int bpp), - PNG_EMPTY); -#endif - -# if PNG_MIPS_MMI_IMPLEMENTATION > 0 -PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_mips, - (png_structp png_ptr, unsigned int bpp), - PNG_EMPTY); -# endif - -# if PNG_INTEL_SSE_IMPLEMENTATION > 0 -PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_sse2, - (png_structp png_ptr, unsigned int bpp), - PNG_EMPTY); -# endif -#endif - -#if PNG_LOONGARCH_LSX_OPT > 0 -PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_lsx, - (png_structp png_ptr, unsigned int bpp), - PNG_EMPTY); -#endif - -# if PNG_RISCV_RVV_IMPLEMENTATION == 1 -PNG_INTERNAL_FUNCTION(void, png_init_filter_functions_rvv, - (png_structp png_ptr, unsigned int bpp), - PNG_EMPTY); -#endif - -PNG_INTERNAL_FUNCTION(png_uint_32, png_check_keyword, - (png_structrp png_ptr, png_const_charp key, png_bytep new_key), - PNG_EMPTY); - -#if PNG_ARM_NEON_IMPLEMENTATION == 1 -PNG_INTERNAL_FUNCTION(void, - png_riffle_palette_neon, - (png_structrp), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(int, - png_do_expand_palette_rgba8_neon, - (png_structrp, - png_row_infop, - png_const_bytep, - const png_bytepp, - const png_bytepp), - PNG_EMPTY); -PNG_INTERNAL_FUNCTION(int, - png_do_expand_palette_rgb8_neon, - (png_structrp, - png_row_infop, - png_const_bytep, - const png_bytepp, - const png_bytepp), - PNG_EMPTY); #endif /* Maintainer: Put new private prototypes here ^ */ @@ -2426,3 +1910,4 @@ PNG_INTERNAL_FUNCTION(int, #endif #endif /* PNG_VERSION_INFO_ONLY */ +#endif /* PNGPRIV_H */ diff --git a/Windows_Libs/Dev/Render/libpng/pngread.c b/Windows_Libs/Dev/Render/libpng/pngread.c index af2f44c..0a00439 100644 --- a/Windows_Libs/Dev/Render/libpng/pngread.c +++ b/Windows_Libs/Dev/Render/libpng/pngread.c @@ -1,9 +1,10 @@ + /* pngread.c - read a PNG file * - * Copyright (c) 2018-2026 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.1 [March 28, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -23,15 +24,14 @@ /* Create a PNG structure for reading, and allocate any memory needed. */ PNG_FUNCTION(png_structp,PNGAPI png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn), - PNG_ALLOCATED) + png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) { #ifndef PNG_USER_MEM_SUPPORTED png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, - error_fn, warn_fn, NULL, NULL, NULL); + error_fn, warn_fn, NULL, NULL, NULL); #else return png_create_read_struct_2(user_png_ver, error_ptr, error_fn, - warn_fn, NULL, NULL, NULL); + warn_fn, NULL, NULL, NULL); } /* Alternate create PNG structure for reading, and allocate any memory @@ -40,12 +40,11 @@ png_create_read_struct,(png_const_charp user_png_ver, png_voidp error_ptr, PNG_FUNCTION(png_structp,PNGAPI png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn), - PNG_ALLOCATED) + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) { png_structp png_ptr = png_create_png_struct(user_png_ver, error_ptr, - error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); -#endif /* USER_MEM */ + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* PNG_USER_MEM_SUPPORTED */ if (png_ptr != NULL) { @@ -64,7 +63,7 @@ png_create_read_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, /* In stable builds only warn if an application error can be completely * handled. */ -# if PNG_RELEASE_BUILD +# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; # endif # endif @@ -114,30 +113,30 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr) */ if (chunk_name == png_IDAT) { - if ((png_ptr->mode & PNG_HAVE_IHDR) == 0) + if (!(png_ptr->mode & PNG_HAVE_IHDR)) png_chunk_error(png_ptr, "Missing IHDR before IDAT"); else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - (png_ptr->mode & PNG_HAVE_PLTE) == 0) + !(png_ptr->mode & PNG_HAVE_PLTE)) png_chunk_error(png_ptr, "Missing PLTE before IDAT"); - else if ((png_ptr->mode & PNG_AFTER_IDAT) != 0) + else if (png_ptr->mode & PNG_AFTER_IDAT) png_chunk_benign_error(png_ptr, "Too many IDATs found"); png_ptr->mode |= PNG_HAVE_IDAT; } - else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) - { - png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT; + else if (png_ptr->mode & PNG_HAVE_IDAT) png_ptr->mode |= PNG_AFTER_IDAT; - } + /* This should be a binary subdivision search or a hash for + * matching the chunk name rather than a linear search. + */ if (chunk_name == png_IHDR) - png_handle_chunk(png_ptr, info_ptr, length); + png_handle_IHDR(png_ptr, info_ptr, length); else if (chunk_name == png_IEND) - png_handle_chunk(png_ptr, info_ptr, length); + png_handle_IEND(png_ptr, info_ptr, length); #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) @@ -154,6 +153,8 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr) } } #endif + else if (chunk_name == png_PLTE) + png_handle_PLTE(png_ptr, info_ptr, length); else if (chunk_name == png_IDAT) { @@ -161,11 +162,97 @@ png_read_info(png_structrp png_ptr, png_inforp info_ptr) break; } +#ifdef PNG_READ_bKGD_SUPPORTED + else if (chunk_name == png_bKGD) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED + else if (chunk_name == png_cHRM) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_gAMA_SUPPORTED + else if (chunk_name == png_gAMA) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_hIST_SUPPORTED + else if (chunk_name == png_hIST) + png_handle_hIST(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED + else if (chunk_name == png_oFFs) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED + else if (chunk_name == png_pCAL) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED + else if (chunk_name == png_sCAL) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED + else if (chunk_name == png_pHYs) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED + else if (chunk_name == png_sBIT) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED + else if (chunk_name == png_sRGB) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_iCCP_SUPPORTED + else if (chunk_name == png_iCCP) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sPLT_SUPPORTED + else if (chunk_name == png_sPLT) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED + else if (chunk_name == png_tEXt) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tIME_SUPPORTED + else if (chunk_name == png_tIME) + png_handle_tIME(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tRNS_SUPPORTED + else if (chunk_name == png_tRNS) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED + else if (chunk_name == png_zTXt) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_iTXt_SUPPORTED + else if (chunk_name == png_iTXt) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif + else - png_handle_chunk(png_ptr, info_ptr, length); + png_handle_unknown(png_ptr, info_ptr, length, + PNG_HANDLE_CHUNK_AS_DEFAULT); } } -#endif /* SEQUENTIAL_READ */ +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ /* Optional call to update the users info_ptr structure */ void PNGAPI @@ -189,7 +276,7 @@ png_read_update_info(png_structrp png_ptr, png_inforp info_ptr) /* New in 1.6.0 this avoids the bug of doing the initializations twice */ else png_app_error(png_ptr, - "png_read_update_info/png_start_read_image: duplicate call"); + "png_read_update_info/png_start_read_image: duplicate call"); } } @@ -212,78 +299,12 @@ png_start_read_image(png_structrp png_ptr) /* New in 1.6.0 this avoids the bug of doing the initializations twice */ else png_app_error(png_ptr, - "png_start_read_image/png_read_update_info: duplicate call"); + "png_start_read_image/png_read_update_info: duplicate call"); } } -#endif /* SEQUENTIAL_READ */ +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED -#ifdef PNG_MNG_FEATURES_SUPPORTED -/* Undoes intrapixel differencing, - * NOTE: this is apparently only supported in the 'sequential' reader. - */ -static void -png_do_read_intrapixel(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_read_intrapixel"); - - if ( - (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) - { - int bytes_per_pixel; - png_uint_32 row_width = row_info->width; - - if (row_info->bit_depth == 8) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 3; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 4; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff); - *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff); - } - } - else if (row_info->bit_depth == 16) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 6; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 8; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - png_uint_32 s0 = (png_uint_32)(*(rp ) << 8) | *(rp + 1); - png_uint_32 s1 = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3); - png_uint_32 s2 = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5); - png_uint_32 red = (s0 + s1 + 65536) & 0xffff; - png_uint_32 blue = (s2 + s1 + 65536) & 0xffff; - *(rp ) = (png_byte)((red >> 8) & 0xff); - *(rp + 1) = (png_byte)(red & 0xff); - *(rp + 4) = (png_byte)((blue >> 8) & 0xff); - *(rp + 5) = (png_byte)(blue & 0xff); - } - } - } -} -#endif /* MNG_FEATURES */ - void PNGAPI png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) { @@ -298,7 +319,7 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) /* png_read_start_row sets the information (in particular iwidth) for this * interlace pass. */ - if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) png_read_start_row(png_ptr); /* 1.5.6: row_info moved out of png_struct to a local here. */ @@ -309,47 +330,45 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) row_info.pixel_depth = png_ptr->pixel_depth; row_info.rowbytes = PNG_ROWBYTES(row_info.pixel_depth, row_info.width); -#ifdef PNG_WARNINGS_SUPPORTED if (png_ptr->row_number == 0 && png_ptr->pass == 0) { /* Check for transforms that have been set but were defined out */ #if defined(PNG_WRITE_INVERT_SUPPORTED) && !defined(PNG_READ_INVERT_SUPPORTED) - if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + if (png_ptr->transformations & PNG_INVERT_MONO) png_warning(png_ptr, "PNG_READ_INVERT_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_FILLER_SUPPORTED) && !defined(PNG_READ_FILLER_SUPPORTED) - if ((png_ptr->transformations & PNG_FILLER) != 0) + if (png_ptr->transformations & PNG_FILLER) png_warning(png_ptr, "PNG_READ_FILLER_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ !defined(PNG_READ_PACKSWAP_SUPPORTED) - if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + if (png_ptr->transformations & PNG_PACKSWAP) png_warning(png_ptr, "PNG_READ_PACKSWAP_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_PACK_SUPPORTED) && !defined(PNG_READ_PACK_SUPPORTED) - if ((png_ptr->transformations & PNG_PACK) != 0) + if (png_ptr->transformations & PNG_PACK) png_warning(png_ptr, "PNG_READ_PACK_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_SHIFT_SUPPORTED) && !defined(PNG_READ_SHIFT_SUPPORTED) - if ((png_ptr->transformations & PNG_SHIFT) != 0) + if (png_ptr->transformations & PNG_SHIFT) png_warning(png_ptr, "PNG_READ_SHIFT_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_BGR_SUPPORTED) && !defined(PNG_READ_BGR_SUPPORTED) - if ((png_ptr->transformations & PNG_BGR) != 0) + if (png_ptr->transformations & PNG_BGR) png_warning(png_ptr, "PNG_READ_BGR_SUPPORTED is not defined"); #endif #if defined(PNG_WRITE_SWAP_SUPPORTED) && !defined(PNG_READ_SWAP_SUPPORTED) - if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + if (png_ptr->transformations & PNG_SWAP_BYTES) png_warning(png_ptr, "PNG_READ_SWAP_SUPPORTED is not defined"); #endif } -#endif /* WARNINGS */ #ifdef PNG_READ_INTERLACING_SUPPORTED /* If interlaced and we do not need a new row, combine row and return. @@ -358,8 +377,7 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) * untransformed) and, because of the libpng API for interlaced images, this * means we must transform before de-interlacing. */ - if (png_ptr->interlaced != 0 && - (png_ptr->transformations & PNG_INTERLACE) != 0) + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) { switch (png_ptr->pass) { @@ -430,7 +448,7 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) default: case 6: - if ((png_ptr->row_number & 1) == 0) + if (!(png_ptr->row_number & 1)) { png_read_finish_row(png_ptr); return; @@ -440,18 +458,17 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) } #endif - if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) + if (!(png_ptr->mode & PNG_HAVE_IDAT)) png_error(png_ptr, "Invalid attempt to read row data"); /* Fill the row with IDAT data: */ - png_ptr->row_buf[0]=255; /* to force error if no data was found */ png_read_IDAT_data(png_ptr, png_ptr->row_buf, row_info.rowbytes + 1); if (png_ptr->row_buf[0] > PNG_FILTER_VALUE_NONE) { if (png_ptr->row_buf[0] < PNG_FILTER_VALUE_LAST) png_read_filter_row(png_ptr, &row_info, png_ptr->row_buf + 1, - png_ptr->prev_row + 1, png_ptr->row_buf[0]); + png_ptr->prev_row + 1, png_ptr->row_buf[0]); else png_error(png_ptr, "bad adaptive filter value"); } @@ -464,7 +481,7 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) memcpy(png_ptr->prev_row, png_ptr->row_buf, row_info.rowbytes + 1); #ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) { /* Intrapixel differencing */ @@ -472,12 +489,9 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) } #endif + #ifdef PNG_READ_TRANSFORMS_SUPPORTED - if (png_ptr->transformations -# ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED - || png_ptr->num_palette_max >= 0 -# endif - ) + if (png_ptr->transformations) png_do_read_transformations(png_ptr, &row_info); #endif @@ -493,13 +507,13 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) png_error(png_ptr, "internal sequential row size calculation error"); #ifdef PNG_READ_INTERLACING_SUPPORTED - /* Expand interlaced rows to full size */ - if (png_ptr->interlaced != 0 && - (png_ptr->transformations & PNG_INTERLACE) != 0) + /* Blow up interlaced rows to full size */ + if (png_ptr->interlaced && + (png_ptr->transformations & PNG_INTERLACE)) { if (png_ptr->pass < 6) png_do_read_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass, - png_ptr->transformations); + png_ptr->transformations); if (dsp_row != NULL) png_combine_row(png_ptr, dsp_row, 1/*display*/); @@ -521,8 +535,9 @@ png_read_row(png_structrp png_ptr, png_bytep row, png_bytep dsp_row) if (png_ptr->read_row_fn != NULL) (*(png_ptr->read_row_fn))(png_ptr, png_ptr->row_number, png_ptr->pass); + } -#endif /* SEQUENTIAL_READ */ +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read one or more rows of image data. If the image is interlaced, @@ -589,7 +604,7 @@ png_read_rows(png_structrp png_ptr, png_bytepp row, dp++; } } -#endif /* SEQUENTIAL_READ */ +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the entire image. If the image has an alpha channel or a tRNS @@ -617,7 +632,7 @@ png_read_image(png_structrp png_ptr, png_bytepp image) return; #ifdef PNG_READ_INTERLACING_SUPPORTED - if ((png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) + if (!(png_ptr->flags & PNG_FLAG_ROW_INIT)) { pass = png_set_interlace_handling(png_ptr); /* And make sure transforms are initialized. */ @@ -625,15 +640,14 @@ png_read_image(png_structrp png_ptr, png_bytepp image) } else { - if (png_ptr->interlaced != 0 && - (png_ptr->transformations & PNG_INTERLACE) == 0) + if (png_ptr->interlaced && !(png_ptr->transformations & PNG_INTERLACE)) { /* Caller called png_start_read_image or png_read_update_info without * first turning on the PNG_INTERLACE transform. We can fix this here, * but the caller should do it! */ png_warning(png_ptr, "Interlace handling should be turned on when " - "using png_read_image"); + "using png_read_image"); /* Make sure this is set correctly */ png_ptr->num_rows = png_ptr->height; } @@ -663,7 +677,7 @@ png_read_image(png_structrp png_ptr, png_bytepp image) } } } -#endif /* SEQUENTIAL_READ */ +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ #ifdef PNG_SEQUENTIAL_READ_SUPPORTED /* Read the end of the PNG file. Will not read past the end of the @@ -686,15 +700,15 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr) * still be pending IDAT data and an owned zstream. Deal with this here. */ #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED - if (png_chunk_unknown_handling(png_ptr, png_IDAT) == 0) + if (!png_chunk_unknown_handling(png_ptr, png_IDAT)) #endif png_read_finish_IDAT(png_ptr); #ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED /* Report invalid palette index; added at libng-1.5.10 */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - png_ptr->num_palette_max >= png_ptr->num_palette) - png_benign_error(png_ptr, "Read palette index exceeding num_palette"); + png_ptr->num_palette_max > png_ptr->num_palette) + png_benign_error(png_ptr, "Read palette index exceeding num_palette"); #endif do @@ -702,31 +716,19 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr) png_uint_32 length = png_read_chunk_header(png_ptr); png_uint_32 chunk_name = png_ptr->chunk_name; - if (chunk_name != png_IDAT) - { - /* These flags must be set consistently for all non-IDAT chunks, - * including the unknown chunks. - */ - png_ptr->mode |= PNG_HAVE_CHUNK_AFTER_IDAT | PNG_AFTER_IDAT; - } + if (chunk_name == png_IHDR) + png_handle_IHDR(png_ptr, info_ptr, length); - if (chunk_name == png_IEND) - png_handle_chunk(png_ptr, info_ptr, length); - - else if (chunk_name == png_IHDR) - png_handle_chunk(png_ptr, info_ptr, length); - - else if (info_ptr == NULL) - png_crc_finish(png_ptr, length); + else if (chunk_name == png_IEND) + png_handle_IEND(png_ptr, info_ptr, length); #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED else if ((keep = png_chunk_unknown_handling(png_ptr, chunk_name)) != 0) { if (chunk_name == png_IDAT) { - if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) - || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) - png_benign_error(png_ptr, ".Too many IDATs found"); + if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + png_benign_error(png_ptr, "Too many IDATs found"); } png_handle_unknown(png_ptr, info_ptr, length, keep); if (chunk_name == png_PLTE) @@ -737,23 +739,107 @@ png_read_end(png_structrp png_ptr, png_inforp info_ptr) else if (chunk_name == png_IDAT) { /* Zero length IDATs are legal after the last IDAT has been - * read, but not after other chunks have been read. 1.6 does not - * always read all the deflate data; specifically it cannot be relied - * upon to read the Adler32 at the end. If it doesn't ignore IDAT - * chunks which are longer than zero as well: + * read, but not after other chunks have been read. */ - if ((length > 0 && !(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) - || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT) != 0) - png_benign_error(png_ptr, "..Too many IDATs found"); + if ((length > 0) || (png_ptr->mode & PNG_HAVE_CHUNK_AFTER_IDAT)) + png_benign_error(png_ptr, "Too many IDATs found"); png_crc_finish(png_ptr, length); } + else if (chunk_name == png_PLTE) + png_handle_PLTE(png_ptr, info_ptr, length); + +#ifdef PNG_READ_bKGD_SUPPORTED + else if (chunk_name == png_bKGD) + png_handle_bKGD(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_cHRM_SUPPORTED + else if (chunk_name == png_cHRM) + png_handle_cHRM(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_gAMA_SUPPORTED + else if (chunk_name == png_gAMA) + png_handle_gAMA(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_hIST_SUPPORTED + else if (chunk_name == png_hIST) + png_handle_hIST(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_oFFs_SUPPORTED + else if (chunk_name == png_oFFs) + png_handle_oFFs(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_pCAL_SUPPORTED + else if (chunk_name == png_pCAL) + png_handle_pCAL(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sCAL_SUPPORTED + else if (chunk_name == png_sCAL) + png_handle_sCAL(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_pHYs_SUPPORTED + else if (chunk_name == png_pHYs) + png_handle_pHYs(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sBIT_SUPPORTED + else if (chunk_name == png_sBIT) + png_handle_sBIT(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sRGB_SUPPORTED + else if (chunk_name == png_sRGB) + png_handle_sRGB(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_iCCP_SUPPORTED + else if (chunk_name == png_iCCP) + png_handle_iCCP(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_sPLT_SUPPORTED + else if (chunk_name == png_sPLT) + png_handle_sPLT(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tEXt_SUPPORTED + else if (chunk_name == png_tEXt) + png_handle_tEXt(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tIME_SUPPORTED + else if (chunk_name == png_tIME) + png_handle_tIME(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_tRNS_SUPPORTED + else if (chunk_name == png_tRNS) + png_handle_tRNS(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_zTXt_SUPPORTED + else if (chunk_name == png_zTXt) + png_handle_zTXt(png_ptr, info_ptr, length); +#endif + +#ifdef PNG_READ_iTXt_SUPPORTED + else if (chunk_name == png_iTXt) + png_handle_iTXt(png_ptr, info_ptr, length); +#endif else - png_handle_chunk(png_ptr, info_ptr, length); - } while ((png_ptr->mode & PNG_HAVE_IEND) == 0); + png_handle_unknown(png_ptr, info_ptr, length, + PNG_HANDLE_CHUNK_AS_DEFAULT); + } while (!(png_ptr->mode & PNG_HAVE_IEND)); } -#endif /* SEQUENTIAL_READ */ +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ /* Free all memory used in the read struct */ static void @@ -766,33 +852,22 @@ png_read_destroy(png_structrp png_ptr) #endif png_free(png_ptr, png_ptr->big_row_buf); - png_ptr->big_row_buf = NULL; png_free(png_ptr, png_ptr->big_prev_row); - png_ptr->big_prev_row = NULL; png_free(png_ptr, png_ptr->read_buffer); - png_ptr->read_buffer = NULL; #ifdef PNG_READ_QUANTIZE_SUPPORTED png_free(png_ptr, png_ptr->palette_lookup); - png_ptr->palette_lookup = NULL; png_free(png_ptr, png_ptr->quantize_index); - png_ptr->quantize_index = NULL; #endif - if ((png_ptr->free_me & PNG_FREE_PLTE) != 0) - { + if (png_ptr->free_me & PNG_FREE_PLTE) png_zfree(png_ptr, png_ptr->palette); - png_ptr->palette = NULL; - } png_ptr->free_me &= ~PNG_FREE_PLTE; #if defined(PNG_tRNS_SUPPORTED) || \ defined(PNG_READ_EXPAND_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) - if ((png_ptr->free_me & PNG_FREE_TRNS) != 0) - { + if (png_ptr->free_me & PNG_FREE_TRNS) png_free(png_ptr, png_ptr->trans_alpha); - png_ptr->trans_alpha = NULL; - } png_ptr->free_me &= ~PNG_FREE_TRNS; #endif @@ -800,25 +875,15 @@ png_read_destroy(png_structrp png_ptr) #ifdef PNG_PROGRESSIVE_READ_SUPPORTED png_free(png_ptr, png_ptr->save_buffer); - png_ptr->save_buffer = NULL; #endif -#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) && \ +#if defined(PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED) &&\ defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) png_free(png_ptr, png_ptr->unknown_chunk.data); - png_ptr->unknown_chunk.data = NULL; #endif #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED png_free(png_ptr, png_ptr->chunk_list); - png_ptr->chunk_list = NULL; -#endif - -#if defined(PNG_READ_EXPAND_SUPPORTED) && \ - (defined(PNG_ARM_NEON_IMPLEMENTATION) || \ - defined(PNG_RISCV_RVV_IMPLEMENTATION)) - png_free(png_ptr, png_ptr->riffled_palette); - png_ptr->riffled_palette = NULL; #endif /* NOTE: the 'setjmp' buffer may still be allocated and the memory and error @@ -868,9 +933,10 @@ png_set_read_status_fn(png_structrp png_ptr, png_read_status_ptr read_row_fn) #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI png_read_png(png_structrp png_ptr, png_inforp info_ptr, - int transforms, png_voidp params) + int transforms, + voidp params) { - png_debug(1, "in png_read_png"); + int row; if (png_ptr == NULL || info_ptr == NULL) return; @@ -883,149 +949,127 @@ png_read_png(png_structrp png_ptr, png_inforp info_ptr, png_error(png_ptr, "Image is too high to process with png_read_png()"); /* -------------- image transformations start here ------------------- */ - /* libpng 1.6.10: add code to cause a png_app_error if a selected TRANSFORM - * is not implemented. This will only happen in de-configured (non-default) - * libpng builds. The results can be unexpected - png_read_png may return - * short or mal-formed rows because the transform is skipped. - */ +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Tell libpng to strip 16-bit/color files down to 8 bits per color. */ - if ((transforms & PNG_TRANSFORM_SCALE_16) != 0) - /* Added at libpng-1.5.4. "strip_16" produces the same result that it - * did in earlier versions, while "scale_16" is now more accurate. - */ -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if (transforms & PNG_TRANSFORM_SCALE_16) + { + /* Added at libpng-1.5.4. "strip_16" produces the same result that it + * did in earlier versions, while "scale_16" is now more accurate. + */ png_set_scale_16(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_SCALE_16 not supported"); + } #endif +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED /* If both SCALE and STRIP are required pngrtran will effectively cancel the * latter by doing SCALE first. This is ok and allows apps not to check for * which is supported to get the right answer. */ - if ((transforms & PNG_TRANSFORM_STRIP_16) != 0) -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + if (transforms & PNG_TRANSFORM_STRIP_16) png_set_strip_16(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_16 not supported"); #endif +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED /* Strip alpha bytes from the input data without combining with * the background (not recommended). */ - if ((transforms & PNG_TRANSFORM_STRIP_ALPHA) != 0) -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if (transforms & PNG_TRANSFORM_STRIP_ALPHA) png_set_strip_alpha(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_ALPHA not supported"); #endif +#if defined(PNG_READ_PACK_SUPPORTED) && !defined(PNG_READ_EXPAND_SUPPORTED) /* Extract multiple pixels with bit depths of 1, 2, or 4 from a single * byte into separate bytes (useful for paletted and grayscale images). */ - if ((transforms & PNG_TRANSFORM_PACKING) != 0) -#ifdef PNG_READ_PACK_SUPPORTED + if (transforms & PNG_TRANSFORM_PACKING) png_set_packing(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); #endif +#ifdef PNG_READ_PACKSWAP_SUPPORTED /* Change the order of packed pixels to least significant bit first * (not useful if you are using png_set_packing). */ - if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) -#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (transforms & PNG_TRANSFORM_PACKSWAP) png_set_packswap(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); #endif +#ifdef PNG_READ_EXPAND_SUPPORTED /* Expand paletted colors into true RGB triplets * Expand grayscale images to full 8 bits from 1, 2, or 4 bits/pixel * Expand paletted or RGB images with transparency to full alpha * channels so the data will be available as RGBA quartets. */ - if ((transforms & PNG_TRANSFORM_EXPAND) != 0) -#ifdef PNG_READ_EXPAND_SUPPORTED - png_set_expand(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND not supported"); + if (transforms & PNG_TRANSFORM_EXPAND) + if ((png_ptr->bit_depth < 8) || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) || + (png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS))) + png_set_expand(png_ptr); #endif /* We don't handle background color or gamma transformation or quantizing. */ +#ifdef PNG_READ_INVERT_SUPPORTED /* Invert monochrome files to have 0 as white and 1 as black */ - if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) -#ifdef PNG_READ_INVERT_SUPPORTED + if (transforms & PNG_TRANSFORM_INVERT_MONO) png_set_invert_mono(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); #endif +#ifdef PNG_READ_SHIFT_SUPPORTED /* If you want to shift the pixel values from the range [0,255] or * [0,65535] to the original [0,7] or [0,31], or whatever range the * colors were originally in: */ - if ((transforms & PNG_TRANSFORM_SHIFT) != 0) -#ifdef PNG_READ_SHIFT_SUPPORTED - if ((info_ptr->valid & PNG_INFO_sBIT) != 0) - png_set_shift(png_ptr, &info_ptr->sig_bit); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); + if ((transforms & PNG_TRANSFORM_SHIFT) + && png_get_valid(png_ptr, info_ptr, PNG_INFO_sBIT)) + { + // 4j change: initialize with null to silence MSVC + png_color_8p sig_bit = NULL; + + png_get_sBIT(png_ptr, info_ptr, &sig_bit); + png_set_shift(png_ptr, sig_bit); + } #endif - /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ - if ((transforms & PNG_TRANSFORM_BGR) != 0) #ifdef PNG_READ_BGR_SUPPORTED + /* Flip the RGB pixels to BGR (or RGBA to BGRA) */ + if (transforms & PNG_TRANSFORM_BGR) png_set_bgr(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); #endif - /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ - if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + /* Swap the RGBA or GA data to ARGB or AG (or BGRA to ABGR) */ + if (transforms & PNG_TRANSFORM_SWAP_ALPHA) png_set_swap_alpha(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); #endif - /* Swap bytes of 16-bit files to least significant byte first */ - if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) #ifdef PNG_READ_SWAP_SUPPORTED + /* Swap bytes of 16-bit files to least significant byte first */ + if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) png_set_swap(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); #endif /* Added at libpng-1.2.41 */ - /* Invert the alpha channel from opacity to transparency */ - if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel from opacity to transparency */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) png_set_invert_alpha(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); #endif /* Added at libpng-1.2.41 */ - /* Expand grayscale image to RGB */ - if ((transforms & PNG_TRANSFORM_GRAY_TO_RGB) != 0) #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* Expand grayscale image to RGB */ + if (transforms & PNG_TRANSFORM_GRAY_TO_RGB) png_set_gray_to_rgb(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_GRAY_TO_RGB not supported"); #endif /* Added at libpng-1.5.4 */ - if ((transforms & PNG_TRANSFORM_EXPAND_16) != 0) #ifdef PNG_READ_EXPAND_16_SUPPORTED + if (transforms & PNG_TRANSFORM_EXPAND_16) png_set_expand_16(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_EXPAND_16 not supported"); #endif /* We don't handle adding filler bytes */ @@ -1048,17 +1092,16 @@ png_read_png(png_structrp png_ptr, png_inforp info_ptr, { png_uint_32 iptr; - info_ptr->row_pointers = png_voidcast(png_bytepp, png_malloc(png_ptr, - info_ptr->height * (sizeof (png_bytep)))); - + info_ptr->row_pointers = (png_bytepp)png_malloc(png_ptr, + info_ptr->height * (sizeof (png_bytep))); for (iptr=0; iptrheight; iptr++) info_ptr->row_pointers[iptr] = NULL; info_ptr->free_me |= PNG_FREE_ROWS; - for (iptr = 0; iptr < info_ptr->height; iptr++) - info_ptr->row_pointers[iptr] = png_voidcast(png_bytep, - png_malloc(png_ptr, info_ptr->rowbytes)); + for (row = 0; row < (int)info_ptr->height; row++) + info_ptr->row_pointers[row] = (png_bytep)png_malloc(png_ptr, + png_get_rowbytes(png_ptr, info_ptr)); } png_read_image(png_ptr, info_ptr->row_pointers); @@ -1067,10 +1110,12 @@ png_read_png(png_structrp png_ptr, png_inforp info_ptr, /* Read rest of file, and get additional chunks in info_ptr - REQUIRED */ png_read_end(png_ptr, info_ptr); + PNG_UNUSED(transforms) /* Quiet compiler warnings */ PNG_UNUSED(params) + } -#endif /* INFO_IMAGE */ -#endif /* SEQUENTIAL_READ */ +#endif /* PNG_INFO_IMAGE_SUPPORTED */ +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ #ifdef PNG_SIMPLIFIED_READ_SUPPORTED /* SIMPLIFIED READ @@ -1081,14 +1126,15 @@ png_read_png(png_structrp png_ptr, png_inforp info_ptr, /* Arguments to png_image_finish_read: */ /* Encoding of PNG data (used by the color-map code) */ -# define P_NOTSET 0 /* File encoding not yet known */ -# define P_sRGB 1 /* 8-bit encoded to sRGB gamma */ -# define P_LINEAR 2 /* 16-bit linear: not encoded, NOT pre-multiplied! */ -# define P_FILE 3 /* 8-bit encoded to file gamma, not sRGB or linear */ -# define P_LINEAR8 4 /* 8-bit linear: only from a file value */ +/* TODO: change these, dang, ANSI-C reserves the 'E' namespace. */ +# define E_NOTSET 0 /* File encoding not yet known */ +# define E_sRGB 1 /* 8-bit encoded to sRGB gamma */ +# define E_LINEAR 2 /* 16-bit linear: not encoded, NOT pre-multiplied! */ +# define E_FILE 3 /* 8-bit encoded to file gamma, not sRGB or linear */ +# define E_LINEAR8 4 /* 8-bit linear: only from a file value */ /* Color-map processing: after libpng has run on the PNG image further - * processing may be needed to convert the data to color-map indices. + * processing may be needed to conver the data to color-map indicies. */ #define PNG_CMAP_NONE 0 #define PNG_CMAP_GA 1 /* Process GA data to a color-map with alpha */ @@ -1105,20 +1151,19 @@ png_read_png(png_structrp png_ptr, png_inforp info_ptr, typedef struct { - /* Arguments */ + /* Arguments: */ png_imagep image; - png_voidp buffer; + png_voidp buffer; png_int_32 row_stride; - png_voidp colormap; + png_voidp colormap; png_const_colorp background; - - /* Instance variables */ - png_voidp local_row; - png_voidp first_row; - ptrdiff_t row_step; /* step between rows */ - int file_encoding; /* E_ values above */ - png_fixed_point gamma_to_linear; /* For P_FILE, reciprocal of gamma */ - int colormap_processing; /* PNG_CMAP_ values above */ + /* Local variables: */ + png_voidp local_row; + png_voidp first_row; + ptrdiff_t row_bytes; /* step between rows */ + int file_encoding; /* E_ values above */ + png_fixed_point gamma_to_linear; /* For E_FILE, reciprocal of gamma */ + int colormap_processing; /* PNG_CMAP_ values above */ } png_image_read_control; /* Do all the *safe* initialization - 'safe' means that png_error won't be @@ -1147,7 +1192,7 @@ png_image_read_init(png_imagep image) if (info_ptr != NULL) { png_controlp control = png_voidcast(png_controlp, - png_malloc_warn(png_ptr, (sizeof *control))); + png_malloc_warn(png_ptr, (sizeof *control))); if (control != NULL) { @@ -1180,10 +1225,10 @@ png_image_format(png_structrp png_ptr) { png_uint_32 format = 0; - if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) format |= PNG_FORMAT_FLAG_COLOR; - if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + if (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) format |= PNG_FORMAT_FLAG_ALPHA; /* Use png_ptr here, not info_ptr, because by examination png_handle_tRNS @@ -1197,37 +1242,12 @@ png_image_format(png_structrp png_ptr) if (png_ptr->bit_depth == 16) format |= PNG_FORMAT_FLAG_LINEAR; - if ((png_ptr->color_type & PNG_COLOR_MASK_PALETTE) != 0) + if (png_ptr->color_type & PNG_COLOR_MASK_PALETTE) format |= PNG_FORMAT_FLAG_COLORMAP; return format; } -static int -chromaticities_match_sRGB(const png_xy *xy) -{ -# define sRGB_TOLERANCE 1000 - static const png_xy sRGB_xy = /* From ITU-R BT.709-3 */ - { - /* color x y */ - /* red */ 64000, 33000, - /* green */ 30000, 60000, - /* blue */ 15000, 6000, - /* white */ 31270, 32900 - }; - - if (PNG_OUT_OF_RANGE(xy->whitex, sRGB_xy.whitex,sRGB_TOLERANCE) || - PNG_OUT_OF_RANGE(xy->whitey, sRGB_xy.whitey,sRGB_TOLERANCE) || - PNG_OUT_OF_RANGE(xy->redx, sRGB_xy.redx, sRGB_TOLERANCE) || - PNG_OUT_OF_RANGE(xy->redy, sRGB_xy.redy, sRGB_TOLERANCE) || - PNG_OUT_OF_RANGE(xy->greenx, sRGB_xy.greenx,sRGB_TOLERANCE) || - PNG_OUT_OF_RANGE(xy->greeny, sRGB_xy.greeny,sRGB_TOLERANCE) || - PNG_OUT_OF_RANGE(xy->bluex, sRGB_xy.bluex, sRGB_TOLERANCE) || - PNG_OUT_OF_RANGE(xy->bluey, sRGB_xy.bluey, sRGB_TOLERANCE)) - return 0; - return 1; -} - /* Is the given gamma significantly different from sRGB? The test is the same * one used in pngrtran.c when deciding whether to do gamma correction. The * arithmetic optimizes the division by using the fact that the inverse of the @@ -1236,44 +1256,22 @@ chromaticities_match_sRGB(const png_xy *xy) static int png_gamma_not_sRGB(png_fixed_point g) { - /* 1.6.47: use the same sanity checks as used in pngrtran.c */ - if (g < PNG_LIB_GAMMA_MIN || g > PNG_LIB_GAMMA_MAX) - return 0; /* Includes the uninitialized value 0 */ + if (g < PNG_FP_1) + { + /* An uninitialized gamma is assumed to be sRGB for the simplified API. */ + if (g == 0) + return 0; - return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */); + return png_gamma_significant((g * 11 + 2)/5 /* i.e. *2.2, rounded */); + } + + return 1; } /* Do the main body of a 'png_image_begin_read' function; read the PNG file * header and fill in all the information. This is executed in a safe context, * unlike the init routine above. */ -static int -png_image_is_not_sRGB(png_const_structrp png_ptr) -{ - /* Does the colorspace **not** match sRGB? The flag is only set if the - * answer can be determined reliably. - * - * png_struct::chromaticities always exists since the simplified API - * requires rgb-to-gray. The mDCV, cICP and cHRM chunks may all set it to - * a non-sRGB value, so it needs to be checked but **only** if one of - * those chunks occured in the file. - */ - /* Highest priority: check to be safe. */ - if (png_has_chunk(png_ptr, cICP) || png_has_chunk(png_ptr, mDCV)) - return !chromaticities_match_sRGB(&png_ptr->chromaticities); - - /* If the image is marked as sRGB then it is... */ - if (png_has_chunk(png_ptr, sRGB)) - return 0; - - /* Last stop: cHRM, must check: */ - if (png_has_chunk(png_ptr, cHRM)) - return !chromaticities_match_sRGB(&png_ptr->chromaticities); - - /* Else default to sRGB */ - return 0; -} - static int png_image_read_header(png_voidp argument) { @@ -1281,9 +1279,7 @@ png_image_read_header(png_voidp argument) png_structrp png_ptr = image->opaque->png_ptr; png_inforp info_ptr = image->opaque->info_ptr; -#ifdef PNG_BENIGN_ERRORS_SUPPORTED png_set_benign_errors(png_ptr, 1/*warn*/); -#endif png_read_info(png_ptr, info_ptr); /* Do this the fast way; just read directly out of png_struct. */ @@ -1295,13 +1291,17 @@ png_image_read_header(png_voidp argument) image->format = format; - /* Greyscale images don't (typically) have colour space information and - * using it is pretty much impossible, so use sRGB for grayscale (it - * doesn't matter r==g==b so the transform is irrelevant.) +#ifdef PNG_COLORSPACE_SUPPORTED + /* Does the colorspace match sRGB? If there is no color endpoint + * (colorant) information assume yes, otherwise require the + * 'ENDPOINTS_MATCHE_sRGB' colorspace flag to have been set. If the + * colorspace has been determined to be invalid ignore it. */ - if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && - png_image_is_not_sRGB(png_ptr)) + if ((format & PNG_FORMAT_FLAG_COLOR) != 0 && ((png_ptr->colorspace.flags + & (PNG_COLORSPACE_HAVE_ENDPOINTS|PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB| + PNG_COLORSPACE_INVALID)) == PNG_COLORSPACE_HAVE_ENDPOINTS)) image->flags |= PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB; +#endif } /* We need the maximum number of entries regardless of the format the @@ -1317,7 +1317,7 @@ png_image_read_header(png_voidp argument) break; case PNG_COLOR_TYPE_PALETTE: - cmap_entries = (png_uint_32)png_ptr->num_palette; + cmap_entries = png_ptr->num_palette; break; default: @@ -1336,13 +1336,13 @@ png_image_read_header(png_voidp argument) #ifdef PNG_STDIO_SUPPORTED int PNGAPI -png_image_begin_read_from_stdio(png_imagep image, FILE *file) +png_image_begin_read_from_stdio(png_imagep image, FILE* file) { if (image != NULL && image->version == PNG_IMAGE_VERSION) { if (file != NULL) { - if (png_image_read_init(image) != 0) + if (png_image_read_init(image)) { /* This is slightly evil, but png_init_io doesn't do anything other * than this and we haven't changed the standard IO functions so @@ -1355,12 +1355,12 @@ png_image_begin_read_from_stdio(png_imagep image, FILE *file) else return png_image_error(image, - "png_image_begin_read_from_stdio: invalid argument"); + "png_image_begin_read_from_stdio: invalid argument"); } else if (image != NULL) return png_image_error(image, - "png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION"); + "png_image_begin_read_from_stdio: incorrect PNG_IMAGE_VERSION"); return 0; } @@ -1376,7 +1376,7 @@ png_image_begin_read_from_file(png_imagep image, const char *file_name) if (fp != NULL) { - if (png_image_read_init(image) != 0) + if (png_image_read_init(image)) { image->opaque->png_ptr->io_ptr = fp; image->opaque->owned_file = 1; @@ -1393,19 +1393,19 @@ png_image_begin_read_from_file(png_imagep image, const char *file_name) else return png_image_error(image, - "png_image_begin_read_from_file: invalid argument"); + "png_image_begin_read_from_file: invalid argument"); } else if (image != NULL) return png_image_error(image, - "png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION"); + "png_image_begin_read_from_file: incorrect PNG_IMAGE_VERSION"); return 0; } -#endif /* STDIO */ +#endif /* PNG_STDIO_SUPPORTED */ static void PNGCBAPI -png_image_memory_read(png_structp png_ptr, png_bytep out, size_t need) +png_image_memory_read(png_structp png_ptr, png_bytep out, png_size_t need) { if (png_ptr != NULL) { @@ -1416,7 +1416,7 @@ png_image_memory_read(png_structp png_ptr, png_bytep out, size_t need) if (cp != NULL) { png_const_bytep memory = cp->memory; - size_t size = cp->size; + png_size_t size = cp->size; if (memory != NULL && size >= need) { @@ -1435,13 +1435,13 @@ png_image_memory_read(png_structp png_ptr, png_bytep out, size_t need) } int PNGAPI png_image_begin_read_from_memory(png_imagep image, - png_const_voidp memory, size_t size) + png_const_voidp memory, png_size_t size) { if (image != NULL && image->version == PNG_IMAGE_VERSION) { if (memory != NULL && size > 0) { - if (png_image_read_init(image) != 0) + if (png_image_read_init(image)) { /* Now set the IO functions to read from the memory buffer and * store it into io_ptr. Again do this in-place to avoid calling a @@ -1458,12 +1458,12 @@ int PNGAPI png_image_begin_read_from_memory(png_imagep image, else return png_image_error(image, - "png_image_begin_read_from_memory: invalid argument"); + "png_image_begin_read_from_memory: invalid argument"); } else if (image != NULL) return png_image_error(image, - "png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION"); + "png_image_begin_read_from_memory: incorrect PNG_IMAGE_VERSION"); return 0; } @@ -1483,41 +1483,37 @@ png_image_skip_unused_chunks(png_structrp png_ptr) * * Or image data handling: * - * tRNS, bKGD, gAMA, cHRM, sRGB, [iCCP] and sBIT. + * tRNS, bKGD, gAMA, cHRM, sRGB, iCCP and sBIT. * * This provides a small performance improvement and eliminates any * potential vulnerability to security problems in the unused chunks. - * - * At present the iCCP chunk data isn't used, so iCCP chunk can be ignored - * too. This allows the simplified API to be compiled without iCCP support. */ { - static const png_byte chunks_to_process[] = { + static PNG_CONST png_byte chunks_to_process[] = { 98, 75, 71, 68, '\0', /* bKGD */ 99, 72, 82, 77, '\0', /* cHRM */ - 99, 73, 67, 80, '\0', /* cICP */ 103, 65, 77, 65, '\0', /* gAMA */ - 109, 68, 67, 86, '\0', /* mDCV */ + 105, 67, 67, 80, '\0', /* iCCP */ 115, 66, 73, 84, '\0', /* sBIT */ 115, 82, 71, 66, '\0', /* sRGB */ - }; + }; /* Ignore unknown chunks and all other chunks except for the * IHDR, PLTE, tRNS, IDAT, and IEND chunks. */ png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_NEVER, - NULL, -1); + NULL, -1); /* But do not ignore image data handling chunks */ png_set_keep_unknown_chunks(png_ptr, PNG_HANDLE_CHUNK_AS_DEFAULT, - chunks_to_process, (int)/*SAFE*/(sizeof chunks_to_process)/5); - } + chunks_to_process, (sizeof chunks_to_process)/5); + } } # define PNG_SKIP_CHUNKS(p) png_image_skip_unused_chunks(p) #else # define PNG_SKIP_CHUNKS(p) ((void)0) -#endif /* HANDLE_AS_UNKNOWN */ +#endif /* PNG_HANDLE_AS_UNKNOWN_SUPPORTED */ /* The following macro gives the exact rounded answer for all values in the * range 0..255 (it actually divides by 51.2, but the rounding still generates @@ -1529,38 +1525,30 @@ png_image_skip_unused_chunks(png_structrp png_ptr) static void set_file_encoding(png_image_read_control *display) { - png_structrp png_ptr = display->image->opaque->png_ptr; - png_fixed_point g = png_resolve_file_gamma(png_ptr); - - /* PNGv3: the result may be 0 however the 'default_gamma' should have been - * set before this is called so zero is an error: - */ - if (g == 0) - png_error(png_ptr, "internal: default gamma not set"); - - if (png_gamma_significant(g) != 0) + png_fixed_point g = display->image->opaque->png_ptr->colorspace.gamma; + if (png_gamma_significant(g)) { - if (png_gamma_not_sRGB(g) != 0) + if (png_gamma_not_sRGB(g)) { - display->file_encoding = P_FILE; + display->file_encoding = E_FILE; display->gamma_to_linear = png_reciprocal(g); } else - display->file_encoding = P_sRGB; + display->file_encoding = E_sRGB; } else - display->file_encoding = P_LINEAR8; + display->file_encoding = E_LINEAR8; } static unsigned int decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding) { - if (encoding == P_FILE) /* double check */ + if (encoding == E_FILE) /* double check */ encoding = display->file_encoding; - if (encoding == P_NOTSET) /* must be the file encoding */ + if (encoding == E_NOTSET) /* must be the file encoding */ { set_file_encoding(display); encoding = display->file_encoding; @@ -1568,26 +1556,25 @@ decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding) switch (encoding) { - case P_FILE: + case E_FILE: value = png_gamma_16bit_correct(value*257, display->gamma_to_linear); break; - case P_sRGB: + case E_sRGB: value = png_sRGB_table[value]; break; - case P_LINEAR: + case E_LINEAR: break; - case P_LINEAR8: + case E_LINEAR8: value *= 257; break; -#ifdef __GNUC__ default: png_error(display->image->opaque->png_ptr, - "unexpected encoding (internal error)"); -#endif + "unexpected encoding (internal error)"); + break; } return value; @@ -1595,13 +1582,13 @@ decode_gamma(png_image_read_control *display, png_uint_32 value, int encoding) static png_uint_32 png_colormap_compose(png_image_read_control *display, - png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha, - png_uint_32 background, int encoding) + png_uint_32 foreground, int foreground_encoding, png_uint_32 alpha, + png_uint_32 background, int encoding) { /* The file value is composed on the background, the background has the given - * encoding and so does the result, the file is encoded with P_FILE and the + * encoding and so does the result, the file is encoded with E_FILE and the * file and alpha are 8-bit values. The (output) encoding will always be - * P_LINEAR or P_sRGB. + * E_LINEAR or E_sRGB. */ png_uint_32 f = decode_gamma(display, foreground, foreground_encoding); png_uint_32 b = decode_gamma(display, background, encoding); @@ -1611,7 +1598,7 @@ png_colormap_compose(png_image_read_control *display, */ f = f * alpha + b * (255-alpha); - if (encoding == P_LINEAR) + if (encoding == E_LINEAR) { /* Scale to 65535; divide by 255, approximately (in fact this is extremely * accurate, it divides by 255.00000005937181414556, with no overflow.) @@ -1621,25 +1608,25 @@ png_colormap_compose(png_image_read_control *display, f = (f+32768) >> 16; } - else /* P_sRGB */ + else /* E_sRGB */ f = PNG_sRGB_FROM_LINEAR(f); return f; } -/* NOTE: P_LINEAR values to this routine must be 16-bit, but P_FILE values must +/* NOTE: E_LINEAR values to this routine must be 16-bit, but E_FILE values must * be 8-bit. */ static void png_create_colormap_entry(png_image_read_control *display, - png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue, - png_uint_32 alpha, int encoding) + png_uint_32 ip, png_uint_32 red, png_uint_32 green, png_uint_32 blue, + png_uint_32 alpha, int encoding) { png_imagep image = display->image; - int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) != 0 ? - P_LINEAR : P_sRGB; - int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 && - (red != green || green != blue); + const int output_encoding = (image->format & PNG_FORMAT_FLAG_LINEAR) ? + E_LINEAR : E_sRGB; + const int convert_to_Y = (image->format & PNG_FORMAT_FLAG_COLOR) == 0 && + (red != green || green != blue); if (ip > 255) png_error(image->opaque->png_ptr, "color-map index out of range"); @@ -1647,18 +1634,18 @@ png_create_colormap_entry(png_image_read_control *display, /* Update the cache with whether the file gamma is significantly different * from sRGB. */ - if (encoding == P_FILE) + if (encoding == E_FILE) { - if (display->file_encoding == P_NOTSET) + if (display->file_encoding == E_NOTSET) set_file_encoding(display); - /* Note that the cached value may be P_FILE too, but if it is then the + /* Note that the cached value may be E_FILE too, but if it is then the * gamma_to_linear member has been set. */ encoding = display->file_encoding; } - if (encoding == P_FILE) + if (encoding == E_FILE) { png_fixed_point g = display->gamma_to_linear; @@ -1666,10 +1653,10 @@ png_create_colormap_entry(png_image_read_control *display, green = png_gamma_16bit_correct(green*257, g); blue = png_gamma_16bit_correct(blue*257, g); - if (convert_to_Y != 0 || output_encoding == P_LINEAR) + if (convert_to_Y || output_encoding == E_LINEAR) { alpha *= 257; - encoding = P_LINEAR; + encoding = E_LINEAR; } else @@ -1677,11 +1664,11 @@ png_create_colormap_entry(png_image_read_control *display, red = PNG_sRGB_FROM_LINEAR(red * 255); green = PNG_sRGB_FROM_LINEAR(green * 255); blue = PNG_sRGB_FROM_LINEAR(blue * 255); - encoding = P_sRGB; + encoding = E_sRGB; } } - else if (encoding == P_LINEAR8) + else if (encoding == E_LINEAR8) { /* This encoding occurs quite frequently in test cases because PngSuite * includes a gAMA 1.0 chunk with most images. @@ -1690,11 +1677,10 @@ png_create_colormap_entry(png_image_read_control *display, green *= 257; blue *= 257; alpha *= 257; - encoding = P_LINEAR; + encoding = E_LINEAR; } - else if (encoding == P_sRGB && - (convert_to_Y != 0 || output_encoding == P_LINEAR)) + else if (encoding == E_sRGB && (convert_to_Y || output_encoding == E_LINEAR)) { /* The values are 8-bit sRGB values, but must be converted to 16-bit * linear. @@ -1703,19 +1689,19 @@ png_create_colormap_entry(png_image_read_control *display, green = png_sRGB_table[green]; blue = png_sRGB_table[blue]; alpha *= 257; - encoding = P_LINEAR; + encoding = E_LINEAR; } /* This is set if the color isn't gray but the output is. */ - if (encoding == P_LINEAR) + if (encoding == E_LINEAR) { - if (convert_to_Y != 0) + if (convert_to_Y) { /* NOTE: these values are copied from png_do_rgb_to_gray */ png_uint_32 y = (png_uint_32)6968 * red + (png_uint_32)23434 * green + (png_uint_32)2366 * blue; - if (output_encoding == P_LINEAR) + if (output_encoding == E_LINEAR) y = (y + 16384) >> 15; else @@ -1724,20 +1710,19 @@ png_create_colormap_entry(png_image_read_control *display, y = (y + 128) >> 8; y *= 255; y = PNG_sRGB_FROM_LINEAR((y + 64) >> 7); - alpha = PNG_DIV257(alpha); - encoding = P_sRGB; + encoding = E_sRGB; } blue = red = green = y; } - else if (output_encoding == P_sRGB) + else if (output_encoding == E_sRGB) { red = PNG_sRGB_FROM_LINEAR(red * 255); green = PNG_sRGB_FROM_LINEAR(green * 255); blue = PNG_sRGB_FROM_LINEAR(blue * 255); alpha = PNG_DIV257(alpha); - encoding = P_sRGB; + encoding = E_sRGB; } } @@ -1746,19 +1731,19 @@ png_create_colormap_entry(png_image_read_control *display, /* Store the value. */ { -# ifdef PNG_FORMAT_AFIRST_SUPPORTED - int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 && +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int afirst = (image->format & PNG_FORMAT_FLAG_AFIRST) != 0 && (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; # else # define afirst 0 # endif # ifdef PNG_FORMAT_BGR_SUPPORTED - int bgr = (image->format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; + const int bgr = (image->format & PNG_FORMAT_FLAG_BGR) ? 2 : 0; # else # define bgr 0 # endif - if (output_encoding == P_LINEAR) + if (output_encoding == E_LINEAR) { png_uint_16p entry = png_voidcast(png_uint_16p, display->colormap); @@ -1772,7 +1757,7 @@ png_create_colormap_entry(png_image_read_control *display, { case 4: entry[afirst ? 0 : 3] = (png_uint_16)alpha; - /* FALLTHROUGH */ + /* FALL THROUGH */ case 3: if (alpha < 65535) @@ -1794,7 +1779,7 @@ png_create_colormap_entry(png_image_read_control *display, case 2: entry[1 ^ afirst] = (png_uint_16)alpha; - /* FALLTHROUGH */ + /* FALL THROUGH */ case 1: if (alpha < 65535) @@ -1813,7 +1798,7 @@ png_create_colormap_entry(png_image_read_control *display, } } - else /* output encoding is P_sRGB */ + else /* output encoding is E_sRGB */ { png_bytep entry = png_voidcast(png_bytep, display->colormap); @@ -1823,7 +1808,6 @@ png_create_colormap_entry(png_image_read_control *display, { case 4: entry[afirst ? 0 : 3] = (png_byte)alpha; - /* FALLTHROUGH */ case 3: entry[afirst + (2 ^ bgr)] = (png_byte)blue; entry[afirst + 1] = (png_byte)green; @@ -1832,7 +1816,6 @@ png_create_colormap_entry(png_image_read_control *display, case 2: entry[1 ^ afirst] = (png_byte)alpha; - /* FALLTHROUGH */ case 1: entry[afirst] = (png_byte)green; break; @@ -1857,9 +1840,9 @@ make_gray_file_colormap(png_image_read_control *display) unsigned int i; for (i=0; i<256; ++i) - png_create_colormap_entry(display, i, i, i, i, 255, P_FILE); + png_create_colormap_entry(display, i, i, i, i, 255, E_FILE); - return (int)i; + return i; } static int @@ -1868,9 +1851,9 @@ make_gray_colormap(png_image_read_control *display) unsigned int i; for (i=0; i<256; ++i) - png_create_colormap_entry(display, i, i, i, i, 255, P_sRGB); + png_create_colormap_entry(display, i, i, i, i, 255, E_sRGB); - return (int)i; + return i; } #define PNG_GRAY_COLORMAP_ENTRIES 256 @@ -1907,13 +1890,13 @@ make_ga_colormap(png_image_read_control *display) while (i < 231) { unsigned int gray = (i * 256 + 115) / 231; - png_create_colormap_entry(display, i++, gray, gray, gray, 255, P_sRGB); + png_create_colormap_entry(display, i++, gray, gray, gray, 255, E_sRGB); } /* 255 is used here for the component values for consistency with the code * that undoes premultiplication in pngwrite.c. */ - png_create_colormap_entry(display, i++, 255, 255, 255, 0, P_sRGB); + png_create_colormap_entry(display, i++, 255, 255, 255, 0, E_sRGB); for (a=1; a<5; ++a) { @@ -1921,10 +1904,10 @@ make_ga_colormap(png_image_read_control *display) for (g=0; g<6; ++g) png_create_colormap_entry(display, i++, g*51, g*51, g*51, a*51, - P_sRGB); + E_sRGB); } - return (int)i; + return i; } #define PNG_GA_COLORMAP_ENTRIES 256 @@ -1945,11 +1928,11 @@ make_rgb_colormap(png_image_read_control *display) for (b=0; b<6; ++b) png_create_colormap_entry(display, i++, r*51, g*51, b*51, 255, - P_sRGB); + E_sRGB); } } - return (int)i; + return i; } #define PNG_RGB_COLORMAP_ENTRIES 216 @@ -1963,16 +1946,16 @@ png_image_read_colormap(png_voidp argument) { png_image_read_control *display = png_voidcast(png_image_read_control*, argument); - png_imagep image = display->image; + const png_imagep image = display->image; - png_structrp png_ptr = image->opaque->png_ptr; - png_uint_32 output_format = image->format; - int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) != 0 ? - P_LINEAR : P_sRGB; + const png_structrp png_ptr = image->opaque->png_ptr; + const png_uint_32 output_format = image->format; + const int output_encoding = (output_format & PNG_FORMAT_FLAG_LINEAR) ? + E_LINEAR : E_sRGB; unsigned int cmap_entries; unsigned int output_processing; /* Output processing option */ - unsigned int data_encoding = P_NOTSET; /* Encoding libpng must produce */ + unsigned int data_encoding = E_NOTSET; /* Encoding libpng must produce */ /* Background information; the background color and the index of this color * in the color-map if it exists (else 256). @@ -1992,12 +1975,12 @@ png_image_read_colormap(png_voidp argument) png_ptr->num_trans > 0) /* alpha in input */ && ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) /* no alpha in output */) { - if (output_encoding == P_LINEAR) /* compose on black */ + if (output_encoding == E_LINEAR) /* compose on black */ back_b = back_g = back_r = 0; else if (display->background == NULL /* no way to remove it */) png_error(png_ptr, - "background color must be supplied to remove alpha/transparency"); + "a background color must be supplied to remove alpha/transparency"); /* Get a copy of the background color (this avoids repeating the checks * below.) The encoding is 8-bit sRGB or 16-bit linear, depending on the @@ -2006,7 +1989,7 @@ png_image_read_colormap(png_voidp argument) else { back_g = display->background->green; - if ((output_format & PNG_FORMAT_FLAG_COLOR) != 0) + if (output_format & PNG_FORMAT_FLAG_COLOR) { back_r = display->background->red; back_b = display->background->blue; @@ -2016,7 +1999,7 @@ png_image_read_colormap(png_voidp argument) } } - else if (output_encoding == P_LINEAR) + else if (output_encoding == E_LINEAR) back_b = back_r = back_g = 65535; else @@ -2025,18 +2008,24 @@ png_image_read_colormap(png_voidp argument) /* Default the input file gamma if required - this is necessary because * libpng assumes that if no gamma information is present the data is in the * output format, but the simplified API deduces the gamma from the input - * format. The 'default' gamma value is also set by png_set_alpha_mode, but - * this is happening before any such call, so: - * - * TODO: should be an internal API and all this code should be copied into a - * single common gamma+colorspace file. + * format. */ - if (png_ptr->bit_depth == 16 && - (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) - png_ptr->default_gamma = PNG_GAMMA_LINEAR; + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_GAMMA) == 0) + { + /* Do this directly, not using the png_colorspace functions, to ensure + * that it happens even if the colorspace is invalid (though probably if + * it is the setting will be ignored) Note that the same thing can be + * achieved at the application interface with png_set_gAMA. + */ + if (png_ptr->bit_depth == 16 && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + png_ptr->colorspace.gamma = PNG_GAMMA_LINEAR; - else - png_ptr->default_gamma = PNG_GAMMA_sRGB_INVERSE; + else + png_ptr->colorspace.gamma = PNG_GAMMA_sRGB_INVERSE; + + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + } /* Decide what to do based on the PNG color type of the input data. The * utility function png_create_colormap_entry deals with most aspects of the @@ -2068,7 +2057,7 @@ png_image_read_colormap(png_voidp argument) trans = png_ptr->trans_color.gray; if ((output_format & PNG_FORMAT_FLAG_ALPHA) == 0) - back_alpha = output_encoding == P_LINEAR ? 65535 : 255; + back_alpha = output_encoding == E_LINEAR ? 65535 : 255; } /* png_create_colormap_entry just takes an RGBA and writes the @@ -2086,7 +2075,7 @@ png_image_read_colormap(png_voidp argument) */ if (i != trans) png_create_colormap_entry(display, i, val, val, val, 255, - P_FILE/*8-bit with file gamma*/); + E_FILE/*8-bit with file gamma*/); /* Else this entry is transparent. The colors don't matter if * there is an alpha channel (back_alpha == 0), but it does no @@ -2098,14 +2087,14 @@ png_image_read_colormap(png_voidp argument) */ else png_create_colormap_entry(display, i, back_r, back_g, back_b, - back_alpha, output_encoding); + back_alpha, output_encoding); } /* We need libpng to preserve the original encoding. */ - data_encoding = P_FILE; + data_encoding = E_FILE; /* The rows from libpng, while technically gray values, are now also - * color-map indices; however, they may need to be expanded to 1 + * color-map indicies; however, they may need to be expanded to 1 * byte per pixel. This is what png_set_packing does (i.e., it * unpacks the bit values into bytes.) */ @@ -2131,18 +2120,18 @@ png_image_read_colormap(png_voidp argument) * ensuring that the corresponding gray level matches the background * color exactly. */ - data_encoding = P_sRGB; + data_encoding = E_sRGB; if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "gray[16] color-map: too few entries"); - cmap_entries = (unsigned int)make_gray_colormap(display); + cmap_entries = make_gray_colormap(display); if (png_ptr->num_trans > 0) { unsigned int back_alpha; - if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + if (output_format & PNG_FORMAT_FLAG_ALPHA) back_alpha = 0; else @@ -2155,7 +2144,7 @@ png_image_read_colormap(png_voidp argument) png_color_16 c; png_uint_32 gray = back_g; - if (output_encoding == P_LINEAR) + if (output_encoding == E_LINEAR) { gray = PNG_sRGB_FROM_LINEAR(gray * 255); @@ -2163,7 +2152,7 @@ png_image_read_colormap(png_voidp argument) * matches. */ png_create_colormap_entry(display, gray, back_g, back_g, - back_g, 65535, P_LINEAR); + back_g, 65535, E_LINEAR); } /* The background passed to libpng, however, must be the @@ -2177,28 +2166,22 @@ png_image_read_colormap(png_voidp argument) * doesn't. */ png_set_background_fixed(png_ptr, &c, - PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, - 0/*gamma: not used*/); + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); output_processing = PNG_CMAP_NONE; break; } -#ifdef __COVERITY__ - /* Coverity claims that output_encoding cannot be 2 (P_LINEAR) - * here. - */ - back_alpha = 255; -#else - back_alpha = output_encoding == P_LINEAR ? 65535 : 255; -#endif + + back_alpha = output_encoding == E_LINEAR ? 65535 : 255; } /* output_processing means that the libpng-processed row will be * 8-bit GA and it has to be processing to single byte color-map * values. Entry 254 is replaced by either a completely * transparent entry or by the background color at full - * precision (and the background color is not a simple gray - * level in this case.) + * precision (and the background color is not a simple gray leve + * in this case.) */ expand_tRNS = 1; output_processing = PNG_CMAP_TRANS; @@ -2208,7 +2191,7 @@ png_image_read_colormap(png_voidp argument) * background color at full precision. */ png_create_colormap_entry(display, 254, back_r, back_g, back_b, - back_alpha, output_encoding); + back_alpha, output_encoding); } else @@ -2227,14 +2210,14 @@ png_image_read_colormap(png_voidp argument) * worry about tRNS matching - tRNS is ignored if there is an alpha * channel. */ - data_encoding = P_sRGB; + data_encoding = E_sRGB; - if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + if (output_format & PNG_FORMAT_FLAG_ALPHA) { if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "gray+alpha color-map: too few entries"); - cmap_entries = (unsigned int)make_ga_colormap(display); + cmap_entries = make_ga_colormap(display); background_index = PNG_CMAP_GA_BACKGROUND; output_processing = PNG_CMAP_GA; @@ -2268,15 +2251,15 @@ png_image_read_colormap(png_voidp argument) if (PNG_GRAY_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "gray-alpha color-map: too few entries"); - cmap_entries = (unsigned int)make_gray_colormap(display); + cmap_entries = make_gray_colormap(display); - if (output_encoding == P_LINEAR) + if (output_encoding == E_LINEAR) { gray = PNG_sRGB_FROM_LINEAR(gray * 255); /* And make sure the corresponding palette entry matches. */ png_create_colormap_entry(display, gray, back_g, back_g, - back_g, 65535, P_LINEAR); + back_g, 65535, E_LINEAR); } /* The background passed to libpng, however, must be the sRGB @@ -2286,8 +2269,8 @@ png_image_read_colormap(png_voidp argument) c.gray = c.red = c.green = c.blue = (png_uint_16)gray; png_set_background_fixed(png_ptr, &c, - PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, - 0/*gamma: not used*/); + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); output_processing = PNG_CMAP_NONE; } @@ -2307,7 +2290,7 @@ png_image_read_colormap(png_voidp argument) { png_uint_32 gray = (i * 256 + 115) / 231; png_create_colormap_entry(display, i++, gray, gray, gray, - 255, P_sRGB); + 255, E_sRGB); } /* NOTE: this preserves the full precision of the application @@ -2315,14 +2298,7 @@ png_image_read_colormap(png_voidp argument) */ background_index = i; png_create_colormap_entry(display, i++, back_r, back_g, back_b, -#ifdef __COVERITY__ - /* Coverity claims that output_encoding - * cannot be 2 (P_LINEAR) here. - */ 255U, -#else - output_encoding == P_LINEAR ? 65535U : 255U, -#endif - output_encoding); + output_encoding == E_LINEAR ? 65535U : 255U, output_encoding); /* For non-opaque input composite on the sRGB background - this * requires inverting the encoding for each component. The input @@ -2332,7 +2308,7 @@ png_image_read_colormap(png_voidp argument) * represents. Consequently 'G' is always sRGB encoded, while * 'A' is linear. We need the linear background colors. */ - if (output_encoding == P_sRGB) /* else already linear */ + if (output_encoding == E_sRGB) /* else already linear */ { /* This may produce a value not exactly matching the * background, but that's ok because these numbers are only @@ -2360,9 +2336,9 @@ png_image_read_colormap(png_voidp argument) png_uint_32 gray = png_sRGB_table[g*51] * alpha; png_create_colormap_entry(display, i++, - PNG_sRGB_FROM_LINEAR(gray + back_rx), - PNG_sRGB_FROM_LINEAR(gray + back_gx), - PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, P_sRGB); + PNG_sRGB_FROM_LINEAR(gray + back_rx), + PNG_sRGB_FROM_LINEAR(gray + back_gx), + PNG_sRGB_FROM_LINEAR(gray + back_bx), 255, E_sRGB); } } @@ -2388,8 +2364,8 @@ png_image_read_colormap(png_voidp argument) * png_set_tRNS_to_alpha before png_set_background_fixed. */ png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, -1, - -1); - data_encoding = P_sRGB; + -1); + data_encoding = E_sRGB; /* The output will now be one or two 8-bit gray or gray+alpha * channels. The more complex case arises when the input has alpha. @@ -2407,15 +2383,13 @@ png_image_read_colormap(png_voidp argument) if (PNG_GA_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "rgb[ga] color-map: too few entries"); - cmap_entries = (unsigned int)make_ga_colormap(display); + cmap_entries = make_ga_colormap(display); background_index = PNG_CMAP_GA_BACKGROUND; output_processing = PNG_CMAP_GA; } else { - const png_fixed_point gamma = png_resolve_file_gamma(png_ptr); - /* Either the input or the output has no alpha channel, so there * will be no non-opaque pixels in the color-map; it will just be * grayscale. @@ -2430,20 +2404,17 @@ png_image_read_colormap(png_voidp argument) * this case and doing it in the palette; this will result in * duplicate palette entries, but that's better than the * alternative of double gamma correction. - * - * NOTE: PNGv3: check the resolved result of all the potentially - * different colour space chunks. */ if ((png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || png_ptr->num_trans > 0) && - png_gamma_not_sRGB(gamma) != 0) + png_gamma_not_sRGB(png_ptr->colorspace.gamma)) { - cmap_entries = (unsigned int)make_gray_file_colormap(display); - data_encoding = P_FILE; + cmap_entries = make_gray_file_colormap(display); + data_encoding = E_FILE; } else - cmap_entries = (unsigned int)make_gray_colormap(display); + cmap_entries = make_gray_colormap(display); /* But if the input has alpha or transparency it must be removed */ @@ -2458,34 +2429,34 @@ png_image_read_colormap(png_voidp argument) * it. Achieve this simply by ensuring that the entry * selected for the background really is the background color. */ - if (data_encoding == P_FILE) /* from the fixup above */ + if (data_encoding == E_FILE) /* from the fixup above */ { /* The app supplied a gray which is in output_encoding, we - * need to convert it to a value of the input (P_FILE) + * need to convert it to a value of the input (E_FILE) * encoding then set this palette entry to the required * output encoding. */ - if (output_encoding == P_sRGB) - gray = png_sRGB_table[gray]; /* now P_LINEAR */ + if (output_encoding == E_sRGB) + gray = png_sRGB_table[gray]; /* now E_LINEAR */ - gray = PNG_DIV257(png_gamma_16bit_correct(gray, gamma)); - /* now P_FILE */ + gray = PNG_DIV257(png_gamma_16bit_correct(gray, + png_ptr->colorspace.gamma)); /* now E_FILE */ /* And make sure the corresponding palette entry contains * exactly the required sRGB value. */ png_create_colormap_entry(display, gray, back_g, back_g, - back_g, 0/*unused*/, output_encoding); + back_g, 0/*unused*/, output_encoding); } - else if (output_encoding == P_LINEAR) + else if (output_encoding == E_LINEAR) { gray = PNG_sRGB_FROM_LINEAR(gray * 255); /* And make sure the corresponding palette entry matches. */ png_create_colormap_entry(display, gray, back_g, back_g, - back_g, 0/*unused*/, P_LINEAR); + back_g, 0/*unused*/, E_LINEAR); } /* The background passed to libpng, however, must be the @@ -2500,8 +2471,8 @@ png_image_read_colormap(png_voidp argument) */ expand_tRNS = 1; png_set_background_fixed(png_ptr, &c, - PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, - 0/*gamma: not used*/); + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); } output_processing = PNG_CMAP_NONE; @@ -2515,7 +2486,7 @@ png_image_read_colormap(png_voidp argument) * to do it once and using PNG_DIV51 on the 6x6x6 reduced RGB cube. * Consequently we always want libpng to produce sRGB data. */ - data_encoding = P_sRGB; + data_encoding = E_sRGB; /* Is there any transparency or alpha? */ if (png_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA || @@ -2524,18 +2495,18 @@ png_image_read_colormap(png_voidp argument) /* Is there alpha in the output too? If so all four channels are * processed into a special RGB cube with alpha support. */ - if ((output_format & PNG_FORMAT_FLAG_ALPHA) != 0) + if (output_format & PNG_FORMAT_FLAG_ALPHA) { png_uint_32 r; if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) png_error(png_ptr, "rgb+alpha color-map: too few entries"); - cmap_entries = (unsigned int)make_rgb_colormap(display); + cmap_entries = make_rgb_colormap(display); /* Add a transparent entry. */ png_create_colormap_entry(display, cmap_entries, 255, 255, - 255, 0, P_sRGB); + 255, 0, E_sRGB); /* This is stored as the background index for the processing * algorithm. @@ -2556,7 +2527,7 @@ png_image_read_colormap(png_voidp argument) */ for (b=0; b<256; b = (b << 1) | 0x7f) png_create_colormap_entry(display, cmap_entries++, - r, g, b, 128, P_sRGB); + r, g, b, 128, E_sRGB); } } @@ -2580,12 +2551,12 @@ png_image_read_colormap(png_voidp argument) if (PNG_RGB_COLORMAP_ENTRIES+1+27 > image->colormap_entries) png_error(png_ptr, "rgb-alpha color-map: too few entries"); - cmap_entries = (unsigned int)make_rgb_colormap(display); + cmap_entries = make_rgb_colormap(display); png_create_colormap_entry(display, cmap_entries, back_r, - back_g, back_b, 0/*unused*/, output_encoding); + back_g, back_b, 0/*unused*/, output_encoding); - if (output_encoding == P_LINEAR) + if (output_encoding == E_LINEAR) { r = PNG_sRGB_FROM_LINEAR(back_r * 255); g = PNG_sRGB_FROM_LINEAR(back_g * 255); @@ -2605,9 +2576,9 @@ png_image_read_colormap(png_voidp argument) * index. */ if (memcmp((png_const_bytep)display->colormap + - sample_size * cmap_entries, - (png_const_bytep)display->colormap + - sample_size * PNG_RGB_INDEX(r,g,b), + sample_size * cmap_entries, + (png_const_bytep)display->colormap + + sample_size * PNG_RGB_INDEX(r,g,b), sample_size) != 0) { /* The background color must be added. */ @@ -2625,13 +2596,13 @@ png_image_read_colormap(png_voidp argument) */ for (b=0; b<256; b = (b << 1) | 0x7f) png_create_colormap_entry(display, cmap_entries++, - png_colormap_compose(display, r, P_sRGB, 128, - back_r, output_encoding), - png_colormap_compose(display, g, P_sRGB, 128, - back_g, output_encoding), - png_colormap_compose(display, b, P_sRGB, 128, - back_b, output_encoding), - 0/*unused*/, output_encoding); + png_colormap_compose(display, r, E_sRGB, 128, + back_r, output_encoding), + png_colormap_compose(display, g, E_sRGB, 128, + back_g, output_encoding), + png_colormap_compose(display, b, E_sRGB, 128, + back_b, output_encoding), + 0/*unused*/, output_encoding); } } @@ -2649,8 +2620,8 @@ png_image_read_colormap(png_voidp argument) c.blue = (png_uint_16)back_b; png_set_background_fixed(png_ptr, &c, - PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, - 0/*gamma: not used*/); + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); output_processing = PNG_CMAP_RGB; } @@ -2665,7 +2636,7 @@ png_image_read_colormap(png_voidp argument) if (PNG_RGB_COLORMAP_ENTRIES > image->colormap_entries) png_error(png_ptr, "rgb color-map: too few entries"); - cmap_entries = (unsigned int)make_rgb_colormap(display); + cmap_entries = make_rgb_colormap(display); output_processing = PNG_CMAP_RGB; } } @@ -2679,7 +2650,7 @@ png_image_read_colormap(png_voidp argument) unsigned int num_trans = png_ptr->num_trans; png_const_bytep trans = num_trans > 0 ? png_ptr->trans_alpha : NULL; png_const_colorp colormap = png_ptr->palette; - int do_background = trans != NULL && + const int do_background = trans != NULL && (output_format & PNG_FORMAT_FLAG_ALPHA) == 0; unsigned int i; @@ -2688,21 +2659,21 @@ png_image_read_colormap(png_voidp argument) num_trans = 0; output_processing = PNG_CMAP_NONE; - data_encoding = P_FILE; /* Don't change from color-map indices */ - cmap_entries = (unsigned int)png_ptr->num_palette; + data_encoding = E_FILE; /* Don't change from color-map indicies */ + cmap_entries = png_ptr->num_palette; if (cmap_entries > 256) cmap_entries = 256; - if (cmap_entries > (unsigned int)image->colormap_entries) + if (cmap_entries > image->colormap_entries) png_error(png_ptr, "palette color-map: too few entries"); for (i=0; i < cmap_entries; ++i) { - if (do_background != 0 && i < num_trans && trans[i] < 255) + if (do_background && i < num_trans && trans[i] < 255) { if (trans[i] == 0) png_create_colormap_entry(display, i, back_r, back_g, - back_b, 0, output_encoding); + back_b, 0, output_encoding); else { @@ -2710,25 +2681,25 @@ png_image_read_colormap(png_voidp argument) * on the sRGB color in 'back'. */ png_create_colormap_entry(display, i, - png_colormap_compose(display, colormap[i].red, - P_FILE, trans[i], back_r, output_encoding), - png_colormap_compose(display, colormap[i].green, - P_FILE, trans[i], back_g, output_encoding), - png_colormap_compose(display, colormap[i].blue, - P_FILE, trans[i], back_b, output_encoding), - output_encoding == P_LINEAR ? trans[i] * 257U : - trans[i], - output_encoding); + png_colormap_compose(display, colormap[i].red, E_FILE, + trans[i], back_r, output_encoding), + png_colormap_compose(display, colormap[i].green, E_FILE, + trans[i], back_g, output_encoding), + png_colormap_compose(display, colormap[i].blue, E_FILE, + trans[i], back_b, output_encoding), + output_encoding == E_LINEAR ? trans[i] * 257U : + trans[i], + output_encoding); } } else png_create_colormap_entry(display, i, colormap[i].red, - colormap[i].green, colormap[i].blue, - i < num_trans ? trans[i] : 255U, P_FILE/*8-bit*/); + colormap[i].green, colormap[i].blue, + i < num_trans ? trans[i] : 255U, E_FILE/*8-bit*/); } - /* The PNG data may have indices packed in fewer than 8 bits, it + /* The PNG data may have indicies packed in fewer than 8 bits, it * must be expanded if so. */ if (png_ptr->bit_depth < 8) @@ -2739,29 +2710,29 @@ png_image_read_colormap(png_voidp argument) default: png_error(png_ptr, "invalid PNG color type"); /*NOT REACHED*/ + break; } /* Now deal with the output processing */ - if (expand_tRNS != 0 && png_ptr->num_trans > 0 && - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0) + if (expand_tRNS && png_ptr->num_trans > 0 && + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0) png_set_tRNS_to_alpha(png_ptr); switch (data_encoding) { - case P_sRGB: + default: + png_error(png_ptr, "bad data option (internal error)"); + break; + + case E_sRGB: /* Change to 8-bit sRGB */ png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, PNG_GAMMA_sRGB); - /* FALLTHROUGH */ + /* FALL THROUGH */ - case P_FILE: + case E_FILE: if (png_ptr->bit_depth > 8) png_set_scale_16(png_ptr); break; - -#ifdef __GNUC__ - default: - png_error(png_ptr, "bad data option (internal error)"); -#endif } if (cmap_entries > 256 || cmap_entries > image->colormap_entries) @@ -2805,7 +2776,7 @@ png_image_read_colormap(png_voidp argument) png_error(png_ptr, "bad background index (internal error)"); } - display->colormap_processing = (int)output_processing; + display->colormap_processing = output_processing; return 1/*ok*/; } @@ -2815,7 +2786,7 @@ static int png_image_read_and_map(png_voidp argument) { png_image_read_control *display = png_voidcast(png_image_read_control*, - argument); + argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; int passes; @@ -2835,21 +2806,22 @@ png_image_read_and_map(png_voidp argument) break; default: + passes = 0; png_error(png_ptr, "unknown interlace type"); } { - png_uint_32 height = image->height; - png_uint_32 width = image->width; - int proc = display->colormap_processing; - png_bytep first_row = png_voidcast(png_bytep, display->first_row); - ptrdiff_t row_step = display->row_step; + png_uint_32 height = image->height; + png_uint_32 width = image->width; + int proc = display->colormap_processing; + png_bytep first_row = png_voidcast(png_bytep, display->first_row); + ptrdiff_t step_row = display->row_bytes; int pass; for (pass = 0; pass < passes; ++pass) { - unsigned int startx, stepx, stepy; - png_uint_32 y; + unsigned int startx, stepx, stepy; + png_uint_32 y; if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) { @@ -2873,7 +2845,7 @@ png_image_read_and_map(png_voidp argument) for (; ylocal_row); - png_bytep outrow = first_row + y * row_step; + png_bytep outrow = first_row + y * step_row; png_const_bytep end_row = outrow + width; /* Read read the libpng data into the temporary buffer. */ @@ -2952,7 +2924,7 @@ png_image_read_and_map(png_voidp argument) if (alpha >= 196) *outrow = PNG_RGB_INDEX(inrow[0], inrow[1], - inrow[2]); + inrow[2]); else if (alpha < 64) *outrow = PNG_CMAP_RGB_ALPHA_BACKGROUND; @@ -3004,7 +2976,7 @@ static int png_image_read_colormapped(png_voidp argument) { png_image_read_control *display = png_voidcast(png_image_read_control*, - argument); + argument); png_imagep image = display->image; png_controlp control = image->opaque; png_structrp png_ptr = control->png_ptr; @@ -3069,7 +3041,8 @@ png_image_read_colormapped(png_voidp argument) image->colormap_entries == 244 /* 216 + 1 + 27 */) break; - goto bad_output; + /* goto bad_output; */ + /* FALL THROUGH */ default: bad_output: @@ -3082,20 +3055,20 @@ png_image_read_colormapped(png_voidp argument) */ { png_voidp first_row = display->buffer; - ptrdiff_t row_step = display->row_stride; + ptrdiff_t row_bytes = display->row_stride; - /* The following adjustment is to ensure that calculations are correct, - * regardless whether row_step is positive or negative. + /* The following expression is designed to work correctly whether it gives + * a signed or an unsigned result. */ - if (row_step < 0) + if (row_bytes < 0) { char *ptr = png_voidcast(char*, first_row); - ptr += (image->height-1) * (-row_step); + ptr += (image->height-1) * (-row_bytes); first_row = png_voidcast(png_voidp, ptr); } display->first_row = first_row; - display->row_step = row_step; + display->row_bytes = row_bytes; } if (passes == 0) @@ -3113,17 +3086,17 @@ png_image_read_colormapped(png_voidp argument) else { - ptrdiff_t row_step = display->row_step; + png_alloc_size_t row_bytes = display->row_bytes; while (--passes >= 0) { - png_uint_32 y = image->height; - png_bytep row = png_voidcast(png_bytep, display->first_row); + png_uint_32 y = image->height; + png_bytep row = png_voidcast(png_bytep, display->first_row); - for (; y > 0; --y) + while (y-- > 0) { png_read_row(png_ptr, row, NULL); - row += row_step; + row += row_bytes; } } @@ -3131,67 +3104,12 @@ png_image_read_colormapped(png_voidp argument) } } -/* Row reading for interlaced 16-to-8 bit depth conversion with local buffer. */ -static int -png_image_read_direct_scaled(png_voidp argument) -{ - png_image_read_control *display = png_voidcast(png_image_read_control*, - argument); - png_imagep image = display->image; - png_structrp png_ptr = image->opaque->png_ptr; - png_inforp info_ptr = image->opaque->info_ptr; - png_bytep local_row = png_voidcast(png_bytep, display->local_row); - png_bytep first_row = png_voidcast(png_bytep, display->first_row); - ptrdiff_t row_step = display->row_step; - size_t row_bytes = png_get_rowbytes(png_ptr, info_ptr); - int passes; - - /* Handle interlacing. */ - switch (png_ptr->interlaced) - { - case PNG_INTERLACE_NONE: - passes = 1; - break; - - case PNG_INTERLACE_ADAM7: - passes = PNG_INTERLACE_ADAM7_PASSES; - break; - - default: - png_error(png_ptr, "unknown interlace type"); - } - - /* Read each pass using local_row as intermediate buffer. */ - while (--passes >= 0) - { - png_uint_32 y = image->height; - png_bytep output_row = first_row; - - for (; y > 0; --y) - { - /* Read into local_row (gets transformed 8-bit data). */ - png_read_row(png_ptr, local_row, NULL); - - /* Copy from local_row to user buffer. - * Use row_bytes (i.e. the actual size in bytes of the row data) for - * copying into output_row. Use row_step for advancing output_row, - * to respect the caller's stride for padding or negative (bottom-up) - * layouts. - */ - memcpy(output_row, local_row, row_bytes); - output_row += row_step; - } - } - - return 1; -} - /* Just the row reading part of png_image_read. */ static int png_image_read_composite(png_voidp argument) { png_image_read_control *display = png_voidcast(png_image_read_control*, - argument); + argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; int passes; @@ -3207,22 +3125,21 @@ png_image_read_composite(png_voidp argument) break; default: + passes = 0; png_error(png_ptr, "unknown interlace type"); } { - png_uint_32 height = image->height; - png_uint_32 width = image->width; - ptrdiff_t row_step = display->row_step; - unsigned int channels = - (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? 3 : 1; - int optimize_alpha = (png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0; + png_uint_32 height = image->height; + png_uint_32 width = image->width; + ptrdiff_t step_row = display->row_bytes; + unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; int pass; for (pass = 0; pass < passes; ++pass) { - unsigned int startx, stepx, stepy; - png_uint_32 y; + unsigned int startx, stepx, stepy; + png_uint_32 y; if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) { @@ -3254,7 +3171,7 @@ png_image_read_composite(png_voidp argument) png_read_row(png_ptr, inrow, NULL); outrow = png_voidcast(png_bytep, display->first_row); - outrow += y * row_step; + outrow += y * step_row; end_row = outrow + width * channels; /* Now do the composition on each pixel in this row. */ @@ -3273,44 +3190,20 @@ png_image_read_composite(png_voidp argument) if (alpha < 255) /* else just use component */ { - if (optimize_alpha != 0) - { - /* This is PNG_OPTIMIZED_ALPHA, the component value - * is a linear 8-bit value. Combine this with the - * current outrow[c] value which is sRGB encoded. - * Arithmetic here is 16-bits to preserve the output - * values correctly. - */ - component *= 257*255; /* =65535 */ - component += (255-alpha)*png_sRGB_table[outrow[c]]; + /* This is PNG_OPTIMIZED_ALPHA, the component value + * is a linear 8-bit value. Combine this with the + * current outrow[c] value which is sRGB encoded. + * Arithmetic here is 16-bits to preserve the output + * values correctly. + */ + component *= 257*255; /* =65535 */ + component += (255-alpha)*png_sRGB_table[outrow[c]]; - /* Clamp to the valid range to defend against - * unforeseen cases where the data might be sRGB - * instead of linear premultiplied. - * (Belt-and-suspenders for CVE-2025-66293.) - */ - if (component > 255*65535) - component = 255*65535; - - /* So 'component' is scaled by 255*65535 and is - * therefore appropriate for the sRGB-to-linear - * conversion table. - */ - component = PNG_sRGB_FROM_LINEAR(component); - } - else - { - /* Compositing was already done on the palette - * entries. The data is sRGB premultiplied on black. - * Composite with the background in sRGB space. - * This is not gamma-correct, but matches what was - * done to the palette. - */ - png_uint_32 background = outrow[c]; - component += ((255-alpha) * background + 127) / 255; - if (component > 255) - component = 255; - } + /* So 'component' is scaled by 255*65535 and is + * therefore appropriate for the sRGB to linear + * conversion table. + */ + component = PNG_sRGB_FROM_LINEAR(component); } outrow[c] = (png_byte)component; @@ -3333,17 +3226,17 @@ png_image_read_composite(png_voidp argument) * PNG_COMPOSITE * PNG_GAMMA * - * This is a work-around for the fact that both the PNG_RGB_TO_GRAY and + * This is a work-round for the fact that both the PNG_RGB_TO_GRAY and * PNG_COMPOSITE code performs gamma correction, so we get double gamma - * correction. The fix-up is to prevent the PNG_COMPOSITE operation from - * happening inside libpng, so this routine sees an 8 or 16-bit gray+alpha - * row and handles the removal or pre-multiplication of the alpha channel. + * correction. The fix-up is to prevent the PNG_COMPOSITE operation happening + * inside libpng, so this routine sees an 8 or 16-bit gray+alpha row and handles + * the removal or pre-multiplication of the alpha channel. */ static int png_image_read_background(png_voidp argument) { png_image_read_control *display = png_voidcast(png_image_read_control*, - argument); + argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; png_inforp info_ptr = image->opaque->info_ptr; @@ -3381,30 +3274,32 @@ png_image_read_background(png_voidp argument) break; default: + passes = 0; png_error(png_ptr, "unknown interlace type"); } - /* Use direct access to info_ptr here because otherwise the simplified API - * would require PNG_EASY_ACCESS_SUPPORTED (just for this.) Note this is - * checking the value after libpng expansions, not the original value in the - * PNG. - */ - switch (info_ptr->bit_depth) + switch (png_get_bit_depth(png_ptr, info_ptr)) { + default: + png_error(png_ptr, "unexpected bit depth"); + break; + case 8: /* 8-bit sRGB gray values with an alpha channel; the alpha channel is - * to be removed by composing on a background: either the row if + * to be removed by composing on a backgroundi: either the row if * display->background is NULL or display->background->green if not. * Unlike the code above ALPHA_OPTIMIZED has *not* been done. */ { png_bytep first_row = png_voidcast(png_bytep, display->first_row); - ptrdiff_t row_step = display->row_step; + ptrdiff_t step_row = display->row_bytes; for (pass = 0; pass < passes; ++pass) { - unsigned int startx, stepx, stepy; - png_uint_32 y; + png_bytep row = png_voidcast(png_bytep, + display->first_row); + unsigned int startx, stepx, stepy; + png_uint_32 y; if (png_ptr->interlaced == PNG_INTERLACE_ADAM7) { @@ -3430,8 +3325,8 @@ png_image_read_background(png_voidp argument) for (; ylocal_row); - png_bytep outrow = first_row + y * row_step; + display->local_row); + png_bytep outrow = first_row + y * step_row; png_const_bytep end_row = outrow + width; /* Read the row, which is packed: */ @@ -3475,8 +3370,8 @@ png_image_read_background(png_voidp argument) for (; ylocal_row); - png_bytep outrow = first_row + y * row_step; + display->local_row); + png_bytep outrow = first_row + y * step_row; png_const_bytep end_row = outrow + width; /* Read the row, which is packed: */ @@ -3507,6 +3402,8 @@ png_image_read_background(png_voidp argument) inrow += 2; /* gray and alpha channel */ } + + row += display->row_bytes; } } } @@ -3520,26 +3417,22 @@ png_image_read_background(png_voidp argument) */ { png_uint_16p first_row = png_voidcast(png_uint_16p, - display->first_row); + display->first_row); /* The division by two is safe because the caller passed in a - * stride which was multiplied by 2 (below) to get row_step. + * stride which was multiplied by 2 (below) to get row_bytes. */ - ptrdiff_t row_step = display->row_step / 2; - unsigned int preserve_alpha = (image->format & - PNG_FORMAT_FLAG_ALPHA) != 0; - unsigned int outchannels = 1U+preserve_alpha; + ptrdiff_t step_row = display->row_bytes / 2; + int preserve_alpha = (image->format & PNG_FORMAT_FLAG_ALPHA) != 0; + unsigned int outchannels = 1+preserve_alpha; int swap_alpha = 0; -# ifdef PNG_SIMPLIFIED_READ_AFIRST_SUPPORTED - if (preserve_alpha != 0 && - (image->format & PNG_FORMAT_FLAG_AFIRST) != 0) - swap_alpha = 1; -# endif + if (preserve_alpha && (image->format & PNG_FORMAT_FLAG_AFIRST)) + swap_alpha = 1; for (pass = 0; pass < passes; ++pass) { - unsigned int startx, stepx, stepy; - png_uint_32 y; + unsigned int startx, stepx, stepy; + png_uint_32 y; /* The 'x' start and step are adjusted to output components here. */ @@ -3566,12 +3459,12 @@ png_image_read_background(png_voidp argument) for (; ylocal_row), NULL); + display->local_row), NULL); inrow = png_voidcast(png_const_uint_16p, display->local_row); /* Now do the pre-multiplication on each pixel in this row. @@ -3596,7 +3489,7 @@ png_image_read_background(png_voidp argument) component = 0; outrow[swap_alpha] = (png_uint_16)component; - if (preserve_alpha != 0) + if (preserve_alpha) outrow[1 ^ swap_alpha] = alpha; inrow += 2; /* components and alpha channel */ @@ -3605,11 +3498,6 @@ png_image_read_background(png_voidp argument) } } break; - -#ifdef __GNUC__ - default: - png_error(png_ptr, "unexpected bit depth"); -#endif } return 1; @@ -3620,7 +3508,7 @@ static int png_image_read_direct(png_voidp argument) { png_image_read_control *display = png_voidcast(png_image_read_control*, - argument); + argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; png_inforp info_ptr = image->opaque->info_ptr; @@ -3629,7 +3517,6 @@ png_image_read_direct(png_voidp argument) int linear = (format & PNG_FORMAT_FLAG_LINEAR) != 0; int do_local_compose = 0; int do_local_background = 0; /* to avoid double gamma correction bug */ - int do_local_scale = 0; /* for interlaced 16-to-8 bit conversion */ int passes = 0; /* Add transforms to ensure the correct output format is produced then check @@ -3647,10 +3534,10 @@ png_image_read_direct(png_voidp argument) int mode; /* alpha mode */ /* Do this first so that we have a record if rgb to gray is happening. */ - if ((change & PNG_FORMAT_FLAG_COLOR) != 0) + if (change & PNG_FORMAT_FLAG_COLOR) { /* gray<->color transformation required. */ - if ((format & PNG_FORMAT_FLAG_COLOR) != 0) + if (format & PNG_FORMAT_FLAG_COLOR) png_set_gray_to_rgb(png_ptr); else @@ -3668,11 +3555,11 @@ png_image_read_direct(png_voidp argument) * enormous change) 'do_local_background' is used to indicate that * the problem exists. */ - if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + if (base_format & PNG_FORMAT_FLAG_ALPHA) do_local_background = 1/*maybe*/; png_set_rgb_to_gray_fixed(png_ptr, PNG_ERROR_ACTION_NONE, - PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); + PNG_RGB_TO_GRAY_DEFAULT, PNG_RGB_TO_GRAY_DEFAULT); } change &= ~PNG_FORMAT_FLAG_COLOR; @@ -3681,16 +3568,10 @@ png_image_read_direct(png_voidp argument) /* Set the gamma appropriately, linear for 16-bit input, sRGB otherwise. */ { - /* This is safe but should no longer be necessary as - * png_ptr->default_gamma should have been set after the - * info-before-IDAT was read in png_image_read_header. - * - * TODO: 1.8: remove this and see what happens. - */ png_fixed_point input_gamma_default; - if ((base_format & PNG_FORMAT_FLAG_LINEAR) != 0 && - (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) + if ((base_format & PNG_FORMAT_FLAG_LINEAR) && + (image->flags & PNG_IMAGE_FLAG_16BIT_sRGB) == 0) input_gamma_default = PNG_GAMMA_LINEAR; else input_gamma_default = PNG_DEFAULT_sRGB; @@ -3701,12 +3582,12 @@ png_image_read_direct(png_voidp argument) png_set_alpha_mode_fixed(png_ptr, PNG_ALPHA_PNG, input_gamma_default); } - if (linear != 0) + if (linear) { /* If there *is* an alpha channel in the input it must be multiplied * out; use PNG_ALPHA_STANDARD, otherwise just use PNG_ALPHA_PNG. */ - if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + if (base_format & PNG_FORMAT_FLAG_ALPHA) mode = PNG_ALPHA_STANDARD; /* associated alpha */ else @@ -3721,19 +3602,13 @@ png_image_read_direct(png_voidp argument) output_gamma = PNG_DEFAULT_sRGB; } - if ((change & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0) - { - mode = PNG_ALPHA_OPTIMIZED; - change &= ~PNG_FORMAT_FLAG_ASSOCIATED_ALPHA; - } - /* If 'do_local_background' is set check for the presence of gamma * correction; this is part of the work-round for the libpng bug * described above. * * TODO: fix libpng and remove this. */ - if (do_local_background != 0) + if (do_local_background) { png_fixed_point gtest; @@ -3742,9 +3617,8 @@ png_image_read_direct(png_voidp argument) * yet; it's set below. png_struct::gamma, however, is set to the * final value. */ - if (png_muldiv(>est, output_gamma, - png_resolve_file_gamma(png_ptr), PNG_FP_1) != 0 && - png_gamma_significant(gtest) == 0) + if (png_muldiv(>est, output_gamma, png_ptr->colorspace.gamma, + PNG_FP_1) && !png_gamma_significant(gtest)) do_local_background = 0; else if (mode == PNG_ALPHA_STANDARD) @@ -3757,44 +3631,36 @@ png_image_read_direct(png_voidp argument) } /* If the bit-depth changes then handle that here. */ - if ((change & PNG_FORMAT_FLAG_LINEAR) != 0) + if (change & PNG_FORMAT_FLAG_LINEAR) { - if (linear != 0 /*16-bit output*/) + if (linear /*16-bit output*/) png_set_expand_16(png_ptr); else /* 8-bit output */ - { png_set_scale_16(png_ptr); - /* For interlaced images, use local_row buffer to avoid overflow - * in png_combine_row() which writes using IHDR bit-depth. - */ - if (png_ptr->interlaced != 0) - do_local_scale = 1; - } - change &= ~PNG_FORMAT_FLAG_LINEAR; } /* Now the background/alpha channel changes. */ - if ((change & PNG_FORMAT_FLAG_ALPHA) != 0) + if (change & PNG_FORMAT_FLAG_ALPHA) { /* Removing an alpha channel requires composition for the 8-bit * formats; for the 16-bit it is already done, above, by the * pre-multiplication and the channel just needs to be stripped. */ - if ((base_format & PNG_FORMAT_FLAG_ALPHA) != 0) + if (base_format & PNG_FORMAT_FLAG_ALPHA) { /* If RGB->gray is happening the alpha channel must be left and the * operation completed locally. * * TODO: fix libpng and remove this. */ - if (do_local_background != 0) + if (do_local_background) do_local_background = 2/*required*/; /* 16-bit output: just remove the channel */ - else if (linear != 0) /* compose on black (well, pre-multiply) */ + else if (linear) /* compose on black (well, pre-multiply) */ png_set_strip_alpha(png_ptr); /* 8-bit output: do an appropriate compose */ @@ -3815,8 +3681,8 @@ png_image_read_direct(png_voidp argument) * pixels. */ png_set_background_fixed(png_ptr, &c, - PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, - 0/*gamma: not used*/); + PNG_BACKGROUND_GAMMA_SCREEN, 0/*need_expand*/, + 0/*gamma: not used*/); } else /* compose on row: implemented below. */ @@ -3841,22 +3707,22 @@ png_image_read_direct(png_voidp argument) png_uint_32 filler; /* opaque filler */ int where; - if (linear != 0) + if (linear) filler = 65535; else filler = 255; -#ifdef PNG_FORMAT_AFIRST_SUPPORTED - if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) - { - where = PNG_FILLER_BEFORE; - change &= ~PNG_FORMAT_FLAG_AFIRST; - } +# ifdef PNG_FORMAT_AFIRST_SUPPORTED + if (format & PNG_FORMAT_FLAG_AFIRST) + { + where = PNG_FILLER_BEFORE; + change &= ~PNG_FORMAT_FLAG_AFIRST; + } - else -#endif - where = PNG_FILLER_AFTER; + else +# endif + where = PNG_FILLER_AFTER; png_set_add_alpha(png_ptr, filler, where); } @@ -3872,12 +3738,12 @@ png_image_read_direct(png_voidp argument) png_set_alpha_mode_fixed(png_ptr, mode, output_gamma); # ifdef PNG_FORMAT_BGR_SUPPORTED - if ((change & PNG_FORMAT_FLAG_BGR) != 0) + if (change & PNG_FORMAT_FLAG_BGR) { /* Check only the output format; PNG is never BGR; don't do this if * the output is gray, but fix up the 'format' value in that case. */ - if ((format & PNG_FORMAT_FLAG_COLOR) != 0) + if (format & PNG_FORMAT_FLAG_COLOR) png_set_bgr(png_ptr); else @@ -3888,14 +3754,14 @@ png_image_read_direct(png_voidp argument) # endif # ifdef PNG_FORMAT_AFIRST_SUPPORTED - if ((change & PNG_FORMAT_FLAG_AFIRST) != 0) + if (change & PNG_FORMAT_FLAG_AFIRST) { /* Only relevant if there is an alpha channel - it's particularly * important to handle this correctly because do_local_compose may * be set above and then libpng will keep the alpha channel for this * code to remove. */ - if ((format & PNG_FORMAT_FLAG_ALPHA) != 0) + if (format & PNG_FORMAT_FLAG_ALPHA) { /* Disable this if doing a local background, * TODO: remove this when local background is no longer required. @@ -3914,16 +3780,16 @@ png_image_read_direct(png_voidp argument) /* If the *output* is 16-bit then we need to check for a byte-swap on this * architecture. */ - if (linear != 0) + if (linear) { - png_uint_16 le = 0x0001; + PNG_CONST png_uint_16 le = 0x0001; - if ((*(png_const_bytep) & le) != 0) + if (*(png_const_bytep)&le) png_set_swap(png_ptr); } /* If change is not now 0 some transformation is missing - error out. */ - if (change != 0) + if (change) png_error(png_ptr, "png_read_image: unsupported transformation"); } @@ -3935,7 +3801,7 @@ png_image_read_direct(png_voidp argument) * * TODO: remove the do_local_background fixup below. */ - if (do_local_compose == 0 && do_local_background != 2) + if (!do_local_compose && do_local_background != 2) passes = png_set_interlace_handling(png_ptr); png_read_update_info(png_ptr, info_ptr); @@ -3943,13 +3809,13 @@ png_image_read_direct(png_voidp argument) { png_uint_32 info_format = 0; - if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) info_format |= PNG_FORMAT_FLAG_COLOR; - if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) { /* do_local_compose removes this channel below. */ - if (do_local_compose == 0) + if (!do_local_compose) { /* do_local_background does the same if required. */ if (do_local_background != 2 || @@ -3958,25 +3824,21 @@ png_image_read_direct(png_voidp argument) } } - else if (do_local_compose != 0) /* internal error */ + else if (do_local_compose) /* internal error */ png_error(png_ptr, "png_image_read: alpha channel lost"); - if ((format & PNG_FORMAT_FLAG_ASSOCIATED_ALPHA) != 0) { - info_format |= PNG_FORMAT_FLAG_ASSOCIATED_ALPHA; - } - if (info_ptr->bit_depth == 16) info_format |= PNG_FORMAT_FLAG_LINEAR; -#ifdef PNG_FORMAT_BGR_SUPPORTED - if ((png_ptr->transformations & PNG_BGR) != 0) - info_format |= PNG_FORMAT_FLAG_BGR; -#endif +# ifdef PNG_FORMAT_BGR_SUPPORTED + if (png_ptr->transformations & PNG_BGR) + info_format |= PNG_FORMAT_FLAG_BGR; +# endif -#ifdef PNG_FORMAT_AFIRST_SUPPORTED +# ifdef PNG_FORMAT_AFIRST_SUPPORTED if (do_local_background == 2) { - if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) + if (format & PNG_FORMAT_FLAG_AFIRST) info_format |= PNG_FORMAT_FLAG_AFIRST; } @@ -4003,26 +3865,26 @@ png_image_read_direct(png_voidp argument) */ { png_voidp first_row = display->buffer; - ptrdiff_t row_step = display->row_stride; + ptrdiff_t row_bytes = display->row_stride; - if (linear != 0) - row_step *= 2; + if (linear) + row_bytes *= 2; - /* The following adjustment is to ensure that calculations are correct, - * regardless whether row_step is positive or negative. + /* The following expression is designed to work correctly whether it gives + * a signed or an unsigned result. */ - if (row_step < 0) + if (row_bytes < 0) { char *ptr = png_voidcast(char*, first_row); - ptr += (image->height - 1) * (-row_step); + ptr += (image->height-1) * (-row_bytes); first_row = png_voidcast(png_voidp, ptr); } display->first_row = first_row; - display->row_step = row_step; + display->row_bytes = row_bytes; } - if (do_local_compose != 0) + if (do_local_compose) { int result; png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); @@ -4048,37 +3910,19 @@ png_image_read_direct(png_voidp argument) return result; } - else if (do_local_scale != 0) - { - /* For interlaced 16-to-8 conversion, use an intermediate row buffer - * to avoid buffer overflows in png_combine_row. The local_row is sized - * for the transformed (8-bit) output, preventing the overflow that would - * occur if png_combine_row wrote 16-bit data directly to the user buffer. - */ - int result; - png_voidp row = png_malloc(png_ptr, png_get_rowbytes(png_ptr, info_ptr)); - - display->local_row = row; - result = png_safe_execute(image, png_image_read_direct_scaled, display); - display->local_row = NULL; - png_free(png_ptr, row); - - return result; - } - else { - ptrdiff_t row_step = display->row_step; + png_alloc_size_t row_bytes = display->row_bytes; while (--passes >= 0) { - png_uint_32 y = image->height; - png_bytep row = png_voidcast(png_bytep, display->first_row); + png_uint_32 y = image->height; + png_bytep row = png_voidcast(png_bytep, display->first_row); - for (; y > 0; --y) + while (y-- > 0) { png_read_row(png_ptr, row, NULL); - row += row_step; + row += row_bytes; } } @@ -4088,120 +3932,70 @@ png_image_read_direct(png_voidp argument) int PNGAPI png_image_finish_read(png_imagep image, png_const_colorp background, - void *buffer, png_int_32 row_stride, void *colormap) + void *buffer, png_int_32 row_stride, void *colormap) { if (image != NULL && image->version == PNG_IMAGE_VERSION) { - /* Check for row_stride overflow. This check is not performed on the - * original PNG format because it may not occur in the output PNG format - * and libpng deals with the issues of reading the original. - */ - unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format); + png_uint_32 check; - /* The following checks just the 'row_stride' calculation to ensure it - * fits in a signed 32-bit value. Because channels/components can be - * either 1 or 2 bytes in size the length of a row can still overflow 32 - * bits; this is just to verify that the 'row_stride' argument can be - * represented. - */ - if (image->width <= 0x7fffffffU/channels) /* no overflow */ + if (row_stride == 0) + row_stride = PNG_IMAGE_ROW_STRIDE(*image); + + if (row_stride < 0) + check = -row_stride; + + else + check = row_stride; + + if (image->opaque != NULL && buffer != NULL && + check >= PNG_IMAGE_ROW_STRIDE(*image)) { - png_uint_32 check; - png_uint_32 png_row_stride = image->width * channels; - - if (row_stride == 0) - row_stride = (png_int_32)/*SAFE*/png_row_stride; - - if (row_stride < 0) - check = (png_uint_32)(-row_stride); - - else - check = (png_uint_32)row_stride; - - /* This verifies 'check', the absolute value of the actual stride - * passed in and detects overflow in the application calculation (i.e. - * if the app did actually pass in a non-zero 'row_stride'. - */ - if (image->opaque != NULL && buffer != NULL && check >= png_row_stride) + if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || + (image->colormap_entries > 0 && colormap != NULL)) { - /* Now check for overflow of the image buffer calculation; this - * limits the whole image size to 32 bits for API compatibility with - * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. - * - * The PNG_IMAGE_BUFFER_SIZE macro is: - * - * (PNG_IMAGE_PIXEL_COMPONENT_SIZE(fmt)*height*(row_stride)) - * - * And the component size is always 1 or 2, so make sure that the - * number of *bytes* that the application is saying are available - * does actually fit into a 32-bit number. - * - * NOTE: this will be changed in 1.7 because PNG_IMAGE_BUFFER_SIZE - * will be changed to use png_alloc_size_t; bigger images can be - * accommodated on 64-bit systems. + int result; + png_image_read_control display; + + memset(&display, 0, (sizeof display)); + display.image = image; + display.buffer = buffer; + display.row_stride = row_stride; + display.colormap = colormap; + display.background = background; + display.local_row = NULL; + + /* Choose the correct 'end' routine; for the color-map case all the + * setup has already been done. */ - if (image->height <= - 0xffffffffU/PNG_IMAGE_PIXEL_COMPONENT_SIZE(image->format)/check) - { - if ((image->format & PNG_FORMAT_FLAG_COLORMAP) == 0 || - (image->colormap_entries > 0 && colormap != NULL)) - { - int result; - png_image_read_control display; - - memset(&display, 0, (sizeof display)); - display.image = image; - display.buffer = buffer; - display.row_stride = row_stride; - display.colormap = colormap; - display.background = background; - display.local_row = NULL; - - /* Choose the correct 'end' routine; for the color-map case - * all the setup has already been done. - */ - if ((image->format & PNG_FORMAT_FLAG_COLORMAP) != 0) - result = - png_safe_execute(image, - png_image_read_colormap, &display) && - png_safe_execute(image, - png_image_read_colormapped, &display); - - else - result = - png_safe_execute(image, - png_image_read_direct, &display); - - png_image_free(image); - return result; - } - - else - return png_image_error(image, - "png_image_finish_read[color-map]: no color-map"); - } + if (image->format & PNG_FORMAT_FLAG_COLORMAP) + result = + png_safe_execute(image, png_image_read_colormap, &display) && + png_safe_execute(image, png_image_read_colormapped, &display); else - return png_image_error(image, - "png_image_finish_read: image too large"); + result = + png_safe_execute(image, png_image_read_direct, &display); + + png_image_free(image); + return result; } else return png_image_error(image, - "png_image_finish_read: invalid argument"); + "png_image_finish_read[color-map]: no color-map"); } else return png_image_error(image, - "png_image_finish_read: row_stride too large"); + "png_image_finish_read: invalid argument"); } else if (image != NULL) return png_image_error(image, - "png_image_finish_read: damaged PNG_IMAGE_VERSION"); + "png_image_finish_read: damaged PNG_IMAGE_VERSION"); return 0; } -#endif /* SIMPLIFIED_READ */ -#endif /* READ */ +#endif /* PNG_SIMPLIFIED_READ_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pngrio.c b/Windows_Libs/Dev/Render/libpng/pngrio.c index b4a2161..d786440 100644 --- a/Windows_Libs/Dev/Render/libpng/pngrio.c +++ b/Windows_Libs/Dev/Render/libpng/pngrio.c @@ -1,9 +1,10 @@ + /* pngrio.c - functions for data input * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.0 [February 14, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -25,10 +26,10 @@ * reads from a file pointer. Note that this routine sometimes gets called * with very small lengths, so you should implement some kind of simple * buffering if you are using unbuffered reads. This should never be asked - * to read more than 64K on a 16-bit machine. + * to read more then 64K on a 16 bit machine. */ void /* PRIVATE */ -png_read_data(png_structrp png_ptr, png_bytep data, size_t length) +png_read_data(png_structrp png_ptr, png_bytep data, png_size_t length) { png_debug1(4, "reading %d bytes", (int)length); @@ -46,17 +47,17 @@ png_read_data(png_structrp png_ptr, png_bytep data, size_t length) * than changing the library. */ void PNGCBAPI -png_default_read_data(png_structp png_ptr, png_bytep data, size_t length) +png_default_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { - size_t check; + png_size_t check; if (png_ptr == NULL) return; - /* fread() returns 0 on error, so it is OK to store this in a size_t + /* fread() returns 0 on error, so it is OK to store this in a png_size_t * instead of an int, which is what fread() actually returns. */ - check = fread(data, 1, length, png_voidcast(FILE *, png_ptr->io_ptr)); + check = fread(data, 1, length, png_voidcast(png_FILE_p, png_ptr->io_ptr)); if (check != length) png_error(png_ptr, "Read Error"); @@ -84,7 +85,7 @@ png_default_read_data(png_structp png_ptr, png_bytep data, size_t length) */ void PNGAPI png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr, - png_rw_ptr read_data_fn) + png_rw_ptr read_data_fn) { if (png_ptr == NULL) return; @@ -101,7 +102,6 @@ png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr, png_ptr->read_data_fn = read_data_fn; #endif -#ifdef PNG_WRITE_SUPPORTED /* It is an error to write to a read device */ if (png_ptr->write_data_fn != NULL) { @@ -110,10 +110,9 @@ png_set_read_fn(png_structrp png_ptr, png_voidp io_ptr, "Can't set both read_data_fn and write_data_fn in the" " same structure"); } -#endif #ifdef PNG_WRITE_FLUSH_SUPPORTED png_ptr->output_flush_fn = NULL; #endif } -#endif /* READ */ +#endif /* PNG_READ_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pngrtran.c b/Windows_Libs/Dev/Render/libpng/pngrtran.c index 1fce9af..e378ceb 100644 --- a/Windows_Libs/Dev/Render/libpng/pngrtran.c +++ b/Windows_Libs/Dev/Render/libpng/pngrtran.c @@ -1,9 +1,10 @@ + /* pngrtran.c - transforms the data in a row for PNG readers * - * Copyright (c) 2018-2026 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -17,23 +18,6 @@ #include "pngpriv.h" -#ifdef PNG_ARM_NEON_IMPLEMENTATION -# if PNG_ARM_NEON_IMPLEMENTATION == 1 -# define PNG_ARM_NEON_INTRINSICS_AVAILABLE -# if defined(_MSC_VER) && !defined(__clang__) && defined(_M_ARM64) -# include -# else -# include -# endif -# endif -#endif - -#ifdef PNG_RISCV_RVV_IMPLEMENTATION -# if PNG_RISCV_RVV_IMPLEMENTATION == 1 -# define PNG_RISCV_RVV_INTRINSICS_AVAILABLE -# endif -#endif - #ifdef PNG_READ_SUPPORTED /* Set the action on getting a CRC error for an ancillary or critical chunk. */ @@ -64,8 +48,7 @@ png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action) case PNG_CRC_WARN_DISCARD: /* Not a valid action for critical data */ png_warning(png_ptr, - "Can't discard critical data on CRC error"); - /* FALLTHROUGH */ + "Can't discard critical data on CRC error"); case PNG_CRC_ERROR_QUIT: /* Error/quit */ case PNG_CRC_DEFAULT: @@ -108,17 +91,16 @@ png_set_crc_action(png_structrp png_ptr, int crit_action, int ancil_action) #ifdef PNG_READ_TRANSFORMS_SUPPORTED /* Is it OK to set a transformation now? Only if png_start_read_image or * png_read_update_info have not been called. It is not necessary for the IHDR - * to have been read in all cases; the need_IHDR parameter allows for this - * check too. + * to have been read in all cases, the parameter allows for this check too. */ static int png_rtran_ok(png_structrp png_ptr, int need_IHDR) { if (png_ptr != NULL) { - if ((png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) + if (png_ptr->flags & PNG_FLAG_ROW_INIT) png_app_error(png_ptr, - "invalid after png_start_read_image or png_read_update_info"); + "invalid after png_start_read_image or png_read_update_info"); else if (need_IHDR && (png_ptr->mode & PNG_HAVE_IHDR) == 0) png_app_error(png_ptr, "invalid before the PNG header has been read"); @@ -145,7 +127,7 @@ png_set_background_fixed(png_structrp png_ptr, { png_debug(1, "in png_set_background_fixed"); - if (png_rtran_ok(png_ptr, 0) == 0 || background_color == NULL) + if (!png_rtran_ok(png_ptr, 0) || background_color == NULL) return; if (background_gamma_code == PNG_BACKGROUND_GAMMA_UNKNOWN) @@ -161,7 +143,7 @@ png_set_background_fixed(png_structrp png_ptr, png_ptr->background = *background_color; png_ptr->background_gamma = background_gamma; png_ptr->background_gamma_type = (png_byte)(background_gamma_code); - if (need_expand != 0) + if (need_expand) png_ptr->transformations |= PNG_BACKGROUND_EXPAND; else png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; @@ -176,7 +158,7 @@ png_set_background(png_structrp png_ptr, png_set_background_fixed(png_ptr, background_color, background_gamma_code, need_expand, png_fixed(png_ptr, background_gamma, "png_set_background")); } -# endif /* FLOATING_POINT */ +# endif /* FLOATING_POINT */ #endif /* READ_BACKGROUND */ /* Scale 16-bit depth files to 8-bit depth. If both of these are set then the @@ -189,7 +171,7 @@ png_set_scale_16(png_structrp png_ptr) { png_debug(1, "in png_set_scale_16"); - if (png_rtran_ok(png_ptr, 0) == 0) + if (!png_rtran_ok(png_ptr, 0)) return; png_ptr->transformations |= PNG_SCALE_16_TO_8; @@ -203,7 +185,7 @@ png_set_strip_16(png_structrp png_ptr) { png_debug(1, "in png_set_strip_16"); - if (png_rtran_ok(png_ptr, 0) == 0) + if (!png_rtran_ok(png_ptr, 0)) return; png_ptr->transformations |= PNG_16_TO_8; @@ -216,7 +198,7 @@ png_set_strip_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_strip_alpha"); - if (png_rtran_ok(png_ptr, 0) == 0) + if (!png_rtran_ok(png_ptr, 0)) return; png_ptr->transformations |= PNG_STRIP_ALPHA; @@ -224,59 +206,9 @@ png_set_strip_alpha(png_structrp png_ptr) #endif #if defined(PNG_READ_ALPHA_MODE_SUPPORTED) || defined(PNG_READ_GAMMA_SUPPORTED) -/* PNGv3 conformance: this private API exists to resolve the now mandatory error - * resolution when multiple conflicting sources of gamma or colour space - * information are available. - * - * Terminology (assuming power law, "gamma", encodings): - * "screen" gamma: a power law imposed by the output device when digital - * samples are converted to visible light output. The EOTF - volage to - * luminance on output. - * - * "file" gamma: a power law used to encode luminance levels from the input - * data (the scene or the mastering display system) into digital voltages. - * The OETF - luminance to voltage on input. - * - * gamma "correction": a power law matching the **inverse** of the overall - * transfer function from input luminance levels to output levels. The - * **inverse** of the OOTF; the correction "corrects" for the OOTF by aiming - * to make the overall OOTF (including the correction) linear. - * - * It is important to understand this terminology because the defined terms are - * scattered throughout the libpng code and it is very easy to end up with the - * inverse of the power law required. - * - * Variable and struct::member names: - * file_gamma OETF how the PNG data was encoded - * - * screen_gamma EOTF how the screen will decode digital levels - * - * -- not used -- OOTF the net effect OETF x EOTF - * gamma_correction the inverse of OOTF to make the result linear - * - * All versions of libpng require a call to "png_set_gamma" to establish the - * "screen" gamma, the power law representing the EOTF. png_set_gamma may also - * set or default the "file" gamma; the OETF. gamma_correction is calculated - * internally. - * - * The earliest libpng versions required file_gamma to be supplied to set_gamma. - * Later versions started allowing png_set_gamma and, later, png_set_alpha_mode, - * to cause defaulting from the file data. - * - * PNGv3 mandated a particular form for this defaulting, one that is compatible - * with what libpng did except that if libpng detected inconsistencies it marked - * all the chunks as "invalid". PNGv3 effectively invalidates this prior code. - * - * Behaviour implemented below: - * translate_gamma_flags(gamma, is_screen) - * The libpng-1.6 API for the gamma parameters to libpng APIs - * (png_set_gamma and png_set_alpha_mode at present). This allows the - * 'gamma' value to be passed as a png_fixed_point number or as one of a - * set of integral values for specific "well known" examples of transfer - * functions. This is compatible with PNGv3. - */ static png_fixed_point -translate_gamma_flags(png_fixed_point output_gamma, int is_screen) +translate_gamma_flags(png_structrp png_ptr, png_fixed_point output_gamma, + int is_screen) { /* Check for flag values. The main reason for having the old Mac value as a * flag is that it is pretty near impossible to work out what the correct @@ -286,7 +218,15 @@ translate_gamma_flags(png_fixed_point output_gamma, int is_screen) if (output_gamma == PNG_DEFAULT_sRGB || output_gamma == PNG_FP_1 / PNG_DEFAULT_sRGB) { - if (is_screen != 0) + /* If there is no sRGB support this just sets the gamma to the standard + * sRGB value. (This is a side effect of using this function!) + */ +# ifdef PNG_READ_sRGB_SUPPORTED + png_ptr->flags |= PNG_FLAG_ASSUME_sRGB; +# else + PNG_UNUSED(png_ptr) +# endif + if (is_screen) output_gamma = PNG_GAMMA_sRGB; else output_gamma = PNG_GAMMA_sRGB_INVERSE; @@ -295,7 +235,7 @@ translate_gamma_flags(png_fixed_point output_gamma, int is_screen) else if (output_gamma == PNG_GAMMA_MAC_18 || output_gamma == PNG_FP_1 / PNG_GAMMA_MAC_18) { - if (is_screen != 0) + if (is_screen) output_gamma = PNG_GAMMA_MAC_OLD; else output_gamma = PNG_GAMMA_MAC_INVERSE; @@ -327,63 +267,36 @@ convert_gamma_value(png_structrp png_ptr, double output_gamma) return (png_fixed_point)output_gamma; } # endif - -static int -unsupported_gamma(png_structrp png_ptr, png_fixed_point gamma, int warn) -{ - /* Validate a gamma value to ensure it is in a reasonable range. The value - * is expected to be 1 or greater, but this range test allows for some - * viewing correction values. The intent is to weed out the API users - * who might use the inverse of the gamma value accidentally! - * - * 1.6.47: apply the test in png_set_gamma as well but only warn and return - * false if it fires. - * - * TODO: 1.8: make this an app_error in png_set_gamma as well. - */ - if (gamma < PNG_LIB_GAMMA_MIN || gamma > PNG_LIB_GAMMA_MAX) - { -# define msg "gamma out of supported range" - if (warn) - png_app_warning(png_ptr, msg); - else - png_app_error(png_ptr, msg); - return 1; -# undef msg - } - - return 0; -} #endif /* READ_ALPHA_MODE || READ_GAMMA */ #ifdef PNG_READ_ALPHA_MODE_SUPPORTED void PNGFAPI png_set_alpha_mode_fixed(png_structrp png_ptr, int mode, - png_fixed_point output_gamma) + png_fixed_point output_gamma) { - png_fixed_point file_gamma; int compose = 0; + png_fixed_point file_gamma; - png_debug(1, "in png_set_alpha_mode_fixed"); + png_debug(1, "in png_set_alpha_mode"); - if (png_rtran_ok(png_ptr, 0) == 0) + if (!png_rtran_ok(png_ptr, 0)) return; - output_gamma = translate_gamma_flags(output_gamma, 1/*screen*/); - if (unsupported_gamma(png_ptr, output_gamma, 0/*error*/)) - return; + output_gamma = translate_gamma_flags(png_ptr, output_gamma, 1/*screen*/); + + /* Validate the value to ensure it is in a reasonable range. The value + * is expected to be 1 or greater, but this range test allows for some + * viewing correction values. The intent is to weed out users of this API + * who use the inverse of the gamma value accidentally! Since some of these + * values are reasonable this may have to be changed. + */ + if (output_gamma < 70000 || output_gamma > 300000) + png_error(png_ptr, "output gamma out of expected range"); /* The default file gamma is the inverse of the output gamma; the output - * gamma may be changed below so get the file value first. The default_gamma - * is set here and from the simplified API (which uses a different algorithm) - * so don't overwrite a set value: + * gamma may be changed below so get the file value first: */ - file_gamma = png_ptr->default_gamma; - if (file_gamma == 0) - { - file_gamma = png_reciprocal(output_gamma); - png_ptr->default_gamma = file_gamma; - } + file_gamma = png_reciprocal(output_gamma); /* There are really 8 possibilities here, composed of any combination * of: @@ -434,23 +347,33 @@ png_set_alpha_mode_fixed(png_structrp png_ptr, int mode, png_error(png_ptr, "invalid alpha mode"); } - /* Set the screen gamma values: */ + /* Only set the default gamma if the file gamma has not been set (this has + * the side effect that the gamma in a second call to png_set_alpha_mode will + * be ignored.) + */ + if (png_ptr->colorspace.gamma == 0) + { + png_ptr->colorspace.gamma = file_gamma; + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + } + + /* But always set the output gamma: */ png_ptr->screen_gamma = output_gamma; /* Finally, if pre-multiplying, set the background fields to achieve the * desired result. */ - if (compose != 0) + if (compose) { /* And obtain alpha pre-multiplication by composing on black: */ memset(&png_ptr->background, 0, (sizeof png_ptr->background)); - png_ptr->background_gamma = file_gamma; /* just in case */ + png_ptr->background_gamma = png_ptr->colorspace.gamma; /* just in case */ png_ptr->background_gamma_type = PNG_BACKGROUND_GAMMA_FILE; png_ptr->transformations &= ~PNG_BACKGROUND_EXPAND; - if ((png_ptr->transformations & PNG_COMPOSE) != 0) + if (png_ptr->transformations & PNG_COMPOSE) png_error(png_ptr, - "conflicting calls to set alpha mode and background"); + "conflicting calls to set alpha mode and background"); png_ptr->transformations |= PNG_COMPOSE; } @@ -461,7 +384,7 @@ void PNGAPI png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma) { png_set_alpha_mode_fixed(png_ptr, mode, convert_gamma_value(png_ptr, - output_gamma)); + output_gamma)); } # endif #endif @@ -470,7 +393,7 @@ png_set_alpha_mode(png_structrp png_ptr, int mode, double output_gamma) /* Dither file to 8-bit. Supply a palette, the current number * of elements in the palette, the maximum number of elements * allowed, and a histogram if possible. If the current number - * of colors is greater than the maximum number, the palette will be + * of colors is greater then the maximum number, the palette will be * modified to fit in the maximum number. "full_quantize" indicates * whether we need a quantizing cube set up for RGB images, or if we * simply are reducing the number of colors in a paletted image. @@ -492,28 +415,18 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, { png_debug(1, "in png_set_quantize"); - if (png_rtran_ok(png_ptr, 0) == 0) + if (!png_rtran_ok(png_ptr, 0)) return; png_ptr->transformations |= PNG_QUANTIZE; - if (full_quantize == 0) + if (!full_quantize) { int i; - /* Initialize the array to index colors. - * - * Ensure quantize_index can fit 256 elements (PNG_MAX_PALETTE_LENGTH) - * rather than num_palette elements. This is to prevent buffer overflows - * caused by malformed PNG files with out-of-range palette indices. - * - * Be careful to avoid leaking memory. Applications are allowed to call - * this function more than once per png_struct. - */ - png_free(png_ptr, png_ptr->quantize_index); png_ptr->quantize_index = (png_bytep)png_malloc(png_ptr, - PNG_MAX_PALETTE_LENGTH); - for (i = 0; i < PNG_MAX_PALETTE_LENGTH; i++) + (png_uint_32)(num_palette * (sizeof (png_byte)))); + for (i = 0; i < num_palette; i++) png_ptr->quantize_index[i] = (png_byte)i; } @@ -525,14 +438,15 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, * Perhaps not the best solution, but good enough. */ - png_bytep quantize_sort; - int i, j; + int i; - /* Initialize the local array to sort colors. */ - quantize_sort = (png_bytep)png_malloc(png_ptr, - (png_alloc_size_t)num_palette); + /* Initialize an array to sort colors */ + png_ptr->quantize_sort = (png_bytep)png_malloc(png_ptr, + (png_uint_32)(num_palette * (sizeof (png_byte)))); + + /* Initialize the quantize_sort array */ for (i = 0; i < num_palette; i++) - quantize_sort[i] = (png_byte)i; + png_ptr->quantize_sort[i] = (png_byte)i; /* Find the least used palette entries by starting a * bubble sort, and running it until we have sorted @@ -544,41 +458,42 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, for (i = num_palette - 1; i >= maximum_colors; i--) { int done; /* To stop early if the list is pre-sorted */ + int j; done = 1; for (j = 0; j < i; j++) { - if (histogram[quantize_sort[j]] - < histogram[quantize_sort[j + 1]]) + if (histogram[png_ptr->quantize_sort[j]] + < histogram[png_ptr->quantize_sort[j + 1]]) { png_byte t; - t = quantize_sort[j]; - quantize_sort[j] = quantize_sort[j + 1]; - quantize_sort[j + 1] = t; + t = png_ptr->quantize_sort[j]; + png_ptr->quantize_sort[j] = png_ptr->quantize_sort[j + 1]; + png_ptr->quantize_sort[j + 1] = t; done = 0; } } - if (done != 0) + if (done) break; } /* Swap the palette around, and set up a table, if necessary */ - if (full_quantize != 0) + if (full_quantize) { - j = num_palette; + int j = num_palette; /* Put all the useful colors within the max, but don't * move the others. */ for (i = 0; i < maximum_colors; i++) { - if ((int)quantize_sort[i] >= maximum_colors) + if ((int)png_ptr->quantize_sort[i] >= maximum_colors) { do j--; - while ((int)quantize_sort[j] >= maximum_colors); + while ((int)png_ptr->quantize_sort[j] >= maximum_colors); palette[i] = palette[j]; } @@ -586,7 +501,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, } else { - j = num_palette; + int j = num_palette; /* Move all the used colors inside the max limit, and * develop a translation table. @@ -594,13 +509,13 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, for (i = 0; i < maximum_colors; i++) { /* Only move the colors we need to */ - if ((int)quantize_sort[i] >= maximum_colors) + if ((int)png_ptr->quantize_sort[i] >= maximum_colors) { png_color tmp_color; do j--; - while ((int)quantize_sort[j] >= maximum_colors); + while ((int)png_ptr->quantize_sort[j] >= maximum_colors); tmp_color = palette[j]; palette[j] = palette[i]; @@ -638,7 +553,8 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, } } } - png_free(png_ptr, quantize_sort); + png_free(png_ptr, png_ptr->quantize_sort); + png_ptr->quantize_sort = NULL; } else { @@ -660,9 +576,9 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, /* Initialize palette index arrays */ png_ptr->index_to_palette = (png_bytep)png_malloc(png_ptr, - (png_alloc_size_t)num_palette); + (png_uint_32)(num_palette * (sizeof (png_byte)))); png_ptr->palette_to_index = (png_bytep)png_malloc(png_ptr, - (png_alloc_size_t)num_palette); + (png_uint_32)(num_palette * (sizeof (png_byte)))); /* Initialize the sort array */ for (i = 0; i < num_palette; i++) @@ -671,7 +587,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, png_ptr->palette_to_index[i] = (png_byte)i; } - hash = (png_dsortpp)png_calloc(png_ptr, (png_alloc_size_t)(769 * + hash = (png_dsortpp)png_calloc(png_ptr, (png_uint_32)(769 * (sizeof (png_dsortp)))); num_new_palette = num_palette; @@ -702,14 +618,14 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, { t = (png_dsortp)png_malloc_warn(png_ptr, - (png_alloc_size_t)(sizeof (png_dsort))); + (png_uint_32)(sizeof (png_dsort))); if (t == NULL) break; t->next = hash[d]; - t->left = png_ptr->palette_to_index[i]; - t->right = png_ptr->palette_to_index[j]; + t->left = (png_byte)i; + t->right = (png_byte)j; hash[d] = t; } } @@ -747,7 +663,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, num_new_palette--; palette[png_ptr->index_to_palette[j]] = palette[num_new_palette]; - if (full_quantize == 0) + if (!full_quantize) { int k; @@ -815,7 +731,7 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, } png_ptr->num_palette = (png_uint_16)num_palette; - if (full_quantize != 0) + if (full_quantize) { int i; png_bytep distance; @@ -824,14 +740,15 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, int num_red = (1 << PNG_QUANTIZE_RED_BITS); int num_green = (1 << PNG_QUANTIZE_GREEN_BITS); int num_blue = (1 << PNG_QUANTIZE_BLUE_BITS); - size_t num_entries = ((size_t)1 << total_bits); + png_size_t num_entries = ((png_size_t)1 << total_bits); png_ptr->palette_lookup = (png_bytep)png_calloc(png_ptr, - (png_alloc_size_t)(num_entries)); + (png_uint_32)(num_entries * (sizeof (png_byte)))); - distance = (png_bytep)png_malloc(png_ptr, (png_alloc_size_t)num_entries); + distance = (png_bytep)png_malloc(png_ptr, (png_uint_32)(num_entries * + (sizeof (png_byte)))); - memset(distance, 0xff, num_entries); + memset(distance, 0xff, num_entries * (sizeof (png_byte))); for (i = 0; i < num_palette; i++) { @@ -876,21 +793,21 @@ png_set_quantize(png_structrp png_ptr, png_colorp palette, png_free(png_ptr, distance); } } -#endif /* READ_QUANTIZE */ +#endif /* PNG_READ_QUANTIZE_SUPPORTED */ #ifdef PNG_READ_GAMMA_SUPPORTED void PNGFAPI png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma, - png_fixed_point file_gamma) + png_fixed_point file_gamma) { png_debug(1, "in png_set_gamma_fixed"); - if (png_rtran_ok(png_ptr, 0) == 0) + if (!png_rtran_ok(png_ptr, 0)) return; /* New in libpng-1.5.4 - reserve particular negative values as flags. */ - scrn_gamma = translate_gamma_flags(scrn_gamma, 1/*screen*/); - file_gamma = translate_gamma_flags(file_gamma, 0/*file*/); + scrn_gamma = translate_gamma_flags(png_ptr, scrn_gamma, 1/*screen*/); + file_gamma = translate_gamma_flags(png_ptr, file_gamma, 0/*file*/); /* Checking the gamma values for being >0 was added in 1.5.4 along with the * premultiplied alpha support; this actually hides an undocumented feature @@ -904,19 +821,17 @@ png_set_gamma_fixed(png_structrp png_ptr, png_fixed_point scrn_gamma, * libpng-1.6.0. */ if (file_gamma <= 0) - png_app_error(png_ptr, "invalid file gamma in png_set_gamma"); + png_error(png_ptr, "invalid file gamma in png_set_gamma"); + if (scrn_gamma <= 0) - png_app_error(png_ptr, "invalid screen gamma in png_set_gamma"); + png_error(png_ptr, "invalid screen gamma in png_set_gamma"); - if (unsupported_gamma(png_ptr, file_gamma, 1/*warn*/) || - unsupported_gamma(png_ptr, scrn_gamma, 1/*warn*/)) - return; - - /* 1.6.47: png_struct::file_gamma and png_struct::screen_gamma are now only - * written by this API. This removes dependencies on the order of API calls - * and allows the complex gamma checks to be delayed until needed. + /* Set the gamma values unconditionally - this overrides the value in the PNG + * file if a gAMA chunk was present. png_set_alpha_mode provides a + * different, easier, way to default the file gamma. */ - png_ptr->file_gamma = file_gamma; + png_ptr->colorspace.gamma = file_gamma; + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; png_ptr->screen_gamma = scrn_gamma; } @@ -925,9 +840,9 @@ void PNGAPI png_set_gamma(png_structrp png_ptr, double scrn_gamma, double file_gamma) { png_set_gamma_fixed(png_ptr, convert_gamma_value(png_ptr, scrn_gamma), - convert_gamma_value(png_ptr, file_gamma)); + convert_gamma_value(png_ptr, file_gamma)); } -# endif /* FLOATING_POINT */ +# endif /* FLOATING_POINT_SUPPORTED */ #endif /* READ_GAMMA */ #ifdef PNG_READ_EXPAND_SUPPORTED @@ -940,7 +855,7 @@ png_set_expand(png_structrp png_ptr) { png_debug(1, "in png_set_expand"); - if (png_rtran_ok(png_ptr, 0) == 0) + if (!png_rtran_ok(png_ptr, 0)) return; png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); @@ -970,7 +885,7 @@ png_set_palette_to_rgb(png_structrp png_ptr) { png_debug(1, "in png_set_palette_to_rgb"); - if (png_rtran_ok(png_ptr, 0) == 0) + if (!png_rtran_ok(png_ptr, 0)) return; png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); @@ -982,7 +897,7 @@ png_set_expand_gray_1_2_4_to_8(png_structrp png_ptr) { png_debug(1, "in png_set_expand_gray_1_2_4_to_8"); - if (png_rtran_ok(png_ptr, 0) == 0) + if (!png_rtran_ok(png_ptr, 0)) return; png_ptr->transformations |= PNG_EXPAND; @@ -994,12 +909,12 @@ png_set_tRNS_to_alpha(png_structrp png_ptr) { png_debug(1, "in png_set_tRNS_to_alpha"); - if (png_rtran_ok(png_ptr, 0) == 0) + if (!png_rtran_ok(png_ptr, 0)) return; png_ptr->transformations |= (PNG_EXPAND | PNG_EXPAND_tRNS); } -#endif /* READ_EXPAND */ +#endif /* defined(PNG_READ_EXPAND_SUPPORTED) */ #ifdef PNG_READ_EXPAND_16_SUPPORTED /* Expand to 16-bit channels, expand the tRNS chunk too (because otherwise @@ -1010,7 +925,7 @@ png_set_expand_16(png_structrp png_ptr) { png_debug(1, "in png_set_expand_16"); - if (png_rtran_ok(png_ptr, 0) == 0) + if (!png_rtran_ok(png_ptr, 0)) return; png_ptr->transformations |= (PNG_EXPAND_16 | PNG_EXPAND | PNG_EXPAND_tRNS); @@ -1023,7 +938,7 @@ png_set_gray_to_rgb(png_structrp png_ptr) { png_debug(1, "in png_set_gray_to_rgb"); - if (png_rtran_ok(png_ptr, 0) == 0) + if (!png_rtran_ok(png_ptr, 0)) return; /* Because rgb must be 8 bits or more: */ @@ -1037,14 +952,14 @@ void PNGFAPI png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, png_fixed_point red, png_fixed_point green) { - png_debug(1, "in png_set_rgb_to_gray_fixed"); + png_debug(1, "in png_set_rgb_to_gray"); /* Need the IHDR here because of the check on color_type below. */ /* TODO: fix this */ - if (png_rtran_ok(png_ptr, 1) == 0) + if (!png_rtran_ok(png_ptr, 1)) return; - switch (error_action) + switch(error_action) { case PNG_ERROR_ACTION_NONE: png_ptr->transformations |= PNG_RGB_TO_GRAY; @@ -1060,6 +975,7 @@ png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, default: png_error(png_ptr, "invalid error action to rgb_to_gray"); + break; } if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) @@ -1071,7 +987,7 @@ png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, * that it just worked and get a memory overwrite. */ png_error(png_ptr, - "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED"); + "Cannot do RGB_TO_GRAY without EXPAND_SUPPORTED"); /* png_ptr->transformations &= ~PNG_RGB_TO_GRAY; */ } @@ -1082,7 +998,7 @@ png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, png_uint_16 red_int, green_int; /* NOTE: this calculation does not round, but this behavior is retained - * for consistency; the inaccuracy is very small. The code here always + * for consistency, the inaccuracy is very small. The code here always * overwrites the coefficients, regardless of whether they have been * defaulted or set already. */ @@ -1094,9 +1010,26 @@ png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, png_ptr->rgb_to_gray_coefficients_set = 1; } - else if (red >= 0 && green >= 0) - png_app_warning(png_ptr, + else + { + if (red >= 0 && green >= 0) + png_app_warning(png_ptr, "ignoring out of range rgb_to_gray coefficients"); + + /* Use the defaults, from the cHRM chunk if set, else the historical + * values which are close to the sRGB/HDTV/ITU-Rec 709 values. See + * png_do_rgb_to_gray for more discussion of the values. In this case + * the coefficients are not marked as 'set' and are not overwritten if + * something has already provided a default. + */ + if (png_ptr->rgb_to_gray_red_coeff == 0 && + png_ptr->rgb_to_gray_green_coeff == 0) + { + png_ptr->rgb_to_gray_red_coeff = 6968; + png_ptr->rgb_to_gray_green_coeff = 23434; + /* png_ptr->rgb_to_gray_blue_coeff = 2366; */ + } + } } } @@ -1107,10 +1040,10 @@ png_set_rgb_to_gray_fixed(png_structrp png_ptr, int error_action, void PNGAPI png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red, - double green) + double green) { png_set_rgb_to_gray_fixed(png_ptr, error_action, - png_fixed(png_ptr, red, "rgb to gray red coefficient"), + png_fixed(png_ptr, red, "rgb to gray red coefficient"), png_fixed(png_ptr, green, "rgb to gray green coefficient")); } #endif /* FLOATING POINT */ @@ -1120,8 +1053,8 @@ png_set_rgb_to_gray(png_structrp png_ptr, int error_action, double red, #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) void PNGAPI -png_set_read_user_transform_fn(png_structrp png_ptr, - png_user_transform_ptr read_user_transform_fn) +png_set_read_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr + read_user_transform_fn) { png_debug(1, "in png_set_read_user_transform_fn"); @@ -1158,7 +1091,7 @@ png_gamma_threshold(png_fixed_point screen_gamma, png_fixed_point file_gamma) * the palette. */ -/* For the moment 'png_init_palette_transformations' and +/*For the moment 'png_init_palette_transformations' and * 'png_init_rgb_transformations' only do some flag canceling optimizations. * The intent is that these two routines should have palette or rgb operations * extracted from 'png_init_read_transformations'. @@ -1183,31 +1116,25 @@ png_init_palette_transformations(png_structrp png_ptr) /* Ignore if all the entries are opaque (unlikely!) */ for (i=0; inum_trans; ++i) - { if (png_ptr->trans_alpha[i] == 255) continue; else if (png_ptr->trans_alpha[i] == 0) input_has_transparency = 1; else - { - input_has_transparency = 1; input_has_alpha = 1; - break; - } - } } /* If no alpha we can optimize. */ - if (input_has_alpha == 0) + if (!input_has_alpha) { /* Any alpha means background and associative alpha processing is - * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA + * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA * and ENCODE_ALPHA are irrelevant. */ png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; - if (input_has_transparency == 0) + if (!input_has_transparency) png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); } @@ -1220,8 +1147,8 @@ png_init_palette_transformations(png_structrp png_ptr) /* The following code cannot be entered in the alpha pre-multiplication case * because PNG_BACKGROUND_EXPAND is cancelled below. */ - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 && - (png_ptr->transformations & PNG_EXPAND) != 0) + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + (png_ptr->transformations & PNG_EXPAND)) { { png_ptr->background.red = @@ -1232,24 +1159,24 @@ png_init_palette_transformations(png_structrp png_ptr) png_ptr->palette[png_ptr->background.index].blue; #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) - { - if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0) - { - /* Invert the alpha channel (in tRNS) unless the pixels are - * going to be expanded, in which case leave it for later - */ - int i, istop = png_ptr->num_trans; + if (png_ptr->transformations & PNG_INVERT_ALPHA) + { + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) + { + /* Invert the alpha channel (in tRNS) unless the pixels are + * going to be expanded, in which case leave it for later + */ + int i, istop = png_ptr->num_trans; - for (i = 0; i < istop; i++) - png_ptr->trans_alpha[i] = - (png_byte)(255 - png_ptr->trans_alpha[i]); - } - } -#endif /* READ_INVERT_ALPHA */ + for (i=0; itrans_alpha[i] = (png_byte)(255 - + png_ptr->trans_alpha[i]); + } + } +#endif /* PNG_READ_INVERT_ALPHA_SUPPORTED */ } } /* background expand and (therefore) no alpha association. */ -#endif /* READ_EXPAND && READ_BACKGROUND */ +#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ } static void /* PRIVATE */ @@ -1263,10 +1190,10 @@ png_init_rgb_transformations(png_structrp png_ptr) int input_has_transparency = png_ptr->num_trans > 0; /* If no alpha we can optimize. */ - if (input_has_alpha == 0) + if (!input_has_alpha) { /* Any alpha means background and associative alpha processing is - * required, however if the alpha is 0 or 1 throughout OPTIMIZE_ALPHA + * required, however if the alpha is 0 or 1 throughout OPTIIMIZE_ALPHA * and ENCODE_ALPHA are irrelevant. */ # ifdef PNG_READ_ALPHA_MODE_SUPPORTED @@ -1274,7 +1201,7 @@ png_init_rgb_transformations(png_structrp png_ptr) png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; # endif - if (input_has_transparency == 0) + if (!input_has_transparency) png_ptr->transformations &= ~(PNG_COMPOSE | PNG_BACKGROUND_EXPAND); } @@ -1287,9 +1214,9 @@ png_init_rgb_transformations(png_structrp png_ptr) /* The following code cannot be entered in the alpha pre-multiplication case * because PNG_BACKGROUND_EXPAND is cancelled below. */ - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0 && - (png_ptr->transformations & PNG_EXPAND) != 0 && - (png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + (png_ptr->transformations & PNG_EXPAND) && + !(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* i.e., GRAY or GRAY_ALPHA */ { { @@ -1317,7 +1244,7 @@ png_init_rgb_transformations(png_structrp png_ptr) default: case 8: - /* FALLTHROUGH */ /* (Already 8 bits) */ + /* FALL THROUGH (Already 8 bits) */ case 16: /* Already a full 16 bits */ @@ -1327,90 +1254,16 @@ png_init_rgb_transformations(png_structrp png_ptr) png_ptr->background.red = png_ptr->background.green = png_ptr->background.blue = (png_uint_16)gray; - if ((png_ptr->transformations & PNG_EXPAND_tRNS) == 0) + if (!(png_ptr->transformations & PNG_EXPAND_tRNS)) { png_ptr->trans_color.red = png_ptr->trans_color.green = png_ptr->trans_color.blue = (png_uint_16)trans_gray; } } } /* background expand and (therefore) no alpha association. */ -#endif /* READ_EXPAND && READ_BACKGROUND */ +#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ } -#ifdef PNG_READ_GAMMA_SUPPORTED -png_fixed_point /* PRIVATE */ -png_resolve_file_gamma(png_const_structrp png_ptr) -{ - png_fixed_point file_gamma; - - /* The file gamma is determined by these precedence rules, in this order - * (i.e. use the first value found): - * - * png_set_gamma; png_struct::file_gammma if not zero, then: - * png_struct::chunk_gamma if not 0 (determined the PNGv3 rules), then: - * png_set_gamma; 1/png_struct::screen_gamma if not zero - * - * 0 (i.e. do no gamma handling) - */ - file_gamma = png_ptr->file_gamma; - if (file_gamma != 0) - return file_gamma; - - file_gamma = png_ptr->chunk_gamma; - if (file_gamma != 0) - return file_gamma; - - file_gamma = png_ptr->default_gamma; - if (file_gamma != 0) - return file_gamma; - - /* If png_reciprocal oveflows it returns 0 which indicates to the caller that - * there is no usable file gamma. (The checks added to png_set_gamma and - * png_set_alpha_mode should prevent a screen_gamma which would overflow.) - */ - if (png_ptr->screen_gamma != 0) - file_gamma = png_reciprocal(png_ptr->screen_gamma); - - return file_gamma; -} - -static int -png_init_gamma_values(png_structrp png_ptr) -{ - /* The following temporary indicates if overall gamma correction is - * required. - */ - int gamma_correction = 0; - png_fixed_point file_gamma, screen_gamma; - - /* Resolve the file_gamma. See above: if png_ptr::screen_gamma is set - * file_gamma will always be set here: - */ - file_gamma = png_resolve_file_gamma(png_ptr); - screen_gamma = png_ptr->screen_gamma; - - if (file_gamma > 0) /* file has been set */ - { - if (screen_gamma > 0) /* screen set too */ - gamma_correction = png_gamma_threshold(file_gamma, screen_gamma); - - else - /* Assume the output matches the input; a long time default behavior - * of libpng, although the standard has nothing to say about this. - */ - screen_gamma = png_reciprocal(file_gamma); - } - - else /* both unset, prevent corrections: */ - file_gamma = screen_gamma = PNG_FP_1; - - png_ptr->file_gamma = file_gamma; - png_ptr->screen_gamma = screen_gamma; - return gamma_correction; - -} -#endif /* READ_GAMMA */ - void /* PRIVATE */ png_init_read_transformations(png_structrp png_ptr) { @@ -1430,26 +1283,63 @@ png_init_read_transformations(png_structrp png_ptr) * the test needs to be performed later - here. In addition prior to 1.5.4 * the tests were repeated for the PALETTE color type here - this is no * longer necessary (and doesn't seem to have been necessary before.) - * - * PNGv3: the new mandatory precedence/priority rules for colour space chunks - * are handled here (by calling the above function). - * - * Turn the gamma transformation on or off as appropriate. Notice that - * PNG_GAMMA just refers to the file->screen correction. Alpha composition - * may independently cause gamma correction because it needs linear data - * (e.g. if the file has a gAMA chunk but the screen gamma hasn't been - * specified.) In any case this flag may get turned off in the code - * immediately below if the transform can be handled outside the row loop. */ - if (png_init_gamma_values(png_ptr) != 0) - png_ptr->transformations |= PNG_GAMMA; + { + /* The following temporary indicates if overall gamma correction is + * required. + */ + int gamma_correction = 0; - else - png_ptr->transformations &= ~PNG_GAMMA; + if (png_ptr->colorspace.gamma != 0) /* has been set */ + { + if (png_ptr->screen_gamma != 0) /* screen set too */ + gamma_correction = png_gamma_threshold(png_ptr->colorspace.gamma, + png_ptr->screen_gamma); + + else + /* Assume the output matches the input; a long time default behavior + * of libpng, although the standard has nothing to say about this. + */ + png_ptr->screen_gamma = png_reciprocal(png_ptr->colorspace.gamma); + } + + else if (png_ptr->screen_gamma != 0) + /* The converse - assume the file matches the screen, note that this + * perhaps undesireable default can (from 1.5.4) be changed by calling + * png_set_alpha_mode (even if the alpha handling mode isn't required + * or isn't changed from the default.) + */ + png_ptr->colorspace.gamma = png_reciprocal(png_ptr->screen_gamma); + + else /* neither are set */ + /* Just in case the following prevents any processing - file and screen + * are both assumed to be linear and there is no way to introduce a + * third gamma value other than png_set_background with 'UNIQUE', and, + * prior to 1.5.4 + */ + png_ptr->screen_gamma = png_ptr->colorspace.gamma = PNG_FP_1; + + /* We have a gamma value now. */ + png_ptr->colorspace.flags |= PNG_COLORSPACE_HAVE_GAMMA; + + /* Now turn the gamma transformation on or off as appropriate. Notice + * that PNG_GAMMA just refers to the file->screen correction. Alpha + * composition may independently cause gamma correction because it needs + * linear data (e.g. if the file has a gAMA chunk but the screen gamma + * hasn't been specified.) In any case this flag may get turned off in + * the code immediately below if the transform can be handled outside the + * row loop. + */ + if (gamma_correction) + png_ptr->transformations |= PNG_GAMMA; + + else + png_ptr->transformations &= ~PNG_GAMMA; + } #endif /* Certain transformations have the effect of preventing other - * transformations that happen afterward in png_do_read_transformations; + * transformations that happen afterward in png_do_read_transformations, * resolve the interdependencies here. From the code of * png_do_read_transformations the order is: * @@ -1467,19 +1357,19 @@ png_init_read_transformations(png_structrp png_ptr) * 12) PNG_EXPAND_16 * 13) PNG_GRAY_TO_RGB iff PNG_BACKGROUND_IS_GRAY * 14) PNG_INVERT_MONO - * 15) PNG_INVERT_ALPHA - * 16) PNG_SHIFT - * 17) PNG_PACK - * 18) PNG_BGR - * 19) PNG_PACKSWAP - * 20) PNG_FILLER (includes PNG_ADD_ALPHA) + * 15) PNG_SHIFT + * 16) PNG_PACK + * 17) PNG_BGR + * 18) PNG_PACKSWAP + * 19) PNG_FILLER (includes PNG_ADD_ALPHA) + * 20) PNG_INVERT_ALPHA * 21) PNG_SWAP_ALPHA * 22) PNG_SWAP_BYTES * 23) PNG_USER_TRANSFORM [must be last] */ #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && - (png_ptr->transformations & PNG_COMPOSE) == 0) + if ((png_ptr->transformations & PNG_STRIP_ALPHA) && + !(png_ptr->transformations & PNG_COMPOSE)) { /* Stripping the alpha channel happens immediately after the 'expand' * transformations, before all other transformation, so it cancels out @@ -1505,7 +1395,7 @@ png_init_read_transformations(png_structrp png_ptr) /* If the screen gamma is about 1.0 then the OPTIMIZE_ALPHA and ENCODE_ALPHA * settings will have no effect. */ - if (png_gamma_significant(png_ptr->screen_gamma) == 0) + if (!png_gamma_significant(png_ptr->screen_gamma)) { png_ptr->transformations &= ~PNG_ENCODE_ALPHA; png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; @@ -1516,8 +1406,8 @@ png_init_read_transformations(png_structrp png_ptr) /* Make sure the coefficients for the rgb to gray conversion are set * appropriately. */ - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) - png_set_rgb_coefficients(png_ptr); + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + png_colorspace_set_rgb_coefficients(png_ptr); #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED @@ -1537,23 +1427,23 @@ png_init_read_transformations(png_structrp png_ptr) * png_set_background, along with the bit depth, then the code has a record * of exactly what color space the background is currently in. */ - if ((png_ptr->transformations & PNG_BACKGROUND_EXPAND) != 0) + if (png_ptr->transformations & PNG_BACKGROUND_EXPAND) { /* PNG_BACKGROUND_EXPAND: the background is in the file color space, so if * the file was grayscale the background value is gray. */ - if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) png_ptr->mode |= PNG_BACKGROUND_IS_GRAY; } - else if ((png_ptr->transformations & PNG_COMPOSE) != 0) + else if (png_ptr->transformations & PNG_COMPOSE) { /* PNG_COMPOSE: png_set_background was called with need_expand false, * so the color is in the color space of the output or png_set_alpha_mode * was called and the color is black. Ignore RGB_TO_GRAY because that * happens before GRAY_TO_RGB. */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) + if (png_ptr->transformations & PNG_GRAY_TO_RGB) { if (png_ptr->background.red == png_ptr->background.green && png_ptr->background.red == png_ptr->background.blue) @@ -1563,8 +1453,8 @@ png_init_read_transformations(png_structrp png_ptr) } } } -#endif /* READ_EXPAND && READ_BACKGROUND */ -#endif /* READ_GRAY_TO_RGB */ +#endif /* PNG_READ_EXPAND_SUPPORTED && PNG_READ_BACKGROUND_SUPPORTED */ +#endif /* PNG_READ_GRAY_TO_RGB_SUPPORTED */ /* For indexed PNG data (PNG_COLOR_TYPE_PALETTE) many of the transformations * can be performed directly on the palette, and some (such as rgb to gray) @@ -1585,10 +1475,10 @@ png_init_read_transformations(png_structrp png_ptr) #if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ defined(PNG_READ_EXPAND_16_SUPPORTED) - if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && - (png_ptr->transformations & PNG_COMPOSE) != 0 && - (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && - png_ptr->bit_depth != 16) + if ((png_ptr->transformations & PNG_EXPAND_16) && + (png_ptr->transformations & PNG_COMPOSE) && + !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + png_ptr->bit_depth != 16) { /* TODO: fix this. Because the expand_16 operation is after the compose * handling the background color must be 8, not 16, bits deep, but the @@ -1607,15 +1497,15 @@ png_init_read_transformations(png_structrp png_ptr) CHOP(png_ptr->background.gray); # undef CHOP } -#endif /* READ_BACKGROUND && READ_EXPAND_16 */ +#endif /* PNG_READ_BACKGROUND_SUPPORTED && PNG_READ_EXPAND_16_SUPPORTED */ #if defined(PNG_READ_BACKGROUND_SUPPORTED) && \ (defined(PNG_READ_SCALE_16_TO_8_SUPPORTED) || \ defined(PNG_READ_STRIP_16_TO_8_SUPPORTED)) - if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) != 0 && - (png_ptr->transformations & PNG_COMPOSE) != 0 && - (png_ptr->transformations & PNG_BACKGROUND_EXPAND) == 0 && - png_ptr->bit_depth == 16) + if ((png_ptr->transformations & (PNG_16_TO_8|PNG_SCALE_16_TO_8)) && + (png_ptr->transformations & PNG_COMPOSE) && + !(png_ptr->transformations & PNG_BACKGROUND_EXPAND) && + png_ptr->bit_depth == 16) { /* On the other hand, if a 16-bit file is to be reduced to 8-bits per * component this will also happen after PNG_COMPOSE and so the background @@ -1658,24 +1548,25 @@ png_init_read_transformations(png_structrp png_ptr) * file gamma - if it is not 1.0 both RGB_TO_GRAY and COMPOSE need the * tables. */ - if ((png_ptr->transformations & PNG_GAMMA) != 0 || - ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0 && - (png_gamma_significant(png_ptr->file_gamma) != 0 || - png_gamma_significant(png_ptr->screen_gamma) != 0)) || - ((png_ptr->transformations & PNG_COMPOSE) != 0 && - (png_gamma_significant(png_ptr->file_gamma) != 0 || - png_gamma_significant(png_ptr->screen_gamma) != 0 + if ((png_ptr->transformations & PNG_GAMMA) + || ((png_ptr->transformations & PNG_RGB_TO_GRAY) + && (png_gamma_significant(png_ptr->colorspace.gamma) || + png_gamma_significant(png_ptr->screen_gamma))) + || ((png_ptr->transformations & PNG_COMPOSE) + && (png_gamma_significant(png_ptr->colorspace.gamma) + || png_gamma_significant(png_ptr->screen_gamma) # ifdef PNG_READ_BACKGROUND_SUPPORTED - || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE && - png_gamma_significant(png_ptr->background_gamma) != 0) + || (png_ptr->background_gamma_type == PNG_BACKGROUND_GAMMA_UNIQUE + && png_gamma_significant(png_ptr->background_gamma)) # endif - )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && - png_gamma_significant(png_ptr->screen_gamma) != 0)) + )) || ((png_ptr->transformations & PNG_ENCODE_ALPHA) + && png_gamma_significant(png_ptr->screen_gamma)) + ) { png_build_gamma_table(png_ptr, png_ptr->bit_depth); #ifdef PNG_READ_BACKGROUND_SUPPORTED - if ((png_ptr->transformations & PNG_COMPOSE) != 0) + if (png_ptr->transformations & PNG_COMPOSE) { /* Issue a warning about this combination: because RGB_TO_GRAY is * optimized to do the gamma transform if present yet do_background has @@ -1683,11 +1574,11 @@ png_init_read_transformations(png_structrp png_ptr) * double-gamma-correction happens. This is true in all versions of * libpng to date. */ - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + if (png_ptr->transformations & PNG_RGB_TO_GRAY) png_warning(png_ptr, - "libpng does not support gamma+background+rgb_to_gray"); + "libpng does not support gamma+background+rgb_to_gray"); - if ((png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) != 0) + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { /* We don't get to here unless there is a tRNS chunk with non-opaque * entries - see the checking code at the start of this function. @@ -1719,15 +1610,15 @@ png_init_read_transformations(png_structrp png_ptr) break; case PNG_BACKGROUND_GAMMA_FILE: - g = png_reciprocal(png_ptr->file_gamma); - gs = png_reciprocal2(png_ptr->file_gamma, - png_ptr->screen_gamma); + g = png_reciprocal(png_ptr->colorspace.gamma); + gs = png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma); break; case PNG_BACKGROUND_GAMMA_UNIQUE: g = png_reciprocal(png_ptr->background_gamma); gs = png_reciprocal2(png_ptr->background_gamma, - png_ptr->screen_gamma); + png_ptr->screen_gamma); break; default: g = PNG_FP_1; /* back_1 */ @@ -1735,7 +1626,7 @@ png_init_read_transformations(png_structrp png_ptr) break; } - if (png_gamma_significant(gs) != 0) + if (png_gamma_significant(gs)) { back.red = png_gamma_8bit_correct(png_ptr->background.red, gs); @@ -1752,14 +1643,14 @@ png_init_read_transformations(png_structrp png_ptr) back.blue = (png_byte)png_ptr->background.blue; } - if (png_gamma_significant(g) != 0) + if (png_gamma_significant(g)) { back_1.red = png_gamma_8bit_correct(png_ptr->background.red, - g); + g); back_1.green = png_gamma_8bit_correct( - png_ptr->background.green, g); + png_ptr->background.green, g); back_1.blue = png_gamma_8bit_correct(png_ptr->background.blue, - g); + g); } else @@ -1781,51 +1672,19 @@ png_init_read_transformations(png_structrp png_ptr) } else /* if (png_ptr->trans_alpha[i] != 0xff) */ { - if ((png_ptr->flags & PNG_FLAG_OPTIMIZE_ALPHA) != 0) - { - /* Premultiply only: - * component = round((component * alpha) / 255) - */ - png_uint_32 component; + png_byte v, w; - component = png_ptr->gamma_to_1[palette[i].red]; - component = - (component * png_ptr->trans_alpha[i] + 128) / 255; - palette[i].red = png_ptr->gamma_from_1[component]; + v = png_ptr->gamma_to_1[palette[i].red]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.red); + palette[i].red = png_ptr->gamma_from_1[w]; - component = png_ptr->gamma_to_1[palette[i].green]; - component = - (component * png_ptr->trans_alpha[i] + 128) / 255; - palette[i].green = png_ptr->gamma_from_1[component]; + v = png_ptr->gamma_to_1[palette[i].green]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.green); + palette[i].green = png_ptr->gamma_from_1[w]; - component = png_ptr->gamma_to_1[palette[i].blue]; - component = - (component * png_ptr->trans_alpha[i] + 128) / 255; - palette[i].blue = png_ptr->gamma_from_1[component]; - } - else - { - /* Composite with background color: - * component = - * alpha * component + (1 - alpha) * background - */ - png_byte v, w; - - v = png_ptr->gamma_to_1[palette[i].red]; - png_composite(w, v, - png_ptr->trans_alpha[i], back_1.red); - palette[i].red = png_ptr->gamma_from_1[w]; - - v = png_ptr->gamma_to_1[palette[i].green]; - png_composite(w, v, - png_ptr->trans_alpha[i], back_1.green); - palette[i].green = png_ptr->gamma_from_1[w]; - - v = png_ptr->gamma_to_1[palette[i].blue]; - png_composite(w, v, - png_ptr->trans_alpha[i], back_1.blue); - palette[i].blue = png_ptr->gamma_from_1[w]; - } + v = png_ptr->gamma_to_1[palette[i].blue]; + png_composite(w, v, png_ptr->trans_alpha[i], back_1.blue); + palette[i].blue = png_ptr->gamma_from_1[w]; } } else @@ -1843,7 +1702,6 @@ png_init_read_transformations(png_structrp png_ptr) * transformations elsewhere. */ png_ptr->transformations &= ~(PNG_COMPOSE | PNG_GAMMA); - png_ptr->flags &= ~PNG_FLAG_OPTIMIZE_ALPHA; } /* color_type == PNG_COLOR_TYPE_PALETTE */ /* if (png_ptr->background_gamma_type!=PNG_BACKGROUND_GAMMA_UNKNOWN) */ @@ -1861,9 +1719,9 @@ png_init_read_transformations(png_structrp png_ptr) break; case PNG_BACKGROUND_GAMMA_FILE: - g = png_reciprocal(png_ptr->file_gamma); - gs = png_reciprocal2(png_ptr->file_gamma, - png_ptr->screen_gamma); + g = png_reciprocal(png_ptr->colorspace.gamma); + gs = png_reciprocal2(png_ptr->colorspace.gamma, + png_ptr->screen_gamma); break; case PNG_BACKGROUND_GAMMA_UNIQUE: @@ -1879,11 +1737,11 @@ png_init_read_transformations(png_structrp png_ptr) g_sig = png_gamma_significant(g); gs_sig = png_gamma_significant(gs); - if (g_sig != 0) + if (g_sig) png_ptr->background_1.gray = png_gamma_correct(png_ptr, png_ptr->background.gray, g); - if (gs_sig != 0) + if (gs_sig) png_ptr->background.gray = png_gamma_correct(png_ptr, png_ptr->background.gray, gs); @@ -1892,7 +1750,7 @@ png_init_read_transformations(png_structrp png_ptr) (png_ptr->background.red != png_ptr->background.gray)) { /* RGB or RGBA with color background */ - if (g_sig != 0) + if (g_sig) { png_ptr->background_1.red = png_gamma_correct(png_ptr, png_ptr->background.red, g); @@ -1904,7 +1762,7 @@ png_init_read_transformations(png_structrp png_ptr) png_ptr->background.blue, g); } - if (gs_sig != 0) + if (gs_sig) { png_ptr->background.red = png_gamma_correct(png_ptr, png_ptr->background.red, gs); @@ -1934,7 +1792,7 @@ png_init_read_transformations(png_structrp png_ptr) else /* Transformation does not include PNG_BACKGROUND */ -#endif /* READ_BACKGROUND */ +#endif /* PNG_READ_BACKGROUND_SUPPORTED */ if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED /* RGB_TO_GRAY needs to have non-gamma-corrected values! */ @@ -1964,11 +1822,11 @@ png_init_read_transformations(png_structrp png_ptr) #ifdef PNG_READ_BACKGROUND_SUPPORTED else #endif -#endif /* READ_GAMMA */ +#endif /* PNG_READ_GAMMA_SUPPORTED */ #ifdef PNG_READ_BACKGROUND_SUPPORTED /* No GAMMA transformation (see the hanging else 4 lines above) */ - if ((png_ptr->transformations & PNG_COMPOSE) != 0 && + if ((png_ptr->transformations & PNG_COMPOSE) && (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) { int i; @@ -2003,11 +1861,11 @@ png_init_read_transformations(png_structrp png_ptr) png_ptr->transformations &= ~PNG_COMPOSE; } -#endif /* READ_BACKGROUND */ +#endif /* PNG_READ_BACKGROUND_SUPPORTED */ #ifdef PNG_READ_SHIFT_SUPPORTED - if ((png_ptr->transformations & PNG_SHIFT) != 0 && - (png_ptr->transformations & PNG_EXPAND) == 0 && + if ((png_ptr->transformations & PNG_SHIFT) && + !(png_ptr->transformations & PNG_EXPAND) && (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE)) { int i; @@ -2016,40 +1874,37 @@ png_init_read_transformations(png_structrp png_ptr) png_ptr->transformations &= ~PNG_SHIFT; - /* significant bits can be in the range 1 to 7 for a meaningful result, if + /* significant bits can be in the range 1 to 7 for a meaninful result, if * the number of significant bits is 0 then no shift is done (this is an * error condition which is silently ignored.) */ - if (shift > 0 && shift < 8) - for (i=0; ipalette[i].red; + if (shift > 0 && shift < 8) for (i=0; ipalette[i].red; - component >>= shift; - png_ptr->palette[i].red = (png_byte)component; - } + component >>= shift; + png_ptr->palette[i].red = (png_byte)component; + } shift = 8 - png_ptr->sig_bit.green; - if (shift > 0 && shift < 8) - for (i=0; ipalette[i].green; + if (shift > 0 && shift < 8) for (i=0; ipalette[i].green; - component >>= shift; - png_ptr->palette[i].green = (png_byte)component; - } + component >>= shift; + png_ptr->palette[i].green = (png_byte)component; + } shift = 8 - png_ptr->sig_bit.blue; - if (shift > 0 && shift < 8) - for (i=0; ipalette[i].blue; + if (shift > 0 && shift < 8) for (i=0; ipalette[i].blue; - component >>= shift; - png_ptr->palette[i].blue = (png_byte)component; - } + component >>= shift; + png_ptr->palette[i].blue = (png_byte)component; + } } -#endif /* READ_SHIFT */ +#endif /* PNG_READ_SHIFT_SUPPORTED */ } /* Modify the info structure to reflect the transformations. The @@ -2062,7 +1917,7 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) png_debug(1, "in png_read_transform_info"); #ifdef PNG_READ_EXPAND_SUPPORTED - if ((png_ptr->transformations & PNG_EXPAND) != 0) + if (png_ptr->transformations & PNG_EXPAND) { if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { @@ -2078,15 +1933,12 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) info_ptr->bit_depth = 8; info_ptr->num_trans = 0; - - if (png_ptr->palette == NULL) - png_error (png_ptr, "Palette is NULL in indexed image"); } else { - if (png_ptr->num_trans != 0) + if (png_ptr->num_trans) { - if ((png_ptr->transformations & PNG_EXPAND_tRNS) != 0) + if (png_ptr->transformations & PNG_EXPAND_tRNS) info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; } if (info_ptr->bit_depth < 8) @@ -2102,7 +1954,7 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) /* The following is almost certainly wrong unless the background value is in * the screen space! */ - if ((png_ptr->transformations & PNG_COMPOSE) != 0) + if (png_ptr->transformations & PNG_COMPOSE) info_ptr->background = png_ptr->background; #endif @@ -2112,28 +1964,28 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) * been called before this from png_read_update_info->png_read_start_row * sometimes does the gamma transform and cancels the flag. * - * TODO: this is confusing. It only changes the result of png_get_gAMA and, - * yes, it does return the value that the transformed data effectively has - * but does any app really understand this? + * TODO: this looks wrong; the info_ptr should end up with a gamma equal to + * the screen_gamma value. The following probably results in weirdness if + * the info_ptr is used by the app after the rows have been read. */ - info_ptr->gamma = png_ptr->file_gamma; + info_ptr->colorspace.gamma = png_ptr->colorspace.gamma; #endif if (info_ptr->bit_depth == 16) { # ifdef PNG_READ_16BIT_SUPPORTED # ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) + if (png_ptr->transformations & PNG_SCALE_16_TO_8) info_ptr->bit_depth = 8; # endif # ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - if ((png_ptr->transformations & PNG_16_TO_8) != 0) + if (png_ptr->transformations & PNG_16_TO_8) info_ptr->bit_depth = 8; # endif # else - /* No 16-bit support: force chopping 16-bit input down to 8, in this case + /* No 16 bit support: force chopping 16-bit input down to 8, in this case * the app program can chose if both APIs are available by setting the * correct scaling to use. */ @@ -2154,27 +2006,27 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) CONFIGURATION ERROR: you must enable at least one 16 to 8 method # endif # endif -#endif /* !READ_16BIT */ +#endif /* !READ_16BIT_SUPPORTED */ } #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) + if (png_ptr->transformations & PNG_GRAY_TO_RGB) info_ptr->color_type = (png_byte)(info_ptr->color_type | PNG_COLOR_MASK_COLOR); #endif #ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) + if (png_ptr->transformations & PNG_RGB_TO_GRAY) info_ptr->color_type = (png_byte)(info_ptr->color_type & ~PNG_COLOR_MASK_COLOR); #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED - if ((png_ptr->transformations & PNG_QUANTIZE) != 0) + if (png_ptr->transformations & PNG_QUANTIZE) { if (((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || (info_ptr->color_type == PNG_COLOR_TYPE_RGB_ALPHA)) && - png_ptr->palette_lookup != 0 && info_ptr->bit_depth == 8) + png_ptr->palette_lookup && info_ptr->bit_depth == 8) { info_ptr->color_type = PNG_COLOR_TYPE_PALETTE; } @@ -2182,31 +2034,29 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED - if ((png_ptr->transformations & PNG_EXPAND_16) != 0 && - info_ptr->bit_depth == 8 && - info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + if (png_ptr->transformations & PNG_EXPAND_16 && info_ptr->bit_depth == 8 && + info_ptr->color_type != PNG_COLOR_TYPE_PALETTE) { info_ptr->bit_depth = 16; } #endif #ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) != 0 && - (info_ptr->bit_depth < 8)) + if ((png_ptr->transformations & PNG_PACK) && (info_ptr->bit_depth < 8)) info_ptr->bit_depth = 8; #endif if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) info_ptr->channels = 1; - else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) info_ptr->channels = 3; else info_ptr->channels = 1; #ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0) + if (png_ptr->transformations & PNG_STRIP_ALPHA) { info_ptr->color_type = (png_byte)(info_ptr->color_type & ~PNG_COLOR_MASK_ALPHA); @@ -2214,30 +2064,30 @@ png_read_transform_info(png_structrp png_ptr, png_inforp info_ptr) } #endif - if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) info_ptr->channels++; #ifdef PNG_READ_FILLER_SUPPORTED /* STRIP_ALPHA and FILLER allowed: MASK_ALPHA bit stripped above */ - if ((png_ptr->transformations & PNG_FILLER) != 0 && - (info_ptr->color_type == PNG_COLOR_TYPE_RGB || - info_ptr->color_type == PNG_COLOR_TYPE_GRAY)) + if ((png_ptr->transformations & PNG_FILLER) && + ((info_ptr->color_type == PNG_COLOR_TYPE_RGB) || + (info_ptr->color_type == PNG_COLOR_TYPE_GRAY))) { info_ptr->channels++; /* If adding a true alpha channel not just filler */ - if ((png_ptr->transformations & PNG_ADD_ALPHA) != 0) + if (png_ptr->transformations & PNG_ADD_ALPHA) info_ptr->color_type |= PNG_COLOR_MASK_ALPHA; } #endif #if defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) && \ defined(PNG_READ_USER_TRANSFORM_SUPPORTED) - if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + if (png_ptr->transformations & PNG_USER_TRANSFORM) { - if (png_ptr->user_transform_depth != 0) + if (info_ptr->bit_depth < png_ptr->user_transform_depth) info_ptr->bit_depth = png_ptr->user_transform_depth; - if (png_ptr->user_transform_channels != 0) + if (info_ptr->channels < png_ptr->user_transform_channels) info_ptr->channels = png_ptr->user_transform_channels; } #endif @@ -2256,11 +2106,308 @@ defined(PNG_READ_USER_TRANSFORM_SUPPORTED) png_ptr->info_rowbytes = info_ptr->rowbytes; #ifndef PNG_READ_EXPAND_SUPPORTED - if (png_ptr != NULL) + if (png_ptr) return; #endif } +/* Transform the row. The order of transformations is significant, + * and is very touchy. If you add a transformation, take care to + * decide how it fits in with the other transformations here. + */ +void /* PRIVATE */ +png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) +{ + png_debug(1, "in png_do_read_transformations"); + + if (png_ptr->row_buf == NULL) + { + /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this + * error is incredibly rare and incredibly easy to debug without this + * information. + */ + png_error(png_ptr, "NULL row buffer"); + } + + /* The following is debugging; prior to 1.5.4 the code was never compiled in; + * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro + * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for + * all transformations, however in practice the ROW_INIT always gets done on + * demand, if necessary. + */ + if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && + !(png_ptr->flags & PNG_FLAG_ROW_INIT)) + { + /* Application has failed to call either png_read_start_image() or + * png_read_update_info() after setting transforms that expand pixels. + * This check added to libpng-1.2.19 (but not enabled until 1.5.4). + */ + png_error(png_ptr, "Uninitialized row"); + } + +#ifdef PNG_READ_EXPAND_SUPPORTED + if (png_ptr->transformations & PNG_EXPAND) + { + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) + { + png_do_expand_palette(row_info, png_ptr->row_buf + 1, + png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); + } + + else + { + if (png_ptr->num_trans && + (png_ptr->transformations & PNG_EXPAND_tRNS)) + png_do_expand(row_info, png_ptr->row_buf + 1, + &(png_ptr->trans_color)); + + else + png_do_expand(row_info, png_ptr->row_buf + 1, + NULL); + } + } +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) && + !(png_ptr->transformations & PNG_COMPOSE) && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + if (png_ptr->transformations & PNG_RGB_TO_GRAY) + { + int rgb_error = + png_do_rgb_to_gray(png_ptr, row_info, + png_ptr->row_buf + 1); + + if (rgb_error) + { + png_ptr->rgb_to_gray_status=1; + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_WARN) + png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + + if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == + PNG_RGB_TO_GRAY_ERR) + png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + } + } +#endif + +/* From Andreas Dilger e-mail to png-implement, 26 March 1998: + * + * In most cases, the "simple transparency" should be done prior to doing + * gray-to-RGB, or you will have to test 3x as many bytes to check if a + * pixel is transparent. You would also need to make sure that the + * transparency information is upgraded to RGB. + * + * To summarize, the current flow is: + * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite + * with background "in place" if transparent, + * convert to RGB if necessary + * - Gray + alpha -> composite with gray background and remove alpha bytes, + * convert to RGB if necessary + * + * To support RGB backgrounds for gray images we need: + * - Gray + simple transparency -> convert to RGB + simple transparency, + * compare 3 or 6 bytes and composite with + * background "in place" if transparent + * (3x compare/pixel compared to doing + * composite with gray bkgrnd) + * - Gray + alpha -> convert to RGB + alpha, composite with background and + * remove alpha bytes (3x float + * operations/pixel compared with composite + * on gray background) + * + * Greg's change will do this. The reason it wasn't done before is for + * performance, as this increases the per-pixel operations. If we would check + * in advance if the background was gray or RGB, and position the gray-to-RGB + * transform appropriately, then it would save a lot of work/time. + */ + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* If gray -> RGB, do so now only if background is non-gray; else do later + * for performance reasons + */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + !(png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + if (png_ptr->transformations & PNG_COMPOSE) + png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_GAMMA_SUPPORTED + if ((png_ptr->transformations & PNG_GAMMA) && +#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED + /* Because RGB_TO_GRAY does the gamma transform. */ + !(png_ptr->transformations & PNG_RGB_TO_GRAY) && +#endif +#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ + defined(PNG_READ_ALPHA_MODE_SUPPORTED) + /* Because PNG_COMPOSE does the gamma transform if there is something to + * do (if there is an alpha channel or transparency.) + */ + !((png_ptr->transformations & PNG_COMPOSE) && + ((png_ptr->num_trans != 0) || + (png_ptr->color_type & PNG_COLOR_MASK_ALPHA))) && +#endif + /* Because png_init_read_transformations transforms the palette, unless + * RGB_TO_GRAY will do the transform. + */ + (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) + png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED + if ((png_ptr->transformations & PNG_STRIP_ALPHA) && + (png_ptr->transformations & PNG_COMPOSE) && + (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || + row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + 0 /* at_start == false, because SWAP_ALPHA happens later */); +#endif + +#ifdef PNG_READ_ALPHA_MODE_SUPPORTED + if ((png_ptr->transformations & PNG_ENCODE_ALPHA) && + (row_info->color_type & PNG_COLOR_MASK_ALPHA)) + png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr); +#endif + +#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED + if (png_ptr->transformations & PNG_SCALE_16_TO_8) + png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED + /* There is no harm in doing both of these because only one has any effect, + * by putting the 'scale' option first if the app asks for scale (either by + * calling the API or in a TRANSFORM flag) this is what happens. + */ + if (png_ptr->transformations & PNG_16_TO_8) + png_do_chop(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_QUANTIZE_SUPPORTED + if (png_ptr->transformations & PNG_QUANTIZE) + { + png_do_quantize(row_info, png_ptr->row_buf + 1, + png_ptr->palette_lookup, png_ptr->quantize_index); + + if (row_info->rowbytes == 0) + png_error(png_ptr, "png_do_quantize returned rowbytes=0"); + } +#endif /* PNG_READ_QUANTIZE_SUPPORTED */ + +#ifdef PNG_READ_EXPAND_16_SUPPORTED + /* Do the expansion now, after all the arithmetic has been done. Notice + * that previous transformations can handle the PNG_EXPAND_16 flag if this + * is efficient (particularly true in the case of gamma correction, where + * better accuracy results faster!) + */ + if (png_ptr->transformations & PNG_EXPAND_16) + png_do_expand_16(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED + /* NOTE: moved here in 1.5.4 (from much later in this list.) */ + if ((png_ptr->transformations & PNG_GRAY_TO_RGB) && + (png_ptr->mode & PNG_BACKGROUND_IS_GRAY)) + png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_INVERT_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_MONO) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SHIFT_SUPPORTED + if (png_ptr->transformations & PNG_SHIFT) + png_do_unshift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_READ_PACK_SUPPORTED + if (png_ptr->transformations & PNG_PACK) + png_do_unpack(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED + /* Added at libpng-1.5.10 */ + if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && + png_ptr->num_palette_max >= 0) + png_do_check_palette_indexes(png_ptr, row_info); +#endif + +#ifdef PNG_READ_BGR_SUPPORTED + if (png_ptr->transformations & PNG_BGR) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_FILLER_SUPPORTED + if (png_ptr->transformations & PNG_FILLER) + png_do_read_filler(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->filler, png_ptr->flags); +#endif + +#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_ALPHA) + png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_ALPHA) + png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_READ_16BIT_SUPPORTED +#ifdef PNG_READ_SWAP_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_do_swap(row_info, png_ptr->row_buf + 1); +#endif +#endif + +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + if (png_ptr->transformations & PNG_USER_TRANSFORM) + { + if (png_ptr->read_user_transform_fn != NULL) + (*(png_ptr->read_user_transform_fn)) /* User read transform function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_size_t rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED + if (png_ptr->user_transform_depth) + row_info->bit_depth = png_ptr->user_transform_depth; + + if (png_ptr->user_transform_channels) + row_info->channels = png_ptr->user_transform_channels; +#endif + row_info->pixel_depth = (png_byte)(row_info->bit_depth * + row_info->channels); + + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); + } +#endif +} + #ifdef PNG_READ_PACK_SUPPORTED /* Unpack pixels of 1, 2, or 4 bits per pixel into 1 byte per pixel, * without changing the actual values. Thus, if you had a row with @@ -2268,7 +2415,7 @@ defined(PNG_READ_USER_TRANSFORM_SUPPORTED) * the numbers 0 or 1. If you would rather they contain 0 and 255, use * png_do_shift() after this. */ -static void +void /* PRIVATE */ png_do_unpack(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_unpack"); @@ -2282,9 +2429,9 @@ png_do_unpack(png_row_infop row_info, png_bytep row) { case 1: { - png_bytep sp = row + (size_t)((row_width - 1) >> 3); - png_bytep dp = row + (size_t)row_width - 1; - png_uint_32 shift = 7U - ((row_width + 7U) & 0x07); + png_bytep sp = row + (png_size_t)((row_width - 1) >> 3); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = 7 - (int)((row_width + 7) & 0x07); for (i = 0; i < row_width; i++) { *dp = (png_byte)((*sp >> shift) & 0x01); @@ -2306,9 +2453,9 @@ png_do_unpack(png_row_infop row_info, png_bytep row) case 2: { - png_bytep sp = row + (size_t)((row_width - 1) >> 2); - png_bytep dp = row + (size_t)row_width - 1; - png_uint_32 shift = ((3U - ((row_width + 3U) & 0x03)) << 1); + png_bytep sp = row + (png_size_t)((row_width - 1) >> 2); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); for (i = 0; i < row_width; i++) { *dp = (png_byte)((*sp >> shift) & 0x03); @@ -2329,9 +2476,9 @@ png_do_unpack(png_row_infop row_info, png_bytep row) case 4: { - png_bytep sp = row + (size_t)((row_width - 1) >> 1); - png_bytep dp = row + (size_t)row_width - 1; - png_uint_32 shift = ((1U - ((row_width + 1U) & 0x01)) << 2); + png_bytep sp = row + (png_size_t)((row_width - 1) >> 1); + png_bytep dp = row + (png_size_t)row_width - 1; + png_uint_32 shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); for (i = 0; i < row_width; i++) { *dp = (png_byte)((*sp >> shift) & 0x0f); @@ -2366,7 +2513,7 @@ png_do_unpack(png_row_infop row_info, png_bytep row) * a row of bit depth 8, but only 5 are significant, this will shift * the values back to 0 through 31. */ -static void +void /* PRIVATE */ png_do_unshift(png_row_infop row_info, png_bytep row, png_const_color_8p sig_bits) { @@ -2383,7 +2530,7 @@ png_do_unshift(png_row_infop row_info, png_bytep row, int channels = 0; int bit_depth = row_info->bit_depth; - if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + if (color_type & PNG_COLOR_MASK_COLOR) { shift[channels++] = bit_depth - sig_bits->red; shift[channels++] = bit_depth - sig_bits->green; @@ -2395,7 +2542,7 @@ png_do_unshift(png_row_infop row_info, png_bytep row, shift[channels++] = bit_depth - sig_bits->gray; } - if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) + if (color_type & PNG_COLOR_MASK_ALPHA) { shift[channels++] = bit_depth - sig_bits->alpha; } @@ -2415,7 +2562,7 @@ png_do_unshift(png_row_infop row_info, png_bytep row, have_shift = 1; } - if (have_shift == 0) + if (!have_shift) return; } @@ -2493,7 +2640,7 @@ png_do_unshift(png_row_infop row_info, png_bytep row, if (++channel >= channels) channel = 0; *bp++ = (png_byte)(value >> 8); - *bp++ = (png_byte)value; + *bp++ = (png_byte)(value & 0xff); } break; } @@ -2505,7 +2652,7 @@ png_do_unshift(png_row_infop row_info, png_bytep row, #ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED /* Scale rows of bit depth 16 down to 8 accurately */ -static void +void /* PRIVATE */ png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_scale_16_to_8"); @@ -2518,8 +2665,8 @@ png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) while (sp < ep) { - /* The input is an array of 16-bit components, these must be scaled to - * 8 bits each. For a 16-bit value V the required value (from the PNG + /* The input is an array of 16 bit components, these must be scaled to + * 8 bits each. For a 16 bit value V the required value (from the PNG * specification) is: * * (V * 255) / 65535 @@ -2540,7 +2687,7 @@ png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) * * The approximate differs from the exact answer only when (vlo-vhi) is * 128; it then gives a correction of +1 when the exact correction is - * 0. This gives 128 errors. The exact answer (correct for all 16-bit + * 0. This gives 128 errors. The exact answer (correct for all 16 bit * input values) is: * * error = (vlo-vhi+128)*65535 >> 24; @@ -2563,7 +2710,7 @@ png_do_scale_16_to_8(png_row_infop row_info, png_bytep row) #endif #ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED -static void +void /* PRIVATE */ /* Simply discard the low byte. This was the default behavior prior * to libpng-1.5.4. */ @@ -2591,103 +2738,104 @@ png_do_chop(png_row_infop row_info, png_bytep row) #endif #ifdef PNG_READ_SWAP_ALPHA_SUPPORTED -static void +void /* PRIVATE */ png_do_read_swap_alpha(png_row_infop row_info, png_bytep row) { - png_uint_32 row_width = row_info->width; - png_debug(1, "in png_do_read_swap_alpha"); - if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - /* This converts from RGBA to ARGB */ - if (row_info->bit_depth == 8) + png_uint_32 row_width = row_info->width; + if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save; - png_uint_32 i; - - for (i = 0; i < row_width; i++) + /* This converts from RGBA to ARGB */ + if (row_info->bit_depth == 8) { - save = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save; + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } } - } #ifdef PNG_READ_16BIT_SUPPORTED - /* This converts from RRGGBBAA to AARRGGBB */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save[2]; - png_uint_32 i; - - for (i = 0; i < row_width; i++) + /* This converts from RRGGBBAA to AARRGGBB */ + else { - save[0] = *(--sp); - save[1] = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save[0]; - *(--dp) = save[1]; + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } } - } #endif - } - - else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) - { - /* This converts from GA to AG */ - if (row_info->bit_depth == 8) - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save; - png_uint_32 i; - - for (i = 0; i < row_width; i++) - { - save = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save; - } } + else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) + { + /* This converts from GA to AG */ + if (row_info->bit_depth == 8) + { + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save; + } + } + #ifdef PNG_READ_16BIT_SUPPORTED - /* This converts from GGAA to AAGG */ - else - { - png_bytep sp = row + row_info->rowbytes; - png_bytep dp = sp; - png_byte save[2]; - png_uint_32 i; - - for (i = 0; i < row_width; i++) + /* This converts from GGAA to AAGG */ + else { - save[0] = *(--sp); - save[1] = *(--sp); - *(--dp) = *(--sp); - *(--dp) = *(--sp); - *(--dp) = save[0]; - *(--dp) = save[1]; + png_bytep sp = row + row_info->rowbytes; + png_bytep dp = sp; + png_byte save[2]; + png_uint_32 i; + + for (i = 0; i < row_width; i++) + { + save[0] = *(--sp); + save[1] = *(--sp); + *(--dp) = *(--sp); + *(--dp) = *(--sp); + *(--dp) = save[0]; + *(--dp) = save[1]; + } } - } #endif + } } } #endif #ifdef PNG_READ_INVERT_ALPHA_SUPPORTED -static void +void /* PRIVATE */ png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) { png_uint_32 row_width; @@ -2789,7 +2937,7 @@ png_do_read_invert_alpha(png_row_infop row_info, png_bytep row) #ifdef PNG_READ_FILLER_SUPPORTED /* Add filler channel if we have RGB color */ -static void +void /* PRIVATE */ png_do_read_filler(png_row_infop row_info, png_bytep row, png_uint_32 filler, png_uint_32 flags) { @@ -2797,9 +2945,9 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, png_uint_32 row_width = row_info->width; #ifdef PNG_READ_16BIT_SUPPORTED - png_byte hi_filler = (png_byte)(filler>>8); + png_byte hi_filler = (png_byte)((filler>>8) & 0xff); #endif - png_byte lo_filler = (png_byte)filler; + png_byte lo_filler = (png_byte)(filler & 0xff); png_debug(1, "in png_do_read_filler"); @@ -2808,11 +2956,11 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, { if (row_info->bit_depth == 8) { - if ((flags & PNG_FLAG_FILLER_AFTER) != 0) + if (flags & PNG_FLAG_FILLER_AFTER) { /* This changes the data from G to GX */ - png_bytep sp = row + (size_t)row_width; - png_bytep dp = sp + (size_t)row_width; + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; for (i = 1; i < row_width; i++) { *(--dp) = lo_filler; @@ -2827,8 +2975,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, else { /* This changes the data from G to XG */ - png_bytep sp = row + (size_t)row_width; - png_bytep dp = sp + (size_t)row_width; + png_bytep sp = row + (png_size_t)row_width; + png_bytep dp = sp + (png_size_t)row_width; for (i = 0; i < row_width; i++) { *(--dp) = *(--sp); @@ -2843,20 +2991,20 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, #ifdef PNG_READ_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { - if ((flags & PNG_FLAG_FILLER_AFTER) != 0) + if (flags & PNG_FLAG_FILLER_AFTER) { /* This changes the data from GG to GGXX */ - png_bytep sp = row + (size_t)row_width * 2; - png_bytep dp = sp + (size_t)row_width * 2; + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 1; i < row_width; i++) { - *(--dp) = lo_filler; *(--dp) = hi_filler; + *(--dp) = lo_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); } - *(--dp) = lo_filler; *(--dp) = hi_filler; + *(--dp) = lo_filler; row_info->channels = 2; row_info->pixel_depth = 32; row_info->rowbytes = row_width * 4; @@ -2865,14 +3013,14 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, else { /* This changes the data from GG to XXGG */ - png_bytep sp = row + (size_t)row_width * 2; - png_bytep dp = sp + (size_t)row_width * 2; + png_bytep sp = row + (png_size_t)row_width * 2; + png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 0; i < row_width; i++) { *(--dp) = *(--sp); *(--dp) = *(--sp); - *(--dp) = lo_filler; *(--dp) = hi_filler; + *(--dp) = lo_filler; } row_info->channels = 2; row_info->pixel_depth = 32; @@ -2885,11 +3033,11 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, { if (row_info->bit_depth == 8) { - if ((flags & PNG_FLAG_FILLER_AFTER) != 0) + if (flags & PNG_FLAG_FILLER_AFTER) { /* This changes the data from RGB to RGBX */ - png_bytep sp = row + (size_t)row_width * 3; - png_bytep dp = sp + (size_t)row_width; + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; for (i = 1; i < row_width; i++) { *(--dp) = lo_filler; @@ -2906,8 +3054,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, else { /* This changes the data from RGB to XRGB */ - png_bytep sp = row + (size_t)row_width * 3; - png_bytep dp = sp + (size_t)row_width; + png_bytep sp = row + (png_size_t)row_width * 3; + png_bytep dp = sp + (png_size_t)row_width; for (i = 0; i < row_width; i++) { *(--dp) = *(--sp); @@ -2924,15 +3072,15 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, #ifdef PNG_READ_16BIT_SUPPORTED else if (row_info->bit_depth == 16) { - if ((flags & PNG_FLAG_FILLER_AFTER) != 0) + if (flags & PNG_FLAG_FILLER_AFTER) { /* This changes the data from RRGGBB to RRGGBBXX */ - png_bytep sp = row + (size_t)row_width * 6; - png_bytep dp = sp + (size_t)row_width * 2; + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 1; i < row_width; i++) { - *(--dp) = lo_filler; *(--dp) = hi_filler; + *(--dp) = lo_filler; *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); @@ -2940,8 +3088,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, *(--dp) = *(--sp); *(--dp) = *(--sp); } - *(--dp) = lo_filler; *(--dp) = hi_filler; + *(--dp) = lo_filler; row_info->channels = 4; row_info->pixel_depth = 64; row_info->rowbytes = row_width * 8; @@ -2950,8 +3098,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, else { /* This changes the data from RRGGBB to XXRRGGBB */ - png_bytep sp = row + (size_t)row_width * 6; - png_bytep dp = sp + (size_t)row_width * 2; + png_bytep sp = row + (png_size_t)row_width * 6; + png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 0; i < row_width; i++) { *(--dp) = *(--sp); @@ -2960,8 +3108,8 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, *(--dp) = *(--sp); *(--dp) = *(--sp); *(--dp) = *(--sp); - *(--dp) = lo_filler; *(--dp) = hi_filler; + *(--dp) = lo_filler; } row_info->channels = 4; @@ -2976,7 +3124,7 @@ png_do_read_filler(png_row_infop row_info, png_bytep row, #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED /* Expand grayscale files to RGB, with or without alpha */ -static void +void /* PRIVATE */ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) { png_uint_32 i; @@ -2985,15 +3133,15 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) png_debug(1, "in png_do_gray_to_rgb"); if (row_info->bit_depth >= 8 && - (row_info->color_type & PNG_COLOR_MASK_COLOR) == 0) + !(row_info->color_type & PNG_COLOR_MASK_COLOR)) { if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { if (row_info->bit_depth == 8) { /* This changes G to RGB */ - png_bytep sp = row + (size_t)row_width - 1; - png_bytep dp = sp + (size_t)row_width * 2; + png_bytep sp = row + (png_size_t)row_width - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 0; i < row_width; i++) { *(dp--) = *sp; @@ -3005,8 +3153,8 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) else { /* This changes GG to RRGGBB */ - png_bytep sp = row + (size_t)row_width * 2 - 1; - png_bytep dp = sp + (size_t)row_width * 4; + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; for (i = 0; i < row_width; i++) { *(dp--) = *sp; @@ -3024,8 +3172,8 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) if (row_info->bit_depth == 8) { /* This changes GA to RGBA */ - png_bytep sp = row + (size_t)row_width * 2 - 1; - png_bytep dp = sp + (size_t)row_width * 2; + png_bytep sp = row + (png_size_t)row_width * 2 - 1; + png_bytep dp = sp + (png_size_t)row_width * 2; for (i = 0; i < row_width; i++) { *(dp--) = *(sp--); @@ -3038,8 +3186,8 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) else { /* This changes GGAA to RRGGBBAA */ - png_bytep sp = row + (size_t)row_width * 4 - 1; - png_bytep dp = sp + (size_t)row_width * 4; + png_bytep sp = row + (png_size_t)row_width * 4 - 1; + png_bytep dp = sp + (png_size_t)row_width * 4; for (i = 0; i < row_width; i++) { *(dp--) = *(sp--); @@ -3067,7 +3215,7 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) * using the equation given in Poynton's ColorFAQ of 1998-01-04 at * (THIS LINK IS DEAD June 2008 but * versions dated 1998 through November 2002 have been archived at - * https://web.archive.org/web/20000816232553/www.inforamp.net/ + * http://web.archive.org/web/20000816232553/http://www.inforamp.net/ * ~poynton/notes/colour_and_gamma/ColorFAQ.txt ) * Charles Poynton poynton at poynton.com * @@ -3110,26 +3258,28 @@ png_do_gray_to_rgb(png_row_infop row_info, png_bytep row) * values this results in an implicit assumption that the original PNG RGB * values were linear. * - * Other integer coefficients can be used via png_set_rgb_to_gray(). Because + * Other integer coefficents can be used via png_set_rgb_to_gray(). Because * the API takes just red and green coefficients the blue coefficient is * calculated to make the sum 32768. This will result in different rounding * to that used above. */ -static int +int /* PRIVATE */ png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) + { int rgb_error = 0; png_debug(1, "in png_do_rgb_to_gray"); - if ((row_info->color_type & PNG_COLOR_MASK_PALETTE) == 0 && - (row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + if (!(row_info->color_type & PNG_COLOR_MASK_PALETTE) && + (row_info->color_type & PNG_COLOR_MASK_COLOR)) { - png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; - png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; - png_uint_32 bc = 32768 - rc - gc; - png_uint_32 row_width = row_info->width; - int have_alpha = (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0; + PNG_CONST png_uint_32 rc = png_ptr->rgb_to_gray_red_coeff; + PNG_CONST png_uint_32 gc = png_ptr->rgb_to_gray_green_coeff; + PNG_CONST png_uint_32 bc = 32768 - rc - gc; + PNG_CONST png_uint_32 row_width = row_info->width; + PNG_CONST int have_alpha = + (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0; if (row_info->bit_depth == 8) { @@ -3173,7 +3323,7 @@ png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) *(dp++) = red; } - if (have_alpha != 0) + if (have_alpha) *(dp++) = *(sp++); } } @@ -3202,7 +3352,7 @@ png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) else *(dp++) = red; - if (have_alpha != 0) + if (have_alpha) *(dp++) = *(sp++); } } @@ -3220,17 +3370,16 @@ png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) for (i = 0; i < row_width; i++) { png_uint_16 red, green, blue, w; - png_byte hi,lo; - hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); - hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); - hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); + red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; + green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; if (red == green && red == blue) { if (png_ptr->gamma_16_table != NULL) - w = png_ptr->gamma_16_table[(red & 0xff) - >> png_ptr->gamma_shift][red >> 8]; + w = png_ptr->gamma_16_table[(red&0xff) + >> png_ptr->gamma_shift][red>>8]; else w = red; @@ -3238,16 +3387,16 @@ png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) else { - png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red & 0xff) + png_uint_16 red_1 = png_ptr->gamma_16_to_1[(red&0xff) >> png_ptr->gamma_shift][red>>8]; png_uint_16 green_1 = - png_ptr->gamma_16_to_1[(green & 0xff) >> + png_ptr->gamma_16_to_1[(green&0xff) >> png_ptr->gamma_shift][green>>8]; - png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue & 0xff) + png_uint_16 blue_1 = png_ptr->gamma_16_to_1[(blue&0xff) >> png_ptr->gamma_shift][blue>>8]; png_uint_16 gray16 = (png_uint_16)((rc*red_1 + gc*green_1 + bc*blue_1 + 16384)>>15); - w = png_ptr->gamma_16_from_1[(gray16 & 0xff) >> + w = png_ptr->gamma_16_from_1[(gray16&0xff) >> png_ptr->gamma_shift][gray16 >> 8]; rgb_error |= 1; } @@ -3255,7 +3404,7 @@ png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) *(dp++) = (png_byte)((w>>8) & 0xff); *(dp++) = (png_byte)(w & 0xff); - if (have_alpha != 0) + if (have_alpha) { *(dp++) = *(sp++); *(dp++) = *(sp++); @@ -3272,25 +3421,24 @@ png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) for (i = 0; i < row_width; i++) { png_uint_16 red, green, blue, gray16; - png_byte hi,lo; - hi=*(sp)++; lo=*(sp)++; red = (png_uint_16)((hi << 8) | (lo)); - hi=*(sp)++; lo=*(sp)++; green = (png_uint_16)((hi << 8) | (lo)); - hi=*(sp)++; lo=*(sp)++; blue = (png_uint_16)((hi << 8) | (lo)); + red = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; + green = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; + blue = (png_uint_16)(((*(sp))<<8) | *(sp + 1)); sp += 2; if (red != green || red != blue) rgb_error |= 1; - /* From 1.5.5 in the 16-bit case do the accurate conversion even + /* From 1.5.5 in the 16 bit case do the accurate conversion even * in the 'fast' case - this is because this is where the code - * ends up when handling linear 16-bit data. + * ends up when handling linear 16 bit data. */ gray16 = (png_uint_16)((rc*red + gc*green + bc*blue + 16384) >> 15); - *(dp++) = (png_byte)((gray16 >> 8) & 0xff); + *(dp++) = (png_byte)((gray16>>8) & 0xff); *(dp++) = (png_byte)(gray16 & 0xff); - if (have_alpha != 0) + if (have_alpha) { *(dp++) = *(sp++); *(dp++) = *(sp++); @@ -3309,14 +3457,73 @@ png_do_rgb_to_gray(png_structrp png_ptr, png_row_infop row_info, png_bytep row) return rgb_error; } #endif +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ +#ifdef PNG_BUILD_GRAYSCALE_PALETTE_SUPPORTED +/* Build a grayscale palette. Palette is assumed to be 1 << bit_depth + * large of png_color. This lets grayscale images be treated as + * paletted. Most useful for gamma correction and simplification + * of code. This API is not used internally. + */ +void PNGAPI +png_build_grayscale_palette(int bit_depth, png_colorp palette) +{ + int num_palette; + int color_inc; + int i; + int v; + + png_debug(1, "in png_do_build_grayscale_palette"); + + if (palette == NULL) + return; + + switch (bit_depth) + { + case 1: + num_palette = 2; + color_inc = 0xff; + break; + + case 2: + num_palette = 4; + color_inc = 0x55; + break; + + case 4: + num_palette = 16; + color_inc = 0x11; + break; + + case 8: + num_palette = 256; + color_inc = 1; + break; + + default: + num_palette = 0; + color_inc = 0; + break; + } + + for (i = 0, v = 0; i < num_palette; i++, v += color_inc) + { + palette[i].red = (png_byte)v; + palette[i].green = (png_byte)v; + palette[i].blue = (png_byte)v; + } +} +#endif + + +#ifdef PNG_READ_TRANSFORMS_SUPPORTED #if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ defined(PNG_READ_ALPHA_MODE_SUPPORTED) /* Replace any alpha or transparency with the supplied background color. * "background" is already in the screen gamma, while "background_1" is * at a gamma of 1.0. Paletted files have already been taken care of. */ -static void +void /* PRIVATE */ png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { #ifdef PNG_READ_GAMMA_SUPPORTED @@ -3337,229 +3544,414 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) png_debug(1, "in png_do_compose"); - switch (row_info->color_type) { - case PNG_COLOR_TYPE_GRAY: + switch (row_info->color_type) { - switch (row_info->bit_depth) + case PNG_COLOR_TYPE_GRAY: { - case 1: + switch (row_info->bit_depth) { - sp = row; - shift = 7; - for (i = 0; i < row_width; i++) + case 1: { - if ((png_uint_16)((*sp >> shift) & 0x01) - == png_ptr->trans_color.gray) + sp = row; + shift = 7; + for (i = 0; i < row_width; i++) { - unsigned int tmp = *sp & (0x7f7f >> (7 - shift)); - tmp |= - (unsigned int)(png_ptr->background.gray << shift); - *sp = (png_byte)(tmp & 0xff); - } + if ((png_uint_16)((*sp >> shift) & 0x01) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x7f7f >> (7 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } - if (shift == 0) + if (!shift) + { + shift = 7; + sp++; + } + + else + shift--; + } + break; + } + + case 2: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) { - shift = 7; - sp++; + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) + { + if ((png_uint_16)((*sp >> shift) & 0x03) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } + + else + { + unsigned int p = (*sp >> shift) & 0x03; + unsigned int g = (gamma_table [p | (p << 2) | + (p << 4) | (p << 6)] >> 6) & 0x03; + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= g << shift; + *sp = (png_byte)(tmp & 0xff); + } + + if (!shift) + { + shift = 6; + sp++; + } + + else + shift -= 2; + } } else - shift--; - } - break; - } - - case 2: - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_table != NULL) - { - sp = row; - shift = 6; - for (i = 0; i < row_width; i++) - { - if ((png_uint_16)((*sp >> shift) & 0x03) - == png_ptr->trans_color.gray) - { - unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); - tmp |= - (unsigned int)png_ptr->background.gray << shift; - *sp = (png_byte)(tmp & 0xff); - } - - else - { - unsigned int p = (*sp >> shift) & 0x03; - unsigned int g = (gamma_table [p | (p << 2) | - (p << 4) | (p << 6)] >> 6) & 0x03; - unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); - tmp |= (unsigned int)(g << shift); - *sp = (png_byte)(tmp & 0xff); - } - - if (shift == 0) - { - shift = 6; - sp++; - } - - else - shift -= 2; - } - } - - else #endif - { - sp = row; - shift = 6; - for (i = 0; i < row_width; i++) { - if ((png_uint_16)((*sp >> shift) & 0x03) - == png_ptr->trans_color.gray) + sp = row; + shift = 6; + for (i = 0; i < row_width; i++) { - unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); - tmp |= - (unsigned int)png_ptr->background.gray << shift; - *sp = (png_byte)(tmp & 0xff); - } + if ((png_uint_16)((*sp >> shift) & 0x03) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0x3f3f >> (6 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } - if (shift == 0) - { - shift = 6; - sp++; - } + if (!shift) + { + shift = 6; + sp++; + } - else - shift -= 2; + else + shift -= 2; + } } + break; } - break; - } - case 4: - { + case 4: + { #ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_table != NULL) - { - sp = row; - shift = 4; - for (i = 0; i < row_width; i++) + if (gamma_table != NULL) { - if ((png_uint_16)((*sp >> shift) & 0x0f) - == png_ptr->trans_color.gray) + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) { - unsigned int tmp = *sp & (0x0f0f >> (4 - shift)); - tmp |= - (unsigned int)(png_ptr->background.gray << shift); - *sp = (png_byte)(tmp & 0xff); - } + if ((png_uint_16)((*sp >> shift) & 0x0f) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } - else - { - unsigned int p = (*sp >> shift) & 0x0f; - unsigned int g = (gamma_table[p | (p << 4)] >> 4) & - 0x0f; - unsigned int tmp = *sp & (0x0f0f >> (4 - shift)); - tmp |= (unsigned int)(g << shift); - *sp = (png_byte)(tmp & 0xff); - } + else + { + unsigned int p = (*sp >> shift) & 0x0f; + unsigned int g = (gamma_table[p | (p << 4)] >> 4) & + 0x0f; + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= g << shift; + *sp = (png_byte)(tmp & 0xff); + } - if (shift == 0) - { - shift = 4; - sp++; - } + if (!shift) + { + shift = 4; + sp++; + } - else - shift -= 4; + else + shift -= 4; + } } - } - else + else #endif - { - sp = row; - shift = 4; - for (i = 0; i < row_width; i++) { - if ((png_uint_16)((*sp >> shift) & 0x0f) - == png_ptr->trans_color.gray) + sp = row; + shift = 4; + for (i = 0; i < row_width; i++) { - unsigned int tmp = *sp & (0x0f0f >> (4 - shift)); - tmp |= - (unsigned int)(png_ptr->background.gray << shift); - *sp = (png_byte)(tmp & 0xff); - } + if ((png_uint_16)((*sp >> shift) & 0x0f) + == png_ptr->trans_color.gray) + { + unsigned int tmp = *sp & (0xf0f >> (4 - shift)); + tmp |= png_ptr->background.gray << shift; + *sp = (png_byte)(tmp & 0xff); + } - if (shift == 0) - { - shift = 4; - sp++; - } + if (!shift) + { + shift = 4; + sp++; + } - else - shift -= 4; + else + shift -= 4; + } } + break; } - break; - } - case 8: + case 8: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == png_ptr->trans_color.gray) + *sp = (png_byte)png_ptr->background.gray; + + else + *sp = gamma_table[*sp]; + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp++) + { + if (*sp == png_ptr->trans_color.gray) + *sp = (png_byte)png_ptr->background.gray; + } + } + break; + } + + case 16: + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + if (v == png_ptr->trans_color.gray) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); + } + + else + { + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 v; + + v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + if (v == png_ptr->trans_color.gray) + { + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray + & 0xff); + } + } + } + break; + } + + default: + break; + } + break; + } + + case PNG_COLOR_TYPE_RGB: + { + if (row_info->bit_depth == 8) { #ifdef PNG_READ_GAMMA_SUPPORTED if (gamma_table != NULL) { sp = row; - for (i = 0; i < row_width; i++, sp++) + for (i = 0; i < row_width; i++, sp += 3) { - if (*sp == png_ptr->trans_color.gray) - *sp = (png_byte)png_ptr->background.gray; + if (*sp == png_ptr->trans_color.red && + *(sp + 1) == png_ptr->trans_color.green && + *(sp + 2) == png_ptr->trans_color.blue) + { + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } else + { *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; + } } } else #endif { sp = row; - for (i = 0; i < row_width; i++, sp++) + for (i = 0; i < row_width; i++, sp += 3) { - if (*sp == png_ptr->trans_color.gray) - *sp = (png_byte)png_ptr->background.gray; + if (*sp == png_ptr->trans_color.red && + *(sp + 1) == png_ptr->trans_color.green && + *(sp + 2) == png_ptr->trans_color.blue) + { + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } } } - break; } - - case 16: + else /* if (row_info->bit_depth == 16) */ { #ifdef PNG_READ_GAMMA_SUPPORTED if (gamma_16 != NULL) { sp = row; - for (i = 0; i < row_width; i++, sp += 2) + for (i = 0; i < row_width; i++, sp += 6) { - png_uint_16 v; + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); - if (v == png_ptr->trans_color.gray) + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + if (r == png_ptr->trans_color.red && + g == png_ptr->trans_color.green && + b == png_ptr->trans_color.blue) { /* Background is already in screen gamma */ - *sp = (png_byte)((png_ptr->background.gray >> 8) - & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.gray - & 0xff); + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); } else { - v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; *sp = (png_byte)((v >> 8) & 0xff); *(sp + 1) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + } + } + + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 6) + { + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + if (r == png_ptr->trans_color.red && + g == png_ptr->trans_color.green && + b == png_ptr->trans_color.blue) + { + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + } + } + } + break; + } + + case PNG_COLOR_TYPE_GRAY_ALPHA: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 2) + { + png_uint_16 a = *(sp + 1); + + if (a == 0xff) + *sp = gamma_table[*sp]; + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)png_ptr->background.gray; + } + + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, png_ptr->background_1.gray); + if (!optimize) + w = gamma_from_1[w]; + *sp = w; } } } @@ -3569,489 +3961,300 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) sp = row; for (i = 0; i < row_width; i++, sp += 2) { - png_uint_16 v; + png_byte a = *(sp + 1); - v = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + if (a == 0) + *sp = (png_byte)png_ptr->background.gray; - if (v == png_ptr->trans_color.gray) + else if (a < 0xff) + png_composite(*sp, *sp, a, png_ptr->background.gray); + } + } + } + else /* if (png_ptr->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + + if (a == (png_uint_16)0xffff) { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } + + else if (a == 0) + { + /* Background is already in screen gamma */ *sp = (png_byte)((png_ptr->background.gray >> 8) - & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.gray - & 0xff); + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); + } + + else + { + png_uint_16 g, v, w; + + g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(v, g, a, png_ptr->background_1.gray); + if (optimize) + w = v; + else + w = gamma_16_from_1[(v&0xff) >> gamma_shift][v >> 8]; + *sp = (png_byte)((w >> 8) & 0xff); + *(sp + 1) = (png_byte)(w & 0xff); } } } - break; - } - - default: - break; - } - break; - } - - case PNG_COLOR_TYPE_RGB: - { - if (row_info->bit_depth == 8) - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_table != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 3) - { - if (*sp == png_ptr->trans_color.red && - *(sp + 1) == png_ptr->trans_color.green && - *(sp + 2) == png_ptr->trans_color.blue) - { - *sp = (png_byte)png_ptr->background.red; - *(sp + 1) = (png_byte)png_ptr->background.green; - *(sp + 2) = (png_byte)png_ptr->background.blue; - } - - else - { - *sp = gamma_table[*sp]; - *(sp + 1) = gamma_table[*(sp + 1)]; - *(sp + 2) = gamma_table[*(sp + 2)]; - } - } - } - else + else #endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 3) { - if (*sp == png_ptr->trans_color.red && - *(sp + 1) == png_ptr->trans_color.green && - *(sp + 2) == png_ptr->trans_color.blue) + sp = row; + for (i = 0; i < row_width; i++, sp += 4) { - *sp = (png_byte)png_ptr->background.red; - *(sp + 1) = (png_byte)png_ptr->background.green; - *(sp + 2) = (png_byte)png_ptr->background.blue; - } - } - } - } - else /* if (row_info->bit_depth == 16) */ - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_16 != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 6) - { - png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - - png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) - + *(sp + 3)); - - png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) - + *(sp + 5)); - - if (r == png_ptr->trans_color.red && - g == png_ptr->trans_color.green && - b == png_ptr->trans_color.blue) - { - /* Background is already in screen gamma */ - *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) - & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green - & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) - & 0xff); - *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); - } - - else - { - png_uint_16 v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - - v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; - *(sp + 2) = (png_byte)((v >> 8) & 0xff); - *(sp + 3) = (png_byte)(v & 0xff); - - v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; - *(sp + 4) = (png_byte)((v >> 8) & 0xff); - *(sp + 5) = (png_byte)(v & 0xff); - } - } - } - - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 6) - { - png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - - png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) - + *(sp + 3)); - - png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) - + *(sp + 5)); - - if (r == png_ptr->trans_color.red && - g == png_ptr->trans_color.green && - b == png_ptr->trans_color.blue) - { - *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) - & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green - & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) - & 0xff); - *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); - } - } - } - } - break; - } - - case PNG_COLOR_TYPE_GRAY_ALPHA: - { - if (row_info->bit_depth == 8) - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_to_1 != NULL && gamma_from_1 != NULL && - gamma_table != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 2) - { - png_uint_16 a = *(sp + 1); - - if (a == 0xff) - *sp = gamma_table[*sp]; - - else if (a == 0) - { - /* Background is already in screen gamma */ - *sp = (png_byte)png_ptr->background.gray; - } - - else - { - png_byte v, w; - - v = gamma_to_1[*sp]; - png_composite(w, v, a, png_ptr->background_1.gray); - if (optimize == 0) - w = gamma_from_1[w]; - *sp = w; - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 2) - { - png_byte a = *(sp + 1); - - if (a == 0) - *sp = (png_byte)png_ptr->background.gray; - - else if (a < 0xff) - png_composite(*sp, *sp, a, png_ptr->background.gray); - } - } - } - else /* if (png_ptr->bit_depth == 16) */ - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_16 != NULL && gamma_16_from_1 != NULL && - gamma_16_to_1 != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 4) - { - png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) - + *(sp + 3)); - - if (a == (png_uint_16)0xffff) - { - png_uint_16 v; - - v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - } - - else if (a == 0) - { - /* Background is already in screen gamma */ - *sp = (png_byte)((png_ptr->background.gray >> 8) - & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); - } - - else - { - png_uint_16 g, v, w; - - g = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; - png_composite_16(v, g, a, png_ptr->background_1.gray); - if (optimize != 0) - w = v; - else - w = gamma_16_from_1[(v & 0xff) >> - gamma_shift][v >> 8]; - *sp = (png_byte)((w >> 8) & 0xff); - *(sp + 1) = (png_byte)(w & 0xff); - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 4) - { - png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) - + *(sp + 3)); - - if (a == 0) - { - *sp = (png_byte)((png_ptr->background.gray >> 8) - & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); - } - - else if (a < 0xffff) - { - png_uint_16 g, v; - - g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_composite_16(v, g, a, png_ptr->background.gray); - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - } - } - } - } - break; - } - - case PNG_COLOR_TYPE_RGB_ALPHA: - { - if (row_info->bit_depth == 8) - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_to_1 != NULL && gamma_from_1 != NULL && - gamma_table != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 4) - { - png_byte a = *(sp + 3); - - if (a == 0xff) - { - *sp = gamma_table[*sp]; - *(sp + 1) = gamma_table[*(sp + 1)]; - *(sp + 2) = gamma_table[*(sp + 2)]; - } - - else if (a == 0) - { - /* Background is already in screen gamma */ - *sp = (png_byte)png_ptr->background.red; - *(sp + 1) = (png_byte)png_ptr->background.green; - *(sp + 2) = (png_byte)png_ptr->background.blue; - } - - else - { - png_byte v, w; - - v = gamma_to_1[*sp]; - png_composite(w, v, a, png_ptr->background_1.red); - if (optimize == 0) w = gamma_from_1[w]; - *sp = w; - - v = gamma_to_1[*(sp + 1)]; - png_composite(w, v, a, png_ptr->background_1.green); - if (optimize == 0) w = gamma_from_1[w]; - *(sp + 1) = w; - - v = gamma_to_1[*(sp + 2)]; - png_composite(w, v, a, png_ptr->background_1.blue); - if (optimize == 0) w = gamma_from_1[w]; - *(sp + 2) = w; - } - } - } - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 4) - { - png_byte a = *(sp + 3); - - if (a == 0) - { - *sp = (png_byte)png_ptr->background.red; - *(sp + 1) = (png_byte)png_ptr->background.green; - *(sp + 2) = (png_byte)png_ptr->background.blue; - } - - else if (a < 0xff) - { - png_composite(*sp, *sp, a, png_ptr->background.red); - - png_composite(*(sp + 1), *(sp + 1), a, - png_ptr->background.green); - - png_composite(*(sp + 2), *(sp + 2), a, - png_ptr->background.blue); - } - } - } - } - else /* if (row_info->bit_depth == 16) */ - { -#ifdef PNG_READ_GAMMA_SUPPORTED - if (gamma_16 != NULL && gamma_16_from_1 != NULL && - gamma_16_to_1 != NULL) - { - sp = row; - for (i = 0; i < row_width; i++, sp += 8) - { - png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) - << 8) + (png_uint_16)(*(sp + 7))); - - if (a == (png_uint_16)0xffff) - { - png_uint_16 v; - - v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); - - v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; - *(sp + 2) = (png_byte)((v >> 8) & 0xff); - *(sp + 3) = (png_byte)(v & 0xff); - - v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; - *(sp + 4) = (png_byte)((v >> 8) & 0xff); - *(sp + 5) = (png_byte)(v & 0xff); - } - - else if (a == 0) - { - /* Background is already in screen gamma */ - *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) - & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green - & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) - & 0xff); - *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); - } - - else - { - png_uint_16 v, w; - - v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; - png_composite_16(w, v, a, png_ptr->background_1.red); - if (optimize == 0) - w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> - 8]; - *sp = (png_byte)((w >> 8) & 0xff); - *(sp + 1) = (png_byte)(w & 0xff); - - v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; - png_composite_16(w, v, a, png_ptr->background_1.green); - if (optimize == 0) - w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> - 8]; - - *(sp + 2) = (png_byte)((w >> 8) & 0xff); - *(sp + 3) = (png_byte)(w & 0xff); - - v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; - png_composite_16(w, v, a, png_ptr->background_1.blue); - if (optimize == 0) - w = gamma_16_from_1[((w & 0xff) >> gamma_shift)][w >> - 8]; - - *(sp + 4) = (png_byte)((w >> 8) & 0xff); - *(sp + 5) = (png_byte)(w & 0xff); - } - } - } - - else -#endif - { - sp = row; - for (i = 0; i < row_width; i++, sp += 8) - { - png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) - << 8) + (png_uint_16)(*(sp + 7))); - - if (a == 0) - { - *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); - *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); - *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) - & 0xff); - *(sp + 3) = (png_byte)(png_ptr->background.green - & 0xff); - *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) - & 0xff); - *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); - } - - else if (a < 0xffff) - { - png_uint_16 v; - - png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); - png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + png_uint_16 a = (png_uint_16)(((*(sp + 2)) << 8) + *(sp + 3)); - png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) - + *(sp + 5)); - png_composite_16(v, r, a, png_ptr->background.red); - *sp = (png_byte)((v >> 8) & 0xff); - *(sp + 1) = (png_byte)(v & 0xff); + if (a == 0) + { + *sp = (png_byte)((png_ptr->background.gray >> 8) + & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.gray & 0xff); + } - png_composite_16(v, g, a, png_ptr->background.green); - *(sp + 2) = (png_byte)((v >> 8) & 0xff); - *(sp + 3) = (png_byte)(v & 0xff); + else if (a < 0xffff) + { + png_uint_16 g, v; - png_composite_16(v, b, a, png_ptr->background.blue); - *(sp + 4) = (png_byte)((v >> 8) & 0xff); - *(sp + 5) = (png_byte)(v & 0xff); + g = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_composite_16(v, g, a, png_ptr->background.gray); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + } } } } + break; } - break; - } - default: - break; + case PNG_COLOR_TYPE_RGB_ALPHA: + { + if (row_info->bit_depth == 8) + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_to_1 != NULL && gamma_from_1 != NULL && + gamma_table != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_byte a = *(sp + 3); + + if (a == 0xff) + { + *sp = gamma_table[*sp]; + *(sp + 1) = gamma_table[*(sp + 1)]; + *(sp + 2) = gamma_table[*(sp + 2)]; + } + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + + else + { + png_byte v, w; + + v = gamma_to_1[*sp]; + png_composite(w, v, a, png_ptr->background_1.red); + if (!optimize) w = gamma_from_1[w]; + *sp = w; + + v = gamma_to_1[*(sp + 1)]; + png_composite(w, v, a, png_ptr->background_1.green); + if (!optimize) w = gamma_from_1[w]; + *(sp + 1) = w; + + v = gamma_to_1[*(sp + 2)]; + png_composite(w, v, a, png_ptr->background_1.blue); + if (!optimize) w = gamma_from_1[w]; + *(sp + 2) = w; + } + } + } + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 4) + { + png_byte a = *(sp + 3); + + if (a == 0) + { + *sp = (png_byte)png_ptr->background.red; + *(sp + 1) = (png_byte)png_ptr->background.green; + *(sp + 2) = (png_byte)png_ptr->background.blue; + } + + else if (a < 0xff) + { + png_composite(*sp, *sp, a, png_ptr->background.red); + + png_composite(*(sp + 1), *(sp + 1), a, + png_ptr->background.green); + + png_composite(*(sp + 2), *(sp + 2), a, + png_ptr->background.blue); + } + } + } + } + else /* if (row_info->bit_depth == 16) */ + { +#ifdef PNG_READ_GAMMA_SUPPORTED + if (gamma_16 != NULL && gamma_16_from_1 != NULL && + gamma_16_to_1 != NULL) + { + sp = row; + for (i = 0; i < row_width; i++, sp += 8) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + + if (a == (png_uint_16)0xffff) + { + png_uint_16 v; + + v = gamma_16[*(sp + 1) >> gamma_shift][*sp]; + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 3) >> gamma_shift][*(sp + 2)]; + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + v = gamma_16[*(sp + 5) >> gamma_shift][*(sp + 4)]; + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + + else if (a == 0) + { + /* Background is already in screen gamma */ + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + + else + { + png_uint_16 v, w; + + v = gamma_16_to_1[*(sp + 1) >> gamma_shift][*sp]; + png_composite_16(w, v, a, png_ptr->background_1.red); + if (!optimize) + w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> + 8]; + *sp = (png_byte)((w >> 8) & 0xff); + *(sp + 1) = (png_byte)(w & 0xff); + + v = gamma_16_to_1[*(sp + 3) >> gamma_shift][*(sp + 2)]; + png_composite_16(w, v, a, png_ptr->background_1.green); + if (!optimize) + w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> + 8]; + + *(sp + 2) = (png_byte)((w >> 8) & 0xff); + *(sp + 3) = (png_byte)(w & 0xff); + + v = gamma_16_to_1[*(sp + 5) >> gamma_shift][*(sp + 4)]; + png_composite_16(w, v, a, png_ptr->background_1.blue); + if (!optimize) + w = gamma_16_from_1[((w&0xff) >> gamma_shift)][w >> + 8]; + + *(sp + 4) = (png_byte)((w >> 8) & 0xff); + *(sp + 5) = (png_byte)(w & 0xff); + } + } + } + + else +#endif + { + sp = row; + for (i = 0; i < row_width; i++, sp += 8) + { + png_uint_16 a = (png_uint_16)(((png_uint_16)(*(sp + 6)) + << 8) + (png_uint_16)(*(sp + 7))); + + if (a == 0) + { + *sp = (png_byte)((png_ptr->background.red >> 8) & 0xff); + *(sp + 1) = (png_byte)(png_ptr->background.red & 0xff); + *(sp + 2) = (png_byte)((png_ptr->background.green >> 8) + & 0xff); + *(sp + 3) = (png_byte)(png_ptr->background.green + & 0xff); + *(sp + 4) = (png_byte)((png_ptr->background.blue >> 8) + & 0xff); + *(sp + 5) = (png_byte)(png_ptr->background.blue & 0xff); + } + + else if (a < 0xffff) + { + png_uint_16 v; + + png_uint_16 r = (png_uint_16)(((*sp) << 8) + *(sp + 1)); + png_uint_16 g = (png_uint_16)(((*(sp + 2)) << 8) + + *(sp + 3)); + png_uint_16 b = (png_uint_16)(((*(sp + 4)) << 8) + + *(sp + 5)); + + png_composite_16(v, r, a, png_ptr->background.red); + *sp = (png_byte)((v >> 8) & 0xff); + *(sp + 1) = (png_byte)(v & 0xff); + + png_composite_16(v, g, a, png_ptr->background.green); + *(sp + 2) = (png_byte)((v >> 8) & 0xff); + *(sp + 3) = (png_byte)(v & 0xff); + + png_composite_16(v, b, a, png_ptr->background.blue); + *(sp + 4) = (png_byte)((v >> 8) & 0xff); + *(sp + 5) = (png_byte)(v & 0xff); + } + } + } + } + break; + } + + default: + break; + } } } -#endif /* READ_BACKGROUND || READ_ALPHA_MODE */ +#endif /* PNG_READ_BACKGROUND_SUPPORTED || PNG_READ_ALPHA_MODE_SUPPORTED */ #ifdef PNG_READ_GAMMA_SUPPORTED /* Gamma correct the image, avoiding the alpha channel. Make sure @@ -4060,7 +4263,7 @@ png_do_compose(png_row_infop row_info, png_bytep row, png_structrp png_ptr) * is 16, use gamma_16_table and gamma_shift. Build these with * build_gamma_table(). */ -static void +void /* PRIVATE */ png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { png_const_bytep gamma_table = png_ptr->gamma_table; @@ -4261,22 +4464,23 @@ png_do_gamma(png_row_infop row_info, png_bytep row, png_structrp png_ptr) * linear.) Called only with color types that have an alpha channel. Needs the * from_1 tables. */ -static void +void /* PRIVATE */ png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr) { png_uint_32 row_width = row_info->width; png_debug(1, "in png_do_encode_alpha"); - if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) { if (row_info->bit_depth == 8) { - png_bytep table = png_ptr->gamma_from_1; + PNG_CONST png_bytep table = png_ptr->gamma_from_1; if (table != NULL) { - int step = (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2; + PNG_CONST int step = + (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 4 : 2; /* The alpha channel is the last component: */ row += step - 1; @@ -4290,12 +4494,13 @@ png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr) else if (row_info->bit_depth == 16) { - png_uint_16pp table = png_ptr->gamma_16_from_1; - int gamma_shift = png_ptr->gamma_shift; + PNG_CONST png_uint_16pp table = png_ptr->gamma_16_from_1; + PNG_CONST int gamma_shift = png_ptr->gamma_shift; if (table != NULL) { - int step = (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4; + PNG_CONST int step = + (row_info->color_type & PNG_COLOR_MASK_COLOR) ? 8 : 4; /* The alpha channel is the last component: */ row += step - 2; @@ -4325,10 +4530,9 @@ png_do_encode_alpha(png_row_infop row_info, png_bytep row, png_structrp png_ptr) /* Expands a palette row to an RGB or RGBA row depending * upon whether you supply trans and num_trans. */ -static void -png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info, - png_bytep row, png_const_colorp palette, png_const_bytep trans_alpha, - int num_trans) +void /* PRIVATE */ +png_do_expand_palette(png_row_infop row_info, png_bytep row, + png_const_colorp palette, png_const_bytep trans_alpha, int num_trans) { int shift, value; png_bytep sp, dp; @@ -4345,8 +4549,8 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info, { case 1: { - sp = row + (size_t)((row_width - 1) >> 3); - dp = row + (size_t)row_width - 1; + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; shift = 7 - (int)((row_width + 7) & 0x07); for (i = 0; i < row_width; i++) { @@ -4372,8 +4576,8 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info, case 2: { - sp = row + (size_t)((row_width - 1) >> 2); - dp = row + (size_t)row_width - 1; + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); for (i = 0; i < row_width; i++) { @@ -4395,8 +4599,8 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info, case 4: { - sp = row + (size_t)((row_width - 1) >> 1); - dp = row + (size_t)row_width - 1; + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; shift = (int)((row_width & 0x01) << 2); for (i = 0; i < row_width; i++) { @@ -4429,30 +4633,17 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info, { if (num_trans > 0) { - sp = row + (size_t)row_width - 1; - dp = row + ((size_t)row_width << 2) - 1; + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 2) - 1; - i = 0; -#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE - if (png_ptr->riffled_palette != NULL) - { - /* The RGBA optimization works with png_ptr->bit_depth == 8 - * but sometimes row_info->bit_depth has been changed to 8. - * In these cases, the palette hasn't been riffled. - */ - i = png_do_expand_palette_rgba8_neon(png_ptr, row_info, row, - &sp, &dp); - } -#else - PNG_UNUSED(png_ptr) -#endif - - for (; i < row_width; i++) + for (i = 0; i < row_width; i++) { if ((int)(*sp) >= num_trans) *dp-- = 0xff; + else *dp-- = trans_alpha[*sp]; + *dp-- = palette[*sp].blue; *dp-- = palette[*sp].green; *dp-- = palette[*sp].red; @@ -4467,17 +4658,10 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info, else { - sp = row + (size_t)row_width - 1; - dp = row + (size_t)(row_width * 3) - 1; - i = 0; -#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE - i = png_do_expand_palette_rgb8_neon(png_ptr, row_info, row, - &sp, &dp); -#else - PNG_UNUSED(png_ptr) -#endif + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width * 3) - 1; - for (; i < row_width; i++) + for (i = 0; i < row_width; i++) { *dp-- = palette[*sp].blue; *dp-- = palette[*sp].green; @@ -4499,7 +4683,7 @@ png_do_expand_palette(png_structrp png_ptr, png_row_infop row_info, /* If the bit depth < 8, it is expanded to 8. Also, if the already * expanded transparency value is supplied, an alpha channel is built. */ -static void +void /* PRIVATE */ png_do_expand(png_row_infop row_info, png_bytep row, png_const_color_16p trans_color) { @@ -4510,130 +4694,193 @@ png_do_expand(png_row_infop row_info, png_bytep row, png_debug(1, "in png_do_expand"); - if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { - unsigned int gray = trans_color != NULL ? trans_color->gray : 0; - - if (row_info->bit_depth < 8) + if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { - switch (row_info->bit_depth) + unsigned int gray = trans_color ? trans_color->gray : 0; + + if (row_info->bit_depth < 8) { - case 1: + switch (row_info->bit_depth) { - gray = (gray & 0x01) * 0xff; - sp = row + (size_t)((row_width - 1) >> 3); - dp = row + (size_t)row_width - 1; - shift = 7 - (int)((row_width + 7) & 0x07); - for (i = 0; i < row_width; i++) + case 1: { - if ((*sp >> shift) & 0x01) - *dp = 0xff; - - else - *dp = 0; - - if (shift == 7) + gray = (gray & 0x01) * 0xff; + sp = row + (png_size_t)((row_width - 1) >> 3); + dp = row + (png_size_t)row_width - 1; + shift = 7 - (int)((row_width + 7) & 0x07); + for (i = 0; i < row_width; i++) { - shift = 0; - sp--; + if ((*sp >> shift) & 0x01) + *dp = 0xff; + + else + *dp = 0; + + if (shift == 7) + { + shift = 0; + sp--; + } + + else + shift++; + + dp--; } - - else - shift++; - - dp--; + break; } - break; + + case 2: + { + gray = (gray & 0x03) * 0x55; + sp = row + (png_size_t)((row_width - 1) >> 2); + dp = row + (png_size_t)row_width - 1; + shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x03; + *dp = (png_byte)(value | (value << 2) | (value << 4) | + (value << 6)); + if (shift == 6) + { + shift = 0; + sp--; + } + + else + shift += 2; + + dp--; + } + break; + } + + case 4: + { + gray = (gray & 0x0f) * 0x11; + sp = row + (png_size_t)((row_width - 1) >> 1); + dp = row + (png_size_t)row_width - 1; + shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); + for (i = 0; i < row_width; i++) + { + value = (*sp >> shift) & 0x0f; + *dp = (png_byte)(value | (value << 4)); + if (shift == 4) + { + shift = 0; + sp--; + } + + else + shift = 4; + + dp--; + } + break; + } + + default: + break; } - case 2: - { - gray = (gray & 0x03) * 0x55; - sp = row + (size_t)((row_width - 1) >> 2); - dp = row + (size_t)row_width - 1; - shift = (int)((3 - ((row_width + 3) & 0x03)) << 1); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x03; - *dp = (png_byte)(value | (value << 2) | (value << 4) | - (value << 6)); - if (shift == 6) - { - shift = 0; - sp--; - } - - else - shift += 2; - - dp--; - } - break; - } - - case 4: - { - gray = (gray & 0x0f) * 0x11; - sp = row + (size_t)((row_width - 1) >> 1); - dp = row + (size_t)row_width - 1; - shift = (int)((1 - ((row_width + 1) & 0x01)) << 2); - for (i = 0; i < row_width; i++) - { - value = (*sp >> shift) & 0x0f; - *dp = (png_byte)(value | (value << 4)); - if (shift == 4) - { - shift = 0; - sp--; - } - - else - shift = 4; - - dp--; - } - break; - } - - default: - break; + row_info->bit_depth = 8; + row_info->pixel_depth = 8; + row_info->rowbytes = row_width; } - row_info->bit_depth = 8; - row_info->pixel_depth = 8; - row_info->rowbytes = row_width; - } + if (trans_color != NULL) + { + if (row_info->bit_depth == 8) + { + gray = gray & 0xff; + sp = row + (png_size_t)row_width - 1; + dp = row + (png_size_t)(row_width << 1) - 1; - if (trans_color != NULL) + for (i = 0; i < row_width; i++) + { + if (*sp == gray) + *dp-- = 0; + + else + *dp-- = 0xff; + + *dp-- = *sp--; + } + } + + else if (row_info->bit_depth == 16) + { + unsigned int gray_high = (gray >> 8) & 0xff; + unsigned int gray_low = gray & 0xff; + sp = row + row_info->rowbytes - 1; + dp = row + (row_info->rowbytes << 1) - 1; + for (i = 0; i < row_width; i++) + { + if (*(sp - 1) == gray_high && *(sp) == gray_low) + { + *dp-- = 0; + *dp-- = 0; + } + + else + { + *dp-- = 0xff; + *dp-- = 0xff; + } + + *dp-- = *sp--; + *dp-- = *sp--; + } + } + + row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; + row_info->channels = 2; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, + row_width); + } + } + else if (row_info->color_type == PNG_COLOR_TYPE_RGB && trans_color) { if (row_info->bit_depth == 8) { - gray = gray & 0xff; - sp = row + (size_t)row_width - 1; - dp = row + ((size_t)row_width << 1) - 1; - + png_byte red = (png_byte)(trans_color->red & 0xff); + png_byte green = (png_byte)(trans_color->green & 0xff); + png_byte blue = (png_byte)(trans_color->blue & 0xff); + sp = row + (png_size_t)row_info->rowbytes - 1; + dp = row + (png_size_t)(row_width << 2) - 1; for (i = 0; i < row_width; i++) { - if ((*sp & 0xffU) == gray) + if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue) *dp-- = 0; else *dp-- = 0xff; *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; } } - else if (row_info->bit_depth == 16) { - unsigned int gray_high = (gray >> 8) & 0xff; - unsigned int gray_low = gray & 0xff; + png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff); + png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff); + png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff); + png_byte red_low = (png_byte)(trans_color->red & 0xff); + png_byte green_low = (png_byte)(trans_color->green & 0xff); + png_byte blue_low = (png_byte)(trans_color->blue & 0xff); sp = row + row_info->rowbytes - 1; - dp = row + (row_info->rowbytes << 1) - 1; + dp = row + (png_size_t)(row_width << 3) - 1; for (i = 0; i < row_width; i++) { - if ((*(sp - 1) & 0xffU) == gray_high && - (*(sp) & 0xffU) == gray_low) + if (*(sp - 5) == red_high && + *(sp - 4) == red_low && + *(sp - 3) == green_high && + *(sp - 2) == green_low && + *(sp - 1) == blue_high && + *(sp ) == blue_low) { *dp-- = 0; *dp-- = 0; @@ -4647,81 +4894,18 @@ png_do_expand(png_row_infop row_info, png_bytep row, *dp-- = *sp--; *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; + *dp-- = *sp--; } } - - row_info->color_type = PNG_COLOR_TYPE_GRAY_ALPHA; - row_info->channels = 2; - row_info->pixel_depth = (png_byte)(row_info->bit_depth << 1); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, - row_width); + row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; + row_info->channels = 4; + row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); + row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); } } - else if (row_info->color_type == PNG_COLOR_TYPE_RGB && - trans_color != NULL) - { - if (row_info->bit_depth == 8) - { - png_byte red = (png_byte)(trans_color->red & 0xff); - png_byte green = (png_byte)(trans_color->green & 0xff); - png_byte blue = (png_byte)(trans_color->blue & 0xff); - sp = row + (size_t)row_info->rowbytes - 1; - dp = row + ((size_t)row_width << 2) - 1; - for (i = 0; i < row_width; i++) - { - if (*(sp - 2) == red && *(sp - 1) == green && *(sp) == blue) - *dp-- = 0; - - else - *dp-- = 0xff; - - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - } - } - else if (row_info->bit_depth == 16) - { - png_byte red_high = (png_byte)((trans_color->red >> 8) & 0xff); - png_byte green_high = (png_byte)((trans_color->green >> 8) & 0xff); - png_byte blue_high = (png_byte)((trans_color->blue >> 8) & 0xff); - png_byte red_low = (png_byte)(trans_color->red & 0xff); - png_byte green_low = (png_byte)(trans_color->green & 0xff); - png_byte blue_low = (png_byte)(trans_color->blue & 0xff); - sp = row + row_info->rowbytes - 1; - dp = row + ((size_t)row_width << 3) - 1; - for (i = 0; i < row_width; i++) - { - if (*(sp - 5) == red_high && - *(sp - 4) == red_low && - *(sp - 3) == green_high && - *(sp - 2) == green_low && - *(sp - 1) == blue_high && - *(sp ) == blue_low) - { - *dp-- = 0; - *dp-- = 0; - } - - else - { - *dp-- = 0xff; - *dp-- = 0xff; - } - - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - *dp-- = *sp--; - } - } - row_info->color_type = PNG_COLOR_TYPE_RGB_ALPHA; - row_info->channels = 4; - row_info->pixel_depth = (png_byte)(row_info->bit_depth << 2); - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_width); - } } #endif @@ -4729,7 +4913,7 @@ png_do_expand(png_row_infop row_info, png_bytep row, /* If the bit depth is 8 and the color type is not a palette type expand the * whole row to 16 bits. Has no effect otherwise. */ -static void +void /* PRIVATE */ png_do_expand_16(png_row_infop row_info, png_bytep row) { if (row_info->bit_depth == 8 && @@ -4747,9 +4931,7 @@ png_do_expand_16(png_row_infop row_info, png_bytep row) png_byte *sp = row + row_info->rowbytes; /* source, last byte + 1 */ png_byte *dp = sp + row_info->rowbytes; /* destination, end + 1 */ while (dp > sp) - { - dp[-2] = dp[-1] = *--sp; dp -= 2; - } + dp[-2] = dp[-1] = *--sp, dp -= 2; row_info->rowbytes *= 2; row_info->bit_depth = 16; @@ -4759,7 +4941,7 @@ png_do_expand_16(png_row_infop row_info, png_bytep row) #endif #ifdef PNG_READ_QUANTIZE_SUPPORTED -static void +void /* PRIVATE */ png_do_quantize(png_row_infop row_info, png_bytep row, png_const_bytep palette_lookup, png_const_bytep quantize_lookup) { @@ -4850,310 +5032,70 @@ png_do_quantize(png_row_infop row_info, png_bytep row, } } } -#endif /* READ_QUANTIZE */ +#endif /* PNG_READ_QUANTIZE_SUPPORTED */ +#endif /* PNG_READ_TRANSFORMS_SUPPORTED */ -/* Transform the row. The order of transformations is significant, - * and is very touchy. If you add a transformation, take care to - * decide how it fits in with the other transformations here. - */ +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Undoes intrapixel differencing */ void /* PRIVATE */ -png_do_read_transformations(png_structrp png_ptr, png_row_infop row_info) +png_do_read_intrapixel(png_row_infop row_info, png_bytep row) { - png_debug(1, "in png_do_read_transformations"); + png_debug(1, "in png_do_read_intrapixel"); - if (png_ptr->row_buf == NULL) + if ( + (row_info->color_type & PNG_COLOR_MASK_COLOR)) { - /* Prior to 1.5.4 this output row/pass where the NULL pointer is, but this - * error is incredibly rare and incredibly easy to debug without this - * information. - */ - png_error(png_ptr, "NULL row buffer"); - } + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; - /* The following is debugging; prior to 1.5.4 the code was never compiled in; - * in 1.5.4 PNG_FLAG_DETECT_UNINITIALIZED was added and the macro - * PNG_WARN_UNINITIALIZED_ROW removed. In 1.6 the new flag is set only for - * all transformations, however in practice the ROW_INIT always gets done on - * demand, if necessary. - */ - if ((png_ptr->flags & PNG_FLAG_DETECT_UNINITIALIZED) != 0 && - (png_ptr->flags & PNG_FLAG_ROW_INIT) == 0) - { - /* Application has failed to call either png_read_start_image() or - * png_read_update_info() after setting transforms that expand pixels. - * This check added to libpng-1.2.19 (but not enabled until 1.5.4). - */ - png_error(png_ptr, "Uninitialized row"); - } - -#ifdef PNG_READ_EXPAND_SUPPORTED - if ((png_ptr->transformations & PNG_EXPAND) != 0) - { - if (row_info->color_type == PNG_COLOR_TYPE_PALETTE) + if (row_info->bit_depth == 8) { -#ifdef PNG_ARM_NEON_INTRINSICS_AVAILABLE - if ((png_ptr->num_trans > 0) && (png_ptr->bit_depth == 8)) - { - if (png_ptr->riffled_palette == NULL) - { - /* Initialize the accelerated palette expansion. */ - png_ptr->riffled_palette = - (png_bytep)png_malloc(png_ptr, 256 * 4); - png_riffle_palette_neon(png_ptr); - } - } -#endif - png_do_expand_palette(png_ptr, row_info, png_ptr->row_buf + 1, - png_ptr->palette, png_ptr->trans_alpha, png_ptr->num_trans); - } + png_bytep rp; + png_uint_32 i; - else - { - if (png_ptr->num_trans != 0 && - (png_ptr->transformations & PNG_EXPAND_tRNS) != 0) - png_do_expand(row_info, png_ptr->row_buf + 1, - &(png_ptr->trans_color)); + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; else - png_do_expand(row_info, png_ptr->row_buf + 1, NULL); + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((256 + *rp + *(rp + 1)) & 0xff); + *(rp+2) = (png_byte)((256 + *(rp + 2) + *(rp + 1)) & 0xff); + } } - } -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && - (png_ptr->transformations & PNG_COMPOSE) == 0 && - (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) - png_do_strip_channel(row_info, png_ptr->row_buf + 1, - 0 /* at_start == false, because SWAP_ALPHA happens later */); -#endif - -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) != 0) - { - int rgb_error = - png_do_rgb_to_gray(png_ptr, row_info, - png_ptr->row_buf + 1); - - if (rgb_error != 0) + else if (row_info->bit_depth == 16) { - png_ptr->rgb_to_gray_status=1; - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == - PNG_RGB_TO_GRAY_WARN) - png_warning(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + png_bytep rp; + png_uint_32 i; - if ((png_ptr->transformations & PNG_RGB_TO_GRAY) == - PNG_RGB_TO_GRAY_ERR) - png_error(png_ptr, "png_do_rgb_to_gray found nongray pixel"); + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; + + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; + + else + return; + + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (s0 + s1 + 65536) & 0xffff; + png_uint_32 blue = (s2 + s1 + 65536) & 0xffff; + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp + 1) = (png_byte)(red & 0xff); + *(rp + 4) = (png_byte)((blue >> 8) & 0xff); + *(rp + 5) = (png_byte)(blue & 0xff); + } } } -#endif - -/* From Andreas Dilger e-mail to png-implement, 26 March 1998: - * - * In most cases, the "simple transparency" should be done prior to doing - * gray-to-RGB, or you will have to test 3x as many bytes to check if a - * pixel is transparent. You would also need to make sure that the - * transparency information is upgraded to RGB. - * - * To summarize, the current flow is: - * - Gray + simple transparency -> compare 1 or 2 gray bytes and composite - * with background "in place" if transparent, - * convert to RGB if necessary - * - Gray + alpha -> composite with gray background and remove alpha bytes, - * convert to RGB if necessary - * - * To support RGB backgrounds for gray images we need: - * - Gray + simple transparency -> convert to RGB + simple transparency, - * compare 3 or 6 bytes and composite with - * background "in place" if transparent - * (3x compare/pixel compared to doing - * composite with gray bkgrnd) - * - Gray + alpha -> convert to RGB + alpha, composite with background and - * remove alpha bytes (3x float - * operations/pixel compared with composite - * on gray background) - * - * Greg's change will do this. The reason it wasn't done before is for - * performance, as this increases the per-pixel operations. If we would check - * in advance if the background was gray or RGB, and position the gray-to-RGB - * transform appropriately, then it would save a lot of work/time. - */ - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* If gray -> RGB, do so now only if background is non-gray; else do later - * for performance reasons - */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && - (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) == 0) - png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); -#endif - -#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) - if ((png_ptr->transformations & PNG_COMPOSE) != 0) - png_do_compose(row_info, png_ptr->row_buf + 1, png_ptr); -#endif - -#ifdef PNG_READ_GAMMA_SUPPORTED - if ((png_ptr->transformations & PNG_GAMMA) != 0 && -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - /* Because RGB_TO_GRAY does the gamma transform. */ - (png_ptr->transformations & PNG_RGB_TO_GRAY) == 0 && -#endif -#if defined(PNG_READ_BACKGROUND_SUPPORTED) ||\ - defined(PNG_READ_ALPHA_MODE_SUPPORTED) - /* Because PNG_COMPOSE does the gamma transform if there is something to - * do (if there is an alpha channel or transparency.) - */ - !((png_ptr->transformations & PNG_COMPOSE) != 0 && - ((png_ptr->num_trans != 0) || - (png_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)) && -#endif - /* Because png_init_read_transformations transforms the palette, unless - * RGB_TO_GRAY will do the transform. - */ - (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE)) - png_do_gamma(row_info, png_ptr->row_buf + 1, png_ptr); -#endif - -#ifdef PNG_READ_STRIP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_STRIP_ALPHA) != 0 && - (png_ptr->transformations & PNG_COMPOSE) != 0 && - (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA || - row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA)) - png_do_strip_channel(row_info, png_ptr->row_buf + 1, - 0 /* at_start == false, because SWAP_ALPHA happens later */); -#endif - -#ifdef PNG_READ_ALPHA_MODE_SUPPORTED - if ((png_ptr->transformations & PNG_ENCODE_ALPHA) != 0 && - (row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) - png_do_encode_alpha(row_info, png_ptr->row_buf + 1, png_ptr); -#endif - -#ifdef PNG_READ_SCALE_16_TO_8_SUPPORTED - if ((png_ptr->transformations & PNG_SCALE_16_TO_8) != 0) - png_do_scale_16_to_8(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_STRIP_16_TO_8_SUPPORTED - /* There is no harm in doing both of these because only one has any effect, - * by putting the 'scale' option first if the app asks for scale (either by - * calling the API or in a TRANSFORM flag) this is what happens. - */ - if ((png_ptr->transformations & PNG_16_TO_8) != 0) - png_do_chop(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_QUANTIZE_SUPPORTED - if ((png_ptr->transformations & PNG_QUANTIZE) != 0) - png_do_quantize(row_info, png_ptr->row_buf + 1, - png_ptr->palette_lookup, png_ptr->quantize_index); -#endif /* READ_QUANTIZE */ - -#ifdef PNG_READ_EXPAND_16_SUPPORTED - /* Do the expansion now, after all the arithmetic has been done. Notice - * that previous transformations can handle the PNG_EXPAND_16 flag if this - * is efficient (particularly true in the case of gamma correction, where - * better accuracy results faster!) - */ - if ((png_ptr->transformations & PNG_EXPAND_16) != 0) - png_do_expand_16(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - /* NOTE: moved here in 1.5.4 (from much later in this list.) */ - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0 && - (png_ptr->mode & PNG_BACKGROUND_IS_GRAY) != 0) - png_do_gray_to_rgb(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_INVERT_SUPPORTED - if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) - png_do_invert(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_INVERT_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) - png_do_read_invert_alpha(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_SHIFT_SUPPORTED - if ((png_ptr->transformations & PNG_SHIFT) != 0) - png_do_unshift(row_info, png_ptr->row_buf + 1, - &(png_ptr->shift)); -#endif - -#ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) != 0) - png_do_unpack(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED - /* Added at libpng-1.5.10 */ - if (row_info->color_type == PNG_COLOR_TYPE_PALETTE && - png_ptr->num_palette_max >= 0) - png_do_check_palette_indexes(png_ptr, row_info); -#endif - -#ifdef PNG_READ_BGR_SUPPORTED - if ((png_ptr->transformations & PNG_BGR) != 0) - png_do_bgr(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_PACKSWAP_SUPPORTED - if ((png_ptr->transformations & PNG_PACKSWAP) != 0) - png_do_packswap(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_FILLER_SUPPORTED - if ((png_ptr->transformations & PNG_FILLER) != 0) - png_do_read_filler(row_info, png_ptr->row_buf + 1, - (png_uint_32)png_ptr->filler, png_ptr->flags); -#endif - -#ifdef PNG_READ_SWAP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) - png_do_read_swap_alpha(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_READ_16BIT_SUPPORTED -#ifdef PNG_READ_SWAP_SUPPORTED - if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) - png_do_swap(row_info, png_ptr->row_buf + 1); -#endif -#endif - -#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) - { - if (png_ptr->read_user_transform_fn != NULL) - (*(png_ptr->read_user_transform_fn)) /* User read transform function */ - (png_ptr, /* png_ptr */ - row_info, /* row_info: */ - /* png_uint_32 width; width of row */ - /* size_t rowbytes; number of bytes in row */ - /* png_byte color_type; color type of pixels */ - /* png_byte bit_depth; bit depth of samples */ - /* png_byte channels; number of channels (1-4) */ - /* png_byte pixel_depth; bits per pixel (depth*channels) */ - png_ptr->row_buf + 1); /* start of pixel data for row */ -#ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED - if (png_ptr->user_transform_depth != 0) - row_info->bit_depth = png_ptr->user_transform_depth; - - if (png_ptr->user_transform_channels != 0) - row_info->channels = png_ptr->user_transform_channels; -#endif - row_info->pixel_depth = (png_byte)(row_info->bit_depth * - row_info->channels); - - row_info->rowbytes = PNG_ROWBYTES(row_info->pixel_depth, row_info->width); - } -#endif } - -#endif /* READ_TRANSFORMS */ -#endif /* READ */ +#endif /* PNG_MNG_FEATURES_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pngrutil.c b/Windows_Libs/Dev/Render/libpng/pngrutil.c index a4eda54..01c3679 100644 --- a/Windows_Libs/Dev/Render/libpng/pngrutil.c +++ b/Windows_Libs/Dev/Render/libpng/pngrutil.c @@ -1,9 +1,10 @@ + /* pngrutil.c - utilities to read a PNG file * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -17,25 +18,7 @@ #ifdef PNG_READ_SUPPORTED -/* The minimum 'zlib' stream is assumed to be just the 2 byte header, 5 bytes - * minimum 'deflate' stream, and the 4 byte checksum. - */ -#define LZ77Min (2U+5U+4U) - -#ifdef PNG_READ_INTERLACING_SUPPORTED -/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */ - -/* Start of interlace block */ -static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; -/* Offset to next interlace block */ -static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; -/* Start of interlace block in the y direction */ -static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; -/* Offset to next interlace block in the y direction */ -static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; - -/* TODO: Move these arrays to a common utility module to avoid duplication. */ -#endif +#define png_strtod(p,a,b) strtod(a,b) png_uint_32 PNGAPI png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf) @@ -45,9 +28,33 @@ png_get_uint_31(png_const_structrp png_ptr, png_const_bytep buf) if (uval > PNG_UINT_31_MAX) png_error(png_ptr, "PNG unsigned integer out of range"); - return uval; + return (uval); } +#if defined(PNG_READ_gAMA_SUPPORTED) || defined(PNG_READ_cHRM_SUPPORTED) +/* The following is a variation on the above for use with the fixed + * point values used for gAMA and cHRM. Instead of png_error it + * issues a warning and returns (-1) - an invalid value because both + * gAMA and cHRM use *unsigned* integers for fixed point values. + */ +#define PNG_FIXED_ERROR (-1) + +static png_fixed_point /* PRIVATE */ +png_get_fixed_point(png_structrp png_ptr, png_const_bytep buf) +{ + png_uint_32 uval = png_get_uint_32(buf); + + if (uval <= PNG_UINT_31_MAX) + return (png_fixed_point)uval; /* known to be in range */ + + /* The caller can turn off the warning by passing NULL. */ + if (png_ptr != NULL) + png_warning(png_ptr, "PNG fixed point integer out of range"); + + return PNG_FIXED_ERROR; +} +#endif + #ifdef PNG_READ_INT_FUNCTIONS_SUPPORTED /* NOTE: the read macros will obscure these definitions, so that if * PNG_USE_READ_MACROS is set the library will not use them internally, @@ -81,25 +88,19 @@ png_get_int_32)(png_const_bytep buf) { png_uint_32 uval = png_get_uint_32(buf); if ((uval & 0x80000000) == 0) /* non-negative */ - return (png_int_32)uval; + return uval; uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ - if ((uval & 0x80000000) == 0) /* no overflow */ - return -(png_int_32)uval; - /* The following has to be safe; this function only gets called on PNG data - * and if we get here that data is invalid. 0 is the most safe value and - * if not then an attacker would surely just generate a PNG with 0 instead. - */ - return 0; + return -(png_int_32)uval; } /* Grab an unsigned 16-bit integer from a buffer in big-endian format. */ png_uint_16 (PNGAPI png_get_uint_16)(png_const_bytep buf) { - /* ANSI-C requires an int value to accommodate at least 16 bits so this + /* ANSI-C requires an int value to accomodate at least 16 bits so this * works and allows the compiler not to worry about possible narrowing - * on 32-bit systems. (Pre-ANSI systems did not make integers smaller + * on 32 bit systems. (Pre-ANSI systems did not make integers smaller * than 16 bits either.) */ unsigned int val = @@ -109,13 +110,13 @@ png_get_uint_16)(png_const_bytep buf) return (png_uint_16)val; } -#endif /* READ_INT_FUNCTIONS */ +#endif /* PNG_READ_INT_FUNCTIONS_SUPPORTED */ /* Read and check the PNG file signature */ void /* PRIVATE */ png_read_sig(png_structrp png_ptr, png_inforp info_ptr) { - size_t num_checked, num_to_check; + png_size_t num_checked, num_to_check; /* Exit if the user application does not expect a signature. */ if (png_ptr->sig_bytes >= 8) @@ -132,10 +133,10 @@ png_read_sig(png_structrp png_ptr, png_inforp info_ptr) png_read_data(png_ptr, &(info_ptr->signature[num_checked]), num_to_check); png_ptr->sig_bytes = 8; - if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check) != 0) + if (png_sig_cmp(info_ptr->signature, num_checked, num_to_check)) { if (num_checked < 4 && - png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4) != 0) + png_sig_cmp(info_ptr->signature, num_checked, num_to_check - 4)) png_error(png_ptr, "Not a PNG file"); else png_error(png_ptr, "PNG file corrupted by ASCII conversion"); @@ -144,38 +145,6 @@ png_read_sig(png_structrp png_ptr, png_inforp info_ptr) png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; } -/* This function is called to verify that a chunk name is valid. - * Do this using the bit-whacking approach from contrib/tools/pngfix.c - * - * Copied from libpng 1.7. - */ -static int -check_chunk_name(png_uint_32 name) -{ - png_uint_32 t; - - /* Remove bit 5 from all but the reserved byte; this means - * every 8-bit unit must be in the range 65-90 to be valid. - * So bit 5 must be zero, bit 6 must be set and bit 7 zero. - */ - name &= ~PNG_U32(32,32,0,32); - t = (name & ~0x1f1f1f1fU) ^ 0x40404040U; - - /* Subtract 65 for each 8-bit quantity, this must not - * overflow and each byte must then be in the range 0-25. - */ - name -= PNG_U32(65,65,65,65); - t |= name; - - /* Subtract 26, handling the overflow which should set the - * top three bits of each byte. - */ - name -= PNG_U32(25,25,25,26); - t |= ~name; - - return (t & 0xe0e0e0e0U) == 0U; -} - /* Read the chunk header (length + type name). * Put the type name into png_ptr->chunk_name, and return the length. */ @@ -183,36 +152,30 @@ png_uint_32 /* PRIVATE */ png_read_chunk_header(png_structrp png_ptr) { png_byte buf[8]; - png_uint_32 chunk_name, length; + png_uint_32 length; #ifdef PNG_IO_STATE_SUPPORTED png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_HDR; #endif - /* Read the length and the chunk name. png_struct::chunk_name is immediately - * updated even if they are detectably wrong. This aids error message - * handling by allowing png_chunk_error to be used. + /* Read the length and the chunk name. + * This must be performed in a single I/O call. */ png_read_data(png_ptr, buf, 8); length = png_get_uint_31(png_ptr, buf); - png_ptr->chunk_name = chunk_name = PNG_CHUNK_FROM_STRING(buf+4); + + /* Put the chunk name into png_ptr->chunk_name. */ + png_ptr->chunk_name = PNG_CHUNK_FROM_STRING(buf+4); + + png_debug2(0, "Reading %lx chunk, length = %lu", + (unsigned long)png_ptr->chunk_name, (unsigned long)length); /* Reset the crc and run it over the chunk name. */ png_reset_crc(png_ptr); png_calculate_crc(png_ptr, buf + 4, 4); - png_debug2(0, "Reading chunk typeid = 0x%lx, length = %lu", - (unsigned long)png_ptr->chunk_name, (unsigned long)length); - - /* Sanity check the length (first by <= 0x80) and the chunk name. An error - * here indicates a broken stream and libpng has no recovery from this. - */ - if (buf[0] >= 0x80U) - png_chunk_error(png_ptr, "bad header (invalid length)"); - /* Check to see if chunk name is valid. */ - if (!check_chunk_name(chunk_name)) - png_chunk_error(png_ptr, "bad header (invalid type)"); + png_check_chunk_name(png_ptr, png_ptr->chunk_name); #ifdef PNG_IO_STATE_SUPPORTED png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_DATA; @@ -232,85 +195,13 @@ png_crc_read(png_structrp png_ptr, png_bytep buf, png_uint_32 length) png_calculate_crc(png_ptr, buf, length); } -/* Compare the CRC stored in the PNG file with that calculated by libpng from - * the data it has read thus far. - */ -static int -png_crc_error(png_structrp png_ptr, int handle_as_ancillary) -{ - png_byte crc_bytes[4]; - png_uint_32 crc; - int need_crc = 1; - - /* There are four flags two for ancillary and two for critical chunks. The - * default setting of these flags is all zero. - * - * PNG_FLAG_CRC_ANCILLARY_USE - * PNG_FLAG_CRC_ANCILLARY_NOWARN - * USE+NOWARN: no CRC calculation (implemented here), else; - * NOWARN: png_chunk_error on error (implemented in png_crc_finish) - * else: png_chunk_warning on error (implemented in png_crc_finish) - * This is the default. - * - * I.e. NOWARN without USE produces png_chunk_error. The default setting - * where neither are set does the same thing. - * - * PNG_FLAG_CRC_CRITICAL_USE - * PNG_FLAG_CRC_CRITICAL_IGNORE - * IGNORE: no CRC calculation (implemented here), else; - * USE: png_chunk_warning on error (implemented in png_crc_finish) - * else: png_chunk_error on error (implemented in png_crc_finish) - * This is the default. - * - * This arose because of original mis-implementation and has persisted for - * compatibility reasons. - * - * TODO: the flag names are internal so maybe this can be changed to - * something comprehensible. - */ - if (handle_as_ancillary || PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0) - { - if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == - (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) - need_crc = 0; - } - - else /* critical */ - { - if ((png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) - need_crc = 0; - } - -#ifdef PNG_IO_STATE_SUPPORTED - png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; -#endif - - /* The chunk CRC must be serialized in a single I/O call. */ - png_read_data(png_ptr, crc_bytes, 4); - - if (need_crc != 0) - { - crc = png_get_uint_32(crc_bytes); - return crc != png_ptr->crc; - } - - else - return 0; -} - /* Optionally skip data and then check the CRC. Depending on whether we * are reading an ancillary or critical chunk, and how the program has set * things up, we may calculate the CRC on the data and print a message. * Returns '1' if there was a CRC error, '0' otherwise. - * - * There is one public version which is used in most places and another which - * takes the value for the 'critical' flag to check. This allows PLTE and IEND - * handling code to ignore the CRC error and removes some confusing code - * duplication. */ -static int -png_crc_finish_critical(png_structrp png_ptr, png_uint_32 skip, - int handle_as_ancillary) +int /* PRIVATE */ +png_crc_finish(png_structrp png_ptr, png_uint_32 skip) { /* The size of the local buffer for inflate is a good guess as to a * reasonable size to use for buffering reads from the application. @@ -328,59 +219,81 @@ png_crc_finish_critical(png_structrp png_ptr, png_uint_32 skip, png_crc_read(png_ptr, tmpbuf, len); } - /* If 'handle_as_ancillary' has been requested and this is a critical chunk - * but PNG_FLAG_CRC_CRITICAL_IGNORE was set then png_read_crc did not, in - * fact, calculate the CRC so the ANCILLARY settings should not be used - * instead. - */ - if (handle_as_ancillary && - (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) != 0) - handle_as_ancillary = 0; - - /* TODO: this might be more comprehensible if png_crc_error was inlined here. - */ - if (png_crc_error(png_ptr, handle_as_ancillary) != 0) + if (png_crc_error(png_ptr)) { - /* See above for the explanation of how the flags work. */ - if (handle_as_ancillary || PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) != 0 ? - (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) == 0 : - (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE) != 0) + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name) ? + !(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) : + (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_USE)) + { png_chunk_warning(png_ptr, "CRC error"); + } else - png_chunk_error(png_ptr, "CRC error"); + { + png_chunk_benign_error(png_ptr, "CRC error"); + return (0); + } - return 1; + return (1); } - return 0; + return (0); } +/* Compare the CRC stored in the PNG file with that calculated by libpng from + * the data it has read thus far. + */ int /* PRIVATE */ -png_crc_finish(png_structrp png_ptr, png_uint_32 skip) +png_crc_error(png_structrp png_ptr) { - return png_crc_finish_critical(png_ptr, skip, 0/*critical handling*/); + png_byte crc_bytes[4]; + png_uint_32 crc; + int need_crc = 1; + + if (PNG_CHUNK_ANCILLARY(png_ptr->chunk_name)) + { + if ((png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_MASK) == + (PNG_FLAG_CRC_ANCILLARY_USE | PNG_FLAG_CRC_ANCILLARY_NOWARN)) + need_crc = 0; + } + + else /* critical */ + { + if (png_ptr->flags & PNG_FLAG_CRC_CRITICAL_IGNORE) + need_crc = 0; + } + +#ifdef PNG_IO_STATE_SUPPORTED + png_ptr->io_state = PNG_IO_READING | PNG_IO_CHUNK_CRC; +#endif + + /* The chunk CRC must be serialized in a single I/O call. */ + png_read_data(png_ptr, crc_bytes, 4); + + if (need_crc) + { + crc = png_get_uint_32(crc_bytes); + return ((int)(crc != png_ptr->crc)); + } + + else + return (0); } -#if defined(PNG_READ_iCCP_SUPPORTED) || defined(PNG_READ_iTXt_SUPPORTED) ||\ - defined(PNG_READ_pCAL_SUPPORTED) || defined(PNG_READ_sCAL_SUPPORTED) ||\ - defined(PNG_READ_sPLT_SUPPORTED) || defined(PNG_READ_tEXt_SUPPORTED) ||\ - defined(PNG_READ_zTXt_SUPPORTED) || defined(PNG_READ_eXIf_SUPPORTED) ||\ - defined(PNG_SEQUENTIAL_READ_SUPPORTED) /* Manage the read buffer; this simply reallocates the buffer if it is not small * enough (or if it is not allocated). The routine returns a pointer to the * buffer; if an error occurs and 'warn' is set the routine returns NULL, else - * it will call png_error on failure. + * it will call png_error (via png_malloc) on failure. (warn == 2 means + * 'silent'). */ static png_bytep -png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size) +png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size, int warn) { png_bytep buffer = png_ptr->read_buffer; - if (new_size > png_chunk_max(png_ptr)) return NULL; - if (buffer != NULL && new_size > png_ptr->read_buffer_size) { + png_ptr->read_buffer = NULL; png_ptr->read_buffer = NULL; png_ptr->read_buffer_size = 0; png_free(png_ptr, buffer); @@ -393,17 +306,27 @@ png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size) if (buffer != NULL) { -# ifndef PNG_NO_MEMZERO /* for detecting UIM bugs **only** */ - memset(buffer, 0, new_size); /* just in case */ -# endif png_ptr->read_buffer = buffer; png_ptr->read_buffer_size = new_size; } + + else if (warn < 2) /* else silent */ + { +#ifdef PNG_WARNINGS_SUPPORTED + if (warn) + png_chunk_warning(png_ptr, "insufficient memory to read chunk"); + else +#endif + { +#ifdef PNG_ERROR_TEXT_SUPPORTED + png_chunk_error(png_ptr, "insufficient memory to read chunk"); +#endif + } + } } return buffer; } -#endif /* READ_iCCP|iTXt|pCAL|sCAL|sPLT|tEXt|zTXt|eXIf|SEQUENTIAL_READ */ /* png_inflate_claim: claim the zstream for some nefarious purpose that involves * decompression. Returns Z_OK on success, else a zlib error code. It checks @@ -411,7 +334,7 @@ png_read_buffer(png_structrp png_ptr, png_alloc_size_t new_size) * chunk apparently owns the stream. Prior to release it does a png_error. */ static int -png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) +png_inflate_claim(png_structrp png_ptr, png_uint_32 owner, int window_bits) { if (png_ptr->zowner != 0) { @@ -423,12 +346,12 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) * are minimal. */ (void)png_safecat(msg, (sizeof msg), 4, " using zstream"); -#if PNG_RELEASE_BUILD - png_chunk_warning(png_ptr, msg); - png_ptr->zowner = 0; -#else - png_chunk_error(png_ptr, msg); -#endif +# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC + png_chunk_warning(png_ptr, msg); + png_ptr->zowner = 0; +# else + png_chunk_error(png_ptr, msg); +# endif } /* Implementation note: unlike 'png_deflate_claim' this internal function @@ -446,24 +369,6 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) */ { int ret; /* zlib return code */ -#if ZLIB_VERNUM >= 0x1240 - int window_bits = 0; - -# if defined(PNG_SET_OPTION_SUPPORTED) && defined(PNG_MAXIMUM_INFLATE_WINDOW) - if (((png_ptr->options >> PNG_MAXIMUM_INFLATE_WINDOW) & 3) == - PNG_OPTION_ON) - { - window_bits = 15; - png_ptr->zstream_start = 0; /* fixed window size */ - } - - else - { - png_ptr->zstream_start = 1; - } -# endif - -#endif /* ZLIB_VERNUM >= 0x1240 */ /* Set this for safety, just in case the previous owner left pointers to * memory allocations. @@ -473,33 +378,28 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) png_ptr->zstream.next_out = NULL; png_ptr->zstream.avail_out = 0; - if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) { -#if ZLIB_VERNUM >= 0x1240 - ret = inflateReset2(&png_ptr->zstream, window_bits); -#else - ret = inflateReset(&png_ptr->zstream); -#endif +# if ZLIB_VERNUM < 0x1240 + PNG_UNUSED(window_bits) + ret = inflateReset(&png_ptr->zstream); +# else + ret = inflateReset2(&png_ptr->zstream, window_bits); +# endif } else { -#if ZLIB_VERNUM >= 0x1240 - ret = inflateInit2(&png_ptr->zstream, window_bits); -#else - ret = inflateInit(&png_ptr->zstream); -#endif +# if ZLIB_VERNUM < 0x1240 + ret = inflateInit(&png_ptr->zstream); +# else + ret = inflateInit2(&png_ptr->zstream, window_bits); +# endif if (ret == Z_OK) png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; } -#ifdef PNG_DISABLE_ADLER32_CHECK_SUPPORTED - if (((png_ptr->options >> PNG_IGNORE_ADLER32) & 3) == PNG_OPTION_ON) - /* Turn off validation of the ADLER32 checksum in IDAT chunks */ - ret = inflateValidate(&png_ptr->zstream, 0); -#endif - if (ret == Z_OK) png_ptr->zowner = owner; @@ -508,39 +408,9 @@ png_inflate_claim(png_structrp png_ptr, png_uint_32 owner) return ret; } - -#ifdef window_bits -# undef window_bits -#endif } -#if ZLIB_VERNUM >= 0x1240 -/* Handle the start of the inflate stream if we called inflateInit2(strm,0); - * in this case some zlib versions skip validation of the CINFO field and, in - * certain circumstances, libpng may end up displaying an invalid image, in - * contrast to implementations that call zlib in the normal way (e.g. libpng - * 1.5). - */ -int /* PRIVATE */ -png_zlib_inflate(png_structrp png_ptr, int flush) -{ - if (png_ptr->zstream_start && png_ptr->zstream.avail_in > 0) - { - if ((*png_ptr->zstream.next_in >> 4) > 7) - { - png_ptr->zstream.msg = "invalid window size (libpng)"; - return Z_DATA_ERROR; - } - - png_ptr->zstream_start = 0; - } - - return inflate(&png_ptr->zstream, flush); -} -#endif /* Zlib >= 1.2.4 */ - #ifdef PNG_READ_COMPRESSED_TEXT_SUPPORTED -#if defined(PNG_READ_zTXt_SUPPORTED) || defined (PNG_READ_iTXt_SUPPORTED) /* png_inflate now returns zlib error codes including Z_OK and Z_STREAM_END to * allow the caller to do multiple calls if required. If the 'finish' flag is * set Z_FINISH will be passed to the final inflate() call and Z_STREAM_END must @@ -633,8 +503,8 @@ png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish, * the previous chunk of input data. Tell zlib if we have reached the * end of the output buffer. */ - ret = PNG_INFLATE(png_ptr, avail_out > 0 ? Z_NO_FLUSH : - (finish ? Z_FINISH : Z_SYNC_FLUSH)); + ret = inflate(&png_ptr->zstream, avail_out > 0 ? Z_NO_FLUSH : + (finish ? Z_FINISH : Z_SYNC_FLUSH)); } while (ret == Z_OK); /* For safety kill the local buffer pointer now */ @@ -679,9 +549,9 @@ png_inflate(png_structrp png_ptr, png_uint_32 owner, int finish, */ static int png_decompress_chunk(png_structrp png_ptr, - png_uint_32 chunklength, png_uint_32 prefix_size, - png_alloc_size_t *newlength /* must be initialized to the maximum! */, - int terminate /*add a '\0' to the end of the uncompressed data*/) + png_uint_32 chunklength, png_uint_32 prefix_size, + png_alloc_size_t *newlength /* must be initialized to the maximum! */, + int terminate /*add a '\0' to the end of the uncompressed data*/) { /* TODO: implement different limits for different types of chunk. * @@ -690,7 +560,16 @@ png_decompress_chunk(png_structrp png_ptr, * maybe a '\0' terminator too. We have to assume that 'prefix_size' is * limited only by the maximum chunk size. */ - png_alloc_size_t limit = png_chunk_max(png_ptr); + png_alloc_size_t limit = PNG_SIZE_MAX; + +# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max > 0 && + png_ptr->user_chunk_malloc_max < limit) + limit = png_ptr->user_chunk_malloc_max; +# elif PNG_USER_CHUNK_MALLOC_MAX > 0 + if (PNG_USER_CHUNK_MALLOC_MAX < limit) + limit = PNG_USER_CHUNK_MALLOC_MAX; +# endif if (limit >= prefix_size + (terminate != 0)) { @@ -701,16 +580,22 @@ png_decompress_chunk(png_structrp png_ptr, if (limit < *newlength) *newlength = limit; - /* Now try to claim the stream. */ - ret = png_inflate_claim(png_ptr, png_ptr->chunk_name); + /* Now try to claim the stream; the 'warn' setting causes zlib to be told + * to use the maximum window size during inflate; this hides errors in the + * deflate header window bits value which is used if '0' is passed. In + * fact this only has an effect with zlib versions 1.2.4 and later - see + * the comments in png_inflate_claim above. + */ + ret = png_inflate_claim(png_ptr, png_ptr->chunk_name, + png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN ? 15 : 0); if (ret == Z_OK) { png_uint_32 lzsize = chunklength - prefix_size; ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, - /* input: */ png_ptr->read_buffer + prefix_size, &lzsize, - /* output: */ NULL, newlength); + /* input: */ png_ptr->read_buffer + prefix_size, &lzsize, + /* output: */ NULL, newlength); if (ret == Z_STREAM_END) { @@ -730,23 +615,21 @@ png_decompress_chunk(png_structrp png_ptr, */ png_alloc_size_t new_size = *newlength; png_alloc_size_t buffer_size = prefix_size + new_size + - (terminate != 0); + (terminate != 0); png_bytep text = png_voidcast(png_bytep, png_malloc_base(png_ptr, - buffer_size)); + buffer_size)); if (text != NULL) { - memset(text, 0, buffer_size); - ret = png_inflate(png_ptr, png_ptr->chunk_name, 1/*finish*/, - png_ptr->read_buffer + prefix_size, &lzsize, - text + prefix_size, newlength); + png_ptr->read_buffer + prefix_size, &lzsize, + text + prefix_size, newlength); if (ret == Z_STREAM_END) { if (new_size == *newlength) { - if (terminate != 0) + if (terminate) text[prefix_size + *newlength] = 0; if (prefix_size > 0) @@ -785,7 +668,7 @@ png_decompress_chunk(png_structrp png_ptr, * the extra space may otherwise be used as a Trojan Horse. */ if (ret == Z_STREAM_END && - chunklength - prefix_size != lzsize) + chunklength - prefix_size != lzsize) png_chunk_benign_error(png_ptr, "extra compressed data"); } @@ -801,7 +684,9 @@ png_decompress_chunk(png_structrp png_ptr, { /* inflateReset failed, store the error message */ png_zstream_error(png_ptr, ret); - ret = PNG_UNEXPECTED_ZLIB_RETURN; + + if (ret == Z_STREAM_END) + ret = PNG_UNEXPECTED_ZLIB_RETURN; } } @@ -825,8 +710,7 @@ png_decompress_chunk(png_structrp png_ptr, return Z_MEM_ERROR; } } -#endif /* READ_zTXt || READ_iTXt */ -#endif /* READ_COMPRESSED_TEXT */ +#endif /* PNG_READ_COMPRESSED_TEXT_SUPPORTED */ #ifdef PNG_READ_iCCP_SUPPORTED /* Perform a partial read and decompress, producing 'avail_out' bytes and @@ -834,8 +718,8 @@ png_decompress_chunk(png_structrp png_ptr, */ static int png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size, - png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size, - int finish) + png_uint_32p chunk_bytes, png_bytep next_out, png_alloc_size_t *out_size, + int finish) { if (png_ptr->zowner == png_ptr->chunk_name) { @@ -874,8 +758,8 @@ png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size, * the available output is produced; this allows reading of truncated * streams. */ - ret = PNG_INFLATE(png_ptr, *chunk_bytes > 0 ? - Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH)); + ret = inflate(&png_ptr->zstream, + *chunk_bytes > 0 ? Z_NO_FLUSH : (finish ? Z_FINISH : Z_SYNC_FLUSH)); } while (ret == Z_OK && (*out_size > 0 || png_ptr->zstream.avail_out > 0)); @@ -893,11 +777,10 @@ png_inflate_read(png_structrp png_ptr, png_bytep read_buffer, uInt read_size, return Z_STREAM_ERROR; } } -#endif /* READ_iCCP */ +#endif -/* CHUNK HANDLING */ /* Read and check the IDHR chunk */ -static png_handle_result_code +void /* PRIVATE */ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[13]; @@ -907,7 +790,12 @@ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) png_debug(1, "in png_handle_IHDR"); - /* Length and position are checked by the caller. */ + if (png_ptr->mode & PNG_HAVE_IHDR) + png_chunk_error(png_ptr, "out of place"); + + /* Check the length */ + if (length != 13) + png_chunk_error(png_ptr, "invalid"); png_ptr->mode |= PNG_HAVE_IHDR; @@ -956,244 +844,301 @@ png_handle_IHDR(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) } /* Set up other useful info */ - png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * png_ptr->channels); + png_ptr->pixel_depth = (png_byte)(png_ptr->bit_depth * + png_ptr->channels); png_ptr->rowbytes = PNG_ROWBYTES(png_ptr->pixel_depth, png_ptr->width); png_debug1(3, "bit_depth = %d", png_ptr->bit_depth); png_debug1(3, "channels = %d", png_ptr->channels); png_debug1(3, "rowbytes = %lu", (unsigned long)png_ptr->rowbytes); - - /* Rely on png_set_IHDR to completely validate the data and call png_error if - * it's wrong. - */ png_set_IHDR(png_ptr, info_ptr, width, height, bit_depth, color_type, interlace_type, compression_type, filter_type); - - return handled_ok; - PNG_UNUSED(length) } /* Read and check the palette */ -/* TODO: there are several obvious errors in this code when handling - * out-of-place chunks and there is much over-complexity caused by trying to - * patch up the problems. - */ -static png_handle_result_code +void /* PRIVATE */ png_handle_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_const_charp errmsg = NULL; + png_color palette[PNG_MAX_PALETTE_LENGTH]; + int num, i; +#ifdef PNG_POINTER_INDEXING_SUPPORTED + png_colorp pal_ptr; +#endif png_debug(1, "in png_handle_PLTE"); - /* 1.6.47: consistency. This used to be especially treated as a critical - * error even in an image which is not colour mapped, there isn't a good - * justification for treating some errors here one way and others another so - * everything uses the same logic. + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + /* Moved to before the 'after IDAT' check below because otherwise duplicate + * PLTE chunks are potentially ignored (the spec says there shall not be more + * than one PLTE, the error is not treated as benign, so this check trumps + * the requirement that PLTE appears before IDAT.) */ - if ((png_ptr->mode & PNG_HAVE_PLTE) != 0) - errmsg = "duplicate"; + else if (png_ptr->mode & PNG_HAVE_PLTE) + png_chunk_error(png_ptr, "duplicate"); - else if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) - errmsg = "out of place"; - - else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) - errmsg = "ignored in grayscale PNG"; - - else if (length > 3*PNG_MAX_PALETTE_LENGTH || (length % 3) != 0) - errmsg = "invalid"; - - /* This drops PLTE in favour of tRNS or bKGD because both of those chunks - * can have an effect on the rendering of the image whereas PLTE only matters - * in the case of an 8-bit display with a decoder which controls the palette. - * - * The alternative here is to ignore the error and store the palette anyway; - * destroying the tRNS will definately cause problems. - * - * NOTE: the case of PNG_COLOR_TYPE_PALETTE need not be considered because - * the png_handle_ routines for the three 'after PLTE' chunks tRNS, bKGD and - * hIST all check for a preceding PLTE in these cases. - */ - else if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE && - (png_has_chunk(png_ptr, tRNS) || png_has_chunk(png_ptr, bKGD))) - errmsg = "out of place"; - - else + else if (png_ptr->mode & PNG_HAVE_IDAT) { - /* If the palette has 256 or fewer entries but is too large for the bit - * depth we don't issue an error to preserve the behavior of previous - * libpng versions. We silently truncate the unused extra palette entries - * here. + /* This is benign because the non-benign error happened before, when an + * IDAT was encountered in a color-mapped image with no PLTE. */ - const unsigned max_palette_length = - (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? - 1U << png_ptr->bit_depth : PNG_MAX_PALETTE_LENGTH; - - /* The cast is safe because 'length' is less than - * 3*PNG_MAX_PALETTE_LENGTH - */ - const unsigned num = (length > 3U*max_palette_length) ? - max_palette_length : (unsigned)length / 3U; - - unsigned i, j; - png_byte buf[3*PNG_MAX_PALETTE_LENGTH]; - png_color palette[PNG_MAX_PALETTE_LENGTH]; - - /* Read the chunk into the buffer then read to the end of the chunk. */ - png_crc_read(png_ptr, buf, num*3U); - png_crc_finish_critical(png_ptr, length - 3U*num, - /* Handle as ancillary if PLTE is optional: */ - png_ptr->color_type != PNG_COLOR_TYPE_PALETTE); - - for (i = 0U, j = 0U; i < num; i++) - { - palette[i].red = buf[j++]; - palette[i].green = buf[j++]; - palette[i].blue = buf[j++]; - } - - /* A valid PLTE chunk has been read */ - png_ptr->mode |= PNG_HAVE_PLTE; - - /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to - * its own copy of the palette. This has the side effect that when - * png_start_row is called (this happens after any call to - * png_read_update_info) the info_ptr palette gets changed. This is - * extremely unexpected and confusing. - * - * REVIEW: there have been consistent bugs in the past about gamma and - * similar transforms to colour mapped images being useless because the - * modified palette cannot be accessed because of the above. - * - * CONSIDER: Fix this by not sharing the palette in this way. But does - * this completely fix the problem? - */ - png_set_PLTE(png_ptr, info_ptr, palette, num); - return handled_ok; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; } - /* Here on error: errmsg is non NULL. */ - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + png_ptr->mode |= PNG_HAVE_PLTE; + + if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) { png_crc_finish(png_ptr, length); - png_chunk_error(png_ptr, errmsg); + png_chunk_benign_error(png_ptr, "ignored in grayscale PNG"); + return; } - else /* not critical to this image */ +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) { - png_crc_finish_critical(png_ptr, length, 1/*handle as ancillary*/); - png_chunk_benign_error(png_ptr, errmsg); + png_crc_finish(png_ptr, length); + return; + } +#endif + + if (length > 3*PNG_MAX_PALETTE_LENGTH || length % 3) + { + png_crc_finish(png_ptr, length); + + if (png_ptr->color_type != PNG_COLOR_TYPE_PALETTE) + png_chunk_benign_error(png_ptr, "invalid"); + + else + png_chunk_error(png_ptr, "invalid"); + + return; } - /* Because PNG_UNUSED(errmsg) does not work if all the uses are compiled out - * (this does happen). + /* The cast is safe because 'length' is less than 3*PNG_MAX_PALETTE_LENGTH */ + num = (int)length / 3; + +#ifdef PNG_POINTER_INDEXING_SUPPORTED + for (i = 0, pal_ptr = palette; i < num; i++, pal_ptr++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + pal_ptr->red = buf[0]; + pal_ptr->green = buf[1]; + pal_ptr->blue = buf[2]; + } +#else + for (i = 0; i < num; i++) + { + png_byte buf[3]; + + png_crc_read(png_ptr, buf, 3); + /* Don't depend upon png_color being any order */ + palette[i].red = buf[0]; + palette[i].green = buf[1]; + palette[i].blue = buf[2]; + } +#endif + + /* If we actually need the PLTE chunk (ie for a paletted image), we do + * whatever the normal CRC configuration tells us. However, if we + * have an RGB image, the PLTE can be considered ancillary, so + * we will act as though it is. */ - return errmsg != NULL ? handled_error : handled_error; +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) +#endif + { + png_crc_finish(png_ptr, 0); + } + +#ifndef PNG_READ_OPT_PLTE_SUPPORTED + else if (png_crc_error(png_ptr)) /* Only if we have a CRC error */ + { + /* If we don't want to use the data from an ancillary chunk, + * we have two options: an error abort, or a warning and we + * ignore the data in this chunk (which should be OK, since + * it's considered ancillary for a RGB or RGBA image). + * + * IMPLEMENTATION NOTE: this is only here because png_crc_finish uses the + * chunk type to determine whether to check the ancillary or the critical + * flags. + */ + if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_USE)) + { + if (png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN) + { + png_chunk_benign_error(png_ptr, "CRC error"); + } + + else + { + png_chunk_warning(png_ptr, "CRC error"); + return; + } + } + + /* Otherwise, we (optionally) emit a warning and use the chunk. */ + else if (!(png_ptr->flags & PNG_FLAG_CRC_ANCILLARY_NOWARN)) + { + png_chunk_warning(png_ptr, "CRC error"); + } + } +#endif + + /* TODO: png_set_PLTE has the side effect of setting png_ptr->palette to its + * own copy of the palette. This has the side effect that when png_start_row + * is called (this happens after any call to png_read_update_info) the + * info_ptr palette gets changed. This is extremely unexpected and + * confusing. + * + * Fix this by not sharing the palette in this way. + */ + png_set_PLTE(png_ptr, info_ptr, palette, num); + + /* The three chunks, bKGD, hIST and tRNS *must* appear after PLTE and before + * IDAT. Prior to 1.6.0 this was not checked; instead the code merely + * checked the apparent validity of a tRNS chunk inserted before PLTE on a + * palette PNG. 1.6.0 attempts to rigorously follow the standard and + * therefore does a benign error if the erroneous condition is detected *and* + * cancels the tRNS if the benign error returns. The alternative is to + * amend the standard since it would be rather hypocritical of the standards + * maintainers to ignore it. + */ +#ifdef PNG_READ_tRNS_SUPPORTED + if (png_ptr->num_trans > 0 || + (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS) != 0)) + { + /* Cancel this because otherwise it would be used if the transforms + * require it. Don't cancel the 'valid' flag because this would prevent + * detection of duplicate chunks. + */ + png_ptr->num_trans = 0; + + if (info_ptr != NULL) + info_ptr->num_trans = 0; + + png_chunk_benign_error(png_ptr, "tRNS must be after"); + } +#endif + +#ifdef PNG_READ_hIST_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST) != 0) + png_chunk_benign_error(png_ptr, "hIST must be after"); +#endif + +#ifdef PNG_READ_bKGD_SUPPORTED + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD) != 0) + png_chunk_benign_error(png_ptr, "bKGD must be after"); +#endif } -/* On read the IDAT chunk is always handled specially, even if marked for - * unknown handling (this is allowed), so: - */ -#define png_handle_IDAT NULL - -static png_handle_result_code +void /* PRIVATE */ png_handle_IEND(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_debug(1, "in png_handle_IEND"); + if (!(png_ptr->mode & PNG_HAVE_IHDR) || !(png_ptr->mode & PNG_HAVE_IDAT)) + png_chunk_error(png_ptr, "out of place"); + png_ptr->mode |= (PNG_AFTER_IDAT | PNG_HAVE_IEND); + png_crc_finish(png_ptr, length); + if (length != 0) png_chunk_benign_error(png_ptr, "invalid"); - png_crc_finish_critical(png_ptr, length, 1/*handle as ancillary*/); - - return handled_ok; PNG_UNUSED(info_ptr) } #ifdef PNG_READ_gAMA_SUPPORTED -static png_handle_result_code +void /* PRIVATE */ png_handle_gAMA(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_uint_32 ugamma; + png_fixed_point igamma; png_byte buf[4]; png_debug(1, "in png_handle_gAMA"); - png_crc_read(png_ptr, buf, 4); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; - - ugamma = png_get_uint_32(buf); - - if (ugamma > PNG_UINT_31_MAX) + else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) { - png_chunk_benign_error(png_ptr, "invalid"); - return handled_error; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; } - png_set_gAMA_fixed(png_ptr, info_ptr, (png_fixed_point)/*SAFE*/ugamma); + if (length != 4) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } -#ifdef PNG_READ_GAMMA_SUPPORTED - /* PNGv3: chunk precedence for gamma is cICP, [iCCP], sRGB, gAMA. gAMA is - * at the end of the chain so simply check for an unset value. - */ - if (png_ptr->chunk_gamma == 0) - png_ptr->chunk_gamma = (png_fixed_point)/*SAFE*/ugamma; -#endif /*READ_GAMMA*/ + png_crc_read(png_ptr, buf, 4); - return handled_ok; - PNG_UNUSED(length) + if (png_crc_finish(png_ptr, 0)) + return; + + igamma = png_get_fixed_point(NULL, buf); + + png_colorspace_set_gamma(png_ptr, &png_ptr->colorspace, igamma); + png_colorspace_sync(png_ptr, info_ptr); } -#else -# define png_handle_gAMA NULL #endif #ifdef PNG_READ_sBIT_SUPPORTED -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - unsigned int truelen, i; - png_byte sample_depth; + unsigned int truelen; png_byte buf[4]; png_debug(1, "in png_handle_sBIT"); - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - truelen = 3; - sample_depth = 8; - } + buf[0] = buf[1] = buf[2] = buf[3] = 0; - else - { - truelen = png_ptr->channels; - sample_depth = png_ptr->bit_depth; - } + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); - if (length != truelen) + else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) { png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "bad length"); - return handled_error; + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sBIT)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 3; + + else + truelen = png_ptr->channels; + + if (length != truelen || length > 4) + { + png_chunk_benign_error(png_ptr, "invalid"); + png_crc_finish(png_ptr, length); + return; } - buf[0] = buf[1] = buf[2] = buf[3] = sample_depth; png_crc_read(png_ptr, buf, truelen); - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; + if (png_crc_finish(png_ptr, 0)) + return; - for (i=0; i sample_depth) - { - png_chunk_benign_error(png_ptr, "invalid"); - return handled_error; - } - } - - if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) { png_ptr->sig_bit.red = buf[0]; png_ptr->sig_bit.green = buf[1]; @@ -1201,7 +1146,7 @@ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) png_ptr->sig_bit.alpha = buf[3]; } - else /* grayscale */ + else { png_ptr->sig_bit.gray = buf[0]; png_ptr->sig_bit.red = buf[0]; @@ -1211,132 +1156,133 @@ png_handle_sBIT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) } png_set_sBIT(png_ptr, info_ptr, &(png_ptr->sig_bit)); - return handled_ok; } -#else -# define png_handle_sBIT NULL #endif #ifdef PNG_READ_cHRM_SUPPORTED -static png_int_32 -png_get_int_32_checked(png_const_bytep buf, int *error) -{ - png_uint_32 uval = png_get_uint_32(buf); - if ((uval & 0x80000000) == 0) /* non-negative */ - return (png_int_32)uval; - - uval = (uval ^ 0xffffffff) + 1; /* 2's complement: -x = ~x+1 */ - if ((uval & 0x80000000) == 0) /* no overflow */ - return -(png_int_32)uval; - - /* This version of png_get_int_32 has a way of returning the error to the - * caller, so: - */ - *error = 1; - return 0; /* Safe */ -} - -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_cHRM(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - int error = 0; - png_xy xy; png_byte buf[32]; + png_xy xy; png_debug(1, "in png_handle_cHRM"); - png_crc_read(png_ptr, buf, 32); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; - - xy.whitex = png_get_int_32_checked(buf + 0, &error); - xy.whitey = png_get_int_32_checked(buf + 4, &error); - xy.redx = png_get_int_32_checked(buf + 8, &error); - xy.redy = png_get_int_32_checked(buf + 12, &error); - xy.greenx = png_get_int_32_checked(buf + 16, &error); - xy.greeny = png_get_int_32_checked(buf + 20, &error); - xy.bluex = png_get_int_32_checked(buf + 24, &error); - xy.bluey = png_get_int_32_checked(buf + 28, &error); - - if (error) + else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) { - png_chunk_benign_error(png_ptr, "invalid"); - return handled_error; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; } - /* png_set_cHRM may complain about some of the values but this doesn't matter - * because it was a cHRM and it did have vaguely (if, perhaps, ridiculous) - * values. Ridiculousity will be checked if the values are used later. - */ - png_set_cHRM_fixed(png_ptr, info_ptr, xy.whitex, xy.whitey, xy.redx, xy.redy, - xy.greenx, xy.greeny, xy.bluex, xy.bluey); + if (length != 32) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } - /* We only use 'chromaticities' for RGB to gray */ -# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - /* There is no need to check sRGB here, cICP is NYI and iCCP is not - * supported so just check mDCV. - */ - if (!png_has_chunk(png_ptr, mDCV)) - { - png_ptr->chromaticities = xy; - } -# endif /* READ_RGB_TO_GRAY */ + png_crc_read(png_ptr, buf, 32); - return handled_ok; - PNG_UNUSED(length) + if (png_crc_finish(png_ptr, 0)) + return; + + xy.whitex = png_get_fixed_point(NULL, buf); + xy.whitey = png_get_fixed_point(NULL, buf + 4); + xy.redx = png_get_fixed_point(NULL, buf + 8); + xy.redy = png_get_fixed_point(NULL, buf + 12); + xy.greenx = png_get_fixed_point(NULL, buf + 16); + xy.greeny = png_get_fixed_point(NULL, buf + 20); + xy.bluex = png_get_fixed_point(NULL, buf + 24); + xy.bluey = png_get_fixed_point(NULL, buf + 28); + + if (xy.whitex == PNG_FIXED_ERROR || + xy.whitey == PNG_FIXED_ERROR || + xy.redx == PNG_FIXED_ERROR || + xy.redy == PNG_FIXED_ERROR || + xy.greenx == PNG_FIXED_ERROR || + xy.greeny == PNG_FIXED_ERROR || + xy.bluex == PNG_FIXED_ERROR || + xy.bluey == PNG_FIXED_ERROR) + { + png_chunk_benign_error(png_ptr, "invalid values"); + return; + } + + /* If a colorspace error has already been output skip this chunk */ + if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) + return; + + if (png_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) + { + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + png_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + (void)png_colorspace_set_chromaticities(png_ptr, &png_ptr->colorspace, &xy, + 1/*prefer cHRM values*/); + png_colorspace_sync(png_ptr, info_ptr); } -#else -# define png_handle_cHRM NULL #endif #ifdef PNG_READ_sRGB_SUPPORTED -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_sRGB(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte intent; png_debug(1, "in png_handle_sRGB"); - png_crc_read(png_ptr, &intent, 1); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; - - /* This checks the range of the "rendering intent" because it is specified in - * the PNG spec itself; the "reserved" values will result in the chunk not - * being accepted, just as they do with the various "reserved" values in - * IHDR. - */ - if (intent > 3/*PNGv3 spec*/) + else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) { - png_chunk_benign_error(png_ptr, "invalid"); - return handled_error; + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; } - png_set_sRGB(png_ptr, info_ptr, intent); - /* NOTE: png_struct::chromaticities is not set here because the RGB to gray - * coefficients are known without a need for the chromaticities. + if (length != 1) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_crc_read(png_ptr, &intent, 1); + + if (png_crc_finish(png_ptr, 0)) + return; + + /* If a colorspace error has already been output skip this chunk */ + if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) + return; + + /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect + * this. */ + if (png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) + { + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); + png_chunk_benign_error(png_ptr, "too many profiles"); + return; + } -#ifdef PNG_READ_GAMMA_SUPPORTED - /* PNGv3: chunk precedence for gamma is cICP, [iCCP], sRGB, gAMA. iCCP is - * not supported by libpng so the only requirement is to check for cICP - * setting the gamma (this is NYI, but this check is safe.) - */ - if (!png_has_chunk(png_ptr, cICP) || png_ptr->chunk_gamma == 0) - png_ptr->chunk_gamma = PNG_GAMMA_sRGB_INVERSE; -#endif /*READ_GAMMA*/ - - return handled_ok; - PNG_UNUSED(length) + (void)png_colorspace_set_sRGB(png_ptr, &png_ptr->colorspace, intent); + png_colorspace_sync(png_ptr, info_ptr); } -#else -# define png_handle_sRGB NULL -#endif /* READ_sRGB */ +#endif /* PNG_READ_sRGB_SUPPORTED */ #ifdef PNG_READ_iCCP_SUPPORTED -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* Note: this does not properly handle profiles that are > 64K under DOS */ { @@ -1345,10 +1291,42 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) png_debug(1, "in png_handle_iCCP"); - /* PNGv3: allow PNG files with both sRGB and iCCP because the PNG spec only - * ever said that there "should" be only one, not "shall" and the PNGv3 - * colour chunk precedence rules give a handling for this case anyway. + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & (PNG_HAVE_IDAT|PNG_HAVE_PLTE)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + /* Consistent with all the above colorspace handling an obviously *invalid* + * chunk is just ignored, so does not invalidate the color space. An + * alternative is to set the 'invalid' flags at the start of this routine + * and only clear them in they were not set before and all the tests pass. + * The minimum 'deflate' stream is assumed to be just the 2 byte header and 4 + * byte checksum. The keyword must be one character and there is a + * terminator (0) byte and the compression method. */ + if (length < 9) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too short"); + return; + } + + /* If a colorspace error has already been output skip this chunk */ + if (png_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) + { + png_crc_finish(png_ptr, length); + return; + } + + /* Only one sRGB or iCCP chunk is allowed, use the HAVE_INTENT flag to detect + * this. + */ + if ((png_ptr->colorspace.flags & PNG_COLORSPACE_HAVE_INTENT) == 0) { uInt read_length, keyword_length; char keyword[81]; @@ -1358,18 +1336,11 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) */ read_length = 81; /* maximum */ if (read_length > length) - read_length = (uInt)/*SAFE*/length; + read_length = (uInt)length; png_crc_read(png_ptr, (png_bytep)keyword, read_length); length -= read_length; - if (length < LZ77Min) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "too short"); - return handled_error; - } - keyword_length = 0; while (keyword_length < 80 && keyword_length < read_length && keyword[keyword_length] != 0) @@ -1386,75 +1357,79 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { read_length -= keyword_length+2; - if (png_inflate_claim(png_ptr, png_iCCP) == Z_OK) + if (png_inflate_claim(png_ptr, png_iCCP, + png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN ? 15 : 0) == Z_OK) { - Byte profile_header[132]={0}; + Byte profile_header[132]; Byte local_buffer[PNG_INFLATE_BUF_SIZE]; png_alloc_size_t size = (sizeof profile_header); png_ptr->zstream.next_in = (Bytef*)keyword + (keyword_length+2); png_ptr->zstream.avail_in = read_length; (void)png_inflate_read(png_ptr, local_buffer, - (sizeof local_buffer), &length, profile_header, &size, - 0/*finish: don't, because the output is too small*/); + (sizeof local_buffer), &length, profile_header, &size, + 0/*finish: don't, because the output is too small*/); if (size == 0) { /* We have the ICC profile header; do the basic header checks. */ - png_uint_32 profile_length = png_get_uint_32(profile_header); + const png_uint_32 profile_length = + png_get_uint_32(profile_header); - if (png_icc_check_length(png_ptr, keyword, profile_length) != - 0) + if (png_icc_check_length(png_ptr, &png_ptr->colorspace, + keyword, profile_length)) { /* The length is apparently ok, so we can check the 132 * byte header. */ - if (png_icc_check_header(png_ptr, keyword, profile_length, - profile_header, png_ptr->color_type) != 0) + if (png_icc_check_header(png_ptr, &png_ptr->colorspace, + keyword, profile_length, profile_header, + png_ptr->color_type)) { /* Now read the tag table; a variable size buffer is * needed at this point, allocate one for the whole * profile. The header check has already validated - * that none of this stuff will overflow. + * that none of these stuff will overflow. */ - png_uint_32 tag_count = - png_get_uint_32(profile_header + 128); + const png_uint_32 tag_count = png_get_uint_32( + profile_header+128); png_bytep profile = png_read_buffer(png_ptr, - profile_length); + profile_length, 2/*silent*/); if (profile != NULL) { memcpy(profile, profile_header, - (sizeof profile_header)); + (sizeof profile_header)); size = 12 * tag_count; (void)png_inflate_read(png_ptr, local_buffer, - (sizeof local_buffer), &length, - profile + (sizeof profile_header), &size, 0); + (sizeof local_buffer), &length, + profile + (sizeof profile_header), &size, 0); - /* Still expect a buffer error because we expect + /* Still expect a a buffer error because we expect * there to be some tag data! */ if (size == 0) { if (png_icc_check_tag_table(png_ptr, - keyword, profile_length, profile) != 0) + &png_ptr->colorspace, keyword, profile_length, + profile)) { /* The profile has been validated for basic * security issues, so read the whole thing in. */ size = profile_length - (sizeof profile_header) - - 12 * tag_count; + - 12 * tag_count; (void)png_inflate_read(png_ptr, local_buffer, - (sizeof local_buffer), &length, - profile + (sizeof profile_header) + - 12 * tag_count, &size, 1/*finish*/); + (sizeof local_buffer), &length, + profile + (sizeof profile_header) + + 12 * tag_count, &size, 1/*finish*/); if (length > 0 && !(png_ptr->flags & - PNG_FLAG_BENIGN_ERRORS_WARN)) + PNG_FLAG_BENIGN_ERRORS_WARN)) errmsg = "extra compressed data"; /* But otherwise allow extra data: */ @@ -1466,27 +1441,34 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) * keep going. */ png_chunk_warning(png_ptr, - "extra compressed data"); + "extra compressed data"); } png_crc_finish(png_ptr, length); finished = 1; +# ifdef PNG_sRGB_SUPPORTED + /* Check for a match against sRGB */ + png_icc_set_sRGB(png_ptr, + &png_ptr->colorspace, profile, + png_ptr->zstream.adler); +# endif + /* Steal the profile for info_ptr. */ if (info_ptr != NULL) { png_free_data(png_ptr, info_ptr, - PNG_FREE_ICCP, 0); + PNG_FREE_ICCP, 0); info_ptr->iccp_name = png_voidcast(char*, - png_malloc_base(png_ptr, - keyword_length+1)); + png_malloc_base(png_ptr, + keyword_length+1)); if (info_ptr->iccp_name != NULL) { memcpy(info_ptr->iccp_name, keyword, - keyword_length+1); + keyword_length+1); info_ptr->iccp_proflen = - profile_length; + profile_length; info_ptr->iccp_profile = profile; png_ptr->read_buffer = NULL; /*steal*/ info_ptr->free_me |= PNG_FREE_ICCP; @@ -1494,7 +1476,11 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) } else + { + png_ptr->colorspace.flags |= + PNG_COLORSPACE_INVALID; errmsg = "out of memory"; + } } /* else the profile remains in the read @@ -1502,17 +1488,26 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) * chunks. */ + if (info_ptr != NULL) + png_colorspace_sync(png_ptr, info_ptr); + if (errmsg == NULL) { png_ptr->zowner = 0; - return handled_ok; + return; } } - if (errmsg == NULL) + + else if (size > 0) + errmsg = "truncated"; + + else errmsg = png_ptr->zstream.msg; } + /* else png_icc_check_tag_table output an error */ } + else /* profile truncated */ errmsg = png_ptr->zstream.msg; } @@ -1546,21 +1541,22 @@ png_handle_iCCP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) errmsg = "bad keyword"; } + else + errmsg = "too many profiles"; + /* Failure: the reason is in 'errmsg' */ - if (finished == 0) + if (!finished) png_crc_finish(png_ptr, length); + png_ptr->colorspace.flags |= PNG_COLORSPACE_INVALID; + png_colorspace_sync(png_ptr, info_ptr); if (errmsg != NULL) /* else already output */ png_chunk_benign_error(png_ptr, errmsg); - - return handled_error; } -#else -# define png_handle_iCCP NULL -#endif /* READ_iCCP */ +#endif /* PNG_READ_iCCP_SUPPORTED */ #ifdef PNG_READ_sPLT_SUPPORTED -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* Note: this does not properly handle chunks that are > 64K under DOS */ { @@ -1571,7 +1567,7 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) int entry_size, i; png_uint_32 skip = 0; png_uint_32 dl; - size_t max_dl; + png_size_t max_dl; png_debug(1, "in png_handle_sPLT"); @@ -1581,24 +1577,43 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) if (png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); - return handled_error; + return; } if (--png_ptr->user_chunk_cache_max == 1) { png_warning(png_ptr, "No space in chunk cache for sPLT"); png_crc_finish(png_ptr, length); - return handled_error; + return; } } #endif - buffer = png_read_buffer(png_ptr, length+1); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + +#ifdef PNG_MAX_MALLOC_64K + if (length > 65535U) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too large to fit in memory"); + return; + } +#endif + + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); if (buffer == NULL) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of memory"); - return handled_error; + return; } @@ -1608,8 +1623,8 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) */ png_crc_read(png_ptr, buffer, length); - if (png_crc_finish(png_ptr, skip) != 0) - return handled_error; + if (png_crc_finish(png_ptr, skip)) + return; buffer[length] = 0; @@ -1619,10 +1634,10 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) ++entry_start; /* A sample depth should follow the separator, and we should be on it */ - if (length < 2U || entry_start > buffer + (length - 2U)) + if (entry_start > buffer + length - 2) { png_warning(png_ptr, "malformed sPLT chunk"); - return handled_error; + return; } new_palette.depth = *entry_start++; @@ -1633,32 +1648,33 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) data_length = length - (png_uint_32)(entry_start - buffer); /* Integrity-check the data length */ - if ((data_length % (unsigned int)entry_size) != 0) + if (data_length % entry_size) { png_warning(png_ptr, "sPLT chunk has bad length"); - return handled_error; + return; } - dl = (png_uint_32)(data_length / (unsigned int)entry_size); + dl = (png_int_32)(data_length / entry_size); max_dl = PNG_SIZE_MAX / (sizeof (png_sPLT_entry)); if (dl > max_dl) { - png_warning(png_ptr, "sPLT chunk too long"); - return handled_error; + png_warning(png_ptr, "sPLT chunk too long"); + return; } - new_palette.nentries = (png_int_32)(data_length / (unsigned int)entry_size); + new_palette.nentries = (png_int_32)(data_length / entry_size); - new_palette.entries = (png_sPLT_entryp)png_malloc_warn(png_ptr, - (png_alloc_size_t) new_palette.nentries * (sizeof (png_sPLT_entry))); + new_palette.entries = (png_sPLT_entryp)png_malloc_warn( + png_ptr, new_palette.nentries * (sizeof (png_sPLT_entry))); if (new_palette.entries == NULL) { - png_warning(png_ptr, "sPLT chunk requires too much memory"); - return handled_error; + png_warning(png_ptr, "sPLT chunk requires too much memory"); + return; } +#ifdef PNG_POINTER_INDEXING_SUPPORTED for (i = 0; i < new_palette.nentries; i++) { pp = new_palette.entries + i; @@ -1681,6 +1697,31 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) pp->frequency = png_get_uint_16(entry_start); entry_start += 2; } +#else + pp = new_palette.entries; + + for (i = 0; i < new_palette.nentries; i++) + { + + if (new_palette.depth == 8) + { + pp[i].red = *entry_start++; + pp[i].green = *entry_start++; + pp[i].blue = *entry_start++; + pp[i].alpha = *entry_start++; + } + + else + { + pp[i].red = png_get_uint_16(entry_start); entry_start += 2; + pp[i].green = png_get_uint_16(entry_start); entry_start += 2; + pp[i].blue = png_get_uint_16(entry_start); entry_start += 2; + pp[i].alpha = png_get_uint_16(entry_start); entry_start += 2; + } + + pp[i].frequency = png_get_uint_16(entry_start); entry_start += 2; + } +#endif /* Discard all chunk data except the name and stash that */ new_palette.name = (png_charp)buffer; @@ -1688,20 +1729,34 @@ png_handle_sPLT(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) png_set_sPLT(png_ptr, info_ptr, &new_palette, 1); png_free(png_ptr, new_palette.entries); - return handled_ok; } -#else -# define png_handle_sPLT NULL -#endif /* READ_sPLT */ +#endif /* PNG_READ_sPLT_SUPPORTED */ #ifdef PNG_READ_tRNS_SUPPORTED -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte readbuf[PNG_MAX_PALETTE_LENGTH]; png_debug(1, "in png_handle_tRNS"); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tRNS)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) { png_byte buf[2]; @@ -1710,7 +1765,7 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); - return handled_error; + return; } png_crc_read(png_ptr, buf, 2); @@ -1726,7 +1781,7 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); - return handled_error; + return; } png_crc_read(png_ptr, buf, length); @@ -1738,20 +1793,20 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) else if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if ((png_ptr->mode & PNG_HAVE_PLTE) == 0) + if (!(png_ptr->mode & PNG_HAVE_PLTE)) { + /* TODO: is this actually an error in the ISO spec? */ png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of place"); - return handled_error; + return; } - if (length > (unsigned int) png_ptr->num_palette || - length > (unsigned int) PNG_MAX_PALETTE_LENGTH || + if (length > png_ptr->num_palette || length > PNG_MAX_PALETTE_LENGTH || length == 0) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); - return handled_error; + return; } png_crc_read(png_ptr, readbuf, length); @@ -1762,13 +1817,13 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid with alpha channel"); - return handled_error; + return; } - if (png_crc_finish(png_ptr, 0) != 0) + if (png_crc_finish(png_ptr, 0)) { png_ptr->num_trans = 0; - return handled_error; + return; } /* TODO: this is a horrible side effect in the palette case because the @@ -1777,14 +1832,11 @@ png_handle_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) */ png_set_tRNS(png_ptr, info_ptr, readbuf, png_ptr->num_trans, &(png_ptr->trans_color)); - return handled_ok; } -#else -# define png_handle_tRNS NULL #endif #ifdef PNG_READ_bKGD_SUPPORTED -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { unsigned int truelen; @@ -1793,19 +1845,29 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) png_debug(1, "in png_handle_bKGD"); - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) - { - if ((png_ptr->mode & PNG_HAVE_PLTE) == 0) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of place"); - return handled_error; - } + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); - truelen = 1; + else if ((png_ptr->mode & PNG_HAVE_IDAT) || + (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && + !(png_ptr->mode & PNG_HAVE_PLTE))) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; } - else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_bKGD)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) + truelen = 1; + + else if (png_ptr->color_type & PNG_COLOR_MASK_COLOR) truelen = 6; else @@ -1815,13 +1877,13 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); - return handled_error; + return; } png_crc_read(png_ptr, buf, truelen); - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; + if (png_crc_finish(png_ptr, 0)) + return; /* We convert the index value into RGB components so that we can allow * arbitrary RGB values for background when we have transparency, and @@ -1832,12 +1894,12 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { background.index = buf[0]; - if (info_ptr != NULL && info_ptr->num_palette != 0) + if (info_ptr && info_ptr->num_palette) { if (buf[0] >= info_ptr->num_palette) { png_chunk_benign_error(png_ptr, "invalid index"); - return handled_error; + return; } background.red = (png_uint_16)png_ptr->palette[buf[0]].red; @@ -1851,17 +1913,8 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) background.gray = 0; } - else if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) /* GRAY */ + else if (!(png_ptr->color_type & PNG_COLOR_MASK_COLOR)) /* GRAY */ { - if (png_ptr->bit_depth <= 8) - { - if (buf[0] != 0 || buf[1] >= (unsigned int)(1 << png_ptr->bit_depth)) - { - png_chunk_benign_error(png_ptr, "invalid gray level"); - return handled_error; - } - } - background.index = 0; background.red = background.green = @@ -1871,15 +1924,6 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) else { - if (png_ptr->bit_depth <= 8) - { - if (buf[0] != 0 || buf[2] != 0 || buf[4] != 0) - { - png_chunk_benign_error(png_ptr, "invalid color"); - return handled_error; - } - } - background.index = 0; background.red = png_get_uint_16(buf); background.green = png_get_uint_16(buf + 2); @@ -1888,174 +1932,11 @@ png_handle_bKGD(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) } png_set_bKGD(png_ptr, info_ptr, &background); - return handled_ok; } -#else -# define png_handle_bKGD NULL -#endif - -#ifdef PNG_READ_cICP_SUPPORTED -static png_handle_result_code /* PRIVATE */ -png_handle_cICP(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_byte buf[4]; - - png_debug(1, "in png_handle_cICP"); - - png_crc_read(png_ptr, buf, 4); - - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; - - png_set_cICP(png_ptr, info_ptr, buf[0], buf[1], buf[2], buf[3]); - - /* We only use 'chromaticities' for RGB to gray */ -# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - if (!png_has_chunk(png_ptr, mDCV)) - { - /* TODO: png_ptr->chromaticities = chromaticities; */ - } -# endif /* READ_RGB_TO_GRAY */ - -#ifdef PNG_READ_GAMMA_SUPPORTED - /* PNGv3: chunk precedence for gamma is cICP, [iCCP], sRGB, gAMA. cICP is - * at the head so simply set the gamma if it can be determined. If not - * chunk_gamma remains unchanged; sRGB and gAMA handling check it for - * being zero. - */ - /* TODO: set png_struct::chunk_gamma when possible */ -#endif /*READ_GAMMA*/ - - return handled_ok; - PNG_UNUSED(length) -} -#else -# define png_handle_cICP NULL -#endif - -#ifdef PNG_READ_cLLI_SUPPORTED -static png_handle_result_code /* PRIVATE */ -png_handle_cLLI(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_byte buf[8]; - - png_debug(1, "in png_handle_cLLI"); - - png_crc_read(png_ptr, buf, 8); - - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; - - /* The error checking happens here, this puts it in just one place: */ - png_set_cLLI_fixed(png_ptr, info_ptr, png_get_uint_32(buf), - png_get_uint_32(buf+4)); - return handled_ok; - PNG_UNUSED(length) -} -#else -# define png_handle_cLLI NULL -#endif - -#ifdef PNG_READ_mDCV_SUPPORTED -static png_handle_result_code /* PRIVATE */ -png_handle_mDCV(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_xy chromaticities; - png_byte buf[24]; - - png_debug(1, "in png_handle_mDCV"); - - png_crc_read(png_ptr, buf, 24); - - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; - - /* The error checking happens here, this puts it in just one place. The - * odd /50000 scaling factor makes it more difficult but the (x.y) values are - * only two bytes so a <<1 is safe. - * - * WARNING: the PNG specification defines the cHRM chunk to **start** with - * the white point (x,y). The W3C PNG v3 specification puts the white point - * **after* R,G,B. The x,y values in mDCV are also scaled by 50,000 and - * stored in just two bytes, whereas those in cHRM are scaled by 100,000 and - * stored in four bytes. This is very, very confusing. These APIs remove - * the confusion by copying the existing, well established, API. - */ - chromaticities.redx = png_get_uint_16(buf+ 0U) << 1; /* red x */ - chromaticities.redy = png_get_uint_16(buf+ 2U) << 1; /* red y */ - chromaticities.greenx = png_get_uint_16(buf+ 4U) << 1; /* green x */ - chromaticities.greeny = png_get_uint_16(buf+ 6U) << 1; /* green y */ - chromaticities.bluex = png_get_uint_16(buf+ 8U) << 1; /* blue x */ - chromaticities.bluey = png_get_uint_16(buf+10U) << 1; /* blue y */ - chromaticities.whitex = png_get_uint_16(buf+12U) << 1; /* white x */ - chromaticities.whitey = png_get_uint_16(buf+14U) << 1; /* white y */ - - png_set_mDCV_fixed(png_ptr, info_ptr, - chromaticities.whitex, chromaticities.whitey, - chromaticities.redx, chromaticities.redy, - chromaticities.greenx, chromaticities.greeny, - chromaticities.bluex, chromaticities.bluey, - png_get_uint_32(buf+16U), /* peak luminance */ - png_get_uint_32(buf+20U));/* minimum perceivable luminance */ - - /* We only use 'chromaticities' for RGB to gray */ -# ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - png_ptr->chromaticities = chromaticities; -# endif /* READ_RGB_TO_GRAY */ - - return handled_ok; - PNG_UNUSED(length) -} -#else -# define png_handle_mDCV NULL -#endif - -#ifdef PNG_READ_eXIf_SUPPORTED -static png_handle_result_code /* PRIVATE */ -png_handle_eXIf(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - png_bytep buffer = NULL; - - png_debug(1, "in png_handle_eXIf"); - - buffer = png_read_buffer(png_ptr, length); - - if (buffer == NULL) - { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of memory"); - return handled_error; - } - - png_crc_read(png_ptr, buffer, length); - - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; - - /* PNGv3: the code used to check the byte order mark at the start for MM or - * II, however PNGv3 states that the the first 4 bytes should be checked. - * The caller ensures that there are four bytes available. - */ - { - png_uint_32 header = png_get_uint_32(buffer); - - /* These numbers are copied from the PNGv3 spec: */ - if (header != 0x49492A00 && header != 0x4D4D002A) - { - png_chunk_benign_error(png_ptr, "invalid"); - return handled_error; - } - } - - png_set_eXIf_1(png_ptr, info_ptr, length, buffer); - return handled_ok; -} -#else -# define png_handle_eXIf NULL #endif #ifdef PNG_READ_hIST_SUPPORTED -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { unsigned int num, i; @@ -2063,21 +1944,30 @@ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) png_debug(1, "in png_handle_hIST"); - /* This cast is safe because the chunk definition limits the length to a - * maximum of 1024 bytes. - * - * TODO: maybe use png_uint_32 anyway, not unsigned int, to reduce the - * casts. - */ - num = (unsigned int)length / 2 ; + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); - if (length != num * 2 || - num != (unsigned int)png_ptr->num_palette || - num > (unsigned int)PNG_MAX_PALETTE_LENGTH) + else if ((png_ptr->mode & PNG_HAVE_IDAT) || !(png_ptr->mode & PNG_HAVE_PLTE)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_hIST)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + num = length / 2 ; + + if (num != png_ptr->num_palette || num > PNG_MAX_PALETTE_LENGTH) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "invalid"); - return handled_error; + return; } for (i = 0; i < num; i++) @@ -2088,18 +1978,15 @@ png_handle_hIST(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) readbuf[i] = png_get_uint_16(buf); } - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; + if (png_crc_finish(png_ptr, 0)) + return; png_set_hIST(png_ptr, info_ptr, readbuf); - return handled_ok; } -#else -# define png_handle_hIST NULL #endif #ifdef PNG_READ_pHYs_SUPPORTED -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[9]; @@ -2108,24 +1995,44 @@ png_handle_pHYs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) png_debug(1, "in png_handle_pHYs"); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pHYs)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (length != 9) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + png_crc_read(png_ptr, buf, 9); - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; + if (png_crc_finish(png_ptr, 0)) + return; res_x = png_get_uint_32(buf); res_y = png_get_uint_32(buf + 4); unit_type = buf[8]; png_set_pHYs(png_ptr, info_ptr, res_x, res_y, unit_type); - return handled_ok; - PNG_UNUSED(length) } -#else -# define png_handle_pHYs NULL #endif #ifdef PNG_READ_oFFs_SUPPORTED -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[9]; @@ -2134,25 +2041,45 @@ png_handle_oFFs(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) png_debug(1, "in png_handle_oFFs"); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_oFFs)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (length != 9) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + png_crc_read(png_ptr, buf, 9); - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; + if (png_crc_finish(png_ptr, 0)) + return; offset_x = png_get_int_32(buf); offset_y = png_get_int_32(buf + 4); unit_type = buf[8]; png_set_oFFs(png_ptr, info_ptr, offset_x, offset_y, unit_type); - return handled_ok; - PNG_UNUSED(length) } -#else -# define png_handle_oFFs NULL #endif #ifdef PNG_READ_pCAL_SUPPORTED /* Read the pCAL chunk (described in the PNG Extensions document) */ -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_int_32 X0, X1; @@ -2162,22 +2089,40 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) int i; png_debug(1, "in png_handle_pCAL"); + + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_pCAL)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + png_debug1(2, "Allocating and reading pCAL chunk data (%u bytes)", length + 1); - buffer = png_read_buffer(png_ptr, length+1); + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); if (buffer == NULL) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of memory"); - return handled_error; + return; } png_crc_read(png_ptr, buffer, length); - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; + if (png_crc_finish(png_ptr, 0)) + return; buffer[length] = 0; /* Null terminate the last string */ @@ -2190,10 +2135,10 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* We need to have at least 12 bytes after the purpose string * in order to get the parameter information. */ - if (endptr - buf <= 12) + if (endptr <= buf + 12) { png_chunk_benign_error(png_ptr, "invalid"); - return handled_error; + return; } png_debug(3, "Reading pCAL X0, X1, type, nparams, and units"); @@ -2213,7 +2158,7 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) (type == PNG_EQUATION_HYPERBOLIC && nparams != 4)) { png_chunk_benign_error(png_ptr, "invalid parameter count"); - return handled_error; + return; } else if (type >= PNG_EQUATION_LAST) @@ -2232,7 +2177,7 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) if (params == NULL) { png_chunk_benign_error(png_ptr, "out of memory"); - return handled_error; + return; } /* Get pointers to the start of each parameter string. */ @@ -2250,59 +2195,76 @@ png_handle_pCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_free(png_ptr, params); png_chunk_benign_error(png_ptr, "invalid data"); - return handled_error; + return; } } png_set_pCAL(png_ptr, info_ptr, (png_charp)buffer, X0, X1, type, nparams, - (png_charp)units, params); + (png_charp)units, params); - /* TODO: BUG: png_set_pCAL calls png_chunk_report which, in this case, calls - * png_benign_error and that can error out. - * - * png_read_buffer needs to be allocated with space for both nparams and the - * parameter strings. Not hard to do. - */ png_free(png_ptr, params); - return handled_ok; } -#else -# define png_handle_pCAL NULL #endif #ifdef PNG_READ_sCAL_SUPPORTED /* Read the sCAL chunk */ -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_bytep buffer; - size_t i; + png_size_t i; int state; png_debug(1, "in png_handle_sCAL"); - png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)", - length + 1); - buffer = png_read_buffer(png_ptr, length+1); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (png_ptr->mode & PNG_HAVE_IDAT) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "out of place"); + return; + } + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_sCAL)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + /* Need unit type, width, \0, height: minimum 4 bytes */ + else if (length < 4) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + + png_debug1(2, "Allocating and reading sCAL chunk data (%u bytes)", + length + 1); + + buffer = png_read_buffer(png_ptr, length+1, 2/*silent*/); if (buffer == NULL) { - png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of memory"); - return handled_error; + png_crc_finish(png_ptr, length); + return; } png_crc_read(png_ptr, buffer, length); buffer[length] = 0; /* Null terminate the last string */ - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; + if (png_crc_finish(png_ptr, 0)) + return; /* Validate the unit. */ if (buffer[0] != 1 && buffer[0] != 2) { png_chunk_benign_error(png_ptr, "invalid unit"); - return handled_error; + return; } /* Validate the ASCII numbers, need two ASCII numbers separated by @@ -2311,42 +2273,35 @@ png_handle_sCAL(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) i = 1; state = 0; - if (png_check_fp_number((png_const_charp)buffer, length, &state, &i) == 0 || + if (!png_check_fp_number((png_const_charp)buffer, length, &state, &i) || i >= length || buffer[i++] != 0) png_chunk_benign_error(png_ptr, "bad width format"); - else if (PNG_FP_IS_POSITIVE(state) == 0) + else if (!PNG_FP_IS_POSITIVE(state)) png_chunk_benign_error(png_ptr, "non-positive width"); else { - size_t heighti = i; + png_size_t heighti = i; state = 0; - if (png_check_fp_number((png_const_charp)buffer, length, - &state, &i) == 0 || i != length) + if (!png_check_fp_number((png_const_charp)buffer, length, &state, &i) || + i != length) png_chunk_benign_error(png_ptr, "bad height format"); - else if (PNG_FP_IS_POSITIVE(state) == 0) + else if (!PNG_FP_IS_POSITIVE(state)) png_chunk_benign_error(png_ptr, "non-positive height"); else - { /* This is the (only) success case. */ png_set_sCAL_s(png_ptr, info_ptr, buffer[0], - (png_charp)buffer+1, (png_charp)buffer+heighti); - return handled_ok; - } + (png_charp)buffer+1, (png_charp)buffer+heighti); } - - return handled_error; } -#else -# define png_handle_sCAL NULL #endif #ifdef PNG_READ_tIME_SUPPORTED -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_byte buf[7]; @@ -2354,17 +2309,30 @@ png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) png_debug(1, "in png_handle_tIME"); - /* TODO: what is this doing here? It should be happened in pngread.c and - * pngpread.c, although it could be moved to png_handle_chunk below and - * thereby avoid some code duplication. - */ - if ((png_ptr->mode & PNG_HAVE_IDAT) != 0) + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + else if (info_ptr != NULL && (info_ptr->valid & PNG_INFO_tIME)) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "duplicate"); + return; + } + + if (png_ptr->mode & PNG_HAVE_IDAT) png_ptr->mode |= PNG_AFTER_IDAT; + if (length != 7) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "invalid"); + return; + } + png_crc_read(png_ptr, buf, 7); - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; + if (png_crc_finish(png_ptr, 0)) + return; mod_time.second = buf[6]; mod_time.minute = buf[5]; @@ -2374,19 +2342,15 @@ png_handle_tIME(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) mod_time.year = png_get_uint_16(buf); png_set_tIME(png_ptr, info_ptr, &mod_time); - return handled_ok; - PNG_UNUSED(length) } -#else -# define png_handle_tIME NULL #endif #ifdef PNG_READ_tEXt_SUPPORTED /* Note: this does not properly handle chunks that are > 64K under DOS */ -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { - png_text text_info; + png_text text_info; png_bytep buffer; png_charp key; png_charp text; @@ -2400,31 +2364,45 @@ png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) if (png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); - return handled_error; + return; } if (--png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "no space in chunk cache"); - return handled_error; + return; } } #endif - buffer = png_read_buffer(png_ptr, length+1); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + +#ifdef PNG_MAX_MALLOC_64K + if (length > 65535U) + { + png_crc_finish(png_ptr, length); + png_chunk_benign_error(png_ptr, "too large to fit in memory"); + return; + } +#endif + + buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); if (buffer == NULL) { - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, "out of memory"); - return handled_error; + png_chunk_benign_error(png_ptr, "out of memory"); + return; } png_crc_read(png_ptr, buffer, length); - if (png_crc_finish(png_ptr, skip) != 0) - return handled_error; + if (png_crc_finish(png_ptr, skip)) + return; key = (png_charp)buffer; key[length] = 0; @@ -2443,24 +2421,19 @@ png_handle_tEXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) text_info.text = text; text_info.text_length = strlen(text); - if (png_set_text_2(png_ptr, info_ptr, &text_info, 1) == 0) - return handled_ok; - - png_chunk_benign_error(png_ptr, "out of memory"); - return handled_error; + if (png_set_text_2(png_ptr, info_ptr, &text_info, 1)) + png_warning(png_ptr, "Insufficient memory to process text chunk"); } -#else -# define png_handle_tEXt NULL #endif #ifdef PNG_READ_zTXt_SUPPORTED /* Note: this does not correctly handle chunks that are > 64K under DOS */ -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_const_charp errmsg = NULL; - png_bytep buffer; - png_uint_32 keyword_length; + png_bytep buffer; + png_uint_32 keyword_length; png_debug(1, "in png_handle_zTXt"); @@ -2470,35 +2443,37 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) if (png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); - return handled_error; + return; } if (--png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "no space in chunk cache"); - return handled_error; + return; } } #endif - /* Note, "length" is sufficient here; we won't be adding - * a null terminator later. The limit check in png_handle_chunk should be - * sufficient. - */ - buffer = png_read_buffer(png_ptr, length); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + + buffer = png_read_buffer(png_ptr, length, 2/*silent*/); if (buffer == NULL) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of memory"); - return handled_error; + return; } png_crc_read(png_ptr, buffer, length); - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; + if (png_crc_finish(png_ptr, 0)) + return; /* TODO: also check that the keyword contents match the spec! */ for (keyword_length = 0; @@ -2528,50 +2503,41 @@ png_handle_zTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) * and text chunks. */ if (png_decompress_chunk(png_ptr, length, keyword_length+2, - &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) { png_text text; - if (png_ptr->read_buffer == NULL) - errmsg="Read failure in png_handle_zTXt"; - else - { - /* It worked; png_ptr->read_buffer now looks like a tEXt chunk - * except for the extra compression type byte and the fact that - * it isn't necessarily '\0' terminated. - */ - buffer = png_ptr->read_buffer; - buffer[uncompressed_length+(keyword_length+2)] = 0; + /* It worked; png_ptr->read_buffer now looks like a tEXt chunk except + * for the extra compression type byte and the fact that it isn't + * necessarily '\0' terminated. + */ + buffer = png_ptr->read_buffer; + buffer[uncompressed_length+(keyword_length+2)] = 0; - text.compression = PNG_TEXT_COMPRESSION_zTXt; - text.key = (png_charp)buffer; - text.text = (png_charp)(buffer + keyword_length+2); - text.text_length = uncompressed_length; - text.itxt_length = 0; - text.lang = NULL; - text.lang_key = NULL; + text.compression = PNG_TEXT_COMPRESSION_zTXt; + text.key = (png_charp)buffer; + text.text = (png_charp)(buffer + keyword_length+2); + text.text_length = uncompressed_length; + text.itxt_length = 0; + text.lang = NULL; + text.lang_key = NULL; - if (png_set_text_2(png_ptr, info_ptr, &text, 1) == 0) - return handled_ok; - - errmsg = "out of memory"; - } + if (png_set_text_2(png_ptr, info_ptr, &text, 1)) + errmsg = "insufficient memory"; } else errmsg = png_ptr->zstream.msg; } - png_chunk_benign_error(png_ptr, errmsg); - return handled_error; + if (errmsg != NULL) + png_chunk_benign_error(png_ptr, errmsg); } -#else -# define png_handle_zTXt NULL #endif #ifdef PNG_READ_iTXt_SUPPORTED /* Note: this does not correctly handle chunks that are > 64K under DOS */ -static png_handle_result_code /* PRIVATE */ +void /* PRIVATE */ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) { png_const_charp errmsg = NULL; @@ -2586,31 +2552,37 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) if (png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); - return handled_error; + return; } if (--png_ptr->user_chunk_cache_max == 1) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "no space in chunk cache"); - return handled_error; + return; } } #endif - buffer = png_read_buffer(png_ptr, length+1); + if (!(png_ptr->mode & PNG_HAVE_IHDR)) + png_chunk_error(png_ptr, "missing IHDR"); + + if (png_ptr->mode & PNG_HAVE_IDAT) + png_ptr->mode |= PNG_AFTER_IDAT; + + buffer = png_read_buffer(png_ptr, length+1, 1/*warn*/); if (buffer == NULL) { png_crc_finish(png_ptr, length); png_chunk_benign_error(png_ptr, "out of memory"); - return handled_error; + return; } png_crc_read(png_ptr, buffer, length); - if (png_crc_finish(png_ptr, 0) != 0) - return handled_error; + if (png_crc_finish(png_ptr, 0)) + return; /* First the keyword. */ for (prefix_length=0; @@ -2655,14 +2627,14 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) /* prefix_length should now be at the trailing '\0' of the translated * keyword, but it may already be over the end. None of this arithmetic * can overflow because chunks are at most 2^31 bytes long, but on 16-bit - * systems the available allocation may overflow. + * systems the available allocaton may overflow. */ ++prefix_length; - if (compressed == 0 && prefix_length <= length) + if (!compressed && prefix_length <= length) uncompressed_length = length - prefix_length; - else if (compressed != 0 && prefix_length < length) + else if (compressed && prefix_length < length) { uncompressed_length = PNG_SIZE_MAX; @@ -2671,7 +2643,7 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) * iCCP and text chunks. */ if (png_decompress_chunk(png_ptr, length, prefix_length, - &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) + &uncompressed_length, 1/*terminate*/) == Z_STREAM_END) buffer = png_ptr->read_buffer; else @@ -2687,7 +2659,7 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) buffer[uncompressed_length+prefix_length] = 0; - if (compressed == 0) + if (compressed) text.compression = PNG_ITXT_COMPRESSION_NONE; else @@ -2700,10 +2672,8 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) text.text_length = 0; text.itxt_length = uncompressed_length; - if (png_set_text_2(png_ptr, info_ptr, &text, 1) == 0) - return handled_ok; - - errmsg = "out of memory"; + if (png_set_text_2(png_ptr, info_ptr, &text, 1)) + errmsg = "insufficient memory"; } } @@ -2712,10 +2682,7 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) if (errmsg != NULL) png_chunk_benign_error(png_ptr, errmsg); - return handled_error; } -#else -# define png_handle_iTXt NULL #endif #ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED @@ -2723,7 +2690,7 @@ png_handle_iTXt(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) static int png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length) { - const png_alloc_size_t limit = png_chunk_max(png_ptr); + png_alloc_size_t limit = PNG_SIZE_MAX; if (png_ptr->unknown_chunk.data != NULL) { @@ -2731,11 +2698,21 @@ png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length) png_ptr->unknown_chunk.data = NULL; } +# ifdef PNG_SET_CHUNK_MALLOC_LIMIT_SUPPORTED + if (png_ptr->user_chunk_malloc_max > 0 && + png_ptr->user_chunk_malloc_max < limit) + limit = png_ptr->user_chunk_malloc_max; + +# elif PNG_USER_CHUNK_MALLOC_MAX > 0 + if (PNG_USER_CHUNK_MALLOC_MAX < limit) + limit = PNG_USER_CHUNK_MALLOC_MAX; +# endif + if (length <= limit) { PNG_CSTRING_FROM_CHUNK(png_ptr->unknown_chunk.name, png_ptr->chunk_name); /* The following is safe because of the PNG_SIZE_MAX init above */ - png_ptr->unknown_chunk.size = (size_t)length/*SAFE*/; + png_ptr->unknown_chunk.size = (png_size_t)length/*SAFE*/; /* 'mode' is a flag array, only the bottom four bits matter here */ png_ptr->unknown_chunk.location = (png_byte)png_ptr->mode/*SAFE*/; @@ -2746,7 +2723,7 @@ png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length) { /* Do a 'warn' here - it is handled below. */ png_ptr->unknown_chunk.data = png_voidcast(png_bytep, - png_malloc_warn(png_ptr, length)); + png_malloc_warn(png_ptr, length)); } } @@ -2766,14 +2743,14 @@ png_cache_unknown_chunk(png_structrp png_ptr, png_uint_32 length) return 1; } } -#endif /* READ_UNKNOWN_CHUNKS */ +#endif /* PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ /* Handle an unknown, or known but disabled, chunk */ -png_handle_result_code /*PRIVATE*/ +void /* PRIVATE */ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, - png_uint_32 length, int keep) + png_uint_32 length, int keep) { - png_handle_result_code handled = handled_discarded; /* the default */ + int handled = 0; /* the chunk was handled */ png_debug(1, "in png_handle_unknown"); @@ -2791,7 +2768,7 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, */ # ifndef PNG_HANDLE_AS_UNKNOWN_SUPPORTED # ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED - keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name); + keep = png_chunk_unknown_handling(png_ptr, png_ptr->chunk_name); # endif # endif @@ -2800,153 +2777,154 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, * PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) */ # ifdef PNG_READ_USER_CHUNKS_SUPPORTED - /* The user callback takes precedence over the chunk keep value, but the - * keep value is still required to validate a save of a critical chunk. - */ - if (png_ptr->read_user_chunk_fn != NULL) - { - if (png_cache_unknown_chunk(png_ptr, length) != 0) + /* The user callback takes precedence over the chunk keep value, but the + * keep value is still required to validate a save of a critical chunk. + */ + if (png_ptr->read_user_chunk_fn != NULL) { - /* Callback to user unknown chunk handler */ - int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr, - &png_ptr->unknown_chunk); - - /* ret is: - * negative: An error occurred; png_chunk_error will be called. - * zero: The chunk was not handled, the chunk will be discarded - * unless png_set_keep_unknown_chunks has been used to set - * a 'keep' behavior for this particular chunk, in which - * case that will be used. A critical chunk will cause an - * error at this point unless it is to be saved. - * positive: The chunk was handled, libpng will ignore/discard it. - */ - if (ret < 0) /* handled_error */ - png_chunk_error(png_ptr, "error in user chunk"); - - else if (ret == 0) + if (png_cache_unknown_chunk(png_ptr, length)) { - /* If the keep value is 'default' or 'never' override it, but - * still error out on critical chunks unless the keep value is - * 'always' While this is weird it is the behavior in 1.4.12. - * A possible improvement would be to obey the value set for the - * chunk, but this would be an API change that would probably - * damage some applications. - * - * The png_app_warning below catches the case that matters, where - * the application has not set specific save or ignore for this - * chunk or global save or ignore. + /* Callback to user unknown chunk handler */ + int ret = (*(png_ptr->read_user_chunk_fn))(png_ptr, + &png_ptr->unknown_chunk); + + /* ret is: + * negative: An error occured, png_chunk_error will be called. + * zero: The chunk was not handled, the chunk will be discarded + * unless png_set_keep_unknown_chunks has been used to set + * a 'keep' behavior for this particular chunk, in which + * case that will be used. A critical chunk will cause an + * error at this point unless it is to be saved. + * positive: The chunk was handled, libpng will ignore/discard it. */ - if (keep < PNG_HANDLE_CHUNK_IF_SAFE) + if (ret < 0) + png_chunk_error(png_ptr, "error in user chunk"); + + else if (ret == 0) { -# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED - if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE) + /* If the keep value is 'default' or 'never' override it, but + * still error out on critical chunks unless the keep value is + * 'always' While this is weird it is the behavior in 1.4.12. + * A possible improvement would be to obey the value set for the + * chunk, but this would be an API change that would probably + * damage some applications. + * + * The png_app_warning below catches the case that matters, where + * the application has not set specific save or ignore for this + * chunk or global save or ignore. + */ + if (keep < PNG_HANDLE_CHUNK_IF_SAFE) { - png_chunk_warning(png_ptr, "Saving unknown chunk:"); - png_app_warning(png_ptr, - "forcing save of an unhandled chunk;" - " please call png_set_keep_unknown_chunks"); - /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */ +# ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED + if (png_ptr->unknown_default < PNG_HANDLE_CHUNK_IF_SAFE) + { + png_chunk_warning(png_ptr, "Saving unknown chunk:"); + png_app_warning(png_ptr, + "forcing save of an unhandled chunk;" + " please call png_set_keep_unknown_chunks"); + /* with keep = PNG_HANDLE_CHUNK_IF_SAFE */ + } +# endif + keep = PNG_HANDLE_CHUNK_IF_SAFE; } -# endif - keep = PNG_HANDLE_CHUNK_IF_SAFE; + } + + else /* chunk was handled */ + { + handled = 1; + /* Critical chunks can be safely discarded at this point. */ + keep = PNG_HANDLE_CHUNK_NEVER; } } - else /* chunk was handled */ - { - handled = handled_ok; - /* Critical chunks can be safely discarded at this point. */ - keep = PNG_HANDLE_CHUNK_NEVER; - } + else + keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */ } else - keep = PNG_HANDLE_CHUNK_NEVER; /* insufficient memory */ - } - - else - /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */ -# endif /* READ_USER_CHUNKS */ + /* Use the SAVE_UNKNOWN_CHUNKS code or skip the chunk */ +# endif /* PNG_READ_USER_CHUNKS_SUPPORTED */ # ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED - { - /* keep is currently just the per-chunk setting, if there was no - * setting change it to the global default now (not that this may - * still be AS_DEFAULT) then obtain the cache of the chunk if required, - * if not simply skip the chunk. - */ - if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) - keep = png_ptr->unknown_default; - - if (keep == PNG_HANDLE_CHUNK_ALWAYS || - (keep == PNG_HANDLE_CHUNK_IF_SAFE && - PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) { - if (png_cache_unknown_chunk(png_ptr, length) == 0) - keep = PNG_HANDLE_CHUNK_NEVER; - } + /* keep is currently just the per-chunk setting, if there was no + * setting change it to the global default now (not that this may + * still be AS_DEFAULT) then obtain the cache of the chunk if required, + * if not simply skip the chunk. + */ + if (keep == PNG_HANDLE_CHUNK_AS_DEFAULT) + keep = png_ptr->unknown_default; - else - png_crc_finish(png_ptr, length); - } + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) + { + if (!png_cache_unknown_chunk(png_ptr, length)) + keep = PNG_HANDLE_CHUNK_NEVER; + } + + else + png_crc_finish(png_ptr, length); + } # else # ifndef PNG_READ_USER_CHUNKS_SUPPORTED # error no method to support READ_UNKNOWN_CHUNKS # endif - { - /* If here there is no read callback pointer set and no support is - * compiled in to just save the unknown chunks, so simply skip this - * chunk. If 'keep' is something other than AS_DEFAULT or NEVER then - * the app has erroneously asked for unknown chunk saving when there - * is no support. - */ - if (keep > PNG_HANDLE_CHUNK_NEVER) - png_app_error(png_ptr, "no unknown chunk support available"); + { + /* If here there is no read callback pointer set and no support is + * compiled in to just save the unknown chunks, so simply skip this + * chunk. If 'keep' is something other than AS_DEFAULT or NEVER then + * the app has erroneously asked for unknown chunk saving when there + * is no support. + */ + if (keep > PNG_HANDLE_CHUNK_NEVER) + png_app_error(png_ptr, "no unknown chunk support available"); - png_crc_finish(png_ptr, length); - } + png_crc_finish(png_ptr, length); + } # endif # ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED - /* Now store the chunk in the chunk list if appropriate, and if the limits - * permit it. - */ - if (keep == PNG_HANDLE_CHUNK_ALWAYS || - (keep == PNG_HANDLE_CHUNK_IF_SAFE && - PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) - { -# ifdef PNG_USER_LIMITS_SUPPORTED - switch (png_ptr->user_chunk_cache_max) + /* Now store the chunk in the chunk list if appropriate, and if the limits + * permit it. + */ + if (keep == PNG_HANDLE_CHUNK_ALWAYS || + (keep == PNG_HANDLE_CHUNK_IF_SAFE && + PNG_CHUNK_ANCILLARY(png_ptr->chunk_name))) { - case 2: - png_ptr->user_chunk_cache_max = 1; - png_chunk_benign_error(png_ptr, "no space in chunk cache"); - /* FALLTHROUGH */ - case 1: - /* NOTE: prior to 1.6.0 this case resulted in an unknown critical - * chunk being skipped, now there will be a hard error below. - */ - break; +# ifdef PNG_USER_LIMITS_SUPPORTED + switch (png_ptr->user_chunk_cache_max) + { + case 2: + png_ptr->user_chunk_cache_max = 1; + png_chunk_benign_error(png_ptr, "no space in chunk cache"); + /* FALL THROUGH */ + case 1: + /* NOTE: prior to 1.6.0 this case resulted in an unknown critical + * chunk being skipped, now there will be a hard error below. + */ + break; - default: /* not at limit */ - --(png_ptr->user_chunk_cache_max); - /* FALLTHROUGH */ - case 0: /* no limit */ -# endif /* USER_LIMITS */ - /* Here when the limit isn't reached or when limits are compiled - * out; store the chunk. - */ - png_set_unknown_chunks(png_ptr, info_ptr, - &png_ptr->unknown_chunk, 1); - handled = handled_saved; -# ifdef PNG_USER_LIMITS_SUPPORTED - break; + default: /* not at limit */ + --(png_ptr->user_chunk_cache_max); + /* FALL THROUGH */ + case 0: /* no limit */ +# endif /* PNG_USER_LIMITS_SUPPORTED */ + /* Here when the limit isn't reached or when limits are compiled + * out; store the chunk. + */ + png_set_unknown_chunks(png_ptr, info_ptr, + &png_ptr->unknown_chunk, 1); + handled = 1; +# ifdef PNG_USER_LIMITS_SUPPORTED + break; + } +# endif } -# endif - } -# else /* no store support: the chunk must be handled by the user callback */ - PNG_UNUSED(info_ptr) +# else /* no store support! */ + PNG_UNUSED(info_ptr) +# error untested code (reading unknown chunks with no store support) # endif /* Regardless of the error handling below the cached data (if any) can be @@ -2962,272 +2940,43 @@ png_handle_unknown(png_structrp png_ptr, png_inforp info_ptr, png_crc_finish(png_ptr, length); PNG_UNUSED(info_ptr) PNG_UNUSED(keep) -#endif /* !READ_UNKNOWN_CHUNKS */ +#endif /* !PNG_READ_UNKNOWN_CHUNKS_SUPPORTED */ /* Check for unhandled critical chunks */ - if (handled < handled_saved && PNG_CHUNK_CRITICAL(png_ptr->chunk_name)) + if (!handled && PNG_CHUNK_CRITICAL(png_ptr->chunk_name)) png_chunk_error(png_ptr, "unhandled critical chunk"); - - return handled; } -/* APNG handling: the minimal implementation of APNG handling in libpng 1.6 - * requires that those significant applications which already handle APNG not - * get hosed. To do this ensure the code here will have to ensure than APNG - * data by default (at least in 1.6) gets stored in the unknown chunk list. - * Maybe this can be relaxed in a few years but at present it's just the only - * safe way. - * - * ATM just cause unknown handling for all three chunks: +/* This function is called to verify that a chunk name is valid. + * This function can't have the "critical chunk check" incorporated + * into it, since in the future we will need to be able to call user + * functions to handle unknown critical chunks after we check that + * the chunk name itself is valid. */ -#define png_handle_acTL NULL -#define png_handle_fcTL NULL -#define png_handle_fdAT NULL -/* - * 1.6.47: This is the new table driven interface to all the chunk handling. +/* Bit hacking: the test for an invalid byte in the 4 byte chunk name is: * - * The table describes the PNG standard rules for **reading** known chunks - - * every chunk which has an entry in PNG_KNOWN_CHUNKS. The table contains an - * entry for each PNG_INDEX_cHNK describing the rules. - * - * In this initial version the only information in the entry is the - * png_handle_cHNK function for the chunk in question. When chunk support is - * compiled out the entry will be NULL. + * ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97)) */ -static const struct + +void /* PRIVATE */ +png_check_chunk_name(png_structrp png_ptr, png_uint_32 chunk_name) { - png_handle_result_code (*handler)( - png_structrp, png_inforp, png_uint_32 length); - /* A chunk-specific 'handler', NULL if the chunk is not supported in this - * build. - */ + int i; - /* Crushing these values helps on modern 32-bit architectures because the - * pointer and the following bit fields both end up requiring 32 bits. - * Typically this will halve the table size. On 64-bit architectures the - * table entries will typically be 8 bytes. - */ - png_uint_32 max_length :12; /* Length min, max in bytes */ - png_uint_32 min_length :8; - /* Length errors on critical chunks have special handling to preserve the - * existing behaviour in libpng 1.6. Anciallary chunks are checked below - * and produce a 'benign' error. - */ - png_uint_32 pos_before :4; /* PNG_HAVE_ values chunk must precede */ - png_uint_32 pos_after :4; /* PNG_HAVE_ values chunk must follow */ - /* NOTE: PLTE, tRNS and bKGD require special handling which depends on - * the colour type of the base image. - */ - png_uint_32 multiple :1; /* Multiple occurences permitted */ - /* This is enabled for PLTE because PLTE may, in practice, be optional */ -} -read_chunks[PNG_INDEX_unknown] = -{ - /* Definitions as above but done indirectly by #define so that - * PNG_KNOWN_CHUNKS can be used safely to build the table in order. - * - * Each CDcHNK definition lists the values for the parameters **after** - * the first, 'handler', function. 'handler' is NULL when the chunk has no - * compiled in support. - */ -# define NoCheck 0x801U /* Do not check the maximum length */ -# define Limit 0x802U /* Limit to png_chunk_max bytes */ -# define LKMin 3U+LZ77Min /* Minimum length of keyword+LZ77 */ + png_debug(1, "in png_check_chunk_name"); -#define hIHDR PNG_HAVE_IHDR -#define hPLTE PNG_HAVE_PLTE -#define hIDAT PNG_HAVE_IDAT - /* For the two chunks, tRNS and bKGD which can occur in PNGs without a PLTE - * but must occur after the PLTE use this and put the check in the handler - * routine for colour mapped images were PLTE is required. Also put a check - * in PLTE for other image types to drop the PLTE if tRNS or bKGD have been - * seen. - */ -#define hCOL (PNG_HAVE_PLTE|PNG_HAVE_IDAT) - /* Used for the decoding chunks which must be before PLTE. */ -#define aIDAT PNG_AFTER_IDAT - - /* Chunks from W3C PNG v3: */ - /* cHNK max_len, min, before, after, multiple */ -# define CDIHDR 13U, 13U, hIHDR, 0, 0 -# define CDPLTE NoCheck, 0U, 0, hIHDR, 1 - /* PLTE errors are only critical for colour-map images, consequently the - * hander does all the checks. - */ -# define CDIDAT NoCheck, 0U, aIDAT, hIHDR, 1 -# define CDIEND NoCheck, 0U, 0, aIDAT, 0 - /* Historically data was allowed in IEND */ -# define CDtRNS 256U, 0U, hIDAT, hIHDR, 0 -# define CDcHRM 32U, 32U, hCOL, hIHDR, 0 -# define CDgAMA 4U, 4U, hCOL, hIHDR, 0 -# define CDiCCP NoCheck, LKMin, hCOL, hIHDR, 0 -# define CDsBIT 4U, 1U, hCOL, hIHDR, 0 -# define CDsRGB 1U, 1U, hCOL, hIHDR, 0 -# define CDcICP 4U, 4U, hCOL, hIHDR, 0 -# define CDmDCV 24U, 24U, hCOL, hIHDR, 0 -# define CDeXIf Limit, 4U, 0, hIHDR, 0 -# define CDcLLI 8U, 8U, hCOL, hIHDR, 0 -# define CDtEXt NoCheck, 2U, 0, hIHDR, 1 - /* Allocates 'length+1'; checked in the handler */ -# define CDzTXt Limit, LKMin, 0, hIHDR, 1 -# define CDiTXt NoCheck, 6U, 0, hIHDR, 1 - /* Allocates 'length+1'; checked in the handler */ -# define CDbKGD 6U, 1U, hIDAT, hIHDR, 0 -# define CDhIST 1024U, 0U, hPLTE, hIHDR, 0 -# define CDpHYs 9U, 9U, hIDAT, hIHDR, 0 -# define CDsPLT NoCheck, 3U, hIDAT, hIHDR, 1 - /* Allocates 'length+1'; checked in the handler */ -# define CDtIME 7U, 7U, 0, hIHDR, 0 -# define CDacTL 8U, 8U, hIDAT, hIHDR, 0 -# define CDfcTL 25U, 26U, 0, hIHDR, 1 -# define CDfdAT Limit, 4U, hIDAT, hIHDR, 1 - /* Supported chunks from PNG extensions 1.5.0, NYI so limit */ -# define CDoFFs 9U, 9U, hIDAT, hIHDR, 0 -# define CDpCAL NoCheck, 14U, hIDAT, hIHDR, 0 - /* Allocates 'length+1'; checked in the handler */ -# define CDsCAL Limit, 4U, hIDAT, hIHDR, 0 - /* Allocates 'length+1'; checked in the handler */ - -# define PNG_CHUNK(cHNK, index) { png_handle_ ## cHNK, CD ## cHNK }, - PNG_KNOWN_CHUNKS -# undef PNG_CHUNK -}; - - -static png_index -png_chunk_index_from_name(png_uint_32 chunk_name) -{ - /* For chunk png_cHNK return PNG_INDEX_cHNK. Return PNG_INDEX_unknown if - * chunk_name is not known. Notice that in a particular build "known" does - * not necessarily mean "supported", although the inverse applies. - */ - switch (chunk_name) + for (i=1; i<=4; ++i) { -# define PNG_CHUNK(cHNK, index)\ - case png_ ## cHNK: return PNG_INDEX_ ## cHNK; /* == index */ + int c = chunk_name & 0xff; - PNG_KNOWN_CHUNKS + if (c < 65 || c > 122 || (c > 90 && c < 97)) + png_chunk_error(png_ptr, "invalid chunk type"); -# undef PNG_CHUNK - - default: return PNG_INDEX_unknown; + chunk_name >>= 8; } } -png_handle_result_code /*PRIVATE*/ -png_handle_chunk(png_structrp png_ptr, png_inforp info_ptr, png_uint_32 length) -{ - /* CSE: these things don't change, these autos are just to save typing and - * make the code more clear. - */ - const png_uint_32 chunk_name = png_ptr->chunk_name; - const png_index chunk_index = png_chunk_index_from_name(chunk_name); - - png_handle_result_code handled = handled_error; - png_const_charp errmsg = NULL; - - /* Is this a known chunk? If not there are no checks performed here; - * png_handle_unknown does the correct checks. This means that the values - * for known but unsupported chunks in the above table are not used here - * however the chunks_seen fields in png_struct are still set. - */ - if (chunk_index == PNG_INDEX_unknown || - read_chunks[chunk_index].handler == NULL) - { - handled = png_handle_unknown( - png_ptr, info_ptr, length, PNG_HANDLE_CHUNK_AS_DEFAULT); - } - - /* First check the position. The first check is historical; the stream must - * start with IHDR and anything else causes libpng to give up immediately. - */ - else if (chunk_index != PNG_INDEX_IHDR && - (png_ptr->mode & PNG_HAVE_IHDR) == 0) - png_chunk_error(png_ptr, "missing IHDR"); /* NORETURN */ - - /* Before all the pos_before chunks, after all the pos_after chunks. */ - else if (((png_ptr->mode & read_chunks[chunk_index].pos_before) != 0) || - ((png_ptr->mode & read_chunks[chunk_index].pos_after) != - read_chunks[chunk_index].pos_after)) - { - errmsg = "out of place"; - } - - /* Now check for duplicates: duplicated critical chunks also produce a - * full error. - */ - else if (read_chunks[chunk_index].multiple == 0 && - png_file_has_chunk(png_ptr, chunk_index)) - { - errmsg = "duplicate"; - } - - else if (length < read_chunks[chunk_index].min_length) - errmsg = "too short"; - else - { - /* NOTE: apart from IHDR the critical chunks (PLTE, IDAT and IEND) are set - * up above not to do any length checks. - * - * The png_chunk_max check ensures that the variable length chunks are - * always checked at this point for being within the system allocation - * limits. - */ - unsigned max_length = read_chunks[chunk_index].max_length; - - switch (max_length) - { - case Limit: - /* png_read_chunk_header has already png_error'ed chunks with a - * length exceeding the 31-bit PNG limit, so just check the memory - * limit: - */ - if (length <= png_chunk_max(png_ptr)) - goto MeetsLimit; - - errmsg = "length exceeds libpng limit"; - break; - - default: - if (length <= max_length) - goto MeetsLimit; - - errmsg = "too long"; - break; - - case NoCheck: - MeetsLimit: - handled = read_chunks[chunk_index].handler( - png_ptr, info_ptr, length); - break; - } - } - - /* If there was an error or the chunk was simply skipped it is not counted as - * 'seen'. - */ - if (errmsg != NULL) - { - if (PNG_CHUNK_CRITICAL(chunk_name)) /* stop immediately */ - png_chunk_error(png_ptr, errmsg); - else /* ancillary chunk */ - { - /* The chunk data is skipped: */ - png_crc_finish(png_ptr, length); - png_chunk_benign_error(png_ptr, errmsg); - } - } - - else if (handled >= handled_saved) - { - if (chunk_index != PNG_INDEX_unknown) - png_file_add_chunk(png_ptr, chunk_index); - } - - return handled; -} - /* Combines the row recently read in with the existing pixels in the row. This * routine takes care of alpha and transparency if requested. This routine also * handles the two methods of progressive display of interlaced images, @@ -3240,7 +2989,7 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) { unsigned int pixel_depth = png_ptr->transformed_pixel_depth; png_const_bytep sp = png_ptr->row_buf + 1; - png_alloc_size_t row_width = png_ptr->width; + png_uint_32 row_width = png_ptr->width; unsigned int pass = png_ptr->pass; png_bytep end_ptr = 0; png_byte end_byte = 0; @@ -3277,13 +3026,12 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) end_ptr = dp + PNG_ROWBYTES(pixel_depth, row_width) - 1; end_byte = *end_ptr; # ifdef PNG_READ_PACKSWAP_SUPPORTED - if ((png_ptr->transformations & PNG_PACKSWAP) != 0) - /* little-endian byte */ - end_mask = (unsigned int)(0xff << end_mask); + if (png_ptr->transformations & PNG_PACKSWAP) /* little-endian byte */ + end_mask = 0xff << end_mask; - else /* big-endian byte */ + else /* big-endian byte */ # endif - end_mask = 0xff >> end_mask; + end_mask = 0xff >> end_mask; /* end_mask is now the bits to *keep* from the destination row */ } @@ -3294,11 +3042,10 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) * pass. */ #ifdef PNG_READ_INTERLACING_SUPPORTED - if (png_ptr->interlaced != 0 && - (png_ptr->transformations & PNG_INTERLACE) != 0 && - pass < 6 && (display == 0 || - /* The following copies everything for 'display' on passes 0, 2 and 4. */ - (display == 1 && (pass & 1) != 0))) + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE) && + pass < 6 && (display == 0 || + /* The following copies everything for 'display' on passes 0, 2 and 4. */ + (display == 1 && (pass & 1) != 0))) { /* Narrow images may have no bits in a pass; the caller should handle * this, but this test is cheap: @@ -3394,14 +3141,14 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) # define S_MASKS(d,s) { S_MASK(0,d,s), S_MASK(1,d,s), S_MASK(2,d,s),\ S_MASK(3,d,s), S_MASK(4,d,s), S_MASK(5,d,s) } -# define B_MASKS(d,s) { B_MASK(1,d,s), B_MASK(3,d,s), B_MASK(5,d,s) } +# define B_MASKS(d,s) { B_MASK(1,d,s), S_MASK(3,d,s), S_MASK(5,d,s) } # define DEPTH_INDEX(d) ((d)==1?0:((d)==2?1:2)) /* Hence the pre-compiled masks indexed by PACKSWAP (or not), depth and * then pass: */ - static const png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] = + static PNG_CONST png_uint_32 row_mask[2/*PACKSWAP*/][3/*depth*/][6] = { /* Little-endian byte masks for PACKSWAP */ { S_MASKS(1,0), S_MASKS(2,0), S_MASKS(4,0) }, @@ -3412,7 +3159,7 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) /* display_mask has only three entries for the odd passes, so index by * pass>>1. */ - static const png_uint_32 display_mask[2][3][3] = + static PNG_CONST png_uint_32 display_mask[2][3][3] = { /* Little-endian byte masks for PACKSWAP */ { B_MASKS(1,0), B_MASKS(2,0), B_MASKS(4,0) }, @@ -3430,10 +3177,10 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) */ # define MASK(pass,depth,display,png)\ ((display)?B_MASK(pass,depth,png):S_MASK(pass,depth,png)) -#endif /* !USE_COMPILE_TIME_MASKS */ +#endif /* !PNG_USE_COMPILE_TIME_MASKS */ /* Use the appropriate mask to copy the required bits. In some cases - * the byte mask will be 0 or 0xff; optimize these cases. row_width is + * the byte mask will be 0 or 0xff, optimize these cases. row_width is * the number of pixels, but the code copies bytes, so it is necessary * to special case the end. */ @@ -3441,12 +3188,12 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) png_uint_32 mask; # ifdef PNG_READ_PACKSWAP_SUPPORTED - if ((png_ptr->transformations & PNG_PACKSWAP) != 0) - mask = MASK(pass, pixel_depth, display, 0); + if (png_ptr->transformations & PNG_PACKSWAP) + mask = MASK(pass, pixel_depth, display, 0); - else + else # endif - mask = MASK(pass, pixel_depth, display, 1); + mask = MASK(pass, pixel_depth, display, 1); for (;;) { @@ -3505,7 +3252,7 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) } /* Work out the bytes to copy. */ - if (display != 0) + if (display) { /* When doing the 'block' algorithm the pixel in the pass gets * replicated to adjacent pixels. This is why the even (0,2,4,6) @@ -3515,7 +3262,7 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) /* But don't allow this number to exceed the actual row width. */ if (bytes_to_copy > row_width) - bytes_to_copy = (unsigned int)/*SAFE*/row_width; + bytes_to_copy = row_width; } else /* normal row; Adam7 only ever gives us one pixel to copy. */ @@ -3553,7 +3300,7 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) */ do { - dp[0] = sp[0]; dp[1] = sp[1]; + dp[0] = sp[0], dp[1] = sp[1]; if (row_width <= bytes_to_jump) return; @@ -3572,9 +3319,9 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) /* This can only be the RGB case, so each copy is exactly one * pixel and it is not necessary to check for a partial copy. */ - for (;;) + for(;;) { - dp[0] = sp[0]; dp[1] = sp[1]; dp[2] = sp[2]; + dp[0] = sp[0], dp[1] = sp[1], dp[2] = sp[2]; if (row_width <= bytes_to_jump) return; @@ -3592,24 +3339,24 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) * wide bytes_to_copy either - use the memcpy there. */ if (bytes_to_copy < 16 /*else use memcpy*/ && - png_isaligned(dp, png_uint_16) && - png_isaligned(sp, png_uint_16) && - bytes_to_copy % (sizeof (png_uint_16)) == 0 && - bytes_to_jump % (sizeof (png_uint_16)) == 0) + png_isaligned(dp, png_uint_16) && + png_isaligned(sp, png_uint_16) && + bytes_to_copy % (sizeof (png_uint_16)) == 0 && + bytes_to_jump % (sizeof (png_uint_16)) == 0) { /* Everything is aligned for png_uint_16 copies, but try for * png_uint_32 first. */ if (png_isaligned(dp, png_uint_32) && - png_isaligned(sp, png_uint_32) && - bytes_to_copy % (sizeof (png_uint_32)) == 0 && - bytes_to_jump % (sizeof (png_uint_32)) == 0) + png_isaligned(sp, png_uint_32) && + bytes_to_copy % (sizeof (png_uint_32)) == 0 && + bytes_to_jump % (sizeof (png_uint_32)) == 0) { png_uint_32p dp32 = png_aligncast(png_uint_32p,dp); png_const_uint_32p sp32 = png_aligncastconst( - png_const_uint_32p, sp); + png_const_uint_32p, sp); size_t skip = (bytes_to_jump-bytes_to_copy) / - (sizeof (png_uint_32)); + (sizeof (png_uint_32)); do { @@ -3681,7 +3428,7 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) return; } } -#endif /* ALIGN_TYPE code */ +#endif /* PNG_ALIGN_ code */ /* The true default - use a memcpy: */ for (;;) @@ -3695,7 +3442,7 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) dp += bytes_to_jump; row_width -= bytes_to_jump; if (bytes_to_copy > row_width) - bytes_to_copy = (unsigned int)/*SAFE*/row_width; + bytes_to_copy = row_width; } } @@ -3705,7 +3452,7 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) /* Here if pixel_depth < 8 to check 'end_ptr' below. */ } else -#endif /* READ_INTERLACING */ +#endif /* If here then the switch above wasn't used so just memcpy the whole row * from the temporary row buffer (notice that this overwrites the end of the @@ -3721,8 +3468,12 @@ png_combine_row(png_const_structrp png_ptr, png_bytep dp, int display) #ifdef PNG_READ_INTERLACING_SUPPORTED void /* PRIVATE */ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, - png_uint_32 transformations /* Because these may affect the byte layout */) + png_uint_32 transformations /* Because these may affect the byte layout */) { + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + /* Offset to next interlace block */ + static PNG_CONST int png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + png_debug(1, "in png_do_read_interlace"); if (row != NULL && row_info != NULL) { @@ -3734,21 +3485,20 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, { case 1: { - png_bytep sp = row + (size_t)((row_info->width - 1) >> 3); - png_bytep dp = row + (size_t)((final_width - 1) >> 3); - unsigned int sshift, dshift; - unsigned int s_start, s_end; - int s_inc; - int jstop = (int)png_pass_inc[pass]; + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 3); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 3); + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; png_byte v; png_uint_32 i; int j; #ifdef PNG_READ_PACKSWAP_SUPPORTED - if ((transformations & PNG_PACKSWAP) != 0) + if (transformations & PNG_PACKSWAP) { - sshift = ((row_info->width + 7) & 0x07); - dshift = ((final_width + 7) & 0x07); + sshift = (int)((row_info->width + 7) & 0x07); + dshift = (int)((final_width + 7) & 0x07); s_start = 7; s_end = 0; s_inc = -1; @@ -3757,8 +3507,8 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, else #endif { - sshift = 7 - ((row_info->width + 7) & 0x07); - dshift = 7 - ((final_width + 7) & 0x07); + sshift = 7 - (int)((row_info->width + 7) & 0x07); + dshift = 7 - (int)((final_width + 7) & 0x07); s_start = 0; s_end = 7; s_inc = 1; @@ -3770,7 +3520,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, for (j = 0; j < jstop; j++) { unsigned int tmp = *dp & (0x7f7f >> (7 - dshift)); - tmp |= (unsigned int)(v << dshift); + tmp |= v << dshift; *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) @@ -3780,7 +3530,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, } else - dshift = (unsigned int)((int)dshift + s_inc); + dshift += s_inc; } if (sshift == s_end) @@ -3790,7 +3540,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, } else - sshift = (unsigned int)((int)sshift + s_inc); + sshift += s_inc; } break; } @@ -3799,17 +3549,16 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, { png_bytep sp = row + (png_uint_32)((row_info->width - 1) >> 2); png_bytep dp = row + (png_uint_32)((final_width - 1) >> 2); - unsigned int sshift, dshift; - unsigned int s_start, s_end; - int s_inc; - int jstop = (int)png_pass_inc[pass]; + int sshift, dshift; + int s_start, s_end, s_inc; + int jstop = png_pass_inc[pass]; png_uint_32 i; #ifdef PNG_READ_PACKSWAP_SUPPORTED - if ((transformations & PNG_PACKSWAP) != 0) + if (transformations & PNG_PACKSWAP) { - sshift = (((row_info->width + 3) & 0x03) << 1); - dshift = (((final_width + 3) & 0x03) << 1); + sshift = (int)(((row_info->width + 3) & 0x03) << 1); + dshift = (int)(((final_width + 3) & 0x03) << 1); s_start = 6; s_end = 0; s_inc = -2; @@ -3818,8 +3567,8 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, else #endif { - sshift = ((3 - ((row_info->width + 3) & 0x03)) << 1); - dshift = ((3 - ((final_width + 3) & 0x03)) << 1); + sshift = (int)((3 - ((row_info->width + 3) & 0x03)) << 1); + dshift = (int)((3 - ((final_width + 3) & 0x03)) << 1); s_start = 0; s_end = 6; s_inc = 2; @@ -3834,7 +3583,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, for (j = 0; j < jstop; j++) { unsigned int tmp = *dp & (0x3f3f >> (6 - dshift)); - tmp |= (unsigned int)(v << dshift); + tmp |= v << dshift; *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) @@ -3844,7 +3593,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, } else - dshift = (unsigned int)((int)dshift + s_inc); + dshift += s_inc; } if (sshift == s_end) @@ -3854,26 +3603,25 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, } else - sshift = (unsigned int)((int)sshift + s_inc); + sshift += s_inc; } break; } case 4: { - png_bytep sp = row + (size_t)((row_info->width - 1) >> 1); - png_bytep dp = row + (size_t)((final_width - 1) >> 1); - unsigned int sshift, dshift; - unsigned int s_start, s_end; - int s_inc; + png_bytep sp = row + (png_size_t)((row_info->width - 1) >> 1); + png_bytep dp = row + (png_size_t)((final_width - 1) >> 1); + int sshift, dshift; + int s_start, s_end, s_inc; png_uint_32 i; - int jstop = (int)png_pass_inc[pass]; + int jstop = png_pass_inc[pass]; #ifdef PNG_READ_PACKSWAP_SUPPORTED - if ((transformations & PNG_PACKSWAP) != 0) + if (transformations & PNG_PACKSWAP) { - sshift = (((row_info->width + 1) & 0x01) << 2); - dshift = (((final_width + 1) & 0x01) << 2); + sshift = (int)(((row_info->width + 1) & 0x01) << 2); + dshift = (int)(((final_width + 1) & 0x01) << 2); s_start = 4; s_end = 0; s_inc = -4; @@ -3882,8 +3630,8 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, else #endif { - sshift = ((1 - ((row_info->width + 1) & 0x01)) << 2); - dshift = ((1 - ((final_width + 1) & 0x01)) << 2); + sshift = (int)((1 - ((row_info->width + 1) & 0x01)) << 2); + dshift = (int)((1 - ((final_width + 1) & 0x01)) << 2); s_start = 0; s_end = 4; s_inc = 4; @@ -3897,7 +3645,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, for (j = 0; j < jstop; j++) { unsigned int tmp = *dp & (0xf0f >> (4 - dshift)); - tmp |= (unsigned int)(v << dshift); + tmp |= v << dshift; *dp = (png_byte)(tmp & 0xff); if (dshift == s_end) @@ -3907,7 +3655,7 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, } else - dshift = (unsigned int)((int)dshift + s_inc); + dshift += s_inc; } if (sshift == s_end) @@ -3917,26 +3665,26 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, } else - sshift = (unsigned int)((int)sshift + s_inc); + sshift += s_inc; } break; } default: { - size_t pixel_bytes = (row_info->pixel_depth >> 3); + png_size_t pixel_bytes = (row_info->pixel_depth >> 3); - png_bytep sp = row + (size_t)(row_info->width - 1) + png_bytep sp = row + (png_size_t)(row_info->width - 1) * pixel_bytes; - png_bytep dp = row + (size_t)(final_width - 1) * pixel_bytes; + png_bytep dp = row + (png_size_t)(final_width - 1) * pixel_bytes; - int jstop = (int)png_pass_inc[pass]; + int jstop = png_pass_inc[pass]; png_uint_32 i; for (i = 0; i < row_info->width; i++) { - png_byte v[8]; /* SAFE; pixel_depth does not exceed 64 */ + png_byte v[8]; int j; memcpy(v, sp, pixel_bytes); @@ -3960,14 +3708,14 @@ png_do_read_interlace(png_row_infop row_info, png_bytep row, int pass, PNG_UNUSED(transformations) /* Silence compiler warning */ #endif } -#endif /* READ_INTERLACING */ +#endif /* PNG_READ_INTERLACING_SUPPORTED */ static void png_read_filter_row_sub(png_row_infop row_info, png_bytep row, - png_const_bytep prev_row) + png_const_bytep prev_row) { - size_t i; - size_t istop = row_info->rowbytes; + png_size_t i; + png_size_t istop = row_info->rowbytes; unsigned int bpp = (row_info->pixel_depth + 7) >> 3; png_bytep rp = row + bpp; @@ -3982,10 +3730,10 @@ png_read_filter_row_sub(png_row_infop row_info, png_bytep row, static void png_read_filter_row_up(png_row_infop row_info, png_bytep row, - png_const_bytep prev_row) + png_const_bytep prev_row) { - size_t i; - size_t istop = row_info->rowbytes; + png_size_t i; + png_size_t istop = row_info->rowbytes; png_bytep rp = row; png_const_bytep pp = prev_row; @@ -3998,13 +3746,13 @@ png_read_filter_row_up(png_row_infop row_info, png_bytep row, static void png_read_filter_row_avg(png_row_infop row_info, png_bytep row, - png_const_bytep prev_row) + png_const_bytep prev_row) { - size_t i; + png_size_t i; png_bytep rp = row; png_const_bytep pp = prev_row; unsigned int bpp = (row_info->pixel_depth + 7) >> 3; - size_t istop = row_info->rowbytes - bpp; + png_size_t istop = row_info->rowbytes - bpp; for (i = 0; i < bpp; i++) { @@ -4025,7 +3773,7 @@ png_read_filter_row_avg(png_row_infop row_info, png_bytep row, static void png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row, - png_const_bytep prev_row) + png_const_bytep prev_row) { png_bytep rp_end = row + row_info->rowbytes; int a, c; @@ -4046,23 +3794,20 @@ png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row, p = b - c; pc = a - c; -#ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -#else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -#endif +# ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +# else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +# endif /* Find the best predictor, the least of pa, pb, pc favoring the earlier * ones in the case of a tie. */ - if (pb < pa) - { - pa = pb; a = b; - } + if (pb < pa) pa = pb, a = b; if (pc < pa) a = c; /* Calculate the current pixel in a, and move the previous row pixel to c @@ -4076,9 +3821,9 @@ png_read_filter_row_paeth_1byte_pixel(png_row_infop row_info, png_bytep row, static void png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row, - png_const_bytep prev_row) + png_const_bytep prev_row) { - unsigned int bpp = (row_info->pixel_depth + 7) >> 3; + int bpp = (row_info->pixel_depth + 7) >> 3; png_bytep rp_end = row + bpp; /* Process the first pixel in the row completely (this is the same as 'up' @@ -4091,7 +3836,7 @@ png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row, } /* Remainder */ - rp_end = rp_end + (row_info->rowbytes - bpp); + rp_end += row_info->rowbytes - bpp; while (row < rp_end) { @@ -4104,22 +3849,20 @@ png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row, p = b - c; pc = a - c; -#ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -#else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -#endif +# ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +# else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +# endif - if (pb < pa) - { - pa = pb; a = b; - } + if (pb < pa) pa = pb, a = b; if (pc < pa) a = c; + c = b; a += *row; *row++ = (png_byte)a; } @@ -4127,8 +3870,7 @@ png_read_filter_row_paeth_multibyte_pixel(png_row_infop row_info, png_bytep row, static void png_init_filter_functions(png_structrp pp) - /* This function is called once for every PNG image (except for PNG images - * that only use PNG_FILTER_VALUE_NONE for all rows) to set the + /* This function is called once for every PNG image to set the * implementations required to reverse the filtering of PNG rows. Reversing * the filter is the first transformation performed on the row data. It is * performed in place, therefore an implementation can be selected based on @@ -4164,25 +3906,22 @@ png_init_filter_functions(png_structrp pp) void /* PRIVATE */ png_read_filter_row(png_structrp pp, png_row_infop row_info, png_bytep row, - png_const_bytep prev_row, int filter) + png_const_bytep prev_row, int filter) { /* OPTIMIZATION: DO NOT MODIFY THIS FUNCTION, instead #define * PNG_FILTER_OPTIMIZATIONS to a function that overrides the generic * implementations. See png_init_filter_functions above. */ + if (pp->read_filter[0] == NULL) + png_init_filter_functions(pp); if (filter > PNG_FILTER_VALUE_NONE && filter < PNG_FILTER_VALUE_LAST) - { - if (pp->read_filter[0] == NULL) - png_init_filter_functions(pp); - pp->read_filter[filter-1](row_info, row, prev_row); - } } #ifdef PNG_SEQUENTIAL_READ_SUPPORTED void /* PRIVATE */ png_read_IDAT_data(png_structrp png_ptr, png_bytep output, - png_alloc_size_t avail_out) + png_alloc_size_t avail_out) { /* Loop reading IDATs and decompressing the result into output[avail_out] */ png_ptr->zstream.next_out = output; @@ -4215,9 +3954,6 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output, avail_in = png_ptr->IDAT_read_size; - if (avail_in > png_chunk_max(png_ptr)) - avail_in = (uInt)/*SAFE*/png_chunk_max(png_ptr); - if (avail_in > png_ptr->idat_size) avail_in = (uInt)png_ptr->idat_size; @@ -4225,13 +3961,8 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output, * to minimize memory usage by causing lots of re-allocs, but * realistically doing IDAT_read_size re-allocs is not likely to be a * big problem. - * - * An error here corresponds to the system being out of memory. */ - buffer = png_read_buffer(png_ptr, avail_in); - - if (buffer == NULL) - png_chunk_error(png_ptr, "out of memory"); + buffer = png_read_buffer(png_ptr, avail_in, 0/*error*/); png_crc_read(png_ptr, buffer, avail_in); png_ptr->idat_size -= avail_in; @@ -4265,7 +3996,7 @@ png_read_IDAT_data(png_structrp png_ptr, png_bytep output, * * TODO: deal more elegantly with truncated IDAT lists. */ - ret = PNG_INFLATE(png_ptr, Z_NO_FLUSH); + ret = inflate(&png_ptr->zstream, Z_NO_FLUSH); /* Take the unconsumed output back. */ if (output != NULL) @@ -4325,7 +4056,7 @@ png_read_finish_IDAT(png_structrp png_ptr) * read it otherwise stray unread IDAT data or, more likely, an IDAT chunk * may still remain to be consumed. */ - if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) { /* The NULL causes png_read_IDAT_data to swallow any remaining bytes in * the compressed stream, but the stream may be damaged too, so even after @@ -4337,7 +4068,7 @@ png_read_finish_IDAT(png_structrp png_ptr) /* Now clear everything out for safety; the following may not have been * done. */ - if ((png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED) == 0) + if (!(png_ptr->flags & PNG_FLAG_ZSTREAM_ENDED)) { png_ptr->mode |= PNG_AFTER_IDAT; png_ptr->flags |= PNG_FLAG_ZSTREAM_ENDED; @@ -4368,12 +4099,29 @@ png_read_finish_IDAT(png_structrp png_ptr) void /* PRIVATE */ png_read_finish_row(png_structrp png_ptr) { +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif /* PNG_READ_INTERLACING_SUPPORTED */ + png_debug(1, "in png_read_finish_row"); png_ptr->row_number++; if (png_ptr->row_number < png_ptr->num_rows) return; - if (png_ptr->interlaced != 0) +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced) { png_ptr->row_number = 0; @@ -4394,7 +4142,7 @@ png_read_finish_row(png_structrp png_ptr) png_pass_start[png_ptr->pass]) / png_pass_inc[png_ptr->pass]; - if ((png_ptr->transformations & PNG_INTERLACE) == 0) + if (!(png_ptr->transformations & PNG_INTERLACE)) { png_ptr->num_rows = (png_ptr->height + png_pass_yinc[png_ptr->pass] - 1 - @@ -4410,26 +4158,44 @@ png_read_finish_row(png_structrp png_ptr) if (png_ptr->pass < 7) return; } +#endif /* PNG_READ_INTERLACING_SUPPORTED */ /* Here after at the end of the last row of the last pass. */ png_read_finish_IDAT(png_ptr); } -#endif /* SEQUENTIAL_READ */ +#endif /* PNG_SEQUENTIAL_READ_SUPPORTED */ void /* PRIVATE */ png_read_start_row(png_structrp png_ptr) { - unsigned int max_pixel_depth; - size_t row_bytes; +#ifdef PNG_READ_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + + int max_pixel_depth; + png_size_t row_bytes; png_debug(1, "in png_read_start_row"); #ifdef PNG_READ_TRANSFORMS_SUPPORTED png_init_read_transformations(png_ptr); #endif - if (png_ptr->interlaced != 0) +#ifdef PNG_READ_INTERLACING_SUPPORTED + if (png_ptr->interlaced) { - if ((png_ptr->transformations & PNG_INTERLACE) == 0) + if (!(png_ptr->transformations & PNG_INTERLACE)) png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - png_pass_ystart[0]) / png_pass_yinc[0]; @@ -4443,14 +4209,15 @@ png_read_start_row(png_structrp png_ptr) } else +#endif /* PNG_READ_INTERLACING_SUPPORTED */ { png_ptr->num_rows = png_ptr->height; png_ptr->iwidth = png_ptr->width; } - max_pixel_depth = (unsigned int)png_ptr->pixel_depth; + max_pixel_depth = png_ptr->pixel_depth; - /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpler set of + /* WARNING: * png_read_transform_info (pngrtran.c) performs a simpliar set of * calculations to calculate the final pixel depth, then * png_do_read_transforms actually does the transforms. This means that the * code which effectively calculates this value is actually repeated in three @@ -4461,16 +4228,16 @@ png_read_start_row(png_structrp png_ptr) * TODO: fix this. */ #ifdef PNG_READ_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) != 0 && png_ptr->bit_depth < 8) + if ((png_ptr->transformations & PNG_PACK) && png_ptr->bit_depth < 8) max_pixel_depth = 8; #endif #ifdef PNG_READ_EXPAND_SUPPORTED - if ((png_ptr->transformations & PNG_EXPAND) != 0) + if (png_ptr->transformations & PNG_EXPAND) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - if (png_ptr->num_trans != 0) + if (png_ptr->num_trans) max_pixel_depth = 32; else @@ -4482,13 +4249,13 @@ png_read_start_row(png_structrp png_ptr) if (max_pixel_depth < 8) max_pixel_depth = 8; - if (png_ptr->num_trans != 0) + if (png_ptr->num_trans) max_pixel_depth *= 2; } else if (png_ptr->color_type == PNG_COLOR_TYPE_RGB) { - if (png_ptr->num_trans != 0) + if (png_ptr->num_trans) { max_pixel_depth *= 4; max_pixel_depth /= 3; @@ -4498,25 +4265,25 @@ png_read_start_row(png_structrp png_ptr) #endif #ifdef PNG_READ_EXPAND_16_SUPPORTED - if ((png_ptr->transformations & PNG_EXPAND_16) != 0) + if (png_ptr->transformations & PNG_EXPAND_16) { -# ifdef PNG_READ_EXPAND_SUPPORTED - /* In fact it is an error if it isn't supported, but checking is - * the safe way. - */ - if ((png_ptr->transformations & PNG_EXPAND) != 0) - { - if (png_ptr->bit_depth < 16) - max_pixel_depth *= 2; - } - else -# endif - png_ptr->transformations &= ~PNG_EXPAND_16; +# ifdef PNG_READ_EXPAND_SUPPORTED + /* In fact it is an error if it isn't supported, but checking is + * the safe way. + */ + if (png_ptr->transformations & PNG_EXPAND) + { + if (png_ptr->bit_depth < 16) + max_pixel_depth *= 2; + } + else +# endif + png_ptr->transformations &= ~PNG_EXPAND_16; } #endif #ifdef PNG_READ_FILLER_SUPPORTED - if ((png_ptr->transformations & (PNG_FILLER)) != 0) + if (png_ptr->transformations & (PNG_FILLER)) { if (png_ptr->color_type == PNG_COLOR_TYPE_GRAY) { @@ -4540,15 +4307,14 @@ png_read_start_row(png_structrp png_ptr) #endif #ifdef PNG_READ_GRAY_TO_RGB_SUPPORTED - if ((png_ptr->transformations & PNG_GRAY_TO_RGB) != 0) + if (png_ptr->transformations & PNG_GRAY_TO_RGB) { if ( #ifdef PNG_READ_EXPAND_SUPPORTED - (png_ptr->num_trans != 0 && - (png_ptr->transformations & PNG_EXPAND) != 0) || + (png_ptr->num_trans && (png_ptr->transformations & PNG_EXPAND)) || #endif #ifdef PNG_READ_FILLER_SUPPORTED - (png_ptr->transformations & (PNG_FILLER)) != 0 || + (png_ptr->transformations & (PNG_FILLER)) || #endif png_ptr->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) { @@ -4581,9 +4347,9 @@ png_read_start_row(png_structrp png_ptr) #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) && \ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) - if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) + if (png_ptr->transformations & PNG_USER_TRANSFORM) { - unsigned int user_pixel_depth = png_ptr->user_transform_depth * + int user_pixel_depth = png_ptr->user_transform_depth * png_ptr->user_transform_channels; if (user_pixel_depth > max_pixel_depth) @@ -4605,7 +4371,7 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) * for safety's sake */ row_bytes = PNG_ROWBYTES(max_pixel_depth, row_bytes) + - 1 + ((max_pixel_depth + 7) >> 3U); + 1 + ((max_pixel_depth + 7) >> 3); #ifdef PNG_MAX_MALLOC_64K if (row_bytes > (png_uint_32)65536L) @@ -4614,41 +4380,42 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) if (row_bytes + 48 > png_ptr->old_big_row_buf_size) { - png_free(png_ptr, png_ptr->big_row_buf); - png_free(png_ptr, png_ptr->big_prev_row); + png_free(png_ptr, png_ptr->big_row_buf); + png_free(png_ptr, png_ptr->big_prev_row); - if (png_ptr->interlaced != 0) - png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, - row_bytes + 48); + if (png_ptr->interlaced) + png_ptr->big_row_buf = (png_bytep)png_calloc(png_ptr, + row_bytes + 48); - else - png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48); + else + png_ptr->big_row_buf = (png_bytep)png_malloc(png_ptr, row_bytes + 48); - png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48); + png_ptr->big_prev_row = (png_bytep)png_malloc(png_ptr, row_bytes + 48); #ifdef PNG_ALIGNED_MEMORY_SUPPORTED - /* Use 16-byte aligned memory for row_buf with at least 16 bytes - * of padding before and after row_buf; treat prev_row similarly. - * NOTE: the alignment is to the start of the pixels, one beyond the start - * of the buffer, because of the filter byte. Prior to libpng 1.5.6 this - * was incorrect; the filter byte was aligned, which had the exact - * opposite effect of that intended. - */ - { - png_bytep temp = png_ptr->big_row_buf + 32; - size_t extra = (size_t)temp & 0x0f; - png_ptr->row_buf = temp - extra - 1/*filter byte*/; + /* Use 16-byte aligned memory for row_buf with at least 16 bytes + * of padding before and after row_buf; treat prev_row similarly. + * NOTE: the alignment is to the start of the pixels, one beyond the start + * of the buffer, because of the filter byte. Prior to libpng 1.5.6 this + * was incorrect; the filter byte was aligned, which had the exact + * opposite effect of that intended. + */ + { + png_bytep temp = png_ptr->big_row_buf + 32; + int extra = (int)((temp - (png_bytep)0) & 0x0f); + png_ptr->row_buf = temp - extra - 1/*filter byte*/; + + temp = png_ptr->big_prev_row + 32; + extra = (int)((temp - (png_bytep)0) & 0x0f); + png_ptr->prev_row = temp - extra - 1/*filter byte*/; + } - temp = png_ptr->big_prev_row + 32; - extra = (size_t)temp & 0x0f; - png_ptr->prev_row = temp - extra - 1/*filter byte*/; - } #else - /* Use 31 bytes of padding before and 17 bytes after row_buf. */ - png_ptr->row_buf = png_ptr->big_row_buf + 31; - png_ptr->prev_row = png_ptr->big_prev_row + 31; + /* Use 31 bytes of padding before and 17 bytes after row_buf. */ + png_ptr->row_buf = png_ptr->big_row_buf + 31; + png_ptr->prev_row = png_ptr->big_prev_row + 31; #endif - png_ptr->old_big_row_buf_size = row_bytes + 48; + png_ptr->old_big_row_buf_size = row_bytes + 48; } #ifdef PNG_MAX_MALLOC_64K @@ -4673,7 +4440,7 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) * does not, so free the read buffer now regardless; the sequential reader * reallocates it on demand. */ - if (png_ptr->read_buffer != NULL) + if (png_ptr->read_buffer) { png_bytep buffer = png_ptr->read_buffer; @@ -4687,9 +4454,9 @@ defined(PNG_USER_TRANSFORM_PTR_SUPPORTED) * IDAT stream has a bogus deflate header window_bits value, but this should * not be happening any longer!) */ - if (png_inflate_claim(png_ptr, png_IDAT) != Z_OK) + if (png_inflate_claim(png_ptr, png_IDAT, 0) != Z_OK) png_error(png_ptr, png_ptr->zstream.msg); png_ptr->flags |= PNG_FLAG_ROW_INIT; } -#endif /* READ */ +#endif /* PNG_READ_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pngset.c b/Windows_Libs/Dev/Render/libpng/pngset.c index 3e63c27..fcb0779 100644 --- a/Windows_Libs/Dev/Render/libpng/pngset.c +++ b/Windows_Libs/Dev/Render/libpng/pngset.c @@ -1,9 +1,10 @@ + /* pngset.c - storage of image information into info struct * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -41,21 +42,27 @@ png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr, png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, png_fixed_point blue_x, png_fixed_point blue_y) { + png_xy xy; + png_debug1(1, "in %s storage function", "cHRM fixed"); if (png_ptr == NULL || info_ptr == NULL) return; - info_ptr->cHRM.redx = red_x; - info_ptr->cHRM.redy = red_y; - info_ptr->cHRM.greenx = green_x; - info_ptr->cHRM.greeny = green_y; - info_ptr->cHRM.bluex = blue_x; - info_ptr->cHRM.bluey = blue_y; - info_ptr->cHRM.whitex = white_x; - info_ptr->cHRM.whitey = white_y; + xy.redx = red_x; + xy.redy = red_y; + xy.greenx = green_x; + xy.greeny = green_y; + xy.bluex = blue_x; + xy.bluey = blue_y; + xy.whitex = white_x; + xy.whitey = white_y; - info_ptr->valid |= PNG_INFO_cHRM; + if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy, + 2/* override with app values*/)) + info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; + + png_colorspace_sync_info(png_ptr, info_ptr); } void PNGFAPI @@ -67,7 +74,6 @@ png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr, png_fixed_point int_blue_Z) { png_XYZ XYZ; - png_xy xy; png_debug1(1, "in %s storage function", "cHRM XYZ fixed"); @@ -84,14 +90,10 @@ png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr, XYZ.blue_Y = int_blue_Y; XYZ.blue_Z = int_blue_Z; - if (png_xy_from_XYZ(&xy, &XYZ) == 0) - { - info_ptr->cHRM = xy; - info_ptr->valid |= PNG_INFO_cHRM; - } + if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace, &XYZ, 2)) + info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM; - else - png_app_error(png_ptr, "invalid cHRM XYZ"); + png_colorspace_sync_info(png_ptr, info_ptr); } # ifdef PNG_FLOATING_POINT_SUPPORTED @@ -101,14 +103,14 @@ png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, double green_x, double green_y, double blue_x, double blue_y) { png_set_cHRM_fixed(png_ptr, info_ptr, - png_fixed(png_ptr, white_x, "cHRM White X"), - png_fixed(png_ptr, white_y, "cHRM White Y"), - png_fixed(png_ptr, red_x, "cHRM Red X"), - png_fixed(png_ptr, red_y, "cHRM Red Y"), - png_fixed(png_ptr, green_x, "cHRM Green X"), - png_fixed(png_ptr, green_y, "cHRM Green Y"), - png_fixed(png_ptr, blue_x, "cHRM Blue X"), - png_fixed(png_ptr, blue_y, "cHRM Blue Y")); + png_fixed(png_ptr, white_x, "cHRM White X"), + png_fixed(png_ptr, white_y, "cHRM White Y"), + png_fixed(png_ptr, red_x, "cHRM Red X"), + png_fixed(png_ptr, red_y, "cHRM Red Y"), + png_fixed(png_ptr, green_x, "cHRM Green X"), + png_fixed(png_ptr, green_y, "cHRM Green Y"), + png_fixed(png_ptr, blue_x, "cHRM Blue X"), + png_fixed(png_ptr, blue_y, "cHRM Blue Y")); } void PNGAPI @@ -117,243 +119,19 @@ png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, double blue_X, double blue_Y, double blue_Z) { png_set_cHRM_XYZ_fixed(png_ptr, info_ptr, - png_fixed(png_ptr, red_X, "cHRM Red X"), - png_fixed(png_ptr, red_Y, "cHRM Red Y"), - png_fixed(png_ptr, red_Z, "cHRM Red Z"), - png_fixed(png_ptr, green_X, "cHRM Green X"), - png_fixed(png_ptr, green_Y, "cHRM Green Y"), - png_fixed(png_ptr, green_Z, "cHRM Green Z"), - png_fixed(png_ptr, blue_X, "cHRM Blue X"), - png_fixed(png_ptr, blue_Y, "cHRM Blue Y"), - png_fixed(png_ptr, blue_Z, "cHRM Blue Z")); + png_fixed(png_ptr, red_X, "cHRM Red X"), + png_fixed(png_ptr, red_Y, "cHRM Red Y"), + png_fixed(png_ptr, red_Z, "cHRM Red Z"), + png_fixed(png_ptr, green_X, "cHRM Red X"), + png_fixed(png_ptr, green_Y, "cHRM Red Y"), + png_fixed(png_ptr, green_Z, "cHRM Red Z"), + png_fixed(png_ptr, blue_X, "cHRM Red X"), + png_fixed(png_ptr, blue_Y, "cHRM Red Y"), + png_fixed(png_ptr, blue_Z, "cHRM Red Z")); } -# endif /* FLOATING_POINT */ +# endif /* PNG_FLOATING_POINT_SUPPORTED */ -#endif /* cHRM */ - -#ifdef PNG_cICP_SUPPORTED -void PNGAPI -png_set_cICP(png_const_structrp png_ptr, png_inforp info_ptr, - png_byte colour_primaries, png_byte transfer_function, - png_byte matrix_coefficients, png_byte video_full_range_flag) -{ - png_debug1(1, "in %s storage function", "cICP"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - info_ptr->cicp_colour_primaries = colour_primaries; - info_ptr->cicp_transfer_function = transfer_function; - info_ptr->cicp_matrix_coefficients = matrix_coefficients; - info_ptr->cicp_video_full_range_flag = video_full_range_flag; - - if (info_ptr->cicp_matrix_coefficients != 0) - { - png_warning(png_ptr, "Invalid cICP matrix coefficients"); - return; - } - - info_ptr->valid |= PNG_INFO_cICP; -} -#endif /* cICP */ - -#ifdef PNG_cLLI_SUPPORTED -void PNGFAPI -png_set_cLLI_fixed(png_const_structrp png_ptr, png_inforp info_ptr, - /* The values below are in cd/m2 (nits) and are scaled by 10,000; not - * 100,000 as in the case of png_fixed_point. - */ - png_uint_32 maxCLL, png_uint_32 maxFALL) -{ - png_debug1(1, "in %s storage function", "cLLI"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - /* Check the light level range: */ - if (maxCLL > 0x7FFFFFFFU || maxFALL > 0x7FFFFFFFU) - { - /* The limit is 200kcd/m2; somewhat bright but not inconceivable because - * human vision is said to run up to 100Mcd/m2. The sun is about 2Gcd/m2. - * - * The reference sRGB monitor is 80cd/m2 and the limit of PQ encoding is - * 2kcd/m2. - */ - png_chunk_report(png_ptr, "cLLI light level exceeds PNG limit", - PNG_CHUNK_WRITE_ERROR); - return; - } - - info_ptr->maxCLL = maxCLL; - info_ptr->maxFALL = maxFALL; - info_ptr->valid |= PNG_INFO_cLLI; -} - -# ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_cLLI(png_const_structrp png_ptr, png_inforp info_ptr, - double maxCLL, double maxFALL) -{ - png_set_cLLI_fixed(png_ptr, info_ptr, - png_fixed_ITU(png_ptr, maxCLL, "png_set_cLLI(maxCLL)"), - png_fixed_ITU(png_ptr, maxFALL, "png_set_cLLI(maxFALL)")); -} -# endif /* FLOATING_POINT */ -#endif /* cLLI */ - -#ifdef PNG_mDCV_SUPPORTED -static png_uint_16 -png_ITU_fixed_16(int *error, png_fixed_point v) -{ - /* Return a safe uint16_t value scaled according to the ITU H273 rules for - * 16-bit display chromaticities. Functions like the corresponding - * png_fixed() internal function with regard to errors: it's an error on - * write, a chunk_benign_error on read: See the definition of - * png_chunk_report in pngpriv.h. - */ - v /= 2; /* rounds to 0 in C: avoids insignificant arithmetic errors */ - if (v > 65535 || v < 0) - { - *error = 1; - return 0; - } - - return (png_uint_16)/*SAFE*/v; -} - -void PNGAPI -png_set_mDCV_fixed(png_const_structrp png_ptr, png_inforp info_ptr, - png_fixed_point white_x, png_fixed_point white_y, - png_fixed_point red_x, png_fixed_point red_y, - png_fixed_point green_x, png_fixed_point green_y, - png_fixed_point blue_x, png_fixed_point blue_y, - png_uint_32 maxDL, - png_uint_32 minDL) -{ - png_uint_16 rx, ry, gx, gy, bx, by, wx, wy; - int error; - - png_debug1(1, "in %s storage function", "mDCV"); - - if (png_ptr == NULL || info_ptr == NULL) - return; - - /* Check the input values to ensure they are in the expected range: */ - error = 0; - rx = png_ITU_fixed_16(&error, red_x); - ry = png_ITU_fixed_16(&error, red_y); - gx = png_ITU_fixed_16(&error, green_x); - gy = png_ITU_fixed_16(&error, green_y); - bx = png_ITU_fixed_16(&error, blue_x); - by = png_ITU_fixed_16(&error, blue_y); - wx = png_ITU_fixed_16(&error, white_x); - wy = png_ITU_fixed_16(&error, white_y); - - if (error) - { - png_chunk_report(png_ptr, - "mDCV chromaticities outside representable range", - PNG_CHUNK_WRITE_ERROR); - return; - } - - /* Check the light level range: */ - if (maxDL > 0x7FFFFFFFU || minDL > 0x7FFFFFFFU) - { - /* The limit is 200kcd/m2; somewhat bright but not inconceivable because - * human vision is said to run up to 100Mcd/m2. The sun is about 2Gcd/m2. - * - * The reference sRGB monitor is 80cd/m2 and the limit of PQ encoding is - * 2kcd/m2. - */ - png_chunk_report(png_ptr, "mDCV display light level exceeds PNG limit", - PNG_CHUNK_WRITE_ERROR); - return; - } - - /* All values are safe, the settings are accepted. - * - * IMPLEMENTATION NOTE: in practice the values can be checked and assigned - * but the result is confusing if a writing app calls png_set_mDCV more than - * once, the second time with an invalid value. This approach is more - * obviously correct at the cost of typing and a very slight machine - * overhead. - */ - info_ptr->mastering_red_x = rx; - info_ptr->mastering_red_y = ry; - info_ptr->mastering_green_x = gx; - info_ptr->mastering_green_y = gy; - info_ptr->mastering_blue_x = bx; - info_ptr->mastering_blue_y = by; - info_ptr->mastering_white_x = wx; - info_ptr->mastering_white_y = wy; - info_ptr->mastering_maxDL = maxDL; - info_ptr->mastering_minDL = minDL; - info_ptr->valid |= PNG_INFO_mDCV; -} - -# ifdef PNG_FLOATING_POINT_SUPPORTED -void PNGAPI -png_set_mDCV(png_const_structrp png_ptr, png_inforp info_ptr, - double white_x, double white_y, double red_x, double red_y, double green_x, - double green_y, double blue_x, double blue_y, - double maxDL, double minDL) -{ - png_set_mDCV_fixed(png_ptr, info_ptr, - png_fixed(png_ptr, white_x, "png_set_mDCV(white(x))"), - png_fixed(png_ptr, white_y, "png_set_mDCV(white(y))"), - png_fixed(png_ptr, red_x, "png_set_mDCV(red(x))"), - png_fixed(png_ptr, red_y, "png_set_mDCV(red(y))"), - png_fixed(png_ptr, green_x, "png_set_mDCV(green(x))"), - png_fixed(png_ptr, green_y, "png_set_mDCV(green(y))"), - png_fixed(png_ptr, blue_x, "png_set_mDCV(blue(x))"), - png_fixed(png_ptr, blue_y, "png_set_mDCV(blue(y))"), - png_fixed_ITU(png_ptr, maxDL, "png_set_mDCV(maxDL)"), - png_fixed_ITU(png_ptr, minDL, "png_set_mDCV(minDL)")); -} -# endif /* FLOATING_POINT */ -#endif /* mDCV */ - -#ifdef PNG_eXIf_SUPPORTED -void PNGAPI -png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, - png_bytep exif) -{ - png_warning(png_ptr, "png_set_eXIf does not work; use png_set_eXIf_1"); - PNG_UNUSED(info_ptr) - PNG_UNUSED(exif) -} - -void PNGAPI -png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr, - png_uint_32 num_exif, png_bytep exif) -{ - png_bytep new_exif; - - png_debug1(1, "in %s storage function", "eXIf"); - - if (png_ptr == NULL || info_ptr == NULL || - (png_ptr->mode & PNG_WROTE_eXIf) != 0) - return; - - new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif)); - - if (new_exif == NULL) - { - png_warning(png_ptr, "Insufficient memory for eXIf chunk data"); - return; - } - - memcpy(new_exif, exif, (size_t)num_exif); - - png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0); - - info_ptr->num_exif = num_exif; - info_ptr->exif = new_exif; - info_ptr->free_me |= PNG_FREE_EXIF; - info_ptr->valid |= PNG_INFO_eXIf; -} -#endif /* eXIf */ +#endif /* PNG_cHRM_SUPPORTED */ #ifdef PNG_gAMA_SUPPORTED void PNGFAPI @@ -365,8 +143,8 @@ png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr, if (png_ptr == NULL || info_ptr == NULL) return; - info_ptr->gamma = file_gamma; - info_ptr->valid |= PNG_INFO_gAMA; + png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma); + png_colorspace_sync_info(png_ptr, info_ptr); } # ifdef PNG_FLOATING_POINT_SUPPORTED @@ -414,10 +192,11 @@ png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, return; } + info_ptr->free_me |= PNG_FREE_HIST; + for (i = 0; i < info_ptr->num_palette; i++) info_ptr->hist[i] = hist[i]; - info_ptr->free_me |= PNG_FREE_HIST; info_ptr->valid |= PNG_INFO_hIST; } #endif @@ -448,18 +227,27 @@ png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr, if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) info_ptr->channels = 1; - else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) + else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR) info_ptr->channels = 3; else info_ptr->channels = 1; - if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) + if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA) info_ptr->channels++; info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); - info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); + /* Check for potential overflow */ + if (width > + (PNG_UINT_32_MAX >> 3) /* 8-byte RRGGBBAA pixels */ + - 48 /* bigrowbuf hack */ + - 1 /* filter byte */ + - 7*8 /* rounding of width to multiple of 8 pixels */ + - 8) /* extra max_pixel_depth pad */ + info_ptr->rowbytes = 0; + else + info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); } #ifdef PNG_oFFs_SUPPORTED @@ -485,13 +273,13 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, int nparams, png_const_charp units, png_charpp params) { - size_t length; + png_size_t length; int i; png_debug1(1, "in %s storage function", "pCAL"); if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL - || (nparams > 0 && params == NULL)) + || (nparams > 0 && params == NULL)) return; length = strlen(purpose) + 1; @@ -502,45 +290,28 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, /* Check that the type matches the specification. */ if (type < 0 || type > 3) - { - png_chunk_report(png_ptr, "Invalid pCAL equation type", - PNG_CHUNK_WRITE_ERROR); - return; - } + png_error(png_ptr, "Invalid pCAL equation type"); if (nparams < 0 || nparams > 255) - { - png_chunk_report(png_ptr, "Invalid pCAL parameter count", - PNG_CHUNK_WRITE_ERROR); - return; - } + png_error(png_ptr, "Invalid pCAL parameter count"); /* Validate params[nparams] */ for (i=0; ipcal_purpose = png_voidcast(png_charp, - png_malloc_warn(png_ptr, length)); + png_malloc_warn(png_ptr, length)); if (info_ptr->pcal_purpose == NULL) { - png_chunk_report(png_ptr, "Insufficient memory for pCAL purpose", - PNG_CHUNK_WRITE_ERROR); + png_warning(png_ptr, "Insufficient memory for pCAL purpose"); return; } memcpy(info_ptr->pcal_purpose, purpose, length); - info_ptr->free_me |= PNG_FREE_PCAL; - png_debug(3, "storing X0, X1, type, and nparams in info"); info_ptr->pcal_X0 = X0; info_ptr->pcal_X1 = X1; @@ -549,10 +320,10 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, length = strlen(units) + 1; png_debug1(3, "allocating units for info (%lu bytes)", - (unsigned long)length); + (unsigned long)length); info_ptr->pcal_units = png_voidcast(png_charp, - png_malloc_warn(png_ptr, length)); + png_malloc_warn(png_ptr, length)); if (info_ptr->pcal_units == NULL) { @@ -563,7 +334,7 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, memcpy(info_ptr->pcal_units, units, length); info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, - (size_t)(((unsigned int)nparams + 1) * (sizeof (png_charp))))); + (png_size_t)((nparams + 1) * (sizeof (png_charp))))); if (info_ptr->pcal_params == NULL) { @@ -571,8 +342,7 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, return; } - memset(info_ptr->pcal_params, 0, ((unsigned int)nparams + 1) * - (sizeof (png_charp))); + memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp))); for (i = 0; i < nparams; i++) { @@ -592,6 +362,7 @@ png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, } info_ptr->valid |= PNG_INFO_pCAL; + info_ptr->free_me |= PNG_FREE_PCAL; } #endif @@ -600,7 +371,7 @@ void PNGAPI png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, int unit, png_const_charp swidth, png_const_charp sheight) { - size_t lengthw = 0, lengthh = 0; + png_size_t lengthw = 0, lengthh = 0; png_debug1(1, "in %s storage function", "sCAL"); @@ -628,12 +399,11 @@ png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw); info_ptr->scal_s_width = png_voidcast(png_charp, - png_malloc_warn(png_ptr, lengthw)); + png_malloc_warn(png_ptr, lengthw)); if (info_ptr->scal_s_width == NULL) { png_warning(png_ptr, "Memory allocation failed while processing sCAL"); - return; } @@ -644,11 +414,11 @@ png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh); info_ptr->scal_s_height = png_voidcast(png_charp, - png_malloc_warn(png_ptr, lengthh)); + png_malloc_warn(png_ptr, lengthh)); if (info_ptr->scal_s_height == NULL) { - png_free(png_ptr, info_ptr->scal_s_width); + png_free (png_ptr, info_ptr->scal_s_width); info_ptr->scal_s_width = NULL; png_warning(png_ptr, "Memory allocation failed while processing sCAL"); @@ -657,8 +427,8 @@ png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, memcpy(info_ptr->scal_s_height, sheight, lengthh); - info_ptr->free_me |= PNG_FREE_SCAL; info_ptr->valid |= PNG_INFO_sCAL; + info_ptr->free_me |= PNG_FREE_SCAL; } # ifdef PNG_FLOATING_POINT_SUPPORTED @@ -682,9 +452,9 @@ png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit, char sheight[PNG_sCAL_MAX_DIGITS+1]; png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width, - PNG_sCAL_PRECISION); + PNG_sCAL_PRECISION); png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height, - PNG_sCAL_PRECISION); + PNG_sCAL_PRECISION); png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); } @@ -742,17 +512,12 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_const_colorp palette, int num_palette) { - png_uint_32 max_palette_length; - png_debug1(1, "in %s storage function", "PLTE"); if (png_ptr == NULL || info_ptr == NULL) return; - max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? - (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; - - if (num_palette < 0 || num_palette > (int) max_palette_length) + if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH) { if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) png_error(png_ptr, "Invalid palette length"); @@ -760,7 +525,6 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, else { png_warning(png_ptr, "Invalid palette length"); - return; } } @@ -772,7 +536,8 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, # endif )) { - png_error(png_ptr, "Invalid palette"); + png_chunk_report(png_ptr, "Invalid palette", PNG_CHUNK_ERROR); + return; } /* It may not actually be necessary to set png_ptr->palette here; @@ -785,19 +550,19 @@ png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead - * of num_palette entries, in case of an invalid PNG file or incorrect - * call to png_set_PLTE() with too-large sample values. + * of num_palette entries, in case of an invalid PNG file that has + * too-large sample values. */ png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); if (num_palette > 0) - memcpy(png_ptr->palette, palette, (unsigned int)num_palette * - (sizeof (png_color))); - + memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color))); info_ptr->palette = png_ptr->palette; info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; + info_ptr->free_me |= PNG_FREE_PLTE; + info_ptr->valid |= PNG_INFO_PLTE; } @@ -825,8 +590,8 @@ png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) if (png_ptr == NULL || info_ptr == NULL) return; - info_ptr->rendering_intent = srgb_intent; - info_ptr->valid |= PNG_INFO_sRGB; + (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent); + png_colorspace_sync_info(png_ptr, info_ptr); } void PNGAPI @@ -838,20 +603,14 @@ png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, if (png_ptr == NULL || info_ptr == NULL) return; - png_set_sRGB(png_ptr, info_ptr, srgb_intent); + if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent)) + { + /* This causes the gAMA and cHRM to be written too */ + info_ptr->colorspace.flags |= + PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; + } -# ifdef PNG_gAMA_SUPPORTED - png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); -# endif /* gAMA */ - -# ifdef PNG_cHRM_SUPPORTED - png_set_cHRM_fixed(png_ptr, info_ptr, - /* color x y */ - /* white */ 31270, 32900, - /* red */ 64000, 33000, - /* green */ 30000, 60000, - /* blue */ 15000, 6000); -# endif /* cHRM */ + png_colorspace_sync_info(png_ptr, info_ptr); } #endif /* sRGB */ @@ -864,7 +623,7 @@ png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, { png_charp new_iccp_name; png_bytep new_iccp_profile; - size_t length; + png_size_t length; png_debug1(1, "in %s storage function", "iCCP"); @@ -874,26 +633,45 @@ png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, if (compression_type != PNG_COMPRESSION_TYPE_BASE) png_app_error(png_ptr, "Invalid iCCP compression method"); + /* Set the colorspace first because this validates the profile; do not + * override previously set app cHRM or gAMA here (because likely as not the + * application knows better than libpng what the correct values are.) Pass + * the info_ptr color_type field to png_colorspace_set_ICC because in the + * write case it has not yet been stored in png_ptr. + */ + { + int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name, + proflen, profile, info_ptr->color_type); + + png_colorspace_sync_info(png_ptr, info_ptr); + + /* Don't do any of the copying if the profile was bad, or inconsistent. */ + if (!result) + return; + + /* But do write the gAMA and cHRM chunks from the profile. */ + info_ptr->colorspace.flags |= + PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM; + } + length = strlen(name)+1; new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); if (new_iccp_name == NULL) { png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk"); - return; } memcpy(new_iccp_name, name, length); new_iccp_profile = png_voidcast(png_bytep, - png_malloc_warn(png_ptr, proflen)); + png_malloc_warn(png_ptr, proflen)); if (new_iccp_profile == NULL) { png_free(png_ptr, new_iccp_name); png_benign_error(png_ptr, "Insufficient memory to process iCCP profile"); - return; } @@ -917,7 +695,7 @@ png_set_text(png_const_structrp png_ptr, png_inforp info_ptr, int ret; ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); - if (ret != 0) + if (ret) png_error(png_ptr, "Insufficient memory to store text"); } @@ -927,11 +705,11 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, { int i; - png_debug1(1, "in text storage function, chunk typeid = 0x%lx", - png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name); + png_debug1(1, "in %lx storage function", png_ptr == NULL ? "unexpected" : + (unsigned long)png_ptr->chunk_name); if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL) - return 0; + return(0); /* Make sure we have enough space in the "text" array in info_struct * to hold all of the incoming text_ptr objects. This compare can't overflow @@ -957,19 +735,18 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, else max_text = INT_MAX; - /* Now allocate a new array and copy the old members in; this does all + /* Now allocate a new array and copy the old members in, this does all * the overflow checks. */ new_text = png_voidcast(png_textp,png_realloc_array(png_ptr, - info_ptr->text, old_num_text, max_text-old_num_text, - sizeof *new_text)); + info_ptr->text, old_num_text, max_text-old_num_text, + sizeof *new_text)); } if (new_text == NULL) { png_chunk_report(png_ptr, "too many text chunks", - PNG_CHUNK_WRITE_ERROR); - + PNG_CHUNK_WRITE_ERROR); return 1; } @@ -996,7 +773,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST) { png_chunk_report(png_ptr, "text compression mode is out of range", - PNG_CHUNK_WRITE_ERROR); + PNG_CHUNK_WRITE_ERROR); continue; } @@ -1025,10 +802,10 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, else lang_key_len = 0; } -# else /* iTXt */ +# else /* PNG_iTXt_SUPPORTED */ { png_chunk_report(png_ptr, "iTXt chunk not supported", - PNG_CHUNK_WRITE_ERROR); + PNG_CHUNK_WRITE_ERROR); continue; } # endif @@ -1057,8 +834,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, if (textp->key == NULL) { png_chunk_report(png_ptr, "text chunk: out of memory", - PNG_CHUNK_WRITE_ERROR); - + PNG_CHUNK_WRITE_ERROR); return 1; } @@ -1088,7 +864,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, textp->text = textp->key + key_len + 1; } - if (text_length != 0) + if (text_length) memcpy(textp->text, text_ptr[i].text, text_length); *(textp->text + text_length) = '\0'; @@ -1111,7 +887,7 @@ png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, png_debug1(3, "transferred text chunk %d", info_ptr->num_text); } - return 0; + return(0); } #endif @@ -1123,7 +899,7 @@ png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr, png_debug1(1, "in %s storage function", "tIME"); if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL || - (png_ptr->mode & PNG_WROTE_tIME) != 0) + (png_ptr->mode & PNG_WROTE_tIME)) return; if (mod_time->month == 0 || mod_time->month > 12 || @@ -1132,7 +908,6 @@ png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr, mod_time->second > 60) { png_warning(png_ptr, "Ignoring invalid time value"); - return; } @@ -1149,7 +924,6 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_debug1(1, "in %s storage function", "tRNS"); if (png_ptr == NULL || info_ptr == NULL) - return; if (trans_alpha != NULL) @@ -1165,36 +939,26 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); - if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) - { - /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ - info_ptr->trans_alpha = png_voidcast(png_bytep, - png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); - memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans); + /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ + png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep, + png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); - info_ptr->free_me |= PNG_FREE_TRNS; - info_ptr->valid |= PNG_INFO_tRNS; - } - png_ptr->trans_alpha = info_ptr->trans_alpha; + if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) + memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans); } if (trans_color != NULL) { -#ifdef PNG_WARNINGS_SUPPORTED - if (info_ptr->bit_depth < 16) - { - int sample_max = (1 << info_ptr->bit_depth) - 1; + int sample_max = (1 << info_ptr->bit_depth); - if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && - trans_color->gray > sample_max) || - (info_ptr->color_type == PNG_COLOR_TYPE_RGB && - (trans_color->red > sample_max || - trans_color->green > sample_max || - trans_color->blue > sample_max))) - png_warning(png_ptr, - "tRNS chunk has out-of-range samples for bit_depth"); - } -#endif + if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && + trans_color->gray > sample_max) || + (info_ptr->color_type == PNG_COLOR_TYPE_RGB && + (trans_color->red > sample_max || + trans_color->green > sample_max || + trans_color->blue > sample_max))) + png_warning(png_ptr, + "tRNS chunk has out-of-range samples for bit_depth"); info_ptr->trans_color = *trans_color; @@ -1206,8 +970,8 @@ png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, if (num_trans != 0) { - info_ptr->free_me |= PNG_FREE_TRNS; info_ptr->valid |= PNG_INFO_tRNS; + info_ptr->free_me |= PNG_FREE_TRNS; } } #endif @@ -1227,8 +991,6 @@ png_set_sPLT(png_const_structrp png_ptr, { png_sPLT_tp np; - png_debug1(1, "in %s storage function", "sPLT"); - if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL) return; @@ -1236,8 +998,8 @@ png_set_sPLT(png_const_structrp png_ptr, * overflows. Notice that the parameters are (int) and (size_t) */ np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr, - info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries, - sizeof *np)); + info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries, + sizeof *np)); if (np == NULL) { @@ -1247,7 +1009,6 @@ png_set_sPLT(png_const_structrp png_ptr, } png_free(png_ptr, info_ptr->splt_palettes); - info_ptr->splt_palettes = np; info_ptr->free_me |= PNG_FREE_SPLT; @@ -1255,7 +1016,7 @@ png_set_sPLT(png_const_structrp png_ptr, do { - size_t length; + png_size_t length; /* Skip invalid input entries */ if (entries->name == NULL || entries->entries == NULL) @@ -1268,8 +1029,8 @@ png_set_sPLT(png_const_structrp png_ptr, np->depth = entries->depth; - /* In the event of out-of-memory just return - there's no point keeping - * on trying to add sPLT chunks. + /* In the even of out-of-memory just return - there's no point keeping on + * trying to add sPLT chunks. */ length = strlen(entries->name) + 1; np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length)); @@ -1280,8 +1041,8 @@ png_set_sPLT(png_const_structrp png_ptr, memcpy(np->name, entries->name, length); /* IMPORTANT: we have memory now that won't get freed if something else - * goes wrong; this code must free it. png_malloc_array produces no - * warnings; use a png_chunk_report (below) if there is an error. + * goes wrong, this code must free it. png_malloc_array produces no + * warnings, use a png_chunk_report (below) if there is an error. */ np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr, entries->nentries, sizeof (png_sPLT_entry))); @@ -1289,7 +1050,6 @@ png_set_sPLT(png_const_structrp png_ptr, if (np->entries == NULL) { png_free(png_ptr, np->name); - np->name = NULL; break; } @@ -1298,7 +1058,7 @@ png_set_sPLT(png_const_structrp png_ptr, * checked it when doing the allocation. */ memcpy(np->entries, entries->entries, - (unsigned int)entries->nentries * sizeof (png_sPLT_entry)); + entries->nentries * sizeof (png_sPLT_entry)); /* Note that 'continue' skips the advance of the out pointer and out * count, so an invalid entry is not added. @@ -1306,14 +1066,13 @@ png_set_sPLT(png_const_structrp png_ptr, info_ptr->valid |= PNG_INFO_sPLT; ++(info_ptr->splt_palettes_num); ++np; - ++entries; } - while (--nentries); + while (++entries, --nentries); if (nentries > 0) png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR); } -#endif /* sPLT */ +#endif /* PNG_sPLT_SUPPORTED */ #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED static png_byte @@ -1322,17 +1081,17 @@ check_location(png_const_structrp png_ptr, int location) location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT); /* New in 1.6.0; copy the location and check it. This is an API - * change; previously the app had to use the + * change, previously the app had to use the * png_set_unknown_chunk_location API below for each chunk. */ - if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + if (location == 0 && !(png_ptr->mode & PNG_IS_READ_STRUCT)) { /* Write struct, so unknown chunks come from the app */ png_app_warning(png_ptr, - "png_set_unknown_chunks now expects a valid location"); + "png_set_unknown_chunks now expects a valid location"); /* Use the old behavior */ location = (png_byte)(png_ptr->mode & - (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)); + (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)); } /* This need not be an internal error - if the app calls @@ -1355,12 +1114,12 @@ check_location(png_const_structrp png_ptr, int location) void PNGAPI png_set_unknown_chunks(png_const_structrp png_ptr, - png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) + png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) { png_unknown_chunkp np; if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 || - unknowns == NULL) + unknowns == NULL) return; /* Check for the failure cases where support has been disabled at compile @@ -1371,19 +1130,17 @@ png_set_unknown_chunks(png_const_structrp png_ptr, */ # if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \ defined(PNG_READ_SUPPORTED) - if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + if (png_ptr->mode & PNG_IS_READ_STRUCT) { png_app_error(png_ptr, "no unknown chunk support on read"); - return; } # endif # if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \ defined(PNG_WRITE_SUPPORTED) - if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) + if (!(png_ptr->mode & PNG_IS_READ_STRUCT)) { png_app_error(png_ptr, "no unknown chunk support on write"); - return; } # endif @@ -1394,18 +1151,17 @@ png_set_unknown_chunks(png_const_structrp png_ptr, * appropriate to read or write. */ np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr, - info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns, - sizeof *np)); + info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns, + sizeof *np)); if (np == NULL) { png_chunk_report(png_ptr, "too many unknown chunks", - PNG_CHUNK_WRITE_ERROR); + PNG_CHUNK_WRITE_ERROR); return; } png_free(png_ptr, info_ptr->unknown_chunks); - info_ptr->unknown_chunks = np; /* safe because it is initialized */ info_ptr->free_me |= PNG_FREE_UNKN; @@ -1429,12 +1185,12 @@ png_set_unknown_chunks(png_const_structrp png_ptr, else { np->data = png_voidcast(png_bytep, - png_malloc_base(png_ptr, unknowns->size)); + png_malloc_base(png_ptr, unknowns->size)); if (np->data == NULL) { png_chunk_report(png_ptr, "unknown chunk: out of memory", - PNG_CHUNK_WRITE_ERROR); + PNG_CHUNK_WRITE_ERROR); /* But just skip storing the unknown chunk */ continue; } @@ -1468,7 +1224,7 @@ png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, { png_app_error(png_ptr, "invalid unknown chunk location"); /* Fake out the pre 1.6.0 behavior: */ - if (((unsigned int)location & PNG_HAVE_IDAT) != 0) /* undocumented! */ + if ((location & PNG_HAVE_IDAT)) /* undocumented! */ location = PNG_AFTER_IDAT; else @@ -1479,11 +1235,12 @@ png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, check_location(png_ptr, location); } } -#endif /* STORE_UNKNOWN_CHUNKS */ +#endif + #ifdef PNG_MNG_FEATURES_SUPPORTED png_uint_32 PNGAPI -png_permit_mng_features(png_structrp png_ptr, png_uint_32 mng_features) +png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features) { png_debug(1, "in png_permit_mng_features"); @@ -1505,14 +1262,10 @@ add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep) /* Utility function: update the 'keep' state of a chunk if it is already in * the list, otherwise add it to the list. */ - for (i=0; i= PNG_HANDLE_CHUNK_LAST) { png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep"); - return; } @@ -1556,17 +1308,13 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep, /* Ignore all unknown chunks and all chunks recognized by * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND */ - static const png_byte chunks_to_ignore[] = { + static PNG_CONST png_byte chunks_to_ignore[] = { 98, 75, 71, 68, '\0', /* bKGD */ 99, 72, 82, 77, '\0', /* cHRM */ - 99, 73, 67, 80, '\0', /* cICP */ - 99, 76, 76, 73, '\0', /* cLLI */ - 101, 88, 73, 102, '\0', /* eXIf */ 103, 65, 77, 65, '\0', /* gAMA */ 104, 73, 83, 84, '\0', /* hIST */ 105, 67, 67, 80, '\0', /* iCCP */ 105, 84, 88, 116, '\0', /* iTXt */ - 109, 68, 67, 86, '\0', /* mDCV */ 111, 70, 70, 115, '\0', /* oFFs */ 112, 67, 65, 76, '\0', /* pCAL */ 112, 72, 89, 115, '\0', /* pHYs */ @@ -1581,7 +1329,7 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep, }; chunk_list = chunks_to_ignore; - num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U; + num_chunks = (sizeof chunks_to_ignore)/5; } else /* num_chunks_in > 0 */ @@ -1592,11 +1340,10 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep, * which can be switched off. */ png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list"); - return; } - num_chunks = (unsigned int)num_chunks_in; + num_chunks = num_chunks_in; } old_num_chunks = png_ptr->num_chunk_list; @@ -1608,7 +1355,6 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep, if (num_chunks + old_num_chunks > UINT_MAX/5) { png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks"); - return; } @@ -1616,7 +1362,7 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep, * required because add_one_chunk above doesn't extend the list if the 'keep' * parameter is the default. */ - if (keep != 0) + if (keep) { new_list = png_voidcast(png_bytep, png_malloc(png_ptr, 5 * (num_chunks + old_num_chunks))); @@ -1643,15 +1389,12 @@ png_set_keep_unknown_chunks(png_structrp png_ptr, int keep, unsigned int i; for (i=0; irow_pointers != NULL && - (info_ptr->row_pointers != row_pointers)) + if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers)) png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); info_ptr->row_pointers = row_pointers; - if (row_pointers != NULL) + if (row_pointers) info_ptr->valid |= PNG_INFO_IDAT; } #endif void PNGAPI -png_set_compression_buffer_size(png_structrp png_ptr, size_t size) +png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size) { - png_debug(1, "in png_set_compression_buffer_size"); + if (png_ptr == NULL) + return; - if (png_ptr == NULL) - return; - - if (size == 0 || size > PNG_UINT_31_MAX) - png_error(png_ptr, "invalid compression buffer size"); + if (size == 0 || size > PNG_UINT_31_MAX) + png_error(png_ptr, "invalid compression buffer size"); # ifdef PNG_SEQUENTIAL_READ_SUPPORTED - if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) - { - png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */ - return; - } + if (png_ptr->mode & PNG_IS_READ_STRUCT) + { + png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */ + return; + } # endif # ifdef PNG_WRITE_SUPPORTED - if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) - { - if (png_ptr->zowner != 0) + if (!(png_ptr->mode & PNG_IS_READ_STRUCT)) { - png_warning(png_ptr, - "Compression buffer size cannot be changed because it is in use"); + if (png_ptr->zowner != 0) + { + png_warning(png_ptr, + "Compression buffer size cannot be changed because it is in use"); + return; + } - return; + if (size > ZLIB_IO_MAX) + { + png_warning(png_ptr, + "Compression buffer size limited to system maximum"); + size = ZLIB_IO_MAX; /* must fit */ + } + + else if (size < 6) + { + /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH + * if this is permitted. + */ + png_warning(png_ptr, + "Compression buffer size cannot be reduced below 6"); + return; + } + + if (png_ptr->zbuffer_size != size) + { + png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); + png_ptr->zbuffer_size = (uInt)size; + } } - -#ifndef __COVERITY__ - /* Some compilers complain that this is always false. However, it - * can be true when integer overflow happens. - */ - if (size > ZLIB_IO_MAX) - { - png_warning(png_ptr, - "Compression buffer size limited to system maximum"); - size = ZLIB_IO_MAX; /* must fit */ - } -#endif - - if (size < 6) - { - /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH - * if this is permitted. - */ - png_warning(png_ptr, - "Compression buffer size cannot be reduced below 6"); - - return; - } - - if (png_ptr->zbuffer_size != size) - { - png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); - png_ptr->zbuffer_size = (uInt)size; - } - } # endif } void PNGAPI png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask) { - if (png_ptr != NULL && info_ptr != NULL) - info_ptr->valid &= (unsigned int)(~mask); + if (png_ptr && info_ptr) + info_ptr->valid &= ~mask; } #ifdef PNG_SET_USER_LIMITS_SUPPORTED /* This function was added to libpng 1.2.6 */ void PNGAPI -png_set_user_limits(png_structrp png_ptr, png_uint_32 user_width_max, +png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max, png_uint_32 user_height_max) { - png_debug(1, "in png_set_user_limits"); - /* Images with dimensions larger than these limits will be * rejected by png_set_IHDR(). To accept any PNG datastream - * regardless of dimensions, set both limits to 0x7fffffff. + * regardless of dimensions, set both limits to 0x7ffffffL. */ if (png_ptr == NULL) return; @@ -1813,41 +1543,21 @@ png_set_user_limits(png_structrp png_ptr, png_uint_32 user_width_max, /* This function was added to libpng 1.4.0 */ void PNGAPI -png_set_chunk_cache_max(png_structrp png_ptr, png_uint_32 user_chunk_cache_max) +png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max) { - png_debug(1, "in png_set_chunk_cache_max"); - - if (png_ptr != NULL) - png_ptr->user_chunk_cache_max = user_chunk_cache_max; + if (png_ptr) + png_ptr->user_chunk_cache_max = user_chunk_cache_max; } /* This function was added to libpng 1.4.1 */ void PNGAPI -png_set_chunk_malloc_max(png_structrp png_ptr, +png_set_chunk_malloc_max (png_structrp png_ptr, png_alloc_size_t user_chunk_malloc_max) { - png_debug(1, "in png_set_chunk_malloc_max"); - - /* pngstruct::user_chunk_malloc_max is initialized to a non-zero value in - * png.c. This API supports '0' for unlimited, make sure the correct - * (unlimited) value is set here to avoid a need to check for 0 everywhere - * the parameter is used. - */ - if (png_ptr != NULL) - { - if (user_chunk_malloc_max == 0U) /* unlimited */ - { -# ifdef PNG_MAX_MALLOC_64K - png_ptr->user_chunk_malloc_max = 65536U; -# else - png_ptr->user_chunk_malloc_max = PNG_SIZE_MAX; -# endif - } - else - png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; - } + if (png_ptr) + png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; } -#endif /* ?SET_USER_LIMITS */ +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */ #ifdef PNG_BENIGN_ERRORS_SUPPORTED @@ -1862,7 +1572,7 @@ png_set_benign_errors(png_structrp png_ptr, int allowed) * is the default behavior if png_set_benign_errors() is not called). */ - if (allowed != 0) + if (allowed) png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN | PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN; @@ -1870,14 +1580,14 @@ png_set_benign_errors(png_structrp png_ptr, int allowed) png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN | PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN); } -#endif /* BENIGN_ERRORS */ +#endif /* PNG_BENIGN_ERRORS_SUPPORTED */ #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED /* Whether to report invalid palette index; added at libng-1.5.10. * It is possible for an indexed (color-type==3) PNG file to contain * pixels with invalid (out-of-range) indexes if the PLTE chunk has * fewer entries than the image's bit-depth would allow. We recover - * from this gracefully by filling any incomplete palette with zeros + * from this gracefully by filling any incomplete palette with zeroes * (opaque black). By default, when this occurs libpng will issue * a benign error. This API can be used to override that behavior. */ @@ -1893,94 +1603,4 @@ png_set_check_for_invalid_index(png_structrp png_ptr, int allowed) png_ptr->num_palette_max = -1; } #endif - -#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) || \ - defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) -/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, - * and if invalid, correct the keyword rather than discarding the entire - * chunk. The PNG 1.0 specification requires keywords 1-79 characters in - * length, forbids leading or trailing whitespace, multiple internal spaces, - * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. - * - * The 'new_key' buffer must be 80 characters in size (for the keyword plus a - * trailing '\0'). If this routine returns 0 then there was no keyword, or a - * valid one could not be generated, and the caller must png_error. - */ -png_uint_32 /* PRIVATE */ -png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) -{ -#ifdef PNG_WARNINGS_SUPPORTED - png_const_charp orig_key = key; -#endif - png_uint_32 key_len = 0; - int bad_character = 0; - int space = 1; - - png_debug(1, "in png_check_keyword"); - - if (key == NULL) - { - *new_key = 0; - return 0; - } - - while (*key && key_len < 79) - { - png_byte ch = (png_byte)*key++; - - if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) - { - *new_key++ = ch; ++key_len; space = 0; - } - - else if (space == 0) - { - /* A space or an invalid character when one wasn't seen immediately - * before; output just a space. - */ - *new_key++ = 32; ++key_len; space = 1; - - /* If the character was not a space then it is invalid. */ - if (ch != 32) - bad_character = ch; - } - - else if (bad_character == 0) - bad_character = ch; /* just skip it, record the first error */ - } - - if (key_len > 0 && space != 0) /* trailing space */ - { - --key_len; --new_key; - if (bad_character == 0) - bad_character = 32; - } - - /* Terminate the keyword */ - *new_key = 0; - - if (key_len == 0) - return 0; - -#ifdef PNG_WARNINGS_SUPPORTED - /* Try to only output one warning per keyword: */ - if (*key != 0) /* keyword too long */ - png_warning(png_ptr, "keyword truncated"); - - else if (bad_character != 0) - { - PNG_WARNING_PARAMETERS(p) - - png_warning_parameter(p, 1, orig_key); - png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character); - - png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'"); - } -#else /* !WARNINGS */ - PNG_UNUSED(png_ptr) -#endif /* !WARNINGS */ - - return key_len; -} -#endif /* TEXT || pCAL || iCCP || sPLT */ -#endif /* READ || WRITE */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pngstruct.h b/Windows_Libs/Dev/Render/libpng/pngstruct.h index fe5fa04..d58c028 100644 --- a/Windows_Libs/Dev/Render/libpng/pngstruct.h +++ b/Windows_Libs/Dev/Render/libpng/pngstruct.h @@ -1,18 +1,22 @@ -/* pngstruct.h - internal structures for libpng + +/* pngstruct.h - header file for PNG reference library * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) + * + * Last changed in libpng 1.6.1 [March 28, 2013] * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h */ -#ifndef PNGPRIV_H -# error This file must not be included by applications; please include -#endif +/* The structure that holds the information to read and write PNG files. + * The only people who need to care about what is inside of this are the + * people who will be modifying the library for their own special needs. + * It should NOT be accessed directly by an application. + */ #ifndef PNGSTRUCT_H #define PNGSTRUCT_H @@ -44,7 +48,7 @@ /* zlib.h declares a magic type 'uInt' that limits the amount of data that zlib * can handle at once. This type need be no larger than 16 bits (so maximum of * 65535), this define allows us to discover how big it is, but limited by the - * maximum for size_t. The value can be overridden in a library build + * maximuum for png_size_t. The value can be overriden in a library build * (pngusr.h, or set it in CPPFLAGS) and it works to set it to a considerably * lower value (e.g. 255 works). A lower value may help memory usage (slightly) * and may even improve performance on some systems (and degrade it on others.) @@ -67,7 +71,13 @@ typedef struct png_compression_buffer /* Colorspace support; structures used in png_struct, png_info and in internal * functions to hold and communicate information about the color space. + * + * PNG_COLORSPACE_SUPPORTED is only required if the application will perform + * colorspace corrections, otherwise all the colorspace information can be + * skipped and the size of libpng can be reduced (significantly) by compiling + * out the colorspace support. */ +#ifdef PNG_COLORSPACE_SUPPORTED /* The chromaticities of the red, green and blue colorants and the chromaticity * of the corresponding white point (i.e. of rgb(1.0,1.0,1.0)). */ @@ -88,36 +98,48 @@ typedef struct png_XYZ png_fixed_point green_X, green_Y, green_Z; png_fixed_point blue_X, blue_Y, blue_Z; } png_XYZ; +#endif /* COLORSPACE */ -/* Chunk index values as an enum, PNG_INDEX_unknown is also a count of the - * number of chunks. - */ -#define PNG_CHUNK(cHNK, i) PNG_INDEX_ ## cHNK = (i), -typedef enum -{ - PNG_KNOWN_CHUNKS - PNG_INDEX_unknown -} png_index; -#undef PNG_CHUNK - -/* Chunk flag values. These are (png_uint_32 values) with exactly one bit set - * and can be combined into a flag set with bitwise 'or'. +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) +/* A colorspace is all the above plus, potentially, profile information, + * however at present libpng does not use the profile internally so it is only + * stored in the png_info struct (if iCCP is supported.) The rendering intent + * is retained here and is checked. * - * TODO: C23: convert these macros to C23 inlines (which are static). + * The file gamma encoding information is also stored here and gamma correction + * is done by libpng, whereas color correction must currently be done by the + * application. */ -#define png_chunk_flag_from_index(i) (0x80000000U >> (31 - (i))) - /* The flag coresponding to the given png_index enum value. This is defined - * for png_unknown as well (until it reaches the value 32) but this should - * not be relied on. - */ +typedef struct png_colorspace +{ +#ifdef PNG_GAMMA_SUPPORTED + png_fixed_point gamma; /* File gamma */ +#endif -#define png_file_has_chunk(png_ptr, i)\ - (((png_ptr)->chunks & png_chunk_flag_from_index(i)) != 0) - /* The chunk has been recorded in png_struct */ +#ifdef PNG_COLORSPACE_SUPPORTED + png_xy end_points_xy; /* End points as chromaticities */ + png_XYZ end_points_XYZ; /* End points as CIE XYZ colorant values */ + png_uint_16 rendering_intent; /* Rendering intent of a profile */ +#endif -#define png_file_add_chunk(pnt_ptr, i)\ - ((void)((png_ptr)->chunks |= png_chunk_flag_from_index(i))) - /* Record the chunk in the png_struct */ + /* Flags are always defined to simplify the code. */ + png_uint_16 flags; /* As defined below */ +} png_colorspace, * PNG_RESTRICT png_colorspacerp; + +typedef const png_colorspace * PNG_RESTRICT png_const_colorspacerp; + +/* General flags for the 'flags' field */ +#define PNG_COLORSPACE_HAVE_GAMMA 0x0001 +#define PNG_COLORSPACE_HAVE_ENDPOINTS 0x0002 +#define PNG_COLORSPACE_HAVE_INTENT 0x0004 +#define PNG_COLORSPACE_FROM_gAMA 0x0008 +#define PNG_COLORSPACE_FROM_cHRM 0x0010 +#define PNG_COLORSPACE_FROM_sRGB 0x0020 +#define PNG_COLORSPACE_ENDPOINTS_MATCH_sRGB 0x0040 +#define PNG_COLORSPACE_MATCHES_sRGB 0x0080 /* exact match on profile */ +#define PNG_COLORSPACE_INVALID 0x8000 +#define PNG_COLORSPACE_CANCEL(flags) (0xffff ^ (flags)) +#endif /* COLORSPACE || GAMMA */ struct png_struct_def { @@ -189,34 +211,27 @@ struct png_struct_def int zlib_set_strategy; #endif - png_uint_32 chunks; /* PNG_CF_ for every chunk read or (NYI) written */ -# define png_has_chunk(png_ptr, cHNK)\ - png_file_has_chunk(png_ptr, PNG_INDEX_ ## cHNK) - /* Convenience accessor - use this to check for a known chunk by name */ - png_uint_32 width; /* width of image in pixels */ png_uint_32 height; /* height of image in pixels */ png_uint_32 num_rows; /* number of rows in current pass */ png_uint_32 usr_width; /* width of row at start of write */ - size_t rowbytes; /* size of row in bytes */ + png_size_t rowbytes; /* size of row in bytes */ png_uint_32 iwidth; /* width of current interlaced row in pixels */ png_uint_32 row_number; /* current row in interlace pass */ png_uint_32 chunk_name; /* PNG_CHUNK() id of current chunk */ png_bytep prev_row; /* buffer to save previous (unfiltered) row. - * While reading this is a pointer into - * big_prev_row; while writing it is separately - * allocated if needed. + * This is a pointer into big_prev_row */ png_bytep row_buf; /* buffer to save current (unfiltered) row. - * While reading, this is a pointer into - * big_row_buf; while writing it is separately - * allocated. + * This is a pointer into big_row_buf */ -#ifdef PNG_WRITE_FILTER_SUPPORTED - png_bytep try_row; /* buffer to save trial row when filtering */ - png_bytep tst_row; /* buffer to save best trial row when filtering */ +#ifdef PNG_WRITE_SUPPORTED + png_bytep sub_row; /* buffer to save "sub" row when filtering */ + png_bytep up_row; /* buffer to save "up" row when filtering */ + png_bytep avg_row; /* buffer to save "avg" row when filtering */ + png_bytep paeth_row; /* buffer to save "Paeth" row when filtering */ #endif - size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */ + png_size_t info_rowbytes; /* Added in 1.5.4: cache of updated row bytes */ png_uint_32 idat_size; /* current IDAT size for read */ png_uint_32 crc; /* current chunk CRC value */ @@ -233,7 +248,7 @@ struct png_struct_def png_byte filter; /* file filter type (always 0) */ png_byte interlaced; /* PNG_INTERLACE_NONE, PNG_INTERLACE_ADAM7 */ png_byte pass; /* current interlace pass (0 - 6) */ - png_byte do_filter; /* row filter flags (see PNG_FILTER_ in png.h ) */ + png_byte do_filter; /* row filter flags (see PNG_FILTER_ below ) */ png_byte color_type; /* color type of file */ png_byte bit_depth; /* bit depth of file */ png_byte usr_bit_depth; /* bit depth of users row: write only */ @@ -247,9 +262,6 @@ struct png_struct_def /* pixel depth used for the row buffers */ png_byte transformed_pixel_depth; /* pixel depth after read/write transforms */ -#if ZLIB_VERNUM >= 0x1240 - png_byte zstream_start; /* at start of an input zlib stream */ -#endif /* Zlib >= 1.2.4 */ #if defined(PNG_READ_FILLER_SUPPORTED) || defined(PNG_WRITE_FILLER_SUPPORTED) png_uint_16 filler; /* filler bytes for pixel expansion */ #endif @@ -262,7 +274,7 @@ struct png_struct_def #ifdef PNG_READ_GAMMA_SUPPORTED png_color_16 background_1; /* background normalized to gamma 1.0 */ #endif -#endif /* bKGD */ +#endif /* PNG_bKGD_SUPPORTED */ #ifdef PNG_WRITE_FLUSH_SUPPORTED png_flush_ptr output_flush_fn; /* Function for flushing output */ @@ -270,16 +282,9 @@ struct png_struct_def png_uint_32 flush_rows; /* number of rows written since last flush */ #endif -#ifdef PNG_READ_RGB_TO_GRAY_SUPPORTED - png_xy chromaticities; /* From mDVC, cICP, [iCCP], sRGB or cHRM */ -#endif - #ifdef PNG_READ_GAMMA_SUPPORTED int gamma_shift; /* number of "insignificant" bits in 16-bit gamma */ - png_fixed_point screen_gamma; /* screen gamma value (display exponent) */ - png_fixed_point file_gamma; /* file gamma value (encoding exponent) */ - png_fixed_point chunk_gamma; /* from cICP, iCCP, sRGB or gAMA */ - png_fixed_point default_gamma;/* from png_set_alpha_mode */ + png_fixed_point screen_gamma; /* screen gamma value (display_exponent) */ png_bytep gamma_table; /* gamma table for 8-bit depth files */ png_uint_16pp gamma_16_table; /* gamma table for 16-bit depth files */ @@ -291,14 +296,14 @@ struct png_struct_def png_uint_16pp gamma_16_from_1; /* converts from 1.0 to screen */ png_uint_16pp gamma_16_to_1; /* converts from file to 1.0 */ #endif /* READ_BACKGROUND || READ_ALPHA_MODE || RGB_TO_GRAY */ -#endif /* READ_GAMMA */ +#endif #if defined(PNG_READ_GAMMA_SUPPORTED) || defined(PNG_sBIT_SUPPORTED) png_color_8 sig_bit; /* significant bits in each available channel */ #endif #if defined(PNG_READ_SHIFT_SUPPORTED) || defined(PNG_WRITE_SHIFT_SUPPORTED) - png_color_8 shift; /* shift for significant bit transformation */ + png_color_8 shift; /* shift for significant bit tranformation */ #endif #if defined(PNG_tRNS_SUPPORTED) || defined(PNG_READ_BACKGROUND_SUPPORTED) \ @@ -319,30 +324,50 @@ struct png_struct_def png_bytep current_buffer; /* buffer for recently used data */ png_uint_32 push_length; /* size of current input chunk */ png_uint_32 skip_length; /* bytes to skip in input data */ - size_t save_buffer_size; /* amount of data now in save_buffer */ - size_t save_buffer_max; /* total size of save_buffer */ - size_t buffer_size; /* total amount of available input data */ - size_t current_buffer_size; /* amount of data now in current_buffer */ + png_size_t save_buffer_size; /* amount of data now in save_buffer */ + png_size_t save_buffer_max; /* total size of save_buffer */ + png_size_t buffer_size; /* total amount of available input data */ + png_size_t current_buffer_size; /* amount of data now in current_buffer */ int process_mode; /* what push library is currently doing */ int cur_palette; /* current push library palette index */ -#endif /* PROGRESSIVE_READ */ + +#endif /* PNG_PROGRESSIVE_READ_SUPPORTED */ + +#if defined(__TURBOC__) && !defined(_Windows) && !defined(__FLAT__) +/* For the Borland special 64K segment handler */ + png_bytepp offset_table_ptr; + png_bytep offset_table; + png_uint_16 offset_table_number; + png_uint_16 offset_table_count; + png_uint_16 offset_table_count_free; +#endif #ifdef PNG_READ_QUANTIZE_SUPPORTED png_bytep palette_lookup; /* lookup table for quantizing */ png_bytep quantize_index; /* index translation for palette files */ #endif -/* Options */ +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + png_byte heuristic_method; /* heuristic for row filter selection */ + png_byte num_prev_filters; /* number of weights for previous rows */ + png_bytep prev_filters; /* filter type(s) of previous row(s) */ + png_uint_16p filter_weights; /* weight(s) for previous line(s) */ + png_uint_16p inv_filter_weights; /* 1/weight(s) for previous line(s) */ + png_uint_16p filter_costs; /* relative filter calculation cost */ + png_uint_16p inv_filter_costs; /* 1/relative filter calculation cost */ +#endif + + /* Options */ #ifdef PNG_SET_OPTION_SUPPORTED - png_uint_32 options; /* On/off state (up to 16 options) */ + png_byte options; /* On/off state (up to 4 options) */ #endif #if PNG_LIBPNG_VER < 10700 /* To do: remove this from libpng-1.7 */ #ifdef PNG_TIME_RFC1123_SUPPORTED char time_buffer[29]; /* String to hold RFC 1123 time text */ -#endif /* TIME_RFC1123 */ -#endif /* LIBPNG_VER < 10700 */ +#endif +#endif /* New members added in libpng-1.0.6 */ @@ -352,8 +377,8 @@ struct png_struct_def png_voidp user_chunk_ptr; #ifdef PNG_READ_USER_CHUNKS_SUPPORTED png_user_chunk_ptr read_user_chunk_fn; /* user read chunk handler */ -#endif /* READ_USER_CHUNKS */ -#endif /* USER_CHUNKS */ +#endif +#endif #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED int unknown_default; /* As PNG_HANDLE_* */ @@ -373,13 +398,6 @@ struct png_struct_def /* deleted in 1.5.5: rgb_to_gray_blue_coeff; */ #endif -/* New member added in libpng-1.6.36 */ -#if defined(PNG_READ_EXPAND_SUPPORTED) && \ - (defined(PNG_ARM_NEON_IMPLEMENTATION) || \ - defined(PNG_RISCV_RVV_IMPLEMENTATION)) - png_bytep riffled_palette; /* buffer for accelerated palette expansion */ -#endif - /* New member added in libpng-1.0.4 (renamed in 1.0.9) */ #if defined(PNG_MNG_FEATURES_SUPPORTED) /* Changed from png_byte to png_uint_32 at version 1.2.0 */ @@ -405,6 +423,7 @@ struct png_struct_def #ifdef PNG_READ_QUANTIZE_SUPPORTED /* The following three members were added at version 1.0.14 and 1.2.4 */ + png_bytep quantize_sort; /* working sort array */ png_bytep index_to_palette; /* where the original index currently is in the palette */ png_bytep palette_to_index; /* which original index points to this @@ -438,7 +457,7 @@ struct png_struct_def #endif /* New member added in libpng-1.2.26 */ - size_t old_big_row_buf_size; + png_size_t old_big_row_buf_size; #ifdef PNG_READ_SUPPORTED /* New member added in libpng-1.2.30 */ @@ -460,5 +479,11 @@ struct png_struct_def /* New member added in libpng-1.5.7 */ void (*read_filter[PNG_FILTER_VALUE_LAST-1])(png_row_infop row_info, png_bytep row, png_const_bytep prev_row); + +#ifdef PNG_READ_SUPPORTED +#if defined(PNG_COLORSPACE_SUPPORTED) || defined(PNG_GAMMA_SUPPORTED) + png_colorspace colorspace; +#endif +#endif }; #endif /* PNGSTRUCT_H */ diff --git a/Windows_Libs/Dev/Render/libpng/pngtest.c b/Windows_Libs/Dev/Render/libpng/pngtest.c index 5426b83..144f2db 100644 --- a/Windows_Libs/Dev/Render/libpng/pngtest.c +++ b/Windows_Libs/Dev/Render/libpng/pngtest.c @@ -1,9 +1,10 @@ -/* pngtest.c - a test program for libpng + +/* pngtest.c - a simple test program to test libpng * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -36,87 +37,57 @@ #include #include -#ifdef PNG_ZLIB_HEADER -# include PNG_ZLIB_HEADER /* defined by pnglibconf.h from 1.7 */ -#else -# include -#endif +/* Defined so I can write to a file on gui/windowing platforms */ +/* #define STDERR stderr */ +#define STDERR stdout /* For DOS */ #include "png.h" -/* This hack was introduced for historical reasons, and we are - * still keeping it in libpng-1.6.x for compatibility reasons. +/* Known chunks that exist in pngtest.png must be supported or pngtest will fail + * simply as a result of re-ordering them. This may be fixed in 1.7 */ -#define STDERR stdout - -/* Generate a compiler error if there is an old png.h in the search path. */ -typedef png_libpng_version_1_6_55 Your_png_h_is_not_version_1_6_55; - -/* Ensure that all version numbers in png.h are consistent with one another. */ -#if (PNG_LIBPNG_VER != PNG_LIBPNG_VER_MAJOR * 10000 + \ - PNG_LIBPNG_VER_MINOR * 100 + \ - PNG_LIBPNG_VER_RELEASE) || \ - (PNG_LIBPNG_VER_SHAREDLIB != PNG_LIBPNG_VER_MAJOR * 10 + \ - PNG_LIBPNG_VER_MINOR) || \ - (PNG_LIBPNG_VER_SHAREDLIB != PNG_LIBPNG_VER_SONUM) || \ - (PNG_LIBPNG_VER_SHAREDLIB != PNG_LIBPNG_VER_DLLNUM) -# error Inconsistent version numbers in "png.h" -#endif - -/* In version 1.6.1, we added support for the configure test harness, which - * uses 77 to indicate a skipped test. On the other hand, in cmake build tests, - * we still need to succeed on a skipped test, so: - */ -#if defined(HAVE_CONFIG_H) -# define SKIP 77 -#else -# define SKIP 0 -#endif - -/* Known chunks that exist in pngtest.png must be supported, or pngtest will - * fail simply as a result of re-ordering them. This may be fixed in the next - * generation of libpng. - * - * pngtest allocates a single row buffer for each row and overwrites it, - * therefore if the write side doesn't support the writing of interlaced images - * nothing can be done for an interlaced image (and the code below will fail - * horribly trying to write extra data after writing garbage). - */ -#if defined PNG_READ_SUPPORTED && /* else nothing can be done */ \ - defined PNG_READ_bKGD_SUPPORTED && \ - defined PNG_READ_cHRM_SUPPORTED && \ - defined PNG_READ_gAMA_SUPPORTED && \ - defined PNG_READ_oFFs_SUPPORTED && \ - defined PNG_READ_pCAL_SUPPORTED && \ - defined PNG_READ_pHYs_SUPPORTED && \ - defined PNG_READ_sBIT_SUPPORTED && \ - defined PNG_READ_sCAL_SUPPORTED && \ - defined PNG_READ_sRGB_SUPPORTED && \ - defined PNG_READ_sPLT_SUPPORTED && \ - defined PNG_READ_tEXt_SUPPORTED && \ - defined PNG_READ_tIME_SUPPORTED && \ - defined PNG_READ_zTXt_SUPPORTED && \ - (defined PNG_WRITE_INTERLACING_SUPPORTED || PNG_LIBPNG_VER >= 10700) +#if defined PNG_READ_SUPPORTED && /* else nothing can be done */\ + defined PNG_READ_bKGD_SUPPORTED &&\ + defined PNG_READ_cHRM_SUPPORTED &&\ + defined PNG_READ_gAMA_SUPPORTED &&\ + defined PNG_READ_oFFs_SUPPORTED &&\ + defined PNG_READ_pCAL_SUPPORTED &&\ + defined PNG_READ_pHYs_SUPPORTED &&\ + defined PNG_READ_sBIT_SUPPORTED &&\ + defined PNG_READ_sCAL_SUPPORTED &&\ + defined PNG_READ_sRGB_SUPPORTED &&\ + defined PNG_READ_tEXt_SUPPORTED &&\ + defined PNG_READ_tIME_SUPPORTED &&\ + defined PNG_READ_zTXt_SUPPORTED +#include "zlib.h" /* Copied from pngpriv.h but only used in error messages below. */ #ifndef PNG_ZBUF_SIZE # define PNG_ZBUF_SIZE 8192 #endif +#define FCLOSE(file) fclose(file) +#ifndef PNG_STDIO_SUPPORTED +typedef FILE * png_FILE_p; +#endif + +/* Makes pngtest verbose so we can find problems. */ #ifndef PNG_DEBUG # define PNG_DEBUG 0 #endif #if PNG_DEBUG > 1 -# define pngtest_debug(m) ((void)fprintf(stderr, m "\n")) -# define pngtest_debug1(m, p1) ((void)fprintf(stderr, m "\n", p1)) -# define pngtest_debug2(m, p1, p2) ((void)fprintf(stderr, m "\n", p1, p2)) -#elif PNG_DEBUG == 0 || PNG_DEBUG == 1 -# define pngtest_debug(m) ((void)0) -# define pngtest_debug1(m, p1) ((void)0) -# define pngtest_debug2(m, p1, p2) ((void)0) -#else /* PNG_DEBUG < 0 */ -# error Bad PNG_DEBUG value +# define pngtest_debug(m) ((void)fprintf(stderr, m "\n")) +# define pngtest_debug1(m,p1) ((void)fprintf(stderr, m "\n", p1)) +# define pngtest_debug2(m,p1,p2) ((void)fprintf(stderr, m "\n", p1, p2)) +#else +# define pngtest_debug(m) ((void)0) +# define pngtest_debug1(m,p1) ((void)0) +# define pngtest_debug2(m,p1,p2) ((void)0) +#endif + +#if !PNG_DEBUG +# define SINGLE_ROWBUF_ALLOC /* Makes buffer overruns easier to nail */ #endif /* Turn on CPU timing @@ -133,21 +104,38 @@ static float t_start, t_stop, t_decode, t_encode, t_misc; #endif #ifdef PNG_TIME_RFC1123_SUPPORTED +#define PNG_tIME_STRING_LENGTH 29 static int tIME_chunk_present = 0; -static char tIME_string[29] = "tIME chunk is not present"; -/* This use case is deprecated. - * See the declaration of png_convert_to_rfc1123_buffer for more details. - */ +static char tIME_string[PNG_tIME_STRING_LENGTH] = "tIME chunk is not present"; #endif static int verbose = 0; static int strict = 0; static int relaxed = 0; -static int xfail = 0; static int unsupported_chunks = 0; /* chunk unsupported by libpng in input */ static int error_count = 0; /* count calls to png_error */ static int warning_count = 0; /* count calls to png_warning */ +#ifdef __TURBOC__ +#include +#endif + +/* Define png_jmpbuf() in case we are using a pre-1.0.6 version of libpng */ +#ifndef png_jmpbuf +# define png_jmpbuf(png_ptr) png_ptr->jmpbuf +#endif + +/* Defines for unknown chunk handling if required. */ +#ifndef PNG_HANDLE_CHUNK_ALWAYS +# define PNG_HANDLE_CHUNK_ALWAYS 3 +#endif +#ifndef PNG_HANDLE_CHUNK_IF_SAFE +# define PNG_HANDLE_CHUNK_IF_SAFE 2 +#endif + +/* Utility to save typing/errors, the argument must be a name */ +#define MEMZERO(var) ((void)memset(&var, 0, sizeof var)) + /* Example of using row callbacks to make a simple progress meter */ static int status_pass = 1; static int status_dots_requested = 0; @@ -156,13 +144,8 @@ static int status_dots = 1; static void PNGCBAPI read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) { - /* The callback should always receive correct parameters. */ - if (png_ptr == NULL) - png_error(png_ptr, "read_row_callback: bad png_ptr"); - if (row_number > PNG_UINT_31_MAX) - png_error(png_ptr, "read_row_callback: bad row number"); - if (pass < 0 || pass > 7) - png_error(png_ptr, "read_row_callback: bad pass"); + if (png_ptr == NULL || row_number > PNG_UINT_31_MAX) + return; if (status_pass != pass) { @@ -176,7 +159,7 @@ read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) if (status_dots == 0) { fprintf(stdout, "\n "); - status_dots = 30; + status_dots=30; } fprintf(stdout, "r"); @@ -186,13 +169,8 @@ read_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) static void PNGCBAPI write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) { - /* The callback should always receive correct parameters. */ - if (png_ptr == NULL) - png_error(png_ptr, "write_row_callback: bad png_ptr"); - if (row_number > PNG_UINT_31_MAX) - png_error(png_ptr, "write_row_callback: bad row number"); - if (pass < 0 || pass > 7) - png_error(png_ptr, "write_row_callback: bad pass"); + if (png_ptr == NULL || row_number > PNG_UINT_31_MAX || pass > 7) + return; fprintf(stdout, "w"); } @@ -200,18 +178,16 @@ write_row_callback(png_structp png_ptr, png_uint_32 row_number, int pass) #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED -/* Example of using a user transform callback (doesn't do anything at present). +/* Example of using user transform callback (we don't transform anything, + * but merely examine the row filters. We set this to 256 rather than + * 5 in case illegal filter values are present.) */ +static png_uint_32 filters_used[256]; static void PNGCBAPI -read_user_callback(png_structp png_ptr, png_row_infop row_info, png_bytep data) +count_filters(png_structp png_ptr, png_row_infop row_info, png_bytep data) { - /* The callback should always receive correct parameters. */ - if (png_ptr == NULL) - png_error(png_ptr, "read_user_callback: bad png_ptr"); - if (row_info == NULL) - png_error(png_ptr, "read_user_callback: bad row info"); - if (data == NULL) - png_error(png_ptr, "read_user_callback: bad data"); + if (png_ptr != NULL && row_info != NULL) + ++filters_used[*(data - 1)]; } #endif @@ -226,14 +202,8 @@ static void PNGCBAPI count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) { png_bytep dp = data; - - /* The callback should always receive correct parameters. */ if (png_ptr == NULL) - png_error(png_ptr, "count_zero_samples: bad png_ptr"); - if (row_info == NULL) - png_error(png_ptr, "count_zero_samples: bad row info"); - if (data == NULL) - png_error(png_ptr, "count_zero_samples: bad data"); + return; /* Contents of row_info: * png_uint_32 width width of row @@ -244,97 +214,96 @@ count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) * png_byte pixel_depth bits per pixel (depth*channels) */ - /* Counts the number of zero samples (or zero pixels if color_type is 3 */ + /* Counts the number of zero samples (or zero pixels if color_type is 3 */ - if (row_info->color_type == 0 || row_info->color_type == 3) - { - int pos = 0; - png_uint_32 n, nstop; + if (row_info->color_type == 0 || row_info->color_type == 3) + { + int pos = 0; + png_uint_32 n, nstop; - for (n = 0, nstop = row_info->width; n < nstop; n++) - { - if (row_info->bit_depth == 1) - { - if (((*dp << pos++ ) & 0x80) == 0) - zero_samples++; + for (n = 0, nstop=row_info->width; nbit_depth == 1) + { + if (((*dp << pos++ ) & 0x80) == 0) + zero_samples++; - if (pos == 8) - { - pos = 0; - dp++; - } - } + if (pos == 8) + { + pos = 0; + dp++; + } + } - if (row_info->bit_depth == 2) - { - if (((*dp << (pos+=2)) & 0xc0) == 0) - zero_samples++; + if (row_info->bit_depth == 2) + { + if (((*dp << (pos+=2)) & 0xc0) == 0) + zero_samples++; - if (pos == 8) - { - pos = 0; - dp++; - } - } + if (pos == 8) + { + pos = 0; + dp++; + } + } - if (row_info->bit_depth == 4) - { - if (((*dp << (pos+=4)) & 0xf0) == 0) - zero_samples++; + if (row_info->bit_depth == 4) + { + if (((*dp << (pos+=4)) & 0xf0) == 0) + zero_samples++; - if (pos == 8) - { - pos = 0; - dp++; - } - } + if (pos == 8) + { + pos = 0; + dp++; + } + } - if (row_info->bit_depth == 8) - if (*dp++ == 0) - zero_samples++; + if (row_info->bit_depth == 8) + if (*dp++ == 0) + zero_samples++; - if (row_info->bit_depth == 16) - { - if ((*dp | *(dp+1)) == 0) - zero_samples++; - dp += 2; - } - } - } - else /* Other color types */ - { - png_uint_32 n, nstop; - int channel; - int color_channels = row_info->channels; - if (row_info->color_type > 3) - color_channels--; + if (row_info->bit_depth == 16) + { + if ((*dp | *(dp+1)) == 0) + zero_samples++; + dp+=2; + } + } + } + else /* Other color types */ + { + png_uint_32 n, nstop; + int channel; + int color_channels = row_info->channels; + if (row_info->color_type > 3)color_channels--; - for (n = 0, nstop = row_info->width; n < nstop; n++) - { - for (channel = 0; channel < color_channels; channel++) - { - if (row_info->bit_depth == 8) - if (*dp++ == 0) - zero_samples++; + for (n = 0, nstop=row_info->width; nbit_depth == 8) + if (*dp++ == 0) + zero_samples++; - if (row_info->bit_depth == 16) - { - if ((*dp | *(dp+1)) == 0) - zero_samples++; + if (row_info->bit_depth == 16) + { + if ((*dp | *(dp+1)) == 0) + zero_samples++; - dp += 2; - } - } - if (row_info->color_type > 3) - { - dp++; - if (row_info->bit_depth == 16) - dp++; - } - } - } + dp+=2; + } + } + if (row_info->color_type > 3) + { + dp++; + if (row_info->bit_depth == 16) + dp++; + } + } + } } -#endif /* WRITE_USER_TRANSFORM */ +#endif /* PNG_WRITE_USER_TRANSFORM_SUPPORTED */ #ifndef PNG_STDIO_SUPPORTED /* START of code to validate stdio-free compilation */ @@ -348,8 +317,11 @@ count_zero_samples(png_structp png_ptr, png_row_infop row_info, png_bytep data) #ifdef PNG_IO_STATE_SUPPORTED void -pngtest_check_io_state(png_structp png_ptr, size_t data_length, - png_uint_32 io_op) +pngtest_check_io_state(png_structp png_ptr, png_size_t data_length, + png_uint_32 io_op); +void +pngtest_check_io_state(png_structp png_ptr, png_size_t data_length, + png_uint_32 io_op) { png_uint_32 io_state = png_get_io_state(png_ptr); int err = 0; @@ -361,7 +333,7 @@ pngtest_check_io_state(png_structp png_ptr, size_t data_length, /* Check if the buffer size specific to the current location * (file signature / header / data / crc) is as expected. */ - switch ((io_state & PNG_IO_MASK_LOC) != 0) + switch (io_state & PNG_IO_MASK_LOC) { case PNG_IO_SIGNATURE: if (data_length > 8) @@ -380,29 +352,30 @@ pngtest_check_io_state(png_structp png_ptr, size_t data_length, default: err = 1; /* uninitialized */ } - if (err != 0) + if (err) png_error(png_ptr, "Bad I/O state or buffer size"); } #endif static void PNGCBAPI -pngtest_read_data(png_structp png_ptr, png_bytep data, size_t length) +pngtest_read_data(png_structp png_ptr, png_bytep data, png_size_t length) { - size_t check = 0; + png_size_t check = 0; png_voidp io_ptr; - if (png_ptr == NULL) - png_error(png_ptr, "pngtest_read_data: bad png_ptr"); - - /* fread() returns 0 on error, so it is OK to store this in a size_t + /* fread() returns 0 on error, so it is OK to store this in a png_size_t * instead of an int, which is what fread() actually returns. */ io_ptr = png_get_io_ptr(png_ptr); if (io_ptr != NULL) - check = fread(data, 1, length, (FILE *)io_ptr); + { + check = fread(data, 1, length, (png_FILE_p)io_ptr); + } if (check != length) + { png_error(png_ptr, "Read Error"); + } #ifdef PNG_IO_STATE_SUPPORTED pngtest_check_io_state(png_ptr, length, PNG_IO_READING); @@ -413,10 +386,8 @@ pngtest_read_data(png_structp png_ptr, png_bytep data, size_t length) static void PNGCBAPI pngtest_flush(png_structp png_ptr) { - if (png_ptr == NULL) - png_error(png_ptr, "pngtest_flush: bad png_ptr"); - /* Do nothing; fflush() is said to be just a waste of energy. */ + PNG_UNUSED(png_ptr) /* Stifle compiler warning */ } #endif @@ -426,23 +397,22 @@ pngtest_flush(png_structp png_ptr) * than changing the library. */ static void PNGCBAPI -pngtest_write_data(png_structp png_ptr, png_bytep data, size_t length) +pngtest_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { - size_t check; + png_size_t check; - if (png_ptr == NULL) - png_error(png_ptr, "pngtest_write_data: bad png_ptr"); - - check = fwrite(data, 1, length, (FILE *)png_get_io_ptr(png_ptr)); + check = fwrite(data, 1, length, (png_FILE_p)png_get_io_ptr(png_ptr)); if (check != length) + { png_error(png_ptr, "Write Error"); + } #ifdef PNG_IO_STATE_SUPPORTED pngtest_check_io_state(png_ptr, length, PNG_IO_WRITING); #endif } -#endif /* !STDIO */ +#endif /* !PNG_STDIO_SUPPORTED */ /* This function is called when there is a warning, but the library thinks * it can continue anyway. Replacement functions don't have to do anything @@ -451,13 +421,13 @@ pngtest_write_data(png_structp png_ptr, png_bytep data, size_t length) */ typedef struct { - const char *file_name; + PNG_CONST char *file_name; } pngtest_error_parameters; static void PNGCBAPI pngtest_warning(png_structp png_ptr, png_const_charp message) { - const char *name = "UNKNOWN (ERROR!)"; + PNG_CONST char *name = "UNKNOWN (ERROR!)"; pngtest_error_parameters *test = (pngtest_error_parameters*)png_get_error_ptr(png_ptr); @@ -466,7 +436,7 @@ pngtest_warning(png_structp png_ptr, png_const_charp message) if (test != NULL && test->file_name != NULL) name = test->file_name; - fprintf(STDERR, "\n%s: libpng warning: %s\n", name, message); + fprintf(STDERR, "%s: libpng warning: %s\n", name, message); } /* This is the default error handling function. Note that replacements for @@ -491,7 +461,7 @@ pngtest_error(png_structp png_ptr, png_const_charp message) #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG /* Allocate memory. For reasonable files, size should never exceed - * 64K. However, zlib may allocate more than 64K if you don't tell + * 64K. However, zlib may allocate more then 64K if you don't tell * it not to. See zconf.h and png.h for more information. zlib does * need to allocate exactly 64K, so whatever you call here must * have the ability to do that. @@ -501,8 +471,8 @@ pngtest_error(png_structp png_ptr, png_const_charp message) */ typedef struct memory_information { - png_alloc_size_t size; - png_voidp pointer; + png_alloc_size_t size; + png_voidp pointer; struct memory_information *next; } memory_information; typedef memory_information *memory_infop; @@ -513,9 +483,9 @@ static int maximum_allocation = 0; static int total_allocation = 0; static int num_allocations = 0; -png_voidp PNGCBAPI png_debug_malloc(png_structp png_ptr, - png_alloc_size_t size); -void PNGCBAPI png_debug_free(png_structp png_ptr, png_voidp ptr); +png_voidp PNGCBAPI png_debug_malloc PNGARG((png_structp png_ptr, + png_alloc_size_t size)); +void PNGCBAPI png_debug_free PNGARG((png_structp png_ptr, png_voidp ptr)); png_voidp PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size) @@ -526,7 +496,7 @@ PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size) */ if (size == 0) - return NULL; + return (NULL); /* This calls the library allocator twice, once to get the requested buffer and once to get a new free list entry. */ @@ -535,11 +505,11 @@ PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size) memory_infop pinfo; png_set_mem_fn(png_ptr, NULL, NULL, NULL); pinfo = (memory_infop)png_malloc(png_ptr, - (sizeof *pinfo)); + (sizeof *pinfo)); pinfo->size = size; current_allocation += size; total_allocation += size; - ++num_allocations; + num_allocations ++; if (current_allocation > maximum_allocation) maximum_allocation = current_allocation; @@ -563,11 +533,11 @@ PNGCBAPI png_debug_malloc(png_structp png_ptr, png_alloc_size_t size) /* Make sure the caller isn't assuming zeroed memory. */ memset(pinfo->pointer, 0xdd, pinfo->size); - if (verbose != 0) + if (verbose) printf("png_malloc %lu bytes at %p\n", (unsigned long)size, - pinfo->pointer); + pinfo->pointer); - return (png_voidp)pinfo->pointer; + return (png_voidp)(pinfo->pointer); } } @@ -587,7 +557,6 @@ png_debug_free(png_structp png_ptr, png_voidp ptr) } /* Unlink the element from the list. */ - if (pinformation != NULL) { memory_infop *ppinfo = &pinformation; @@ -604,14 +573,14 @@ png_debug_free(png_structp png_ptr, png_voidp ptr) /* We must free the list element too, but first kill the memory that is to be freed. */ memset(ptr, 0x55, pinfo->size); - free(pinfo); + png_free_default(png_ptr, pinfo); pinfo = NULL; break; } if (pinfo->next == NULL) { - fprintf(STDERR, "Pointer %p not found\n", ptr); + fprintf(STDERR, "Pointer %x not found\n", (unsigned int)ptr); break; } @@ -620,14 +589,13 @@ png_debug_free(png_structp png_ptr, png_voidp ptr) } /* Finally free the data. */ - if (verbose != 0) + if (verbose) printf("Freeing %p\n", ptr); - if (ptr != NULL) - free(ptr); + png_free_default(png_ptr, ptr); ptr = NULL; } -#endif /* USER_MEM && DEBUG */ +#endif /* PNG_USER_MEM_SUPPORTED && PNG_DEBUG */ /* END of code to test memory allocation/deallocation */ @@ -637,14 +605,15 @@ png_debug_free(png_structp png_ptr, png_voidp ptr) /* (sTER is a public chunk not yet known by libpng. vpAg is a private chunk used in ImageMagick to store "virtual page" size). */ -typedef struct user_chunk_info_def +static struct user_chunk_data { png_const_infop info_ptr; - png_uint_32 vpAg_width, vpAg_height; - png_byte vpAg_units; - png_byte sTER_mode; - int location[2]; -} user_chunk_info; + png_uint_32 vpAg_width, vpAg_height; + png_byte vpAg_units; + png_byte sTER_mode; + int location[2]; +} +user_chunk_data; /* Used for location and order; zero means nothing. */ #define have_sTER 0x01 @@ -654,60 +623,59 @@ typedef struct user_chunk_info_def #define after_IDAT 0x40 static void -init_user_chunk_info(png_const_infop info_ptr, user_chunk_info *chunk_data) +init_callback_info(png_const_infop info_ptr) { - memset(chunk_data, 0, sizeof(*chunk_data)); - chunk_data->info_ptr = info_ptr; + MEMZERO(user_chunk_data); + user_chunk_data.info_ptr = info_ptr; } static int -set_chunk_location(png_structp png_ptr, user_chunk_info *chunk_data, int what) +set_location(png_structp png_ptr, struct user_chunk_data *data, int what) { int location; - if ((chunk_data->location[0] & what) != 0 || - (chunk_data->location[1] & what) != 0) - return 0; /* we already have one of these */ + if ((data->location[0] & what) || (data->location[1] & what)) + return 0; /* already have one of these */ - /* Find where we are (the code below zeroes info_ptr to indicate that the + /* Find where we are (the code below zeros info_ptr to indicate that the * chunks before the first IDAT have been read.) */ - if (chunk_data->info_ptr == NULL) /* after IDAT */ + if (data->info_ptr == NULL) /* after IDAT */ location = what | after_IDAT; - else if (png_get_valid(png_ptr, chunk_data->info_ptr, PNG_INFO_PLTE) != 0) + else if (png_get_valid(png_ptr, data->info_ptr, PNG_INFO_PLTE)) location = what | before_IDAT; else location = what | before_PLTE; - if (chunk_data->location[0] == 0) - chunk_data->location[0] = location; + if (data->location[0] == 0) + data->location[0] = location; else - chunk_data->location[1] = location; + data->location[1] = location; return 1; /* handled */ } -static int PNGCBAPI -read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk) +static int PNGCBAPI read_user_chunk_callback(png_struct *png_ptr, + png_unknown_chunkp chunk) { - user_chunk_info *my_user_chunk_data = - (user_chunk_info*)png_get_user_chunk_ptr(png_ptr); + struct user_chunk_data *my_user_chunk_data = + (struct user_chunk_data*)png_get_user_chunk_ptr(png_ptr); if (my_user_chunk_data == NULL) - png_error(png_ptr, "lost pointer to user chunk data"); + png_error(png_ptr, "lost user chunk pointer"); /* Return one of the following: - * return -n; chunk had an error - * return 0; did not recognize - * return n; success + * return (-n); chunk had an error + * return (0); did not recognize + * return (n); success * * The unknown chunk structure contains the chunk data: * png_byte name[5]; * png_byte *data; - * size_t size; + * png_size_t size; * * Note that libpng has already taken care of the CRC handling. */ @@ -717,73 +685,73 @@ read_user_chunk_callback(png_struct *png_ptr, png_unknown_chunkp chunk) { /* Found sTER chunk */ if (chunk->size != 1) - return -1; /* Error return */ + return (-1); /* Error return */ if (chunk->data[0] != 0 && chunk->data[0] != 1) - return -1; /* Invalid mode */ + return (-1); /* Invalid mode */ - if (set_chunk_location(png_ptr, my_user_chunk_data, have_sTER) != 0) + if (set_location(png_ptr, my_user_chunk_data, have_sTER)) { - my_user_chunk_data->sTER_mode = chunk->data[0]; - return 1; + my_user_chunk_data->sTER_mode=chunk->data[0]; + return (1); } else - return 0; /* duplicate sTER - give it to libpng */ + return (0); /* duplicate sTER - give it to libpng */ } if (chunk->name[0] != 118 || chunk->name[1] != 112 || /* v p */ chunk->name[2] != 65 || chunk->name[3] != 103) /* A g */ - return 0; /* Did not recognize */ + return (0); /* Did not recognize */ /* Found ImageMagick vpAg chunk */ if (chunk->size != 9) - return -1; /* Error return */ + return (-1); /* Error return */ - if (set_chunk_location(png_ptr, my_user_chunk_data, have_vpAg) == 0) - return 0; /* duplicate vpAg */ + if (!set_location(png_ptr, my_user_chunk_data, have_vpAg)) + return (0); /* duplicate vpAg */ my_user_chunk_data->vpAg_width = png_get_uint_31(png_ptr, chunk->data); my_user_chunk_data->vpAg_height = png_get_uint_31(png_ptr, chunk->data + 4); my_user_chunk_data->vpAg_units = chunk->data[8]; - return 1; + return (1); } #ifdef PNG_WRITE_SUPPORTED static void -write_sTER_chunk(png_structp write_ptr, user_chunk_info *data) +write_sTER_chunk(png_structp write_ptr) { - png_byte sTER[5] = {115, 84, 69, 82, '\0'}; + png_byte png_sTER[5] = {115, 84, 69, 82, '\0'}; - if (verbose != 0) - fprintf(STDERR, "\n stereo mode = %d\n", data->sTER_mode); + if (verbose) + fprintf(STDERR, "\n stereo mode = %d\n", user_chunk_data.sTER_mode); - png_write_chunk(write_ptr, sTER, &data->sTER_mode, 1); + png_write_chunk(write_ptr, png_sTER, &user_chunk_data.sTER_mode, 1); } static void -write_vpAg_chunk(png_structp write_ptr, user_chunk_info *data) +write_vpAg_chunk(png_structp write_ptr) { - png_byte vpAg[5] = {118, 112, 65, 103, '\0'}; + png_byte png_vpAg[5] = {118, 112, 65, 103, '\0'}; png_byte vpag_chunk_data[9]; - if (verbose != 0) + if (verbose) fprintf(STDERR, " vpAg = %lu x %lu, units = %d\n", - (unsigned long)data->vpAg_width, - (unsigned long)data->vpAg_height, - data->vpAg_units); + (unsigned long)user_chunk_data.vpAg_width, + (unsigned long)user_chunk_data.vpAg_height, + user_chunk_data.vpAg_units); - png_save_uint_32(vpag_chunk_data, data->vpAg_width); - png_save_uint_32(vpag_chunk_data + 4, data->vpAg_height); - vpag_chunk_data[8] = data->vpAg_units; - png_write_chunk(write_ptr, vpAg, vpag_chunk_data, 9); + png_save_uint_32(vpag_chunk_data, user_chunk_data.vpAg_width); + png_save_uint_32(vpag_chunk_data + 4, user_chunk_data.vpAg_height); + vpag_chunk_data[8] = user_chunk_data.vpAg_units; + png_write_chunk(write_ptr, png_vpAg, vpag_chunk_data, 9); } static void -write_chunks(png_structp write_ptr, user_chunk_info *data, int location) +write_chunks(png_structp write_ptr, int location) { int i; @@ -793,17 +761,17 @@ write_chunks(png_structp write_ptr, user_chunk_info *data, int location) * vpAg chunks, resulting in an error later. This is not worth worrying * about - the chunks should not be duplicated! */ - for (i = 0; i < 2; ++i) + for (i=0; i<2; ++i) { - if (data->location[i] == (location | have_sTER)) - write_sTER_chunk(write_ptr, data); + if (user_chunk_data.location[i] == (location | have_sTER)) + write_sTER_chunk(write_ptr); - else if (data->location[i] == (location | have_vpAg)) - write_vpAg_chunk(write_ptr, data); + else if (user_chunk_data.location[i] == (location | have_vpAg)) + write_vpAg_chunk(write_ptr); } } -#endif /* WRITE */ -#else /* !READ_USER_CHUNKS */ +#endif /* PNG_WRITE_SUPPORTED */ +#else /* !PNG_READ_USER_CHUNKS_SUPPORTED */ # define write_chunks(pp,loc) ((void)0) #endif /* END of code to demonstrate user chunk support */ @@ -814,8 +782,8 @@ write_chunks(png_structp write_ptr, user_chunk_info *data, int location) */ #ifdef PNG_TEXT_SUPPORTED static void -pngtest_check_text_support(png_structp png_ptr, png_textp text_ptr, - int num_text) +pngtest_check_text_support(png_const_structp png_ptr, png_textp text_ptr, + int num_text) { while (num_text > 0) { @@ -827,8 +795,6 @@ pngtest_check_text_support(png_structp png_ptr, png_textp text_ptr, case PNG_TEXT_COMPRESSION_zTXt: # ifndef PNG_WRITE_zTXt_SUPPORTED ++unsupported_chunks; - /* In libpng 1.7 this now does an app-error, so stop it: */ - text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE; # endif break; @@ -836,7 +802,6 @@ pngtest_check_text_support(png_structp png_ptr, png_textp text_ptr, case PNG_ITXT_COMPRESSION_zTXt: # ifndef PNG_WRITE_iTXt_SUPPORTED ++unsupported_chunks; - text_ptr[num_text].compression = PNG_TEXT_COMPRESSION_NONE; # endif break; @@ -852,10 +817,10 @@ pngtest_check_text_support(png_structp png_ptr, png_textp text_ptr, /* Test one file */ static int -test_one_file(const char *inname, const char *outname) +test_one_file(PNG_CONST char *inname, PNG_CONST char *outname) { - static FILE *fpin; - static FILE *fpout; /* "static" prevents setjmp corruption */ + static png_FILE_p fpin; + static png_FILE_p fpout; /* "static" prevents setjmp corruption */ pngtest_error_parameters error_parameters; png_structp read_ptr; png_infop read_info_ptr, end_info_ptr; @@ -863,20 +828,16 @@ test_one_file(const char *inname, const char *outname) png_structp write_ptr; png_infop write_info_ptr; png_infop write_end_info_ptr; -#ifdef PNG_WRITE_FILTER_SUPPORTED - int interlace_preserved = 1; -#endif /* WRITE_FILTER */ -#else /* !WRITE */ +#else png_structp write_ptr = NULL; png_infop write_info_ptr = NULL; png_infop write_end_info_ptr = NULL; -#endif /* !WRITE */ +#endif png_bytep row_buf; png_uint_32 y; png_uint_32 width, height; + int num_pass, pass; int bit_depth, color_type; - user_chunk_info my_user_chunk_data; - int pass, num_passes; row_buf = NULL; error_parameters.file_name = inname; @@ -884,39 +845,39 @@ test_one_file(const char *inname, const char *outname) if ((fpin = fopen(inname, "rb")) == NULL) { fprintf(STDERR, "Could not find input file %s\n", inname); - return 1; + return (1); } if ((fpout = fopen(outname, "wb")) == NULL) { fprintf(STDERR, "Could not open output file %s\n", outname); - fclose(fpin); - return 1; + FCLOSE(fpin); + return (1); } pngtest_debug("Allocating read and write structures"); #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG read_ptr = - png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, - NULL, NULL, NULL, png_debug_malloc, png_debug_free); + png_create_read_struct_2(PNG_LIBPNG_VER_STRING, NULL, + NULL, NULL, NULL, png_debug_malloc, png_debug_free); #else read_ptr = - png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); #endif png_set_error_fn(read_ptr, &error_parameters, pngtest_error, - pngtest_warning); + pngtest_warning); #ifdef PNG_WRITE_SUPPORTED #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG write_ptr = - png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, - NULL, NULL, NULL, png_debug_malloc, png_debug_free); + png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, + NULL, NULL, NULL, png_debug_malloc, png_debug_free); #else write_ptr = - png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); #endif png_set_error_fn(write_ptr, &error_parameters, pngtest_error, - pngtest_warning); + pngtest_warning); #endif pngtest_debug("Allocating read_info, write_info and end_info structures"); read_info_ptr = png_create_info_struct(read_ptr); @@ -927,9 +888,9 @@ test_one_file(const char *inname, const char *outname) #endif #ifdef PNG_READ_USER_CHUNKS_SUPPORTED - init_user_chunk_info(read_info_ptr, &my_user_chunk_data); - png_set_read_user_chunk_fn(read_ptr, &my_user_chunk_data, - read_user_chunk_callback); + init_callback_info(read_info_ptr); + png_set_read_user_chunk_fn(read_ptr, &user_chunk_data, + read_user_chunk_callback); #endif #ifdef PNG_SETJMP_SUPPORTED @@ -939,18 +900,14 @@ test_one_file(const char *inname, const char *outname) fprintf(STDERR, "%s -> %s: libpng read error\n", inname, outname); png_free(read_ptr, row_buf); row_buf = NULL; - if (verbose != 0) - fprintf(STDERR, " destroy read structs\n"); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); #ifdef PNG_WRITE_SUPPORTED - if (verbose != 0) - fprintf(STDERR, " destroy write structs\n"); png_destroy_info_struct(write_ptr, &write_end_info_ptr); png_destroy_write_struct(&write_ptr, &write_info_ptr); #endif - fclose(fpin); - fclose(fpout); - return 1; + FCLOSE(fpin); + FCLOSE(fpout); + return (1); } #ifdef PNG_WRITE_SUPPORTED @@ -959,32 +916,27 @@ test_one_file(const char *inname, const char *outname) if (setjmp(png_jmpbuf(write_ptr))) { fprintf(STDERR, "%s -> %s: libpng write error\n", inname, outname); - png_free(read_ptr, row_buf); - row_buf = NULL; - if (verbose != 0) - fprintf(STDERR, " destroying read structs\n"); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); - if (verbose != 0) - fprintf(STDERR, " destroying write structs\n"); png_destroy_info_struct(write_ptr, &write_end_info_ptr); +#ifdef PNG_WRITE_SUPPORTED png_destroy_write_struct(&write_ptr, &write_info_ptr); - fclose(fpin); - fclose(fpout); - return 1; +#endif + FCLOSE(fpin); + FCLOSE(fpout); + return (1); } #endif #endif -#ifdef PNG_BENIGN_ERRORS_SUPPORTED - if (strict != 0) + if (strict) { /* Treat png_benign_error() as errors on read */ png_set_benign_errors(read_ptr, 0); -# ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_SUPPORTED /* Treat them as errors on write */ png_set_benign_errors(write_ptr, 0); -# endif +#endif /* if strict is not set, then app warnings and errors are treated as * warnings in release builds, but not in unstable builds; this can be @@ -992,25 +944,15 @@ test_one_file(const char *inname, const char *outname) */ } - else if (relaxed != 0) + else if (relaxed) { /* Allow application (pngtest) errors and warnings to pass */ png_set_benign_errors(read_ptr, 1); - /* Turn off CRC checking while reading */ - png_set_crc_action(read_ptr, PNG_CRC_QUIET_USE, PNG_CRC_QUIET_USE); - -#ifdef PNG_IGNORE_ADLER32 - /* Turn off ADLER32 checking while reading */ - png_set_option(read_ptr, PNG_IGNORE_ADLER32, PNG_OPTION_ON); -#endif - -# ifdef PNG_WRITE_SUPPORTED +#ifdef PNG_WRITE_SUPPORTED png_set_benign_errors(write_ptr, 1); -# endif - +#endif } -#endif /* BENIGN_ERRORS */ pngtest_debug("Initializing input and output streams"); #ifdef PNG_STDIO_SUPPORTED @@ -1023,9 +965,9 @@ test_one_file(const char *inname, const char *outname) # ifdef PNG_WRITE_SUPPORTED png_set_write_fn(write_ptr, (png_voidp)fpout, pngtest_write_data, # ifdef PNG_WRITE_FLUSH_SUPPORTED - pngtest_flush); + pngtest_flush); # else - NULL); + NULL); # endif # endif #endif @@ -1047,7 +989,14 @@ test_one_file(const char *inname, const char *outname) } #ifdef PNG_READ_USER_TRANSFORM_SUPPORTED - png_set_read_user_transform_fn(read_ptr, read_user_callback); + { + int i; + + for (i = 0; i<256; i++) + filters_used[i] = 0; + + png_set_read_user_transform_fn(read_ptr, count_filters); + } #endif #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED zero_samples = 0; @@ -1055,21 +1004,21 @@ test_one_file(const char *inname, const char *outname) #endif #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED - /* Preserve all the unknown chunks, if possible. If this is disabled, then + /* Preserve all the unknown chunks, if possible. If this is disabled then, * even if the png_{get,set}_unknown_chunks stuff is enabled, we can't use * libpng to *save* the unknown chunks on read (because we can't switch the * save option on!) * - * Notice that if SET_UNKNOWN_CHUNKS is *not* supported, the reader will - * discard all unknown chunks, and the writer will write them all. + * Notice that if SET_UNKNOWN_CHUNKS is *not* supported read will discard all + * unknown chunks and write will write them all. */ #ifdef PNG_SAVE_UNKNOWN_CHUNKS_SUPPORTED png_set_keep_unknown_chunks(read_ptr, PNG_HANDLE_CHUNK_ALWAYS, - NULL, 0); + NULL, 0); #endif #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED png_set_keep_unknown_chunks(write_ptr, PNG_HANDLE_CHUNK_ALWAYS, - NULL, 0); + NULL, 0); #endif #endif @@ -1082,7 +1031,7 @@ test_one_file(const char *inname, const char *outname) * remove the info_ptr (which is only used to determine position relative to * PLTE) here to indicate that we are after the IDAT. */ - my_user_chunk_data.info_ptr = NULL; + user_chunk_data.info_ptr = NULL; #endif pngtest_debug("Transferring info struct"); @@ -1090,43 +1039,27 @@ test_one_file(const char *inname, const char *outname) int interlace_type, compression_type, filter_type; if (png_get_IHDR(read_ptr, read_info_ptr, &width, &height, &bit_depth, - &color_type, &interlace_type, &compression_type, &filter_type) != 0) + &color_type, &interlace_type, &compression_type, &filter_type)) { png_set_IHDR(write_ptr, write_info_ptr, width, height, bit_depth, - color_type, interlace_type, compression_type, filter_type); - /* num_passes may not be available below if interlace support is not - * provided by libpng for both read and write. - */ - switch (interlace_type) - { - case PNG_INTERLACE_NONE: - num_passes = 1; - break; - - case PNG_INTERLACE_ADAM7: - num_passes = 7; - break; - - default: - png_error(read_ptr, "invalid interlace type"); - /*NOT REACHED*/ - } +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + color_type, interlace_type, compression_type, filter_type); +#else + color_type, PNG_INTERLACE_NONE, compression_type, filter_type); +#endif } - - else - png_error(read_ptr, "png_get_IHDR failed"); } #ifdef PNG_FIXED_POINT_SUPPORTED #ifdef PNG_cHRM_SUPPORTED { png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x, - blue_y; + blue_y; if (png_get_cHRM_fixed(read_ptr, read_info_ptr, &white_x, &white_y, - &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0) + &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y)) { png_set_cHRM_fixed(write_ptr, write_info_ptr, white_x, white_y, red_x, - red_y, green_x, green_y, blue_x, blue_y); + red_y, green_x, green_y, blue_x, blue_y); } } #endif @@ -1134,46 +1067,22 @@ test_one_file(const char *inname, const char *outname) { png_fixed_point gamma; - if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma) != 0) + if (png_get_gAMA_fixed(read_ptr, read_info_ptr, &gamma)) png_set_gAMA_fixed(write_ptr, write_info_ptr, gamma); } #endif -#ifdef PNG_cLLI_SUPPORTED - { - png_uint_32 maxCLL; - png_uint_32 maxFALL; - - if (png_get_cLLI_fixed(read_ptr, read_info_ptr, &maxCLL, &maxFALL) != 0) - png_set_cLLI_fixed(write_ptr, write_info_ptr, maxCLL, maxFALL); - } -#endif -#ifdef PNG_mDCV_SUPPORTED - { - png_fixed_point white_x, white_y, red_x, red_y, green_x, green_y, blue_x, - blue_y; - png_uint_32 maxDL; - png_uint_32 minDL; - - if (png_get_mDCV_fixed(read_ptr, read_info_ptr, &white_x, &white_y, - &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y, - &maxDL, &minDL) != 0) - png_set_mDCV_fixed(write_ptr, write_info_ptr, white_x, white_y, - red_x, red_y, green_x, green_y, blue_x, blue_y, - maxDL, minDL); - } -#endif #else /* Use floating point versions */ #ifdef PNG_FLOATING_POINT_SUPPORTED #ifdef PNG_cHRM_SUPPORTED { double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, - blue_y; + blue_y; if (png_get_cHRM(read_ptr, read_info_ptr, &white_x, &white_y, &red_x, - &red_y, &green_x, &green_y, &blue_x, &blue_y) != 0) + &red_y, &green_x, &green_y, &blue_x, &blue_y)) { png_set_cHRM(write_ptr, write_info_ptr, white_x, white_y, red_x, - red_y, green_x, green_y, blue_x, blue_y); + red_y, green_x, green_y, blue_x, blue_y); } } #endif @@ -1181,50 +1090,12 @@ test_one_file(const char *inname, const char *outname) { double gamma; - if (png_get_gAMA(read_ptr, read_info_ptr, &gamma) != 0) + if (png_get_gAMA(read_ptr, read_info_ptr, &gamma)) png_set_gAMA(write_ptr, write_info_ptr, gamma); } #endif -#ifdef PNG_cLLI_SUPPORTED - { - double maxCLL; - double maxFALL; - - if (png_get_cLLI(read_ptr, read_info_ptr, &maxCLL, &maxFALL) != 0) - png_set_cLLI(write_ptr, write_info_ptr, maxCLL, maxFALL); - } -#endif -#ifdef PNG_mDCV_SUPPORTED - { - double white_x, white_y, red_x, red_y, green_x, green_y, blue_x, blue_y; - double maxDL; - double minDL; - - if (png_get_mDCV(read_ptr, read_info_ptr, &white_x, &white_y, - &red_x, &red_y, &green_x, &green_y, &blue_x, &blue_y, - &maxDL, &minDL) != 0) - png_set_mDCV(write_ptr, write_info_ptr, white_x, white_y, - red_x, red_y, green_x, green_y, blue_x, blue_y, - maxDL, minDL); - } -#endif #endif /* Floating point */ #endif /* Fixed point */ -#ifdef PNG_cICP_SUPPORTED - { - png_byte colour_primaries; - png_byte transfer_function; - png_byte matrix_coefficients; - png_byte video_full_range_flag; - - if (png_get_cICP(read_ptr, read_info_ptr, - &colour_primaries, &transfer_function, - &matrix_coefficients, &video_full_range_flag) != 0) - png_set_cICP(write_ptr, write_info_ptr, - colour_primaries, transfer_function, - matrix_coefficients, video_full_range_flag); - } -#endif #ifdef PNG_iCCP_SUPPORTED { png_charp name; @@ -1233,10 +1104,10 @@ test_one_file(const char *inname, const char *outname) int compression_type; if (png_get_iCCP(read_ptr, read_info_ptr, &name, &compression_type, - &profile, &proflen) != 0) + &profile, &proflen)) { png_set_iCCP(write_ptr, write_info_ptr, name, compression_type, - profile, proflen); + profile, proflen); } } #endif @@ -1244,7 +1115,7 @@ test_one_file(const char *inname, const char *outname) { int intent; - if (png_get_sRGB(read_ptr, read_info_ptr, &intent) != 0) + if (png_get_sRGB(read_ptr, read_info_ptr, &intent)) png_set_sRGB(write_ptr, write_info_ptr, intent); } #endif @@ -1252,30 +1123,16 @@ test_one_file(const char *inname, const char *outname) png_colorp palette; int num_palette; - if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette) != 0) + if (png_get_PLTE(read_ptr, read_info_ptr, &palette, &num_palette)) png_set_PLTE(write_ptr, write_info_ptr, palette, num_palette); } #ifdef PNG_bKGD_SUPPORTED { png_color_16p background; - if (png_get_bKGD(read_ptr, read_info_ptr, &background) != 0) - png_set_bKGD(write_ptr, write_info_ptr, background); - } -#endif -#ifdef PNG_READ_eXIf_SUPPORTED - { - png_bytep exif = NULL; - png_uint_32 exif_length; - - if (png_get_eXIf_1(read_ptr, read_info_ptr, &exif_length, &exif) != 0) + if (png_get_bKGD(read_ptr, read_info_ptr, &background)) { - if (exif_length > 1) - fprintf(STDERR," eXIf type %c%c, %lu bytes\n",exif[0],exif[1], - (unsigned long)exif_length); -# ifdef PNG_WRITE_eXIf_SUPPORTED - png_set_eXIf_1(write_ptr, write_info_ptr, exif_length, exif); -# endif + png_set_bKGD(write_ptr, write_info_ptr, background); } } #endif @@ -1283,7 +1140,7 @@ test_one_file(const char *inname, const char *outname) { png_uint_16p hist; - if (png_get_hIST(read_ptr, read_info_ptr, &hist) != 0) + if (png_get_hIST(read_ptr, read_info_ptr, &hist)) png_set_hIST(write_ptr, write_info_ptr, hist); } #endif @@ -1293,8 +1150,10 @@ test_one_file(const char *inname, const char *outname) int unit_type; if (png_get_oFFs(read_ptr, read_info_ptr, &offset_x, &offset_y, - &unit_type) != 0) + &unit_type)) + { png_set_oFFs(write_ptr, write_info_ptr, offset_x, offset_y, unit_type); + } } #endif #ifdef PNG_pCAL_SUPPORTED @@ -1305,9 +1164,11 @@ test_one_file(const char *inname, const char *outname) int type, nparams; if (png_get_pCAL(read_ptr, read_info_ptr, &purpose, &X0, &X1, &type, - &nparams, &units, ¶ms) != 0) + &nparams, &units, ¶ms)) + { png_set_pCAL(write_ptr, write_info_ptr, purpose, X0, X1, type, - nparams, units, params); + nparams, units, params); + } } #endif #ifdef PNG_pHYs_SUPPORTED @@ -1315,8 +1176,7 @@ test_one_file(const char *inname, const char *outname) png_uint_32 res_x, res_y; int unit_type; - if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, - &unit_type) != 0) + if (png_get_pHYs(read_ptr, read_info_ptr, &res_x, &res_y, &unit_type)) png_set_pHYs(write_ptr, write_info_ptr, res_x, res_y, unit_type); } #endif @@ -1324,7 +1184,7 @@ test_one_file(const char *inname, const char *outname) { png_color_8p sig_bit; - if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit) != 0) + if (png_get_sBIT(read_ptr, read_info_ptr, &sig_bit)) png_set_sBIT(write_ptr, write_info_ptr, sig_bit); } #endif @@ -1336,8 +1196,10 @@ test_one_file(const char *inname, const char *outname) double scal_width, scal_height; if (png_get_sCAL(read_ptr, read_info_ptr, &unit, &scal_width, - &scal_height) != 0) + &scal_height)) + { png_set_sCAL(write_ptr, write_info_ptr, unit, scal_width, scal_height); + } } #else #ifdef PNG_FIXED_POINT_SUPPORTED @@ -1346,7 +1208,7 @@ test_one_file(const char *inname, const char *outname) png_charp scal_width, scal_height; if (png_get_sCAL_s(read_ptr, read_info_ptr, &unit, &scal_width, - &scal_height) != 0) + &scal_height)) { png_set_sCAL_s(write_ptr, write_info_ptr, unit, scal_width, scal_height); @@ -1355,17 +1217,6 @@ test_one_file(const char *inname, const char *outname) #endif #endif #endif - -#ifdef PNG_sPLT_SUPPORTED - { - png_sPLT_tp entries; - - int num_entries = png_get_sPLT(read_ptr, read_info_ptr, &entries); - if (num_entries != 0) - png_set_sPLT(write_ptr, write_info_ptr, entries, num_entries); - } -#endif - #ifdef PNG_TEXT_SUPPORTED { png_textp text_ptr; @@ -1377,15 +1228,15 @@ test_one_file(const char *inname, const char *outname) pngtest_check_text_support(read_ptr, text_ptr, num_text); - if (verbose != 0) + if (verbose) { int i; - fprintf(STDERR,"\n"); - for (i = 0; i < num_text; i++) + printf("\n"); + for (i=0; i 0) - pass_height = PNG_PASS_ROWS(height, pass); - - else - pass_height = 0; - } - - else /* not interlaced */ - pass_height = height; -# else -# define pass_height height -# endif - pngtest_debug1("Writing row data for pass %d", pass); - for (y = 0; y < pass_height; y++) + for (y = 0; y < height; y++) { +#ifndef SINGLE_ROWBUF_ALLOC pngtest_debug2("Allocating row buffer (pass %d, y = %u)...", pass, y); - row_buf = (png_bytep)png_malloc(read_ptr, - png_get_rowbytes(read_ptr, read_info_ptr)); + png_get_rowbytes(read_ptr, read_info_ptr)); - pngtest_debug2("\t%p (%lu bytes)", row_buf, - (unsigned long)png_get_rowbytes(read_ptr, read_info_ptr)); + pngtest_debug2("\t0x%08lx (%u bytes)", (unsigned long)row_buf, + png_get_rowbytes(read_ptr, read_info_ptr)); +#endif /* !SINGLE_ROWBUF_ALLOC */ png_read_rows(read_ptr, (png_bytepp)&row_buf, NULL, 1); #ifdef PNG_WRITE_SUPPORTED @@ -1541,21 +1381,21 @@ test_one_file(const char *inname, const char *outname) t_encode += (t_stop - t_start); t_start = t_stop; #endif -#endif /* WRITE */ +#endif /* PNG_WRITE_SUPPORTED */ +#ifndef SINGLE_ROWBUF_ALLOC pngtest_debug2("Freeing row buffer (pass %d, y = %u)", pass, y); png_free(read_ptr, row_buf); row_buf = NULL; +#endif /* !SINGLE_ROWBUF_ALLOC */ } } -#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED -# ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED - png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); -# endif -# ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); -# endif +#ifdef PNG_READ_UNKNOWN_CHUNKS_SUPPORTED + png_free_data(read_ptr, read_info_ptr, PNG_FREE_UNKN, -1); +#endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + png_free_data(write_ptr, write_info_ptr, PNG_FREE_UNKN, -1); #endif pngtest_debug("Reading and writing end_info data"); @@ -1572,15 +1412,15 @@ test_one_file(const char *inname, const char *outname) pngtest_check_text_support(read_ptr, text_ptr, num_text); - if (verbose != 0) + if (verbose) { int i; - fprintf(STDERR,"\n"); - for (i = 0; i < num_text; i++) + printf("\n"); + for (i=0; i 1) - fprintf(STDERR," eXIf type %c%c, %lu bytes\n",exif[0],exif[1], - (unsigned long)exif_length); -# ifdef PNG_WRITE_eXIf_SUPPORTED - png_set_eXIf_1(write_ptr, write_end_info_ptr, exif_length, exif); -# endif - } - } -#endif #ifdef PNG_tIME_SUPPORTED { png_timep mod_time; - if (png_get_tIME(read_ptr, end_info_ptr, &mod_time) != 0) + if (png_get_tIME(read_ptr, end_info_ptr, &mod_time)) { png_set_tIME(write_ptr, write_end_info_ptr, mod_time); #ifdef PNG_TIME_RFC1123_SUPPORTED - if (png_convert_to_rfc1123_buffer(tIME_string, mod_time) != 0) + if (png_convert_to_rfc1123_buffer(tIME_string, mod_time)) tIME_string[(sizeof tIME_string) - 1] = '\0'; else @@ -1622,7 +1446,7 @@ test_one_file(const char *inname, const char *outname) } tIME_chunk_present++; -#endif /* TIME_RFC1123 */ +#endif /* PNG_TIME_RFC1123_SUPPORTED */ } } #endif @@ -1630,11 +1454,25 @@ test_one_file(const char *inname, const char *outname) { png_unknown_chunkp unknowns; int num_unknowns = png_get_unknown_chunks(read_ptr, end_info_ptr, - &unknowns); + &unknowns); - if (num_unknowns != 0) + if (num_unknowns) + { png_set_unknown_chunks(write_ptr, write_end_info_ptr, unknowns, - num_unknowns); + num_unknowns); +#if PNG_LIBPNG_VER < 10600 + /* Copy the locations from the read_info_ptr. The automatically + * generated locations in write_end_info_ptr are wrong prior to 1.6.0 + * because they are reset from the write pointer (removed in 1.6.0). + */ + { + int i; + for (i = 0; i < num_unknowns; i++) + png_set_unknown_chunk_location(write_ptr, write_end_info_ptr, i, + unknowns[i].location); + } +#endif + } } #endif @@ -1653,35 +1491,40 @@ test_one_file(const char *inname, const char *outname) * There seems to be no way round this, however vpAg/sTER are not expected * after IDAT. */ - write_chunks(write_ptr, &my_user_chunk_data, after_IDAT); + write_chunks(write_ptr, after_IDAT); png_write_end(write_ptr, write_end_info_ptr); #endif #ifdef PNG_EASY_ACCESS_SUPPORTED - if (verbose != 0) + if (verbose) { png_uint_32 iwidth, iheight; iwidth = png_get_image_width(write_ptr, write_info_ptr); iheight = png_get_image_height(write_ptr, write_info_ptr); fprintf(STDERR, "\n Image width = %lu, height = %lu\n", - (unsigned long)iwidth, (unsigned long)iheight); + (unsigned long)iwidth, (unsigned long)iheight); } #endif pngtest_debug("Destroying data structs"); - pngtest_debug("Destroying read_ptr, read_info_ptr, end_info_ptr"); +#ifdef SINGLE_ROWBUF_ALLOC + pngtest_debug("destroying row_buf for read_ptr"); + png_free(read_ptr, row_buf); + row_buf = NULL; +#endif /* SINGLE_ROWBUF_ALLOC */ + pngtest_debug("destroying read_ptr, read_info_ptr, end_info_ptr"); png_destroy_read_struct(&read_ptr, &read_info_ptr, &end_info_ptr); #ifdef PNG_WRITE_SUPPORTED - pngtest_debug("Destroying write_end_info_ptr"); + pngtest_debug("destroying write_end_info_ptr"); png_destroy_info_struct(write_ptr, &write_end_info_ptr); - pngtest_debug("Destroying write_ptr, write_info_ptr"); + pngtest_debug("destroying write_ptr, write_info_ptr"); png_destroy_write_struct(&write_ptr, &write_info_ptr); #endif pngtest_debug("Destruction complete."); - fclose(fpin); - fclose(fpout); + FCLOSE(fpin); + FCLOSE(fpout); /* Summarize any warnings or errors and in 'strict' mode fail the test. * Unsupported chunks can result in warnings, in that case ignore the strict @@ -1693,110 +1536,108 @@ test_one_file(const char *inname, const char *outname) * above, but this is safe. */ fprintf(STDERR, "\n %s: %d libpng errors found (%d warnings)", - inname, error_count, warning_count); + inname, error_count, warning_count); if (strict != 0) - return 1; + return (1); } # ifdef PNG_WRITE_SUPPORTED - /* If there is no write support nothing was written! */ + /* If there we no write support nothing was written! */ else if (unsupported_chunks > 0) { fprintf(STDERR, "\n %s: unsupported chunks (%d)%s", - inname, unsupported_chunks, strict ? ": IGNORED --strict!" : ""); + inname, unsupported_chunks, strict ? ": IGNORED --strict!" : ""); } # endif else if (warning_count > 0) { fprintf(STDERR, "\n %s: %d libpng warnings found", - inname, warning_count); + inname, warning_count); if (strict != 0) - return 1; + return (1); } pngtest_debug("Opening files for comparison"); if ((fpin = fopen(inname, "rb")) == NULL) { fprintf(STDERR, "Could not find file %s\n", inname); - return 1; + return (1); } if ((fpout = fopen(outname, "rb")) == NULL) { fprintf(STDERR, "Could not find file %s\n", outname); - fclose(fpin); - return 1; + FCLOSE(fpin); + return (1); } -#if defined (PNG_WRITE_SUPPORTED) /* else nothing was written */ &&\ - defined (PNG_WRITE_FILTER_SUPPORTED) - if (interlace_preserved != 0) /* else the files will be changed */ +#ifdef PNG_WRITE_SUPPORTED /* else nothing was written */ { + int wrote_question = 0; + for (;;) { - static int wrote_question = 0; - size_t num_in, num_out; + png_size_t num_in, num_out; char inbuf[256], outbuf[256]; + num_in = fread(inbuf, 1, sizeof inbuf, fpin); num_out = fread(outbuf, 1, sizeof outbuf, fpout); if (num_in != num_out) { fprintf(STDERR, "\nFiles %s and %s are of a different size\n", - inname, outname); + inname, outname); if (wrote_question == 0 && unsupported_chunks == 0) { fprintf(STDERR, - " Was %s written with the same maximum IDAT" - " chunk size (%d bytes),", - inname, PNG_ZBUF_SIZE); + " Was %s written with the same maximum IDAT chunk size (%d bytes),", + inname, PNG_ZBUF_SIZE); fprintf(STDERR, - "\n filtering heuristic (libpng default), compression"); + "\n filtering heuristic (libpng default), compression"); fprintf(STDERR, - " level (zlib default),\n and zlib version (%s)?\n\n", - ZLIB_VERSION); + " level (zlib default),\n and zlib version (%s)?\n\n", + ZLIB_VERSION); wrote_question = 1; } - fclose(fpin); - fclose(fpout); + FCLOSE(fpin); + FCLOSE(fpout); if (strict != 0 && unsupported_chunks == 0) - return 1; + return (1); else - return 0; + return (0); } - if (num_in == 0) + if (!num_in) break; if (memcmp(inbuf, outbuf, num_in)) { fprintf(STDERR, "\nFiles %s and %s are different\n", inname, - outname); + outname); if (wrote_question == 0 && unsupported_chunks == 0) { fprintf(STDERR, - " Was %s written with the same maximum" - " IDAT chunk size (%d bytes),", + " Was %s written with the same maximum IDAT chunk size (%d bytes),", inname, PNG_ZBUF_SIZE); fprintf(STDERR, - "\n filtering heuristic (libpng default), compression"); + "\n filtering heuristic (libpng default), compression"); fprintf(STDERR, - " level (zlib default),\n and zlib version (%s)?\n\n", + " level (zlib default),\n and zlib version (%s)?\n\n", ZLIB_VERSION); wrote_question = 1; } - fclose(fpin); - fclose(fpout); + FCLOSE(fpin); + FCLOSE(fpout); /* NOTE: the unsupported_chunks escape is permitted here because * unsupported text chunk compression will result in the compression @@ -1804,28 +1645,28 @@ test_one_file(const char *inname, const char *outname) * can be exactly the same size! */ if (strict != 0 && unsupported_chunks == 0) - return 1; + return (1); else - return 0; + return (0); } } } -#endif /* WRITE && WRITE_FILTER */ +#endif /* PNG_WRITE_SUPPORTED */ - fclose(fpin); - fclose(fpout); + FCLOSE(fpin); + FCLOSE(fpout); - return 0; + return (0); } /* Input and output filenames */ #ifdef RISCOS -static const char *inname = "pngtest/png"; -static const char *outname = "pngout/png"; +static PNG_CONST char *inname = "pngtest/png"; +static PNG_CONST char *outname = "pngout/png"; #else -static const char *inname = "pngtest.png"; -static const char *outname = "pngout.png"; +static PNG_CONST char *inname = "pngtest.png"; +static PNG_CONST char *outname = "pngout.png"; #endif int @@ -1834,19 +1675,17 @@ main(int argc, char *argv[]) int multiple = 0; int ierror = 0; - png_structp dummy_ptr; - fprintf(STDERR, "\n Testing libpng version %s\n", PNG_LIBPNG_VER_STRING); fprintf(STDERR, " with zlib version %s\n", ZLIB_VERSION); fprintf(STDERR, "%s", png_get_copyright(NULL)); /* Show the version of libpng used in building the library */ fprintf(STDERR, " library (%lu):%s", - (unsigned long)png_access_version_number(), - png_get_header_version(NULL)); + (unsigned long)png_access_version_number(), + png_get_header_version(NULL)); /* Show the version of libpng used in building the application */ fprintf(STDERR, " pngtest (%lu):%s", (unsigned long)PNG_LIBPNG_VER, - PNG_HEADER_VERSION_STRING); + PNG_HEADER_VERSION_STRING); /* Do some consistency checking on the memory allocation settings, I'm * not sure this matters, but it is nice to know, the first of these @@ -1861,11 +1700,12 @@ main(int argc, char *argv[]) fprintf(STDERR, " NOTE: libpng compiled for max 64k, zlib not\n"); #endif - if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING) != 0) + if (strcmp(png_libpng_ver, PNG_LIBPNG_VER_STRING)) { - fprintf(STDERR, "Warning: mismatching versions of png.h and png.c\n"); - fprintf(STDERR, " png.h version string: %s\n", PNG_LIBPNG_VER_STRING); - fprintf(STDERR, " png.c version string: %s\n\n", png_libpng_ver); + fprintf(STDERR, + "Warning: versions are different between png.h and png.c\n"); + fprintf(STDERR, " png.h version: %s\n", PNG_LIBPNG_VER_STRING); + fprintf(STDERR, " png.c version: %s\n\n", png_libpng_ver); ++ierror; } @@ -1899,7 +1739,6 @@ main(int argc, char *argv[]) inname = argv[2]; strict++; relaxed = 0; - multiple = 1; } else if (strcmp(argv[1], "--relaxed") == 0) @@ -1909,17 +1748,6 @@ main(int argc, char *argv[]) inname = argv[2]; strict = 0; relaxed++; - multiple = 1; - } - else if (strcmp(argv[1], "--xfail") == 0) - { - status_dots_requested = 0; - verbose = 1; - inname = argv[2]; - strict = 0; - xfail++; - relaxed++; - multiple = 1; } else @@ -1929,79 +1757,79 @@ main(int argc, char *argv[]) } } - if (multiple == 0 && argc == 3 + verbose) - outname = argv[2 + verbose]; + if (!multiple && argc == 3 + verbose) + outname = argv[2 + verbose]; - if ((multiple == 0 && argc > 3 + verbose) || - (multiple != 0 && argc < 2)) + if ((!multiple && argc > 3 + verbose) || (multiple && argc < 2)) { - fprintf(STDERR, - "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", - argv[0], argv[0]); - fprintf(STDERR, - " reads/writes one PNG file (without -m) or multiple files (-m)\n"); - fprintf(STDERR, - " with -m %s is used as a temporary file\n", outname); - exit(1); + fprintf(STDERR, + "usage: %s [infile.png] [outfile.png]\n\t%s -m {infile.png}\n", + argv[0], argv[0]); + fprintf(STDERR, + " reads/writes one PNG file (without -m) or multiple files (-m)\n"); + fprintf(STDERR, + " with -m %s is used as a temporary file\n", outname); + exit(1); } - if (multiple != 0) + if (multiple) { int i; #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG int allocation_now = current_allocation; #endif - for (i = 2; i < argc; ++i) + for (i=2; i 0 - fprintf(STDERR, "\n"); -#endif kerror = test_one_file(argv[i], outname); if (kerror == 0) { +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + int k; +#endif #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED fprintf(STDERR, "\n PASS (%lu zero samples)\n", - (unsigned long)zero_samples); + (unsigned long)zero_samples); #else fprintf(STDERR, " PASS\n"); #endif +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + for (k = 0; k<256; k++) + if (filters_used[k]) + fprintf(STDERR, " Filter %d was used %lu times\n", + k, (unsigned long)filters_used[k]); +#endif #ifdef PNG_TIME_RFC1123_SUPPORTED - if (tIME_chunk_present != 0) - fprintf(STDERR, " tIME = %s\n", tIME_string); + if (tIME_chunk_present != 0) + fprintf(STDERR, " tIME = %s\n", tIME_string); - tIME_chunk_present = 0; -#endif /* TIME_RFC1123 */ + tIME_chunk_present = 0; +#endif /* PNG_TIME_RFC1123_SUPPORTED */ } else { - if (xfail) - fprintf(STDERR, " XFAIL\n"); - else - { - fprintf(STDERR, " FAIL\n"); - ierror += kerror; - } + fprintf(STDERR, " FAIL\n"); + ierror += kerror; } #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG if (allocation_now != current_allocation) fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", - current_allocation - allocation_now); + current_allocation - allocation_now); if (current_allocation != 0) { memory_infop pinfo = pinformation; fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", - current_allocation); + current_allocation); while (pinfo != NULL) { - fprintf(STDERR, " %lu bytes at %p\n", - (unsigned long)pinfo->size, - pinfo->pointer); + fprintf(STDERR, " %lu bytes at %x\n", + (unsigned long)pinfo->size, + (unsigned int)pinfo->pointer); pinfo = pinfo->next; } } @@ -2009,20 +1837,20 @@ main(int argc, char *argv[]) } #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG fprintf(STDERR, " Current memory allocation: %10d bytes\n", - current_allocation); + current_allocation); fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", - maximum_allocation); + maximum_allocation); fprintf(STDERR, " Total memory allocation: %10d bytes\n", - total_allocation); + total_allocation); fprintf(STDERR, " Number of allocations: %10d\n", - num_allocations); + num_allocations); #endif } else { int i; - for (i = 0; i < 3; ++i) + for (i = 0; i<3; ++i) { int kerror; #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG @@ -2035,12 +1863,7 @@ main(int argc, char *argv[]) status_dots_requested = 0; if (i == 0 || verbose == 1 || ierror != 0) - { fprintf(STDERR, "\n Testing %s:", inname); -#if PNG_DEBUG > 0 - fprintf(STDERR, "\n"); -#endif - } kerror = test_one_file(inname, outname); @@ -2048,53 +1871,52 @@ main(int argc, char *argv[]) { if (verbose == 1 || i == 2) { +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + int k; +#endif #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED fprintf(STDERR, "\n PASS (%lu zero samples)\n", - (unsigned long)zero_samples); + (unsigned long)zero_samples); #else fprintf(STDERR, " PASS\n"); #endif +#ifdef PNG_READ_USER_TRANSFORM_SUPPORTED + for (k = 0; k<256; k++) + if (filters_used[k]) + fprintf(STDERR, " Filter %d was used %lu times\n", + k, (unsigned long)filters_used[k]); +#endif #ifdef PNG_TIME_RFC1123_SUPPORTED if (tIME_chunk_present != 0) fprintf(STDERR, " tIME = %s\n", tIME_string); -#endif /* TIME_RFC1123 */ +#endif /* PNG_TIME_RFC1123_SUPPORTED */ } } else { if (verbose == 0 && i != 2) - { fprintf(STDERR, "\n Testing %s:", inname); -#if PNG_DEBUG > 0 - fprintf(STDERR, "\n"); -#endif - } - if (xfail) - fprintf(STDERR, " XFAIL\n"); - else - { - fprintf(STDERR, " FAIL\n"); - ierror += kerror; - } + fprintf(STDERR, " FAIL\n"); + ierror += kerror; } #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG if (allocation_now != current_allocation) fprintf(STDERR, "MEMORY ERROR: %d bytes lost\n", - current_allocation - allocation_now); + current_allocation - allocation_now); if (current_allocation != 0) { memory_infop pinfo = pinformation; fprintf(STDERR, "MEMORY ERROR: %d bytes still allocated\n", - current_allocation); + current_allocation); while (pinfo != NULL) { - fprintf(STDERR, " %lu bytes at %p\n", - (unsigned long)pinfo->size, pinfo->pointer); + fprintf(STDERR, " %lu bytes at %x\n", + (unsigned long)pinfo->size, (unsigned int)pinfo->pointer); pinfo = pinfo->next; } } @@ -2102,13 +1924,13 @@ main(int argc, char *argv[]) } #if defined(PNG_USER_MEM_SUPPORTED) && PNG_DEBUG fprintf(STDERR, " Current memory allocation: %10d bytes\n", - current_allocation); + current_allocation); fprintf(STDERR, " Maximum memory allocation: %10d bytes\n", - maximum_allocation); + maximum_allocation); fprintf(STDERR, " Total memory allocation: %10d bytes\n", - total_allocation); + total_allocation); fprintf(STDERR, " Number of allocations: %10d\n", - num_allocations); + num_allocations); #endif } @@ -2117,13 +1939,13 @@ main(int argc, char *argv[]) t_misc += (t_stop - t_start); t_start = t_stop; fprintf(STDERR, " CPU time used = %.3f seconds", - (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); + (t_misc+t_decode+t_encode)/(float)CLOCKS_PER_SEC); fprintf(STDERR, " (decoding %.3f,\n", - t_decode/(float)CLOCKS_PER_SEC); + t_decode/(float)CLOCKS_PER_SEC); fprintf(STDERR, " encoding %.3f ,", - t_encode/(float)CLOCKS_PER_SEC); + t_encode/(float)CLOCKS_PER_SEC); fprintf(STDERR, " other %.3f seconds)\n\n", - t_misc/(float)CLOCKS_PER_SEC); + t_misc/(float)CLOCKS_PER_SEC); #endif if (ierror == 0) @@ -2132,35 +1954,18 @@ main(int argc, char *argv[]) else fprintf(STDERR, " libpng FAILS test\n"); - dummy_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); -#ifdef PNG_USER_LIMITS_SUPPORTED - fprintf(STDERR, " Default limits:\n"); - fprintf(STDERR, " width_max = %lu\n", - (unsigned long) png_get_user_width_max(dummy_ptr)); - fprintf(STDERR, " height_max = %lu\n", - (unsigned long) png_get_user_height_max(dummy_ptr)); - if (png_get_chunk_cache_max(dummy_ptr) == 0) - fprintf(STDERR, " cache_max = unlimited\n"); - else - fprintf(STDERR, " cache_max = %lu\n", - (unsigned long) png_get_chunk_cache_max(dummy_ptr)); - if (png_get_chunk_malloc_max(dummy_ptr) == 0) - fprintf(STDERR, " malloc_max = unlimited\n"); - else - fprintf(STDERR, " malloc_max = %lu\n", - (unsigned long) png_get_chunk_malloc_max(dummy_ptr)); -#endif - png_destroy_read_struct(&dummy_ptr, NULL, NULL); - - return (ierror != 0); + return (int)(ierror != 0); } #else int main(void) { fprintf(STDERR, - " test ignored because libpng was not built with read support\n"); + " test ignored because libpng was not built with read support\n"); /* And skip this test */ - return SKIP; + return 77; } #endif + +/* Generate a compiler error if there is an old png.h in the search path. */ +typedef png_libpng_version_1_6_2 Your_png_h_is_not_version_1_6_2; diff --git a/Windows_Libs/Dev/Render/libpng/pngtrans.c b/Windows_Libs/Dev/Render/libpng/pngtrans.c index 19f5c64..8f8bc5d 100644 --- a/Windows_Libs/Dev/Render/libpng/pngtrans.c +++ b/Windows_Libs/Dev/Render/libpng/pngtrans.c @@ -1,9 +1,10 @@ + /* pngtrans.c - transforms the data in a row (used by both readers and writers) * - * Copyright (c) 2018-2024 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -29,7 +30,7 @@ png_set_bgr(png_structrp png_ptr) #endif #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -/* Turn on 16-bit byte swapping */ +/* Turn on 16 bit byte swapping */ void PNGAPI png_set_swap(png_structrp png_ptr) { @@ -56,9 +57,7 @@ png_set_packing(png_structrp png_ptr) if (png_ptr->bit_depth < 8) { png_ptr->transformations |= PNG_PACK; -# ifdef PNG_WRITE_SUPPORTED - png_ptr->usr_bit_depth = 8; -# endif + png_ptr->usr_bit_depth = 8; } } #endif @@ -99,13 +98,13 @@ png_set_interlace_handling(png_structrp png_ptr) { png_debug(1, "in png_set_interlace handling"); - if (png_ptr != 0 && png_ptr->interlaced != 0) + if (png_ptr && png_ptr->interlaced) { png_ptr->transformations |= PNG_INTERLACE; - return 7; + return (7); } - return 1; + return (1); } #endif @@ -126,7 +125,7 @@ png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc) /* In libpng 1.6 it is possible to determine whether this is a read or write * operation and therefore to do more checking here for a valid call. */ - if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) + if (png_ptr->mode & PNG_IS_READ_STRUCT) { # ifdef PNG_READ_FILLER_SUPPORTED /* On read png_set_filler is always valid, regardless of the base PNG @@ -171,14 +170,13 @@ png_set_filler(png_structrp png_ptr, png_uint_32 filler, int filler_loc) * size! */ png_app_error(png_ptr, - "png_set_filler is invalid for" - " low bit depth gray output"); + "png_set_filler is invalid for low bit depth gray output"); return; } default: png_app_error(png_ptr, - "png_set_filler: inappropriate color type"); + "png_set_filler: inappropriate color type"); return; } # else @@ -210,7 +208,7 @@ png_set_add_alpha(png_structrp png_ptr, png_uint_32 filler, int filler_loc) png_set_filler(png_ptr, filler, filler_loc); /* The above may fail to do anything. */ - if ((png_ptr->transformations & PNG_FILLER) != 0) + if (png_ptr->transformations & PNG_FILLER) png_ptr->transformations |= PNG_ADD_ALPHA; } @@ -268,8 +266,8 @@ png_do_invert(png_row_infop row_info, png_bytep row) if (row_info->color_type == PNG_COLOR_TYPE_GRAY) { png_bytep rp = row; - size_t i; - size_t istop = row_info->rowbytes; + png_size_t i; + png_size_t istop = row_info->rowbytes; for (i = 0; i < istop; i++) { @@ -282,8 +280,8 @@ png_do_invert(png_row_infop row_info, png_bytep row) row_info->bit_depth == 8) { png_bytep rp = row; - size_t i; - size_t istop = row_info->rowbytes; + png_size_t i; + png_size_t istop = row_info->rowbytes; for (i = 0; i < istop; i += 2) { @@ -297,8 +295,8 @@ png_do_invert(png_row_infop row_info, png_bytep row) row_info->bit_depth == 16) { png_bytep rp = row; - size_t i; - size_t istop = row_info->rowbytes; + png_size_t i; + png_size_t istop = row_info->rowbytes; for (i = 0; i < istop; i += 4) { @@ -313,7 +311,7 @@ png_do_invert(png_row_infop row_info, png_bytep row) #ifdef PNG_16BIT_SUPPORTED #if defined(PNG_READ_SWAP_SUPPORTED) || defined(PNG_WRITE_SWAP_SUPPORTED) -/* Swaps byte order on 16-bit depth images */ +/* Swaps byte order on 16 bit depth images */ void /* PRIVATE */ png_do_swap(png_row_infop row_info, png_bytep row) { @@ -327,16 +325,9 @@ png_do_swap(png_row_infop row_info, png_bytep row) for (i = 0; i < istop; i++, rp += 2) { -#ifdef PNG_BUILTIN_BSWAP16_SUPPORTED - /* Feature added to libpng-1.6.11 for testing purposes, not - * enabled by default. - */ - *(png_uint_16*)rp = __builtin_bswap16(*(png_uint_16*)rp); -#else png_byte t = *rp; *rp = *(rp + 1); *(rp + 1) = t; -#endif } } } @@ -344,7 +335,7 @@ png_do_swap(png_row_infop row_info, png_bytep row) #endif #if defined(PNG_READ_PACKSWAP_SUPPORTED)||defined(PNG_WRITE_PACKSWAP_SUPPORTED) -static const png_byte onebppswaptable[256] = { +static PNG_CONST png_byte onebppswaptable[256] = { 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, @@ -379,7 +370,7 @@ static const png_byte onebppswaptable[256] = { 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF }; -static const png_byte twobppswaptable[256] = { +static PNG_CONST png_byte twobppswaptable[256] = { 0x00, 0x40, 0x80, 0xC0, 0x10, 0x50, 0x90, 0xD0, 0x20, 0x60, 0xA0, 0xE0, 0x30, 0x70, 0xB0, 0xF0, 0x04, 0x44, 0x84, 0xC4, 0x14, 0x54, 0x94, 0xD4, @@ -414,7 +405,7 @@ static const png_byte twobppswaptable[256] = { 0x2F, 0x6F, 0xAF, 0xEF, 0x3F, 0x7F, 0xBF, 0xFF }; -static const png_byte fourbppswaptable[256] = { +static PNG_CONST png_byte fourbppswaptable[256] = { 0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, 0x90, 0xA0, 0xB0, 0xC0, 0xD0, 0xE0, 0xF0, 0x01, 0x11, 0x21, 0x31, 0x41, 0x51, 0x61, 0x71, @@ -478,7 +469,7 @@ png_do_packswap(png_row_infop row_info, png_bytep row) *rp = table[*rp]; } } -#endif /* PACKSWAP || WRITE_PACKSWAP */ +#endif /* PNG_READ_PACKSWAP_SUPPORTED or PNG_WRITE_PACKSWAP_SUPPORTED */ #if defined(PNG_WRITE_FILLER_SUPPORTED) || \ defined(PNG_READ_STRIP_ALPHA_SUPPORTED) @@ -497,8 +488,6 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) png_bytep dp = row; /* destination pointer */ png_bytep ep = row + row_info->rowbytes; /* One beyond end of row */ - png_debug(1, "in png_do_strip_channel"); - /* At the start sp will point to the first byte to copy and dp to where * it is copied to. ep always points just beyond the end of the row, so * the loop simply copies (channels-1) channels until sp reaches ep. @@ -512,35 +501,27 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) { if (row_info->bit_depth == 8) { - if (at_start != 0) /* Skip initial filler */ + if (at_start) /* Skip initial filler */ ++sp; else /* Skip initial channel and, for sp, the filler */ - { - sp += 2; ++dp; - } + sp += 2, ++dp; /* For a 1 pixel wide image there is nothing to do */ while (sp < ep) - { - *dp++ = *sp; sp += 2; - } + *dp++ = *sp, sp += 2; row_info->pixel_depth = 8; } else if (row_info->bit_depth == 16) { - if (at_start != 0) /* Skip initial filler */ + if (at_start) /* Skip initial filler */ sp += 2; else /* Skip initial channel and, for sp, the filler */ - { - sp += 4; dp += 2; - } + sp += 4, dp += 2; while (sp < ep) - { - *dp++ = *sp++; *dp++ = *sp; sp += 3; - } + *dp++ = *sp++, *dp++ = *sp, sp += 3; row_info->pixel_depth = 16; } @@ -560,37 +541,31 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) { if (row_info->bit_depth == 8) { - if (at_start != 0) /* Skip initial filler */ + if (at_start) /* Skip initial filler */ ++sp; else /* Skip initial channels and, for sp, the filler */ - { - sp += 4; dp += 3; - } + sp += 4, dp += 3; /* Note that the loop adds 3 to dp and 4 to sp each time. */ while (sp < ep) - { - *dp++ = *sp++; *dp++ = *sp++; *dp++ = *sp; sp += 2; - } + *dp++ = *sp++, *dp++ = *sp++, *dp++ = *sp, sp += 2; row_info->pixel_depth = 24; } else if (row_info->bit_depth == 16) { - if (at_start != 0) /* Skip initial filler */ + if (at_start) /* Skip initial filler */ sp += 2; else /* Skip initial channels and, for sp, the filler */ - { - sp += 8; dp += 6; - } + sp += 8, dp += 6; while (sp < ep) { /* Copy 6 bytes, skip 2 */ - *dp++ = *sp++; *dp++ = *sp++; - *dp++ = *sp++; *dp++ = *sp++; - *dp++ = *sp++; *dp++ = *sp; sp += 3; + *dp++ = *sp++, *dp++ = *sp++; + *dp++ = *sp++, *dp++ = *sp++; + *dp++ = *sp++, *dp++ = *sp, sp += 3; } row_info->pixel_depth = 48; @@ -610,7 +585,7 @@ png_do_strip_channel(png_row_infop row_info, png_bytep row, int at_start) return; /* The filler channel has gone already */ /* Fix the rowbytes value. */ - row_info->rowbytes = (size_t)(dp-row); + row_info->rowbytes = dp-row; } #endif @@ -621,7 +596,7 @@ png_do_bgr(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_bgr"); - if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + if ((row_info->color_type & PNG_COLOR_MASK_COLOR)) { png_uint_32 row_width = row_info->width; if (row_info->bit_depth == 8) @@ -691,7 +666,7 @@ png_do_bgr(png_row_infop row_info, png_bytep row) #endif } } -#endif /* READ_BGR || WRITE_BGR */ +#endif /* PNG_READ_BGR_SUPPORTED or PNG_WRITE_BGR_SUPPORTED */ #if defined(PNG_READ_CHECK_FOR_INVALID_INDEX_SUPPORTED) || \ defined(PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED) @@ -699,8 +674,6 @@ png_do_bgr(png_row_infop row_info, png_bytep row) void /* PRIVATE */ png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info) { - png_debug(1, "in png_do_check_palette_indexes"); - if (png_ptr->num_palette < (1 << row_info->bit_depth) && png_ptr->num_palette > 0) /* num_palette can be 0 in MNG files */ { @@ -710,7 +683,7 @@ png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info) * and this calculation is used because it avoids warnings that other * forms produced on either GCC or MSVC. */ - int padding = PNG_PADBITS(row_info->pixel_depth, row_info->width); + int padding = (-row_info->pixel_depth * row_info->width) & 7; png_bytep rp = png_ptr->row_buf + row_info->rowbytes; switch (row_info->bit_depth) @@ -722,7 +695,7 @@ png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info) */ for (; rp > png_ptr->row_buf; rp--) { - if ((*rp >> padding) != 0) + if (*rp >> padding != 0) png_ptr->num_palette_max = 1; padding = 0; } @@ -796,14 +769,14 @@ png_do_check_palette_indexes(png_structrp png_ptr, png_row_infop row_info) } } } -#endif /* CHECK_FOR_INVALID_INDEX */ +#endif /* PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED */ #if defined(PNG_READ_USER_TRANSFORM_SUPPORTED) || \ defined(PNG_WRITE_USER_TRANSFORM_SUPPORTED) #ifdef PNG_USER_TRANSFORM_PTR_SUPPORTED void PNGAPI -png_set_user_transform_info(png_structrp png_ptr, png_voidp user_transform_ptr, - int user_transform_depth, int user_transform_channels) +png_set_user_transform_info(png_structrp png_ptr, png_voidp + user_transform_ptr, int user_transform_depth, int user_transform_channels) { png_debug(1, "in png_set_user_transform_info"); @@ -815,7 +788,7 @@ png_set_user_transform_info(png_structrp png_ptr, png_voidp user_transform_ptr, (png_ptr->flags & PNG_FLAG_ROW_INIT) != 0) { png_app_error(png_ptr, - "info change after png_start_read_image or png_read_update_info"); + "info change after png_start_read_image or png_read_update_info"); return; } #endif @@ -836,7 +809,7 @@ png_voidp PNGAPI png_get_user_transform_ptr(png_const_structrp png_ptr) { if (png_ptr == NULL) - return NULL; + return (NULL); return png_ptr->user_transform_ptr; } @@ -846,7 +819,7 @@ png_get_user_transform_ptr(png_const_structrp png_ptr) png_uint_32 PNGAPI png_get_current_row_number(png_const_structrp png_ptr) { - /* See the comments in png.h - this is the sub-image row when reading an + /* See the comments in png.h - this is the sub-image row when reading and * interlaced image. */ if (png_ptr != NULL) @@ -862,6 +835,7 @@ png_get_current_pass_number(png_const_structrp png_ptr) return png_ptr->pass; return 8; /* invalid */ } -#endif /* USER_TRANSFORM_INFO */ -#endif /* READ_USER_TRANSFORM || WRITE_USER_TRANSFORM */ -#endif /* READ || WRITE */ +#endif /* PNG_USER_TRANSFORM_INFO_SUPPORTED */ +#endif /* PNG_READ_USER_TRANSFORM_SUPPORTED || + PNG_WRITE_USER_TRANSFORM_SUPPORTED */ +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pngwio.c b/Windows_Libs/Dev/Render/libpng/pngwio.c index 96a3187..e3289df 100644 --- a/Windows_Libs/Dev/Render/libpng/pngwio.c +++ b/Windows_Libs/Dev/Render/libpng/pngwio.c @@ -1,9 +1,10 @@ + /* pngwio.c - functions for data output * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2014,2016,2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.0 [February 14, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -25,16 +26,16 @@ * writes to a file pointer. Note that this routine sometimes gets called * with very small lengths, so you should implement some kind of simple * buffering if you are using unbuffered writes. This should never be asked - * to write more than 64K on a 16-bit machine. + * to write more than 64K on a 16 bit machine. */ void /* PRIVATE */ -png_write_data(png_structrp png_ptr, png_const_bytep data, size_t length) +png_write_data(png_structrp png_ptr, png_const_bytep data, png_size_t length) { /* NOTE: write_data_fn must not change the buffer! */ if (png_ptr->write_data_fn != NULL ) (*(png_ptr->write_data_fn))(png_ptr, png_constcast(png_bytep,data), - length); + length); else png_error(png_ptr, "Call to NULL write function"); @@ -47,14 +48,14 @@ png_write_data(png_structrp png_ptr, png_const_bytep data, size_t length) * than changing the library. */ void PNGCBAPI -png_default_write_data(png_structp png_ptr, png_bytep data, size_t length) +png_default_write_data(png_structp png_ptr, png_bytep data, png_size_t length) { - size_t check; + png_size_t check; if (png_ptr == NULL) return; - check = fwrite(data, 1, length, (FILE *)png_ptr->io_ptr); + check = fwrite(data, 1, length, (png_FILE_p)(png_ptr->io_ptr)); if (check != length) png_error(png_ptr, "Write Error"); @@ -77,12 +78,12 @@ png_flush(png_structrp png_ptr) void PNGCBAPI png_default_flush(png_structp png_ptr) { - FILE *io_ptr; + png_FILE_p io_ptr; if (png_ptr == NULL) return; - io_ptr = png_voidcast(FILE *, png_ptr->io_ptr); + io_ptr = png_voidcast(png_FILE_p, (png_ptr->io_ptr)); fflush(io_ptr); } # endif @@ -148,11 +149,8 @@ png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr, # else png_ptr->output_flush_fn = output_flush_fn; # endif -#else - PNG_UNUSED(output_flush_fn) -#endif /* WRITE_FLUSH */ +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ -#ifdef PNG_READ_SUPPORTED /* It is an error to read while writing a png file */ if (png_ptr->read_data_fn != NULL) { @@ -162,6 +160,5 @@ png_set_write_fn(png_structrp png_ptr, png_voidp io_ptr, "Can't set both read_data_fn and write_data_fn in the" " same structure"); } -#endif } -#endif /* WRITE */ +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pngwrite.c b/Windows_Libs/Dev/Render/libpng/pngwrite.c index 362a8c3..53aaa8c 100644 --- a/Windows_Libs/Dev/Render/libpng/pngwrite.c +++ b/Windows_Libs/Dev/Render/libpng/pngwrite.c @@ -1,9 +1,10 @@ + /* pngwrite.c - general routines to write a PNG file * - * Copyright (c) 2018-2026 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -11,9 +12,9 @@ */ #include "pngpriv.h" -#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED +#if defined(PNG_SIMPLIFIED_WRITE_SUPPORTED) && defined(PNG_STDIO_SUPPORTED) # include -#endif /* SIMPLIFIED_WRITE_STDIO */ +#endif #ifdef PNG_WRITE_SUPPORTED @@ -21,9 +22,9 @@ /* Write out all the unknown chunks for the current given location */ static void write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, - unsigned int where) + unsigned int where) { - if (info_ptr->unknown_chunks_num != 0) + if (info_ptr->unknown_chunks_num) { png_const_unknown_chunkp up; @@ -32,7 +33,7 @@ write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, for (up = info_ptr->unknown_chunks; up < info_ptr->unknown_chunks + info_ptr->unknown_chunks_num; ++up) - if ((up->location & where) != 0) + if (up->location & where) { /* If per-chunk unknown chunk handling is enabled use it, otherwise * just write the chunks the application has set. @@ -68,16 +69,16 @@ write_unknown_chunks(png_structrp png_ptr, png_const_inforp info_ptr, } } } -#endif /* WRITE_UNKNOWN_CHUNKS */ +#endif /* PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED */ /* Writes all the PNG information. This is the suggested way to use the * library. If you have a new chunk to add, make a function to write it, * and put it in the correct location here. If you want the chunk written * after the image data, put it in png_write_end(). I strongly encourage - * you to supply a PNG_INFO_ flag, and check info_ptr->valid before - * writing the chunk, as that will keep the code from breaking if you want - * to just write a plain PNG file. If you have long comments, I suggest - * writing them in png_write_end(), and compressing them. + * you to supply a PNG_INFO_ flag, and check info_ptr->valid before writing + * the chunk, as that will keep the code from breaking if you want to just + * write a plain PNG file. If you have long comments, I suggest writing + * them in png_write_end(), and compressing them. */ void PNGAPI png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) @@ -87,133 +88,100 @@ png_write_info_before_PLTE(png_structrp png_ptr, png_const_inforp info_ptr) if (png_ptr == NULL || info_ptr == NULL) return; - if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) + if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) { - /* Write PNG signature */ - png_write_sig(png_ptr); + /* Write PNG signature */ + png_write_sig(png_ptr); #ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) != 0 && \ - png_ptr->mng_features_permitted != 0) - { - png_warning(png_ptr, - "MNG features are not allowed in a PNG datastream"); - png_ptr->mng_features_permitted = 0; - } + if ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) && \ + (png_ptr->mng_features_permitted)) + { + png_warning(png_ptr, "MNG features are not allowed in a PNG datastream"); + png_ptr->mng_features_permitted = 0; + } #endif - /* Write IHDR information. */ - png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, - info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, - info_ptr->filter_type, + /* Write IHDR information. */ + png_write_IHDR(png_ptr, info_ptr->width, info_ptr->height, + info_ptr->bit_depth, info_ptr->color_type, info_ptr->compression_type, + info_ptr->filter_type, #ifdef PNG_WRITE_INTERLACING_SUPPORTED - info_ptr->interlace_type + info_ptr->interlace_type #else - 0 + 0 #endif - ); + ); - /* The rest of these check to see if the valid field has the appropriate - * flag set, and if it does, writes the chunk. - * - * 1.6.0: COLORSPACE support controls the writing of these chunks too, and - * the chunks will be written if the WRITE routine is there and - * information * is available in the COLORSPACE. (See - * png_colorspace_sync_info in png.c for where the valid flags get set.) - * - * Under certain circumstances the colorspace can be invalidated without - * syncing the info_struct 'valid' flags; this happens if libpng detects - * an error and calls png_error while the color space is being set, yet - * the application continues writing the PNG. So check the 'invalid' - * flag here too. - */ -#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED - /* Write unknown chunks first; PNG v3 establishes a precedence order - * for colourspace chunks. It is certain therefore that new - * colourspace chunks will have a precedence and very likely it will be - * higher than all known so far. Writing the unknown chunks here is - * most likely to present the chunks in the most convenient order. - * - * FUTURE: maybe write chunks in the order the app calls png_set_chnk - * to give the app control. - */ - write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); + /* The rest of these check to see if the valid field has the appropriate + * flag set, and if it does, writes the chunk. + * + * 1.6.0: COLORSPACE support controls the writing of these chunks too, and + * the chunks will be written if the WRITE routine is there and information + * is available in the COLORSPACE. (See png_colorspace_sync_info in png.c + * for where the valid flags get set.) + * + * Under certain circumstances the colorspace can be invalidated without + * syncing the info_struct 'valid' flags; this happens if libpng detects and + * error and calls png_error while the color space is being set, yet the + * application continues writing the PNG. So check the 'invalid' flag here + * too. + */ +#ifdef PNG_GAMMA_SUPPORTED +# ifdef PNG_WRITE_gAMA_SUPPORTED + if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_gAMA) && + (info_ptr->valid & PNG_INFO_gAMA)) + png_write_gAMA_fixed(png_ptr, info_ptr->colorspace.gamma); +# endif #endif +#ifdef PNG_COLORSPACE_SUPPORTED + /* Write only one of sRGB or an ICC profile. If a profile was supplied + * and it matches one of the known sRGB ones issue a warning. + */ +# ifdef PNG_WRITE_iCCP_SUPPORTED + if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && + (info_ptr->valid & PNG_INFO_iCCP)) + { +# ifdef PNG_WRITE_sRGB_SUPPORTED + if (info_ptr->valid & PNG_INFO_sRGB) + png_app_warning(png_ptr, + "profile matches sRGB but writing iCCP instead"); +# endif + + png_write_iCCP(png_ptr, info_ptr->iccp_name, + info_ptr->iccp_profile); + } +# ifdef PNG_WRITE_sRGB_SUPPORTED + else +# endif +# endif + +# ifdef PNG_WRITE_sRGB_SUPPORTED + if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && + (info_ptr->valid & PNG_INFO_sRGB)) + png_write_sRGB(png_ptr, info_ptr->colorspace.rendering_intent); +# endif /* WRITE_sRGB */ +#endif /* COLORSPACE */ + #ifdef PNG_WRITE_sBIT_SUPPORTED - /* PNG v3: a streaming app will need to see this before cICP because - * the information is helpful in handling HLG encoding (which is - * natively 10 bits but gets expanded to 16 in PNG.) - * - * The app shouldn't care about the order ideally, but it might have - * no choice. In PNG v3, apps are allowed to reject PNGs where the - * APNG chunks are out of order so it behooves libpng to be nice here. - */ - if ((info_ptr->valid & PNG_INFO_sBIT) != 0) - png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); + if (info_ptr->valid & PNG_INFO_sBIT) + png_write_sBIT(png_ptr, &(info_ptr->sig_bit), info_ptr->color_type); #endif - /* PNG v3: the July 2004 version of the TR introduced the concept of colour - * space priority. As above it therefore behooves libpng to write the colour - * space chunks in the priority order so that a streaming app need not buffer - * them. - * - * PNG v3: Chunks mDCV and cLLI provide ancillary information for the - * interpretation of the colourspace chunkgs but do not require support for - * those chunks so are outside the "COLORSPACE" check but before the write of - * the colourspace chunks themselves. - */ -#ifdef PNG_WRITE_cLLI_SUPPORTED - if ((info_ptr->valid & PNG_INFO_cLLI) != 0) - { - png_write_cLLI_fixed(png_ptr, info_ptr->maxCLL, info_ptr->maxFALL); - } -#endif -#ifdef PNG_WRITE_mDCV_SUPPORTED - if ((info_ptr->valid & PNG_INFO_mDCV) != 0) - { - png_write_mDCV_fixed(png_ptr, - info_ptr->mastering_red_x, info_ptr->mastering_red_y, - info_ptr->mastering_green_x, info_ptr->mastering_green_y, - info_ptr->mastering_blue_x, info_ptr->mastering_blue_y, - info_ptr->mastering_white_x, info_ptr->mastering_white_y, - info_ptr->mastering_maxDL, info_ptr->mastering_minDL); - } +#ifdef PNG_COLORSPACE_SUPPORTED +# ifdef PNG_WRITE_cHRM_SUPPORTED + if (!(info_ptr->colorspace.flags & PNG_COLORSPACE_INVALID) && + (info_ptr->colorspace.flags & PNG_COLORSPACE_FROM_cHRM) && + (info_ptr->valid & PNG_INFO_cHRM)) + png_write_cHRM_fixed(png_ptr, &info_ptr->colorspace.end_points_xy); +# endif #endif -# ifdef PNG_WRITE_cICP_SUPPORTED /* Priority 4 */ - if ((info_ptr->valid & PNG_INFO_cICP) != 0) - { - png_write_cICP(png_ptr, - info_ptr->cicp_colour_primaries, - info_ptr->cicp_transfer_function, - info_ptr->cicp_matrix_coefficients, - info_ptr->cicp_video_full_range_flag); - } -# endif - -# ifdef PNG_WRITE_iCCP_SUPPORTED /* Priority 3 */ - if ((info_ptr->valid & PNG_INFO_iCCP) != 0) - { - png_write_iCCP(png_ptr, info_ptr->iccp_name, - info_ptr->iccp_profile, info_ptr->iccp_proflen); - } -# endif - -# ifdef PNG_WRITE_sRGB_SUPPORTED /* Priority 2 */ - if ((info_ptr->valid & PNG_INFO_sRGB) != 0) - png_write_sRGB(png_ptr, info_ptr->rendering_intent); -# endif /* WRITE_sRGB */ - -# ifdef PNG_WRITE_gAMA_SUPPORTED /* Priority 1 */ - if ((info_ptr->valid & PNG_INFO_gAMA) != 0) - png_write_gAMA_fixed(png_ptr, info_ptr->gamma); -# endif - -# ifdef PNG_WRITE_cHRM_SUPPORTED /* Also priority 1 */ - if ((info_ptr->valid & PNG_INFO_cHRM) != 0) - png_write_cHRM_fixed(png_ptr, &info_ptr->cHRM); -# endif +#ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED + write_unknown_chunks(png_ptr, info_ptr, PNG_HAVE_IHDR); +#endif png_ptr->mode |= PNG_WROTE_INFO_BEFORE_PLTE; } @@ -233,7 +201,7 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) png_write_info_before_PLTE(png_ptr, info_ptr); - if ((info_ptr->valid & PNG_INFO_PLTE) != 0) + if (info_ptr->valid & PNG_INFO_PLTE) png_write_PLTE(png_ptr, info_ptr->palette, (png_uint_32)info_ptr->num_palette); @@ -241,20 +209,15 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) png_error(png_ptr, "Valid palette required for paletted images"); #ifdef PNG_WRITE_tRNS_SUPPORTED - if ((info_ptr->valid & PNG_INFO_tRNS) !=0) + if (info_ptr->valid & PNG_INFO_tRNS) { #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED /* Invert the alpha channel (in tRNS) */ - if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0 && + if ((png_ptr->transformations & PNG_INVERT_ALPHA) && info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { - int j, jend; - - jend = info_ptr->num_trans; - if (jend > PNG_MAX_PALETTE_LENGTH) - jend = PNG_MAX_PALETTE_LENGTH; - - for (j = 0; jnum_trans; j++) info_ptr->trans_alpha[j] = (png_byte)(255 - info_ptr->trans_alpha[j]); } @@ -264,50 +227,42 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) } #endif #ifdef PNG_WRITE_bKGD_SUPPORTED - if ((info_ptr->valid & PNG_INFO_bKGD) != 0) + if (info_ptr->valid & PNG_INFO_bKGD) png_write_bKGD(png_ptr, &(info_ptr->background), info_ptr->color_type); #endif -#ifdef PNG_WRITE_eXIf_SUPPORTED - if ((info_ptr->valid & PNG_INFO_eXIf) != 0) - { - png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif); - png_ptr->mode |= PNG_WROTE_eXIf; - } -#endif - #ifdef PNG_WRITE_hIST_SUPPORTED - if ((info_ptr->valid & PNG_INFO_hIST) != 0) + if (info_ptr->valid & PNG_INFO_hIST) png_write_hIST(png_ptr, info_ptr->hist, info_ptr->num_palette); #endif #ifdef PNG_WRITE_oFFs_SUPPORTED - if ((info_ptr->valid & PNG_INFO_oFFs) != 0) + if (info_ptr->valid & PNG_INFO_oFFs) png_write_oFFs(png_ptr, info_ptr->x_offset, info_ptr->y_offset, info_ptr->offset_unit_type); #endif #ifdef PNG_WRITE_pCAL_SUPPORTED - if ((info_ptr->valid & PNG_INFO_pCAL) != 0) + if (info_ptr->valid & PNG_INFO_pCAL) png_write_pCAL(png_ptr, info_ptr->pcal_purpose, info_ptr->pcal_X0, info_ptr->pcal_X1, info_ptr->pcal_type, info_ptr->pcal_nparams, info_ptr->pcal_units, info_ptr->pcal_params); #endif #ifdef PNG_WRITE_sCAL_SUPPORTED - if ((info_ptr->valid & PNG_INFO_sCAL) != 0) + if (info_ptr->valid & PNG_INFO_sCAL) png_write_sCAL_s(png_ptr, (int)info_ptr->scal_unit, info_ptr->scal_s_width, info_ptr->scal_s_height); #endif /* sCAL */ #ifdef PNG_WRITE_pHYs_SUPPORTED - if ((info_ptr->valid & PNG_INFO_pHYs) != 0) + if (info_ptr->valid & PNG_INFO_pHYs) png_write_pHYs(png_ptr, info_ptr->x_pixels_per_unit, info_ptr->y_pixels_per_unit, info_ptr->phys_unit_type); #endif /* pHYs */ #ifdef PNG_WRITE_tIME_SUPPORTED - if ((info_ptr->valid & PNG_INFO_tIME) != 0) + if (info_ptr->valid & PNG_INFO_tIME) { png_write_tIME(png_ptr, &(info_ptr->mod_time)); png_ptr->mode |= PNG_WROTE_tIME; @@ -315,7 +270,7 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) #endif /* tIME */ #ifdef PNG_WRITE_sPLT_SUPPORTED - if ((info_ptr->valid & PNG_INFO_sPLT) != 0) + if (info_ptr->valid & PNG_INFO_sPLT) for (i = 0; i < (int)info_ptr->splt_palettes_num; i++) png_write_sPLT(png_ptr, info_ptr->splt_palettes + i); #endif /* sPLT */ @@ -337,14 +292,11 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) info_ptr->text[i].lang, info_ptr->text[i].lang_key, info_ptr->text[i].text); - /* Mark this chunk as written */ - if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; - else - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else - png_warning(png_ptr, "Unable to write international text"); + png_warning(png_ptr, "Unable to write international text"); #endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } /* If we want a compressed text chunk */ @@ -353,12 +305,13 @@ png_write_info(png_structrp png_ptr, png_const_inforp info_ptr) #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, info_ptr->text[i].compression); - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; + info_ptr->text[i].text, 0, + info_ptr->text[i].compression); #else png_warning(png_ptr, "Unable to write compressed text"); #endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; } else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) @@ -396,12 +349,11 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) if (png_ptr == NULL) return; - if ((png_ptr->mode & PNG_HAVE_IDAT) == 0) + if (!(png_ptr->mode & PNG_HAVE_IDAT)) png_error(png_ptr, "No IDATs written into file"); #ifdef PNG_WRITE_CHECK_FOR_INVALID_INDEX_SUPPORTED - if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE && - png_ptr->num_palette_max >= png_ptr->num_palette) + if (png_ptr->num_palette_max > png_ptr->num_palette) png_benign_error(png_ptr, "Wrote palette index exceeding num_palette"); #endif @@ -413,8 +365,8 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) #endif #ifdef PNG_WRITE_tIME_SUPPORTED /* Check to see if user has supplied a time chunk */ - if ((info_ptr->valid & PNG_INFO_tIME) != 0 && - (png_ptr->mode & PNG_WROTE_tIME) == 0) + if ((info_ptr->valid & PNG_INFO_tIME) && + !(png_ptr->mode & PNG_WROTE_tIME)) png_write_tIME(png_ptr, &(info_ptr->mod_time)); #endif @@ -423,7 +375,7 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) for (i = 0; i < info_ptr->num_text; i++) { png_debug2(2, "Writing trailer text chunk %d, type %d", i, - info_ptr->text[i].compression); + info_ptr->text[i].compression); /* An internationalized chunk? */ if (info_ptr->text[i].compression > 0) { @@ -435,14 +387,11 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) info_ptr->text[i].lang, info_ptr->text[i].lang_key, info_ptr->text[i].text); - /* Mark this chunk as written */ - if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; - else - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; #else png_warning(png_ptr, "Unable to write international text"); #endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } else if (info_ptr->text[i].compression >= PNG_TEXT_COMPRESSION_zTXt) @@ -450,12 +399,13 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) #ifdef PNG_WRITE_zTXt_SUPPORTED /* Write compressed chunk */ png_write_zTXt(png_ptr, info_ptr->text[i].key, - info_ptr->text[i].text, info_ptr->text[i].compression); - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; + info_ptr->text[i].text, 0, + info_ptr->text[i].compression); #else png_warning(png_ptr, "Unable to write compressed text"); #endif + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_zTXt_WR; } else if (info_ptr->text[i].compression == PNG_TEXT_COMPRESSION_NONE) @@ -464,21 +414,15 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) /* Write uncompressed chunk */ png_write_tEXt(png_ptr, info_ptr->text[i].key, info_ptr->text[i].text, 0); - /* Mark this chunk as written */ - info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; #else png_warning(png_ptr, "Unable to write uncompressed text"); #endif + + /* Mark this chunk as written */ + info_ptr->text[i].compression = PNG_TEXT_COMPRESSION_NONE_WR; } } #endif - -#ifdef PNG_WRITE_eXIf_SUPPORTED - if ((info_ptr->valid & PNG_INFO_eXIf) != 0 && - (png_ptr->mode & PNG_WROTE_eXIf) == 0) - png_write_eXIf(png_ptr, info_ptr->exif, info_ptr->num_exif); -#endif - #ifdef PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED write_unknown_chunks(png_ptr, info_ptr, PNG_AFTER_IDAT); #endif @@ -488,7 +432,6 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) /* Write end of PNG file */ png_write_IEND(png_ptr); - /* This flush, added in libpng-1.0.8, removed from libpng-1.0.9beta03, * and restored again in libpng-1.2.30, may cause some applications that * do not set png_ptr->output_flush_fn to crash. If your application @@ -505,7 +448,7 @@ png_write_end(png_structrp png_ptr, png_inforp info_ptr) #ifdef PNG_CONVERT_tIME_SUPPORTED void PNGAPI -png_convert_from_struct_tm(png_timep ptime, const struct tm * ttime) +png_convert_from_struct_tm(png_timep ptime, PNG_CONST struct tm * ttime) { png_debug(1, "in png_convert_from_struct_tm"); @@ -525,16 +468,6 @@ png_convert_from_time_t(png_timep ptime, time_t ttime) png_debug(1, "in png_convert_from_time_t"); tbuf = gmtime(&ttime); - if (tbuf == NULL) - { - /* TODO: add a safe function which takes a png_ptr argument and raises - * a png_error if the ttime argument is invalid and the call to gmtime - * fails as a consequence. - */ - memset(ptime, 0, sizeof(*ptime)); - return; - } - png_convert_from_struct_tm(ptime, tbuf); } #endif @@ -542,12 +475,11 @@ png_convert_from_time_t(png_timep ptime, time_t ttime) /* Initialize png_ptr structure, and allocate any memory needed */ PNG_FUNCTION(png_structp,PNGAPI png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, - png_error_ptr error_fn, png_error_ptr warn_fn), - PNG_ALLOCATED) + png_error_ptr error_fn, png_error_ptr warn_fn),PNG_ALLOCATED) { #ifndef PNG_USER_MEM_SUPPORTED png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, - error_fn, warn_fn, NULL, NULL, NULL); + error_fn, warn_fn, NULL, NULL, NULL); #else return png_create_write_struct_2(user_png_ver, error_ptr, error_fn, warn_fn, NULL, NULL, NULL); @@ -557,56 +489,56 @@ png_create_write_struct,(png_const_charp user_png_ver, png_voidp error_ptr, PNG_FUNCTION(png_structp,PNGAPI png_create_write_struct_2,(png_const_charp user_png_ver, png_voidp error_ptr, png_error_ptr error_fn, png_error_ptr warn_fn, png_voidp mem_ptr, - png_malloc_ptr malloc_fn, png_free_ptr free_fn), - PNG_ALLOCATED) + png_malloc_ptr malloc_fn, png_free_ptr free_fn),PNG_ALLOCATED) { png_structrp png_ptr = png_create_png_struct(user_png_ver, error_ptr, - error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); -#endif /* USER_MEM */ - if (png_ptr != NULL) - { - /* Set the zlib control values to defaults; they can be overridden by the - * application after the struct has been created. - */ - png_ptr->zbuffer_size = PNG_ZBUF_SIZE; + error_fn, warn_fn, mem_ptr, malloc_fn, free_fn); +#endif /* PNG_USER_MEM_SUPPORTED */ - /* The 'zlib_strategy' setting is irrelevant because png_default_claim in - * pngwutil.c defaults it according to whether or not filters will be - * used, and ignores this setting. - */ - png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY; - png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION; - png_ptr->zlib_mem_level = 8; - png_ptr->zlib_window_bits = 15; - png_ptr->zlib_method = 8; + /* Set the zlib control values to defaults; they can be overridden by the + * application after the struct has been created. + */ + png_ptr->zbuffer_size = PNG_ZBUF_SIZE; + + /* The 'zlib_strategy' setting is irrelevant because png_default_claim in + * pngwutil.c defaults it according to whether or not filters will be used, + * and ignores this setting. + */ + png_ptr->zlib_strategy = PNG_Z_DEFAULT_STRATEGY; + png_ptr->zlib_level = PNG_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_mem_level = 8; + png_ptr->zlib_window_bits = 15; + png_ptr->zlib_method = 8; #ifdef PNG_WRITE_COMPRESSED_TEXT_SUPPORTED - png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY; - png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION; - png_ptr->zlib_text_mem_level = 8; - png_ptr->zlib_text_window_bits = 15; - png_ptr->zlib_text_method = 8; -#endif /* WRITE_COMPRESSED_TEXT */ + png_ptr->zlib_text_strategy = PNG_TEXT_Z_DEFAULT_STRATEGY; + png_ptr->zlib_text_level = PNG_TEXT_Z_DEFAULT_COMPRESSION; + png_ptr->zlib_text_mem_level = 8; + png_ptr->zlib_text_window_bits = 15; + png_ptr->zlib_text_method = 8; +#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ - /* This is a highly dubious configuration option; by default it is off, - * but it may be appropriate for private builds that are testing - * extensions not conformant to the current specification, or of - * applications that must not fail to write at all costs! - */ -#ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED + /* This is a highly dubious configuration option; by default it is off, but + * it may be appropriate for private builds that are testing extensions not + * conformant to the current specification, or of applications that must not + * fail to write at all costs! + */ +# ifdef PNG_BENIGN_WRITE_ERRORS_SUPPORTED + png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; /* In stable builds only warn if an application error can be completely * handled. */ - png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN; -#endif +# endif - /* App warnings are warnings in release (or release candidate) builds but - * are errors during development. - */ -#if PNG_RELEASE_BUILD + /* App warnings are warnings in release (or release candidate) builds but + * are errors during development. + */ +# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC png_ptr->flags |= PNG_FLAG_APP_WARNINGS_WARN; -#endif +# endif + if (png_ptr != NULL) + { /* TODO: delay this, it can be done in png_init_io() (if the app doesn't * do it itself) avoiding setting the default function if it is not * required. @@ -676,71 +608,6 @@ png_write_image(png_structrp png_ptr, png_bytepp image) } } -#ifdef PNG_MNG_FEATURES_SUPPORTED -/* Performs intrapixel differencing */ -static void -png_do_write_intrapixel(png_row_infop row_info, png_bytep row) -{ - png_debug(1, "in png_do_write_intrapixel"); - - if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) - { - int bytes_per_pixel; - png_uint_32 row_width = row_info->width; - if (row_info->bit_depth == 8) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 3; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 4; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - *(rp) = (png_byte)(*rp - *(rp + 1)); - *(rp + 2) = (png_byte)(*(rp + 2) - *(rp + 1)); - } - } - -#ifdef PNG_WRITE_16BIT_SUPPORTED - else if (row_info->bit_depth == 16) - { - png_bytep rp; - png_uint_32 i; - - if (row_info->color_type == PNG_COLOR_TYPE_RGB) - bytes_per_pixel = 6; - - else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) - bytes_per_pixel = 8; - - else - return; - - for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) - { - png_uint_32 s0 = (png_uint_32)(*(rp ) << 8) | *(rp + 1); - png_uint_32 s1 = (png_uint_32)(*(rp + 2) << 8) | *(rp + 3); - png_uint_32 s2 = (png_uint_32)(*(rp + 4) << 8) | *(rp + 5); - png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); - png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); - *(rp ) = (png_byte)(red >> 8); - *(rp + 1) = (png_byte)red; - *(rp + 4) = (png_byte)(blue >> 8); - *(rp + 5) = (png_byte)blue; - } - } -#endif /* WRITE_16BIT */ - } -} -#endif /* MNG_FEATURES */ - /* Called by user to write a row of image data */ void PNGAPI png_write_row(png_structrp png_ptr, png_const_bytep row) @@ -748,54 +615,54 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) /* 1.5.6: moved from png_struct to be a local structure: */ png_row_info row_info; - png_debug2(1, "in png_write_row (row %u, pass %d)", - png_ptr->row_number, png_ptr->pass); - if (png_ptr == NULL) return; + png_debug2(1, "in png_write_row (row %u, pass %d)", + png_ptr->row_number, png_ptr->pass); + /* Initialize transformations and other stuff if first time */ if (png_ptr->row_number == 0 && png_ptr->pass == 0) { /* Make sure we wrote the header info */ - if ((png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE) == 0) + if (!(png_ptr->mode & PNG_WROTE_INFO_BEFORE_PLTE)) png_error(png_ptr, "png_write_info was never called before png_write_row"); /* Check for transforms that have been set but were defined out */ #if !defined(PNG_WRITE_INVERT_SUPPORTED) && defined(PNG_READ_INVERT_SUPPORTED) - if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) + if (png_ptr->transformations & PNG_INVERT_MONO) png_warning(png_ptr, "PNG_WRITE_INVERT_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_FILLER_SUPPORTED) && defined(PNG_READ_FILLER_SUPPORTED) - if ((png_ptr->transformations & PNG_FILLER) != 0) + if (png_ptr->transformations & PNG_FILLER) png_warning(png_ptr, "PNG_WRITE_FILLER_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_PACKSWAP_SUPPORTED) && \ defined(PNG_READ_PACKSWAP_SUPPORTED) - if ((png_ptr->transformations & PNG_PACKSWAP) != 0) + if (png_ptr->transformations & PNG_PACKSWAP) png_warning(png_ptr, "PNG_WRITE_PACKSWAP_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_PACK_SUPPORTED) && defined(PNG_READ_PACK_SUPPORTED) - if ((png_ptr->transformations & PNG_PACK) != 0) + if (png_ptr->transformations & PNG_PACK) png_warning(png_ptr, "PNG_WRITE_PACK_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_SHIFT_SUPPORTED) && defined(PNG_READ_SHIFT_SUPPORTED) - if ((png_ptr->transformations & PNG_SHIFT) != 0) + if (png_ptr->transformations & PNG_SHIFT) png_warning(png_ptr, "PNG_WRITE_SHIFT_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_BGR_SUPPORTED) && defined(PNG_READ_BGR_SUPPORTED) - if ((png_ptr->transformations & PNG_BGR) != 0) + if (png_ptr->transformations & PNG_BGR) png_warning(png_ptr, "PNG_WRITE_BGR_SUPPORTED is not defined"); #endif #if !defined(PNG_WRITE_SWAP_SUPPORTED) && defined(PNG_READ_SWAP_SUPPORTED) - if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) + if (png_ptr->transformations & PNG_SWAP_BYTES) png_warning(png_ptr, "PNG_WRITE_SWAP_SUPPORTED is not defined"); #endif @@ -804,13 +671,12 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced and not interested in row, return */ - if (png_ptr->interlaced != 0 && - (png_ptr->transformations & PNG_INTERLACE) != 0) + if (png_ptr->interlaced && (png_ptr->transformations & PNG_INTERLACE)) { switch (png_ptr->pass) { case 0: - if ((png_ptr->row_number & 0x07) != 0) + if (png_ptr->row_number & 0x07) { png_write_finish_row(png_ptr); return; @@ -818,7 +684,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) break; case 1: - if ((png_ptr->row_number & 0x07) != 0 || png_ptr->width < 5) + if ((png_ptr->row_number & 0x07) || png_ptr->width < 5) { png_write_finish_row(png_ptr); return; @@ -834,7 +700,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) break; case 3: - if ((png_ptr->row_number & 0x03) != 0 || png_ptr->width < 3) + if ((png_ptr->row_number & 0x03) || png_ptr->width < 3) { png_write_finish_row(png_ptr); return; @@ -850,7 +716,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) break; case 5: - if ((png_ptr->row_number & 0x01) != 0 || png_ptr->width < 2) + if ((png_ptr->row_number & 0x01) || png_ptr->width < 2) { png_write_finish_row(png_ptr); return; @@ -858,7 +724,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) break; case 6: - if ((png_ptr->row_number & 0x01) == 0) + if (!(png_ptr->row_number & 0x01)) { png_write_finish_row(png_ptr); return; @@ -892,11 +758,11 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* Handle interlacing */ if (png_ptr->interlaced && png_ptr->pass < 6 && - (png_ptr->transformations & PNG_INTERLACE) != 0) + (png_ptr->transformations & PNG_INTERLACE)) { png_do_write_interlace(&row_info, png_ptr->row_buf + 1, png_ptr->pass); /* This should always get caught above, but still ... */ - if (row_info.width == 0) + if (!(row_info.width)) { png_write_finish_row(png_ptr); return; @@ -906,7 +772,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED /* Handle other transformations */ - if (png_ptr->transformations != 0) + if (png_ptr->transformations) png_do_write_transformations(png_ptr, &row_info); #endif @@ -914,7 +780,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) * which is also the output depth. */ if (row_info.pixel_depth != png_ptr->pixel_depth || - row_info.pixel_depth != png_ptr->transformed_pixel_depth) + row_info.pixel_depth != png_ptr->transformed_pixel_depth) png_error(png_ptr, "internal write transform logic error"); #ifdef PNG_MNG_FEATURES_SUPPORTED @@ -927,7 +793,7 @@ png_write_row(png_structrp png_ptr, png_const_bytep row) * 4. The filter_method is 64 and * 5. The color_type is RGB or RGBA */ - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && (png_ptr->filter_type == PNG_INTRAPIXEL_DIFFERENCING)) { /* Intrapixel differencing */ @@ -960,7 +826,7 @@ png_set_flush(png_structrp png_ptr, int nrows) if (png_ptr == NULL) return; - png_ptr->flush_dist = (nrows < 0 ? 0 : (png_uint_32)nrows); + png_ptr->flush_dist = (nrows < 0 ? 0 : nrows); } /* Flush the current output buffers now */ @@ -980,7 +846,11 @@ png_write_flush(png_structrp png_ptr) png_ptr->flush_rows = 0; png_flush(png_ptr); } -#endif /* WRITE_FLUSH */ +#endif /* PNG_WRITE_FLUSH_SUPPORTED */ + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED +static void png_reset_filter_heuristics(png_structrp png_ptr);/* forward decl */ +#endif /* Free any memory used in png_ptr struct without freeing the struct itself. */ static void @@ -989,25 +859,29 @@ png_write_destroy(png_structrp png_ptr) png_debug(1, "in png_write_destroy"); /* Free any memory zlib uses */ - if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) deflateEnd(&png_ptr->zstream); /* Free our memory. png_free checks NULL for us. */ png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); png_free(png_ptr, png_ptr->row_buf); - png_ptr->row_buf = NULL; #ifdef PNG_WRITE_FILTER_SUPPORTED png_free(png_ptr, png_ptr->prev_row); - png_free(png_ptr, png_ptr->try_row); - png_free(png_ptr, png_ptr->tst_row); - png_ptr->prev_row = NULL; - png_ptr->try_row = NULL; - png_ptr->tst_row = NULL; + png_free(png_ptr, png_ptr->sub_row); + png_free(png_ptr, png_ptr->up_row); + png_free(png_ptr, png_ptr->avg_row); + png_free(png_ptr, png_ptr->paeth_row); +#endif + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + /* Use this to save a little code space, it doesn't free the filter_costs */ + png_reset_filter_heuristics(png_ptr); + png_free(png_ptr, png_ptr->filter_costs); + png_free(png_ptr, png_ptr->inv_filter_costs); #endif #ifdef PNG_SET_UNKNOWN_CHUNKS_SUPPORTED png_free(png_ptr, png_ptr->chunk_list); - png_ptr->chunk_list = NULL; #endif /* The error handling and memory handling information is left intact at this @@ -1053,7 +927,7 @@ png_set_filter(png_structrp png_ptr, int method, int filters) return; #ifdef PNG_MNG_FEATURES_SUPPORTED - if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && + if ((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && (method == PNG_INTRAPIXEL_DIFFERENCING)) method = PNG_FILTER_TYPE_BASE; @@ -1066,8 +940,8 @@ png_set_filter(png_structrp png_ptr, int method, int filters) case 5: case 6: case 7: png_app_error(png_ptr, "Unknown row filter for method 0"); -#endif /* WRITE_FILTER */ - /* FALLTHROUGH */ + /* FALL THROUGH */ +#endif /* PNG_WRITE_FILTER_SUPPORTED */ case PNG_FILTER_VALUE_NONE: png_ptr->do_filter = PNG_FILTER_NONE; break; @@ -1089,88 +963,211 @@ png_set_filter(png_structrp png_ptr, int method, int filters) #else default: png_app_error(png_ptr, "Unknown row filter for method 0"); -#endif /* WRITE_FILTER */ +#endif /* PNG_WRITE_FILTER_SUPPORTED */ } -#ifdef PNG_WRITE_FILTER_SUPPORTED /* If we have allocated the row_buf, this means we have already started * with the image and we should have allocated all of the filter buffers * that have been selected. If prev_row isn't already allocated, then * it is too late to start using the filters that need it, since we * will be missing the data in the previous row. If an application * wants to start and stop using particular filters during compression, - * it should start out with all of the filters, and then remove them - * or add them back after the start of compression. - * - * NOTE: this is a nasty constraint on the code, because it means that the - * prev_row buffer must be maintained even if there are currently no - * 'prev_row' requiring filters active. + * it should start out with all of the filters, and then add and + * remove them after the start of compression. */ if (png_ptr->row_buf != NULL) { - int num_filters; - png_alloc_size_t buf_size; - - /* Repeat the checks in png_write_start_row; 1 pixel high or wide - * images cannot benefit from certain filters. If this isn't done here - * the check below will fire on 1 pixel high images. - */ - if (png_ptr->height == 1) - filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); - - if (png_ptr->width == 1) - filters &= ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH); - - if ((filters & (PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH)) != 0 - && png_ptr->prev_row == NULL) +#ifdef PNG_WRITE_FILTER_SUPPORTED + if ((png_ptr->do_filter & PNG_FILTER_SUB) && png_ptr->sub_row == NULL) { - /* This is the error case, however it is benign - the previous row - * is not available so the filter can't be used. Just warn here. - */ - png_app_warning(png_ptr, - "png_set_filter: UP/AVG/PAETH cannot be added after start"); - filters &= ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; } - num_filters = 0; - - if (filters & PNG_FILTER_SUB) - num_filters++; - - if (filters & PNG_FILTER_UP) - num_filters++; - - if (filters & PNG_FILTER_AVG) - num_filters++; - - if (filters & PNG_FILTER_PAETH) - num_filters++; - - /* Allocate needed row buffers if they have not already been - * allocated. - */ - buf_size = PNG_ROWBYTES(png_ptr->usr_channels * png_ptr->usr_bit_depth, - png_ptr->width) + 1; - - if (png_ptr->try_row == NULL) - png_ptr->try_row = png_voidcast(png_bytep, - png_malloc(png_ptr, buf_size)); - - if (num_filters > 1) + if ((png_ptr->do_filter & PNG_FILTER_UP) && png_ptr->up_row == NULL) { - if (png_ptr->tst_row == NULL) - png_ptr->tst_row = png_voidcast(png_bytep, - png_malloc(png_ptr, buf_size)); + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Up filter after starting"); + png_ptr->do_filter = (png_byte)(png_ptr->do_filter & + ~PNG_FILTER_UP); + } + + else + { + png_ptr->up_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; + } } + + if ((png_ptr->do_filter & PNG_FILTER_AVG) && png_ptr->avg_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Average filter after starting"); + png_ptr->do_filter = (png_byte)(png_ptr->do_filter & + ~PNG_FILTER_AVG); + } + + else + { + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; + } + } + + if ((png_ptr->do_filter & PNG_FILTER_PAETH) && + png_ptr->paeth_row == NULL) + { + if (png_ptr->prev_row == NULL) + { + png_warning(png_ptr, "Can't add Paeth filter after starting"); + png_ptr->do_filter &= (png_byte)(~PNG_FILTER_PAETH); + } + + else + { + png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, + (png_ptr->rowbytes + 1)); + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; + } + } + + if (png_ptr->do_filter == PNG_NO_FILTERS) +#endif /* PNG_WRITE_FILTER_SUPPORTED */ + png_ptr->do_filter = PNG_FILTER_NONE; } - png_ptr->do_filter = (png_byte)filters; -#endif } else png_error(png_ptr, "Unknown custom filter method"); } -#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* DEPRECATED */ +/* This allows us to influence the way in which libpng chooses the "best" + * filter for the current scanline. While the "minimum-sum-of-absolute- + * differences metric is relatively fast and effective, there is some + * question as to whether it can be improved upon by trying to keep the + * filtered data going to zlib more consistent, hopefully resulting in + * better compression. + */ +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED /* GRR 970116 */ +/* Convenience reset API. */ +static void +png_reset_filter_heuristics(png_structrp png_ptr) +{ + /* Clear out any old values in the 'weights' - this must be done because if + * the app calls set_filter_heuristics multiple times with different + * 'num_weights' values we would otherwise potentially have wrong sized + * arrays. + */ + png_ptr->num_prev_filters = 0; + png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_UNWEIGHTED; + if (png_ptr->prev_filters != NULL) + { + png_bytep old = png_ptr->prev_filters; + png_ptr->prev_filters = NULL; + png_free(png_ptr, old); + } + if (png_ptr->filter_weights != NULL) + { + png_uint_16p old = png_ptr->filter_weights; + png_ptr->filter_weights = NULL; + png_free(png_ptr, old); + } + + if (png_ptr->inv_filter_weights != NULL) + { + png_uint_16p old = png_ptr->inv_filter_weights; + png_ptr->inv_filter_weights = NULL; + png_free(png_ptr, old); + } + + /* Leave the filter_costs - this array is fixed size. */ +} + +static int +png_init_filter_heuristics(png_structrp png_ptr, int heuristic_method, + int num_weights) +{ + if (png_ptr == NULL) + return 0; + + /* Clear out the arrays */ + png_reset_filter_heuristics(png_ptr); + + /* Check arguments; the 'reset' function makes the correct settings for the + * unweighted case, but we must handle the weight case by initializing the + * arrays for the caller. + */ + if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int i; + + if (num_weights > 0) + { + png_ptr->prev_filters = (png_bytep)png_malloc(png_ptr, + (png_uint_32)((sizeof (png_byte)) * num_weights)); + + /* To make sure that the weighting starts out fairly */ + for (i = 0; i < num_weights; i++) + { + png_ptr->prev_filters[i] = 255; + } + + png_ptr->filter_weights = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)((sizeof (png_uint_16)) * num_weights)); + + png_ptr->inv_filter_weights = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)((sizeof (png_uint_16)) * num_weights)); + + for (i = 0; i < num_weights; i++) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + + /* Safe to set this now */ + png_ptr->num_prev_filters = (png_byte)num_weights; + } + + /* If, in the future, there are other filter methods, this would + * need to be based on png_ptr->filter. + */ + if (png_ptr->filter_costs == NULL) + { + png_ptr->filter_costs = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); + + png_ptr->inv_filter_costs = (png_uint_16p)png_malloc(png_ptr, + (png_uint_32)((sizeof (png_uint_16)) * PNG_FILTER_VALUE_LAST)); + } + + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) + { + png_ptr->inv_filter_costs[i] = + png_ptr->filter_costs[i] = PNG_COST_FACTOR; + } + + /* All the arrays are inited, safe to set this: */ + png_ptr->heuristic_method = PNG_FILTER_HEURISTIC_WEIGHTED; + + /* Return the 'ok' code. */ + return 1; + } + else if (heuristic_method == PNG_FILTER_HEURISTIC_DEFAULT || + heuristic_method == PNG_FILTER_HEURISTIC_UNWEIGHTED) + { + return 1; + } + else + { + png_warning(png_ptr, "Unknown filter heuristic method"); + return 0; + } +} + /* Provide floating and fixed point APIs */ #ifdef PNG_FLOATING_POINT_SUPPORTED void PNGAPI @@ -1178,11 +1175,52 @@ png_set_filter_heuristics(png_structrp png_ptr, int heuristic_method, int num_weights, png_const_doublep filter_weights, png_const_doublep filter_costs) { - PNG_UNUSED(png_ptr) - PNG_UNUSED(heuristic_method) - PNG_UNUSED(num_weights) - PNG_UNUSED(filter_weights) - PNG_UNUSED(filter_costs) + png_debug(1, "in png_set_filter_heuristics"); + + /* The internal API allocates all the arrays and ensures that the elements of + * those arrays are set to the default value. + */ + if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights)) + return; + + /* If using the weighted method copy in the weights. */ + if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int i; + for (i = 0; i < num_weights; i++) + { + if (filter_weights[i] <= 0.0) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + + else + { + png_ptr->inv_filter_weights[i] = + (png_uint_16)(PNG_WEIGHT_FACTOR*filter_weights[i]+.5); + + png_ptr->filter_weights[i] = + (png_uint_16)(PNG_WEIGHT_FACTOR/filter_weights[i]+.5); + } + } + + /* Here is where we set the relative costs of the different filters. We + * should take the desired compression level into account when setting + * the costs, so that Paeth, for instance, has a high relative cost at low + * compression levels, while it has a lower relative cost at higher + * compression settings. The filter types are in order of increasing + * relative cost, so it would be possible to do this with an algorithm. + */ + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) if (filter_costs[i] >= 1.0) + { + png_ptr->inv_filter_costs[i] = + (png_uint_16)(PNG_COST_FACTOR / filter_costs[i] + .5); + + png_ptr->filter_costs[i] = + (png_uint_16)(PNG_COST_FACTOR * filter_costs[i] + .5); + } + } } #endif /* FLOATING_POINT */ @@ -1192,16 +1230,67 @@ png_set_filter_heuristics_fixed(png_structrp png_ptr, int heuristic_method, int num_weights, png_const_fixed_point_p filter_weights, png_const_fixed_point_p filter_costs) { - PNG_UNUSED(png_ptr) - PNG_UNUSED(heuristic_method) - PNG_UNUSED(num_weights) - PNG_UNUSED(filter_weights) - PNG_UNUSED(filter_costs) + png_debug(1, "in png_set_filter_heuristics_fixed"); + + /* The internal API allocates all the arrays and ensures that the elements of + * those arrays are set to the default value. + */ + if (!png_init_filter_heuristics(png_ptr, heuristic_method, num_weights)) + return; + + /* If using the weighted method copy in the weights. */ + if (heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int i; + for (i = 0; i < num_weights; i++) + { + if (filter_weights[i] <= 0) + { + png_ptr->inv_filter_weights[i] = + png_ptr->filter_weights[i] = PNG_WEIGHT_FACTOR; + } + + else + { + png_ptr->inv_filter_weights[i] = (png_uint_16) + ((PNG_WEIGHT_FACTOR*filter_weights[i]+PNG_FP_HALF)/PNG_FP_1); + + png_ptr->filter_weights[i] = (png_uint_16)((PNG_WEIGHT_FACTOR* + PNG_FP_1+(filter_weights[i]/2))/filter_weights[i]); + } + } + + /* Here is where we set the relative costs of the different filters. We + * should take the desired compression level into account when setting + * the costs, so that Paeth, for instance, has a high relative cost at low + * compression levels, while it has a lower relative cost at higher + * compression settings. The filter types are in order of increasing + * relative cost, so it would be possible to do this with an algorithm. + */ + for (i = 0; i < PNG_FILTER_VALUE_LAST; i++) + if (filter_costs[i] >= PNG_FP_1) + { + png_uint_32 tmp; + + /* Use a 32 bit unsigned temporary here because otherwise the + * intermediate value will be a 32 bit *signed* integer (ANSI rules) + * and this will get the wrong answer on division. + */ + tmp = PNG_COST_FACTOR*PNG_FP_1 + (filter_costs[i]/2); + tmp /= filter_costs[i]; + + png_ptr->inv_filter_costs[i] = (png_uint_16)tmp; + + tmp = PNG_COST_FACTOR * filter_costs[i] + PNG_FP_HALF; + tmp /= PNG_FP_1; + + png_ptr->filter_costs[i] = (png_uint_16)tmp; + } + } } #endif /* FIXED_POINT */ -#endif /* WRITE_WEIGHTED_FILTER */ +#endif /* PNG_WRITE_WEIGHTED_FILTER_SUPPORTED */ -#ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED void PNGAPI png_set_compression_level(png_structrp png_ptr, int level) { @@ -1244,13 +1333,11 @@ png_set_compression_strategy(png_structrp png_ptr, int strategy) void PNGAPI png_set_compression_window_bits(png_structrp png_ptr, int window_bits) { - png_debug(1, "in png_set_compression_window_bits"); - if (png_ptr == NULL) return; - /* Prior to 1.6.0 this would warn but then set the window_bits value. This - * meant that negative window bits values could be selected that would cause + /* Prior to 1.6.0 this would warn but then set the window_bits value, this + * meant that negative window bits values could be selected which would cause * libpng to write a non-standard PNG file with raw deflate or gzip * compressed IDAT or ancillary chunks. Such files can be read and there is * no warning on read, so this seems like a very bad idea. @@ -1286,7 +1373,6 @@ png_set_compression_method(png_structrp png_ptr, int method) png_ptr->zlib_method = method; } -#endif /* WRITE_CUSTOMIZE_COMPRESSION */ /* The following were added to libpng-1.5.4 */ #ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED @@ -1329,8 +1415,6 @@ png_set_text_compression_strategy(png_structrp png_ptr, int strategy) void PNGAPI png_set_text_compression_window_bits(png_structrp png_ptr, int window_bits) { - png_debug(1, "in png_set_text_compression_window_bits"); - if (png_ptr == NULL) return; @@ -1362,14 +1446,12 @@ png_set_text_compression_method(png_structrp png_ptr, int method) png_ptr->zlib_text_method = method; } -#endif /* WRITE_CUSTOMIZE_ZTXT_COMPRESSION */ +#endif /* PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED */ /* end of API added to libpng-1.5.4 */ void PNGAPI png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn) { - png_debug(1, "in png_set_write_status_fn"); - if (png_ptr == NULL) return; @@ -1378,8 +1460,8 @@ png_set_write_status_fn(png_structrp png_ptr, png_write_status_ptr write_row_fn) #ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED void PNGAPI -png_set_write_user_transform_fn(png_structrp png_ptr, - png_user_transform_ptr write_user_transform_fn) +png_set_write_user_transform_fn(png_structrp png_ptr, png_user_transform_ptr + write_user_transform_fn) { png_debug(1, "in png_set_write_user_transform_fn"); @@ -1395,145 +1477,114 @@ png_set_write_user_transform_fn(png_structrp png_ptr, #ifdef PNG_INFO_IMAGE_SUPPORTED void PNGAPI png_write_png(png_structrp png_ptr, png_inforp info_ptr, - int transforms, png_voidp params) + int transforms, voidp params) { - png_debug(1, "in png_write_png"); - if (png_ptr == NULL || info_ptr == NULL) return; - if ((info_ptr->valid & PNG_INFO_IDAT) == 0) - { - png_app_error(png_ptr, "no rows for png_write_image to write"); - return; - } - /* Write the file header information. */ png_write_info(png_ptr, info_ptr); /* ------ these transformations don't touch the info structure ------- */ - /* Invert monochrome pixels */ - if ((transforms & PNG_TRANSFORM_INVERT_MONO) != 0) #ifdef PNG_WRITE_INVERT_SUPPORTED + /* Invert monochrome pixels */ + if (transforms & PNG_TRANSFORM_INVERT_MONO) png_set_invert_mono(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_MONO not supported"); #endif +#ifdef PNG_WRITE_SHIFT_SUPPORTED /* Shift the pixels up to a legal bit depth and fill in * as appropriate to correctly scale the image. */ - if ((transforms & PNG_TRANSFORM_SHIFT) != 0) -#ifdef PNG_WRITE_SHIFT_SUPPORTED - if ((info_ptr->valid & PNG_INFO_sBIT) != 0) - png_set_shift(png_ptr, &info_ptr->sig_bit); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_SHIFT not supported"); + if ((transforms & PNG_TRANSFORM_SHIFT) + && (info_ptr->valid & PNG_INFO_sBIT)) + png_set_shift(png_ptr, &info_ptr->sig_bit); #endif - /* Pack pixels into bytes */ - if ((transforms & PNG_TRANSFORM_PACKING) != 0) #ifdef PNG_WRITE_PACK_SUPPORTED - png_set_packing(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_PACKING not supported"); + /* Pack pixels into bytes */ + if (transforms & PNG_TRANSFORM_PACKING) + png_set_packing(png_ptr); #endif - /* Swap location of alpha bytes from ARGB to RGBA */ - if ((transforms & PNG_TRANSFORM_SWAP_ALPHA) != 0) #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + /* Swap location of alpha bytes from ARGB to RGBA */ + if (transforms & PNG_TRANSFORM_SWAP_ALPHA) png_set_swap_alpha(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ALPHA not supported"); #endif - /* Remove a filler (X) from XRGB/RGBX/AG/GA into to convert it into - * RGB, note that the code expects the input color type to be G or RGB; no - * alpha channel. - */ - if ((transforms & (PNG_TRANSFORM_STRIP_FILLER_AFTER| - PNG_TRANSFORM_STRIP_FILLER_BEFORE)) != 0) - { #ifdef PNG_WRITE_FILLER_SUPPORTED - if ((transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) != 0) - { - if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) - png_app_error(png_ptr, - "PNG_TRANSFORM_STRIP_FILLER: BEFORE+AFTER not supported"); + /* Pack XRGB/RGBX/ARGB/RGBA into RGB (4 channels -> 3 channels) */ + if (transforms & PNG_TRANSFORM_STRIP_FILLER_AFTER) + png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); - /* Continue if ignored - this is the pre-1.6.10 behavior */ - png_set_filler(png_ptr, 0, PNG_FILLER_AFTER); - } - - else if ((transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) != 0) - png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_STRIP_FILLER not supported"); + else if (transforms & PNG_TRANSFORM_STRIP_FILLER_BEFORE) + png_set_filler(png_ptr, 0, PNG_FILLER_BEFORE); #endif - } - /* Flip BGR pixels to RGB */ - if ((transforms & PNG_TRANSFORM_BGR) != 0) #ifdef PNG_WRITE_BGR_SUPPORTED + /* Flip BGR pixels to RGB */ + if (transforms & PNG_TRANSFORM_BGR) png_set_bgr(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_BGR not supported"); #endif - /* Swap bytes of 16-bit files to most significant byte first */ - if ((transforms & PNG_TRANSFORM_SWAP_ENDIAN) != 0) #ifdef PNG_WRITE_SWAP_SUPPORTED + /* Swap bytes of 16-bit files to most significant byte first */ + if (transforms & PNG_TRANSFORM_SWAP_ENDIAN) png_set_swap(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_SWAP_ENDIAN not supported"); #endif - /* Swap bits of 1-bit, 2-bit, 4-bit packed pixel formats */ - if ((transforms & PNG_TRANSFORM_PACKSWAP) != 0) #ifdef PNG_WRITE_PACKSWAP_SUPPORTED + /* Swap bits of 1, 2, 4 bit packed pixel formats */ + if (transforms & PNG_TRANSFORM_PACKSWAP) png_set_packswap(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_PACKSWAP not supported"); #endif - /* Invert the alpha channel from opacity to transparency */ - if ((transforms & PNG_TRANSFORM_INVERT_ALPHA) != 0) #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + /* Invert the alpha channel from opacity to transparency */ + if (transforms & PNG_TRANSFORM_INVERT_ALPHA) png_set_invert_alpha(png_ptr); -#else - png_app_error(png_ptr, "PNG_TRANSFORM_INVERT_ALPHA not supported"); #endif /* ----------------------- end of transformations ------------------- */ /* Write the bits */ - png_write_image(png_ptr, info_ptr->row_pointers); + if (info_ptr->valid & PNG_INFO_IDAT) + png_write_image(png_ptr, info_ptr->row_pointers); /* It is REQUIRED to call this to finish writing the rest of the file */ png_write_end(png_ptr, info_ptr); + PNG_UNUSED(transforms) /* Quiet compiler warnings */ PNG_UNUSED(params) } #endif #ifdef PNG_SIMPLIFIED_WRITE_SUPPORTED +#ifdef PNG_STDIO_SUPPORTED /* currently required for png_image_write_* */ /* Initialize the write structure - general purpose utility. */ static int -png_image_write_init(png_imagep image) +// 4j studios: callback support +png_image_write_init(png_imagep image, /*begin 4j change*/ png_rw_ptr write_fn, png_flush_ptr flush_fn /*end 4j change*/) { png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, image, - png_safe_error, png_safe_warning); + png_safe_error, png_safe_warning); if (png_ptr != NULL) { png_infop info_ptr = png_create_info_struct(png_ptr); + /*begin 4j change*/ + if (write_fn != NULL) + png_set_write_fn(png_ptr, NULL, write_fn, flush_fn); + /*end 4j change*/ + if (info_ptr != NULL) { png_controlp control = png_voidcast(png_controlp, - png_malloc_warn(png_ptr, (sizeof *control))); + png_malloc_warn(png_ptr, (sizeof *control))); if (control != NULL) { @@ -1560,22 +1611,16 @@ png_image_write_init(png_imagep image) /* Arguments to png_image_write_main: */ typedef struct { - /* Arguments */ - png_imagep image; + /* Arguments: */ + png_imagep image; png_const_voidp buffer; - png_int_32 row_stride; + png_int_32 row_stride; png_const_voidp colormap; - int convert_to_8bit; - - /* Instance variables */ + int convert_to_8bit; + /* Local variables: */ png_const_voidp first_row; - png_voidp local_row; - ptrdiff_t row_step; - - /* Byte count for memory writing */ - png_bytep memory; - png_alloc_size_t memory_bytes; /* not used for STDIO */ - png_alloc_size_t output_bytes; /* running total */ + ptrdiff_t row_bytes; + png_voidp local_row; } png_image_write_control; /* Write png_uint_16 input to a 16-bit PNG; the png_ptr has already been set to @@ -1586,33 +1631,29 @@ static int png_write_image_16bit(png_voidp argument) { png_image_write_control *display = png_voidcast(png_image_write_control*, - argument); + argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, - display->first_row); + display->first_row); png_uint_16p output_row = png_voidcast(png_uint_16p, display->local_row); png_uint_16p row_end; - unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? - 3 : 1; + const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; int aindex = 0; png_uint_32 y = image->height; - if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + if (image->format & PNG_FORMAT_FLAG_ALPHA) { -# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED - if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + if (image->format & PNG_FORMAT_FLAG_AFIRST) { aindex = -1; ++input_row; /* To point to the first component */ ++output_row; } - else - aindex = (int)channels; -# else - aindex = (int)channels; -# endif + + else + aindex = channels; } else @@ -1624,14 +1665,14 @@ png_write_image_16bit(png_voidp argument) */ row_end = output_row + image->width * (channels+1); - for (; y > 0; --y) + while (y-- > 0) { png_const_uint_16p in_ptr = input_row; png_uint_16p out_ptr = output_row; while (out_ptr < row_end) { - png_uint_16 alpha = in_ptr[aindex]; + const png_uint_16 alpha = in_ptr[aindex]; png_uint_32 reciprocal = 0; int c; @@ -1645,7 +1686,7 @@ png_write_image_16bit(png_voidp argument) if (alpha > 0 && alpha < 65535) reciprocal = ((0xffff<<15)+(alpha>>1))/alpha; - c = (int)channels; + c = channels; do /* always at least one channel */ { png_uint_16 component = *in_ptr++; @@ -1680,7 +1721,7 @@ png_write_image_16bit(png_voidp argument) } png_write_row(png_ptr, png_voidcast(png_const_bytep, display->local_row)); - input_row += display->row_step / 2; + input_row += display->row_bytes/(sizeof (png_uint_16)); } return 1; @@ -1694,11 +1735,11 @@ png_write_image_16bit(png_voidp argument) * calculation can be done to 15 bits of accuracy; however, the output needs to * be scaled in the range 0..255*65535, so include that scaling here. */ -# define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+((alpha)>>1))/(alpha)) +#define UNP_RECIPROCAL(alpha) ((((0xffff*0xff)<<7)+(alpha>>1))/alpha) static png_byte png_unpremultiply(png_uint_32 component, png_uint_32 alpha, - png_uint_32 reciprocal/*from the above macro*/) + png_uint_32 reciprocal/*from the above macro*/) { /* The following gives 1.0 for an alpha of 0, which is fine, otherwise if 0/0 * is represented as some other value there is more likely to be a @@ -1745,24 +1786,22 @@ static int png_write_image_8bit(png_voidp argument) { png_image_write_control *display = png_voidcast(png_image_write_control*, - argument); + argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; png_const_uint_16p input_row = png_voidcast(png_const_uint_16p, - display->first_row); + display->first_row); png_bytep output_row = png_voidcast(png_bytep, display->local_row); png_uint_32 y = image->height; - unsigned int channels = (image->format & PNG_FORMAT_FLAG_COLOR) != 0 ? - 3 : 1; + const int channels = (image->format & PNG_FORMAT_FLAG_COLOR) ? 3 : 1; - if ((image->format & PNG_FORMAT_FLAG_ALPHA) != 0) + if (image->format & PNG_FORMAT_FLAG_ALPHA) { png_bytep row_end; int aindex; -# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED - if ((image->format & PNG_FORMAT_FLAG_AFIRST) != 0) + if (image->format & PNG_FORMAT_FLAG_AFIRST) { aindex = -1; ++input_row; /* To point to the first component */ @@ -1770,13 +1809,12 @@ png_write_image_8bit(png_voidp argument) } else -# endif - aindex = (int)channels; + aindex = channels; /* Use row_end in place of a loop counter: */ row_end = output_row + image->width * (channels+1); - for (; y > 0; --y) + while (y-- > 0) { png_const_uint_16p in_ptr = input_row; png_bytep out_ptr = output_row; @@ -1794,7 +1832,7 @@ png_write_image_8bit(png_voidp argument) if (alphabyte > 0 && alphabyte < 255) reciprocal = UNP_RECIPROCAL(alpha); - c = (int)channels; + c = channels; do /* always at least one channel */ *out_ptr++ = png_unpremultiply(*in_ptr++, alpha, reciprocal); while (--c > 0); @@ -1805,8 +1843,8 @@ png_write_image_8bit(png_voidp argument) } /* while out_ptr < row_end */ png_write_row(png_ptr, png_voidcast(png_const_bytep, - display->local_row)); - input_row += display->row_step / 2; + display->local_row)); + input_row += display->row_bytes/(sizeof (png_uint_16)); } /* while y */ } @@ -1817,7 +1855,7 @@ png_write_image_8bit(png_voidp argument) */ png_bytep row_end = output_row + image->width * channels; - for (; y > 0; --y) + while (y-- > 0) { png_const_uint_16p in_ptr = input_row; png_bytep out_ptr = output_row; @@ -1831,7 +1869,7 @@ png_write_image_8bit(png_voidp argument) } png_write_row(png_ptr, output_row); - input_row += display->row_step / 2; + input_row += display->row_bytes/(sizeof (png_uint_16)); } } @@ -1841,28 +1879,27 @@ png_write_image_8bit(png_voidp argument) static void png_image_set_PLTE(png_image_write_control *display) { - png_imagep image = display->image; + const png_imagep image = display->image; const void *cmap = display->colormap; - int entries = image->colormap_entries > 256 ? 256 : - (int)image->colormap_entries; + const int entries = image->colormap_entries > 256 ? 256 : + (int)image->colormap_entries; /* NOTE: the caller must check for cmap != NULL and entries != 0 */ - png_uint_32 format = image->format; - unsigned int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); + const png_uint_32 format = image->format; + const int channels = PNG_IMAGE_SAMPLE_CHANNELS(format); -# if defined(PNG_FORMAT_BGR_SUPPORTED) &&\ - defined(PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED) - int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && - (format & PNG_FORMAT_FLAG_ALPHA) != 0; -# else +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int afirst = (format & PNG_FORMAT_FLAG_AFIRST) != 0 && + (format & PNG_FORMAT_FLAG_ALPHA) != 0; +# else # define afirst 0 -# endif +# endif -# ifdef PNG_FORMAT_BGR_SUPPORTED - int bgr = (format & PNG_FORMAT_FLAG_BGR) != 0 ? 2 : 0; -# else +# ifdef PNG_FORMAT_BGR_SUPPORTED + const int bgr = (format & PNG_FORMAT_FLAG_BGR) ? 2 : 0; +# else # define bgr 0 -# endif +# endif int i, num_trans; png_color palette[256]; @@ -1876,22 +1913,22 @@ png_image_set_PLTE(png_image_write_control *display) /* This gets automatically converted to sRGB with reversal of the * pre-multiplication if the color-map has an alpha channel. */ - if ((format & PNG_FORMAT_FLAG_LINEAR) != 0) + if (format & PNG_FORMAT_FLAG_LINEAR) { png_const_uint_16p entry = png_voidcast(png_const_uint_16p, cmap); - entry += (unsigned int)i * channels; + entry += i * channels; - if ((channels & 1) != 0) /* no alpha */ + if (channels & 1) /* no alpha */ { if (channels >= 3) /* RGB */ { palette[i].blue = (png_byte)PNG_sRGB_FROM_LINEAR(255 * - entry[(2 ^ bgr)]); + entry[(2 ^ bgr)]); palette[i].green = (png_byte)PNG_sRGB_FROM_LINEAR(255 * - entry[1]); + entry[1]); palette[i].red = (png_byte)PNG_sRGB_FROM_LINEAR(255 * - entry[bgr]); + entry[bgr]); } else /* Gray */ @@ -1919,16 +1956,16 @@ png_image_set_PLTE(png_image_write_control *display) if (channels >= 3) /* RGB */ { palette[i].blue = png_unpremultiply(entry[afirst + (2 ^ bgr)], - alpha, reciprocal); + alpha, reciprocal); palette[i].green = png_unpremultiply(entry[afirst + 1], alpha, - reciprocal); + reciprocal); palette[i].red = png_unpremultiply(entry[afirst + bgr], alpha, - reciprocal); + reciprocal); } else /* gray */ palette[i].blue = palette[i].red = palette[i].green = - png_unpremultiply(entry[afirst], alpha, reciprocal); + png_unpremultiply(entry[afirst], alpha, reciprocal); } } @@ -1936,7 +1973,7 @@ png_image_set_PLTE(png_image_write_control *display) { png_const_bytep entry = png_voidcast(png_const_bytep, cmap); - entry += (unsigned int)i * channels; + entry += i * channels; switch (channels) { @@ -1944,7 +1981,7 @@ png_image_set_PLTE(png_image_write_control *display) tRNS[i] = entry[afirst ? 0 : 3]; if (tRNS[i] < 255) num_trans = i+1; - /* FALLTHROUGH */ + /* FALL THROUGH */ case 3: palette[i].blue = entry[afirst + (2 ^ bgr)]; palette[i].green = entry[afirst + 1]; @@ -1955,7 +1992,7 @@ png_image_set_PLTE(png_image_write_control *display) tRNS[i] = entry[1 ^ afirst]; if (tRNS[i] < 255) num_trans = i+1; - /* FALLTHROUGH */ + /* FALL THROUGH */ case 1: palette[i].blue = palette[i].red = palette[i].green = entry[afirst]; @@ -1967,108 +2004,73 @@ png_image_set_PLTE(png_image_write_control *display) } } -# ifdef afirst +# ifdef afirst # undef afirst -# endif -# ifdef bgr +# endif +# ifdef bgr # undef bgr -# endif +# endif png_set_PLTE(image->opaque->png_ptr, image->opaque->info_ptr, palette, - entries); + entries); if (num_trans > 0) png_set_tRNS(image->opaque->png_ptr, image->opaque->info_ptr, tRNS, - num_trans, NULL); + num_trans, NULL); - image->colormap_entries = (png_uint_32)entries; + image->colormap_entries = entries; } static int png_image_write_main(png_voidp argument) { png_image_write_control *display = png_voidcast(png_image_write_control*, - argument); + argument); png_imagep image = display->image; png_structrp png_ptr = image->opaque->png_ptr; png_inforp info_ptr = image->opaque->info_ptr; png_uint_32 format = image->format; - /* The following four ints are actually booleans */ - int colormap = (format & PNG_FORMAT_FLAG_COLORMAP); - int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR); /* input */ - int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA); - int write_16bit = linear && (display->convert_to_8bit == 0); + int colormap = (format & PNG_FORMAT_FLAG_COLORMAP) != 0; + int linear = !colormap && (format & PNG_FORMAT_FLAG_LINEAR) != 0; /* input */ + int alpha = !colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0; + int write_16bit = linear && !colormap && !display->convert_to_8bit; -# ifdef PNG_BENIGN_ERRORS_SUPPORTED +# ifdef PNG_BENIGN_ERRORS_SUPPORTED /* Make sure we error out on any bad situation */ png_set_benign_errors(png_ptr, 0/*error*/); -# endif +# endif - /* Default the 'row_stride' parameter if required, also check the row stride - * and total image size to ensure that they are within the system limits. - */ - { - unsigned int channels = PNG_IMAGE_PIXEL_CHANNELS(image->format); - - if (image->width <= 0x7fffffffU/channels) /* no overflow */ - { - png_uint_32 check; - png_uint_32 png_row_stride = image->width * channels; - - if (display->row_stride == 0) - display->row_stride = (png_int_32)/*SAFE*/png_row_stride; - - if (display->row_stride < 0) - check = (png_uint_32)(-display->row_stride); - - else - check = (png_uint_32)display->row_stride; - - if (check >= png_row_stride) - { - /* Now check for overflow of the image buffer calculation; this - * limits the whole image size to 32 bits for API compatibility with - * the current, 32-bit, PNG_IMAGE_BUFFER_SIZE macro. - */ - if (image->height > 0xffffffffU/png_row_stride) - png_error(image->opaque->png_ptr, "memory image too large"); - } - - else - png_error(image->opaque->png_ptr, "supplied row stride too small"); - } - - else - png_error(image->opaque->png_ptr, "image row stride too large"); - } + /* Default the 'row_stride' parameter if required. */ + if (display->row_stride == 0) + display->row_stride = PNG_IMAGE_ROW_STRIDE(*image); /* Set the required transforms then write the rows in the correct order. */ - if ((format & PNG_FORMAT_FLAG_COLORMAP) != 0) + if (format & PNG_FORMAT_FLAG_COLORMAP) { if (display->colormap != NULL && image->colormap_entries > 0) { png_uint_32 entries = image->colormap_entries; png_set_IHDR(png_ptr, info_ptr, image->width, image->height, - entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), - PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + entries > 16 ? 8 : (entries > 4 ? 4 : (entries > 2 ? 2 : 1)), + PNG_COLOR_TYPE_PALETTE, PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_image_set_PLTE(display); } else png_error(image->opaque->png_ptr, - "no color-map for color-mapped image"); + "no color-map for color-mapped image"); } else png_set_IHDR(png_ptr, info_ptr, image->width, image->height, - write_16bit ? 16 : 8, - ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + - ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), - PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); + write_16bit ? 16 : 8, + ((format & PNG_FORMAT_FLAG_COLOR) ? PNG_COLOR_MASK_COLOR : 0) + + ((format & PNG_FORMAT_FLAG_ALPHA) ? PNG_COLOR_MASK_ALPHA : 0), + PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); /* Counter-intuitively the data transformations must be called *after* * png_write_info, not before as in the read code, but the 'set' functions @@ -2076,22 +2078,22 @@ png_image_write_main(png_voidp argument) * write an interlaced image. */ - if (write_16bit != 0) + if (write_16bit) { /* The gamma here is 1.0 (linear) and the cHRM chunk matches sRGB. */ png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_LINEAR); - if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) + if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB)) png_set_cHRM_fixed(png_ptr, info_ptr, - /* color x y */ - /* white */ 31270, 32900, - /* red */ 64000, 33000, - /* green */ 30000, 60000, - /* blue */ 15000, 6000 + /* color x y */ + /* white */ 31270, 32900, + /* red */ 64000, 33000, + /* green */ 30000, 60000, + /* blue */ 15000, 6000 ); } - else if ((image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB) == 0) + else if (!(image->flags & PNG_IMAGE_FLAG_COLORSPACE_NOT_sRGB)) png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_PERCEPTUAL); /* Else writing an 8-bit file and the *colors* aren't sRGB, but the 8-bit @@ -2106,38 +2108,38 @@ png_image_write_main(png_voidp argument) /* Now set up the data transformations (*after* the header is written), * remove the handled transformations from the 'format' flags for checking. * - * First check for a little endian system if writing 16-bit files. + * First check for a little endian system if writing 16 bit files. */ - if (write_16bit != 0) + if (write_16bit) { - png_uint_16 le = 0x0001; + PNG_CONST png_uint_16 le = 0x0001; - if ((*(png_const_bytep) & le) != 0) + if (*(png_const_bytep)&le) png_set_swap(png_ptr); } -# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED - if ((format & PNG_FORMAT_FLAG_BGR) != 0) +# ifdef PNG_SIMPLIFIED_WRITE_BGR_SUPPORTED + if (format & PNG_FORMAT_FLAG_BGR) { - if (colormap == 0 && (format & PNG_FORMAT_FLAG_COLOR) != 0) + if (!colormap && (format & PNG_FORMAT_FLAG_COLOR) != 0) png_set_bgr(png_ptr); format &= ~PNG_FORMAT_FLAG_BGR; } -# endif +# endif -# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED - if ((format & PNG_FORMAT_FLAG_AFIRST) != 0) +# ifdef PNG_SIMPLIFIED_WRITE_AFIRST_SUPPORTED + if (format & PNG_FORMAT_FLAG_AFIRST) { - if (colormap == 0 && (format & PNG_FORMAT_FLAG_ALPHA) != 0) + if (!colormap && (format & PNG_FORMAT_FLAG_ALPHA) != 0) png_set_swap_alpha(png_ptr); format &= ~PNG_FORMAT_FLAG_AFIRST; } -# endif +# endif /* If there are 16 or fewer color-map entries we wrote a lower bit depth * above, but the application data is still byte packed. */ - if (colormap != 0 && image->colormap_entries <= 16) + if (colormap && image->colormap_entries <= 16) png_set_packing(png_ptr); /* That should have handled all (both) the transforms. */ @@ -2147,16 +2149,16 @@ png_image_write_main(png_voidp argument) { png_const_bytep row = png_voidcast(png_const_bytep, display->buffer); - ptrdiff_t row_step = display->row_stride; + ptrdiff_t row_bytes = display->row_stride; - if (linear != 0) - row_step *= 2; + if (linear) + row_bytes *= (sizeof (png_uint_16)); - if (row_step < 0) - row += (image->height-1) * (-row_step); + if (row_bytes < 0) + row += (image->height-1) * (-row_bytes); display->first_row = row; - display->row_step = row_step; + display->row_bytes = row_bytes; } /* Apply 'fast' options if the flag is set. */ @@ -2168,23 +2170,21 @@ png_image_write_main(png_voidp argument) * it about 50 times. The speed-up in pngstest was about 10-20% of the * total (user) time on a heavily loaded system. */ -# ifdef PNG_WRITE_CUSTOMIZE_COMPRESSION_SUPPORTED png_set_compression_level(png_ptr, 3); -# endif } /* Check for the cases that currently require a pre-transform on the row * before it is written. This only applies when the input is 16-bit and * either there is an alpha channel or it is converted to 8-bit. */ - if (linear != 0 && (alpha != 0 || display->convert_to_8bit != 0)) + if ((linear && alpha) || (!colormap && display->convert_to_8bit)) { png_bytep row = png_voidcast(png_bytep, png_malloc(png_ptr, - png_get_rowbytes(png_ptr, info_ptr))); + png_get_rowbytes(png_ptr, info_ptr))); int result; display->local_row = row; - if (write_16bit != 0) + if (write_16bit) result = png_safe_execute(image, png_write_image_16bit, display); else result = png_safe_execute(image, png_write_image_8bit, display); @@ -2193,7 +2193,7 @@ png_image_write_main(png_voidp argument) png_free(png_ptr, row); /* Skip the 'write_end' on error: */ - if (result == 0) + if (!result) return 0; } @@ -2203,13 +2203,13 @@ png_image_write_main(png_voidp argument) else { png_const_bytep row = png_voidcast(png_const_bytep, display->first_row); - ptrdiff_t row_step = display->row_step; + ptrdiff_t row_bytes = display->row_bytes; png_uint_32 y = image->height; - for (; y > 0; --y) + while (y-- > 0) { png_write_row(png_ptr, row); - row += row_step; + row += row_bytes; } } @@ -2217,131 +2217,20 @@ png_image_write_main(png_voidp argument) return 1; } - -static void (PNGCBAPI -image_memory_write)(png_structp png_ptr, png_bytep/*const*/ data, size_t size) -{ - png_image_write_control *display = png_voidcast(png_image_write_control*, - png_ptr->io_ptr/*backdoor: png_get_io_ptr(png_ptr)*/); - png_alloc_size_t ob = display->output_bytes; - - /* Check for overflow; this should never happen: */ - if (size <= ((png_alloc_size_t)-1) - ob) - { - /* I don't think libpng ever does this, but just in case: */ - if (size > 0) - { - if (display->memory_bytes >= ob+size) /* writing */ - memcpy(display->memory+ob, data, size); - - /* Always update the size: */ - display->output_bytes = ob+size; - } - } - - else - png_error(png_ptr, "png_image_write_to_memory: PNG too big"); -} - -static void (PNGCBAPI -image_memory_flush)(png_structp png_ptr) -{ - PNG_UNUSED(png_ptr) -} - -static int -png_image_write_memory(png_voidp argument) -{ - png_image_write_control *display = png_voidcast(png_image_write_control*, - argument); - - /* The rest of the memory-specific init and write_main in an error protected - * environment. This case needs to use callbacks for the write operations - * since libpng has no built in support for writing to memory. - */ - png_set_write_fn(display->image->opaque->png_ptr, display/*io_ptr*/, - image_memory_write, image_memory_flush); - - return png_image_write_main(display); -} - -int PNGAPI -png_image_write_to_memory(png_imagep image, void *memory, - png_alloc_size_t * PNG_RESTRICT memory_bytes, int convert_to_8bit, - const void *buffer, png_int_32 row_stride, const void *colormap) -{ - /* Write the image to the given buffer, or count the bytes if it is NULL */ - if (image != NULL && image->version == PNG_IMAGE_VERSION) - { - if (memory_bytes != NULL && buffer != NULL) - { - /* This is to give the caller an easier error detection in the NULL - * case and guard against uninitialized variable problems: - */ - if (memory == NULL) - *memory_bytes = 0; - - if (png_image_write_init(image) != 0) - { - png_image_write_control display; - int result; - - memset(&display, 0, (sizeof display)); - display.image = image; - display.buffer = buffer; - display.row_stride = row_stride; - display.colormap = colormap; - display.convert_to_8bit = convert_to_8bit; - display.memory = png_voidcast(png_bytep, memory); - display.memory_bytes = *memory_bytes; - display.output_bytes = 0; - - result = png_safe_execute(image, png_image_write_memory, &display); - png_image_free(image); - - /* write_memory returns true even if we ran out of buffer. */ - if (result) - { - /* On out-of-buffer this function returns '0' but still updates - * memory_bytes: - */ - if (memory != NULL && display.output_bytes > *memory_bytes) - result = 0; - - *memory_bytes = display.output_bytes; - } - - return result; - } - - else - return 0; - } - - else - return png_image_error(image, - "png_image_write_to_memory: invalid argument"); - } - - else if (image != NULL) - return png_image_error(image, - "png_image_write_to_memory: incorrect PNG_IMAGE_VERSION"); - - else - return 0; -} - -#ifdef PNG_SIMPLIFIED_WRITE_STDIO_SUPPORTED int PNGAPI +// 4j studios: callback support png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, - const void *buffer, png_int_32 row_stride, const void *colormap) + const void *buffer, png_int_32 row_stride, const void *colormap, + /*begin 4j change*/ png_rw_ptr write_fn, png_flush_ptr flush_fn /*end 4j change*/) { - /* Write the image to the given FILE object. */ + /* Write the image to the given (FILE*). */ if (image != NULL && image->version == PNG_IMAGE_VERSION) { - if (file != NULL && buffer != NULL) - { - if (png_image_write_init(image) != 0) + // begin 4j change: allow null file, callback support + //if (file != NULL) + //{ + //if (png_image_write_init(image)) + if (png_image_write_init(image, write_fn, flush_fn)) { png_image_write_control display; int result; @@ -2366,16 +2255,16 @@ png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, else return 0; - } + //} - else - return png_image_error(image, - "png_image_write_to_stdio: invalid argument"); + //else + //return png_image_error(image, + //"png_image_write_to_stdio: invalid argument"); } else if (image != NULL) return png_image_error(image, - "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); + "png_image_write_to_stdio: incorrect PNG_IMAGE_VERSION"); else return 0; @@ -2383,20 +2272,20 @@ png_image_write_to_stdio(png_imagep image, FILE *file, int convert_to_8bit, int PNGAPI png_image_write_to_file(png_imagep image, const char *file_name, - int convert_to_8bit, const void *buffer, png_int_32 row_stride, - const void *colormap) + int convert_to_8bit, const void *buffer, png_int_32 row_stride, + const void *colormap) { /* Write the image to the named file. */ if (image != NULL && image->version == PNG_IMAGE_VERSION) { - if (file_name != NULL && buffer != NULL) + if (file_name != NULL) { FILE *fp = fopen(file_name, "wb"); if (fp != NULL) { if (png_image_write_to_stdio(image, fp, convert_to_8bit, buffer, - row_stride, colormap) != 0) + row_stride, colormap /*begin 4j change*/, NULL, NULL /*end 4j change*/)) { int error; /* from fflush/fclose */ @@ -2437,16 +2326,16 @@ png_image_write_to_file(png_imagep image, const char *file_name, else return png_image_error(image, - "png_image_write_to_file: invalid argument"); + "png_image_write_to_file: invalid argument"); } else if (image != NULL) return png_image_error(image, - "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); + "png_image_write_to_file: incorrect PNG_IMAGE_VERSION"); else return 0; } -#endif /* SIMPLIFIED_WRITE_STDIO */ +#endif /* PNG_STDIO_SUPPORTED */ #endif /* SIMPLIFIED_WRITE */ -#endif /* WRITE */ +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pngwtran.c b/Windows_Libs/Dev/Render/libpng/pngwtran.c index a208470..98703f8 100644 --- a/Windows_Libs/Dev/Render/libpng/pngwtran.c +++ b/Windows_Libs/Dev/Render/libpng/pngwtran.c @@ -1,9 +1,10 @@ + /* pngwtran.c - transforms the data in a row for PNG writers * - * Copyright (c) 2018 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2016,2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.0 [February 14, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer @@ -13,14 +14,90 @@ #include "pngpriv.h" #ifdef PNG_WRITE_SUPPORTED + #ifdef PNG_WRITE_TRANSFORMS_SUPPORTED +/* Transform the data according to the user's wishes. The order of + * transformations is significant. + */ +void /* PRIVATE */ +png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info) +{ + png_debug(1, "in png_do_write_transformations"); + + if (png_ptr == NULL) + return; + +#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED + if (png_ptr->transformations & PNG_USER_TRANSFORM) + if (png_ptr->write_user_transform_fn != NULL) + (*(png_ptr->write_user_transform_fn)) /* User write transform + function */ + (png_ptr, /* png_ptr */ + row_info, /* row_info: */ + /* png_uint_32 width; width of row */ + /* png_size_t rowbytes; number of bytes in row */ + /* png_byte color_type; color type of pixels */ + /* png_byte bit_depth; bit depth of samples */ + /* png_byte channels; number of channels (1-4) */ + /* png_byte pixel_depth; bits per pixel (depth*channels) */ + png_ptr->row_buf + 1); /* start of pixel data for row */ +#endif + +#ifdef PNG_WRITE_FILLER_SUPPORTED + if (png_ptr->transformations & PNG_FILLER) + png_do_strip_channel(row_info, png_ptr->row_buf + 1, + !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); +#endif + +#ifdef PNG_WRITE_PACKSWAP_SUPPORTED + if (png_ptr->transformations & PNG_PACKSWAP) + png_do_packswap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_PACK_SUPPORTED + if (png_ptr->transformations & PNG_PACK) + png_do_pack(row_info, png_ptr->row_buf + 1, + (png_uint_32)png_ptr->bit_depth); +#endif + +#ifdef PNG_WRITE_SWAP_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_BYTES) + png_do_swap(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_SHIFT_SUPPORTED + if (png_ptr->transformations & PNG_SHIFT) + png_do_shift(row_info, png_ptr->row_buf + 1, + &(png_ptr->shift)); +#endif + +#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_SWAP_ALPHA) + png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_ALPHA) + png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_BGR_SUPPORTED + if (png_ptr->transformations & PNG_BGR) + png_do_bgr(row_info, png_ptr->row_buf + 1); +#endif + +#ifdef PNG_WRITE_INVERT_SUPPORTED + if (png_ptr->transformations & PNG_INVERT_MONO) + png_do_invert(row_info, png_ptr->row_buf + 1); +#endif +} #ifdef PNG_WRITE_PACK_SUPPORTED /* Pack pixels into bytes. Pass the true bit depth in bit_depth. The * row_info bit depth should be 8 (one pixel per byte). The channels * should be 1 (this only happens on grayscale and paletted images). */ -static void +void /* PRIVATE */ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) { png_debug(1, "in png_do_pack"); @@ -70,8 +147,7 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) case 2: { png_bytep sp, dp; - unsigned int shift; - int v; + int shift, v; png_uint_32 i; png_uint_32 row_width = row_info->width; @@ -110,8 +186,7 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) case 4: { png_bytep sp, dp; - unsigned int shift; - int v; + int shift, v; png_uint_32 i; png_uint_32 row_width = row_info->width; @@ -167,7 +242,7 @@ png_do_pack(png_row_infop row_info, png_bytep row, png_uint_32 bit_depth) * would pass 3 as bit_depth, and this routine would translate the * data to 0 to 15. */ -static void +void /* PRIVATE */ png_do_shift(png_row_infop row_info, png_bytep row, png_const_color_8p bit_depth) { @@ -176,9 +251,9 @@ png_do_shift(png_row_infop row_info, png_bytep row, if (row_info->color_type != PNG_COLOR_TYPE_PALETTE) { int shift_start[4], shift_dec[4]; - unsigned int channels = 0; + int channels = 0; - if ((row_info->color_type & PNG_COLOR_MASK_COLOR) != 0) + if (row_info->color_type & PNG_COLOR_MASK_COLOR) { shift_start[channels] = row_info->bit_depth - bit_depth->red; shift_dec[channels] = bit_depth->red; @@ -200,7 +275,7 @@ png_do_shift(png_row_infop row_info, png_bytep row, channels++; } - if ((row_info->color_type & PNG_COLOR_MASK_ALPHA) != 0) + if (row_info->color_type & PNG_COLOR_MASK_ALPHA) { shift_start[channels] = row_info->bit_depth - bit_depth->alpha; shift_dec[channels] = bit_depth->alpha; @@ -211,9 +286,9 @@ png_do_shift(png_row_infop row_info, png_bytep row, if (row_info->bit_depth < 8) { png_bytep bp = row; - size_t i; + png_size_t i; unsigned int mask; - size_t row_bytes = row_info->rowbytes; + png_size_t row_bytes = row_info->rowbytes; if (bit_depth->gray == 1 && row_info->bit_depth == 2) mask = 0x55; @@ -253,7 +328,8 @@ png_do_shift(png_row_infop row_info, png_bytep row, for (i = 0; i < istop; i++, bp++) { - unsigned int c = i%channels; + + const unsigned int c = i%channels; int j; unsigned int v, out; @@ -281,7 +357,7 @@ png_do_shift(png_row_infop row_info, png_bytep row, for (bp = row, i = 0; i < istop; i++) { - unsigned int c = i%channels; + const unsigned int c = i%channels; int j; unsigned int value, v; @@ -305,7 +381,7 @@ png_do_shift(png_row_infop row_info, png_bytep row, #endif #ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED -static void +void /* PRIVATE */ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_write_swap_alpha"); @@ -353,7 +429,7 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) *(dp++) = save[1]; } } -#endif /* WRITE_16BIT */ +#endif /* PNG_WRITE_16BIT_SUPPORTED */ } else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) @@ -392,14 +468,14 @@ png_do_write_swap_alpha(png_row_infop row_info, png_bytep row) *(dp++) = save[1]; } } -#endif /* WRITE_16BIT */ +#endif /* PNG_WRITE_16BIT_SUPPORTED */ } } } #endif #ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED -static void +void /* PRIVATE */ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) { png_debug(1, "in png_do_write_invert_alpha"); @@ -422,7 +498,7 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) *(dp++) = *(sp++); */ sp+=3; dp = sp; - *dp = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); } } @@ -446,10 +522,10 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) */ sp+=6; dp = sp; *(dp++) = (png_byte)(255 - *(sp++)); - *dp = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); } } -#endif /* WRITE_16BIT */ +#endif /* PNG_WRITE_16BIT_SUPPORTED */ } else if (row_info->color_type == PNG_COLOR_TYPE_GRAY_ALPHA) @@ -484,91 +560,78 @@ png_do_write_invert_alpha(png_row_infop row_info, png_bytep row) */ sp+=2; dp = sp; *(dp++) = (png_byte)(255 - *(sp++)); - *dp = (png_byte)(255 - *(sp++)); + *(dp++) = (png_byte)(255 - *(sp++)); } } -#endif /* WRITE_16BIT */ +#endif /* PNG_WRITE_16BIT_SUPPORTED */ } } } #endif +#endif /* PNG_WRITE_TRANSFORMS_SUPPORTED */ -/* Transform the data according to the user's wishes. The order of - * transformations is significant. - */ +#ifdef PNG_MNG_FEATURES_SUPPORTED +/* Undoes intrapixel differencing */ void /* PRIVATE */ -png_do_write_transformations(png_structrp png_ptr, png_row_infop row_info) +png_do_write_intrapixel(png_row_infop row_info, png_bytep row) { - png_debug(1, "in png_do_write_transformations"); + png_debug(1, "in png_do_write_intrapixel"); - if (png_ptr == NULL) - return; + if ((row_info->color_type & PNG_COLOR_MASK_COLOR)) + { + int bytes_per_pixel; + png_uint_32 row_width = row_info->width; + if (row_info->bit_depth == 8) + { + png_bytep rp; + png_uint_32 i; -#ifdef PNG_WRITE_USER_TRANSFORM_SUPPORTED - if ((png_ptr->transformations & PNG_USER_TRANSFORM) != 0) - if (png_ptr->write_user_transform_fn != NULL) - (*(png_ptr->write_user_transform_fn)) /* User write transform - function */ - (png_ptr, /* png_ptr */ - row_info, /* row_info: */ - /* png_uint_32 width; width of row */ - /* size_t rowbytes; number of bytes in row */ - /* png_byte color_type; color type of pixels */ - /* png_byte bit_depth; bit depth of samples */ - /* png_byte channels; number of channels (1-4) */ - /* png_byte pixel_depth; bits per pixel (depth*channels) */ - png_ptr->row_buf + 1); /* start of pixel data for row */ -#endif + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 3; -#ifdef PNG_WRITE_FILLER_SUPPORTED - if ((png_ptr->transformations & PNG_FILLER) != 0) - png_do_strip_channel(row_info, png_ptr->row_buf + 1, - !(png_ptr->flags & PNG_FLAG_FILLER_AFTER)); -#endif + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 4; -#ifdef PNG_WRITE_PACKSWAP_SUPPORTED - if ((png_ptr->transformations & PNG_PACKSWAP) != 0) - png_do_packswap(row_info, png_ptr->row_buf + 1); -#endif + else + return; -#ifdef PNG_WRITE_PACK_SUPPORTED - if ((png_ptr->transformations & PNG_PACK) != 0) - png_do_pack(row_info, png_ptr->row_buf + 1, - (png_uint_32)png_ptr->bit_depth); -#endif + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + *(rp) = (png_byte)((*rp - *(rp + 1)) & 0xff); + *(rp + 2) = (png_byte)((*(rp + 2) - *(rp + 1)) & 0xff); + } + } -#ifdef PNG_WRITE_SWAP_SUPPORTED -# ifdef PNG_16BIT_SUPPORTED - if ((png_ptr->transformations & PNG_SWAP_BYTES) != 0) - png_do_swap(row_info, png_ptr->row_buf + 1); -# endif -#endif +#ifdef PNG_WRITE_16BIT_SUPPORTED + else if (row_info->bit_depth == 16) + { + png_bytep rp; + png_uint_32 i; -#ifdef PNG_WRITE_SHIFT_SUPPORTED - if ((png_ptr->transformations & PNG_SHIFT) != 0) - png_do_shift(row_info, png_ptr->row_buf + 1, - &(png_ptr->shift)); -#endif + if (row_info->color_type == PNG_COLOR_TYPE_RGB) + bytes_per_pixel = 6; -#ifdef PNG_WRITE_SWAP_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_SWAP_ALPHA) != 0) - png_do_write_swap_alpha(row_info, png_ptr->row_buf + 1); -#endif + else if (row_info->color_type == PNG_COLOR_TYPE_RGB_ALPHA) + bytes_per_pixel = 8; -#ifdef PNG_WRITE_INVERT_ALPHA_SUPPORTED - if ((png_ptr->transformations & PNG_INVERT_ALPHA) != 0) - png_do_write_invert_alpha(row_info, png_ptr->row_buf + 1); -#endif + else + return; -#ifdef PNG_WRITE_BGR_SUPPORTED - if ((png_ptr->transformations & PNG_BGR) != 0) - png_do_bgr(row_info, png_ptr->row_buf + 1); -#endif - -#ifdef PNG_WRITE_INVERT_SUPPORTED - if ((png_ptr->transformations & PNG_INVERT_MONO) != 0) - png_do_invert(row_info, png_ptr->row_buf + 1); -#endif + for (i = 0, rp = row; i < row_width; i++, rp += bytes_per_pixel) + { + png_uint_32 s0 = (*(rp ) << 8) | *(rp + 1); + png_uint_32 s1 = (*(rp + 2) << 8) | *(rp + 3); + png_uint_32 s2 = (*(rp + 4) << 8) | *(rp + 5); + png_uint_32 red = (png_uint_32)((s0 - s1) & 0xffffL); + png_uint_32 blue = (png_uint_32)((s2 - s1) & 0xffffL); + *(rp ) = (png_byte)((red >> 8) & 0xff); + *(rp + 1) = (png_byte)(red & 0xff); + *(rp + 4) = (png_byte)((blue >> 8) & 0xff); + *(rp + 5) = (png_byte)(blue & 0xff); + } + } +#endif /* PNG_WRITE_16BIT_SUPPORTED */ + } } -#endif /* WRITE_TRANSFORMS */ -#endif /* WRITE */ +#endif /* PNG_MNG_FEATURES_SUPPORTED */ +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/libpng/pngwutil.c b/Windows_Libs/Dev/Render/libpng/pngwutil.c index b4b845a..49e6a2d 100644 --- a/Windows_Libs/Dev/Render/libpng/pngwutil.c +++ b/Windows_Libs/Dev/Render/libpng/pngwutil.c @@ -1,37 +1,20 @@ + /* pngwutil.c - utilities to write a PNG file * - * Copyright (c) 2018-2025 Cosmin Truta - * Copyright (c) 1998-2002,2004,2006-2018 Glenn Randers-Pehrson - * Copyright (c) 1996-1997 Andreas Dilger - * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. + * Last changed in libpng 1.6.2 [April 25, 2013] + * Copyright (c) 1998-2013 Glenn Randers-Pehrson + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger) + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.) * * This code is released under the libpng license. * For conditions of distribution and use, see the disclaimer * and license in png.h - * - * This file contains routines that are only called from within - * libpng itself during the course of writing an image. */ #include "pngpriv.h" #ifdef PNG_WRITE_SUPPORTED -#ifdef PNG_WRITE_INTERLACING_SUPPORTED -/* Arrays to facilitate interlacing - use pass (0 - 6) as index. */ - -/* Start of interlace block */ -static const png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; -/* Offset to next interlace block */ -static const png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; -/* Start of interlace block in the y direction */ -static const png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; -/* Offset to next interlace block in the y direction */ -static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; - -/* TODO: Move these arrays to a common utility module to avoid duplication. */ -#endif - #ifdef PNG_WRITE_INT_FUNCTIONS_SUPPORTED /* Place a 32-bit number into a buffer in PNG byte order. We work * with unsigned numbers for convenience, although one supported @@ -40,10 +23,10 @@ static const png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; void PNGAPI png_save_uint_32(png_bytep buf, png_uint_32 i) { - buf[0] = (png_byte)((i >> 24) & 0xffU); - buf[1] = (png_byte)((i >> 16) & 0xffU); - buf[2] = (png_byte)((i >> 8) & 0xffU); - buf[3] = (png_byte)( i & 0xffU); + buf[0] = (png_byte)((i >> 24) & 0xff); + buf[1] = (png_byte)((i >> 16) & 0xff); + buf[2] = (png_byte)((i >> 8) & 0xff); + buf[3] = (png_byte)(i & 0xff); } /* Place a 16-bit number into a buffer in PNG byte order. @@ -53,8 +36,8 @@ png_save_uint_32(png_bytep buf, png_uint_32 i) void PNGAPI png_save_uint_16(png_bytep buf, unsigned int i) { - buf[0] = (png_byte)((i >> 8) & 0xffU); - buf[1] = (png_byte)( i & 0xffU); + buf[0] = (png_byte)((i >> 8) & 0xff); + buf[1] = (png_byte)(i & 0xff); } #endif @@ -76,7 +59,7 @@ png_write_sig(png_structrp png_ptr) /* Write the rest of the 8 byte signature */ png_write_data(png_ptr, &png_signature[png_ptr->sig_bytes], - (size_t)(8 - png_ptr->sig_bytes)); + (png_size_t)(8 - png_ptr->sig_bytes)); if (png_ptr->sig_bytes < 3) png_ptr->mode |= PNG_HAVE_PNG_SIGNATURE; @@ -141,7 +124,8 @@ png_write_chunk_start(png_structrp png_ptr, png_const_bytep chunk_string, * given to png_write_chunk_header(). */ void PNGAPI -png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, size_t length) +png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, + png_size_t length) { /* Write the data, and run the CRC over it */ if (png_ptr == NULL) @@ -152,7 +136,7 @@ png_write_chunk_data(png_structrp png_ptr, png_const_bytep data, size_t length) png_write_data(png_ptr, data, length); /* Update the CRC after writing the data, - * in case the user I/O routine alters it. + * in case that the user I/O routine alters it. */ png_calculate_crc(png_ptr, data, length); } @@ -176,7 +160,7 @@ png_write_chunk_end(png_structrp png_ptr) /* Write the crc in a single operation */ png_save_uint_32(buf, png_ptr->crc); - png_write_data(png_ptr, buf, 4); + png_write_data(png_ptr, buf, (png_size_t)4); } /* Write a PNG chunk all at once. The type is an array of ASCII characters @@ -190,14 +174,14 @@ png_write_chunk_end(png_structrp png_ptr) */ static void png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, - png_const_bytep data, size_t length) + png_const_bytep data, png_size_t length) { if (png_ptr == NULL) return; - /* On 64-bit architectures 'length' may not fit in a png_uint_32. */ + /* On 64 bit architectures 'length' may not fit in a png_uint_32. */ if (length > PNG_UINT_31_MAX) - png_error(png_ptr, "length exceeds PNG maximum"); + png_error(png_ptr, "length exceeds PNG maxima"); png_write_chunk_header(png_ptr, chunk_name, (png_uint_32)length); png_write_chunk_data(png_ptr, data, length); @@ -207,10 +191,10 @@ png_write_complete_chunk(png_structrp png_ptr, png_uint_32 chunk_name, /* This is the API that calls the internal function above. */ void PNGAPI png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, - png_const_bytep data, size_t length) + png_const_bytep data, png_size_t length) { png_write_complete_chunk(png_ptr, PNG_CHUNK_FROM_STRING(chunk_string), data, - length); + length); } /* This is used below to find the size of an image to pass to png_deflate_claim, @@ -220,14 +204,14 @@ png_write_chunk(png_structrp png_ptr, png_const_bytep chunk_string, static png_alloc_size_t png_image_size(png_structrp png_ptr) { - /* Only return sizes up to the maximum of a png_uint_32; do this by limiting + /* Only return sizes up to the maximum of a png_uint_32, do this by limiting * the width and height used to 15 bits. */ png_uint_32 h = png_ptr->height; if (png_ptr->rowbytes < 32768 && h < 32768) { - if (png_ptr->interlaced != 0) + if (png_ptr->interlaced) { /* Interlacing makes the image larger because of the replication of * both the filter byte and the padding to a byte boundary. @@ -302,16 +286,17 @@ optimize_cmf(png_bytep data, png_alloc_size_t data_size) } } } -#endif /* WRITE_OPTIMIZE_CMF */ +#else +# define optimize_cmf(dp,dl) ((void)0) +#endif /* PNG_WRITE_OPTIMIZE_CMF_SUPPORTED */ /* Initialize the compressor for the appropriate type of compression. */ static int png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, - png_alloc_size_t data_size) + png_alloc_size_t data_size) { if (png_ptr->zowner != 0) { -#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED) char msg[64]; PNG_STRING_FROM_CHUNK(msg, owner); @@ -323,8 +308,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, * are minimal. */ (void)png_safecat(msg, (sizeof msg), 10, " using zstream"); -#endif -#if PNG_RELEASE_BUILD +# if PNG_LIBPNG_BUILD_BASE_TYPE >= PNG_LIBPNG_BUILD_RC png_warning(png_ptr, msg); /* Attempt sane error recovery */ @@ -335,9 +319,9 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, } png_ptr->zowner = 0; -#else +# else png_error(png_ptr, msg); -#endif +# endif } { @@ -350,7 +334,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, if (owner == png_IDAT) { - if ((png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) != 0) + if (png_ptr->flags & PNG_FLAG_ZLIB_CUSTOM_STRATEGY) strategy = png_ptr->zlib_strategy; else if (png_ptr->do_filter != PNG_FILTER_NONE) @@ -362,20 +346,20 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, else { -#ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED +# ifdef PNG_WRITE_CUSTOMIZE_ZTXT_COMPRESSION_SUPPORTED level = png_ptr->zlib_text_level; method = png_ptr->zlib_text_method; windowBits = png_ptr->zlib_text_window_bits; memLevel = png_ptr->zlib_text_mem_level; strategy = png_ptr->zlib_text_strategy; -#else +# else /* If customization is not supported the values all come from the * IDAT values except for the strategy, which is fixed to the * default. (This is the pre-1.6.0 behavior too, although it was * implemented in a very different way.) */ strategy = Z_DEFAULT_STRATEGY; -#endif +# endif } /* Adjust 'windowBits' down if larger than 'data_size'; to stop this @@ -402,7 +386,7 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, } /* Check against the previous initialized values, if any. */ - if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0 && + if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) && (png_ptr->zlib_set_level != level || png_ptr->zlib_set_method != method || png_ptr->zlib_set_window_bits != windowBits || @@ -424,15 +408,15 @@ png_deflate_claim(png_structrp png_ptr, png_uint_32 owner, png_ptr->zstream.avail_out = 0; /* Now initialize if required, setting the new parameters, otherwise just - * do a simple reset to the previous parameters. + * to a simple reset to the previous parameters. */ - if ((png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) != 0) + if (png_ptr->flags & PNG_FLAG_ZSTREAM_INITIALIZED) ret = deflateReset(&png_ptr->zstream); else { ret = deflateInit2(&png_ptr->zstream, level, method, windowBits, - memLevel, strategy); + memLevel, strategy); if (ret == Z_OK) png_ptr->flags |= PNG_FLAG_ZSTREAM_INITIALIZED; @@ -485,15 +469,15 @@ png_free_buffer_list(png_structrp png_ptr, png_compression_bufferp *listp) */ typedef struct { - png_const_bytep input; /* The uncompressed input data */ - png_alloc_size_t input_len; /* Its length */ - png_uint_32 output_len; /* Final compressed length */ - png_byte output[1024]; /* First block of output */ + png_const_bytep input; /* The uncompressed input data */ + png_alloc_size_t input_len; /* Its length */ + png_uint_32 output_len; /* Final compressed length */ + png_byte output[1024]; /* First block of output */ } compression_state; static void png_text_compress_init(compression_state *comp, png_const_bytep input, - png_alloc_size_t input_len) + png_alloc_size_t input_len) { comp->input = input; comp->input_len = input_len; @@ -503,12 +487,12 @@ png_text_compress_init(compression_state *comp, png_const_bytep input, /* Compress the data in the compression state input */ static int png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, - compression_state *comp, png_uint_32 prefix_len) + compression_state *comp, png_uint_32 prefix_len) { int ret; /* To find the length of the output it is necessary to first compress the - * input. The result is buffered rather than using the two-pass algorithm + * input, the result is buffered rather than using the two-pass algorithm * that is used on the inflate side; deflate is assumed to be slower and a * PNG writer is assumed to have more memory available than a PNG reader. * @@ -595,7 +579,7 @@ png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, /* Compress the data */ ret = deflate(&png_ptr->zstream, - input_len > 0 ? Z_NO_FLUSH : Z_FINISH); + input_len > 0 ? Z_NO_FLUSH : Z_FINISH); /* Claw back input data that was not consumed (because avail_in is * reset above every time round the loop). @@ -605,7 +589,7 @@ png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, } while (ret == Z_OK); - /* There may be some space left in the last output buffer. This needs to + /* There may be some space left in the last output buffer, this needs to * be subtracted from output_len. */ output_len -= png_ptr->zstream.avail_out; @@ -628,15 +612,14 @@ png_text_compress(png_structrp png_ptr, png_uint_32 chunk_name, /* Reset zlib for another zTXt/iTXt or image data */ png_ptr->zowner = 0; - /* The only success case is Z_STREAM_END, input_len must be 0; if not this + /* The only success case is Z_STREAM_END, input_len must be 0, if not this * is an internal error. */ if (ret == Z_STREAM_END && input_len == 0) { -#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED /* Fix up the deflate header, if required */ optimize_cmf(comp->output, comp->input_len); -#endif + /* But Z_OK is returned, not Z_STREAM_END; this allows the claim * function above to return Z_STREAM_END on an error (though it never * does in the current versions of zlib.) @@ -679,7 +662,89 @@ png_write_compressed_data_out(png_structrp png_ptr, compression_state *comp) if (output_len > 0) png_error(png_ptr, "error writing ancillary chunked compressed data"); } -#endif /* WRITE_COMPRESSED_TEXT */ +#endif /* PNG_WRITE_COMPRESSED_TEXT_SUPPORTED */ + +#if defined(PNG_WRITE_TEXT_SUPPORTED) || defined(PNG_WRITE_pCAL_SUPPORTED) || \ + defined(PNG_WRITE_iCCP_SUPPORTED) || defined(PNG_WRITE_sPLT_SUPPORTED) +/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, + * and if invalid, correct the keyword rather than discarding the entire + * chunk. The PNG 1.0 specification requires keywords 1-79 characters in + * length, forbids leading or trailing whitespace, multiple internal spaces, + * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. + * + * The 'new_key' buffer must be 80 characters in size (for the keyword plus a + * trailing '\0'). If this routine returns 0 then there was no keyword, or a + * valid one could not be generated, and the caller must png_error. + */ +static png_uint_32 +png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) +{ + png_const_charp orig_key = key; + png_uint_32 key_len = 0; + int bad_character = 0; + int space = 1; + + png_debug(1, "in png_check_keyword"); + + if (key == NULL) + { + *new_key = 0; + return 0; + } + + while (*key && key_len < 79) + { + png_byte ch = (png_byte)(0xff & *key++); + + if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) + *new_key++ = ch, ++key_len, space = 0; + + else if (!space) + { + /* A space or an invalid character when one wasn't seen immediately + * before; output just a space. + */ + *new_key++ = 32, ++key_len, space = 1; + + /* If the character was not a space then it is invalid. */ + if (ch != 32) + bad_character = ch; + } + + else if (!bad_character) + bad_character = ch; /* just skip it, record the first error */ + } + + if (key_len > 0 && space) /* trailing space */ + { + --key_len, --new_key; + if (!bad_character) + bad_character = 32; + } + + /* Terminate the keyword */ + *new_key = 0; + + if (key_len == 0) + return 0; + + /* Try to only output one warning per keyword: */ + if (*key) /* keyword too long */ + png_warning(png_ptr, "keyword truncated"); + + else if (bad_character) + { + PNG_WARNING_PARAMETERS(p) + + png_warning_parameter(p, 1, orig_key); + png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character); + + png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'"); + } + + return key_len; +} +#endif /* Write the IHDR chunk, and update the png_struct with the necessary * information. Note that the rest of this code depends upon this @@ -691,7 +756,6 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, int interlace_type) { png_byte buf[13]; /* Buffer to store the IHDR info */ - int is_invalid_depth; png_debug(1, "in png_write_IHDR"); @@ -717,11 +781,11 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, break; case PNG_COLOR_TYPE_RGB: - is_invalid_depth = (bit_depth != 8); #ifdef PNG_WRITE_16BIT_SUPPORTED - is_invalid_depth = (is_invalid_depth && bit_depth != 16); + if (bit_depth != 8 && bit_depth != 16) +#else + if (bit_depth != 8) #endif - if (is_invalid_depth) png_error(png_ptr, "Invalid bit depth for RGB image"); png_ptr->channels = 3; @@ -743,22 +807,18 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, break; case PNG_COLOR_TYPE_GRAY_ALPHA: - is_invalid_depth = (bit_depth != 8); -#ifdef PNG_WRITE_16BIT_SUPPORTED - is_invalid_depth = (is_invalid_depth && bit_depth != 16); -#endif - if (is_invalid_depth) + if (bit_depth != 8 && bit_depth != 16) png_error(png_ptr, "Invalid bit depth for grayscale+alpha image"); png_ptr->channels = 2; break; case PNG_COLOR_TYPE_RGB_ALPHA: - is_invalid_depth = (bit_depth != 8); #ifdef PNG_WRITE_16BIT_SUPPORTED - is_invalid_depth = (is_invalid_depth && bit_depth != 16); + if (bit_depth != 8 && bit_depth != 16) +#else + if (bit_depth != 8) #endif - if (is_invalid_depth) png_error(png_ptr, "Invalid bit depth for RGBA image"); png_ptr->channels = 4; @@ -785,8 +845,8 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, */ if ( #ifdef PNG_MNG_FEATURES_SUPPORTED - !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) != 0 && - ((png_ptr->mode & PNG_HAVE_PNG_SIGNATURE) == 0) && + !((png_ptr->mng_features_permitted & PNG_FLAG_MNG_FILTER_64) && + ((png_ptr->mode&PNG_HAVE_PNG_SIGNATURE) == 0) && (color_type == PNG_COLOR_TYPE_RGB || color_type == PNG_COLOR_TYPE_RGB_ALPHA) && (filter_type == PNG_INTRAPIXEL_DIFFERENCING)) && @@ -808,7 +868,7 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, interlace_type=PNG_INTERLACE_NONE; #endif - /* Save the relevant information */ + /* Save the relevent information */ png_ptr->bit_depth = (png_byte)bit_depth; png_ptr->color_type = (png_byte)color_type; png_ptr->interlaced = (png_byte)interlace_type; @@ -836,9 +896,9 @@ png_write_IHDR(png_structrp png_ptr, png_uint_32 width, png_uint_32 height, buf[12] = (png_byte)interlace_type; /* Write the chunk */ - png_write_complete_chunk(png_ptr, png_IHDR, buf, 13); + png_write_complete_chunk(png_ptr, png_IHDR, buf, (png_size_t)13); - if ((png_ptr->do_filter) == PNG_NO_FILTERS) + if (!(png_ptr->do_filter)) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE || png_ptr->bit_depth < 8) @@ -859,20 +919,17 @@ void /* PRIVATE */ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, png_uint_32 num_pal) { - png_uint_32 max_palette_length, i; + png_uint_32 i; png_const_colorp pal_ptr; png_byte buf[3]; png_debug(1, "in png_write_PLTE"); - max_palette_length = (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? - (1 << png_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; - if (( #ifdef PNG_MNG_FEATURES_SUPPORTED - (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 && + !(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) && #endif - num_pal == 0) || num_pal > max_palette_length) + num_pal == 0) || num_pal > 256) { if (png_ptr->color_type == PNG_COLOR_TYPE_PALETTE) { @@ -886,7 +943,7 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, } } - if ((png_ptr->color_type & PNG_COLOR_MASK_COLOR) == 0) + if (!(png_ptr->color_type&PNG_COLOR_MASK_COLOR)) { png_warning(png_ptr, "Ignoring request to write a PLTE chunk in grayscale PNG"); @@ -905,7 +962,7 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, buf[0] = pal_ptr->red; buf[1] = pal_ptr->green; buf[2] = pal_ptr->blue; - png_write_chunk_data(png_ptr, buf, 3); + png_write_chunk_data(png_ptr, buf, (png_size_t)3); } #else @@ -919,7 +976,7 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, buf[0] = pal_ptr[i].red; buf[1] = pal_ptr[i].green; buf[2] = pal_ptr[i].blue; - png_write_chunk_data(png_ptr, buf, 3); + png_write_chunk_data(png_ptr, buf, (png_size_t)3); } #endif @@ -941,12 +998,12 @@ png_write_PLTE(png_structrp png_ptr, png_const_colorp palette, * Z_FINISH: this is the end of the input, do a Z_FINISH and clean up * * The routine manages the acquire and release of the png_ptr->zstream by - * checking and (at the end) clearing png_ptr->zowner; it does some sanity + * checking and (at the end) clearing png_ptr->zowner, it does some sanity * checks on the 'mode' flags while doing this. */ void /* PRIVATE */ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, - png_alloc_size_t input_len, int flush) + png_alloc_size_t input_len, int flush) { if (png_ptr->zowner != png_IDAT) { @@ -958,7 +1015,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, if (png_ptr->zbuffer_list == NULL) { png_ptr->zbuffer_list = png_voidcast(png_compression_bufferp, - png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); + png_malloc(png_ptr, PNG_COMPRESSION_BUFFER_SIZE(png_ptr))); png_ptr->zbuffer_list->next = NULL; } @@ -1001,7 +1058,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, input_len += png_ptr->zstream.avail_in; png_ptr->zstream.avail_in = 0; - /* OUTPUT: write complete IDAT chunks when avail_out drops to zero. Note + /* OUTPUT: write complete IDAT chunks when avail_out drops to zero, note * that these two zstream fields are preserved across the calls, therefore * there is no need to set these up on entry to the loop. */ @@ -1013,14 +1070,13 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, /* Write an IDAT containing the data then reset the buffer. The * first IDAT may need deflate header optimization. */ -#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED - if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && - png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) +# ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if (!(png_ptr->mode & PNG_HAVE_IDAT) && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) optimize_cmf(data, png_image_size(png_ptr)); -#endif +# endif - if (size > 0) - png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_write_complete_chunk(png_ptr, png_IDAT, data, size); png_ptr->mode |= PNG_HAVE_IDAT; png_ptr->zstream.next_out = data; @@ -1034,7 +1090,7 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, continue; } - /* The order of these checks doesn't matter much; it just affects which + /* The order of these checks doesn't matter much; it just effect which * possible error might be detected if multiple things go wrong at once. */ if (ret == Z_OK) /* most likely return code! */ @@ -1060,14 +1116,13 @@ png_compress_IDAT(png_structrp png_ptr, png_const_bytep input, png_bytep data = png_ptr->zbuffer_list->output; uInt size = png_ptr->zbuffer_size - png_ptr->zstream.avail_out; -#ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED - if ((png_ptr->mode & PNG_HAVE_IDAT) == 0 && - png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) - optimize_cmf(data, png_image_size(png_ptr)); -#endif +# ifdef PNG_WRITE_OPTIMIZE_CMF_SUPPORTED + if (!(png_ptr->mode & PNG_HAVE_IDAT) && + png_ptr->compression_type == PNG_COMPRESSION_TYPE_BASE) + optimize_cmf(data, png_image_size(png_ptr)); +# endif - if (size > 0) - png_write_complete_chunk(png_ptr, png_IDAT, data, size); + png_write_complete_chunk(png_ptr, png_IDAT, data, size); png_ptr->zstream.avail_out = 0; png_ptr->zstream.next_out = NULL; png_ptr->mode |= PNG_HAVE_IDAT | PNG_AFTER_IDAT; @@ -1091,7 +1146,7 @@ png_write_IEND(png_structrp png_ptr) { png_debug(1, "in png_write_IEND"); - png_write_complete_chunk(png_ptr, png_IEND, NULL, 0); + png_write_complete_chunk(png_ptr, png_IEND, NULL, (png_size_t)0); png_ptr->mode |= PNG_HAVE_IEND; } @@ -1106,7 +1161,7 @@ png_write_gAMA_fixed(png_structrp png_ptr, png_fixed_point file_gamma) /* file_gamma is saved in 1/100,000ths */ png_save_uint_32(buf, (png_uint_32)file_gamma); - png_write_complete_chunk(png_ptr, png_gAMA, buf, 4); + png_write_complete_chunk(png_ptr, png_gAMA, buf, (png_size_t)4); } #endif @@ -1124,7 +1179,7 @@ png_write_sRGB(png_structrp png_ptr, int srgb_intent) "Invalid sRGB rendering intent specified"); buf[0]=(png_byte)srgb_intent; - png_write_complete_chunk(png_ptr, png_sRGB, buf, 1); + png_write_complete_chunk(png_ptr, png_sRGB, buf, (png_size_t)1); } #endif @@ -1132,12 +1187,12 @@ png_write_sRGB(png_structrp png_ptr, int srgb_intent) /* Write an iCCP chunk */ void /* PRIVATE */ png_write_iCCP(png_structrp png_ptr, png_const_charp name, - png_const_bytep profile, png_uint_32 profile_len) + png_const_bytep profile) { png_uint_32 name_len; + png_uint_32 profile_len; png_byte new_name[81]; /* 1 byte for the compression byte */ compression_state comp; - png_uint_32 temp; png_debug(1, "in png_write_iCCP"); @@ -1147,14 +1202,12 @@ png_write_iCCP(png_structrp png_ptr, png_const_charp name, if (profile == NULL) png_error(png_ptr, "No profile for iCCP chunk"); /* internal error */ + profile_len = png_get_uint_32(profile); + if (profile_len < 132) png_error(png_ptr, "ICC profile too short"); - if (png_get_uint_32(profile) != profile_len) - png_error(png_ptr, "Incorrect data in iCCP"); - - temp = (png_uint_32) (*(profile+8)); - if (temp > 3 && (profile_len & 0x03)) + if (profile_len & 0x03) png_error(png_ptr, "ICC profile length invalid (not a multiple of 4)"); { @@ -1198,8 +1251,8 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) png_uint_32 name_len; png_byte new_name[80]; png_byte entrybuf[10]; - size_t entry_size = (spalette->depth == 8 ? 6 : 10); - size_t palette_size = entry_size * (size_t)spalette->nentries; + png_size_t entry_size = (spalette->depth == 8 ? 6 : 10); + png_size_t palette_size = entry_size * spalette->nentries; png_sPLT_entryp ep; #ifndef PNG_POINTER_INDEXING_SUPPORTED int i; @@ -1216,9 +1269,10 @@ png_write_sPLT(png_structrp png_ptr, png_const_sPLT_tp spalette) png_write_chunk_header(png_ptr, png_sPLT, (png_uint_32)(name_len + 2 + palette_size)); - png_write_chunk_data(png_ptr, (png_bytep)new_name, (size_t)(name_len + 1)); + png_write_chunk_data(png_ptr, (png_bytep)new_name, + (png_size_t)(name_len + 1)); - png_write_chunk_data(png_ptr, &spalette->depth, 1); + png_write_chunk_data(png_ptr, &spalette->depth, (png_size_t)1); /* Loop through each palette entry, writing appropriately */ #ifdef PNG_POINTER_INDEXING_SUPPORTED @@ -1280,12 +1334,12 @@ void /* PRIVATE */ png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type) { png_byte buf[4]; - size_t size; + png_size_t size; png_debug(1, "in png_write_sBIT"); /* Make sure we don't depend upon the order of PNG_COLOR_8 */ - if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + if (color_type & PNG_COLOR_MASK_COLOR) { png_byte maxbits; @@ -1318,7 +1372,7 @@ png_write_sBIT(png_structrp png_ptr, png_const_color_8p sbit, int color_type) size = 1; } - if ((color_type & PNG_COLOR_MASK_ALPHA) != 0) + if (color_type & PNG_COLOR_MASK_ALPHA) { if (sbit->alpha == 0 || sbit->alpha > png_ptr->usr_bit_depth) { @@ -1380,12 +1434,12 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, /* Write the chunk out as it is */ png_write_complete_chunk(png_ptr, png_tRNS, trans_alpha, - (size_t)num_trans); + (png_size_t)num_trans); } else if (color_type == PNG_COLOR_TYPE_GRAY) { - /* One 16-bit value */ + /* One 16 bit value */ if (tran->gray >= (1 << png_ptr->bit_depth)) { png_app_warning(png_ptr, @@ -1395,27 +1449,27 @@ png_write_tRNS(png_structrp png_ptr, png_const_bytep trans_alpha, } png_save_uint_16(buf, tran->gray); - png_write_complete_chunk(png_ptr, png_tRNS, buf, 2); + png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)2); } else if (color_type == PNG_COLOR_TYPE_RGB) { - /* Three 16-bit values */ + /* Three 16 bit values */ png_save_uint_16(buf, tran->red); png_save_uint_16(buf + 2, tran->green); png_save_uint_16(buf + 4, tran->blue); #ifdef PNG_WRITE_16BIT_SUPPORTED - if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) #else - if ((buf[0] | buf[2] | buf[4]) != 0) + if (buf[0] | buf[2] | buf[4]) #endif { png_app_warning(png_ptr, - "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); + "Ignoring attempt to write 16-bit tRNS chunk when bit_depth is 8"); return; } - png_write_complete_chunk(png_ptr, png_tRNS, buf, 6); + png_write_complete_chunk(png_ptr, png_tRNS, buf, (png_size_t)6); } else @@ -1438,8 +1492,8 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) { if ( #ifdef PNG_MNG_FEATURES_SUPPORTED - (png_ptr->num_palette != 0 || - (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0) && + (png_ptr->num_palette || + (!(png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE))) && #endif back->index >= png_ptr->num_palette) { @@ -1448,28 +1502,27 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) } buf[0] = back->index; - png_write_complete_chunk(png_ptr, png_bKGD, buf, 1); + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)1); } - else if ((color_type & PNG_COLOR_MASK_COLOR) != 0) + else if (color_type & PNG_COLOR_MASK_COLOR) { png_save_uint_16(buf, back->red); png_save_uint_16(buf + 2, back->green); png_save_uint_16(buf + 4, back->blue); #ifdef PNG_WRITE_16BIT_SUPPORTED - if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4]) != 0) + if (png_ptr->bit_depth == 8 && (buf[0] | buf[2] | buf[4])) #else - if ((buf[0] | buf[2] | buf[4]) != 0) + if (buf[0] | buf[2] | buf[4]) #endif { png_warning(png_ptr, - "Ignoring attempt to write 16-bit bKGD chunk " - "when bit_depth is 8"); + "Ignoring attempt to write 16-bit bKGD chunk when bit_depth is 8"); return; } - png_write_complete_chunk(png_ptr, png_bKGD, buf, 6); + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)6); } else @@ -1483,100 +1536,11 @@ png_write_bKGD(png_structrp png_ptr, png_const_color_16p back, int color_type) } png_save_uint_16(buf, back->gray); - png_write_complete_chunk(png_ptr, png_bKGD, buf, 2); + png_write_complete_chunk(png_ptr, png_bKGD, buf, (png_size_t)2); } } #endif -#ifdef PNG_WRITE_cICP_SUPPORTED -/* Write the cICP data */ -void /* PRIVATE */ -png_write_cICP(png_structrp png_ptr, - png_byte colour_primaries, png_byte transfer_function, - png_byte matrix_coefficients, png_byte video_full_range_flag) -{ - png_byte buf[4]; - - png_debug(1, "in png_write_cICP"); - - png_write_chunk_header(png_ptr, png_cICP, 4); - - buf[0] = colour_primaries; - buf[1] = transfer_function; - buf[2] = matrix_coefficients; - buf[3] = video_full_range_flag; - png_write_chunk_data(png_ptr, buf, 4); - - png_write_chunk_end(png_ptr); -} -#endif - -#ifdef PNG_WRITE_cLLI_SUPPORTED -void /* PRIVATE */ -png_write_cLLI_fixed(png_structrp png_ptr, png_uint_32 maxCLL, - png_uint_32 maxFALL) -{ - png_byte buf[8]; - - png_debug(1, "in png_write_cLLI_fixed"); - - png_save_uint_32(buf, maxCLL); - png_save_uint_32(buf + 4, maxFALL); - - png_write_complete_chunk(png_ptr, png_cLLI, buf, 8); -} -#endif - -#ifdef PNG_WRITE_mDCV_SUPPORTED -void /* PRIVATE */ -png_write_mDCV_fixed(png_structrp png_ptr, - png_uint_16 red_x, png_uint_16 red_y, - png_uint_16 green_x, png_uint_16 green_y, - png_uint_16 blue_x, png_uint_16 blue_y, - png_uint_16 white_x, png_uint_16 white_y, - png_uint_32 maxDL, png_uint_32 minDL) -{ - png_byte buf[24]; - - png_debug(1, "in png_write_mDCV_fixed"); - - png_save_uint_16(buf + 0, red_x); - png_save_uint_16(buf + 2, red_y); - png_save_uint_16(buf + 4, green_x); - png_save_uint_16(buf + 6, green_y); - png_save_uint_16(buf + 8, blue_x); - png_save_uint_16(buf + 10, blue_y); - png_save_uint_16(buf + 12, white_x); - png_save_uint_16(buf + 14, white_y); - png_save_uint_32(buf + 16, maxDL); - png_save_uint_32(buf + 20, minDL); - - png_write_complete_chunk(png_ptr, png_mDCV, buf, 24); -} -#endif - -#ifdef PNG_WRITE_eXIf_SUPPORTED -/* Write the Exif data */ -void /* PRIVATE */ -png_write_eXIf(png_structrp png_ptr, png_bytep exif, int num_exif) -{ - int i; - png_byte buf[1]; - - png_debug(1, "in png_write_eXIf"); - - png_write_chunk_header(png_ptr, png_eXIf, (png_uint_32)(num_exif)); - - for (i = 0; i < num_exif; i++) - { - buf[0] = exif[i]; - png_write_chunk_data(png_ptr, buf, 1); - } - - png_write_chunk_end(png_ptr); -} -#endif - #ifdef PNG_WRITE_hIST_SUPPORTED /* Write the histogram */ void /* PRIVATE */ @@ -1601,7 +1565,7 @@ png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist) for (i = 0; i < num_hist; i++) { png_save_uint_16(buf, hist[i]); - png_write_chunk_data(png_ptr, buf, 2); + png_write_chunk_data(png_ptr, buf, (png_size_t)2); } png_write_chunk_end(png_ptr); @@ -1612,7 +1576,7 @@ png_write_hIST(png_structrp png_ptr, png_const_uint_16p hist, int num_hist) /* Write a tEXt chunk */ void /* PRIVATE */ png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, - size_t text_len) + png_size_t text_len) { png_uint_32 key_len; png_byte new_key[80]; @@ -1644,7 +1608,7 @@ png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, */ png_write_chunk_data(png_ptr, new_key, key_len + 1); - if (text_len != 0) + if (text_len) png_write_chunk_data(png_ptr, (png_const_bytep)text, text_len); png_write_chunk_end(png_ptr); @@ -1655,13 +1619,14 @@ png_write_tEXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, /* Write a compressed text chunk */ void /* PRIVATE */ png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, - int compression) + png_size_t text_len, int compression) { png_uint_32 key_len; png_byte new_key[81]; compression_state comp; png_debug(1, "in png_write_zTXt"); + PNG_UNUSED(text_len) /* Always use strlen */ if (compression == PNG_TEXT_COMPRESSION_NONE) { @@ -1683,7 +1648,7 @@ png_write_zTXt(png_structrp png_ptr, png_const_charp key, png_const_charp text, /* Compute the compressed data; do it now for the length */ png_text_compress_init(&comp, (png_const_bytep)text, - text == NULL ? 0 : strlen(text)); + text == NULL ? 0 : strlen(text)); if (png_text_compress(png_ptr, png_zTXt, &comp, key_len) != Z_OK) png_error(png_ptr, png_ptr->zstream.msg); @@ -1709,7 +1674,7 @@ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, png_const_charp lang, png_const_charp lang_key, png_const_charp text) { png_uint_32 key_len, prefix_len; - size_t lang_len, lang_key_len; + png_size_t lang_len, lang_key_len; png_byte new_key[82]; compression_state comp; @@ -1769,7 +1734,7 @@ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, png_text_compress_init(&comp, (png_const_bytep)text, strlen(text)); - if (compression != 0) + if (compression) { if (png_text_compress(png_ptr, png_iTXt, &comp, prefix_len) != Z_OK) png_error(png_ptr, png_ptr->zstream.msg); @@ -1792,11 +1757,11 @@ png_write_iTXt(png_structrp png_ptr, int compression, png_const_charp key, png_write_chunk_data(png_ptr, (png_const_bytep)lang_key, lang_key_len); - if (compression != 0) + if (compression) png_write_compressed_data_out(png_ptr, &comp); else - png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.output_len); + png_write_chunk_data(png_ptr, (png_const_bytep)text, comp.input_len); png_write_chunk_end(png_ptr); } @@ -1819,7 +1784,7 @@ png_write_oFFs(png_structrp png_ptr, png_int_32 x_offset, png_int_32 y_offset, png_save_int_32(buf + 4, y_offset); buf[8] = (png_byte)unit_type; - png_write_complete_chunk(png_ptr, png_oFFs, buf, 9); + png_write_complete_chunk(png_ptr, png_oFFs, buf, (png_size_t)9); } #endif #ifdef PNG_WRITE_pCAL_SUPPORTED @@ -1830,8 +1795,8 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, png_charpp params) { png_uint_32 purpose_len; - size_t units_len, total_len; - size_t *params_len; + png_size_t units_len, total_len; + png_size_tp params_len; png_byte buf[10]; png_byte new_purpose[80]; int i; @@ -1853,8 +1818,8 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, png_debug1(3, "pCAL units length = %d", (int)units_len); total_len = purpose_len + units_len + 10; - params_len = (size_t *)png_malloc(png_ptr, - (png_alloc_size_t)((png_alloc_size_t)nparams * (sizeof (size_t)))); + params_len = (png_size_tp)png_malloc(png_ptr, + (png_alloc_size_t)(nparams * (sizeof (png_size_t)))); /* Find the length of each parameter, making sure we don't count the * null terminator for the last parameter. @@ -1874,8 +1839,8 @@ png_write_pCAL(png_structrp png_ptr, png_charp purpose, png_int_32 X0, png_save_int_32(buf + 4, X1); buf[8] = (png_byte)type; buf[9] = (png_byte)nparams; - png_write_chunk_data(png_ptr, buf, 10); - png_write_chunk_data(png_ptr, (png_const_bytep)units, (size_t)units_len); + png_write_chunk_data(png_ptr, buf, (png_size_t)10); + png_write_chunk_data(png_ptr, (png_const_bytep)units, (png_size_t)units_len); for (i = 0; i < nparams; i++) { @@ -1894,7 +1859,7 @@ png_write_sCAL_s(png_structrp png_ptr, int unit, png_const_charp width, png_const_charp height) { png_byte buf[64]; - size_t wlen, hlen, total_len; + png_size_t wlen, hlen, total_len; png_debug(1, "in png_write_sCAL_s"); @@ -1935,7 +1900,7 @@ png_write_pHYs(png_structrp png_ptr, png_uint_32 x_pixels_per_unit, png_save_uint_32(buf + 4, y_pixels_per_unit); buf[8] = (png_byte)unit_type; - png_write_complete_chunk(png_ptr, png_pHYs, buf, 9); + png_write_complete_chunk(png_ptr, png_pHYs, buf, (png_size_t)9); } #endif @@ -1965,7 +1930,7 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) buf[5] = mod_time->minute; buf[6] = mod_time->second; - png_write_complete_chunk(png_ptr, png_tIME, buf, 7); + png_write_complete_chunk(png_ptr, png_tIME, buf, (png_size_t)7); } #endif @@ -1973,13 +1938,25 @@ png_write_tIME(png_structrp png_ptr, png_const_timep mod_time) void /* PRIVATE */ png_write_start_row(png_structrp png_ptr) { +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + png_alloc_size_t buf_size; int usr_pixel_depth; -#ifdef PNG_WRITE_FILTER_SUPPORTED - png_byte filters; -#endif - png_debug(1, "in png_write_start_row"); usr_pixel_depth = png_ptr->usr_channels * png_ptr->usr_bit_depth; @@ -1990,61 +1967,56 @@ png_write_start_row(png_structrp png_ptr) png_ptr->maximum_pixel_depth = (png_byte)usr_pixel_depth; /* Set up row buffer */ - png_ptr->row_buf = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size)); + png_ptr->row_buf = (png_bytep)png_malloc(png_ptr, buf_size); png_ptr->row_buf[0] = PNG_FILTER_VALUE_NONE; #ifdef PNG_WRITE_FILTER_SUPPORTED - filters = png_ptr->do_filter; - - if (png_ptr->height == 1) - filters &= 0xff & ~(PNG_FILTER_UP|PNG_FILTER_AVG|PNG_FILTER_PAETH); - - if (png_ptr->width == 1) - filters &= 0xff & ~(PNG_FILTER_SUB|PNG_FILTER_AVG|PNG_FILTER_PAETH); - - if (filters == 0) - filters = PNG_FILTER_NONE; - - png_ptr->do_filter = filters; - - if (((filters & (PNG_FILTER_SUB | PNG_FILTER_UP | PNG_FILTER_AVG | - PNG_FILTER_PAETH)) != 0) && png_ptr->try_row == NULL) + /* Set up filtering buffer, if using this filter */ + if (png_ptr->do_filter & PNG_FILTER_SUB) { - int num_filters = 0; + png_ptr->sub_row = (png_bytep)png_malloc(png_ptr, png_ptr->rowbytes + 1); - png_ptr->try_row = png_voidcast(png_bytep, png_malloc(png_ptr, buf_size)); - - if (filters & PNG_FILTER_SUB) - num_filters++; - - if (filters & PNG_FILTER_UP) - num_filters++; - - if (filters & PNG_FILTER_AVG) - num_filters++; - - if (filters & PNG_FILTER_PAETH) - num_filters++; - - if (num_filters > 1) - png_ptr->tst_row = png_voidcast(png_bytep, png_malloc(png_ptr, - buf_size)); + png_ptr->sub_row[0] = PNG_FILTER_VALUE_SUB; } - /* We only need to keep the previous row if we are using one of the following - * filters. - */ - if ((filters & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) != 0) - png_ptr->prev_row = png_voidcast(png_bytep, - png_calloc(png_ptr, buf_size)); -#endif /* WRITE_FILTER */ + /* We only need to keep the previous row if we are using one of these. */ + if (png_ptr->do_filter & (PNG_FILTER_AVG | PNG_FILTER_UP | PNG_FILTER_PAETH)) + { + /* Set up previous row buffer */ + png_ptr->prev_row = (png_bytep)png_calloc(png_ptr, buf_size); + + if (png_ptr->do_filter & PNG_FILTER_UP) + { + png_ptr->up_row = (png_bytep)png_malloc(png_ptr, + png_ptr->rowbytes + 1); + + png_ptr->up_row[0] = PNG_FILTER_VALUE_UP; + } + + if (png_ptr->do_filter & PNG_FILTER_AVG) + { + png_ptr->avg_row = (png_bytep)png_malloc(png_ptr, + png_ptr->rowbytes + 1); + + png_ptr->avg_row[0] = PNG_FILTER_VALUE_AVG; + } + + if (png_ptr->do_filter & PNG_FILTER_PAETH) + { + png_ptr->paeth_row = (png_bytep)png_malloc(png_ptr, + png_ptr->rowbytes + 1); + + png_ptr->paeth_row[0] = PNG_FILTER_VALUE_PAETH; + } + } +#endif /* PNG_WRITE_FILTER_SUPPORTED */ #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced, we need to set up width and height of pass */ - if (png_ptr->interlaced != 0) + if (png_ptr->interlaced) { - if ((png_ptr->transformations & PNG_INTERLACE) == 0) + if (!(png_ptr->transformations & PNG_INTERLACE)) { png_ptr->num_rows = (png_ptr->height + png_pass_yinc[0] - 1 - png_pass_ystart[0]) / png_pass_yinc[0]; @@ -2072,6 +2044,22 @@ png_write_start_row(png_structrp png_ptr) void /* PRIVATE */ png_write_finish_row(png_structrp png_ptr) { +#ifdef PNG_WRITE_INTERLACING_SUPPORTED + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + + /* Start of interlace block in the y direction */ + static PNG_CONST png_byte png_pass_ystart[7] = {0, 0, 4, 0, 2, 0, 1}; + + /* Offset to next interlace block in the y direction */ + static PNG_CONST png_byte png_pass_yinc[7] = {8, 8, 8, 4, 4, 2, 2}; +#endif + png_debug(1, "in png_write_finish_row"); /* Next row */ @@ -2083,10 +2071,10 @@ png_write_finish_row(png_structrp png_ptr) #ifdef PNG_WRITE_INTERLACING_SUPPORTED /* If interlaced, go to next pass */ - if (png_ptr->interlaced != 0) + if (png_ptr->interlaced) { png_ptr->row_number = 0; - if ((png_ptr->transformations & PNG_INTERLACE) != 0) + if (png_ptr->transformations & PNG_INTERLACE) { png_ptr->pass++; } @@ -2111,7 +2099,7 @@ png_write_finish_row(png_structrp png_ptr) png_pass_ystart[png_ptr->pass]) / png_pass_yinc[png_ptr->pass]; - if ((png_ptr->transformations & PNG_INTERLACE) != 0) + if (png_ptr->transformations & PNG_INTERLACE) break; } while (png_ptr->usr_width == 0 || png_ptr->num_rows == 0); @@ -2123,8 +2111,8 @@ png_write_finish_row(png_structrp png_ptr) { if (png_ptr->prev_row != NULL) memset(png_ptr->prev_row, 0, - PNG_ROWBYTES(png_ptr->usr_channels * - png_ptr->usr_bit_depth, png_ptr->width) + 1); + (png_size_t)(PNG_ROWBYTES(png_ptr->usr_channels* + png_ptr->usr_bit_depth, png_ptr->width)) + 1); return; } @@ -2147,6 +2135,14 @@ png_write_finish_row(png_structrp png_ptr) void /* PRIVATE */ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) { + /* Arrays to facilitate easy interlacing - use pass (0 - 6) as index */ + + /* Start of interlace block */ + static PNG_CONST png_byte png_pass_start[7] = {0, 4, 0, 2, 0, 1, 0}; + + /* Offset to next interlace block */ + static PNG_CONST png_byte png_pass_inc[7] = {8, 8, 4, 4, 2, 2, 1}; + png_debug(1, "in png_do_write_interlace"); /* We don't have to do anything on the last pass (6) */ @@ -2159,7 +2155,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) { png_bytep sp; png_bytep dp; - unsigned int shift; + int shift; int d; int value; png_uint_32 i; @@ -2172,7 +2168,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) for (i = png_pass_start[pass]; i < row_width; i += png_pass_inc[pass]) { - sp = row + (size_t)(i >> 3); + sp = row + (png_size_t)(i >> 3); value = (int)(*sp >> (7 - (int)(i & 0x07))) & 0x01; d |= (value << shift); @@ -2197,7 +2193,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) { png_bytep sp; png_bytep dp; - unsigned int shift; + int shift; int d; int value; png_uint_32 i; @@ -2210,7 +2206,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) for (i = png_pass_start[pass]; i < row_width; i += png_pass_inc[pass]) { - sp = row + (size_t)(i >> 2); + sp = row + (png_size_t)(i >> 2); value = (*sp >> ((3 - (int)(i & 0x03)) << 1)) & 0x03; d |= (value << shift); @@ -2234,7 +2230,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) { png_bytep sp; png_bytep dp; - unsigned int shift; + int shift; int d; int value; png_uint_32 i; @@ -2246,7 +2242,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) for (i = png_pass_start[pass]; i < row_width; i += png_pass_inc[pass]) { - sp = row + (size_t)(i >> 1); + sp = row + (png_size_t)(i >> 1); value = (*sp >> ((1 - (int)(i & 0x01)) << 2)) & 0x0f; d |= (value << shift); @@ -2272,7 +2268,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) png_bytep dp; png_uint_32 i; png_uint_32 row_width = row_info->width; - size_t pixel_bytes; + png_size_t pixel_bytes; /* Start at the beginning */ dp = row; @@ -2285,7 +2281,7 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) i += png_pass_inc[pass]) { /* Find out where the original pixel is */ - sp = row + (size_t)i * pixel_bytes; + sp = row + (png_size_t)i * pixel_bytes; /* Move the pixel */ if (dp != sp) @@ -2309,308 +2305,49 @@ png_do_write_interlace(png_row_infop row_info, png_bytep row, int pass) } #endif - /* This filters the row, chooses which filter to use, if it has not already * been specified by the application, and then writes the row out with the * chosen filter. */ -static void /* PRIVATE */ -png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, - size_t row_bytes); - -#ifdef PNG_WRITE_FILTER_SUPPORTED -static size_t /* PRIVATE */ -png_setup_sub_row(png_structrp png_ptr, png_uint_32 bpp, - size_t row_bytes, size_t lmins) -{ - png_bytep rp, dp, lp; - size_t i; - size_t sum = 0; - unsigned int v; - - png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB; - - for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp; - i++, rp++, dp++) - { - v = *dp = *rp; -#ifdef PNG_USE_ABS - sum += 128 - abs((int)v - 128); -#else - sum += (v < 128) ? v : 256 - v; -#endif - } - - for (lp = png_ptr->row_buf + 1; i < row_bytes; - i++, rp++, lp++, dp++) - { - v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); -#ifdef PNG_USE_ABS - sum += 128 - abs((int)v - 128); -#else - sum += (v < 128) ? v : 256 - v; -#endif - - if (sum > lmins) /* We are already worse, don't continue. */ - break; - } - - return sum; -} - -static void /* PRIVATE */ -png_setup_sub_row_only(png_structrp png_ptr, png_uint_32 bpp, - size_t row_bytes) -{ - png_bytep rp, dp, lp; - size_t i; - - png_ptr->try_row[0] = PNG_FILTER_VALUE_SUB; - - for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1; i < bpp; - i++, rp++, dp++) - { - *dp = *rp; - } - - for (lp = png_ptr->row_buf + 1; i < row_bytes; - i++, rp++, lp++, dp++) - { - *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); - } -} - -static size_t /* PRIVATE */ -png_setup_up_row(png_structrp png_ptr, size_t row_bytes, size_t lmins) -{ - png_bytep rp, dp, pp; - size_t i; - size_t sum = 0; - unsigned int v; - - png_ptr->try_row[0] = PNG_FILTER_VALUE_UP; - - for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, - pp = png_ptr->prev_row + 1; i < row_bytes; - i++, rp++, pp++, dp++) - { - v = *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); -#ifdef PNG_USE_ABS - sum += 128 - abs((int)v - 128); -#else - sum += (v < 128) ? v : 256 - v; -#endif - - if (sum > lmins) /* We are already worse, don't continue. */ - break; - } - - return sum; -} -static void /* PRIVATE */ -png_setup_up_row_only(png_structrp png_ptr, size_t row_bytes) -{ - png_bytep rp, dp, pp; - size_t i; - - png_ptr->try_row[0] = PNG_FILTER_VALUE_UP; - - for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, - pp = png_ptr->prev_row + 1; i < row_bytes; - i++, rp++, pp++, dp++) - { - *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); - } -} - -static size_t /* PRIVATE */ -png_setup_avg_row(png_structrp png_ptr, png_uint_32 bpp, - size_t row_bytes, size_t lmins) -{ - png_bytep rp, dp, pp, lp; - png_uint_32 i; - size_t sum = 0; - unsigned int v; - - png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG; - - for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, - pp = png_ptr->prev_row + 1; i < bpp; i++) - { - v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); - -#ifdef PNG_USE_ABS - sum += 128 - abs((int)v - 128); -#else - sum += (v < 128) ? v : 256 - v; -#endif - } - - for (lp = png_ptr->row_buf + 1; i < row_bytes; i++) - { - v = *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) - & 0xff); - -#ifdef PNG_USE_ABS - sum += 128 - abs((int)v - 128); -#else - sum += (v < 128) ? v : 256 - v; -#endif - - if (sum > lmins) /* We are already worse, don't continue. */ - break; - } - - return sum; -} -static void /* PRIVATE */ -png_setup_avg_row_only(png_structrp png_ptr, png_uint_32 bpp, - size_t row_bytes) -{ - png_bytep rp, dp, pp, lp; - png_uint_32 i; - - png_ptr->try_row[0] = PNG_FILTER_VALUE_AVG; - - for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, - pp = png_ptr->prev_row + 1; i < bpp; i++) - { - *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); - } - - for (lp = png_ptr->row_buf + 1; i < row_bytes; i++) - { - *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) - & 0xff); - } -} - -static size_t /* PRIVATE */ -png_setup_paeth_row(png_structrp png_ptr, png_uint_32 bpp, - size_t row_bytes, size_t lmins) -{ - png_bytep rp, dp, pp, cp, lp; - size_t i; - size_t sum = 0; - unsigned int v; - - png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH; - - for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, - pp = png_ptr->prev_row + 1; i < bpp; i++) - { - v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); - -#ifdef PNG_USE_ABS - sum += 128 - abs((int)v - 128); -#else - sum += (v < 128) ? v : 256 - v; -#endif - } - - for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes; - i++) - { - int a, b, c, pa, pb, pc, p; - - b = *pp++; - c = *cp++; - a = *lp++; - - p = b - c; - pc = a - c; - -#ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -#else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -#endif - - p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; - - v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); - -#ifdef PNG_USE_ABS - sum += 128 - abs((int)v - 128); -#else - sum += (v < 128) ? v : 256 - v; -#endif - - if (sum > lmins) /* We are already worse, don't continue. */ - break; - } - - return sum; -} -static void /* PRIVATE */ -png_setup_paeth_row_only(png_structrp png_ptr, png_uint_32 bpp, - size_t row_bytes) -{ - png_bytep rp, dp, pp, cp, lp; - size_t i; - - png_ptr->try_row[0] = PNG_FILTER_VALUE_PAETH; - - for (i = 0, rp = png_ptr->row_buf + 1, dp = png_ptr->try_row + 1, - pp = png_ptr->prev_row + 1; i < bpp; i++) - { - *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); - } - - for (lp = png_ptr->row_buf + 1, cp = png_ptr->prev_row + 1; i < row_bytes; - i++) - { - int a, b, c, pa, pb, pc, p; - - b = *pp++; - c = *cp++; - a = *lp++; - - p = b - c; - pc = a - c; - -#ifdef PNG_USE_ABS - pa = abs(p); - pb = abs(pc); - pc = abs(p + pc); -#else - pa = p < 0 ? -p : p; - pb = pc < 0 ? -pc : pc; - pc = (p + pc) < 0 ? -(p + pc) : p + pc; -#endif - - p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; - - *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); - } -} -#endif /* WRITE_FILTER */ +static void png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, + png_size_t row_bytes); +#define PNG_MAXSUM (((png_uint_32)(-1)) >> 1) +#define PNG_HISHIFT 10 +#define PNG_LOMASK ((png_uint_32)0xffffL) +#define PNG_HIMASK ((png_uint_32)(~PNG_LOMASK >> PNG_HISHIFT)) void /* PRIVATE */ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) { -#ifndef PNG_WRITE_FILTER_SUPPORTED - png_write_filtered_row(png_ptr, png_ptr->row_buf, row_info->rowbytes+1); -#else - unsigned int filter_to_do = png_ptr->do_filter; - png_bytep row_buf; png_bytep best_row; - png_uint_32 bpp; - size_t mins; - size_t row_bytes = row_info->rowbytes; +#ifdef PNG_WRITE_FILTER_SUPPORTED + png_bytep prev_row, row_buf; + png_uint_32 mins, bpp; + png_byte filter_to_do = png_ptr->do_filter; + png_size_t row_bytes = row_info->rowbytes; +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + int num_p_filters = png_ptr->num_prev_filters; +#endif png_debug(1, "in png_write_find_filter"); +#ifndef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->row_number == 0 && filter_to_do == PNG_ALL_FILTERS) + { + /* These will never be selected so we need not test them. */ + filter_to_do &= ~(PNG_FILTER_UP | PNG_FILTER_PAETH); + } +#endif + /* Find out how many bytes offset each pixel is */ bpp = (row_info->pixel_depth + 7) >> 3; - row_buf = png_ptr->row_buf; - mins = PNG_SIZE_MAX - 256/* so we can detect potential overflow of the - running sum */; + prev_row = png_ptr->prev_row; +#endif + best_row = png_ptr->row_buf; +#ifdef PNG_WRITE_FILTER_SUPPORTED + row_buf = best_row; + mins = PNG_MAXSUM; /* The prediction method we use is to find which method provides the * smallest value when summing the absolute values of the distances @@ -2640,38 +2377,57 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) /* We don't need to test the 'no filter' case if this is the only filter * that has been chosen, as it doesn't actually do anything to the data. */ - best_row = png_ptr->row_buf; - - if (PNG_SIZE_MAX/128 <= row_bytes) + if ((filter_to_do & PNG_FILTER_NONE) && filter_to_do != PNG_FILTER_NONE) { - /* Overflow can occur in the calculation, just select the lowest set - * filter. - */ - filter_to_do &= 0U-filter_to_do; - } - else if ((filter_to_do & PNG_FILTER_NONE) != 0 && - filter_to_do != PNG_FILTER_NONE) - { - /* Overflow not possible and multiple filters in the list, including the - * 'none' filter. - */ png_bytep rp; - size_t sum = 0; - size_t i; - unsigned int v; + png_uint_32 sum = 0; + png_size_t i; + int v; + for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) { - for (i = 0, rp = row_buf + 1; i < row_bytes; i++, rp++) - { - v = *rp; -#ifdef PNG_USE_ABS - sum += 128 - abs((int)v - 128); -#else - sum += (v < 128) ? v : 256 - v; -#endif - } + v = *rp; + sum += (v < 128) ? v : 256 - v; } +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + png_uint_32 sumhi, sumlo; + int j; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; /* Gives us some footroom */ + + /* Reduce the sum if we match any of the previous rows */ + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + /* Factor in the cost of this filter (this is here for completeness, + * but it makes no sense to have a "cost" for the NONE filter, as + * it has the minimum possible computational cost - none). + */ + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> + PNG_COST_SHIFT; + + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_NONE]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif mins = sum; } @@ -2679,117 +2435,561 @@ png_write_find_filter(png_structrp png_ptr, png_row_infop row_info) if (filter_to_do == PNG_FILTER_SUB) /* It's the only filter so no testing is needed */ { - png_setup_sub_row_only(png_ptr, bpp, row_bytes); - best_row = png_ptr->try_row; + png_bytep rp, lp, dp; + png_size_t i; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + *dp = *rp; + } + + for (lp = row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + } + + best_row = png_ptr->sub_row; } - else if ((filter_to_do & PNG_FILTER_SUB) != 0) + else if (filter_to_do & PNG_FILTER_SUB) { - size_t sum; - size_t lmins = mins; + png_bytep rp, dp, lp; + png_uint_32 sum = 0, lmins = mins; + png_size_t i; + int v; - sum = png_setup_sub_row(png_ptr, bpp, row_bytes, lmins); +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + /* We temporarily increase the "minimum sum" by the factor we + * would reduce the sum of this filter, so that we can do the + * early exit comparison without scaling the sum each time. + */ + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->sub_row + 1; i < bpp; + i++, rp++, dp++) + { + v = *dp = *rp; + + sum += (v < 128) ? v : 256 - v; + } + + for (lp = row_buf + 1; i < row_bytes; + i++, rp++, lp++, dp++) + { + v = *dp = (png_byte)(((int)*rp - (int)*lp) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_SUB) + { + sumlo = (sumlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + sumhi = (sumhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + sumhi = (sumhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_SUB]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif if (sum < mins) { mins = sum; - best_row = png_ptr->try_row; - if (png_ptr->tst_row != NULL) - { - png_ptr->try_row = png_ptr->tst_row; - png_ptr->tst_row = best_row; - } + best_row = png_ptr->sub_row; } } /* Up filter */ if (filter_to_do == PNG_FILTER_UP) { - png_setup_up_row_only(png_ptr, row_bytes); - best_row = png_ptr->try_row; + png_bytep rp, dp, pp; + png_size_t i; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_bytes; + i++, rp++, pp++, dp++) + { + *dp = (png_byte)(((int)*rp - (int)*pp) & 0xff); + } + + best_row = png_ptr->up_row; } - else if ((filter_to_do & PNG_FILTER_UP) != 0) + else if (filter_to_do & PNG_FILTER_UP) { - size_t sum; - size_t lmins = mins; + png_bytep rp, dp, pp; + png_uint_32 sum = 0, lmins = mins; + png_size_t i; + int v; - sum = png_setup_up_row(png_ptr, row_bytes, lmins); + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->up_row + 1, + pp = prev_row + 1; i < row_bytes; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_UP) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_UP]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif if (sum < mins) { mins = sum; - best_row = png_ptr->try_row; - if (png_ptr->tst_row != NULL) - { - png_ptr->try_row = png_ptr->tst_row; - png_ptr->tst_row = best_row; - } + best_row = png_ptr->up_row; } } /* Avg filter */ if (filter_to_do == PNG_FILTER_AVG) { - png_setup_avg_row_only(png_ptr, bpp, row_bytes); - best_row = png_ptr->try_row; + png_bytep rp, dp, pp, lp; + png_uint_32 i; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + } + + for (lp = row_buf + 1; i < row_bytes; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) + & 0xff); + } + best_row = png_ptr->avg_row; } - else if ((filter_to_do & PNG_FILTER_AVG) != 0) + else if (filter_to_do & PNG_FILTER_AVG) { - size_t sum; - size_t lmins = mins; + png_bytep rp, dp, pp, lp; + png_uint_32 sum = 0, lmins = mins; + png_size_t i; + int v; - sum= png_setup_avg_row(png_ptr, bpp, row_bytes, lmins); +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_AVG) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->avg_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - ((int)*pp++ / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + + for (lp = row_buf + 1; i < row_bytes; i++) + { + v = *dp++ = + (png_byte)(((int)*rp++ - (((int)*pp++ + (int)*lp++) / 2)) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_NONE) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_AVG]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif if (sum < mins) { mins = sum; - best_row = png_ptr->try_row; - if (png_ptr->tst_row != NULL) - { - png_ptr->try_row = png_ptr->tst_row; - png_ptr->tst_row = best_row; - } + best_row = png_ptr->avg_row; } } /* Paeth filter */ if (filter_to_do == PNG_FILTER_PAETH) { - png_setup_paeth_row_only(png_ptr, bpp, row_bytes); - best_row = png_ptr->try_row; + png_bytep rp, dp, pp, cp, lp; + png_size_t i; + + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + } + + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + + p = b - c; + pc = a - c; + +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; + + *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + } + best_row = png_ptr->paeth_row; } - else if ((filter_to_do & PNG_FILTER_PAETH) != 0) + else if (filter_to_do & PNG_FILTER_PAETH) { - size_t sum; - size_t lmins = mins; + png_bytep rp, dp, pp, cp, lp; + png_uint_32 sum = 0, lmins = mins; + png_size_t i; + int v; - sum = png_setup_paeth_row(png_ptr, bpp, row_bytes, lmins); +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 lmhi, lmlo; + lmlo = lmins & PNG_LOMASK; + lmhi = (lmins >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) + { + lmlo = (lmlo * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + lmlo = (lmlo * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + lmhi = (lmhi * png_ptr->inv_filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + if (lmhi > PNG_HIMASK) + lmins = PNG_MAXSUM; + + else + lmins = (lmhi << PNG_HISHIFT) + lmlo; + } +#endif + + for (i = 0, rp = row_buf + 1, dp = png_ptr->paeth_row + 1, + pp = prev_row + 1; i < bpp; i++) + { + v = *dp++ = (png_byte)(((int)*rp++ - (int)*pp++) & 0xff); + + sum += (v < 128) ? v : 256 - v; + } + + for (lp = row_buf + 1, cp = prev_row + 1; i < row_bytes; i++) + { + int a, b, c, pa, pb, pc, p; + + b = *pp++; + c = *cp++; + a = *lp++; + +#ifndef PNG_SLOW_PAETH + p = b - c; + pc = a - c; +#ifdef PNG_USE_ABS + pa = abs(p); + pb = abs(pc); + pc = abs(p + pc); +#else + pa = p < 0 ? -p : p; + pb = pc < 0 ? -pc : pc; + pc = (p + pc) < 0 ? -(p + pc) : p + pc; +#endif + p = (pa <= pb && pa <=pc) ? a : (pb <= pc) ? b : c; +#else /* PNG_SLOW_PAETH */ + p = a + b - c; + pa = abs(p - a); + pb = abs(p - b); + pc = abs(p - c); + + if (pa <= pb && pa <= pc) + p = a; + + else if (pb <= pc) + p = b; + + else + p = c; +#endif /* PNG_SLOW_PAETH */ + + v = *dp++ = (png_byte)(((int)*rp++ - p) & 0xff); + + sum += (v < 128) ? v : 256 - v; + + if (sum > lmins) /* We are already worse, don't continue. */ + break; + } + +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + if (png_ptr->heuristic_method == PNG_FILTER_HEURISTIC_WEIGHTED) + { + int j; + png_uint_32 sumhi, sumlo; + sumlo = sum & PNG_LOMASK; + sumhi = (sum >> PNG_HISHIFT) & PNG_HIMASK; + + for (j = 0; j < num_p_filters; j++) + { + if (png_ptr->prev_filters[j] == PNG_FILTER_VALUE_PAETH) + { + sumlo = (sumlo * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + + sumhi = (sumhi * png_ptr->filter_weights[j]) >> + PNG_WEIGHT_SHIFT; + } + } + + sumlo = (sumlo * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + sumhi = (sumhi * png_ptr->filter_costs[PNG_FILTER_VALUE_PAETH]) >> + PNG_COST_SHIFT; + + if (sumhi > PNG_HIMASK) + sum = PNG_MAXSUM; + + else + sum = (sumhi << PNG_HISHIFT) + sumlo; + } +#endif if (sum < mins) { - best_row = png_ptr->try_row; - if (png_ptr->tst_row != NULL) - { - png_ptr->try_row = png_ptr->tst_row; - png_ptr->tst_row = best_row; - } + best_row = png_ptr->paeth_row; } } +#endif /* PNG_WRITE_FILTER_SUPPORTED */ /* Do the actual writing of the filtered row data from the chosen filter. */ png_write_filtered_row(png_ptr, best_row, row_info->rowbytes+1); -#endif /* WRITE_FILTER */ +#ifdef PNG_WRITE_FILTER_SUPPORTED +#ifdef PNG_WRITE_WEIGHTED_FILTER_SUPPORTED + /* Save the type of filter we picked this time for future calculations */ + if (png_ptr->num_prev_filters > 0) + { + int j; + + for (j = 1; j < num_p_filters; j++) + { + png_ptr->prev_filters[j] = png_ptr->prev_filters[j - 1]; + } + + png_ptr->prev_filters[j] = best_row[0]; + } +#endif +#endif /* PNG_WRITE_FILTER_SUPPORTED */ } /* Do the actual writing of a previously filtered row. */ static void png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, - size_t full_row_length/*includes filter byte*/) + png_size_t full_row_length/*includes filter byte*/) { png_debug(1, "in png_write_filtered_row"); @@ -2797,7 +2997,6 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, png_compress_IDAT(png_ptr, filtered_row, full_row_length, Z_NO_FLUSH); -#ifdef PNG_WRITE_FILTER_SUPPORTED /* Swap the current and previous rows */ if (png_ptr->prev_row != NULL) { @@ -2807,7 +3006,6 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, png_ptr->prev_row = png_ptr->row_buf; png_ptr->row_buf = tptr; } -#endif /* WRITE_FILTER */ /* Finish row - updates counters and flushes zlib if last row */ png_write_finish_row(png_ptr); @@ -2820,6 +3018,6 @@ png_write_filtered_row(png_structrp png_ptr, png_bytep filtered_row, { png_write_flush(png_ptr); } -#endif /* WRITE_FLUSH */ +#endif } -#endif /* WRITE */ +#endif /* PNG_WRITE_SUPPORTED */ diff --git a/Windows_Libs/Dev/Render/microprofile/microprofile.config.h b/Windows_Libs/Dev/Render/microprofile/microprofile.config.h new file mode 100644 index 0000000..7c66cfd --- /dev/null +++ b/Windows_Libs/Dev/Render/microprofile/microprofile.config.h @@ -0,0 +1,4 @@ + +#define MICROPROFILE_ENABLED 1 +#define MICROPROFILE_GPU_TIMERS_D3D11 1 +#define MICROPROFILE_GPU_TIMERS_D3D12 1 diff --git a/Windows_Libs/Dev/Render/microprofile/microprofile.cpp b/Windows_Libs/Dev/Render/microprofile/microprofile.cpp new file mode 100644 index 0000000..c4af767 --- /dev/null +++ b/Windows_Libs/Dev/Render/microprofile/microprofile.cpp @@ -0,0 +1,16191 @@ +#include "../Profiler.h" + +#ifdef ENABLE_PROFILING + +#define MICROPROFILE_IMPL +#include "microprofile.h" +#if MICROPROFILE_ENABLED + +#define BREAK_SKIP() __builtin_trap() + +#ifdef _WIN32 +#if !defined(WIN32_LEAN_AND_MEAN) +#define WIN32_LEAN_AND_MEAN +#endif +#include +#endif + +#ifdef _WIN32 +#define MICROPROFILE_MAX_PATH MAX_PATH +#else +#define MICROPROFILE_MAX_PATH 1024 +#endif + +#include +#include +#include +#include +#include +#include +#include + +#if defined(MICROPROFILE_SYSTEM_STB) +#include +#else +#define STB_SPRINTF_IMPLEMENTATION +#include "stb/stb_sprintf.h" +#endif + +#if defined(_WIN32) && _MSC_VER == 1700 +#define PRIx64 "llx" +#define PRIu64 "llu" +#define PRId64 "lld" +#else +#include +#endif + +#define MICROPROFILE_MAX_COUNTERS 512 +#define MICROPROFILE_MAX_COUNTER_NAME_CHARS (MICROPROFILE_MAX_COUNTERS * 16) +#define MICROPROFILE_MAX_GROUP_INTS (MICROPROFILE_MAX_GROUPS / 32) +#define MICROPROFILE_MAX_CATEGORIES 16 +#define MICROPROFILE_MAX_GRAPHS 5 +#define MICROPROFILE_GRAPH_HISTORY 128 +#define MICROPROFILE_BUFFER_SIZE ((MICROPROFILE_PER_THREAD_BUFFER_SIZE) / sizeof(MicroProfileLogEntry)) +#define MICROPROFILE_GPU_BUFFER_SIZE ((MICROPROFILE_PER_THREAD_GPU_BUFFER_SIZE) / sizeof(MicroProfileLogEntry)) +#define MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS 256 +#define MICROPROFILE_WEBSOCKET_BUFFER_SIZE (64 << 10) +#define MICROPROFILE_INVALID_TICK ((uint64_t) - 1) +#define MICROPROFILE_DROPPED_TICK ((uint64_t) - 2) +#define MICROPROFILE_INVALID_FRAME ((uint32_t) - 1) +#define MICROPROFILE_GROUP_MASK_ALL 0xffffffff +#define MICROPROFILE_MAX_PATCH_ERRORS 32 +#define MICROPROFILE_MAX_MODULE_EXEC_REGIONS 16 + +#define MP_LOG_TICK_MASK 0x0000ffffffffffff +#define MP_LOG_INDEX_MASK 0x3fff000000000000 +#define MP_LOG_BEGIN_MASK 0xc000000000000000 +#define MP_LOG_CSTR_MASK 0xe000000000000000 +#define MP_LOG_CSTR_BIT 0x2000000000000000 +#define MP_LOG_PAYLOAD_PTR_MASK (~(MP_LOG_BEGIN_MASK | MP_LOG_CSTR_BIT)) + +#define MP_LOG_ENTER_LEAVE_MASK 0x8000000000000000 + +#define MP_LOG_LEAVE 0x0 +#define MP_LOG_ENTER 0x1 +#define MP_LOG_EXTENDED 0x2 +#define MP_LOG_EXTENDED_NO_DATA 0x3 + +#ifndef MICROPROFILE_SETTINGS_FILE +#define MICROPROFILE_SETTINGS_FILE "mppresets.cfg" +#endif +#ifndef MICROPROFILE_SETTINGS_FILE_BUILTIN +#define MICROPROFILE_SETTINGS_FILE_BUILTIN "mppresets.builtin.cfg" +#endif +#ifndef MICROPROFILE_SETTINGS_FILE_TEMP +#define MICROPROFILE_SETTINGS_FILE_TEMP ".tmp" +#endif + +// #define MP_LOG_EXTRA_DATA 0x3 + +static_assert(0 == (MICROPROFILE_MAX_GROUPS % 32), "MICROPROFILE_MAX_GROUPS must be divisible by 32"); + +enum EMicroProfileTokenExtended +{ + ETOKEN_GPU_CPU_TIMESTAMP = 0x3fff, + ETOKEN_GPU_CPU_SOURCE_THREAD = 0x3ffe, + ETOKEN_META_MARKER = 0x3ffd, + ETOKEN_CUSTOM_NAME = 0x3ffc, + ETOKEN_CUSTOM_COLOR = 0x3ffb, + ETOKEN_CUSTOM_ID = 0x3ffa, + ETOKEN_CSTR_PTR = 0x2000, // note, matches MP_LOG_CSTR_BIT + ETOKEN_MAX = 0x2000, +}; + +enum +{ + MICROPROFILE_WEBSOCKET_DIRTY_MENU, + MICROPROFILE_WEBSOCKET_DIRTY_ENABLED, +}; + +#ifndef MICROPROFILE_ALLOC // redefine all if overriding +#define MICROPROFILE_ALLOC(nSize, nAlign) MicroProfileAllocAligned(nSize, nAlign); +#define MICROPROFILE_REALLOC(p, s) realloc(p, s) +#define MICROPROFILE_FREE(p) MicroProfileFreeAligned(p) +#define MICROPROFILE_FREE_NON_ALIGNED(p) free(p) +#endif + +#define MP_ALLOC(nSize, nAlign) MicroProfileAllocInternal(nSize, nAlign) +#define MP_REALLOC(p, s) MicroProfileReallocInternal(p, s) +#define MP_FREE(p) MicroProfileFreeInternal(p) +#define MP_ALLOC_OBJECT(T) (T*)MP_ALLOC(sizeof(T), alignof(T)) +#define MP_ALLOC_OBJECT_ARRAY(T, Count) (T*)MP_ALLOC(sizeof(T) * Count, alignof(T)) + +#ifndef MICROPROFILE_DEBUG +#define MICROPROFILE_DEBUG 0 +#endif + +typedef uint64_t MicroProfileLogEntry; + +void MicroProfileSleep(uint32_t nMs); +template +T MicroProfileMin(T a, T b); +template +T MicroProfileMax(T a, T b); +template +T MicroProfileClamp(T a, T min_, T max_); +int64_t MicroProfileMsToTick(float fMs, int64_t nTicksPerSecond); +float MicroProfileTickToMsMultiplier(int64_t nTicksPerSecond); +uint32_t MicroProfileLogGetType(MicroProfileLogEntry Index); +uint64_t MicroProfileLogGetTimerIndex(MicroProfileLogEntry Index); +MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfileToken nToken, int64_t nTick); +int64_t MicroProfileLogTickDifference(MicroProfileLogEntry Start, MicroProfileLogEntry End); +int64_t MicroProfileLogSetTick(MicroProfileLogEntry e, int64_t nTick); +uint16_t MicroProfileGetTimerIndex(MicroProfileToken t); +uint32_t MicroProfileGetGroupMask(MicroProfileToken t); +MicroProfileToken MicroProfileMakeToken(uint64_t nGroupMask, uint32_t nGroupIndex, uint16_t nTimer); +bool MicroProfileAnyGroupActive(); +void MicroProfileWriteFile(void* Handle, size_t nSize, const char* pData); + +// defer implementation +#define CONCAT_INTERNAL(x, y) x##y +#define CONCAT(x, y) CONCAT_INTERNAL(x, y) +void IntentionallyNotDefinedFunction__(); // DO NOT DEFINE THIS +template +struct MicroProfileExitScope +{ + T lambda; + MicroProfileExitScope(T lambda) + : lambda(lambda) + { + } + ~MicroProfileExitScope() + { + lambda(); + } + + MicroProfileExitScope(const MicroProfileExitScope& rhs) + : lambda(rhs.lambda) + { + IntentionallyNotDefinedFunction__(); // this is here to ensure the compiler does not create duplicate copies + } + + private: + MicroProfileExitScope& operator=(const MicroProfileExitScope&); +}; + +class MicroProfileExitScopeHelp +{ + public: + template + MicroProfileExitScope operator+(T t) + { + return t; + } +}; +#define defer const auto& CONCAT(defer__, __LINE__) = MicroProfileExitScopeHelp() + [&]() + +////////////////////////////////////////////////////////////////////////// +// platform IMPL +void* MicroProfileAllocInternal(size_t nSize, size_t nAlign); +void MicroProfileFreeInternal(void* pPtr); +void* MicroProfileReallocInternal(void* pPtr, size_t nSize); + +void* MicroProfileAllocAligned(size_t nSize, size_t nAlign); +void MicroProfileFreeAligned(void* pMem); + +#if defined(__APPLE__) +#include +#include +#include +#include +#include +#include + +#if TARGET_OS_IPHONE +#define MICROPROFILE_IOS +#endif + +#define MP_TICK() mach_absolute_time() +inline int64_t MicroProfileTicksPerSecondCpu_() +{ + static int64_t nTicksPerSecond = 0; + if(nTicksPerSecond == 0) + { + mach_timebase_info_data_t sTimebaseInfo; + mach_timebase_info(&sTimebaseInfo); + nTicksPerSecond = 1000000000ll * sTimebaseInfo.denom / sTimebaseInfo.numer; + } + return nTicksPerSecond; +} + +int64_t MicroProfileTicksPerSecondCpu() +{ + return MicroProfileTicksPerSecondCpu_(); +} +#define MicroProfileTicksPerSecondCpu MicroProfileTicksPerSecondCpu_ + +inline uint64_t MicroProfileGetCurrentThreadId() +{ + uint64_t tid; + pthread_threadid_np(pthread_self(), &tid); + return tid; +} + +#include + +#define MP_BREAK() __builtin_trap() +#define MP_THREAD_LOCAL __thread +#define MP_STRCASECMP strcasecmp +#define MP_GETCURRENTTHREADID() MicroProfileGetCurrentThreadId() +#define MP_STRCASESTR strcasestr +#define MP_THREAD_LOCAL __thread +#define MP_NOINLINE __attribute__((noinline)) + +void* MicroProfileAllocAligned(size_t nSize, size_t nAlign) +{ + void* p; + int result = posix_memalign(&p, nAlign, nSize); + if(result != 0) + { + return nullptr; + } + return p; +} + +void MicroProfileFreeAligned(void* pMem) +{ + free(pMem); +} + +#elif defined(_WIN32) +#include +#include +#include +int64_t MicroProfileGetTick(); +#define MP_TICK() MicroProfileGetTick() +#define MP_BREAK() __debugbreak() +#define MP_THREAD_LOCAL __declspec(thread) +#define MP_STRCASECMP _stricmp +#define MP_GETCURRENTTHREADID() GetCurrentThreadId() +#define MP_STRCASESTR StrStrI +#define MP_THREAD_LOCAL __declspec(thread) +#define MP_NOINLINE __declspec(noinline) + +#ifndef MICROPROFILE_WIN32_TRAP_ALLOCATOR +#define MICROPROFILE_WIN32_TRAP_ALLOCATOR 0 +#endif + +#if MICROPROFILE_WIN32_TRAP_ALLOCATOR +// minimal trap allocator +#define PAGE_SIZE (4096) +void* MicroProfileAllocAligned(size_t nSize, size_t nAlign) +{ + (void)nAlign; + size_t nAlignedSize = (nSize + PAGE_SIZE - 1) & (~(PAGE_SIZE - 1)); + size_t nDelta = nAlignedSize - nSize; + size_t nFullSize = nAlignedSize + 2 * PAGE_SIZE; + + void* ptr = VirtualAlloc(0, nFullSize, MEM_RESERVE, PAGE_READWRITE); + intptr_t intptr = (intptr_t)ptr; + + void* pResult = VirtualAlloc((void*)(intptr + PAGE_SIZE), nAlignedSize, MEM_COMMIT, PAGE_READWRITE); + memset(pResult, 0xf0, nAlignedSize); + + intptr_t page = (intptr_t)pResult; + //((char*)page)[-1] = 0x70; //trap test + page += nDelta; + pResult = (void*)page; + memset(pResult, 0xfe, nSize); + //((char*)page)[nSize] = 0x70; //trap test + return (void*)page; +} + +void MicroProfileFreeAligned(void* pMem) +{ + intptr_t intptr = (intptr_t)pMem; + intptr = (intptr & (~(PAGE_SIZE - 1))) - PAGE_SIZE; + VirtualFree(pMem, 0, MEM_RELEASE); +} +#else +void* MicroProfileAllocAligned(size_t nSize, size_t nAlign) +{ + return _aligned_malloc(nSize, nAlign); +} + +void MicroProfileFreeAligned(void* pMem) +{ + _aligned_free(pMem); +} +#endif + +#else + +#ifndef MICROPROFILE_CUSTOM_PLATFORM +#include +#include +#include +#include +#include + +inline int64_t MicroProfileTicksPerSecondCpu_() +{ + return 1000000000ll; +} + +int64_t MicroProfileTicksPerSecondCpu() +{ + return MicroProfileTicksPerSecondCpu_(); +} +#define MicroProfileTicksPerSecondCpu MicroProfileTicksPerSecondCpu_ + +inline int64_t MicroProfileGetTick() +{ + timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return 1000000000ll * ts.tv_sec + ts.tv_nsec; +} +#define MP_TICK() MicroProfileGetTick() +#define MP_BREAK() __builtin_trap() +#define MP_THREAD_LOCAL __thread +#define MP_STRCASECMP strcasecmp +#define MP_GETCURRENTTHREADID() (uint64_t) pthread_self() +#define MP_STRCASESTR strcasestr +#define MP_THREAD_LOCAL __thread +#define MP_NOINLINE __attribute__((noinline)) + +void* MicroProfileAllocAligned(size_t nSize, size_t nAlign) +{ +#if defined(__linux__) + void* p; + int result = posix_memalign(&p, nAlign, nSize); + if(result != 0) + { + return nullptr; + } + return p; +#else + return memalign(nAlign, nSize); +#endif +} +void MicroProfileFreeAligned(void* pMem) +{ + free(pMem); +} +#endif + +#endif + +#ifdef MICROPROFILE_PS4 +#define MICROPROFILE_PS4_DECL +#include "microprofile_ps4.h" +#endif + +#ifdef MICROPROFILE_XBOXONE +#define MICROPROFILE_XBOXONE_DECL +#include "microprofile_xboxone.h" +#else +#ifdef _WIN32 +#include +#endif +#endif + +#ifdef _WIN32 +typedef uint32_t MicroProfileThreadIdType; +#else +#ifdef MICROPROFILE_THREADID_SIZE_4BYTE +typedef uint32_t MicroProfileThreadIdType; +#elif MICROPROFILE_THREADID_SIZE_8BYTE +typedef uint64_t MicroProfileThreadIdType; +#else +typedef uint64_t MicroProfileThreadIdType; +#endif +#endif + +#define MP_ASSERT(a) \ + do \ + { \ + if(!(a)) \ + { \ + MP_BREAK(); \ + } \ + } while(0) + +#ifdef _WIN32 +#include +typedef UINT_PTR MpSocket; +#else +typedef int MpSocket; +#endif + +#ifndef _WIN32 +typedef pthread_t MicroProfileThread; +#elif defined(_WIN32) +#if _MSC_VER == 1900 +typedef void* HANDLE; +#endif + +typedef HANDLE MicroProfileThread; +#else +typedef std::thread* MicroProfileThread; +#endif + +#if MICROPROFILE_DYNAMIC_INSTRUMENT +struct MicroProfileSymbolDesc; + +#define MICROPROFILE_SUSPEND_MAX (4 << 10) +struct MicroProfileSuspendState +{ + uint32_t SuspendCounter = 0; + uint32_t NumSuspended = 0; +#ifdef _WIN32 + HANDLE Suspended[MICROPROFILE_SUSPEND_MAX]; + intptr_t SuspendedIP[MICROPROFILE_SUSPEND_MAX]; +#endif +}; + +void MicroProfileSymbolQueryFunctions(MpSocket Connection, const char* pFilter); +bool MicroProfileInstrumentFunction(void* pFunction, const char* pModuleName, const char* pFunctionName, uint32_t nColor); +bool MicroProfileSymbolInitialize(bool bStartLoad, const char* pModuleName = 0); +MicroProfileSymbolDesc* MicroProfileSymbolFindFuction(void* pAddress); +void MicroProfileInstrumentFunctionsCalled(void* pFunction, const char* pModuleName, const char* pFunctionName, int nMinBytes, int nMaxCalls); +void MicroProfileSymbolQuerySendResult(MpSocket Connection); +void MicroProfileSymbolSendFunctionNames(MpSocket Connection); +void MicroProfileSymbolSendErrors(MpSocket Connection); +const char* MicroProfileSymbolModuleGetString(uint32_t nIndex); +void MicroProfileInstrumentWithoutSymbols(const char** pModules, const char** pSymbols, uint32_t nNumSymbols); +void MicroProfileSymbolUpdateModuleList(); +bool MicroProfileSymInit(); +void MicroProfileSymCleanup(); +#endif + +struct MicroProfileFunctionQuery; + +// hash table functions & declarations +struct MicroProfileHashTable; +struct MicroProfileHashTableIterator; +typedef bool (*MicroProfileHashCompareFunction)(uint64_t l, uint64_t r); +typedef uint64_t (*MicroProfileHashFunction)(uint64_t p); +uint64_t MicroProfileHashTableHashString(uint64_t pString); +bool MicroProfileHashTableCompareString(uint64_t L, uint64_t R); +uint64_t MicroProfileHashTableHashPtr(uint64_t pString); +bool MicroProfileHashTableComparePtr(uint64_t L, uint64_t R); +void MicroProfileHashTableInit(MicroProfileHashTable* pTable, uint32_t nInitialSize, uint32_t nSearchLimit, MicroProfileHashCompareFunction CompareFunc, MicroProfileHashFunction HashFunc); +void MicroProfileHashTableDestroy(MicroProfileHashTable* pTable); +uint64_t MicroProfileHashTableHash(MicroProfileHashTable* pTable, uint64_t K); +bool MicroProfileHashTableSet(MicroProfileHashTable* pTable, uint64_t Key, uintptr_t Value); +MicroProfileHashTableIterator MicroProfileGetHashTableIteratorBegin(MicroProfileHashTable* HashTable); +MicroProfileHashTableIterator MicroProfileGetHashTableIteratorEnd(MicroProfileHashTable* HashTable); + +template +struct MicroProfileArray +{ + T* Data = nullptr; + uint32_t Size = 0; + uint32_t Capacity = 0; + T& operator[](const uint32_t Index); + const T& operator[](const uint32_t Index) const; + T* begin(); + T* end(); +}; + +template +void MicroProfileArrayInit(MicroProfileArray& Array, uint32_t InitialCapacity); +template +void MicroProfileArrayDestroy(MicroProfileArray& Array, uint32_t InitialCapacity); +template +void MicroProfileArrayClear(MicroProfileArray& Array); +template +void MicroProfileArrayPushBack(MicroProfileArray& Array, const T& v); + +struct MicroProfileTimer +{ + uint64_t nTicks; + uint32_t nCount; +}; + +struct MicroProfileCategory +{ + char pName[MICROPROFILE_NAME_MAX_LEN]; + uint32_t nGroupMask[MICROPROFILE_MAX_GROUP_INTS]; +}; + +struct MicroProfileGroupInfo +{ + char pName[MICROPROFILE_NAME_MAX_LEN]; + uint32_t nNameLen; + uint32_t nGroupIndex; + uint32_t nNumTimers; + uint32_t nMaxTimerNameLen; + uint32_t nColor; + uint32_t nCategory; + MicroProfileTokenType Type; + int nWSNext; +}; + +struct MicroProfileTimerInfo +{ + MicroProfileToken nToken; + uint32_t nTimerIndex; + uint32_t nGroupIndex; + char pName[MICROPROFILE_NAME_MAX_LEN]; + char pNameExt[MICROPROFILE_NAME_MAX_LEN]; + uint32_t nNameLen; + uint32_t nColor; + int nWSNext; + bool bGraph; + MicroProfileTokenType Type; + uint32_t Flags; +}; + +struct MicroProfileCounterInfo +{ + int nParent; + int nSibling; + int nFirstChild; + uint16_t nNameLen; + uint8_t nLevel; + const char* pName; + uint32_t nFlags; + int64_t nLimit; + double dLimit; + int nWSNext; + MicroProfileCounterFormat eFormat; + std::atomic ExternalAtomic; +}; + +struct MicroProfileCounterHistory +{ + uint32_t nPut; + uint64_t nHistory[MICROPROFILE_GRAPH_HISTORY]; +}; + +struct MicroProfileCounterSource +{ + void* pSource; + uint32_t nSourceSize; +}; + +struct MicroProfileGraphState +{ + int64_t nHistory[MICROPROFILE_GRAPH_HISTORY]; + MicroProfileToken nToken; + int32_t nKey; +}; + +struct MicroProfileContextSwitch +{ + MicroProfileThreadIdType nThreadOut; + MicroProfileThreadIdType nThreadIn; + int64_t nCpu : 8; + int64_t nTicks : 56; +}; + +struct MicroProfileFrameState +{ + uint64_t nFrameStartCpu; + uint64_t nFrameStartGpu; + uint64_t nFrameId; + uint32_t nGpuPending; + uint32_t nLogStart[MICROPROFILE_MAX_THREADS]; + uint32_t nLogStartTimeline; + uint32_t nTimelineFrameMax; + int32_t nHistoryTimeline; +}; + +// All frame counter data stored. Used to store the time for all counters/groups for every frame. +// Must be enabled with MicroProfileEnableFrameCounterExtraData() +// Will allocate sizeof(MicroProfileFrameExtraCounterData) * MICROPROFILE_MAX_FRAME_HISTORY bytes +struct MicroProfileFrameExtraCounterData +{ + uint16_t NumTimers; + uint16_t NumGroups; + uint64_t Timers[MICROPROFILE_MAX_TIMERS]; + uint64_t Groups[MICROPROFILE_MAX_GROUPS]; +}; + +struct MicroProfileCsvConfig +{ + enum CsvConfigState + { + INACTIVE = 0, + CONFIG, + ACTIVE, + }; + CsvConfigState State; + uint32_t NumTimers; + uint32_t NumGroups; + uint32_t NumCounters; + uint32_t MaxTimers; + uint32_t MaxGroups; + uint32_t MaxCounters; + uint32_t TotalElements; + uint16_t* TimerIndices; + uint16_t* GroupIndices; + uint16_t* CounterIndices; + uint64_t* FrameData; + const char** pTimerNames; + const char** pGroupNames; + const char** pCounterNames; + uint32_t Flags; +}; + +#ifdef _WIN32 +#pragma warning(push) +#pragma warning(disable : 4200) // zero-sized struct +#pragma warning(disable : 4201) // nameless struct/union +#pragma warning(disable : 4244) // possible loss of data +#pragma warning(disable : 4100) // unreferenced formal parameter +#pragma warning(disable : 4091) +#pragma warning(disable : 4189) // local variable is initialized but not referenced. (for defer local variables) +#pragma warning(disable : 4456) +#pragma warning(disable : 4702) +#endif + +struct MicroProfileStringBlock +{ + enum + { + DEFAULT_SIZE = 8192, + }; + MicroProfileStringBlock* pNext; + uint32_t nUsed; + uint32_t nSize; + char Memory[]; +}; + +struct MicroProfileHashTableEntry +{ + uint64_t Key; + uint64_t Hash; + uintptr_t Value; +}; + +struct MicroProfileHashTable +{ + MicroProfileHashTableEntry* pEntries; + uint32_t nUsed; + uint32_t nAllocated; + uint32_t nSearchLimit; + uint32_t nLim; + MicroProfileHashCompareFunction CompareFunc; + MicroProfileHashFunction HashFunc; +}; + +struct MicroProfileHashTableIterator +{ + MicroProfileHashTableIterator(uint32_t nIndex, MicroProfileHashTable* pTable) + : nIndex(nIndex) + , pTable(pTable) + { + } + MicroProfileHashTableIterator(const MicroProfileHashTableIterator& other) + : nIndex(other.nIndex) + , pTable(other.pTable) + { + } + + uint32_t nIndex; + MicroProfileHashTable* pTable; + + void AssertValid() + { + MP_ASSERT(nIndex < pTable->nAllocated); + } + + MicroProfileHashTableEntry& operator*() + { + AssertValid(); + return pTable->pEntries[nIndex]; + } + MicroProfileHashTableEntry* operator->() + { + AssertValid(); + return &pTable->pEntries[nIndex]; + } + bool operator==(const MicroProfileHashTableIterator& rhs) + { + return nIndex == rhs.nIndex && pTable == rhs.pTable; + } + bool operator!=(const MicroProfileHashTableIterator& rhs) + { + return nIndex != rhs.nIndex || pTable != rhs.pTable; + } + + void SkipInvalid() + { + while(nIndex < pTable->nAllocated && pTable->pEntries[nIndex].Hash == 0) + nIndex++; + } + MicroProfileHashTableIterator operator++() + { + AssertValid(); + nIndex++; + SkipInvalid(); + return *this; + } + MicroProfileHashTableIterator operator++(int) + { + MicroProfileHashTableIterator tmp = *this; + ++(*this); + return tmp; + } +}; + +struct MicroProfileStrings +{ + MicroProfileHashTable HashTable; + MicroProfileStringBlock* pFirst; + MicroProfileStringBlock* pLast; +}; + +struct MicroProfileThreadLog +{ + + std::atomic nPut; + std::atomic nGet; + + MicroProfileLogEntry Log[MICROPROFILE_BUFFER_SIZE]; + + uint32_t nStackPut; + uint32_t nStackScope; +#ifdef MICROPROFILE_VERIFY_BALANCED + uint64_t VerifyStack[MICROPROFILE_STACK_MAX]; +#endif + MicroProfileScopeStateC ScopeState[MICROPROFILE_STACK_MAX]; + + uint32_t nActive; + uint32_t nGpu; + MicroProfileThreadIdType nThreadId; + uint32_t nLogIndex; + uint32_t nCustomId; + uint32_t nIdleFrames; + + MicroProfileLogEntry nStackLogEntry[MICROPROFILE_STACK_MAX]; + uint64_t nChildTickStack[MICROPROFILE_STACK_MAX + 1]; + int32_t nStackPos; + + uint8_t nGroupStackPos[MICROPROFILE_MAX_GROUPS]; + uint64_t nGroupTicks[MICROPROFILE_MAX_GROUPS]; + uint64_t nAggregateGroupTicks[MICROPROFILE_MAX_GROUPS]; + enum + { + THREAD_MAX_LEN = 64, + }; + char ThreadName[64]; + int nFreeListNext; +}; + +struct MicroProfileWebSocketBuffer +{ + char* pBufferAllocation; + char* pBuffer; + uint32_t nBufferSize; + uint32_t nPut; + MpSocket Socket; + + char SendBuffer[MICROPROFILE_WEBSOCKET_BUFFER_SIZE]; + std::atomic nSendPut; + std::atomic nSendGet; +}; + +typedef void (*MicroProfileHookFunc)(int x); + +struct MicroProfilePatchError +{ + unsigned char Code[32]; + char Message[256]; + int AlreadyInstrumented; + int nCodeSize; +}; + +// linear, per-frame per-thread gpu log +struct MicroProfileThreadLogGpu +{ + MicroProfileLogEntry Log[MICROPROFILE_GPU_BUFFER_SIZE]; + uint32_t nPut; + uint32_t nStart; + uint32_t nId; + void* pContext; + uint32_t nAllocated; + + uint32_t nStackScope; + MicroProfileScopeStateC ScopeState[MICROPROFILE_STACK_MAX]; +}; + +#if MICROPROFILE_GPU_TIMERS +static MicroProfileGpuInsertTimeStamp_CB MicroProfileGpuInsertTimeStamp_Callback = 0; +static MicroProfileGpuGetTimeStamp_CB MicroProfileGpuGetTimeStamp_Callback = 0; +static MicroProfileTicksPerSecondGpu_CB MicroProfileTicksPerSecondGpu_Callback = 0; +static MicroProfileGetGpuTickReference_CB MicroProfileGetGpuTickReference_Callback = 0; +static MicroProfileGpuFlip_CB MicroProfileGpuFlip_Callback = 0; +static MicroProfileGpuShutdown_CB MicroProfileGpuShutdown_Callback = 0; + +uint32_t MicroProfileGpuInsertTimeStamp(void* pContext) +{ + return MicroProfileGpuInsertTimeStamp_Callback ? MicroProfileGpuInsertTimeStamp_Callback(pContext) : 0; +} +uint64_t MicroProfileGpuGetTimeStamp(uint32_t nKey) +{ + return MicroProfileGpuGetTimeStamp_Callback ? MicroProfileGpuGetTimeStamp_Callback(nKey) : 1; +} +uint64_t MicroProfileTicksPerSecondGpu() +{ + return MicroProfileTicksPerSecondGpu_Callback ? MicroProfileTicksPerSecondGpu_Callback() : 1; +} +int MicroProfileGetGpuTickReference(int64_t* pOutCPU, int64_t* pOutGpu) +{ + return MicroProfileGetGpuTickReference_Callback ? MicroProfileGetGpuTickReference_Callback(pOutCPU, pOutGpu) : 0; +} +uint32_t MicroProfileGpuFlip(void* p) +{ + return MicroProfileGpuFlip_Callback ? MicroProfileGpuFlip_Callback(p) : 0; +} +void MicroProfileGpuShutdown() +{ + if(MicroProfileGpuShutdown_Callback) + MicroProfileGpuShutdown_Callback(); +} + +#endif + +#if MICROPROFILE_GPU_TIMERS_D3D11 +//:'######:::'########::'##::::'##::::'########:::'#######::'########:::::'##::::::'##::: +//'##... ##:: ##.... ##: ##:::: ##:::: ##.... ##:'##.... ##: ##.... ##::'####::::'####::: +// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::: ##:..::::: ##: ##:::: ##::.. ##::::.. ##::: +// ##::'####: ########:: ##:::: ##:::: ##:::: ##::'#######:: ##:::: ##:::: ##:::::: ##::: +// ##::: ##:: ##.....::: ##:::: ##:::: ##:::: ##::...... ##: ##:::: ##:::: ##:::::: ##::: +// ##::: ##:: ##:::::::: ##:::: ##:::: ##:::: ##:'##:::: ##: ##:::: ##:::: ##:::::: ##::: +//. ######::: ##::::::::. #######::::: ########::. #######:: ########:::'######::'######: +//:......::::..::::::::::.......::::::........::::.......:::........::::......:::......:: + +struct MicroProfileD3D11Frame +{ + uint32_t m_nQueryStart; + uint32_t m_nQueryCountMax; + std::atomic m_nQueryCount; + uint32_t m_nRateQueryStarted; + void* m_pRateQuery; +}; + +struct MicroProfileGpuTimerStateD3D11 : public MicroProfileGpuTimerState +{ + uint32_t bInitialized; + void* m_pDevice; + void* m_pImmediateContext; + void* m_pQueries[MICROPROFILE_D3D11_MAX_QUERIES]; + int64_t m_nQueryResults[MICROPROFILE_D3D11_MAX_QUERIES]; + + uint32_t m_nQueryPut; + uint32_t m_nQueryGet; + uint32_t m_nQueryFrame; + int64_t m_nQueryFrequency; + void* pSyncQuery; + + MicroProfileD3D11Frame m_QueryFrames[MICROPROFILE_GPU_FRAME_DELAY]; +}; + +uint32_t MicroProfileGpuInsertTimeStampD3D11(void* pContext_); +uint64_t MicroProfileGpuGetTimeStampD3D11(uint32_t nIndex); +bool MicroProfileGpuGetDataD3D11(void* pQuery, void* pData, uint32_t nDataSize); +uint64_t MicroProfileTicksPerSecondGpuD3D11(); +uint32_t MicroProfileGpuFlipD3D11(void* pDeviceContext_); +void MicroProfileGpuInitD3D11(void* pDevice_, void* pImmediateContext); +void MicroProfileGpuShutdownD3D11(); +int MicroProfileGetGpuTickReferenceD3D11(int64_t* pOutCPU, int64_t* pOutGpu); +MicroProfileGpuTimerStateD3D11* MicroProfileGetGpuTimerStateD3D11(); +#endif + +#if MICROPROFILE_GPU_TIMERS_D3D12 +//:'######:::'########::'##::::'##::::'########:::'#######::'########:::::'##::::'#######:: +//'##... ##:: ##.... ##: ##:::: ##:::: ##.... ##:'##.... ##: ##.... ##::'####:::'##.... ##: +// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::: ##:..::::: ##: ##:::: ##::.. ##:::..::::: ##: +// ##::'####: ########:: ##:::: ##:::: ##:::: ##::'#######:: ##:::: ##:::: ##::::'#######:: +// ##::: ##:: ##.....::: ##:::: ##:::: ##:::: ##::...... ##: ##:::: ##:::: ##:::'##:::::::: +// ##::: ##:: ##:::::::: ##:::: ##:::: ##:::: ##:'##:::: ##: ##:::: ##:::: ##::: ##:::::::: +//. ######::: ##::::::::. #######::::: ########::. #######:: ########:::'######: #########: +//:......::::..::::::::::.......::::::........::::.......:::........::::......::.........:: + +#include + +#ifndef MICROPROFILE_D3D12_MAX_QUERIES +#define MICROPROFILE_D3D12_MAX_QUERIES (32 << 10) +#endif + +#define MICROPROFILE_D3D_MAX_NODE_COUNT 4 +#define MICROPROFILE_D3D_INTERNAL_DELAY 8 + +#define MP_NODE_MASK_ALL(n) ((1u << (n)) - 1u) +#define MP_NODE_MASK_ONE(n) (1u << (n)) + +struct MicroProfileGpuTimerStateD3D12; + +int MicroProfileGetGpuTickReferenceD3D12(int64_t* pOutCPU, int64_t* pOutGpu); +uint32_t MicroProfileGpuInsertTimeStampD3D12(void* pContext); +uint64_t MicroProfileGpuGetTimeStampD3D12(uint32_t nIndex); +uint64_t MicroProfileTicksPerSecondGpuD3D12(); +uint32_t MicroProfileGpuFlipD3D12(void* pContext); +void MicroProfileGpuInitD3D12(void* pDevice_, uint32_t nNodeCount, void** pCommandQueues_, void** pCommandQueuesCopy_); +void MicroProfileGpuShutdownD3D12(); +void MicroProfileSetCurrentNodeD3D12(uint32_t nNode); +int MicroProfileGetGpuTickReferenceD3D12(int64_t* pOutCPU, int64_t* pOutGpu); +MicroProfileGpuTimerStateD3D12* MicroProfileGetGpuTimerStateD3D12(); + +struct MicroProfileFrameD3D12 +{ + uint32_t nTimeStampBegin; + uint32_t nTimeStampCount; + uint32_t nTimeStampBeginCopyQueue; + uint32_t nTimeStampCountCopyQueue; + uint32_t nNode; + ID3D12GraphicsCommandList* pCommandList[MICROPROFILE_D3D_MAX_NODE_COUNT]; + ID3D12GraphicsCommandList* pCommandListCopy[MICROPROFILE_D3D_MAX_NODE_COUNT]; + ID3D12CommandAllocator* pCommandAllocator; + ID3D12CommandAllocator* pCommandAllocatorCopy; +}; + +struct MicroProfileGpuTimerStateD3D12 : public MicroProfileGpuTimerState +{ + ID3D12Device* pDevice; + uint32_t nNodeCount; + uint32_t nCurrentNode; + + uint64_t nFrame; + uint64_t nPendingFrame; + + uint32_t nFrameStartTimeStamps; + uint32_t nFrameStartCopyQueueTimeStamps; + std::atomic nFrameCountTimeStamps; + std::atomic nFrameCountCopyQueueTimeStamps; + + int64_t nFrequency; + ID3D12Resource* pBuffer; + ID3D12Resource* pBufferCopy; + + struct + { + ID3D12CommandQueue* pCommandQueue; + ID3D12CommandQueue* pCommandQueueCopy; + ID3D12QueryHeap* pHeap; + ID3D12QueryHeap* pCopyQueueHeap; + ID3D12Fence* pFence; + ID3D12Fence* pFenceCopy; + } NodeState[MICROPROFILE_D3D_MAX_NODE_COUNT]; + + uint16_t nQueryFrames[MICROPROFILE_D3D12_MAX_QUERIES]; + int64_t nResults[MICROPROFILE_D3D12_MAX_QUERIES]; + uint16_t nQueryFramesCopy[MICROPROFILE_D3D12_MAX_QUERIES]; + int64_t nResultsCopy[MICROPROFILE_D3D12_MAX_QUERIES]; + + MicroProfileFrameD3D12 Frames[MICROPROFILE_D3D_INTERNAL_DELAY]; +}; +#endif + +#if MICROPROFILE_GPU_TIMERS_GL +//:'######:::'########::'##::::'##:::::'######:::'##::::::: +//'##... ##:: ##.... ##: ##:::: ##::::'##... ##:: ##::::::: +// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::..::: ##::::::: +// ##::'####: ########:: ##:::: ##:::: ##::'####: ##::::::: +// ##::: ##:: ##.....::: ##:::: ##:::: ##::: ##:: ##::::::: +// ##::: ##:: ##:::::::: ##:::: ##:::: ##::: ##:: ##::::::: +//. ######::: ##::::::::. #######:::::. ######::: ########: +//:......::::..::::::::::.......:::::::......::::........:: +struct MicroProfileGpuTimerStateGL : public MicroProfileGpuTimerState +{ + uint32_t GLTimers[MICROPROFILE_GL_MAX_QUERIES]; + uint32_t GLTimerPos; +}; + +MicroProfileGpuTimerStateGL* MicroProfileGetGpuTimerStateGL(); +uint32_t MicroProfileGpuInsertTimeStampGL(void* pContext); +uint64_t MicroProfileGpuGetTimeStampGL(uint32_t nKey); +uint64_t MicroProfileTicksPerSecondGpuGL(); +int MicroProfileGetGpuTickReferenceGL(int64_t* pOutCpu, int64_t* pOutGpu); +uint32_t MicroProfileGpuFlipGL(void* pContext); +void MicroProfileGpuShutdownGL(); +#endif + +#if MICROPROFILE_GPU_TIMERS_VULKAN + +//:'######:::'########::'##::::'##::::'##::::'##:'##::::'##:'##:::::::'##:::'##::::'###::::'##::: ##: +//'##... ##:: ##.... ##: ##:::: ##:::: ##:::: ##: ##:::: ##: ##::::::: ##::'##::::'## ##::: ###:: ##: +// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::: ##: ##:::: ##: ##::::::: ##:'##::::'##:. ##:: ####: ##: +// ##::'####: ########:: ##:::: ##:::: ##:::: ##: ##:::: ##: ##::::::: #####::::'##:::. ##: ## ## ##: +// ##::: ##:: ##.....::: ##:::: ##::::. ##:: ##:: ##:::: ##: ##::::::: ##. ##::: #########: ##. ####: +// ##::: ##:: ##:::::::: ##:::: ##:::::. ## ##::: ##:::: ##: ##::::::: ##:. ##:: ##.... ##: ##:. ###: +//. ######::: ##::::::::. #######:::::::. ###::::. #######:: ########: ##::. ##: ##:::: ##: ##::. ##: +//:......::::..::::::::::.......:::::::::...::::::.......:::........::..::::..::..:::::..::..::::..:: + +struct MicroProfileGpuTimerStateVulkan; +MicroProfileGpuTimerStateVulkan* MicroProfileGetGpuTimerStateVulkan(); +uint32_t MicroProfileGpuInsertTimeStampVulkan(void* pContext); +uint64_t MicroProfileGpuGetTimeStampVulkan(uint32_t nKey); +uint64_t MicroProfileTicksPerSecondGpuVulkan(); +int MicroProfileGetGpuTickReferenceVulkan(int64_t* pOutCpu, int64_t* pOutGpu); +uint32_t MicroProfileGpuFlipVulkan(void* pContext); +void MicroProfileGpuShutdownVulkan(); +#endif + +struct MicroProfileSymbolState +{ + std::atomic nModuleLoadsFinished; + std::atomic nModuleLoadsRequested; + std::atomic nSymbolsLoaded; +}; + +struct MicroProfileSymbolModuleRegion +{ + intptr_t nBegin; + intptr_t nEnd; +}; +struct MicroProfileSymbolModule +{ + uint64_t nModuleBase; + uint32_t nMatchOffset; + uint32_t nStringOffset; + const char* pBaseString; + const char* pTrimmedString; + MicroProfileSymbolModuleRegion Regions[MICROPROFILE_MAX_MODULE_EXEC_REGIONS]; + int nNumExecutableRegions; + + bool bDownloading; + intptr_t nProgress; + intptr_t nProgressTarget; + struct MicroProfileSymbolBlock* pSymbolBlock; + MicroProfileHashTable AddressToSymbol; + + int64_t nSymbols; + std::atomic nSymbolsLoaded; + std::atomic nModuleLoadRequested; + std::atomic nModuleLoadFinished; +}; + +struct MicroProfileInstrumentMemoryRegion +{ + intptr_t Start; + intptr_t Size; + uint32_t Protect; +}; + +struct MicroProfile +{ + uint32_t nTotalTimers; + uint32_t nGroupCount; + uint32_t nCategoryCount; + uint32_t nAggregateClear; + uint32_t nAggregateFlip; + uint32_t nAggregateFlipCount; + uint32_t nAggregateFrames; + + uint64_t nFlipStartTick; + uint64_t nAggregateFlipTick; + + uint32_t nDisplay; + uint32_t nBars; + uint32_t nActiveGroups[MICROPROFILE_MAX_GROUP_INTS]; + bool AnyActive; + uint32_t nFrozen; + uint32_t nWasFrozen; + uint32_t nPlatformMarkersEnabled; + + uint32_t nForceEnable; + + uint32_t nForceGroups[MICROPROFILE_MAX_GROUP_INTS]; + uint32_t nActiveGroupsWanted[MICROPROFILE_MAX_GROUP_INTS]; + uint32_t nGroupMask[MICROPROFILE_MAX_GROUP_INTS]; + + uint32_t nStartEnabled; + uint32_t nAllThreadsWanted; + + uint32_t nOverflow; + + uint32_t nMaxGroupSize; + uint32_t nDumpFileNextFrame; + uint32_t nDumpFileCountDown; + uint32_t nDumpSpikeMask; + uint32_t nAutoClearFrames; + + float fDumpCpuSpike; + float fDumpGpuSpike; + char HtmlDumpPath[512]; + char CsvDumpPath[512]; + uint32_t DumpFrameCount; + + int64_t nPauseTicks; + std::atomic nContextSwitchStalledTick; + int64_t nContextSwitchLastPushed; + int64_t nContextSwitchLastIndexPushed; + + float fReferenceTime; + float fRcpReferenceTime; + + MicroProfileCategory CategoryInfo[MICROPROFILE_MAX_CATEGORIES]; + MicroProfileGroupInfo GroupInfo[MICROPROFILE_MAX_GROUPS]; + MicroProfileTimerInfo TimerInfo[MICROPROFILE_MAX_TIMERS]; + uint32_t TimerToGroup[MICROPROFILE_MAX_TIMERS]; + + MicroProfileTimer AccumTimers[MICROPROFILE_MAX_TIMERS]; + uint64_t AccumMaxTimers[MICROPROFILE_MAX_TIMERS]; + uint64_t AccumMinTimers[MICROPROFILE_MAX_TIMERS]; + uint64_t AccumTimersExclusive[MICROPROFILE_MAX_TIMERS]; + uint64_t AccumMaxTimersExclusive[MICROPROFILE_MAX_TIMERS]; + + MicroProfileTimer Frame[MICROPROFILE_MAX_TIMERS]; + uint64_t FrameExclusive[MICROPROFILE_MAX_TIMERS]; + + MicroProfileTimer Aggregate[MICROPROFILE_MAX_TIMERS]; + uint64_t AggregateMax[MICROPROFILE_MAX_TIMERS]; + uint64_t AggregateMin[MICROPROFILE_MAX_TIMERS]; + uint64_t AggregateExclusive[MICROPROFILE_MAX_TIMERS]; + uint64_t AggregateMaxExclusive[MICROPROFILE_MAX_TIMERS]; + + uint32_t FrameGroupThreadValid[MICROPROFILE_MAX_THREADS / 32 + 1]; + struct GroupTime + { + uint64_t nTicks; + uint64_t nTicksExclusive; + uint32_t nCount; + }; + + GroupTime FrameGroupThread[MICROPROFILE_MAX_THREADS][MICROPROFILE_MAX_GROUPS]; + GroupTime FrameGroup[MICROPROFILE_MAX_GROUPS]; + uint64_t AccumGroup[MICROPROFILE_MAX_GROUPS]; + uint64_t AccumGroupMax[MICROPROFILE_MAX_GROUPS]; + + uint64_t AggregateGroup[MICROPROFILE_MAX_GROUPS]; + uint64_t AggregateGroupMax[MICROPROFILE_MAX_GROUPS]; + + MicroProfileGraphState Graph[MICROPROFILE_MAX_GRAPHS]; + uint32_t nGraphPut; + + uint32_t nThreadActive[MICROPROFILE_MAX_THREADS]; + MicroProfileThreadLog* Pool[MICROPROFILE_MAX_THREADS]; + MicroProfileThreadLogGpu* PoolGpu[MICROPROFILE_MAX_THREADS]; + + MicroProfileThreadLog TimelineLog; + uint32_t TimelineTokenFrameEnter[MICROPROFILE_TIMELINE_MAX_TOKENS]; + uint32_t TimelineTokenFrameLeave[MICROPROFILE_TIMELINE_MAX_TOKENS]; + uint32_t TimelineToken[MICROPROFILE_TIMELINE_MAX_TOKENS]; + const char* TimelineTokenStaticString[MICROPROFILE_TIMELINE_MAX_TOKENS]; + + uint32_t nTimelineFrameMax; + MicroProfileFrameExtraCounterData* FrameExtraCounterData; + MicroProfileCsvConfig CsvConfig; + const char* pSettings; + const char* pSettingsReadOnly; + const char* pSettingsTemp; + + uint32_t nNumLogs; + uint32_t nNumLogsGpu; + uint32_t nMemUsage; + int nFreeListHead; + + uint32_t nFrameCurrent; + uint32_t nFrameCurrentIndex; + uint32_t nFramePut; + uint32_t nFrameNext; + uint64_t nFramePutIndex; + + MicroProfileFrameState Frames[MICROPROFILE_MAX_FRAME_HISTORY]; + + uint64_t nFlipTicks; + uint64_t nFlipAggregate; + uint64_t nFlipMax; + uint64_t nFlipAggregateDisplay; + uint64_t nFlipMaxDisplay; + + MicroProfileThread ContextSwitchThread; + bool bContextSwitchRunning; + bool bContextSwitchStop; + bool bContextSwitchAllThreads; + bool bContextSwitchNoBars; + uint32_t nContextSwitchUsage; + uint32_t nContextSwitchLastPut; + + int64_t nContextSwitchHoverTickIn; + int64_t nContextSwitchHoverTickOut; + uint32_t nContextSwitchHoverThread; + uint32_t nContextSwitchHoverThreadBefore; + uint32_t nContextSwitchHoverThreadAfter; + uint8_t nContextSwitchHoverCpu; + uint8_t nContextSwitchHoverCpuNext; + + uint32_t CoreCount; + uint8_t CoreEfficiencyClass[MICROPROFILE_MAX_CPU_CORES]; + + uint32_t nContextSwitchPut; + MicroProfileContextSwitch ContextSwitch[MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE]; + + MpSocket ListenerSocket; + uint32_t nWebServerPort; + + char WebServerBuffer[MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE]; + uint32_t WebServerPut; + + uint64_t nWebServerDataSent; + + int WebSocketTimers; + int WebSocketCounters; + int WebSocketGroups; + uint32_t nWebSocketDirty; + MpSocket WebSockets[1]; + int64_t WebSocketFrameLast[1]; + uint32_t nNumWebSockets; + uint32_t nSocketFail; // for error propagation. + + MicroProfileThread WebSocketSendThread; + bool WebSocketThreadRunning; + bool WebSocketThreadJoined; + + uint32_t WSCategoriesSent; + uint32_t WSGroupsSent; + uint32_t WSTimersSent; + uint32_t WSCountersSent; + MicroProfileWebSocketBuffer WSBuf; + char* pJsonSettings; + const char* pJsonSettingsName; + bool bJsonSettingsReadOnly; + uint32_t nJsonSettingsPending; + uint32_t nJsonSettingsBufferSize; + uint32_t nWSWasConnected; + uint32_t nMicroProfileShutdown; + uint32_t nWSViewMode; + + char CounterNames[MICROPROFILE_MAX_COUNTER_NAME_CHARS]; + MicroProfileCounterInfo CounterInfo[MICROPROFILE_MAX_COUNTERS]; + MicroProfileCounterSource CounterSource[MICROPROFILE_MAX_COUNTERS]; + uint32_t nNumCounters; + uint32_t nCounterNamePos; + std::atomic Counters[MICROPROFILE_MAX_COUNTERS]; + std::atomic* CountersDouble; +#if MICROPROFILE_COUNTER_HISTORY // uses 1kb per allocated counter. 512kb for default counter count + uint32_t nCounterHistoryPut; + int64_t nCounterHistory[MICROPROFILE_GRAPH_HISTORY][MICROPROFILE_MAX_COUNTERS]; // flipped to make swapping cheap, drawing more expensive. + int64_t nCounterMax[MICROPROFILE_MAX_COUNTERS]; + int64_t nCounterMin[MICROPROFILE_MAX_COUNTERS]; + double* dCounterHistory; + double* dCounterMax; + double* dCounterMin; +#endif + + MicroProfileThread AutoFlipThread; + std::atomic nAutoFlipDelay; + std::atomic nAutoFlipStop; + + MicroProfileStrings Strings; + MicroProfileToken CounterToken_MicroProfile; + MicroProfileToken CounterToken_StringBlock; + MicroProfileToken CounterToken_StringBlock_Count; + MicroProfileToken CounterToken_StringBlock_Waste; + MicroProfileToken CounterToken_StringBlock_Strings; + MicroProfileToken CounterToken_StringBlock_Memory; + + MicroProfileToken CounterToken_Alloc; + MicroProfileToken CounterToken_Alloc_Memory; + MicroProfileToken CounterToken_Alloc_Count; + +#if MICROPROFILE_DYNAMIC_INSTRUMENT + uint32_t DynamicTokenIndex; + MicroProfileToken DynamicTokens[MICROPROFILE_MAX_DYNAMIC_TOKENS]; + void* FunctionsInstrumented[MICROPROFILE_MAX_DYNAMIC_TOKENS]; + const char* FunctionsInstrumentedName[MICROPROFILE_MAX_DYNAMIC_TOKENS]; + const char* FunctionsInstrumentedModuleNames[MICROPROFILE_MAX_DYNAMIC_TOKENS]; + // const char* FunctionsInstrumentedUnmangled[MICROPROFILE_MAX_DYNAMIC_TOKENS]; + uint32_t WSFunctionsInstrumentedSent; + MicroProfileSymbolState SymbolState; + + MicroProfileSymbolModule SymbolModules[MICROPROFILE_INSTRUMENT_MAX_MODULES]; + char SymbolModuleNameBuffer[MICROPROFILE_INSTRUMENT_MAX_MODULE_CHARS]; + int SymbolModuleNameOffset; + int SymbolNumModules; + int WSSymbolModulesSent; + std::atomic nSymbolsDirty; + + MicroProfileFunctionQuery* pPendingQuery; + MicroProfileFunctionQuery* pFinishedQuery; + MicroProfileFunctionQuery* pQueryFreeList; + uint32_t nQueryProcessed; + uint32_t nNumQueryFree; + uint32_t nNumQueryAllocated; + + int SymbolThreadRunning; + int SymbolThreadFinished; + MicroProfileThread SymbolThread; + int nNumPatchErrors; + MicroProfilePatchError PatchErrors[MICROPROFILE_MAX_PATCH_ERRORS]; + int nNumPatchErrorFunctions; + const char* PatchErrorFunctionNames[MICROPROFILE_MAX_PATCH_ERRORS]; + MicroProfileSuspendState SuspendState; + MicroProfileArray MemoryRegions; +#endif + + int GpuQueue; + MicroProfileThreadLogGpu* pGpuGlobal; + MicroProfileGpuTimerState* pGPU; +}; + +inline uint32_t MicroProfileLogGetType(MicroProfileLogEntry Index) +{ + return ((MP_LOG_BEGIN_MASK & Index) >> 62) & 0x3; +} + +inline uint64_t MicroProfileLogGetTimerIndex(MicroProfileLogEntry Index) +{ + return (0x3fff & (Index >> 48)); +} +uint32_t MicroProfileLogGetDataSize(MicroProfileLogEntry Index) +{ + if(MicroProfileLogGetType(Index) == MP_LOG_EXTENDED) + return 0xffff & (Index >> 32); + else + return 0; +} + +inline EMicroProfileTokenExtended MicroProfileLogGetExtendedToken(MicroProfileLogEntry Index) +{ + return (EMicroProfileTokenExtended)(0x3fff & (Index >> 48)); +} + +inline uint32_t MicroProfileLogGetExtendedDataSize(MicroProfileLogEntry Index) +{ + return (uint32_t)(0xffff & (Index >> 32)); +} + +inline uint32_t MicroProfileLogGetExtendedPayload(MicroProfileLogEntry Index) +{ + return (uint32_t)(0xffffffff & Index); +} + +inline uint64_t MicroProfileLogGetExtendedPayloadNoData(MicroProfileLogEntry Index) +{ + return (uint64_t)(MP_LOG_TICK_MASK & Index); +} + +inline void* MicroProfileLogGetExtendedPayloadNoDataPtr(MicroProfileLogEntry Index) +{ + return (void*)(MP_LOG_PAYLOAD_PTR_MASK & Index); +} + +MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfileToken nToken, int64_t nTick); +MicroProfileLogEntry MicroProfileMakeLogExtended(EMicroProfileTokenExtended eTokenExt, uint32_t nDataSizeQWords, uint32_t nPayload); +MicroProfileLogEntry MicroProfileMakeLogExtendedNoData(EMicroProfileTokenExtended eTokenExt, uint64_t nTick); + +inline MicroProfileLogEntry MicroProfileMakeLogIndex(uint64_t nBegin, MicroProfileToken nToken, int64_t nTick) +{ + MicroProfileLogEntry Entry = (nBegin << 62) | ((0x3fff & nToken) << 48) | (MP_LOG_TICK_MASK & nTick); + uint32_t t = MicroProfileLogGetType(Entry); + uint64_t nTimerIndex = MicroProfileLogGetTimerIndex(Entry); + MP_ASSERT(t == nBegin); + MP_ASSERT(nTimerIndex == (nToken & 0x3fff)); + return Entry; +} + +// extended data, with the option to store 0xfffe * 8 bytes after +inline MicroProfileLogEntry MicroProfileMakeLogExtended(EMicroProfileTokenExtended eTokenExt, uint32_t nDataSizeQWords, uint32_t nPayload) +{ + MP_ASSERT(nDataSizeQWords < 0xffff); + MicroProfileLogEntry Entry = (((uint64_t)MP_LOG_EXTENDED) << 62) | ((0x3fff & (uint64_t)eTokenExt) << 48) | ((0xffff & (uint64_t)nDataSizeQWords) << 32) | nPayload; + + MP_ASSERT(MicroProfileLogGetExtendedToken(Entry) == eTokenExt); + MP_ASSERT(MicroProfileLogGetExtendedDataSize(Entry) == nDataSizeQWords); + MP_ASSERT(MicroProfileLogGetExtendedPayload(Entry) == nPayload); + + return Entry; +} +// extended with no data, but instead 48 bits payload +inline MicroProfileLogEntry MicroProfileMakeLogExtendedNoData(EMicroProfileTokenExtended eTokenExt, uint64_t nPayload) +{ + MicroProfileLogEntry Entry = (((uint64_t)MP_LOG_EXTENDED_NO_DATA) << 62) | ((0x3fff & (uint64_t)eTokenExt) << 48) | (MP_LOG_TICK_MASK & nPayload); + + MP_ASSERT(MicroProfileLogGetExtendedToken(Entry) == eTokenExt); + MP_ASSERT(MicroProfileLogGetExtendedPayloadNoData(Entry) == nPayload); + + return Entry; +} + +// extended with no data, but instead 61 bits payload. used to store a pointer. +inline MicroProfileLogEntry MicroProfileMakeLogExtendedNoDataPtr(uint64_t nPayload) +{ + uint64_t hest = ETOKEN_CSTR_PTR; + MicroProfileLogEntry Entry = (((uint64_t)MP_LOG_EXTENDED_NO_DATA) << 62) | (hest << 48) | (MP_LOG_PAYLOAD_PTR_MASK & nPayload); + uint64_t v0 = (MP_LOG_PAYLOAD_PTR_MASK & nPayload); + uint64_t v1 = (uint64_t)MicroProfileLogGetExtendedPayloadNoDataPtr(Entry); + + MP_ASSERT(v0 == v1); + return Entry; +} + +inline uint32_t MicroProfileGetQWordSize(uint32_t nDataSize) +{ + uint32_t nSize = (nDataSize + 7) / 8; + MP_ASSERT(nSize < 0xffff); // won't pack... + return nSize; +} + +namespace +{ +struct MicroProfilePayloadPack +{ + union + { + struct + { +#if MICROPROFILE_BIG_ENDIAN /// NOT implemented. + char h; + char message[7]; +#else + char message[7]; + char h; +#endif + }; + uint64_t LogEntry; + }; +}; +}; // namespace + +inline int64_t MicroProfileLogTickDifference(MicroProfileLogEntry Start, MicroProfileLogEntry End) +{ + int64_t nStart = Start; + int64_t nEnd = End; + int64_t nDifference = ((nEnd << 16) - (nStart << 16)); + return nDifference >> 16; +} +inline int64_t MicroProfileLogTickMax(MicroProfileLogEntry A, MicroProfileLogEntry B) +{ + int64_t Diff = MicroProfileLogTickDifference(A, B); + if(Diff < 0) + { + return A; + } + else + { + return B; + } +} + +inline int64_t MicroProfileLogTickMin(MicroProfileLogEntry A, MicroProfileLogEntry B) +{ + int64_t Diff = MicroProfileLogTickDifference(A, B); + if(Diff < 0) + { + return B; + } + else + { + return A; + } +} +inline int64_t MicroProfileLogTickClamp(uint64_t T, uint64_t min, uint64_t max) +{ + return MicroProfileLogTickMin(MicroProfileLogTickMax(T, min), max); +} + +inline int64_t MicroProfileLogGetTick(MicroProfileLogEntry e) +{ + return MP_LOG_TICK_MASK & e; +} + +inline int64_t MicroProfileLogSetTick(MicroProfileLogEntry e, int64_t nTick) +{ + return (MP_LOG_TICK_MASK & nTick) | (e & ~MP_LOG_TICK_MASK); +} + +inline uint16_t MicroProfileGetTimerIndex(MicroProfileToken t) +{ + return (t & 0xffff); +} +inline uint32_t MicroProfileGetGroupMask(MicroProfileToken t) +{ + return (uint32_t)((t >> 16) & MICROPROFILE_GROUP_MASK_ALL); +} +inline uint32_t MicroProfileGetGroupMaskIndex(MicroProfileToken t) +{ + return (uint32_t)(t >> 48); +} + +inline MicroProfileToken MicroProfileMakeToken(uint32_t nGroupMask, uint16_t nGroupIndex, uint16_t nTimer) +{ + uint64_t token = ((uint64_t)nGroupIndex << 48llu) | ((uint64_t)nGroupMask << 16llu) | nTimer; + if(0 != (token & MP_LOG_CSTR_MASK)) + { + MP_BREAK(); // should never happen + } + return token; +} + +template +T MicroProfileMin(T a, T b) +{ + return a < b ? a : b; +} + +template +T MicroProfileMax(T a, T b) +{ + return a > b ? a : b; +} +template +T MicroProfileClamp(T a, T min_, T max_) +{ + return MicroProfileMin(max_, MicroProfileMax(min_, a)); +} + +inline int64_t MicroProfileMsToTick(float fMs, int64_t nTicksPerSecond) +{ + return (int64_t)(fMs * 0.001f * nTicksPerSecond); +} + +inline float MicroProfileTickToMsMultiplier(int64_t nTicksPerSecond) +{ + return 1000.f / (nTicksPerSecond ? nTicksPerSecond : 1); +} +float MicroProfileTickToMsMultiplierCpu() +{ + return MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()); +} + +float MicroProfileTickToMsMultiplierGpu() +{ + return MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu()); +} +uint16_t MicroProfileGetGroupIndex(MicroProfileToken t) +{ + return (uint16_t)MicroProfileGet()->TimerToGroup[MicroProfileGetTimerIndex(t)]; +} + +uint64_t MicroProfileTick() +{ + return MP_TICK(); +} + +#ifdef _WIN32 +#include +#define fopen microprofile_fopen_helper + +FILE* microprofile_fopen_helper(const char* filename, const char* mode) +{ + FILE* F = 0; + if(0 == fopen_s(&F, filename, mode)) + { + return F; + } + return 0; +} + +int64_t MicroProfileTicksPerSecondCpu() +{ + static int64_t nTicksPerSecond = 0; + if(nTicksPerSecond == 0) + { + QueryPerformanceFrequency((LARGE_INTEGER*)&nTicksPerSecond); + } + return nTicksPerSecond; +} +int64_t MicroProfileGetTick() +{ + int64_t ticks; + QueryPerformanceCounter((LARGE_INTEGER*)&ticks); + return ticks; +} + +#endif + +#if 1 + +typedef void* (*MicroProfileThreadFunc)(void*); + +#ifndef _WIN32 +typedef pthread_t MicroProfileThread; +void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func) +{ + pthread_attr_t Attr; + int r = pthread_attr_init(&Attr); + MP_ASSERT(r == 0); + pthread_create(pThread, &Attr, Func, 0); +} +void MicroProfileThreadJoin(MicroProfileThread* pThread) +{ + int r = pthread_join(*pThread, 0); + MP_ASSERT(r == 0); +} +#elif defined(_WIN32) +typedef HANDLE MicroProfileThread; +DWORD __stdcall ThreadTrampoline(void* pFunc) +{ + MicroProfileThreadFunc F = (MicroProfileThreadFunc)pFunc; + return (uint32_t)(uintptr_t)F(0); +} + +void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func) +{ + *pThread = CreateThread(0, 0, ThreadTrampoline, Func, 0, 0); +} +void MicroProfileThreadJoin(MicroProfileThread* pThread) +{ + WaitForSingleObject(*pThread, INFINITE); + CloseHandle(*pThread); +} +#else +#include +typedef std::thread* MicroProfileThread; +inline void MicroProfileThreadStart(MicroProfileThread* pThread, MicroProfileThreadFunc Func) +{ + *pThread = MP_ALLOC_OBJECT(std::thread); + new(*pThread) std::thread(Func, nullptr); +} +inline void MicroProfileThreadJoin(MicroProfileThread* pThread) +{ + (*pThread)->join(); + (*pThread)->~thread(); + MP_FREE(*pThread); + *pThread = 0; +} +#endif +#endif + +#if MICROPROFILE_WEBSERVER + +#ifdef _WIN32 +#define MP_INVALID_SOCKET(f) (f == INVALID_SOCKET) +#else +#include +#include +#include +#define MP_INVALID_SOCKET(f) (f < 0) +#endif + +void MicroProfileWebServerStart(); +void MicroProfileWebServerStop(); +void MicroProfileWebServerJoin(); +bool MicroProfileWebServerUpdate(); +void MicroProfileDumpToFile(); + +#else + +#define MicroProfileWebServerStart() \ + do \ + { \ + } while(0) +#define MicroProfileWebServerStop() \ + do \ + { \ + } while(0) +#define MicroProfileWebServerJoin() \ + do \ + { \ + } while(0) +#define MicroProfileWebServerUpdate() false +#define MicroProfileDumpToFile() \ + do \ + { \ + } while(0) +#endif + +#include +#include +#include +#include + +#if MICROPROFILE_DEBUG +#ifdef _WIN32 +void uprintf(const char* fmt, ...) +{ + va_list args; + va_start(args, fmt); + char buffer[1024]; + stbsp_vsnprintf(buffer, sizeof(buffer) - 1, fmt, args); + OutputDebugStringA(buffer); + va_end(args); +} +#else +#define uprintf(...) printf(__VA_ARGS__) +#endif +#else +#define uprintf(...) \ + do \ + { \ + sizeof(__VA_ARGS__); \ + } while(0) +#endif + +#define S g_MicroProfile + +MicroProfile g_MicroProfile; +#ifdef MICROPROFILE_IOS +// iOS doesn't support __thread +static pthread_key_t g_MicroProfileThreadLogKey; +static pthread_once_t g_MicroProfileThreadLogKeyOnce = PTHREAD_ONCE_INIT; + +static void MicroProfileCreateThreadLogKey() +{ + pthread_key_create(&g_MicroProfileThreadLogKey, NULL); +} +#else +MP_THREAD_LOCAL MicroProfileThreadLog* g_MicroProfileThreadLogThreadLocal = 0; +#endif +static bool g_bUseLock = false; /// This is used because windows does not support using mutexes under dll init(which is where global initialization is handled) + +MICROPROFILE_DEFINE(g_MicroProfileFlip, "MicroProfile", "MicroProfileFlip", MP_GREEN4); +MICROPROFILE_DEFINE(g_MicroProfileThreadLoop, "MicroProfile", "ThreadLoop", MP_GREEN4); +MICROPROFILE_DEFINE(g_MicroProfileClear, "MicroProfile", "Clear", MP_GREEN4); +MICROPROFILE_DEFINE(g_MicroProfileAccumulate, "MicroProfile", "Accumulate", MP_GREEN4); +MICROPROFILE_DEFINE(g_MicroProfileContextSwitchSearch, "MicroProfile", "ContextSwitchSearch", MP_GREEN4); +MICROPROFILE_DEFINE(g_MicroProfileGpuSubmit, "MicroProfile", "MicroProfileGpuSubmit", MP_HOTPINK2); +MICROPROFILE_DEFINE(g_MicroProfileSendLoop, "MicroProfile", "MicroProfileSocketSendLoop", MP_GREEN4); +MICROPROFILE_DEFINE_LOCAL_ATOMIC_COUNTER(g_MicroProfileBytesPerFlip, "microprofile/bytesperflip"); + +// void MicroProfileHashTableInit(MicroProfileHashTable* pTable, uint32_t nInitialSize, MicroProfileHashCompareFunction CompareFunc, MicroProfileHashFunction HashFunc); +void MicroProfileHashTableDestroy(MicroProfileHashTable* pTable); +uint64_t MicroProfileHashTableHash(MicroProfileHashTable* pTable, uint64_t K); +void MicroProfileHashTableGrow(MicroProfileHashTable* pTable); + +bool MicroProfileHashTableSet(MicroProfileHashTable* pTable, uint64_t Key, uintptr_t Value, uint64_t H, bool bAllowGrow); +bool MicroProfileHashTableGet(MicroProfileHashTable* pTable, uint64_t Key, uintptr_t* pValue); +bool MicroProfileHashTableRemove(MicroProfileHashTable* pTable, uint64_t Key); + +bool MicroProfileHashTableSetString(MicroProfileHashTable* pTable, const char* pKey, const char* pValue); +bool MicroProfileHashTableGetString(MicroProfileHashTable* pTable, const char* pKey, const char** pValue); +bool MicroProfileHashTableRemoveString(MicroProfileHashTable* pTable, const char* pKey); + +bool MicroProfileHashTableSetPtr(MicroProfileHashTable* pTable, const void* pKey, void* pValue); +template +bool MicroProfileHashTableGetPtr(MicroProfileHashTable* pTable, const void* pKey, T** pValue = nullptr); +bool MicroProfileHashTableRemovePtr(MicroProfileHashTable* pTable, const void* pKey); + +enum +{ + ESTRINGINTERN_LOWERCASE = 1, + ESTRINGINTERN_FORCEFORWARDSLASH = 0x2, +}; +const char* MicroProfileStringIntern(const char* pStr); +const char* MicroProfileStringInternLower(const char* pStr); +const char* MicroProfileStringInternSlash(const char* pStr); +const char* MicroProfileStringIntern(const char* pStr, uint32_t nLen, uint32_t nInternalFlags = 0); + +void MicroProfileStringsInit(MicroProfileStrings* pStrings); +void MicroProfileStringsDestroy(MicroProfileStrings* pStrings); + +MicroProfileToken MicroProfileCounterTokenInit(int nParent, uint32_t nFlags); +void MicroProfileCounterTokenInitName(MicroProfileToken nToken, const char* pName); +void MicroProfileCounterConfigToken(MicroProfileToken, uint32_t eFormat, int64_t nLimit, uint32_t nFlags); +uint16_t MicroProfileFindGroup(const char* pGroup); + +inline std::recursive_mutex& MicroProfileMutex() +{ + static std::recursive_mutex Mutex; + return Mutex; +} +std::recursive_mutex& MicroProfileGetMutex() +{ + return MicroProfileMutex(); +} + +inline std::recursive_mutex& MicroProfileTimelineMutex() +{ + static std::recursive_mutex Mutex; + return Mutex; +} +MICROPROFILE_API MicroProfile* MicroProfileGet() +{ + return &g_MicroProfile; +} + +MicroProfileThreadLog* MicroProfileCreateThreadLog(const char* pName); +MicroProfileThreadLogGpu* MicroProfileThreadLogGpuAllocInternal(); +void* MicroProfileSocketSenderThread(void*); + +void MicroProfileInit() +{ + static bool bOnce = true; + if(!bOnce) + { + return; + } + + std::recursive_mutex& mutex = MicroProfileMutex(); + bool bUseLock = g_bUseLock; + if(bUseLock) + mutex.lock(); + if(bOnce) + { + bOnce = false; + memset(&S, 0, sizeof(S)); + + MicroProfileStringsInit(&S.Strings); + + // these strings are used for counter names inside the string + S.CounterToken_MicroProfile = MicroProfileCounterTokenInit(-1, 0); + S.CounterToken_StringBlock = MicroProfileCounterTokenInit(S.CounterToken_MicroProfile, 0); + S.CounterToken_StringBlock_Count = MicroProfileCounterTokenInit(S.CounterToken_StringBlock, 0); + S.CounterToken_StringBlock_Waste = MicroProfileCounterTokenInit(S.CounterToken_StringBlock, 0); + S.CounterToken_StringBlock_Strings = MicroProfileCounterTokenInit(S.CounterToken_StringBlock, 0); + S.CounterToken_StringBlock_Memory = MicroProfileCounterTokenInit(S.CounterToken_StringBlock, 0); + + S.CounterToken_Alloc = MicroProfileCounterTokenInit(S.CounterToken_MicroProfile, 0); + S.CounterToken_Alloc_Memory = MicroProfileCounterTokenInit(S.CounterToken_Alloc, 0); + S.CounterToken_Alloc_Count = MicroProfileCounterTokenInit(S.CounterToken_Alloc, 0); + + MicroProfileCounterTokenInitName(S.CounterToken_MicroProfile, "microprofile"); + MicroProfileCounterTokenInitName(S.CounterToken_StringBlock, "stringblock"); + MicroProfileCounterTokenInitName(S.CounterToken_StringBlock_Count, "count"); + MicroProfileCounterTokenInitName(S.CounterToken_StringBlock_Waste, "waste"); + MicroProfileCounterTokenInitName(S.CounterToken_StringBlock_Strings, "strings"); + MicroProfileCounterTokenInitName(S.CounterToken_StringBlock_Memory, "memory"); + + MicroProfileCounterTokenInitName(S.CounterToken_Alloc, "alloc"); + MicroProfileCounterTokenInitName(S.CounterToken_Alloc_Memory, "memory"); + MicroProfileCounterTokenInitName(S.CounterToken_Alloc_Count, "count"); + + S.nMemUsage += sizeof(S); + for(int i = 0; i < MICROPROFILE_MAX_GROUPS; ++i) + { + S.GroupInfo[i].pName[0] = '\0'; + } + for(int i = 0; i < MICROPROFILE_MAX_CATEGORIES; ++i) + { + S.CategoryInfo[i].pName[0] = '\0'; + memset(S.CategoryInfo[i].nGroupMask, 0, sizeof(S.CategoryInfo[i].nGroupMask)); + } + memcpy(&S.CategoryInfo[0].pName[0], "default", sizeof("default")); + S.nCategoryCount = 1; + for(int i = 0; i < MICROPROFILE_MAX_TIMERS; ++i) + { + S.TimerInfo[i].pName[0] = '\0'; + } + S.nGroupCount = 0; + S.nFlipStartTick = MP_TICK(); + S.nContextSwitchStalledTick = MP_TICK(); + S.nAggregateFlipTick = MP_TICK(); + memset(S.nActiveGroups, 0, sizeof(S.nActiveGroups)); + S.nFrozen = 0; + S.nWasFrozen = 0; + memset(S.nForceGroups, 0, sizeof(S.nForceGroups)); + memset(S.nActiveGroupsWanted, 0, sizeof(S.nActiveGroupsWanted)); + S.nStartEnabled = 0; + S.nAllThreadsWanted = 1; + S.nAggregateFlip = 0; + S.nTotalTimers = 0; + for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i) + { + S.Graph[i].nToken = MICROPROFILE_INVALID_TOKEN; + } + S.fReferenceTime = 33.33f; + S.fRcpReferenceTime = 1.f / S.fReferenceTime; + S.nFreeListHead = -1; + int64_t nTick = MP_TICK(); + for(int i = 0; i < MICROPROFILE_MAX_FRAME_HISTORY; ++i) + { + S.Frames[i].nFrameStartCpu = nTick; + S.Frames[i].nFrameStartGpu = MICROPROFILE_INVALID_TICK; + } + S.nWebServerPort = MICROPROFILE_WEBSERVER_PORT; // Use defined value as default port + S.nWebServerDataSent = (uint64_t)-1; + S.WebSocketTimers = -1; + S.WebSocketCounters = -1; + S.WebSocketGroups = -1; + S.nSocketFail = 0; + + S.DumpFrameCount = MICROPROFILE_WEBSERVER_DEFAULT_FRAMES; + +#if MICROPROFILE_COUNTER_HISTORY + S.nCounterHistoryPut = 0; + for(uint32_t i = 0; i < MICROPROFILE_MAX_COUNTERS; ++i) + { + S.nCounterMin[i] = 0x7fffffffffffffff; + S.nCounterMax[i] = 0x8000000000000000; + } +#endif + S.GpuQueue = MICROPROFILE_GPU_INIT_QUEUE("GPU"); + S.pGpuGlobal = MicroProfileThreadLogGpuAllocInternal(); + MicroProfileGpuBegin(0, S.pGpuGlobal); + + S.pJsonSettings = 0; + S.pJsonSettingsName = nullptr; + S.nJsonSettingsPending = 0; + S.nJsonSettingsBufferSize = 0; + S.nWSWasConnected = 0; + + for(uint32_t i = 0; i < MICROPROFILE_TIMELINE_MAX_TOKENS; ++i) + { + S.TimelineTokenFrameEnter[i] = MICROPROFILE_INVALID_FRAME; + S.TimelineTokenFrameLeave[i] = MICROPROFILE_INVALID_FRAME; + S.TimelineTokenStaticString[i] = nullptr; + S.TimelineToken[i] = 0; + } + memset(&S.AccumMinTimers[0], 0xFF, sizeof(S.AccumMinTimers)); + S.CountersDouble = (std::atomic*)&S.Counters; +#if MICROPROFILE_COUNTER_HISTORY + S.dCounterHistory = (double*)S.nCounterHistory; + S.dCounterMax = (double*)S.nCounterMax; + S.dCounterMin = (double*)S.nCounterMin; +#endif + } + MicroProfileUpdateSettingsPath(); + +#if MICROPROFILE_FRAME_EXTRA_DATA + S.FrameExtraCounterData = (MicroProfileFrameExtraCounterData*)1; +#endif + MicroProfileCounterConfigToken(S.CounterToken_Alloc_Memory, MICROPROFILE_COUNTER_FORMAT_BYTES, 0, MICROPROFILE_COUNTER_FLAG_DETAILED); + MICROPROFILE_COUNTER_CONFIG("MicroProfile/ThreadLog/Memory", MICROPROFILE_COUNTER_FORMAT_BYTES, 0, MICROPROFILE_COUNTER_FLAG_DETAILED); + + if(bUseLock) + { + mutex.unlock(); + } +} +void MicroProfileUpdateSettingsPath() +{ + if(S.pSettings) + { + MicroProfileFreeInternal((void*)S.pSettings); + S.pSettings = nullptr; + } + if(S.pSettingsReadOnly) + { + MicroProfileFreeInternal((void*)S.pSettingsReadOnly); + S.pSettingsReadOnly = nullptr; + } + if(S.pSettingsTemp) + { + MicroProfileFreeInternal((void*)S.pSettingsTemp); + S.pSettingsTemp = nullptr; + } + auto DupeString = [](const char* BasePath, const char* File) -> const char* + { + size_t BaseLen = strlen(BasePath); + bool TrailingSlash = BaseLen > 1 && (BasePath[BaseLen - 1] == '\\' || BasePath[BaseLen - 1] == '/'); + size_t Len = BaseLen + strlen(File) + 2; + char* Data = (char*)MicroProfileAllocInternal(Len + 1, 1); +#ifdef _WIN32 + char Slash = '\\'; +#else + char Slash = '/'; +#endif + if(TrailingSlash) + snprintf(Data, Len, "%s%s", BasePath, File); + else + snprintf(Data, Len, "%s%c%s", BasePath, Slash, File); + + return Data; + }; + const char* pBaseSettingsPath = MICROPROFILE_GET_SETTINGS_FILE_PATH; + S.pSettings = DupeString(pBaseSettingsPath, MICROPROFILE_SETTINGS_FILE); + S.pSettingsReadOnly = DupeString(pBaseSettingsPath, MICROPROFILE_SETTINGS_FILE_BUILTIN); + S.pSettingsTemp = DupeString(pBaseSettingsPath, MICROPROFILE_SETTINGS_FILE MICROPROFILE_SETTINGS_FILE_TEMP); +} + +void MicroProfileJoinContextSwitchTrace(); + +void MicroProfileShutdown() +{ + { + std::lock_guard Lock(MicroProfileMutex()); + S.nMicroProfileShutdown = 1; + MicroProfileStopContextSwitchTrace(); + } + MicroProfileWebServerJoin(); + MicroProfileJoinContextSwitchTrace(); + { + + std::lock_guard Lock(MicroProfileMutex()); + if(S.pJsonSettings) + { + MP_FREE(S.pJsonSettings); + S.pJsonSettings = 0; + S.pJsonSettingsName = 0; + S.nJsonSettingsBufferSize = 0; + } + if(S.pGPU) + { + MicroProfileGpuShutdownPlatform(); + } + MicroProfileHashTableDestroy(&S.Strings.HashTable); + MicroProfileStringsDestroy(&S.Strings); + MICROPROFILE_FREE_NON_ALIGNED(S.WSBuf.pBufferAllocation); + + MicroProfileFreeGpuQueue(S.GpuQueue); + MicroProfileThreadLogGpuFree(S.pGpuGlobal); + + for(uint32_t i = 0; i < S.nNumLogs; ++i) + { +#if MICROPROFILE_ASSERT_LOG_FREED + MP_ASSERT(S.Pool[i]->nActive != 1); +#endif + MP_FREE(S.Pool[i]); + } + + for(uint32_t i = 0; i < S.nNumLogsGpu; ++i) + { +#if MICROPROFILE_ASSERT_LOG_FREED + MP_ASSERT(!S.PoolGpu[i]->nAllocated); +#endif + MP_FREE(S.PoolGpu[i]); + } + MicroProfileFreeInternal((void*)S.pSettings); + S.pSettings = nullptr; + MicroProfileFreeInternal((void*)S.pSettingsReadOnly); + S.pSettingsReadOnly = nullptr; + MicroProfileFreeInternal((void*)S.pSettingsTemp); + S.pSettingsTemp = nullptr; + } +} + +static void* MicroProfileAutoFlipThread(void*) +{ + MicroProfileOnThreadCreate("AutoFlipThread"); + while(0 == S.nAutoFlipStop.load()) + { + MICROPROFILE_SCOPEI("MICROPROFILE", "AutoFlipThread", 0); + MicroProfileSleep(S.nAutoFlipDelay); + MicroProfileFlip(0); + } + MicroProfileOnThreadExit(); + return 0; +} + +void MicroProfileStartAutoFlip(uint32_t nMsDelay) +{ + S.nAutoFlipDelay = nMsDelay; + S.nAutoFlipStop.store(0); + MicroProfileThreadStart(&S.AutoFlipThread, MicroProfileAutoFlipThread); +} +void MicroProfileStopAutoFlip() +{ + S.nAutoFlipStop.store(1); + MicroProfileThreadJoin(&S.AutoFlipThread); +} + +void MicroProfileEnableFrameExtraCounterData() +{ + // should not be called at the same time as MicroProfileFlip. + if(!S.FrameExtraCounterData) + { + S.FrameExtraCounterData = (MicroProfileFrameExtraCounterData*)1; + } +} + +void MicroProfileCsvConfigEnd() +{ + MP_ASSERT(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG); + S.CsvConfig.State = MicroProfileCsvConfig::ACTIVE; +} +void MicroProfileCsvConfigBegin(uint32_t MaxTimers, uint32_t MaxGroups, uint32_t MaxCounters, uint32_t Flags) +{ + MP_ASSERT(S.CsvConfig.State == MicroProfileCsvConfig::INACTIVE); // right now, only support being configured once. + uint32_t TotalElements = MaxTimers + MaxGroups + MaxCounters; + uint32_t BaseSize = (sizeof(MicroProfileCsvConfig) + 7) & 7; + uint32_t TimerIndexSize = sizeof(uint16_t) * MaxTimers; + uint32_t GroupIndexSize = sizeof(uint16_t) * MaxGroups; + uint32_t CounterIndexSize = sizeof(uint16_t) * MaxCounters; + uint32_t FrameBlockSize = TotalElements * sizeof(uint64_t); + uint32_t FrameDataSize = FrameBlockSize * MICROPROFILE_MAX_FRAME_HISTORY; + S.CsvConfig.NumTimers = 0; + S.CsvConfig.NumGroups = 0; + S.CsvConfig.NumCounters = 0; + S.CsvConfig.MaxTimers = MaxTimers; + S.CsvConfig.MaxGroups = MaxGroups; + S.CsvConfig.MaxCounters = MaxCounters; + S.CsvConfig.TotalElements = TotalElements; + S.CsvConfig.TimerIndices = (uint16_t*)MicroProfileAllocInternal(TimerIndexSize, alignof(uint16_t)); + S.CsvConfig.pTimerNames = (const char**)MicroProfileAllocInternal(MaxTimers * sizeof(const char*), alignof(const char*)); + memset(S.CsvConfig.pTimerNames, 0, MaxTimers * sizeof(const char*)); + for(uint32_t i = 0; i < MaxTimers; ++i) + S.CsvConfig.TimerIndices[i] = UINT16_MAX; + S.CsvConfig.pGroupNames = (const char**)MicroProfileAllocInternal(MaxGroups * sizeof(const char*), alignof(const char*)); + memset(S.CsvConfig.pGroupNames, 0, MaxGroups * sizeof(const char*)); + S.CsvConfig.GroupIndices = (uint16_t*)MicroProfileAllocInternal(GroupIndexSize, alignof(uint16_t)); + for(uint32_t i = 0; i < MaxGroups; ++i) + S.CsvConfig.GroupIndices[i] = UINT16_MAX; + S.CsvConfig.pCounterNames = (const char**)MicroProfileAllocInternal(MaxCounters * sizeof(const char*), alignof(const char*)); + memset(S.CsvConfig.pCounterNames, 0, MaxCounters * sizeof(const char*)); + S.CsvConfig.CounterIndices = (uint16_t*)MicroProfileAllocInternal(CounterIndexSize, alignof(uint16_t)); + for(uint32_t i = 0; i < MaxCounters; ++i) + S.CsvConfig.CounterIndices[i] = UINT16_MAX; + S.CsvConfig.FrameData = (uint64_t*)MicroProfileAllocInternal(FrameDataSize, alignof(uint64_t)); + memset(S.CsvConfig.FrameData, 0, FrameDataSize); + S.CsvConfig.State = MicroProfileCsvConfig::CONFIG; + S.CsvConfig.Flags = Flags; +} +void MicroProfileCsvConfigAddTimer(const char* Group, const char* Timer, const char* Name, MicroProfileTokenType Type) +{ + MP_ASSERT(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG); + if(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG && S.CsvConfig.NumTimers < S.CsvConfig.MaxTimers) + { + MicroProfileToken ret = MicroProfileGetToken(Group, Timer, MP_AUTO, Type, MICROPROFILE_TIMER_FLAG_PLACEHOLDER); + if(ret != MICROPROFILE_INVALID_TOKEN) + { + MP_ASSERT(S.CsvConfig.NumTimers < S.CsvConfig.MaxTimers); + uint16_t TimerIndex = MicroProfileGetTimerIndex(ret); + for(uint32_t i = 0; i < S.CsvConfig.NumTimers; ++i) + { + if(S.CsvConfig.TimerIndices[i] == TimerIndex) + return; + } + S.CsvConfig.pTimerNames[S.CsvConfig.NumTimers] = Name; + S.CsvConfig.TimerIndices[S.CsvConfig.NumTimers++] = TimerIndex; + } + } +} +void MicroProfileCsvConfigAddGroup(const char* Group, const char* Name) +{ + MP_ASSERT(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG); + if(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG && S.CsvConfig.NumGroups < S.CsvConfig.MaxGroups) + { + uint16_t Index = MicroProfileFindGroup(Group); + MP_ASSERT(UINT16_MAX != Index); + if(UINT16_MAX != Index) + { + MP_ASSERT(S.CsvConfig.NumGroups < S.CsvConfig.MaxGroups); + for(uint32_t i = 0; i < S.CsvConfig.NumGroups; ++i) + { + if(S.CsvConfig.GroupIndices[i] == Index) + return; + } + S.CsvConfig.pGroupNames[S.CsvConfig.NumGroups] = Name; + S.CsvConfig.GroupIndices[S.CsvConfig.NumGroups++] = Index; + } + } +} +void MicroProfileCsvConfigAddCounter(const char* CounterName, const char* Name) +{ + MP_ASSERT(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG); + if(S.CsvConfig.State == MicroProfileCsvConfig::CONFIG && S.CsvConfig.NumCounters < S.CsvConfig.MaxCounters) + { + MicroProfileToken Token = MicroProfileGetCounterToken(CounterName, 0); + if(MICROPROFILE_INVALID_TOKEN != Token) + { + MP_ASSERT(Token < UINT16_MAX); + MP_ASSERT(S.CsvConfig.NumCounters < S.CsvConfig.MaxCounters); + for(uint32_t i = 0; i < S.CsvConfig.NumCounters; ++i) + { + if(S.CsvConfig.CounterIndices[i] == (uint16_t)Token) + return; + } + S.CsvConfig.pCounterNames[S.CsvConfig.NumCounters] = Name; + S.CsvConfig.CounterIndices[S.CsvConfig.NumCounters++] = (uint16_t)Token; + } + } +} + +#ifdef MICROPROFILE_IOS +inline MicroProfileThreadLog* MicroProfileGetThreadLog() +{ + pthread_once(&g_MicroProfileThreadLogKeyOnce, MicroProfileCreateThreadLogKey); + return (MicroProfileThreadLog*)pthread_getspecific(g_MicroProfileThreadLogKey); +} + +inline void MicroProfileSetThreadLog(MicroProfileThreadLog* pLog) +{ + pthread_once(&g_MicroProfileThreadLogKeyOnce, MicroProfileCreateThreadLogKey); + pthread_setspecific(g_MicroProfileThreadLogKey, pLog); +} +#else +MicroProfileThreadLog* MicroProfileGetThreadLog() +{ + return g_MicroProfileThreadLogThreadLocal; +} +void MicroProfileSetThreadLog(MicroProfileThreadLog* pLog) +{ + g_MicroProfileThreadLogThreadLocal = pLog; +} +#endif + +MicroProfileThreadLog* MicroProfileGetThreadLog2() +{ + MicroProfileThreadLog* pLog = MicroProfileGetThreadLog(); + if(!pLog) + { + MicroProfileInitThreadLog(); + pLog = MicroProfileGetThreadLog(); + } + return pLog; +} + +struct MicroProfileScopeLock +{ + bool bUseLock; + int nUnlock; + std::recursive_mutex& m; + MicroProfileScopeLock(std::recursive_mutex& m) + : bUseLock(g_bUseLock) + , nUnlock(0) + , m(m) + { + if(bUseLock) + m.lock(); + } + ~MicroProfileScopeLock() + { + MP_ASSERT(nUnlock == 0); + if(bUseLock) + m.unlock(); + } + void Unlock() + { + MP_ASSERT(bUseLock); + m.unlock(); + nUnlock++; + } + void Lock() + { + m.lock(); + nUnlock--; + } +}; + +void MicroProfileLogReset(MicroProfileThreadLog* pLog); +void MicroProfileLogClearInternal(MicroProfileThreadLog* pLog); + +MicroProfileThreadLog* MicroProfileCreateThreadLog(const char* pName) +{ + MicroProfileScopeLock L(MicroProfileMutex()); + + if(S.nNumLogs == MICROPROFILE_MAX_THREADS && S.nFreeListHead == -1) + { + uprintf("recycling thread logs\n"); + // reuse the oldest. + MicroProfileThreadLog* pOldest = 0; + uint32_t nIdleFrames = 0; + for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i) + { + MicroProfileThreadLog* pLog = S.Pool[i]; + uprintf("tlactive %p, %d. idle:%d\n", pLog, pLog->nActive, pLog->nIdleFrames); + if(pLog->nActive == 2) + { + if(pLog->nIdleFrames >= nIdleFrames) + { + nIdleFrames = pLog->nIdleFrames; + pOldest = pLog; + } + } + } + MP_ASSERT(pOldest); + MicroProfileLogReset(pOldest); + } + + MicroProfileThreadLog* pLog = 0; + if(S.nFreeListHead != -1) + { + pLog = S.Pool[S.nFreeListHead]; + MP_ASSERT(pLog->nPut.load() == 0); + MP_ASSERT(pLog->nGet.load() == 0); + S.nFreeListHead = S.Pool[S.nFreeListHead]->nFreeListNext; + } + else + { + MICROPROFILE_COUNTER_ADD("MicroProfile/ThreadLog/Allocated", 1); + MICROPROFILE_COUNTER_ADD("MicroProfile/ThreadLog/Memory", sizeof(MicroProfileThreadLog)); + pLog = MP_ALLOC_OBJECT(MicroProfileThreadLog); + MicroProfileLogClearInternal(pLog); + S.nMemUsage += sizeof(MicroProfileThreadLog); + pLog->nLogIndex = S.nNumLogs; + MP_ASSERT(S.nNumLogs < MICROPROFILE_MAX_THREADS); + S.Pool[S.nNumLogs++] = pLog; + } + int len = 0; + if(pName) + { + len = (int)strlen(pName); + int maxlen = sizeof(pLog->ThreadName) - 1; + len = len < maxlen ? len : maxlen; + memcpy(&pLog->ThreadName[0], pName, len); + } + else + { + len = snprintf(&pLog->ThreadName[0], sizeof(pLog->ThreadName) - 1, "TID:[%" PRId64 "]", (int64_t)MP_GETCURRENTTHREADID()); + } + pLog->ThreadName[len] = '\0'; + pLog->nThreadId = MP_GETCURRENTTHREADID(); + pLog->nFreeListNext = -1; + pLog->nActive = 1; + return pLog; +} + +void MicroProfileOnThreadCreate(const char* pThreadName) +{ + char Buffer[64]; + g_bUseLock = true; + MicroProfileInit(); + MP_ASSERT(MicroProfileGetThreadLog() == 0); + MicroProfileThreadLog* pLog = MicroProfileCreateThreadLog(pThreadName ? pThreadName : MicroProfileGetThreadName(Buffer)); + (void)Buffer; + MP_ASSERT(pLog); + MicroProfileSetThreadLog(pLog); +} + +void MicroProfileThreadLogGpuReset(MicroProfileThreadLogGpu* pLog) +{ + MP_ASSERT(pLog->nAllocated); + pLog->pContext = (void*)-1; + pLog->nStart = (uint32_t)-1; + pLog->nPut = 0; + pLog->nStackScope = 0; +} + +MicroProfileThreadLogGpu* MicroProfileThreadLogGpuAllocInternal() +{ + MicroProfileThreadLogGpu* pLog = 0; + for(uint32_t i = 0; i < S.nNumLogsGpu; ++i) + { + MicroProfileThreadLogGpu* pNextLog = S.PoolGpu[i]; + if(pNextLog && !pNextLog->nAllocated) + { + pLog = pNextLog; + break; + } + } + if(!pLog) + { + pLog = MP_ALLOC_OBJECT(MicroProfileThreadLogGpu); + int nLogIndex = S.nNumLogsGpu++; + MP_ASSERT(nLogIndex < MICROPROFILE_MAX_THREADS); + pLog->nId = nLogIndex; + S.PoolGpu[nLogIndex] = pLog; + } + pLog->nAllocated = 1; + MicroProfileThreadLogGpuReset(pLog); + return pLog; +} + +MicroProfileThreadLogGpu* MicroProfileThreadLogGpuAlloc() +{ + std::lock_guard Lock(MicroProfileMutex()); + return MicroProfileThreadLogGpuAllocInternal(); +} + +void MicroProfileThreadLogGpuFree(MicroProfileThreadLogGpu* pLog) +{ + MP_ASSERT(pLog->nAllocated); + pLog->nAllocated = 0; +} + +int MicroProfileGetGpuQueue(const char* pQueueName) +{ + for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; i++) + { + MicroProfileThreadLog* pLog = S.Pool[i]; + if(pLog && pLog->nGpu && pLog->nActive && 0 == MP_STRCASECMP(pQueueName, pLog->ThreadName)) + { + return i; + } + } + MP_ASSERT(0); // call MicroProfileInitGpuQueue + return 0; +} + +MicroProfileThreadLog* MicroProfileGetGpuQueueLog(const char* pQueueName) +{ + for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; i++) + { + MicroProfileThreadLog* pLog = S.Pool[i]; + if(pLog && pLog->nGpu && pLog->nActive && 0 == MP_STRCASECMP(pQueueName, pLog->ThreadName)) + { + return pLog; + } + } + MP_ASSERT(0); // call MicroProfileInitGpuQueue + return 0; +} + +int MicroProfileInitGpuQueue(const char* pQueueName) +{ + for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i) + { + MicroProfileThreadLog* pLog = S.Pool[i]; + if(pLog && 0 == MP_STRCASECMP(pQueueName, pLog->ThreadName)) + { + + MP_ASSERT(0); // call MicroProfileInitGpuQueue only once per CommandQueue. name must not clash with threadname + } + } + MicroProfileThreadLog* pLog = MicroProfileCreateThreadLog(pQueueName); + pLog->nGpu = 1; + pLog->nThreadId = 0; + for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i) + { + if(S.Pool[i] == pLog) + { + return i; + } + } + MP_BREAK(); + return 0; +} + +void MicroProfileFreeGpuQueue(int nQueue) +{ + MicroProfileThreadLog* pLog = S.Pool[nQueue]; + if(pLog) + { + MP_ASSERT(pLog->nActive == 1); + pLog->nActive = 2; + } +} + +MicroProfileThreadLogGpu* MicroProfileGetGlobalGpuThreadLog() +{ + return S.pGpuGlobal; +} + +MICROPROFILE_API int MicroProfileGetGlobalGpuQueue() +{ + return S.GpuQueue; +} +void MicroProfileLogClearInternal(MicroProfileThreadLog* pLog) +{ + // can't clear atomics.. + void* pStart = (void*)&pLog->Log[0]; + void* pEnd = (void*)(pLog + 1); + memset(pStart, 0, (uintptr_t)pEnd - (uintptr_t)pStart); + pLog->nPut.store(0); + pLog->nGet.store(0); +} +void MicroProfileLogReset(MicroProfileThreadLog* pLog) +{ + std::lock_guard Lock(MicroProfileMutex()); + + int32_t nLogIndex = -1; + for(int i = 0; i < MICROPROFILE_MAX_THREADS; ++i) + { + if(pLog == S.Pool[i]) + { + nLogIndex = i; + break; + } + } + MP_ASSERT(nLogIndex < MICROPROFILE_MAX_THREADS && nLogIndex > 0); + MicroProfileLogClearInternal(pLog); + pLog->nFreeListNext = S.nFreeListHead; + S.nFreeListHead = nLogIndex; + for(int i = 0; i < MICROPROFILE_MAX_FRAME_HISTORY; ++i) + { + S.Frames[i].nLogStart[nLogIndex] = 0; + } +} + +void MicroProfileOnThreadExit() +{ + MicroProfileThreadLog* pLog = MicroProfileGetThreadLog(); + if(pLog) + { + MP_ASSERT(pLog->nActive == 1); + pLog->nActive = 2; + } +} + +void MicroProfileInitThreadLog() +{ + MicroProfileOnThreadCreate(nullptr); +} + +MicroProfileToken MicroProfileFindTokenInternal(const char* pGroup, const char* pName) +{ + MicroProfileInit(); + MicroProfileScopeLock L(MicroProfileMutex()); + for(uint32_t i = 0; i < S.nTotalTimers; ++i) + { + if(!MP_STRCASECMP(pName, S.TimerInfo[i].pName) && !MP_STRCASECMP(pGroup, S.GroupInfo[S.TimerToGroup[i]].pName)) + { + return S.TimerInfo[i].nToken; + } + } + return MICROPROFILE_INVALID_TOKEN; +} +MicroProfileToken MicroProfileFindToken(const char* pGroup, const char* pName) +{ + return MicroProfileGetToken(pGroup, pName, MP_AUTO, MicroProfileTokenTypeCpu, MICROPROFILE_TIMER_FLAG_PLACEHOLDER); +} + +uint16_t MicroProfileFindGroup(const char* pGroup) +{ + for(uint32_t i = 0; i < S.nGroupCount; ++i) + { + if(!MP_STRCASECMP(pGroup, S.GroupInfo[i].pName)) + { + return i; + } + } + return UINT16_MAX; +} + +uint16_t MicroProfileGetGroup(const char* pGroup, MicroProfileTokenType Type) +{ + for(uint32_t i = 0; i < S.nGroupCount; ++i) + { + if(!MP_STRCASECMP(pGroup, S.GroupInfo[i].pName)) + { + return i; + } + } + uint16_t nGroupIndex = 0xffff; + uint32_t nLen = (uint32_t)strlen(pGroup); + if(nLen > MICROPROFILE_NAME_MAX_LEN - 1) + nLen = MICROPROFILE_NAME_MAX_LEN - 1; + memcpy(&S.GroupInfo[S.nGroupCount].pName[0], pGroup, nLen); + S.GroupInfo[S.nGroupCount].pName[nLen] = '\0'; + S.GroupInfo[S.nGroupCount].nNameLen = nLen; + S.GroupInfo[S.nGroupCount].nNumTimers = 0; + S.GroupInfo[S.nGroupCount].nGroupIndex = S.nGroupCount; + S.GroupInfo[S.nGroupCount].Type = Type; + S.GroupInfo[S.nGroupCount].nMaxTimerNameLen = 0; + S.GroupInfo[S.nGroupCount].nColor = 0x42; + S.GroupInfo[S.nGroupCount].nCategory = 0; + S.GroupInfo[S.nGroupCount].nWSNext = -2; + + uint32_t nIndex = S.nGroupCount / 32; + uint32_t nBit = S.nGroupCount % 32; + { + S.CategoryInfo[0].nGroupMask[nIndex] |= (1 << nBit); + } + if(S.nStartEnabled) + { + S.nActiveGroupsWanted[nIndex] |= (1ll << nBit); + S.nActiveGroups[nIndex] |= (1ll << nBit); + S.AnyActive = true; + } + nGroupIndex = S.nGroupCount++; + S.nGroupMask[nIndex] |= (1 << nBit); + MP_ASSERT(S.nGroupCount < MICROPROFILE_MAX_GROUPS); + return nGroupIndex; +} + +void MicroProfileRegisterGroup(const char* pGroup, const char* pCategory, uint32_t nColor) +{ + MicroProfileScopeLock L(MicroProfileMutex()); + + int nCategoryIndex = -1; + for(uint32_t i = 0; i < S.nCategoryCount; ++i) + { + if(!MP_STRCASECMP(pCategory, S.CategoryInfo[i].pName)) + { + nCategoryIndex = (int)i; + break; + } + } + if(-1 == nCategoryIndex && S.nCategoryCount < MICROPROFILE_MAX_CATEGORIES) + { + MP_ASSERT(S.CategoryInfo[S.nCategoryCount].pName[0] == '\0'); + nCategoryIndex = (int)S.nCategoryCount++; + uint32_t nLen = (uint32_t)strlen(pCategory); + if(nLen > MICROPROFILE_NAME_MAX_LEN - 1) + nLen = MICROPROFILE_NAME_MAX_LEN - 1; + memcpy(&S.CategoryInfo[nCategoryIndex].pName[0], pCategory, nLen); + S.CategoryInfo[nCategoryIndex].pName[nLen] = '\0'; + } + uint16_t nGroup = MicroProfileGetGroup(pGroup, 0 != MP_STRCASECMP(pGroup, "gpu") ? MicroProfileTokenTypeCpu : MicroProfileTokenTypeGpu); + S.GroupInfo[nGroup].nColor = nColor; + if(nCategoryIndex >= 0) + { + uint32_t nIndex = nGroup / 32; + uint32_t nBit = nGroup % 32; + nBit = (1 << nBit); + uint32_t nOldCategory = S.GroupInfo[nGroup].nCategory; + S.CategoryInfo[nOldCategory].nGroupMask[nIndex] &= ~nBit; + S.CategoryInfo[nCategoryIndex].nGroupMask[nIndex] |= nBit; + S.GroupInfo[nGroup].nCategory = nCategoryIndex; + } +} + +MicroProfileToken MicroProfileGetToken(const char* pGroup, const char* pName, uint32_t nColor, MicroProfileTokenType Type, uint32_t Flags) +{ + MicroProfileInit(); + MicroProfileScopeLock L(MicroProfileMutex()); + MicroProfileToken ret = MicroProfileFindTokenInternal(pGroup, pName); + if(ret != MICROPROFILE_INVALID_TOKEN) + { + int idx = MicroProfileGetTimerIndex(ret); + if(S.TimerInfo[idx].Flags & MICROPROFILE_TIMER_FLAG_PLACEHOLDER) + { + S.TimerInfo[idx].nColor = nColor & 0xffffff; + S.TimerInfo[idx].Flags = Flags; + S.TimerInfo[idx].Type = Type; + } + MP_ASSERT(S.TimerInfo[idx].Flags == Flags || (Flags & MICROPROFILE_TIMER_FLAG_PLACEHOLDER)); + return ret; + } + uint16_t nGroupIndex = MicroProfileGetGroup(pGroup, Type); + uint16_t nTimerIndex = (uint16_t)(S.nTotalTimers++); + MP_ASSERT(nTimerIndex < MICROPROFILE_MAX_TIMERS); + + uint32_t nBitIndex = nGroupIndex / 32; + uint32_t nBit = nGroupIndex % 32; + uint32_t nGroupMask = 1ll << nBit; + MicroProfileToken nToken = MicroProfileMakeToken(nGroupMask, (uint16_t)nBitIndex, nTimerIndex); + S.GroupInfo[nGroupIndex].nNumTimers++; + S.GroupInfo[nGroupIndex].nMaxTimerNameLen = MicroProfileMax(S.GroupInfo[nGroupIndex].nMaxTimerNameLen, (uint32_t)strlen(pName)); + MP_ASSERT(S.GroupInfo[nGroupIndex].Type == Type); // dont mix cpu & gpu timers in the same group + S.nMaxGroupSize = MicroProfileMax(S.nMaxGroupSize, S.GroupInfo[nGroupIndex].nNumTimers); + S.TimerInfo[nTimerIndex].nToken = nToken; + uint32_t nLen = (uint32_t)strlen(pName); + if(nLen > MICROPROFILE_NAME_MAX_LEN - 1) + nLen = MICROPROFILE_NAME_MAX_LEN - 1; + memcpy(&S.TimerInfo[nTimerIndex].pName, pName, nLen); + snprintf(&S.TimerInfo[nTimerIndex].pNameExt[0], sizeof(S.TimerInfo[nTimerIndex].pNameExt) - 1, "%s %s", S.GroupInfo[nGroupIndex].pName, pName); + S.TimerInfo[nTimerIndex].pName[nLen] = '\0'; + S.TimerInfo[nTimerIndex].nNameLen = nLen; + S.TimerInfo[nTimerIndex].nColor = nColor & 0xffffff; + S.TimerInfo[nTimerIndex].nGroupIndex = nGroupIndex; + S.TimerInfo[nTimerIndex].nTimerIndex = nTimerIndex; + S.TimerInfo[nTimerIndex].nWSNext = -2; + S.TimerInfo[nTimerIndex].Type = Type; + S.TimerInfo[nTimerIndex].Flags = Flags; + // printf("*** TOKEN %08d %s\\%s .. flags %08x\n", nTimerIndex, pGroup, pName, Flags); + S.TimerToGroup[nTimerIndex] = nGroupIndex; + return nToken; +} + +void MicroProfileGetTokenC(MicroProfileToken* pToken, const char* pGroup, const char* pName, uint32_t nColor, MicroProfileTokenType Type, uint32_t flags) +{ + if(*pToken == MICROPROFILE_INVALID_TOKEN) + { + MicroProfileInit(); + MicroProfileScopeLock L(MicroProfileMutex()); + if(*pToken == MICROPROFILE_INVALID_TOKEN) + { + *pToken = MicroProfileGetToken(pGroup, pName, nColor, Type, flags); + } + } +} + +const char* MicroProfileNextName(const char* pName, char* pNameOut, uint32_t* nSubNameLen) +{ + int nMaxLen = MICROPROFILE_NAME_MAX_LEN - 1; + const char* pRet = 0; + bool bDone = false; + uint32_t nChars = 0; + for(int i = 0; i < nMaxLen && !bDone; ++i) + { + char c = *pName++; + switch(c) + { + case 0: + bDone = true; + break; + case '\\': + case '/': + if(nChars) + { + bDone = true; + pRet = pName; + } + break; + default: + nChars++; + *pNameOut++ = c; + } + } + *nSubNameLen = nChars; + *pNameOut = '\0'; + return pRet; +} + +const char* MicroProfileCounterFullName(int nCounter) +{ + static char Buffer[1024]; + int nNodes[32]; + int nIndex = 0; + do + { + nNodes[nIndex++] = nCounter; + nCounter = S.CounterInfo[nCounter].nParent; + } while(nCounter >= 0); + int nOffset = 0; + while(nIndex >= 0 && nOffset < (int)sizeof(Buffer) - 2) + { + uint32_t nLen = S.CounterInfo[nNodes[nIndex]].nNameLen + nOffset; // < sizeof(Buffer)-1 + nLen = MicroProfileMin((uint32_t)(sizeof(Buffer) - 2 - nOffset), nLen); + memcpy(&Buffer[nOffset], S.CounterInfo[nNodes[nIndex]].pName, nLen); + + nOffset += S.CounterInfo[nNodes[nIndex]].nNameLen + 1; + if(nIndex) + { + Buffer[nOffset++] = '/'; + } + nIndex--; + } + return &Buffer[0]; +} + +MicroProfileToken MicroProfileCounterTokenInit(int nParent, uint32_t nFlags) +{ + MP_ASSERT(0 == (nFlags & (~MICROPROFILE_COUNTER_FLAG_TYPE_MASK))); + MicroProfileToken nResult = S.nNumCounters++; + S.CounterInfo[nResult].nParent = nParent; + S.CounterInfo[nResult].nSibling = -1; + S.CounterInfo[nResult].nFirstChild = -1; + S.CounterInfo[nResult].nFlags = nFlags; + S.CounterInfo[nResult].eFormat = MICROPROFILE_COUNTER_FORMAT_DEFAULT; + S.CounterInfo[nResult].nLimit = 0; + S.CounterInfo[nResult].ExternalAtomic = 0; + S.CounterSource[nResult].pSource = 0; + S.CounterSource[nResult].nSourceSize = 0; + S.CounterInfo[nResult].nNameLen = 0; + S.CounterInfo[nResult].pName = nullptr; + S.CounterInfo[nResult].nWSNext = -2; + if(nParent >= 0) + { + MP_ASSERT(nParent < (int)S.nNumCounters); + S.CounterInfo[nResult].nSibling = S.CounterInfo[nParent].nFirstChild; + S.CounterInfo[nResult].nLevel = S.CounterInfo[nParent].nLevel + 1; + S.CounterInfo[nParent].nFirstChild = nResult; + } + else + { + S.CounterInfo[nResult].nLevel = 0; + } + return nResult; +} +void MicroProfileCounterTokenInitName(MicroProfileToken nToken, const char* pName) +{ + MP_ASSERT(0 == S.CounterInfo[nToken].pName); + S.CounterInfo[nToken].nNameLen = (uint16_t)strlen(pName); + S.CounterInfo[nToken].pName = MicroProfileStringInternLower(pName); +} + +MicroProfileToken MicroProfileGetCounterTokenByParent(int nParent, const char* pName, uint32_t nFlags) +{ + for(uint32_t i = 0; i < S.nNumCounters; ++i) + { + if(nParent == S.CounterInfo[i].nParent && S.CounterInfo[i].pName == pName) + { + return i; + } + } + if(0 != (MICROPROFILE_COUNTER_FLAG_TOKEN_DONT_CREATE & nFlags)) + return MICROPROFILE_INVALID_TOKEN; + MicroProfileToken nResult = MicroProfileCounterTokenInit(nParent, nFlags); + MicroProfileCounterTokenInitName(nResult, pName); + return nResult; +} + +// by passing in last token/parent, and a non-changing static string, +// we can quickly return in case the parent is the same as before. +// Note that this doesn't support paths, but instead must be called once per level in the tree +// String must be preinterned. +MicroProfileToken MicroProfileCounterTokenTree(MicroProfileToken* LastToken, MicroProfileToken CurrentParent, const char* pString) +{ + MicroProfileToken Token = *LastToken; + if(Token != MICROPROFILE_INVALID_TOKEN) + { + if(S.CounterInfo[Token].pName == pString && S.CounterInfo[Token].nParent == CurrentParent) + { + return Token; + } + } + MicroProfileInit(); + MicroProfileScopeLock L(MicroProfileMutex()); + Token = MicroProfileGetCounterTokenByParent(CurrentParent, pString, 0); + *LastToken = Token; + return Token; +} + +const char* MicroProfileCounterString(const char* pString) +{ + MicroProfileInit(); + MicroProfileScopeLock L(MicroProfileMutex()); + return MicroProfileStringInternLower(pString); +} + +// Same as above, but works with non-static strings. always takes a lock, and does a search, so expect this to be not cheap +MicroProfileToken MicroProfileCounterTokenTreeDynamic(MicroProfileToken* LastToken, MicroProfileToken Parent, const char* pString) +{ + (void)LastToken; + MicroProfileInit(); + MicroProfileScopeLock L(MicroProfileMutex()); + const char* pSubNameLower = MicroProfileStringInternLower(pString); + return MicroProfileGetCounterTokenByParent(Parent, pSubNameLower, 0); +} + +MicroProfileToken MicroProfileGetCounterToken(const char* pName, uint32_t CounterFlag) +{ + MicroProfileInit(); + MicroProfileScopeLock L(MicroProfileMutex()); + char SubName[MICROPROFILE_NAME_MAX_LEN]; + MicroProfileToken nResult = MICROPROFILE_INVALID_TOKEN; + do + { + uint32_t nLen = 0; + pName = MicroProfileNextName(pName, &SubName[0], &nLen); + if(0 == nLen) + { + break; + } + const char* pSubNameLower = MicroProfileStringInternLower(SubName); + nResult = MicroProfileGetCounterTokenByParent(nResult, pSubNameLower, 0); + if(MICROPROFILE_INVALID_TOKEN == nResult) + return nResult; + + } while(pName != 0); + S.CounterInfo[nResult].nFlags |= MICROPROFILE_COUNTER_FLAG_LEAF; + +#if MICROPROFILE_COUNTER_HISTORY + if(CounterFlag & MICROPROFILE_COUNTER_FLAG_DOUBLE) + { + S.CounterInfo[nResult].nFlags |= MICROPROFILE_COUNTER_FLAG_DOUBLE; + S.dCounterMax[nResult] = -DBL_MAX; + S.dCounterMin[nResult] = DBL_MAX; + } +#endif + + MP_ASSERT((int)nResult >= 0); + return nResult; +} + +MicroProfileToken MicroProfileGetChildCounterToken(MicroProfileToken Parent, const char* pName) +{ + MP_ASSERT(NULL == strpbrk(pName, "\\/")); // delimiters not supported when manually building the tree. + return MicroProfileCounterTokenTreeDynamic(nullptr, Parent, pName); +} + +inline void MicroProfileLogPut(MicroProfileLogEntry LE, MicroProfileThreadLog* pLog) +{ + MP_ASSERT(pLog != 0); // this assert is hit if MicroProfileOnCreateThread is not called + MP_ASSERT(pLog->nActive == 1); // Dont put after calling thread exit + uint32_t nPut = pLog->nPut.load(std::memory_order_relaxed); + uint32_t nNextPos = (nPut + 1) % MICROPROFILE_BUFFER_SIZE; + uint32_t nGet = pLog->nGet.load(std::memory_order_relaxed); + uint32_t nDistance = (nGet - nNextPos) % MICROPROFILE_BUFFER_SIZE; + MP_ASSERT(nDistance < MICROPROFILE_BUFFER_SIZE); + uint32_t nStackPut = pLog->nStackPut; + if(nDistance < nStackPut + 2) + { + S.nOverflow = 100; + } + else + { + pLog->Log[nPut] = LE; + pLog->nPut.store(nNextPos, std::memory_order_release); + } +} + +inline uint64_t MicroProfileLogPutEnter(MicroProfileToken nToken_, uint64_t nTick, MicroProfileThreadLog* pLog) +{ + MP_ASSERT(pLog != 0); // this assert is hit if MicroProfileOnCreateThread is not called + MP_ASSERT(pLog->nActive == 1); // Dont put after calling thread exit + uint32_t nStackPut = pLog->nStackPut; + if(nStackPut < MICROPROFILE_STACK_MAX) + { + uint64_t LE = MicroProfileMakeLogIndex(MP_LOG_ENTER, nToken_, nTick); + uint32_t nPut = pLog->nPut.load(std::memory_order_relaxed); + uint32_t nNextPos = (nPut + 1) % MICROPROFILE_BUFFER_SIZE; + uint32_t nGet = pLog->nGet.load(std::memory_order_acquire); + uint32_t nDistance = (nGet - nNextPos) % MICROPROFILE_BUFFER_SIZE; + MP_ASSERT(nDistance < MICROPROFILE_BUFFER_SIZE); + if(nDistance < nStackPut + 4) // 2 for ring buffer, 2 for the actual entries + { + S.nOverflow = 100; + return MICROPROFILE_INVALID_TICK; + } + else + { +#ifdef MICROPROFILE_VERIFY_BALANCED + pLog->VerifyStack[nStackPut] = LE; +#endif + pLog->nStackPut = nStackPut + 1; + pLog->Log[nPut] = LE; + pLog->nPut.store(nNextPos, std::memory_order_release); + return nTick; + } + } + else + { + S.nOverflow = 100; + pLog->nStackPut = nStackPut + 1; + return MICROPROFILE_DROPPED_TICK; + } +} + +inline uint64_t MicroProfileLogPutEnterCStr(const char* pStr, uint64_t nTick, MicroProfileThreadLog* pLog) +{ + MP_ASSERT(pLog != 0); // this assert is hit if MicroProfileOnCreateThread is not called + MP_ASSERT(pLog->nActive == 1); // Dont put after calling thread exit + uint32_t nStackPut = pLog->nStackPut; + if(nStackPut < MICROPROFILE_STACK_MAX) + { + uint64_t LE = MicroProfileMakeLogIndex(MP_LOG_ENTER, ETOKEN_CSTR_PTR, nTick); + uint64_t LEStr = MicroProfileMakeLogExtendedNoDataPtr((uint64_t)pStr); + + MP_ASSERT(ETOKEN_CSTR_PTR == MicroProfileLogGetTimerIndex(LE)); + + uint32_t nPut = pLog->nPut.load(std::memory_order_relaxed); + uint32_t nNextPos = (nPut + 2) % MICROPROFILE_BUFFER_SIZE; + uint32_t nGet = pLog->nGet.load(std::memory_order_acquire); + uint32_t nDistance = (nGet - nNextPos) % MICROPROFILE_BUFFER_SIZE; + MP_ASSERT(nDistance < MICROPROFILE_BUFFER_SIZE); + if(nDistance < nStackPut + 6) // 2 for ring buffer, 4 for the actual entries + { + S.nOverflow = 100; + return MICROPROFILE_INVALID_TICK; + } + else + { + pLog->nStackPut = nStackPut + 1; + pLog->Log[nPut + 0] = LE; + pLog->Log[(nPut + 1) % MICROPROFILE_BUFFER_SIZE] = LEStr; + pLog->nPut.store(nNextPos, std::memory_order_release); + return nTick; + } + } + else + { + S.nOverflow = 100; + pLog->nStackPut = nStackPut + 1; + return MICROPROFILE_DROPPED_TICK; + } +} +inline void MicroProfileLogPutLeaveCStr(const char* pStr, uint64_t nTick, MicroProfileThreadLog* pLog) +{ + MP_ASSERT(pLog != 0); // this assert is hit if MicroProfileOnCreateThread is not called + MP_ASSERT(pLog->nActive); + MP_ASSERT(pLog->nStackPut != 0); + uint32_t nStackPut = --(pLog->nStackPut); + MP_ASSERT(nStackPut < 0xf0000000); + if(nStackPut < MICROPROFILE_STACK_MAX) + { + uint64_t LE = MicroProfileMakeLogIndex(MP_LOG_LEAVE, ETOKEN_CSTR_PTR, nTick); + uint64_t LEStr = MicroProfileMakeLogExtendedNoDataPtr((uint64_t)pStr); + MP_ASSERT(ETOKEN_CSTR_PTR == MicroProfileLogGetTimerIndex(LE)); + + uint32_t nPos = pLog->nPut.load(std::memory_order_relaxed); + uint32_t nNextPos = (nPos + 2) % MICROPROFILE_BUFFER_SIZE; + + uint32_t nGet = pLog->nGet.load(std::memory_order_acquire); + MP_ASSERT(nStackPut < MICROPROFILE_STACK_MAX); + MP_ASSERT(nNextPos != nGet); // should never happen + pLog->Log[nPos + 0] = LE; + pLog->Log[(nPos + 1) % MICROPROFILE_BUFFER_SIZE] = LEStr; + + pLog->nPut.store(nNextPos, std::memory_order_release); + } +} + +inline void MicroProfileLogPutLeave(MicroProfileToken nToken_, uint64_t nTick, MicroProfileThreadLog* pLog) +{ + MP_ASSERT(pLog != 0); // this assert is hit if MicroProfileOnCreateThread is not called + MP_ASSERT(pLog->nActive); + MP_ASSERT(pLog->nStackPut != 0); + uint32_t nStackPut = --(pLog->nStackPut); + if(nStackPut < MICROPROFILE_STACK_MAX) + { + uint64_t LE = MicroProfileMakeLogIndex(MP_LOG_LEAVE, nToken_, nTick); + uint32_t nPos = pLog->nPut.load(std::memory_order_relaxed); + uint32_t nNextPos = (nPos + 1) % MICROPROFILE_BUFFER_SIZE; + + uint32_t nGet = pLog->nGet.load(std::memory_order_acquire); + MP_ASSERT(nStackPut < MICROPROFILE_STACK_MAX); + MP_ASSERT(nNextPos != nGet); // should never happen + +#ifdef MICROPROFILE_VERIFY_BALANCED + // verify what we pop is what we push. + uint64_t Pushed = pLog->VerifyStack[nStackPut]; + uint64_t TimerPopped = MicroProfileLogGetTimerIndex(LE); + uint64_t TimerOnStack = MicroProfileLogGetTimerIndex(Pushed); + if(TimerPopped != TimerOnStack) + { + uprintf("Push/Pop Mismatch %s vs %s\n", S.TimerInfo[TimerPopped].pName, S.TimerInfo[TimerOnStack].pName); + MP_ASSERT(0); + } +#endif + + pLog->Log[nPos] = LE; + pLog->nPut.store(nNextPos, std::memory_order_release); + } +} + +inline void MicroProfileLogPut(MicroProfileToken nToken_, uint64_t nTick, uint64_t nBegin, MicroProfileThreadLog* pLog) +{ + MicroProfileLogPut(MicroProfileMakeLogIndex(nBegin, nToken_, nTick), pLog); +} + +inline void MicroProfileLogPutGpu(MicroProfileLogEntry LE, MicroProfileThreadLogGpu* pLog) +{ + uint32_t nPos = pLog->nPut; + if(nPos < MICROPROFILE_GPU_BUFFER_SIZE) + { + pLog->Log[nPos] = LE; + pLog->nPut = nPos + 1; + } +} + +inline void MicroProfileLogPutGpuTimer(MicroProfileToken nToken_, uint64_t nTick, uint64_t nBegin, MicroProfileThreadLogGpu* pLog) +{ + MicroProfileLogPutGpu(MicroProfileMakeLogIndex(nBegin, nToken_, nTick), pLog); +} + +inline void MicroProfileLogPutGpuExtended(EMicroProfileTokenExtended eTokenExt, uint32_t nDataSizeQWords, uint32_t nPayload, MicroProfileThreadLogGpu* pLog) +{ + MicroProfileLogEntry LE = MicroProfileMakeLogExtended(eTokenExt, nDataSizeQWords, nPayload); + MicroProfileLogPutGpu(LE, pLog); +} + +inline void MicroProfileLogPutGpuExtendedNoData(EMicroProfileTokenExtended eTokenExt, uint64_t nPayload, MicroProfileThreadLogGpu* pLog) +{ + MicroProfileLogEntry LE = MicroProfileMakeLogExtendedNoData(eTokenExt, nPayload); + MicroProfileLogPutGpu(LE, pLog); +} + +uint32_t MicroProfileGroupTokenActive(MicroProfileToken nToken_) +{ + uint32_t nMask = MicroProfileGetGroupMask(nToken_); + uint32_t nIndex = MicroProfileGetGroupMaskIndex(nToken_); + return 0 != (S.nActiveGroups[nIndex] & nMask); +} + +uint64_t MicroProfileEnterInternal(MicroProfileToken nToken_) +{ + if(MicroProfileGroupTokenActive(nToken_)) + { + uint64_t nTick = MP_TICK(); + if(MICROPROFILE_PLATFORM_MARKERS_ENABLED) + { + uint32_t idx = MicroProfileGetTimerIndex(nToken_); + MicroProfileTimerInfo& TI = S.TimerInfo[idx]; + MICROPROFILE_PLATFORM_MARKER_BEGIN(TI.nColor, TI.pNameExt); + return nTick; + } + else + { + return MicroProfileLogPutEnter(nToken_, nTick, MicroProfileGetThreadLog2()); + } + } + return MICROPROFILE_INVALID_TICK; +} + +uint64_t MicroProfileEnterInternalCStr(const char* pStr) +{ + if(S.AnyActive) + { + uint64_t nTick = MP_TICK(); + if(MICROPROFILE_PLATFORM_MARKERS_ENABLED) + { + MICROPROFILE_PLATFORM_MARKER_BEGIN(0, pStr); + return nTick; + } + else + { + return MicroProfileLogPutEnterCStr(pStr, nTick, MicroProfileGetThreadLog2()); + } + } + return MICROPROFILE_INVALID_TICK; +} + +void MicroProfileTimelineLeave(uint32_t id) +{ + if(!id) + return; + std::lock_guard Lock(MicroProfileTimelineMutex()); + MicroProfileThreadLog* pLog = &S.TimelineLog; + uint32_t nPut = pLog->nPut.load(std::memory_order_relaxed); + uint32_t nNextPos = (nPut + 1) % MICROPROFILE_BUFFER_SIZE; + uint32_t nGet = pLog->nGet.load(std::memory_order_acquire); + uint32_t nDistance = (nGet - nNextPos) % MICROPROFILE_BUFFER_SIZE; + + { + uint32_t nFrameStart = S.TimelineTokenFrameEnter[id % MICROPROFILE_TIMELINE_MAX_TOKENS]; + uint32_t nFrameCurrent = S.nFrameCurrent; + if(nFrameCurrent < nFrameStart) + nFrameCurrent += MICROPROFILE_MAX_FRAME_HISTORY; + uint32_t nFrameDistance = (nFrameCurrent - nFrameStart) % MICROPROFILE_MAX_FRAME_HISTORY; + + S.TimelineTokenFrameEnter[id % MICROPROFILE_TIMELINE_MAX_TOKENS] = MICROPROFILE_INVALID_FRAME; + S.TimelineTokenFrameLeave[id % MICROPROFILE_TIMELINE_MAX_TOKENS] = nFrameCurrent; + + S.TimelineToken[id % MICROPROFILE_TIMELINE_MAX_TOKENS] = 0; + S.nTimelineFrameMax = MicroProfileMax(S.nTimelineFrameMax, nFrameDistance); + } + + if(nDistance < 2 + 4) + { + S.nOverflow = 100; + } + else + { + uint64_t LEEnter = MicroProfileMakeLogIndex(MP_LOG_LEAVE, ETOKEN_CUSTOM_NAME, MP_TICK()); + uint64_t LEId = MicroProfileMakeLogExtended(ETOKEN_CUSTOM_ID, 0, id); + + pLog->Log[nPut++] = LEEnter; + nPut %= MICROPROFILE_BUFFER_SIZE; + pLog->Log[nPut++] = LEId; + nPut %= MICROPROFILE_BUFFER_SIZE; + pLog->nPut.store(nPut); + } +} + +void MicroProfileTimelineEnterStatic(uint32_t nColor, const char* pStr) +{ + if(!S.AnyActive) + return; + uint32_t nToken = MicroProfileTimelineEnterInternal(nColor, pStr, (uint32_t)strlen(pStr), true); + (void)nToken; +} +void MicroProfileTimelineLeaveStatic(const char* pStr) +{ + if(!S.AnyActive) + return; + + for(uint32_t i = 0; i < MICROPROFILE_TIMELINE_MAX_TOKENS; ++i) + { + if(S.TimelineTokenStaticString[i] && 0 == MP_STRCASECMP(pStr, S.TimelineTokenStaticString[i])) + { + MicroProfileTimelineLeave(S.TimelineToken[i]); + } + } +} + +uint32_t MicroProfileTimelineEnterInternal(uint32_t nColor, const char* pStr, uint32_t nStrLen, int bIsStaticString) +{ + if(!S.AnyActive) + return 0; + std::lock_guard Lock(MicroProfileTimelineMutex()); + MicroProfileThreadLog* pLog = &S.TimelineLog; + MP_ASSERT(pStr[nStrLen] == '\0'); + nStrLen += 1; + uint32_t nStringQwords = MicroProfileGetQWordSize(nStrLen); + uint32_t nNumMessages = nStringQwords; + + uint32_t nPut = pLog->nPut.load(std::memory_order_relaxed); + uint32_t nNextPos = (nPut + 1) % MICROPROFILE_BUFFER_SIZE; + uint32_t nGet = pLog->nGet.load(std::memory_order_acquire); + uint32_t nDistance = (nGet - nNextPos) % MICROPROFILE_BUFFER_SIZE; + + if(nDistance < nNumMessages + 7) + { + S.nOverflow = 100; + return 0; + } + else + { + + uint32_t token = pLog->nCustomId; + uint32_t nFrameLeave = S.TimelineTokenFrameLeave[token % MICROPROFILE_TIMELINE_MAX_TOKENS]; + uint32_t nFrameEnter = S.TimelineTokenFrameEnter[token % MICROPROFILE_TIMELINE_MAX_TOKENS]; + uint32_t nCounter = 0; + uint32_t nFrameCurrent = S.nFrameCurrent; + { + + /// dont reuse tokens until their leave command has been dead for the maximum amount of frames we can generate a capture for. + while(token == 0 || nFrameEnter != MICROPROFILE_INVALID_FRAME || (nFrameCurrent - nFrameLeave < MICROPROFILE_MAX_FRAME_HISTORY + 3 && nFrameLeave != MICROPROFILE_INVALID_FRAME)) + { + token = (uint32_t)pLog->nCustomId++; + nFrameLeave = S.TimelineTokenFrameLeave[token % MICROPROFILE_TIMELINE_MAX_TOKENS]; + nFrameEnter = S.TimelineTokenFrameEnter[token % MICROPROFILE_TIMELINE_MAX_TOKENS]; + if(++nCounter == MICROPROFILE_TIMELINE_MAX_TOKENS) + { + // MP_BREAK(); + return 0; + } + } + S.TimelineTokenFrameEnter[token % MICROPROFILE_TIMELINE_MAX_TOKENS] = S.nFrameCurrent; + } + if(bIsStaticString) + { + S.TimelineTokenStaticString[token % MICROPROFILE_TIMELINE_MAX_TOKENS] = pStr; + } + else + { + S.TimelineTokenStaticString[token % MICROPROFILE_TIMELINE_MAX_TOKENS] = nullptr; + } + S.TimelineToken[token % MICROPROFILE_TIMELINE_MAX_TOKENS] = token; + + uint64_t LEEnter = MicroProfileMakeLogIndex(MP_LOG_ENTER, ETOKEN_CUSTOM_NAME, MP_TICK()); + uint64_t LEColor = MicroProfileMakeLogExtended(ETOKEN_CUSTOM_COLOR, 0, nColor); + uint64_t LEId = MicroProfileMakeLogExtended(ETOKEN_CUSTOM_ID, nStringQwords, token); + + pLog->Log[nPut++] = LEEnter; + nPut %= MICROPROFILE_BUFFER_SIZE; + pLog->Log[nPut++] = LEColor; + nPut %= MICROPROFILE_BUFFER_SIZE; + pLog->Log[nPut++] = LEId; + nPut %= MICROPROFILE_BUFFER_SIZE; + + // copy if we dont wrap + if(nPut + nStringQwords <= MICROPROFILE_BUFFER_SIZE) + { + memcpy(&pLog->Log[nPut], pStr, nStrLen + 1); + nPut += nStringQwords; + } + else + { + int nCharsLeft = (int)nStrLen; + while(nCharsLeft > 0) + { + int nCount = MicroProfileMin(nCharsLeft, 8); + memcpy(&pLog->Log[nPut++], pStr, nCount); + // uint64_t LEPayload = MicroProfileMakeLogPayload(pStr, nCount); + // pLog->Log[nPut++] = LEPayload; nPut %= MICROPROFILE_BUFFER_SIZE; + pStr += nCount; + nCharsLeft -= nCount; + } + } + pLog->nPut.store(nPut); + return token; + } +} + +uint32_t MicroProfileTimelineEnter(uint32_t nColor, const char* pStr) +{ + return MicroProfileTimelineEnterInternal(nColor, pStr, (uint32_t)strlen(pStr), false); +} + +uint32_t MicroProfileTimelineEnterf(uint32_t nColor, const char* pStr, ...) +{ + if(!S.AnyActive) + return 0; + char buffer[MICROPROFILE_MAX_STRING + 1]; + va_list args; + va_start(args, pStr); +#ifdef _WIN32 + size_t size = vsprintf_s(buffer, pStr, args); +#else + size_t size = vsnprintf(buffer, sizeof(buffer) - 1, pStr, args); +#endif + va_end(args); + MP_ASSERT(size < sizeof(buffer)); + buffer[size] = '\0'; + return MicroProfileTimelineEnterInternal(nColor, buffer, (uint32_t)size, false); +} + +void MicroProfileLocalCounterAdd(int64_t* pCounter, int64_t nCount) +{ + *pCounter += nCount; +} +int64_t MicroProfileLocalCounterSet(int64_t* pCounter, int64_t nCount) +{ + int64_t r = *pCounter; + *pCounter = nCount; + return r; +} + +void MicroProfileLocalCounterAddAtomic(MicroProfileToken nToken, int64_t nCount) +{ + std::atomic* pCounter = &S.CounterInfo[nToken].ExternalAtomic; + pCounter->fetch_add(nCount); +} +int64_t MicroProfileLocalCounterSetAtomic(MicroProfileToken nToken, int64_t nCount) +{ + + std::atomic* pCounter = &S.CounterInfo[nToken].ExternalAtomic; + return pCounter->exchange(nCount); +} + +void MicroProfileCounterAdd(MicroProfileToken nToken, int64_t nCount) +{ + MP_ASSERT(nToken < S.nNumCounters); + S.Counters[nToken].fetch_add(nCount); +} +void MicroProfileCounterSet(MicroProfileToken nToken, int64_t nCount) +{ + MP_ASSERT(nToken < S.nNumCounters); + S.Counters[nToken].store(nCount); +} +int64_t MicroProfileCounterGet(MicroProfileToken nToken) +{ + MP_ASSERT(nToken < S.nNumCounters); + return S.Counters[nToken].load(); +} + +void MicroProfileCounterSetDouble(MicroProfileToken nToken, double nCount) +{ + MP_ASSERT(nToken < S.nNumCounters); + MP_ASSERT((S.CounterInfo[nToken].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) == MICROPROFILE_COUNTER_FLAG_DOUBLE); + S.CountersDouble[nToken].store(nCount); +} +double MicroProfileCounterGetDouble(MicroProfileToken nToken) +{ + MP_ASSERT(nToken < S.nNumCounters); + MP_ASSERT((S.CounterInfo[nToken].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) == MICROPROFILE_COUNTER_FLAG_DOUBLE); + return S.CountersDouble[nToken].load(); +} +void MicroProfileCounterSetLimit(MicroProfileToken nToken, int64_t nCount) +{ + MP_ASSERT(nToken < S.nNumCounters); + S.CounterInfo[nToken].nLimit = nCount; +} + +void MicroProfileCounterSetLimitDouble(MicroProfileToken nToken, double dCount) +{ + MP_ASSERT(nToken < S.nNumCounters); + MP_ASSERT((S.CounterInfo[nToken].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) == MICROPROFILE_COUNTER_FLAG_DOUBLE); + S.CounterInfo[nToken].dLimit = dCount; +} + +void MicroProfileCounterConfigToken(MicroProfileToken nToken, uint32_t eFormat, int64_t nLimit, uint32_t nFlags) +{ + S.CounterInfo[nToken].eFormat = (MicroProfileCounterFormat)eFormat; + S.CounterInfo[nToken].nLimit = nLimit; + S.CounterInfo[nToken].nFlags |= (nFlags & ~MICROPROFILE_COUNTER_FLAG_INTERNAL_MASK); +} + +void MicroProfileCounterConfig(const char* pName, uint32_t eFormat, int64_t nLimit, uint32_t nFlags) +{ + MicroProfileToken nToken = MicroProfileGetCounterToken(pName, 0); + MicroProfileCounterConfigToken(nToken, eFormat, nLimit, nFlags); +} + +void MicroProfileCounterSetPtr(const char* pCounterName, void* pSource, uint32_t nSize) +{ + MicroProfileToken nToken = MicroProfileGetCounterToken(pCounterName, 0); + S.CounterSource[nToken].pSource = pSource; + S.CounterSource[nToken].nSourceSize = nSize; +} + +inline void MicroProfileFetchCounter(uint32_t i) +{ + MP_ASSERT(0 == S.CounterSource[i].nSourceSize || (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) == MICROPROFILE_COUNTER_FLAG_DOUBLE); + switch(S.CounterSource[i].nSourceSize) + { + case sizeof(int32_t): + S.Counters[i] = *(int32_t*)S.CounterSource[i].pSource; + break; + case sizeof(int64_t): + S.Counters[i] = *(int64_t*)S.CounterSource[i].pSource; + break; + default: + break; + } +} +void MicroProfileCounterFetchCounters() +{ + for(uint32_t i = 0; i < S.nNumCounters; ++i) + { + MicroProfileFetchCounter(i); + } +} + +void MicroProfileLeaveInternal(MicroProfileToken nToken_, uint64_t nTickStart) +{ + if(MICROPROFILE_INVALID_TICK != nTickStart) + { + if(MICROPROFILE_PLATFORM_MARKERS_ENABLED) + { + MICROPROFILE_PLATFORM_MARKER_END(); + } + else + { + uint64_t nTick = MP_TICK(); + MicroProfileThreadLog* pLog = MicroProfileGetThreadLog2(); + MicroProfileLogPutLeave(nToken_, nTick, pLog); + } + } +} + +void MicroProfileLeaveInternalCStr(const char* pStr, uint64_t nTickStart) +{ + if(MICROPROFILE_INVALID_TICK != nTickStart) + { + if(MICROPROFILE_PLATFORM_MARKERS_ENABLED) + { + MICROPROFILE_PLATFORM_MARKER_END(); + } + else + { + uint64_t nTick = MP_TICK(); + MicroProfileThreadLog* pLog = MicroProfileGetThreadLog2(); + MicroProfileLogPutLeaveCStr(pStr, nTick, pLog); + } + } +} + +void MicroProfileEnter(MicroProfileToken nToken) +{ + MicroProfileThreadLog* pLog = MicroProfileGetThreadLog2(); + MP_ASSERT(pLog->nStackScope < MICROPROFILE_STACK_MAX); // if youre hitting this assert you probably have mismatched _ENTER/_LEAVE markers + uint32_t nStackPos = pLog->nStackScope++; + if(nStackPos < MICROPROFILE_STACK_MAX) + { + MicroProfileScopeStateC* pScopeState = &pLog->ScopeState[nStackPos]; + pScopeState->Token = nToken; + pScopeState->nTick = MicroProfileEnterInternal(nToken); + } + else + { + S.nOverflow = 100; + } +} +void MicroProfileLeave() +{ + MicroProfileThreadLog* pLog = MicroProfileGetThreadLog2(); + MP_ASSERT(pLog->nStackScope > 0); // if youre hitting this assert you probably have mismatched _ENTER/_LEAVE markers + uint32_t nStackPos = --pLog->nStackScope; + if(nStackPos < MICROPROFILE_STACK_MAX) + { + MicroProfileScopeStateC* pScopeState = &pLog->ScopeState[nStackPos]; + MicroProfileLeaveInternal(pScopeState->Token, pScopeState->nTick); + } + else + { + S.nOverflow = 100; + } +} + +void MicroProfileEnterGpu(MicroProfileToken nToken, MicroProfileThreadLogGpu* pLog) +{ + // MP_ASSERT(pLog->nStackScope < MICROPROFILE_STACK_MAX); // if youre hitting this assert you probably have mismatched _ENTER/_LEAVE markers + uint32_t nStackPos = pLog->nStackScope++; + if(nStackPos < MICROPROFILE_STACK_MAX) + { + MicroProfileScopeStateC* pScopeState = &pLog->ScopeState[nStackPos]; + pScopeState->Token = nToken; + pScopeState->nTick = MicroProfileGpuEnterInternal(pLog, nToken); + } + else + { + S.nOverflow = 100; + } +} +void MicroProfileLeaveGpu(MicroProfileThreadLogGpu* pLog) +{ + uint32_t nStackPos = --pLog->nStackScope; + if(nStackPos < MICROPROFILE_STACK_MAX) + { + MicroProfileScopeStateC* pScopeState = &pLog->ScopeState[nStackPos]; + MicroProfileGpuLeaveInternal(pLog, pScopeState->Token, pScopeState->nTick); + } +} + +void MicroProfileGpuBegin(void* pContext, MicroProfileThreadLogGpu* pLog) +{ + MP_ASSERT(pLog->pContext == (void*)-1); // dont call begin without calling end + MP_ASSERT(pLog->nStart == (uint32_t)-1); + MP_ASSERT(pContext != (void*)-1); + + pLog->pContext = pContext; + pLog->nStart = pLog->nPut; + MicroProfileLogPutGpu(0, pLog); +} + +void MicroProfileGpuSetContext(void* pContext, MicroProfileThreadLogGpu* pLog) +{ + MP_ASSERT(pLog->pContext != (void*)-1); // dont call begin without calling end + MP_ASSERT(pLog->nStart != (uint32_t)-1); + pLog->pContext = pContext; +} + +uint64_t MicroProfileGpuEnd(MicroProfileThreadLogGpu* pLog) +{ + uint64_t nStart = pLog->nStart; + uint32_t nEnd = pLog->nPut; + uint64_t nId = pLog->nId; + if(nStart < MICROPROFILE_GPU_BUFFER_SIZE) + { + pLog->Log[nStart] = nEnd - nStart - 1; + } + pLog->pContext = (void*)-1; + pLog->nStart = (uint32_t)-1; + return nStart | (nId << 32); +} + +void MicroProfileGpuSubmit(int nQueue, uint64_t nWork) +{ + MP_ASSERT(nQueue >= 0 && nQueue < MICROPROFILE_MAX_THREADS); + MICROPROFILE_SCOPE(g_MicroProfileGpuSubmit); + uint32_t nStart = (uint32_t)nWork; + uint32_t nThreadLog = uint32_t(nWork >> 32); + + MicroProfileThreadLog* pQueueLog = S.Pool[nQueue]; + MP_ASSERT(nQueue < MICROPROFILE_MAX_THREADS); + MicroProfileThreadLogGpu* pGpuLog = S.PoolGpu[nThreadLog]; + MP_ASSERT(pGpuLog); + + int64_t nCount = 0; + if(nStart < MICROPROFILE_GPU_BUFFER_SIZE) + { + nCount = pGpuLog->Log[nStart]; + } + MP_ASSERT(nCount < (int64_t)MICROPROFILE_GPU_BUFFER_SIZE); + nStart++; + for(int32_t i = 0; i < nCount; ++i) + { + MP_ASSERT(nStart < MICROPROFILE_GPU_BUFFER_SIZE); + MicroProfileLogEntry LE = pGpuLog->Log[nStart++]; + MicroProfileLogPut(LE, pQueueLog); + } +} + +uint64_t MicroProfileGpuEnterInternal(MicroProfileThreadLogGpu* pGpuLog, MicroProfileToken nToken_) +{ + if(MicroProfileGroupTokenActive(nToken_)) + { + if(!MicroProfileGetThreadLog()) + { + MicroProfileInitThreadLog(); + } + + MP_ASSERT(pGpuLog->pContext != (void*)-1); // must be called between GpuBegin/GpuEnd + uint64_t nTimer = MicroProfileGpuInsertTimeStamp(pGpuLog->pContext); + MicroProfileLogPutGpuTimer(nToken_, nTimer, MP_LOG_ENTER, pGpuLog); + MicroProfileThreadLog* pLog = MicroProfileGetThreadLog(); + + MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_TIMESTAMP, MP_TICK(), pGpuLog); + MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_SOURCE_THREAD, pLog->nLogIndex, pGpuLog); + // MP_ASSERT(pGpuLog->pContext != (void*)-1); // must be called between GpuBegin/GpuEnd + // uint64_t nTimer = MicroProfileGpuInsertTimeStamp(pGpuLog->pContext); + // MicroProfileLogPutGpu(nToken_, nTimer, MP_LOG_ENTER, pGpuLog); + // MicroProfileThreadLog* pLog = MicroProfileGetThreadLog(); + // MicroProfileLogPutGpu(ETOKEN_GPU_CPU_TIMESTAMP, MP_TICK(), MP_LOG_EXTRA_DATA, pGpuLog); + // MicroProfileLogPutGpu(ETOKEN_GPU_CPU_SOURCE_THREAD, pLog->nLogIndex, MP_LOG_EXTRA_DATA, pGpuLog); + + return 1; + } + return 0; +} + +uint64_t MicroProfileGpuEnterInternalCStr(MicroProfileThreadLogGpu* pGpuLog, const char* pStr) +{ + MP_BREAK(); // not implemented + return 0; + // if(S.AnyGpuActive) + // { + // if(!MicroProfileGetThreadLog()) + // { + // MicroProfileInitThreadLog(); + // } + + // MP_ASSERT(pGpuLog->pContext != (void*)-1); // must be called between GpuBegin/GpuEnd + // uint64_t nTimer = MicroProfileGpuInsertTimeStamp(pGpuLog->pContext); + // MicroProfileLogPutGpuTimer(nToken_, nTimer, MP_LOG_ENTER, pGpuLog); + // MicroProfileThreadLog* pLog = MicroProfileGetThreadLog(); + + // MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_TIMESTAMP, MP_TICK(), pGpuLog); + // MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_SOURCE_THREAD, pLog->nLogIndex, pGpuLog); + // // MP_ASSERT(pGpuLog->pContext != (void*)-1); // must be called between GpuBegin/GpuEnd + // // uint64_t nTimer = MicroProfileGpuInsertTimeStamp(pGpuLog->pContext); + // // MicroProfileLogPutGpu(nToken_, nTimer, MP_LOG_ENTER, pGpuLog); + // // MicroProfileThreadLog* pLog = MicroProfileGetThreadLog(); + // // MicroProfileLogPutGpu(ETOKEN_GPU_CPU_TIMESTAMP, MP_TICK(), MP_LOG_EXTRA_DATA, pGpuLog); + // // MicroProfileLogPutGpu(ETOKEN_GPU_CPU_SOURCE_THREAD, pLog->nLogIndex, MP_LOG_EXTRA_DATA, pGpuLog); + + // return 1; + // } + // return 0; +} + +void MicroProfileGpuLeaveInternal(MicroProfileThreadLogGpu* pGpuLog, MicroProfileToken nToken_, uint64_t nTickStart) +{ + if(nTickStart) + { + if(!MicroProfileGetThreadLog()) + { + MicroProfileInitThreadLog(); + } + + MP_ASSERT(pGpuLog->pContext != (void*)-1); // must be called between GpuBegin/GpuEnd + uint64_t nTimer = MicroProfileGpuInsertTimeStamp(pGpuLog->pContext); + MicroProfileLogPutGpuTimer(nToken_, nTimer, MP_LOG_LEAVE, pGpuLog); + MicroProfileThreadLog* pLog = MicroProfileGetThreadLog(); + MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_TIMESTAMP, MP_TICK(), pGpuLog); + MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_SOURCE_THREAD, pLog->nLogIndex, pGpuLog); + } +} + +void MicroProfileGpuLeaveInternalCStr(MicroProfileThreadLogGpu* pGpuLog, uint64_t nTickStart) +{ + MP_BREAK(); // not implemented + return; + // if(nTickStart) + // { + // if(!MicroProfileGetThreadLog()) + // { + // MicroProfileInitThreadLog(); + // } + + // MP_ASSERT(pGpuLog->pContext != (void*)-1); // must be called between GpuBegin/GpuEnd + // uint64_t nTimer = MicroProfileGpuInsertTimeStamp(pGpuLog->pContext); + // MicroProfileLogPutGpuTimer(nToken_, nTimer, MP_LOG_LEAVE, pGpuLog); + // MicroProfileThreadLog* pLog = MicroProfileGetThreadLog(); + // MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_TIMESTAMP, MP_TICK(), pGpuLog); + // MicroProfileLogPutGpuExtendedNoData(ETOKEN_GPU_CPU_SOURCE_THREAD, pLog->nLogIndex, pGpuLog); + // } +} + +void MicroProfileContextSwitchPut(MicroProfileContextSwitch* pContextSwitch) +{ + if(0 == S.nPauseTicks || (S.nPauseTicks - pContextSwitch->nTicks) > 0) + { + uint32_t nPut = S.nContextSwitchPut; + S.ContextSwitch[nPut] = *pContextSwitch; + S.nContextSwitchPut = (S.nContextSwitchPut + 1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE; + // if(S.nContextSwitchPut < nPut) + //{ + // float fMsDelay = MicroProfileTickToMsMultiplierCpu() * ((int64_t)S.nFlipStartTick - pContextSwitch->nTicks); + // uprintf("context switch wrap .. %7.3fms\n", fMsDelay); + // } + // if(S.nContextSwitchPut % 1024 == 0) + //{ + // float fMsDelay = MicroProfileTickToMsMultiplierCpu() * ((int64_t)S.nFlipStartTick - pContextSwitch->nTicks); + // uprintf("cswitch tick %x ... %7.3fms\n", S.nContextSwitchPut, fMsDelay); + // } + S.nContextSwitchLastPushed = pContextSwitch->nTicks; + } + else + { + S.nContextSwitchStalledTick = MP_TICK(); + } +} + +void MicroProfileGetRange(uint32_t nPut, uint32_t nGet, uint32_t nRange[2][2]) +{ + if(nPut > nGet) + { + nRange[0][0] = nGet; + nRange[0][1] = nPut; + nRange[1][0] = nRange[1][1] = 0; + } + else if(nPut != nGet) + { + MP_ASSERT(nGet != MICROPROFILE_BUFFER_SIZE); + uint32_t nCountEnd = MICROPROFILE_BUFFER_SIZE - nGet; + nRange[0][0] = nGet; + nRange[0][1] = nGet + nCountEnd; + nRange[1][0] = 0; + nRange[1][1] = nPut; + } +} + +void MicroProfileToggleFrozen() +{ + S.nFrozen = !S.nFrozen; +} + +int MicroProfileIsFrozen() +{ + return S.nFrozen != 0 ? 1 : 0; +} +int MicroProfileEnabled() +{ + return MicroProfileAnyGroupActive(); +} +void* MicroProfileAllocInternal(size_t nSize, size_t nAlign) +{ + nAlign = MicroProfileMax(4 * sizeof(uint32_t), nAlign); + nSize += nAlign; + intptr_t nPtr = (intptr_t)MICROPROFILE_ALLOC(nSize, nAlign); + nPtr += nAlign; + uint32_t* pVal = (uint32_t*)nPtr; + MP_ASSERT(nSize < 0xffffffff); + MP_ASSERT(nAlign < 0xffffffff); + pVal[-1] = (uint32_t)nSize; + pVal[-2] = (uint32_t)nAlign; + pVal[-3] = (uint32_t)0x28586813; + MicroProfileCounterAdd(S.CounterToken_Alloc_Memory, nSize); + MicroProfileCounterAdd(S.CounterToken_Alloc_Count, 1); + return (void*)nPtr; +} +void MicroProfileFreeInternal(void* pPtr) +{ + intptr_t p = (intptr_t)pPtr; + uint32_t* p4 = (uint32_t*)pPtr; + uint32_t nSize = p4[-1]; + uint32_t nAlign = p4[-2]; + uint32_t nMagic = p4[-3]; + MP_ASSERT(nMagic == 0x28586813); + MICROPROFILE_FREE((void*)(p - nAlign)); + MicroProfileCounterAdd(S.CounterToken_Alloc_Memory, -(int)nSize); + MicroProfileCounterAdd(S.CounterToken_Alloc_Count, -1); +} +void* MicroProfileReallocInternal(void* pPtr, size_t nSize) +{ + intptr_t p = (intptr_t)pPtr; + uint32_t nAlignBase; + + if(p) + { + uint32_t* p4 = (uint32_t*)pPtr; + uint32_t nSizeBase = p4[-1]; + nAlignBase = p4[-2]; + uint32_t nMagicBase = p4[-3]; + MP_ASSERT(nMagicBase == 0x28586813); + + MicroProfileCounterAdd(S.CounterToken_Alloc_Memory, nSize - nSizeBase); + } + else + { + nAlignBase = 4 * sizeof(uint32_t); + MicroProfileCounterAdd(S.CounterToken_Alloc_Memory, nSize + nAlignBase); + MicroProfileCounterAdd(S.CounterToken_Alloc_Count, 1); + } + + nSize += nAlignBase; + MP_ASSERT(nAlignBase >= 4 * sizeof(uint32_t)); + if(p) + { + p = (intptr_t)MICROPROFILE_REALLOC((void*)(p - nAlignBase), nSize); + } + else + { + p = (intptr_t)MICROPROFILE_REALLOC((void*)(p), nSize); + } + p += nAlignBase; + uint32_t* pVal = (uint32_t*)p; + MP_ASSERT(nSize < 0xffffffff); + MP_ASSERT(nAlignBase < 0xffffffff); + pVal[-1] = (uint32_t)nSize; + pVal[-2] = (uint32_t)nAlignBase; + pVal[-3] = (uint32_t)0x28586813; + return (void*)p; +} + +static void MicroProfileFlipEnabled() +{ + if(S.nFrozen) + { + memset(S.nActiveGroups, 0, sizeof(S.nActiveGroups)); + S.AnyActive = false; + } + else + { + bool AnyActive = false; + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i) + { + uint32_t nNew = S.nActiveGroupsWanted[i]; + nNew |= S.nForceGroups[i]; + if(nNew) + AnyActive = true; + if(S.nActiveGroups[i] != nNew) + { + S.nActiveGroups[i] = nNew; + } + } + S.AnyActive = AnyActive; + } +} + +void MicroProfileFlip(void* pContext, uint32_t FlipFlag) +{ + MicroProfileFlip_CB(pContext, nullptr, FlipFlag); +} + +#define MICROPROFILE_TICK_VALIDATE_FRAME_TIME 0 + +void MicroProfileFlip_CB(void* pContext, MicroProfileOnFreeze FreezeCB, uint32_t FlipFlag) +{ + MICROPROFILE_COUNTER_LOCAL_UPDATE_SET_ATOMIC(g_MicroProfileBytesPerFlip); +#if 0 + //verify LogEntry wraps correctly + MicroProfileLogEntry c = MP_LOG_TICK_MASK-5000; + for(int i = 0; i < 10000; ++i, c += 1) + { + MicroProfileLogEntry l2 = (c+2500) & MP_LOG_TICK_MASK; + MP_ASSERT(2500 == MicroProfileLogTickDifference(c, l2)); + } +#endif + MICROPROFILE_SCOPE(g_MicroProfileFlip); + std::lock_guard Lock(MicroProfileMutex()); + + if(S.nDumpFileNextFrame) + { + if(0 == S.nDumpFileCountDown) + { + MicroProfileDumpToFile(); + S.nDumpFileNextFrame = 0; + S.nAutoClearFrames = MICROPROFILE_GPU_FRAME_DELAY + 3; // hide spike from dumping webpage + } + else + { + S.nDumpFileCountDown--; + } + } +#if MICROPROFILE_WEBSERVER + if(MICROPROFILE_FLIP_FLAG_START_WEBSERVER == (MICROPROFILE_FLIP_FLAG_START_WEBSERVER & FlipFlag) && S.nWebServerDataSent == (uint64_t)-1) + { + MicroProfileWebServerStart(); + S.nWebServerDataSent = 0; + if(!S.WebSocketThreadRunning) + { + S.WebSocketThreadRunning = 1; + MicroProfileThreadStart(&S.WebSocketSendThread, MicroProfileSocketSenderThread); + } + } +#endif + + int nLoop = 0; + do + { +#if MICROPROFILE_WEBSERVER + if(MicroProfileWebServerUpdate()) + { + S.nAutoClearFrames = MICROPROFILE_GPU_FRAME_DELAY + 3; // hide spike from dumping webpage + } +#endif + if(nLoop++) + { + MicroProfileSleep(100); + if((nLoop % 10) == 0) + { + uprintf("microprofile frozen %d\n", nLoop); + } + } + } while(S.nFrozen); + + uint32_t nAggregateClear = S.nAggregateClear || S.nAutoClearFrames, nAggregateFlip = 0; + + if(S.nAutoClearFrames) + { + nAggregateClear = 1; + nAggregateFlip = 1; + S.nAutoClearFrames -= 1; + } + + bool nRunning = MicroProfileAnyGroupActive(); + if(nRunning) + { + S.nFlipStartTick = MP_TICK(); + int64_t nGpuWork = MicroProfileGpuEnd(S.pGpuGlobal); + MicroProfileGpuSubmit(S.GpuQueue, nGpuWork); + MicroProfileThreadLogGpuReset(S.pGpuGlobal); + for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i) + { + if(S.PoolGpu[i]) + { + S.PoolGpu[i]->nPut = 0; + } + } + + MicroProfileGpuBegin(pContext, S.pGpuGlobal); + + uint32_t nGpuTimeStamp = MicroProfileGpuFlip(pContext); + + uint64_t nFrameIdx = S.nFramePutIndex++; + S.nFramePut = (S.nFramePut + 1) % MICROPROFILE_MAX_FRAME_HISTORY; + S.Frames[S.nFramePut].nFrameId = nFrameIdx; + MP_ASSERT((S.nFramePutIndex % MICROPROFILE_MAX_FRAME_HISTORY) == S.nFramePut); + S.nFrameCurrent = (S.nFramePut + MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 1) % MICROPROFILE_MAX_FRAME_HISTORY; + S.nFrameCurrentIndex++; + uint32_t nFrameNext = (S.nFrameCurrent + 1) % MICROPROFILE_MAX_FRAME_HISTORY; + S.nFrameNext = nFrameNext; + + uint32_t nContextSwitchPut = S.nContextSwitchPut; + if(S.nContextSwitchLastPut < nContextSwitchPut) + { + S.nContextSwitchUsage = (nContextSwitchPut - S.nContextSwitchLastPut); + } + else + { + S.nContextSwitchUsage = MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE - S.nContextSwitchLastPut + nContextSwitchPut; + } + S.nContextSwitchLastPut = nContextSwitchPut; + + MicroProfileFrameState* pFramePut = &S.Frames[S.nFramePut]; + MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent]; + MicroProfileFrameState* pFrameNext = &S.Frames[nFrameNext]; + const int64_t nTickStartFrame = pFrameCurrent->nFrameStartCpu; + const int64_t nTickEndFrame = pFrameNext->nFrameStartCpu; + + pFrameCurrent->nGpuPending = 0; + pFramePut->nGpuPending = 1; + + pFramePut->nFrameStartCpu = MP_TICK(); + + pFramePut->nFrameStartGpu = nGpuTimeStamp; + { + const float fDumpTimeThreshold = 1000.f * 60 * 60 * 24 * 365.f; // if time above this, then we're handling uninitialized counters + int nDumpNextFrame = 0; + float fTimeGpu = 0.f; + if(pFrameNext->nFrameStartGpu != MICROPROFILE_INVALID_TICK) + { + + uint64_t nTickCurrent = pFrameCurrent->nFrameStartGpu; + uint64_t nTickNext = pFrameNext->nFrameStartGpu = MicroProfileGpuGetTimeStamp((uint32_t)pFrameNext->nFrameStartGpu); + nTickCurrent = MicroProfileLogTickMin(nTickCurrent, nTickNext); + float fTime = 1000.f * (nTickNext - nTickCurrent) / (MicroProfileTicksPerSecondGpu()); + fTime = fTimeGpu; + if(S.fDumpGpuSpike > 0.f && fTime > S.fDumpGpuSpike && fTime < fDumpTimeThreshold) + { + nDumpNextFrame = 1; + } + } + float fTimeCpu = 1000.f * (pFrameNext->nFrameStartCpu - pFrameCurrent->nFrameStartCpu) / MicroProfileTicksPerSecondCpu(); + if(S.fDumpCpuSpike > 0.f && fTimeCpu > S.fDumpCpuSpike && fTimeCpu < fDumpTimeThreshold) + { + nDumpNextFrame = 1; + } + if(nDumpNextFrame) + { + S.nDumpFileNextFrame = S.nDumpSpikeMask; + S.nDumpSpikeMask = 0; + S.nDumpFileCountDown = 5; + } + } + + const uint64_t nTickEndFrameGpu_ = pFrameNext->nFrameStartGpu; + const uint64_t nTickStartFrameGpu_ = pFrameCurrent->nFrameStartGpu; + const bool bGpuFrameInvalid = nTickEndFrameGpu_ == MICROPROFILE_INVALID_TICK || nTickStartFrameGpu_ == MICROPROFILE_INVALID_TICK; + const uint64_t nTickEndFrameGpu = bGpuFrameInvalid ? 1 : nTickEndFrameGpu_; + const uint64_t nTickStartFrameGpu = bGpuFrameInvalid ? 2 : nTickStartFrameGpu_; + + MicroProfileFrameExtraCounterData* ExtraData = S.FrameExtraCounterData; + bool UsingExtraData = false; + if(ExtraData) + { + if((intptr_t)ExtraData == 1) + { + size_t Bytes = sizeof(MicroProfileFrameExtraCounterData) * MICROPROFILE_MAX_FRAME_HISTORY; + printf(" allocating %d bytes %f\n", (int)Bytes, Bytes / (1024.0 * 1024.0)); + ExtraData = S.FrameExtraCounterData = (MicroProfileFrameExtraCounterData*)MicroProfileAllocInternal(Bytes, alignof(uint64_t)); + memset(ExtraData, 0, Bytes); + } + ExtraData = ExtraData + S.nFrameCurrent; + UsingExtraData = true; + } +#define MP_ASSERT_LE_WRAP(l, g) MP_ASSERT(uint64_t(g - l) < 0x8000000000000000) + + { + MP_ASSERT_LE_WRAP(nTickStartFrame, nTickEndFrame); + uint64_t nTick = nTickEndFrame - nTickStartFrame; + S.nFlipTicks = nTick; + S.nFlipAggregate += nTick; + S.nFlipMax = MicroProfileMax(S.nFlipMax, nTick); + } + + uint32_t* pTimerToGroup = &S.TimerToGroup[0]; + for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i) + { + MicroProfileThreadLog* pLog = S.Pool[i]; + if(!pLog) + { + pFramePut->nLogStart[i] = 0; + } + else + { + uint32_t nPut = pLog->nPut.load(std::memory_order_acquire); + pFramePut->nLogStart[i] = nPut; + if(!pLog->nGpu) + { + uint32_t nStart = pFrameCurrent->nLogStart[i]; + while(nStart != nPut) + { + int64_t LE = pLog->Log[nStart]; + int64_t nDifference = MicroProfileLogTickDifference(LE, nTickEndFrame); + uint32_t Ext = MicroProfileLogGetType(LE); + if(nDifference > 0 || 0 != (0x2 & Ext)) + { + nStart = (nStart + 1) % MICROPROFILE_BUFFER_SIZE; + } + else + { + break; + } + } + pFrameNext->nLogStart[i] = nStart; + } + } + } + { + pFramePut->nLogStartTimeline = S.TimelineLog.nPut.load(std::memory_order_acquire); + + uint32_t nFrameCurrent = S.nFrameCurrent; + uint32_t nTimelineFrameDeltaMax = S.nTimelineFrameMax; + for(uint32_t i = 0; i != MICROPROFILE_TIMELINE_MAX_TOKENS; ++i) + { + uint32_t nFrameStart = S.TimelineTokenFrameEnter[i]; + if(nFrameStart != MICROPROFILE_INVALID_FRAME) + { + uint32_t nCur = nFrameCurrent; + if(nCur < nFrameStart) + nCur += MICROPROFILE_MAX_FRAME_HISTORY; + if(nCur >= nFrameStart) + { + uint32_t D = nCur - nFrameStart; + nTimelineFrameDeltaMax = MicroProfileMax(nTimelineFrameDeltaMax, D); + } + } + } + pFramePut->nTimelineFrameMax = nTimelineFrameDeltaMax; + S.nTimelineFrameMax = 0; + } + { + for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i) + { + MicroProfileThreadLog* pLog = S.Pool[i]; + if(!pLog) + continue; + if(pLog->nGpu) + { + uint32_t nPut = pFrameNext->nLogStart[i]; + uint32_t nGet = pFrameCurrent->nLogStart[i]; + uint32_t nRange[2][2] = { + { 0, 0 }, + { 0, 0 }, + }; + MicroProfileGetRange(nPut, nGet, nRange); + for(uint32_t j = 0; j < 2; ++j) + { + uint32_t nStart = nRange[j][0]; + uint32_t nEnd = nRange[j][1]; + for(uint32_t k = nStart; k < nEnd; ++k) + { + MicroProfileLogEntry L = pLog->Log[k]; + if(MicroProfileLogGetType(L) < MP_LOG_EXTENDED) + { + pLog->Log[k] = MicroProfileLogSetTick(L, MicroProfileGpuGetTimeStamp((uint32_t)MicroProfileLogGetTick(L))); + } + k += MicroProfileLogGetDataSize(L); + } + } + } + } + } + + { + MicroProfile::GroupTime* pFrameGroup = &S.FrameGroup[0]; + { + MICROPROFILE_SCOPE(g_MicroProfileClear); + for(uint32_t i = 0; i < S.nTotalTimers; ++i) + { + S.Frame[i].nTicks = 0; + S.Frame[i].nCount = 0; + S.FrameExclusive[i] = 0; + } + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i) + { + pFrameGroup[i].nTicks = 0; + pFrameGroup[i].nTicksExclusive = 0; + pFrameGroup[i].nCount = 0; + } + } + { + MICROPROFILE_SCOPE(g_MicroProfileThreadLoop); + memset(S.FrameGroupThreadValid, 0, sizeof(S.FrameGroupThreadValid)); + + for(uint32_t idx_thread = 0; idx_thread < MICROPROFILE_MAX_THREADS; ++idx_thread) + { + MicroProfileThreadLog* pLog = S.Pool[idx_thread]; + if(!pLog) + continue; + bool bGpu = pLog->nGpu != 0; + int64_t nTickStartLog = bGpu ? nTickStartFrameGpu : nTickStartFrame; + int64_t nTickEndLog = bGpu ? nTickEndFrameGpu : nTickEndFrame; + + float fToMs = bGpu ? MicroProfileTickToMsMultiplierGpu() : MicroProfileTickToMsMultiplierCpu(); + float fFrameTime = fToMs * (nTickEndLog - nTickStartLog); + + MicroProfile::GroupTime* pFrameGroupThread = &S.FrameGroupThread[idx_thread][0]; + + uint32_t nPut = pFrameNext->nLogStart[idx_thread]; + uint32_t nGet = pFrameCurrent->nLogStart[idx_thread]; + uint32_t nRange[2][2] = { + { 0, 0 }, + { 0, 0 }, + }; + MicroProfileGetRange(nPut, nGet, nRange); + if(nPut != nGet) + { + S.FrameGroupThreadValid[idx_thread / 32] |= 1 << (idx_thread % 32); + memset(pFrameGroupThread, 0, sizeof(S.FrameGroupThread[idx_thread])); + } + + uint64_t* pStackLog = &pLog->nStackLogEntry[0]; + uint64_t* pChildTickStack = &pLog->nChildTickStack[1]; + int32_t nStackPos = pLog->nStackPos; + uint8_t TimerStackPos[MICROPROFILE_MAX_TIMERS]; + uint8_t GroupStackPos[MICROPROFILE_MAX_GROUPS]; + memset(TimerStackPos, 0, sizeof(TimerStackPos)); + memset(GroupStackPos, 0, sizeof(GroupStackPos)); + + // restore group and timer stack pos. + for(int32_t i = 0; i < nStackPos; ++i) + { + uint64_t nTimer = MicroProfileLogGetTimerIndex(pStackLog[i]); + uint32_t nGroup = pTimerToGroup[nTimer]; + MP_ASSERT(nTimer < MICROPROFILE_MAX_TIMERS); + MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS); + TimerStackPos[nTimer]++; + GroupStackPos[nGroup]++; + } + + for(uint32_t j = 0; j < 2; ++j) + { + uint32_t nStart = nRange[j][0]; + uint32_t nEnd = nRange[j][1]; + for(uint32_t k = nStart; k < nEnd; ++k) + { + MicroProfileLogEntry LE = pLog->Log[k]; + uint32_t nType = MicroProfileLogGetType(LE); + + switch(nType) + { + case MP_LOG_ENTER: + { + uint64_t nTimer = MicroProfileLogGetTimerIndex(LE); + if(nTimer != ETOKEN_CSTR_PTR) + { + MP_ASSERT(nTimer < S.nTotalTimers); + uint32_t nGroup = pTimerToGroup[nTimer]; + MP_ASSERT(nStackPos < MICROPROFILE_STACK_MAX); + MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS); + + // When we aggretate the total time, we have to count if the timers & groups are layered, to avoid summing them twice when calculating the total time. + // Averages become nonsense regardless. + TimerStackPos[nTimer]++; + GroupStackPos[nGroup]++; + + pStackLog[nStackPos] = LE; + + pChildTickStack[nStackPos] = 0; + nStackPos++; + } + break; + } + case MP_LOG_LEAVE: + { + uint64_t nTimer = MicroProfileLogGetTimerIndex(LE); + if(nTimer != ETOKEN_CSTR_PTR) + { + MP_ASSERT(nTimer < S.nTotalTimers); + uint32_t nGroup = pTimerToGroup[nTimer]; + MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS); + MP_ASSERT(nStackPos); + uint64_t nTicks; + bool bGroupRoot = 0 == GroupStackPos[nGroup] || 0 == --GroupStackPos[nGroup]; + bool bTimerRoot = 0 == TimerStackPos[nTimer] || 0 == --TimerStackPos[nTimer]; + { + nStackPos--; + MicroProfileLogEntry LEStack = pStackLog[nStackPos]; + MP_ASSERT(MicroProfileLogGetTimerIndex(LEStack) == nTimer); // unbalanced timers are not supported + uint64_t nTickStart = MicroProfileLogTickClamp(LEStack, nTickStartLog, nTickEndLog); + uint64_t nClamped = MicroProfileLogTickClamp(LE, nTickStartLog, nTickEndLog); + nTicks = MicroProfileLogTickDifference(nTickStart, nClamped); + MP_ASSERT(nTicks < 0x8000000000000000); + + uint64_t nChildTicks = pChildTickStack[nStackPos]; + + MP_ASSERT(nStackPos < MICROPROFILE_STACK_MAX); + if(nStackPos) + { + pChildTickStack[nStackPos - 1] += nTicks; + } + MP_ASSERT(nTicks >= nChildTicks); + uint64_t nTicksExclusive = (nTicks - nChildTicks); + S.FrameExclusive[nTimer] += nTicksExclusive; + pFrameGroupThread[nGroup].nTicksExclusive += nTicksExclusive; + if(bTimerRoot) // dont count this if its below another instance of the same timer. + { + S.Frame[nTimer].nTicks += nTicks; + S.Frame[nTimer].nCount += 1; + MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS); + if(bGroupRoot) + { + pFrameGroupThread[nGroup].nTicks += nTicks; + pFrameGroupThread[nGroup].nCount += 1; + } + } + } + } + break; + } + case MP_LOG_EXTENDED: + { + k += MicroProfileLogGetDataSize(LE); + break; + } + case MP_LOG_EXTENDED_NO_DATA: + break; + } + } + } + + for(int32_t i = nStackPos - 1; i >= 0; --i) + { + + MicroProfileLogEntry LE = pStackLog[i]; + uint64_t nTickStart = MicroProfileLogTickClamp(LE, nTickStartLog, nTickEndLog); + uint64_t nTicks = MicroProfileLogTickDifference(nTickStart, nTickEndLog); + int64_t nChildTicks = pChildTickStack[i]; + pChildTickStack[i] = 0; // consume.. + + MP_ASSERT(i < MICROPROFILE_STACK_MAX && i >= 0); + if(i) + { + pChildTickStack[i - 1] += nTicks; + } + MP_ASSERT(nTicks >= (uint64_t)nChildTicks); + + uint32_t nTimer = (uint32_t)MicroProfileLogGetTimerIndex(LE); + uint32_t nGroup = pTimerToGroup[nTimer]; + + bool bGroupRoot = 0 == GroupStackPos[nGroup] || 0 == --GroupStackPos[nGroup]; + bool bTimerRoot = 0 == TimerStackPos[nTimer] || 0 == --TimerStackPos[nTimer]; + + uint64_t nTicksExclusive = (nTicks - nChildTicks); + S.FrameExclusive[nTimer] += nTicksExclusive; + pFrameGroupThread[nGroup].nTicksExclusive += nTicksExclusive; + if(bTimerRoot) + { + S.Frame[nTimer].nTicks += nTicks; + S.Frame[nTimer].nCount += 1; + + MP_ASSERT(nGroup < MICROPROFILE_MAX_GROUPS); + if(bGroupRoot) + { + pFrameGroupThread[nGroup].nTicks += nTicks; + pFrameGroupThread[nGroup].nCount += 1; + } + } + } +#ifdef MP_ASSERT + for(uint8_t& g : GroupStackPos) + { + MP_ASSERT(g == 0); + } + for(uint8_t& g : TimerStackPos) + { + MP_ASSERT(g == 0); + } +#endif + + pLog->nStackPos = nStackPos; + for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j) + { + pLog->nGroupTicks[j] += pFrameGroupThread[j].nTicks; + + if((S.FrameGroupThreadValid[idx_thread / 32] & (1 << (idx_thread % 32))) != 0) + { + pFrameGroup[j].nTicks += pFrameGroupThread[j].nTicks; + pFrameGroup[j].nTicksExclusive += pFrameGroupThread[j].nTicksExclusive; + pFrameGroup[j].nCount += pFrameGroupThread[j].nCount; + } + } + + if(pLog->nPut == pLog->nGet && pLog->nActive == 2) + { + pLog->nIdleFrames++; + } + else + { + pLog->nIdleFrames = 0; + } + if(pLog->nActive == 2 && pLog->nIdleFrames > MICROPROFILE_THREAD_LOG_FRAMES_REUSE) + { + MicroProfileLogReset(pLog); + } + } + } + { + MICROPROFILE_SCOPE(g_MicroProfileAccumulate); + uint64_t* ExtraPut = nullptr; + if(UsingExtraData) + { + ExtraPut = &ExtraData->Timers[0]; + ExtraData->NumTimers = S.nTotalTimers; + } + + for(uint32_t i = 0; i < S.nTotalTimers; ++i) + { + S.AccumTimers[i].nTicks += S.Frame[i].nTicks; + S.AccumTimers[i].nCount += S.Frame[i].nCount; + S.AccumMaxTimers[i] = MicroProfileMax(S.AccumMaxTimers[i], S.Frame[i].nTicks); + S.AccumMinTimers[i] = MicroProfileMin(S.AccumMinTimers[i], S.Frame[i].nTicks); + S.AccumTimersExclusive[i] += S.FrameExclusive[i]; + S.AccumMaxTimersExclusive[i] = MicroProfileMax(S.AccumMaxTimersExclusive[i], S.FrameExclusive[i]); + if(ExtraPut) + *ExtraPut++ = S.Frame[i].nTicks; + } + ExtraPut = nullptr; + if(UsingExtraData) + { + ExtraPut = &ExtraData->Groups[0]; + ExtraData->NumGroups = S.nGroupCount; + } + + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i) + { + S.AccumGroup[i] += pFrameGroup[i].nTicks; + S.AccumGroupMax[i] = MicroProfileMax(S.AccumGroupMax[i], pFrameGroup[i].nTicks); + if(ExtraPut) + *ExtraPut++ = pFrameGroup[i].nTicks; + } +#if MICROPROFILE_IMGUI + void MicroProfileImguiGather(); + MicroProfileImguiGather(); +#endif + if(S.CsvConfig.State == MicroProfileCsvConfig::ACTIVE) + { + uint32_t FrameIndex = S.nFrameCurrent % MICROPROFILE_MAX_FRAME_HISTORY; + uint64_t* FrameData = S.CsvConfig.FrameData + S.CsvConfig.TotalElements * FrameIndex; + { + uint16_t* TimerIndices = S.CsvConfig.TimerIndices; + for(uint32_t i = 0; i < S.CsvConfig.NumTimers; ++i) + { + uint16_t Index = TimerIndices[i]; + if(Index != UINT16_MAX) + { + *FrameData = S.Frame[Index].nTicks; + } + else + { + *FrameData = 0; + } + FrameData++; + } + } + { + uint16_t* GroupIndices = S.CsvConfig.GroupIndices; + for(uint32_t i = 0; i < S.CsvConfig.NumGroups; ++i) + { + uint16_t Index = GroupIndices[i]; + if(Index != UINT16_MAX) + { + *FrameData = pFrameGroup[Index].nTicks; + } + else + { + *FrameData = 0; + } + FrameData++; + } + } + { + uint16_t* CounterIndices = S.CsvConfig.CounterIndices; + for(uint32_t i = 0; i < S.CsvConfig.NumCounters; ++i) + { + uint16_t Index = CounterIndices[i]; + if(Index != UINT16_MAX) + { + if(S.CounterInfo[Index].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) + { + double d = S.CountersDouble[Index].load(); + memcpy(FrameData, &d, sizeof(d)); + } + else + { + *FrameData = S.Counters[Index].load(); + } + } + else + { + *FrameData = 0; + } + FrameData++; + } + } + } + } + for(uint32_t i = 0; i < MICROPROFILE_MAX_GRAPHS; ++i) + { + if(S.Graph[i].nToken != MICROPROFILE_INVALID_TOKEN) + { + MicroProfileToken nToken = S.Graph[i].nToken; + S.Graph[i].nHistory[S.nGraphPut] = S.Frame[MicroProfileGetTimerIndex(nToken)].nTicks; + } + } + S.nGraphPut = (S.nGraphPut + 1) % MICROPROFILE_GRAPH_HISTORY; + } + + if(S.nAggregateFlip <= ++S.nAggregateFlipCount) + { + nAggregateFlip = 1; + if(S.nAggregateFlip) // if 0 accumulate indefinitely + { + nAggregateClear = 1; + } + } + + for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i) + { + MicroProfileThreadLog* pLog = S.Pool[i]; + uint32_t nNewGet = pFrameNext->nLogStart[i]; + + if(pLog && nNewGet != (uint32_t)-1) + { + pLog->nGet.store(nNewGet); + } + } + if(pFrameNext->nLogStartTimeline != (uint32_t)-1) + { + S.TimelineLog.nGet.store(pFrameNext->nLogStartTimeline); + } + } + if(nAggregateFlip) + { + memcpy(&S.Aggregate[0], &S.AccumTimers[0], sizeof(S.Aggregate[0]) * S.nTotalTimers); + memcpy(&S.AggregateMax[0], &S.AccumMaxTimers[0], sizeof(S.AggregateMax[0]) * S.nTotalTimers); + memcpy(&S.AggregateMin[0], &S.AccumMinTimers[0], sizeof(S.AggregateMin[0]) * S.nTotalTimers); + memcpy(&S.AggregateExclusive[0], &S.AccumTimersExclusive[0], sizeof(S.AggregateExclusive[0]) * S.nTotalTimers); + memcpy(&S.AggregateMaxExclusive[0], &S.AccumMaxTimersExclusive[0], sizeof(S.AggregateMaxExclusive[0]) * S.nTotalTimers); + + memcpy(&S.AggregateGroup[0], &S.AccumGroup[0], sizeof(S.AggregateGroup)); + memcpy(&S.AggregateGroupMax[0], &S.AccumGroupMax[0], sizeof(S.AggregateGroup)); + + for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i) + { + MicroProfileThreadLog* pLog = S.Pool[i]; + if(!pLog) + continue; + + memcpy(&pLog->nAggregateGroupTicks[0], &pLog->nGroupTicks[0], sizeof(pLog->nAggregateGroupTicks)); + + if(nAggregateClear) + { + memset(&pLog->nGroupTicks[0], 0, sizeof(pLog->nGroupTicks)); + } + } + + S.nAggregateFrames = S.nAggregateFlipCount; + S.nFlipAggregateDisplay = S.nFlipAggregate; + S.nFlipMaxDisplay = S.nFlipMax; + if(nAggregateClear) + { + memset(&S.AccumTimers[0], 0, sizeof(S.Aggregate[0]) * S.nTotalTimers); + memset(&S.AccumMaxTimers[0], 0, sizeof(S.AccumMaxTimers[0]) * S.nTotalTimers); + memset(&S.AccumMinTimers[0], 0xFF, sizeof(S.AccumMinTimers[0]) * S.nTotalTimers); + memset(&S.AccumTimersExclusive[0], 0, sizeof(S.AggregateExclusive[0]) * S.nTotalTimers); + memset(&S.AccumMaxTimersExclusive[0], 0, sizeof(S.AccumMaxTimersExclusive[0]) * S.nTotalTimers); + memset(&S.AccumGroup[0], 0, sizeof(S.AggregateGroup)); + memset(&S.AccumGroupMax[0], 0, sizeof(S.AggregateGroup)); + + S.nAggregateFlipCount = 0; + S.nFlipAggregate = 0; + S.nFlipMax = 0; + + S.nAggregateFlipTick = MP_TICK(); + } + +#if MICROPROFILE_COUNTER_HISTORY + int64_t* pDest = &S.nCounterHistory[S.nCounterHistoryPut][0]; + S.nCounterHistoryPut = (S.nCounterHistoryPut + 1) % MICROPROFILE_GRAPH_HISTORY; + for(uint32_t i = 0; i < S.nNumCounters; ++i) + { + if(0 != (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DETAILED)) + { + MicroProfileFetchCounter(i); + bool IsDouble = (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) != 0; + if(IsDouble) + { + double dValue = S.CountersDouble[i].load(std::memory_order_relaxed); + memcpy(&pDest[i], &dValue, sizeof(dValue)); + S.dCounterMin[i] = MicroProfileMin(S.dCounterMin[i], dValue); + S.dCounterMax[i] = MicroProfileMax(S.dCounterMax[i], dValue); + } + else + { + uint64_t nValue = S.Counters[i].load(std::memory_order_relaxed); + pDest[i] = nValue; + S.nCounterMin[i] = MicroProfileMin(S.nCounterMin[i], (int64_t)nValue); + S.nCounterMax[i] = MicroProfileMax(S.nCounterMax[i], (int64_t)nValue); + } + } + } +#endif + } + S.nAggregateClear = 0; + + MicroProfileFlipEnabled(); +} + +void MicroProfileSetEnableAllGroups(int bEnable) +{ + if(bEnable) + { + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i) + { + S.nActiveGroupsWanted[i] = S.nGroupMask[i]; + } + S.nStartEnabled = 1; + MicroProfileFlipEnabled(); + } + else + { + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i) + { + S.nActiveGroupsWanted[i] = 0; + } + S.nStartEnabled = 0; + MicroProfileFlipEnabled(); + } +} +void MicroProfileEnableCategory(const char* pCategory, int bEnabled) +{ + int nCategoryIndex = -1; + for(uint32_t i = 0; i < S.nCategoryCount; ++i) + { + if(!MP_STRCASECMP(pCategory, S.CategoryInfo[i].pName)) + { + nCategoryIndex = (int)i; + break; + } + } + if(nCategoryIndex >= 0) + { + if(bEnabled) + { + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i) + { + S.nActiveGroupsWanted[i] |= S.CategoryInfo[nCategoryIndex].nGroupMask[i]; + } + } + else + { + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i) + { + S.nActiveGroupsWanted[i] &= ~S.CategoryInfo[nCategoryIndex].nGroupMask[i]; + } + } + } +} + +void MicroProfileEnableCategory(const char* pCategory) +{ + MicroProfileEnableCategory(pCategory, true); +} +void MicroProfileDisableCategory(const char* pCategory) +{ + MicroProfileEnableCategory(pCategory, false); +} + +int MicroProfileGetEnableAllGroups() +{ + return 0 == memcmp(S.nGroupMask, S.nActiveGroupsWanted, sizeof(S.nGroupMask)); +} + +void MicroProfileSetForceMetaCounters(int bForce) +{ +} + +int MicroProfileGetForceMetaCounters() +{ + + return 0; +} + +void MicroProfileEnableMetaCounter(const char* pMeta) +{ +} + +void MicroProfileDisableMetaCounter(const char* pMeta) +{ +} + +void MicroProfileSetAggregateFrames(int nFrames) +{ + S.nAggregateFlip = (uint32_t)nFrames; + if(0 == nFrames) + { + S.nAggregateClear = 1; + } +} + +int MicroProfileGetAggregateFrames() +{ + return S.nAggregateFlip; +} + +int MicroProfileGetCurrentAggregateFrames() +{ + return int(S.nAggregateFlip ? S.nAggregateFlip : S.nAggregateFlipCount); +} + +void MicroProfileForceEnableGroup(const char* pGroup, MicroProfileTokenType Type) +{ + MicroProfileInit(); + std::lock_guard Lock(MicroProfileMutex()); + uint16_t nGroup = MicroProfileGetGroup(pGroup, Type); + uint32_t nIndex = nGroup / 32; + uint32_t nBit = nGroup % 32; + S.nForceGroups[nIndex] |= (1ll << nBit); +} + +void MicroProfileForceDisableGroup(const char* pGroup, MicroProfileTokenType Type) +{ + MicroProfileInit(); + std::lock_guard Lock(MicroProfileMutex()); + uint16_t nGroup = MicroProfileGetGroup(pGroup, Type); + uint32_t nIndex = nGroup / 32; + uint32_t nBit = nGroup % 32; + + S.nForceGroups[nIndex] &= ~(1ll << nBit); +} + +struct MicroProfileTimerValues +{ + float TimeMs; + float AverageMs; + float MaxMs; + float MinMs; + float CallAverageMs; + float ExclusiveMs; + float AverageExclusiveMs; + float MaxExclusiveMs; + float TotalMs; + uint32_t nCount; +}; + +void MicroProfileCalcTimers(int nTimer, MicroProfileTimerValues& Out) +{ + const uint32_t nGroupId = S.TimerInfo[nTimer].nGroupIndex; + const float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu()); + uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1; + uint32_t nAggregateCount = S.Aggregate[nTimer].nCount ? S.Aggregate[nTimer].nCount : 1; + Out.nCount = S.Aggregate[nTimer].nCount; + + float fToPrc = S.fRcpReferenceTime; + float fMs = fToMs * (S.Frame[nTimer].nTicks); + + float fAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateFrames); + float fMaxMs = fToMs * (S.AggregateMax[nTimer]); + float fMinMs = fToMs * (S.AggregateMin[nTimer] != uint64_t(-1) ? S.AggregateMin[nTimer] : 0); + float fCallAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateCount); + float fMsExclusive = fToMs * (S.FrameExclusive[nTimer]); + float fAverageMsExclusive = fToMs * (S.AggregateExclusive[nTimer] / nAggregateFrames); + float fMaxMsExclusive = fToMs * (S.AggregateMaxExclusive[nTimer]); + float fTotalMs = fToMs * S.Aggregate[nTimer].nTicks; + + Out.TimeMs = fMs; + Out.AverageMs = fAverageMs; + Out.MaxMs = fMaxMs; + Out.MinMs = fMinMs; + Out.CallAverageMs = fCallAverageMs; + Out.ExclusiveMs = fMsExclusive; + Out.AverageExclusiveMs = fAverageMsExclusive; + Out.MaxExclusiveMs = fMaxMsExclusive; + Out.TotalMs = fTotalMs; +} + +void MicroProfileCalcAllTimers( + float* pTimers, float* pAverage, float* pMax, float* pMin, float* pCallAverage, float* pExclusive, float* pAverageExclusive, float* pMaxExclusive, float* pTotal, uint32_t nSize) +{ + for(uint32_t i = 0; i < S.nTotalTimers && i < nSize; ++i) + { + const uint32_t nGroupId = S.TimerInfo[i].nGroupIndex; + const float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[nGroupId].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu()); + uint32_t nTimer = i; + uint32_t nIdx = i * 2; + uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1; + uint32_t nAggregateCount = S.Aggregate[nTimer].nCount ? S.Aggregate[nTimer].nCount : 1; + float fToPrc = S.fRcpReferenceTime; + float fMs = fToMs * (S.Frame[nTimer].nTicks); + float fPrc = MicroProfileMin(fMs * fToPrc, 1.f); + float fAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateFrames); + float fAveragePrc = MicroProfileMin(fAverageMs * fToPrc, 1.f); + float fMaxMs = fToMs * (S.AggregateMax[nTimer]); + float fMaxPrc = MicroProfileMin(fMaxMs * fToPrc, 1.f); + float fMinMs = fToMs * (S.AggregateMin[nTimer] != uint64_t(-1) ? S.AggregateMin[nTimer] : 0); + float fMinPrc = MicroProfileMin(fMinMs * fToPrc, 1.f); + float fCallAverageMs = fToMs * (S.Aggregate[nTimer].nTicks / nAggregateCount); + float fCallAveragePrc = MicroProfileMin(fCallAverageMs * fToPrc, 1.f); + float fMsExclusive = fToMs * (S.FrameExclusive[nTimer]); + float fPrcExclusive = MicroProfileMin(fMsExclusive * fToPrc, 1.f); + float fAverageMsExclusive = fToMs * (S.AggregateExclusive[nTimer] / nAggregateFrames); + float fAveragePrcExclusive = MicroProfileMin(fAverageMsExclusive * fToPrc, 1.f); + float fMaxMsExclusive = fToMs * (S.AggregateMaxExclusive[nTimer]); + float fMaxPrcExclusive = MicroProfileMin(fMaxMsExclusive * fToPrc, 1.f); + float fTotalMs = fToMs * S.Aggregate[nTimer].nTicks; + pTimers[nIdx] = fMs; + pTimers[nIdx + 1] = fPrc; + pAverage[nIdx] = fAverageMs; + pAverage[nIdx + 1] = fAveragePrc; + pMax[nIdx] = fMaxMs; + pMax[nIdx + 1] = fMaxPrc; + pMin[nIdx] = fMinMs; + pMin[nIdx + 1] = fMinPrc; + pCallAverage[nIdx] = fCallAverageMs; + pCallAverage[nIdx + 1] = fCallAveragePrc; + pExclusive[nIdx] = fMsExclusive; + pExclusive[nIdx + 1] = fPrcExclusive; + pAverageExclusive[nIdx] = fAverageMsExclusive; + pAverageExclusive[nIdx + 1] = fAveragePrcExclusive; + pMaxExclusive[nIdx] = fMaxMsExclusive; + pMaxExclusive[nIdx + 1] = fMaxPrcExclusive; + pTotal[nIdx] = fTotalMs; + pTotal[nIdx + 1] = 0.f; + } +} + +float MicroProfileGetTime(const char* pGroup, const char* pName) +{ + MicroProfileToken nToken = MicroProfileFindTokenInternal(pGroup, pName); + if(nToken == MICROPROFILE_INVALID_TOKEN) + { + return 0.f; + } + uint32_t nTimerIndex = MicroProfileGetTimerIndex(nToken); + uint32_t nGroupIndex = MicroProfileGetGroupIndex(nToken); + float fToMs = MicroProfileTickToMsMultiplier(S.GroupInfo[nGroupIndex].Type == MicroProfileTokenTypeGpu ? MicroProfileTicksPerSecondGpu() : MicroProfileTicksPerSecondCpu()); + return S.Frame[nTimerIndex].nTicks * fToMs; +} + +int MicroProfilePlatformMarkersGetEnabled() +{ + return S.nPlatformMarkersEnabled != 0 ? 1 : 0; +} +void MicroProfilePlatformMarkersSetEnabled(int bEnabled) +{ + S.nPlatformMarkersEnabled = bEnabled ? 1 : 0; +} + +#define MICROPROFILE_CONTEXT_SWITCH_SEARCH_DEBUG MICROPROFILE_DEBUG + +void MicroProfileContextSwitchSearch(uint32_t* pContextSwitchStart, uint32_t* pContextSwitchEnd, uint64_t nBaseTicksCpu, uint64_t nBaseTicksEndCpu) +{ + MICROPROFILE_SCOPE(g_MicroProfileContextSwitchSearch); + uint32_t nContextSwitchPut = S.nContextSwitchPut; + uint64_t nContextSwitchStart, nContextSwitchEnd; + nContextSwitchStart = nContextSwitchEnd = (nContextSwitchPut + MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE - 1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE; + int64_t nSearchEnd = nBaseTicksEndCpu + MicroProfileMsToTick(30.f, MicroProfileTicksPerSecondCpu()); + int64_t nSearchBegin = nBaseTicksCpu - MicroProfileMsToTick(30.f, MicroProfileTicksPerSecondCpu()); + +#if MICROPROFILE_CONTEXT_SWITCH_SEARCH_DEBUG + int64_t lp = S.nContextSwitchLastPushed; + uprintf("cswitch-search\n"); + uprintf("Begin %" PRId64 " End %" PRId64 " Last %" PRId64 "\n", nSearchBegin, nSearchEnd, lp); + + float fToMs = MicroProfileTickToMsMultiplierCpu(); + uprintf("E %6.2fms\n", fToMs * (nSearchEnd - nSearchBegin)); + uprintf("LAST %6.2fms\n", fToMs * (lp - nSearchBegin)); +#endif + + int64_t nMax = INT64_MIN; + int64_t nMin = INT64_MAX; + for(uint32_t i = 0; i < MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE; ++i) + { + uint32_t nIndex = (nContextSwitchPut + MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE - (i + 1)) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE; + MicroProfileContextSwitch& CS = S.ContextSwitch[nIndex]; + if(nMax < CS.nTicks) + nMax = CS.nTicks; + if(nMin > CS.nTicks && CS.nTicks != 0) + nMin = CS.nTicks; + if(CS.nTicks > nSearchEnd) + { + nContextSwitchEnd = nIndex; + } + if(CS.nTicks > nSearchBegin) + { + nContextSwitchStart = nIndex; + } + } + *pContextSwitchStart = nContextSwitchStart; + *pContextSwitchEnd = nContextSwitchEnd; + +#if MICROPROFILE_CONTEXT_SWITCH_SEARCH_DEBUG + { + uprintf("contextswitch start %" PRId64 " %" PRId64 "\n", nContextSwitchStart, nContextSwitchEnd); + + MicroProfileContextSwitch& CS0 = S.ContextSwitch[0]; + int64_t nMax = CS0.nTicks; + int64_t nMin = CS0.nTicks; + int64_t nBegin = 0; + int64_t nEnd = 0; + int nRanges = 0; + for(uint32_t i = 0; i < MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE; i += 1024) + { + int64_t MinTick = INT64_MAX; + int64_t MaxTick = INT64_MIN; + for(int j = 0; j < 1024; ++j) + { + MicroProfileContextSwitch& CS = S.ContextSwitch[i + j]; + int64_t nTicks = CS.nTicks; + MinTick = MicroProfileMin(nTicks, MinTick); + MaxTick = MicroProfileMax(nTicks, MaxTick); + } + + uprintf("XX range [%5" PRIx64 ":%5" PRIx64 "] :: [%6.2f:%6.2f] [%p :: %p] .. ref %p\n", + i, + i + 1024, + fToMs * (MinTick - nSearchBegin), + fToMs * (MaxTick - nSearchBegin), + (void*)MinTick, + (void*)MaxTick, + (void*)nSearchBegin + + ); + } + uprintf("\n\n"); + + for(uint32_t i = 0; i < MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE; ++i) + { + MicroProfileContextSwitch& CS = S.ContextSwitch[i]; + int64_t nTicks = CS.nTicks; + float fMs = (nTicks - nMax) * fToMs; + if(fMs < 0 || fMs > 50) + { + // dump range here + uprintf("range [%5" PRId64 ":%5" PRId64 "] :: [%6.2f:%6.2f] [%p :: %p] .. ref %p\n", + nBegin, + nEnd, + fToMs * (nMin - nSearchBegin), + fToMs * (nMax - nSearchBegin), + (void*)nMin, + (void*)nMax, + (void*)nSearchBegin + + ); + + nEnd = nBegin = i; + nMax = nMin = CS.nTicks; + nRanges++; + } + else + { + nEnd = i; + nMax = MicroProfileMax(nTicks, nMax); + } + } + } + + lp = S.nContextSwitchLastPushed; + uprintf("E %6.2fms\n", fToMs * (nSearchEnd - nSearchBegin)); + uprintf("LP2 %6.2fms\n", fToMs * (lp - nSearchBegin)); +#endif +} + +int MicroProfileFormatCounter(int eFormat, int64_t nCounter, char* pOut, uint32_t nBufferSize) +{ + if(!nCounter) + { + pOut[0] = '0'; + pOut[1] = '\0'; + return 1; + } + int nLen = 0; + char* pBase = pOut; + char* pTmp = pOut; + char* pEnd = pOut + nBufferSize; + int nNegative = 0; + if(nCounter < 0) + { + nCounter = -nCounter; + nNegative = 1; + if(nCounter < 0) // handle INT_MIN + { + nCounter = -(nCounter + 1); + } + } + + switch(eFormat) + { + case MICROPROFILE_COUNTER_FORMAT_DEFAULT: + { + int nSeperate = 0; + while(nCounter) + { + if(nSeperate) + { + *pTmp++ = '.'; + } + nSeperate = 1; + for(uint32_t i = 0; nCounter && i < 3; ++i) + { + int nDigit = nCounter % 10; + nCounter /= 10; + *pTmp++ = '0' + nDigit; + } + } + if(nNegative) + { + *pTmp++ = '-'; + } + nLen = pTmp - pOut; + --pTmp; + MP_ASSERT(pTmp <= pEnd); + while(pTmp > pOut) // reverse string + { + char c = *pTmp; + *pTmp = *pOut; + *pOut = c; + pTmp--; + pOut++; + } + } + break; + case MICROPROFILE_COUNTER_FORMAT_BYTES: + { + const char* pExt[] = { "b", "kb", "mb", "gb", "tb", "pb", "eb", "zb", "yb" }; + size_t nNumExt = sizeof(pExt) / sizeof(pExt[0]); + int64_t nShift = 0; + int64_t nDivisor = 1; + int64_t nCountShifted = nCounter >> 10; + while(nCountShifted) + { + nDivisor <<= 10; + nCountShifted >>= 10; + nShift++; + } + MP_ASSERT(nShift < (int64_t)nNumExt); + if(nShift) + { + nLen = snprintf(pOut, nBufferSize - 1, "%c%3.2f%s", nNegative ? '-' : ' ', (double)nCounter / nDivisor, pExt[nShift]); + } + else + { + nLen = snprintf(pOut, nBufferSize - 1, "%c%" PRId64 "%s", nNegative ? '-' : ' ', nCounter, pExt[nShift]); + } + } + break; + } + pBase[nLen] = '\0'; + + return nLen; +} + +int MicroProfileFormatCounterDouble(int eFormat, double dCounter, char* pOut, uint32_t nBufferSize) +{ + int nLen = 0; + switch(eFormat) + { + case MICROPROFILE_COUNTER_FORMAT_DEFAULT: + { + nLen = stbsp_snprintf(pOut, nBufferSize - 1, "%f", dCounter); + } + break; + case MICROPROFILE_COUNTER_FORMAT_BYTES: + { + const char* pExt[] = { "b", "kb", "mb", "gb", "tb", "pb", "eb", "zb", "yb" }; + double scale = 1.f; + int offset = 0; + int end = sizeof(pExt) / sizeof(pExt[0]); + double d = dCounter; + while(d / scale > 1024.f && offset + 1 < end) + { + scale *= 1024.f; + offset += 1; + } + nLen = stbsp_snprintf(pOut, nBufferSize - 1, "%.3f%s", d / scale, pExt[offset]); + } + break; + } + pOut[nLen] = '\0'; + + return nLen; +} + +bool MicroProfileAnyGroupActive() +{ + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i) + { + if(S.nActiveGroups[i] != 0) + return true; + } + return false; +} +bool MicroProfileGroupActive(uint32_t nGroupIndex) +{ + MP_ASSERT(nGroupIndex < MICROPROFILE_MAX_GROUPS); + uint32_t nIndex = nGroupIndex / 32; + uint32_t nBit = nGroupIndex % 32; + return ((S.nActiveGroups[nIndex] >> nBit) & 1) == 1; +} + +void MicroProfileToggleGroup(uint32_t nGroup) +{ + if(nGroup < S.nGroupCount) + { + uint32_t nIndex = nGroup / 32; + uint32_t nBit = nGroup % 32; + S.nActiveGroupsWanted[nIndex] ^= (1ll << nBit); + S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED; + } +} +void MicroProfileGroupSetEnabled(uint32_t nGroup) +{ + if(nGroup < S.nGroupCount) + { + uint32_t nIndex = nGroup / 32; + uint32_t nBit = nGroup % 32; + S.nActiveGroupsWanted[nIndex] |= (1ll << nBit); + S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED; + } +} +bool MicroProfileGroupEnabled(uint32_t nGroup) +{ + if(nGroup < S.nGroupCount) + { + uint32_t nIndex = nGroup / 32; + uint32_t nBit = nGroup % 32; + return 0 != (S.nActiveGroupsWanted[nIndex] & (1ll << nBit)); + } + return false; +} +bool MicroProfileCategoryEnabled(uint32_t nCategory) +{ + if(nCategory < S.nCategoryCount) + { + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i) + { + if(S.CategoryInfo[nCategory].nGroupMask[i] != (S.CategoryInfo[nCategory].nGroupMask[i] & S.nActiveGroupsWanted[i])) + { + return false; + } + } + return true; + } + return false; +} + +bool MicroProfileCategoryDisabled(uint32_t nCategory) +{ + if(nCategory < S.nCategoryCount) + { + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i) + { + uint32_t ActiveMask = S.nActiveGroupsWanted[i]; + uint32_t CategoryMask = S.CategoryInfo[nCategory].nGroupMask[i]; + + if(0 != (ActiveMask & CategoryMask)) + { + return false; + } + } + return true; + } + return false; +} + +void MicroProfileToggleCategory(uint32_t nCategory) +{ + if(nCategory < S.nCategoryCount) + { + bool bAllSet = true; + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i) + { + bAllSet = bAllSet && S.CategoryInfo[nCategory].nGroupMask[i] == (S.CategoryInfo[nCategory].nGroupMask[i] & S.nActiveGroupsWanted[i]); + } + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUP_INTS; ++i) + { + if(bAllSet) + { + S.nActiveGroupsWanted[i] &= ~S.CategoryInfo[nCategory].nGroupMask[i]; + } + else + { + S.nActiveGroupsWanted[i] |= S.CategoryInfo[nCategory].nGroupMask[i]; + } + } + S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED; + } +} + +void MicroProfileSleep(uint32_t nMs) +{ +#ifdef _WIN32 + Sleep(nMs); +#else + usleep(nMs * 1000); +#endif +} + +#if MICROPROFILE_WEBSERVER + +#define MICROPROFILE_EMBED_HTML + +extern const char* g_MicroProfileHtml_begin[]; +extern size_t g_MicroProfileHtml_begin_sizes[]; +extern size_t g_MicroProfileHtml_begin_count; +extern const char* g_MicroProfileHtml_end[]; +extern size_t g_MicroProfileHtml_end_sizes[]; +extern size_t g_MicroProfileHtml_end_count; + +extern const char* g_MicroProfileHtmlLive_begin[]; +extern size_t g_MicroProfileHtmlLive_begin_sizes[]; +extern size_t g_MicroProfileHtmlLive_begin_count; +extern const char* g_MicroProfileHtmlLive_end[]; +extern size_t g_MicroProfileHtmlLive_end_sizes[]; +extern size_t g_MicroProfileHtmlLive_end_count; + +extern const uint32_t uprof_16[]; +extern const uint32_t uprof_16_len; +extern const uint32_t uprof_32[]; +extern const uint32_t uprof_32_len; +extern const uint32_t uprof_192[]; +extern const uint32_t uprof_192_len; +extern const uint32_t uprof_512[]; +extern const uint32_t uprof_512_len; + +typedef void (*MicroProfileWriteCallback)(void* Handle, size_t size, const char* pData); + +uint32_t MicroProfileWebServerPort() +{ + return S.nWebServerPort; +} + +void MicroProfileSetWebServerPort(uint32_t nPort) +{ + if(S.nWebServerPort != nPort) + { + MicroProfileWebServerJoin(); + MicroProfileWebServerStop(); + S.nWebServerPort = nPort; + S.nWebServerDataSent = (uint64_t)-1; // Will cause the web server and its thread to be restarted next time MicroProfileFlip() is called. + } +} + +void MicroProfileDumpFileImmediately(const char* pHtml, const char* pCsv, void* pGpuContext, uint32_t FrameCount) +{ + for(uint32_t i = 0; i < 2; ++i) + { + MicroProfileFlip(pGpuContext); + } + for(uint32_t i = 0; i < MICROPROFILE_GPU_FRAME_DELAY + 1; ++i) + { + MicroProfileFlip(pGpuContext); + } + + uint32_t nDumpMask = 0; + if(pHtml) + { + + size_t nLen = strlen(pHtml); + if(nLen > sizeof(S.HtmlDumpPath) - 1) + { + return; + } + const size_t ExtSize = sizeof(".html") - 1; + if(nLen > ExtSize && 0 == memcmp(".html", pHtml + nLen - ExtSize, ExtSize)) + nLen -= ExtSize; + memcpy(S.HtmlDumpPath, pHtml, nLen); + S.HtmlDumpPath[nLen] = '\0'; + + nDumpMask |= 1; + } + if(pCsv) + { + size_t nLen = strlen(pCsv); + if(nLen > sizeof(S.CsvDumpPath) - 1) + { + return; + } + const size_t ExtSize = sizeof(".csv") - 1; + if(nLen > ExtSize && 0 == memcmp(".csv", pCsv + nLen - ExtSize, ExtSize)) + nLen -= ExtSize; + memcpy(S.CsvDumpPath, pCsv, nLen + 1); + S.CsvDumpPath[nLen] = '\0'; + + nDumpMask |= 2; + } + std::lock_guard Lock(MicroProfileMutex()); + S.nDumpFileNextFrame = nDumpMask; + S.nDumpSpikeMask = 0; + S.nDumpFileCountDown = 0; + S.DumpFrameCount = FrameCount; + + MicroProfileDumpToFile(); +} +void MicroProfileDumpFile(const char* pHtml, const char* pCsv, float fCpuSpike, float fGpuSpike, uint32_t FrameCount) +{ + S.fDumpCpuSpike = fCpuSpike; + S.fDumpGpuSpike = fGpuSpike; + S.DumpFrameCount = FrameCount; + uint32_t nDumpMask = 0; + if(pHtml) + { + size_t nLen = strlen(pHtml); + if(nLen > sizeof(S.HtmlDumpPath) - 1) + { + return; + } + const size_t ExtSize = sizeof(".html") - 1; + if(nLen > ExtSize && 0 == memcmp(".html", pHtml + nLen - ExtSize, ExtSize)) + nLen -= ExtSize; + memcpy(S.HtmlDumpPath, pHtml, nLen); + S.HtmlDumpPath[nLen] = '\0'; + + nDumpMask |= 1; + } + if(pCsv) + { + size_t nLen = strlen(pCsv); + if(nLen > sizeof(S.CsvDumpPath) - 1) + { + return; + } + const size_t ExtSize = sizeof(".csv") - 1; + if(nLen > ExtSize && 0 == memcmp(".csv", pCsv + nLen - ExtSize, ExtSize)) + nLen -= ExtSize; + memcpy(S.CsvDumpPath, pCsv, nLen); + S.CsvDumpPath[nLen] = '\0'; + + nDumpMask |= 2; + } + if(fCpuSpike > 0.f || fGpuSpike > 0.f) + { + S.nDumpFileNextFrame = 0; + S.nDumpSpikeMask = nDumpMask; + } + else + { + std::lock_guard Lock(MicroProfileMutex()); + S.nDumpFileNextFrame = nDumpMask; + S.nDumpSpikeMask = 0; + S.nDumpFileCountDown = 0; + + MicroProfileDumpToFile(); + } +} + +struct MicroProfilePrintfArgs +{ + MicroProfileWriteCallback CB; + void* Handle; +}; + +char* MicroProfilePrintfCallback(const char* buf, void* user, int len) +{ + MicroProfilePrintfArgs* A = (MicroProfilePrintfArgs*)user; + (A->CB)(A->Handle, len, buf); + return const_cast(buf); +}; + +void MicroProfilePrintf(MicroProfileWriteCallback CB, void* Handle, const char* pFmt, ...) +{ + va_list args; + va_start(args, pFmt); + MicroProfilePrintfArgs A; + A.CB = CB; + A.Handle = Handle; + char Buffer[STB_SPRINTF_MIN]; + int size = stbsp_vsprintfcb(MicroProfilePrintfCallback, (void*)&A, Buffer, pFmt, args); + (void)size; + va_end(args); +} + +void MicroProfileGetFramesToDump(uint64_t nStartFrameId, uint32_t nMaxFrames, uint32_t& nFirstFrame, uint32_t& nLastFrame, uint32_t& nNumFrames) +{ + nFirstFrame = (uint32_t)-1; + nNumFrames = 0; + + if(nStartFrameId != (uint64_t)-1) + { + // search for the frane + for(uint32_t i = 0; i < MICROPROFILE_MAX_FRAME_HISTORY; ++i) + { + if(S.Frames[i].nFrameId == nStartFrameId) + { + nFirstFrame = i; + break; + } + } + if(nFirstFrame != (uint32_t)-1) + { + nLastFrame = S.nFrameCurrent; + uint32_t nDistance = (MICROPROFILE_MAX_FRAME_HISTORY + nFirstFrame - nLastFrame) % MICROPROFILE_MAX_FRAME_HISTORY; + nNumFrames = MicroProfileMin(nDistance, (uint32_t)nMaxFrames); + } + } + + if(nNumFrames == 0) + { + nNumFrames = (MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 3); // leave a few to not overwrite + nNumFrames = MicroProfileMin(nNumFrames, (uint32_t)nMaxFrames); + nFirstFrame = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - nNumFrames) % MICROPROFILE_MAX_FRAME_HISTORY; + } + + nLastFrame = (nFirstFrame + nNumFrames) % MICROPROFILE_MAX_FRAME_HISTORY; +} + +#define printf(...) MicroProfilePrintf(CB, Handle, __VA_ARGS__) + +void MicroProfileDumpCsvWithConfig(MicroProfileWriteCallback CB, void* Handle, uint32_t nFirstFrame, uint32_t nLastFrame, uint32_t nNumFrames) +{ + uint32_t NumTimers = S.CsvConfig.NumTimers; + uint32_t NumGroups = S.CsvConfig.NumGroups; + uint32_t NumCounters = S.CsvConfig.NumCounters; + uint16_t* TimerIndices = S.CsvConfig.TimerIndices; + uint16_t* GroupIndices = S.CsvConfig.GroupIndices; + uint64_t* FrameData = S.CsvConfig.FrameData; + uint16_t* CounterIndices = S.CsvConfig.CounterIndices; + uint32_t TotalElements = S.CsvConfig.TotalElements; + uint32_t Offset = 0; + bool UseFrameTime = 0 != (MICROPROFILE_CSV_FLAG_FRAME_TIME & S.CsvConfig.Flags); + const char** pTimerNames = S.CsvConfig.pTimerNames; + const char** pGroupNames = S.CsvConfig.pGroupNames; + const char** pCounterNames = S.CsvConfig.pCounterNames; + if(UseFrameTime) + printf("Time"); + else + printf("FrameNumber"); + for(uint32_t i = 0; i < NumTimers; ++i, ++Offset) + printf(", %s", pTimerNames[i] ? pTimerNames[i] : S.TimerInfo[TimerIndices[i]].pName); + + for(uint32_t i = 0; i < NumGroups; ++i, ++Offset) + printf(", %s", pGroupNames[i] ? pGroupNames[i] : S.GroupInfo[GroupIndices[i]].pName); + for(uint32_t i = 0; i < NumCounters; ++i, ++Offset) + printf(", %s", pCounterNames[i] ? pCounterNames[i] : S.CounterInfo[CounterIndices[i]].pName); + printf("\n"); + + float* fToMsTimer = (float*)alloca(sizeof(float) * NumTimers); + float* fToMsGroup = (float*)alloca(sizeof(float) * NumGroups); + float fToMsCPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()); + float fToMsGPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu()); + + for(uint32_t i = 0; i < NumTimers; ++i) + fToMsTimer[i] = S.TimerInfo[TimerIndices[i]].Type == MicroProfileTokenTypeGpu ? fToMsGPU : fToMsCPU; + for(uint32_t i = 0; i < NumGroups; ++i) + fToMsGroup[i] = S.GroupInfo[GroupIndices[i]].Type == MicroProfileTokenTypeGpu ? fToMsGPU : fToMsCPU; + + uint64_t TickStart = S.Frames[nFirstFrame % MICROPROFILE_MAX_FRAME_HISTORY].nFrameStartCpu; + for(uint32_t i = 0; i < nNumFrames; ++i) + { + uint32_t FrameIndex = ((nFirstFrame + i) % MICROPROFILE_MAX_FRAME_HISTORY); + uint64_t TickFrame = S.Frames[FrameIndex].nFrameStartCpu; + uint64_t* Data = FrameData + TotalElements * FrameIndex; + if(UseFrameTime) + printf("%f", (TickFrame - TickStart) * fToMsCPU); + else + printf("%d", i); + Offset = 0; + for(uint32_t j = 0; j < NumTimers; ++j) + printf(", %f", Data[Offset++] * fToMsTimer[j]); + for(uint32_t j = 0; j < NumGroups; ++j) + printf(", %f", Data[Offset++] * fToMsGroup[j]); + for(uint32_t j = 0; j < NumCounters; ++j) + { + if(S.CounterInfo[CounterIndices[j]].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) + { + printf(", %f", ((double*)Data)[Offset++]); + } + else + { + printf(", %lld", Data[Offset++]); + } + } + printf("\n"); + } +} +void MicroProfileDumpCsvTimerFrames(MicroProfileWriteCallback CB, void* Handle, uint32_t nFirstFrame, uint32_t nLastFrame, uint32_t nNumFrames) +{ + MP_ASSERT(S.FrameExtraCounterData); + uint32_t TotalTimers = S.nTotalTimers; + float* fToMs = (float*)alloca(sizeof(float) * TotalTimers); + float fToMsCPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()); + float fToMsGPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu()); + + for(uint32_t i = 0; i < TotalTimers; ++i) + fToMs[i] = S.TimerInfo[i].Type == MicroProfileTokenTypeGpu ? fToMsGPU : fToMsCPU; + + for(uint32_t i = 0; i < TotalTimers; ++i) + { + printf(i == 0 ? "FrameNumber, \"%s\"" : ",\"%s\"", S.TimerInfo[i].pName); + } + printf("\n"); + + for(uint32_t i = 0; i < nNumFrames; ++i) + { + // printf("%d", i) MicroProfileFrame& F = S.Frames[(i + nFirstFrame) % MICROPROFILE_MAX_FRAME_HISTORY]; + MicroProfileFrameExtraCounterData* Data = S.FrameExtraCounterData; + uint32_t NumTimers = 0; + uint32_t j; + printf("%d", i); + Data += ((i + nFirstFrame) % MICROPROFILE_MAX_FRAME_HISTORY); + NumTimers = MicroProfileMin(TotalTimers, (uint32_t)Data->NumTimers); + for(j = 0; j < NumTimers; ++j) + { + printf(",%f", Data->Timers[j] * fToMs[j]); + } + for(; j < TotalTimers; ++j) + printf(",0"); + printf("\n"); + } +} + +void MicroProfileDumpCsvGroupFrames(MicroProfileWriteCallback CB, void* Handle, uint32_t nFirstFrame, uint32_t nLastFrame, uint32_t nNumFrames) +{ + MP_ASSERT(S.FrameExtraCounterData); + float fToMsCPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()); + float fToMsGPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu()); + + uint32_t nGroupCount = S.nGroupCount; + + float* fToMs = (float*)alloca(sizeof(float) * nGroupCount); + for(uint32_t i = 0; i < nGroupCount; ++i) + fToMs[i] = S.GroupInfo[i].Type == MicroProfileTokenTypeGpu ? fToMsGPU : fToMsCPU; + + for(uint32_t i = 0; i < nGroupCount; ++i) + { + printf(i == 0 ? "FrameNumber, \"%s\"" : ",\"%s\"", S.GroupInfo[i].pName); + } + + printf("\n"); + for(uint32_t i = 0; i < nNumFrames; ++i) + { + MicroProfileFrameExtraCounterData* Data = S.FrameExtraCounterData; + uint32_t NumGroups = 0; + uint32_t j; + printf("%d", i); + Data += ((i + nFirstFrame) % MICROPROFILE_MAX_FRAME_HISTORY); + NumGroups = MicroProfileMin(nGroupCount, (uint32_t)Data->NumGroups); + for(j = 0; j < NumGroups; ++j) + { + printf(",%f", Data->Groups[j] * fToMs[j]); + } + for(; j < nGroupCount; ++j) + printf(",0"); + printf("\n"); + } +} + +void MicroProfileDumpCsv(uint32_t nDumpFrameCount) +{ + uint32_t nNumFrames, nFirstFrame, nLastFrame; + MicroProfileGetFramesToDump((uint64_t)-1, nDumpFrameCount, nFirstFrame, nLastFrame, nNumFrames); + + char Path[MICROPROFILE_MAX_PATH]; + int Length; + if(S.FrameExtraCounterData) + { + Length = snprintf(Path, sizeof(S.CsvDumpPath), "%s_timer_frames.csv", S.CsvDumpPath); + if(Length > 0 && Length < MICROPROFILE_MAX_PATH) + { + FILE* F = fopen(Path, "w"); + if(F) + { + MicroProfileDumpCsvTimerFrames(MicroProfileWriteFile, F, nFirstFrame, nLastFrame, nNumFrames); + fclose(F); + } + } + Length = snprintf(Path, sizeof(S.CsvDumpPath), "%s_group_frames.csv", S.CsvDumpPath); + if(Length > 0 && Length < MICROPROFILE_MAX_PATH) + { + FILE* F = fopen(Path, "w"); + if(F) + { + MicroProfileDumpCsvGroupFrames(MicroProfileWriteFile, F, nFirstFrame, nLastFrame, nNumFrames); + fclose(F); + } + } + } + if(S.CsvConfig.State == MicroProfileCsvConfig::ACTIVE) + { + Length = snprintf(Path, sizeof(S.CsvDumpPath), "%s_custom.csv", S.CsvDumpPath); + if(Length > 0 && Length < MICROPROFILE_MAX_PATH) + { + FILE* F = fopen(Path, "w"); + if(F) + { + MicroProfileDumpCsvWithConfig(MicroProfileWriteFile, F, nFirstFrame, nLastFrame, nNumFrames); + fclose(F); + } + } + } +} + +void MicroProfileDumpCsvLegacy(MicroProfileWriteCallback CB, void* Handle) +{ + uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1; + float fToMsCPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()); + float fToMsGPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu()); + + printf("frames,%d\n", nAggregateFrames); + printf("group,name,average,max,callaverage\n"); + + uint32_t nNumTimers = S.nTotalTimers; + uint32_t nBlockSize = 2 * nNumTimers; + float* pTimers = (float*)alloca(nBlockSize * 9 * sizeof(float)); + float* pAverage = pTimers + nBlockSize; + float* pMax = pTimers + 2 * nBlockSize; + float* pMin = pTimers + 3 * nBlockSize; + float* pCallAverage = pTimers + 4 * nBlockSize; + float* pTimersExclusive = pTimers + 5 * nBlockSize; + float* pAverageExclusive = pTimers + 6 * nBlockSize; + float* pMaxExclusive = pTimers + 7 * nBlockSize; + float* pTotal = pTimers + 8 * nBlockSize; + + MicroProfileCalcAllTimers(pTimers, pAverage, pMax, pMin, pCallAverage, pTimersExclusive, pAverageExclusive, pMaxExclusive, pTotal, nNumTimers); + + for(uint32_t i = 0; i < S.nTotalTimers; ++i) + { + uint32_t nIdx = i * 2; + printf("\"%s\",\"%s\",%f,%f,%f\n", S.TimerInfo[i].pName, S.GroupInfo[S.TimerInfo[i].nGroupIndex].pName, pAverage[nIdx], pMax[nIdx], pCallAverage[nIdx]); + } + + printf("\n\n"); + + printf("group,average,max,total\n"); + for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j) + { + const char* pGroupName = S.GroupInfo[j].pName; + float fToMs = S.GroupInfo[j].Type == MicroProfileTokenTypeGpu ? fToMsGPU : fToMsCPU; + if(pGroupName[0] != '\0') + { + printf("\"%s\",%.3f,%.3f,%.3f\n", pGroupName, fToMs * S.AggregateGroup[j] / nAggregateFrames, fToMs * S.AggregateGroup[j] / nAggregateFrames, fToMs * S.AggregateGroup[j]); + } + } + + printf("\n\n"); + printf("group,thread,average,total\n"); + for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j) + { + for(uint32_t i = 0; i < S.nNumLogs; ++i) + { + if(S.Pool[i]) + { + const char* pThreadName = &S.Pool[i]->ThreadName[0]; + // MicroProfilePrintf(CB, Handle, "var ThreadGroupTime%d = [", i); + float fToMs = S.Pool[i]->nGpu ? fToMsGPU : fToMsCPU; + { + uint64_t nTicks = S.Pool[i]->nAggregateGroupTicks[j]; + float fTime = nTicks / nAggregateFrames * fToMs; + float fTimeTotal = nTicks * fToMs; + if(fTimeTotal > 0.01f) + { + const char* pGroupName = S.GroupInfo[j].pName; + printf("\"%s\",\"%s\",%.3f,%.3f\n", pGroupName, pThreadName, fTime, fTimeTotal); + } + } + } + } + } + + printf("\n\n"); + printf("frametimecpu\n"); + + const uint32_t nCount = MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 3; + const uint32_t nStart = S.nFrameCurrent; + for(uint32_t i = nCount; i > 0; i--) + { + uint32_t nFrame = (nStart + MICROPROFILE_MAX_FRAME_HISTORY - i) % MICROPROFILE_MAX_FRAME_HISTORY; + uint32_t nFrameNext = (nStart + MICROPROFILE_MAX_FRAME_HISTORY - i + 1) % MICROPROFILE_MAX_FRAME_HISTORY; + uint64_t nTicks = S.Frames[nFrameNext].nFrameStartCpu - S.Frames[nFrame].nFrameStartCpu; + printf("%f,", nTicks * fToMsCPU); + } + printf("\n"); + + printf("\n\n"); + printf("frametimegpu\n"); + + for(uint32_t i = nCount; i > 0; i--) + { + uint32_t nFrame = (nStart + MICROPROFILE_MAX_FRAME_HISTORY - i) % MICROPROFILE_MAX_FRAME_HISTORY; + uint32_t nFrameNext = (nStart + MICROPROFILE_MAX_FRAME_HISTORY - i + 1) % MICROPROFILE_MAX_FRAME_HISTORY; + uint64_t nTicks = S.Frames[nFrameNext].nFrameStartGpu - S.Frames[nFrame].nFrameStartGpu; + printf("%f,", nTicks * fToMsGPU); + } + printf("\n\n"); +} +#undef printf + +void MicroProfileDumpCsvLegacy() +{ + char Path[MICROPROFILE_MAX_PATH]; + int Length = snprintf(Path, sizeof(S.CsvDumpPath), "%s.csv", S.CsvDumpPath); + if(Length > 0 && Length < MICROPROFILE_MAX_PATH) + { + FILE* F = fopen(Path, "w"); + if(F) + { + MicroProfileDumpCsvLegacy(MicroProfileWriteFile, F); + fclose(F); + } + } +} + +void MicroProfileDumpHtmlLive(MicroProfileWriteCallback CB, void* Handle) +{ + for(size_t i = 0; i < g_MicroProfileHtmlLive_begin_count; ++i) + { + CB(Handle, g_MicroProfileHtmlLive_begin_sizes[i] - 1, g_MicroProfileHtmlLive_begin[i]); + } + for(size_t i = 0; i < g_MicroProfileHtmlLive_end_count; ++i) + { + CB(Handle, g_MicroProfileHtmlLive_end_sizes[i] - 1, g_MicroProfileHtmlLive_end[i]); + } +} +void MicroProfileGetCoreInformation() +{ +#ifdef _WIN32 + unsigned long BufferSize; + HANDLE Process = GetCurrentProcess(); + GetSystemCpuSetInformation(nullptr, 0, &BufferSize, Process, 0); + char* Buffer = (char*)alloca(BufferSize); + if(!GetSystemCpuSetInformation((PSYSTEM_CPU_SET_INFORMATION)Buffer, BufferSize, &BufferSize, Process, 0)) + { + return; + } + for(ULONG Size = 0; Size < BufferSize;) + { + PSYSTEM_CPU_SET_INFORMATION CpuSet = reinterpret_cast(Buffer); + if(CpuSet->Type == CPU_SET_INFORMATION_TYPE::CpuSetInformation) + { + if(CpuSet->CpuSet.CoreIndex < MICROPROFILE_MAX_CPU_CORES) + { + S.CoreEfficiencyClass[CpuSet->CpuSet.LogicalProcessorIndex] = CpuSet->CpuSet.EfficiencyClass; + } + } + Buffer += CpuSet->Size; + Size += CpuSet->Size; + } +#endif +} + +void MicroProfileDumpHtml(MicroProfileWriteCallback CB, void* Handle, uint64_t nMaxFrames, const char* pHost, uint64_t nStartFrameId = (uint64_t)-1) +{ + // Stall pushing of timers + uint64_t nActiveGroup[MICROPROFILE_MAX_GROUP_INTS]; + memcpy(nActiveGroup, S.nActiveGroups, sizeof(S.nActiveGroups)); + memset(S.nActiveGroups, 0, sizeof(S.nActiveGroups)); + bool AnyActive = S.AnyActive; + S.AnyActive = false; + + S.nPauseTicks = MP_TICK(); + + MicroProfileGetCoreInformation(); + + if(S.bContextSwitchRunning) + { + auto StallForContextSwitchThread = []() + { + int64_t nPauseTicks = S.nPauseTicks; + int64_t nContextSwitchStalledTick = S.nContextSwitchStalledTick; + return (nPauseTicks - nContextSwitchStalledTick) > 0; + }; + int SleepMs = 1; + while(S.bContextSwitchRunning && !S.bContextSwitchStop && StallForContextSwitchThread()) + { + MicroProfileSleep(SleepMs); + SleepMs = SleepMs * 2 / 3; + SleepMs = MicroProfileMin(128, SleepMs); + } + int64_t TicksAfterStall = MP_TICK(); + uprintf("Stalled %7.2fms for context switch data\n", MicroProfileTickToMsMultiplierCpu() * (TicksAfterStall - S.nPauseTicks)); + } + + MicroProfileHashTable StringsHashTable; + MicroProfileHashTableInit(&StringsHashTable, 50, 25, MicroProfileHashTableCompareString, MicroProfileHashTableHashString); + + defer + { + MicroProfileHashTableDestroy(&StringsHashTable); + }; + + MicroProfileCounterFetchCounters(); + for(size_t i = 0; i < g_MicroProfileHtml_begin_count; ++i) + { + CB(Handle, g_MicroProfileHtml_begin_sizes[i] - 1, g_MicroProfileHtml_begin[i]); + } + // dump info + uint64_t nTicks = MP_TICK(); + + float fToMsCPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()); + float fToMsGPU = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu()); + float fAggregateMs = fToMsCPU * (nTicks - S.nAggregateFlipTick); + + uint32_t nNumFrames = 0; + uint32_t nFirstFrame = (uint32_t)-1; + if(nStartFrameId != (uint64_t)-1) + { + // search for the frane + for(uint32_t i = 0; i < MICROPROFILE_MAX_FRAME_HISTORY; ++i) + { + if(S.Frames[i].nFrameId == nStartFrameId) + { + nFirstFrame = i; + break; + } + } + if(nFirstFrame != (uint32_t)-1) + { + uint32_t nLastFrame = S.nFrameCurrent; + uint32_t nDistance = (MICROPROFILE_MAX_FRAME_HISTORY + nFirstFrame - nLastFrame) % MICROPROFILE_MAX_FRAME_HISTORY; + nNumFrames = MicroProfileMin(nDistance, (uint32_t)nMaxFrames); + } + } + + if(nNumFrames == 0) + { + nNumFrames = (MICROPROFILE_MAX_FRAME_HISTORY - MICROPROFILE_GPU_FRAME_DELAY - 3); // leave a few to not overwrite + nNumFrames = MicroProfileMin(nNumFrames, (uint32_t)nMaxFrames); + nFirstFrame = (S.nFrameCurrent + MICROPROFILE_MAX_FRAME_HISTORY - nNumFrames) % MICROPROFILE_MAX_FRAME_HISTORY; + } + + uint32_t nLastFrame = (nFirstFrame + nNumFrames) % MICROPROFILE_MAX_FRAME_HISTORY; + MP_ASSERT(nFirstFrame < MICROPROFILE_MAX_FRAME_HISTORY); + MP_ASSERT(nLastFrame < MICROPROFILE_MAX_FRAME_HISTORY); + + MicroProfilePrintf(CB, Handle, "S.DumpHost = '%s';\n", pHost ? pHost : ""); + time_t CaptureTime; + time(&CaptureTime); + MicroProfilePrintf(CB, Handle, "S.DumpUtcCaptureTime = %ld;\n", CaptureTime); + MicroProfilePrintf(CB, Handle, "S.AggregateInfo = {'Frames':%d, 'Time':%f};\n", S.nAggregateFrames, fAggregateMs); + + // categories + MicroProfilePrintf(CB, Handle, "S.CategoryInfo = Array(%d);\n", S.nCategoryCount); + for(uint32_t i = 0; i < S.nCategoryCount; ++i) + { + MicroProfilePrintf(CB, Handle, "S.CategoryInfo[%d] = \"%s\";\n", i, S.CategoryInfo[i].pName); + } + + // groups + MicroProfilePrintf(CB, Handle, "S.GroupInfo = Array(%d);\n\n", S.nGroupCount + 1); + uint32_t nAggregateFrames = S.nAggregateFrames ? S.nAggregateFrames : 1; + float fRcpAggregateFrames = 1.f / nAggregateFrames; + (void)fRcpAggregateFrames; + char ColorString[32]; + for(uint32_t i = 0; i < S.nGroupCount; ++i) + { + MP_ASSERT(i == S.GroupInfo[i].nGroupIndex); + float fToMs = S.GroupInfo[i].Type == MicroProfileTokenTypeCpu ? fToMsCPU : fToMsGPU; + const char* pColorStr = ""; + if(S.GroupInfo[i].nColor != 0x42) + { + stbsp_snprintf(ColorString, + sizeof(ColorString) - 1, + "#%02x%02x%02x", + MICROPROFILE_UNPACK_RED(S.GroupInfo[i].nColor) & 0xff, + MICROPROFILE_UNPACK_GREEN(S.GroupInfo[i].nColor) & 0xff, + MICROPROFILE_UNPACK_BLUE(S.GroupInfo[i].nColor) & 0xff); + pColorStr = &ColorString[0]; + } + MicroProfilePrintf(CB, + Handle, + "S.GroupInfo[%d] = MakeGroup(%d, \"%s\", %d, %d, %d, %f, %f, %f, '%s');\n", + S.GroupInfo[i].nGroupIndex, + S.GroupInfo[i].nGroupIndex, + S.GroupInfo[i].pName, + S.GroupInfo[i].nCategory, + S.GroupInfo[i].nNumTimers, + S.GroupInfo[i].Type == MicroProfileTokenTypeGpu ? 1 : 0, + fToMs * S.AggregateGroup[i], + fToMs * S.AggregateGroup[i] / nAggregateFrames, + fToMs * S.AggregateGroupMax[i], + pColorStr); + } + uint32_t nUncategorized = S.nGroupCount; + + MicroProfilePrintf(CB, + Handle, + "S.GroupInfo[%d] = MakeGroup(%d, \"%s\", %d, %d, %d, %f, %f, %f, 'grey');\n", + nUncategorized, + nUncategorized, + "Uncategorized", + -1, + 1, + // S.GroupInfo[i].Type == MicroProfileTokenTypeGpu ? 1 : + 0, + 0, + 0, + 0); + + // timers + + uint32_t nNumTimers = S.nTotalTimers; + uint32_t nBlockSize = 2 * nNumTimers; + float* pTimers = (float*)alloca(nBlockSize * 9 * sizeof(float)); + float* pAverage = pTimers + nBlockSize; + float* pMax = pTimers + 2 * nBlockSize; + float* pMin = pTimers + 3 * nBlockSize; + float* pCallAverage = pTimers + 4 * nBlockSize; + float* pTimersExclusive = pTimers + 5 * nBlockSize; + float* pAverageExclusive = pTimers + 6 * nBlockSize; + float* pMaxExclusive = pTimers + 7 * nBlockSize; + float* pTotal = pTimers + 8 * nBlockSize; + + MicroProfileCalcAllTimers(pTimers, pAverage, pMax, pMin, pCallAverage, pTimersExclusive, pAverageExclusive, pMaxExclusive, pTotal, nNumTimers); + + MicroProfilePrintf(CB, Handle, "\nS.TimerInfo = Array(%d);\n\n", S.nTotalTimers); + for(uint32_t i = 0; i < S.nTotalTimers; ++i) + { + uint32_t nIdx = i * 2; + MP_ASSERT(i == S.TimerInfo[i].nTimerIndex); + MicroProfilePrintf(CB, Handle, "S.Meta%d = [];\n", i); + MicroProfilePrintf(CB, Handle, "S.MetaAvg%d = [];\n", i); + MicroProfilePrintf(CB, Handle, "S.MetaMax%d = [];\n", i); + + uint32_t nColor = S.TimerInfo[i].nColor; + uint32_t nColorDark = (nColor >> 1) & ~0x80808080; + MicroProfilePrintf(CB, + Handle, + "S.TimerInfo[%d] = MakeTimer(%d, \"%s\", %d, '#%02x%02x%02x','#%02x%02x%02x', %f, %f, %f, %f, %f, %f, %d, %f, S.Meta%d, S.MetaAvg%d, S.MetaMax%d, %d);\n", + S.TimerInfo[i].nTimerIndex, + S.TimerInfo[i].nTimerIndex, + S.TimerInfo[i].pName, + S.TimerInfo[i].nGroupIndex, + MICROPROFILE_UNPACK_RED(nColor) & 0xff, + MICROPROFILE_UNPACK_GREEN(nColor) & 0xff, + MICROPROFILE_UNPACK_BLUE(nColor) & 0xff, + MICROPROFILE_UNPACK_RED(nColorDark) & 0xff, + MICROPROFILE_UNPACK_GREEN(nColorDark) & 0xff, + MICROPROFILE_UNPACK_BLUE(nColorDark) & 0xff, + pAverage[nIdx], + pMax[nIdx], + pMin[nIdx], + pAverageExclusive[nIdx], + pMaxExclusive[nIdx], + pCallAverage[nIdx], + S.Aggregate[i].nCount, + pTotal[nIdx], + i, + i, + i, + S.TimerInfo[i].Flags); + } + + uint32_t nTotalTimersExt = S.nTotalTimers; + { + for(uint32_t j = 0; j < S.nNumLogs; ++j) + { + MicroProfileThreadLog* pLog = S.Pool[j]; + uint32_t nLogStart = S.Frames[nFirstFrame].nLogStart[j]; + uint32_t nLogEnd = S.Frames[nLastFrame].nLogStart[j]; + uint64_t nLogType; + if(nLogStart != nLogEnd) + { + for(uint32_t k = nLogStart; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE) + { + uint64_t v = pLog->Log[k]; + nLogType = MicroProfileLogGetType(v); + uint32_t tidx = MicroProfileLogGetTimerIndex(v); + if((nLogType == MP_LOG_ENTER || nLogType == MP_LOG_LEAVE) && tidx == ETOKEN_CSTR_PTR) + { + MP_ASSERT(k + 1 != nLogEnd); + uint64_t v1 = pLog->Log[(k + 1) % MICROPROFILE_BUFFER_SIZE]; + const char* pString = (const char*)MicroProfileLogGetExtendedPayloadNoDataPtr(v1); + uintptr_t value; + if(!MicroProfileHashTableGet(&StringsHashTable, (uint64_t)pString, &value)) + { + uintptr_t nTimerIndex = nTotalTimersExt++; + MicroProfileHashTableSet(&StringsHashTable, (uint64_t)pString, nTimerIndex); + MicroProfilePrintf( + CB, Handle, "S.TimerInfo.push(MakeTimer(%d, \"%s\", %d, '#000000','#000000', 0, 0, 0, 0, 0, 0, 0, 0, null, null, null, 0));\n", nTimerIndex, pString, nUncategorized); + } + } + } + } + } + } + + MicroProfilePrintf(CB, Handle, "\nS.ThreadNames = ["); + for(uint32_t i = 0; i < S.nNumLogs; ++i) + { + if(S.Pool[i]) + { + MicroProfilePrintf(CB, Handle, "'%s',", S.Pool[i]->ThreadName); + } + else + { + MicroProfilePrintf(CB, Handle, "'Thread %d',", i); + } + } + MicroProfilePrintf(CB, Handle, "];\n\n"); + MicroProfilePrintf(CB, Handle, "\nS.ISGPU = ["); + for(uint32_t i = 0; i < S.nNumLogs; ++i) + { + MicroProfilePrintf(CB, Handle, "%d,", (S.Pool[i] && S.Pool[i]->nGpu) ? 1 : 0); + } + MicroProfilePrintf(CB, Handle, "];\n\n"); + + for(uint32_t i = 0; i < S.nNumLogs; ++i) + { + if(S.Pool[i]) + { + MicroProfilePrintf(CB, Handle, "S.ThreadGroupTime%d = [", i); + float fToMs = S.Pool[i]->nGpu ? fToMsGPU : fToMsCPU; + for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j) + { + MicroProfilePrintf(CB, Handle, "%f,", S.Pool[i]->nAggregateGroupTicks[j] / nAggregateFrames * fToMs); + } + MicroProfilePrintf(CB, Handle, "];\n"); + } + } + MicroProfilePrintf(CB, Handle, "\nS.ThreadGroupTimeArray = ["); + for(uint32_t i = 0; i < S.nNumLogs; ++i) + { + if(S.Pool[i]) + { + MicroProfilePrintf(CB, Handle, "S.ThreadGroupTime%d,", i); + } + } + MicroProfilePrintf(CB, Handle, "];\n"); + + for(uint32_t i = 0; i < S.nNumLogs; ++i) + { + if(S.Pool[i]) + { + MicroProfilePrintf(CB, Handle, "S.ThreadGroupTimeTotal%d = [", i); + float fToMs = S.Pool[i]->nGpu ? fToMsGPU : fToMsCPU; + for(uint32_t j = 0; j < MICROPROFILE_MAX_GROUPS; ++j) + { + MicroProfilePrintf(CB, Handle, "%f,", S.Pool[i]->nAggregateGroupTicks[j] * fToMs); + } + MicroProfilePrintf(CB, Handle, "];\n"); + } + } + MicroProfilePrintf(CB, Handle, "\nS.ThreadGroupTimeTotalArray = ["); + for(uint32_t i = 0; i < S.nNumLogs; ++i) + { + if(S.Pool[i]) + { + MicroProfilePrintf(CB, Handle, "S.ThreadGroupTimeTotal%d,", i); + } + } + MicroProfilePrintf(CB, Handle, "];"); + + MicroProfilePrintf(CB, Handle, "\nS.ThreadIds = ["); + for(uint32_t i = 0; i < S.nNumLogs; ++i) + { + if(S.Pool[i]) + { + MicroProfileThreadIdType ThreadId = S.Pool[i]->nThreadId; + if(!ThreadId) + { + ThreadId = (MicroProfileThreadIdType)-1; + } + MicroProfilePrintf(CB, Handle, "%" PRIu64 ",", (uint64_t)ThreadId); + } + else + { + MicroProfilePrintf(CB, Handle, "-1,"); + } + } + MicroProfilePrintf(CB, Handle, "];\n\n"); + + for(int i = 0; i < (int)S.nNumCounters; ++i) + { + bool IsDouble = (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) != 0; + if(0 != (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DETAILED) && !IsDouble) + { + int64_t nCounterMax = S.nCounterMax[i]; + int64_t nCounterMin = S.nCounterMin[i]; + uint32_t nBaseIndex = S.nCounterHistoryPut; + MicroProfilePrintf(CB, Handle, "\nS.CounterHistoryArray%d =[", i); + for(uint32_t j = 0; j < MICROPROFILE_GRAPH_HISTORY; ++j) + { + uint32_t nHistoryIndex = (nBaseIndex + j) % MICROPROFILE_GRAPH_HISTORY; + int64_t nValue = MicroProfileClamp(S.nCounterHistory[nHistoryIndex][i], nCounterMin, nCounterMax); + MicroProfilePrintf(CB, Handle, "%lld,", nValue); + } + MicroProfilePrintf(CB, Handle, "];\n"); + + int64_t nCounterHeightBase = nCounterMax; + int64_t nCounterOffset = 0; + if(nCounterMin < 0) + { + nCounterHeightBase = nCounterMax - nCounterMin; + nCounterOffset = -nCounterMin; + } + double fRcp = nCounterHeightBase ? (1.0 / nCounterHeightBase) : 0; + + MicroProfilePrintf(CB, Handle, "\nS.CounterHistoryArrayPrc%d =[", i); + for(uint32_t j = 0; j < MICROPROFILE_GRAPH_HISTORY; ++j) + { + uint32_t nHistoryIndex = (nBaseIndex + j) % MICROPROFILE_GRAPH_HISTORY; + int64_t nValue = MicroProfileClamp(S.nCounterHistory[nHistoryIndex][i], nCounterMin, nCounterMax); + float fPrc = (nValue + nCounterOffset) * fRcp; + MicroProfilePrintf(CB, Handle, "%f,", fPrc); + } + MicroProfilePrintf(CB, Handle, "];\n"); + MicroProfilePrintf(CB, Handle, "S.CounterHistory%d = MakeCounterHistory(%d, S.CounterHistoryArray%d, S.CounterHistoryArrayPrc%d)\n", i, i, i, i); + } + else + { + MicroProfilePrintf(CB, Handle, "S.CounterHistory%d;\n", i); + } + } + + MicroProfilePrintf(CB, Handle, "\nS.CounterInfo = ["); + + for(int i = 0; i < (int)S.nNumCounters; ++i) + { + bool IsDouble = (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) != 0; + float fCounterPrc = 0.f; + float fBoxPrc = 1.f; + double dCounter, dLimit, dMax, dMin; + char Formatted[64]; + char FormattedLimit[64]; + + if(!IsDouble) + { + uint64_t nCounter = S.Counters[i].load(); + uint64_t nLimit = S.CounterInfo[i].nLimit; + fCounterPrc = 0.f; + if(nLimit) + { + fCounterPrc = (float)nCounter / nLimit; + if(fCounterPrc > 1.f) + { + fBoxPrc = 1.f / fCounterPrc; + fCounterPrc = 1.f; + } + } + MicroProfileFormatCounter(S.CounterInfo[i].eFormat, nCounter, Formatted, sizeof(Formatted) - 1); + MicroProfileFormatCounter(S.CounterInfo[i].eFormat, S.CounterInfo[i].nLimit, FormattedLimit, sizeof(FormattedLimit) - 1); + + dCounter = (double)nCounter; + dMin = (double)S.nCounterMin[i]; + dMax = (double)S.nCounterMax[i]; + dLimit = (double)nLimit; + } + else + { + dCounter = S.CountersDouble[i].load(); + dLimit = S.CounterInfo[i].dLimit; + fCounterPrc = 0.f; + if(dLimit > 0.f) + { + fCounterPrc = (float)(dCounter / dLimit); + if(fCounterPrc > 1.f) + { + fBoxPrc = 1.f / fCounterPrc; + fCounterPrc = 1.f; + } + } + MicroProfileFormatCounterDouble(S.CounterInfo[i].eFormat, dCounter, Formatted, sizeof(Formatted) - 1); + MicroProfileFormatCounterDouble(S.CounterInfo[i].eFormat, S.CounterInfo[i].dLimit, FormattedLimit, sizeof(FormattedLimit) - 1); + dMin = (double)S.dCounterMin[i]; + dMax = (double)S.dCounterMax[i]; + } + MicroProfilePrintf(CB, + Handle, + "MakeCounter(%d, %d, %d, %d, %d, '%s', %f, %f, %f, '%s', %f, '%s', %f, %f, %d, S.CounterHistory%d),", + i, + S.CounterInfo[i].nParent, + S.CounterInfo[i].nSibling, + S.CounterInfo[i].nFirstChild, + S.CounterInfo[i].nLevel, + S.CounterInfo[i].pName, + dCounter, + dMin, + dMax, + Formatted, + dLimit, + FormattedLimit, + fCounterPrc, + fBoxPrc, + S.CounterInfo[i].eFormat == MICROPROFILE_COUNTER_FORMAT_BYTES ? 1 : 0, + i); + } + MicroProfilePrintf(CB, Handle, "];\n\n"); + + const int64_t nTickStart = S.Frames[nFirstFrame].nFrameStartCpu; + const int64_t nTickEnd = S.Frames[nLastFrame].nFrameStartCpu; + int64_t nTickStartGpu = S.Frames[nFirstFrame].nFrameStartGpu; + + int64_t nTickReferenceCpu, nTickReferenceGpu; + int64_t nTicksPerSecondCpu = MicroProfileTicksPerSecondCpu(); + int64_t nTicksPerSecondGpu = MicroProfileTicksPerSecondGpu(); + int nTickReference = 0; + if(MicroProfileGetGpuTickReference(&nTickReferenceCpu, &nTickReferenceGpu)) + { + nTickStartGpu = (nTickStart - nTickReferenceCpu) * nTicksPerSecondGpu / nTicksPerSecondCpu + nTickReferenceGpu; + nTickReference = 1; + } + + uprintf("dumping %d frames\n", nNumFrames); + uprintf("dumping frame %d to %d\n", nFirstFrame, nLastFrame); + + uint32_t* nTimerCounter = (uint32_t*)alloca(sizeof(uint32_t) * S.nTotalTimers); + memset(nTimerCounter, 0, sizeof(uint32_t) * S.nTotalTimers); + + { + MicroProfilePrintf(CB, Handle, " //Timeline begin\n"); + MicroProfileThreadLog* pLog = &S.TimelineLog; + uint32_t nFrameIndexFirst = (nFirstFrame) % MICROPROFILE_MAX_FRAME_HISTORY; + uint32_t nFrameIndexLast = (nFirstFrame + nNumFrames) % MICROPROFILE_MAX_FRAME_HISTORY; + { + // find the frame that has an active marker the furtest distance from the selected range + int nDelta = 0; + int nOffset = 0; + for(uint32_t i = nFrameIndexFirst; i != nFrameIndexLast; i = (i + 1) % MICROPROFILE_MAX_FRAME_HISTORY) + { + int D = (int)S.Frames[i].nTimelineFrameMax - nOffset; + nDelta = MicroProfileMax(D, nDelta); + nOffset++; + } + nFrameIndexFirst = (nFirstFrame - nDelta) % MICROPROFILE_MAX_FRAME_HISTORY; + } + + uint32_t nLogStart = S.Frames[nFrameIndexFirst].nLogStartTimeline; + uint32_t nLogEnd = S.Frames[nFrameIndexLast].nLogStartTimeline; + float fToMs = MicroProfileTickToMsMultiplier(nTicksPerSecondCpu); + +#define pp(...) MicroProfilePrintf(CB, Handle, __VA_ARGS__) + + if(nLogStart != nLogEnd) + { + uint32_t nLogType; + float fTime; + int f = 0; + + pp("S.TimelineColorArray=["); + for(uint32_t k = nLogStart; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE) + { + uint64_t v = pLog->Log[k]; + uint64_t nIndex = MicroProfileLogGetTimerIndex(v); + uint64_t nTick = MicroProfileLogGetTick(v); + (void)nTick; + nLogType = MicroProfileLogGetType(v); + switch(nLogType) + { + case MP_LOG_ENTER: + break; + case MP_LOG_LEAVE: + pp("%c'%s'", f++ ? ',' : ' ', "#ff8080"); + break; + + case MP_LOG_EXTENDED: + case MP_LOG_EXTENDED_NO_DATA: + uint32_t payload = MicroProfileLogGetExtendedPayload(v); + if(nIndex == ETOKEN_CUSTOM_COLOR) + { + uint32_t nColor = payload; + pp("%c'#%02x%02x%02x'", f++ ? ',' : ' ', MICROPROFILE_UNPACK_RED(nColor) & 0xff, MICROPROFILE_UNPACK_GREEN(nColor) & 0xff, MICROPROFILE_UNPACK_BLUE(nColor) & 0xff); + } + k += MicroProfileLogGetDataSize(v); + break; + } + } + pp("];\n"); + + f = 0; + pp("S.TimelineIdArray=["); + for(uint32_t k = nLogStart; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE) + { + uint64_t v = pLog->Log[k]; + uint64_t nIndex = MicroProfileLogGetTimerIndex(v); + uint64_t nTick = MicroProfileLogGetTick(v); + (void)nTick; + nLogType = MicroProfileLogGetType(v); + switch(nLogType) + { + case MP_LOG_ENTER: + case MP_LOG_LEAVE: + case MP_LOG_EXTENDED_NO_DATA: + + break; + case MP_LOG_EXTENDED: + if(nIndex == ETOKEN_CUSTOM_ID) + { + pp("%c%d", f++ ? ',' : ' ', (uint32_t)nTick); + } + k += MicroProfileLogGetDataSize(v); + break; + } + } + pp("];\n"); + + f = 0; + + pp("S.TimelineArray=["); + for(uint32_t k = nLogStart; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE) + { + uint64_t v = pLog->Log[k]; + nLogType = MicroProfileLogGetType(v); + switch(nLogType) + { + case MP_LOG_ENTER: + case MP_LOG_LEAVE: + fTime = MicroProfileLogTickDifference(nTickStart, v) * fToMs; + pp("%c%f", f++ ? ',' : ' ', fTime); + break; + case MP_LOG_EXTENDED: + k += MicroProfileLogGetDataSize(v); + break; + case MP_LOG_EXTENDED_NO_DATA: + break; + } + } + pp("];\n"); + pp("S.TimelineNames=["); + f = 0; + char String[MICROPROFILE_MAX_STRING + 1]; + for(uint32_t k = nLogStart; k != nLogEnd;) + { + uint64_t v = pLog->Log[k]; + nLogType = MicroProfileLogGetType(v); + uint64_t nIndex = MicroProfileLogGetTimerIndex(v); + uint64_t nTick = MicroProfileLogGetTick(v); + (void)nTick; + switch(nLogType) + { + case MP_LOG_ENTER: + case MP_LOG_LEAVE: + if(nIndex == ETOKEN_CUSTOM_NAME && nLogType == MP_LOG_LEAVE) + { + // pp(f++ ? ",''" : "''"); + } + k = (k + 1) % MICROPROFILE_BUFFER_SIZE; + break; + case MP_LOG_EXTENDED_NO_DATA: + k = (k + 1) % MICROPROFILE_BUFFER_SIZE; + break; + case MP_LOG_EXTENDED: + uint32_t nSize = MicroProfileLogGetDataSize(v); + + if(nIndex == ETOKEN_CUSTOM_ID) + { + char* pSource = (char*)&pLog->Log[(k + 1) % MICROPROFILE_BUFFER_SIZE]; + const char* pOut = nullptr; + if(nSize == 0) + { + pOut = ""; + } + else if(k + nSize <= MICROPROFILE_BUFFER_SIZE) + { + pOut = pSource; + } + else + { + pOut = &String[0]; + char* pDest = &String[0]; + MP_ASSERT(nSize * 8 < sizeof(MICROPROFILE_MAX_STRING) + 1); + uint32_t Index = (k + 1) % MICROPROFILE_BUFFER_SIZE; + for(uint32_t l = 0; l < nSize; ++l) + { + memcpy(pDest, (char*)pLog->Log[Index], sizeof(uint64_t)); + Index = (Index + 1) % MICROPROFILE_BUFFER_SIZE; + } + } + if(f++) + { + pp(",'%s'", pOut); + } + else + { + pp("'%s'", pOut); + } + } + k = (k + 1 + nSize) % MICROPROFILE_BUFFER_SIZE; + break; + } + } + pp("];\n"); + } + MicroProfilePrintf(CB, Handle, " //Timeline end\n"); + } + + MicroProfilePrintf(CB, Handle, "S.Frames = Array(%d);\n", nNumFrames); + for(uint32_t i = 0; i < nNumFrames; ++i) + { + uint32_t nFrameIndex = (nFirstFrame + i) % MICROPROFILE_MAX_FRAME_HISTORY; + uint32_t nFrameIndexNext = (nFrameIndex + 1) % MICROPROFILE_MAX_FRAME_HISTORY; + + for(uint32_t j = 0; j < S.nNumLogs; ++j) + { + MicroProfileThreadLog* pLog = S.Pool[j]; + int64_t nStartTickBase = pLog->nGpu ? nTickStartGpu : nTickStart; + uint32_t nLogStart = S.Frames[nFrameIndex].nLogStart[j]; + uint32_t nLogEnd = S.Frames[nFrameIndexNext].nLogStart[j]; + uint32_t nLogType; + float fToMs; + uint64_t nStartTick; + float fToMsCpu = MicroProfileTickToMsMultiplier(nTicksPerSecondCpu); + float fToMsBase = MicroProfileTickToMsMultiplier(pLog->nGpu ? nTicksPerSecondGpu : nTicksPerSecondCpu); + MicroProfilePrintf(CB, Handle, "S.ts_%d_%d = [", i, j); + if(nLogStart != nLogEnd) + { + int f = 0; + for(uint32_t k = nLogStart; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE) + { + float fTime; + MicroProfileLogEntry v = pLog->Log[k]; + nLogType = MicroProfileLogGetType(v); + fToMs = fToMsBase; + nStartTick = nStartTickBase; + switch(nLogType) + { + case MP_LOG_EXTENDED: + { + fTime = 0.f; + k += MicroProfileLogGetDataSize(v); + break; + } + case MP_LOG_EXTENDED_NO_DATA: + { + uint32_t nTimerIndex = (uint32_t)MicroProfileLogGetTimerIndex(v); + if(nTimerIndex == ETOKEN_GPU_CPU_TIMESTAMP) + { + fToMs = fToMsCpu; + nStartTick = nTickStart; + fTime = MicroProfileLogTickDifference(nStartTick, v) * fToMs; + } + else + { + fTime = 0.f; + } + break; + } + default: + fTime = MicroProfileLogTickDifference(nStartTick, pLog->Log[k]) * fToMs; + } + MicroProfilePrintf(CB, Handle, f++ ? ",%f" : "%f", fTime); + } + } + MicroProfilePrintf(CB, Handle, "];\n"); + + MicroProfilePrintf(CB, Handle, "S.tt_%d_%d = [", i, j); + if(nLogStart != nLogEnd) + { + uint32_t k = nLogStart; + MicroProfilePrintf(CB, Handle, "%d", MicroProfileLogGetType(pLog->Log[k])); + for(k = (k + 1) % MICROPROFILE_BUFFER_SIZE; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE) + { + uint64_t v = pLog->Log[k]; + uint32_t nLogType2 = MicroProfileLogGetType(v); + + if(nLogType2 > MP_LOG_ENTER) + nLogType2 |= (MicroProfileLogGetExtendedToken(v)) + << 2; // pack extended token here.. this way all code can check agains ENTER/LEAVE, and only the ext code needs to care about the top bits. + MicroProfilePrintf(CB, Handle, ",%d", nLogType2); + if(nLogType2 == MP_LOG_EXTENDED) + k += MicroProfileLogGetDataSize(v); + } + } + MicroProfilePrintf(CB, Handle, "];\n"); + + MicroProfilePrintf(CB, Handle, "S.ti_%d_%d = [", i, j); + if(nLogStart != nLogEnd) + { + for(uint32_t k = nLogStart; k != nLogEnd; k = (k + 1) % MICROPROFILE_BUFFER_SIZE) + { + uint64_t v = pLog->Log[k]; + nLogType = MicroProfileLogGetType(v); + const char* pFormat = k == nLogStart ? "%d" : ",%d"; + if(nLogType == MP_LOG_ENTER || nLogType == MP_LOG_LEAVE) + { + uint32_t nTimerIndex = (uint32_t)MicroProfileLogGetTimerIndex(pLog->Log[k]); + if(ETOKEN_CSTR_PTR == nTimerIndex) + { + MP_ASSERT(k + 1 != nLogEnd); + uint64_t v1 = pLog->Log[(k + 1) % MICROPROFILE_BUFFER_SIZE]; + + const char* pString = (const char*)MicroProfileLogGetExtendedPayloadNoDataPtr(v1); + uintptr_t value; + if(!MicroProfileHashTableGet(&StringsHashTable, (uint64_t)pString, &value)) + { + MP_BREAK(); // should be covered earlier. + } + MicroProfilePrintf(CB, Handle, pFormat, value); + } + else + { + if(nTimerIndex < S.nTotalTimers) + { + nTimerCounter[nTimerIndex]++; + } + MicroProfilePrintf(CB, Handle, pFormat, nTimerIndex); + } + } + else + { + uint64_t ExtendedToken = MicroProfileLogGetExtendedToken(v); + uint64_t PayloadNoData = MicroProfileLogGetExtendedPayloadNoData(v); + switch(ExtendedToken) + { + case ETOKEN_GPU_CPU_SOURCE_THREAD: + MicroProfilePrintf(CB, Handle, pFormat, PayloadNoData); + break; + default: + MicroProfilePrintf(CB, Handle, pFormat, -1); + } + + if(nLogType == MP_LOG_EXTENDED) + k += MicroProfileLogGetDataSize(v); + } + } + } + MicroProfilePrintf(CB, Handle, "];\n"); + } + + MicroProfilePrintf(CB, Handle, "S.ts%d = [", i); + for(uint32_t j = 0; j < S.nNumLogs; ++j) + { + MicroProfilePrintf(CB, Handle, "S.ts_%d_%d,", i, j); + } + MicroProfilePrintf(CB, Handle, "];\n"); + MicroProfilePrintf(CB, Handle, "S.tt%d = [", i); + for(uint32_t j = 0; j < S.nNumLogs; ++j) + { + MicroProfilePrintf(CB, Handle, "S.tt_%d_%d,", i, j); + } + MicroProfilePrintf(CB, Handle, "];\n"); + + MicroProfilePrintf(CB, Handle, "S.ti%d = [", i); + for(uint32_t j = 0; j < S.nNumLogs; ++j) + { + MicroProfilePrintf(CB, Handle, "S.ti_%d_%d,", i, j); + } + MicroProfilePrintf(CB, Handle, "];\n"); + + int64_t nFrameStart = S.Frames[nFrameIndex].nFrameStartCpu; + int64_t nFrameEnd = S.Frames[nFrameIndexNext].nFrameStartCpu; + + float fToMs = MicroProfileTickToMsMultiplier(nTicksPerSecondCpu); + float fFrameMs = MicroProfileLogTickDifference(nTickStart, nFrameStart) * fToMs; + float fFrameEndMs = MicroProfileLogTickDifference(nTickStart, nFrameEnd) * fToMs; + float fFrameGpuMs = 0; + float fFrameGpuEndMs = 0; + if(nTickReference) + { + fFrameGpuMs = MicroProfileLogTickDifference(nTickStartGpu, S.Frames[nFrameIndex].nFrameStartGpu) * fToMsGPU; + fFrameGpuEndMs = MicroProfileLogTickDifference(nTickStartGpu, S.Frames[nFrameIndexNext].nFrameStartGpu) * fToMsGPU; + } + MicroProfilePrintf(CB, Handle, "S.Frames[%d] = MakeFrame(%d, %f, %f, %f, %f, S.ts%d, S.tt%d, S.ti%d);\n", i, 0, fFrameMs, fFrameEndMs, fFrameGpuMs, fFrameGpuEndMs, i, i, i); + } + + uint32_t nContextSwitchStart = 0; + uint32_t nContextSwitchEnd = 0; + MicroProfileContextSwitchSearch(&nContextSwitchStart, &nContextSwitchEnd, nTickStart, nTickEnd); + + uprintf("CONTEXT SWITCH SEARCH .... %d %d %d .... %lld, %lld\n", nContextSwitchStart, nContextSwitchEnd, nContextSwitchEnd - nContextSwitchStart, nTickStart, nTickEnd); + + uint32_t nWrittenBefore = S.nWebServerDataSent; + MicroProfilePrintf(CB, Handle, "S.CSwitchThreadInOutCpu = ["); + for(uint32_t j = nContextSwitchStart; j != nContextSwitchEnd; j = (j + 1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE) + { + MicroProfileContextSwitch CS = S.ContextSwitch[j]; + int nCpu = CS.nCpu; + MicroProfilePrintf(CB, Handle, "%d,%d,%d,", CS.nThreadIn, CS.nThreadOut, nCpu); + } + MicroProfilePrintf(CB, Handle, "];\n"); + MicroProfilePrintf(CB, Handle, "S.CSwitchTime = ["); + float fToMsCpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()); + for(uint32_t j = nContextSwitchStart; j != nContextSwitchEnd; j = (j + 1) % MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE) + { + MicroProfileContextSwitch CS = S.ContextSwitch[j]; + float fTime = MicroProfileLogTickDifference(nTickStart, CS.nTicks) * fToMsCpu; + MicroProfilePrintf(CB, Handle, "%f,", fTime); + } + MicroProfilePrintf(CB, Handle, "];\n"); + + MicroProfilePrintf(CB, Handle, "S.CSwitchThreads = {"); + + MicroProfileThreadInfo* pThreadInfo = nullptr; + uint32_t nNumThreads = MicroProfileGetThreadInfoArray(&pThreadInfo); + for(uint32_t i = 0; i < nNumThreads; ++i) + { + const char* p1 = pThreadInfo[i].pThreadModule ? pThreadInfo[i].pThreadModule : "?"; + const char* p2 = pThreadInfo[i].pProcessModule ? pThreadInfo[i].pProcessModule : "?"; + + MicroProfilePrintf(CB, + Handle, + "%" PRId64 ":{\'tid\':%" PRId64 ",\'pid\':%" PRId64 ",\'t\':\'%s\',\'p\':\'%s\'},", + (uint64_t)pThreadInfo[i].tid, + (uint64_t)pThreadInfo[i].tid, + (uint64_t)pThreadInfo[i].pid, + p1, + p2); + } + + MicroProfilePrintf(CB, Handle, "};\n"); + MicroProfilePrintf(CB, Handle, "S.CoreEfficiencyClass = ["); + for(uint32_t i = 0; i < MICROPROFILE_MAX_CPU_CORES; ++i) + { + MicroProfilePrintf(CB, Handle, "%d,", S.CoreEfficiencyClass[i]); + } + MicroProfilePrintf(CB, Handle, "];\n"); + + { + MicroProfilePrintf(CB, Handle, "//String Table\n"); + MicroProfilePrintf(CB, Handle, "S.StringTable = {}\n"); + // dump string table + MicroProfileHashTableIterator beg = MicroProfileGetHashTableIteratorBegin(&StringsHashTable); + MicroProfileHashTableIterator end = MicroProfileGetHashTableIteratorEnd(&StringsHashTable); + while(beg != end) + { + uint64_t Key = beg->Key; + uint64_t Value = beg->Value; + MicroProfilePrintf(CB, Handle, "S.StringTable[%d] = '%s';\n", Value, (const char*)Key); + beg++; + } + } + + uint32_t nWrittenAfter = S.nWebServerDataSent; + + MicroProfilePrintf(CB, Handle, "//CSwitch Size %d\n", nWrittenAfter - nWrittenBefore); + + for(size_t i = 0; i < g_MicroProfileHtml_end_count; ++i) + { + CB(Handle, g_MicroProfileHtml_end_sizes[i] - 1, g_MicroProfileHtml_end[i]); + } + + uint32_t* nGroupCounter = (uint32_t*)alloca(sizeof(uint32_t) * S.nGroupCount); + + memset(nGroupCounter, 0, sizeof(uint32_t) * S.nGroupCount); + for(uint32_t i = 0; i < S.nTotalTimers; ++i) + { + uint32_t nGroupIndex = S.TimerInfo[i].nGroupIndex; + nGroupCounter[nGroupIndex] += nTimerCounter[i]; + } + + uint32_t* nGroupCounterSort = (uint32_t*)alloca(sizeof(uint32_t) * S.nGroupCount); + uint32_t* nTimerCounterSort = (uint32_t*)alloca(sizeof(uint32_t) * S.nTotalTimers); + for(uint32_t i = 0; i < S.nGroupCount; ++i) + { + nGroupCounterSort[i] = i; + } + for(uint32_t i = 0; i < S.nTotalTimers; ++i) + { + nTimerCounterSort[i] = i; + } + std::sort(nGroupCounterSort, nGroupCounterSort + S.nGroupCount, [nGroupCounter](const uint32_t l, const uint32_t r) { return nGroupCounter[l] > nGroupCounter[r]; }); + + std::sort(nTimerCounterSort, nTimerCounterSort + S.nTotalTimers, [nTimerCounter](const uint32_t l, const uint32_t r) { return nTimerCounter[l] > nTimerCounter[r]; }); + + MicroProfilePrintf(CB, Handle, "\n\n"); + + memcpy(S.nActiveGroups, nActiveGroup, sizeof(S.nActiveGroups)); + S.AnyActive = AnyActive; +#if MICROPROFILE_DEBUG + int64_t nTicksEnd = MP_TICK(); + float fMs = fToMsCpu * (nTicksEnd - S.nPauseTicks); + uprintf("html dump took %6.2fms\n", fMs); +#endif + +#undef pp + + S.nPauseTicks = 0; +} + +void MicroProfileWriteFile(void* Handle, size_t nSize, const char* pData) +{ + fwrite(pData, nSize, 1, (FILE*)Handle); +} + +void MicroProfileDumpToFile() +{ + std::lock_guard Lock(MicroProfileMutex()); + if(S.nDumpFileNextFrame & 1) + { + char Path[MICROPROFILE_MAX_PATH]; + int Length = snprintf(Path, sizeof(S.HtmlDumpPath), "%s.html", S.HtmlDumpPath); + if(Length > 0 && Length < MICROPROFILE_MAX_PATH) + { + FILE* F = fopen(Path, "w"); + if(F) + { + MicroProfileDumpHtml(MicroProfileWriteFile, F, S.DumpFrameCount, S.HtmlDumpPath); + fclose(F); + } + } + } + if(S.nDumpFileNextFrame & 2) + { +#if MICROPROFILE_LEGACY_CSV + MicroProfileDumpCsvLegacy(); +#else + MicroProfileDumpCsv(S.DumpFrameCount); +#endif + } +} + +void MicroProfileFlushSocket(MpSocket Socket) +{ + send(Socket, &S.WebServerBuffer[0], S.WebServerPut, 0); + S.WebServerPut = 0; +} + +void MicroProfileWriteSocket(void* Handle, size_t nSize, const char* pData) +{ + S.nWebServerDataSent += nSize; + MpSocket Socket = *(MpSocket*)Handle; + if(nSize > MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE / 2) + { + MicroProfileFlushSocket(Socket); + send(Socket, pData, (int)nSize, 0); + } + else + { + memcpy(&S.WebServerBuffer[S.WebServerPut], pData, nSize); + S.WebServerPut += (uint32_t)nSize; + if(S.WebServerPut > MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE / 2) + { + MicroProfileFlushSocket(Socket); + } + } +} + +#if MICROPROFILE_MINIZ +#ifndef MICROPROFILE_COMPRESS_BUFFER_SIZE +#define MICROPROFILE_COMPRESS_BUFFER_SIZE (256 << 10) +#endif + +#define MICROPROFILE_COMPRESS_CHUNK (MICROPROFILE_COMPRESS_BUFFER_SIZE / 2) +struct MicroProfileCompressedSocketState +{ + unsigned char DeflateOut[MICROPROFILE_COMPRESS_CHUNK]; + unsigned char DeflateIn[MICROPROFILE_COMPRESS_CHUNK]; + mz_stream Stream; + MpSocket Socket; + uint32_t nSize; + uint32_t nCompressedSize; + uint32_t nFlushes; + uint32_t nMemmoveBytes; +}; + +void MicroProfileCompressedSocketFlush(MicroProfileCompressedSocketState* pState) +{ + mz_stream& Stream = pState->Stream; + unsigned char* pSendStart = &pState->DeflateOut[0]; + unsigned char* pSendEnd = &pState->DeflateOut[MICROPROFILE_COMPRESS_CHUNK - Stream.avail_out]; + if(pSendStart != pSendEnd) + { + send(pState->Socket, (const char*)pSendStart, pSendEnd - pSendStart, 0); + pState->nCompressedSize += pSendEnd - pSendStart; + } + Stream.next_out = &pState->DeflateOut[0]; + Stream.avail_out = MICROPROFILE_COMPRESS_CHUNK; +} +void MicroProfileCompressedSocketStart(MicroProfileCompressedSocketState* pState, MpSocket Socket) +{ + mz_stream& Stream = pState->Stream; + memset(&Stream, 0, sizeof(Stream)); + Stream.next_out = &pState->DeflateOut[0]; + Stream.avail_out = MICROPROFILE_COMPRESS_CHUNK; + Stream.next_in = &pState->DeflateIn[0]; + Stream.avail_in = 0; + mz_deflateInit(&Stream, Z_DEFAULT_COMPRESSION); + pState->Socket = Socket; + pState->nSize = 0; + pState->nCompressedSize = 0; + pState->nFlushes = 0; + pState->nMemmoveBytes = 0; +} +void MicroProfileCompressedSocketFinish(MicroProfileCompressedSocketState* pState) +{ + mz_stream& Stream = pState->Stream; + MicroProfileCompressedSocketFlush(pState); + int r = mz_deflate(&Stream, MZ_FINISH); + MP_ASSERT(r == MZ_STREAM_END); + MicroProfileCompressedSocketFlush(pState); + r = mz_deflateEnd(&Stream); + MP_ASSERT(r == MZ_OK); +} + +void MicroProfileCompressedWriteSocket(void* Handle, size_t nSize, const char* pData) +{ + MicroProfileCompressedSocketState* pState = (MicroProfileCompressedSocketState*)Handle; + mz_stream& Stream = pState->Stream; + const unsigned char* pDeflateInEnd = Stream.next_in + Stream.avail_in; + const unsigned char* pDeflateInStart = &pState->DeflateIn[0]; + const unsigned char* pDeflateInRealEnd = &pState->DeflateIn[MICROPROFILE_COMPRESS_CHUNK]; + pState->nSize += (uint32_t)nSize; + if((ptrdiff_t)nSize <= pDeflateInRealEnd - pDeflateInEnd) + { + memcpy((void*)pDeflateInEnd, pData, nSize); + Stream.avail_in += (uint32_t)nSize; + MP_ASSERT(Stream.next_in + Stream.avail_in <= pDeflateInRealEnd); + return; + } + int Flush = 0; + while(nSize) + { + pDeflateInEnd = Stream.next_in + Stream.avail_in; + if(Flush) + { + pState->nFlushes++; + MicroProfileCompressedSocketFlush(pState); + pDeflateInRealEnd = &pState->DeflateIn[MICROPROFILE_COMPRESS_CHUNK]; + if(pDeflateInEnd == pDeflateInRealEnd) + { + if(Stream.avail_in) + { + MP_ASSERT(pDeflateInStart != Stream.next_in); + memmove((void*)pDeflateInStart, Stream.next_in, Stream.avail_in); + pState->nMemmoveBytes += Stream.avail_in; + } + Stream.next_in = pDeflateInStart; + pDeflateInEnd = Stream.next_in + Stream.avail_in; + } + } + size_t nSpace = pDeflateInRealEnd - pDeflateInEnd; + size_t nBytes = MicroProfileMin(nSpace, nSize); + MP_ASSERT(nBytes + pDeflateInEnd <= pDeflateInRealEnd); + memcpy((void*)pDeflateInEnd, pData, nBytes); + Stream.avail_in += (uint32_t)nBytes; + nSize -= nBytes; + pData += nBytes; + int r = mz_deflate(&Stream, MZ_NO_FLUSH); + Flush = r == MZ_BUF_ERROR || nBytes == 0 || Stream.avail_out == 0 ? 1 : 0; + MP_ASSERT(r == MZ_BUF_ERROR || r == MZ_OK); + if(r == MZ_BUF_ERROR) + { + r = mz_deflate(&Stream, MZ_SYNC_FLUSH); + } + } +} +#endif + +#ifndef MicroProfileSetNonBlocking // fcntl doesnt work on a some unix like platforms.. +void MicroProfileSetNonBlocking(MpSocket Socket, int NonBlocking) +{ +#ifdef _WIN32 + u_long nonBlocking = NonBlocking ? 1 : 0; + ioctlsocket(Socket, FIONBIO, &nonBlocking); +#else + int Options = fcntl(Socket, F_GETFL); + if(NonBlocking) + { + fcntl(Socket, F_SETFL, Options | O_NONBLOCK); + } + else + { + fcntl(Socket, F_SETFL, Options & (~O_NONBLOCK)); + } +#endif +} +#endif + +void MicroProfileWebServerStart() +{ +#ifdef _WIN32 + WSADATA wsa; + if(WSAStartup(MAKEWORD(2, 2), &wsa)) + { + S.ListenerSocket = (MpSocket)-1; + return; + } +#endif + + S.ListenerSocket = socket(PF_INET, SOCK_STREAM, 6); + MP_ASSERT(!MP_INVALID_SOCKET(S.ListenerSocket)); + MicroProfileSetNonBlocking(S.ListenerSocket, 1); + + { + int r = 0; + int on = 1; +#if defined(_WIN32) + r = setsockopt(S.ListenerSocket, SOL_SOCKET, SO_REUSEADDR, (const char*)&on, sizeof(on)); +#else + r = setsockopt(S.ListenerSocket, SOL_SOCKET, SO_REUSEADDR, (void*)&on, sizeof(on)); +#endif + (void)r; + } + + int nStartPort = S.nWebServerPort; + struct sockaddr_in Addr; + Addr.sin_family = AF_INET; + Addr.sin_addr.s_addr = INADDR_ANY; + for(int i = 0; i < 20; ++i) + { + Addr.sin_port = htons(nStartPort + i); + if(0 == bind(S.ListenerSocket, (sockaddr*)&Addr, sizeof(Addr))) + { + S.nWebServerPort = (uint32_t)(nStartPort + i); + break; + } + } + listen(S.ListenerSocket, 8); +} + +void MicroProfileWebServerJoin() +{ + if(S.WebSocketThreadRunning) + { + MicroProfileThreadJoin(&S.WebSocketSendThread); + } + S.WebSocketThreadJoined = 1; +} + +void MicroProfileWebServerStop() +{ + MP_ASSERT(S.WebSocketThreadJoined); +#ifdef _WIN32 + closesocket(S.ListenerSocket); + WSACleanup(); +#else + close(S.ListenerSocket); +#endif +} +enum MicroProfileGetCommand +{ + EMICROPROFILE_GET_COMMAND_DUMP, + EMICROPROFILE_GET_COMMAND_DUMP_RANGE, + EMICROPROFILE_GET_COMMAND_LIVE, + EMICROPROFILE_GET_COMMAND_FAVICON, + EMICROPROFILE_GET_COMMAND_SERVICE_WORKER, + EMICROPROFILE_GET_COMMAND_UNKNOWN, +}; +struct MicroProfileParseGetResult +{ + uint64_t nFrames; + uint64_t nFrameStart; +}; +MicroProfileGetCommand MicroProfileParseGet(const char* pGet, MicroProfileParseGetResult* pResult) +{ + if(0 == strlen(pGet)) + { + return EMICROPROFILE_GET_COMMAND_LIVE; + } + if(0 == strcmp(pGet, "favicon.ico")) + { + return EMICROPROFILE_GET_COMMAND_FAVICON; + } + if(0 == strcmp(pGet, "favicon.png")) + { + return EMICROPROFILE_GET_COMMAND_FAVICON; + } + if(0 == strcmp(pGet, "service-worker.js")) + { + return EMICROPROFILE_GET_COMMAND_SERVICE_WORKER; + } + const char* pStart = pGet; + if(*pStart == 'b' || *pStart == 'p') + { + S.nWSWasConnected = 1; // do not load default when url has one specified. + return EMICROPROFILE_GET_COMMAND_LIVE; + } + if(*pStart == 'r') // range + { + // very very manual parsing + if('/' != *++pStart) + return EMICROPROFILE_GET_COMMAND_UNKNOWN; + ++pStart; + + char* pEnd = nullptr; + uint64_t nFrameStart = strtoll(pStart, &pEnd, 10); + if(pEnd == pStart || *pEnd != '/' || *pEnd == '\0') + { + return EMICROPROFILE_GET_COMMAND_UNKNOWN; + } + pStart = pEnd + 1; + + uint64_t nFrameEnd = strtoll(pStart, &pEnd, 10); + + if(pEnd == pStart || nFrameEnd <= nFrameStart) + { + return EMICROPROFILE_GET_COMMAND_UNKNOWN; + } + pResult->nFrames = nFrameEnd - nFrameStart; + pResult->nFrameStart = nFrameStart; + return EMICROPROFILE_GET_COMMAND_DUMP_RANGE; + } + while(*pGet != '\0') + { + if(*pGet < '0' || *pGet > '9') + return EMICROPROFILE_GET_COMMAND_UNKNOWN; + pGet++; + } + int nFrames = atoi(pStart); + pResult->nFrameStart = (uint64_t)-1; + if(nFrames) + { + pResult->nFrames = nFrames; + } + else + { + pResult->nFrames = MICROPROFILE_WEBSERVER_DEFAULT_FRAMES; + } + return EMICROPROFILE_GET_COMMAND_DUMP; +} + +void MicroProfileBase64Encode(char* pOut, const uint8_t* pIn, uint32_t nLen) +{ + static const char* CODES = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; + //..straight from wikipedia. + int b; + char* o = pOut; + for(uint32_t i = 0; i < nLen; i += 3) + { + b = (pIn[i] & 0xfc) >> 2; + *o++ = CODES[b]; + b = (pIn[i] & 0x3) << 4; + if(i + 1 < nLen) + { + b |= (pIn[i + 1] & 0xF0) >> 4; + *o++ = CODES[b]; + b = (pIn[i + 1] & 0x0F) << 2; + if(i + 2 < nLen) + { + b |= (pIn[i + 2] & 0xC0) >> 6; + *o++ = CODES[b]; + b = pIn[i + 2] & 0x3F; + *o++ = CODES[b]; + } + else + { + *o++ = CODES[b]; + *o++ = '='; + } + } + else + { + *o++ = CODES[b]; + *o++ = '='; + *o++ = '='; + } + } +} + +// begin: SHA-1 in C +// ftp://ftp.funet.fi/pub/crypt/hash/sha/sha1.c +// SHA-1 in C +// By Steve Reid +// 100% Public Domain + +typedef struct +{ + uint32_t state[5]; + uint32_t count[2]; + unsigned char buffer[64]; +} MicroProfile_SHA1_CTX; +#include +#ifndef _WIN32 +#include +#endif + +static void MicroProfile_SHA1_Transform(uint32_t[5], const unsigned char[64]); + +#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) + +#define blk0(i) (block->l[i] = htonl(block->l[i])) +#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1)) + +#define R0(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk0(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R1(v, w, x, y, z, i) \ + z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ + w = rol(w, 30); +#define R2(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ + w = rol(w, 30); +#define R3(v, w, x, y, z, i) \ + z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ + w = rol(w, 30); +#define R4(v, w, x, y, z, i) \ + z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ + w = rol(w, 30); + +// Hash a single 512-bit block. This is the core of the algorithm. + +static void MicroProfile_SHA1_Transform(uint32_t state[5], const unsigned char buffer[64]) +{ + uint32_t a, b, c, d, e; + typedef union + { + unsigned char c[64]; + uint32_t l[16]; + } CHAR64LONG16; + CHAR64LONG16* block; + + block = (CHAR64LONG16*)buffer; + // Copy context->state[] to working vars + a = state[0]; + b = state[1]; + c = state[2]; + d = state[3]; + e = state[4]; + // 4 rounds of 20 operations each. Loop unrolled. + R0(a, b, c, d, e, 0); + R0(e, a, b, c, d, 1); + R0(d, e, a, b, c, 2); + R0(c, d, e, a, b, 3); + R0(b, c, d, e, a, 4); + R0(a, b, c, d, e, 5); + R0(e, a, b, c, d, 6); + R0(d, e, a, b, c, 7); + R0(c, d, e, a, b, 8); + R0(b, c, d, e, a, 9); + R0(a, b, c, d, e, 10); + R0(e, a, b, c, d, 11); + R0(d, e, a, b, c, 12); + R0(c, d, e, a, b, 13); + R0(b, c, d, e, a, 14); + R0(a, b, c, d, e, 15); + R1(e, a, b, c, d, 16); + R1(d, e, a, b, c, 17); + R1(c, d, e, a, b, 18); + R1(b, c, d, e, a, 19); + R2(a, b, c, d, e, 20); + R2(e, a, b, c, d, 21); + R2(d, e, a, b, c, 22); + R2(c, d, e, a, b, 23); + R2(b, c, d, e, a, 24); + R2(a, b, c, d, e, 25); + R2(e, a, b, c, d, 26); + R2(d, e, a, b, c, 27); + R2(c, d, e, a, b, 28); + R2(b, c, d, e, a, 29); + R2(a, b, c, d, e, 30); + R2(e, a, b, c, d, 31); + R2(d, e, a, b, c, 32); + R2(c, d, e, a, b, 33); + R2(b, c, d, e, a, 34); + R2(a, b, c, d, e, 35); + R2(e, a, b, c, d, 36); + R2(d, e, a, b, c, 37); + R2(c, d, e, a, b, 38); + R2(b, c, d, e, a, 39); + R3(a, b, c, d, e, 40); + R3(e, a, b, c, d, 41); + R3(d, e, a, b, c, 42); + R3(c, d, e, a, b, 43); + R3(b, c, d, e, a, 44); + R3(a, b, c, d, e, 45); + R3(e, a, b, c, d, 46); + R3(d, e, a, b, c, 47); + R3(c, d, e, a, b, 48); + R3(b, c, d, e, a, 49); + R3(a, b, c, d, e, 50); + R3(e, a, b, c, d, 51); + R3(d, e, a, b, c, 52); + R3(c, d, e, a, b, 53); + R3(b, c, d, e, a, 54); + R3(a, b, c, d, e, 55); + R3(e, a, b, c, d, 56); + R3(d, e, a, b, c, 57); + R3(c, d, e, a, b, 58); + R3(b, c, d, e, a, 59); + R4(a, b, c, d, e, 60); + R4(e, a, b, c, d, 61); + R4(d, e, a, b, c, 62); + R4(c, d, e, a, b, 63); + R4(b, c, d, e, a, 64); + R4(a, b, c, d, e, 65); + R4(e, a, b, c, d, 66); + R4(d, e, a, b, c, 67); + R4(c, d, e, a, b, 68); + R4(b, c, d, e, a, 69); + R4(a, b, c, d, e, 70); + R4(e, a, b, c, d, 71); + R4(d, e, a, b, c, 72); + R4(c, d, e, a, b, 73); + R4(b, c, d, e, a, 74); + R4(a, b, c, d, e, 75); + R4(e, a, b, c, d, 76); + R4(d, e, a, b, c, 77); + R4(c, d, e, a, b, 78); + R4(b, c, d, e, a, 79); + // Add the working vars back into context.state[] + state[0] += a; + state[1] += b; + state[2] += c; + state[3] += d; + state[4] += e; + // Wipe variables + a = b = c = d = e = 0; +} + +void MicroProfile_SHA1_Init(MicroProfile_SHA1_CTX* context) +{ + // SHA1 initialization constants + context->state[0] = 0x67452301; + context->state[1] = 0xEFCDAB89; + context->state[2] = 0x98BADCFE; + context->state[3] = 0x10325476; + context->state[4] = 0xC3D2E1F0; + context->count[0] = context->count[1] = 0; +} + +// Run your data through this. + +void MicroProfile_SHA1_Update(MicroProfile_SHA1_CTX* context, const unsigned char* data, unsigned int len) +{ + unsigned int i, j; + + j = (context->count[0] >> 3) & 63; + if((context->count[0] += len << 3) < (len << 3)) + context->count[1]++; + context->count[1] += (len >> 29); + i = 64 - j; + while(len >= i) + { + memcpy(&context->buffer[j], data, i); + MicroProfile_SHA1_Transform(context->state, context->buffer); + data += i; + len -= i; + i = 64; + j = 0; + } + + memcpy(&context->buffer[j], data, len); +} + +// Add padding and return the message digest. + +void MicroProfile_SHA1_Final(unsigned char digest[20], MicroProfile_SHA1_CTX* context) +{ + uint32_t i, j; + unsigned char finalcount[8]; + + for(i = 0; i < 8; i++) + { + finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); // Endian independent + } + MicroProfile_SHA1_Update(context, (unsigned char*)"\200", 1); + while((context->count[0] & 504) != 448) + { + MicroProfile_SHA1_Update(context, (unsigned char*)"\0", 1); + } + MicroProfile_SHA1_Update(context, finalcount, 8); // Should cause a SHA1Transform() + for(i = 0; i < 20; i++) + { + digest[i] = (unsigned char)((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); + } + // Wipe variables + i = j = 0; + memset(context->buffer, 0, 64); + memset(context->state, 0, 20); + memset(context->count, 0, 8); + memset(&finalcount, 0, 8); +} + +#undef rol +#undef blk0 +#undef blk +#undef R0 +#undef R1 +#undef R2 +#undef R3 +#undef R4 + +// end: SHA-1 in C + +void MicroProfileWebSocketSendState(MpSocket C); +void MicroProfileWebSocketSendEnabled(MpSocket C); +void MicroProfileWSPrintStart(MpSocket C); +void MicroProfileWSPrintf(const char* pFmt, ...); +void MicroProfileWSPrintEnd(); +void MicroProfileWSFlush(); +bool MicroProfileWebSocketReceive(MpSocket C); + +enum +{ + TYPE_NONE = 0, + TYPE_TIMER = 1, + TYPE_GROUP = 2, + TYPE_CATEGORY = 3, + TYPE_SETTING = 4, + TYPE_COUNTER = 5, +}; + +enum +{ + SETTING_FORCE_ENABLE = 0, + SETTING_CONTEXT_SWITCH_TRACE = 1, + SETTING_PLATFORM_MARKERS = 2, +}; + +enum +{ + MSG_TIMER_TREE = 1, + MSG_ENABLED = 2, + MSG_FRAME = 3, + MSG_LOADSETTINGS = 4, + MSG_PRESETS = 5, + MSG_CURRENTSETTINGS = 6, + MSG_COUNTERS = 7, + MSG_FUNCTION_RESULTS = 8, + MSG_INACTIVE_FRAME = 9, + MSG_FUNCTION_NAMES = 10, + MSG_INSTRUMENT_ERROR = 11, + MSG_QUERY_INDEX = 12, + // MSG_MODULE_NAME = 12, +}; + +enum +{ + VIEW_GRAPH_SPLIT = 0, + VIEW_GRAPH_PERCENTILE = 1, + VIEW_GRAPH_THREAD_GROUP = 2, + VIEW_BAR = 3, + VIEW_BAR_ALL = 4, + VIEW_BAR_SINGLE = 5, + VIEW_COUNTERS = 6, + VIEW_SIZE = 7, +}; + +void MicroProfileSocketDumpState() +{ + fd_set Read, Write, Error; + FD_ZERO(&Read); + FD_ZERO(&Write); + FD_ZERO(&Error); + MpSocket LastSocket = 1; + for(uint32_t i = 0; i < S.nNumWebSockets; ++i) + { + LastSocket = MicroProfileMax(LastSocket, S.WebSockets[i] + 1); + FD_SET(S.WebSockets[i], &Read); + FD_SET(S.WebSockets[i], &Write); + FD_SET(S.WebSockets[i], &Error); + } + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + if(-1 == select(LastSocket, &Read, &Write, &Error, &tv)) + { + MP_ASSERT(0); + } + for(uint32_t i = 0; i < S.nNumWebSockets; i++) + { + MpSocket s = S.WebSockets[i]; + uprintf("%" PRId64 " ", (uint64_t)s); + + if(FD_ISSET(s, &Error)) + { + uprintf("e"); + } + else + { + uprintf("_"); + } + if(FD_ISSET(s, &Read)) + { + uprintf("r"); + } + else + { + uprintf(" "); + } + if(FD_ISSET(s, &Write)) + { + uprintf("w"); + } + else + { + uprintf(" "); + } + } + uprintf("\n"); + for(uint32_t i = 1; i < S.nNumWebSockets; i++) + { + MpSocket s = S.WebSockets[i]; + int error_code; + socklen_t error_code_size = sizeof(error_code); + int r = getsockopt(s, SOL_SOCKET, SO_ERROR, (char*)&error_code, &error_code_size); + MP_ASSERT(r >= 0); + if(error_code != 0) + { +#ifdef _WIN32 + char buffer[1024]; + strerror_s(buffer, sizeof(buffer) - 1, error_code); + fprintf(stderr, "socket error: %d %s\n", (int)s, buffer); +#else + fprintf(stderr, "socket error: %d %s\n", (int)s, strerror(error_code)); +#endif + MP_ASSERT(0); + } + } +} + +bool MicroProfileSocketSend2(MpSocket Connection, const void* pMessage, int nLen); +void* MicroProfileSocketSenderThread(void*) +{ + MicroProfileOnThreadCreate("MicroProfileSocketSenderThread"); + while(!S.nMicroProfileShutdown) + { + if(S.nSocketFail) + { + MicroProfileSleep(100); + continue; + } + + uint32_t nEnd = MICROPROFILE_WEBSOCKET_BUFFER_SIZE; + uint32_t nGet = S.WSBuf.nSendGet.load(); + uint32_t nPut = S.WSBuf.nSendPut.load(); + uint32_t nSendStart = 0; + uint32_t nSendAmount = 0; + if(nGet > nPut) + { + nSendStart = nGet; + nSendAmount = nEnd - nGet; + } + else if(nGet < nPut) + { + nSendStart = nGet; + nSendAmount = nPut - nGet; + } + + if(nSendAmount) + { + MICROPROFILE_SCOPE(g_MicroProfileSendLoop); + MICROPROFILE_COUNTER_LOCAL_ADD_ATOMIC(g_MicroProfileBytesPerFlip, nSendAmount); + if(!MicroProfileSocketSend2(S.WebSockets[0], &S.WSBuf.SendBuffer[nSendStart], nSendAmount)) + { + S.nSocketFail = 1; + } + else + { + S.WSBuf.nSendGet.store((nGet + nSendAmount) % MICROPROFILE_WEBSOCKET_BUFFER_SIZE); + } + } + else + { + MicroProfileSleep(20); + } + } + MicroProfileOnThreadExit(); + return 0; +} + +void MicroProfileSocketSend(MpSocket Connection, const void* pMessage, int nLen) +{ + if(S.nSocketFail || nLen <= 0) + { + return; + } + MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileSocketSend", MP_GREEN4); + while(nLen != 0) + { + MP_ASSERT(nLen > 0); + uint32_t nEnd = MICROPROFILE_WEBSOCKET_BUFFER_SIZE; + uint32_t nGet = S.WSBuf.nSendGet.load(); + uint32_t nPut = S.WSBuf.nSendPut.load(); + uint32_t nAmount = 0; + if(nPut < nGet) + { + nAmount = nGet - nPut - 1; + } + else + { + if(nGet == 0) + { + nAmount = nEnd - nPut - 1; + } + else + { + nAmount = nEnd - nPut; + } + } + MP_ASSERT((int)nAmount >= 0); + nAmount = MicroProfileMin(nLen, (int)nAmount); + if(nAmount) + { + memcpy(&S.WSBuf.SendBuffer[nPut], pMessage, nAmount); + pMessage = (void*)((char*)pMessage + nAmount); + nLen -= nAmount; + S.WSBuf.nSendPut.store((nPut + nAmount) % MICROPROFILE_WEBSOCKET_BUFFER_SIZE); + } + else + { + if(S.nSocketFail) + { + return; + } + MicroProfileSleep(20); + } + } +} + +bool MicroProfileSocketSend2(MpSocket Connection, const void* pMessage, int nLen) +{ + if(S.nSocketFail || nLen <= 0) + { + return false; + } + // MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileSocketSend2", 0); +#ifndef _WIN32 + int error_code; + socklen_t error_code_size = sizeof(error_code); + getsockopt(Connection, SOL_SOCKET, SO_ERROR, &error_code, &error_code_size); + if(error_code != 0) + { + return false; + } +#endif + + int s = 0; + while(nLen) + { + s = send(Connection, (const char*)pMessage, nLen, 0); + if(s < 0) + { + const int error = errno; + if(error == EAGAIN || error == EWOULDBLOCK) + { + MicroProfileSleep(20); + continue; + } + break; + } + + nLen -= s; + pMessage = (const char*)pMessage + s; + } +#ifdef _WIN32 + if(s == SOCKET_ERROR) + { + return false; + } +#endif + if(s < 0) + { + return false; + } + return true; +} + +uint32_t MicroProfileWebSocketIdPack(uint32_t type, uint32_t element) +{ + MP_ASSERT(type < 255); + MP_ASSERT(element < 0xffffff); + return type << 24 | element; +} +void MicroProfileWebSocketIdUnpack(uint32_t nPacked, uint32_t& type, uint32_t& element) +{ + type = (nPacked >> 24) & 0xff; + element = nPacked & 0xffffff; +} + +struct MicroProfileWebSocketHeader0 +{ + union + { + struct + { + uint8_t opcode : 4; + uint8_t RSV3 : 1; + uint8_t RSV2 : 1; + uint8_t RSV1 : 1; + uint8_t FIN : 1; + }; + uint8_t v; + }; +}; + +struct MicroProfileWebSocketHeader1 +{ + union + { + struct + { + uint8_t payload : 7; + uint8_t MASK : 1; + }; + uint8_t v; + }; +}; + +bool MicroProfileWebSocketSend(MpSocket Connection, const char* pMessage, uint64_t nLen) +{ + MicroProfileWebSocketHeader0 h0; + MicroProfileWebSocketHeader1 h1; + h0.v = 0; + h1.v = 0; + h0.opcode = 1; + h0.FIN = 1; + uint32_t nExtraSizeBytes = 0; + uint8_t nExtraSize[8]; + if(nLen > 125) + { + if(nLen > 0xffff) + { + nExtraSizeBytes = 8; + h1.payload = 127; + } + else + { + h1.payload = 126; + nExtraSizeBytes = 2; + } + uint64_t nCount = nLen; + for(uint32_t i = 0; i < nExtraSizeBytes; ++i) + { + nExtraSize[nExtraSizeBytes - i - 1] = nCount & 0xff; + nCount >>= 8; + } + + uint32_t nSize = 0; + for(uint32_t i = 0; i < nExtraSizeBytes; i++) + { + nSize <<= 8; + nSize += nExtraSize[i]; + } + MP_ASSERT(nSize == nLen); // verify + } + else + { + h1.payload = nLen; + } + MP_ASSERT(pMessage == S.WSBuf.pBuffer); // space for header is preallocated here + MP_ASSERT(pMessage == S.WSBuf.pBufferAllocation + 20); // space for header is preallocated here + MP_ASSERT(nExtraSizeBytes < 18); + char* pTmp = (char*)(pMessage - nExtraSizeBytes - 2); + memcpy(pTmp + 2, &nExtraSize[0], nExtraSizeBytes); + pTmp[1] = *(char*)&h1; + pTmp[0] = *(char*)&h0; +// MicroProfileSocketSend(Connection, pTmp, nExtraSizeBytes + 2 + nLen); +#if 1 + MicroProfileSocketSend(Connection, &h0, 1); + MicroProfileSocketSend(Connection, &h1, 1); + if(nExtraSizeBytes) + { + MicroProfileSocketSend(Connection, &nExtraSize[0], nExtraSizeBytes); + } + MicroProfileSocketSend(Connection, pMessage, nLen); +#endif + return true; +} + +void MicroProfileWebSocketClearTimers() +{ + while(S.WebSocketTimers > -1) + { + int nNext = S.TimerInfo[S.WebSocketTimers].nWSNext; + S.TimerInfo[S.WebSocketTimers].nWSNext = -2; + S.WebSocketTimers = nNext; + } + MP_ASSERT(S.WebSocketTimers == -1); + while(S.WebSocketCounters > -1) + { + int nNext = S.CounterInfo[S.WebSocketCounters].nWSNext; + S.CounterInfo[S.WebSocketCounters].nWSNext = -2; + S.WebSocketCounters = nNext; + } + MP_ASSERT(S.WebSocketCounters == -1); + + while(S.WebSocketGroups > -1) + { + int nNext = S.GroupInfo[S.WebSocketGroups].nWSNext; + S.GroupInfo[S.WebSocketGroups].nWSNext = -2; + S.WebSocketGroups = nNext; + } + MP_ASSERT(S.WebSocketGroups == -1); + S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED; +} +void MicroProfileWebSocketToggleTimer(uint32_t nTimer) +{ + if(nTimer < S.nTotalTimers) + { + auto& TI = S.TimerInfo[nTimer]; + int* pPrev = &S.WebSocketTimers; + while(*pPrev > -1 && *pPrev != (int)nTimer) + { + MP_ASSERT(*pPrev < (int)S.nTotalTimers && *pPrev >= 0); + pPrev = &S.TimerInfo[*pPrev].nWSNext; + } + if(TI.nWSNext >= -1) + { + MP_ASSERT(*pPrev == (int)nTimer); + *pPrev = TI.nWSNext; + TI.nWSNext = -2; + } + else + { + MP_ASSERT(*pPrev == -1); + TI.nWSNext = -1; + *pPrev = (int)nTimer; + } + S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED; + } +} + +void MicroProfileWebSocketToggleCounter(uint32_t nCounter) +{ + if(nCounter < S.nNumCounters) + { + auto& TI = S.CounterInfo[nCounter]; + int* pPrev = &S.WebSocketCounters; + while(*pPrev > -1 && *pPrev != (int)nCounter) + { + MP_ASSERT(*pPrev < (int)S.nNumCounters && *pPrev >= 0); + pPrev = &S.CounterInfo[*pPrev].nWSNext; + } + if(TI.nWSNext >= -1) + { + MP_ASSERT(*pPrev == (int)nCounter); + *pPrev = TI.nWSNext; + TI.nWSNext = -2; + } + else + { + MP_ASSERT(*pPrev == -1); + TI.nWSNext = -1; + *pPrev = (int)nCounter; + } + S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED; + } +} + +void MicroProfileWebSocketToggleGroup(uint32_t nGroup) +{ + if(nGroup < S.nGroupCount) + { + auto& TI = S.GroupInfo[nGroup]; + int* pPrev = &S.WebSocketGroups; + while(*pPrev > -1 && *pPrev != (int)nGroup) + { + MP_ASSERT(*pPrev < (int)S.nGroupCount && *pPrev >= 0); + pPrev = &S.GroupInfo[*pPrev].nWSNext; + } + if(TI.nWSNext >= -1) + { + MP_ASSERT(*pPrev == (int)nGroup); + *pPrev = TI.nWSNext; + TI.nWSNext = -2; + } + else + { + MP_ASSERT(*pPrev == -1); + TI.nWSNext = -1; + *pPrev = (int)nGroup; + } + S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED; + } +} + +bool MicroProfileWebSocketTimerEnabled(uint32_t nTimer) +{ + if(nTimer < S.nTotalTimers) + { + return S.TimerInfo[nTimer].nWSNext > -2; + } + return false; +} + +bool MicroProfileWebSocketCounterEnabled(uint32_t nCounter) +{ + if(nCounter < S.nNumCounters) + { + return S.CounterInfo[nCounter].nWSNext > -2; + } + return false; +} +void MicroProfileWebSocketCommand(uint32_t nCommand) +{ + uint32_t nType, nElement; + MicroProfileWebSocketIdUnpack(nCommand, nType, nElement); + switch(nType) + { + case TYPE_NONE: + break; + case TYPE_SETTING: + switch(nElement) + { + case SETTING_FORCE_ENABLE: + MicroProfileSetEnableAllGroups(!MicroProfileGetEnableAllGroups()); + break; + case SETTING_CONTEXT_SWITCH_TRACE: + if(!S.bContextSwitchRunning) + { + MicroProfileStartContextSwitchTrace(); + } + else + { + MicroProfileStopContextSwitchTrace(); + } + break; + case SETTING_PLATFORM_MARKERS: + MicroProfilePlatformMarkersSetEnabled(!MicroProfilePlatformMarkersGetEnabled()); + break; + } + S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED; + break; + case TYPE_TIMER: + MicroProfileWebSocketToggleTimer(nElement); + break; + case TYPE_GROUP: + MicroProfileToggleGroup(nElement); + break; + case TYPE_CATEGORY: + MicroProfileToggleCategory(nElement); + break; + case TYPE_COUNTER: + MicroProfileWebSocketToggleCounter(nElement); + break; + default: + uprintf("unknown type %d\n", nType); + } +} +#define MICROPROFILE_PRESET_HEADER_MAGIC2 0x28586813 +#define MICROPROFILE_PRESET_HEADER_VERSION2 0x00000200 + +struct MicroProfileSettingsFileHeader +{ + uint32_t nMagic; + uint32_t nVersion; + uint32_t nNumHeaders; + uint32_t nHeadersOffset; + uint32_t nMaxJsonSize; + uint32_t nMaxNameSize; +}; +struct MicroProfileSettingsHeader +{ + uint32_t nJsonOffset; + uint32_t nJsonSize; + uint32_t nNameOffset; + uint32_t nNameSize; +}; + +template +void MicroProfileParseSettings(const char* pFileName, T CB) +{ + std::lock_guard Lock(MicroProfileGetMutex()); + + FILE* F = fopen(pFileName, "rb"); + if(!F) + { + return; + } + long nFileSize = 0; + fseek(F, 0, SEEK_END); + nFileSize = ftell(F); + char* pFile = 0; + char* pAlloc = 0; + if(nFileSize > (32 << 10)) + { + pFile = pAlloc = (char*)MP_ALLOC(nFileSize + 1, 1); + } + else + { + pFile = (char*)alloca(nFileSize + 1); + } + fseek(F, 0, SEEK_SET); + if(1 != fread(pFile, nFileSize, 1, F)) + { + uprintf("failed to read settings file\n"); + fclose(F); + return; + } + fclose(F); + pFile[nFileSize] = '\0'; + + char* pPos = pFile; + char* pEnd = pFile + nFileSize; + + while(pPos != pEnd) + { + const char* pName = 0; + int nNameLen = 0; + const char* pJson = 0; + int nJsonLen = 0; + int Failed = 0; + + auto SkipWhite = [&](char* pPos, const char* pEnd) + { + while(pPos != pEnd) + { + if(isspace(*pPos)) + { + pPos++; + } + else if('#' == *pPos) + { + while(pPos != pEnd && *pPos != '\n') + { + ++pPos; + } + } + else + { + break; + } + } + return pPos; + }; + + auto ParseName = [&](char* pPos, char* pEnd, const char** ppName, int* pLen) + { + pPos = SkipWhite(pPos, pEnd); + int nLen = 0; + *ppName = pPos; + + while(pPos != pEnd && (isalpha(*pPos) || isdigit(*pPos) || *pPos == '_')) + { + nLen++; + pPos++; + } + *pLen = nLen; + if(pPos == pEnd || !isspace(*pPos)) + { + Failed = 1; + return pEnd; + } + *pPos++ = '\0'; + return pPos; + }; + + auto ParseJson = [&](char* pPos, char* pEnd, const char** pJson, int* pLen) -> char* + { + pPos = SkipWhite(pPos, pEnd); + if(*pPos != '{' || pPos == pEnd) + { + Failed = 1; + return pPos; + } + *pJson = pPos++; + int nLen = 1; + int nDepth = 1; + while(pPos != pEnd && nDepth != 0) + { + nLen++; + char nChar = *pPos++; + if(nChar == '{') + { + nDepth++; + } + else if(nChar == '}') + { + nDepth--; + } + } + if(pPos == pEnd || !isspace(*pPos)) + { + Failed = 1; + return pEnd; + } + *pLen = nLen; + *pPos++ = '\0'; + return pPos; + }; + + pPos = ParseName(pPos, pEnd, &pName, &nNameLen); + pPos = ParseJson(pPos, pEnd, &pJson, &nJsonLen); + if(Failed) + { + break; + } + if(!CB(pName, nNameLen, pJson, nJsonLen)) + { + break; + } + } + if(pAlloc) + MP_FREE(pAlloc); +} + +bool MicroProfileSavePresets(const char* pSettingsName, const char* pJsonSettings) +{ + std::lock_guard Lock(MicroProfileGetMutex()); + + FILE* F = fopen(S.pSettingsTemp, "w"); + if(!F) + { + return false; + } + + bool bWritten = false; + + MicroProfileParseSettings(S.pSettings, + [&](const char* pName, uint32_t nNameSize, const char* pJson, uint32_t nJsonSize) -> bool + { + fwrite(pName, nNameSize, 1, F); + fputc(' ', F); + if(0 != MP_STRCASECMP(pSettingsName, pName)) + { + fwrite(pJson, nJsonSize, 1, F); + } + else + { + bWritten = true; + fwrite(pJsonSettings, strlen(pJsonSettings), 1, F); + } + fputc('\n', F); + return true; + }); + if(!bWritten) + { + fwrite(pSettingsName, strlen(pSettingsName), 1, F); + fputc(' ', F); + fwrite(pJsonSettings, strlen(pJsonSettings), 1, F); + fputc('\n', F); + } + fflush(F); + fclose(F); +#ifdef MICROPROFILE_MOVE_FILE + MICROPROFILE_MOVE_FILE(S.pSettingsTemp, S.pSettings); +#elif defined(_WIN32) + MoveFileExA(S.pSettingsTemp, S.pSettings, MOVEFILE_REPLACE_EXISTING); +#else + rename(S.pSettingsTemp, S.pSettings); +#endif + return false; +} + +void MicroProfileWriteJsonString(const char* pJson, uint32_t nJsonLen) +{ + char* pCur = (char*)pJson; + char* pEnd = pCur + nJsonLen; + MicroProfileWSPrintf("\"", pCur); + while(pCur != pEnd) + { + char* pTag = strchr(pCur, '\"'); + if(pTag) + { + *pTag = '\0'; + MicroProfileWSPrintf("%s\\\"", pCur); + *pTag = '\"'; + pCur = pTag + 1; + } + else + { + MicroProfileWSPrintf("%s\"", pCur); + pCur = pEnd; + } + } +}; + +void MicroProfileWebSocketSendPresets(MpSocket Connection) +{ + std::lock_guard Lock(MicroProfileGetMutex()); + uprintf("sending presets ... \n"); + MicroProfileWSPrintStart(Connection); + MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{", MSG_PRESETS); + MicroProfileWSPrintf("\"p\":{\"Default\":\"{}\""); + + MicroProfileParseSettings(S.pSettings, + [](const char* pName, uint32_t nNameLen, const char* pJson, uint32_t nJsonLen) + { + MicroProfileWSPrintf(",\"%s\":", pName); + MicroProfileWriteJsonString(pJson, nJsonLen); + + return true; + }); + MicroProfileWSPrintf("},\"r\":{"); + bool bFirst = true; + MicroProfileParseSettings(S.pSettingsReadOnly, + [&bFirst](const char* pName, uint32_t nNameLen, const char* pJson, uint32_t nJsonLen) + { + MicroProfileWSPrintf("%c\"%s\":", bFirst ? ' ' : ',', pName); + MicroProfileWriteJsonString(pJson, nJsonLen); + + bFirst = false; + return true; + }); + MicroProfileWSPrintf("}}}"); + MicroProfileWSFlush(); + MicroProfileWSPrintEnd(); +} + +#define LOAD_PRESET_DEFAULT 0x1 +#define LOAD_PRESET_READONLY 0x2 + +void MicroProfileLoadPresets(const char* pSettingsName, uint32_t nLoadPresetType) +{ + std::lock_guard Lock(MicroProfileGetMutex()); + const char* pPresetFiles[] = { S.pSettings, S.pSettingsReadOnly }; + for(uint32_t i = 0; i < 2; ++i) + { + if(nLoadPresetType & (1u << i)) + { + const char* pPresetFile = pPresetFiles[i]; + bool bReadOnly = (1u << i) == LOAD_PRESET_READONLY; + bool bSuccess = false; + MicroProfileParseSettings(pPresetFile, + [&bSuccess, bReadOnly, pSettingsName](const char* pName, uint32_t l0, const char* pJson, uint32_t l1) + { + if(0 == MP_STRCASECMP(pName, pSettingsName)) + { + uint32_t nLen = (uint32_t)strlen(pJson) + 1; + if(nLen > S.nJsonSettingsBufferSize) + { + if(S.pJsonSettings) + S.pJsonSettings = nullptr; + S.pJsonSettings = (char*)MP_ALLOC(nLen, 1); + S.nJsonSettingsBufferSize = nLen; + } + S.pJsonSettingsName = pSettingsName; + memcpy(S.pJsonSettings, pJson, nLen); + S.nJsonSettingsPending = 1; + S.bJsonSettingsReadOnly = bReadOnly ? 1 : 0; + bSuccess = true; + return false; + } + return true; + }); + if(bSuccess) + return; + } + } +} + +bool MicroProfileWebSocketReceive(MpSocket Connection) +{ + + // 0 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-------+-+-------------+-------------------------------+ + // |F|R|R|R| opcode|M| Payload len | Extended payload length | + // |I|S|S|S| (4) |A| (7) | (16/64) | + // |N|V|V|V| |S| | (if payload len==126/127) | + // | |1|2|3| |K| | | + // +-+-+-+-+-------+-+-------------+ - - - - - - - - - - - - - - - + + int r; + uint64_t nSize; + uint64_t nSizeBytes = 0; + uint8_t Mask[4]; + static unsigned char* Bytes = 0; + static uint64_t BytesAllocated = 0; + MicroProfileWebSocketHeader0 h0; + MicroProfileWebSocketHeader1 h1; + static_assert(sizeof(h0) == 1, ""); + static_assert(sizeof(h1) == 1, ""); + r = recv(Connection, (char*)&h0, 1, 0); + if(1 != r) + goto fail; + r = recv(Connection, (char*)&h1, 1, 0); + if(1 != r) + goto fail; + + if(h0.v == 0x88) + { + goto fail; + } + + if(h0.RSV1 != 0 || h0.RSV2 != 0 || h0.RSV3 != 0) + goto fail; + + nSize = h1.payload; + nSizeBytes = 0; + switch(nSize) + { + case 126: + nSizeBytes = 2; + break; + case 127: + nSizeBytes = 8; + break; + default: + break; + } + if(nSizeBytes) + { + nSize = 0; + uint64_t MessageLength = 0; + + uint8_t BytesMessage[8]; + r = recv(Connection, (char*)&BytesMessage[0], nSizeBytes, 0); + if((int)nSizeBytes != r) + goto fail; + for(uint32_t i = 0; i < nSizeBytes; i++) + { + nSize <<= 8; + nSize += BytesMessage[i]; + } + + for(uint32_t i = 0; i < nSizeBytes; i++) + MessageLength |= BytesMessage[i] << ((nSizeBytes - 1 - i) * 8); + MP_ASSERT(MessageLength == nSize); + } + + if(h1.MASK) + { + recv(Connection, (char*)&Mask[0], 4, 0); + } + + MICROPROFILE_COUNTER_LOCAL_ADD_ATOMIC(g_MicroProfileBytesPerFlip, nSize); + if(nSize + 1 > BytesAllocated) + { + Bytes = (unsigned char*)MP_REALLOC(Bytes, nSize + 1); + BytesAllocated = nSize + 1; + } + recv(Connection, (char*)Bytes, nSize, 0); + for(uint32_t i = 0; i < nSize; ++i) + Bytes[i] ^= Mask[i & 3]; + + Bytes[nSize] = '\0'; + switch(Bytes[0]) + { + case 'a': + { + S.nAggregateFlip = strtoll((const char*)&Bytes[1], nullptr, 10); + } + break; + case 's': + { + char* pJson = strchr((char*)Bytes, ','); + if(pJson && *pJson != '\0') + { + *pJson = '\0'; + MicroProfileSavePresets((const char*)Bytes + 1, (const char*)pJson + 1); + } + break; + } + + case 'l': + { + MicroProfileLoadPresets((const char*)Bytes + 1, LOAD_PRESET_DEFAULT); + break; + } + case 'm': + { + MicroProfileLoadPresets((const char*)Bytes + 1, LOAD_PRESET_READONLY); + break; + } + case 'd': + { + MicroProfileWebSocketClearTimers(); + memset(&S.nActiveGroupsWanted, 0, sizeof(S.nActiveGroupsWanted)); + S.nWebSocketDirty |= MICROPROFILE_WEBSOCKET_DIRTY_ENABLED; + break; + } + case 'c': + { + char* pStr = (char*)Bytes + 1; + char* pEnd = pStr + nSize - 1; + uint32_t Message = strtol(pStr, &pEnd, 10); + MicroProfileWebSocketCommand(Message); + } + break; + case 'f': + MicroProfileToggleFrozen(); + break; + case 'v': + S.nWSViewMode = (int)Bytes[1] - '0'; + break; + case 'r': + uprintf("got clear message\n"); + S.nAggregateClear = 1; + break; + case 'x': + MicroProfileWebSocketClearTimers(); + break; +#if MICROPROFILE_DYNAMIC_INSTRUMENT + case 'D': // instrumentation without loading queryable symbols. + { + uprintf("got INSTRUMENT Message: %s\n", (const char*)&Bytes[0]); + char* pGet = (char*)&Bytes[1]; + uint32_t nNumArguments = 0; +#ifdef _WIN32 + r = sscanf_s(pGet, "%d", &nNumArguments); +#else + r = sscanf(pGet, "%d", &nNumArguments); +#endif + if(r != 1) + { + uprintf("failed to parse..\n"); + break; + } + while(' ' == *pGet || (*pGet >= '0' && *pGet <= '9')) + { + pGet++; + } + if(nNumArguments > 200) + nNumArguments = 200; + uint32_t nParsedArguments = 0; + const char* pModule = 0; + const char* pSymbol = 0; + const char** pModules = (const char**)(alloca(sizeof(const char*) * nNumArguments)); + const char** pSymbols = (const char**)(alloca(sizeof(const char*) * nNumArguments)); + auto Next = [&pGet]() -> const char* + { + if(!pGet) + return 0; + const char* pRet = pGet; + pGet = (char*)strchr(pRet, '!'); + if(!pGet) + { + return 0; + } + *pGet++ = '\0'; + return (const char*)pRet; + }; + do + { + pModule = Next(); + pSymbol = Next(); + if(pModule && pSymbol) + { + pModules[nParsedArguments] = pModule; + pSymbols[nParsedArguments] = pSymbol; + uprintf("found symbol %s ::: %s \n", pModule, pSymbol); + nParsedArguments++; + if(nParsedArguments == nNumArguments) + { + break; + } + } + } while(pGet); + + MicroProfileInstrumentWithoutSymbols(pModules, pSymbols, nParsedArguments); + + break; + } + case 'I': + case 'i': + { + uprintf("got Message: %s\n", (const char*)&Bytes[0]); + void* p = 0; + uint32_t nColor = 0x0; + int nMinBytes = 0; + int nMaxCalls = 0; + int nCharsRead = 0; +#ifdef _WIN32 + r = sscanf_s((const char*)&Bytes[1], "%p %x %d %d%n", &p, &nColor, &nMinBytes, &nMaxCalls, &nCharsRead); +#else + r = sscanf((const char*)&Bytes[1], "%p %x %d %d%n", &p, &nColor, &nMinBytes, &nMaxCalls, &nCharsRead); +#endif + if(r == 4) + { + const char* pModule = (const char*)&Bytes[1]; + // int nNumChars = stbsp_snprintf(0, 0, "%p %x", p, nColor); + pModule += nCharsRead; + while(*pModule != ' ' && *pModule != '\0') + ++pModule; + + if(*pModule == '\0') + break; + + pModule++; + const char* pName = pModule; + while(*pName != '!' && *pName != '\0') + { + pName++; + } + if(*pName == '!') + { + // name and module seperately + *(char*)pName = '\0'; + pName++; + } + else + { + // name only + pName = pModule; + pModule = ""; + } + + uprintf("scanning for ptr %p %x mod:'%s' name'%s'\n", p, nColor, pModule, pName); + if(Bytes[0] == 'I') + { + MicroProfileInstrumentFunctionsCalled(p, pModule, pName, nMinBytes, nMaxCalls); + } + else + { + MicroProfileInstrumentFunction(p, pModule, pName, nColor); + } + } + } + break; + case 'S': + uprintf("loading symbols...\n"); + MicroProfileSymbolInitialize(true); + break; + case 'q': + MicroProfileSymbolQueryFunctions(Connection, 1 + (const char*)Bytes); + break; + case 'L': + uprintf("LOAD MODULE: '%s'\n", 1 + (const char*)Bytes); + MicroProfileSymbolInitialize(true, 1 + (const char*)Bytes); + break; +#else + case 'D': + case 'I': + case 'i': + case 'S': + case 'q': + case 'L': + break; +#endif + default: + uprintf("got unknown message size %lld: '%s'\n", (long long)nSize, Bytes); + } + return true; + +fail: + return false; +} +void MicroProfileWebSocketSendPresets(MpSocket Connection); + +void MicroProfileWebSocketHandshake(MpSocket Connection, char* pWebSocketKey) +{ + // reset web socket buffer + S.WSBuf.nSendPut.store(0); + S.WSBuf.nSendGet.store(0); + S.nSocketFail = 0; + + const char* pGUID = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; + const char* pHandShake = "HTTP/1.1 101 Switching Protocols\r\n" + "Upgrade: websocket\r\n" + "Connection: Upgrade\r\n" + "Sec-WebSocket-Accept: "; + + char EncodeBuffer[512]; + int nLen = stbsp_snprintf(EncodeBuffer, sizeof(EncodeBuffer) - 1, "%s%s", pWebSocketKey, pGUID); + // uprintf("encode buffer is '%s' %d, %d\n", EncodeBuffer, nLen, (int)strlen(EncodeBuffer)); + + uint8_t sha[20]; + MicroProfile_SHA1_CTX ctx; + MicroProfile_SHA1_Init(&ctx); + MicroProfile_SHA1_Update(&ctx, (unsigned char*)EncodeBuffer, nLen); + MicroProfile_SHA1_Final((unsigned char*)&sha[0], &ctx); + char HashOut[(2 + sizeof(sha) / 3) * 4]; + memset(&HashOut[0], 0, sizeof(HashOut)); + MicroProfileBase64Encode(&HashOut[0], &sha[0], sizeof(sha)); + + char Reply[11024]; + nLen = stbsp_snprintf(Reply, sizeof(Reply) - 1, "%s%s\r\n\r\n", pHandShake, HashOut); + ; + MP_ASSERT(nLen >= 0); + MicroProfileSocketSend(Connection, Reply, nLen); + S.WebSockets[S.nNumWebSockets++] = Connection; + + S.WSCategoriesSent = 0; + S.WSGroupsSent = 0; + S.WSTimersSent = 0; + S.WSCountersSent = 0; + S.nJsonSettingsPending = 0; +#if MICROPROFILE_DYNAMIC_INSTRUMENT + S.WSFunctionsInstrumentedSent = 0; + S.WSSymbolModulesSent = 0; + { + uint64_t t0 = MP_TICK(); + MicroProfileSymbolUpdateModuleList(); + uint64_t t1 = MP_TICK(); + float fTime = float(MicroProfileTickToMsMultiplierCpu()) * (t1 - t0); + (void)fTime; + uprintf("update module list time %6.2fms\n", fTime); + } +#endif + + MicroProfileWebSocketSendState(Connection); + MicroProfileWebSocketSendPresets(Connection); + if(!S.nWSWasConnected) + { + S.nWSWasConnected = 1; + MicroProfileLoadPresets("Default", LOAD_PRESET_DEFAULT | LOAD_PRESET_READONLY); + } + else + { +#if MICROPROFILE_DYNAMIC_INSTRUMENT + MicroProfileWSPrintStart(Connection); + MicroProfileWSPrintf("{\"k\":\"%d\",\"qp\":%d}", MSG_QUERY_INDEX, S.nQueryProcessed); + MicroProfileWSFlush(); + MicroProfileWSPrintEnd(); +#endif + if(S.pJsonSettings) + { + MicroProfileWSPrintStart(Connection); + MicroProfileWSPrintf( + "{\"k\":\"%d\",\"ro\":%d,\"name\":\"%s\",\"v\":%s}", MSG_CURRENTSETTINGS, S.bJsonSettingsReadOnly ? 1 : 0, S.pJsonSettingsName ? S.pJsonSettingsName : "", S.pJsonSettings); + MicroProfileWSFlush(); + MicroProfileWSPrintEnd(); + } + } +} + +void MicroProfileWebSocketSendCounters() +{ + MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileWebSocketSendCounters", MP_GREEN4); + if(S.nWSViewMode == VIEW_COUNTERS) + { + MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":[", MSG_COUNTERS); + for(uint32_t i = 0; i < S.nNumCounters; ++i) + { + bool IsDouble = (S.CounterInfo[i].nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) != 0; + if(IsDouble) + { + double dCounter = S.CountersDouble[i].load(); + MicroProfileWSPrintf("%c%f", i == 0 ? ' ' : ',', dCounter); + } + else + { + uint64_t nCounter = S.Counters[i].load(); + MicroProfileWSPrintf("%c%lld", i == 0 ? ' ' : ',', nCounter); + } + } + MicroProfileWSPrintf("]}"); + MicroProfileWSFlush(); + } +} + +#if MICROPROFILE_DYNAMIC_INSTRUMENT +void MicroProfileSymbolSendModuleState() +{ + if(S.WSSymbolModulesSent != S.SymbolNumModules || S.nSymbolsDirty.load()) // todo: tag when modulestate is updated. + { + S.nSymbolsDirty.exchange(0); + MicroProfileWSPrintf(",\"M\":["); + bool bFirst = true; + for(int i = 0; i < S.SymbolNumModules; ++i) + { + MicroProfileSymbolModule& M = S.SymbolModules[i]; + const char* pModuleName = (const char*)M.pBaseString; + uint64_t nAddrBegin = M.Regions[0].nBegin; + // intptr_t nProgress = M.nProgress; + intptr_t nProgressTarget = M.nProgressTarget; + nProgressTarget = MicroProfileMax(intptr_t(1), M.nProgressTarget); + // nProgress = MicroProfileMin(nProgressTarget, M.nProgress); + float fLoadPrc = M.nProgress / float(nProgressTarget); + uint64_t nNumSymbols = M.nSymbolsLoaded; +#define FMT "{\"n\":\"%s\",\"a\":\"%llx\",\"s\":\"%lld\", \"p\":%f, \"d\":%d}" + MicroProfileWSPrintf(bFirst ? FMT : ("," FMT), pModuleName, nAddrBegin, nNumSymbols, fLoadPrc, M.bDownloading ? 1 : 0); +#undef FMT + bFirst = false; + } + MicroProfileWSPrintf("]"); + S.WSSymbolModulesSent = S.SymbolNumModules; + } +} +#endif + +void MicroProfileWebSocketSendFrame(MpSocket Connection) +{ + if(S.nFrameCurrent != S.WebSocketFrameLast[0] || S.nFrozen) + { + MicroProfileWebSocketSendState(Connection); + MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileWebSocketSendFrame", MP_GREEN4); + MicroProfileWSPrintStart(Connection); + float fTickToMsCpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()); + float fTickToMsGpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondGpu()); + MicroProfileFrameState* pFrameCurrent = &S.Frames[S.nFrameCurrent]; + MicroProfileFrameState* pFrameNext = &S.Frames[S.nFrameNext]; + + uint64_t nFrameTicks = pFrameNext->nFrameStartCpu - pFrameCurrent->nFrameStartCpu; + uint64_t nFrame = pFrameCurrent->nFrameId; + double fTime = nFrameTicks * fTickToMsCpu; + MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{\"t\":%f,\"f\":%lld,\"a\":%d,\"fr\":%d,\"m\":%d", MSG_FRAME, fTime, nFrame, MicroProfileGetCurrentAggregateFrames(), S.nFrozen, S.nWSViewMode); +#if MICROPROFILE_DYNAMIC_INSTRUMENT + MicroProfileWSPrintf(",\"s\":{\"n\":%d,\"f\":%d,\"r\":%d,\"l\":%d,\"q\":%d}", + S.SymbolNumModules, + S.SymbolState.nModuleLoadsFinished.load(), + S.SymbolState.nModuleLoadsRequested.load(), + S.SymbolState.nSymbolsLoaded.load(), + S.pPendingQuery ? 1 : 0); + MicroProfileSymbolSendModuleState(); +#endif + + auto WriteTickArray = [fTickToMsCpu, fTickToMsGpu](MicroProfile::GroupTime* pFrameGroup) + { + MicroProfileWSPrintf("["); + int f = 0; + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i) + { + uint64_t nTicksExcl = pFrameGroup[i].nTicksExclusive; + if(nTicksExcl) + { + uint64_t nTicks = pFrameGroup[i].nTicks; + float fCount = (float)pFrameGroup[i].nCount; + float fToMs = S.GroupInfo[i].Type == MicroProfileTokenTypeCpu ? fTickToMsCpu : fTickToMsGpu; + + MicroProfileWSPrintf("%c[%f,%f,%f]", f ? ',' : ' ', nTicks * fToMs, nTicksExcl * fToMs, fCount); + f = 1; + } + } + MicroProfileWSPrintf("]"); + }; + auto WriteIndexArray = [](MicroProfile::GroupTime* pFrameGroup) + { + MicroProfileWSPrintf("["); + int f = 0; + for(uint32_t i = 0; i < MICROPROFILE_MAX_GROUPS; ++i) + { + uint64_t nTicksExcl = pFrameGroup[i].nTicksExclusive; + if(nTicksExcl) + { + uint32_t id = MicroProfileWebSocketIdPack(TYPE_GROUP, i); + MicroProfileWSPrintf("%c%d", f ? ',' : ' ', id); + f = 1; + } + } + MicroProfileWSPrintf("]"); + }; + + MicroProfileWSPrintf(",\"g\":"); + WriteTickArray(S.FrameGroup); + MicroProfileWSPrintf(",\"gi\":"); + WriteIndexArray(S.FrameGroup); + if(S.nWSViewMode == VIEW_GRAPH_THREAD_GROUP) + { + MicroProfileWSPrintf(",\"gt\":["); + int f = 0; + for(uint32_t i = 0; i < MICROPROFILE_MAX_THREADS; ++i) + { + if(0 != (S.FrameGroupThreadValid[i / 32] & (1 << (i % 32)))) + { + if(!f) + MicroProfileWSPrintf("{"); + else + MicroProfileWSPrintf(",{"); + MicroProfileThreadLog* pLog = S.Pool[i]; + MicroProfileWSPrintf("\"i\":%d,\"n\":\"%s\",\"g\":", i, pLog->ThreadName); + WriteTickArray(&S.FrameGroupThread[i][0]); + MicroProfileWSPrintf(",\"gi\":"); + WriteIndexArray(&S.FrameGroupThread[i][0]); + MicroProfileWSPrintf("}"); + f = 1; + } + } + MicroProfileWSPrintf("]"); + } + + if(S.nFrameCurrent != S.WebSocketFrameLast[0]) + { + MicroProfileWSPrintf(",\"x\":{\"t\":{"); + int nTimer = S.WebSocketTimers; + // uprintf("T : "); + while(nTimer >= 0) + { + MicroProfileTimerInfo& TI = S.TimerInfo[nTimer]; + float fTickToMs = TI.Type == MicroProfileTokenTypeGpu ? fTickToMsGpu : fTickToMsCpu; + uint32_t id = MicroProfileWebSocketIdPack(TYPE_TIMER, nTimer); + fTime = fTickToMs * S.Frame[nTimer].nTicks; + float fCount = (float)S.Frame[nTimer].nCount; + float fTimeExcl = fTickToMs * S.FrameExclusive[nTimer]; + // uprintf("%4.2f, ", fTimeExcl); + if(!MicroProfileGroupActive(TI.nGroupIndex)) + { + fTime = fCount = fTimeExcl = 0.f; + } + nTimer = TI.nWSNext; + MicroProfileWSPrintf("\"%d\":[%f,%f,%f]%c", id, fTime, fTimeExcl, fCount, nTimer == -1 ? ' ' : ','); + } + MicroProfileWSPrintf("}, \"c\":{"); + int nCounter = S.WebSocketCounters; + while(nCounter >= 0) + { + MicroProfileCounterInfo& CI = S.CounterInfo[nCounter]; + bool IsDouble = (CI.nFlags & MICROPROFILE_COUNTER_FLAG_DOUBLE) != 0; + uint32_t id = MicroProfileWebSocketIdPack(TYPE_COUNTER, nCounter); + int nCounterNext = CI.nWSNext; + if(IsDouble) + { + double value = S.CountersDouble[nCounter].load(); + MicroProfileWSPrintf("\"%d\":%f%c", id, value, nCounterNext < 0 ? ' ' : ','); + } + else + { + uint64_t value = S.Counters[nCounter].load(); + MicroProfileWSPrintf("\"%d\":%lld%c", id, value, nCounterNext < 0 ? ' ' : ','); + } + nCounter = nCounterNext; + } + MicroProfileWSPrintf("}, \"g\":{"); + // uprintf("\n"); + MicroProfileWSPrintf("}}"); + } + MicroProfileWSPrintf("}}"); + MicroProfileWSFlush(); + MicroProfileWebSocketSendCounters(); + MicroProfileWSPrintEnd(); + S.WebSocketFrameLast[0] = S.nFrameCurrent; + } + else + { + MicroProfileWSPrintStart(Connection); + MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{\"fr\":%d,\"m\":%d", MSG_INACTIVE_FRAME, S.nFrozen, S.nWSViewMode); +#if MICROPROFILE_DYNAMIC_INSTRUMENT + MicroProfileWSPrintf(",\"s\":{\"n\":%d,\"f\":%d,\"r\":%d,\"l\":%d,\"q\":%d}", + S.SymbolNumModules, + S.SymbolState.nModuleLoadsFinished.load(), + S.SymbolState.nModuleLoadsRequested.load(), + S.SymbolState.nSymbolsLoaded.load(), + S.pPendingQuery ? 1 : 0); +#endif + MicroProfileWSPrintf("}}"); + MicroProfileWSFlush(); + MicroProfileWebSocketSendCounters(); + MicroProfileWSPrintEnd(); + } +#if MICROPROFILE_DYNAMIC_INSTRUMENT + MicroProfileSymbolQuerySendResult(Connection); + MicroProfileSymbolSendFunctionNames(Connection); + MicroProfileSymbolSendErrors(Connection); +#endif +} + +void MicroProfileWebSocketFrame() +{ + if(!S.nNumWebSockets) + { + return; + } + MICROPROFILE_SCOPEI("MicroProfile", "Websocket-update", MP_GREEN4); + fd_set Read, Write, Error; + FD_ZERO(&Read); + FD_ZERO(&Write); + FD_ZERO(&Error); + MpSocket LastSocket = 1; + for(uint32_t i = 0; i < S.nNumWebSockets; ++i) + { + LastSocket = MicroProfileMax(LastSocket, S.WebSockets[i] + 1); + FD_SET(S.WebSockets[i], &Read); + FD_SET(S.WebSockets[i], &Write); + FD_SET(S.WebSockets[i], &Error); + } + timeval tv; + tv.tv_sec = 0; + tv.tv_usec = 0; + + if(-1 == select(LastSocket, &Read, &Write, &Error, &tv)) + { + MP_ASSERT(0); + } + for(uint32_t i = 0; i < S.nNumWebSockets;) + { + MpSocket s = S.WebSockets[i]; + bool bConnected = true; + if(FD_ISSET(s, &Error)) + { + MP_ASSERT(0); // todo, remove & fix. + } + if(FD_ISSET(s, &Read)) + { + bConnected = MicroProfileWebSocketReceive(s); + } + if(FD_ISSET(s, &Write)) + { + if(S.nJsonSettingsPending) + { + MicroProfileWSPrintStart(s); + MicroProfileWSPrintf( + "{\"k\":\"%d\",\"ro\":%d,\"name\":\"%s\",\"v\":%s}", MSG_LOADSETTINGS, S.bJsonSettingsReadOnly ? 1 : 0, S.pJsonSettingsName ? S.pJsonSettingsName : "", S.pJsonSettings); + MicroProfileWSFlush(); + MicroProfileWSPrintEnd(); + S.nJsonSettingsPending = 0; + } + if(S.nWebSocketDirty) + { + MicroProfileFlipEnabled(); + MicroProfileWebSocketSendEnabled(s); + S.nWebSocketDirty = 0; + } + MicroProfileWebSocketSendFrame(s); + } + if(S.nSocketFail) + { + bConnected = false; + } + S.nSocketFail = 0; + + if(!bConnected) + { + uprintf("removing socket %" PRId64 "\n", (uint64_t)s); + +#ifndef _WIN32 + shutdown(S.WebSockets[i], SHUT_WR); +#else + shutdown(S.WebSockets[i], 1); +#endif + char tmp[128]; + int r = 1; + while(r > 0) + { + r = recv(S.WebSockets[i], tmp, sizeof(tmp), 0); + } +#ifdef _WIN32 + closesocket(S.WebSockets[i]); +#else + close(S.WebSockets[i]); +#endif + + --S.nNumWebSockets; + S.WebSockets[i] = S.WebSockets[S.nNumWebSockets]; + uprintf("done removing\n"); + } + else + { + ++i; + } + } + if(S.nWasFrozen) + { + S.nWasFrozen--; + } +} + +void MicroProfileWSPrintStart(MpSocket C) +{ + MP_ASSERT(S.WSBuf.Socket == 0); + MP_ASSERT(S.WSBuf.nPut == 0); + S.WSBuf.Socket = C; +} + +void MicroProfileResizeWSBuf(uint32_t nMinSize = 0) +{ + uint32_t nNewSize = MicroProfileMax(S.WSBuf.nPut + 2 * (nMinSize + 2 + 20), MicroProfileMax(S.WSBuf.nBufferSize * 3 / 2, (uint32_t)MICROPROFILE_WEBSOCKET_BUFFER_SIZE)); + S.WSBuf.pBufferAllocation = (char*)MICROPROFILE_REALLOC(S.WSBuf.pBufferAllocation, nNewSize); + S.WSBuf.pBuffer = S.WSBuf.pBufferAllocation + 20; + S.WSBuf.nBufferSize = nNewSize - 20; +} + +char* MicroProfileWSPrintfCallback(const char* buf, void* user, int len) +{ + MP_ASSERT(S.WSBuf.nPut == buf - S.WSBuf.pBuffer); + S.WSBuf.nPut += len; + if(S.WSBuf.nPut + STB_SPRINTF_MIN + 2 >= S.WSBuf.nBufferSize) // + { + MicroProfileResizeWSBuf(S.WSBuf.nPut + STB_SPRINTF_MIN); + } + return S.WSBuf.pBuffer + S.WSBuf.nPut; +} + +void MicroProfileWSPrintf(const char* pFmt, ...) +{ + if(!S.WSBuf.nBufferSize) + { + MicroProfileResizeWSBuf(STB_SPRINTF_MIN * 2); + } + va_list args; + va_start(args, pFmt); + MP_ASSERT(S.WSBuf.nPut + STB_SPRINTF_MIN < S.WSBuf.nBufferSize); + stbsp_vsprintfcb(MicroProfileWSPrintfCallback, 0, S.WSBuf.pBuffer + S.WSBuf.nPut, pFmt, args); + va_end(args); +} + +void MicroProfileWSPrintEnd() +{ + MP_ASSERT(S.WSBuf.nPut == 0); + S.WSBuf.Socket = 0; +} + +void MicroProfileWSFlush() +{ + MP_ASSERT(S.WSBuf.Socket != 0); + MP_ASSERT(S.WSBuf.nPut != 0); + MicroProfileWebSocketSend(S.WSBuf.Socket, &S.WSBuf.pBuffer[0], S.WSBuf.nPut); + S.WSBuf.nPut = 0; +} +void MicroProfileWebSocketSendEnabledMessage(uint32_t id, int bEnabled) +{ + MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{\"id\":%d,\"e\":%d}}", MSG_ENABLED, id, bEnabled ? 1 : 0); + MicroProfileWSFlush(); +} +void MicroProfileWebSocketSendEnabled(MpSocket C) +{ + MICROPROFILE_SCOPEI("MicroProfile", "Websocket-SendEnabled", MP_GREEN4); + MicroProfileWSPrintStart(C); + for(uint32_t i = 0; i < S.nCategoryCount; ++i) + { + MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_CATEGORY, i), MicroProfileCategoryEnabled(i)); + } + + for(uint32_t i = 0; i < S.nGroupCount; ++i) + { + MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_GROUP, i), MicroProfileGroupEnabled(i)); + } + for(uint32_t i = 0; i < S.nTotalTimers; ++i) + { + MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_TIMER, i), MicroProfileWebSocketTimerEnabled(i)); + } + for(uint32_t i = 0; i < S.nNumCounters; ++i) + { + MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_COUNTER, i), MicroProfileWebSocketCounterEnabled(i)); + } + MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_SETTING, SETTING_FORCE_ENABLE), MicroProfileGetEnableAllGroups()); + MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_SETTING, SETTING_CONTEXT_SWITCH_TRACE), S.bContextSwitchRunning); + MicroProfileWebSocketSendEnabledMessage(MicroProfileWebSocketIdPack(TYPE_SETTING, SETTING_PLATFORM_MARKERS), MicroProfilePlatformMarkersGetEnabled()); + + MicroProfileWSPrintEnd(); +} +void MicroProfileWebSocketSendEntry(uint32_t id, uint32_t parent, const char* pName, int nEnabled, uint32_t nColor, uint32_t nType) +{ + MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{\"id\":%d,\"pid\":%d,", MSG_TIMER_TREE, id, parent); + MicroProfileWSPrintf("\"name\":\"%s\",", pName); + MicroProfileWSPrintf("\"e\":%d,", nEnabled); + MicroProfileWSPrintf("\"type\":%d,", nType); + if(nColor == 0x42) + { + MicroProfileWSPrintf("\"color\":\"\""); + } + else + { + MicroProfileWSPrintf("\"color\":\"#%02x%02x%02x\"", MICROPROFILE_UNPACK_RED(nColor) & 0xff, MICROPROFILE_UNPACK_GREEN(nColor) & 0xff, MICROPROFILE_UNPACK_BLUE(nColor) & 0xff); + } + + MicroProfileWSPrintf("}}"); + MicroProfileWSFlush(); +} + +void MicroProfileWebSocketSendCounterEntry(uint32_t id, uint32_t parent, const char* pName, int nEnabled, int64_t nLimit, int nFormat) +{ + MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{\"id\":%d,\"pid\":%d,", MSG_TIMER_TREE, id, parent); + MicroProfileWSPrintf("\"name\":\"%s\",", pName); + MicroProfileWSPrintf("\"e\":%d,", nEnabled); + MicroProfileWSPrintf("\"limit\":%lld,", nLimit); + MicroProfileWSPrintf("\"format\":%d", nFormat); + MicroProfileWSPrintf("}}"); + MicroProfileWSFlush(); +} + +void MicroProfileWebSocketSendState(MpSocket C) +{ + if(S.WSCategoriesSent != S.nCategoryCount || S.WSGroupsSent != S.nGroupCount || S.WSTimersSent != S.nTotalTimers || S.WSCountersSent != S.nNumCounters) + { + MicroProfileWSPrintStart(C); + uint32_t root = MicroProfileWebSocketIdPack(TYPE_SETTING, SETTING_FORCE_ENABLE); + MicroProfileWebSocketSendEntry(root, 0, "All", MicroProfileGetEnableAllGroups(), (uint32_t)-1, 0); + for(uint32_t i = S.WSCategoriesSent; i < S.nCategoryCount; ++i) + { + + MicroProfileCategory& CI = S.CategoryInfo[i]; + uint32_t id = MicroProfileWebSocketIdPack(TYPE_CATEGORY, i); + uint32_t parent = root; + MicroProfileWebSocketSendEntry(id, parent, CI.pName, MicroProfileCategoryEnabled(i), 0xffffffff, 0); + } + + for(uint32_t i = S.WSGroupsSent; i < S.nGroupCount; ++i) + { + MicroProfileGroupInfo& GI = S.GroupInfo[i]; + uint32_t id = MicroProfileWebSocketIdPack(TYPE_GROUP, i); + uint32_t parent = MicroProfileWebSocketIdPack(TYPE_CATEGORY, GI.nCategory); + MicroProfileWebSocketSendEntry(id, parent, GI.pName, MicroProfileGroupEnabled(i), GI.nColor, GI.Type); + } + + for(uint32_t i = S.WSTimersSent; i < S.nTotalTimers; ++i) + { + MicroProfileTimerInfo& TI = S.TimerInfo[i]; + uint32_t id = MicroProfileWebSocketIdPack(TYPE_TIMER, i); + uint32_t parent = MicroProfileWebSocketIdPack(TYPE_GROUP, TI.nGroupIndex); + MicroProfileWebSocketSendEntry(id, parent, TI.pName, MicroProfileWebSocketTimerEnabled(i), TI.nColor, TI.Type); + } + + for(uint32_t i = S.WSCountersSent; i < S.nNumCounters; ++i) + { + MicroProfileCounterInfo& CI = S.CounterInfo[i]; + uint32_t id = MicroProfileWebSocketIdPack(TYPE_COUNTER, i); + uint32_t parent = CI.nParent == -1 ? 0u : MicroProfileWebSocketIdPack(TYPE_COUNTER, CI.nParent); + MicroProfileWebSocketSendCounterEntry(id, parent, CI.pName, MicroProfileWebSocketCounterEnabled(i), CI.nLimit, CI.eFormat); + } +#if MICROPROFILE_CONTEXT_SWITCH_TRACE + MicroProfileWebSocketSendEntry(MicroProfileWebSocketIdPack(TYPE_SETTING, SETTING_CONTEXT_SWITCH_TRACE), 0, "Context Switch Trace", S.bContextSwitchRunning, (uint32_t)-1, 0); +#endif +#if MICROPROFILE_PLATFORM_MARKERS + MicroProfileWebSocketSendEntry(MicroProfileWebSocketIdPack(TYPE_SETTING, SETTING_PLATFORM_MARKERS), 0, "Platform Markers", S.bContextSwitchRunning, (uint32_t)-1); +#endif + MicroProfileWSPrintEnd(); + + S.WSCategoriesSent = S.nCategoryCount; + S.WSGroupsSent = S.nGroupCount; + S.WSTimersSent = S.nTotalTimers; + S.WSCountersSent = S.nNumCounters; + } +} + +bool MicroProfileWebServerUpdate() +{ + MICROPROFILE_SCOPEI("MicroProfile", "Webserver-update", MP_GREEN4); + MpSocket Connection = accept(S.ListenerSocket, 0, 0); + bool bServed = false; + MicroProfileWebSocketFrame(); + if(!MP_INVALID_SOCKET(Connection)) + { + std::lock_guard Lock(MicroProfileMutex()); + char Req[8192]; + int nReceived = recv(Connection, Req, sizeof(Req) - 1, 0); + if(nReceived > 0) + { + Req[nReceived] = '\0'; + uprintf("req received\n%s", Req); + +#define MICROPROFILE_HTML_PNG_HEADER "HTTP/1.0 200 OK\r\nContent-Type: image/png\r\n\r\n" +#define MICROPROFILE_HTML_JS_HEADER "HTTP/1.0 200 OK\r\nContent-Type: text/javascript\r\n\r\n" +#if MICROPROFILE_MINIZ + // Expires: Tue, 01 Jan 2199 16:00:00 GMT\r\n +#define MICROPROFILE_HTML_HEADER "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\nContent-Encoding: deflate\r\n\r\n" +#else +#define MICROPROFILE_HTML_HEADER "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" +#endif + + char* pHttp = strstr(Req, "HTTP/"); + + char* pGet = strstr(Req, "GET /"); + char* pHost = strstr(Req, "Host: "); + char* pWebSocketKey = strstr(Req, "Sec-WebSocket-Key: "); + auto Terminate = [](char* pString) + { + char* pEnd = pString; + while(*pEnd != '\0') + { + if(*pEnd == '\r' || *pEnd == '\n' || *pEnd == ' ') + { + *pEnd = '\0'; + return; + } + pEnd++; + } + }; + + if(pWebSocketKey) + { + if(S.nNumWebSockets) // only allow 1 + { + return false; + } + pWebSocketKey += sizeof("Sec-WebSocket-Key: ") - 1; + Terminate(pWebSocketKey); + MicroProfileWebSocketHandshake(Connection, pWebSocketKey); + return false; + } + + if(pHost) + { + pHost += sizeof("Host: ") - 1; + Terminate(pHost); + } + + if(pHttp && pGet) + { + *pHttp = '\0'; + pGet += sizeof("GET /") - 1; + Terminate(pGet); + MicroProfileParseGetResult R; + auto P = MicroProfileParseGet(pGet, &R); + switch(P) + { + case EMICROPROFILE_GET_COMMAND_SERVICE_WORKER: + { + MicroProfileSetNonBlocking(Connection, 1); + uint64_t nTickStart = MP_TICK(); + send(Connection, MICROPROFILE_HTML_JS_HEADER, sizeof(MICROPROFILE_HTML_JS_HEADER) - 1, 0); + const char* JsCode = "self.addEventListener(\"fetch\", () => {}); \r\n\r\n"; + send(Connection, JsCode, (int)strlen(JsCode), 0); + break; + } + case EMICROPROFILE_GET_COMMAND_FAVICON: + { + MicroProfileSetNonBlocking(Connection, 1); + uint64_t nTickStart = MP_TICK(); + send(Connection, MICROPROFILE_HTML_PNG_HEADER, sizeof(MICROPROFILE_HTML_PNG_HEADER) - 1, 0); + extern const uint32_t uprof_512[]; + extern const uint32_t uprof_512_len; + const char* pFile = (const char*)&uprof_512[0]; + uint32_t nFileSize = uprof_512_len; + send(Connection, pFile, nFileSize, 0); + } + break; + case EMICROPROFILE_GET_COMMAND_LIVE: + { + MicroProfileSetNonBlocking(Connection, 0); + uint64_t nTickStart = MP_TICK(); + send(Connection, MICROPROFILE_HTML_HEADER, sizeof(MICROPROFILE_HTML_HEADER) - 1, 0); + uint64_t nDataStart = S.nWebServerDataSent; + S.WebServerPut = 0; +#if 0 == MICROPROFILE_MINIZ + MicroProfileDumpHtmlLive(MicroProfileWriteSocket, &Connection); + uint64_t nDataEnd = S.nWebServerDataSent; + uint64_t nTickEnd = MP_TICK(); + uint64_t nDiff = (nTickEnd - nTickStart); + float fMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * nDiff; + int nKb = ((nDataEnd-nDataStart)>>10) + 1; + int nCompressedKb = nKb; + MicroProfilePrintf(MicroProfileWriteSocket, &Connection, "\n\n\n",nKb, fMs); + MicroProfileFlushSocket(Connection); +#else + MicroProfileCompressedSocketState CompressState; + MicroProfileCompressedSocketStart(&CompressState, Connection); + MicroProfileDumpHtmlLive(MicroProfileCompressedWriteSocket, &CompressState); + S.nWebServerDataSent += CompressState.nSize; + uint64_t nDataEnd = S.nWebServerDataSent; + uint64_t nTickEnd = MP_TICK(); + uint64_t nDiff = (nTickEnd - nTickStart); + float fMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * nDiff; + int nKb = ((nDataEnd - nDataStart) >> 10) + 1; + int nCompressedKb = ((CompressState.nCompressedSize) >> 10) + 1; + MicroProfilePrintf(MicroProfileCompressedWriteSocket, &CompressState, "\n\n\n", nKb, nCompressedKb, fMs); + MicroProfileCompressedSocketFinish(&CompressState); + MicroProfileFlushSocket(Connection); +#endif + + uprintf("\n\n\n", nKb, nCompressedKb, fMs); + (void)nCompressedKb; + } + break; + case EMICROPROFILE_GET_COMMAND_DUMP_RANGE: + case EMICROPROFILE_GET_COMMAND_DUMP: + { + { + MicroProfileSetNonBlocking(Connection, 0); + uint64_t nTickStart = MP_TICK(); + send(Connection, MICROPROFILE_HTML_HEADER, sizeof(MICROPROFILE_HTML_HEADER) - 1, 0); + uint64_t nDataStart = S.nWebServerDataSent; + S.WebServerPut = 0; +#if 0 == MICROPROFILE_MINIZ + MicroProfileDumpHtml(MicroProfileWriteSocket, &Connection, R.nFrames, pHost, R.nFrameStart); + uint64_t nDataEnd = S.nWebServerDataSent; + uint64_t nTickEnd = MP_TICK(); + uint64_t nDiff = (nTickEnd - nTickStart); + float fMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * nDiff; + int nKb = ((nDataEnd-nDataStart)>>10) + 1; + int nCompressedKb = nKb; + MicroProfilePrintf(MicroProfileWriteSocket, &Connection, "\n\n\n",nKb, fMs); + MicroProfileFlushSocket(Connection); +#else + MicroProfileCompressedSocketState CompressState; + MicroProfileCompressedSocketStart(&CompressState, Connection); + + MicroProfileDumpHtml(MicroProfileCompressedWriteSocket, &CompressState, R.nFrames, pHost, R.nFrameStart); + + S.nWebServerDataSent += CompressState.nSize; + uint64_t nDataEnd = S.nWebServerDataSent; + uint64_t nTickEnd = MP_TICK(); + uint64_t nDiff = (nTickEnd - nTickStart); + float fMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()) * nDiff; + int nKb = ((nDataEnd - nDataStart) >> 10) + 1; + int nCompressedKb = ((CompressState.nCompressedSize) >> 10) + 1; + MicroProfilePrintf(MicroProfileCompressedWriteSocket, &CompressState, "\n\n\n", nKb, nCompressedKb, fMs); + MicroProfileCompressedSocketFinish(&CompressState); + MicroProfileFlushSocket(Connection); +#endif + + uprintf("\n\n\n", nKb, nCompressedKb, fMs); + (void)nCompressedKb; + } + } + break; + case EMICROPROFILE_GET_COMMAND_UNKNOWN: + { + uprintf("unknown get command %s\n", pGet); + } + break; + } + } + } +#ifdef _WIN32 + closesocket(Connection); +#else + close(Connection); +#endif + } + return bServed; +} +#endif + +#if MICROPROFILE_CONTEXT_SWITCH_TRACE +// functions that need to be implemented per platform. +void* MicroProfileTraceThread(void* unused); +int MicroProfileIsLocalThread(uint32_t nThreadId); + +void MicroProfileStartContextSwitchTrace() +{ + if(!S.bContextSwitchRunning && !S.nMicroProfileShutdown) + { + S.bContextSwitchRunning = true; + S.bContextSwitchStop = false; + MicroProfileThreadStart(&S.ContextSwitchThread, MicroProfileTraceThread); + } +} + +void MicroProfileJoinContextSwitchTrace() +{ + if(S.bContextSwitchStop) + { + MicroProfileThreadJoin(&S.ContextSwitchThread); + } +} + +void MicroProfileStopContextSwitchTrace() +{ + if(S.bContextSwitchRunning) + { + S.bContextSwitchStop = true; + } +} + +#ifdef _WIN32 +#define INITGUID +#include +#include +#include + +static GUID g_MicroProfileThreadClassGuid = { 0x3d6fa8d1, 0xfe05, 0x11d0, 0x9d, 0xda, 0x00, 0xc0, 0x4f, 0xd7, 0xba, 0x7c }; + +struct MicroProfileSCSwitch +{ + uint32_t NewThreadId; + uint32_t OldThreadId; + int8_t NewThreadPriority; + int8_t OldThreadPriority; + uint8_t PreviousCState; + int8_t SpareByte; + int8_t OldThreadWaitReason; + int8_t OldThreadWaitMode; + int8_t OldThreadState; + int8_t OldThreadWaitIdealProcessor; + uint32_t NewThreadWaitTime; + uint32_t Reserved; +}; + +VOID WINAPI MicroProfileContextSwitchCallback(PEVENT_TRACE pEvent) +{ + if(pEvent->Header.Guid == g_MicroProfileThreadClassGuid) + { + if(pEvent->Header.Class.Type == 36) + { + MicroProfileSCSwitch* pCSwitch = (MicroProfileSCSwitch*)pEvent->MofData; + if((pCSwitch->NewThreadId != 0) || (pCSwitch->OldThreadId != 0)) + { + MicroProfileContextSwitch Switch; + Switch.nThreadOut = pCSwitch->OldThreadId; + Switch.nThreadIn = pCSwitch->NewThreadId; + Switch.nCpu = pEvent->BufferContext.ProcessorNumber; + Switch.nTicks = pEvent->Header.TimeStamp.QuadPart; + MicroProfileContextSwitchPut(&Switch); + } + } + } +} + +ULONG WINAPI MicroProfileBufferCallback(PEVENT_TRACE_LOGFILEA Buffer) +{ + return (S.bContextSwitchStop || !S.bContextSwitchRunning) ? FALSE : TRUE; +} + +struct MicroProfileKernelTraceProperties : public EVENT_TRACE_PROPERTIES +{ + char dummy[sizeof(KERNEL_LOGGER_NAME)]; +}; + +void MicroProfileContextSwitchShutdownTrace() +{ + TRACEHANDLE SessionHandle = 0; + MicroProfileKernelTraceProperties sessionProperties; + + ZeroMemory(&sessionProperties, sizeof(sessionProperties)); + sessionProperties.Wnode.BufferSize = sizeof(sessionProperties); + sessionProperties.Wnode.Flags = WNODE_FLAG_TRACED_GUID; + sessionProperties.Wnode.ClientContext = 1; // QPC clock resolution + sessionProperties.Wnode.Guid = SystemTraceControlGuid; + sessionProperties.BufferSize = 1; + sessionProperties.NumberOfBuffers = 128; + sessionProperties.EnableFlags = EVENT_TRACE_FLAG_CSWITCH; + sessionProperties.LogFileMode = EVENT_TRACE_REAL_TIME_MODE; + sessionProperties.MaximumFileSize = 0; + sessionProperties.LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); + sessionProperties.LogFileNameOffset = 0; + + EVENT_TRACE_LOGFILEA log; + ZeroMemory(&log, sizeof(log)); + log.LoggerName = (LPSTR)KERNEL_LOGGER_NAMEA; + log.ProcessTraceMode = 0; + TRACEHANDLE hLog = OpenTraceA(&log); + if(hLog) + { + ControlTrace(SessionHandle, KERNEL_LOGGER_NAME, &sessionProperties, EVENT_TRACE_CONTROL_STOP); + } + CloseTrace(hLog); +} + +typedef VOID(WINAPI* EventCallback)(PEVENT_TRACE); +typedef ULONG(WINAPI* BufferCallback)(PEVENT_TRACE_LOGFILEA); +bool MicroProfileStartWin32Trace(EventCallback EvtCb, BufferCallback BufferCB) +{ + MicroProfileContextSwitchShutdownTrace(); + ULONG status = ERROR_SUCCESS; + TRACEHANDLE SessionHandle = 0; + MicroProfileKernelTraceProperties sessionProperties; + + ZeroMemory(&sessionProperties, sizeof(sessionProperties)); + sessionProperties.Wnode.BufferSize = sizeof(sessionProperties); + sessionProperties.Wnode.Flags = WNODE_FLAG_TRACED_GUID; + sessionProperties.Wnode.ClientContext = 1; // QPC clock resolution + sessionProperties.Wnode.Guid = SystemTraceControlGuid; + sessionProperties.BufferSize = 1; + sessionProperties.NumberOfBuffers = 128; + sessionProperties.EnableFlags = EVENT_TRACE_FLAG_CSWITCH | EVENT_TRACE_FLAG_PROCESS; + sessionProperties.LogFileMode = EVENT_TRACE_REAL_TIME_MODE; + sessionProperties.MaximumFileSize = 0; + sessionProperties.LoggerNameOffset = sizeof(EVENT_TRACE_PROPERTIES); + sessionProperties.LogFileNameOffset = 0; + + StopTrace(NULL, KERNEL_LOGGER_NAME, &sessionProperties); + status = StartTrace((PTRACEHANDLE)&SessionHandle, KERNEL_LOGGER_NAME, &sessionProperties); + + if(ERROR_SUCCESS != status) + { + return false; + } + + EVENT_TRACE_LOGFILEA log; + ZeroMemory(&log, sizeof(log)); + + log.LoggerName = (LPSTR)KERNEL_LOGGER_NAME; + log.ProcessTraceMode = PROCESS_TRACE_MODE_REAL_TIME | PROCESS_TRACE_MODE_RAW_TIMESTAMP; + log.EventCallback = EvtCb; + log.BufferCallback = BufferCB; + + TRACEHANDLE hLog = OpenTraceA(&log); + ProcessTrace(&hLog, 1, 0, 0); + CloseTrace(hLog); + MicroProfileContextSwitchShutdownTrace(); + return true; +} + +#include +#include +#include +#define ThreadQuerySetWin32StartAddress 9 +typedef LONG NTSTATUS; +typedef NTSTATUS(WINAPI* pNtQIT)(HANDLE, LONG, PVOID, ULONG, PULONG); +#define STATUS_SUCCESS ((NTSTATUS)0x000 00000L) +#define ThreadQuerySetWin32StartAddress 9 +#undef Process32First +#undef Process32Next +#undef PROCESSENTRY32 +#undef Module32First +#undef Module32Next +#undef MODULEENTRY32 + +struct MicroProfileWin32ContextSwitchShared +{ + std::atomic nPut; + std::atomic nGet; + std::atomic nQuit; + std::atomic nTickTrace; + std::atomic nTickProgram; + enum + { + BUFFER_SIZE = (2 << 20) / sizeof(MicroProfileContextSwitch), + }; + MicroProfileContextSwitch Buffer[BUFFER_SIZE]; +}; + +struct MicroProfileWin32ThreadInfo +{ + struct Process + { + uint32_t pid; + uint32_t nNumModules; + uint32_t nModuleStart; + const char* pProcessModule; + }; + struct Module + { + int64_t nBase; + int64_t nEnd; + const char* pName; + }; + enum + { + MAX_PROCESSES = 5 * 1024, + MAX_THREADS = 20 * 1024, + MAX_MODULES = 20 * 1024, + MAX_STRINGS = 16 * 1024, + MAX_CHARS = 128 * 1024, + }; + uint32_t nNumProcesses; + uint32_t nNumThreads; + uint32_t nStringOffset; + uint32_t nNumStrings; + uint32_t nNumModules; + Process P[MAX_PROCESSES]; + Module M[MAX_MODULES]; + MicroProfileThreadInfo T[MAX_THREADS]; + const char* pStrings[MAX_STRINGS]; + char StringData[MAX_CHARS]; +}; + +static MicroProfileWin32ThreadInfo g_ThreadInfo; + +const char* MicroProfileWin32ThreadInfoAddString(const char* pString) +{ + size_t nLen = strlen(pString); + uint32_t nHash = *(uint32_t*)pString; + nHash ^= (nHash >> 16); + enum + { + MAX_SEARCH = 256, + }; + for(uint32_t i = 0; i < MAX_SEARCH; ++i) + { + uint32_t idx = (i + nHash) % MicroProfileWin32ThreadInfo::MAX_STRINGS; + if(0 == g_ThreadInfo.pStrings[idx]) + { + g_ThreadInfo.pStrings[idx] = &g_ThreadInfo.StringData[g_ThreadInfo.nStringOffset]; + memcpy(&g_ThreadInfo.StringData[g_ThreadInfo.nStringOffset], pString, nLen + 1); + g_ThreadInfo.nStringOffset += (uint32_t)(nLen + 1); + return g_ThreadInfo.pStrings[idx]; + } + if(0 == strcmp(g_ThreadInfo.pStrings[idx], pString)) + { + return g_ThreadInfo.pStrings[idx]; + } + } + return "internal hash table fail: should never happen"; +} +void MicroProfileWin32ExtractModules(MicroProfileWin32ThreadInfo::Process& P) +{ + HANDLE hModuleSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, P.pid); + MODULEENTRY32 me; + if(Module32First(hModuleSnapshot, &me)) + { + do + { + if(g_ThreadInfo.nNumModules < MicroProfileWin32ThreadInfo::MAX_MODULES) + { + auto& M = g_ThreadInfo.M[g_ThreadInfo.nNumModules++]; + P.nNumModules++; + intptr_t nBase = (intptr_t)me.modBaseAddr; + intptr_t nEnd = nBase + me.modBaseSize; + M.nBase = nBase; + M.nEnd = nEnd; + M.pName = MicroProfileWin32ThreadInfoAddString(&me.szModule[0]); + } + } while(Module32Next(hModuleSnapshot, &me)); + } + if(hModuleSnapshot) + CloseHandle(hModuleSnapshot); +} +void MicroProfileWin32InitThreadInfo2() +{ + memset(&g_ThreadInfo, 0, sizeof(g_ThreadInfo)); +#if MICROPROFILE_DEBUG + float fToMsCpu = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()); +#endif + + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPALL, 0); + PROCESSENTRY32 pe32; + THREADENTRY32 te32; + te32.dwSize = sizeof(THREADENTRY32); + pe32.dwSize = sizeof(PROCESSENTRY32); + { +#if MICROPROFILE_DEBUG + int64_t nTickStart = MP_TICK(); +#endif + if(Process32First(hSnap, &pe32)) + { + do + { + + MicroProfileWin32ThreadInfo::Process P; + P.pid = pe32.th32ProcessID; + P.pProcessModule = MicroProfileWin32ThreadInfoAddString(pe32.szExeFile); + g_ThreadInfo.P[g_ThreadInfo.nNumProcesses++] = P; + } while(Process32Next(hSnap, &pe32) && g_ThreadInfo.nNumProcesses < MicroProfileWin32ThreadInfo::MAX_PROCESSES); + } +#if MICROPROFILE_DEBUG + int64_t nTicksEnd = MP_TICK(); + float fMs = fToMsCpu * (nTicksEnd - nTickStart); + uprintf("Process iteration %6.2fms processes %d\n", fMs, g_ThreadInfo.nNumProcesses); +#endif + } + { +#if MICROPROFILE_DEBUG + int64_t nTickStart = MP_TICK(); +#endif + for(uint32_t i = 0; i < g_ThreadInfo.nNumProcesses; ++i) + { + g_ThreadInfo.P[i].nModuleStart = g_ThreadInfo.nNumModules; + g_ThreadInfo.P[i].nNumModules = 0; + MicroProfileWin32ExtractModules(g_ThreadInfo.P[i]); + } +#if MICROPROFILE_DEBUG + int64_t nTicksEnd = MP_TICK(); + float fMs = fToMsCpu * (nTicksEnd - nTickStart); + uprintf("Module iteration %6.2fms NumModules %d\n", fMs, g_ThreadInfo.nNumModules); +#endif + } + + pNtQIT NtQueryInformationThread = (pNtQIT)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQueryInformationThread"); + intptr_t dwStartAddress; + ULONG olen; + uint32_t nThreadsTested = 0; + uint32_t nThreadsSucceeded = 0; + + if(Thread32First(hSnap, &te32)) + { +#if MICROPROFILE_DEBUG + int64_t nTickStart = MP_TICK(); +#endif + do + { + nThreadsTested++; + const char* pModule = "?"; + HANDLE hThread = OpenThread(THREAD_QUERY_INFORMATION, FALSE, te32.th32ThreadID); + if(hThread) + { + + NTSTATUS ntStatus = NtQueryInformationThread(hThread, (THREADINFOCLASS)ThreadQuerySetWin32StartAddress, &dwStartAddress, sizeof(dwStartAddress), &olen); + if(0 == ntStatus) + { + uint32_t nProcessIndex = (uint32_t)-1; + for(uint32_t i = 0; i < g_ThreadInfo.nNumProcesses; ++i) + { + if(g_ThreadInfo.P[i].pid == te32.th32OwnerProcessID) + { + nProcessIndex = i; + break; + } + } + if(nProcessIndex != (uint32_t)-1) + { + uint32_t nModuleStart = g_ThreadInfo.P[nProcessIndex].nModuleStart; + uint32_t nNumModules = g_ThreadInfo.P[nProcessIndex].nNumModules; + for(uint32_t i = 0; i < nNumModules; ++i) + { + auto& M = g_ThreadInfo.M[nModuleStart + i]; + if(M.nBase <= dwStartAddress && M.nEnd >= dwStartAddress) + { + pModule = M.pName; + } + } + } + } + } + if(hThread) + CloseHandle(hThread); + { + MicroProfileThreadInfo T; + T.pid = te32.th32OwnerProcessID; + T.tid = te32.th32ThreadID; + const char* pProcess = "unknown"; + for(uint32_t i = 0; i < g_ThreadInfo.nNumProcesses; ++i) + { + if(g_ThreadInfo.P[i].pid == T.pid) + { + pProcess = g_ThreadInfo.P[i].pProcessModule; + break; + } + } + T.pProcessModule = pProcess; + T.pThreadModule = MicroProfileWin32ThreadInfoAddString(pModule); + T.nIsLocal = GetCurrentProcessId() == T.pid ? 1 : 0; + nThreadsSucceeded++; + g_ThreadInfo.T[g_ThreadInfo.nNumThreads++] = T; + } + + } while(Thread32Next(hSnap, &te32) && g_ThreadInfo.nNumThreads < MicroProfileWin32ThreadInfo::MAX_THREADS); + +#if MICROPROFILE_DEBUG + int64_t nTickEnd = MP_TICK(); + float fMs = fToMsCpu * (nTickEnd - nTickStart); + uprintf("Thread iteration %6.2fms Threads %d\n", fMs, g_ThreadInfo.nNumThreads); +#endif + } +} + +void MicroProfileWin32UpdateThreadInfo() +{ + static int nWasRunning = 1; + static int nOnce = 0; + int nRunning = MicroProfileAnyGroupActive() ? 1 : 0; + + if((0 == nRunning && 1 == nWasRunning) || nOnce == 0) + { + nOnce = 1; + MicroProfileWin32InitThreadInfo2(); + } + nWasRunning = nRunning; +} + +const char* MicroProfileThreadNameFromId(MicroProfileThreadIdType nThreadId) +{ + MicroProfileWin32UpdateThreadInfo(); + static char result[1024]; + for(uint32_t i = 0; i < g_ThreadInfo.nNumThreads; ++i) + { + if(g_ThreadInfo.T[i].tid == nThreadId) + { + sprintf_s(result, "p:%s t:%s", g_ThreadInfo.T[i].pProcessModule, g_ThreadInfo.T[i].pThreadModule); + return result; + } + } + sprintf_s(result, "?"); + return result; +} + +#define MICROPROFILE_FILEMAPPING "microprofile-shared" +#ifdef MICROPROFILE_WIN32_COLLECTOR +#define MICROPROFILE_WIN32_CSWITCH_TIMEOUT 15 // seconds to wait before collector exits +static MicroProfileWin32ContextSwitchShared* g_pShared = 0; +VOID WINAPI MicroProfileContextSwitchCallbackCollector(PEVENT_TRACE pEvent) +{ + static int64_t nPackets = 0; + static int64_t nSkips = 0; + if(pEvent->Header.Guid == g_MicroProfileThreadClassGuid) + { + if(pEvent->Header.Class.Type == 36) + { + MicroProfileSCSwitch* pCSwitch = (MicroProfileSCSwitch*)pEvent->MofData; + if((pCSwitch->NewThreadId != 0) || (pCSwitch->OldThreadId != 0)) + { + MicroProfileContextSwitch Switch; + Switch.nThreadOut = pCSwitch->OldThreadId; + Switch.nThreadIn = pCSwitch->NewThreadId; + Switch.nCpu = pEvent->BufferContext.ProcessorNumber; + Switch.nTicks = pEvent->Header.TimeStamp.QuadPart; + int64_t nPut = g_pShared->nPut.load(std::memory_order_relaxed); + int64_t nGet = g_pShared->nGet.load(std::memory_order_relaxed); + nPackets++; + if(nPut - nGet < MicroProfileWin32ContextSwitchShared::BUFFER_SIZE) + { + g_pShared->Buffer[nPut % MicroProfileWin32ContextSwitchShared::BUFFER_SIZE] = Switch; + g_pShared->nPut.store(nPut + 1, std::memory_order_release); + nSkips = 0; + } + else + { + nSkips++; + } + } + } + } + if(0 == (nPackets % (4 << 10))) + { + int64_t nTickTrace = MP_TICK(); + g_pShared->nTickTrace.store(nTickTrace); + int64_t nTickProgram = g_pShared->nTickProgram.load(); + float fTickToMs = MicroProfileTickToMsMultiplier(MicroProfileTicksPerSecondCpu()); + float fTime = fabs(fTickToMs * (nTickTrace - nTickProgram)); + printf("\rRead %" PRId64 " CSwitch Packets, Skips %" PRId64 " Time difference %6.3fms ", nPackets, nSkips, fTime); + fflush(stdout); + if(fTime > MICROPROFILE_WIN32_CSWITCH_TIMEOUT * 1000) + { + g_pShared->nQuit.store(1); + } + } +} + +ULONG WINAPI MicroProfileBufferCallbackCollector(PEVENT_TRACE_LOGFILEA Buffer) +{ + return (g_pShared->nQuit.load()) ? FALSE : TRUE; +} + +int main(int argc, char* argv[]) +{ + if(argc != 2) + { + return 1; + } + printf("using file '%s'\n", argv[1]); + HANDLE hMemory = OpenFileMappingA(FILE_MAP_ALL_ACCESS, FALSE, argv[1]); + if(hMemory == NULL) + { + return 1; + } + g_pShared = (MicroProfileWin32ContextSwitchShared*)MapViewOfFile(hMemory, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(MicroProfileWin32ContextSwitchShared)); + + if(g_pShared != NULL) + { + MicroProfileStartWin32Trace(MicroProfileContextSwitchCallbackCollector, MicroProfileBufferCallbackCollector); + UnmapViewOfFile(g_pShared); + } + + CloseHandle(hMemory); + return 0; +} +#endif +#include +void* MicroProfileTraceThread(void* unused) +{ + MicroProfileOnThreadCreate("ContextSwitchThread"); + MicroProfileContextSwitchShutdownTrace(); + if(!MicroProfileStartWin32Trace(MicroProfileContextSwitchCallback, MicroProfileBufferCallback)) + { + MicroProfileContextSwitchShutdownTrace(); + // not running as admin. try and start other process. + MicroProfileWin32ContextSwitchShared* pShared = 0; + char Filename[512]; + time_t t = time(NULL); + _snprintf_s(Filename, sizeof(Filename), "%s_%d", MICROPROFILE_FILEMAPPING, (int)t); + + HANDLE hMemory = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(MicroProfileWin32ContextSwitchShared), Filename); + if(hMemory != NULL) + { + pShared = (MicroProfileWin32ContextSwitchShared*)MapViewOfFile(hMemory, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(MicroProfileWin32ContextSwitchShared)); + if(pShared != NULL) + { +#ifdef _M_IX86 +#define CSWITCH_EXE "microprofile-win32-cswitch_x86.exe" +#else +#define CSWITCH_EXE "microprofile-win32-cswitch_x64.exe" +#endif + pShared->nTickProgram.store(MP_TICK()); + pShared->nTickTrace.store(MP_TICK()); + HINSTANCE Instance = ShellExecuteA(NULL, "runas", CSWITCH_EXE, Filename, "", SW_SHOWMINNOACTIVE); + int64_t nInstance = (int64_t)Instance; + if(nInstance >= 32) + { + int64_t nPut, nGet; + while(!S.bContextSwitchStop) + { + nPut = pShared->nPut.load(std::memory_order_acquire); + nGet = pShared->nGet.load(std::memory_order_relaxed); + if(nPut == nGet) + { + Sleep(20); + } + else + { + for(int64_t i = nGet; i != nPut; i++) + { + MicroProfileContextSwitchPut(&pShared->Buffer[i % MicroProfileWin32ContextSwitchShared::BUFFER_SIZE]); + } + pShared->nGet.store(nPut, std::memory_order_release); + pShared->nTickProgram.store(MP_TICK()); + } + } + pShared->nQuit.store(1); + } + } + UnmapViewOfFile(pShared); + } + CloseHandle(hMemory); + } + S.bContextSwitchRunning = false; + MicroProfileOnThreadExit(); + return 0; +} + +MicroProfileThreadInfo MicroProfileGetThreadInfo(MicroProfileThreadIdType nThreadId) +{ + MicroProfileWin32UpdateThreadInfo(); + + for(uint32_t i = 0; i < g_ThreadInfo.nNumThreads; ++i) + { + if(g_ThreadInfo.T[i].tid == nThreadId) + { + return g_ThreadInfo.T[i]; + } + } + MicroProfileThreadInfo TI((uint32_t)nThreadId, 0, 0); + return TI; +} +uint32_t MicroProfileGetThreadInfoArray(MicroProfileThreadInfo** pThreadArray) +{ + MicroProfileWin32InitThreadInfo2(); + *pThreadArray = &g_ThreadInfo.T[0]; + return g_ThreadInfo.nNumThreads; +} + +#elif defined(__APPLE__) +#include +void* MicroProfileTraceThread(void* unused) +{ + FILE* pFile = fopen("mypipe", "r"); + if(!pFile) + { + uprintf("CONTEXT SWITCH FAILED TO OPEN FILE: make sure to run dtrace script\n"); + S.bContextSwitchRunning = false; + return 0; + } + uprintf("STARTING TRACE THREAD\n"); + char* pLine = 0; + size_t cap = 0; + size_t len = 0; + struct timeval tv; + + gettimeofday(&tv, NULL); + + uint64_t nsSinceEpoch = ((uint64_t)(tv.tv_sec) * 1000000 + (uint64_t)(tv.tv_usec)) * 1000; + uint64_t nTickEpoch = MP_TICK(); + uint32_t nLastThread[MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS] = { 0 }; + mach_timebase_info_data_t sTimebaseInfo; + mach_timebase_info(&sTimebaseInfo); + S.bContextSwitchRunning = true; + + uint64_t nProcessed = 0; + uint64_t nProcessedLast = 0; + while((len = getline(&pLine, &cap, pFile)) > 0 && !S.bContextSwitchStop) + { + nProcessed += len; + if(nProcessed - nProcessedLast > 10 << 10) + { + nProcessedLast = nProcessed; + uprintf("processed %llukb %llukb\n", (nProcessed - nProcessedLast) >> 10, nProcessed >> 10); + } + + char* pX = strchr(pLine, 'X'); + if(pX) + { + int cpu = atoi(pX + 1); + char* pX2 = strchr(pX + 1, 'X'); + char* pX3 = strchr(pX2 + 1, 'X'); + int thread = atoi(pX2 + 1); + char* lala; + int64_t timestamp = strtoll(pX3 + 1, &lala, 10); + MicroProfileContextSwitch Switch; + + // convert to ticks. + uint64_t nDeltaNsSinceEpoch = timestamp - nsSinceEpoch; + uint64_t nDeltaTickSinceEpoch = sTimebaseInfo.numer * nDeltaNsSinceEpoch / sTimebaseInfo.denom; + uint64_t nTicks = nDeltaTickSinceEpoch + nTickEpoch; + if(cpu < MICROPROFILE_MAX_CONTEXT_SWITCH_THREADS) + { + Switch.nThreadOut = nLastThread[cpu]; + Switch.nThreadIn = thread; + nLastThread[cpu] = thread; + Switch.nCpu = cpu; + Switch.nTicks = nTicks; + MicroProfileContextSwitchPut(&Switch); + } + } + } + uprintf("EXITING TRACE THREAD\n"); + S.bContextSwitchRunning = false; + return 0; +} + +MicroProfileThreadInfo MicroProfileGetThreadInfo(MicroProfileThreadIdType nThreadId) +{ + MicroProfileThreadInfo TI((uint32_t)nThreadId, 0, 0); + return TI; +} +uint32_t MicroProfileGetThreadInfoArray(MicroProfileThreadInfo** pThreadArray) +{ + *pThreadArray = 0; + return 0; +} + +#endif +#else + +MicroProfileThreadInfo MicroProfileGetThreadInfo(MicroProfileThreadIdType nThreadId) +{ + MicroProfileThreadInfo TI((uint32_t)nThreadId, 0, 0); + return TI; +} +uint32_t MicroProfileGetThreadInfoArray(MicroProfileThreadInfo** pThreadArray) +{ + *pThreadArray = 0; + return 0; +} +void MicroProfileStopContextSwitchTrace() +{ +} +void MicroProfileJoinContextSwitchTrace() +{ +} +void MicroProfileStartContextSwitchTrace() +{ +} + +#endif + +#if MICROPROFILE_GPU_TIMERS +void MicroProfileGpuShutdownPlatform() +{ + if(S.pGPU) + { + MicroProfileGpuShutdown(); + MP_FREE(S.pGPU); + S.pGPU = nullptr; + MicroProfileGpuInsertTimeStamp_Callback = nullptr; + MicroProfileGpuGetTimeStamp_Callback = nullptr; + MicroProfileTicksPerSecondGpu_Callback = nullptr; + MicroProfileGetGpuTickReference_Callback = nullptr; + MicroProfileGpuFlip_Callback = nullptr; + MicroProfileGpuShutdown_Callback = nullptr; + } +} + +void MicroProfileGpuInitPlatform(MicroProfileGpuTimerStateType eType, + MicroProfileGpuTimerState* pGPU, + MicroProfileGpuInsertTimeStamp_CB InsertTimeStamp, + MicroProfileGpuGetTimeStamp_CB GetTimeStamp, + MicroProfileTicksPerSecondGpu_CB TicksPerSecond, + MicroProfileGetGpuTickReference_CB GetTickReference, + MicroProfileGpuFlip_CB Flip, + MicroProfileGpuShutdown_CB Shutdown) +{ + + MP_ASSERT(S.pGPU == nullptr); + pGPU->Type = eType; + S.pGPU = pGPU; + + MicroProfileGpuInsertTimeStamp_Callback = InsertTimeStamp; + MicroProfileGpuGetTimeStamp_Callback = GetTimeStamp; + MicroProfileTicksPerSecondGpu_Callback = TicksPerSecond; + MicroProfileGetGpuTickReference_Callback = GetTickReference; + MicroProfileGpuFlip_Callback = Flip; + MicroProfileGpuShutdown_Callback = Shutdown; +} +#endif + +#if MICROPROFILE_GPU_TIMERS_D3D11 +//:'######:::'########::'##::::'##::::'########:::'#######::'########:::::'##::::::'##::: +//'##... ##:: ##.... ##: ##:::: ##:::: ##.... ##:'##.... ##: ##.... ##::'####::::'####::: +// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::: ##:..::::: ##: ##:::: ##::.. ##::::.. ##::: +// ##::'####: ########:: ##:::: ##:::: ##:::: ##::'#######:: ##:::: ##:::: ##:::::: ##::: +// ##::: ##:: ##.....::: ##:::: ##:::: ##:::: ##::...... ##: ##:::: ##:::: ##:::::: ##::: +// ##::: ##:: ##:::::::: ##:::: ##:::: ##:::: ##:'##:::: ##: ##:::: ##:::: ##:::::: ##::: +//. ######::: ##::::::::. #######::::: ########::. #######:: ########:::'######::'######: +//:......::::..::::::::::.......::::::........::::.......:::........::::......:::......:: +uint32_t MicroProfileGpuInsertTimeStampD3D11(void* pContext_) +{ + MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11(); + if(!pGPU) + return 0; + MicroProfileD3D11Frame& Frame = pGPU->m_QueryFrames[pGPU->m_nQueryFrame]; + uint32_t nStart = Frame.m_nQueryStart; + if(Frame.m_nRateQueryStarted) + { + uint32_t nIndex = (uint32_t)-1; + do + { + nIndex = Frame.m_nQueryCount.load(); + if(nIndex + 1 >= Frame.m_nQueryCountMax) + { + return (uint32_t)-1; + } + } while(!Frame.m_nQueryCount.compare_exchange_weak(nIndex, nIndex + 1)); + nIndex += nStart; + uint32_t nQueryIndex = nIndex % MICROPROFILE_D3D11_MAX_QUERIES; + + ID3D11Query* pQuery = (ID3D11Query*)pGPU->m_pQueries[nQueryIndex]; + ID3D11DeviceContext* pContext = (ID3D11DeviceContext*)pContext_; + pContext->End(pQuery); + return nQueryIndex; + } + return (uint32_t)-1; +} + +uint64_t MicroProfileGpuGetTimeStampD3D11(uint32_t nIndex) +{ + if(nIndex == (uint32_t)-1) + { + return (uint64_t)-1; + } + MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11(); + if(!pGPU) + return 0; + + int64_t nResult = pGPU->m_nQueryResults[nIndex]; + MP_ASSERT(nResult != -1); + return nResult; +} + +bool MicroProfileGpuGetDataD3D11(void* pQuery, void* pData, uint32_t nDataSize) +{ + MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11(); + if(!pGPU) + return false; + + HRESULT hr; + do + { + hr = ((ID3D11DeviceContext*)pGPU->m_pImmediateContext)->GetData((ID3D11Query*)pQuery, pData, nDataSize, 0); + } while(hr == S_FALSE); + switch(hr) + { + case DXGI_ERROR_DEVICE_REMOVED: + case DXGI_ERROR_INVALID_CALL: + case E_INVALIDARG: + MP_BREAK(); + return false; + } + return true; +} + +uint64_t MicroProfileTicksPerSecondGpuD3D11() +{ + MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11(); + if(!pGPU) + return 1; + + return pGPU->m_nQueryFrequency; +} + +uint32_t MicroProfileGpuFlipD3D11(void* pDeviceContext_) +{ + if(!pDeviceContext_) + { + return (uint32_t)-1; + } + MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11(); + if(!pGPU) + return 0; + + ID3D11DeviceContext* pDeviceContext = (ID3D11DeviceContext*)pDeviceContext_; + uint32_t nFrameTimeStamp = MicroProfileGpuInsertTimeStamp(pDeviceContext); + MicroProfileD3D11Frame& CurrentFrame = pGPU->m_QueryFrames[pGPU->m_nQueryFrame]; + ID3D11DeviceContext* pImmediateContext = (ID3D11DeviceContext*)pGPU->m_pImmediateContext; + if(CurrentFrame.m_nRateQueryStarted) + { + pImmediateContext->End((ID3D11Query*)CurrentFrame.m_pRateQuery); + } + uint32_t nNextFrame = (pGPU->m_nQueryFrame + 1) % MICROPROFILE_GPU_FRAME_DELAY; + pGPU->m_nQueryPut = (CurrentFrame.m_nQueryStart + CurrentFrame.m_nQueryCount) % MICROPROFILE_D3D11_MAX_QUERIES; + MicroProfileD3D11Frame& OldFrame = pGPU->m_QueryFrames[nNextFrame]; + if(OldFrame.m_nRateQueryStarted) + { + struct RateQueryResult + { + uint64_t nFrequency; + BOOL bDisjoint; + }; + RateQueryResult Result; + if(MicroProfileGpuGetDataD3D11(OldFrame.m_pRateQuery, &Result, sizeof(Result))) + { + if(pGPU->m_nQueryFrequency != (int64_t)Result.nFrequency) + { + if(pGPU->m_nQueryFrequency) + { + OutputDebugStringA("Query freq changing"); + } + pGPU->m_nQueryFrequency = Result.nFrequency; + } + uint32_t nStart = OldFrame.m_nQueryStart; + uint32_t nCount = OldFrame.m_nQueryCount; + for(uint32_t i = 0; i < nCount; ++i) + { + uint32_t nIndex = (i + nStart) % MICROPROFILE_D3D11_MAX_QUERIES; + + if(!MicroProfileGpuGetDataD3D11(pGPU->m_pQueries[nIndex], &pGPU->m_nQueryResults[nIndex], sizeof(uint64_t))) + { + pGPU->m_nQueryResults[nIndex] = -1; + } + } + } + else + { + uint32_t nStart = OldFrame.m_nQueryStart; + uint32_t nCount = OldFrame.m_nQueryCount; + + for(uint32_t i = 0; i < nCount; ++i) + { + uint32_t nIndex = (i + nStart) % MICROPROFILE_D3D11_MAX_QUERIES; + pGPU->m_nQueryResults[nIndex] = -1; + } + } + pGPU->m_nQueryGet = (OldFrame.m_nQueryStart + OldFrame.m_nQueryCount) % MICROPROFILE_D3D11_MAX_QUERIES; + } + + pGPU->m_nQueryFrame = nNextFrame; + MicroProfileD3D11Frame& NextFrame = pGPU->m_QueryFrames[nNextFrame]; + pImmediateContext->Begin((ID3D11Query*)NextFrame.m_pRateQuery); + NextFrame.m_nQueryStart = pGPU->m_nQueryPut; + NextFrame.m_nQueryCount = 0; + if(pGPU->m_nQueryPut >= pGPU->m_nQueryGet) + { + NextFrame.m_nQueryCountMax = (MICROPROFILE_D3D11_MAX_QUERIES - pGPU->m_nQueryPut) + pGPU->m_nQueryGet; + } + else + { + NextFrame.m_nQueryCountMax = pGPU->m_nQueryGet - pGPU->m_nQueryPut - 1; + } + if(NextFrame.m_nQueryCountMax) + NextFrame.m_nQueryCountMax -= 1; + NextFrame.m_nRateQueryStarted = 1; + return nFrameTimeStamp; +} + +void MicroProfileGpuInitD3D11(void* pDevice_, void* pImmediateContext) +{ + ID3D11Device* pDevice = (ID3D11Device*)pDevice_; + + MicroProfileGpuTimerStateD3D11* pGPU = MP_ALLOC_OBJECT(MicroProfileGpuTimerStateD3D11); + + MicroProfileGpuInitPlatform(MicroProfileGpuTimerStateType_D3D11, + pGPU, + MicroProfileGpuInsertTimeStampD3D11, + MicroProfileGpuGetTimeStampD3D11, + MicroProfileTicksPerSecondGpuD3D11, + MicroProfileGetGpuTickReferenceD3D11, + MicroProfileGpuFlipD3D11, + MicroProfileGpuShutdownD3D11); + + pGPU->m_pImmediateContext = pImmediateContext; + + D3D11_QUERY_DESC Desc; + Desc.MiscFlags = 0; + Desc.Query = D3D11_QUERY_TIMESTAMP; + for(uint32_t i = 0; i < MICROPROFILE_D3D11_MAX_QUERIES; ++i) + { + HRESULT hr = pDevice->CreateQuery(&Desc, (ID3D11Query**)&pGPU->m_pQueries[i]); + MP_ASSERT(hr == S_OK); + pGPU->m_nQueryResults[i] = -1; + } + HRESULT hr = pDevice->CreateQuery(&Desc, (ID3D11Query**)&pGPU->pSyncQuery); + MP_ASSERT(hr == S_OK); + + pGPU->m_nQueryPut = 0; + pGPU->m_nQueryGet = 0; + pGPU->m_nQueryFrame = 0; + pGPU->m_nQueryFrequency = 0; + Desc.Query = D3D11_QUERY_TIMESTAMP_DISJOINT; + for(uint32_t i = 0; i < MICROPROFILE_GPU_FRAME_DELAY; ++i) + { + pGPU->m_QueryFrames[i].m_nQueryStart = 0; + pGPU->m_QueryFrames[i].m_nQueryCount = 0; + pGPU->m_QueryFrames[i].m_nRateQueryStarted = 0; + hr = pDevice->CreateQuery(&Desc, (ID3D11Query**)&pGPU->m_QueryFrames[i].m_pRateQuery); + MP_ASSERT(hr == S_OK); + } +} + +void MicroProfileGpuShutdownD3D11() +{ + MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11(); + if(!pGPU) + return; + + for(uint32_t i = 0; i < MICROPROFILE_D3D11_MAX_QUERIES; ++i) + { + if(pGPU->m_pQueries[i]) + { + ID3D11Query* pQuery = (ID3D11Query*)pGPU->m_pQueries[i]; + pQuery->Release(); + pGPU->m_pQueries[i] = 0; + } + } + for(uint32_t i = 0; i < MICROPROFILE_GPU_FRAME_DELAY; ++i) + { + if(pGPU->m_QueryFrames[i].m_pRateQuery) + { + ID3D11Query* pQuery = (ID3D11Query*)pGPU->m_QueryFrames[i].m_pRateQuery; + pQuery->Release(); + pGPU->m_QueryFrames[i].m_pRateQuery = 0; + } + } + if(pGPU->pSyncQuery) + { + ID3D11Query* pSyncQuery = (ID3D11Query*)pGPU->pSyncQuery; + pSyncQuery->Release(); + pGPU->pSyncQuery = 0; + } +} + +int MicroProfileGetGpuTickReferenceD3D11(int64_t* pOutCPU, int64_t* pOutGpu) +{ + MicroProfileGpuTimerStateD3D11* pGPU = MicroProfileGetGpuTimerStateD3D11(); + if(!pGPU) + return 0; + { + MicroProfileD3D11Frame& Frame = pGPU->m_QueryFrames[pGPU->m_nQueryFrame]; + if(Frame.m_nRateQueryStarted) + { + ID3D11Query* pSyncQuery = (ID3D11Query*)pGPU->pSyncQuery; + ID3D11DeviceContext* pImmediateContext = (ID3D11DeviceContext*)pGPU->m_pImmediateContext; + pImmediateContext->End(pSyncQuery); + + HRESULT hr; + do + { + hr = pImmediateContext->GetData(pSyncQuery, pOutGpu, sizeof(*pOutGpu), 0); + } while(hr == S_FALSE); + *pOutCPU = MP_TICK(); + switch(hr) + { + case DXGI_ERROR_DEVICE_REMOVED: + case DXGI_ERROR_INVALID_CALL: + case E_INVALIDARG: + MP_BREAK(); + return false; + } + MP_ASSERT(hr == S_OK); + return 1; + } + } + return 0; +} +MicroProfileGpuTimerStateD3D11* MicroProfileGetGpuTimerStateD3D11() +{ + if(S.pGPU && S.pGPU->Type == MicroProfileGpuTimerStateType_D3D11) + return (MicroProfileGpuTimerStateD3D11*)S.pGPU; + return nullptr; +} + +#endif + +#if MICROPROFILE_GPU_TIMERS_D3D12 +//:'######:::'########::'##::::'##::::'########:::'#######::'########:::::'##::::'#######:: +//'##... ##:: ##.... ##: ##:::: ##:::: ##.... ##:'##.... ##: ##.... ##::'####:::'##.... ##: +// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::: ##:..::::: ##: ##:::: ##::.. ##:::..::::: ##: +// ##::'####: ########:: ##:::: ##:::: ##:::: ##::'#######:: ##:::: ##:::: ##::::'#######:: +// ##::: ##:: ##.....::: ##:::: ##:::: ##:::: ##::...... ##: ##:::: ##:::: ##:::'##:::::::: +// ##::: ##:: ##:::::::: ##:::: ##:::: ##:::: ##:'##:::: ##: ##:::: ##:::: ##::: ##:::::::: +//. ######::: ##::::::::. #######::::: ########::. #######:: ########:::'######: #########: +//:......::::..::::::::::.......::::::........::::.......:::........::::......::.........:: +#include +uint32_t MicroProfileGpuInsertTimeStampD3D12(void* pContext) +{ + MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12(); + if(!pGPU || !pContext) + return 0; + + ID3D12GraphicsCommandList* pCommandList = (ID3D12GraphicsCommandList*)pContext; + + bool IsCopy = D3D12_COMMAND_LIST_TYPE_COPY == pCommandList->GetType(); + uint32_t nNode = pGPU->nCurrentNode; + uint32_t nFrame = pGPU->nFrame; + + ID3D12QueryHeap* pHeap = IsCopy ? pGPU->NodeState[nNode].pCopyQueueHeap : pGPU->NodeState[nNode].pHeap; + + uint32_t nQueryIndex = IsCopy ? ((pGPU->nFrameCountCopyQueueTimeStamps.fetch_add(1) + pGPU->nFrameStartCopyQueueTimeStamps) % MICROPROFILE_D3D12_MAX_QUERIES) + : ((pGPU->nFrameCountTimeStamps.fetch_add(1) + pGPU->nFrameStartTimeStamps) % MICROPROFILE_D3D12_MAX_QUERIES); + + pCommandList->EndQuery(pHeap, D3D12_QUERY_TYPE_TIMESTAMP, nQueryIndex); + MP_ASSERT(nQueryIndex <= 0xffff); + uint32_t res = (IsCopy ? 0x80000000 : 0) | ((nFrame << 16) & 0x7fff0000) | (nQueryIndex); + return res; +} + +void MicroProfileGpuFetchRange(uint32_t nBegin, int32_t nCount, uint64_t nFrame, int64_t nTimestampOffset) +{ + MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12(); + if(!pGPU || nCount <= 0) + return; + void* pData = 0; + // uprintf("fetch [%d-%d]\n", nBegin, nBegin + nCount); + D3D12_RANGE Range = { sizeof(uint64_t) * nBegin, sizeof(uint64_t) * (nBegin + nCount) }; + pGPU->pBuffer->Map(0, &Range, &pData); + memcpy(&pGPU->nResults[nBegin], nBegin + (uint64_t*)pData, nCount * sizeof(uint64_t)); + for(int i = 0; i < nCount; ++i) + { + pGPU->nQueryFrames[i + nBegin] = nFrame; + pGPU->nResults[i + nBegin] -= nTimestampOffset; + } + pGPU->pBuffer->Unmap(0, 0); +} +void MicroProfileGpuFetchRangeCopy(uint32_t nBegin, int32_t nCount, uint64_t nFrame, int64_t nTimestampOffset) +{ + MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12(); + if(!pGPU || nCount <= 0) + return; + void* pData = 0; + D3D12_RANGE Range = { sizeof(uint64_t) * nBegin, sizeof(uint64_t) * (nBegin + nCount) }; + pGPU->pBufferCopy->Map(0, &Range, &pData); + memcpy(&pGPU->nResultsCopy[nBegin], nBegin + (uint64_t*)pData, nCount * sizeof(uint64_t)); + for(int i = 0; i < nCount; ++i) + { + pGPU->nQueryFramesCopy[i + nBegin] = nFrame; + pGPU->nResultsCopy[i + nBegin] -= nTimestampOffset; + } + pGPU->pBufferCopy->Unmap(0, 0); +} +void MicroProfileGpuWaitFenceD3D12(uint32_t nNode, uint64_t nFence) +{ + MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12(); + if(!pGPU) + return; + + auto GetFence = [&]() -> uint64_t + { + uint64_t f0 = pGPU->NodeState[nNode].pFence->GetCompletedValue(); + uint64_t f1 = pGPU->NodeState[nNode].pFenceCopy->GetCompletedValue(); + return MicroProfileMin(f0, f1); + }; + uint64_t nCompletedFrame = GetFence(); + // while(nCompletedFrame < nPending) + // while(0 < nPending - nCompletedFrame) + while(0 < (int64_t)(nFence - nCompletedFrame)) + { + MICROPROFILE_SCOPEI("Microprofile", "gpu-wait", MP_GREEN4); + Sleep(20); // todo: use event. + nCompletedFrame = GetFence(); + if((uint64_t)-1 == nCompletedFrame) // likely device removed. + return; + } +} + +void MicroProfileGpuFetchResultsD3D12(uint64_t nFrame) +{ + MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12(); + if(!pGPU) + return; + uint64_t nPending = pGPU->nPendingFrame; + + // while(nPending <= nFrame) + // while(0 <= nFrame - nPending) + while(0 <= (int64_t)(nFrame - nPending)) + { + uint32_t nInternal = nPending % MICROPROFILE_D3D_INTERNAL_DELAY; + uint32_t nNode = pGPU->Frames[nInternal].nNode; + MicroProfileGpuWaitFenceD3D12(nNode, nPending); + int64_t nTimestampOffset = 0; + if(nNode != 0) + { + // Adjust timestamp queries from GPU x to be in GPU 0's frame of reference + HRESULT hr; + int64_t nCPU0, nGPU0; + hr = pGPU->NodeState[0].pCommandQueue->GetClockCalibration((uint64_t*)&nGPU0, (uint64_t*)&nCPU0); + MP_ASSERT(hr == S_OK); + int64_t nCPUx, nGPUx; + hr = pGPU->NodeState[nNode].pCommandQueue->GetClockCalibration((uint64_t*)&nGPUx, (uint64_t*)&nCPUx); + MP_ASSERT(hr == S_OK); + int64_t nFreqCPU = MicroProfileTicksPerSecondCpu(); + int64_t nElapsedCPU = nCPUx - nCPU0; + int64_t nElapsedGPU = pGPU->nFrequency * nElapsedCPU / nFreqCPU; + nTimestampOffset = nGPUx - nGPU0 - nElapsedGPU; + } + + { + uint32_t nTimeStampBegin = pGPU->Frames[nInternal].nTimeStampBegin; + uint32_t nTimeStampCount = pGPU->Frames[nInternal].nTimeStampCount; + MicroProfileGpuFetchRange( + nTimeStampBegin, (nTimeStampBegin + nTimeStampCount) > MICROPROFILE_D3D12_MAX_QUERIES ? MICROPROFILE_D3D12_MAX_QUERIES - nTimeStampBegin : nTimeStampCount, nPending, nTimestampOffset); + MicroProfileGpuFetchRange(0, (nTimeStampBegin + nTimeStampCount) - MICROPROFILE_D3D12_MAX_QUERIES, nPending, nTimestampOffset); + } + { + uint32_t nTimeStampBegin = pGPU->Frames[nInternal].nTimeStampBeginCopyQueue; + uint32_t nTimeStampCount = pGPU->Frames[nInternal].nTimeStampCountCopyQueue; + MicroProfileGpuFetchRangeCopy( + nTimeStampBegin, (nTimeStampBegin + nTimeStampCount) > MICROPROFILE_D3D12_MAX_QUERIES ? MICROPROFILE_D3D12_MAX_QUERIES - nTimeStampBegin : nTimeStampCount, nPending, nTimestampOffset); + MicroProfileGpuFetchRangeCopy(0, (nTimeStampBegin + nTimeStampCount) - MICROPROFILE_D3D12_MAX_QUERIES, nPending, nTimestampOffset); + } + nPending = ++pGPU->nPendingFrame; + MP_ASSERT(pGPU->nFrame > nPending); + } +} + +uint64_t MicroProfileGpuGetTimeStampD3D12(uint32_t nIndex) +{ + MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12(); + if(!pGPU) + return 0; + + uint32_t nFrame = nIndex >> 16; + bool IsCopy = (nFrame & 0x8000) != 0; + nFrame &= 0x7fff; + uint32_t nQueryIndex = nIndex & 0xffff; + uint32_t lala = IsCopy ? pGPU->nQueryFramesCopy[nQueryIndex] : pGPU->nQueryFrames[nQueryIndex]; + // uprintf("read TS [%d <- %lld]\n", nQueryIndex, pGPU->nResults[nQueryIndex]); + MP_ASSERT(nIndex == 0 || (0x7fff & lala) == nFrame); + uint64_t r = IsCopy ? pGPU->nResultsCopy[nQueryIndex] : pGPU->nResults[nQueryIndex]; + if(r == 0x7fffffffffffffff) + { + MP_BREAK(); + } + return r; +} + +uint64_t MicroProfileTicksPerSecondGpuD3D12() +{ + MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12(); + if(!pGPU) + return 1; + return pGPU->nFrequency; +} + +uint32_t MicroProfileGpuFlipD3D12(void* pContext) +{ + MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12(); + if(!pGPU) + return 0; + uint32_t nNode = pGPU->nCurrentNode; + uint32_t nFrameIndex = pGPU->nFrame % MICROPROFILE_D3D_INTERNAL_DELAY; + uint32_t nCount = 0, nStart = 0; + uint32_t nCountCopyQueue = 0, nStartCopyQueue = 0; + + ID3D12CommandAllocator* pCommandAllocator = pGPU->Frames[nFrameIndex].pCommandAllocator; + ID3D12CommandAllocator* pCommandAllocatorCopy = pGPU->Frames[nFrameIndex].pCommandAllocatorCopy; + pCommandAllocator->Reset(); + pCommandAllocatorCopy->Reset(); + ID3D12GraphicsCommandList* pCommandList = pGPU->Frames[nFrameIndex].pCommandList[nNode]; + + pCommandList->Reset(pCommandAllocator, nullptr); + + ID3D12GraphicsCommandList* pCommandListCopy = nullptr; + + uint32_t nFrameTimeStamp = MicroProfileGpuInsertTimeStamp(pCommandList); + + { + nCount = pGPU->nFrameCountTimeStamps.exchange(0); + nStart = pGPU->nFrameStartTimeStamps; + pGPU->nFrameStartTimeStamps = (pGPU->nFrameStartTimeStamps + nCount) % MICROPROFILE_D3D12_MAX_QUERIES; + uint32_t nEnd = MicroProfileMin(nStart + nCount, (uint32_t)MICROPROFILE_D3D12_MAX_QUERIES); + MP_ASSERT(nStart != nEnd); + uint32_t nSize = nEnd - nStart; + pCommandList->ResolveQueryData(pGPU->NodeState[nNode].pHeap, D3D12_QUERY_TYPE_TIMESTAMP, nStart, nEnd - nStart, pGPU->pBuffer, nStart * sizeof(int64_t)); + if(nStart + nCount > MICROPROFILE_D3D12_MAX_QUERIES) + { + pCommandList->ResolveQueryData(pGPU->NodeState[nNode].pHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0, nEnd + nStart - MICROPROFILE_D3D12_MAX_QUERIES, pGPU->pBuffer, 0); + } + pCommandList->Close(); + } + + { + pCommandListCopy = pGPU->Frames[nFrameIndex].pCommandListCopy[nNode]; + pCommandListCopy->Reset(pCommandAllocatorCopy, nullptr); + + nCountCopyQueue = pGPU->nFrameCountCopyQueueTimeStamps.exchange(0); + nStartCopyQueue = pGPU->nFrameStartCopyQueueTimeStamps; + pGPU->nFrameStartCopyQueueTimeStamps = (nStartCopyQueue + nCountCopyQueue) % MICROPROFILE_D3D12_MAX_QUERIES; + uint32_t nEnd = MicroProfileMin(nStartCopyQueue + nCountCopyQueue, (uint32_t)MICROPROFILE_D3D12_MAX_QUERIES); + if(nStartCopyQueue != nEnd) + { + uint32_t nSize = nEnd - nStartCopyQueue; + pCommandListCopy->ResolveQueryData( + pGPU->NodeState[nNode].pCopyQueueHeap, D3D12_QUERY_TYPE_TIMESTAMP, nStartCopyQueue, nEnd - nStartCopyQueue, pGPU->pBufferCopy, nStartCopyQueue * sizeof(int64_t)); + if(nStartCopyQueue + nCountCopyQueue > MICROPROFILE_D3D12_MAX_QUERIES) + { + pCommandListCopy->ResolveQueryData(pGPU->NodeState[nNode].pCopyQueueHeap, D3D12_QUERY_TYPE_TIMESTAMP, 0, nEnd + nStartCopyQueue - MICROPROFILE_D3D12_MAX_QUERIES, pGPU->pBufferCopy, 0); + } + } + pCommandListCopy->Close(); + } + + if(pCommandList) + { + ID3D12CommandList* pList = pCommandList; + pGPU->NodeState[nNode].pCommandQueue->ExecuteCommandLists(1, &pList); + } + if(pCommandListCopy) + { + ID3D12CommandList* pList = pCommandListCopy; + pGPU->NodeState[nNode].pCommandQueueCopy->ExecuteCommandLists(1, &pList); + } + pGPU->NodeState[nNode].pCommandQueue->Signal(pGPU->NodeState[nNode].pFence, pGPU->nFrame); + pGPU->NodeState[nNode].pCommandQueueCopy->Signal(pGPU->NodeState[nNode].pFenceCopy, pGPU->nFrame); + pGPU->Frames[nFrameIndex].nTimeStampBegin = nStart; + pGPU->Frames[nFrameIndex].nTimeStampCount = nCount; + pGPU->Frames[nFrameIndex].nTimeStampBeginCopyQueue = nStartCopyQueue; + pGPU->Frames[nFrameIndex].nTimeStampCountCopyQueue = nCountCopyQueue; + + pGPU->Frames[nFrameIndex].nNode = nNode; + + pGPU->nFrame++; + // fetch from earlier frames + + MicroProfileGpuFetchResultsD3D12(pGPU->nFrame - MICROPROFILE_GPU_FRAME_DELAY); + return nFrameTimeStamp; +} + +void MicroProfileGpuInitD3D12(void* pDevice_, uint32_t nNodeCount, void** pCommandQueues_, void** pCommandQueuesCopy_) +{ + MicroProfileGpuTimerStateD3D12* pGPU = MP_ALLOC_OBJECT(MicroProfileGpuTimerStateD3D12); + memset(pGPU, 0, sizeof(MicroProfileGpuTimerStateD3D12)); + + MicroProfileGpuInitPlatform(MicroProfileGpuTimerStateType_D3D12, + pGPU, + MicroProfileGpuInsertTimeStampD3D12, + MicroProfileGpuGetTimeStampD3D12, + MicroProfileTicksPerSecondGpuD3D12, + MicroProfileGetGpuTickReferenceD3D12, + MicroProfileGpuFlipD3D12, + MicroProfileGpuShutdownD3D12); + + ID3D12Device* pDevice = (ID3D12Device*)pDevice_; + + pGPU->pDevice = pDevice; + pGPU->nNodeCount = nNodeCount; + MP_ASSERT(pGPU->nNodeCount <= MICROPROFILE_D3D_MAX_NODE_COUNT); + + for(uint32_t nNode = 0; nNode < pGPU->nNodeCount; ++nNode) + { + pGPU->NodeState[nNode].pCommandQueue = (ID3D12CommandQueue*)pCommandQueues_[nNode]; + pGPU->NodeState[nNode].pCommandQueueCopy = (ID3D12CommandQueue*)pCommandQueuesCopy_[nNode]; + if(nNode == 0) + { + pGPU->NodeState[nNode].pCommandQueue->GetTimestampFrequency((uint64_t*)&(pGPU->nFrequency)); + MP_ASSERT(pGPU->nFrequency); + } + else + { + // Don't support GPUs with different timer frequencies for now + int64_t nFrequency; + pGPU->NodeState[nNode].pCommandQueue->GetTimestampFrequency((uint64_t*)&nFrequency); + MP_ASSERT(nFrequency == pGPU->nFrequency); + } + + D3D12_QUERY_HEAP_DESC QHDesc; + QHDesc.Count = MICROPROFILE_D3D12_MAX_QUERIES; + QHDesc.Type = D3D12_QUERY_HEAP_TYPE_TIMESTAMP; + QHDesc.NodeMask = MP_NODE_MASK_ONE(nNode); + HRESULT hr = pDevice->CreateQueryHeap(&QHDesc, IID_PPV_ARGS(&pGPU->NodeState[nNode].pHeap)); + MP_ASSERT(hr == S_OK); + QHDesc.Type = D3D12_QUERY_HEAP_TYPE_COPY_QUEUE_TIMESTAMP; + hr = pDevice->CreateQueryHeap(&QHDesc, IID_PPV_ARGS(&pGPU->NodeState[nNode].pCopyQueueHeap)); + MP_ASSERT(hr == S_OK); + + pDevice->CreateFence(pGPU->nPendingFrame, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&pGPU->NodeState[nNode].pFence)); + pDevice->CreateFence(pGPU->nPendingFrame, D3D12_FENCE_FLAG_NONE, IID_PPV_ARGS(&pGPU->NodeState[nNode].pFenceCopy)); + } + + HRESULT hr; + D3D12_HEAP_PROPERTIES HeapProperties; + HeapProperties.CPUPageProperty = D3D12_CPU_PAGE_PROPERTY_UNKNOWN; + HeapProperties.MemoryPoolPreference = D3D12_MEMORY_POOL_UNKNOWN; + HeapProperties.CreationNodeMask = 0; + HeapProperties.VisibleNodeMask = MP_NODE_MASK_ALL(pGPU->nNodeCount); + HeapProperties.Type = D3D12_HEAP_TYPE_READBACK; + + const size_t nResourceSize = MICROPROFILE_D3D12_MAX_QUERIES * 8; + + D3D12_RESOURCE_DESC ResourceDesc; + ResourceDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + ResourceDesc.Alignment = 0; + ResourceDesc.Width = nResourceSize; + ResourceDesc.Height = 1; + ResourceDesc.DepthOrArraySize = 1; + ResourceDesc.MipLevels = 1; + ResourceDesc.Format = DXGI_FORMAT_UNKNOWN; + ResourceDesc.SampleDesc.Count = 1; + ResourceDesc.SampleDesc.Quality = 0; + ResourceDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + ResourceDesc.Flags = D3D12_RESOURCE_FLAG_NONE; + + hr = pDevice->CreateCommittedResource(&HeapProperties, D3D12_HEAP_FLAG_NONE, &ResourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pGPU->pBuffer)); + MP_ASSERT(hr == S_OK); + hr = pDevice->CreateCommittedResource(&HeapProperties, D3D12_HEAP_FLAG_NONE, &ResourceDesc, D3D12_RESOURCE_STATE_COPY_DEST, nullptr, IID_PPV_ARGS(&pGPU->pBufferCopy)); + MP_ASSERT(hr == S_OK); + + pGPU->nFrame = 0; + pGPU->nPendingFrame = 0; + + for(MicroProfileFrameD3D12& Frame : pGPU->Frames) + { + hr = pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_DIRECT, IID_PPV_ARGS(&Frame.pCommandAllocator)); + MP_ASSERT(hr == S_OK); + hr = pDevice->CreateCommandAllocator(D3D12_COMMAND_LIST_TYPE_COPY, IID_PPV_ARGS(&Frame.pCommandAllocatorCopy)); + MP_ASSERT(hr == S_OK); + for(uint32_t nNode = 0; nNode < pGPU->nNodeCount; ++nNode) + { + hr = pDevice->CreateCommandList(MP_NODE_MASK_ONE(nNode), D3D12_COMMAND_LIST_TYPE_DIRECT, Frame.pCommandAllocator, nullptr, IID_PPV_ARGS(&Frame.pCommandList[nNode])); + MP_ASSERT(hr == S_OK); + hr = Frame.pCommandList[nNode]->Close(); + MP_ASSERT(hr == S_OK); + hr = pDevice->CreateCommandList(MP_NODE_MASK_ONE(nNode), D3D12_COMMAND_LIST_TYPE_COPY, Frame.pCommandAllocatorCopy, nullptr, IID_PPV_ARGS(&Frame.pCommandListCopy[nNode])); + MP_ASSERT(hr == S_OK); + hr = Frame.pCommandListCopy[nNode]->Close(); + MP_ASSERT(hr == S_OK); + } + } +} + +void MicroProfileGpuShutdownD3D12() +{ + MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12(); + if(!pGPU) + return; + for(uint32_t nNode = 0; nNode < pGPU->nNodeCount; ++nNode) + { + MicroProfileGpuWaitFenceD3D12(nNode, pGPU->nFrame - 1); + } + for(uint32_t nNode = 0; nNode < pGPU->nNodeCount; ++nNode) + { + pGPU->NodeState[nNode].pHeap->Release(); + pGPU->NodeState[nNode].pCopyQueueHeap->Release(); + pGPU->NodeState[nNode].pFence->Release(); + pGPU->NodeState[nNode].pFenceCopy->Release(); + } + pGPU->pBuffer->Release(); + pGPU->pBufferCopy->Release(); + for(MicroProfileFrameD3D12& Frame : pGPU->Frames) + { + Frame.pCommandAllocator->Release(); + Frame.pCommandAllocatorCopy->Release(); + for(uint32_t nNode = 0; nNode < pGPU->nNodeCount; ++nNode) + { + Frame.pCommandList[nNode]->Release(); + Frame.pCommandListCopy[nNode]->Release(); + } + } +} +void MicroProfileSetCurrentNodeD3D12(uint32_t nNode) +{ + MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12(); + pGPU->nCurrentNode = nNode; +} + +int MicroProfileGetGpuTickReferenceD3D12(int64_t* pOutCPU, int64_t* pOutGpu) +{ + MicroProfileGpuTimerStateD3D12* pGPU = MicroProfileGetGpuTimerStateD3D12(); + if(!pGPU) + { + *pOutCPU = 1; + *pOutGpu = 1; + return 1; + } + + HRESULT hr = pGPU->NodeState[0].pCommandQueue->GetClockCalibration((uint64_t*)pOutGpu, (uint64_t*)pOutCPU); + MP_ASSERT(hr == S_OK); + return 1; +} + +MicroProfileGpuTimerStateD3D12* MicroProfileGetGpuTimerStateD3D12() +{ + if(S.pGPU && S.pGPU->Type == MicroProfileGpuTimerStateType_D3D12) + return (MicroProfileGpuTimerStateD3D12*)S.pGPU; + return nullptr; +} + +#endif + +#if MICROPROFILE_GPU_TIMERS_VULKAN + +//:'######:::'########::'##::::'##::::'##::::'##:'##::::'##:'##:::::::'##:::'##::::'###::::'##::: ##: +//'##... ##:: ##.... ##: ##:::: ##:::: ##:::: ##: ##:::: ##: ##::::::: ##::'##::::'## ##::: ###:: ##: +// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::: ##: ##:::: ##: ##::::::: ##:'##::::'##:. ##:: ####: ##: +// ##::'####: ########:: ##:::: ##:::: ##:::: ##: ##:::: ##: ##::::::: #####::::'##:::. ##: ## ## ##: +// ##::: ##:: ##.....::: ##:::: ##::::. ##:: ##:: ##:::: ##: ##::::::: ##. ##::: #########: ##. ####: +// ##::: ##:: ##:::::::: ##:::: ##:::::. ## ##::: ##:::: ##: ##::::::: ##:. ##:: ##.... ##: ##:. ###: +//. ######::: ##::::::::. #######:::::::. ###::::. #######:: ########: ##::. ##: ##:::: ##: ##::. ##: +//:......::::..::::::::::.......:::::::::...::::::.......:::........::..::::..::..:::::..::..::::..:: + +#ifndef MICROPROFILE_VULKAN_MAX_QUERIES +#define MICROPROFILE_VULKAN_MAX_QUERIES (32 << 10) +#endif + +#define MICROPROFILE_VULKAN_MAX_NODE_COUNT 4 +#define MICROPROFILE_VULKAN_INTERNAL_DELAY 8 + +#include +struct MicroProfileGpuFrameVulkan +{ + uint32_t nBegin; + uint32_t nCount; + uint32_t nNode; + VkCommandBuffer CommandBuffer[MICROPROFILE_VULKAN_MAX_NODE_COUNT]; + VkFence Fences[MICROPROFILE_VULKAN_MAX_NODE_COUNT]; +}; +struct MicroProfileGpuTimerStateVulkan : public MicroProfileGpuTimerState +{ + VkDevice Devices[MICROPROFILE_VULKAN_MAX_NODE_COUNT]; + VkPhysicalDevice PhysicalDevices[MICROPROFILE_VULKAN_MAX_NODE_COUNT]; + VkQueue Queues[MICROPROFILE_VULKAN_MAX_NODE_COUNT]; + VkQueryPool QueryPool[MICROPROFILE_VULKAN_MAX_NODE_COUNT]; + VkCommandPool CommandPool[MICROPROFILE_VULKAN_MAX_NODE_COUNT]; + + uint32_t nNodeCount; + uint32_t nCurrentNode; + uint64_t nFrame; + uint64_t nPendingFrame; + uint32_t nFrameStart; + std::atomic nFrameCount; + int64_t nFrequency; + + uint16_t nQueryFrames[MICROPROFILE_VULKAN_MAX_QUERIES]; + int64_t nResults[MICROPROFILE_VULKAN_MAX_QUERIES]; + + MicroProfileGpuFrameVulkan Frames[MICROPROFILE_VULKAN_INTERNAL_DELAY]; +}; + +MicroProfileGpuTimerStateVulkan* MicroProfileGetGpuTimerStateVulkan() +{ + if(S.pGPU && S.pGPU->Type == MicroProfileGpuTimerStateType_Vulkan) + return (MicroProfileGpuTimerStateVulkan*)S.pGPU; + return nullptr; +} + +uint32_t MicroProfileGpuInsertTimeStampVulkan(void* pContext) +{ + MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan(); + if(!pGPU) + return 0; + VkCommandBuffer CB = (VkCommandBuffer)pContext; + uint32_t nNode = pGPU->nCurrentNode; + uint32_t nFrame = pGPU->nFrame; + uint32_t nQueryIndex = (pGPU->nFrameCount.fetch_add(1) + pGPU->nFrameStart) % MICROPROFILE_VULKAN_MAX_QUERIES; + vkCmdWriteTimestamp(CB, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, pGPU->QueryPool[nNode], nQueryIndex); + MP_ASSERT(nQueryIndex <= 0xffff); + // uprintf("insert timestamp %d :: %d ... ctx %p\n", nQueryIndex, nFrame, pContext); + return ((nFrame << 16) & 0xffff0000) | (nQueryIndex); +} + +void MicroProfileGpuFetchRangeVulkan(VkCommandBuffer CommandBuffer, uint32_t nNode, uint32_t nBegin, int32_t nCount, uint64_t nFrame, int64_t nTimestampOffset) +{ + if(nCount <= 0) + return; + MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan(); + if(!pGPU) + return; + + vkGetQueryPoolResults(pGPU->Devices[nNode], pGPU->QueryPool[nNode], nBegin, nCount, 8 * nCount, &pGPU->nResults[nBegin], 8, VK_QUERY_RESULT_64_BIT | VK_QUERY_RESULT_PARTIAL_BIT); + vkCmdResetQueryPool(CommandBuffer, pGPU->QueryPool[nNode], nBegin, nCount); + for(int i = 0; i < nCount; ++i) + { + pGPU->nQueryFrames[i + nBegin] = nFrame; + } +} +void MicroProfileGpuWaitFenceVulkan(uint32_t nNode, uint64_t nFrame) +{ + MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan(); + if(!pGPU) + return; + + int r; + int c = 0; + do + { + MICROPROFILE_SCOPEI("Microprofile", "gpu-wait", MP_GREEN4); + r = vkWaitForFences(pGPU->Devices[nNode], 1, &pGPU->Frames[nFrame].Fences[nNode], 1, 1000 * 30); +#if 0 + if(c++ > 1000 && (c%100) == 0) + { + uprintf("waiting really long time for fence\n"); + OutputDebugString("waiting really long time for fence\n"); + } +#endif + } while(r != VK_SUCCESS); +} + +void MicroProfileGpuFetchResultsVulkan(VkCommandBuffer Buffer, uint64_t nFrame) +{ + MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan(); + if(!pGPU) + return; + + uint64_t nPending = pGPU->nPendingFrame; + // while(nPending <= nFrame) + // while(0 <= nFrame - nPending) + while(0 <= (int64_t)(nFrame - nPending)) + { + uint32_t nInternal = nPending % MICROPROFILE_VULKAN_INTERNAL_DELAY; + uint32_t nNode = pGPU->Frames[nInternal].nNode; + MicroProfileGpuWaitFenceVulkan(nNode, nInternal); + int64_t nTimestampOffset = 0; + + if(nNode != 0) + { + MP_ASSERT(0 && "NOT IMPLEMENTED"); + // note: timestamp adjustment not implemented. + } + + uint32_t nBegin = pGPU->Frames[nInternal].nBegin; + uint32_t nCount = pGPU->Frames[nInternal].nCount; + MicroProfileGpuFetchRangeVulkan(Buffer, nNode, nBegin, (nBegin + nCount) > MICROPROFILE_VULKAN_MAX_QUERIES ? MICROPROFILE_VULKAN_MAX_QUERIES - nBegin : nCount, nPending, nTimestampOffset); + MicroProfileGpuFetchRangeVulkan(Buffer, nNode, 0, (nBegin + nCount) - MICROPROFILE_VULKAN_MAX_QUERIES, nPending, nTimestampOffset); + + nPending = ++pGPU->nPendingFrame; + MP_ASSERT(pGPU->nFrame > nPending); + } +} + +uint64_t MicroProfileGpuGetTimeStampVulkan(uint32_t nIndex) +{ + if(nIndex == (uint32_t)-1) + { + return 0; + } + + MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan(); + if(!pGPU) + return 0; + + uint32_t nFrame = nIndex >> 16; + uint32_t nQueryIndex = nIndex & 0xffff; + uint32_t lala = pGPU->nQueryFrames[nQueryIndex]; + MP_ASSERT((0xffff & lala) == nFrame); + // uprintf("read TS [%d <- %lld]\n", nQueryIndex, pGPU->nResults[nQueryIndex]); + return pGPU->nResults[nQueryIndex]; +} + +uint64_t MicroProfileTicksPerSecondGpuVulkan() +{ + MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan(); + if(!pGPU) + return 1; + return pGPU->nFrequency; +} + +uint32_t MicroProfileGpuFlipVulkan(void* pContext) +{ + MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan(); + if(!pGPU) + return 0; + + uint32_t nNode = pGPU->nCurrentNode; + uint32_t nFrameIndex = pGPU->nFrame % MICROPROFILE_VULKAN_INTERNAL_DELAY; + uint32_t nCount = 0, nStart = 0; + + VkCommandBuffer CommandBuffer = pGPU->Frames[nFrameIndex].CommandBuffer[nNode]; + auto& F = pGPU->Frames[nFrameIndex]; + VkFence Fence = F.Fences[nNode]; + VkDevice Device = pGPU->Devices[nNode]; + VkQueue Queue = pGPU->Queues[nNode]; + + vkWaitForFences(Device, 1, &Fence, 1, (uint64_t)-1); + uint32_t nFrameTimeStamp = MicroProfileGpuInsertTimeStamp(pContext); + vkResetCommandBuffer(F.CommandBuffer[nNode], VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + + VkCommandBufferBeginInfo CBI; + CBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + CBI.pNext = 0; + CBI.pInheritanceInfo = 0; + CBI.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(F.CommandBuffer[nNode], &CBI); + vkResetFences(Device, 1, &Fence); + + nCount = pGPU->nFrameCount.exchange(0); + nStart = pGPU->nFrameStart; + pGPU->nFrameStart = (pGPU->nFrameStart + nCount) % MICROPROFILE_VULKAN_MAX_QUERIES; + uint32_t nEnd = MicroProfileMin(nStart + nCount, (uint32_t)MICROPROFILE_VULKAN_MAX_QUERIES); + MP_ASSERT(nStart != nEnd); + uint32_t nSize = nEnd - nStart; + + pGPU->Frames[nFrameIndex].nBegin = nStart; + pGPU->Frames[nFrameIndex].nCount = nCount; + pGPU->Frames[nFrameIndex].nNode = nNode; + pGPU->nFrame++; + ////fetch from earlier frames + MicroProfileGpuFetchResultsVulkan(CommandBuffer, pGPU->nFrame - MICROPROFILE_GPU_FRAME_DELAY); + + vkEndCommandBuffer(F.CommandBuffer[nNode]); + VkSubmitInfo SubmitInfo = {}; + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + SubmitInfo.pNext = nullptr; + SubmitInfo.waitSemaphoreCount = 0; + SubmitInfo.pWaitSemaphores = nullptr; + SubmitInfo.commandBufferCount = 1; + SubmitInfo.pCommandBuffers = &CommandBuffer; + SubmitInfo.signalSemaphoreCount = 0; + SubmitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(Queue, 1, &SubmitInfo, Fence); + return nFrameTimeStamp; +} + +void MicroProfileGpuInitVulkan(VkDevice* pDevices, VkPhysicalDevice* pPhysicalDevices, VkQueue* pQueues, uint32_t* QueueFamily, uint32_t nNodeCount) +{ + MicroProfileGpuTimerStateVulkan* pGPU = MP_ALLOC_OBJECT(MicroProfileGpuTimerStateVulkan); + memset(pGPU, 0, sizeof(MicroProfileGpuTimerStateVulkan)); + MicroProfileGpuInitPlatform(MicroProfileGpuTimerStateType_Vulkan, + pGPU, + MicroProfileGpuInsertTimeStampVulkan, + MicroProfileGpuGetTimeStampVulkan, + MicroProfileTicksPerSecondGpuVulkan, + MicroProfileGetGpuTickReferenceVulkan, + MicroProfileGpuFlipVulkan, + MicroProfileGpuShutdownVulkan); + + pGPU->nNodeCount = nNodeCount; + + VkQueryPoolCreateInfo Q; + Q.sType = VK_STRUCTURE_TYPE_QUERY_POOL_CREATE_INFO; + Q.pNext = 0; + Q.flags = 0; + Q.queryType = VK_QUERY_TYPE_TIMESTAMP; + Q.queryCount = MICROPROFILE_VULKAN_MAX_QUERIES + 1; + + VkCommandPoolCreateInfo CreateInfo; + CreateInfo.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; + CreateInfo.pNext = 0; + CreateInfo.flags = VK_COMMAND_POOL_CREATE_TRANSIENT_BIT | VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; + + VkResult r; + for(uint32_t i = 0; i < nNodeCount; ++i) + { + pGPU->Devices[i] = pDevices[i]; + pGPU->PhysicalDevices[i] = pPhysicalDevices[i]; + pGPU->Queues[i] = pQueues[i]; + r = vkCreateQueryPool(pGPU->Devices[i], &Q, 0, &pGPU->QueryPool[i]); + MP_ASSERT(r == VK_SUCCESS); + + CreateInfo.queueFamilyIndex = QueueFamily[i]; + r = vkCreateCommandPool(pGPU->Devices[i], &CreateInfo, 0, &pGPU->CommandPool[i]); + MP_ASSERT(r == VK_SUCCESS); + + for(uint32_t j = 0; j < MICROPROFILE_VULKAN_INTERNAL_DELAY; ++j) + { + auto& F = pGPU->Frames[j]; + VkCommandBufferAllocateInfo AllocInfo; + AllocInfo.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; + AllocInfo.pNext = 0; + AllocInfo.commandBufferCount = 1; + AllocInfo.commandPool = pGPU->CommandPool[i]; + AllocInfo.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY; + r = vkAllocateCommandBuffers(pGPU->Devices[i], &AllocInfo, &F.CommandBuffer[i]); + MP_ASSERT(r == VK_SUCCESS); + + VkFenceCreateInfo FCI; + FCI.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO; + FCI.pNext = 0; + FCI.flags = j == 0 ? 0 : VK_FENCE_CREATE_SIGNALED_BIT; + r = vkCreateFence(pGPU->Devices[i], &FCI, 0, &F.Fences[i]); + MP_ASSERT(r == VK_SUCCESS); + if(j == 0) + { + VkCommandBufferBeginInfo CBI; + CBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + CBI.pNext = 0; + CBI.pInheritanceInfo = 0; + CBI.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + vkBeginCommandBuffer(F.CommandBuffer[i], &CBI); + vkCmdResetQueryPool(F.CommandBuffer[i], pGPU->QueryPool[i], 0, MICROPROFILE_VULKAN_MAX_QUERIES + 1); + + vkEndCommandBuffer(F.CommandBuffer[i]); + VkSubmitInfo SubmitInfo = {}; + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + SubmitInfo.pNext = nullptr; + SubmitInfo.waitSemaphoreCount = 0; + SubmitInfo.pWaitSemaphores = nullptr; + SubmitInfo.commandBufferCount = 1; + SubmitInfo.pCommandBuffers = &F.CommandBuffer[i]; + SubmitInfo.signalSemaphoreCount = 0; + SubmitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(pQueues[i], 1, &SubmitInfo, F.Fences[i]); + vkWaitForFences(pGPU->Devices[i], 1, &F.Fences[i], 1, (uint64_t)-1); + vkResetCommandBuffer(F.CommandBuffer[i], VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + } + } + } + + VkPhysicalDeviceProperties Properties; + vkGetPhysicalDeviceProperties(pPhysicalDevices[0], &Properties); + pGPU->nFrequency = 1000000000ll / Properties.limits.timestampPeriod; +} + +void MicroProfileGpuShutdownVulkan() +{ + // this is clearly leaking .. +} +void MicroProfileSetCurrentNodeVulkan(uint32_t nNode) +{ + + MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan(); + if(!pGPU) + return; + pGPU->nCurrentNode = nNode; +} + +int MicroProfileGetGpuTickReferenceVulkan(int64_t* pOutCPU, int64_t* pOutGpu) +{ + MicroProfileGpuTimerStateVulkan* pGPU = MicroProfileGetGpuTimerStateVulkan(); + if(!pGPU) + return 0; + + auto& F = pGPU->Frames[pGPU->nFrame % MICROPROFILE_VULKAN_INTERNAL_DELAY]; + uint32_t nGpu = pGPU->nCurrentNode; + + VkCommandBufferBeginInfo CBI; + CBI.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + CBI.pNext = 0; + CBI.pInheritanceInfo = 0; + CBI.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + VkCommandBuffer CB = F.CommandBuffer[nGpu]; + VkDevice Device = pGPU->Devices[nGpu]; + VkFence Fence = F.Fences[nGpu]; + + vkWaitForFences(Device, 1, &Fence, 1, (uint64_t)-1); + vkResetFences(Device, 1, &Fence); + vkResetCommandBuffer(CB, VK_COMMAND_BUFFER_RESET_RELEASE_RESOURCES_BIT); + vkBeginCommandBuffer(CB, &CBI); + vkCmdResetQueryPool(CB, pGPU->QueryPool[nGpu], MICROPROFILE_VULKAN_MAX_QUERIES, 1); + vkCmdWriteTimestamp(CB, VK_PIPELINE_STAGE_ALL_GRAPHICS_BIT, pGPU->QueryPool[nGpu], MICROPROFILE_VULKAN_MAX_QUERIES); + vkEndCommandBuffer(CB); + VkSubmitInfo SubmitInfo = {}; + SubmitInfo.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + SubmitInfo.pNext = nullptr; + SubmitInfo.waitSemaphoreCount = 0; + SubmitInfo.pWaitSemaphores = nullptr; + SubmitInfo.commandBufferCount = 1; + SubmitInfo.pCommandBuffers = &CB; + SubmitInfo.signalSemaphoreCount = 0; + SubmitInfo.pSignalSemaphores = nullptr; + vkQueueSubmit(pGPU->Queues[nGpu], 1, &SubmitInfo, Fence); + vkWaitForFences(Device, 1, &Fence, 1, (uint64_t)-1); + *pOutGpu = 0; + vkGetQueryPoolResults(Device, pGPU->QueryPool[nGpu], MICROPROFILE_VULKAN_MAX_QUERIES, 1, 8, pOutGpu, 8, VK_QUERY_RESULT_64_BIT); + *pOutCPU = MP_TICK(); + return 1; +} +#endif + +#if MICROPROFILE_GPU_TIMERS_GL +//:'######:::'########::'##::::'##:::::'######:::'##::::::: +//'##... ##:: ##.... ##: ##:::: ##::::'##... ##:: ##::::::: +// ##:::..::: ##:::: ##: ##:::: ##:::: ##:::..::: ##::::::: +// ##::'####: ########:: ##:::: ##:::: ##::'####: ##::::::: +// ##::: ##:: ##.....::: ##:::: ##:::: ##::: ##:: ##::::::: +// ##::: ##:: ##:::::::: ##:::: ##:::: ##::: ##:: ##::::::: +//. ######::: ##::::::::. #######:::::. ######::: ########: +//:......::::..::::::::::.......:::::::......::::........:: + +void MicroProfileGpuInitGL() +{ + MicroProfileGpuTimerStateGL* pGPU = MP_ALLOC_OBJECT(MicroProfileGpuTimerStateGL); + memset(pGPU, 0, sizeof(MicroProfileGpuTimerStateGL)); + MicroProfileGpuInitPlatform(MicroProfileGpuTimerStateType_GL, + pGPU, + MicroProfileGpuInsertTimeStampGL, + MicroProfileGpuGetTimeStampGL, + MicroProfileTicksPerSecondGpuGL, + MicroProfileGetGpuTickReferenceGL, + MicroProfileGpuFlipGL, + MicroProfileGpuShutdownGL); + + pGPU->GLTimerPos = 0; + glGenQueries(MICROPROFILE_GL_MAX_QUERIES, &pGPU->GLTimers[0]); +} + +uint32_t MicroProfileGpuInsertTimeStampGL(void* pContext) +{ + MicroProfileGpuTimerStateGL* pGPU = MicroProfileGetGpuTimerStateGL(); + if(!pGPU) + return 0; + + uint32_t nIndex = (pGPU->GLTimerPos + 1) % MICROPROFILE_GL_MAX_QUERIES; + glQueryCounter(pGPU->GLTimers[nIndex], GL_TIMESTAMP); + pGPU->GLTimerPos = nIndex; + return nIndex; +} +uint64_t MicroProfileGpuGetTimeStampGL(uint32_t nKey) +{ + MicroProfileGpuTimerStateGL* pGPU = MicroProfileGetGpuTimerStateGL(); + if(!pGPU) + return 0; + + uint64_t result; + glGetQueryObjectui64v(pGPU->GLTimers[nKey], GL_QUERY_RESULT, &result); + return result; +} + +uint64_t MicroProfileTicksPerSecondGpuGL() +{ + return 1000000000ll; +} + +int MicroProfileGetGpuTickReferenceGL(int64_t* pOutCpu, int64_t* pOutGpu) +{ + MicroProfileGpuTimerStateGL* pGPU = MicroProfileGetGpuTimerStateGL(); + if(!pGPU) + return 0; + + int64_t nGpuTimeStamp; + glGetInteger64v(GL_TIMESTAMP, &nGpuTimeStamp); + if(nGpuTimeStamp) + { + *pOutCpu = MP_TICK(); + *pOutGpu = nGpuTimeStamp; +#if 0 // debug test if timestamp diverges + static int64_t nTicksPerSecondCpu = MicroProfileTicksPerSecondCpu(); + static int64_t nTicksPerSecondGpu = MicroProfileTicksPerSecondGpu(); + static int64_t nGpuStart = 0; + static int64_t nCpuStart = 0; + if(!nCpuStart) + { + nCpuStart = *pOutCpu; + nGpuStart = *pOutGpu; + } + static int nCountDown = 100; + if(0 == nCountDown--) + { + int64_t nCurCpu = *pOutCpu; + int64_t nCurGpu = *pOutGpu; + double fDistanceCpu = (nCurCpu - nCpuStart) / (double)nTicksPerSecondCpu; + double fDistanceGpu = (nCurGpu - nGpuStart) / (double)nTicksPerSecondGpu; + + char buf[254]; + snprintf(buf, sizeof(buf)-1,"Distance %f %f diff %f\n", fDistanceCpu, fDistanceGpu, fDistanceCpu-fDistanceGpu); + OutputDebugString(buf); + nCountDown = 100; + } +#endif + return 1; + } + return 0; +} +uint32_t MicroProfileGpuFlipGL(void* pContext) +{ + return MicroProfileGpuInsertTimeStampGL(pContext); +} + +void MicroProfileGpuShutdownGL() +{ + MicroProfileGpuTimerStateGL* pGPU = MicroProfileGetGpuTimerStateGL(); + if(!pGPU) + return; + + glDeleteQueries(MICROPROFILE_GL_MAX_QUERIES, &pGPU->GLTimers[0]); +} + +MicroProfileGpuTimerStateGL* MicroProfileGetGpuTimerStateGL() +{ + if(S.pGPU && S.pGPU->Type == MicroProfileGpuTimerStateType_GL) + return (MicroProfileGpuTimerStateGL*)S.pGPU; + return nullptr; +} +#endif + +uint32_t MicroProfileStringHash(const char* pString) // note matching: code in javascript: microprofilelive.html: function StringHash(s) +{ + uint32_t h = 0xfeedba3e; + char c; + while(0 != (c = *pString++)) + { + h = c + ((h << 5) - h); + } + return h; +} + +const char* MicroProfileStrDup(const char* pStr) +{ + size_t len = strlen(pStr) + 1; + char* pOut = (char*)MP_ALLOC(len, 8); + memcpy(pOut, pStr, len); + return pOut; +} + +uint32_t MicroProfileColorFromString(const char* pString) // note matching code/constants in javascript: microprofilelive.html: function StringToColor(s) +{ + // var h = StringHash(s); + // var cidx = h % 360; + // return "hsl(" + cidx + ",50%, 70%)"; //note: matching code constants in microprofile.cpp: MicroProfileColorFromString + + float h = MicroProfileStringHash(pString) % 360; + float s = 0.5f; + float l = 0.7f; + // from https://www.rapidtables.com/convert/color/hsl-to-rgb.html + float c = (1 - fabsf(2 * l - 1)) * s; + float x = c * (1 - fabsf(fmodf(h / 60, 2.f) - 1)); + float m = l - c / 2.f; + float r = 0.f, g = 0.f, b = 0.f; + if(h < 60) + { + r = c; + g = x; + } + else if(h < 120.f) + { + r = x; + g = c; + } + else if(h < 180.f) + { + g = c; + b = x; + } + else if(h < 240.f) + { + g = x; + b = c; + } + else if(h < 300.f) + { + r = x; + b = c; + } + else + { + r = c; + b = x; + } + r += m; + g += m; + b += m; + + r *= 255.f; + g *= 255.f; + b *= 255.f; + + uint32_t R = MicroProfileMin(0xffu, (uint32_t)r); + uint32_t G = MicroProfileMin(0xffu, (uint32_t)g); + uint32_t B = MicroProfileMin(0xffu, (uint32_t)b); + + return (R << 16) | (G << 8) | B; +} + +#if MICROPROFILE_DYNAMIC_INSTRUMENT +// '##::::'##::'#######:::'#######::'##:::'##:::::'######::'##::::'##::::'###::::'########::'########:'########:: +// ##:::: ##:'##.... ##:'##.... ##: ##::'##:::::'##... ##: ##:::: ##:::'## ##::: ##.... ##: ##.....:: ##.... ##: +// ##:::: ##: ##:::: ##: ##:::: ##: ##:'##:::::: ##:::..:: ##:::: ##::'##:. ##:: ##:::: ##: ##::::::: ##:::: ##: +// #########: ##:::: ##: ##:::: ##: #####:::::::. ######:: #########:'##:::. ##: ########:: ######::: ##:::: ##: +// ##.... ##: ##:::: ##: ##:::: ##: ##. ##:::::::..... ##: ##.... ##: #########: ##.. ##::: ##...:::: ##:::: ##: +// ##:::: ##: ##:::: ##: ##:::: ##: ##:. ##:::::'##::: ##: ##:::: ##: ##.... ##: ##::. ##:: ##::::::: ##:::: ##: +// ##:::: ##:. #######::. #######:: ##::. ##::::. ######:: ##:::: ##: ##:::: ##: ##:::. ##: ########: ########:: +// ..:::::..:::.......::::.......:::..::::..::::::......:::..:::::..::..:::::..::..:::::..::........::........::: + +#include +#include + +#if MICROPROFILE_BREAK_ON_PATCH_FAIL +#define BREAK_ON_PATCH_FAIL() MP_BREAK() +#else +#define BREAK_ON_PATCH_FAIL() \ + do \ + { \ + } while(0) +#endif + +void* MicroProfileX64FollowJump(void* pSrc); +bool MicroProfileCopyInstructionBytes(char* pDest, + void* pSrc, + const int nLimit, + const int nMaxSize, + char* pTrunk, + intptr_t nTrunkSize, + uint32_t nUsableJumpRegs, + int* nBytesDest, + int* nBytesSrc, + uint32_t* pRegsWritten, + uint32_t* nRetSafe); +bool MicroProfilePatchFunction(void* f, int Argument, MicroProfileHookFunc enter, MicroProfileHookFunc leave, MicroProfilePatchError* pError); +template +void MicroProfileIterateSymbols(Callback CB, uint32_t* nModules, uint32_t nNumModules); + +bool MicroProfileDemangleName(const char* pName, char* OutName, uint32_t Size); +bool MicroProfilePatchBeginSuspend(); +void MicroProfilePatchEndSuspend(); +bool MicroProfilePatchHasSuspendedThread(intptr_t Begin, intptr_t End); + +#if 1 +#define STRING_MATCH_SIZE 64 +typedef uint64_t uint_string_match; +#else +#define STRING_MATCH_SIZE 32 +typedef uint32_t uint_string_match; +#endif + +struct MicroProfileStringMatchMask +{ + uint_string_match nMask; + uint_string_match M[64]; +}; + +struct MicroProfileSymbolDesc +{ + const char* pName; + const char* pShortName; + intptr_t nAddress; + intptr_t nAddressEnd; + uint_string_match nMask; + int nIgnoreSymbol; + uint32_t nModule; +}; + +struct MicroProfileSymbolBlock +{ + MicroProfileSymbolBlock* pNext; + uint32_t nNumSymbols; + uint32_t nNumChars; + uint_string_match nMask; + MicroProfileStringMatchMask MatchMask; + enum + { + ESIZE = 4 << 10, + }; + union + { + MicroProfileSymbolDesc Symbols[ESIZE / sizeof(MicroProfileSymbolDesc)]; + char Chars[ESIZE]; + }; +}; + +typedef void (*MicroProfileOnSymbolCallback)(const char* pSymbolName, intptr_t nAddress); + +MP_THREAD_LOCAL uintptr_t g_MicroProfile_TLS[17] = { 16 }; + +extern "C" MP_NOINLINE uintptr_t MicroProfile_Patch_TLS_PUSH(uintptr_t t) +{ + uintptr_t* pTLS = &g_MicroProfile_TLS[0]; + + uintptr_t Limit = (uint32_t)pTLS[0]; + uintptr_t Pos = (uint32_t)(pTLS[0] >> 32); + if(Pos == Limit) + { + return 0; + } + else + { + pTLS[0] = (Limit) | ((Pos + 1) << 32); + } + pTLS[Pos + 1] = t; + return 1; +} +extern "C" MP_NOINLINE uintptr_t MicroProfile_Patch_TLS_POP() +{ + uintptr_t* pTLS = &g_MicroProfile_TLS[0]; + uintptr_t Limit = (uint32_t)pTLS[0]; + uintptr_t Pos = (uint32_t)(pTLS[0] >> 32); + if(Pos == 0) + { + MP_BREAK(); // this should never happen + return 0; + } + else + { + pTLS[0] = (Limit) | ((Pos - 1) << 32); + } + uintptr_t t = pTLS[Pos]; + return t; +} + +char* MicroProfileInsertRegisterJump(char* pCode, intptr_t pDest, int reg) +{ + MP_ASSERT(reg >= R_RAX && reg <= R_R15); + int large = reg >= R_R8 ? 1 : 0; + int offset = large ? (reg - R_R8) : (reg - R_RAX); + unsigned char* uc = (unsigned char*)pCode; + *uc++ = large ? 0x49 : 0x48; + *uc++ = 0xb8 + offset; + memcpy(uc, &pDest, 8); + uc += 8; + if(large) + *uc++ = 0x41; + *uc++ = 0xff; + *uc++ = 0xe0 + offset; + return (char*)uc; + // 164: 48 b8 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rax + // 16e: 48 b9 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rcx + // 178: 48 ba 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rdx + // 182: 48 bb 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rbx + // 18c: 48 bc 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rsp + // 196: 48 bd 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rbp + // 1a0: 48 be 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rsi + // 1aa: 48 bf 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %rdi + // 1b4: 49 b8 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r8 + // 1be: 49 b9 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r9 + // 1c8: 49 ba 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r10 + // 1d2: 49 bb 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r11 + // 1dc: 49 bc 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r12 + // 1e6: 49 bd 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r13 + // 1f0: 49 be 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r14 + // 1fa: 49 bf 08 07 06 05 04 03 02 01 movabsq $72623859790382856, %r15 + // 204: ff e0 jmpq *%rax + // 206: ff e1 jmpq *%rcx + // 208: ff e2 jmpq *%rdx + // 20a: ff e3 jmpq *%rbx + // 20c: ff e4 jmpq *%rsp + // 20e: ff e5 jmpq *%rbp + // 210: ff e6 jmpq *%rsi + // 212: ff e7 jmpq *%rdi + // 214: 41 ff e0 jmpq *%r8 + // 217: 41 ff e1 jmpq *%r9 + // 21a: 41 ff e2 jmpq *%r10 + // 21d: 41 ff e3 jmpq *%r11 + // 220: 41 ff e4 jmpq *%r12 + // 223: 41 ff e5 jmpq *%r13 + // 226: 41 ff e6 jmpq *%r14 + // 229: 41 ff e7 jmpq *%r15 +} + +char* MicroProfileInsertRelativeJump(char* pCode, intptr_t pDest) +{ + intptr_t src = intptr_t(pCode) + 5; + intptr_t off = pDest - src; + MP_ASSERT(off > intptr_t(0xffffffff80000000) && off <= 0x7fffffff); + int32_t i32off = (int32_t)off; + unsigned char* uc = (unsigned char*)pCode; + unsigned char* c = (unsigned char*)&i32off; + *uc++ = 0xe9; + memcpy(uc, c, 4); + uc += 4; + return (char*)uc; +} + +char* MicroProfileInsertRetJump(char* pCode, intptr_t pDest) +{ + uint32_t lower = (uint32_t)pDest; + uint32_t upper = (uint32_t)(pDest >> 32); + unsigned char* uc = (unsigned char*)pCode; + *uc++ = 0x68; + memcpy(uc, &lower, 4); + uc += 4; + *uc++ = 0xc7; + *uc++ = 0x44; + *uc++ = 0x24; + *uc++ = 0x04; + memcpy(uc, &upper, 4); + uc += 4; + *uc++ = 0xc3; + return (char*)uc; +} + +uint8_t* MicroProfileInsertMov(uint8_t* p, uint8_t* pend, int r, intptr_t value) +{ + int Large = r >= R_R8 ? 1 : 0; + int RegIndex = Large ? (r - R_R8) : (r - R_RAX); + *p++ = Large ? 0x49 : 0x48; + *p++ = 0xb8 + RegIndex; // + (reg - (large?(R_R8-R_RAX):0)); + intptr_t* pAddress = (intptr_t*)p; + pAddress[0] = value; + p = (uint8_t*)(pAddress + 1); + MP_ASSERT(p < pend); + return p; +} + +uint8_t* MicroProfileInsertCall(uint8_t* p, uint8_t* pend, int r) +{ + int Large = r >= R_R8 ? 1 : 0; + int RegIndex = Large ? (r - R_R8) : (r - R_RAX); + if(Large) + { + *p++ = 0x41; + } + *p++ = 0xff; + *p++ = 0xd0 + RegIndex; + MP_ASSERT(p < pend); + return p; +} + +bool MicroProfileStringMatch(const char* pSymbol, uint32_t nStartOffset, const char** pPatterns, uint32_t* nPatternLength, uint32_t nNumPatterns) +{ + MP_ASSERT(nStartOffset <= nNumPatterns); + const char* p = pSymbol; + for(uint32_t i = nStartOffset; i < nNumPatterns; ++i) + { + p = MP_STRCASESTR(p, pPatterns[i]); + if(p) + { + p += nPatternLength[i]; + } + else + { + return false; + } + } + return true; +} + +int MicroProfileStringMatchOffset(const char* pSymbol, const char** pPatterns, uint32_t* nPatternLength, uint32_t nNumPatterns) +{ + int nOffset = 0; + const char* p = pSymbol; + for(uint32_t i = 0; i < nNumPatterns; ++i) + { + p = MP_STRCASESTR(p, pPatterns[i]); + if(p) + { + p += nPatternLength[i]; + nOffset++; + } + else + { + break; + } + } + return nOffset; +} + +void* MicroProfileX64FollowJump(void* pSrc) +{ + for(uint32_t i = 0; i < S.DynamicTokenIndex; ++i) + if(S.FunctionsInstrumented[i] == pSrc) + return pSrc; // if already instrumented, do not follow the jump inserted by itself. + + // uprintf("deref possible trampoline for %p\n", pSrc); + _DecodeType dt = Decode64Bits; + _DInst Instructions[1]; + unsigned int nCount = 0; + + _CodeInfo ci; + ci.code = (uint8_t*)pSrc; + ci.codeLen = 15; + ci.codeOffset = 0; + ci.dt = dt; + ci.features = DF_NONE; + int r = distorm_decompose(&ci, Instructions, 1, &nCount); + if(!r || nCount != 1) + { + return pSrc; // fail, just return + } + + auto& I = Instructions[0]; + if(I.opcode == I_JMP) + { + if(I.ops[0].type == O_PC) + { + if(I.ops[0].size == 0x20) + { + intptr_t p = (intptr_t)pSrc; + p += I.size; + p += I.imm.sdword; + return (void*)p; + } + } + else if(I.ops[0].type == O_SMEM) + { + if(I.ops[0].index == R_RIP) + { + intptr_t p = (intptr_t)pSrc; + p += I.size; + p += I.disp; + void* pHest = *(void**)p; + return pHest; + } + } + uprintf("failed to interpret I_JMP %p %d %d\n", pSrc, I.ops[0].size, I.ops[0].type); + return pSrc; + MP_BREAK(); + } + return pSrc; +} + +bool MicroProfileCopyInstructionBytes(char* pDest, + void* pSrc, + const int nLimit, + const int nMaxSize, + char* pTrunk, + intptr_t nTrunkSize, + const uint32_t nUsableJumpRegs, + int* pBytesDest, + int* pBytesSrc, + uint32_t* pRegsWritten, + uint32_t* pRetSafe) +{ + + _DecodeType dt = Decode64Bits; + _DInst Instructions[128]; + int rip[128] = { 0 }; + uint32_t nRegsWrittenInstr[128] = { 0 }; + int offsets[129] = { 0 }; + unsigned int nCount = 0; + + _CodeInfo ci; + ci.code = (uint8_t*)pSrc; + ci.codeLen = nLimit + 15; + ci.codeOffset = 0; + ci.dt = dt; + ci.features = DF_NONE; + int r = distorm_decompose(&ci, Instructions, 128, &nCount); + if(r != DECRES_SUCCESS) + { + BREAK_ON_PATCH_FAIL(); + return false; + } + int offset = 0; + unsigned int i = 0; + unsigned nInstructions = 0; + int64_t nTrunkUsage = 0; + offsets[0] = 0; + uint32_t nRegsWritten = 0; + + auto Align16 = [](intptr_t p) { return (p + 15) & (~15); }; + + { + + intptr_t iTrunk = (intptr_t)pTrunk; + intptr_t iTrunkEnd = iTrunk + nTrunkSize; + intptr_t iTrunkAligned = (iTrunk + 15) & ~15; + nTrunkSize = iTrunkEnd - iTrunkAligned; + pTrunk = (char*)iTrunkAligned; + } + const uint8_t* pTrunkEnd = (uint8_t*)(pTrunk + nTrunkSize); + + auto RegToBit = [](int r) -> uint32_t + { + if(r >= R_RAX && r <= R_R15) + { + return (1u << (r - R_RAX)); + } + else if(r >= R_EAX && r <= R_R15D) + { + return (1u << (r - R_EAX)); + } + else if(r >= R_AX && r <= R_R15W) + { + return (1u << (r - R_AX)); + } + else if(r >= R_AL && r <= R_R15B) + { + return (1u << (r - R_AL)); + } + return 0; // might hit on registers like RIP + MP_BREAK(); + }; +#ifdef _WIN32 + const uint32_t nUsableRegisters = RegToBit(R_RAX) | RegToBit(R_R10) | RegToBit(R_R11); +#else + const uint32_t nUsableRegisters = RegToBit(R_RAX) | RegToBit(R_R10) | RegToBit(R_R11); +#endif + + int nBytesToMove = 0; + for(i = 0; i < nCount; ++i) + { + nBytesToMove += Instructions[i].size; + if(nBytesToMove >= nLimit) + break; + } + *pBytesSrc = nBytesToMove; + + uint32_t nRspMask = RegToBit(R_RSP); + *pRetSafe = 1; + + for(i = 0; i < nCount; ++i) + { + rip[i] = 0; + auto& I = Instructions[i]; + // bool bHasRipReference = false; + if(I.opcode == I_LEA) + { + } + if(I.opcode == I_CALL) + { + auto& O = I.ops[0]; + if(O.type != O_PC || O.size != 0x20) + { + uprintf("unknown call encountered. cannot move\n"); + BREAK_ON_PATCH_FAIL(); + return false; + } + if((nRegsWritten & nUsableRegisters) == nUsableRegisters) + { + uprintf("call encountered, but register all regs was written to. TODO: push regs?\n"); + BREAK_ON_PATCH_FAIL(); + return false; + } + // return value might be used past return so preserve registers. +#ifdef _WIN32 + nRegsWritten |= RegToBit(R_RAX); +#else + nRegsWritten |= RegToBit(R_RAX) | RegToBit(R_RDX); +#endif + } + + switch(I.ops[0].type) + { + case O_REG: + { + uint32_t reg = I.ops[0].index; + nRegsWritten |= RegToBit(reg); + auto& O2 = I.ops[1]; + switch(O2.type) + { + case O_REG: + case O_MEM: + case O_SMEM: + { + // if register is RSP 'contaminated', it prevents us from using that to do retjmps + uint32_t nMask = RegToBit(O2.index); + if(nRspMask & nMask) + { + nRspMask |= RegToBit(reg); + } + } + default: + break; + } + break; + } + case O_MEM: + case O_SMEM: + { + uint32_t reg = I.ops[0].index; + if(nRspMask & RegToBit(reg)) + { + uprintf("found contaminated reg at +%lld\n", (long long)I.addr); + *pRetSafe = 0; + } + break; + } + } + nRegsWrittenInstr[i] = nRegsWritten; + for(int j = 0; j < 4; ++j) + { + auto& O = I.ops[j]; + + switch(O.type) + { + case O_REG: + case O_SMEM: + case O_MEM: + { + if(O.index == R_RIP) + { + if(j != 1) + { + uprintf("found non base reference of rip. fail\n"); + BREAK_ON_PATCH_FAIL(); + return false; + } + if(I.dispSize != 0x20 && I.dispSize != 0x10) + { + uprintf("found offset size != 32 && != 16 bit. not implemented\n"); + BREAK_ON_PATCH_FAIL(); + return false; + } + rip[i] = 1; + nTrunkUsage += Align16(O.size / 8); + if(nTrunkUsage > nTrunkSize) + { + uprintf("overuse of trunk %lld\n", (long long)nTrunkUsage); + BREAK_ON_PATCH_FAIL(); + return false; + } + } + break; + } + } + } + if(rip[i]) + { + if(I.ops[0].type != O_REG) + { + uprintf("arg 0 should be O_REG, fail\n"); + BREAK_ON_PATCH_FAIL(); + return false; + } + if(I.ops[1].type != O_SMEM) + { + uprintf("arg 1 should be O_SMEM, fail was %d\n", O_SMEM); + BREAK_ON_PATCH_FAIL(); + return false; + } + } + int fc = META_GET_FC(Instructions[i].meta); + switch(fc) + { + case FC_CALL: + { + break; + } + case FC_RET: + case FC_SYS: + case FC_UNC_BRANCH: + case FC_CND_BRANCH: + uprintf("found branch inst %d :: %d\n", fc, offset); + BREAK_ON_PATCH_FAIL(); + return false; + } + offset += Instructions[i].size; + offsets[i + 1] = offset; + if(offset >= nLimit) + { + nInstructions = i + 1; + break; + } + } + if(nTrunkUsage > nTrunkSize) + { + uprintf("function using too much trunk space\n"); + BREAK_ON_PATCH_FAIL(); + return false; + } + if(offset < nLimit) + { + uprintf("function only had %d bytes of %d\n", offset, nLimit); + BREAK_ON_PATCH_FAIL(); + return false; + } + + if(0 == *pRetSafe && 0 == (nUsableJumpRegs & ~nRegsWritten)) + { + // if ret jump is unsafe all of the usable jump regs are taken, fail. + uprintf("cannot patch function without breaking code]\n"); + BREAK_ON_PATCH_FAIL(); + MP_BREAK(); + return false; + } + + // MP_BREAK(); + *pRegsWritten = nRegsWritten; + uint8_t* d = (uint8_t*)pDest; + uint8_t* dend = d + nMaxSize; + const uint8_t* s = (const uint8_t*)pSrc; + + nTrunkUsage = 0; + + for(i = 0; i < nInstructions; ++i) + { + auto& I = Instructions[i]; + unsigned size = Instructions[i].size; + if(I.opcode == I_CALL) + { + // find reg + uint32_t nRegsWritten = nRegsWrittenInstr[i]; + uint32_t nUsable = nUsableRegisters & ~nRegsWritten; + MP_ASSERT(nUsable); + int r = R_RAX; + while(0 == (1 & nUsable)) + { + nUsable >>= 1; + r++; + } + + intptr_t p = offsets[i + 1]; + p += (intptr_t)pSrc; + p += I.imm.sdword; + d = MicroProfileInsertMov(d, dend, r, p); + d = MicroProfileInsertCall(d, dend, r); + s += size; + } + else if(rip[i]) + { + if(I.opcode == I_LEA) + { + if(I.ops[0].type != O_REG) + { + MP_BREAK(); + } + if(I.ops[1].index != R_RIP) + { + MP_BREAK(); + } + int reg = I.ops[0].index - R_RAX; + int large = I.ops[0].index >= R_R8 ? 1 : 0; + *d++ = large ? 0x49 : 0x48; + *d++ = 0xb8 + (reg - (large ? (R_R8 - R_RAX) : 0)); + // calculate the offset + int64_t offset = offsets[i + 1] + I.disp; + intptr_t base = (intptr_t)pSrc; + + intptr_t sum = base + offset; + intptr_t* pAddress = (intptr_t*)d; + pAddress[0] = sum; + s += size; + d += 10; + d = (uint8_t*)(pAddress + 1); + } + else + { + if(15 & (intptr_t)pTrunk) + { + MP_BREAK(); + } + intptr_t t = (intptr_t)pTrunk; + t = (t + 15) & ~15; + pTrunk = (char*)t; + auto& O = I.ops[1]; + uint32_t Op1Size = O.size / 8; + + memcpy(d, s, size); + int32_t DispOriginal = (int32_t)I.disp; + const uint8_t* pOriginal = (s + size) + DispOriginal; + + intptr_t DispNew = ((uint8_t*)pTrunk - (d + size)); + if(!((intptr_t)pTrunk + Op1Size <= (intptr_t)pTrunkEnd)) + { + MP_BREAK(); + } + memcpy(pTrunk, pOriginal, Op1Size); + pTrunk += Align16(Op1Size); + if(I.dispSize == 32) + { + int32_t off = (int32_t)DispNew; + if(DispNew > 0x7fffffff || DispNew < 0) + { + MP_BREAK(); + } + memcpy(d + size - 4, &off, 4); + } + else if(I.dispSize == 16) + { + int16_t off = (int16_t)DispNew; + if(DispNew > 0x7fff || DispNew < 0) + { + MP_BREAK(); + } + memcpy(d + size - 2, &off, 2); + } + + d += size; + s += size; + } + } + else + { + memcpy(d, s, size); + d += size; + s += size; + } + } + + *pBytesDest = (int)(d - (uint8_t*)pDest); + + return true; +} + +extern "C" void MicroProfileInterceptEnter(int a) +{ + MicroProfileToken T = S.DynamicTokens[a]; + MicroProfileThreadLog* pLog = MicroProfileGetThreadLog2(); + MP_ASSERT(pLog->nStackScope < MICROPROFILE_STACK_MAX); // if youre hitting this assert your instrumenting a deeply nested function + MicroProfileScopeStateC* pScopeState = &pLog->ScopeState[pLog->nStackScope++]; + pScopeState->Token = T; + if(T) + { + pScopeState->nTick = MicroProfileEnterInternal(T); + } + else + { + pScopeState->nTick = MICROPROFILE_INVALID_TICK; + } +} +extern "C" void MicroProfileInterceptLeave(int a) +{ + MicroProfileThreadLog* pLog = MicroProfileGetThreadLog2(); + MP_ASSERT(pLog->nStackScope > 0); // if youre hitting this assert you probably have mismatched _ENTER/_LEAVE markers + MicroProfileScopeStateC* pScopeState = &pLog->ScopeState[--pLog->nStackScope]; + MicroProfileLeaveInternal(pScopeState->Token, pScopeState->nTick); +} + +bool MicroProfileInstrumentFromAddressOnly(void* pFunction) +{ + MicroProfileSymbolDesc* pDesc = MicroProfileSymbolFindFuction(pFunction); + if(pDesc) + { + uprintf("Found function %p :: %s %s\n", (void*)pDesc->nAddress, pDesc->pName, pDesc->pShortName); + uint32_t nColor = MicroProfileColorFromString(pDesc->pName); + + return MicroProfileInstrumentFunction(pFunction, MicroProfileSymbolModuleGetString(pDesc->nModule), pDesc->pName, nColor); + } + else + { + uprintf("No Function Found %p\n", pFunction); + return false; + } +} + +template +void MicroProfileInstrumentScanForFunctionCalls(CB Callback, void* pFunction, size_t nFunctionSize) +{ + pFunction = MicroProfileX64FollowJump(pFunction); + const intptr_t nCodeLen = nFunctionSize; + const uint32_t nMaxInstructions = 15; + intptr_t nOffset = 0; + _DecodeType dt = Decode64Bits; + _DInst Instructions[15]; + _CodeInfo ci; + do + { + ci.code = nOffset + (uint8_t*)pFunction; + ci.codeLen = nCodeLen - nOffset; + ci.codeOffset = 0; + ci.dt = dt; + ci.features = DF_RETURN_FC_ONLY; + uint32_t nCount = 0; + uint32_t nOffsetNext = 0; + + int r = distorm_decompose(&ci, Instructions, nMaxInstructions, &nCount); + // uprintf("decomposed %d\n", nCount); + if(r != DECRES_SUCCESS && r != DECRES_MEMORYERR) + { + BREAK_ON_PATCH_FAIL(); + return; + } + if(nCount == 0) + { + // no instructions left + break; + } + // uprintf("instructions decoded %d %p ::\n", nCount, pFunction); + for(int i = 0; i < (int)nCount; ++i) + { + // rip[i] = 0; + auto& I = Instructions[i]; + // bool bHasRipReference = false; + if(I.addr < nOffsetNext) + { + MP_BREAK(); + } + nOffsetNext = I.addr + I.size; + if(I.opcode == I_CALL) + { + auto& O = I.ops[0]; + if(O.type != O_PC || O.size != 0x20) + { + uprintf("non immediate call encountered. cannot follow\n"); + BREAK_ON_PATCH_FAIL(); + continue; + } + intptr_t pDst = nOffset + (intptr_t)pFunction; + pDst += I.addr; + pDst += I.size; + pDst += I.imm.sdword; + + void* fFun1 = MicroProfileX64FollowJump((void*)pDst); + Callback(fFun1); + } + } + nOffset += nOffsetNext; + } while(nOffset < nCodeLen); +} + +void MicroProfileInstrumentFunctionsCalled(void* pFunction, const char* pModuleName, const char* pFunctionName, int nMinBytes, int nMaxCalls) +{ + pFunction = MicroProfileX64FollowJump(pFunction); + + MicroProfileSymbolDesc* pDesc = MicroProfileSymbolFindFuction(pFunction); + if(pDesc) + { + uprintf("instrumenting child functions %p %p :: %s :: %s\n", (void*)pDesc->nAddress, (void*)pDesc->nAddressEnd, pDesc->pName, pDesc->pShortName); + int a = 0; + (void)a; + } + else + { + uprintf("could not find symbol info\n"); + return; + } + + const intptr_t nCodeLen = (intptr_t)pDesc->nAddressEnd - (intptr_t)pDesc->nAddress; + + MicroProfilePatchBeginSuspend(); + int NumFunctionsInstrumented = 0; + auto Callback = [&NumFunctionsInstrumented, nMinBytes, nMaxCalls](void* pFunc) + { + MicroProfileSymbolDesc* pDesc = MicroProfileSymbolFindFuction(pFunc); + if(!pDesc) + return; + const char* pName = pDesc ? pDesc->pName : "??"; + intptr_t Size = pDesc->nAddressEnd - pDesc->nAddress; + if(nMinBytes == 0 || Size >= nMinBytes) + { + if(0 == nMaxCalls || NumFunctionsInstrumented < nMaxCalls) + { + uprintf("** func Instrumented, count %d, size %d %s\n", NumFunctionsInstrumented, Size, pName); + if(MicroProfileInstrumentFromAddressOnly(pFunc)) + { + ++NumFunctionsInstrumented; + } + } + else + { + uprintf("** func Skipped, count %d>=%d :: %s\n", NumFunctionsInstrumented, nMaxCalls, pName); + } + } + else + { + uprintf("** func Skipped, Size %d<%d :: %s\n", Size, nMinBytes, pName); + } + }; + MicroProfileInstrumentScanForFunctionCalls(Callback, pFunction, nCodeLen); + + MicroProfilePatchEndSuspend(); +} + +bool MicroProfileInstrumentFunction(void* pFunction, const char* pModuleName, const char* pFunctionName, uint32_t nColor) +{ + MicroProfilePatchBeginSuspend(); + struct ScopeExit + { + ~ScopeExit() + { + MicroProfilePatchEndSuspend(); + } + } dummy; + + MicroProfilePatchError Err; + if(S.DynamicTokenIndex == MICROPROFILE_MAX_DYNAMIC_TOKENS) + { + uprintf("instrument failing, out of dynamic tokens %d\n", S.DynamicTokenIndex); + return false; + } + for(uint32_t i = 0; i < S.DynamicTokenIndex; ++i) + { + if(S.FunctionsInstrumented[i] == pFunction) + { + uprintf("function %p already instrumented\n", pFunction); + return false; + } + } + if(MicroProfilePatchFunction(pFunction, S.DynamicTokenIndex, MicroProfileInterceptEnter, MicroProfileInterceptLeave, &Err)) + { + MicroProfileToken Tok = S.DynamicTokens[S.DynamicTokenIndex] = MicroProfileGetToken("PATCHED", pFunctionName, nColor, MicroProfileTokenTypeCpu, 0); + S.FunctionsInstrumented[S.DynamicTokenIndex] = pFunction; + S.FunctionsInstrumentedName[S.DynamicTokenIndex] = MicroProfileStringIntern(pFunctionName); + S.FunctionsInstrumentedModuleNames[S.DynamicTokenIndex] = MicroProfileStringIntern(pModuleName); + S.DynamicTokenIndex++; + + uint16_t nGroup = MicroProfileGetGroupIndex(Tok); + if(!MicroProfileGroupActive(nGroup)) + { + MicroProfileGroupSetEnabled(nGroup); + } +#if MICROPROFILE_WEBSERVER + MicroProfileWebSocketToggleTimer(MicroProfileGetTimerIndex(Tok)); +#endif + + return false; + } + else + { + bool bFound = false; + for(int i = 0; i < S.nNumPatchErrors; ++i) + { + if(Err.nCodeSize == S.PatchErrors[i].nCodeSize && 0 == memcmp(Err.Code, S.PatchErrors[i].Code, Err.nCodeSize)) + { + bFound = true; + break; + } + } + if(!bFound && S.nNumPatchErrors < MICROPROFILE_MAX_PATCH_ERRORS) + { + memcpy(&S.PatchErrors[S.nNumPatchErrors++], &Err, sizeof(Err)); + } + bFound = false; + for(int i = 0; i < S.nNumPatchErrorFunctions; ++i) + { + if(0 == strcmp(pFunctionName, S.PatchErrorFunctionNames[i])) + { + bFound = true; + } + } + if(!bFound && S.nNumPatchErrorFunctions < MICROPROFILE_MAX_PATCH_ERRORS) + { + S.PatchErrorFunctionNames[S.nNumPatchErrorFunctions++] = pFunctionName; + } + uprintf("interception fail!!\n"); + return false; + } +} + +void MicroProfileInstrumentPreInit(); +void MicroProfileSymbolInitializeInternal(); +void MicroProfileSymbolFreeDataInternal(); +void MicroProfileSymbolKickThread(); +void MicroProfileQueryJoinThread(); + +bool MicroProfileSymbolInitialize(bool bStartLoad, const char* pModuleName) +{ + if(!bStartLoad) + return S.SymbolState.nModuleLoadsFinished.load() != 0; + // int nRequests = 0; + { + MicroProfileScopeLock L(MicroProfileMutex()); + for(int i = 0; i < S.SymbolNumModules; ++i) + { + if(0 == pModuleName || 0 == strcmp(pModuleName, (const char*)S.SymbolModules[i].pBaseString)) + { + if(0 == S.SymbolModules[i].nModuleLoadRequested.exchange(1)) + { + S.SymbolState.nModuleLoadsRequested.fetch_add(1); + } + } + } + } + + // todo: unload modules + MicroProfileSymbolKickThread(); + return S.SymbolState.nModuleLoadsRequested.load() == S.SymbolState.nModuleLoadsFinished.load(); + + // if(S.SymbolState.nState == MICROPROFILE_SYMBOLSTATE_DEFAULT) + // { + // if(!bStartLoad) + // return false; + // { + // MicroProfileScopeLock L(MicroProfileMutex()); + // S.SymbolState.nState.store(MICROPROFILE_SYMBOLSTATE_LOADING); + // S.SymbolState.nSymbolsLoaded.store(0); + // } + // MicroProfileSymbolKickThread(); + // return false; + // } + // if(nRequests) + // { + // } + // if(S.SymbolState.nState.load() == MICROPROFILE_SYMBOLSTATE_DONE) + // { + // MicroProfileQueryJoinThread(); + // } + // if(S.SymbolState.nState == MICROPROFILE_SYMBOLSTATE_DONE && bStartLoad) + // { + // MicroProfileSymbolFreeDataInternal(); + // { + // MicroProfileScopeLock L(MicroProfileMutex()); + // S.SymbolState.nState.store(MICROPROFILE_SYMBOLSTATE_LOADING); + // S.SymbolState.nSymbolsLoaded.store(0); + // } + // MicroProfileSymbolKickThread(); + // return false; + + // } + // else + // { + // return S.SymbolState.nState == MICROPROFILE_SYMBOLSTATE_DONE; + // } +} + +void MicroProfileSymbolFreeDataInternal() +{ + { + uprintf("todod;....\n"); + MP_BREAK(); + // MP_ASSERT(S.SymbolState.nState == MICROPROFILE_SYMBOLSTATE_DONE); + + S.nNumPatchErrorFunctions = 0; + memset(S.PatchErrorFunctionNames, 0, sizeof(S.PatchErrorFunctionNames)); + + for(int i = 0; i < S.SymbolNumModules; ++i) + { + + while(S.SymbolModules[i].pSymbolBlock) + { + MicroProfileSymbolBlock* pBlock = S.SymbolModules[i].pSymbolBlock; + S.SymbolModules[i].pSymbolBlock = pBlock->pNext; + MP_FREE(pBlock); + MICROPROFILE_COUNTER_SUB("/MicroProfile/Symbols/Allocs", 1); + MICROPROFILE_COUNTER_SUB("/MicroProfile/Symbols/Memory", sizeof(MicroProfileSymbolBlock)); + } + } + memset(&S.SymbolModules[0], 0, sizeof(S.SymbolModules)); + memset(&S.SymbolModuleNameBuffer[0], 0, sizeof(S.SymbolModuleNameBuffer)); + S.SymbolModuleNameOffset = 0; + S.SymbolNumModules = 0; + } +} +#if STRING_MATCH_SIZE == 64 +int MicroProfileCharacterMaskCharIndex(char c) +{ + if(c >= 'A' && c <= 'Z') + c = 'a' + (c - 'A'); + // abcdefghijklmnopqrstuvwxyz + if(c >= 'a' && c <= 'z') + { + int b = c - 'a'; + return b; + } + if(c >= '0' && c <= '9') + { + int b = c - '0'; + return b + 26; + } + switch(c) + { + case ':': + return 37; + case ';': + return 38; + case '\\': + return 39; + case '\'': + return 40; + case '\"': + return 41; + case '/': + return 42; + case '{': + return 43; + case '}': + return 44; + case '(': + return 45; + case ')': + return 46; + case '[': + return 47; + case ']': + return 48; + case '<': + return 49; + case '>': + return 50; + case '.': + return 51; + case ',': + return 52; // special characters + case ' ': + return -1; // special characters + } + return 63; +} + +uint64_t MicroProfileCharacterMaskChar(char c) +{ + uint64_t nMask = 1; + int nIndex = MicroProfileCharacterMaskCharIndex(c); + if(nIndex == -1) + return 0; + return nMask << nIndex; +} + +#else +uint32_t MicroProfileCharacterMaskChar(char c) +{ + if(c >= 'A' && c <= 'Z') + c = 'a' + (c - 'A'); + // abcdefghijklmnopqrstuvwxyz + if(c >= 'a' && c <= 'z') + { + int b = c - 'a'; + b = MicroProfileMin(20, b); // squish the last together + // static int once = 0; + // if(0 == once) + //{ + // for(int i = 20; i < 28; ++i) + // { + // uprintf("char %d is %c\n", i, (char)('a' + i)); + // } + // once = 1; + //} + uint32_t v = 1; + return v << b; + } + if(c >= '0' && c <= '9') + { + int b = c - '0'; + b += 21; + if(b < 21 || b > 30) + MP_BREAK(); + return 1 << b; + } + switch(c) + { + case ':': + case ';': + case '\\': + case '\'': + case '\"': + case '/': + case '{': + case '}': + case '(': + case ')': + case '[': + case ']': + return 1u << 31; // special characters + case ' ': + return 0; + } + return 0; +} +int MicroProfileCharacterMaskCharIndex(char c) +{ + if(c >= 'A' && c <= 'Z') + c = 'a' + (c - 'A'); + // abcdefghijklmnopqrstuvwxyz + if(c >= 'a' && c <= 'z') + { + int b = c - 'a'; + b = MicroProfileMin(20, b); // squish the last together + static int once = 0; + if(0 == once) + { + for(int i = 20; i < 28; ++i) + { + uprintf("char %d is %c\n", i, (char)('a' + i)); + } + once = 1; + } + return b; + } + if(c >= '0' && c <= '9') + { + int b = c - '0'; + b += 21; + if(b < 21 || b > 30) + MP_BREAK(); + return b; + } + switch(c) + { + case ':': + case ';': + case '\\': + case '\'': + case '\"': + case '/': + case '{': + case '}': + case '(': + case ')': + case '[': + case ']': + return 31; // special characters + case ' ': + return -1; + } + return 1; +} +#endif + +uint_string_match MicroProfileCharacterMaskString(const char* pStr) +{ + uint_string_match nMask = 0; + char c = 0; + while(0 != (c = *pStr++)) + { + nMask |= MicroProfileCharacterMaskChar(c); + } + return nMask; +} + +void MicroProfileCharacterMaskString2(const char* pStr, MicroProfileStringMatchMask& M) +{ + uint_string_match nMask = 0; + char c = 0; + int nLast = -1; + while(0 != (c = *pStr++)) + { + nMask |= MicroProfileCharacterMaskChar(c); + int nIndex = MicroProfileCharacterMaskCharIndex(c); + if(nIndex >= 0 && nLast >= 0) + { + MP_ASSERT(nIndex < STRING_MATCH_SIZE); + M.M[nLast] |= 1llu << nIndex; + } + nLast = nIndex; + } + M.nMask |= nMask; +} + +bool MicroProfileCharacterMatch(const MicroProfileStringMatchMask& Block, const MicroProfileStringMatchMask& String) +{ + if(String.nMask != (Block.nMask & String.nMask)) + return false; + for(uint32_t i = 0; i < STRING_MATCH_SIZE; ++i) + { + if(String.M[i] != (Block.M[i] & String.M[i])) + return false; + } + return true; +} + +uint32_t MicroProfileSymbolGetModule(const char* pString, intptr_t nBaseAddr) +{ + + for(int i = 0; i < S.SymbolNumModules; ++i) + { + auto& M = S.SymbolModules[i]; + for(int j = 0; j < M.nNumExecutableRegions; ++j) + { + if(M.Regions[j].nBegin <= nBaseAddr && nBaseAddr < M.Regions[j].nEnd) + return i; + } + } + MP_BREAK(); // should never happen. + return 0; +} + +void MicroProfileSymbolMergeExecutableRegions() +{ + for(int i = 0; i < S.SymbolNumModules; ++i) + { + auto& M = S.SymbolModules[i]; + if(M.nNumExecutableRegions > 1) + { + std::sort(&M.Regions[0], &M.Regions[M.nNumExecutableRegions], [](const MicroProfileSymbolModuleRegion& l, const MicroProfileSymbolModuleRegion& r) { return l.nBegin < r.nBegin; }); + + int p = 0; + int g = 1; + while(g < M.nNumExecutableRegions) + { + if(M.Regions[p].nEnd == M.Regions[g].nBegin) + { + M.Regions[p].nEnd = M.Regions[g].nEnd; + g++; + } + else + { + ++p; + if(p != g) + M.Regions[p] = M.Regions[g]; + g++; + } + } + M.nNumExecutableRegions = p + 1; + } + } + for(int i = 0; i < S.SymbolNumModules; ++i) + { + auto& M = S.SymbolModules[i]; + uprintf("region %s %s\n", M.pTrimmedString, M.pBaseString); + for(int j = 0; j < M.nNumExecutableRegions; ++j) + uprintf("\t[%p-%p]\n", (void*)M.Regions[j].nBegin, (void*)M.Regions[j].nEnd); + } +} + +uint32_t MicroProfileSymbolInitModule(const char* pString_, intptr_t nAddrBegin, intptr_t nAddrEnd) +{ + const char* pString = MicroProfileStringInternSlash(pString_); + for(int i = 0; i < S.SymbolNumModules; ++i) + { + auto& M = S.SymbolModules[i]; + for(int j = 0; j < M.nNumExecutableRegions; ++j) + { + if(M.Regions[j].nBegin <= nAddrBegin && nAddrEnd < M.Regions[j].nEnd) + { + MP_ASSERT(pString == M.pBaseString); + return i; + } + } + } + + for(int i = 0; i < S.SymbolNumModules; ++i) + { + auto& M = S.SymbolModules[i]; + if(M.pBaseString == pString) + { + MP_ASSERT((intptr_t)pString != -2); + for(int j = 0; j < M.nNumExecutableRegions; ++j) + if(nAddrBegin == M.Regions[j].nBegin) + return i; + + if(M.nNumExecutableRegions == MICROPROFILE_MAX_MODULE_EXEC_REGIONS) + { + return (uint32_t)-1; + } + M.Regions[M.nNumExecutableRegions].nBegin = nAddrBegin; + M.Regions[M.nNumExecutableRegions].nEnd = nAddrEnd; + // uprintf("added module region %d %p %p %s \n", M.nNumExecutableRegions, (void*)nAddrBegin, (void*)nAddrEnd, pString); + M.nNumExecutableRegions++; + return i; + } + } + + MP_ASSERT((intptr_t)pString != -2); + // trim untill last path char + const char* pTrimmedString = pString; + + const char* pWork = pTrimmedString; + bool bLastSeperator = false; + while(*pWork != '\0') + { + if(bLastSeperator) + pTrimmedString = pWork; + bLastSeperator = *pWork == '\\' || *pWork == '/'; + + pWork++; + } + int nLen = (int)strlen(pTrimmedString) + 1; + // uprintf("STRING '%s' :: trimmedstring %s . len %d\n", pString, pTrimmedString, nLen); + + const char* pTrimmedIntern = MicroProfileStringIntern(pTrimmedString); + if(S.SymbolModuleNameOffset + nLen > MICROPROFILE_INSTRUMENT_MAX_MODULE_CHARS) + return 0; + memcpy(S.SymbolModuleNameOffset + &S.SymbolModuleNameBuffer[0], pTrimmedString, nLen); + + MP_ASSERT(S.SymbolNumModules < MICROPROFILE_INSTRUMENT_MAX_MODULES); + S.SymbolModules[S.SymbolNumModules].nModuleBase = nAddrBegin; + S.SymbolModules[S.SymbolNumModules].nMatchOffset = 0; + S.SymbolModules[S.SymbolNumModules].nStringOffset = S.SymbolModuleNameOffset; + S.SymbolModules[S.SymbolNumModules].pBaseString = (const char*)pString; + S.SymbolModules[S.SymbolNumModules].pTrimmedString = pTrimmedIntern; + S.SymbolModules[S.SymbolNumModules].Regions[0].nBegin = nAddrBegin; + S.SymbolModules[S.SymbolNumModules].Regions[0].nEnd = nAddrEnd; + S.SymbolModules[S.SymbolNumModules].nNumExecutableRegions = 1; + S.SymbolModules[S.SymbolNumModules].bDownloading = false; + S.SymbolModules[S.SymbolNumModules].nProgress = 0; + S.SymbolModules[S.SymbolNumModules].nProgressTarget = 0; + + S.SymbolModuleNameOffset += nLen; + return S.SymbolNumModules++; +} + +const char* MicroProfileSymbolModuleGetString(uint32_t nIndex) +{ + MP_ASSERT(S.SymbolNumModules > (int)nIndex); + return S.SymbolModules[nIndex].nStringOffset + &S.SymbolModuleNameBuffer[0]; +} + +bool MicroProfileSymbolIgnoreSymbol(const char* pName) +{ + if(strstr(pName, "MicroProfile")) + { +#if MICROPROFILE_INSTRUMENT_MICROPROFILE == 0 + return true; +#else + if(strstr(pName, "Log") || strstr(pName, "Scope") || strstr(pName, "Tick") || strstr(pName, "Enter") || strstr(pName, "Leave") || strstr(pName, "Thread") || strstr(pName, "Thread") || + strstr(pName, "Mutex")) // just for debugging: skip these so we can play around with the sample projects + { + return true; + } +#endif + } +#ifdef _WIN32 + if(pName[0] == '_' && pName[1] == '_') + return true; + if(strstr(pName, "__security_check_cookie") || strstr(pName, "_RTC_CheckStackVars") || strstr(pName, "__chkstk") || strstr(pName, "std::_Atomic") || strstr(pName, "_Init_thread_header") || + strstr(pName, "_Init_thread_footer")) + { + return true; + } +#endif + return false; +} + +void MicroProfileSymbolInitializeInternal() +{ + uprintf("Starting load...\n"); + MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileSymbolInitialize", MP_CYAN); + + auto AllocBlock = []() -> MicroProfileSymbolBlock* + { + MicroProfileSymbolBlock* pBlock = MP_ALLOC_OBJECT(MicroProfileSymbolBlock); + MICROPROFILE_COUNTER_ADD("/MicroProfile/Symbols/Allocs", 1); + MICROPROFILE_COUNTER_ADD("/MicroProfile/Symbols/Memory", sizeof(MicroProfileSymbolBlock)); + MICROPROFILE_COUNTER_CONFIG_ONCE("/MicroProfile/Symbols/Memory", MICROPROFILE_COUNTER_FORMAT_BYTES, 0, 0); + memset(pBlock, 0, sizeof(MicroProfileSymbolBlock)); + return pBlock; + }; + + auto SymbolCallback = [&](const char* pName, const char* pShortName, intptr_t nAddress, intptr_t nAddressEnd, uint32_t nModuleId) + { + MICROPROFILE_SCOPEI("microprofile", "SymbolCallback", MP_AUTO); + uint32_t nModule = nModuleId; + if(MicroProfileHashTableGetPtr(&S.SymbolModules[nModule].AddressToSymbol, (void*)nAddress)) + { + return; + } + char Demangled[1024]; + if(MicroProfileDemangleName(pName, Demangled, sizeof(Demangled))) + { + pName = &Demangled[0]; + pShortName = &Demangled[0]; + } + intptr_t delta = nAddressEnd - nAddress; + S.SymbolModules[nModule].nProgress = MicroProfileMax(delta, S.SymbolModules[nModule].nProgress); + S.nSymbolsDirty++; + + int nIgnoreSymbol = MicroProfileSymbolIgnoreSymbol(pName) ? 1 : 0; + + MicroProfileSymbolBlock* pActiveBlock = S.SymbolModules[nModule].pSymbolBlock; + if(!pActiveBlock) + { + pActiveBlock = AllocBlock(); + pActiveBlock->pNext = S.SymbolModules[nModule].pSymbolBlock; + S.SymbolModules[nModule].pSymbolBlock = pActiveBlock; + } + + if(pName == pShortName) + { + pShortName = 0; + } + uint32_t nLen = (uint32_t)strlen(pName) + 1; + + if(nLen > MICROPROFILE_INSTRUMENT_SYMBOLNAME_MAXLEN) + nLen = MICROPROFILE_INSTRUMENT_SYMBOLNAME_MAXLEN; + uint32_t nLenShort = (uint32_t)(pShortName ? 1 + strlen(pShortName) : 0); + if(nLenShort && nLenShort > MICROPROFILE_INSTRUMENT_SYMBOLNAME_MAXLEN) + nLenShort = MICROPROFILE_INSTRUMENT_SYMBOLNAME_MAXLEN; + uint32_t S0 = sizeof(MicroProfileSymbolDesc) * pActiveBlock->nNumSymbols; + uint32_t S1 = pActiveBlock->nNumChars; + uint32_t S3 = nLenShort + nLen + sizeof(MicroProfileSymbolDesc) + 64; + if(S0 + S1 + S3 >= MicroProfileSymbolBlock::ESIZE) + { + MicroProfileSymbolBlock* pNewBlock = AllocBlock(); + MP_ASSERT(pActiveBlock == S.SymbolModules[nModule].pSymbolBlock); + pNewBlock->pNext = pActiveBlock; + S.SymbolModules[nModule].pSymbolBlock = pNewBlock; + pActiveBlock = pNewBlock; + } + S0 = sizeof(MicroProfileSymbolDesc) * pActiveBlock->nNumSymbols; + S1 = pActiveBlock->nNumChars; + S3 = nLenShort + nLen + sizeof(MicroProfileSymbolDesc); + MP_ASSERT(S0 + S1 + S3 < MicroProfileSymbolBlock::ESIZE); + pActiveBlock->nNumChars += nLen; + char* pStr = &pActiveBlock->Chars[MicroProfileSymbolBlock::ESIZE - pActiveBlock->nNumChars - 1]; + memcpy(pStr, pName, nLen); + pStr[nLen - 1] = '\0'; + MicroProfileSymbolDesc& E = pActiveBlock->Symbols[pActiveBlock->nNumSymbols++]; + MicroProfileHashTableSetPtr(&S.SymbolModules[nModule].AddressToSymbol, (void*)nAddress, &E); + + E.pName = pStr; + E.nAddress = nAddress; + E.nAddressEnd = nAddressEnd; + E.nIgnoreSymbol = nIgnoreSymbol; + E.nModule = nModule; + if(pShortName && strlen(pShortName)) + { + pActiveBlock->nNumChars += nLenShort; + char* pStrShort = &pActiveBlock->Chars[MicroProfileSymbolBlock::ESIZE - pActiveBlock->nNumChars - 1]; + memcpy(pStrShort, pShortName, nLenShort); + pStrShort[nLenShort - 1] = '\0'; + E.pShortName = pStrShort; + } + else + { + E.pShortName = E.pName; + } +#define SYMDBG 0 +#if SYMDBG + uprintf("Got symbol %lld %lld %f .. %llx %llx %llx %s\n", + S.SymbolModules[nModule].nProgress, + S.SymbolModules[nModule].nProgressTarget, + S.SymbolModules[nModule].nProgressTarget ? float(S.SymbolModules[nModule].nProgress) / float(S.SymbolModules[nModule].nProgressTarget) : 0.f, + (int64_t)E.nAddress, + (int64_t)S.SymbolModules[nModule].nAddrBegin, + (int64_t)S.SymbolModules[nModule].nAddrEnd, + E.pName); + if(E.nAddress < (int64_t)S.SymbolModules[nModule].nAddrBegin || E.nAddress > (int64_t)S.SymbolModules[nModule].nAddrEnd) + { + MP_BREAK(); + } +#endif + E.nMask = MicroProfileCharacterMaskString(E.pShortName); + MicroProfileCharacterMaskString2(E.pShortName, pActiveBlock->MatchMask); + + pActiveBlock->nMask |= E.nMask; + MICROPROFILE_COUNTER_ADD("/MicroProfile/Symbols/Count", 1); + if(nIgnoreSymbol) + { + MICROPROFILE_COUNTER_ADD("/MicroProfile/Symbols/Ignored", 1); + } +#if SYMDBG + MicroProfileSleep(10); +#endif +#undef SYMDBG + + S.SymbolModules[nModule].nSymbolsLoaded.fetch_add(1); + S.nSymbolsDirty.exchange(1); + S.SymbolState.nSymbolsLoaded.fetch_add(1); + MP_ASSERT((intptr_t)E.pShortName >= (intptr_t)&E); // assert pointer arithmetic is correct. + }; + do + { + uint32_t nModuleLoad[MICROPROFILE_INSTRUMENT_MAX_MODULES]; + uint32_t nNumModulesRequested = 0; + for(int i = 0; i < S.SymbolNumModules; ++i) + { + if(S.SymbolModules[i].nModuleLoadRequested.load() != 0 && S.SymbolModules[i].nModuleLoadFinished.load() == 0) + { + nModuleLoad[nNumModulesRequested] = i; + S.SymbolModules[i].nProgress = 0; + MicroProfileHashTableInit(&S.SymbolModules[i].AddressToSymbol, 256, 64, MicroProfileHashTableComparePtr, MicroProfileHashTableHashPtr); + nNumModulesRequested++; + } + } + if(0 == nNumModulesRequested) + { + break; + } + MicroProfileIterateSymbols(SymbolCallback, nModuleLoad, nNumModulesRequested); + S.SymbolState.nModuleLoadsFinished.fetch_add(nNumModulesRequested); + for(uint32_t i = 0; i < nNumModulesRequested; ++i) + { + if(S.SymbolModules[nModuleLoad[i]].nModuleLoadRequested.load() == S.SymbolModules[nModuleLoad[i]].nModuleLoadFinished.load()) + { + S.SymbolModules[nModuleLoad[i]].nProgress = S.SymbolModules[nModuleLoad[i]].nProgressTarget; + S.nSymbolsDirty.exchange(1); + } + } + } while(1); +} + +MicroProfileSymbolDesc* MicroProfileSymbolFindFuction(void* pAddress) +{ + for(int i = 0; i < S.SymbolNumModules; ++i) + { + MicroProfileSymbolDesc* pDesc = nullptr; + if(MicroProfileHashTableGetPtr(&S.SymbolModules[i].AddressToSymbol, pAddress, &pDesc)) + { + if(0 == pDesc->nIgnoreSymbol) + return pDesc; + else + return nullptr; + } + } + return nullptr; +} + +#define MICROPROFILE_MAX_FILTER 32 +#define MICROPROFILE_MAX_QUERY_RESULTS 32 +#define MICROPROFILE_MAX_FILTER_STRING 1024 + +struct MicroProfileFunctionQuery +{ + MicroProfileFunctionQuery* pNext; + uint32_t nState; + const char* pFilterStrings[MICROPROFILE_MAX_FILTER]; + uint32_t nPatternLength[MICROPROFILE_MAX_FILTER]; + int nMaxFilter; + + uint32_t nModuleFilterMatch[MICROPROFILE_INSTRUMENT_MAX_MODULES]; // prematch the modules, so it can be skipped during search + uint32_t nMask[MICROPROFILE_MAX_FILTER]; // masks for subpatterns skipped + MicroProfileStringMatchMask MatchMask[MICROPROFILE_MAX_FILTER]; // masks for subpatterns skipped + + // results + MicroProfileSymbolDesc* Results[MICROPROFILE_MAX_QUERY_RESULTS]; + uint32_t nNumResults; + char FilterString[MICROPROFILE_MAX_FILTER_STRING]; + + uint32_t QueryId; +}; + +MicroProfileFunctionQuery* MicroProfileAllocFunctionQuery() +{ + MicroProfileScopeLock L(MicroProfileMutex()); + MicroProfileFunctionQuery* pQ = nullptr; + S.nNumQueryAllocated++; + if(S.pQueryFreeList != 0) + { + pQ = S.pQueryFreeList; + S.pQueryFreeList = pQ->pNext; + S.nNumQueryFree--; + } + else + { + pQ = MP_ALLOC_OBJECT(MicroProfileFunctionQuery); + MICROPROFILE_COUNTER_ADD("MicroProfile/Symbols/FunctionQuery", 1); + MICROPROFILE_COUNTER_ADD("MicroProfile/Symbols/FunctionQueryMem", sizeof(MicroProfileFunctionQuery)); + S.nNumQueryAllocated++; + } + memset(pQ, 0, sizeof(MicroProfileFunctionQuery)); + return pQ; +} +void MicroProfileFreeFunctionQuery(MicroProfileFunctionQuery* pQ) +{ + pQ->pNext = S.pQueryFreeList; + S.pQueryFreeList = pQ; +} + +void MicroProfileProcessQuery(MicroProfileFunctionQuery* pQuery) +{ + MicroProfileFunctionQuery& Q = *pQuery; + + int nBlocksTested = 0, nSymbolsTested = 0, nStringsTested = 0, nStringsTested0 = 0; + int nBlocks = 0; + // (void)nBlocksTested; + // (void)nSymbolsTested; + // (void)nStringsTested; + // (void)nStringsTested0; + // (void)nBlocks; + + int64_t t = MP_TICK(); + int64_t tt = 0; + + for(int i = 0; i < S.SymbolNumModules; ++i) + { + int nModule = i; + uint32_t nModuleMatchOffset = Q.nModuleFilterMatch[nModule]; + MicroProfileSymbolBlock* pSymbols = S.SymbolModules[nModule].pSymbolBlock; + + uint32_t nMaskQ = Q.nMask[nModuleMatchOffset]; + MicroProfileStringMatchMask& MatchMaskQ = Q.MatchMask[nModuleMatchOffset]; + { + while(pSymbols && 0 == S.pPendingQuery && Q.nNumResults < MICROPROFILE_MAX_QUERY_RESULTS) + { + + MICROPROFILE_SCOPEI("MicroProfile", "SymbolQueryLoop", MP_YELLOW); + nBlocks++; + if(MicroProfileCharacterMatch(pSymbols->MatchMask, MatchMaskQ)) + { + nBlocksTested++; + for(uint32_t i = 0; i < pSymbols->nNumSymbols && 0 == S.pPendingQuery && Q.nNumResults < MICROPROFILE_MAX_QUERY_RESULTS; ++i) + { + MicroProfileSymbolDesc& E = pSymbols->Symbols[i]; + if(0 == E.nIgnoreSymbol) + { + nSymbolsTested++; + if(nMaskQ == (nMaskQ & E.nMask)) + { + nStringsTested++; + MP_ASSERT((int)E.nModule < S.SymbolNumModules); + if(MicroProfileStringMatch(E.pShortName, nModuleMatchOffset, &Q.pFilterStrings[0], Q.nPatternLength, Q.nMaxFilter)) + { + if(Q.nNumResults < MICROPROFILE_MAX_QUERY_RESULTS) + { + + Q.Results[Q.nNumResults++] = &E; + if(Q.nNumResults == MICROPROFILE_MAX_QUERY_RESULTS) + tt = MP_TICK(); + } + } + if(Q.nNumResults < MICROPROFILE_MAX_QUERY_RESULTS) + nStringsTested0++; + } + } + } + } + pSymbols = pSymbols->pNext; + } + } + } + int64_t tend = MP_TICK(); + float ToMS = MicroProfileTickToMsMultiplierCpu(); + float TIME = (tend - t) * ToMS; + float TIME0 = (tt - t) * ToMS; + uprintf(" %6.3fms [%6.3f]: %5d/%5d blocks tested. %5d symbols %5d/%5d string compares\n", TIME, TIME0, nBlocksTested, nBlocks, nSymbolsTested, nStringsTested, nStringsTested0); +} + +void* MicroProfileQueryThread(void* p) +{ + MicroProfileOnThreadCreate("MicroProfileSymbolThread"); + { + while(1) + { + MicroProfileSleep(100); // todo:: use an event instead + MicroProfileScopeLock L(MicroProfileMutex()); + if(S.pPendingQuery != nullptr) + { + MICROPROFILE_SCOPEI("MicroProfile", "SymbolQuery", MP_WHEAT); + MicroProfileFunctionQuery* pQuery = S.pPendingQuery; + + MP_ASSERT(pQuery->QueryId > S.nQueryProcessed); + S.pPendingQuery = 0; + L.Unlock(); + + // uprintf("processing query %d\n", pQuery->QueryId); + MicroProfileProcessQuery(pQuery); + + L.Lock(); + S.nQueryProcessed = MicroProfileMax(pQuery->QueryId, S.nQueryProcessed); + + pQuery->pNext = S.pFinishedQuery; + S.pFinishedQuery = pQuery; + } + if(S.SymbolState.nModuleLoadsRequested.load() != S.SymbolState.nModuleLoadsFinished.load()) + { + L.Unlock(); + MicroProfileSymbolInitializeInternal(); + L.Lock(); + } + } + + S.SymbolThreadFinished = 1; + } + MicroProfileOnThreadExit(); + return 0; +} + +void MicroProfileQueryJoinThread() +{ + if(S.SymbolThreadFinished) + { + MicroProfileThreadJoin(&S.SymbolThread); + S.SymbolThreadFinished = 0; + S.SymbolThreadRunning = 0; + } +} +void MicroProfileSymbolKickThread() +{ + // MicroProfileQueryJoinThread(); + if(S.SymbolThreadRunning == 0) + { + S.SymbolThreadRunning = 1; + MicroProfileThreadStart(&S.SymbolThread, MicroProfileQueryThread); + } +} +#if MICROPROFILE_WEBSERVER +void MicroProfileSymbolSendFunctionNames(MpSocket Connection) +{ + if(S.WSFunctionsInstrumentedSent < S.DynamicTokenIndex) + { + MicroProfileWSPrintStart(Connection); + MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":[", MSG_FUNCTION_NAMES); + bool bFirst = true; + for(uint32_t i = S.WSFunctionsInstrumentedSent; i < S.DynamicTokenIndex; ++i) + { + const char* pString = S.FunctionsInstrumentedName[i]; + const char* pModuleString = S.FunctionsInstrumentedModuleNames[i]; + MicroProfileWSPrintf(bFirst ? "[\"%s\",\"%s\",\"%s\"]" : ",[\"%s\",\"%s\",\"%s\"]", pString, pModuleString, "unused"); + bFirst = false; + } + MicroProfileWSPrintf("]}"); + MicroProfileWSFlush(); + MicroProfileWSPrintEnd(); + + S.WSFunctionsInstrumentedSent = S.DynamicTokenIndex; + } +} + +void MicroProfileSymbolSendErrors(MpSocket Connection) +{ + if(S.nNumPatchErrors) + { + MicroProfileWSPrintStart(Connection); + MicroProfileWSPrintf("{\"k\":\"%d\",\"v\":{\"version\":\"%d.%d\",\"data\":[", MSG_INSTRUMENT_ERROR, MICROPROFILE_MAJOR_VERSION, MICROPROFILE_MINOR_VERSION); + bool bFirst = true; + for(int i = 0; i < S.nNumPatchErrors; ++i) + { + MicroProfilePatchError& E = S.PatchErrors[i]; + (void)E; + if(!bFirst) + MicroProfileWSPrintf(","); + MicroProfileWSPrintf("{\"code\":\""); + for(int i = 0; i < E.nCodeSize; ++i) + MicroProfileWSPrintf("%02x", E.Code[i] & 0xff); + MicroProfileWSPrintf("\",\"message\":\"%s\",\"already\":%d}", &E.Message[0], E.AlreadyInstrumented); + bFirst = false; + } + + MicroProfileWSPrintf("],\"functions\":["); + bFirst = true; + for(int i = 0; i < S.nNumPatchErrorFunctions; ++i) + { + if(!bFirst) + MicroProfileWSPrintf(","); + + MicroProfileWSPrintf("\"%s\"", S.PatchErrorFunctionNames[i]); + + bFirst = false; + } + + MicroProfileWSPrintf("]}}"); + + MicroProfileWSFlush(); + MicroProfileWSPrintEnd(); + + S.nNumPatchErrors = 0; + S.nNumPatchErrorFunctions = 0; + } +} + +void MicroProfileSymbolQuerySendResult(MpSocket Connection) +{ + MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileSymbolQuerySendResult", MP_PINK2); + MicroProfileFunctionQuery* pQuery = 0; + { + MicroProfileScopeLock L(MicroProfileMutex()); + + uint32_t nBest = 0; + + while(S.pFinishedQuery != nullptr) + { + if(!pQuery) + { + pQuery = S.pFinishedQuery; + nBest = pQuery->QueryId; + S.pFinishedQuery = pQuery->pNext; + } + else + { + MicroProfileFunctionQuery* pQ = S.pFinishedQuery; + S.pFinishedQuery = pQ->pNext; + if(pQ->QueryId > nBest) + { + MicroProfileFreeFunctionQuery(pQuery); + nBest = pQ->QueryId; + pQuery = pQ; + } + else + { + MicroProfileFreeFunctionQuery(pQ); + } + } + } + } + + if(pQuery) + { + uprintf("Sending result for query %d\n", pQuery->QueryId); + MicroProfileWSPrintStart(Connection); + MicroProfileWSPrintf("{\"k\":\"%d\",\"q\":%d,\"v\":[", MSG_FUNCTION_RESULTS, pQuery->QueryId); + bool bFirst = true; + for(uint32_t i = 0; i < pQuery->nNumResults; ++i) + { + MicroProfileSymbolDesc& E = *pQuery->Results[i]; + if(bFirst) + { + MicroProfileWSPrintf("{\"a\":\"%p\",\"n\":\"%s\",\"sn\":\"%s\",\"m\":\"%s\"}", E.nAddress, E.pName, E.pShortName, MicroProfileSymbolModuleGetString(E.nModule)); + bFirst = false; + } + else + { + MicroProfileWSPrintf(",{\"a\":\"%p\",\"n\":\"%s\",\"sn\":\"%s\",\"m\":\"%s\"}", E.nAddress, E.pName, E.pShortName, MicroProfileSymbolModuleGetString(E.nModule)); + } + } + MicroProfileWSPrintf("]}"); + MicroProfileWSFlush(); + MicroProfileWSPrintEnd(); + + MicroProfileScopeLock L(MicroProfileMutex()); + MicroProfileFreeFunctionQuery(pQuery); + } +} +#endif + +void MicroProfileSymbolQueryFunctions(MpSocket Connection, const char* pFilter) +{ + MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileSymbolQueryFunctions", MP_WHEAT); + + if(!MicroProfileSymbolInitialize(false)) + { + return; + } + { + int QueryId = atoi(pFilter); + pFilter = strchr(pFilter, 'x'); + pFilter++; + MicroProfileScopeLock L(MicroProfileMutex()); + if(0 == S.pPendingQuery || S.pPendingQuery->QueryId < (uint32_t)QueryId) + { + MicroProfileFunctionQuery* pQuery = S.pPendingQuery; + if(!pQuery) + { + S.pPendingQuery = pQuery = MicroProfileAllocFunctionQuery(); + } + MP_ASSERT(pQuery->pNext == 0); + memset(pQuery, 0, sizeof(*pQuery)); + + MicroProfileFunctionQuery& Q = *pQuery; + Q.QueryId = QueryId; + + uint32_t nLen = (uint32_t)strlen(pFilter) + 1; + if(nLen >= MICROPROFILE_MAX_FILTER_STRING) + nLen = MICROPROFILE_MAX_FILTER_STRING - 1; + + memcpy(Q.FilterString, pFilter, nLen); + Q.FilterString[nLen] = '\0'; + + char* pBuffer = Q.FilterString; + bool bStartString = true; + for(uint32_t i = 0; i < nLen; ++i) + { + char c = pBuffer[i]; + if(c == '\0') + { + break; + } + if(isspace(c) || c == '*') + { + pBuffer[i] = '\0'; + bStartString = true; + } + else + { + if(bStartString) + { + if(Q.nMaxFilter < MICROPROFILE_MAX_FILTER) + { + const char* pstr = &pBuffer[i]; + Q.nMask[Q.nMaxFilter] = MicroProfileCharacterMaskString(pstr); + MicroProfileCharacterMaskString2(pstr, Q.MatchMask[Q.nMaxFilter]); + Q.pFilterStrings[Q.nMaxFilter++] = &pBuffer[i]; + } + } + bStartString = false; + } + } + memset(Q.nModuleFilterMatch, 0xff, sizeof(Q.nModuleFilterMatch)); + for(int i = 0; i < S.SymbolNumModules; ++i) + { + Q.nModuleFilterMatch[i] = MicroProfileStringMatchOffset(MicroProfileSymbolModuleGetString(i), Q.pFilterStrings, Q.nPatternLength, Q.nMaxFilter); + } + +#if 0 + uprintf("query %d::",QueryId); + for(int i = 0; i < Q.nMaxFilter; ++i) + { + Q.nPatternLength[i] = (uint32_t)strlen(Q.pFilterStrings[i]); + uprintf("'%s' ", Q.pFilterStrings[i]); + } + uprintf("\n"); +#endif + } + } + MicroProfileSymbolKickThread(); +} + +#if defined(_WIN32) +// '##::::'##::'#######:::'#######::'##:::'##::::'##:::::'##:'####:'##::: ##::'#######:::'#######:: +// ##:::: ##:'##.... ##:'##.... ##: ##::'##::::: ##:'##: ##:. ##:: ###:: ##:'##.... ##:'##.... ##: +// ##:::: ##: ##:::: ##: ##:::: ##: ##:'##:::::: ##: ##: ##:: ##:: ####: ##:..::::: ##:..::::: ##: +// #########: ##:::: ##: ##:::: ##: #####::::::: ##: ##: ##:: ##:: ## ## ##::'#######:::'#######:: +// ##.... ##: ##:::: ##: ##:::: ##: ##. ##:::::: ##: ##: ##:: ##:: ##. ####::...... ##:'##:::::::: +// ##:::: ##: ##:::: ##: ##:::: ##: ##:. ##::::: ##: ##: ##:: ##:: ##:. ###:'##:::: ##: ##:::::::: +// ##:::: ##:. #######::. #######:: ##::. ##::::. ###. ###::'####: ##::. ##:. #######:: #########: +// ..:::::..:::.......::::.......:::..::::..::::::...::...:::....::..::::..:::.......:::.........:: + +#ifdef _WIN32 +static void* MicroProfileAllocExecutableMemory(void* pBase, size_t s); +static void* MicroProfileAllocExecutableMemoryFar(size_t s); +static void MicroProfileMakeMemoryExecutable(void* p, size_t s); +static void MicroProfileMakeWriteable(void* p_, size_t size, DWORD* oldFlags); +static void MicroProfileRestore(void* p_, size_t size, DWORD* oldFlags); + +extern "C" void microprofile_tramp_enter_patch(); +extern "C" void microprofile_tramp_enter(); +extern "C" void microprofile_tramp_code_begin(); +extern "C" void microprofile_tramp_code_end(); +extern "C" void microprofile_tramp_intercept0(); +extern "C" void microprofile_tramp_end(); +extern "C" void microprofile_tramp_exit(); +extern "C" void microprofile_tramp_leave(); +extern "C" void microprofile_tramp_trunk(); +extern "C" void microprofile_tramp_call_patch_pop(); +extern "C" void microprofile_tramp_call_patch_push(); + +bool MicroProfilePatchFunction(void* f, int Argument, MicroProfileHookFunc enter, MicroProfileHookFunc leave, MicroProfilePatchError* pError) +{ + char* pOriginal = (char*)f; + + f = MicroProfileX64FollowJump(f); + if(MicroProfilePatchHasSuspendedThread((intptr_t)f, (intptr_t)f + 32)) + { + uprintf("failed to patch, thread running in patch position"); + return false; + } + intptr_t t_enter = (intptr_t)microprofile_tramp_enter; + intptr_t t_enter_patch_offset = (intptr_t)microprofile_tramp_enter_patch - t_enter; + intptr_t t_code_begin_offset = (intptr_t)microprofile_tramp_code_begin - t_enter; + intptr_t t_code_end_offset = (intptr_t)microprofile_tramp_code_end - t_enter; + intptr_t t_code_intercept0_offset = (intptr_t)microprofile_tramp_intercept0 - t_enter; + intptr_t t_code_exit_offset = (intptr_t)microprofile_tramp_exit - t_enter; + intptr_t t_code_leave_offset = (intptr_t)microprofile_tramp_leave - t_enter; + + intptr_t t_code_call_patch_push_offset = (intptr_t)microprofile_tramp_call_patch_push - t_enter; + intptr_t t_code_call_patch_pop_offset = (intptr_t)microprofile_tramp_call_patch_pop - t_enter; + intptr_t codemaxsize = t_code_end_offset - t_code_begin_offset; + intptr_t t_end_offset = (intptr_t)microprofile_tramp_end - t_enter; + intptr_t t_trunk_offset = (intptr_t)microprofile_tramp_trunk - t_enter; + int t_trunk_size = (int)((intptr_t)microprofile_tramp_end - (intptr_t)microprofile_tramp_trunk); + + char* ptramp = (char*)MicroProfileAllocExecutableMemory(f, t_end_offset); + if(!ptramp) + ptramp = (char*)MicroProfileAllocExecutableMemoryFar(t_end_offset); + + intptr_t offset = ((intptr_t)f + 6 - (intptr_t)ptramp); + + uint32_t nBytesToCopy = 14; + if(offset < 0x80000000 && offset > -0x7fffffff) + { + /// offset is small enough to insert a relative jump + nBytesToCopy = 5; + } + + memcpy(ptramp, (void*)t_enter, t_end_offset); + + int nInstructionBytesDest = 0; + char* pInstructionMoveDest = ptramp + t_code_begin_offset; + char* pTrunk = ptramp + t_trunk_offset; + + int nInstructionBytesSrc = 0; + uint32_t nRegsWritten = 0; + uint32_t nRetSafe = 1; + uint32_t nUsableJumpRegs = (1 << R_RAX) | (1 << R_R10) | (1 << R_R11); + static_assert(R_RAX == 0, "R_RAX must be 0"); + if(!MicroProfileCopyInstructionBytes( + pInstructionMoveDest, f, nBytesToCopy, (int)codemaxsize, pTrunk, t_trunk_size, nUsableJumpRegs, &nInstructionBytesDest, &nInstructionBytesSrc, &nRegsWritten, &nRetSafe)) + { + if(pError) + { + const char* pCode = (const char*)f; + memset(pError->Code, 0, sizeof(pError->Code)); + memcpy(pError->Code, pCode, nInstructionBytesSrc); + int off = stbsp_snprintf(pError->Message, sizeof(pError->Message), "Failed to move %d code bytes ", nInstructionBytesSrc); + pError->nCodeSize = nInstructionBytesSrc; + for(int i = 0; i < nInstructionBytesSrc; ++i) + { + off += stbsp_snprintf(off + pError->Message, sizeof(pError->Message) - off, "%02x ", 0xff & pCode[i]); + } + uprintf("%s\n", pError->Message); + } + return false; + } + + intptr_t phome = nInstructionBytesSrc + (intptr_t)f; + uint32_t reg = nUsableJumpRegs & ~nRegsWritten; + if(0 == reg) + { + if(0 == nRetSafe) + MP_BREAK(); // should be caught earlier + MicroProfileInsertRetJump(pInstructionMoveDest + nInstructionBytesDest, phome); + } + else + { + int r = R_RAX; + while((reg & 1) == 0) + { + reg >>= 1; + r++; + } + MicroProfileInsertRegisterJump(pInstructionMoveDest + nInstructionBytesDest, phome, r); + } + + // PATCH 1 TRAMP EXIT + intptr_t microprofile_tramp_exit = (intptr_t)ptramp + t_code_exit_offset; + memcpy(ptramp + t_enter_patch_offset + 2, (void*)µprofile_tramp_exit, 8); + + char* pintercept = t_code_intercept0_offset + ptramp; + + // PATCH 1.5 Argument + memcpy(pintercept - 4, (void*)&Argument, 4); + + // PATCH 2 INTERCEPT0 + intptr_t addr = (intptr_t)enter; //&intercept0; + memcpy(pintercept + 2, (void*)&addr, 8); + + // PATHC 2.5 argument + memcpy(ptramp + t_code_exit_offset + 3, (void*)&Argument, 4); + + intptr_t microprofile_tramp_leave = (intptr_t)ptramp + t_code_leave_offset; + // PATCH 3 INTERCEPT1 + intptr_t addr1 = (intptr_t)leave; //&intercept1; + memcpy((char*)microprofile_tramp_leave + 2, (void*)&addr1, 8); + + intptr_t patch_push_addr = (intptr_t)(&MicroProfile_Patch_TLS_PUSH); + intptr_t patch_pop_addr = (intptr_t)(&MicroProfile_Patch_TLS_POP); + memcpy((char*)ptramp + t_code_call_patch_push_offset + 2, &patch_push_addr, 8); + memcpy((char*)ptramp + t_code_call_patch_pop_offset + 2, &patch_pop_addr, 8); + MicroProfileMakeMemoryExecutable(ptramp, t_end_offset); + + { + // PATCH 4 DEST FUNC + + DWORD OldFlags[2] = { 0 }; + MicroProfileMakeWriteable(f, nInstructionBytesSrc, OldFlags); + char* pp = (char*)f; + char* ppend = pp + nInstructionBytesSrc; + + if(nInstructionBytesSrc < 14) + { + pp = MicroProfileInsertRelativeJump((char*)pp, (intptr_t)ptramp); + } + else + { + pp = MicroProfileInsertRegisterJump((char*)pp, (intptr_t)ptramp, R_RAX); + } + + while(pp != ppend) + { + char c = (unsigned char)0x90; + MP_ASSERT((unsigned char)c == (unsigned char)0x90); + *pp++ = (unsigned char)0x90; + } + MicroProfileRestore(f, nInstructionBytesSrc, OldFlags); + } + return true; +} + +static void MicroProfileMakeWriteable(void* p_, size_t s, DWORD* oldFlags) +{ + static uint64_t nPageSize = 4 << 10; + + intptr_t aligned = (intptr_t)p_; + aligned = (aligned & (~(nPageSize - 1))); + intptr_t aligned_end = (intptr_t)p_; + aligned_end += s; + aligned_end = (aligned_end + nPageSize - 1) & (~(nPageSize - 1)); + uint32_t nNumPages = (uint32_t)((aligned_end - aligned) / nPageSize); + MP_ASSERT(nNumPages >= 1 && nNumPages <= 2); + for(uint32_t i = 0; i < nNumPages; ++i) + { + if(!VirtualProtect((void*)(aligned + nPageSize * i), nPageSize, PAGE_EXECUTE_READWRITE, oldFlags + i)) + { + MP_BREAK(); + } + } + //*(unsigned char*)p_ = 0x90; +} + +static void MicroProfileRestore(void* p_, size_t s, DWORD* oldFlags) +{ + static uint64_t nPageSize = 4 << 10; + + intptr_t aligned = (intptr_t)p_; + aligned = (aligned & (~(nPageSize - 1))); + intptr_t aligned_end = (intptr_t)p_; + aligned_end += s; + aligned_end = (aligned_end + nPageSize - 1) & (~(nPageSize - 1)); + uint32_t nNumPages = (uint32_t)((aligned_end - aligned) / nPageSize); + DWORD Dummy; + for(uint32_t i = 0; i < nNumPages; ++i) + { + if(!VirtualProtect((void*)(aligned + nPageSize * i), nPageSize, oldFlags[i], &Dummy)) + { + MP_BREAK(); + } + } +} + +void* MicroProfileAllocExecutableMemoryUp(intptr_t nBase, size_t s, uint32_t RegionIndex) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + size_t Granularity = si.dwAllocationGranularity << 1; + nBase = (nBase / Granularity) * Granularity; + intptr_t nEnd = nBase + 0x80000000; + + for(uint32_t i = RegionIndex; i < S.MemoryRegions.Size; i++) + { + // try and allocate 2x before + nBase = S.MemoryRegions[i].Start + S.MemoryRegions[i].Size + Granularity; + nBase = (nBase / Granularity) * Granularity; + + if(nBase >= nEnd) + break; + void* pMemory = VirtualAlloc((void*)nBase, s, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if(pMemory) + { + return pMemory; + } + } + return nullptr; +} + +static void MicroProfileUpdateMemoryRegions() +{ + MicroProfileArrayClear(S.MemoryRegions); + SYSTEM_INFO si; + GetSystemInfo(&si); + + BYTE* Addr = (BYTE*)si.lpMinimumApplicationAddress; + BYTE* MaxAddr = (BYTE*)si.lpMaximumApplicationAddress; + // uprintf("updating memory regions\n"); + uint32_t idx = 0; + (void)idx; + while(Addr < MaxAddr) + { + MEMORY_BASIC_INFORMATION mbi; + SIZE_T Result = VirtualQuery(Addr, &mbi, sizeof(mbi)); + if(Result == 0) + break; + MicroProfileInstrumentMemoryRegion region; + region.Start = (intptr_t)mbi.BaseAddress; + region.Size = (intptr_t)mbi.RegionSize; + MicroProfileArrayPushBack(S.MemoryRegions, region); + // uprintf("Memory Region %d: %p(%p) %p .. State=%08x Protect=%08x Type=%08x\n", idx++, mbi.BaseAddress, mbi.AllocationBase, (intptr_t)mbi.BaseAddress + mbi.RegionSize, mbi.State, mbi.Protect, + // mbi.Type); + Addr = (BYTE*)mbi.BaseAddress + mbi.RegionSize; + } + uprintf("Iterated %d regions\n", S.MemoryRegions.Size); +} + +static void* MicroProfileAllocExecutableMemoryDown(intptr_t nBase, size_t s, uint32_t RegionIndex) +{ + SYSTEM_INFO si; + GetSystemInfo(&si); + size_t Granularity = si.dwAllocationGranularity << 1; + intptr_t nEnd = nBase - 0x80000000; + + for(int32_t i = RegionIndex; i >= 0; i--) + { + // try and allocate 2x before + nBase = S.MemoryRegions[i].Start - Granularity; + nBase = (nBase / Granularity) * Granularity; + if(nBase < nEnd) + break; + void* pMemory = VirtualAlloc((void*)nBase, s, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); + if(pMemory) + { + return pMemory; + } + } + return nullptr; +} + +static void* MicroProfileAllocExecutableMemory(void* pBase, size_t s) +{ + uint32_t RegionIndex = 0; + for(uint32_t i = 0; i < S.MemoryRegions.Size; ++i) + { + auto& R = S.MemoryRegions[i]; + if(R.Start <= (intptr_t)pBase && (intptr_t)pBase < R.Start + R.Size) + { + RegionIndex = i; + break; + } + } + + s = (s + 4095) & ~(4095); + intptr_t nBase = (intptr_t)pBase; + void* pResult = 0; + if(0 == pResult && nBase > 0x40000000) + { + pResult = MicroProfileAllocExecutableMemoryDown(nBase - 0x40000000, s, RegionIndex); + if(0 == pResult) + { + pResult = MicroProfileAllocExecutableMemoryUp(nBase - 0x40000000, s, RegionIndex); + } + } + if(0 == pResult && nBase < 0xffffffff40000000) + { + pResult = MicroProfileAllocExecutableMemoryUp(nBase + 0x40000000, s, RegionIndex); + if(0 == pResult) + { + pResult = MicroProfileAllocExecutableMemoryUp(nBase + 0x40000000, s, RegionIndex); + } + } + return pResult; +} +static void* MicroProfileAllocExecutableMemoryFar(size_t s) +{ + static uint64_t nPageSize = 4 << 10; + s = (s + (nPageSize - 1)) & (~(nPageSize - 1)); + + void* pMem = VirtualAlloc(0, s, MEM_COMMIT, PAGE_READWRITE); + MP_ASSERT(pMem); + + // uprintf("Allocating %zu %p\n", s, pMem); + return pMem; +} +static void MicroProfileMakeMemoryExecutable(void* p, size_t s) +{ + static uint64_t nPageSize = 4 << 10; + s = (s + (nPageSize - 1)) & (~(nPageSize - 1)); + DWORD Unused; + if(!VirtualProtect(p, s, PAGE_EXECUTE_READ, &Unused)) + { + MP_BREAK(); + } +} +#endif + +int MicroProfileTrimFunctionName(const char* pStr, char* pOutBegin, char* pOutEnd) +{ + const char* pStart = pOutBegin; + int l = (int)strlen(pStr) - 1; + int sz = 0; + pOutEnd--; + if(l < 1024 && pOutBegin != pOutEnd) + { + const char* p = pStr; + const char* pEnd = pStr + l + 1; + int in = 0; + while(p != pEnd && pOutBegin != pOutEnd) + { + char c = *p++; + if(c == '(' || c == '<') + { + in++; + } + else if(c == ')' || c == '>') + { + in--; + continue; + } + + if(in == 0) + { + *pOutBegin++ = c; + sz++; + } + } + + *pOutBegin++ = '\0'; + } + return sz; +} + +int MicroProfileFindFunctionName(const char* pStr, const char** ppStart) +{ + int l = (int)strlen(pStr) - 1; + if(l < 1024) + { + char b[1024] = { 0 }; + char* put = &b[0]; + + const char* p = pStr; + const char* pEnd = pStr + l + 1; + int in = 0; + while(p != pEnd) + { + char c = *p++; + if(c == '(' || c == '<') + { + in++; + } + else if(c == ')' || c == '>') + { + in--; + continue; + } + + if(in == 0) + { + *put++ = c; + } + } + + *put++ = '\0'; + uprintf("trimmed %s\n", b); + } + + // int nFirstParen = l; + int nNumParen = 0; + int c = 0; + + while(l >= 0 && pStr[l] != ')' && c++ < sizeof(" const") - 1) + { + l--; + } + if(pStr[l] == ')') + { + do + { + if(pStr[l] == ')') + { + nNumParen++; + } + else if(pStr[l] == '(') + { + nNumParen--; + } + l--; + } while(nNumParen > 0 && l >= 0); + } + else + { + *ppStart = pStr; + return 0; + } + while(l >= 0 && isspace(pStr[l])) + { + --l; + } + int nLast = l; + while(l >= 0 && !isspace(pStr[l])) + { + l--; + } + int nFirst = l; + if(nFirst == nLast) + return 0; + int nCount = nLast - nFirst + 1; + *ppStart = pStr + nFirst; + return nCount; +} + +#include +#include +#include +#include +struct MicroProfileQueryContext +{ + + const char* pFilterStrings[MICROPROFILE_MAX_FILTER]; + uint32_t nPatternLength[MICROPROFILE_MAX_FILTER]; + int nMaxFilter = 0; + char TempBuffer[128]; + uint32_t size = 0; + bool bFirst = false; +}; + +BOOL CALLBACK MicroProfileEnumModules(_In_ PCTSTR ModuleName, _In_ DWORD64 BaseOfDll, _In_opt_ PVOID UserContext) +{ + + MODULEINFO MI; + GetModuleInformation(GetCurrentProcess(), (HMODULE)BaseOfDll, &MI, sizeof(MI)); + MEMORY_BASIC_INFORMATION B; + int r = VirtualQuery((LPCVOID)BaseOfDll, (MEMORY_BASIC_INFORMATION*)&B, sizeof(B)); + char buffer[1024]; + int r1 = GetLastError(); + if(r == 0) + { + stbsp_snprintf(buffer, sizeof(buffer) - 1, "Error %d\n", r1); + OutputDebugString(buffer); + MP_BREAK(); + } + MicroProfileSymbolInitModule(ModuleName, BaseOfDll, BaseOfDll + MI.SizeOfImage); + return true; +} + +namespace +{ +struct QueryCallbackBase // fucking c++, this is a pain in the ass +{ + virtual void CB(const char* pName, const char* pShortName, intptr_t addr, intptr_t addrend, uint32_t nModuleId) = 0; +}; +template +struct QueryCallbackImpl : public QueryCallbackBase +{ + T t; + QueryCallbackImpl(T t) + : t(t) + { + } + virtual void CB(const char* pName, const char* pShortName, intptr_t addr, intptr_t addrend, uint32_t nModuleId) + { + t(pName, pShortName, addr, addrend, nModuleId); + } +}; +} // namespace + +static uint32_t nLastModuleIdWin32 = (uint32_t)-1; +static intptr_t nLastModuleBaseWin32 = (intptr_t)-1; + +BOOL MicroProfileQueryContextEnumSymbols(_In_ PSYMBOL_INFO pSymInfo, _In_ ULONG SymbolSize, _In_opt_ PVOID UserContext) +{ + uint32_t nModuleId = nLastModuleIdWin32; + if(nLastModuleBaseWin32 != (intptr_t)pSymInfo->ModBase) + { + nLastModuleIdWin32 = nModuleId = MicroProfileSymbolGetModule((const char*)(intptr_t)-2, pSymInfo->ModBase); + nLastModuleBaseWin32 = (intptr_t)pSymInfo->ModBase; + } + + if(pSymInfo->Tag == 5 || pSymInfo->Tag == 10) + { + + char FunctionName[1024]; + int ret = 0; + int l = MicroProfileTrimFunctionName(pSymInfo->Name, &FunctionName[0], &FunctionName[1024]); + QueryCallbackBase* pCB = (QueryCallbackBase*)UserContext; + + pCB->CB(pSymInfo->Name, l ? &FunctionName[0] : 0, (intptr_t)pSymInfo->Address, pSymInfo->Size + (intptr_t)pSymInfo->Address, nModuleId); + } + return TRUE; +}; + +bool MicroProfileDemangleName(const char* pName, char* OutName, uint32_t Size) +{ + MICROPROFILE_SCOPEI("microprofile", "SymbolDemangle", MP_AUTO); + if(UnDecorateSymbolName(pName, OutName, Size, UNDNAME_NAME_ONLY)) + { + return true; + } + return false; +} + +bool MicroProfileExtractPdbInfo(HMODULE hMod, GUID& guid, DWORD& age, char pdbName[MAX_PATH]) +{ + struct CV_INFO_PDB70 + { + DWORD CvSignature; // "RSDS" + GUID Signature; // GUID + DWORD Age; // Age + char PdbFileName[1]; // Null-terminated string + }; + + BYTE* base = (BYTE*)hMod; + IMAGE_DOS_HEADER* dos = (IMAGE_DOS_HEADER*)base; + if(dos->e_magic != IMAGE_DOS_SIGNATURE) + return false; + IMAGE_NT_HEADERS* nt = (IMAGE_NT_HEADERS*)(base + dos->e_lfanew); + if(nt->Signature != IMAGE_NT_SIGNATURE) + return false; + auto& dd = nt->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_DEBUG]; + if(!dd.VirtualAddress || !dd.Size) + return false; + IMAGE_DEBUG_DIRECTORY* debugDir = (IMAGE_DEBUG_DIRECTORY*)(base + dd.VirtualAddress); + int count = dd.Size / sizeof(IMAGE_DEBUG_DIRECTORY); + for(int i = 0; i < count; i++) + { + if(debugDir[i].Type == IMAGE_DEBUG_TYPE_CODEVIEW) + { + auto cv = (CV_INFO_PDB70*)(base + debugDir[i].AddressOfRawData); + if(cv->CvSignature != 'SDSR') + continue; // "RSDS" + guid = cv->Signature; + age = cv->Age; + strcpy_s(pdbName, MAX_PATH, cv->PdbFileName); + return true; + } + } + return false; +} + +bool MicroProfileDownloadPDB(HMODULE Module, HANDLE Process, char outPath[MAX_PATH]) +{ + GUID guid; + DWORD age; + char pdbName[MAX_PATH]; + if(!MicroProfileExtractPdbInfo(Module, guid, age, pdbName)) + { + uprintf("Failed to download pdb\n"); + MP_BREAK(); + return false; + } + uprintf("pdb name %s age %d\n", pdbName, age); + + FILE* f = fopen(pdbName, "r"); + if(f) + { + fclose(f); + strcpy_s(outPath, MAX_PATH, pdbName); + return true; + } + char localPath[MAX_PATH] = {}; + BOOL ok = SymFindFileInPath(Process, + NULL, + pdbName, + (PVOID)&guid, // GUID + age, // Age + 0, // FileSize (not used for PDBs) + SSRVOPT_GUIDPTR, // we're passing GUID pointer + outPath, + NULL, + NULL); + return ok != 0; +} + +#include "PDB.h" +#include "PDB_DBIStream.h" +#include "PDB_IPIStream.h" +#include "PDB_InfoStream.h" +#include "PDB_NamesStream.h" +#include "PDB_RawFile.h" +#include "PDB_TPIStream.h" + +template +void MicroProfileLoadRawPDB(Callback CB, const char* Filename, uint64_t Base, uint32_t nModuleId) +{ + auto OnSymbol = [CB, Base, nModuleId](const char* Sym, uint32_t Offset, uint32_t Size) + { + char FunctionName[1024]; + int ret = 0; + int l = MicroProfileTrimFunctionName(Sym, &FunctionName[0], &FunctionName[1024]); + const char* fname = l ? &FunctionName[0] : nullptr; + CB(Sym, fname, (intptr_t)Offset + Base, (intptr_t)Offset + Base + Size, nModuleId); + }; + + void* File = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_READONLY, nullptr); + + if(File == INVALID_HANDLE_VALUE) + { + MP_BREAK(); + } + + void* FileMapping = CreateFileMappingA(File, nullptr, PAGE_READONLY, 0, 0, nullptr); + + if(FileMapping == nullptr) + { + CloseHandle(File); + MP_BREAK(); + } + + void* BaseAddress = MapViewOfFile(FileMapping, FILE_MAP_READ, 0, 0, 0); + + if(BaseAddress == nullptr) + { + CloseHandle(FileMapping); + CloseHandle(File); + } + + BY_HANDLE_FILE_INFORMATION FileInformation; + const bool GetInformationResult = GetFileInformationByHandle(File, &FileInformation); + if(!GetInformationResult) + { + UnmapViewOfFile(BaseAddress); + CloseHandle(FileMapping); + CloseHandle(File); + + MP_BREAK(); + } + + const size_t FileSizeHighBytes = static_cast(FileInformation.nFileSizeHigh) << 32; + const size_t FileSizeLowBytes = FileInformation.nFileSizeLow; + const size_t FileSize = FileSizeHighBytes | FileSizeLowBytes; + + const PDB::RawFile RawPdbFile = PDB::CreateRawFile(BaseAddress); + if(PDB::HasValidDBIStream(RawPdbFile) != PDB::ErrorCode::Success) + { + MP_BREAK(); + } + const PDB::InfoStream InfoStream(RawPdbFile); + if(InfoStream.UsesDebugFastLink()) + { + MP_BREAK(); + } + + // const PDB::Header* h = InfoStream.GetHeader(); + // uprintf("Version %u, signature %u, age %u, GUID %08x-%04x-%04x-%02x%02x%02x%02x%02x%02x%02x%02x\n", + // static_cast(h->version), h->signature, h->age, + // h->guid.Data1, h->guid.Data2, h->guid.Data3, + // h->guid.Data4[0], h->guid.Data4[1], h->guid.Data4[2], h->guid.Data4[3], h->guid.Data4[4], h->guid.Data4[5], h->guid.Data4[6], h->guid.Data4[7]); + + const PDB::DBIStream DbiStream = PDB::CreateDBIStream(RawPdbFile); + if(PDB::ErrorCode::Success != DbiStream.HasValidSymbolRecordStream(RawPdbFile)) + { + MP_BREAK(); + } + + if(PDB::ErrorCode::Success != DbiStream.HasValidPublicSymbolStream(RawPdbFile)) + { + MP_BREAK(); + } + + if(PDB::ErrorCode::Success != DbiStream.HasValidGlobalSymbolStream(RawPdbFile)) + { + MP_BREAK(); + } + + if(PDB::ErrorCode::Success != DbiStream.HasValidSectionContributionStream(RawPdbFile)) + { + MP_BREAK(); + } + + if(PDB::ErrorCode::Success != DbiStream.HasValidImageSectionStream(RawPdbFile)) + { + MP_BREAK(); + } + + const PDB::ImageSectionStream ImageSectionStream = DbiStream.CreateImageSectionStream(RawPdbFile); + const PDB::ModuleInfoStream ModuleInfoStream = DbiStream.CreateModuleInfoStream(RawPdbFile); + const PDB::CoalescedMSFStream SymbolRecordStream = DbiStream.CreateSymbolRecordStream(RawPdbFile); + + const PDB::ArrayView modules = ModuleInfoStream.GetModules(); + + for(const PDB::ModuleInfoStream::Module& module : modules) + { + if(!module.HasSymbolStream()) + { + continue; + } + + const PDB::ModuleSymbolStream moduleSymbolStream = module.CreateSymbolStream(RawPdbFile); + moduleSymbolStream.ForEachSymbol( + [&ImageSectionStream, &OnSymbol](const PDB::CodeView::DBI::Record* record) + { + // only grab function symbols from the module streams + const char* name = nullptr; + uint32_t rva = 0u; + uint32_t size = 0u; + if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_FRAMEPROC) + { + // functionSymbols[functionSymbols.size() - 1].frameProc = record; + return; + } + else if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_THUNK32) + { + if(record->data.S_THUNK32.thunk == PDB::CodeView::DBI::ThunkOrdinal::TrampolineIncremental) + { + // we have never seen incremental linking thunks stored inside a S_THUNK32 symbol, but better safe than sorry + name = "ILT"; + rva = ImageSectionStream.ConvertSectionOffsetToRVA(record->data.S_THUNK32.section, record->data.S_THUNK32.offset); + size = 5u; + } + } + else if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_TRAMPOLINE) + { + // incremental linking thunks are stored in the linker module + name = "ILT"; + rva = ImageSectionStream.ConvertSectionOffsetToRVA(record->data.S_TRAMPOLINE.thunkSection, record->data.S_TRAMPOLINE.thunkOffset); + size = 5u; + } + else if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_LPROC32) + { + name = record->data.S_LPROC32.name; + rva = ImageSectionStream.ConvertSectionOffsetToRVA(record->data.S_LPROC32.section, record->data.S_LPROC32.offset); + size = record->data.S_LPROC32.codeSize; + } + else if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_GPROC32) + { + name = record->data.S_GPROC32.name; + rva = ImageSectionStream.ConvertSectionOffsetToRVA(record->data.S_GPROC32.section, record->data.S_GPROC32.offset); + size = record->data.S_GPROC32.codeSize; + } + else if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_LPROC32_ID) + { + name = record->data.S_LPROC32_ID.name; + rva = ImageSectionStream.ConvertSectionOffsetToRVA(record->data.S_LPROC32_ID.section, record->data.S_LPROC32_ID.offset); + size = record->data.S_LPROC32_ID.codeSize; + } + else if(record->header.kind == PDB::CodeView::DBI::SymbolRecordKind::S_GPROC32_ID) + { + name = record->data.S_GPROC32_ID.name; + rva = ImageSectionStream.ConvertSectionOffsetToRVA(record->data.S_GPROC32_ID.section, record->data.S_GPROC32_ID.offset); + size = record->data.S_GPROC32_ID.codeSize; + } + + if(rva == 0u) + { + return; + } + // uprintf("func %p / %d .. %s \n", rva, size, name); + OnSymbol(name, rva, size); + }); + } + const PDB::PublicSymbolStream PublicSymbolStream = DbiStream.CreatePublicSymbolStream(RawPdbFile); + { + const PDB::ArrayView HashRecords = PublicSymbolStream.GetRecords(); + const size_t Count = HashRecords.GetLength(); + + for(const PDB::HashRecord& HashRecord : HashRecords) + { + const PDB::CodeView::DBI::Record* Record = PublicSymbolStream.GetRecord(SymbolRecordStream, HashRecord); + if(Record->header.kind != PDB::CodeView::DBI::SymbolRecordKind::S_PUB32) + { + continue; + } + + if((PDB_AS_UNDERLYING(Record->data.S_PUB32.flags) & PDB_AS_UNDERLYING(PDB::CodeView::DBI::PublicSymbolFlags::Function)) == 0u) + { + continue; + } + + const uint32_t rva = ImageSectionStream.ConvertSectionOffsetToRVA(Record->data.S_PUB32.section, Record->data.S_PUB32.offset); + if(rva == 0u) + { + continue; + } + OnSymbol(Record->data.S_PUB32.name, rva, 0); + } + } + UnmapViewOfFile(BaseAddress); + CloseHandle(FileMapping); + CloseHandle(File); +} + +bool MicroProfilePatchHasSuspendedThread(intptr_t Begin, intptr_t End) +{ + MicroProfileSuspendState& State = S.SuspendState; + for(uint32_t i = 0; i < State.NumSuspended; ++i) + { + intptr_t ip = State.SuspendedIP[i]; + if(Begin <= ip && ip <= End) + return true; + } + return false; +} + +bool MicroProfilePatchBeginSuspend() +{ + MicroProfileSuspendState& State = S.SuspendState; + + if(State.SuspendCounter++ > 0) + return true; + MicroProfileUpdateMemoryRegions(); + + MicroProfileMutex().lock(); + MP_ASSERT(State.NumSuspended == 0); + + DWORD ProcessId = GetCurrentProcessId(); + DWORD ThreadId = GetCurrentThreadId(); + + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0); + if(hSnap == INVALID_HANDLE_VALUE) + { + return false; + } + THREADENTRY32 te{}; + te.dwSize = sizeof(te); + State.NumSuspended = 0; + + if(Thread32First(hSnap, &te)) + { + do + { + if(te.th32OwnerProcessID != ProcessId) + continue; + if(te.th32ThreadID == ThreadId) + continue; + HANDLE hThread = OpenThread(THREAD_SUSPEND_RESUME | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, FALSE, te.th32ThreadID); + if(!hThread) + { + continue; + } + DWORD PrevCount = SuspendThread(hThread); + if(PrevCount == (DWORD)-1) + { + CloseHandle(hThread); + continue; + } + + CONTEXT ctx{}; + ctx.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER; // Rip + registers + if(GetThreadContext(hThread, &ctx)) + { + State.SuspendedIP[State.NumSuspended] = (intptr_t)ctx.Rip; + } + if(State.NumSuspended < MICROPROFILE_SUSPEND_MAX) + { + State.Suspended[State.NumSuspended++] = hThread; + } + } while(Thread32Next(hSnap, &te)); + } + else + { + uprintf("Thread32First failed %08x\n", GetLastError()); + CloseHandle(hSnap); + return false; + } + CloseHandle(hSnap); + return State.NumSuspended > 0; +} + +void MicroProfilePatchEndSuspend() +{ + MicroProfileSuspendState& State = S.SuspendState; + if(0 == --State.SuspendCounter) + { + + for(uint32_t i = 0; i < State.NumSuspended; ++i) + { + ResumeThread(State.Suspended[i]); + CloseHandle(State.Suspended[i]); + } + State.NumSuspended = 0; + MicroProfileMutex().unlock(); + } +} + +template +void MicroProfileIterateSymbols(Callback CB, uint32_t* nModules, uint32_t nNumModules) +{ + MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileIterateSymbols", MP_PINK3); + QueryCallbackImpl Context(CB); + if(MicroProfileSymInit()) + { + // uprintf("symbols loaded!\n"); + // API_VERSION* pv = ImagehlpApiVersion(); + // uprintf("VERSION %d.%d.%d\n", pv->MajorVersion, pv->MinorVersion, pv->Revision); + + nLastModuleBaseWin32 = -1; + if(SymEnumerateModules64(GetCurrentProcess(), (PSYM_ENUMMODULES_CALLBACK64)MicroProfileEnumModules, NULL)) + { + } + QueryCallbackBase* pBase = &Context; + if(nNumModules) + { + HANDLE hProcess = GetCurrentProcess(); + char buffer[sizeof(SYMBOL_INFO) + MAX_SYM_NAME * sizeof(TCHAR)]; + PSYMBOL_INFO pSymbol = (PSYMBOL_INFO)buffer; + uint64_t t0 = MP_TICK(); + for(uint32_t i = 0; i < nNumModules; ++i) + { + uint32_t nModule = nModules[i]; + int64_t nBytes = 0; + MEMORY_BASIC_INFORMATION B; + + for(int j = 0; j < S.SymbolModules[nModule].nNumExecutableRegions; ++j) + { + intptr_t b = S.SymbolModules[nModule].Regions[j].nBegin; + intptr_t e = S.SymbolModules[nModule].Regions[j].nEnd; + while(b < e) + { + int r = VirtualQuery((LPCVOID)b, &B, sizeof(B)); + if(!r) + break; + switch(B.Protect) + { + case PAGE_EXECUTE: + case PAGE_EXECUTE_READ: + case PAGE_EXECUTE_READWRITE: + case PAGE_EXECUTE_WRITECOPY: + nBytes += B.RegionSize; + // uprintf("RANGE %p, %p .. %5.2fkb %08x, %08x\n", B.BaseAddress, (void*)(intptr_t(B.BaseAddress) + B.RegionSize), B.RegionSize / 1024.f, B.State, B.Protect); + } + b = intptr_t(B.BaseAddress) + B.RegionSize; + } + } + S.SymbolModules[nModule].nProgressTarget = nBytes; + + char pdbPath[MAX_PATH]; + HMODULE Module = (HMODULE)S.SymbolModules[nModule].nModuleBase; + S.nSymbolsDirty++; + S.SymbolModules[nModule].bDownloading = true; + if(MicroProfileDownloadPDB(Module, hProcess, pdbPath)) + { + S.SymbolModules[nModule].bDownloading = false; + S.nSymbolsDirty++; + MicroProfileLoadRawPDB(CB, pdbPath, S.SymbolModules[nModule].nModuleBase, nModule); + } + S.SymbolModules[nModule].bDownloading = false; + S.nSymbolsDirty++; + S.SymbolModules[nModule].nProgress = S.SymbolModules[nModule].nProgressTarget; + S.SymbolModules[nModule].nModuleLoadFinished.exchange(1); + } + + uint64_t t1 = MP_TICK(); + float fTime = float(MicroProfileTickToMsMultiplierCpu()) * (t1 - t0); + uprintf("load symbol time %6.2fms\n", fTime); + } + MicroProfileSymCleanup(); + } +} + +static int MicroProfileWin32SymInitCount = 0; +static int MicroProfileWin32SymInitSuccess = 0; + +bool MicroProfileSymInit() +{ + if(0 == MicroProfileWin32SymInitCount++) + { + auto h = GetCurrentProcess(); + SymCleanup(h); + SymSetOptions(SYMOPT_DEFERRED_LOADS); + if(SymInitialize(h, 0, FALSE)) + { + + MicroProfileWin32SymInitSuccess = 1; + char Path[MAX_PATH]; + bool PathValid = SymGetSearchPath(h, Path, MAX_PATH) > 0; + if(PathValid) + { + PathValid = strlen(Path) > 3; + } + if(!PathValid) + { + SymSetSearchPath(h, "srv*C:\\symbols*https://msdl.microsoft.com/download/symbols"); + } + } + else + { + MicroProfileWin32SymInitSuccess = 0; + } + } + return MicroProfileWin32SymInitSuccess != 0; +} +void MicroProfileSymCleanup() +{ + if(0 == --MicroProfileWin32SymInitCount) + { + MicroProfileWin32SymInitSuccess = 0; + SymCleanup(GetCurrentProcess()); + } +} + +static void* g_pFunctionFoundHack = 0; +static const char* g_pFunctionpNameFound = 0; +static char g_Demangled[512]; + +BOOL MicroProfileQueryContextEnumSymbols1(_In_ PSYMBOL_INFO pSymInfo, _In_ ULONG SymbolSize, _In_opt_ PVOID UserContext) +{ + if(pSymInfo->Tag == 5 || pSymInfo->Tag == 10) + { + char str[200]; + stbsp_snprintf(str, sizeof(str) - 1, "%s : %p\n", pSymInfo->Name, (void*)pSymInfo->Address); + OutputDebugStringA(str); + g_pFunctionpNameFound = pSymInfo->Name; + g_pFunctionFoundHack = (void*)pSymInfo->Address; + return FALSE; + } + return TRUE; +}; + +const char* MicroProfileDemangleSymbol(const char* pSymbol) +{ + return pSymbol; // todo: for some reasons all symbols im seaing right now are already undecorated? +} + +void MicroProfileInstrumentWithoutSymbols(const char** pModules, const char** pSymbols, uint32_t nNumSymbols) +{ + char SymString[512]; + const char* pStr = 0; + if(MicroProfileSymInit()) + { + HANDLE h = GetCurrentProcess(); + for(uint32_t i = 0; i < nNumSymbols; ++i) + { + int nCount = stbsp_snprintf(SymString, sizeof(SymString) - 1, "%s!%s", pModules[i], pSymbols[i]); + if(nCount <= sizeof(SymString) - 1) + { + g_pFunctionFoundHack = 0; + if(SymEnumSymbols(h, 0, SymString, MicroProfileQueryContextEnumSymbols1, 0)) + { + if(g_pFunctionFoundHack) + { + uint32_t nColor = MicroProfileColorFromString(pSymbols[i]); + const char* pDemangled = pSymbols[i]; // MicroProfileDemangleSymbol(pSymbols[i]); + MicroProfileInstrumentFunction(g_pFunctionFoundHack, pModules[i], pDemangled, nColor); + } + } + } + } + MicroProfileSymCleanup(); + } +} + +void MicroProfileSymbolEnumModules() +{ + HMODULE modules[1024]; + DWORD needed; + HANDLE h = GetCurrentProcess(); + + if(EnumProcessModules(h, modules, sizeof(modules), &needed)) + { + int count = needed / sizeof(HMODULE); + for(int i = 0; i < count; i++) + { + char moduleName[MAX_PATH]; + if(GetModuleFileNameEx(h, modules[i], moduleName, MAX_PATH)) + { + MODULEINFO mi = {}; + if(GetModuleInformation(h, modules[i], &mi, sizeof(mi))) + { + MicroProfileEnumModules(moduleName, (DWORD64)mi.lpBaseOfDll, 0); + } + } + } + } +} + +void MicroProfileSymbolUpdateModuleList() +{ + MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileSymbolUpdateModuleList", MP_PINK3); + // QueryCallbackImpl Context(CB); + if(MicroProfileSymInit()) + { + uprintf("symbols loaded!\n"); + API_VERSION* pv = ImagehlpApiVersion(); + uprintf("VERSION %d.%d.%d\n", pv->MajorVersion, pv->MinorVersion, pv->Revision); + + nLastModuleBaseWin32 = -1; + MicroProfileSymbolEnumModules(); + MicroProfileSymCleanup(); + } +} + +#endif + +#if defined(__APPLE__) && defined(__MACH__) +// '##::::'##::'#######:::'#######::'##:::'##:::::'#######:::'######::'##::::'##: +// ##:::: ##:'##.... ##:'##.... ##: ##::'##:::::'##.... ##:'##... ##:. ##::'##:: +// ##:::: ##: ##:::: ##: ##:::: ##: ##:'##:::::: ##:::: ##: ##:::..:::. ##'##::: +// #########: ##:::: ##: ##:::: ##: #####::::::: ##:::: ##:. ######::::. ###:::: +// ##.... ##: ##:::: ##: ##:::: ##: ##. ##:::::: ##:::: ##::..... ##::: ## ##::: +// ##:::: ##: ##:::: ##: ##:::: ##: ##:. ##::::: ##:::: ##:'##::: ##:: ##:. ##:: +// ##:::: ##:. #######::. #######:: ##::. ##::::. #######::. ######:: ##:::. ##: +// ..:::::..:::.......::::.......:::..::::..::::::.......::::......:::..:::::..:: + +#include +#include +#include +#include +#include +#include +#include +#include + +static void* MicroProfileAllocExecutableMemory(void* f, size_t s); +static void MicroProfileMakeWriteable(void* p_); + +extern "C" void microprofile_tramp_enter_patch(); +extern "C" void microprofile_tramp_enter(); +extern "C" void microprofile_tramp_code_begin(); +extern "C" void microprofile_tramp_code_end(); +extern "C" void microprofile_tramp_intercept0(); +extern "C" void microprofile_tramp_end(); +extern "C" void microprofile_tramp_exit(); +extern "C" void microprofile_tramp_leave(); +extern "C" void microprofile_tramp_trunk(); +extern "C" void microprofile_tramp_call_patch_pop(); +extern "C" void microprofile_tramp_call_patch_push(); + +bool MicroProfilePatchFunction(void* f, int Argument, MicroProfileHookFunc enter, MicroProfileHookFunc leave, MicroProfilePatchError* pError) __attribute__((optnone)) +{ + if(pError) + { + memcpy(&pError->Code[0], f, 12); + } + + intptr_t t_enter = (intptr_t)microprofile_tramp_enter; + intptr_t t_enter_patch_offset = (intptr_t)microprofile_tramp_enter_patch - t_enter; + intptr_t t_code_begin_offset = (intptr_t)microprofile_tramp_code_begin - t_enter; + intptr_t t_code_end_offset = (intptr_t)microprofile_tramp_code_end - t_enter; + intptr_t t_code_intercept0_offset = (intptr_t)microprofile_tramp_intercept0 - t_enter; + intptr_t t_code_exit_offset = (intptr_t)microprofile_tramp_exit - t_enter; + intptr_t t_code_leave_offset = (intptr_t)microprofile_tramp_leave - t_enter; + + intptr_t t_code_call_patch_push_offset = (intptr_t)microprofile_tramp_call_patch_push - t_enter; + intptr_t t_code_call_patch_pop_offset = (intptr_t)microprofile_tramp_call_patch_pop - t_enter; + intptr_t codemaxsize = t_code_end_offset - t_code_begin_offset; + intptr_t t_end_offset = (intptr_t)microprofile_tramp_end - t_enter; + intptr_t t_trunk_offset = (intptr_t)microprofile_tramp_trunk - t_enter; + intptr_t t_trunk_size = (intptr_t)microprofile_tramp_end - (intptr_t)microprofile_tramp_trunk; + + char* ptramp = (char*)MicroProfileAllocExecutableMemory(f, t_end_offset); + + intptr_t offset = ((intptr_t)f + 6 - (intptr_t)ptramp); + + uint32_t nBytesToCopy = 14; + if(offset < 0x80000000 && offset > -0x7fffffff) + { + /// offset is small enough to insert a relative jump + nBytesToCopy = 5; + } + + memcpy(ptramp, (void*)t_enter, t_end_offset); + + int nInstructionBytesDest = 0; + char* pInstructionMoveDest = ptramp + t_code_begin_offset; + char* pTrunk = ptramp + t_trunk_offset; + + int nInstructionBytesSrc = 0; + + uint32_t nRegsWritten = 0; + uint32_t nRetSafe = 0; + uint32_t nUsableJumpRegs = (1 << R_RAX) | (1 << R_R10) | (1 << R_R11); // scratch && !parameter register + if(!MicroProfileCopyInstructionBytes( + pInstructionMoveDest, f, nBytesToCopy, codemaxsize, pTrunk, t_trunk_size, nUsableJumpRegs, &nInstructionBytesDest, &nInstructionBytesSrc, &nRegsWritten, &nRetSafe)) + { + if(pError) + { + const char* pCode = (const char*)f; + memset(pError->Code, 0, sizeof(pError->Code)); + memcpy(pError->Code, pCode, nInstructionBytesSrc); + int off = stbsp_snprintf(pError->Message, sizeof(pError->Message), "Failed to move %d code bytes ", nInstructionBytesSrc); + pError->nCodeSize = nInstructionBytesSrc; + for(int i = 0; i < nInstructionBytesSrc; ++i) + { + off += stbsp_snprintf(off + pError->Message, sizeof(pError->Message) - off, "%02x ", 0xff & pCode[i]); + } + uprintf("%s\n", pError->Message); + } + return false; + } + intptr_t phome = nInstructionBytesSrc + (intptr_t)f; + uint32_t reg = nUsableJumpRegs & ~nRegsWritten; + static_assert(R_RAX == 0, "R_RAX must be 0"); + if(0 == reg) + { + if(nRetSafe == 0) + { + MP_BREAK(); // shout fail earlier + } + MicroProfileInsertRetJump(pInstructionMoveDest + nInstructionBytesDest, phome); + } + else + { + int r = R_RAX; + while((reg & 1) == 0) + { + reg >>= 1; + r++; + } + MicroProfileInsertRegisterJump(pInstructionMoveDest + nInstructionBytesDest, phome, r); + } + + // PATCH 1 TRAMP EXIT + intptr_t microprofile_tramp_exit = (intptr_t)ptramp + t_code_exit_offset; + memcpy(ptramp + t_enter_patch_offset + 2, (void*)µprofile_tramp_exit, 8); + + char* pintercept = t_code_intercept0_offset + ptramp; + + // PATCH 1.5 Argument + memcpy(pintercept - 4, (void*)&Argument, 4); + + // PATCH 2 INTERCEPT0 + intptr_t addr = (intptr_t)enter; //&intercept0; + memcpy(pintercept + 2, (void*)&addr, 8); + + // PATHC 2.5 argument + memcpy(ptramp + t_code_exit_offset + 3, (void*)&Argument, 4); + + intptr_t microprofile_tramp_leave = (intptr_t)ptramp + t_code_leave_offset; + // PATCH 3 INTERCEPT1 + intptr_t addr1 = (intptr_t)leave; //&intercept1; + memcpy((char*)microprofile_tramp_leave + 2, (void*)&addr1, 8); + + intptr_t patch_push_addr = (intptr_t)(&MicroProfile_Patch_TLS_PUSH); + intptr_t patch_pop_addr = (intptr_t)(&MicroProfile_Patch_TLS_POP); + memcpy((char*)ptramp + t_code_call_patch_push_offset + 2, &patch_push_addr, 8); + memcpy((char*)ptramp + t_code_call_patch_pop_offset + 2, &patch_pop_addr, 8); + + { + // PATCH 4 DEST FUNC + + MicroProfileMakeWriteable(f); + char* pp = (char*)f; + char* ppend = pp + nInstructionBytesSrc; + if(nInstructionBytesSrc < 14) + { + uprintf("inserting 5b jump\n"); + pp = MicroProfileInsertRelativeJump((char*)pp, (intptr_t)ptramp); + } + else + { + uprintf("inserting 14b jump\n"); + pp = MicroProfileInsertRegisterJump(pp, (intptr_t)ptramp, R_RAX); + } + while(pp != ppend) + { + *pp++ = 0x90; + } + } + return true; +} + +static void MicroProfileMakeWriteable(void* p_) +{ +#ifdef _PATCH_TEST + // for testing.. + static const uint32_t WritableSize = 16; + static uint32_t WritableCount = 0; + static intptr_t WritableStart[WritableSize] = { 0 }; + static intptr_t WritableEnd[WritableSize] = { 0 }; + for(uint32_t i = 0; i < WritableCount; ++i) + { + intptr_t x = (intptr_t)p_; + if(x >= WritableStart[i] && x < WritableEnd[i]) + { + return; + } + } + +#endif + + intptr_t p = (intptr_t)p_; + // uprintf("MicroProfilemakewriteable %lx\n", p); + mach_port_name_t task = mach_task_self(); + vm_map_offset_t vmoffset = 0; + mach_vm_size_t vmsize = 0; + uint32_t nd; + kern_return_t kr; + vm_region_submap_info_64 vbr; + mach_msg_type_number_t vbrcount = sizeof(vbr) / 4; + + while(KERN_SUCCESS == (kr = mach_vm_region_recurse(task, &vmoffset, &vmsize, &nd, (vm_region_recurse_info_t)&vbr, &vbrcount))) + { + if(p >= (intptr_t)vmoffset && p <= intptr_t(vmoffset + vmsize)) + { + if(0 == (vbr.protection & VM_PROT_WRITE)) + { + // uprintf("region match .. enabling write\n"); + int x = mprotect((void*)vmoffset, vmsize, PROT_WRITE | PROT_READ | PROT_EXEC); + if(x) + { + // uprintf("mprotect failed ... err %d:: %d %s\n", errno, x, strerror(errno)); + } + else + { + uprintf("region is [%llx,%llx] .. %08llx %d", vmoffset, vmoffset + vmsize, vmsize, vbr.is_submap); + uprintf("prot: %c%c%c %c%c%c\n", + vbr.protection & VM_PROT_READ ? 'r' : '-', + vbr.protection & VM_PROT_WRITE ? 'w' : '-', + vbr.protection & VM_PROT_EXECUTE ? 'x' : '-', + + vbr.max_protection & VM_PROT_READ ? 'r' : '-', + vbr.max_protection & VM_PROT_WRITE ? 'w' : '-', + vbr.max_protection & VM_PROT_EXECUTE ? 'x' : '-'); + continue; + } + } + else + { +#ifdef _PATCH_TEST + if(WritableCount < WritableSize) + { + WritableStart[WritableCount] = vmoffset; + WritableEnd[WritableCount] = vmoffset + vmsize; + WritableCount++; + } + +#endif + } + } + + vmoffset += vmsize; + vbrcount = sizeof(vbr) / 4; + } +} + +int MicroProfileTrimFunctionName(const char* pStr, char* pOutBegin, char* pOutEnd) +{ + int l = strlen(pStr) - 1; + int sz = 0; + pOutEnd--; + if(l < pOutEnd - pOutBegin && pOutBegin != pOutEnd) + { + const char* p = pStr; + const char* pEnd = pStr + l + 1; + int in = 0; + while(p != pEnd && pOutBegin != pOutEnd) + { + char c = *p++; + if(c == '(' || c == '<') + { + in++; + } + else if(c == ')' || c == '>') + { + in--; + continue; + } + + if(in == 0) + { + *pOutBegin++ = c; + sz++; + } + } + + *pOutBegin++ = '\0'; + } + return sz; +} + +int MicroProfileFindFunctionName(const char* pStr, const char** ppStart) +{ + int l = strlen(pStr) - 1; + if(l < 1024) + { + char b[1024] = { 0 }; + char* put = &b[0]; + + const char* p = pStr; + const char* pEnd = pStr + l + 1; + int in = 0; + while(p != pEnd) + { + char c = *p++; + if(c == '(' || c == '<') + { + in++; + } + else if(c == ')' || c == '>') + { + in--; + continue; + } + + if(in == 0) + { + *put++ = c; + } + } + + *put++ = '\0'; + uprintf("trimmed %s\n", b); + } + + // int nFirstParen = l; + int nNumParen = 0; + int c = 0; + + while(l >= 0 && pStr[l] != ')' && c++ < (int)(sizeof(" const") - 1)) + { + l--; + } + if(pStr[l] == ')') + { + do + { + if(pStr[l] == ')') + { + nNumParen++; + } + else if(pStr[l] == '(') + { + nNumParen--; + } + l--; + } while(nNumParen > 0 && l >= 0); + } + else + { + *ppStart = pStr; + return 0; + } + while(l >= 0 && isspace(pStr[l])) + { + --l; + } + int nLast = l; + while(l >= 0 && !isspace(pStr[l])) + { + l--; + } + int nFirst = l; + if(nFirst == nLast) + return 0; + int nCount = nLast - nFirst + 1; + *ppStart = pStr + nFirst; + return nCount; +} + +const char* MicroProfileDemangleSymbol(const char* pSymbol) +{ + static unsigned long size = 128; + static char* pTempBuffer = (char*)malloc(size); // needs to be malloc because demangle function might realloc it. + unsigned long len = size; + int ret = 0; + char* pBuffer = pTempBuffer; + pBuffer = abi::__cxa_demangle(pSymbol, pTempBuffer, &len, &ret); + if(ret == 0) + { + if(pBuffer != pTempBuffer) + { + pTempBuffer = pBuffer; + if(len < size) + __builtin_trap(); + size = len; + } + return pTempBuffer; + } + else + { + return pSymbol; + } +} + +template +void MicroProfileIterateSymbols(Callback CB, uint32_t* nModules, uint32_t nNumModules) +{ + MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileIterateSymbols", MP_PINK3); + char FunctionName[1024]; + (void)FunctionName; + mach_port_name_t task = mach_task_self(); + vm_map_offset_t vmoffset = 0; + mach_vm_size_t vmsize = 0; + uint32_t nd; + kern_return_t kr; + vm_region_submap_info_64 vbr; + mach_msg_type_number_t vbrcount = sizeof(vbr) / 4; + + intptr_t nCurrentModule = -1; + uint32_t nCurrentModuleId = -1; + + auto OnFunction = [&](void* addr, void* addrend, const char* pSymbol, const char* pModuleName, void* pModuleAddr) -> bool + { + const char* pStr = MicroProfileDemangleSymbol(pSymbol); + ; + int l = MicroProfileTrimFunctionName(pStr, &FunctionName[0], &FunctionName[1024]); + if(nCurrentModule != (intptr_t)pModuleAddr) + { + nCurrentModule = (intptr_t)pModuleAddr; + nCurrentModuleId = MicroProfileSymbolGetModule(pModuleName, nCurrentModule); + } + + CB(l ? &FunctionName[0] : pStr, l ? &FunctionName[0] : 0, (intptr_t)addr, (intptr_t)addrend, nCurrentModuleId); + return true; + }; + vm_offset_t addr_prev = 0; + + while(KERN_SUCCESS == (kr = mach_vm_region_recurse(task, &vmoffset, &vmsize, &nd, (vm_region_recurse_info_t)&vbr, &vbrcount))) + { + { + addr_prev = vmoffset + vmsize; + if(0 != (vbr.protection & VM_PROT_EXECUTE)) + { + bool bProcessModule = true; + int nModule = -1; + if(nNumModules) + { + bProcessModule = false; + for(uint32_t i = 0; i < nNumModules; ++i) + { + intptr_t nBase = S.SymbolModules[nModules[i]].Regions[0].nBegin; + if((intptr_t)vmoffset == nBase) + { + bProcessModule = true; + nModule = nModules[i]; + break; + } + } + } + if(bProcessModule) + { + S.SymbolModules[nModule].nProgressTarget = S.SymbolModules[nModule].Regions[0].nEnd - S.SymbolModules[nModule].Regions[0].nBegin; + dl_info di; + int r = 0; + r = dladdr((void*)vmoffset, &di); + if(r) + { + OnFunction(di.dli_saddr, (void*)addr_prev, di.dli_sname, di.dli_fname, di.dli_fbase); + } + intptr_t addr = vmoffset + vmsize - 1; + while(1) + { + r = dladdr((void*)(addr), &di); + if(r) + { + if(!di.dli_sname) + { + break; + } + OnFunction(di.dli_saddr, (void*)addr_prev, di.dli_sname, di.dli_fname, di.dli_fbase); + } + else + { + break; + } + addr_prev = (vm_offset_t)di.dli_saddr; + addr = (intptr_t)di.dli_saddr - 1; + if(di.dli_saddr < (void*)vmoffset) + { + break; + } + } + for(int i = 0; i < S.SymbolNumModules; ++i) + { + if(S.SymbolModules[i].Regions[0].nBegin == (intptr_t)vmoffset) + { + S.SymbolModules[i].nModuleLoadFinished.store(1); + } + } + } + } + } + vmoffset += vmsize; + vbrcount = sizeof(vbr) / 4; + } +} + +void MicroProfileSymbolUpdateModuleList() +{ + char FunctionName[1024]; + (void)FunctionName; + mach_port_name_t task = mach_task_self(); + vm_map_offset_t vmoffset = 0; + mach_vm_size_t vmsize = 0; + uint32_t nd; + kern_return_t kr; + vm_region_submap_info_64 vbr; + mach_msg_type_number_t vbrcount = sizeof(vbr) / 4; + + while(KERN_SUCCESS == (kr = mach_vm_region_recurse(task, &vmoffset, &vmsize, &nd, (vm_region_recurse_info_t)&vbr, &vbrcount))) + { + { + if(0 != (vbr.protection & VM_PROT_EXECUTE)) + { + dl_info di; + int r = 0; + r = dladdr((void*)vmoffset, &di); + if(r) + { + uprintf("[0x%p-0x%p] (0x%p) %s %s\n", (void*)vmoffset, (void*)addr_prev, di.dli_fbase, di.dli_fname, di.dli_sname); + MicroProfileSymbolInitModule(di.dli_fname, (intptr_t)vmoffset, (intptr_t)vmoffset + vmsize); + } + } + } + vmoffset += vmsize; + vbrcount = sizeof(vbr) / 4; + } +} + +static void* MicroProfileAllocExecutableMemory(void* f, size_t s) +{ + static uint64_t nPageSize = 0; + if(!nPageSize) + { + nPageSize = getpagesize(); + } + s = (s + (nPageSize - 1)) & (~(nPageSize - 1)); + + void* pMem = mmap((void*)f, s, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, 0, 0); + + // uprintf("Allocating %zu %p\n", s, pMem); + return pMem; +} + +bool MicroProfileDemangleName(const char* pName, char* OutName, uint32_t Size) +{ + // demangle not implemented + strcpy(OutName, pName); + return true; +} + +bool MicroProfilePatchBeginSuspend() +{ + // Not implemented + return true; +} + +void MicroProfilePatchEndSuspend() +{ + // Not implemented +} + +void MicroProfileInstrumentWithoutSymbols(const char** pModules, const char** pSymbols, uint32_t nNumSymbols) +{ + void* M = dlopen(0, 0); + for(uint32_t i = 0; i < nNumSymbols; ++i) + { + // uprintf("trying to find symbol %s\n", pSym); + void* s = dlsym(M, pSymbols[i]); + uprintf("sym returned %p\n", s); + if(s) + { + uint32_t nColor = MicroProfileColorFromString(pSymbols[i]); + const char* pDemangled = MicroProfileDemangleSymbol(pSymbols[i]); + MicroProfileInstrumentFunction(s, pModules[i], pDemangled, nColor); + } + } + dlclose(M); +} +#endif + +#if defined(__unix__) && defined(__x86_64__) +// '##::::'##::'#######:::'#######::'##:::'##::::'##:::::::'####:'##::: ##:'##::::'##:'##::::'##: +// ##:::: ##:'##.... ##:'##.... ##: ##::'##::::: ##:::::::. ##:: ###:: ##: ##:::: ##:. ##::'##:: +// ##:::: ##: ##:::: ##: ##:::: ##: ##:'##:::::: ##:::::::: ##:: ####: ##: ##:::: ##::. ##'##::: +// #########: ##:::: ##: ##:::: ##: #####::::::: ##:::::::: ##:: ## ## ##: ##:::: ##:::. ###:::: +// ##.... ##: ##:::: ##: ##:::: ##: ##. ##:::::: ##:::::::: ##:: ##. ####: ##:::: ##::: ## ##::: +// ##:::: ##: ##:::: ##: ##:::: ##: ##:. ##::::: ##:::::::: ##:: ##:. ###: ##:::: ##:: ##:. ##:: +// ##:::: ##:. #######::. #######:: ##::. ##:::: ########:'####: ##::. ##:. #######:: ##:::. ##: +// ..:::::..:::.......::::.......:::..::::..:::::........::....::..::::..:::.......:::..:::::..:: + +#include +#include +#include +#include +#include +#include + +static void* MicroProfileAllocExecutableMemory(void* f, size_t s); +static void MicroProfileMakeWriteable(void* p_); + +extern "C" void microprofile_tramp_enter_patch() asm("_microprofile_tramp_enter_patch"); +extern "C" void microprofile_tramp_enter() asm("_microprofile_tramp_enter"); +extern "C" void microprofile_tramp_code_begin() asm("_microprofile_tramp_code_begin"); +extern "C" void microprofile_tramp_code_end() asm("_microprofile_tramp_code_end"); +extern "C" void microprofile_tramp_intercept0() asm("_microprofile_tramp_intercept0"); +extern "C" void microprofile_tramp_end() asm("_microprofile_tramp_end"); +extern "C" void microprofile_tramp_exit() asm("_microprofile_tramp_exit"); +extern "C" void microprofile_tramp_leave() asm("_microprofile_tramp_leave"); +extern "C" void microprofile_tramp_trunk() asm("_microprofile_tramp_trunk"); +extern "C" void microprofile_tramp_call_patch_pop() asm("_microprofile_tramp_call_patch_pop"); +extern "C" void microprofile_tramp_call_patch_push() asm("_microprofile_tramp_call_patch_push"); + +bool MicroProfilePatchFunction(void* f, int Argument, MicroProfileHookFunc enter, MicroProfileHookFunc leave, MicroProfilePatchError* pError) +{ + if(pError) + { + memcpy(&pError->Code[0], f, 12); + } + + intptr_t t_enter = (intptr_t)microprofile_tramp_enter; + intptr_t t_enter_patch_offset = (intptr_t)microprofile_tramp_enter_patch - t_enter; + intptr_t t_code_begin_offset = (intptr_t)microprofile_tramp_code_begin - t_enter; + intptr_t t_code_end_offset = (intptr_t)microprofile_tramp_code_end - t_enter; + intptr_t t_code_intercept0_offset = (intptr_t)microprofile_tramp_intercept0 - t_enter; + intptr_t t_code_exit_offset = (intptr_t)microprofile_tramp_exit - t_enter; + intptr_t t_code_leave_offset = (intptr_t)microprofile_tramp_leave - t_enter; + + intptr_t t_code_call_patch_push_offset = (intptr_t)microprofile_tramp_call_patch_push - t_enter; + intptr_t t_code_call_patch_pop_offset = (intptr_t)microprofile_tramp_call_patch_pop - t_enter; + intptr_t codemaxsize = t_code_end_offset - t_code_begin_offset; + intptr_t t_end_offset = (intptr_t)microprofile_tramp_end - t_enter; + intptr_t t_trunk_offset = (intptr_t)microprofile_tramp_trunk - t_enter; + intptr_t t_trunk_size = (intptr_t)microprofile_tramp_end - (intptr_t)microprofile_tramp_trunk; + + char* ptramp = (char*)MicroProfileAllocExecutableMemory(f, t_end_offset); + + intptr_t offset = ((intptr_t)f + 6 - (intptr_t)ptramp); + + uint32_t nBytesToCopy = 14; + if(offset < 0x80000000 && offset > -0x7fffffff) + { + /// offset is small enough to insert a relative jump + nBytesToCopy = 5; + } + + memcpy(ptramp, (void*)t_enter, t_end_offset); + + int nInstructionBytesDest = 0; + char* pInstructionMoveDest = ptramp + t_code_begin_offset; + char* pTrunk = ptramp + t_trunk_offset; + + int nInstructionBytesSrc = 0; + + uint32_t nRegsWritten = 0; + uint32_t nRetSafe = 0; + uint32_t nUsableJumpRegs = (1 << R_RAX) | (1 << R_R10) | (1 << R_R11); // scratch && !parameter register + if(!MicroProfileCopyInstructionBytes( + pInstructionMoveDest, f, nBytesToCopy, codemaxsize, pTrunk, t_trunk_size, nUsableJumpRegs, &nInstructionBytesDest, &nInstructionBytesSrc, &nRegsWritten, &nRetSafe)) + { + if(pError) + { + const char* pCode = (const char*)f; + memset(pError->Code, 0, sizeof(pError->Code)); + memcpy(pError->Code, pCode, nInstructionBytesSrc); + int off = stbsp_snprintf(pError->Message, sizeof(pError->Message), "Failed to move %d code bytes ", nInstructionBytesSrc); + pError->nCodeSize = nInstructionBytesSrc; + for(int i = 0; i < nInstructionBytesSrc; ++i) + { + off += stbsp_snprintf(off + pError->Message, sizeof(pError->Message) - off, "%02x ", 0xff & pCode[i]); + } + uprintf("%s\n", pError->Message); + } + return false; + } + intptr_t phome = nInstructionBytesSrc + (intptr_t)f; + uint32_t reg = nUsableJumpRegs & ~nRegsWritten; + static_assert(R_RAX == 0, "R_RAX must be 0"); + if(0 == reg) + { + if(nRetSafe == 0) + { + MP_BREAK(); // shout fail earlier + } + MicroProfileInsertRetJump(pInstructionMoveDest + nInstructionBytesDest, phome); + } + else + { + int r = R_RAX; + while((reg & 1) == 0) + { + reg >>= 1; + r++; + } + MicroProfileInsertRegisterJump(pInstructionMoveDest + nInstructionBytesDest, phome, r); + } + + // PATCH 1 TRAMP EXIT + intptr_t microprofile_tramp_exit = (intptr_t)ptramp + t_code_exit_offset; + memcpy(ptramp + t_enter_patch_offset + 2, (void*)µprofile_tramp_exit, 8); + + char* pintercept = t_code_intercept0_offset + ptramp; + + // PATCH 1.5 Argument + memcpy(pintercept - 4, (void*)&Argument, 4); + + // PATCH 2 INTERCEPT0 + intptr_t addr = (intptr_t)enter; //&intercept0; + memcpy(pintercept + 2, (void*)&addr, 8); + + // PATHC 2.5 argument + memcpy(ptramp + t_code_exit_offset + 3, (void*)&Argument, 4); + + intptr_t microprofile_tramp_leave = (intptr_t)ptramp + t_code_leave_offset; + // PATCH 3 INTERCEPT1 + intptr_t addr1 = (intptr_t)leave; //&intercept1; + memcpy((char*)microprofile_tramp_leave + 2, (void*)&addr1, 8); + + intptr_t patch_push_addr = (intptr_t)(&MicroProfile_Patch_TLS_PUSH); + intptr_t patch_pop_addr = (intptr_t)(&MicroProfile_Patch_TLS_POP); + memcpy((char*)ptramp + t_code_call_patch_push_offset + 2, &patch_push_addr, 8); + memcpy((char*)ptramp + t_code_call_patch_pop_offset + 2, &patch_pop_addr, 8); + + { + // PATCH 4 DEST FUNC + + MicroProfileMakeWriteable(f); + char* pp = (char*)f; + char* ppend = pp + nInstructionBytesSrc; + + if(nInstructionBytesSrc < 14) + { + uprintf("inserting 5b jump\n"); + pp = MicroProfileInsertRelativeJump((char*)pp, (intptr_t)ptramp); + } + else + { + uprintf("inserting 14b jump\n"); + pp = MicroProfileInsertRegisterJump(pp, (intptr_t)ptramp, R_RAX); + } + while(pp != ppend) + { + *pp++ = 0x90; + } + } + return true; +} + +static void MicroProfileMakeWriteable(void* p_) +{ + intptr_t nPageSize = (intptr_t)getpagesize(); + intptr_t p = ((intptr_t)p_) & ~(nPageSize - 1); + intptr_t e = nPageSize + ((14 + (intptr_t)p_) & ~(nPageSize - 1)); + size_t s = e - p; + mprotect((void*)p, s, PROT_READ | PROT_WRITE | PROT_EXEC); +} + +int MicroProfileTrimFunctionName(const char* pStr, char* pOutBegin, char* pOutEnd) +{ + int l = strlen(pStr) - 1; + int sz = 0; + pOutEnd--; + if(l < pOutEnd - pOutBegin && pOutBegin != pOutEnd) + { + const char* p = pStr; + const char* pEnd = pStr + l + 1; + int in = 0; + while(p != pEnd && pOutBegin != pOutEnd) + { + char c = *p++; + if(c == '(' || c == '<') + { + in++; + } + else if(c == ')' || c == '>') + { + in--; + continue; + } + + if(in == 0) + { + *pOutBegin++ = c; + sz++; + } + } + + *pOutBegin++ = '\0'; + } + return sz; +} + +int MicroProfileFindFunctionName(const char* pStr, const char** ppStart) +{ + int l = strlen(pStr) - 1; + if(l < 1024) + { + char b[1024] = { 0 }; + char* put = &b[0]; + + const char* p = pStr; + const char* pEnd = pStr + l + 1; + int in = 0; + while(p != pEnd) + { + char c = *p++; + if(c == '(' || c == '<') + { + in++; + } + else if(c == ')' || c == '>') + { + in--; + continue; + } + + if(in == 0) + { + *put++ = c; + } + } + + *put++ = '\0'; + uprintf("trimmed %s\n", b); + } + + // int nFirstParen = l; + int nNumParen = 0; + int c = 0; + + while(l >= 0 && pStr[l] != ')' && c++ < (int)(sizeof(" const") - 1)) + { + l--; + } + if(pStr[l] == ')') + { + do + { + if(pStr[l] == ')') + { + nNumParen++; + } + else if(pStr[l] == '(') + { + nNumParen--; + } + l--; + } while(nNumParen > 0 && l >= 0); + } + else + { + *ppStart = pStr; + return 0; + } + while(l >= 0 && isspace(pStr[l])) + { + --l; + } + int nLast = l; + while(l >= 0 && !isspace(pStr[l])) + { + l--; + } + int nFirst = l; + if(nFirst == nLast) + return 0; + int nCount = nLast - nFirst + 1; + *ppStart = pStr + nFirst; + return nCount; +} + +const char* MicroProfileDemangleSymbol(const char* pSymbol) +{ + static unsigned long size = 128; + static char* pTempBuffer = (char*)malloc(size); // needs to be malloc because demangle function might realloc it. + unsigned long len = size; + int ret = 0; + char* pBuffer = pTempBuffer; + pBuffer = abi::__cxa_demangle(pSymbol, pTempBuffer, &len, &ret); + if(ret == 0) + { + if(pBuffer != pTempBuffer) + { + pTempBuffer = pBuffer; + if(len < size) + __builtin_trap(); + size = len; + } + return pTempBuffer; + } + else + { + return pSymbol; + } +} + +template +void MicroProfileIterateSymbols(Callback CB, uint32_t* nModules, uint32_t nNumModules) +{ + MICROPROFILE_SCOPEI("MicroProfile", "MicroProfileIterateSymbols", MP_PINK3); + char FunctionName[1024]; + + intptr_t nCurrentModule = -1; + uint32_t nCurrentModuleId = -1; + + auto OnFunction = [&](void* addr, void* addrend, const char* pSymbol, const char* pModuleName, void* pModuleAddr) -> bool + { + const char* pStr = MicroProfileDemangleSymbol(pSymbol); + ; + int l = MicroProfileTrimFunctionName(pStr, &FunctionName[0], &FunctionName[1024]); + MP_ASSERT(nCurrentModule == (intptr_t)pModuleAddr); + CB(l ? &FunctionName[0] : pStr, l ? &FunctionName[0] : 0, (intptr_t)addr, (intptr_t)addrend, nCurrentModuleId); + return true; + }; + + for(int i = 0; i < S.SymbolNumModules; ++i) + { + auto& M = S.SymbolModules[i]; + if(0 != nNumModules) + { + bool bProcess = false; + for(uint32_t j = 0; j < nNumModules; ++j) + { + if(nModules[j] == (uint32_t)i) + { + bProcess = true; + break; + } + } + if(!bProcess) + continue; + } + nCurrentModuleId = i; + Dl_info di; + int r = 0; + r = dladdr((void*)(M.Regions[0].nBegin), &di); + if(r) + { + nCurrentModule = (intptr_t)di.dli_fbase; + M.nProgressTarget = 0; + for(int j = 0; j < M.nNumExecutableRegions; ++j) + { + M.nProgressTarget += M.Regions[j].nEnd - M.Regions[j].nBegin; + } + for(int j = 0; j < M.nNumExecutableRegions; ++j) + { + const intptr_t nBegin = M.Regions[j].nBegin; + const intptr_t nEnd = M.Regions[j].nEnd; + int r = 0; + intptr_t nAddr = (nEnd - 8) & ~7; + intptr_t nAddrPrev = nEnd; + while(1) + { + r = dladdr((void*)(nAddr), &di); + if(r && di.dli_sname) + { + OnFunction(di.dli_saddr, (void*)nAddrPrev, di.dli_sname, di.dli_fname, di.dli_fbase); + nAddrPrev = (intptr_t)di.dli_saddr; + nAddr = (intptr_t)di.dli_saddr - 1; + } + else + { + nAddr = (nAddr - 7) & ~7; // pretty ineffecient, but it seems linux just returns 0 when there is no symbols, making this the only option I can come up with? + } + if(nAddr < nBegin) + { + break; + } + } + } + M.nProgress = M.nProgressTarget; + M.nModuleLoadFinished.store(1); + } + } +} + +void MicroProfileSymbolUpdateModuleList() +{ + // So, this was the only way I could find to do this.. + // Is this seriously how they want this to be done? + FILE* F = fopen("/proc/self/maps", "r"); + char* line = 0; + size_t len; + ssize_t read; + Dl_info di; + while((read = getline(&line, &len, F)) != -1) + { + void* pBase = 0; + void* pEnd = 0; + char c, r, w, x, p; + + if(8 == sscanf(line, "%p%c%p%c%c%c%c%c", &pBase, &c, &pEnd, &c, &r, &w, &x, &p)) + { + if('x' == x) + { + int r = 0; + r = dladdr(pBase, &di); + if(r) + { + if('[' != di.dli_fname[0]) + { + MicroProfileSymbolInitModule(di.dli_fname, (intptr_t)pBase, (intptr_t)pEnd); + } + } + } + } + } + fclose(F); + MicroProfileSymbolMergeExecutableRegions(); +} + +static void* MicroProfileAllocExecutableMemory(void* f, size_t s) +{ + static uint64_t nPageSize = 0; + if(!nPageSize) + { + nPageSize = getpagesize(); + } + s = (s + (nPageSize - 1)) & (~(nPageSize - 1)); + + void* pMem = mmap(f, s, PROT_READ | PROT_WRITE | PROT_EXEC, MAP_ANON | MAP_PRIVATE, 0, 0); + return pMem; +} + +bool MicroProfileDemangleName(const char* pName, char* OutName, uint32_t Size) +{ + // demangle not implemented + strcpy(OutName, pName); + return true; +} + +bool MicroProfilePatchBeginSuspend() +{ + // Not implemented + return true; +} + +void MicroProfilePatchEndSuspend() +{ + // Not implemented +} + +// not yet tested. +void MicroProfileInstrumentWithoutSymbols(const char** pModules, const char** pSymbols, uint32_t nNumSymbols) +{ + void* M = dlopen(0, 0); + for(uint32_t i = 0; i < nNumSymbols; ++i) + { + // uprintf("trying to find symbol %s\n", pSym); + void* s = dlsym(M, pSymbols[i]); + uprintf("sym returned %p\n", s); + if(s) + { + uint32_t nColor = MicroProfileColorFromString(pSymbols[i]); + const char* pDemangled = MicroProfileDemangleSymbol(pSymbols[i]); + MicroProfileInstrumentFunction(s, pModules[i], pDemangled, nColor); + } + } + dlclose(M); +} + +#endif + +#endif + +void MicroProfileHashTableInit(MicroProfileHashTable* pTable, uint32_t nInitialSize, uint32_t nSearchLimit, MicroProfileHashCompareFunction CompareFunc, MicroProfileHashFunction HashFunc) +{ + pTable->nAllocated = nInitialSize; + pTable->nUsed = 0; + uint32_t nSize = nInitialSize * sizeof(MicroProfileHashTableEntry); + pTable->pEntries = (MicroProfileHashTableEntry*)MICROPROFILE_ALLOC(nSize, 8); + pTable->CompareFunc = CompareFunc; + pTable->HashFunc = HashFunc; + pTable->nSearchLimit = nSearchLimit; + pTable->nLim = pTable->nAllocated / 5; + if(pTable->nLim > pTable->nSearchLimit) + pTable->nLim = pTable->nSearchLimit; + memset(pTable->pEntries, 0, nSize); +} +void MicroProfileHashTableDestroy(MicroProfileHashTable* pTable) +{ + MICROPROFILE_FREE(pTable->pEntries); +} + +uint64_t MicroProfileHashTableHash(MicroProfileHashTable* pTable, uint64_t K) +{ + uint64_t H = pTable->HashFunc ? (*pTable->HashFunc)(K) : K; + return H == 0 ? 1 : H; +} + +void MicroProfileHashTableGrow(MicroProfileHashTable* pTable) +{ + uint32_t nAllocated = pTable->nAllocated; + uint32_t nNewSize = nAllocated * 2; + uprintf("GROW %d -> %d\n", nAllocated, nNewSize); + + MicroProfileHashTable New; + MicroProfileHashTableInit(&New, nNewSize, pTable->nSearchLimit, pTable->CompareFunc, pTable->HashFunc); + for(uint32_t i = 0; i < nAllocated; ++i) + { + MicroProfileHashTableEntry& E = pTable->pEntries[i]; + if(E.Hash != 0) + { + MicroProfileHashTableSet(&New, E.Key, E.Value, E.Hash, false); + } + } + MicroProfileHashTableDestroy(pTable); + *pTable = New; +} + +bool MicroProfileHashTableSet(MicroProfileHashTable* pTable, uint64_t Key, uintptr_t Value) +{ + uint64_t H = MicroProfileHashTableHash(pTable, Key); + return MicroProfileHashTableSet(pTable, Key, Value, H, true); +} + +MicroProfileHashTableIterator MicroProfileGetHashTableIteratorBegin(MicroProfileHashTable* HashTable) +{ + return MicroProfileHashTableIterator(0, HashTable); +} + +MicroProfileHashTableIterator MicroProfileGetHashTableIteratorEnd(MicroProfileHashTable* HashTable) +{ + return MicroProfileHashTableIterator(HashTable->nAllocated, HashTable); +} + +bool MicroProfileHashTableSet(MicroProfileHashTable* pTable, uint64_t Key, uintptr_t Value, uint64_t H, bool bAllowGrow) +{ + if(H == 0) + MP_BREAK(); // not supported. + MicroProfileHashCompareFunction Cmp = pTable->CompareFunc; + while(1) + { + const uint32_t nLim = pTable->nLim; + uint32_t B = H % pTable->nAllocated; + MicroProfileHashTableEntry* pEntries = pTable->pEntries; + + for(uint32_t i = 0; i < pTable->nAllocated; ++i) + { + uint32_t Idx = (B + i) % pTable->nAllocated; + if(pEntries[Idx].Hash == 0) + { + pEntries[Idx].Hash = H; + pEntries[Idx].Key = Key; + pEntries[Idx].Value = Value; + return true; + } + else if(pEntries[Idx].Hash == H && (Cmp ? (Cmp)(Key, pEntries[Idx].Key) : Key == pEntries[Idx].Key)) + { + pEntries[Idx].Value = Value; + return true; + } + else if(i > nLim) + { + break; + } + } + if(bAllowGrow) + { + MicroProfileHashTableGrow(pTable); + } + else + { + MP_BREAK(); + } + } + MP_BREAK(); +} + +bool MicroProfileHashTableGet(MicroProfileHashTable* pTable, uint64_t Key, uintptr_t* pValue) +{ + uint64_t H = MicroProfileHashTableHash(pTable, Key); + uint32_t B = H % pTable->nAllocated; + MicroProfileHashTableEntry* pEntries = pTable->pEntries; + MicroProfileHashCompareFunction Cmp = pTable->CompareFunc; + for(uint32_t i = 0; i < pTable->nAllocated; ++i) + { + uint32_t Idx = (B + i) % pTable->nAllocated; + if(pEntries[Idx].Hash == 0) + { + return false; + } + else if(pEntries[Idx].Hash == H && (Cmp ? (Cmp)(Key, pEntries[Idx].Key) : Key == pEntries[Idx].Key)) + { + *pValue = pEntries[Idx].Value; + return true; + } + } + return false; +} + +bool MicroProfileHashTableRemove(MicroProfileHashTable* pTable, uint64_t Key) +{ + + uint64_t H = MicroProfileHashTableHash(pTable, Key); + uint32_t B = H % pTable->nAllocated; + MicroProfileHashTableEntry* pEntries = pTable->pEntries; + MicroProfileHashCompareFunction Cmp = pTable->CompareFunc; + uint32_t nBase = (uint32_t)-1; + uint32_t nAllocated = pTable->nAllocated; + for(uint32_t i = 0; i < nAllocated; ++i) + { + uint32_t Idx = (B + i) % nAllocated; + if(pEntries[Idx].Hash == 0) + { + return false; + } + else if(pEntries[Idx].Hash == H && (Cmp ? (Cmp)(Key, pEntries[Idx].Key) : Key == pEntries[Idx].Key)) + { + nBase = Idx; + break; + } + } + pEntries[nBase].Hash = 0; + pEntries[nBase].Key = 0; + pEntries[nBase].Value = 0; + nBase++; + for(uint32_t i = 0; i < nAllocated; ++i) + { + uint32_t Idx = (nBase + i) % nAllocated; + if(pEntries[Idx].Hash == 0) + { + break; + } + else + { + MicroProfileHashTableEntry E = pEntries[Idx]; + pEntries[Idx] = {}; + MicroProfileHashTableSet(pTable, E.Key, E.Value, E.Hash, false); + } + } + return true; +} +uint64_t MicroProfileHashTableHashString(uint64_t pString) +{ + return MicroProfileStringHash((const char*)pString); +} + +bool MicroProfileHashTableCompareString(uint64_t L, uint64_t R) +{ + return 0 == strcmp((const char*)L, (const char*)R); +} +uint64_t MicroProfileHashTableHashPtr(uint64_t x) +{ + x ^= x >> 33; + x *= 0xff51afd7ed558ccdULL; + x ^= x >> 33; + x *= 0xc4ceb9fe1a85ec53ULL; + x ^= x >> 33; + return x; +} +bool MicroProfileHashTableComparePtr(uint64_t L, uint64_t R) +{ + return L == R; +} + +bool MicroProfileHashTableSetString(MicroProfileHashTable* pTable, const char* pKey, const char* pValue) +{ + return MicroProfileHashTableSet(pTable, (uint64_t)pKey, (uintptr_t)pValue); +} + +bool MicroProfileHashTableGetString(MicroProfileHashTable* pTable, const char* pKey, const char** pValue) +{ + return MicroProfileHashTableGet(pTable, (uint64_t)pKey, (uintptr_t*)pValue); +} + +bool MicroProfileHashTableRemoveString(MicroProfileHashTable* pTable, const char* pKey) +{ + return MicroProfileHashTableRemove(pTable, (uint64_t)pKey); +} + +bool MicroProfileHashTableSetPtr(MicroProfileHashTable* pTable, const void* pKey, void* pValue) +{ + return MicroProfileHashTableSet(pTable, (uint64_t)pKey, (uintptr_t)pValue); +} + +template +bool MicroProfileHashTableGetPtr(MicroProfileHashTable* pTable, const void* pKey, T** pValue) +{ + uintptr_t Dummy; + uintptr_t* Arg = pValue ? (uintptr_t*)pValue : &Dummy; + return MicroProfileHashTableGet(pTable, (uint64_t)pKey, Arg); +} + +bool MicroProfileHashTableRemovePtr(MicroProfileHashTable* pTable, const char* pKey) +{ + return MicroProfileHashTableRemove(pTable, (uint64_t)pKey); +} + +template +T& MicroProfileArray::operator[](const uint32_t Index) +{ + return Data[Index]; +} + +template +const T& MicroProfileArray::operator[](const uint32_t Index) const +{ + MP_ASSERT(Index < Size); + return Data[Index]; +} +template +T* MicroProfileArray::begin() +{ + return Data; +} +template +T* MicroProfileArray::end() +{ + return Data + Size; +} + +template +void MicroProfileArrayInit(MicroProfileArray& Array, uint32_t InitialCapacity) +{ + MP_ASSERT(Array.Data == nullptr); + MP_ASSERT(Array.Size == 0); + MP_ASSERT(Array.Capacity == 0); + Array.Capacity = InitialCapacity; + Array.Data = MP_ALLOC_OBJECT_ARRAY(T, InitialCapacity); + Array.Size = 0; +} +template +void MicroProfileArrayDestroy(MicroProfileArray& Array, uint32_t InitialCapacity) +{ + if(Array.Data) + MP_FREE(Array.Data); + memset(Array, 0, sizeof(*Array)); +} +template +void MicroProfileArrayClear(MicroProfileArray& Array) +{ + Array.Size = 0; +} + +template +void MicroProfileArrayPushBack(MicroProfileArray& Array, const T& v) +{ + uint32_t& Size = Array.Size; + uint32_t& Capacity = Array.Capacity; + if(Size >= Capacity) + { + uint32_t NewCapacity = (MicroProfileMax(1u, Capacity) + 1) * 3 / 2; + T* NewData = MP_ALLOC_OBJECT_ARRAY(T, NewCapacity); + memcpy(NewData, Array.Data, Size * sizeof(T)); + if(Array.Data) + { + MP_FREE(Array.Data); + } + Array.Data = NewData; + Capacity = NewCapacity; + } + Array.Data[Size++] = v; +} + +void MicroProfileStringBlockFree(MicroProfileStringBlock* pBlock) +{ + MicroProfileCounterAdd(S.CounterToken_StringBlock_Count, -1); + MicroProfileCounterAdd(S.CounterToken_StringBlock_Memory, -(int64_t)(pBlock->nSize + sizeof(MicroProfileStringBlock))); + + MP_FREE(pBlock); +} +MicroProfileStringBlock* MicroProfileStringBlockAlloc(uint32_t nSize) +{ + nSize = MicroProfileMax(nSize, (uint32_t)(MicroProfileStringBlock::DEFAULT_SIZE - sizeof(MicroProfileStringBlock))); + nSize += sizeof(MicroProfileStringBlock); + MicroProfileCounterAdd(S.CounterToken_StringBlock_Count, 1); + MicroProfileCounterAdd(S.CounterToken_StringBlock_Memory, nSize); + // uprintf("alloc string block %d sizeof strings is %d\n", nSize, (int)sizeof(MicroProfileStringBlock)); + MicroProfileStringBlock* pBlock = (MicroProfileStringBlock*)MP_ALLOC(nSize, 8); + pBlock->pNext = 0; + pBlock->nSize = nSize - sizeof(MicroProfileStringBlock); + pBlock->nUsed = 0; + return pBlock; +} + +void MicroProfileStringsInit(MicroProfileStrings* pStrings) +{ + MicroProfileHashTableInit(&pStrings->HashTable, 1, 25, MicroProfileHashTableCompareString, MicroProfileHashTableHashString); + pStrings->pFirst = 0; + pStrings->pLast = 0; +} +void MicroProfileStringsDestroy(MicroProfileStrings* pStrings) +{ + MicroProfileStringBlock* pBlock = pStrings->pFirst; + while(pBlock) + { + MicroProfileStringBlock* pNext = pBlock->pNext; + MicroProfileStringBlockFree(pBlock); + pBlock = pNext; + } + MicroProfileCounterSet(S.CounterToken_StringBlock_Waste, 0); + MicroProfileCounterSet(S.CounterToken_StringBlock_Strings, 0); + + memset(pStrings, 0, sizeof(*pStrings)); +} + +const char* MicroProfileStringIntern(const char* pStr) +{ + return MicroProfileStringIntern(pStr, (uint32_t)strlen(pStr), 0); +} + +const char* MicroProfileStringInternLower(const char* pStr) +{ + return MicroProfileStringIntern(pStr, (uint32_t)strlen(pStr), ESTRINGINTERN_LOWERCASE); +} +const char* MicroProfileStringInternSlash(const char* pStr) +{ + return MicroProfileStringIntern(pStr, (uint32_t)strlen(pStr), ESTRINGINTERN_FORCEFORWARDSLASH); +} + +const char* MicroProfileStringIntern(const char* pStr_, uint32_t nLen, uint32_t nFlags) +{ + MicroProfileStrings* pStrings = &S.Strings; + const char* pStr = pStr_; + char* pLowerCaseStr = (char*)alloca(nLen + 1); + if(0 != (nFlags & (ESTRINGINTERN_FORCEFORWARDSLASH | ESTRINGINTERN_LOWERCASE))) + { + for(uint32_t i = 0; i < nLen; ++i) + { + char c = pStr[i]; + if(nFlags & ESTRINGINTERN_LOWERCASE) + { + c = tolower(c); + } + if(nFlags & ESTRINGINTERN_FORCEFORWARDSLASH) + { + if(c == '\\') + c = '/'; + } + pLowerCaseStr[i] = c; + } + pLowerCaseStr[nLen] = '\0'; + pStr = pLowerCaseStr; + } + const char* pRet; + if(MicroProfileHashTableGetString(&pStrings->HashTable, pStr, &pRet)) + { + if(0 != strcmp(pStr, pRet)) + { + MP_BREAK(); + } + return pRet; + } + else + { + if(pStr[nLen] != '\0') + MP_BREAK(); // string should be 0 terminated. + nLen += 1; + MicroProfileStringBlock* pBlock = pStrings->pLast; + if(0 == pBlock || pBlock->nUsed + nLen > pBlock->nSize) + { + MicroProfileStringBlock* pNewBlock = MicroProfileStringBlockAlloc(nLen); + if(pBlock) + { + pBlock->pNext = pNewBlock; + pStrings->pLast = pNewBlock; + MicroProfileCounterAdd(S.CounterToken_StringBlock_Waste, pBlock->nSize - pBlock->nUsed); + } + else + { + pStrings->pLast = pStrings->pFirst = pNewBlock; + } + pBlock = pNewBlock; + } + MicroProfileCounterAdd(S.CounterToken_StringBlock_Strings, 1); + char* pDest = &pBlock->Memory[pBlock->nUsed]; + pBlock->nUsed += nLen; + MP_ASSERT(pBlock->nUsed <= pBlock->nSize); + memcpy(pDest, pStr, nLen); + MicroProfileHashTableSetString(&pStrings->HashTable, pDest, pDest); + +#if 0 + void DumpTableStr(MicroProfileHashTable* pTable); + DumpTableStr(&pStrings->HashTable); +#endif + + return pDest; + } +} + +void DumpTable(MicroProfileHashTable* pTable) +{ + for(uint32_t i = 0; i < pTable->nAllocated; ++i) + { + if(pTable->pEntries[i].Hash != 0) + { + uprintf("[%05d,%05" PRIu64 "] ::::%" PRIx64 ", %p .. hash %" PRIx64 "\n", + i, + pTable->pEntries[i].Hash % pTable->nAllocated, + pTable->pEntries[i].Key, + (void*)pTable->pEntries[i].Value, + pTable->pEntries[i].Hash); + } + } +}; +void DumpTableStr(MicroProfileHashTable* pTable) +{ + int c = 0; + (void)c; + for(uint32_t i = 0; i < pTable->nAllocated; ++i) + { + if(pTable->pEntries[i].Hash != 0) + { + uprintf("%03d [%05d,%05" PRIu64 "] ::::%s, %s .. hash %" PRIx64 "\n", + c++, + i, + pTable->pEntries[i].Hash % pTable->nAllocated, + (const char*)pTable->pEntries[i].Key, + (const char*)pTable->pEntries[i].Value, + pTable->pEntries[i].Hash); + } + } + uprintf("FillPrc %f\n", 100.f * c / (float)pTable->nAllocated); +}; + +static const char* txt[] = { "gaudy", "chilly", "obtain", "suspend", "jelly", "peel", "nauseating", "complain", "cave", "practise", "sail", "close", + "drawer", "mature", "impossible", "exist", "sister", "poke", "ancient", "paddle", "ask", "shallow", "outrageous", "healthy", + "reading", "obey", "water", "elbow", "abnormal", "trap", "wholesale", "lovely", "stupid", "comparison", "swim", "brash", + "towering", "accept", "invention", "plantation", "spooky", "tiger", "knot", "literate", "awake", "itch", "medical", "ticket", + "tawdry", "correct", "mine", "accidental", "dinner", "produce", "protective", "red", "dreary", "toe", "drain", "zesty", + "inform", "boundless", "ghost", "attend", "rely", "fill", "liquid", "pump", "continue", "spark", "church", "fortunate", + "truthful", "conscious", "possible", "motion", "evanescent", "branch", "skirt", "number", "meek", "hour", "form", "work", + "car", "post", "talk", "fear", "tightfisted", "dress", "perform", "fry", "courageous", "dysfunctional", "page", "one", + "annoy", "abrasive", "dependent", "payment" }; + +void MicroProfileStringInternTest() +{ + MicroProfileStringsInit(&S.Strings); + uint32_t nCount = sizeof(txt) / sizeof(txt[0]); + const char* pStrings[100]; + const char* pStrings2[100]; + + DumpTableStr(&S.Strings.HashTable); + for(uint32_t i = 0; i < nCount; ++i) + { + pStrings[i] = MicroProfileStringIntern(txt[i]); + pStrings2[i] = MicroProfileStrDup(txt[i]); + } + + for(uint32_t i = 0; i < nCount; ++i) + { + const char* pStr = MicroProfileStringIntern(pStrings2[i]); + if(pStr != pStrings[i]) + { + MP_BREAK(); + } + } + DumpTableStr(&S.Strings.HashTable); + + MicroProfileStringsDestroy(&S.Strings); +} + +void MicroProfileHashTableTest() +{ + MicroProfileStringInternTest(); + + MicroProfileHashTable T; + MicroProfileHashTable* pTable = &T; + MicroProfileHashTableInit(pTable, 1, 100, 0, 0); + +#define NUM_ITEMS 100 + + uint64_t Keys[NUM_ITEMS]; + uint64_t Values[NUM_ITEMS]; + memset(Keys, 0xff, sizeof(Keys)); + memset(Values, 0xff, sizeof(Values)); + + static int l = 0; + auto RR = [&]() -> uint64_t + { + if(l++ % 4 < 2) + { + return l; + } + uint64_t l2 = rand(); + uint64_t u = rand(); + return l2 | (u << 32); + }; + auto RRUnique = [&]() + { + bool bFound = false; + uint64_t V = 0; + do + { + V = RR(); + for(uint32_t i = 0; i != NUM_ITEMS; ++i) + { + if(V == Keys[i]) + { + bFound = true; + } + } + if(!bFound) + { + return V; + } + } while(bFound); + MP_BREAK(); + return (uint64_t)0; + }; + + Keys[0] = 0; + Values[0] = 42; + for(uint32_t i = 1; i < NUM_ITEMS; ++i) + { + Keys[i] = RRUnique(); + Values[i] = RR(); + } + + for(uint32_t i = 0; i < NUM_ITEMS; ++i) + { + MicroProfileHashTableSet(pTable, Keys[i], Values[i]); + } + + for(uint32_t i = 0; i < NUM_ITEMS; ++i) + { + uintptr_t V; + if(MicroProfileHashTableGet(pTable, Keys[i], &V)) + { + if(V != Values[i]) + { + MP_BREAK(); + } + } + else + { + MP_BREAK(); + } + uint64_t nonkey = RRUnique(); + if(MicroProfileHashTableGet(pTable, nonkey, &V)) + { + MP_BREAK(); + } + } + + DumpTable(pTable); + if(!MicroProfileHashTableRemove(pTable, 0)) + { + MP_BREAK(); + } + uprintf("removed\n"); + DumpTable(pTable); + uintptr_t v; + if(MicroProfileHashTableGet(pTable, 0, &v)) + { + MP_BREAK(); + } + if(MicroProfileHashTableGet(pTable, 1, &v)) + { + if(v != 2) + MP_BREAK(); + } + + MicroProfileHashTableDestroy(pTable); + + MicroProfileHashTable Strings; + MicroProfileHashTableInit(&Strings, 1, 25, MicroProfileHashTableCompareString, MicroProfileHashTableHashString); + uint32_t nCount = sizeof(txt) / sizeof(txt[0]); + for(uint32_t i = 0; i < nCount; i += 2) + { + MicroProfileHashTableSetString(&Strings, txt[i], txt[i + 1]); + } + DumpTableStr(&Strings); + + for(uint32_t i = 0; i < nCount; i += 2) + { + const char* pKey = txt[i]; + const char* pValue = txt[i + 1]; + const char* pRes = 0; + if(MicroProfileHashTableGetString(&Strings, pKey, &pRes)) + { + if(pRes != pValue) + { + MP_BREAK(); + } + } + else + { + MP_BREAK(); + } + } + uint32_t nRem = nCount / 2; + for(uint32_t i = 0; i < nRem; i += 2) + { + const char* pKey = txt[i]; + const char* pValue = txt[i + 1]; + + if(!MicroProfileHashTableRemoveString(&Strings, pKey)) + { + MP_BREAK(); + } + if(MicroProfileHashTableRemoveString(&Strings, pValue)) + { + MP_BREAK(); + } + } + for(uint32_t i = 0; i < nRem; i += 2) + { + const char* pKey = txt[i]; + if(MicroProfileHashTableRemoveString(&Strings, pKey)) + { + MP_BREAK(); + } + } + + for(uint32_t i = 0; i < nCount; i += 2) + { + const char* pKey = txt[i]; + const char* pValue = txt[i + 1]; + const char* V; + if(MicroProfileHashTableGetString(&Strings, pKey, &V)) + { + if(i < nRem) + { + MP_BREAK(); + } + else + { + if(V != pValue) + MP_BREAK(); + } + } + else + { + if(i >= nRem) + MP_BREAK(); + } + } + + DumpTableStr(&Strings); + MicroProfileHashTableDestroy(&Strings); +} + +uint32_t MicroProfileGetColor(uint32_t TimerIndex) +{ + MicroProfileTimerInfo& TI = S.TimerInfo[TimerIndex]; + if(TI.nColor == MP_AUTO) + { + return MicroProfileColorFromString(TI.pName); + } + else + { + return TI.nColor; + } +} + +#if MICROPROFILE_IMGUI +#include "imgui.h" +#ifndef MICROPROFILE_IMGUI_MAX_GRAPHS +#define MICROPROFILE_IMGUI_MAX_GRAPHS 64 +#endif + +#define MICROPROFILE_IMGUI_GRAPH_SIZE 256 + +struct MicroProfileImguiTimerState +{ + int TimerIndex = -1; + uint64_t FrameFetched = (uint64_t)-1; + uint32_t nColor = 0; + float fValues[MICROPROFILE_IMGUI_GRAPH_SIZE]; +}; + +struct MicroProfileImguiState +{ + MicroProfileImguiTimerState Timers[MICROPROFILE_IMGUI_MAX_GRAPHS]; + uint32_t NumTimers = 0; + uint32_t GraphPut; +}; + +static MicroProfileImguiState ImguiState; + +void MicroProfileImguiGather() +{ + MICROPROFILE_SCOPEI("MicroProfile", "ImguiGather", MP_AUTO); + uint32_t Put = ImguiState.GraphPut; + for(uint32_t i = 0; i < ImguiState.NumTimers; ++i) + { + MicroProfileImguiTimerState* pGraphInfo = &ImguiState.Timers[i]; + uint64_t Ticks = S.Frame[pGraphInfo->TimerIndex].nTicks; + float fToMs = S.TimerInfo[pGraphInfo->TimerIndex].Type == MicroProfileTokenTypeGpu ? MicroProfileTickToMsMultiplierGpu() : MicroProfileTickToMsMultiplierCpu(); + pGraphInfo->fValues[Put] = fToMs * Ticks; + } + ImguiState.GraphPut = (ImguiState.GraphPut + 1) % MICROPROFILE_IMGUI_GRAPH_SIZE; +} + +uint32_t MicroProfileImGuiColor(uint32_t Color) +{ + uint32_t A = 0xff; + uint32_t R = 0xff & (Color >> 16); + uint32_t G = 0xff & (Color >> 8); + uint32_t B = 0xff & (Color); + + return (A << IM_COL32_A_SHIFT) | (R << IM_COL32_R_SHIFT) | (G << IM_COL32_G_SHIFT) | (B << IM_COL32_B_SHIFT); +} + +void MicroProfileImguiControls() +{ + using namespace ImGui; + uint32_t IdCounter = 42; + { + PushID(IdCounter++); + int Aggr = MicroProfileGetAggregateFrames(); + Text("Aggregate Frames %7d", MicroProfileGetCurrentAggregateFrames()); + SameLine(); + if(RadioButton("Inf", Aggr == 0)) + MicroProfileSetAggregateFrames(0); + int AggrFrameOptions[] = { + 30, + 60, + 100, + 1000, + }; + for(int i = 0; i < sizeof(AggrFrameOptions) / sizeof(AggrFrameOptions[0]); ++i) + { + int v = AggrFrameOptions[i]; + char Buffer[32]; + stbsp_snprintf(Buffer, sizeof(Buffer) - 1, "%d", v); + SameLine(); + if(RadioButton(Buffer, Aggr == v)) + MicroProfileSetAggregateFrames(v); + } + + if(Aggr == 0) + { + if(Button("Clear Inf Aggregate")) + S.nAggregateClear = 1; + } + + PopID(); + } + Separator(); + { + PushID(IdCounter++); + Text("Categories"); + if(BeginTable("CategoryTable", 3, 0)) + { + TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch); + TableSetupColumn("On", ImGuiTableColumnFlags_WidthFixed, 70); + TableSetupColumn("Off", ImGuiTableColumnFlags_WidthFixed, 70); + for(uint32_t i = 0; i < S.nCategoryCount; ++i) + { + PushID(i); + TableNextRow(); + TableSetColumnIndex(0); + Text(S.CategoryInfo[i].pName); + bool bEnabled = MicroProfileCategoryEnabled(i); + bool bDisabled = MicroProfileCategoryDisabled(i); + TableSetColumnIndex(1); + if(RadioButton("On", bEnabled)) + MicroProfileEnableCategory(S.CategoryInfo[i].pName); + TableSetColumnIndex(2); + if(RadioButton("Off", bDisabled)) + MicroProfileDisableCategory(S.CategoryInfo[i].pName); + + PopID(); + } + EndTable(); + } + PopID(); + } + Separator(); + { + PushID(IdCounter++); + Text("Groups"); + if(BeginTable("GroupTable", 3, 0)) + { + TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch); + TableSetupColumn("On", ImGuiTableColumnFlags_WidthFixed, 70); + TableSetupColumn("Off", ImGuiTableColumnFlags_WidthFixed, 70); + + for(uint32_t i = 0; i < S.nGroupCount; ++i) + { + TableNextRow(); + PushID(i); + const char* pName = S.GroupInfo[i].pName; + bool bEnabled = MicroProfileGroupEnabled(i); + TableSetColumnIndex(0); + Text(pName); + TableSetColumnIndex(1); + if(RadioButton("On", bEnabled)) + MicroProfileToggleGroup(i); + TableSetColumnIndex(2); + if(RadioButton("Off", !bEnabled)) + MicroProfileToggleGroup(i); + PopID(); + } + EndTable(); + } + PopID(); + } +} + +MicroProfileImguiTimerState* MicroProfileImguiGetTimerState(int TimerIndex) +{ + MicroProfileImguiTimerState* ptr = nullptr; + for(uint32_t i = 0; i < ImguiState.NumTimers; ++i) + if(ImguiState.Timers[i].TimerIndex == TimerIndex) + return &ImguiState.Timers[i]; + + if(ImguiState.NumTimers < MICROPROFILE_IMGUI_MAX_GRAPHS) + { + MicroProfileImguiTimerState* pState = &ImguiState.Timers[ImguiState.NumTimers++]; + pState->TimerIndex = TimerIndex; + pState->nColor = MicroProfileGetColor(TimerIndex); + memset(&pState->fValues[0], 0, sizeof(pState->fValues)); + return pState; + } + + return nullptr; +} + +void MicroProfileImguiTable(const MicroProfileImguiWindowDesc& Window, const MicroProfileImguiEntryDesc* Entries, uint32_t NumEntries) +{ + using namespace ImGui; + const uint32_t NumColumns = 6; + ImGuiIO& io = ImGui::GetIO(); + + float Padding = GetStyle().CellPadding.x * 2; + float GroupWidth = CalcTextSize("Group").x; + float NameWidth = CalcTextSize("Name").x; + float BaseWidth = CalcTextSize("100000.00").x; + float Height = CalcTextSize("G").y + Padding; + + for(uint32_t i = 0; i < NumEntries; ++i) + { + uint32_t TimerIndex = MicroProfileGetTimerIndex(Entries[i].GraphTimer); + const MicroProfileTimerInfo& TI = S.TimerInfo[TimerIndex]; + const MicroProfileGroupInfo& GI = S.GroupInfo[TI.nGroupIndex]; + GroupWidth = MicroProfileMax(GroupWidth, CalcTextSize(GI.pName).x); + NameWidth = MicroProfileMax(NameWidth, CalcTextSize(TI.pName).x); + } + + float TableWidth = GroupWidth + NameWidth + BaseWidth * 4 + NumColumns * Padding + (NumColumns - 1) * GetStyle().ItemSpacing.x; + float TableHeight = Height * (NumEntries + 1); + + ImVec2 TablePos = ImVec2(0.f, 0.f); + if(Window.Align == MICROPROFILE_IMGUI_ALIGN_TOP_RIGHT || Window.Align == MICROPROFILE_IMGUI_ALIGN_BOTTOM_RIGHT) + TablePos.x = io.DisplaySize.x - TableWidth; + + if(Window.Align == MICROPROFILE_IMGUI_ALIGN_BOTTOM_LEFT || Window.Align == MICROPROFILE_IMGUI_ALIGN_BOTTOM_RIGHT) + TablePos.y = io.DisplaySize.y - TableHeight; + TablePos.x += Window.OffsetX; + TablePos.y += Window.OffsetY; + + SetCursorScreenPos(TablePos); + + if(BeginTable("MicroProfileImguiTable", NumColumns, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoHostExtendX)) + { + TableSetupColumn("Group", ImGuiTableColumnFlags_WidthFixed, GroupWidth); + TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, NameWidth); + + TableSetupColumn("Max", ImGuiTableColumnFlags_WidthFixed, BaseWidth); + TableSetupColumn("Min", ImGuiTableColumnFlags_WidthFixed, BaseWidth); + TableSetupColumn("Avg", ImGuiTableColumnFlags_WidthFixed, BaseWidth); + TableSetupColumn("Time", ImGuiTableColumnFlags_WidthFixed, BaseWidth); + + TableHeadersRow(); + + for(uint32_t i = 0; i < NumEntries; ++i) + { + uint32_t TimerIndex = MicroProfileGetTimerIndex(Entries[i].GraphTimer); + + MicroProfileTimerValues Values; + MicroProfileCalcTimers(TimerIndex, Values); + const MicroProfileTimerInfo& TI = S.TimerInfo[TimerIndex]; + const MicroProfileGroupInfo& GI = S.GroupInfo[TI.nGroupIndex]; + TableNextRow(); + ImU32 RowBGColor = GetColorU32((i % 2) ? ImVec4(0.1f, 0.1f, 0.1f, 0.85f) : ImVec4(0.2f, 0.2f, 0.2f, 0.85f)); + TableSetBgColor(ImGuiTableBgTarget_RowBg1, RowBGColor); + PushID(i); + float fMax = 0.f, fMin = 0.f, fAvg = 0.f, fTime = 0.f; + + auto RightAlignedFloat = [](float f) + { + float CellWidth = GetContentRegionAvail().x; + char Buffer[32]; + stbsp_snprintf(Buffer, sizeof(Buffer) - 1, "%.2f", f); + ImVec2 TextSize = CalcTextSize(Buffer); + SetCursorPosX(GetCursorPosX() + (CellWidth - TextSize.x)); + TextUnformatted(Buffer); + }; + + TableSetColumnIndex(0); + Text(GI.pName); + TableSetColumnIndex(1); + Text(TI.pName); + TableSetColumnIndex(2); + RightAlignedFloat(Values.MaxMs); + TableSetColumnIndex(3); + RightAlignedFloat(Values.MinMs); + TableSetColumnIndex(4); + RightAlignedFloat(Values.AverageMs); + TableSetColumnIndex(5); + RightAlignedFloat(Values.TimeMs); + PopID(); + } + EndTable(); + } +} + +void MicroProfileImguiGraphs(const MicroProfileImguiWindowDesc& Window, const MicroProfileImguiEntryDesc* Entries, uint32_t NumEntries) +{ + using namespace ImGui; + ImGuiIO& io = ImGui::GetIO(); + uint32_t Width = Window.GraphWidth; + uint32_t Height = (Window.GraphHeight + GetStyle().ItemSpacing.y) * NumEntries; + + ImVec2 Pos = ImVec2(0.f, 0.f); + if(Window.Align == MICROPROFILE_IMGUI_ALIGN_TOP_RIGHT || Window.Align == MICROPROFILE_IMGUI_ALIGN_BOTTOM_RIGHT) + Pos.x = io.DisplaySize.x - Width; + + if(Window.Align == MICROPROFILE_IMGUI_ALIGN_BOTTOM_LEFT || Window.Align == MICROPROFILE_IMGUI_ALIGN_BOTTOM_RIGHT) + Pos.y = io.DisplaySize.y - Height; + + Pos.x += Window.OffsetX; + Pos.y += Window.OffsetY; + for(uint32_t i = 0; i < NumEntries; ++i) + { + SetCursorScreenPos(Pos); + uint32_t TimerIndex = MicroProfileGetTimerIndex(Entries[i].GraphTimer); + float GraphMax = Entries[i].GraphMax; + const MicroProfileTimerInfo& TI = S.TimerInfo[TimerIndex]; + + MicroProfileImguiTimerState* TimerState = MicroProfileImguiGetTimerState(TimerIndex); + + PushID(i << 16 | TimerIndex); + if(TimerState->nColor == 0) + TimerState->nColor = MicroProfileGetColor(TimerIndex); + ImVec4 FrameBg = GetStyleColorVec4(ImGuiCol_FrameBg); + FrameBg.x = 0.15f; + FrameBg.y = 0.15f; + FrameBg.z = 0.15f; + FrameBg.w = 0.8f; + + PushStyleColor(ImGuiCol_PlotLines, MicroProfileImGuiColor(TimerState->nColor)); + PushStyleColor(ImGuiCol_FrameBg, FrameBg); + uint32_t Start = (ImguiState.GraphPut) % MICROPROFILE_IMGUI_GRAPH_SIZE; + uint32_t Last = (ImguiState.GraphPut + MICROPROFILE_IMGUI_GRAPH_SIZE - 1) % MICROPROFILE_IMGUI_GRAPH_SIZE; + PlotLines("", &TimerState->fValues[0], MICROPROFILE_IMGUI_GRAPH_SIZE, Start, nullptr, 0.f, GraphMax, ImVec2(Window.GraphWidth, Window.GraphHeight)); + + char TimeStr[32]; + stbsp_snprintf(TimeStr, sizeof(TimeStr) - 1, "%.3fms", TimerState->fValues[Last]); + ImVec2 PlotMin = GetItemRectMin(); + ImVec2 PlotMax = GetItemRectMax(); + ImVec2 NameSize = CalcTextSize(TI.pName); + ImVec2 NamePos = ImVec2(PlotMin.x + 1, PlotMax.y - NameSize.y - 1); + ImVec2 TimeSize = CalcTextSize(TimeStr); + ImVec2 TimePos = ImVec2(PlotMax.x - TimeSize.x - 1, PlotMax.y - TimeSize.y - 1); + GetWindowDrawList()->AddText(NamePos, GetColorU32(ImGuiCol_Text), TI.pName); + GetWindowDrawList()->AddText(TimePos, GetColorU32(ImGuiCol_Text), TimeStr); + + PopStyleColor(); + PopStyleColor(); + PopID(); + Pos.y += Window.GraphHeight + GetStyle().ItemSpacing.y; + } +} + +#endif + +#undef uprintf + +#undef S +#ifdef _WIN32 +#pragma warning(pop) +#undef microprofile_fopen_helper +#endif + +#ifdef MICROPROFILE_PS4 +#define MICROPROFILE_PS4_IMPL +#include "microprofile_ps4.h" +#endif +#ifdef MICROPROFILE_XBOXONE +#define MICROPROFILE_XBOXONE_IMPL +#include "microprofile_xboxone.h" +#endif + +#endif // #if MICROPROFILE_ENABLED + +#include "microprofile_html.h" +#include "microprofile_icons.h" + +#endif \ No newline at end of file diff --git a/Windows_Libs/Dev/Render/microprofile/microprofile.h b/Windows_Libs/Dev/Render/microprofile/microprofile.h new file mode 100644 index 0000000..1f1dfa0 --- /dev/null +++ b/Windows_Libs/Dev/Render/microprofile/microprofile.h @@ -0,0 +1,2058 @@ +#pragma once +// MIT License +// +// Copyright (c) 2023 Jonas Meyer +// +// 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. +// *********************************************************************** + +#ifndef MICROPROFILE_USE_CONFIG +#define MICROPROFILE_USE_CONFIG 1 +#endif + +#if MICROPROFILE_USE_CONFIG +#include "microprofile.config.h" +#endif + +#ifndef MICROPROFILE_ENABLED +#define MICROPROFILE_ENABLED 1 +#endif + +#ifndef MICROPROFILE_DYNAMIC_INSTRUMENT +#if(defined(__APPLE__) && defined(__MACH__)) || (defined(_WIN32) && defined(_M_X64)) || (defined(__unix__) && defined(__x86_64__)) +#ifdef MICROPROFILE_DYNAMIC_INSTRUMENT_ENABLE +#define MICROPROFILE_DYNAMIC_INSTRUMENT 1 +#endif +#endif +#endif + +#ifndef MICROPROFILE_DYNAMIC_INSTRUMENT +#define MICROPROFILE_DYNAMIC_INSTRUMENT 0 +#endif + +#ifndef MICROPROFILE_GPU_TIMERS_D3D11 +#define MICROPROFILE_GPU_TIMERS_D3D11 0 +#endif + +#ifndef MICROPROFILE_GPU_TIMERS_GL +#define MICROPROFILE_GPU_TIMERS_GL 0 +#endif + +#ifndef MICROPROFILE_GPU_TIMERS_D3D12 +#define MICROPROFILE_GPU_TIMERS_D3D12 0 +#endif + +#ifndef MICROPROFILE_BIG_ENDIAN +#define MICROPROFILE_BIG_ENDIAN 0 +#endif + +#ifndef MICROPROFILE_GPU_TIMERS_VULKAN +#define MICROPROFILE_GPU_TIMERS_VULKAN 0 +#endif + +#ifndef MICROPROFILE_LEGACY_CSV // set this if you rely on the legacy csv dump format. (single file with multiple csv sections) +#define MICROPROFILE_LEGACY_CSV 0 +#endif + +#ifndef MICROPROFILE_FRAME_EXTRA_DATA // Set this to always allocate frame extra data. This is useful if you're doing profiling on platform where there is plenty of memory. +#define MICROPROFILE_FRAME_EXTRA_DATA 0 +#endif + +#ifndef MICROPROFILE_IMGUI +#define MICROPROFILE_IMGUI 0 +#endif + +#ifndef MICROPROFILE_VERIFY_BALANCED +#define MICROPROFILE_VERIFY_BALANCED 0 +#endif + +#ifndef MICROPROFILE_ONCE +#define MICROPROFILE_ONCE + +#include + +typedef uint64_t MicroProfileToken; +typedef uint16_t MicroProfileGroupId; +typedef uint32_t MicroProfileTimelineToken; + +#if 0 == MICROPROFILE_ENABLED + +#define MICROPROFILE_DECLARE(var) +#define MICROPROFILE_DEFINE(var, group, name, color) +#define MICROPROFILE_REGISTER_GROUP(group, color, category) +#define MICROPROFILE_DECLARE_GPU(var) +#define MICROPROFILE_DEFINE_GPU(var, name, color) +#define MICROPROFILE_SCOPE(var) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SCOPEI(group, name, color) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SCOPE_CSTR(cstr) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SCOPE_TOKEN(token) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SCOPEGPU_TOKEN(token) +#define MICROPROFILE_SCOPEGPU(var) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SCOPEGPUI(name, color) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SCOPEGPU_CSTR(cstr) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SCOPEGPU_TOKEN_L(Log, token) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SCOPEGPU_L(Log, var) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SCOPEGPUI_L(Log, name, color) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SCOPEGPU_CSTR_L(Log, cstr) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SECTIONGPU_TOKEN(token) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SECTIONGPU(var) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SECTIONGPUI(name, color) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SECTIONGPU_TOKEN_L(Log, token) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SECTIONGPU_L(Log, var) \ + do \ + { \ + } while(0) +#define MICROPROFILE_SECTIONGPUI_L(Log, name, color) \ + do \ + { \ + } while(0) + +#define MICROPROFILE_CONDITIONAL_SCOPEI(condition, group, name, color) \ + do \ + { \ + } while(0) +#define MICROPROFILE_ENTER(var) \ + do \ + { \ + } while(0) +#define MICROPROFILE_ENTER_TOKEN(var) \ + do \ + { \ + } while(0) +#define MICROPROFILE_ENTERI(group, name, color) \ + do \ + { \ + } while(0) +#define MICROPROFILE_LEAVE() \ + do \ + { \ + } while(0) + +#define MICROPROFILE_GPU_ENTER(var) \ + do \ + { \ + } while(0) +#define MICROPROFILE_GPU_ENTER_TOKEN(token) \ + do \ + { \ + } while(0) +#define MICROPROFILE_GPU_ENTERI(group, name, color) \ + do \ + { \ + } while(0) +#define MICROPROFILE_GPU_LEAVE() \ + do \ + { \ + } while(0) +#define MICROPROFILE_GPU_ENTER_L(Log, var) \ + do \ + { \ + } while(0) +#define MICROPROFILE_GPU_ENTER_TOKEN_L(Log, token) \ + do \ + { \ + } while(0) +#define MICROPROFILE_GPU_ENTERI_L(Log, name, color) \ + do \ + { \ + } while(0) +#define MICROPROFILE_GPU_LEAVE_L(Log) \ + do \ + { \ + } while(0) +#define MICROPROFILE_GPU_INIT_QUEUE(QueueName) \ + do \ + { \ + } while(0) +#define MICROPROFILE_GPU_GET_QUEUE(QueueName) \ + do \ + { \ + } while(0) +#define MICROPROFILE_GPU_BEGIN(pContext, pLog) \ + do \ + { \ + } while(0) +#define MICROPROFILE_GPU_SET_CONTEXT(pContext, pLog) \ + do \ + { \ + } while(0) +#define MICROPROFILE_GPU_END(pLog) 0 +#define MICROPROFILE_GPU_SUBMIT(Queue, Work) \ + do \ + { \ + } while(0) + +#define MICROPROFILE_TIMELINE_TOKEN(token) \ + do \ + { \ + } while(0) +#define MICROPROFILE_TIMELINE_ENTER(token, color, name) \ + do \ + { \ + } while(0) +#define MICROPROFILE_TIMELINE_ENTERF(token, color, fmt, ...) \ + do \ + { \ + } while(0) +#define MICROPROFILE_TIMELINE_LEAVE(token) \ + do \ + { \ + } while(0) +#define MICROPROFILE_TIMELINE_ENTER_STATIC(color, name) \ + do \ + { \ + } while(0) +#define MICROPROFILE_TIMELINE_LEAVE_STATIC(name) \ + do \ + { \ + } while(0) +#define MICROPROFILE_TIMELINE_SCOPE(...) \ + do \ + { \ + } while(0) +#define MICROPROFILE_THREADLOGGPURESET(a) \ + do \ + { \ + } while(0) +#define MICROPROFILE_META_CPU(name, count) +#define MICROPROFILE_META_GPU(name, count) +#define MICROPROFILE_FORCEENABLECPUGROUP(s) \ + do \ + { \ + } while(0) +#define MICROPROFILE_FORCEDISABLECPUGROUP(s) \ + do \ + { \ + } while(0) +#define MICROPROFILE_FORCEENABLEGPUGROUP(s) \ + do \ + { \ + } while(0) +#define MICROPROFILE_FORCEDISABLEGPUGROUP(s) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_ADD(name, count) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_SUB(name, count) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_SET(name, count) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_SET_DOUBLE(name, count) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_SET_INT32_PTR(name, ptr) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_SET_INT64_PTR(name, ptr) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_CLEAR_PTR(name) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_SET_LIMIT(name, count) \ + do \ + { \ + } while(0) +#define MICROPROFILE_CONDITIONAL(expr) +#define MICROPROFILE_COUNTER_CONFIG(name, type, limit, flags) +#define MICROPROFILE_COUNTER_CONFIG_ONCE(name, type, limit, flags) +#define MICROPROFILE_DECLARE_LOCAL_COUNTER(var) +#define MICROPROFILE_DEFINE_LOCAL_COUNTER(var, name) +#define MICROPROFILE_DECLARE_LOCAL_ATOMIC_COUNTER(var) +#define MICROPROFILE_DEFINE_LOCAL_ATOMIC_COUNTER(var, name) +#define MICROPROFILE_COUNTER_LOCAL_ADD(var, count) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_LOCAL_SUB(var, count) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_LOCAL_SET(var, count) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_LOCAL_UPDATE_ADD(var) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_LOCAL_UPDATE_SET(var) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_LOCAL_ADD_ATOMIC(var, count) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_LOCAL_SUB_ATOMIC(var, count) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_LOCAL_SET_ATOMIC(var, count) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_LOCAL_UPDATE_ADD_ATOMIC(var) \ + do \ + { \ + } while(0) +#define MICROPROFILE_COUNTER_LOCAL_UPDATE_SET_ATOMIC(var) \ + do \ + { \ + } while(0) + +#define MICROPROFILE_COUNTER_GET_TOKEN(name, f) 0 +#define MICROPROFILE_COUNTER_TOKEN_ADD(v, count) do{}while(0) +#define MICROPROFILE_COUNTER_TOKEN_SUB(v, count) do{}while(0) +#define MICROPROFILE_COUNTER_TOKEN_SET(v, count) do{}while(0) + + +#define MicroProfileStartAutoFlip(nHz) \ + do \ + { \ + } while(0) +#define MicroProfileStopAutoFlip() \ + do \ + { \ + } while(0) +#define MicroProfileEnableFrameExtraCounterData() \ + do \ + { \ + } while(0) +#define MicroProfileGetTime(group, name) 0.f +#define MicroProfileOnThreadCreate(foo) \ + do \ + { \ + } while(0) +#define MicroProfileOnThreadExit() \ + do \ + { \ + } while(0) +#define MicroProfileFlip(...) \ + do \ + { \ + } while(0) +#define MicroProfileFlip_CB(pContext, FreezeCB, Flag) \ + do \ + { \ + } while(0) +#define MicroProfileSetAggregateFrames(a) \ + do \ + { \ + } while(0) +#define MicroProfileGetAggregateFrames() 0 +#define MicroProfileGetCurrentAggregateFrames() 0 +#define MicroProfileTogglePause() \ + do \ + { \ + } while(0) +#define MicroProfileToggleAllGroups() \ + do \ + { \ + } while(0) +#define MicroProfileDumpTimers() \ + do \ + { \ + } while(0) +#define MicroProfileShutdown() \ + do \ + { \ + } while(0) +#define MicroProfileSetForceEnable(a) \ + do \ + { \ + } while(0) +#define MicroProfileGetForceEnable() false +#define MicroProfileSetEnableAllGroups(b) \ + do \ + { \ + } while(0) +#define MicroProfileEnableCategory(a) \ + do \ + { \ + } while(0) +#define MicroProfileDisableCategory(a) \ + do \ + { \ + } while(0) +#define MicroProfileGetEnableAllGroups() false +#define MicroProfileSetForceMetaCounters(a) +#define MicroProfileGetForceMetaCounters() 0 +#define MicroProfileEnableMetaCounter(c) \ + do \ + { \ + } while(0) +#define MicroProfileDisableMetaCounter(c) \ + do \ + { \ + } while(0) +#define MicroProfileDumpFile(...) \ + do \ + { \ + } while(0) +#define MicroProfileDumpFileImmediately(...) \ + do \ + { \ + } while(0) +#define MicroProfileStartContextSwitchTrace() \ + do \ + { \ + } while(0) +#define MicroProfileGpuInsertTimeStamp(a) 1 +#define MicroProfileGpuGetTimeStamp(a) 0 +#define MicroProfileTicksPerSecondGpu() 1 +#define MicroProfileGetGpuTickReference(a, b) 0 +#define MicroProfileGpuInitD3D12(pDevice, nNodeCount, pCommandQueue, pCopyQueue) \ + do \ + { \ + } while(0) +#define MicroProfileGpuInitD3D11(pDevice, pDeviceContext) \ + do \ + { \ + } while(0) +#define MicroProfileGpuShutdown() \ + do \ + { \ + } while(0) +#define MicroProfileGpuShutdownPlatform() \ + do \ + { \ + } while(0) +#define MicroProfileGpuInitGL() \ + do \ + { \ + } while(0) +#define MicroProfileSetCurrentNodeD3D12(nNode) \ + do \ + { \ + } while(0) +#define MicroProfilePlatformMarkersGetEnabled() 0 +#define MicroProfilePlatformMarkersSetEnabled(bEnabled) \ + do \ + { \ + } while(0) +#define MicroProfileTickToMsMultiplierCpu() 1.f +#define MicroProfileTickToMsMultiplierGpu() 0.f +#define MicroProfileTicksPerSecondCpu() 1 +#define MicroProfileTick() 0 +#define MicroProfileEnabled() 0 + +#define MicroProfileCounterString nullptr +#define MicroProfileCounterTokenTree 0 +#define MicroProfileCounterTokenTreeDynamic 0 + +#define MicroProfileCsvConfigEnd() +#define MicroProfileCsvConfigBegin(...) +#define MicroProfileCsvConfigAddTimer(...) +#define MicroProfileCsvConfigAddGroup(...) +#define MicroProfileCsvConfigAddCounter(...) +#define MicroProfileUpdateSettingsPath(...) + +#define MicroProfileImguiGraphs(...) \ + do \ + { \ + } while(0) +#define MicroProfileImguiTable(...) \ + do \ + { \ + } while(0) +#define MicroProfileImguiControls(...) \ + do \ + { \ + } while(0) + +#else + +#include + +#ifdef MICROPROFILE_EXPORT +#include "microprofile.export.h" +#else +#ifndef MICROPROFILE_API +#define MICROPROFILE_API +#endif +#endif + +#ifdef MICROPROFILE_PS4 +#include "microprofile_ps4.h" +#endif +#ifdef MICROPROFILE_XBOXONE +#include "microprofile_xboxone.h" +#endif + +#ifdef _WIN32 +typedef uint32_t MicroProfileThreadIdType; +#else +#ifdef MICROPROFILE_THREADID_SIZE_4BYTE +typedef uint32_t MicroProfileThreadIdType; +#elif MICROPROFILE_THREADID_SIZE_8BYTE +typedef uint64_t MicroProfileThreadIdType; +#else +typedef uint64_t MicroProfileThreadIdType; +#endif +#endif + +typedef void (*MicroProfileOnFreeze)(int nFrozen); + +#define MICROPROFILE_TOKEN_PASTE0(a, b) a##b +#define MICROPROFILE_TOKEN_PASTE(a, b) MICROPROFILE_TOKEN_PASTE0(a, b) + +#define MICROPROFILE_DECLARE(var) extern MicroProfileToken g_mp_##var +#define MICROPROFILE_DECLARE_GPU(var) extern MicroProfileToken g_mpGPU_##var + +#define MICROPROFILE_DECLARE_SECTION(var) extern MicroProfileToken g_mp_##var +#define MICROPROFILE_DECLARE_SECTION_GPU(var) extern MicroProfileToken g_mpGPU_##var + +#define MICROPROFILE_DEFINE(var, group, name, color) MicroProfileToken g_mp_##var = MicroProfileGetToken(group, name, color, MicroProfileTokenTypeCpu, 0) +#define MICROPROFILE_DEFINE_GPU(var, name, color) MicroProfileToken g_mpGPU_##var = MicroProfileGetToken("GPU", name, color, MicroProfileTokenTypeGpu, 0) + +#define MICROPROFILE_DEFINE_SECTION(var, name, color) MicroProfileToken g_mp_##var = MicroProfileGetToken("__SECTION", name, color, MicroProfileTokenTypeCpu, MICROPROFILE_TIMER_FLAG_SECTION) +#define MICROPROFILE_DEFINE_SECTION_GPU(var, name, color) MicroProfileToken g_mpGPU_##var = MicroProfileGetToken("GPU", name, color, MicroProfileTokenTypeGpu, MICROPROFILE_TIMER_FLAG_SECTION) + +#define MICROPROFILE_REGISTER_GROUP(group, category, color) MicroProfileRegisterGroup(group, category, color) + +#define MICROPROFILE_SCOPE(var) MicroProfileScopeHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(g_mp_##var) +#define MICROPROFILE_SCOPE_TOKEN(token) MicroProfileScopeHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(token) +#define MICROPROFILE_SCOPEI(group, name, color) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp, __LINE__) = MicroProfileGetToken(group, name, color, MicroProfileTokenTypeCpu, 0); \ + MicroProfileScopeHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(MICROPROFILE_TOKEN_PASTE(g_mp, __LINE__)) +#define MICROPROFILE_SCOPE_CSTR(CStr) MicroProfileScopeHandlerCStr MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(CStr) + +#define MICROPROFILE_SECTION(var) MICROPROFILE_SCOPE(var) +#define MICROPROFILE_SECTIONI(name, color) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp, __LINE__) = MicroProfileGetToken("__SECTION", name, color, MicroProfileTokenTypeCpu, MICROPROFILE_TIMER_FLAG_SECTION); \ + MicroProfileScopeHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(MICROPROFILE_TOKEN_PASTE(g_mp, __LINE__)) + +#define MICROPROFILE_SCOPEGPU_TOKEN(token) MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(fooGPU, __LINE__)(token, MicroProfileGetGlobalGpuThreadLog()) +#define MICROPROFILE_SCOPEGPU(var) MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(fooGPU, __LINE__)(g_mpGPU_##var, MicroProfileGetGlobalGpuThreadLog()) +#define MICROPROFILE_SCOPEGPUI(name, color) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__) = MicroProfileGetToken("GPU", name, color, MicroProfileTokenTypeGpu, 0); \ + MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(fooGPU, __LINE__)(MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__), MicroProfileGetGlobalGpuThreadLog()) +#define MICROPROFILE_SCOPEGPU_CSTR(CStr) MicroProfileScopeGpuHandlerCStr MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(CStr, MicroProfileGetGlobalGpuThreadLog()) + +#define MICROPROFILE_SCOPEGPU_TOKEN_L(Log, token) MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(fooGPU, __LINE__)(token, Log) +#define MICROPROFILE_SCOPEGPU_L(Log, var) MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(fooGPU, __LINE__)(g_mpGPU_##var, Log) +#define MICROPROFILE_SCOPEGPUI_L(Log, name, color) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__) = MicroProfileGetToken("GPU", name, color, MicroProfileTokenTypeGpu, 0); \ + MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(fooGPU, __LINE__)(MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__), Log) +#define MICROPROFILE_SCOPEGPU_CSTR_L(Log, CStr) MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(CStr, Log) + +#define MICROPROFILE_SECTIONGPU_TOKEN(token) MICROPROFILE_SCOPEGPU_TOKEN(token) +#define MICROPROFILE_SECTIONGPU(var) MICROPROFILE_SCOPEGPU(var) +#define MICROPROFILE_SECTIONGPUI(name, color) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__) = MicroProfileGetToken("__SECTIONGPU", name, color, MicroProfileTokenTypeGpu, MICROPROFILE_TIMER_FLAG_SECTION); \ + MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(fooGPU, __LINE__)(MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__)) + +#define MICROPROFILE_SECTIONGPU_TOKEN_L(Log, token) MICROPROFILE_SCOPEGPU_TOKEN_L(token, Log) +#define MICROPROFILE_SECTIONGPU_L(Log, var) MICROPROFILE_SCOPEGPU_L(var, Log) +#define MICROPROFILE_SECTIONGPUI_L(Log, name, color) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__) = MicroProfileGetToken("__SECTIONGPU", name, color, MicroProfileTokenTypeGpu, MICROPROFILE_TIMER_FLAG_SECTION); \ + MicroProfileScopeGpuHandler MICROPROFILE_TOKEN_PASTE(fooGPU, __LINE__)(MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__), Log) + +#define MICROPROFILE_CONDITIONAL_SCOPEI(condition, group, name, color) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp, __LINE__) = MicroProfileGetToken(group, name, color, MicroProfileTokenTypeCpu, 0); \ + MicroProfileConditionalScopeHandler MICROPROFILE_TOKEN_PASTE(foo, __LINE__)(MICROPROFILE_TOKEN_PASTE(g_mp, __LINE__), condition) +#define MICROPROFILE_ENTER(var) MicroProfileEnter(g_mp_##var) +#define MICROPROFILE_ENTER_TOKEN(token) MicroProfileEnter(token) +#define MICROPROFILE_ENTERI(group, name, color) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp, __LINE__) = MICROPROFILE_INVALID_TOKEN; \ + if(MICROPROFILE_INVALID_TOKEN == MICROPROFILE_TOKEN_PASTE(g_mp, __LINE__)) \ + { \ + MicroProfileGetTokenC(&MICROPROFILE_TOKEN_PASTE(g_mp, __LINE__), group, name, color, MicroProfileTokenTypeCpu, 0); \ + } \ + MicroProfileEnter(MICROPROFILE_TOKEN_PASTE(g_mp, __LINE__)) +#define MICROPROFILE_LEAVE() MicroProfileLeave() + +#define MICROPROFILE_GPU_ENTER(var) MicroProfileEnterGpu(g_mpGPU_##var, MicroProfileGetGlobalGpuThreadLog()) +#define MICROPROFILE_GPU_ENTER_TOKEN(token) MicroProfileEnterGpu(token, MicroProfileGetGlobalGpuThreadLog()) +#define MICROPROFILE_GPU_ENTERI(group, name, color) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__) = MICROPROFILE_INVALID_TOKEN; \ + if(MICROPROFILE_INVALID_TOKEN == MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__)) \ + { \ + MicroProfileGetTokenC(&MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__), group, name, color, MicroProfileTokenTypeGpu, 0); \ + } \ + MicroProfileEnterGpu(MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__), MicroProfileGetGlobalGpuThreadLog()) +#define MICROPROFILE_GPU_LEAVE() MicroProfileLeaveGpu(MicroProfileGetGlobalGpuThreadLog()) +#define MICROPROFILE_GPU_ENTER_L(Log, var) MicroProfileEnterGpu(g_mpGPU_##var, Log) +#define MICROPROFILE_GPU_ENTER_TOKEN_L(Log, token) MicroProfileEnterGpu(token, Log) +#define MICROPROFILE_GPU_ENTERI_L(Log, name, color) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__) = MICROPROFILE_INVALID_TOKEN; \ + if(MICROPROFILE_INVALID_TOKEN == MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__)) \ + { \ + MicroProfileGetTokenC(&MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__), group, name, color, MicroProfileTokenTypeGpu, 0); \ + } \ + MicroProfileEnterGpu(MICROPROFILE_TOKEN_PASTE(g_mpGPU, __LINE__), Log) +#define MICROPROFILE_GPU_LEAVE_L(Log) MicroProfileLeaveGpu(Log) +#define MICROPROFILE_GPU_INIT_QUEUE(QueueName) MicroProfileInitGpuQueue(QueueName) +#define MICROPROFILE_GPU_FREE_QUEUE(QueueName) MicroProfileFreeGpuQueue(QueueName) +#define MICROPROFILE_GPU_GET_QUEUE(QueueName) MicroProfileGetGpuQueue(QueueName) +#define MICROPROFILE_GPU_BEGIN(pContext, pLog) MicroProfileGpuBegin(pContext, pLog) +#define MICROPROFILE_GPU_SET_CONTEXT(pContext, pLog) MicroProfileGpuSetContext(pContext, pLog) +#define MICROPROFILE_GPU_END(pLog) MicroProfileGpuEnd(pLog) +#define MICROPROFILE_GPU_SUBMIT(Queue, Work) MicroProfileGpuSubmit(Queue, Work) +#define MICROPROFILE_TIMELINE_TOKEN(token) MicroProfileTimelineToken token = 0 +#define MICROPROFILE_TIMELINE_ENTER(token, color, name) token = MicroProfileTimelineEnter(color, name) +#define MICROPROFILE_TIMELINE_ENTERF(token, color, fmt, ...) token = MicroProfileTimelineEnterf(color, fmt, ##__VA_ARGS__) +#define MICROPROFILE_TIMELINE_LEAVE(token) \ + do \ + { \ + if(token) \ + { \ + MicroProfileTimelineLeave(token); \ + } \ + } while(0) +// use only with static string literals +#define MICROPROFILE_TIMELINE_ENTER_STATIC(color, name) MicroProfileTimelineEnterStatic(color, name) +// use only with static string literals +#define MICROPROFILE_TIMELINE_LEAVE_STATIC(name) MicroProfileTimelineLeaveStatic(name) +#define MICROPROFILE_TIMELINE_SCOPE(color, fmt, ...) \ + MicroProfileTimelineToken MICROPROFILE_TOKEN_PASTE(__timeline__, __LINE__) = MicroProfileTimelineEnterf(color, fmt, ##__VA_ARGS__); \ + MicroProfileScopeTimelineExitHandler MICROPROFILE_TOKEN_PASTE(__timeline__0, __LINE__)(MICROPROFILE_TOKEN_PASTE(__timeline__, __LINE__)) + +#define MICROPROFILE_THREADLOGGPURESET(a) MicroProfileThreadLogGpuReset(a) +#define MICROPROFILE_META_CPU(name, count) \ + do \ + { \ + } while(0) // static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp_meta,__LINE__) = MicroProfileGetMetaToken(name); MicroProfileMetaUpdate(MICROPROFILE_TOKEN_PASTE(g_mp_meta,__LINE__), count, + // MicroProfileTokenTypeCpu) +#define MICROPROFILE_COUNTER_ADD(name, count) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp_counter, __LINE__) = MicroProfileGetCounterToken(name, 0); \ + MicroProfileCounterAdd(MICROPROFILE_TOKEN_PASTE(g_mp_counter, __LINE__), count) +#define MICROPROFILE_COUNTER_SUB(name, count) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp_counter, __LINE__) = MicroProfileGetCounterToken(name, 0); \ + MicroProfileCounterAdd(MICROPROFILE_TOKEN_PASTE(g_mp_counter, __LINE__), -(int64_t)count) +#define MICROPROFILE_COUNTER_SET(name, count) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp_counter_set, __LINE__) = MicroProfileGetCounterToken(name, 0); \ + MicroProfileCounterSet(MICROPROFILE_TOKEN_PASTE(g_mp_counter_set, __LINE__), count) +#define MICROPROFILE_COUNTER_SET_DOUBLE(name, count) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp_counter_set, __LINE__) = MicroProfileGetCounterToken(name, MICROPROFILE_COUNTER_FLAG_DOUBLE); \ + MicroProfileCounterSetDouble(MICROPROFILE_TOKEN_PASTE(g_mp_counter_set, __LINE__), count) +#define MICROPROFILE_COUNTER_SET_INT32_PTR(name, ptr) MicroProfileCounterSetPtr(name, ptr, sizeof(int32_t)) +#define MICROPROFILE_COUNTER_SET_INT64_PTR(name, ptr) MicroProfileCounterSetPtr(name, ptr, sizeof(int64_t)) +#define MICROPROFILE_COUNTER_CLEAR_PTR(name) MicroProfileCounterSetPtr(name, 0, 0) +#define MICROPROFILE_COUNTER_SET_LIMIT(name, count) \ + static MicroProfileToken MICROPROFILE_TOKEN_PASTE(g_mp_counter, __LINE__) = MicroProfileGetCounterToken(name, 0); \ + MicroProfileCounterSetLimit(MICROPROFILE_TOKEN_PASTE(g_mp_counter, __LINE__), count) +#define MICROPROFILE_COUNTER_CONFIG(name, type, limit, flags) MicroProfileCounterConfig(name, type, limit, flags) +#define MICROPROFILE_COUNTER_CONFIG_ONCE(name, type, limit, flags) \ + do \ + { \ + static bool MICROPROFILE_TOKEN_PASTE(g_mponce, __LINE__) = false; \ + if(!MICROPROFILE_TOKEN_PASTE(g_mponce, __LINE__)) \ + { \ + MICROPROFILE_TOKEN_PASTE(g_mponce, __LINE__) = true; \ + MicroProfileCounterConfig(name, type, limit, flags); \ + } \ + } while(0) +#define MICROPROFILE_DECLARE_LOCAL_COUNTER(var) \ + extern int64_t g_mp_local_counter##var; \ + extern MicroProfileToken g_mp_counter_token##var; +#define MICROPROFILE_DEFINE_LOCAL_COUNTER(var, name) \ + int64_t g_mp_local_counter##var = 0; \ + MicroProfileToken g_mp_counter_token##var = MicroProfileGetCounterToken(name, 0) +#define MICROPROFILE_DECLARE_LOCAL_ATOMIC_COUNTER(var) extern MicroProfileToken g_mp_counter_token##var; +#define MICROPROFILE_DEFINE_LOCAL_ATOMIC_COUNTER(var, name) MicroProfileToken g_mp_counter_token##var = MicroProfileGetCounterToken(name, 0) +#define MICROPROFILE_COUNTER_LOCAL_ADD(var, count) MicroProfileLocalCounterAdd(&g_mp_local_counter##var, (count)) +#define MICROPROFILE_COUNTER_LOCAL_SUB(var, count) MicroProfileLocalCounterAdd(&g_mp_local_counter##var, -(int64_t)(count)) +#define MICROPROFILE_COUNTER_LOCAL_SET(var, count) MicroProfileLocalCounterSet(&g_mp_local_counter##var, count) +#define MICROPROFILE_COUNTER_LOCAL_UPDATE_ADD(var) MicroProfileCounterAdd(g_mp_counter_token##var, MicroProfileLocalCounterSet(&g_mp_local_counter##var, 0)) +#define MICROPROFILE_COUNTER_LOCAL_UPDATE_SET(var) MicroProfileCounterSet(g_mp_counter_token##var, MicroProfileLocalCounterSet(&g_mp_local_counter##var, 0)) +#define MICROPROFILE_COUNTER_LOCAL_ADD_ATOMIC(var, count) MicroProfileLocalCounterAddAtomic(g_mp_counter_token##var, (count)) +#define MICROPROFILE_COUNTER_LOCAL_SUB_ATOMIC(var, count) MicroProfileLocalCounterAddAtomic(g_mp_counter_token##var, -(int64_t)(count)) +#define MICROPROFILE_COUNTER_LOCAL_SET_ATOMIC(var, count) MicroProfileLocalCounterSetAtomic(g_mp_counter_token##var, count) +#define MICROPROFILE_COUNTER_LOCAL_UPDATE_ADD_ATOMIC(var) MicroProfileCounterAdd(g_mp_counter_token##var, MicroProfileLocalCounterSetAtomic(g_mp_counter_token##var, 0)) +#define MICROPROFILE_COUNTER_LOCAL_UPDATE_SET_ATOMIC(var) MicroProfileCounterSet(g_mp_counter_token##var, MicroProfileLocalCounterSetAtomic(g_mp_counter_token##var, 0)) +#define MICROPROFILE_COUNTER_GET_TOKEN(name, f) MicroProfileGetCounterToken(name, f) +#define MICROPROFILE_COUNTER_TOKEN_ADD(v, count) MicroProfileCounterAdd(v, count) +#define MICROPROFILE_COUNTER_TOKEN_SUB(v, count) MicroProfileCounterAdd(v, -(int64_t)count) +#define MICROPROFILE_COUNTER_TOKEN_SET(v, count) MicroProfileCounterSet(v, count) +#define MICROPROFILE_FORCEENABLECPUGROUP(s) MicroProfileForceEnableGroup(s, MicroProfileTokenTypeCpu) +#define MICROPROFILE_FORCEDISABLECPUGROUP(s) MicroProfileForceDisableGroup(s, MicroProfileTokenTypeCpu) +#define MICROPROFILE_FORCEENABLEGPUGROUP(s) MicroProfileForceEnableGroup(s, MicroProfileTokenTypeGpu) +#define MICROPROFILE_FORCEDISABLEGPUGROUP(s) MicroProfileForceDisableGroup(s, MicroProfileTokenTypeGpu) +#define MICROPROFILE_CONDITIONAL(expr) expr + +#ifndef MICROPROFILE_PLATFORM_MARKERS +#define MICROPROFILE_PLATFORM_MARKERS 0 +#endif + +#if MICROPROFILE_PLATFORM_MARKERS +#define MICROPROFILE_PLATFORM_MARKERS_ENABLED S.nPlatformMarkersEnabled +#define MICROPROFILE_PLATFORM_MARKER_BEGIN(color, marker) MicroProfilePlatformMarkerBegin(color, marker) +#define MICROPROFILE_PLATFORM_MARKER_END() MicroProfilePlatformMarkerEnd() +#else +#define MICROPROFILE_PLATFORM_MARKER_BEGIN(color, marker) \ + do \ + { \ + (void)color; \ + (void)marker; \ + } while(0) +#define MICROPROFILE_PLATFORM_MARKER_END() \ + do \ + { \ + } while(0) +#define MICROPROFILE_PLATFORM_MARKERS_ENABLED 0 +#endif + +#define MICROPROFILE_MAJOR_VERSION 4 +#define MICROPROFILE_MINOR_VERSION 0 + +#ifndef MICROPROFILE_USE_THREAD_NAME_CALLBACK +#define MICROPROFILE_USE_THREAD_NAME_CALLBACK 0 +#endif + +#ifndef MICROPROFILE_PER_THREAD_BUFFER_SIZE +#define MICROPROFILE_PER_THREAD_BUFFER_SIZE (2048 << 10) +#endif + +#ifndef MICROPROFILE_PER_THREAD_GPU_BUFFER_SIZE +#define MICROPROFILE_PER_THREAD_GPU_BUFFER_SIZE (128 << 10) +#endif + +#ifndef MICROPROFILE_MAX_FRAME_HISTORY +#define MICROPROFILE_MAX_FRAME_HISTORY 512 +#endif + +#ifndef MICROPROFILE_PRINTF +#define MICROPROFILE_PRINTF printf +#endif + +// #ifndef MICROPROFILE_META_MAX +// #define MICROPROFILE_META_MAX 8 +// #endif + +#ifndef MICROPROFILE_WEBSERVER_PORT +#define MICROPROFILE_WEBSERVER_PORT 1338 +#endif + +#ifndef MICROPROFILE_WEBSERVER +#define MICROPROFILE_WEBSERVER 1 +#endif + +#ifndef MICROPROFILE_WEBSERVER_AUTO_START +#define MICROPROFILE_WEBSERVER_AUTO_START 1 // when set to 1, the webserver will start on first call to MicroProfileFlip +#endif + +#ifndef MICROPROFILE_WEBSERVER_DEFAULT_FRAMES +#define MICROPROFILE_WEBSERVER_DEFAULT_FRAMES 30 +#endif + +#ifndef MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE +#define MICROPROFILE_WEBSERVER_SOCKET_BUFFER_SIZE (16 << 10) +#endif + +#ifndef MICROPROFILE_GPU_TIMERS +#if defined(MICROPROFILE_GPU_TIMERS_VULKAN) || defined(MICROPROFILE_GPU_TIMERS_D3D12) || defined(MICROPROFILE_GPU_TIMERS_D3D11) || defined(MICROPROFILE_GPU_TIMERS_GL) +#define MICROPROFILE_GPU_TIMERS 1 +#else +#define MICROPROFILE_GPU_TIMERS 0 +#endif +#endif + +#ifndef MICROPROFILE_GPU_FRAME_DELAY +#define MICROPROFILE_GPU_FRAME_DELAY 5 // must be > 0 +#endif + +#ifndef MICROPROFILE_NAME_MAX_LEN +#define MICROPROFILE_NAME_MAX_LEN 64 +#endif + +#ifndef MICROPROFILE_MAX_TIMERS +#define MICROPROFILE_MAX_TIMERS 1024 +#endif + +#ifndef MICROPROFILE_MAX_THREADS +#define MICROPROFILE_MAX_THREADS 128 +#endif + +#ifndef MICROPROFILE_UNPACK_RED +#define MICROPROFILE_UNPACK_RED(c) (0xff & ((c) >> 16)) +#endif + +#ifndef MICROPROFILE_UNPACK_GREEN +#define MICROPROFILE_UNPACK_GREEN(c) (0xff & ((c) >> 8)) +#endif + +#ifndef MICROPROFILE_UNPACK_BLUE +#define MICROPROFILE_UNPACK_BLUE(c) (0xff & ((c))) +#endif + +#ifndef MICROPROFILE_DEFAULT_PRESET +#define MICROPROFILE_DEFAULT_PRESET "Default" +#endif + +#ifndef MICROPROFILE_TIMELINE_MAX_ENTRIES +#define MICROPROFILE_TIMELINE_MAX_ENTRIES (4 << 10) +#endif + +#ifndef MICROPROFILE_MAX_STRING +#define MICROPROFILE_MAX_STRING 128 +#endif + +#ifndef MICROPROFILE_TIMELINE_MAX_TOKENS +#define MICROPROFILE_TIMELINE_MAX_TOKENS 64 +#endif + +#ifndef MICROPROFILE_THREAD_LOG_FRAMES_REUSE +#define MICROPROFILE_THREAD_LOG_FRAMES_REUSE 200 +#endif + +#ifndef MICROPROFILE_CONTEXT_SWITCH_TRACE +#if defined(_WIN32) +#define MICROPROFILE_CONTEXT_SWITCH_TRACE 1 +#elif defined(__APPLE__) +#define MICROPROFILE_CONTEXT_SWITCH_TRACE 0 // disabled until dtrace script is working. +#else +#define MICROPROFILE_CONTEXT_SWITCH_TRACE 0 +#endif +#endif + +#if MICROPROFILE_CONTEXT_SWITCH_TRACE +#define MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE (128 * 1024) // 2mb with 16 byte entry size +#else +#define MICROPROFILE_CONTEXT_SWITCH_BUFFER_SIZE (1) +#endif + +#ifndef MICROPROFILE_MINIZ +#define MICROPROFILE_MINIZ 0 +#endif + +#ifndef MICROPROFILE_COUNTER_HISTORY +#define MICROPROFILE_COUNTER_HISTORY 1 +#endif + +#ifndef MICROPROFILE_MAX_GROUPS +#define MICROPROFILE_MAX_GROUPS 128 // must be multiple of 32 +#endif + +#ifndef MICROPROFILE_STACK_MAX +#define MICROPROFILE_STACK_MAX 64 +#endif + +#ifndef MICROPROFILE_BREAK_ON_PATCH_FAIL +#define MICROPROFILE_BREAK_ON_PATCH_FAIL 0 +#endif + +#ifndef MICROPROFILE_INSTRUMENT_MICROPROFILE +#define MICROPROFILE_INSTRUMENT_MICROPROFILE 0 +#endif + +#ifndef MICROPROFILE_MAX_DYNAMIC_TOKENS +#define MICROPROFILE_MAX_DYNAMIC_TOKENS 2048 +#endif + +#ifndef MICROPROFILE_INSTRUMENT_SYMBOLNAME_MAXLEN +#define MICROPROFILE_INSTRUMENT_SYMBOLNAME_MAXLEN 128 +#endif + +#ifndef MICROPROFILE_INSTRUMENT_MAX_MODULES +#define MICROPROFILE_INSTRUMENT_MAX_MODULES 256 +#endif + +#ifndef MICROPROFILE_INSTRUMENT_MAX_MODULE_CHARS +#define MICROPROFILE_INSTRUMENT_MAX_MODULE_CHARS (8 << 10) +#endif + +#ifndef MICROPROFILE_ASSERT_LOG_FREED +#define MICROPROFILE_ASSERT_LOG_FREED 0 +#endif + +#define MICROPROFILE_FLIP_FLAG_START_WEBSERVER 0x1 + +#if MICROPROFILE_WEBSERVER_AUTO_START +#define MICROPROFILE_FLIP_FLAG_DEFAULT (MICROPROFILE_FLIP_FLAG_START_WEBSERVER) +#else +#define MICROPROFILE_FLIP_FLAG_DEFAULT (0) +#endif + +#ifndef MICROPROFILE_GET_SETTINGS_FILE_PATH +#define MICROPROFILE_GET_SETTINGS_FILE_PATH "" +#endif + +#ifndef MICROPROFILE_MAX_CPU_CORES +#define MICROPROFILE_MAX_CPU_CORES 256 +#endif + +typedef enum MicroProfileTokenType_t +{ + MicroProfileTokenTypeCpu, + MicroProfileTokenTypeGpu, +} MicroProfileTokenType; + +struct MicroProfile; +struct MicroProfileThreadLogGpu; +struct MicroProfileScopeStateC; + +#ifdef __cplusplus +#define IF_CPP(exp) exp +#else +#define IF_CPP(exp) +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#define MICROPROFILE_INVALID_TOKEN ((uint64_t) - 1) +#define MICROPROFILE_TIMER_FLAG_SECTION 0x1 +#define MICROPROFILE_TIMER_FLAG_PLACEHOLDER 0x1000 +#define MICROPROFILE_CSV_FLAG_FRAME_NUMBERS 0x0 +#define MICROPROFILE_CSV_FLAG_FRAME_TIME 0x1 + + MICROPROFILE_API void MicroProfileInit(); + MICROPROFILE_API void MicroProfileShutdown(); + MICROPROFILE_API void MicroProfileStartAutoFlip(uint32_t nHz); + MICROPROFILE_API void MicroProfileStopAutoFlip(); + MICROPROFILE_API void MicroProfileEnableFrameExtraCounterData(); // enable per frame counter storage. uses more memory + MICROPROFILE_API MicroProfileToken MicroProfileFindToken(const char* sGroup, const char* sName); + MICROPROFILE_API MicroProfileToken MicroProfileGetToken(const char* sGroup, const char* sName, uint32_t nColor, MicroProfileTokenType Token, uint32_t flags); + MICROPROFILE_API void MicroProfileGetTokenC(MicroProfileToken* pToken, const char* sGroup, const char* sName, uint32_t nColor, MicroProfileTokenType Token, uint32_t flags); + MICROPROFILE_API MicroProfileToken MicroProfileGetCounterToken(const char* pName, uint32_t CounterTokenFlag); + MICROPROFILE_API MicroProfileToken MicroProfileGetChildCounterToken(MicroProfileToken Parent, const char* pName); // manually create the child/parent tree + MICROPROFILE_API void MicroProfileCounterAdd(MicroProfileToken nToken, int64_t nCount); + MICROPROFILE_API void MicroProfileCounterSet(MicroProfileToken nToken, int64_t nCount); + MICROPROFILE_API int64_t MicroProfileCounterGet(MicroProfileToken nToken); + MICROPROFILE_API void MicroProfileCounterSetDouble(MicroProfileToken nToken, double dCount); + MICROPROFILE_API double MicroProfileCounterGetDouble(MicroProfileToken nToken); + MICROPROFILE_API void MicroProfileCounterSetLimit(MicroProfileToken nToken, int64_t nCount); + MICROPROFILE_API void MicroProfileCounterSetLimitDouble(MicroProfileToken nToken, double nCount); + MICROPROFILE_API void MicroProfileCounterConfig(const char* pCounterName, uint32_t nFormat, int64_t nLimit, uint32_t nFlags); + MICROPROFILE_API void MicroProfileCounterConfigToken(MicroProfileToken nToken, uint32_t nFormat, int64_t nLimit, uint32_t nFlags); + MICROPROFILE_API void MicroProfileCounterSetPtr(const char* pCounterName, void* pValue, uint32_t nSize); + MICROPROFILE_API void MicroProfileCounterFetchCounters(); + MICROPROFILE_API void MicroProfileLocalCounterAdd(int64_t* pCounter, int64_t nCount); + MICROPROFILE_API int64_t MicroProfileLocalCounterSet(int64_t* pCounter, int64_t nCount); + MICROPROFILE_API uint64_t MicroProfileEnterInternal(MicroProfileToken nToken); + MICROPROFILE_API void MicroProfileLeaveInternal(MicroProfileToken nToken, uint64_t nTick); + MICROPROFILE_API uint64_t MicroProfileEnterInternalCStr(const char* pStr); + + MICROPROFILE_API void MicroProfileLeaveInternalCStr(const char* pStr, uint64_t nTickStart); + + MICROPROFILE_API void MicroProfileEnter(MicroProfileToken nToken); + MICROPROFILE_API void MicroProfileLeave(); + + MICROPROFILE_API void MicroProfileEnterSection(const char* pName, uint32_t nColor); + MICROPROFILE_API void MicroProfileLeaveSection(); + + MICROPROFILE_API void MicroProfileEnterGpu(MicroProfileToken nToken, struct MicroProfileThreadLogGpu* pLog); + MICROPROFILE_API void MicroProfileLeaveGpu(struct MicroProfileThreadLogGpu* pLog); + MICROPROFILE_API MicroProfileTimelineToken MicroProfileTimelineEnterInternal(uint32_t nColor, const char* pStr, uint32_t nStrLen, int bIsStaticString); + MICROPROFILE_API MicroProfileTimelineToken MicroProfileTimelineEnter(uint32_t nColor, const char* pStr); + MICROPROFILE_API MicroProfileTimelineToken MicroProfileTimelineEnterf(uint32_t nColor, const char* pStr, ...); + MICROPROFILE_API void MicroProfileTimelineLeave(MicroProfileTimelineToken id); + MICROPROFILE_API void MicroProfileTimelineEnterStatic(uint32_t nColor, const char* pStr); + MICROPROFILE_API void MicroProfileTimelineLeaveStatic(const char* pStr); + + MICROPROFILE_API uint64_t MicroProfileGpuEnterInternal(struct MicroProfileThreadLogGpu* pLog, MicroProfileToken nToken); + MICROPROFILE_API void MicroProfileGpuLeaveInternal(struct MicroProfileThreadLogGpu* pLog, MicroProfileToken nToken, uint64_t nTick); + MICROPROFILE_API uint64_t MicroProfileGpuEnterInternalCStr(struct MicroProfileThreadLogGpu* pGpuLog, const char* pStr); + MICROPROFILE_API void MicroProfileGpuLeaveInternalCStr(struct MicroProfileThreadLogGpu* pGpuLog, uint64_t nTickStart); + + MICROPROFILE_API void MicroProfileGpuBegin(void* pContext, struct MicroProfileThreadLogGpu* pLog); + MICROPROFILE_API void MicroProfileGpuSetContext(void* pContext, struct MicroProfileThreadLogGpu* pLog); + MICROPROFILE_API uint64_t MicroProfileGpuEnd(struct MicroProfileThreadLogGpu* pLog); + MICROPROFILE_API struct MicroProfileThreadLogGpu* MicroProfileThreadLogGpuAlloc(); + MICROPROFILE_API void MicroProfileThreadLogGpuFree(struct MicroProfileThreadLogGpu* pLog); + MICROPROFILE_API void MicroProfileThreadLogGpuReset(struct MicroProfileThreadLogGpu* pLog); + MICROPROFILE_API void MicroProfileGpuSubmit(int nQueue, uint64_t nWork); + MICROPROFILE_API int MicroProfileInitGpuQueue(const char* pQueueName); + MICROPROFILE_API void MicroProfileFreeGpuQueue(int nQueue); + MICROPROFILE_API int MicroProfileGetGpuQueue(const char* pQueueName); + + MICROPROFILE_API void MicroProfileFlip(void* pGpuContext, uint32_t FlipFlag IF_CPP(= MICROPROFILE_FLIP_FLAG_DEFAULT)); //! call once per frame. + MICROPROFILE_API void MicroProfileFlip_CB(void* pGpuContext, MicroProfileOnFreeze FreezeCB, uint32_t FlipFlag IF_CPP(= MICROPROFILE_FLIP_FLAG_DEFAULT)); //! call once per frame. + MICROPROFILE_API void MicroProfileToggleFrozen(); + MICROPROFILE_API int MicroProfileIsFrozen(); + MICROPROFILE_API int MicroProfileEnabled(); + MICROPROFILE_API void MicroProfileForceEnableGroup(const char* pGroup, MicroProfileTokenType Type); + MICROPROFILE_API void MicroProfileForceDisableGroup(const char* pGroup, MicroProfileTokenType Type); + MICROPROFILE_API float MicroProfileGetTime(const char* pGroup, const char* pName); + MICROPROFILE_API int MicroProfilePlatformMarkersGetEnabled(); // enable platform markers. disables microprofile markers + MICROPROFILE_API void MicroProfilePlatformMarkersSetEnabled(int bEnabled); // enable platform markers. disables microprofile markers + MICROPROFILE_API void MicroProfileContextSwitchSearch(uint32_t* pContextSwitchStart, uint32_t* pContextSwitchEnd, uint64_t nBaseTicksCpu, uint64_t nBaseTicksEndCpu); + MICROPROFILE_API void MicroProfileOnThreadCreate(const char* pThreadName); // should be called from newly created threads + MICROPROFILE_API void MicroProfileOnThreadExit(); // call on exit to reuse log + MICROPROFILE_API void MicroProfileInitThreadLog(); + MICROPROFILE_API void MicroProfileSetEnableAllGroups(int bEnable); + MICROPROFILE_API void MicroProfileEnableCategory(const char* pCategory); + MICROPROFILE_API void MicroProfileDisableCategory(const char* pCategory); + MICROPROFILE_API int MicroProfileGetEnableAllGroups(); + MICROPROFILE_API void MicroProfileSetForceMetaCounters(int bEnable); + MICROPROFILE_API int MicroProfileGetForceMetaCounters(); + MICROPROFILE_API void MicroProfileEnableMetaCounter(const char* pMet); + MICROPROFILE_API void MicroProfileDisableMetaCounter(const char* pMet); + MICROPROFILE_API void MicroProfileSetAggregateFrames(int frames); + MICROPROFILE_API int MicroProfileGetAggregateFrames(); + MICROPROFILE_API int MicroProfileGetCurrentAggregateFrames(); + MICROPROFILE_API struct MicroProfile* MicroProfileGet(); + MICROPROFILE_API void MicroProfileGetRange(uint32_t nPut, uint32_t nGet, uint32_t nRange[2][2]); + MICROPROFILE_API void MicroProfileStartContextSwitchTrace(); + MICROPROFILE_API void MicroProfileStopContextSwitchTrace(); + MICROPROFILE_API int MicroProfileIsLocalThread(uint32_t nThreadId); + MICROPROFILE_API int MicroProfileFormatCounter(int eFormat, int64_t nCounter, char* pOut, uint32_t nBufferSize); + MICROPROFILE_API struct MicroProfileThreadLogGpu* MicroProfileGetGlobalGpuThreadLog(); + MICROPROFILE_API int MicroProfileGetGlobalGpuQueue(); + MICROPROFILE_API void MicroProfileRegisterGroup(const char* pGroup, const char* pCategory, uint32_t nColor); +#if MICROPROFILE_PLATFORM_MARKERS + MICROPROFILE_API void MicroProfilePlatformMarkerBegin(uint32_t nColor, const char* pMarker); // not implemented by microprofile. + MICROPROFILE_API void MicroProfilePlatformMarkerEnd(); // not implemented by microprofile. +#endif + + MICROPROFILE_API float MicroProfileTickToMsMultiplierCpu(); + MICROPROFILE_API float MicroProfileTickToMsMultiplierGpu(); + MICROPROFILE_API int64_t MicroProfileTicksPerSecondCpu(); + MICROPROFILE_API uint64_t MicroProfileTick(); + + MICROPROFILE_API void MicroProfileLocalCounterAddAtomic(MicroProfileToken Token, int64_t nCount); + MICROPROFILE_API int64_t MicroProfileLocalCounterSetAtomic(MicroProfileToken, int64_t nCount); + + MICROPROFILE_API const char* MicroProfileCounterString(const char* String); + MICROPROFILE_API MicroProfileToken MicroProfileCounterTokenTree(MicroProfileToken* LastToken, MicroProfileToken CurrentParent, const char* pString); + MICROPROFILE_API MicroProfileToken MicroProfileCounterTokenTreeDynamic(MicroProfileToken* LastToken, MicroProfileToken Parent, const char* pString); + + MICROPROFILE_API void MicroProfileCsvConfigEnd(); + MICROPROFILE_API void MicroProfileCsvConfigBegin(uint32_t MaxTimers, uint32_t MaxGroups, uint32_t MaxCounters, uint32_t Flags); + MICROPROFILE_API void MicroProfileCsvConfigAddTimer(const char* Group, const char* Timer, const char* DisplayName IF_CPP(= nullptr), MicroProfileTokenType Type IF_CPP(= MicroProfileTokenTypeCpu)); + MICROPROFILE_API void MicroProfileCsvConfigAddGroup(const char* Group, const char* DisplayName IF_CPP(= nullptr)); + MICROPROFILE_API void MicroProfileCsvConfigAddCounter(const char* CounterName, const char* DisplayName IF_CPP(= nullptr)); + + MICROPROFILE_API void MicroProfileUpdateSettingsPath(); + +#if MICROPROFILE_IMGUI + // Basic support for controlling MicroProfile from ImGui, and for rendering graphs & tables + enum MicroProfileImguiAlign; + struct MicroProfileImguiWindowDesc; + struct MicroProfileImguiEntryDesc; + MICROPROFILE_API void MicroProfileImguiGraphs(const MicroProfileImguiWindowDesc& Window, const MicroProfileImguiEntryDesc* Entries, uint32_t NumEntries); + MICROPROFILE_API void MicroProfileImguiTable(const MicroProfileImguiWindowDesc& Window, const MicroProfileImguiEntryDesc* Entries, uint32_t NumEntries); + MICROPROFILE_API void MicroProfileImguiControls(); +#endif + +#ifdef __cplusplus +} +#endif + +#ifdef __cplusplus +struct MicroProfileThreadInfo +{ + // 3 first members are used to sort. dont reorder + uint32_t nIsLocal; + MicroProfileThreadIdType pid; + MicroProfileThreadIdType tid; + // 3 first members are used to sort. dont reorder + + const char* pThreadModule; + const char* pProcessModule; + MicroProfileThreadInfo() + : nIsLocal(0) + , pid(0) + , tid(0) + , pThreadModule("?") + , pProcessModule("?") + { + } + MicroProfileThreadInfo(uint32_t ThreadId, uint32_t ProcessId, uint32_t nIsLocal) + : nIsLocal(nIsLocal) + , pid(ProcessId) + , tid(ThreadId) + , pThreadModule("?") + , pProcessModule("?") + { + } + ~MicroProfileThreadInfo() + { + } +}; +MICROPROFILE_API MicroProfileThreadInfo MicroProfileGetThreadInfo(MicroProfileThreadIdType nThreadId); +MICROPROFILE_API uint32_t MicroProfileGetThreadInfoArray(MicroProfileThreadInfo** pThreadArray); +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +#if MICROPROFILE_GPU_TIMERS_D3D12 + MICROPROFILE_API void MicroProfileGpuInitD3D12(void* pDevice, uint32_t nNodeCount, void** pCommandQueues, void** pCopyQueues); + MICROPROFILE_API void MicroProfileGpuShutdownD3D12(); + MICROPROFILE_API void MicroProfileSetCurrentNodeD3D12(uint32_t nNode); +#endif + +#if MICROPROFILE_GPU_TIMERS_VULKAN +#include + void MicroProfileGpuInitVulkan(VkDevice* pDevices, VkPhysicalDevice* pPhysicalDevices, VkQueue* pQueues, uint32_t* QueueFamily, uint32_t nNodeCount); + MICROPROFILE_API void MicroProfileGpuShutdownVulkan(); + MICROPROFILE_API void MicroProfileSetCurrentNodeVulkan(uint32_t nNode); +#endif + + MICROPROFILE_API void MicroProfileDumpFile(const char* pHtml, const char* pCsv, float fCpuSpike, float fGpuSpike, uint32_t FrameCount IF_CPP(= MICROPROFILE_WEBSERVER_DEFAULT_FRAMES)); + MICROPROFILE_API void MicroProfileDumpFileImmediately(const char* pHtml, const char* pCsv, void* pGpuContext, uint32_t FrameCount IF_CPP(= MICROPROFILE_WEBSERVER_DEFAULT_FRAMES)); + +#if MICROPROFILE_ENABLED && MICROPROFILE_WEBSERVER + MICROPROFILE_API uint32_t MicroProfileWebServerPort(); + MICROPROFILE_API void MicroProfileSetWebServerPort(uint32_t nPort); +#else +#define MicroProfileWebServerPort() ((uint32_t) - 1) +#define MicroProfileSetWebServerPort(a) \ + do \ + { \ + } while(0) +#endif + + typedef enum MicroProfileGpuTimerStateType_ + { + MicroProfileGpuTimerStateType_Invalid = 0, + MicroProfileGpuTimerStateType_D3D11, + MicroProfileGpuTimerStateType_D3D12, + MicroProfileGpuTimerStateType_Vulkan, + MicroProfileGpuTimerStateType_GL, + MicroProfileGpuTimerStateType_Custom + } MicroProfileGpuTimerStateType; + + typedef struct MicroProfileGpuTimerState_ + { + MicroProfileGpuTimerStateType Type; + } MicroProfileGpuTimerState; + +#if MICROPROFILE_GPU_TIMERS + typedef uint32_t(*MicroProfileGpuInsertTimeStamp_CB)(void* pContext); + typedef uint64_t(*MicroProfileGpuGetTimeStamp_CB)(uint32_t nKey); + typedef uint64_t(*MicroProfileTicksPerSecondGpu_CB)(); + typedef int (*MicroProfileGetGpuTickReference_CB)(int64_t* pOutCPU, int64_t* pOutGpu); + typedef uint32_t(*MicroProfileGpuFlip_CB)(void*); + typedef void (*MicroProfileGpuShutdown_CB)(); + + MICROPROFILE_API void MicroProfileGpuShutdownPlatform(); + + MICROPROFILE_API void MicroProfileGpuInitPlatform(MicroProfileGpuTimerStateType eType, + MicroProfileGpuTimerState* pGpuState, + MicroProfileGpuInsertTimeStamp_CB InsertTimeStamp, + MicroProfileGpuGetTimeStamp_CB GetTimeStamp, + MicroProfileTicksPerSecondGpu_CB TicksPerSecond, + MicroProfileGetGpuTickReference_CB GetTickReference, + MicroProfileGpuFlip_CB Flip, + MicroProfileGpuShutdown_CB Shutdown); +#else +#define MicroProfileGpuShutdownPlatform() \ + do \ + { \ + } while(0) +#define MicroProfileGpuInitPlatform(...) \ + do \ + { \ + } while(0) +#define MicroProfileGpuInsertTimeStamp(a) 1 +#define MicroProfileGpuGetTimeStamp(a) 0 +#define MicroProfileTicksPerSecondGpu() 1 +#define MicroProfileGetGpuTickReference(a, b) 0 +#define MicroProfileGpuFlip(a) 0 +#define MicroProfileGpuShutdown() \ + do \ + { \ + } while(0) + +#endif + +#if MICROPROFILE_GPU_TIMERS_D3D11 +#define MICROPROFILE_D3D11_MAX_QUERIES (32 << 10) + MICROPROFILE_API void MicroProfileGpuInitD3D11(void* pDevice, void* pDeviceContext); + MICROPROFILE_API void MicroProfileGpuShutdownD3D11(); +#endif + +#if MICROPROFILE_GPU_TIMERS_GL +#define MICROPROFILE_GL_MAX_QUERIES (8 << 10) + MICROPROFILE_API void MicroProfileGpuInitGL(); +#endif + +#if MICROPROFILE_USE_THREAD_NAME_CALLBACK + MICROPROFILE_API const char* MicroProfileGetThreadName(char* pzName); +#else +#define MicroProfileGetThreadName(a) 0 +#endif + +#ifdef __cplusplus +} +#endif + +struct MicroProfileScopeStateC +{ + MicroProfileToken Token; + int64_t nTick; +}; + +#ifdef __cplusplus +struct MicroProfileScopeHandler +{ + MicroProfileToken nToken; + uint64_t nTick; + MicroProfileScopeHandler(MicroProfileToken Token) + : nToken(Token) + { + nTick = MicroProfileEnterInternal(nToken); + } + ~MicroProfileScopeHandler() + { + MicroProfileLeaveInternal(nToken, nTick); + } +}; + +struct MicroProfileScopeHandlerCStr +{ + uint64_t nTick; + const char* pStr; + MicroProfileScopeHandlerCStr(const char* pStr) + : pStr(pStr) + { + nTick = MicroProfileEnterInternalCStr(pStr); + } + ~MicroProfileScopeHandlerCStr() + { + MicroProfileLeaveInternalCStr(pStr, nTick); + } +}; + +struct MicroProfileScopeGpuHandler +{ + MicroProfileToken nToken; + MicroProfileThreadLogGpu* pLog; + uint64_t nTick; + MicroProfileScopeGpuHandler(MicroProfileToken Token, MicroProfileThreadLogGpu* pLog) + : nToken(Token) + , pLog(pLog) + { + nTick = MicroProfileGpuEnterInternal(pLog, nToken); + } + ~MicroProfileScopeGpuHandler() + { + MicroProfileGpuLeaveInternal(pLog, nToken, nTick); + } +}; + +struct MicroProfileScopeGpuHandlerCStr +{ + MicroProfileThreadLogGpu* pLog; + uint64_t nTick; + MicroProfileScopeGpuHandlerCStr(const char* pStr, MicroProfileThreadLogGpu* pLog) + : pLog(pLog) + { + nTick = MicroProfileGpuEnterInternalCStr(pLog, pStr); + } + ~MicroProfileScopeGpuHandlerCStr() + { + MicroProfileGpuLeaveInternalCStr(pLog, nTick); + } +}; + +struct MicroProfileConditionalScopeHandler +{ + MicroProfileToken nToken; + uint64_t nTick; + MicroProfileConditionalScopeHandler(MicroProfileToken token, bool condition) + : nToken(token) + { + nTick = condition ? MicroProfileEnterInternal(token) : MICROPROFILE_INVALID_TOKEN; + } + ~MicroProfileConditionalScopeHandler() + { + if (nTick != MICROPROFILE_INVALID_TOKEN) + { + MicroProfileLeaveInternal(nToken, nTick); + } + } +}; +struct MicroProfileScopeTimelineExitHandler +{ + MicroProfileTimelineToken nToken; + MicroProfileScopeTimelineExitHandler(MicroProfileTimelineToken Token) + : nToken(Token) + { + } + ~MicroProfileScopeTimelineExitHandler() + { + MicroProfileTimelineLeave(nToken); + } +}; + +#if MICROPROFILE_IMGUI +enum MicroProfileImguiAlign +{ + MICROPROFILE_IMGUI_ALIGN_TOP_LEFT = 0, + MICROPROFILE_IMGUI_ALIGN_TOP_RIGHT = 1, + MICROPROFILE_IMGUI_ALIGN_BOTTOM_LEFT = 2, + MICROPROFILE_IMGUI_ALIGN_BOTTOM_RIGHT = 3, +}; + +struct MicroProfileImguiWindowDesc +{ + uint32_t Align = MICROPROFILE_IMGUI_ALIGN_TOP_LEFT; + int GraphWidth = 300; + int GraphHeight = 80; + int OffsetX = 0; + int OffsetY = 0; +}; +struct MicroProfileImguiEntryDesc +{ + MicroProfileToken GraphTimer; + float GraphMax = -1; +}; +#endif + +#endif //__cplusplus +#endif // enabled + +enum MicroProfileCounterFormat +{ + MICROPROFILE_COUNTER_FORMAT_DEFAULT = 0, + MICROPROFILE_COUNTER_FORMAT_BYTES = 1, +}; + +enum MicroProfileCounterFlags +{ + MICROPROFILE_COUNTER_FLAG_NONE = 0, + MICROPROFILE_COUNTER_FLAG_DETAILED = 0x1, + MICROPROFILE_COUNTER_FLAG_DETAILED_GRAPH = 0x2, + // internal: + MICROPROFILE_COUNTER_FLAG_INTERNAL_MASK = ~0x3, + MICROPROFILE_COUNTER_FLAG_HAS_LIMIT = 0x4, + MICROPROFILE_COUNTER_FLAG_CLOSED = 0x8, + MICROPROFILE_COUNTER_FLAG_MANUAL_SWAP = 0x10, + MICROPROFILE_COUNTER_FLAG_LEAF = 0x20, + MICROPROFILE_COUNTER_FLAG_DOUBLE = 0x40, + MICROPROFILE_COUNTER_FLAG_TYPE_MASK = MICROPROFILE_COUNTER_FLAG_DOUBLE, + MICROPROFILE_COUNTER_FLAG_TOKEN_DONT_CREATE = 0x80000000, +}; + +#endif // once + +#define MP_AUTO 0 +// from http://fugal.net/vim/rgbtxt.html +#define MP_SNOW 0xfffafa +#define MP_GHOSTWHITE 0xf8f8ff +#define MP_WHITESMOKE 0xf5f5f5 +#define MP_GAINSBORO 0xdcdcdc +#define MP_FLORALWHITE 0xfffaf0 +#define MP_OLDLACE 0xfdf5e6 +#define MP_LINEN 0xfaf0e6 +#define MP_ANTIQUEWHITE 0xfaebd7 +#define MP_PAPAYAWHIP 0xffefd5 +#define MP_BLANCHEDALMOND 0xffebcd +#define MP_BISQUE 0xffe4c4 +#define MP_PEACHPUFF 0xffdab9 +#define MP_NAVAJOWHITE 0xffdead +#define MP_MOCCASIN 0xffe4b5 +#define MP_CORNSILK 0xfff8dc +#define MP_IVORY 0xfffff0 +#define MP_LEMONCHIFFON 0xfffacd +#define MP_SEASHELL 0xfff5ee +#define MP_HONEYDEW 0xf0fff0 +#define MP_MINTCREAM 0xf5fffa +#define MP_AZURE 0xf0ffff +#define MP_ALICEBLUE 0xf0f8ff +#define MP_LAVENDER 0xe6e6fa +#define MP_LAVENDERBLUSH 0xfff0f5 +#define MP_MISTYROSE 0xffe4e1 +#define MP_WHITE 0xffffff +#define MP_BLACK 0x010101 +#define MP_DARKSLATEGRAY 0x2f4f4f +#define MP_DARKSLATEGREY 0x2f4f4f +#define MP_DIMGRAY 0x696969 +#define MP_DIMGREY 0x696969 +#define MP_SLATEGRAY 0x708090 +#define MP_SLATEGREY 0x708090 +#define MP_LIGHTSLATEGRAY 0x778899 +#define MP_LIGHTSLATEGREY 0x778899 +#define MP_GRAY 0xbebebe +#define MP_GREY 0xbebebe +#define MP_LIGHTGREY 0xd3d3d3 +#define MP_LIGHTGRAY 0xd3d3d3 +#define MP_MIDNIGHTBLUE 0x191970 +#define MP_NAVY 0x000080 +#define MP_NAVYBLUE 0x000080 +#define MP_CORNFLOWERBLUE 0x6495ed +#define MP_DARKSLATEBLUE 0x483d8b +#define MP_SLATEBLUE 0x6a5acd +#define MP_MEDIUMSLATEBLUE 0x7b68ee +#define MP_LIGHTSLATEBLUE 0x8470ff +#define MP_MEDIUMBLUE 0x0000cd +#define MP_ROYALBLUE 0x4169e1 +#define MP_BLUE 0x0000ff +#define MP_DODGERBLUE 0x1e90ff +#define MP_DEEPSKYBLUE 0x00bfff +#define MP_SKYBLUE 0x87ceeb +#define MP_LIGHTSKYBLUE 0x87cefa +#define MP_STEELBLUE 0x4682b4 +#define MP_LIGHTSTEELBLUE 0xb0c4de +#define MP_LIGHTBLUE 0xadd8e6 +#define MP_POWDERBLUE 0xb0e0e6 +#define MP_PALETURQUOISE 0xafeeee +#define MP_DARKTURQUOISE 0x00ced1 +#define MP_MEDIUMTURQUOISE 0x48d1cc +#define MP_TURQUOISE 0x40e0d0 +#define MP_CYAN 0x00ffff +#define MP_LIGHTCYAN 0xe0ffff +#define MP_CADETBLUE 0x5f9ea0 +#define MP_MEDIUMAQUAMARINE 0x66cdaa +#define MP_AQUAMARINE 0x7fffd4 +#define MP_DARKGREEN 0x006400 +#define MP_DARKOLIVEGREEN 0x556b2f +#define MP_DARKSEAGREEN 0x8fbc8f +#define MP_SEAGREEN 0x2e8b57 +#define MP_MEDIUMSEAGREEN 0x3cb371 +#define MP_LIGHTSEAGREEN 0x20b2aa +#define MP_PALEGREEN 0x98fb98 +#define MP_SPRINGGREEN 0x00ff7f +#define MP_LAWNGREEN 0x7cfc00 +#define MP_GREEN 0x00ff00 +#define MP_CHARTREUSE 0x7fff00 +#define MP_MEDIUMSPRINGGREEN 0x00fa9a +#define MP_GREENYELLOW 0xadff2f +#define MP_LIMEGREEN 0x32cd32 +#define MP_YELLOWGREEN 0x9acd32 +#define MP_FORESTGREEN 0x228b22 +#define MP_OLIVEDRAB 0x6b8e23 +#define MP_DARKKHAKI 0xbdb76b +#define MP_KHAKI 0xf0e68c +#define MP_PALEGOLDENROD 0xeee8aa +#define MP_LIGHTGOLDENRODYELLOW 0xfafad2 +#define MP_LIGHTYELLOW 0xffffe0 +#define MP_YELLOW 0xffff00 +#define MP_GOLD 0xffd700 +#define MP_LIGHTGOLDENROD 0xeedd82 +#define MP_GOLDENROD 0xdaa520 +#define MP_DARKGOLDENROD 0xb8860b +#define MP_ROSYBROWN 0xbc8f8f +#define MP_INDIANRED 0xcd5c5c +#define MP_SADDLEBROWN 0x8b4513 +#define MP_SIENNA 0xa0522d +#define MP_PERU 0xcd853f +#define MP_BURLYWOOD 0xdeb887 +#define MP_BEIGE 0xf5f5dc +#define MP_WHEAT 0xf5deb3 +#define MP_SANDYBROWN 0xf4a460 +#define MP_TAN 0xd2b48c +#define MP_CHOCOLATE 0xd2691e +#define MP_FIREBRICK 0xb22222 +#define MP_BROWN 0xa52a2a +#define MP_DARKSALMON 0xe9967a +#define MP_SALMON 0xfa8072 +#define MP_LIGHTSALMON 0xffa07a +#define MP_ORANGE 0xffa500 +#define MP_DARKORANGE 0xff8c00 +#define MP_CORAL 0xff7f50 +#define MP_LIGHTCORAL 0xf08080 +#define MP_TOMATO 0xff6347 +#define MP_ORANGERED 0xff4500 +#define MP_RED 0xff0000 +#define MP_HOTPINK 0xff69b4 +#define MP_DEEPPINK 0xff1493 +#define MP_PINK 0xffc0cb +#define MP_LIGHTPINK 0xffb6c1 +#define MP_PALEVIOLETRED 0xdb7093 +#define MP_MAROON 0xb03060 +#define MP_MEDIUMVIOLETRED 0xc71585 +#define MP_VIOLETRED 0xd02090 +#define MP_MAGENTA 0xff00ff +#define MP_VIOLET 0xee82ee +#define MP_PLUM 0xdda0dd +#define MP_ORCHID 0xda70d6 +#define MP_MEDIUMORCHID 0xba55d3 +#define MP_DARKORCHID 0x9932cc +#define MP_DARKVIOLET 0x9400d3 +#define MP_BLUEVIOLET 0x8a2be2 +#define MP_PURPLE 0xa020f0 +#define MP_MEDIUMPURPLE 0x9370db +#define MP_THISTLE 0xd8bfd8 +#define MP_SNOW1 0xfffafa +#define MP_SNOW2 0xeee9e9 +#define MP_SNOW3 0xcdc9c9 +#define MP_SNOW4 0x8b8989 +#define MP_SEASHELL1 0xfff5ee +#define MP_SEASHELL2 0xeee5de +#define MP_SEASHELL3 0xcdc5bf +#define MP_SEASHELL4 0x8b8682 +#define MP_ANTIQUEWHITE1 0xffefdb +#define MP_ANTIQUEWHITE2 0xeedfcc +#define MP_ANTIQUEWHITE3 0xcdc0b0 +#define MP_ANTIQUEWHITE4 0x8b8378 +#define MP_BISQUE1 0xffe4c4 +#define MP_BISQUE2 0xeed5b7 +#define MP_BISQUE3 0xcdb79e +#define MP_BISQUE4 0x8b7d6b +#define MP_PEACHPUFF1 0xffdab9 +#define MP_PEACHPUFF2 0xeecbad +#define MP_PEACHPUFF3 0xcdaf95 +#define MP_PEACHPUFF4 0x8b7765 +#define MP_NAVAJOWHITE1 0xffdead +#define MP_NAVAJOWHITE2 0xeecfa1 +#define MP_NAVAJOWHITE3 0xcdb38b +#define MP_NAVAJOWHITE4 0x8b795e +#define MP_LEMONCHIFFON1 0xfffacd +#define MP_LEMONCHIFFON2 0xeee9bf +#define MP_LEMONCHIFFON3 0xcdc9a5 +#define MP_LEMONCHIFFON4 0x8b8970 +#define MP_CORNSILK1 0xfff8dc +#define MP_CORNSILK2 0xeee8cd +#define MP_CORNSILK3 0xcdc8b1 +#define MP_CORNSILK4 0x8b8878 +#define MP_IVORY1 0xfffff0 +#define MP_IVORY2 0xeeeee0 +#define MP_IVORY3 0xcdcdc1 +#define MP_IVORY4 0x8b8b83 +#define MP_HONEYDEW1 0xf0fff0 +#define MP_HONEYDEW2 0xe0eee0 +#define MP_HONEYDEW3 0xc1cdc1 +#define MP_HONEYDEW4 0x838b83 +#define MP_LAVENDERBLUSH1 0xfff0f5 +#define MP_LAVENDERBLUSH2 0xeee0e5 +#define MP_LAVENDERBLUSH3 0xcdc1c5 +#define MP_LAVENDERBLUSH4 0x8b8386 +#define MP_MISTYROSE1 0xffe4e1 +#define MP_MISTYROSE2 0xeed5d2 +#define MP_MISTYROSE3 0xcdb7b5 +#define MP_MISTYROSE4 0x8b7d7b +#define MP_AZURE1 0xf0ffff +#define MP_AZURE2 0xe0eeee +#define MP_AZURE3 0xc1cdcd +#define MP_AZURE4 0x838b8b +#define MP_SLATEBLUE1 0x836fff +#define MP_SLATEBLUE2 0x7a67ee +#define MP_SLATEBLUE3 0x6959cd +#define MP_SLATEBLUE4 0x473c8b +#define MP_ROYALBLUE1 0x4876ff +#define MP_ROYALBLUE2 0x436eee +#define MP_ROYALBLUE3 0x3a5fcd +#define MP_ROYALBLUE4 0x27408b +#define MP_BLUE1 0x0000ff +#define MP_BLUE2 0x0000ee +#define MP_BLUE3 0x0000cd +#define MP_BLUE4 0x00008b +#define MP_DODGERBLUE1 0x1e90ff +#define MP_DODGERBLUE2 0x1c86ee +#define MP_DODGERBLUE3 0x1874cd +#define MP_DODGERBLUE4 0x104e8b +#define MP_STEELBLUE1 0x63b8ff +#define MP_STEELBLUE2 0x5cacee +#define MP_STEELBLUE3 0x4f94cd +#define MP_STEELBLUE4 0x36648b +#define MP_DEEPSKYBLUE1 0x00bfff +#define MP_DEEPSKYBLUE2 0x00b2ee +#define MP_DEEPSKYBLUE3 0x009acd +#define MP_DEEPSKYBLUE4 0x00688b +#define MP_SKYBLUE1 0x87ceff +#define MP_SKYBLUE2 0x7ec0ee +#define MP_SKYBLUE3 0x6ca6cd +#define MP_SKYBLUE4 0x4a708b +#define MP_LIGHTSKYBLUE1 0xb0e2ff +#define MP_LIGHTSKYBLUE2 0xa4d3ee +#define MP_LIGHTSKYBLUE3 0x8db6cd +#define MP_LIGHTSKYBLUE4 0x607b8b +#define MP_SLATEGRAY1 0xc6e2ff +#define MP_SLATEGRAY2 0xb9d3ee +#define MP_SLATEGRAY3 0x9fb6cd +#define MP_SLATEGRAY4 0x6c7b8b +#define MP_LIGHTSTEELBLUE1 0xcae1ff +#define MP_LIGHTSTEELBLUE2 0xbcd2ee +#define MP_LIGHTSTEELBLUE3 0xa2b5cd +#define MP_LIGHTSTEELBLUE4 0x6e7b8b +#define MP_LIGHTBLUE1 0xbfefff +#define MP_LIGHTBLUE2 0xb2dfee +#define MP_LIGHTBLUE3 0x9ac0cd +#define MP_LIGHTBLUE4 0x68838b +#define MP_LIGHTCYAN1 0xe0ffff +#define MP_LIGHTCYAN2 0xd1eeee +#define MP_LIGHTCYAN3 0xb4cdcd +#define MP_LIGHTCYAN4 0x7a8b8b +#define MP_PALETURQUOISE1 0xbbffff +#define MP_PALETURQUOISE2 0xaeeeee +#define MP_PALETURQUOISE3 0x96cdcd +#define MP_PALETURQUOISE4 0x668b8b +#define MP_CADETBLUE1 0x98f5ff +#define MP_CADETBLUE2 0x8ee5ee +#define MP_CADETBLUE3 0x7ac5cd +#define MP_CADETBLUE4 0x53868b +#define MP_TURQUOISE1 0x00f5ff +#define MP_TURQUOISE2 0x00e5ee +#define MP_TURQUOISE3 0x00c5cd +#define MP_TURQUOISE4 0x00868b +#define MP_CYAN1 0x00ffff +#define MP_CYAN2 0x00eeee +#define MP_CYAN3 0x00cdcd +#define MP_CYAN4 0x008b8b +#define MP_DARKSLATEGRAY1 0x97ffff +#define MP_DARKSLATEGRAY2 0x8deeee +#define MP_DARKSLATEGRAY3 0x79cdcd +#define MP_DARKSLATEGRAY4 0x528b8b +#define MP_AQUAMARINE1 0x7fffd4 +#define MP_AQUAMARINE2 0x76eec6 +#define MP_AQUAMARINE3 0x66cdaa +#define MP_AQUAMARINE4 0x458b74 +#define MP_DARKSEAGREEN1 0xc1ffc1 +#define MP_DARKSEAGREEN2 0xb4eeb4 +#define MP_DARKSEAGREEN3 0x9bcd9b +#define MP_DARKSEAGREEN4 0x698b69 +#define MP_SEAGREEN1 0x54ff9f +#define MP_SEAGREEN2 0x4eee94 +#define MP_SEAGREEN3 0x43cd80 +#define MP_SEAGREEN4 0x2e8b57 +#define MP_PALEGREEN1 0x9aff9a +#define MP_PALEGREEN2 0x90ee90 +#define MP_PALEGREEN3 0x7ccd7c +#define MP_PALEGREEN4 0x548b54 +#define MP_SPRINGGREEN1 0x00ff7f +#define MP_SPRINGGREEN2 0x00ee76 +#define MP_SPRINGGREEN3 0x00cd66 +#define MP_SPRINGGREEN4 0x008b45 +#define MP_GREEN1 0x00ff00 +#define MP_GREEN2 0x00ee00 +#define MP_GREEN3 0x00cd00 +#define MP_GREEN4 0x008b00 +#define MP_CHARTREUSE1 0x7fff00 +#define MP_CHARTREUSE2 0x76ee00 +#define MP_CHARTREUSE3 0x66cd00 +#define MP_CHARTREUSE4 0x458b00 +#define MP_OLIVEDRAB1 0xc0ff3e +#define MP_OLIVEDRAB2 0xb3ee3a +#define MP_OLIVEDRAB3 0x9acd32 +#define MP_OLIVEDRAB4 0x698b22 +#define MP_DARKOLIVEGREEN1 0xcaff70 +#define MP_DARKOLIVEGREEN2 0xbcee68 +#define MP_DARKOLIVEGREEN3 0xa2cd5a +#define MP_DARKOLIVEGREEN4 0x6e8b3d +#define MP_KHAKI1 0xfff68f +#define MP_KHAKI2 0xeee685 +#define MP_KHAKI3 0xcdc673 +#define MP_KHAKI4 0x8b864e +#define MP_LIGHTGOLDENROD1 0xffec8b +#define MP_LIGHTGOLDENROD2 0xeedc82 +#define MP_LIGHTGOLDENROD3 0xcdbe70 +#define MP_LIGHTGOLDENROD4 0x8b814c +#define MP_LIGHTYELLOW1 0xffffe0 +#define MP_LIGHTYELLOW2 0xeeeed1 +#define MP_LIGHTYELLOW3 0xcdcdb4 +#define MP_LIGHTYELLOW4 0x8b8b7a +#define MP_YELLOW1 0xffff00 +#define MP_YELLOW2 0xeeee00 +#define MP_YELLOW3 0xcdcd00 +#define MP_YELLOW4 0x8b8b00 +#define MP_GOLD1 0xffd700 +#define MP_GOLD2 0xeec900 +#define MP_GOLD3 0xcdad00 +#define MP_GOLD4 0x8b7500 +#define MP_GOLDENROD1 0xffc125 +#define MP_GOLDENROD2 0xeeb422 +#define MP_GOLDENROD3 0xcd9b1d +#define MP_GOLDENROD4 0x8b6914 +#define MP_DARKGOLDENROD1 0xffb90f +#define MP_DARKGOLDENROD2 0xeead0e +#define MP_DARKGOLDENROD3 0xcd950c +#define MP_DARKGOLDENROD4 0x8b6508 +#define MP_ROSYBROWN1 0xffc1c1 +#define MP_ROSYBROWN2 0xeeb4b4 +#define MP_ROSYBROWN3 0xcd9b9b +#define MP_ROSYBROWN4 0x8b6969 +#define MP_INDIANRED1 0xff6a6a +#define MP_INDIANRED2 0xee6363 +#define MP_INDIANRED3 0xcd5555 +#define MP_INDIANRED4 0x8b3a3a +#define MP_SIENNA1 0xff8247 +#define MP_SIENNA2 0xee7942 +#define MP_SIENNA3 0xcd6839 +#define MP_SIENNA4 0x8b4726 +#define MP_BURLYWOOD1 0xffd39b +#define MP_BURLYWOOD2 0xeec591 +#define MP_BURLYWOOD3 0xcdaa7d +#define MP_BURLYWOOD4 0x8b7355 +#define MP_WHEAT1 0xffe7ba +#define MP_WHEAT2 0xeed8ae +#define MP_WHEAT3 0xcdba96 +#define MP_WHEAT4 0x8b7e66 +#define MP_TAN1 0xffa54f +#define MP_TAN2 0xee9a49 +#define MP_TAN3 0xcd853f +#define MP_TAN4 0x8b5a2b +#define MP_CHOCOLATE1 0xff7f24 +#define MP_CHOCOLATE2 0xee7621 +#define MP_CHOCOLATE3 0xcd661d +#define MP_CHOCOLATE4 0x8b4513 +#define MP_FIREBRICK1 0xff3030 +#define MP_FIREBRICK2 0xee2c2c +#define MP_FIREBRICK3 0xcd2626 +#define MP_FIREBRICK4 0x8b1a1a +#define MP_BROWN1 0xff4040 +#define MP_BROWN2 0xee3b3b +#define MP_BROWN3 0xcd3333 +#define MP_BROWN4 0x8b2323 +#define MP_SALMON1 0xff8c69 +#define MP_SALMON2 0xee8262 +#define MP_SALMON3 0xcd7054 +#define MP_SALMON4 0x8b4c39 +#define MP_LIGHTSALMON1 0xffa07a +#define MP_LIGHTSALMON2 0xee9572 +#define MP_LIGHTSALMON3 0xcd8162 +#define MP_LIGHTSALMON4 0x8b5742 +#define MP_ORANGE1 0xffa500 +#define MP_ORANGE2 0xee9a00 +#define MP_ORANGE3 0xcd8500 +#define MP_ORANGE4 0x8b5a00 +#define MP_DARKORANGE1 0xff7f00 +#define MP_DARKORANGE2 0xee7600 +#define MP_DARKORANGE3 0xcd6600 +#define MP_DARKORANGE4 0x8b4500 +#define MP_CORAL1 0xff7256 +#define MP_CORAL2 0xee6a50 +#define MP_CORAL3 0xcd5b45 +#define MP_CORAL4 0x8b3e2f +#define MP_TOMATO1 0xff6347 +#define MP_TOMATO2 0xee5c42 +#define MP_TOMATO3 0xcd4f39 +#define MP_TOMATO4 0x8b3626 +#define MP_ORANGERED1 0xff4500 +#define MP_ORANGERED2 0xee4000 +#define MP_ORANGERED3 0xcd3700 +#define MP_ORANGERED4 0x8b2500 +#define MP_RED1 0xff0000 +#define MP_RED2 0xee0000 +#define MP_RED3 0xcd0000 +#define MP_RED4 0x8b0000 +#define MP_DEEPPINK1 0xff1493 +#define MP_DEEPPINK2 0xee1289 +#define MP_DEEPPINK3 0xcd1076 +#define MP_DEEPPINK4 0x8b0a50 +#define MP_HOTPINK1 0xff6eb4 +#define MP_HOTPINK2 0xee6aa7 +#define MP_HOTPINK3 0xcd6090 +#define MP_HOTPINK4 0x8b3a62 +#define MP_PINK1 0xffb5c5 +#define MP_PINK2 0xeea9b8 +#define MP_PINK3 0xcd919e +#define MP_PINK4 0x8b636c +#define MP_LIGHTPINK1 0xffaeb9 +#define MP_LIGHTPINK2 0xeea2ad +#define MP_LIGHTPINK3 0xcd8c95 +#define MP_LIGHTPINK4 0x8b5f65 +#define MP_PALEVIOLETRED1 0xff82ab +#define MP_PALEVIOLETRED2 0xee799f +#define MP_PALEVIOLETRED3 0xcd6889 +#define MP_PALEVIOLETRED4 0x8b475d +#define MP_MAROON1 0xff34b3 +#define MP_MAROON2 0xee30a7 +#define MP_MAROON3 0xcd2990 +#define MP_MAROON4 0x8b1c62 +#define MP_VIOLETRED1 0xff3e96 +#define MP_VIOLETRED2 0xee3a8c +#define MP_VIOLETRED3 0xcd3278 +#define MP_VIOLETRED4 0x8b2252 +#define MP_MAGENTA1 0xff00ff +#define MP_MAGENTA2 0xee00ee +#define MP_MAGENTA3 0xcd00cd +#define MP_MAGENTA4 0x8b008b +#define MP_ORCHID1 0xff83fa +#define MP_ORCHID2 0xee7ae9 +#define MP_ORCHID3 0xcd69c9 +#define MP_ORCHID4 0x8b4789 +#define MP_PLUM1 0xffbbff +#define MP_PLUM2 0xeeaeee +#define MP_PLUM3 0xcd96cd +#define MP_PLUM4 0x8b668b +#define MP_MEDIUMORCHID1 0xe066ff +#define MP_MEDIUMORCHID2 0xd15fee +#define MP_MEDIUMORCHID3 0xb452cd +#define MP_MEDIUMORCHID4 0x7a378b +#define MP_DARKORCHID1 0xbf3eff +#define MP_DARKORCHID2 0xb23aee +#define MP_DARKORCHID3 0x9a32cd +#define MP_DARKORCHID4 0x68228b +#define MP_PURPLE1 0x9b30ff +#define MP_PURPLE2 0x912cee +#define MP_PURPLE3 0x7d26cd +#define MP_PURPLE4 0x551a8b +#define MP_MEDIUMPURPLE1 0xab82ff +#define MP_MEDIUMPURPLE2 0x9f79ee +#define MP_MEDIUMPURPLE3 0x8968cd +#define MP_MEDIUMPURPLE4 0x5d478b +#define MP_THISTLE1 0xffe1ff +#define MP_THISTLE2 0xeed2ee +#define MP_THISTLE3 0xcdb5cd +#define MP_THISTLE4 0x8b7b8b +#define MP_GRAY0 0x000000 +#define MP_GREY0 0x000000 +#define MP_GRAY1 0x030303 +#define MP_GREY1 0x030303 +#define MP_GRAY2 0x050505 +#define MP_GREY2 0x050505 +#define MP_GRAY3 0x080808 +#define MP_GREY3 0x080808 +#define MP_GRAY4 0x0a0a0a +#define MP_GREY4 0x0a0a0a +#define MP_GRAY5 0x0d0d0d +#define MP_GREY5 0x0d0d0d +#define MP_GRAY6 0x0f0f0f +#define MP_GREY6 0x0f0f0f +#define MP_GRAY7 0x121212 +#define MP_GREY7 0x121212 +#define MP_GRAY8 0x141414 +#define MP_GREY8 0x141414 +#define MP_GRAY9 0x171717 +#define MP_GREY9 0x171717 +#define MP_GRAY10 0x1a1a1a +#define MP_GREY10 0x1a1a1a +#define MP_GRAY11 0x1c1c1c +#define MP_GREY11 0x1c1c1c +#define MP_GRAY12 0x1f1f1f +#define MP_GREY12 0x1f1f1f +#define MP_GRAY13 0x212121 +#define MP_GREY13 0x212121 +#define MP_GRAY14 0x242424 +#define MP_GREY14 0x242424 +#define MP_GRAY15 0x262626 +#define MP_GREY15 0x262626 +#define MP_GRAY16 0x292929 +#define MP_GREY16 0x292929 +#define MP_GRAY17 0x2b2b2b +#define MP_GREY17 0x2b2b2b +#define MP_GRAY18 0x2e2e2e +#define MP_GREY18 0x2e2e2e +#define MP_GRAY19 0x303030 +#define MP_GREY19 0x303030 +#define MP_GRAY20 0x333333 +#define MP_GREY20 0x333333 +#define MP_GRAY21 0x363636 +#define MP_GREY21 0x363636 +#define MP_GRAY22 0x383838 +#define MP_GREY22 0x383838 +#define MP_GRAY23 0x3b3b3b +#define MP_GREY23 0x3b3b3b +#define MP_GRAY24 0x3d3d3d +#define MP_GREY24 0x3d3d3d +#define MP_GRAY25 0x404040 +#define MP_GREY25 0x404040 +#define MP_GRAY26 0x424242 +#define MP_GREY26 0x424242 +#define MP_GRAY27 0x454545 +#define MP_GREY27 0x454545 +#define MP_GRAY28 0x474747 +#define MP_GREY28 0x474747 +#define MP_GRAY29 0x4a4a4a +#define MP_GREY29 0x4a4a4a +#define MP_GRAY30 0x4d4d4d +#define MP_GREY30 0x4d4d4d +#define MP_GRAY31 0x4f4f4f +#define MP_GREY31 0x4f4f4f +#define MP_GRAY32 0x525252 +#define MP_GREY32 0x525252 +#define MP_GRAY33 0x545454 +#define MP_GREY33 0x545454 +#define MP_GRAY34 0x575757 +#define MP_GREY34 0x575757 +#define MP_GRAY35 0x595959 +#define MP_GREY35 0x595959 +#define MP_GRAY36 0x5c5c5c +#define MP_GREY36 0x5c5c5c +#define MP_GRAY37 0x5e5e5e +#define MP_GREY37 0x5e5e5e +#define MP_GRAY38 0x616161 +#define MP_GREY38 0x616161 +#define MP_GRAY39 0x636363 +#define MP_GREY39 0x636363 +#define MP_GRAY40 0x666666 +#define MP_GREY40 0x666666 +#define MP_GRAY41 0x696969 +#define MP_GREY41 0x696969 +#define MP_GRAY42 0x6b6b6b +#define MP_GREY42 0x6b6b6b +#define MP_GRAY43 0x6e6e6e +#define MP_GREY43 0x6e6e6e +#define MP_GRAY44 0x707070 +#define MP_GREY44 0x707070 +#define MP_GRAY45 0x737373 +#define MP_GREY45 0x737373 +#define MP_GRAY46 0x757575 +#define MP_GREY46 0x757575 +#define MP_GRAY47 0x787878 +#define MP_GREY47 0x787878 +#define MP_GRAY48 0x7a7a7a +#define MP_GREY48 0x7a7a7a +#define MP_GRAY49 0x7d7d7d +#define MP_GREY49 0x7d7d7d +#define MP_GRAY50 0x7f7f7f +#define MP_GREY50 0x7f7f7f +#define MP_GRAY51 0x828282 +#define MP_GREY51 0x828282 +#define MP_GRAY52 0x858585 +#define MP_GREY52 0x858585 +#define MP_GRAY53 0x878787 +#define MP_GREY53 0x878787 +#define MP_GRAY54 0x8a8a8a +#define MP_GREY54 0x8a8a8a +#define MP_GRAY55 0x8c8c8c +#define MP_GREY55 0x8c8c8c +#define MP_GRAY56 0x8f8f8f +#define MP_GREY56 0x8f8f8f +#define MP_GRAY57 0x919191 +#define MP_GREY57 0x919191 +#define MP_GRAY58 0x949494 +#define MP_GREY58 0x949494 +#define MP_GRAY59 0x969696 +#define MP_GREY59 0x969696 +#define MP_GRAY60 0x999999 +#define MP_GREY60 0x999999 +#define MP_GRAY61 0x9c9c9c +#define MP_GREY61 0x9c9c9c +#define MP_GRAY62 0x9e9e9e +#define MP_GREY62 0x9e9e9e +#define MP_GRAY63 0xa1a1a1 +#define MP_GREY63 0xa1a1a1 +#define MP_GRAY64 0xa3a3a3 +#define MP_GREY64 0xa3a3a3 +#define MP_GRAY65 0xa6a6a6 +#define MP_GREY65 0xa6a6a6 +#define MP_GRAY66 0xa8a8a8 +#define MP_GREY66 0xa8a8a8 +#define MP_GRAY67 0xababab +#define MP_GREY67 0xababab +#define MP_GRAY68 0xadadad +#define MP_GREY68 0xadadad +#define MP_GRAY69 0xb0b0b0 +#define MP_GREY69 0xb0b0b0 +#define MP_GRAY70 0xb3b3b3 +#define MP_GREY70 0xb3b3b3 +#define MP_GRAY71 0xb5b5b5 +#define MP_GREY71 0xb5b5b5 +#define MP_GRAY72 0xb8b8b8 +#define MP_GREY72 0xb8b8b8 +#define MP_GRAY73 0xbababa +#define MP_GREY73 0xbababa +#define MP_GRAY74 0xbdbdbd +#define MP_GREY74 0xbdbdbd +#define MP_GRAY75 0xbfbfbf +#define MP_GREY75 0xbfbfbf +#define MP_GRAY76 0xc2c2c2 +#define MP_GREY76 0xc2c2c2 +#define MP_GRAY77 0xc4c4c4 +#define MP_GREY77 0xc4c4c4 +#define MP_GRAY78 0xc7c7c7 +#define MP_GREY78 0xc7c7c7 +#define MP_GRAY79 0xc9c9c9 +#define MP_GREY79 0xc9c9c9 +#define MP_GRAY80 0xcccccc +#define MP_GREY80 0xcccccc +#define MP_GRAY81 0xcfcfcf +#define MP_GREY81 0xcfcfcf +#define MP_GRAY82 0xd1d1d1 +#define MP_GREY82 0xd1d1d1 +#define MP_GRAY83 0xd4d4d4 +#define MP_GREY83 0xd4d4d4 +#define MP_GRAY84 0xd6d6d6 +#define MP_GREY84 0xd6d6d6 +#define MP_GRAY85 0xd9d9d9 +#define MP_GREY85 0xd9d9d9 +#define MP_GRAY86 0xdbdbdb +#define MP_GREY86 0xdbdbdb +#define MP_GRAY87 0xdedede +#define MP_GREY87 0xdedede +#define MP_GRAY88 0xe0e0e0 +#define MP_GREY88 0xe0e0e0 +#define MP_GRAY89 0xe3e3e3 +#define MP_GREY89 0xe3e3e3 +#define MP_GRAY90 0xe5e5e5 +#define MP_GREY90 0xe5e5e5 +#define MP_GRAY91 0xe8e8e8 +#define MP_GREY91 0xe8e8e8 +#define MP_GRAY92 0xebebeb +#define MP_GREY92 0xebebeb +#define MP_GRAY93 0xededed +#define MP_GREY93 0xededed +#define MP_GRAY94 0xf0f0f0 +#define MP_GREY94 0xf0f0f0 +#define MP_GRAY95 0xf2f2f2 +#define MP_GREY95 0xf2f2f2 +#define MP_GRAY96 0xf5f5f5 +#define MP_GREY96 0xf5f5f5 +#define MP_GRAY97 0xf7f7f7 +#define MP_GREY97 0xf7f7f7 +#define MP_GRAY98 0xfafafa +#define MP_GREY98 0xfafafa +#define MP_GRAY99 0xfcfcfc +#define MP_GREY99 0xfcfcfc +#define MP_GRAY100 0xffffff +#define MP_GREY100 0xffffff +#define MP_DARKGREY 0xa9a9a9 +#define MP_DARKGRAY 0xa9a9a9 +#define MP_DARKBLUE 0x00008b +#define MP_DARKCYAN 0x008b8b +#define MP_DARKMAGENTA 0x8b008b +#define MP_DARKRED 0x8b0000 +#define MP_LIGHTGREEN 0x90ee90 diff --git a/Windows_Libs/Dev/Render/microprofile/microprofile_html.h b/Windows_Libs/Dev/Render/microprofile/microprofile_html.h new file mode 100644 index 0000000..49a1727 --- /dev/null +++ b/Windows_Libs/Dev/Render/microprofile/microprofile_html.h @@ -0,0 +1,17160 @@ +///start file generated from microprofile.html +#ifdef MICROPROFILE_EMBED_HTML +const char g_MicroProfileHtml_begin_0[] = +"\n" +"\n" +"\n" +"MicroProfile Capture\n" +"\n" +"\n" +" \n" +"\n" +"
drop .html file to compare
\n" +"
\n" +"
\n" +"
Group
\n" +"
Timer/Thread
\n" +"
\n" +"
Filter
\n" +"
Filter
\n" +"\n" +"\n" +"\n" +"
\n" +"
\n" +"History View:
\n" +"Click + Drag: Pan View
\n" +"Right Click + Drag : Zoom on region
\n" +"Click Frame : Center on frame
\n" +"
\n" +"Main View:
\n" +"Ctrl + Mouse up/down: Zoom
\n" +"Mousewheel : Zoom
\n" +"Right Click + Drag: Select region
\n" +"Ctrl + Shift + Drag: Select region
\n" +"Space: Zoom to Selection
\n" +"Ctrl + Drag: Pan
\n" +"Click + Drag: Pan
\n" +"hold alt: Show tooltip from timer view in detailed, detailed in timer
\n" +"x : Toggle View
\n" +"\\ : Switch color mode
\n" +"c : toggle collapse mode
\n" +"h : hightlight core types(context switch only)
\n" +"tab : go to filter view
\n" +"
\n" +"Detailed View:
\n" +"Tab: Go To Worst Instance
\n" +"Left/Right Arror: Next/Prev Instance
\n" +"Enter: Search for timer in view
\n" +"
\n" +"Timer Views:
\n" +"Tab: go to filtering
\n" +"Esc: Exit & Clear filter\n" +"
\n" +"\n" +"\n" +"\n" +"\n" +"\n" +"
CloseClose, Never Show
\n" +"
\n" +"\n" +"\n" +""; + +const size_t g_MicroProfileHtml_end_6_size = sizeof(g_MicroProfileHtml_end_6); +const char* g_MicroProfileHtml_end[] = { +&g_MicroProfileHtml_end_0[0], +&g_MicroProfileHtml_end_1[0], +&g_MicroProfileHtml_end_2[0], +&g_MicroProfileHtml_end_3[0], +&g_MicroProfileHtml_end_4[0], +&g_MicroProfileHtml_end_5[0], +&g_MicroProfileHtml_end_6[0], +}; +size_t g_MicroProfileHtml_end_sizes[] = { +sizeof(g_MicroProfileHtml_end_0), +sizeof(g_MicroProfileHtml_end_1), +sizeof(g_MicroProfileHtml_end_2), +sizeof(g_MicroProfileHtml_end_3), +sizeof(g_MicroProfileHtml_end_4), +sizeof(g_MicroProfileHtml_end_5), +sizeof(g_MicroProfileHtml_end_6), +}; +size_t g_MicroProfileHtml_end_count = 7; +#endif //MICROPROFILE_EMBED_HTML + +///end file generated from microprofile.html +///start file generated from microprofilelive.html +#ifdef MICROPROFILE_EMBED_HTML +const char g_MicroProfileHtmlLive_begin_0[] = +"\n" +"\n" +"\n" +"MicroProfile Live\n" +"\n" +"\n" +"\n" +"\n" +"\n" +"
drop .csv files to view CSV data
\n" +"
Filter
\n" +"
\n" +"History View:
\n" +"Right Click + Drag : Select Region
\n" +"Click + Drag: Move Selection
\n" +"Click Frame : Center on frame
\n" +"
\n" +"Main View:
\n" +"space: Freeze capturing
\n" +"x : Toggle View
\n" +"/ : Rotate connection port % 3
\n" +"Ctrl + Drag: Pan
\n" +"Click + Drag: Pan
\n" +"Enter: Capture selection/Next N Frames\n" +"
\n" +"\n" +"\n" +"\n" +"\n" +"
Close
\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +"
\n" +" \n" +" \n" +"
\n" +"
\n" +"
\n" +"\n" +"\n" +"\n" +"\n" +"\n" +""; + +const size_t g_MicroProfileHtmlLive_begin_5_size = sizeof(g_MicroProfileHtmlLive_begin_5); +const char* g_MicroProfileHtmlLive_begin[] = { +&g_MicroProfileHtmlLive_begin_0[0], +&g_MicroProfileHtmlLive_begin_1[0], +&g_MicroProfileHtmlLive_begin_2[0], +&g_MicroProfileHtmlLive_begin_3[0], +&g_MicroProfileHtmlLive_begin_4[0], +&g_MicroProfileHtmlLive_begin_5[0], +}; +size_t g_MicroProfileHtmlLive_begin_sizes[] = { +sizeof(g_MicroProfileHtmlLive_begin_0), +sizeof(g_MicroProfileHtmlLive_begin_1), +sizeof(g_MicroProfileHtmlLive_begin_2), +sizeof(g_MicroProfileHtmlLive_begin_3), +sizeof(g_MicroProfileHtmlLive_begin_4), +sizeof(g_MicroProfileHtmlLive_begin_5), +}; +size_t g_MicroProfileHtmlLive_begin_count = 6; +const char* g_MicroProfileHtmlLive_end[] = { +""}; +size_t g_MicroProfileHtmlLive_end_sizes[] = { +0}; +size_t g_MicroProfileHtmlLive_end_count = 0; +#endif //MICROPROFILE_EMBED_HTML + +///end file generated from microprofilelive.html diff --git a/Windows_Libs/Dev/Render/microprofile/microprofile_icons.h b/Windows_Libs/Dev/Render/microprofile/microprofile_icons.h new file mode 100644 index 0000000..73c53ce --- /dev/null +++ b/Windows_Libs/Dev/Render/microprofile/microprofile_icons.h @@ -0,0 +1,333 @@ +#ifdef MICROPROFILE_EMBED_HTML +#include + +const uint32_t uprof_16[] = { + 0x474e5089, 0x0a1a0a0d, 0x0d000000, 0x52444849, 0x10000000, 0x10000000, 0x00000308, 0x0f2d2800, 0x00000053, 0x47527301, 0xc9d90142, 0x00007f2c, 0x48700900, 0x00007359, 0x0000130b, 0x0001130b, + 0x00189c9a, 0x50ff0000, 0x0045544c, 0x3d190000, 0x366b3818, 0x296ad96f, 0x6b382757, 0x214b2336, 0x37245226, 0x6b383569, 0x183e1936, 0x3569d76e, 0x411b336e, 0x2652281a, 0x19183d19, 0x6b38183d, + 0x46924936, 0x20275729, 0x57291e49, 0x4fa45327, 0x38193e1a, 0x7d40366b, 0x5cbd603e, 0x2665ce6a, 0x6b382456, 0x366b3836, 0x4557b05b, 0x4f244286, 0x2e673122, 0x38275929, 0xcc68366b, 0x27572963, + 0x3c265628, 0xb65c3a75, 0x27572958, 0x19183d19, 0x7439183d, 0x23532636, 0x6b316933, 0x512566d1, 0x366b3823, 0x66366b38, 0x6b3862c9, 0x376d3936, 0x29408043, 0x5d2a2757, 0x27572927, 0x2f275729, + 0x3d192d62, 0x53ac5718, 0x2f4a964d, 0x3d192d62, 0x438d4718, 0x521a411b, 0x6b384f9f, 0x5ec36336, 0x1938793a, 0x6a37183d, 0x3b773e35, 0x385bb95f, 0x3d19366b, 0x183d1918, 0x5947954b, 0x9a4f55b0, + 0x2a5e2d4c, 0x2b366b38, 0x67252959, 0x00002581, 0x52745500, 0xff00534e, 0xf6ffffff, 0x33ffffff, 0xffffffff, 0x2d1ff3ff, 0x23fff1ff, 0xffa97fff, 0xc9ffffff, 0xffffff89, 0xff30ffff, 0xffa2ff25, + 0xffae5bbd, 0x5cffff8b, 0x81ffc34c, 0xffb2ff67, 0x27a17a3e, 0x38ffffff, 0x57ff89ff, 0xff62ffff, 0x2337ffff, 0xffffffb3, 0x6bffccff, 0x00656578, 0x49c30000, 0x78544144, 0x458f3d9c, 0x0c40c316, + 0xa8753d43, 0x9999940d, 0xe1999999, 0x4ce967fe, 0x2f3ff692, 0x190b4b2c, 0x05897180, 0xfc2b3102, 0x3a2dbeb0, 0xb7a1a751, 0x6f84c5bc, 0xc1d53ee9, 0xc7ea53f8, 0x32cf12e7, 0xf06d6a51, 0xa570fa2e, + 0x0c806d49, 0x2ab19ecb, 0xb4115114, 0xecba0663, 0xd08fc610, 0xa0a2f390, 0x0890a0f5, 0x4d98129e, 0x461a182b, 0x4c1ae922, 0x0bba8b5e, 0x1b0edf65, 0xaeaa9b29, 0xdc71cc61, 0x859c6503, 0x39084930, + 0x3a1e8e40, 0x4210f798, 0x40299087, 0xd6614b89, 0xb46e0c46, 0xb8add787, 0x3bb6a6f6, 0x3b91d558, 0x4bec0669, 0x40ef19e3, 0x38ae9954, 0x9ae6fffe, 0xaaf97f7e, 0xa5be5faf, 0x2b110712, 0x00001d18, + 0x45490000, 0x42ae444e, 0x00008260, +}; + +const uint32_t uprof_16_len = 650; + +const uint32_t uprof_32[] = { + 0x474e5089, 0x0a1a0a0d, 0x0d000000, 0x52444849, 0x20000000, 0x20000000, 0x00000308, 0x8aa44400, 0x000000c6, 0x47527301, 0xc9d90142, 0x00007f2c, 0x48700900, 0x00007359, 0x0000130b, 0x0001130b, + 0x00189c9a, 0x50b90100, 0x0045544c, 0x3d190000, 0x366b3818, 0x296ad96f, 0x4b232757, 0x224d2421, 0x34193f1a, 0x6b383264, 0x366b3836, 0x3a255727, 0x5729386e, 0x2b662e27, 0x3e2a5f2c, 0x3d193b76, + 0x285e2b18, 0x19366b38, 0x6b38183d, 0x67d46c36, 0x1f225224, 0x6b381d49, 0x285c2a36, 0x2255ae59, 0x3d192050, 0x2f673218, 0x38366b38, 0x3d19366b, 0x69d76e18, 0x2d1d461e, 0x713b2a63, 0x214c2339, + 0x3366d16b, 0x56283164, 0x40834326, 0x192c602d, 0x7137183d, 0x5dc16235, 0x38468d49, 0x5729366b, 0x366b3827, 0x383b7c3e, 0xd06a366b, 0x4c9f5065, 0x3057b55b, 0x83412d63, 0x2757293e, 0x6637763a, + 0x6b3862c8, 0x27572936, 0x19366b38, 0x6c34183d, 0x3f864331, 0x693e7b40, 0x743c64cd, 0x366b383a, 0x29245126, 0xc4642757, 0x366b3860, 0x38469049, 0x4b213574, 0x366b3820, 0x3c3f7e41, 0xbb603978, + 0x2757295c, 0x2552ab56, 0xb75c2351, 0x2e643158, 0x29183d19, 0x3d192757, 0x2c612f18, 0x1c183d19, 0x57291b41, 0x366b3827, 0x56275729, 0x864552a7, 0x183d1943, 0x29366b38, 0x57292757, 0x183d1927, + 0x5a366b38, 0x3d1956b0, 0x366b3818, 0x29275729, 0x4e232757, 0x366b3822, 0x21275729, 0x3d19204e, 0x183d1918, 0x19366b38, 0x5729183d, 0x27572927, 0x20469649, 0x612c1e48, 0x30613229, 0x535ab85e, + 0x6b3850a2, 0x366b3836, 0x291b421c, 0x7f3d2757, 0x4488473a, 0x19183d19, 0x3d19183d, 0x366b3818, 0x38356a37, 0x944d366b, 0x27572949, 0x4c3d823f, 0x9d514998, 0x2554274e, 0x3850a653, 0x6b38366b, + 0x2a5c2c36, 0x40e8e81c, 0x93000000, 0x534e5274, 0xffffff00, 0xffffffff, 0xff26fdff, 0xfffffcff, 0xd5ff19ff, 0xffff1127, 0xffffddff, 0x3aff0cff, 0xffff3709, 0xffffffff, 0xffffffff, 0xffffffcd, + 0xff8b0643, 0xffffffa7, 0xff84ffff, 0xce2b1eff, 0xffffffc1, 0xffc8ffff, 0xff9eff14, 0xff38ffff, 0xffc7ffff, 0x04ffffff, 0x802371b6, 0x8e01d6ff, 0xc0b424ff, 0x33301ded, 0x6d99de10, 0xade3f703, + 0xf028f9ff, 0xffc30e8d, 0xffffff2a, 0x19aefbff, 0xd3ffffbe, 0xff492f94, 0xff22ffe9, 0xffffffff, 0x2cffd806, 0x002e00bf, 0x49ff0100, 0x78544144, 0x8993759c, 0x18511257, 0x016f1fc5, 0x14150505, + 0x40410104, 0x2b525c91, 0x4d295cb7, 0x36972d41, 0xd17db4b5, 0xf6cb2f68, 0x2feb353d, 0x1ad9beee, 0xce67ba06, 0xbf7ce77c, 0x337df73b, 0x66210def, 0x51a33a1d, 0x8ff921e7, 0xeef5dd6e, 0x3bd76852, + 0x77065733, 0x8d26a69f, 0xe6e0b17e, 0xac5a4abe, 0x7e66f537, 0x512d37f2, 0xb7c4d3a3, 0xdfa5394b, 0x57b3470c, 0xd4d554ed, 0x26a24a9c, 0x8664ab51, 0xf68ccabe, 0xd8c66bc8, 0x21a50eec, 0x343689d4, + 0xd51e54fa, 0xd00b3be7, 0x67a1da91, 0x0af62350, 0xc315ba74, 0x56d17d35, 0x6d10b480, 0xec1ac671, 0xd7463a42, 0xc07a9dc1, 0x10a7783c, 0x84350862, 0x8bf21d2a, 0xfb01e8f5, 0xc7007b00, 0x754208e5, + 0x7c60c0f4, 0x430057c1, 0x2251cbe8, 0x1a38aec2, 0x5f2c7861, 0x80595e50, 0x6036e83f, 0x2b708f04, 0x936f5f19, 0x9df5da7a, 0xece92576, 0x48b0f824, 0x11c8754d, 0x6a60e9dc, 0xcf084ea9, 0xdf31b20b, + 0xa161fedb, 0x2ae5727d, 0xe127b2c0, 0xf73c2397, 0x77090227, 0x15d2fdc0, 0x33c69723, 0xdefe8591, 0x900cbe01, 0x3f1a6bad, 0x5fc27a86, 0xd936adb0, 0x1896811c, 0x0d35ca79, 0x72b8a933, 0x9b0e9d67, + 0x5c8447aa, 0x333f7957, 0x6dc6bdeb, 0xa99e4261, 0x95b40986, 0xcb2e4cf4, 0x7f8d79e2, 0xaa0e6bc4, 0x9cc04586, 0xd74053cb, 0x03d2e4b1, 0xa370c32e, 0x1dc8315a, 0x3e86fa32, 0x20bacdcb, 0xb5d30679, + 0x4c7cac3a, 0x1911cdd9, 0xc5808031, 0x7a988092, 0xf0c0ae20, 0x569f860b, 0x513b49fe, 0xbe71cf47, 0x5b060c12, 0x5848fc2c, 0x6bd3943f, 0x0c954f9c, 0xdff6a770, 0xc6469eb1, 0x79e5aac1, 0x832ac713, + 0xb45d3cd5, 0x293093c4, 0xce03c8d6, 0xbcde06f3, 0xfcefe659, 0x96ddef71, 0x2ec70f84, 0x4560cafa, 0x7cfadff7, 0x5a8be7b5, 0x0e16017f, 0xe8187143, 0x00000636, 0x45490000, 0x42ae444e, 0x00008260, +}; + +const uint32_t uprof_32_len = 1214; + +const uint32_t uprof_192[] = { + 0x474e5089, 0x0a1a0a0d, 0x0d000000, 0x52444849, 0xc0000000, 0xc0000000, 0x00000308, 0x9c026500, 0x00000035, 0x47527301, 0xc9d90142, 0x00007f2c, 0x48700900, 0x00007359, 0x0000130b, 0x0001130b, + 0x00189c9a, 0x50c20100, 0x0045544c, 0x3d190000, 0x366b3818, 0x296ad96f, 0x4b232757, 0x224d2421, 0x1a69d66e, 0x421c193f, 0x2556271b, 0x253e9443, 0x592b2351, 0x3e844129, 0x3e60c565, 0x753b3a8a, + 0x3c8e4039, 0x60295e2b, 0x54265bbd, 0x2b5c2d24, 0x49357f39, 0xcd69468f, 0x5ab85e64, 0x3c62c967, 0x88443885, 0x3f804141, 0x3567d36c, 0xc1633276, 0x2b622d5e, 0x2f366f38, 0x6b382c69, 0x51a75536, + 0x513b7b3e, 0x6b384da0, 0x66d06a36, 0x4f2e6030, 0x6a334c99, 0x49954c31, 0x30347a37, 0x5c292e65, 0x1d471e26, 0x3350a354, 0x8c463071, 0x55af5943, 0x4e366b38, 0x6b384a9c, 0x57b45b36, 0x382e6e31, + 0x6b37366b, 0x27572935, 0x20366b38, 0x3d191f4b, 0x366b3818, 0x19366b38, 0x5729183d, 0x53ab5627, 0x38366b38, 0x3d19366b, 0x366b3818, 0x38183d19, 0x3d19366b, 0x366b3818, 0x29366b38, 0x57292757, + 0x366b3827, 0x29275729, 0x3e192757, 0x183d1918, 0x38183d19, 0x3d19366b, 0x183d1918, 0x19366b38, 0x5729183d, 0x366b3827, 0x29275729, 0x57292757, 0x366b3827, 0x38183d19, 0x6b38366b, 0x46944a36, + 0x38366b38, 0x6b38366b, 0x27572936, 0x29183d19, 0x57292757, 0x27572927, 0x19366b38, 0x5729183d, 0x366b3827, 0x19183d19, 0x3d19183d, 0x183d1918, 0x19183d19, 0x6b38183d, 0x27572936, 0x29366b38, + 0x3d192757, 0x183d1918, 0x19366b38, 0x6b38183d, 0x183d1936, 0x29275729, 0x3d192757, 0x366b3818, 0x29275729, 0x3d192757, 0x27572918, 0x45366b38, 0x57294098, 0x2d633027, 0x6d448c47, 0xa05068d6, + 0x62c8664d, 0x2868d56d, 0xd56d2656, 0xe6ab1468, 0x000000dc, 0x4e527496, 0xffff0053, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfffcffff, + 0xff02ffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xfff6ffee, 0x03ff1dff, 0x0e03ffd6, 0xff0cfb40, 0xcf231507, 0xb61b2312, 0x85fd2495, 0x0b4ed0e7, 0x70cbaca5, 0xc7f79fde, 0xe7f03dc4, 0xff7853f3, + 0x864ca429, 0xa7dc17ec, 0x7173e5bf, 0x7e96bdb1, 0xb363d536, 0x5d89312e, 0x3e37645c, 0x8c2c9d49, 0x5bdb5366, 0x0593ff6c, 0x78b998d4, 0x67d57f01, 0x007fccad, 0x49831000, 0x78544144, 0xf95bed9c, + 0x1f47135f, 0x3b9b26ce, 0x1721b721, 0x80920490, 0x84120102, 0x4a9c8080, 0x0aada811, 0xa282d56a, 0xb5bc55a8, 0xd5eb155a, 0xe8f7db6a, 0x33befffb, 0xbb3639bb, 0x4863ddf3, 0xf1f3f636, 0x7491a1f9, + 0xbe679f74, 0x31677ce7, 0x2be2be18, 0xe819a2be, 0xb9313d9d, 0x7f7f7cf2, 0x7f6e6e6e, 0xe4cafaff, 0x56ded989, 0xa58b5253, 0x6b4fb995, 0x1c2fa777, 0x5631ef1d, 0xf47e33d0, 0xdaeaf4c2, 0x2fc9b9b3, + 0xcaef465a, 0xd31bd3d5, 0x8c24da35, 0xdb5c6f4f, 0x53356c9d, 0xf7f91002, 0xc9e4b697, 0xad6c4557, 0xb2fdde9e, 0xdafd716c, 0xee2ab8f2, 0xf4bd1c35, 0xb0d10be9, 0x4176bbb4, 0xa60af923, 0xb52fefdf, + 0xf3ef7d98, 0xeeb4976b, 0xee1d9d7d, 0xbd0ed4b6, 0x6107ab73, 0xb1b0d65f, 0x93fa22df, 0x475d68d7, 0x27fbe58c, 0xbbdf6774, 0xf451ba72, 0xefa67a11, 0x4f5a9ceb, 0x38da3fbc, 0xaeb61cfa, 0x93cf18e9, + 0xfaee0fef, 0x67a70904, 0xfb3fa1f5, 0xf409ba69, 0xaf967a11, 0x7f6121ea, 0x39f439b9, 0x37af7709, 0x86e4fe9b, 0x5a8176ba, 0x46a6fbc2, 0x06abd2f3, 0xcb001ea6, 0x6cabcdbb, 0xddcdabb3, 0x6b3d1e7e, + 0xde848a4d, 0xd03a5b57, 0xdbb0b8c7, 0x6bb3fe0c, 0x649dc8cd, 0xbc6fdf8c, 0x989a5611, 0x6d58087c, 0x5b6782b4, 0x6547f2ba, 0xb191ae6d, 0x3f5f74bc, 0x782aa9f7, 0x4b0538d6, 0x47d3ba6b, 0x28dd39e8, + 0xb52e2705, 0x8dc23f82, 0x2bd974c6, 0x346fe2ad, 0xc142346e, 0x6eb526f5, 0xf07cb0aa, 0xab7cf464, 0x8291fc85, 0xfb777683, 0xe47e6fcd, 0xcd60e971, 0xf356f3dd, 0x0fa71a37, 0x5b2b0712, 0x708fa6ad, + 0xbf9e8569, 0x0403edbe, 0xf662b6ea, 0x97a9ab6e, 0xd1574ab1, 0xfe14be96, 0xcd1ae346, 0x74e962c4, 0x30d769ab, 0x06c29f7e, 0x7d38f4cf, 0x9cf8c5a9, 0x8dbbfe66, 0x0c1d5c9e, 0xb416b547, 0x002fad13, + 0x56d558f5, 0xb556960e, 0x99edf3fd, 0x48c8c8cc, 0x823b972e, 0xd0303031, 0x23e8a1ce, 0x2f10ef2f, 0x77d7e1df, 0x4d623cc8, 0xd35c1853, 0x3498dfc6, 0x9c391111, 0x211f2e27, 0xb00d372f, 0x8c47c0c7, + 0x7fc0d2bf, 0xff1b4b6e, 0xd0991f6c, 0x4fd2cba8, 0x04041f5a, 0x586ecd64, 0x5df551c1, 0x0ed692d1, 0xb420007a, 0x485b3663, 0x9af40036, 0x053966dc, 0x8356d437, 0xf91af7de, 0x4201471b, 0x70523369, + 0x03bcb258, 0xcb431e58, 0x745e32cd, 0x6903ad4d, 0x2103c13e, 0x64947780, 0x1960c803, 0x06c65cbc, 0x3adaea5b, 0xda442ded, 0x04a3b32a, 0x0101441b, 0x21fd7e59, 0x555dc150, 0x10b7b402, 0x88d08009, + 0x07c0a899, 0xbb9f4084, 0xc1b61ebc, 0x27fc1555, 0x286097b5, 0x5477962b, 0x810a00ac, 0xdeb2a5a4, 0x59693d0d, 0xdef51339, 0x0a1fccd0, 0x6643ce81, 0x0a2382a2, 0x045ec306, 0xa2b4ea3d, 0x3ded3980, + 0x6953b65c, 0x01029147, 0xb5672825, 0x368396d5, 0xc714aa38, 0x0c087b5a, 0x66320428, 0x4836aa21, 0xadcbc87b, 0x0a1566fd, 0x7808286e, 0xcd043145, 0x758a0201, 0xd16eaa02, 0xe82c1801, 0xa1172e20, + 0xed2dbe47, 0x416299a5, 0x5ebfb159, 0xa1536540, 0x2f231810, 0x1ebe4317, 0xf7f052ef, 0x3c84c8c5, 0x72a3116e, 0x02012f82, 0x89cb243a, 0xdb3d938f, 0x218cd12c, 0xcb19408a, 0xf88cc458, 0x9af4054d, + 0x64e59252, 0x02321b05, 0x07f052ae, 0x424240ab, 0x7c746b88, 0x6108f2c0, 0xc68bd139, 0xb011c39f, 0x6d402341, 0x8e94f008, 0xa3e58115, 0xa216d584, 0xa444e00d, 0x00c38bbd, 0x8bab031a, 0x2eccc024, + 0x88da0202, 0xc60a49cb, 0x9525d3c1, 0xa100b201, 0xd9909120, 0x41015405, 0x22f456d9, 0xa59eada8, 0xbd40441a, 0x962b38b1, 0x80aa0291, 0xa2306c87, 0x26032d17, 0x1fc34678, 0x32698acc, 0x33862821, + 0x2f64e5e4, 0xb3a53722, 0xbe315754, 0x84509908, 0x0c81d325, 0xa059ca46, 0x74b0f202, 0xd7146a9f, 0xa0815401, 0x00700ab4, 0xe625660c, 0x2f521e2c, 0x10fa22da, 0xda142cdd, 0x9bb01cd1, 0x024b1940, + 0xf06c0306, 0x041e61a9, 0xc692c6f6, 0xb3940780, 0x8290bd00, 0x5d808269, 0x069022aa, 0x3cd6330e, 0x2018c999, 0xaa055c80, 0x0f517b10, 0x774664e1, 0x9401df1b, 0x5c6f5131, 0x0fb65405, 0x1c100bcb, + 0x933c7827, 0xe69ba00a, 0xcb8dedaa, 0x4f210170, 0xa844846a, 0xa486c1b7, 0xe2a15ea9, 0xfa0435af, 0x46a4e581, 0x2f7a8448, 0x3e888e92, 0x1a0009d1, 0x02101303, 0x10a72750, 0xbcea3c02, 0xedea3c48, + 0x02217ba5, 0xe47dabaa, 0xa601602a, 0x242350ba, 0x6b06d082, 0xe8270122, 0xf3a0642e, 0xc0cc897c, 0x127c840d, 0xfac48468, 0x45960a05, 0x8a8e78c5, 0x080331bf, 0x38332768, 0x1b872c06, 0x5e6a1121, + 0x6bb61e24, 0x01e0d1bd, 0x119a484e, 0x366a1c02, 0x14743510, 0x3c2338f3, 0x55018ad2, 0xc8cc3800, 0xd4224235, 0x41f57c46, 0x834af9a0, 0x40a3b407, 0x83003808, 0x21bd57d5, 0x885ee9e9, 0x3ae5828a, + 0x62e9cf01, 0xefcf3a18, 0x03ed9f90, 0xd55d58ca, 0xf2c378b3, 0xd17b2846, 0x7b295d78, 0xadab7745, 0xa317e830, 0x8772cd5d, 0x939f2e33, 0x37545e2a, 0xa56ba3a2, 0x1f4cc3a1, 0xd95004e0, 0xe9bf200e, + 0xf6ea2cae, 0x26f243fb, 0x5d517b28, 0xe71d5314, 0x4b80ed8d, 0x042d8094, 0xc8be00aa, 0x1657f419, 0x439dbb85, 0x7ab8020a, 0x508ffd90, 0x418bdd00, 0xf92f75e0, 0x396029b9, 0x677102ae, 0x3fc87459, + 0x628f97e3, 0x4745ef33, 0x201425fe, 0xe10ee18a, 0x24b67995, 0x944c5de2, 0xf75d00ff, 0x858fc8fa, 0x72f0666e, 0xbbdb657f, 0x84f0b6e3, 0x45ec0092, 0x59ff7fc9, 0xa22b3fe3, 0x3e721418, 0x30bd1262, + 0x9ff28910, 0x980aa069, 0x1e5d5324, 0xabe00840, 0x5e338b31, 0x278517e0, 0x652eae98, 0xcefe9601, 0x0135dbe9, 0x9d3a5ed5, 0x3d1472c9, 0xa6a3be02, 0x121857fa, 0x48af1891, 0x0a57baf6, 0xc61c7007, + 0x3bd67fc7, 0x3989e711, 0x7d774c43, 0x2311751e, 0x71fa552a, 0x0d09d09d, 0xd3b00698, 0x4db52358, 0xedac7b4f, 0x09d9e6f5, 0x21a6cb16, 0x202c9163, 0x5205532f, 0xc51f0761, 0x199db881, 0x3dfdd6f2, + 0x4840bfaf, 0xe5b0854b, 0x65404d45, 0xf3ed9d2a, 0x7b47d064, 0xf4db5929, 0x4474a7a2, 0x33a3bfc8, 0x0d951035, 0xd330e001, 0x55c72c06, 0xcc3130a0, 0x3760f147, 0xc2bcb8c3, 0x53f9773d, 0x54694e5d, + 0x676c87c4, 0x97ee026a, 0x77048dc9, 0x81d1b730, 0x91e71ad1, 0x508cb1d1, 0xf5946640, 0x708da675, 0x4bace815, 0xcaee8122, 0x89b800d1, 0x1fcec4ea, 0x01fdd94f, 0x618bad8e, 0x1de5bd86, 0x61523ee7, + 0x171dd31b, 0x87790ff3, 0x01359799, 0x3a2397e5, 0x27ace962, 0xb2c74c6d, 0x0e28b563, 0x4309b4ee, 0xb349e7da, 0x99096287, 0x394ca810, 0x4f51b827, 0x579873f8, 0x17e60160, 0xb66b2741, 0x970c43f8, + 0x1b4e027b, 0x7cbcd8c3, 0x15700a46, 0x4664db0d, 0x5e52db52, 0xd25e731b, 0xd847468b, 0x7a8b27bc, 0xd56dc3cc, 0xa6774e28, 0x1a4149d3, 0x2cdd45ca, 0x8728cb9b, 0x4e33eb80, 0xd0e71626, 0xadef17a0, + 0x63281fb9, 0x3982aec5, 0x52661ce4, 0x57516883, 0xc8308317, 0xd78b6595, 0x7e2d3e89, 0x9b06fe07, 0x09a81529, 0xd71f0bc0, 0x0c56ac04, 0x84c1b2c0, 0xd36318b1, 0x5f70939c, 0x48f95326, 0x53c026b6, + 0xe7d65964, 0xf9e7c1f1, 0xe1372772, 0x600e738c, 0xcab817b7, 0x7cde1d04, 0xd0863fc8, 0xb7cf63c6, 0xa65b31c4, 0x80d1e5c0, 0x5b8c2bb3, 0x4df461a3, 0x2bdd8fc0, 0xe7996d8e, 0xc037adf2, 0x04d4bf30, + 0xa477af70, 0x5b883b93, 0x1b98c466, 0x157df365, 0x963923ce, 0xba42d6b5, 0x8b479623, 0xf0097ddc, 0x722a6330, 0xbbf8b6e6, 0x53c72bb1, 0x3843f1e8, 0x5bc3a140, 0xe734e42a, 0x77630cbd, 0xaf01cc3a, + 0x70080b1d, 0x089e1d01, 0x94e65df9, 0x8c337f1f, 0xdc5767fe, 0xebd29d8f, 0xcec3600c, 0x5123cc30, 0x3b103127, 0x07b5b884, 0xeb04d18d, 0xd9d4a24e, 0x9a22cb1e, 0xa9eb2c1d, 0x1628d1e5, 0x198bb2c9, + 0x632a0263, 0x6e2ece63, 0xeee1ecff, 0xb571fef2, 0x73dbba15, 0x41857220, 0x329bcab4, 0xb44fe177, 0x2075e0be, 0x78b6c3e6, 0xc854ecaa, 0x99ce0287, 0xd632f202, 0x98b7e13f, 0xf4a46103, 0x5fc04d62, + 0xd8933a38, 0xc46cd839, 0x8647e9e7, 0x7db221c8, 0x13b674d1, 0xe71478ed, 0x2e4523a4, 0x0273f687, 0x1434c912, 0x20d2a602, 0x0b88284e, 0x2f6e8df2, 0xb8a1f8f7, 0x772d0f25, 0x30a9bcd8, 0x5c26540a, + 0xc3031ce0, 0xc2bb0e1e, 0xb4970605, 0x8df710f8, 0x609f1e23, 0xb98b4e42, 0xcdec30ab, 0x1826bb9b, 0xfeff80a1, 0xa853812f, 0xb7eb531b, 0x88027bb6, 0xebe8c961, 0xdbda46cc, 0x50add863, 0x38ac26cc, + 0x8e517394, 0xe8758e3f, 0x6a34c362, 0x905b889f, 0x272e3347, 0x3dd841ef, 0xd450d002, 0x050a6294, 0x9a2d086f, 0x63b0bb08, 0x1e217ff0, 0xc6185a77, 0x87f874e2, 0x9138a379, 0x29bdd977, 0x0cc5d397, + 0x2c7e1df9, 0xc0555ceb, 0x8a457f9f, 0x472cbebe, 0x968b102d, 0x8f31c7d0, 0xcee2332f, 0xe8238246, 0x3ab85407, 0x3b58c53c, 0x5e3ea1ca, 0x8398bb00, 0xb514c25c, 0xd405e3d9, 0x64763193, 0xccf1fe6d, + 0x7aaa17a0, 0xf0e31f26, 0xbc86cb72, 0xb2b65d13, 0xf00b5400, 0x61bcdb1e, 0x14abf96f, 0x4f0818d6, 0xc3c69360, 0x009d7b4e, 0x9e63f7c3, 0xa78062d2, 0x431cea56, 0x99d43dff, 0xa3b22088, 0x30ef2cd6, + 0x58f745c1, 0xb78478d4, 0xe40afe12, 0x90588a6f, 0x29d8bdad, 0x32e1fd06, 0x1418c09f, 0x6d9ca631, 0xf31fb3f8, 0x03faf199, 0x5cc3154c, 0x073b7738, 0x4eec0119, 0x1d77fe3f, 0x0533ce4e, 0x3bbdf031, + 0x532fea67, 0xe07531db, 0x83d44f0f, 0xc531655d, 0x324ccd65, 0xb2c7f6cf, 0x22f29dc9, 0x00a069e4, 0x42250253, 0xe38c00ec, 0xe4fcaa73, 0x11b55002, 0x338c033a, 0xfc4979ce, 0xc22330f3, 0xbaeee7f0, + 0x49bcc39f, 0x0122130b, 0x85775997, 0xe3ebeb3f, 0x4d6a38fe, 0x31b655b0, 0x8247762e, 0xe0e50e5c, 0xc3f3de86, 0x3d8c4294, 0x9162e364, 0xde80e467, 0x1a50e167, 0xa699f30e, 0x8fe62e2b, 0xfdd50bbe, + 0xfc121968, 0x3fa34820, 0x12a435b3, 0xc58c9b9c, 0xdcafd552, 0xf9412e51, 0xf57739ac, 0x700aa82b, 0xc18f2a94, 0xec73606e, 0x5845adc8, 0xab7176ec, 0x00a90e5d, 0x5dfa4dbb, 0xf6428205, 0xef209596, + 0x87c0fc13, 0x35573b87, 0xfa0fdb13, 0x4edf4634, 0x7627cf80, 0xbb24b647, 0x18a44392, 0x10c26982, 0xa53712b4, 0x75001402, 0x63583572, 0x26444f1e, 0x821a4452, 0x0156bca5, 0x9eee6682, 0x5a600166, + 0x467586a7, 0x043d7299, 0xcd47f4ed, 0x1691a002, 0xf2b5163d, 0x9a070467, 0xf7f95a2b, 0x129169c3, 0x633294d6, 0x04d49e11, 0xd0156bac, 0xd5b9daa6, 0xcad76822, 0x4d64fb7f, 0x015682c0, 0x0a9d89b2, + 0x7806cd09, 0x804d4dfa, 0x028d3be1, 0x1686cec0, 0x500d4211, 0x02b383c0, 0xf1b59701, 0x76e72b77, 0x14c9c88d, 0x4282002c, 0xd1dc306c, 0x68dd2026, 0xcd7ea6fe, 0xc06585fc, 0x9b5bf860, 0xf3469d80, + 0x8037698f, 0x0c1a8b30, 0x85ab7fbf, 0x55e1bbbf, 0x7f3b5da0, 0xc050a4e6, 0x7c514d0b, 0x1e25fa18, 0xa3c58005, 0xff9da5cf, 0x80a171fc, 0x08b5efa9, 0xe5e7ee80, 0xa087cc91, 0x30a195e4, 0x0ea1a6c0, + 0xba18a29a, 0x758392eb, 0x019c750c, 0xa83114e0, 0x478257cc, 0xb53402f5, 0xabbbd073, 0x9df20832, 0x06d10cc2, 0x1c7dcd49, 0xd4618a23, 0xe288690d, 0x14070a43, 0x95fd4a29, 0x236f632c, 0x2af68fc4, + 0x4eb730cc, 0xfdb80bd5, 0x3e017aa3, 0xc81837e8, 0xd8b9da41, 0xdaeb3825, 0x04891902, 0x851855ed, 0x017af1c0, 0x316a1a53, 0x797c0554, 0xed3c6982, 0xab96d392, 0x4a2ebf58, 0x021c5fc1, 0xf507c306, + 0x6ea9a002, 0x16f9b188, 0x26b1d605, 0xfc965973, 0x98a14b78, 0x6bce568b, 0x2f011a05, 0xd5d602c5, 0x12300107, 0x1106e3ea, 0x973160ec, 0x76e4cc59, 0x1981d2da, 0x1b6afab9, 0x74f9b176, 0x4dada3b6, + 0x81514c32, 0x02c5275b, 0xe5a93f0c, 0x4b394d0f, 0x8b491b34, 0x0225c773, 0x002b50fe, 0xc9a2ebba, 0x7890d425, 0xebf0c190, 0x80052a0f, 0xf91d7e83, 0x0a929fcf, 0x4dd95058, 0x473f6f40, 0x2d11aa68, + 0x55fca536, 0x54d0d4b7, 0xd2192a94, 0x804935e2, 0x850c62ca, 0xfc8e98c0, 0x935865c5, 0xf9e7410f, 0x1e028eac, 0x53a3f890, 0x6efe1a8d, 0x06b625a0, 0x30db9f94, 0x580b219c, 0x410fd350, 0x8eaa2d23, + 0xdf9b1292, 0x3aa80590, 0xbdd74014, 0x6a056314, 0x1bf8079c, 0x0130a8ae, 0x875696f4, 0x21b7fc7e, 0x7ea61803, 0x9d001656, 0xc70f350a, 0xe21171e9, 0x62b1aa8f, 0x43437526, 0x8c8e9a51, 0x3ed2db0e, + 0x8ac616ae, 0x3ce802a7, 0xbf8dd49f, 0xc29576f0, 0x5d6fe004, 0xfb7fc6e9, 0xa5009c8d, 0x05540af1, 0x09ba5d4c, 0xa46d28b8, 0xdf28f885, 0x9181e693, 0x64c52756, 0x32f30e8a, 0x4099c011, 0x2181113e, + 0x827af9a0, 0x8011b216, 0x41d2df21, 0xd19a79e7, 0x6dc8151a, 0xde099d5c, 0xce8009ca, 0xc69dbaf3, 0x97f12b1e, 0xa0a5109f, 0x78c51691, 0x8a9b0a9f, 0x1bf84006, 0xf42ca276, 0xc57a788b, 0xd686d030, + 0x638e0163, 0x517b7ae8, 0xce0618a7, 0x015c6201, 0x96f42953, 0x04fdcd16, 0x5214f605, 0xe0530568, 0x0dd013ab, 0x011f5a45, 0x512d1b60, 0xe863d400, 0xfa4d3957, 0xb3c5c084, 0x4e2bd4ca, 0x8271be44, + 0x5d11330e, 0x25ca330e, 0x7df20040, 0x46055407, 0xaf3fe0f5, 0x9d55032a, 0x4cba7488, 0xa6d02141, 0xe45f8087, 0x6e31389b, 0x87bd6613, 0x11e800da, 0x73c10f02, 0xf9d20024, 0xcb5ba1d8, 0x96b6c126, + 0x6a41e000, 0xce7a1dac, 0x25b8853f, 0x63218a7b, 0xa5a926ea, 0x3d38eb30, 0xbcfe61a9, 0x2b2800b6, 0x9614b620, 0x18d02856, 0x9b9015c0, 0x81fe90a2, 0x518eb840, 0x45627587, 0x03c15dd6, 0x86a809ad, + 0xac8ae4db, 0xd43f286f, 0x6c94809e, 0x80206ba0, 0x78755c93, 0xb4bcbe41, 0x9b46e6e8, 0xd8685b2a, 0xd22f6406, 0x9d54102b, 0x90141521, 0x5d0e8dc7, 0x1b9aa186, 0x740a2d08, 0xe403e508, 0x91a0211f, + 0xfcd9a5af, 0xc13fa91f, 0x76202828, 0x6aeb2c15, 0x536c206a, 0x82800ff5, 0x7e73e47b, 0xbdec1533, 0x847f1c6e, 0xd464e48f, 0xef7b06bc, 0x23e9235d, 0x22d303ac, 0xcfe85373, 0xf84c6b9f, 0x07f0b10a, + 0x8cd8e679, 0xbe7dbcaa, 0xc42be151, 0x3764afd4, 0xc15c3572, 0xd9944f6f, 0x2de16150, 0x5c1b9631, 0x371fe795, 0x0aaa7dde, 0x46b6277e, 0x9bcaad0d, 0x7d9a1a67, 0x10ee1224, 0xaab0d08d, 0x2fedccdc, + 0x1d3105e3, 0xe6102635, 0xf7b41dcf, 0x0f858354, 0x034243a4, 0xe6fcda6a, 0x1f246699, 0x847b8492, 0x50e07a8c, 0x13ad7bde, 0xf7db8c7d, 0x40f52908, 0x29b4fca1, 0xd4c61fa9, 0xc49fcdfa, 0xf6439e1d, + 0xcc395745, 0xf07f3d3f, 0x2c668b83, 0x54e4907c, 0x7cde50ca, 0x57eeefa9, 0xade57531, 0x42281828, 0xb351ef79, 0x092aaeea, 0xae5dee2f, 0x431a0c2b, 0xf3c3d6f9, 0xb75a9b27, 0xd14068d4, 0x4fca1940, + 0x356a9f1f, 0x3fd632fb, 0x2565a9dc, 0x6fe9ed75, 0x297f5ee7, 0xad4c39ec, 0xf979bc7f, 0x29556fbb, 0xf87bdf98, 0x8a2f99cb, 0x0b53197d, 0xf9ddee2f, 0x50d907e9, 0xee7a7ede, 0xe516bbf5, 0x5a98951c, + 0xdfc3f5ff, 0xfe6c1e8f, 0xdd5db7b6, 0xa7bdedf2, 0x7a3c1f0f, 0xcb4df2fc, 0x8e355623, 0xf2753d9f, 0x4f27bbe4, 0xf379bcde, 0x93bbdde4, 0xfb39bea7, 0x15fea18f, 0xc2cff15f, 0x69e401ff, 0x6f1037bd, + 0x000063a5, 0x45490000, 0x42ae444e, 0x00008260, +}; + +const uint32_t uprof_192_len = 4942; + +const uint32_t uprof_512[] = { + 0x474e5089, 0x0a1a0a0d, 0x0d000000, 0x52444849, 0x00020000, 0x00020000, 0x00000308, 0x24a6c300, 0x000000c8, 0x47527301, 0xc9d90142, 0x00007f2c, 0x48700900, 0x00007359, 0x0000130b, 0x0001130b, + 0x00189c9a, 0x50c20100, 0x0045544c, 0x3d190000, 0x366b3818, 0x296ad96f, 0x4b232757, 0x40994521, 0x2a224e24, 0x9644285a, 0x1b431c3f, 0x26193f1a, 0xbf612451, 0x68d56d5d, 0x42265628, 0xd76e3e93, + 0x48954b69, 0x2567d26c, 0x5f2b2354, 0x42894529, 0x2d468f49, 0x3d192b62, 0x5bbb5f18, 0x68366b38, 0xcf6a64cc, 0x346a3765, 0x5b2b5d2d, 0xab5657b2, 0x2e683053, 0x672e6e31, 0x873d62c9, 0x38703b38, + 0x65316834, 0xa25260c5, 0x3a763c4f, 0x3f2f6231, 0x70343a8b, 0x59b75d31, 0x3e50a654, 0x672e3b7a, 0x3378362b, 0x38327535, 0xaf59366b, 0x3f814255, 0x38275729, 0x8040347c, 0x4b994e3d, 0x381d481f, + 0x833b366b, 0x5ec16237, 0x44357338, 0x7f3a4285, 0x27572936, 0x21366b38, 0x6b381f4b, 0x183d1936, 0x4e366b38, 0x57294a9e, 0x366b3827, 0x384d9d50, 0x8e40366b, 0x366b383c, 0x38366b38, 0x6b38366b, + 0x366b3836, 0x19183d19, 0x3d19183d, 0x366b3818, 0x38366b38, 0x3d19366b, 0x438e4618, 0x38275729, 0x6b38366b, 0x366b3836, 0x29183d19, 0x57292757, 0x183d1927, 0x38366b38, 0x3d19366b, 0x27572918, + 0x19183d19, 0x5729183d, 0x366b3827, 0x38366b38, 0x5729366b, 0x183d1927, 0x29275729, 0x3d192757, 0x27572918, 0x29275729, 0x6b382757, 0x183d1936, 0x29275729, 0x3d192757, 0x366b3818, 0x38366b38, + 0x6b38366b, 0x366b3836, 0x29275729, 0x3d192757, 0x183d1918, 0x38183d19, 0x3d19366b, 0x366b3818, 0x19183d19, 0x5729183d, 0x366b3827, 0x29183d19, 0x3d192757, 0x27572918, 0x6e183d19, 0xd96f69d6, + 0x6ad96f6a, 0x6f52a756, 0xd96f6ad9, 0xf9a3176a, 0x00000094, 0x4e527496, 0xffff0053, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff04ffff, 0xfffffffc, 0xffffffff, 0xffffffff, + 0xffffffff, 0xffffffff, 0xffffffff, 0xfffff6ff, 0xfffffffa, 0xffff02ff, 0x04ffffff, 0xfb0cff06, 0x2910ff17, 0x20ff95ff, 0x3489d5e9, 0xef2917f1, 0xffb1c0ce, 0xaf3cdcf1, 0x5163e83c, 0x324762a8, + 0x4426c00f, 0x58734b9f, 0x1b73c53f, 0x655bd14b, 0xb9dd94dc, 0x70e3c652, 0x8b217cb9, 0x69807832, 0x80a1e597, 0x86a3adc8, 0xac5507d2, 0x127dd934, 0x00bc7d27, 0x49422f00, 0x78544144, 0xf99ded9c, + 0x9a46d47f, 0xddba6987, 0x8f7df03e, 0xc19f17b1, 0x303e3076, 0x83180d8c, 0xcb9a7301, 0x662f1009, 0xe1308136, 0x92c0d848, 0x3930201d, 0x99612048, 0x6efff9ec, 0x492ae955, 0x6f4952a5, 0x5ddd5549, + 0x19f32fcf, 0x7a356da7, 0xdf7d555f, 0x8763b4ab, 0x183060c1, 0xc183060c, 0x0c183060, 0x60c18306, 0x060c1830, 0xf271d543, 0xd7f3a5f4, 0x6f6f6dae, 0x5f6c203f, 0xd2fe76bb, 0xbfaa9399, 0x4e432195, + 0xf67eda5e, 0xdbc3eafa, 0x795c6f37, 0x27717d75, 0x5fd7dd93, 0xf371badd, 0x6f8b9df6, 0x7f383eee, 0x3637f55a, 0xf6f4e148, 0x6e77abdd, 0x9bbcb95e, 0xd70e736d, 0xfb7f7d6f, 0x9747ebe2, 0x27feaa8e, + 0x7a715218, 0x2f8bd7fb, 0x6c4f5c6e, 0xb78b10f7, 0xf37c3e6e, 0x7fea8ce0, 0xa398418f, 0xbc5eefe7, 0x23f92af9, 0x8dfae7cf, 0x8db66f3b, 0xa39cd04c, 0xb9df5ed7, 0xcbc3b111, 0xdbadf760, 0xea303fbf, + 0x3cce4f40, 0xeda5987b, 0x72b82f29, 0xa379f5e7, 0xd2e2b40c, 0xe56fb7af, 0xcb8f7b61, 0x66bf7e2f, 0xce0b409c, 0x55fb7afc, 0xb877c6be, 0x8138d37e, 0x7cbf4e62, 0xf18d4578, 0xfedf2e1d, 0x8a0804d5, + 0x66e6f4b8, 0x2c7e7b2e, 0x9b6e2e57, 0xb66f2085, 0xf47e2a2f, 0xfdbe5cfd, 0xb90704cc, 0x9dd1f471, 0x1e2daacb, 0xafc5f166, 0x407207c6, 0x2c5beb4f, 0x903e34de, 0x6a1ed731, 0xc58b7d6b, 0xba4ccf17, + 0x5d2e2b30, 0x4fd839cd, 0x0f3bf5c7, 0x6aa9df54, 0xdfafe4e4, 0x67ef4ecb, 0x26abadc7, 0xf6cb9436, 0xbd75091d, 0xd37dd93c, 0x38d2056c, 0x6a86faf9, 0xf2e1a67b, 0xefaa4bc5, 0xfe70555c, 0xfc3d8561, + 0xbc5fbb1e, 0x18221934, 0xd0565f47, 0xd6e2cfce, 0xa618131b, 0x8a9bf4e7, 0xae7cfd90, 0x413b343f, 0xac5cce3a, 0xcfdfb5d8, 0xaadb17ee, 0x720565ef, 0x951e8efe, 0xff7c391e, 0xacfdf552, 0xaeddae30, + 0xcc3fadec, 0x0f466795, 0xa2fdb30a, 0xb98fccda, 0x80b8d775, 0x5537db10, 0x8c2b2a9b, 0xad70080b, 0x077e9f2a, 0x9c3102e3, 0x3fbdbaaf, 0x072315c8, 0xa77339a3, 0xb98fcdda, 0x36428261, 0x5356afa7, + 0xc5e3c7e0, 0x5af7d579, 0xd6be8e43, 0x2643d5bc, 0x729a1fbb, 0x5a478071, 0xcf6678f5, 0xb54ddff5, 0x0bfce298, 0x9fc906d5, 0x3a0d465b, 0x2b58be9c, 0x9b9fbf9b, 0xee100a46, 0x52ec9a2a, 0x5345e2cf, + 0xbe71de2b, 0x227ef36a, 0x7df5aabc, 0x84cd64e0, 0xa8bc517e, 0x07816ee9, 0x01f0d055, 0xcd4df165, 0x3f4f8766, 0x5fc485ac, 0x546a373c, 0x59acbe0c, 0xf16417f1, 0x05260d6a, 0x7d51df4e, 0xcae275db, + 0xc8f6d535, 0x9435479b, 0x776115f8, 0x27022d6d, 0xa21feecd, 0xb6c09496, 0x160cff11, 0x3848d75f, 0x79aaf470, 0xacdcd9fc, 0xa5e11a89, 0x67df55ef, 0x48fcb97d, 0xe7b275b5, 0x7b4c9559, 0x2ac5c464, + 0x1f2782d7, 0xbac3beaa, 0x53aaa373, 0xac6be7c3, 0x8b0d23ed, 0x295b54cf, 0xe59aee3b, 0x5587845f, 0xbd1c0dba, 0x56cefaa8, 0x0db9d50a, 0x63c8a99c, 0xb970d43e, 0x7a998f0a, 0x09bf7260, 0xb57bfdd8, + 0xd75e8525, 0x5247e37a, 0xb755576e, 0xfd1351d8, 0x154ae625, 0x26338109, 0xcb8297f9, 0x76423355, 0xa47e74de, 0x6aaef162, 0x91e1c9cb, 0x72d3fe89, 0xe0a41ab5, 0x4bfb536b, 0x4148154f, 0x7101fd93, + 0xc42bc2a3, 0x1fe74d27, 0x1d155b90, 0xf2369c0c, 0x0ae5cc1f, 0x633d17ee, 0x58127f8a, 0x112ed8ac, 0x61c9fe13, 0x88168577, 0xbfec99af, 0xb6ab5e2c, 0x981e1a65, 0xbf1e5ff0, 0x7266b6ab, 0x8fea9a5e, + 0x5a562e4c, 0xb199e84a, 0x561e5cbf, 0x35dc0796, 0x9dcd97f6, 0xbb146a4a, 0xf2bfd26b, 0xf80f20a9, 0x0b3fd8d5, 0x078a576e, 0x233fe798, 0x8c03c42a, 0x4ee333fd, 0xa3412825, 0x02a433ff, 0xff130162, + 0x1ef68a67, 0x3fd8c8f0, 0xb6aa2e5b, 0xc6079f30, 0x557359fe, 0x5c798db5, 0xecfff933, 0x7432b8d1, 0xf2ffd4de, 0xe166db40, 0x9ffea633, 0xed35bb0b, 0xfa6d3910, 0x5162727f, 0x93b12ecb, 0x372fffa6, + 0xa478ebae, 0xcdffe99c, 0x75fa5791, 0x7d555f8b, 0x1b8b6a4f, 0x988c4dba, 0xdcce6002, 0x68252bd6, 0xa3b94012, 0xbce84255, 0x8fe50049, 0xd380e946, 0x055fece6, 0xfce6d6ec, 0xfd35a380, 0x5c7527de, + 0xd06c65d7, 0xe22b000c, 0x80a11e8a, 0x865200e9, 0x35c0a116, 0xe3a80013, 0x9beb6a8d, 0x9462900a, 0x008c85d7, 0x21728b54, 0x8ac03268, 0x55b6a1b9, 0x8011a5fc, 0x24da51aa, 0x0064c978, 0xf8f0a3d5, + 0x0f4aa388, 0x9d9b9f00, 0xba9a9a9d, 0xe88c3880, 0x43ececec, 0xf6f6f56c, 0x3a1c471e, 0x31196874, 0x8d373737, 0xfb2108f8, 0xeaf853f2, 0xc9d5de53, 0x1fabbde5, 0xd99eaeb2, 0xd5163de5, 0xcda80735, + 0x26285d00, 0xd5d115a6, 0x188435d5, 0x7d5d841c, 0x3bd5f93a, 0x97dbabac, 0x5dce58ff, 0x1f30a9d8, 0x00ad48f4, 0x04dc9fd8, 0x25f55d34, 0x613bd5c8, 0xd40e2f57, 0x11bac835, 0x19c064aa, 0x83c03dc5, + 0xd48c0b30, 0xae01b5d5, 0x80740c3e, 0x1e893abe, 0x038952f0, 0xcc00ce28, 0xbc702d01, 0x3fc0790e, 0x38fcbea5, 0x75abf2f0, 0x49403d12, 0xac8de036, 0xc3929f6f, 0xadec0b40, 0x0a407883, 0x54a7e009, + 0x6e03d327, 0x38145fe6, 0x0004baaf, 0x9a3b835c, 0x9aea05b1, 0x54007a53, 0xab90b402, 0xdc80f3cb, 0x2a8e85c7, 0xae00021f, 0x0596c3c1, 0x41c07ad2, 0xda7403a0, 0xe923df97, 0x0b1ee46e, 0x43014f2a, + 0x3aade0d7, 0x024c0790, 0x275abf2f, 0xe4ae03d9, 0x56de129b, 0xae86029e, 0x107533c1, 0x03a8f80f, 0x9d52f978, 0xb5c80f6c, 0xfaa4f449, 0x18684026, 0xf10756d6, 0xd5e03e80, 0x9757798f, 0xf3bb01e5, + 0xa0d3179c, 0x06b80c09, 0xa81650b7, 0xf49bde6b, 0x700950ea, 0x07be4eb8, 0x136fcadc, 0x8001bf50, 0xda4ee0d7, 0x49f57502, 0x012a003d, 0xf032eba6, 0x140edc80, 0x000360d6, 0x75abc1af, 0x4b000f10, + 0x0cba8680, 0x4db7203c, 0xb0047940, 0x0706be13, 0x03d0902c, 0x1f57817a, 0x925d5c0f, 0x0914e407, 0x0a05d168, 0x1643835c, 0x2301e648, 0x10b80740, 0x0f1cbcba, 0x5447a7c8, 0x4380b787, 0x05b0e0d7, + 0xd413eaea, 0x1d018f67, 0x797c3a60, 0x4b901e29, 0x8cb5e83a, 0xba050a6f, 0x2d85cf06, 0x5a03c490, 0xc3df9781, 0x0f14bcb8, 0x7026a1c8, 0x302e8b46, 0xcfdc1ae8, 0x07b880b0, 0x3d5e071c, 0xf34901bc, + 0xc3fbec80, 0x9af8cb6e, 0xf06b8060, 0x04d33d50, 0x301e8275, 0x2980740b, 0x7865d5f6, 0x8facf5c0, 0xe120790e, 0xb8004a4b, 0x2db08f06, 0x2d01ea20, 0x6d600740, 0x203cb240, 0xa3a0eee3, 0x7600a41a, + 0x43e0d7c2, 0xe6200e51, 0xcbc05d01, 0x2c8024b3, 0x1938c80f, 0x1bfc3bf0, 0x06ba00ca, 0x803a468f, 0x010e0d88, 0xba083eaf, 0x67df1c7a, 0x50f503a9, 0xb835e080, 0x04da39b5, 0x02983602, 0x0484403a, + 0x5901e590, 0x8e5d40ea, 0xc1ae0382, 0x080b1cc3, 0xe80060d8, 0x40125100, 0xce5c0792, 0x9afc4bae, 0x011022fa, 0x72f706ba, 0x06d6201d, 0x33cbc043, 0x1e895063, 0x48515d90, 0xa140b397, 0xd70cf06b, + 0x58367102, 0x239d5e06, 0xc078e401, 0xc23d5662, 0x4cdfa0cf, 0x9835d016, 0xdc080127, 0x1314cd5e, 0xe3663e49, 0x80f60eae, 0x5fd8d93b, 0x27701093, 0x881e0d78, 0x1d5d40b3, 0x3808686f, 0x8e5c5491, + 0x03d83abd, 0x550509b2, 0x40b8020f, 0x58cee0d7, 0x203d700b, 0x8040095b, 0x12660dce, 0xe6d69e0a, 0x35d0106d, 0x02de3578, 0x4e800f1c, 0xa1a54524, 0x16407aa5, 0xd0e8c727, 0x5d016206, 0x06f14b83, + 0x1a1e8ba8, 0xc5244e82, 0x1e19004a, 0x12fe4570, 0x680e4ba0, 0x742a7827, 0x9102c852, 0x04bd901e, 0xf201e190, 0x683545c7, 0xae81b604, 0x1d0567c1, 0x8003c220, 0x58fc57ee, 0x0f30eaf0, 0x3bbb2578, + 0x7d0e92ec, 0x35d01660, 0x138ed198, 0x00606b01, 0x2424913a, 0x80782401, 0x1fa4a3ec, 0x548dbe82, 0x64706ba0, 0x03c84e2d, 0x5917eea0, 0x01ec9689, 0x1ac21392, 0xa9d0002d, 0x5c44b8d0, 0x2740078c, + 0xd12ba292, 0xee403d92, 0x02d1a012, 0xc5835d00, 0x07a47854, 0xe0860f40, 0x7ae5a254, 0x2a9965c0, 0x0005a740, 0xa82a153a, 0x003c23c2, 0xc25d7eea, 0x01ec0012, 0x8d009732, 0x1af00016, 0xac11e89c, + 0x420e0e0b, 0x04812fdd, 0xc4807a80, 0x468ce025, 0x2474000b, 0x5823e124, 0x81191817, 0x9125244e, 0x900f5000, 0x93e804b7, 0x848f8003, 0x016a4c1c, 0xa74007bf, 0x3fae9342, 0x96900f10, 0x4fad380b, + 0x153e1012, 0x120cd31a, 0xf75001e3, 0xfebc4d6b, 0x56403c40, 0x2a9f503a, 0x1af84ec0, 0x038537bc, 0x75001e78, 0x0feb14bf, 0x552403c0, 0x536a4e04, 0xd700c406, 0x66d88ee0, 0xd807b610, 0xdfba8046, + 0x4f5754f1, 0xa40f01ed, 0x7d368038, 0x1ae81800, 0x05953fbc, 0x4a800f5c, 0x4feb5480, 0x29b80f7a, 0x34fafec3, 0x80b66102, 0xe94be816, 0x80079600, 0xf5ba4025, 0xc807bd27, 0xa6d20d68, 0x9d009013, + 0x066a150a, 0x74023489, 0x04953928, 0x43c07880, 0x4ba00e09, 0x7405b02b, 0x19ac5f32, 0x5008ca24, 0x82134bf7, 0xbd392458, 0x7c376280, 0x649af456, 0x4e01020b, 0xbf8b1e85, 0x800f3cd5, 0x094a5fba, + 0xf800f000, 0x0cba2199, 0xa7405903, 0xdfc70f42, 0x80119e69, 0x025a97ee, 0xeb80f7a4, 0x69f0aad0, 0xf0c0b29d, 0x66f150a9, 0xc0331610, 0x0097a7ab, 0x3a003de9, 0x38c9a829, 0x327403b0, 0x0833413f, + 0x28256803, 0xef4804bd, 0x0e803701, 0x080c55a0, 0x9f650a9e, 0xb40c22cd, 0x01200917, 0x2c007bd2, 0xdd247c12, 0x53a02084, 0x6cc1bca1, 0x07ee8001, 0x3da90092, 0xc8647600, 0x8446f90b, 0x4d0a9d00, + 0x60120cd8, 0xfceaf02f, 0x3cacf4a9, 0x03221160, 0xd8046ab5, 0x150a9f09, 0xa366c96d, 0xc12910a2, 0x016d2003, 0x7701d55a, 0x92f2c782, 0x80f88337, 0x254122f6, 0xb80f4a40, 0xcd007002, 0x2a742024, + 0x563f6934, 0x0848e000, 0xf4a4025c, 0x5032f480, 0x5ce13393, 0xe9a153a0, 0x1f0eb18a, 0x412eaf03, 0x901e5802, 0xf4fb6cf4, 0xe3d112ef, 0xb50f4850, 0x10b41861, 0x10024329, 0xea407a92, 0x5966a06c, + 0x5e58f040, 0x071066ca, 0x4c48bd25, 0xda407a92, 0xb35ff161, 0xa06a6331, 0x9b69a153, 0x90f46c41, 0x1e848400, 0x03a53b70, 0x6c377e28, 0xde58e808, 0xe59dfc56, 0x757807b0, 0x90801259, 0x165203cc, + 0x7268cf85, 0x540b9c28, 0x0e1dc402, 0x0cda07c6, 0x10024d22, 0xba407992, 0xbd568054, 0x58e81880, 0x7dfc5b5e, 0x066d00e5, 0x08012791, 0xfbe03c89, 0xc3a00e54, 0xa068419b, 0xf12d7963, 0xd0079577, + 0x004a64fd, 0x480f2242, 0x25e07273, 0x680076dd, 0x70e45631, 0x801a68b0, 0x012a9757, 0x203c4908, 0x75a5bbcd, 0xa783034b, 0xa0fd0142, 0xa78f8c88, 0x0f02434d, 0xa015d348, 0x96000edb, 0xc537c100, + 0x8bda0325, 0x10025924, 0xf2407812, 0xca5d49b7, 0x80a994d0, 0x9b03e4f6, 0x21238041, 0x410025d2, 0xef9203dc, 0x82f59a01, 0x60f2c7c1, 0xe02520cd, 0x004be5d5, 0x2407b082, 0xdbb403df, 0x5899a001, + 0xb1fd29ee, 0x19910b40, 0xb0820048, 0x038d2407, 0x8102cbb4, 0x8e04f2c7, 0xa3a0e5e8, 0x7a882004, 0x905cd240, 0xa487af16, 0xf1004a81, 0x0098f9f3, 0x91b24247, 0x0f410400, 0x01d09178, 0x84066b34, + 0x9ac2854f, 0x3ff2da41, 0x31184497, 0xac9dd80f, 0xa7527c26, 0xd0084143, 0xc3e26c4c, 0x0b407c79, 0x9456b091, 0x203cc418, 0xb3584d59, 0xf09df076, 0x87e4d0a9, 0xdb40d0f3, 0x00933391, 0x480f2104, + 0xd3ae1ed6, 0x2a1670b9, 0xeaeaf2c7, 0x9d4f7cb2, 0xe03c4404, 0xa323a27a, 0x8506eb34, 0xe2c2854f, 0xfba066f0, 0xac012965, 0x01e0282f, 0xb5437a49, 0xa782034b, 0xf8716142, 0x99eaf02a, 0x8082004a, + 0x06492407, 0x000ad76a, 0x35850a9e, 0x5e059c83, 0x40095b3d, 0x2480f788, 0x17690607, 0xd7df8204, 0xbbba0ddc, 0xaca489c0, 0xd6210025, 0x82041203, 0x020bb547, 0x8158c5a1, 0x8071c537, 0xb9910c1e, + 0x5eb02004, 0xfc43e16f, 0x5cedb8d0, 0x68049a8c, 0x066b0618, 0x10025fd1, 0x7c403ce2, 0x5ebb4440, 0x2854f010, 0xda0419ac, 0x41cb0c8e, 0x01e31388, 0xba8243e2, 0x5fc383f5, 0x066b08d6, 0x0323b601, + 0x10135267, 0xdda201e3, 0x0049fae1, 0xf4563168, 0xea6c714d, 0x38140a81, 0xbe049a93, 0x83668807, 0xd00093f5, 0x37e150a9, 0x9e8131c5, 0x432b050d, 0x01eb8324, 0xbb4022a2, 0x48f02066, 0x0419ac08, + 0x979c8eda, 0x3cf02004, 0x482db440, 0x7d00093f, 0x70ec2359, 0x00918ab0, 0x08079e04, 0x8ead008a, 0x8b40c787, 0x14de89b1, 0x40a80617, 0x04009473, 0x6588078e, 0x68e7ce02, 0x79f2315a, 0xd014735f, + 0x2760a1b3, 0xda20a553, 0x01cac403, 0xe7854dba, 0x08e6bef6, 0xb0c8eda0, 0x10d2a993, 0x736201e9, 0x0e9d7ae2, 0x848e818c, 0x9c004cc0, 0x23360248, 0x03ca22a6, 0x21de8516, 0xeb5f2573, 0x0a9d03c6, + 0x26a6f34d, 0x8502a00a, 0x89293fed, 0x019100f2, 0x35da93a1, 0x30c34384, 0x1fa62d58, 0xfda17578, 0x72416c67, 0x03c230c1, 0xa623de44, 0x3a081a5f, 0x066b0a15, 0x8b23b681, 0x968c23cc, 0x8586b0cb, + 0x100f6c30, 0xd7e90549, 0x0095020c, 0x9c0b7bb0, 0x410a1248, 0x09e5ca57, 0xc06497d0, 0xa69100f4, 0x2034ed10, 0x78042474, 0xfdd01838, 0xeb124644, 0x76e5cb1b, 0xc16497d0, 0x814580f2, 0x86ed50ce, + 0x1861a102, 0x7a0419ac, 0x16489436, 0xe500ed1a, 0x21aefcb2, 0xabc40796, 0x1dbaa3c0, 0x0a9e080e, 0x38a6fd4d, 0x286cf402, 0x0af42c91, 0xc5580076, 0x03c3099a, 0x9a820be2, 0x276a24bd, 0xd6142a7c, + 0x489c020c, 0xa0953a12, 0x6c003b11, 0xd84d9578, 0x225fe203, 0x101e5da5, 0x6f40012a, 0x0c1f038a, 0x12e04171, 0x7232e5fd, 0xd7d03181, 0x01e4208c, 0x9d40b9f1, 0x804f155e, 0x37b06186, 0x86cf41c5, + 0x3552def2, 0xcbb514b6, 0x4031409f, 0xfa00bcb9, 0x3d04519e, 0x03ac72e0, 0x860b5768, 0xdec2854e, 0x476d0714, 0xf9f67776, 0xc440f972, 0xe5cbda35, 0x0579729e, 0x09233df4, 0x456c407a, 0x331a95f8, + 0x0a9d0347, 0x0e29bd85, 0xf5e49138, 0x7cc7a1a2, 0xc812fb1f, 0xb29afbf8, 0x7c2d0388, 0xf23d301e, 0xd7f6313f, 0xec0c112f, 0x833607c9, 0xb7802500, 0xbe45a0fc, 0x2c49aecc, 0x85f3cb95, 0x40e22cf6, + 0x0e03da0b, 0xc62bff16, 0x020bb401, 0xb0a153a0, 0x50129066, 0x48117a81, 0xb7a4647b, 0xb0a33c81, 0x89865caf, 0x9e6d0e55, 0xff178c07, 0xee01c62f, 0x1335b42a, 0xec2854e8, 0x3b683070, 0x66d46bb2, + 0xb3cde91c, 0x5680d12e, 0x44e142ff, 0x85a07136, 0xc5d301eb, 0x38c77fe2, 0x21337680, 0x5850a9d0, 0xfdd00833, 0x7b89e3bc, 0x853003b0, 0x008a02fe, 0xe503850b, 0xa3bd8672, 0x2e1c078e, 0xc637ff16, + 0x4b7b7401, 0x142a780c, 0x54020cd6, 0xda44dea0, 0xa6007618, 0x403b440a, 0x9f30a177, 0x61681c55, 0x62fec07b, 0xf27fe0f1, 0x12bc401d, 0x91ff1d30, 0x85c75d63, 0xb347dcff, 0xc342cfcc, 0x6e4b5830, + 0xb00934b7, 0x8c3d9244, 0x7686d32f, 0x42855d80, 0xa0716677, 0x01e2197d, 0xdee2c583, 0x85030398, 0x8b67823b, 0x411f71e3, 0x76116bc6, 0xd762c980, 0x431f8c47, 0xcd6142a7, 0x245ed020, 0x13050def, + 0x50c3d924, 0x3fed6881, 0x8e142850, 0x5a071764, 0x2b980f60, 0x8f4a8716, 0x8f17f6b9, 0x16745102, 0x0de378f7, 0x16546594, 0x97a7ebb8, 0x54e873f1, 0x17306c28, 0x1d547ee8, 0x4b010512, 0x8fb8154c, + 0x028500ec, 0x08907d7b, 0x012400f2, 0xb94f4b66, 0x12dc200e, 0xc3e6978e, 0xfac19f31, 0xeff0596d, 0x308ecfe1, 0x0a9d0e7e, 0x01cd9d85, 0x4bdea054, 0xd010508a, 0xd1e6dcce, 0xc26c687f, 0x1c65900e, + 0x4ff6d168, 0x2a1c0248, 0x0075cd7d, 0xf0e1e3e1, 0xcc70deb4, 0x870a7067, 0x203354f5, 0xe15d1fa3, 0x30c3439f, 0xf4083358, 0x15af286c, 0xeb7aa709, 0x89102a59, 0x7f6c05c3, 0x40f6071c, 0x6d00abbe, + 0x968c0248, 0x8075c6fe, 0xa76213c8, 0xff7cb647, 0xc7eab71f, 0x49520088, 0x6c255b8f, 0x787f9aac, 0x854e814f, 0x0714dec2, 0xc9d40094, 0xd6386330, 0x2bf2ad63, 0x07101848, 0x240e36c8, 0x063b6694, + 0x73bfa54b, 0x16b2201d, 0xf56c5938, 0x2bd27ec9, 0x49e0dfcd, 0xc8566715, 0x47a11ffe, 0x53f6ed0d, 0x1d00ffa1, 0x29bd8109, 0x1436780e, 0xda1d3475, 0x0c0a7bff, 0xc19b8815, 0xe0500ec8, 0x31648b14, + 0x5b3d9e56, 0xd73bfd2a, 0x00d2a201, 0x8fab3878, 0xb3d6fffa, 0x556b8871, 0x101f4692, 0xa0f40072, 0x96b2ac0f, 0x2854e814, 0xa80419ac, 0x3a012940, 0x42dea581, 0x968e0558, 0xfd8827cb, 0x71626d0b, + 0x8989db60, 0x35b76903, 0x94f4dab4, 0xe35e7f4a, 0x6cf7c039, 0xb5847d03, 0x5b30fd18, 0x3c9d7a7d, 0x51d47ea3, 0x26dd8d6c, 0xddd1c66c, 0x25860d2a, 0x142a7423, 0xa838a6f6, 0x7496a004, 0x291c0414, + 0x205587f4, 0x00e589b6, 0x10dc0e28, 0x384b4ef8, 0x9a32b4a1, 0x5fc0602a, 0x7a54a9a2, 0x888073c2, 0x16c94213, 0xc1ffe2dd, 0x776cb631, 0x70dd8141, 0x881c58ab, 0x435742d4, 0x18ac2469, 0xb0a153a0, + 0xcf01c537, 0x5072a286, 0x1635ff48, 0xd8150c0a, 0x42c31d88, 0x28dc0e2c, 0x244f1a13, 0xa0341caf, 0x4d0a17cb, 0x073c7ba5, 0xe681e760, 0x4ad0a3c8, 0x7f5904fd, 0xcf00f90b, 0x0428c3aa, 0x9cf64f40, + 0xa5a00380, 0x4254b3b6, 0xf0327f8a, 0x0012a01f, 0xd0183876, 0x70b1a8fd, 0x6cb0041c, 0xbcfd6f3c, 0xf181c760, 0x270e15eb, 0x601f6c17, 0xcc389696, 0xe143a290, 0x74132f08, 0x42079d94, 0xf49e1876, + 0xc47912d9, 0x07628e9e, 0xf8c8aacf, 0xd9f10333, 0x0774c422, 0x0d4a4f0e, 0x2062c55d, 0x091d0cbf, 0x00833581, 0x86550025, 0x7deeb31a, 0x709e0548, 0x38c10077, 0x0a12e710, 0x8da43d4d, 0x3fe131b8, + 0x1b52fd07, 0x1c17d0be, 0x34c33807, 0xccfa4e10, 0x0bda07a0, 0xd1238f04, 0x3ee49a56, 0xed38d3de, 0x8e97e238, 0x1d4fa011, 0x8386212c, 0x899a02aa, 0x060e1d85, 0x5a8a1b3d, 0x432c97a4, 0xda205487, + 0x0e394f95, 0xda071420, 0xa470a87f, 0xde71237f, 0xbe3809c0, 0xbb0038e3, 0x7a59041d, 0x8e9674a4, 0x76d0a6d2, 0xb1c5ed8d, 0x1e3b492e, 0x21768566, 0xc55cc290, 0xac1bd00e, 0x42a7401d, 0x1714dec5, + 0xcf02f3b5, 0xc2c7a286, 0x6f7cac27, 0x90f60550, 0x2846d95d, 0x9b87dc0e, 0x49330847, 0x012446c3, 0xfe6fc826, 0x978071c2, 0x3320fb2c, 0x1de3f6b4, 0x23fbbf7a, 0xf9ce38b4, 0x4904225d, 0x4f8f1e3b, + 0x99571217, 0xed2ff6c4, 0xe8466a09, 0x3348a854, 0xd4637cc8, 0xfdd0265c, 0x0f3c165a, 0x5eb4b0d8, 0x66920550, 0x07140730, 0xb2fb889e, 0xcbb06d38, 0xa4a9f8fa, 0x615e007b, 0xe5be6fc8, 0x28730038, + 0x7d678500, 0x9d3f52a5, 0x453925aa, 0x18844b9f, 0x0d591fc2, 0x6830baeb, 0x0e25e981, 0x581fda50, 0x4012a053, 0x6f0b2c64, 0xc8cc13a7, 0x4740a81a, 0x511cfbca, 0x61010567, 0x3ee1b815, 0x607151cf, + 0xfd0ae37f, 0xb4ddfadd, 0x898d1101, 0x157b00f6, 0xe33e142a, 0x80eb0038, 0x9ab459b8, 0x19d641ed, 0xd91a24f4, 0x112efddf, 0xac7910e4, 0x8763f8f7, 0xeeb64fa8, 0xcfa01cb1, 0x478060bf, 0x52a11842, + 0x24ff01f3, 0xca993d7e, 0x6fe860d9, 0xeb3804a8, 0x11c1b419, 0x68157efb, 0xb0b98335, 0xff09c0e2, 0xb502f8dc, 0x6c258c64, 0x8e737121, 0xc00e39ef, 0xa34f04c8, 0x7ed97975, 0x4f451d3c, 0x4b9f77f6, + 0xe12a4084, 0x6c47cc6c, 0x624fad86, 0x52b54b90, 0x2a74007b, 0xcb387594, 0xfe24c081, 0x97d3a928, 0x0bfac31b, 0x78d43678, 0xdf5ba34f, 0xfe6ab31b, 0x35681541, 0x846cb983, 0xb286c0e3, 0x9f70597f, + 0x480f7b62, 0x71ea0f90, 0x1ce7ce23, 0x2abc6007, 0xa067d908, 0xca675b01, 0x5b0cd3cb, 0xc82f368b, 0xa12ac16b, 0xcb896a54, 0xc0329317, 0xa500ed8c, 0x21f2be63, 0x75942a74, 0x6046db3e, 0xb8a9c61b, + 0xbbb1dc06, 0x4099bc10, 0x59453009, 0x01eed1db, 0x9941b815, 0x5e12b113, 0xa6044fd3, 0xd8a7dd46, 0xec124e5e, 0xb1e2de01, 0x708071c9, 0xc3ae6029, 0xa0b4e896, 0x366cb49b, 0x21f629cb, 0x915bf6b3, + 0x881c4c5d, 0xc77ec8fe, 0x525758fe, 0x54e845d9, 0x5688e328, 0xbd499bd2, 0xdc99a23c, 0x70fb23d2, 0x08405ec3, 0x1ce81500, 0xe2b7e6d5, 0x02a7da58, 0x973066ed, 0x8da0a970, 0x15bc7c64, 0x1bca81ab, + 0x89603d91, 0x3f12ecfa, 0x1e2d4431, 0x80768a7f, 0x06429bf0, 0x54bd18ec, 0xf626ebda, 0xc1bf9671, 0x460edb0a, 0x0a249598, 0x0446cbfc, 0xe152d683, 0x1593c35e, 0x68c00960, 0xe8113906, 0x1137c6ce, + 0x9c2692dd, 0x3ff0df62, 0x9456c04f, 0xdb46bc79, 0x1370ded6, 0x8f3ef4be, 0xfeca2377, 0x3139f085, 0xd02d5be8, 0x90ae62ad, 0xb7a35477, 0xc7b73407, 0xfc5e07ac, 0xb46bf850, 0x416a8403, 0x16761b78, + 0x48272ee8, 0xb43f6e3b, 0x3d6ba37b, 0x5bb92423, 0x14c56d2a, 0x398c700c, 0x003ae0d4, 0xbbb92e4e, 0xb42a740a, 0x44f6d0c8, 0xd6d151f2, 0x9f8e5384, 0x1e8042c7, 0x5e051dd0, 0x677bc91c, 0x010707da, + 0xdb65dcbb, 0xf9f7d15d, 0x43428077, 0xcbc40e30, 0xf09d3d53, 0xc6fff159, 0xb04b3504, 0x6f3aec14, 0x15a15a5e, 0x78b53f45, 0x00ed127c, 0x71e09ea1, 0x19b1f19c, 0xc773f670, 0x844b9eba, 0x34f99b40, + 0x5c74c4fe, 0x84891841, 0x78fecf2d, 0x0b7370c5, 0xaed0a9d0, 0x43d1fdb0, 0x373f42b6, 0x16434edd, 0x10b1c30a, 0x0084f258, 0xed768150, 0x6a7536f2, 0xf996a6e5, 0x2c2dcf66, 0x456b054e, 0x3a79784b, + 0xda7c2540, 0xdbe00969, 0xb3d84a03, 0xbffd9b1b, 0x5ffd413c, 0x31f87e3a, 0x478201da, 0xdfb92204, 0xce31c7b5, 0x1da99388, 0x48ed5670, 0x6f578789, 0x8c7f5cf2, 0xfd9e701e, 0x0f77bd71, 0x537400e5, + 0x942a7400, 0xbac40791, 0x074ed689, 0x578e791c, 0x780d1c54, 0x04a07925, 0x64902818, 0x76ed98dd, 0x152855ce, 0x398336e8, 0xcff46aec, 0x00059207, 0xe12706cb, 0x8713a253, 0x7cf2e378, 0x38395f79, + 0x3feed479, 0x6e5e8273, 0x80768d3e, 0xb7183540, 0xa7cf7801, 0x590f9cbb, 0x9d14af02, 0x9573efea, 0xf8414c5d, 0x7a5015a0, 0xd0014d50, 0xc1f0d0a9, 0x2f81e800, 0x5b518d37, 0x6e156fad, 0x02f30642, + 0x90f1e831, 0xe0be9ad4, 0x15287c95, 0x66d76138, 0xd9b7d03c, 0x0b22c547, 0xede1c2d6, 0xb0fe6301, 0x4603da91, 0x5be5fef1, 0x43b1c840, 0xa35fee1b, 0xc2858852, 0xf00ed1cf, 0x639e642a, 0x39d3f40d, + 0x56b53f69, 0x19d4b6ea, 0xec35f2d5, 0x62bf0e3a, 0x55c06384, 0x4d78039f, 0x50a9d001, 0x38100cdc, 0xf03c8194, 0x0a8ddedd, 0xef25f0ea, 0x818f8e9c, 0x9fb3ef17, 0xe8b7fc50, 0x8155dbad, 0xf5fe8dcd, + 0x5a1872dc, 0xbf5bb405, 0x4ffd25e6, 0x61c58238, 0x563cfede, 0xdabbf380, 0x09e2bee9, 0x7423a9ff, 0x97f0b10a, 0xb7f00768, 0x901ce003, 0x0d4bd0a7, 0xfc0ec5ad, 0x8f0ae334, 0xba6993f5, 0xf5a1737a, + 0x8facfb98, 0x3f71d2bb, 0xc17c20b7, 0xbc3c160e, 0x54e800a6, 0xf4007228, 0x1ed06c18, 0xedde0560, 0x10b8206e, 0x5e6de1d0, 0x40aa05da, 0x37050b97, 0x0105e3b5, 0xa51c0a94, 0xd419e24d, 0xecc7f0db, + 0xfa4bdf05, 0xd0877fd3, 0x862e1f64, 0x585dfbf7, 0x8cbfb85f, 0x4a1ec803, 0xf44fa015, 0xff80388b, 0x3a61b084, 0x34912f44, 0xc7eb21cd, 0xa0976dc7, 0xa8b8bd32, 0x69b7e8ef, 0x17e3e1d2, 0xddc64c0e, + 0x997ae53f, 0x9d0014db, 0xe24e2d0a, 0x992e8307, 0xbc0f58f5, 0xc811a037, 0x2dcbd0c4, 0x64b50934, 0x897828af, 0xab9ed5a6, 0x56a85702, 0x413c1700, 0x1bb53ce8, 0xa49c07ce, 0x733fb37f, 0x1721598c, + 0x37472bc0, 0x795c5ed9, 0x3b019d8b, 0xdfaff39b, 0xbe1d5747, 0xd2007414, 0xe71b4006, 0x7be5b5a0, 0xc0bd378f, 0x3f6ecd13, 0xfd7187ec, 0xc0976638, 0xe28e7af4, 0x400536e2, 0x838b42a7, 0x12a7e824, + 0x252c2769, 0xb42ce3dc, 0xa01d810d, 0xe86e4940, 0x6d92ca40, 0x1d5403cf, 0xc0aae316, 0x5ce3e0c6, 0xeec65db0, 0xbf75180a, 0xa5fd98dc, 0xfd492d28, 0x5d6215b5, 0xb0a92722, 0xdd1f6c90, 0x1fdebfee, + 0x423a7071, 0xe9300e7c, 0x26369199, 0xd5aef852, 0x72112ea8, 0x4dadc6c7, 0x60f7bf60, 0x81864bfb, 0x2701d009, 0x9a70a49e, 0xa153a002, 0x932a7168, 0x55d3cfa0, 0x85fb568d, 0x82179e2b, 0x6e5bcaa2, + 0x2717a097, 0x3e49600e, 0x151ce19f, 0xea4bef38, 0x38ad34b9, 0xbb9f7e62, 0x6a5f3842, 0x3466bc29, 0xc661c0e1, 0xdcc76589, 0x5ade6fc8, 0x7050dc2c, 0xc577cad4, 0xb49d003b, 0x6800dab1, 0xed1f2dac, + 0x4fcec38e, 0x178b16ce, 0x760f4fdc, 0x1e009b39, 0x313fb542, 0x0d164be3, 0x5ca83b17, 0xe60addbf, 0x800a69c7, 0x9022854e, 0x3dda9b7d, 0xd54a3fcd, 0x45ec7ae4, 0x47703eb6, 0x19b6e5ed, 0xce28839a, + 0x8bb6bfe1, 0x043a3e48, 0x09e05577, 0x4d800ed6, 0x6341be8a, 0x47426583, 0x6a5fda23, 0xe2ebf85f, 0x46b1b23e, 0xeec77f67, 0x2fece6d0, 0x7a0ff6fd, 0x71c3bec2, 0x63c3ba00, 0xf801b49c, 0xfcb6436c, + 0xdee7ea11, 0xfa8b8df3, 0x3f081478, 0x5aa4cbe1, 0x74e9ef6c, 0xf39e20e7, 0x47491aa1, 0x8d3334dc, 0x9d0014dd, 0x459c450a, 0x212b10b7, 0x709bb43b, 0x081d82ee, 0x54f784f6, 0x00b2b727, 0x8f1441cd, + 0x10d6ae3b, 0x2ad9dfc8, 0x03b99db0, 0xded01ed8, 0x281dad86, 0x3922fafc, 0xf6221e87, 0x2f9fec57, 0xc24eded9, 0x1983fc5d, 0xa0dc143b, 0x0e78cf5a, 0xe6549ff0, 0x036eca7e, 0x7e5b21a0, 0xc3e49d8b, + 0xab1e79b8, 0x6d603fa8, 0x2f57e802, 0x1543bfb8, 0x64499784, 0x43026def, 0x609018c1, 0x37400537, 0xb76cc461, 0x65adc375, 0x4e2bbdd0, 0xc7ebe820, 0x513f6e71, 0x608dcdce, 0xfe49d201, 0xf3f3e91c, + 0x054b7ddf, 0xc0bad0f6, 0x1be411cf, 0x8a5efd1b, 0xf6fc29d2, 0x268d36b0, 0x1676db92, 0xb37b6e86, 0x7c567058, 0x598e00bc, 0x9df291f2, 0xe00e786f, 0x021c7668, 0x436d06f6, 0x3a56fcb6, 0xd798e777, + 0x5bf7ea2a, 0x1d00c09b, 0xe3357a3d, 0x56e1f469, 0xb6e47eaa, 0x9ab1f982, 0xa153a002, 0x3f722d98, 0x45596d1b, 0x40acfd65, 0xa4b19db0, 0xaf997f62, 0x84ce025b, 0x0f3a0e21, 0xff9d52e8, 0x2054b5c9, + 0xba1cf9cb, 0x79695189, 0x0380f642, 0x42c15fcc, 0x41ffc177, 0x27e9ba3a, 0x4fea3d0e, 0xc03b463a, 0xacf95e1a, 0xfc521edc, 0x4e81412d, 0xb3d100ba, 0x89fbcc7e, 0xbb69de6d, 0x026d6fa8, 0x10a64ead, + 0x16cdd073, 0x6bbdb5a2, 0x70ec58ae, 0x86498416, 0x5348618b, 0x142a7400, 0x63853d63, 0xc54c3876, 0x9c10247c, 0xdd56240f, 0xd6d1363b, 0xd1020d08, 0x1afe48c2, 0xf06af36e, 0x0a96ec3f, 0x010aaff4, + 0x5003881a, 0x03d9043b, 0xab318256, 0x26f6d9f3, 0x5c2783fa, 0xa1204809, 0x70704060, 0x191fa01c, 0xfac715a5, 0x0d001b5e, 0xd02ff2de, 0x096e3beb, 0xf376b4e8, 0x8c438efd, 0x7def1d63, 0x13a382e2, + 0xc65baab1, 0x2365b01f, 0x72160ad5, 0x48f011b3, 0xf918e608, 0x904d36e7, 0x5a87a958, 0x78204906, 0xe144f982, 0x1944f535, 0x3548012c, 0x0b1240b0, 0x0de88133, 0x8606c0ab, 0x5dc0a0fc, 0x90eff40b, + 0x287b6fc2, 0x6a584873, 0xcac2dca7, 0xff50ad0c, 0x6a119c32, 0xb45bb80b, 0xf528ec03, 0x3437e923, 0xe1f15647, 0xead069b0, 0x7dba443c, 0x0096ec5d, 0x378fa8b7, 0x705f2181, 0x1c0d34e7, 0xc585256a, + 0x4fe2b765, 0x21f982b5, 0xa9d0014d, 0xdd08ca50, 0xdb422ca4, 0xec82049b, 0xe2449c40, 0xc4020965, 0xf3e2314a, 0x868e0341, 0xaf82e055, 0xbe661fb0, 0x205beedc, 0x318cefd0, 0x3820ac17, 0xfdf6682a, + 0x2c4856cb, 0x4e3773ec, 0x8d2a5014, 0x383f3ba2, 0xd001b74d, 0xee38ffa0, 0x12257885, 0x8afa4de5, 0xfaf1d6fa, 0x5627ded3, 0x0b1eb8ad, 0xc0fc0180, 0x825bda4f, 0x0fcc15af, 0x227408fa, 0xfad562c0, + 0x9bc01f07, 0x14fd2340, 0x5b03904c, 0x59388158, 0x0012e17f, 0xc86184b7, 0xa5fe60e1, 0x50c0ab1b, 0xe048320a, 0x7e231f59, 0x6cfec634, 0x1c6fdbe0, 0x47fd05f0, 0xadf0a288, 0xf8071c41, 0xd1f60a33, + 0x1e3e3c33, 0x859274f1, 0x09fe8879, 0xa2e9da89, 0xa8df093e, 0x1deedda5, 0x4439bf46, 0x3b61c184, 0xe40d9c12, 0x88a62999, 0xa0e0499b, 0x4837377d, 0x9bbfa7e7, 0x88111caa, 0x56788523, 0x6c5002c2, + 0x37610f25, 0x69ef90b9, 0x7cdab7ee, 0x8f1d1142, 0x534e5623, 0x843893e0, 0x81d77bf0, 0x1df2afd0, 0x3a4cb4a0, 0xdb98bab1, 0xf8cec933, 0x1f5c7762, 0x877acb40, 0x09bc71fb, 0xba4b2cf8, 0xc7657046, + 0x74f624da, 0xd7d1ba59, 0x3807e60a, 0xab614b95, 0xbda0b6fc, 0x8b3283bb, 0x5a046162, 0xe520b687, 0x42e45da0, 0x5bd7633e, 0x63013a75, 0xfc844c52, 0x6e620228, 0x50e1779f, 0xe54fffd0, 0xe33fc038, + 0xf1564ffb, 0x8e69a62d, 0x1613fe87, 0x796ec3f9, 0x877afc90, 0x1723dc5f, 0xf0ebee59, 0x112cc174, 0x30568105, 0x0004523f, 0x6a31d7a6, 0x5097ecb9, 0x609ca6f8, 0x0926c1de, 0xa0c24829, 0x7053f673, + 0xed0c6eef, 0x25e0f10a, 0xd16451ab, 0x5f856b20, 0x1507cedc, 0xf418a727, 0x6ffee42f, 0x5ccf6fa1, 0x57a44a00, 0xe01d17de, 0x376040fa, 0xb3e43d5f, 0xa0eeae2c, 0xf3bf7535, 0x091251c3, 0x18f944b6, + 0x75889c06, 0x1a1fb2e8, 0xb6f814fc, 0x1da8a5c1, 0x004247a0, 0x6fbc4360, 0x5b01b821, 0x3190b34f, 0x67bcb029, 0x1310964a, 0x44eda5e1, 0x38dddfbb, 0x01cb60e5, 0x117d734a, 0xe7af0cf2, 0x5c2e16be, + 0x150c181f, 0x92cc7df5, 0x9790cff4, 0x6091c019, 0x8fcc15b0, 0xc5902c8c, 0x8daec761, 0x4fa4be8d, 0x5419994f, 0x59ca7535, 0x78ad09fe, 0x3d0f9de3, 0x889f2c90, 0xd7744567, 0x4049f068, 0xf8071c26, + 0x1d218e77, 0x7ef8b5e3, 0x2d55bd60, 0x58c7376a, 0x5c5495dd, 0x50c12380, 0x068f982b, 0xa2706679, 0x47fe5dad, 0x0c092d0e, 0x2740cc1b, 0x1e4cfc11, 0x60dc6921, 0xf87f57e7, 0x6d760247, 0x8880d214, + 0xba56319e, 0x12d38680, 0x0e716ff6, 0x09754230, 0x1ebd605b, 0xec979bbd, 0x5657d9c7, 0x026b249a, 0xfbe00ca3, 0x6c1872a3, 0xfa84df66, 0x05617086, 0x621c8c3a, 0x36a211ff, 0x29f22b02, 0x0313eaf6, + 0x85a70be3, 0xeb1a14d3, 0x5d5dd300, 0xbbe1c301, 0xb0fec7d6, 0xc30dd605, 0x47210f3e, 0x8d76f0af, 0x1091d03d, 0xbe70c98a, 0x88c3499f, 0x0c3a8bc4, 0x6e8f429c, 0x489e4568, 0x854803be, 0xaffe16d3, + 0x96800e71, 0xc7ffc0e7, 0xe67e9349, 0x8aba1d27, 0xe00ffe83, 0x0ad83048, 0x0cde03e6, 0x0ece3142, 0x1d8cfdf7, 0xf8fcc0cc, 0xc605a3e2, 0x59ed2b83, 0x3067074e, 0x0ef1efe4, 0x2b6f6410, 0xacc7376f, + 0xe525056e, 0x2c15a32c, 0xd225dff0, 0xe0b319d1, 0xddc9f7d6, 0x0acc7dfb, 0xc23940ae, 0x8ffb0d19, 0x9a500ee4, 0xf3968dee, 0xd38ff411, 0xe03084f5, 0x8300d07e, 0xaba2d19d, 0x9b206fa7, 0xf5a1df87, + 0x3f98c26c, 0xa1c33873, 0x8070a5bf, 0x7d703434, 0x58c48f66, 0xa47261cc, 0xafc7a973, 0xaf7576c6, 0xcb4b0e76, 0xd818f139, 0xeabc51ea, 0xc3c6f0d3, 0x039396ff, 0x0f9f01f0, 0xe4d7491a, 0xd991c1c0, + 0x91d9a9a9, 0x0cc981e1, 0xa19a2cdc, 0xcb7db3fd, 0xd3ab33ab, 0xde0397ea, 0xa83f1101, 0x56413db6, 0xd44b5632, 0x11de024b, 0xb6ab9f31, 0x3f42413d, 0xa88cb6a8, 0x90ff3f36, 0x6daaa7a8, 0x0798918f, + 0x55848fd4, 0x1de02cc0, 0xb54f7713, 0xf3e031f1, 0x30663541, 0x3a500a79, 0x9f2283bc, 0x463e36a8, 0xae8e3f46, 0x27dbc6f4, 0xc5477873, 0x3e36a9ae, 0xa83f4646, 0x018fa8ae, 0x3b4587f8, 0x80a560f5, + 0x65f43287, 0x31f1b558, 0x40b06a9c, 0xe47b383d, 0xc7e98435, 0xb279bc4c, 0x140c5387, 0x8d6506aa, 0x2d60869c, 0x0240d219, 0xe9416b72, 0xa992018a, 0xa5b00962, 0x7598f6da, 0x8b40294e, 0x9e8cb05c, + 0xa9294d6c, 0x97863e36, 0xe3b1de09, 0x2fe6d56b, 0xa0d35f01, 0xdb55fb33, 0xd715f09e, 0x02a7d401, 0xac0258ab, 0x813db6aa, 0xb1dc0897, 0xfb6abee3, 0xe637a497, 0x16974369, 0x2df0b012, 0xfed601d7, + 0x7201daac, 0xa12bd029, 0x2de9b553, 0xf52079b8, 0x6be02099, 0xb046741a, 0xb86b3bad, 0x89f52079, 0xe111f000, 0xdaa032da, 0x9e9c36f2, 0x44ea8c60, 0x0e6cfc00, 0x6d56995d, 0x1a7e0b79, 0x7f8ec760, + 0x0c807628, 0xd2d573fb, 0xce459eca, 0xf6f83f9d, 0x0413dd57, 0x5f59a33d, 0xbcb6aace, 0x071887cd, 0xd212dc50, 0x994edaab, 0x929e3221, 0x5028fc07, 0x6d281c79, 0x8e375c30, 0x1e17d2e9, 0x2eaa0513, + 0x04ad5708, 0x786d5658, 0xb068ce07, 0x30e98a45, 0x0a9cc879, 0x910e8ad5, 0x81725de3, 0xa1661733, 0x75281eb4, 0xa627542a, 0xe1dddb54, 0xd5fd9c5d, 0xa7720186, 0xf2223542, 0xe1bcd85c, 0x2858050d, + 0x9ec9072d, 0x4985d50a, 0x6c60245d, 0x80c28010, 0xff67567f, 0xb542a62c, 0xc8091b40, 0x21cc213b, 0xec9094f6, 0x542a6ec8, 0x0207ea31, 0x012a621d, 0xc446bc98, 0x54eb5419, 0xb36a88e8, 0x54c66cbb, + 0xbb0a3002, 0x0a9bf4c2, 0x91955aed, 0x0c1ee099, 0x7efc2b9d, 0xc9750b30, 0x42a6fd60, 0x120bba07, 0x1875549a, 0xcde1b408, 0x4ba83a05, 0x15376b06, 0x372d87da, 0x1d4b760a, 0x626d0206, 0x6518c113, + 0xa9b3502a, 0xe57b71d0, 0x27a6819e, 0x542a8e23, 0x54068081, 0x92f502a8, 0x02dd8700, 0x0d6c0cfe, 0xe2d2a838, 0xa034447e, 0x4ea05cc2, 0xfd2da153, 0x051b7dd4, 0x062d337d, 0xf3e22d02, 0x87551880, + 0x15346804, 0xafc87ada, 0x67001adb, 0x1031ead7, 0x1a3bc168, 0x67514280, 0x21233eb0, 0x9b894367, 0x93dbf4fa, 0x36810316, 0x0ec11d31, 0xbac22a8a, 0xb30e854c, 0x0e9a779a, 0x8973fda7, 0x8ecf060f, + 0xb05ad8f5, 0xe2c3a285, 0x6d0a98f4, 0xccdaca89, 0x7a7efba4, 0xf05a040c, 0x51a3880e, 0x62d20a93, 0x2665b42a, 0x9f576eba, 0x8f4d5faa, 0x910b4081, 0x4d461034, 0x09035041, 0x5f97b030, 0xae499db6, + 0x08193505, 0x052810b4, 0x0111285a, 0x7850a9c0, 0x7f48d933, 0xa9bed56c, 0x404a6937, 0x0b408193, 0x68a00941, 0x1538043a, 0x26eb0bda, 0x1313ed6a, 0xc95b756b, 0x8193405c, 0x4cdc4240, 0x110a8788, + 0x1d0a9d00, 0xfe97d5dd, 0x8aaff797, 0x5a9cedcf, 0xe811b04e, 0x10481032, 0x04480095, 0x4004c828, 0xa14f42a7, 0x22dd3a2d, 0x309bde32, 0x7fd5db52, 0xa8353456, 0xcd140493, 0x88146002, 0x2854e000, + 0xa9f85379, 0x78fac1e4, 0x9bfca3ba, 0xd6453b46, 0x02065d01, 0x0059a209, 0x10a6828c, 0xfd85e360, 0x4486c082, 0xc703454d, 0xe8722f21, 0xe71b3d5e, 0xffe38704, 0x15887e4a, 0x2ff22c02, 0x42a74007, + 0x7bb6b5dd, 0x33612c4b, 0x42467879, 0xe8fd5ea7, 0x744b54f2, 0x40cba200, 0x10b04120, 0x80fb9160, 0x942a7418, 0xe69bc6da, 0xa062f93b, 0x5eef60eb, 0x4d9a6d99, 0x9d73a3dd, 0xe1c2c723, 0x81033681, + 0xa109ee04, 0x0f9f7241, 0x76854e02, 0xdb756e05, 0x2300e76a, 0xee1c1b5e, 0xce6d1e5c, 0xda472cca, 0x9757467a, 0x46a73ab7, 0x265a0786, 0x35070707, 0xe2c21339, 0x802f509d, 0x1dbce3c3, 0x58012800, + 0xeabb174d, 0x2ead8cf7, 0x76756ef7, 0x9a1ef56e, 0xa9ed199b, 0x972b29d7, 0xb1253f3b, 0xe0d9ee7f, 0xef22607e, 0xabdbea90, 0x6079c23f, 0x41039c8b, 0x36a854e8, 0x92da77b3, 0xe4c40824, 0x9d0617dc, + 0xde29d50a, 0x412493d6, 0xbe5ce620, 0x60c7e1cd, 0xfaa63ff6, 0x37cfeaf6, 0xdf201d09, 0x07a10303, 0x73556843, 0x5bee13d3, 0x9ae45802, 0x854e840c, 0xd772956a, 0x30999112, 0x01eeb93f, 0x8d50a9d0, + 0x2534eefa, 0x22d01a51, 0x38003dcf, 0x034c1212, 0xde244219, 0x0d6d7201, 0x8e854e85, 0xdabdbea8, 0x4a0eda23, 0x3dbf24f3, 0xaa153a00, 0xba1c01cf, 0xc8076292, 0x4e800f73, 0xdfc7f685, 0xc5271a81, + 0x1c67900e, 0x350a9d00, 0x9218a069, 0xf22c8166, 0x5380038b, 0xefaa2da1, 0xce24f6af, 0x55e45902, 0x854e800f, 0x0c50349a, 0x0e00eb49, 0x5203d579, 0x68d9dd8f, 0x27ad7f34, 0x47c44771, 0x184d5791, + 0xd26a153a, 0xac243140, 0x74e47b04, 0x2a700856, 0x6281a4d4, 0x84173b10, 0x22033e45, 0x11d0a9d0, 0x775837d5, 0x424207c4, 0x145e72e4, 0xa4d42a74, 0xd4486281, 0x9727ea0d, 0x5df43074, 0xc40d26a1, + 0xd81a4d27, 0x00549721, 0x26a15df4, 0x6527c40d, 0x8722c012, 0xa74208d7, 0x881a4d42, 0x24ca66cf, 0xed0e4580, 0x50a9d0e1, 0x93e20693, 0x443c1dac, 0xfa1032f6, 0x069350ae, 0x809003e2, 0x422bec98, + 0x08f82380, 0xb0efaadd, 0x05ef24de, 0xeb2e73f3, 0x2a74206c, 0x81a4c874, 0x0f1d08b8, 0x6ceb23cd, 0x742a7420, 0xd61df556, 0x8113649b, 0x897eb22c, 0xa15df414, 0x25c40d26, 0xb15125fe, 0x86145c64, + 0xa4c391be, 0xa7ac7881, 0xf3f2056a, 0x43fb5334, 0x1a4d42a7, 0xb85bcb88, 0x048e33fd, 0x5aa153a1, 0x1fa5c31d, 0x22d018c0, 0xe810bed3, 0xea9f6854, 0xe935ac5b, 0xac83017a, 0x0c5e7965, 0xa4d42a70, + 0x3824b881, 0x86478e18, 0xebf04135, 0x881a4dc2, 0x0c707bc3, 0xbb2e7168, 0x81972373, 0x69341ff6, 0x5ba90e20, 0x776482c1, 0x2a743076, 0x3881a4d4, 0x016921fc, 0x0c1f32c8, 0x6931091d, 0x46a00e20, + 0x9d593f00, 0x577e071a, 0x312756a8, 0x6973c66a, 0x4b76400b, 0xa15df800, 0x5bf07d35, 0x8017120c, 0xe80096cc, 0x0349a854, 0x01732345, 0x80096cc8, 0x0693004a, 0x02ea468a, 0x0012d590, 0x49a8577d, + 0x77224503, 0x0968c801, 0xd42bbf00, 0x012281a4, 0xc9048237, 0x9d001722, 0x7d541d0a, 0x5e45f597, 0x8b21c00e, 0x2a742074, 0x2281a4d4, 0xf4049691, 0x0022a0c8, 0x9ce8577d, 0x2dacdbea, 0x3400aab2, + 0xe0828bf2, 0x349a8577, 0xca921450, 0xf7a47e80, 0x42a74005, 0x281a4c3b, 0x007d3902, 0xb764d641, 0x42a74106, 0xb32f7a75, 0x0469485e, 0x4e7b230a, 0xba153a0c, 0xeb3efaa5, 0x2c1a700a, 0xc20db91a, + 0x9350a9d0, 0x53608a06, 0x9b302b42, 0xc5a752fb, 0xc5a153a1, 0x5a77d566, 0x02cc2453, 0x21352144, 0x350a9d0c, 0xb2362069, 0x5234c093, 0xa9d041b3, 0x77d529d0, 0xc832535a, 0x0c487901, 0xa153a105, + 0xe6c40d26, 0x00170cb3, 0x3bca0a14, 0x153a1a41, 0x4c40d26a, 0xd2cc7fd6, 0x8e4f32fe, 0x9a854e83, 0xc0131034, 0x48627099, 0x4e87171b, 0x10349a85, 0x13a0778b, 0xa5904481, 0xa153c103, 0x22c40d26, + 0x21680553, 0xa7420749, 0xaa638b42, 0x648eb5ef, 0xe46d00ab, 0x54e840e8, 0x0be65168, 0xec85abe0, 0xf7348072, 0x418774a5, 0x55c742a7, 0x491d6cdf, 0xe4a06af5, 0x010d68c8, 0x349a854f, 0xda2c9850, + 0xa8c85840, 0x42a7430b, 0xcc281a4d, 0xe055467a, 0x45e0f730, 0xa854e821, 0xc9850349, 0x041408b0, 0x1d0c22de, 0xa0693109, 0x006d7910, 0x0026f018, 0x69350a9e, 0x6df920a0, 0x67681800, 0xb42a7800, + 0xd6fdf557, 0x00371c8e, 0x8012300c, 0xf716854e, 0xbadfbeaa, 0x1b8e55f1, 0x16580600, 0x93004a84, 0x99b00a06, 0xcc301171, 0x083a5013, 0xd26a153a, 0xcf240140, 0xa9008b02, 0x42a78009, 0xe1bea82f, + 0x0d4b919a, 0x75e00820, 0xd0a9d032, 0x3beab4e2, 0x72ef17ae, 0x390401a9, 0x0c567e97, 0x6c5a153a, 0xf5cb7d50, 0xb0499322, 0x0427d278, 0x26a153a1, 0xf323e40d, 0xd228a02e, 0xa9e082c6, 0xb7d561d0, + 0x8ef22b5c, 0x52d63d00, 0xa7410a8e, 0x881a4d42, 0xd008ff26, 0x187f6523, 0x38b42a74, 0xeba6faaa, 0x605d0e44, 0x254e3cd1, 0x805b8603, 0xe9bea9d4, 0x004ca11a, 0xad7aa458, 0xe239b35c, 0x04ea1a59, + 0xaa5ac580, 0x519b406c, 0x935092f1, 0x9749a001, 0x201e300d, 0x19457587, 0x3d949a00, 0xdf54a7a2, 0xa720aabb, 0x293e502e, 0xea662b5f, 0x2ade7079, 0x29360016, 0x0a4641f3, 0x002d5142, 0x4109d21d, + 0xa8a00423, 0x690e8017, 0xccdb045b, 0xac011f5b, 0xeedaacff, 0x16d24f1e, 0x4c148d06, 0x600cd28f, 0xfb697b90, 0x108dea83, 0x4dce4948, 0x7ea471a0, 0x8291b0c3, 0x0024d0e9, 0x139548f0, 0x982918c6, + 0x603d2506, 0x211fd27c, 0x6260a467, 0x20fcc8fe, 0x0da4e490, 0xb8a61106, 0x027d1097, 0xa8c01a40, 0x89829180, 0x0a75ccd8, 0xe9739c4c, 0x8dbb0627, 0x43a38807, 0xea4d8805, 0x82918074, 0x012ad049, + 0xe03ee7e0, 0x05233108, 0x04305105, 0xfce40e24, 0x85052320, 0x1c02a2d0, 0x6094ea4d, 0x8484e4c9, 0x18012cd0, 0x03c031e6, 0xe58c148c, 0x4012fd17, 0x0a35d241, 0x1829185b, 0x1fd80543, 0x0a4601e6, + 0x12a9f972, 0xc763bfec, 0x18078853, 0x854d1829, 0x01e81fd8, 0x51460a46, 0xee07f631, 0x0846dd02, 0xfb20a930, 0x230162c3, 0x84549905, 0x7900f3fe, 0x61829180, 0xb0fecc2a, 0x1a19908c, 0xa56df108, + 0x17561fd9, 0x80305230, 0x365ff9e6, 0x9bef41f7, 0x63c04237, 0xb6d50bfd, 0xd013c74c, 0x03c6c289, 0xae35d61c, 0x0739f2ff, 0x0cd44e3b, 0x3536100d, 0x0a49001a, 0x63104fa0, 0xb9e220a4, 0xe08023c2, + 0x375ec1ac, 0xe160a46d, 0x9ffd96bd, 0x2f3d4809, 0x2179a840, 0xfd8699f0, 0x0a7909df, 0xf8d4084a, 0xa54568fc, 0x07b8a37f, 0x2d68d77b, 0xaaefc14b, 0x70d0fec1, 0x068776b0, 0xfc362b36, 0x160e720b, + 0x14a8d40c, 0xf8e9ae7c, 0x60d61a47, 0x49a9986f, 0xf2055829, 0x0526068f, 0x583cb06b, 0x068ff215, 0xb5a81956, 0xad75b14e, 0x01d23fa7, 0x25350214, 0x70579f05, 0xb59a37f6, 0x1b2f41af, 0x582921ac, + 0xc7bfdb65, 0xa0465063, 0x0560a466, 0xf2887f36, 0xac1e5604, 0xa9b82909, 0x0cb7f0ed, 0x0d60f180, 0x2acfc148, 0x0713f8bd, 0x76a81b6c, 0xc55eb829, 0x2c03bfcb, 0xf9eea81a, 0xff54ead1, 0x873ed641, + 0x2cd50344, 0xab543f05, 0x1f720ffa, 0x55ab05a4, 0x68566e0a, 0xd61a67eb, 0xa3f3307e, 0xfd5eaa41, 0xc907b9f9, 0x4e61570c, 0x4a4ab368, 0xfdace2ff, 0x5408b003, 0x67e8fcdd, 0x99f9dd15, 0x3e807b92, + 0x8292ea91, 0x5bf8f7b5, 0x15409480, 0xdb1ac149, 0xe12069fd, 0xc148b540, 0xf36a2fcd, 0xfb58b7f1, 0x48a37d3c, 0xb7c14875, 0x47fb12b5, 0xd4b7e4f1, 0x4205501e, 0xaeaa8fe0, 0x38f208fc, 0x74ac18b5, + 0xf155a80f, 0x0fb00417, 0xc0d0f454, 0x7f15dadb, 0x1ea49e41, 0xf9dcac21, 0x5135f7d1, 0x5ee611f8, 0x42a078da, 0x6fbbe0a5, 0xe01feacc, 0x70e4ca69, 0xcd810a25, 0xfb5d6b6f, 0x052b48b3, 0xd47e6f2a, + 0x9c11fe6c, 0x5e16a1fb, 0x8aa1ff45, 0xf3a4be46, 0xa8895d24, 0x67e0a482, 0x79f1fb46, 0x2e34b7f2, 0xf0522950, 0xf68c5ffd, 0x1a7ee58b, 0x2908a817, 0xbf3195f8, 0x405ca918, 0xcc68297b, 0x1b34809f, + 0xd052de81, 0x4f213f98, 0x1a044792, 0x307c0d0f, 0xe7392fd2, 0x433a4f3e, 0x5c14a9a2, 0x1b16a9ff, 0xf6b064be, 0x58826134, 0xeef82947, 0x01f6935b, 0x64b7ef70, 0x29374062, 0xfba6bef8, 0xe4f0a47d, + 0x813b44eb, 0xeb629d4e, 0xe6367f6f, 0xd3dac097, 0x00f027bf, 0xf3e0a46d, 0x2fdaccef, 0x883ffb8d, 0xcc5a032f, 0x307fae8f, 0xd65c9f61, 0x01ab0b1e, 0xfdf052f5, 0x9bdca637, 0x173ee701, 0x4a940a0d, + 0x98bf77c1, 0xdc665f72, 0x6dac5aff, 0xdc149944, 0xfd2cc9fc, 0x07ef7319, 0x92501f11, 0xfb7cda13, 0x0e7eb1a5, 0x40f889ac, 0x58d052ee, 0xc7ee573f, 0xa55c81ea, 0xcc5ff3e0, 0xe73b9fca, 0xafc6fe9e, + 0x0524e517, 0xeefabfd7, 0x357d6353, 0xfafbddac, 0x61c1395f, 0xf9f0520e, 0x889a5f4f, 0x1ee72d4f, 0xb67223ff, 0xf8295b2c, 0xa637c3ee, 0xe707a7cc, 0x96c0ff1e, 0x251d9904, 0x37edfcf2, 0x5f759a3f, + 0xfe3dce2b, 0xf9c23ffc, 0xe0a40ce2, 0x7cbf57fa, 0x9afcb269, 0xd7e9e4f2, 0xd9902f41, 0xd5feb629, 0xc118df4f, 0x1e4f3da7, 0x7fb7fe7f, 0x9ca1b4f3, 0x1fe781a1, 0xd8c2fdbe, 0xbb5882be, 0xefe0dc8f, + 0x829702ff, 0xe9b1ef9b, 0x50afd48d, 0xf83f21ce, 0x9eafb7e1, 0xfc3627af, 0x7e1ff7bb, 0x9fcbeef9, 0x7d4f313f, 0xbfa7f055, 0x2f97fa7e, 0x97f6f9bf, 0xf57d9fb7, 0xb64dbbc7, 0xfbbe6c3b, 0x1f67fde3, + 0xbbf6fa7e, 0xa9f2fe2f, 0xf3757bb1, 0xf27ebfa7, 0x7e9f8fc9, 0x08cfe9fa, 0xfe3f3ff4, 0x8d5fc9f8, 0x83060dc5, 0x183060c1, 0xc183060c, 0x0c183060, 0x60c18306, 0xff1f5430, 0x3cd2fa0f, 0x05b0d517, + 0x000000b2, 0x4e454900, 0x6042ae44, 0x00000082, +}; + +const uint32_t uprof_512_len = 12813; + +#endif //MICROPROFILE_EMBED_HTML diff --git a/Windows_Libs/Dev/Render/microprofile/stb/stb_sprintf.h b/Windows_Libs/Dev/Render/microprofile/stb/stb_sprintf.h new file mode 100644 index 0000000..d8011fa --- /dev/null +++ b/Windows_Libs/Dev/Render/microprofile/stb/stb_sprintf.h @@ -0,0 +1,1906 @@ +// stb_sprintf - v1.10 - public domain snprintf() implementation +// originally by Jeff Roberts / RAD Game Tools, 2015/10/20 +// http://github.com/nothings/stb +// +// allowed types: sc uidBboXx p AaGgEef n +// lengths : hh h ll j z t I64 I32 I +// +// Contributors: +// Fabian "ryg" Giesen (reformatting) +// github:aganm (attribute format) +// +// Contributors (bugfixes): +// github:d26435 +// github:trex78 +// github:account-login +// Jari Komppa (SI suffixes) +// Rohit Nirmal +// Marcin Wojdyr +// Leonard Ritter +// Stefano Zanotti +// Adam Allison +// Arvid Gerstmann +// Markus Kolb +// +// LICENSE: +// +// See end of file for license information. + +#ifndef STB_SPRINTF_H_INCLUDE +#define STB_SPRINTF_H_INCLUDE + +/* +Single file sprintf replacement. + +Originally written by Jeff Roberts at RAD Game Tools - 2015/10/20. +Hereby placed in public domain. + +This is a full sprintf replacement that supports everything that +the C runtime sprintfs support, including float/double, 64-bit integers, +hex floats, field parameters (%*.*d stuff), length reads backs, etc. + +Why would you need this if sprintf already exists? Well, first off, +it's *much* faster (see below). It's also much smaller than the CRT +versions code-space-wise. We've also added some simple improvements +that are super handy (commas in thousands, callbacks at buffer full, +for example). Finally, the format strings for MSVC and GCC differ +for 64-bit integers (among other small things), so this lets you use +the same format strings in cross platform code. + +It uses the standard single file trick of being both the header file +and the source itself. If you just include it normally, you just get +the header file function definitions. To get the code, you include +it from a C or C++ file and define STB_SPRINTF_IMPLEMENTATION first. + +It only uses va_args macros from the C runtime to do it's work. It +does cast doubles to S64s and shifts and divides U64s, which does +drag in CRT code on most platforms. + +It compiles to roughly 8K with float support, and 4K without. +As a comparison, when using MSVC static libs, calling sprintf drags +in 16K. + +API: +==== +int stbsp_sprintf( char * buf, char const * fmt, ... ) +int stbsp_snprintf( char * buf, int count, char const * fmt, ... ) + Convert an arg list into a buffer. stbsp_snprintf always returns + a zero-terminated string (unlike regular snprintf). + +int stbsp_vsprintf( char * buf, char const * fmt, va_list va ) +int stbsp_vsnprintf( char * buf, int count, char const * fmt, va_list va ) + Convert a va_list arg list into a buffer. stbsp_vsnprintf always returns + a zero-terminated string (unlike regular snprintf). + +int stbsp_vsprintfcb( STBSP_SPRINTFCB * callback, void * user, char * buf, char const * fmt, va_list va ) + typedef char * STBSP_SPRINTFCB( char const * buf, void * user, int len ); + Convert into a buffer, calling back every STB_SPRINTF_MIN chars. + Your callback can then copy the chars out, print them or whatever. + This function is actually the workhorse for everything else. + The buffer you pass in must hold at least STB_SPRINTF_MIN characters. + // you return the next buffer to use or 0 to stop converting + +void stbsp_set_separators( char comma, char period ) + Set the comma and period characters to use. + +FLOATS/DOUBLES: +=============== +This code uses a internal float->ascii conversion method that uses +doubles with error correction (double-doubles, for ~105 bits of +precision). This conversion is round-trip perfect - that is, an atof +of the values output here will give you the bit-exact double back. + +One difference is that our insignificant digits will be different than +with MSVC or GCC (but they don't match each other either). We also +don't attempt to find the minimum length matching float (pre-MSVC15 +doesn't either). + +If you don't need float or doubles at all, define STB_SPRINTF_NOFLOAT +and you'll save 4K of code space. + +64-BIT INTS: +============ +This library also supports 64-bit integers and you can use MSVC style or +GCC style indicators (%I64d or %lld). It supports the C99 specifiers +for size_t and ptr_diff_t (%jd %zd) as well. + +EXTRAS: +======= +Like some GCCs, for integers and floats, you can use a ' (single quote) +specifier and commas will be inserted on the thousands: "%'d" on 12345 +would print 12,345. + +For integers and floats, you can use a "$" specifier and the number +will be converted to float and then divided to get kilo, mega, giga or +tera and then printed, so "%$d" 1000 is "1.0 k", "%$.2d" 2536000 is +"2.53 M", etc. For byte values, use two $:s, like "%$$d" to turn +2536000 to "2.42 Mi". If you prefer JEDEC suffixes to SI ones, use three +$:s: "%$$$d" -> "2.42 M". To remove the space between the number and the +suffix, add "_" specifier: "%_$d" -> "2.53M". + +In addition to octal and hexadecimal conversions, you can print +integers in binary: "%b" for 256 would print 100. + +PERFORMANCE vs MSVC 2008 32-/64-bit (GCC is even slower than MSVC): +=================================================================== +"%d" across all 32-bit ints (4.8x/4.0x faster than 32-/64-bit MSVC) +"%24d" across all 32-bit ints (4.5x/4.2x faster) +"%x" across all 32-bit ints (4.5x/3.8x faster) +"%08x" across all 32-bit ints (4.3x/3.8x faster) +"%f" across e-10 to e+10 floats (7.3x/6.0x faster) +"%e" across e-10 to e+10 floats (8.1x/6.0x faster) +"%g" across e-10 to e+10 floats (10.0x/7.1x faster) +"%f" for values near e-300 (7.9x/6.5x faster) +"%f" for values near e+300 (10.0x/9.1x faster) +"%e" for values near e-300 (10.1x/7.0x faster) +"%e" for values near e+300 (9.2x/6.0x faster) +"%.320f" for values near e-300 (12.6x/11.2x faster) +"%a" for random values (8.6x/4.3x faster) +"%I64d" for 64-bits with 32-bit values (4.8x/3.4x faster) +"%I64d" for 64-bits > 32-bit values (4.9x/5.5x faster) +"%s%s%s" for 64 char strings (7.1x/7.3x faster) +"...512 char string..." ( 35.0x/32.5x faster!) +*/ + +#if defined(__clang__) + #if defined(__has_feature) && defined(__has_attribute) + #if __has_feature(address_sanitizer) + #if __has_attribute(__no_sanitize__) + #define STBSP__ASAN __attribute__((__no_sanitize__("address"))) + #elif __has_attribute(__no_sanitize_address__) + #define STBSP__ASAN __attribute__((__no_sanitize_address__)) + #elif __has_attribute(__no_address_safety_analysis__) + #define STBSP__ASAN __attribute__((__no_address_safety_analysis__)) + #endif + #endif + #endif +#elif defined(__GNUC__) && (__GNUC__ >= 5 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 8)) + #if defined(__SANITIZE_ADDRESS__) && __SANITIZE_ADDRESS__ + #define STBSP__ASAN __attribute__((__no_sanitize_address__)) + #endif +#endif + +#ifndef STBSP__ASAN +#define STBSP__ASAN +#endif + +#ifdef STB_SPRINTF_STATIC +#define STBSP__PUBLICDEC static +#define STBSP__PUBLICDEF static STBSP__ASAN +#else +#ifdef __cplusplus +#define STBSP__PUBLICDEC extern "C" +#define STBSP__PUBLICDEF extern "C" STBSP__ASAN +#else +#define STBSP__PUBLICDEC extern +#define STBSP__PUBLICDEF STBSP__ASAN +#endif +#endif + +#if defined(__has_attribute) + #if __has_attribute(format) + #define STBSP__ATTRIBUTE_FORMAT(fmt,va) __attribute__((format(printf,fmt,va))) + #endif +#endif + +#ifndef STBSP__ATTRIBUTE_FORMAT +#define STBSP__ATTRIBUTE_FORMAT(fmt,va) +#endif + +#ifdef _MSC_VER +#define STBSP__NOTUSED(v) (void)(v) +#else +#define STBSP__NOTUSED(v) (void)sizeof(v) +#endif + +#include // for va_arg(), va_list() +#include // size_t, ptrdiff_t + +#ifndef STB_SPRINTF_MIN +#define STB_SPRINTF_MIN 512 // how many characters per callback +#endif +typedef char *STBSP_SPRINTFCB(const char *buf, void *user, int len); + +#ifndef STB_SPRINTF_DECORATE +#define STB_SPRINTF_DECORATE(name) stbsp_##name // define this before including if you want to change the names +#endif + +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsnprintf)(char *buf, int count, char const *fmt, va_list va); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(2,3); +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) STBSP__ATTRIBUTE_FORMAT(3,4); + +STBSP__PUBLICDEC int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va); +STBSP__PUBLICDEC void STB_SPRINTF_DECORATE(set_separators)(char comma, char period); + +#endif // STB_SPRINTF_H_INCLUDE + +#ifdef STB_SPRINTF_IMPLEMENTATION + +#define stbsp__uint32 unsigned int +#define stbsp__int32 signed int + +#ifdef _MSC_VER +#define stbsp__uint64 unsigned __int64 +#define stbsp__int64 signed __int64 +#else +#define stbsp__uint64 unsigned long long +#define stbsp__int64 signed long long +#endif +#define stbsp__uint16 unsigned short + +#ifndef stbsp__uintptr +#if defined(__ppc64__) || defined(__powerpc64__) || defined(__aarch64__) || defined(_M_X64) || defined(__x86_64__) || defined(__x86_64) || defined(__s390x__) +#define stbsp__uintptr stbsp__uint64 +#else +#define stbsp__uintptr stbsp__uint32 +#endif +#endif + +#ifndef STB_SPRINTF_MSVC_MODE // used for MSVC2013 and earlier (MSVC2015 matches GCC) +#if defined(_MSC_VER) && (_MSC_VER < 1900) +#define STB_SPRINTF_MSVC_MODE +#endif +#endif + +#ifdef STB_SPRINTF_NOUNALIGNED // define this before inclusion to force stbsp_sprintf to always use aligned accesses +#define STBSP__UNALIGNED(code) +#else +#define STBSP__UNALIGNED(code) code +#endif + +#ifndef STB_SPRINTF_NOFLOAT +// internal float utility functions +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits); +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value); +#define STBSP__SPECIAL 0x7000 +#endif + +static char stbsp__period = '.'; +static char stbsp__comma = ','; +static struct +{ + short temp; // force next field to be 2-byte aligned + char pair[201]; +} stbsp__digitpair = +{ + 0, + "00010203040506070809101112131415161718192021222324" + "25262728293031323334353637383940414243444546474849" + "50515253545556575859606162636465666768697071727374" + "75767778798081828384858687888990919293949596979899" +}; + +STBSP__PUBLICDEF void STB_SPRINTF_DECORATE(set_separators)(char pcomma, char pperiod) +{ + stbsp__period = pperiod; + stbsp__comma = pcomma; +} + +#define STBSP__LEFTJUST 1 +#define STBSP__LEADINGPLUS 2 +#define STBSP__LEADINGSPACE 4 +#define STBSP__LEADING_0X 8 +#define STBSP__LEADINGZERO 16 +#define STBSP__INTMAX 32 +#define STBSP__TRIPLET_COMMA 64 +#define STBSP__NEGATIVE 128 +#define STBSP__METRIC_SUFFIX 256 +#define STBSP__HALFWIDTH 512 +#define STBSP__METRIC_NOSPACE 1024 +#define STBSP__METRIC_1024 2048 +#define STBSP__METRIC_JEDEC 4096 + +static void stbsp__lead_sign(stbsp__uint32 fl, char *sign) +{ + sign[0] = 0; + if (fl & STBSP__NEGATIVE) { + sign[0] = 1; + sign[1] = '-'; + } else if (fl & STBSP__LEADINGSPACE) { + sign[0] = 1; + sign[1] = ' '; + } else if (fl & STBSP__LEADINGPLUS) { + sign[0] = 1; + sign[1] = '+'; + } +} + +static STBSP__ASAN stbsp__uint32 stbsp__strlen_limited(char const *s, stbsp__uint32 limit) +{ + char const * sn = s; + + // get up to 4-byte alignment + for (;;) { + if (((stbsp__uintptr)sn & 3) == 0) + break; + + if (!limit || *sn == 0) + return (stbsp__uint32)(sn - s); + + ++sn; + --limit; + } + + // scan over 4 bytes at a time to find terminating 0 + // this will intentionally scan up to 3 bytes past the end of buffers, + // but becase it works 4B aligned, it will never cross page boundaries + // (hence the STBSP__ASAN markup; the over-read here is intentional + // and harmless) + while (limit >= 4) { + stbsp__uint32 v = *(stbsp__uint32 *)sn; + // bit hack to find if there's a 0 byte in there + if ((v - 0x01010101) & (~v) & 0x80808080UL) + break; + + sn += 4; + limit -= 4; + } + + // handle the last few characters to find actual size + while (limit && *sn) { + ++sn; + --limit; + } + + return (stbsp__uint32)(sn - s); +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintfcb)(STBSP_SPRINTFCB *callback, void *user, char *buf, char const *fmt, va_list va) +{ + static char hex[] = "0123456789abcdefxp"; + static char hexu[] = "0123456789ABCDEFXP"; + char *bf; + char const *f; + int tlen = 0; + + bf = buf; + f = fmt; + for (;;) { + stbsp__int32 fw, pr, tz; + stbsp__uint32 fl; + + // macros for the callback buffer stuff + #define stbsp__chk_cb_bufL(bytes) \ + { \ + int len = (int)(bf - buf); \ + if ((len + (bytes)) >= STB_SPRINTF_MIN) { \ + tlen += len; \ + if (0 == (bf = buf = callback(buf, user, len))) \ + goto done; \ + } \ + } + #define stbsp__chk_cb_buf(bytes) \ + { \ + if (callback) { \ + stbsp__chk_cb_bufL(bytes); \ + } \ + } + #define stbsp__flush_cb() \ + { \ + stbsp__chk_cb_bufL(STB_SPRINTF_MIN - 1); \ + } // flush if there is even one byte in the buffer + #define stbsp__cb_buf_clamp(cl, v) \ + cl = v; \ + if (callback) { \ + int lg = STB_SPRINTF_MIN - (int)(bf - buf); \ + if (cl > lg) \ + cl = lg; \ + } + + // fast copy everything up to the next % (or end of string) + for (;;) { + while (((stbsp__uintptr)f) & 3) { + schk1: + if (f[0] == '%') + goto scandd; + schk2: + if (f[0] == 0) + goto endfmt; + stbsp__chk_cb_buf(1); + *bf++ = f[0]; + ++f; + } + for (;;) { + // Check if the next 4 bytes contain %(0x25) or end of string. + // Using the 'hasless' trick: + // https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord + stbsp__uint32 v, c; + v = *(stbsp__uint32 *)f; + c = (~v) & 0x80808080; + if (((v ^ 0x25252525) - 0x01010101) & c) + goto schk1; + if ((v - 0x01010101) & c) + goto schk2; + if (callback) + if ((STB_SPRINTF_MIN - (int)(bf - buf)) < 4) + goto schk1; + #ifdef STB_SPRINTF_NOUNALIGNED + if(((stbsp__uintptr)bf) & 3) { + bf[0] = f[0]; + bf[1] = f[1]; + bf[2] = f[2]; + bf[3] = f[3]; + } else + #endif + { + *(stbsp__uint32 *)bf = v; + } + bf += 4; + f += 4; + } + } + scandd: + + ++f; + + // ok, we have a percent, read the modifiers first + fw = 0; + pr = -1; + fl = 0; + tz = 0; + + // flags + for (;;) { + switch (f[0]) { + // if we have left justify + case '-': + fl |= STBSP__LEFTJUST; + ++f; + continue; + // if we have leading plus + case '+': + fl |= STBSP__LEADINGPLUS; + ++f; + continue; + // if we have leading space + case ' ': + fl |= STBSP__LEADINGSPACE; + ++f; + continue; + // if we have leading 0x + case '#': + fl |= STBSP__LEADING_0X; + ++f; + continue; + // if we have thousand commas + case '\'': + fl |= STBSP__TRIPLET_COMMA; + ++f; + continue; + // if we have kilo marker (none->kilo->kibi->jedec) + case '$': + if (fl & STBSP__METRIC_SUFFIX) { + if (fl & STBSP__METRIC_1024) { + fl |= STBSP__METRIC_JEDEC; + } else { + fl |= STBSP__METRIC_1024; + } + } else { + fl |= STBSP__METRIC_SUFFIX; + } + ++f; + continue; + // if we don't want space between metric suffix and number + case '_': + fl |= STBSP__METRIC_NOSPACE; + ++f; + continue; + // if we have leading zero + case '0': + fl |= STBSP__LEADINGZERO; + ++f; + goto flags_done; + default: goto flags_done; + } + } + flags_done: + + // get the field width + if (f[0] == '*') { + fw = va_arg(va, stbsp__uint32); + ++f; + } else { + while ((f[0] >= '0') && (f[0] <= '9')) { + fw = fw * 10 + f[0] - '0'; + f++; + } + } + // get the precision + if (f[0] == '.') { + ++f; + if (f[0] == '*') { + pr = va_arg(va, stbsp__uint32); + ++f; + } else { + pr = 0; + while ((f[0] >= '0') && (f[0] <= '9')) { + pr = pr * 10 + f[0] - '0'; + f++; + } + } + } + + // handle integer size overrides + switch (f[0]) { + // are we halfwidth? + case 'h': + fl |= STBSP__HALFWIDTH; + ++f; + if (f[0] == 'h') + ++f; // QUARTERWIDTH + break; + // are we 64-bit (unix style) + case 'l': + fl |= ((sizeof(long) == 8) ? STBSP__INTMAX : 0); + ++f; + if (f[0] == 'l') { + fl |= STBSP__INTMAX; + ++f; + } + break; + // are we 64-bit on intmax? (c99) + case 'j': + fl |= (sizeof(size_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + // are we 64-bit on size_t or ptrdiff_t? (c99) + case 'z': + fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + case 't': + fl |= (sizeof(ptrdiff_t) == 8) ? STBSP__INTMAX : 0; + ++f; + break; + // are we 64-bit (msft style) + case 'I': + if ((f[1] == '6') && (f[2] == '4')) { + fl |= STBSP__INTMAX; + f += 3; + } else if ((f[1] == '3') && (f[2] == '2')) { + f += 3; + } else { + fl |= ((sizeof(void *) == 8) ? STBSP__INTMAX : 0); + ++f; + } + break; + default: break; + } + + // handle each replacement + switch (f[0]) { + #define STBSP__NUMSZ 512 // big enough for e308 (with commas) or e-307 + char num[STBSP__NUMSZ]; + char lead[8]; + char tail[8]; + char *s; + char const *h; + stbsp__uint32 l, n, cs; + stbsp__uint64 n64; +#ifndef STB_SPRINTF_NOFLOAT + double fv; +#endif + stbsp__int32 dp; + char const *sn; + + case 's': + // get the string + s = va_arg(va, char *); + if (s == 0) + s = (char *)"null"; + // get the length, limited to desired precision + // always limit to ~0u chars since our counts are 32b + l = stbsp__strlen_limited(s, (pr >= 0) ? pr : ~0u); + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + // copy the string in + goto scopy; + + case 'c': // char + // get the character + s = num + STBSP__NUMSZ - 1; + *s = (char)va_arg(va, int); + l = 1; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + + case 'n': // weird write-bytes specifier + { + int *d = va_arg(va, int *); + *d = tlen + (int)(bf - buf); + } break; + +#ifdef STB_SPRINTF_NOFLOAT + case 'A': // float + case 'a': // hex float + case 'G': // float + case 'g': // float + case 'E': // float + case 'e': // float + case 'f': // float + va_arg(va, double); // eat it + s = (char *)"No float"; + l = 8; + lead[0] = 0; + tail[0] = 0; + pr = 0; + cs = 0; + STBSP__NOTUSED(dp); + goto scopy; +#else + case 'A': // hex float + case 'a': // hex float + h = (f[0] == 'A') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_parts((stbsp__int64 *)&n64, &dp, fv)) + fl |= STBSP__NEGATIVE; + + s = num + 64; + + stbsp__lead_sign(fl, lead); + + if (dp == -1023) + dp = (n64) ? -1022 : 0; + else + n64 |= (((stbsp__uint64)1) << 52); + n64 <<= (64 - 56); + if (pr < 15) + n64 += ((((stbsp__uint64)8) << 56) >> (pr * 4)); +// add leading chars + +#ifdef STB_SPRINTF_MSVC_MODE + *s++ = '0'; + *s++ = 'x'; +#else + lead[1 + lead[0]] = '0'; + lead[2 + lead[0]] = 'x'; + lead[0] += 2; +#endif + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + if (pr) + *s++ = stbsp__period; + sn = s; + + // print the bits + n = pr; + if (n > 13) + n = 13; + if (pr > (stbsp__int32)n) + tz = pr - n; + pr = 0; + while (n--) { + *s++ = h[(n64 >> 60) & 15]; + n64 <<= 4; + } + + // print the expo + tail[1] = h[17]; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; + n = (dp >= 1000) ? 6 : ((dp >= 100) ? 5 : ((dp >= 10) ? 4 : 3)); + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + + dp = (int)(s - sn); + l = (int)(s - (num + 64)); + s = num + 64; + cs = 1 + (3 << 24); + goto scopy; + + case 'G': // float + case 'g': // float + h = (f[0] == 'G') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; + else if (pr == 0) + pr = 1; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, (pr - 1) | 0x80000000)) + fl |= STBSP__NEGATIVE; + + // clamp the precision and delete extra zeros after clamp + n = pr; + if (l > (stbsp__uint32)pr) + l = pr; + while ((l > 1) && (pr) && (sn[l - 1] == '0')) { + --pr; + --l; + } + + // should we use %e + if ((dp <= -4) || (dp > (stbsp__int32)n)) { + if (pr > (stbsp__int32)l) + pr = l - 1; + else if (pr) + --pr; // when using %e, there is one digit before the decimal + goto doexpfromg; + } + // this is the insane action to get the pr to match %g semantics for %f + if (dp > 0) { + pr = (dp < (stbsp__int32)l) ? l - dp : 0; + } else { + pr = -dp + ((pr > (stbsp__int32)l) ? (stbsp__int32) l : pr); + } + goto dofloatfromg; + + case 'E': // float + case 'e': // float + h = (f[0] == 'E') ? hexu : hex; + fv = va_arg(va, double); + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr | 0x80000000)) + fl |= STBSP__NEGATIVE; + doexpfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + // handle leading chars + *s++ = sn[0]; + + if (pr) + *s++ = stbsp__period; + + // handle after decimal + if ((l - 1) > (stbsp__uint32)pr) + l = pr + 1; + for (n = 1; n < l; n++) + *s++ = sn[n]; + // trailing zeros + tz = pr - (l - 1); + pr = 0; + // dump expo + tail[1] = h[0xe]; + dp -= 1; + if (dp < 0) { + tail[2] = '-'; + dp = -dp; + } else + tail[2] = '+'; +#ifdef STB_SPRINTF_MSVC_MODE + n = 5; +#else + n = (dp >= 100) ? 5 : 4; +#endif + tail[0] = (char)n; + for (;;) { + tail[n] = '0' + dp % 10; + if (n <= 3) + break; + --n; + dp /= 10; + } + cs = 1 + (3 << 24); // how many tens + goto flt_lead; + + case 'f': // float + fv = va_arg(va, double); + doafloat: + // do kilos + if (fl & STBSP__METRIC_SUFFIX) { + double divisor; + divisor = 1000.0f; + if (fl & STBSP__METRIC_1024) + divisor = 1024.0; + while (fl < 0x4000000) { + if ((fv < divisor) && (fv > -divisor)) + break; + fv /= divisor; + fl += 0x1000000; + } + } + if (pr == -1) + pr = 6; // default is 6 + // read the double into a string + if (stbsp__real_to_str(&sn, &l, num, &dp, fv, pr)) + fl |= STBSP__NEGATIVE; + dofloatfromg: + tail[0] = 0; + stbsp__lead_sign(fl, lead); + if (dp == STBSP__SPECIAL) { + s = (char *)sn; + cs = 0; + pr = 0; + goto scopy; + } + s = num + 64; + + // handle the three decimal varieties + if (dp <= 0) { + stbsp__int32 i; + // handle 0.000*000xxxx + *s++ = '0'; + if (pr) + *s++ = stbsp__period; + n = -dp; + if ((stbsp__int32)n > pr) + n = pr; + i = n; + while (i) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + i -= 4; + } + while (i) { + *s++ = '0'; + --i; + } + if ((stbsp__int32)(l + n) > pr) + l = pr - n; + i = l; + while (i) { + *s++ = *sn++; + --i; + } + tz = pr - (n + l); + cs = 1 + (3 << 24); // how many tens did we write (for commas below) + } else { + cs = (fl & STBSP__TRIPLET_COMMA) ? ((600 - (stbsp__uint32)dp) % 3) : 0; + if ((stbsp__uint32)dp >= l) { + // handle xxxx000*000.0 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= l) + break; + } + } + if (n < (stbsp__uint32)dp) { + n = dp - n; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (n) { + if ((((stbsp__uintptr)s) & 3) == 0) + break; + *s++ = '0'; + --n; + } + while (n >= 4) { + *(stbsp__uint32 *)s = 0x30303030; + s += 4; + n -= 4; + } + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = '0'; + --n; + } + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) { + *s++ = stbsp__period; + tz = pr; + } + } else { + // handle xxxxx.xxxx000*000 + n = 0; + for (;;) { + if ((fl & STBSP__TRIPLET_COMMA) && (++cs == 4)) { + cs = 0; + *s++ = stbsp__comma; + } else { + *s++ = sn[n]; + ++n; + if (n >= (stbsp__uint32)dp) + break; + } + } + cs = (int)(s - (num + 64)) + (3 << 24); // cs is how many tens + if (pr) + *s++ = stbsp__period; + if ((l - dp) > (stbsp__uint32)pr) + l = pr + dp; + while (n < l) { + *s++ = sn[n]; + ++n; + } + tz = pr - (l - dp); + } + } + pr = 0; + + // handle k,m,g,t + if (fl & STBSP__METRIC_SUFFIX) { + char idx; + idx = 1; + if (fl & STBSP__METRIC_NOSPACE) + idx = 0; + tail[0] = idx; + tail[1] = ' '; + { + if (fl >> 24) { // SI kilo is 'k', JEDEC and SI kibits are 'K'. + if (fl & STBSP__METRIC_1024) + tail[idx + 1] = "_KMGT"[fl >> 24]; + else + tail[idx + 1] = "_kMGT"[fl >> 24]; + idx++; + // If printing kibits and not in jedec, add the 'i'. + if (fl & STBSP__METRIC_1024 && !(fl & STBSP__METRIC_JEDEC)) { + tail[idx + 1] = 'i'; + idx++; + } + tail[0] = idx; + } + } + }; + + flt_lead: + // get the length that we copied + l = (stbsp__uint32)(s - (num + 64)); + s = num + 64; + goto scopy; +#endif + + case 'B': // upper binary + case 'b': // lower binary + h = (f[0] == 'B') ? hexu : hex; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[0xb]; + } + l = (8 << 4) | (1 << 8); + goto radixnum; + + case 'o': // octal + h = hexu; + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 1; + lead[1] = '0'; + } + l = (3 << 4) | (3 << 8); + goto radixnum; + + case 'p': // pointer + fl |= (sizeof(void *) == 8) ? STBSP__INTMAX : 0; + pr = sizeof(void *) * 2; + fl &= ~STBSP__LEADINGZERO; // 'p' only prints the pointer with zeros + // fall through - to X + + case 'X': // upper hex + case 'x': // lower hex + h = (f[0] == 'X') ? hexu : hex; + l = (4 << 4) | (4 << 8); + lead[0] = 0; + if (fl & STBSP__LEADING_0X) { + lead[0] = 2; + lead[1] = '0'; + lead[2] = h[16]; + } + radixnum: + // get the number + if (fl & STBSP__INTMAX) + n64 = va_arg(va, stbsp__uint64); + else + n64 = va_arg(va, stbsp__uint32); + + s = num + STBSP__NUMSZ; + dp = 0; + // clear tail, and clear leading if value is zero + tail[0] = 0; + if (n64 == 0) { + lead[0] = 0; + if (pr == 0) { + l = 0; + cs = 0; + goto scopy; + } + } + // convert to string + for (;;) { + *--s = h[n64 & ((1 << (l >> 8)) - 1)]; + n64 >>= (l >> 8); + if (!((n64) || ((stbsp__int32)((num + STBSP__NUMSZ) - s) < pr))) + break; + if (fl & STBSP__TRIPLET_COMMA) { + ++l; + if ((l & 15) == ((l >> 4) & 15)) { + l &= ~15; + *--s = stbsp__comma; + } + } + }; + // get the tens and the comma pos + cs = (stbsp__uint32)((num + STBSP__NUMSZ) - s) + ((((l >> 4) & 15)) << 24); + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + // copy it + goto scopy; + + case 'u': // unsigned + case 'i': + case 'd': // integer + // get the integer and abs it + if (fl & STBSP__INTMAX) { + stbsp__int64 i64 = va_arg(va, stbsp__int64); + n64 = (stbsp__uint64)i64; + if ((f[0] != 'u') && (i64 < 0)) { + n64 = (stbsp__uint64)-i64; + fl |= STBSP__NEGATIVE; + } + } else { + stbsp__int32 i = va_arg(va, stbsp__int32); + n64 = (stbsp__uint32)i; + if ((f[0] != 'u') && (i < 0)) { + n64 = (stbsp__uint32)-i; + fl |= STBSP__NEGATIVE; + } + } + +#ifndef STB_SPRINTF_NOFLOAT + if (fl & STBSP__METRIC_SUFFIX) { + if (n64 < 1024) + pr = 0; + else if (pr == -1) + pr = 1; + fv = (double)(stbsp__int64)n64; + goto doafloat; + } +#endif + + // convert to string + s = num + STBSP__NUMSZ; + l = 0; + + for (;;) { + // do in 32-bit chunks (avoid lots of 64-bit divides even with constant denominators) + char *o = s - 8; + if (n64 >= 100000000) { + n = (stbsp__uint32)(n64 % 100000000); + n64 /= 100000000; + } else { + n = (stbsp__uint32)n64; + n64 = 0; + } + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + do { + s -= 2; + *(stbsp__uint16 *)s = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; + n /= 100; + } while (n); + } + while (n) { + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = (char)(n % 10) + '0'; + n /= 10; + } + } + if (n64 == 0) { + if ((s[0] == '0') && (s != (num + STBSP__NUMSZ))) + ++s; + break; + } + while (s != o) + if ((fl & STBSP__TRIPLET_COMMA) && (l++ == 3)) { + l = 0; + *--s = stbsp__comma; + --o; + } else { + *--s = '0'; + } + } + + tail[0] = 0; + stbsp__lead_sign(fl, lead); + + // get the length that we copied + l = (stbsp__uint32)((num + STBSP__NUMSZ) - s); + if (l == 0) { + *--s = '0'; + l = 1; + } + cs = l + (3 << 24); + if (pr < 0) + pr = 0; + + scopy: + // get fw=leading/trailing space, pr=leading zeros + if (pr < (stbsp__int32)l) + pr = l; + n = pr + lead[0] + tail[0] + tz; + if (fw < (stbsp__int32)n) + fw = n; + fw -= n; + pr -= l; + + // handle right justify and leading zeros + if ((fl & STBSP__LEFTJUST) == 0) { + if (fl & STBSP__LEADINGZERO) // if leading zeros, everything is in pr + { + pr = (fw > pr) ? fw : pr; + fw = 0; + } else { + fl &= ~STBSP__TRIPLET_COMMA; // if no leading zeros, then no commas + } + } + + // copy the spaces and/or zeros + if (fw + pr) { + stbsp__int32 i; + stbsp__uint32 c; + + // copy leading spaces (or when doing %8.4d stuff) + if ((fl & STBSP__LEFTJUST) == 0) + while (fw > 0) { + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = ' '; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy leader + sn = lead + 1; + while (lead[0]) { + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy leading zeros + c = cs >> 24; + cs &= 0xffffff; + cs = (fl & STBSP__TRIPLET_COMMA) ? ((stbsp__uint32)(c - ((pr + cs) % (c + 1)))) : 0; + while (pr > 0) { + stbsp__cb_buf_clamp(i, pr); + pr -= i; + if ((fl & STBSP__TRIPLET_COMMA) == 0) { + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + } + while (i) { + if ((fl & STBSP__TRIPLET_COMMA) && (cs++ == c)) { + cs = 0; + *bf++ = stbsp__comma; + } else + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + } + + // copy leader if there is still one + sn = lead + 1; + while (lead[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, lead[0]); + lead[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy the string + n = l; + while (n) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, n); + n -= i; + STBSP__UNALIGNED(while (i >= 4) { + *(stbsp__uint32 volatile *)bf = *(stbsp__uint32 volatile *)s; + bf += 4; + s += 4; + i -= 4; + }) + while (i) { + *bf++ = *s++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy trailing zeros + while (tz) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tz); + tz -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = '0'; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x30303030; + bf += 4; + i -= 4; + } + while (i) { + *bf++ = '0'; + --i; + } + stbsp__chk_cb_buf(1); + } + + // copy tail if there is one + sn = tail + 1; + while (tail[0]) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, tail[0]); + tail[0] -= (char)i; + while (i) { + *bf++ = *sn++; + --i; + } + stbsp__chk_cb_buf(1); + } + + // handle the left justify + if (fl & STBSP__LEFTJUST) + if (fw > 0) { + while (fw) { + stbsp__int32 i; + stbsp__cb_buf_clamp(i, fw); + fw -= i; + while (i) { + if ((((stbsp__uintptr)bf) & 3) == 0) + break; + *bf++ = ' '; + --i; + } + while (i >= 4) { + *(stbsp__uint32 *)bf = 0x20202020; + bf += 4; + i -= 4; + } + while (i--) + *bf++ = ' '; + stbsp__chk_cb_buf(1); + } + } + break; + + default: // unknown, just copy code + s = num + STBSP__NUMSZ - 1; + *s = f[0]; + l = 1; + fw = fl = 0; + lead[0] = 0; + tail[0] = 0; + pr = 0; + dp = 0; + cs = 0; + goto scopy; + } + ++f; + } +endfmt: + + if (!callback) + *bf = 0; + else + stbsp__flush_cb(); + +done: + return tlen + (int)(bf - buf); +} + +// cleanup +#undef STBSP__LEFTJUST +#undef STBSP__LEADINGPLUS +#undef STBSP__LEADINGSPACE +#undef STBSP__LEADING_0X +#undef STBSP__LEADINGZERO +#undef STBSP__INTMAX +#undef STBSP__TRIPLET_COMMA +#undef STBSP__NEGATIVE +#undef STBSP__METRIC_SUFFIX +#undef STBSP__NUMSZ +#undef stbsp__chk_cb_bufL +#undef stbsp__chk_cb_buf +#undef stbsp__flush_cb +#undef stbsp__cb_buf_clamp + +// ============================================================================ +// wrapper functions + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(sprintf)(char *buf, char const *fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + result = STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); + va_end(va); + return result; +} + +typedef struct stbsp__context { + char *buf; + int count; + int length; + char tmp[STB_SPRINTF_MIN]; +} stbsp__context; + +static char *stbsp__clamp_callback(const char *buf, void *user, int len) +{ + stbsp__context *c = (stbsp__context *)user; + c->length += len; + + if (len > c->count) + len = c->count; + + if (len) { + if (buf != c->buf) { + const char *s, *se; + char *d; + d = c->buf; + s = buf; + se = buf + len; + do { + *d++ = *s++; + } while (s < se); + } + c->buf += len; + c->count -= len; + } + + if (c->count <= 0) + return c->tmp; + return (c->count >= STB_SPRINTF_MIN) ? c->buf : c->tmp; // go direct into buffer if you can +} + +static char * stbsp__count_clamp_callback( const char * buf, void * user, int len ) +{ + stbsp__context * c = (stbsp__context*)user; + (void) sizeof(buf); + + c->length += len; + return c->tmp; // go direct into buffer if you can +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE( vsnprintf )( char * buf, int count, char const * fmt, va_list va ) +{ + stbsp__context c; + + if ( (count == 0) && !buf ) + { + c.length = 0; + + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__count_clamp_callback, &c, c.tmp, fmt, va ); + } + else + { + int l; + + c.buf = buf; + c.count = count; + c.length = 0; + + STB_SPRINTF_DECORATE( vsprintfcb )( stbsp__clamp_callback, &c, stbsp__clamp_callback(0,&c,0), fmt, va ); + + // zero-terminate + l = (int)( c.buf - buf ); + if ( l >= count ) // should never be greater, only equal (or less) than count + l = count - 1; + buf[l] = 0; + } + + return c.length; +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(snprintf)(char *buf, int count, char const *fmt, ...) +{ + int result; + va_list va; + va_start(va, fmt); + + result = STB_SPRINTF_DECORATE(vsnprintf)(buf, count, fmt, va); + va_end(va); + + return result; +} + +STBSP__PUBLICDEF int STB_SPRINTF_DECORATE(vsprintf)(char *buf, char const *fmt, va_list va) +{ + return STB_SPRINTF_DECORATE(vsprintfcb)(0, 0, buf, fmt, va); +} + +// ======================================================================= +// low level float utility functions + +#ifndef STB_SPRINTF_NOFLOAT + +// copies d to bits w/ strict aliasing (this compiles to nothing on /Ox) +#define STBSP__COPYFP(dest, src) \ + { \ + int cn; \ + for (cn = 0; cn < 8; cn++) \ + ((char *)&dest)[cn] = ((char *)&src)[cn]; \ + } + +// get float info +static stbsp__int32 stbsp__real_to_parts(stbsp__int64 *bits, stbsp__int32 *expo, double value) +{ + double d; + stbsp__int64 b = 0; + + // load value and round at the frac_digits + d = value; + + STBSP__COPYFP(b, d); + + *bits = b & ((((stbsp__uint64)1) << 52) - 1); + *expo = (stbsp__int32)(((b >> 52) & 2047) - 1023); + + return (stbsp__int32)((stbsp__uint64) b >> 63); +} + +static double const stbsp__bot[23] = { + 1e+000, 1e+001, 1e+002, 1e+003, 1e+004, 1e+005, 1e+006, 1e+007, 1e+008, 1e+009, 1e+010, 1e+011, + 1e+012, 1e+013, 1e+014, 1e+015, 1e+016, 1e+017, 1e+018, 1e+019, 1e+020, 1e+021, 1e+022 +}; +static double const stbsp__negbot[22] = { + 1e-001, 1e-002, 1e-003, 1e-004, 1e-005, 1e-006, 1e-007, 1e-008, 1e-009, 1e-010, 1e-011, + 1e-012, 1e-013, 1e-014, 1e-015, 1e-016, 1e-017, 1e-018, 1e-019, 1e-020, 1e-021, 1e-022 +}; +static double const stbsp__negboterr[22] = { + -5.551115123125783e-018, -2.0816681711721684e-019, -2.0816681711721686e-020, -4.7921736023859299e-021, -8.1803053914031305e-022, 4.5251888174113741e-023, + 4.5251888174113739e-024, -2.0922560830128471e-025, -6.2281591457779853e-026, -3.6432197315497743e-027, 6.0503030718060191e-028, 2.0113352370744385e-029, + -3.0373745563400371e-030, 1.1806906454401013e-032, -7.7705399876661076e-032, 2.0902213275965398e-033, -7.1542424054621921e-034, -7.1542424054621926e-035, + 2.4754073164739869e-036, 5.4846728545790429e-037, 9.2462547772103625e-038, -4.8596774326570872e-039 +}; +static double const stbsp__top[13] = { + 1e+023, 1e+046, 1e+069, 1e+092, 1e+115, 1e+138, 1e+161, 1e+184, 1e+207, 1e+230, 1e+253, 1e+276, 1e+299 +}; +static double const stbsp__negtop[13] = { + 1e-023, 1e-046, 1e-069, 1e-092, 1e-115, 1e-138, 1e-161, 1e-184, 1e-207, 1e-230, 1e-253, 1e-276, 1e-299 +}; +static double const stbsp__toperr[13] = { + 8388608, + 6.8601809640529717e+028, + -7.253143638152921e+052, + -4.3377296974619174e+075, + -1.5559416129466825e+098, + -3.2841562489204913e+121, + -3.7745893248228135e+144, + -1.7356668416969134e+167, + -3.8893577551088374e+190, + -9.9566444326005119e+213, + 6.3641293062232429e+236, + -5.2069140800249813e+259, + -5.2504760255204387e+282 +}; +static double const stbsp__negtoperr[13] = { + 3.9565301985100693e-040, -2.299904345391321e-063, 3.6506201437945798e-086, 1.1875228833981544e-109, + -5.0644902316928607e-132, -6.7156837247865426e-155, -2.812077463003139e-178, -5.7778912386589953e-201, + 7.4997100559334532e-224, -4.6439668915134491e-247, -6.3691100762962136e-270, -9.436808465446358e-293, + 8.0970921678014997e-317 +}; + +#if defined(_MSC_VER) && (_MSC_VER <= 1200) +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000, + 100000000000, + 1000000000000, + 10000000000000, + 100000000000000, + 1000000000000000, + 10000000000000000, + 100000000000000000, + 1000000000000000000, + 10000000000000000000U +}; +#define stbsp__tento19th ((stbsp__uint64)1000000000000000000) +#else +static stbsp__uint64 const stbsp__powten[20] = { + 1, + 10, + 100, + 1000, + 10000, + 100000, + 1000000, + 10000000, + 100000000, + 1000000000, + 10000000000ULL, + 100000000000ULL, + 1000000000000ULL, + 10000000000000ULL, + 100000000000000ULL, + 1000000000000000ULL, + 10000000000000000ULL, + 100000000000000000ULL, + 1000000000000000000ULL, + 10000000000000000000ULL +}; +#define stbsp__tento19th (1000000000000000000ULL) +#endif + +#define stbsp__ddmulthi(oh, ol, xh, yh) \ + { \ + double ahi = 0, alo, bhi = 0, blo; \ + stbsp__int64 bt; \ + oh = xh * yh; \ + STBSP__COPYFP(bt, xh); \ + bt &= ((~(stbsp__uint64)0) << 27); \ + STBSP__COPYFP(ahi, bt); \ + alo = xh - ahi; \ + STBSP__COPYFP(bt, yh); \ + bt &= ((~(stbsp__uint64)0) << 27); \ + STBSP__COPYFP(bhi, bt); \ + blo = yh - bhi; \ + ol = ((ahi * bhi - oh) + ahi * blo + alo * bhi) + alo * blo; \ + } + +#define stbsp__ddtoS64(ob, xh, xl) \ + { \ + double ahi = 0, alo, vh, t; \ + ob = (stbsp__int64)xh; \ + vh = (double)ob; \ + ahi = (xh - vh); \ + t = (ahi - xh); \ + alo = (xh - (ahi - t)) - (vh + t); \ + ob += (stbsp__int64)(ahi + alo + xl); \ + } + +#define stbsp__ddrenorm(oh, ol) \ + { \ + double s; \ + s = oh + ol; \ + ol = ol - (s - oh); \ + oh = s; \ + } + +#define stbsp__ddmultlo(oh, ol, xh, xl, yh, yl) ol = ol + (xh * yl + xl * yh); + +#define stbsp__ddmultlos(oh, ol, xh, yl) ol = ol + (xh * yl); + +static void stbsp__raise_to_power10(double *ohi, double *olo, double d, stbsp__int32 power) // power can be -323 to +350 +{ + double ph, pl; + if ((power >= 0) && (power <= 22)) { + stbsp__ddmulthi(ph, pl, d, stbsp__bot[power]); + } else { + stbsp__int32 e, et, eb; + double p2h, p2l; + + e = power; + if (power < 0) + e = -e; + et = (e * 0x2c9) >> 14; /* %23 */ + if (et > 13) + et = 13; + eb = e - (et * 23); + + ph = d; + pl = 0.0; + if (power < 0) { + if (eb) { + --eb; + stbsp__ddmulthi(ph, pl, d, stbsp__negbot[eb]); + stbsp__ddmultlos(ph, pl, d, stbsp__negboterr[eb]); + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__negtop[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__negtop[et], stbsp__negtoperr[et]); + ph = p2h; + pl = p2l; + } + } else { + if (eb) { + e = eb; + if (eb > 22) + eb = 22; + e -= eb; + stbsp__ddmulthi(ph, pl, d, stbsp__bot[eb]); + if (e) { + stbsp__ddrenorm(ph, pl); + stbsp__ddmulthi(p2h, p2l, ph, stbsp__bot[e]); + stbsp__ddmultlos(p2h, p2l, stbsp__bot[e], pl); + ph = p2h; + pl = p2l; + } + } + if (et) { + stbsp__ddrenorm(ph, pl); + --et; + stbsp__ddmulthi(p2h, p2l, ph, stbsp__top[et]); + stbsp__ddmultlo(p2h, p2l, ph, pl, stbsp__top[et], stbsp__toperr[et]); + ph = p2h; + pl = p2l; + } + } + } + stbsp__ddrenorm(ph, pl); + *ohi = ph; + *olo = pl; +} + +// given a float value, returns the significant bits in bits, and the position of the +// decimal point in decimal_pos. +/-INF and NAN are specified by special values +// returned in the decimal_pos parameter. +// frac_digits is absolute normally, but if you want from first significant digits (got %g and %e), or in 0x80000000 +static stbsp__int32 stbsp__real_to_str(char const **start, stbsp__uint32 *len, char *out, stbsp__int32 *decimal_pos, double value, stbsp__uint32 frac_digits) +{ + double d; + stbsp__int64 bits = 0; + stbsp__int32 expo, e, ng, tens; + + d = value; + STBSP__COPYFP(bits, d); + expo = (stbsp__int32)((bits >> 52) & 2047); + ng = (stbsp__int32)((stbsp__uint64) bits >> 63); + if (ng) + d = -d; + + if (expo == 2047) // is nan or inf? + { + *start = (bits & ((((stbsp__uint64)1) << 52) - 1)) ? "NaN" : "Inf"; + *decimal_pos = STBSP__SPECIAL; + *len = 3; + return ng; + } + + if (expo == 0) // is zero or denormal + { + if (((stbsp__uint64) bits << 1) == 0) // do zero + { + *decimal_pos = 1; + *start = out; + out[0] = '0'; + *len = 1; + return ng; + } + // find the right expo for denormals + { + stbsp__int64 v = ((stbsp__uint64)1) << 51; + while ((bits & v) == 0) { + --expo; + v >>= 1; + } + } + } + + // find the decimal exponent as well as the decimal bits of the value + { + double ph, pl; + + // log10 estimate - very specifically tweaked to hit or undershoot by no more than 1 of log10 of all expos 1..2046 + tens = expo - 1023; + tens = (tens < 0) ? ((tens * 617) / 2048) : (((tens * 1233) / 4096) + 1); + + // move the significant bits into position and stick them into an int + stbsp__raise_to_power10(&ph, &pl, d, 18 - tens); + + // get full as much precision from double-double as possible + stbsp__ddtoS64(bits, ph, pl); + + // check if we undershot + if (((stbsp__uint64)bits) >= stbsp__tento19th) + ++tens; + } + + // now do the rounding in integer land + frac_digits = (frac_digits & 0x80000000) ? ((frac_digits & 0x7ffffff) + 1) : (tens + frac_digits); + if ((frac_digits < 24)) { + stbsp__uint32 dg = 1; + if ((stbsp__uint64)bits >= stbsp__powten[9]) + dg = 10; + while ((stbsp__uint64)bits >= stbsp__powten[dg]) { + ++dg; + if (dg == 20) + goto noround; + } + if (frac_digits < dg) { + stbsp__uint64 r; + // add 0.5 at the right position and round + e = dg - frac_digits; + if ((stbsp__uint32)e >= 24) + goto noround; + r = stbsp__powten[e]; + bits = bits + (r / 2); + if ((stbsp__uint64)bits >= stbsp__powten[dg]) + ++tens; + bits /= r; + } + noround:; + } + + // kill long trailing runs of zeros + if (bits) { + stbsp__uint32 n; + for (;;) { + if (bits <= 0xffffffff) + break; + if (bits % 1000) + goto donez; + bits /= 1000; + } + n = (stbsp__uint32)bits; + while ((n % 1000) == 0) + n /= 1000; + bits = n; + donez:; + } + + // convert to string + out += 64; + e = 0; + for (;;) { + stbsp__uint32 n; + char *o = out - 8; + // do the conversion in chunks of U32s (avoid most 64-bit divides, worth it, constant denomiators be damned) + if (bits >= 100000000) { + n = (stbsp__uint32)(bits % 100000000); + bits /= 100000000; + } else { + n = (stbsp__uint32)bits; + bits = 0; + } + while (n) { + out -= 2; + *(stbsp__uint16 *)out = *(stbsp__uint16 *)&stbsp__digitpair.pair[(n % 100) * 2]; + n /= 100; + e += 2; + } + if (bits == 0) { + if ((e) && (out[0] == '0')) { + ++out; + --e; + } + break; + } + while (out != o) { + *--out = '0'; + ++e; + } + } + + *decimal_pos = tens; + *start = out; + *len = e; + return ng; +} + +#undef stbsp__ddmulthi +#undef stbsp__ddrenorm +#undef stbsp__ddmultlo +#undef stbsp__ddmultlos +#undef STBSP__SPECIAL +#undef STBSP__COPYFP + +#endif // STB_SPRINTF_NOFLOAT + +// clean up +#undef stbsp__uint16 +#undef stbsp__uint32 +#undef stbsp__int32 +#undef stbsp__uint64 +#undef stbsp__int64 +#undef STBSP__UNALIGNED + +#endif // STB_SPRINTF_IMPLEMENTATION + +/* +------------------------------------------------------------------------------ +This software is available under 2 licenses -- choose whichever you prefer. +------------------------------------------------------------------------------ +ALTERNATIVE A - MIT License +Copyright (c) 2017 Sean Barrett +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. +------------------------------------------------------------------------------ +ALTERNATIVE B - Public Domain (www.unlicense.org) +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. +------------------------------------------------------------------------------ +*/ \ No newline at end of file diff --git a/Windows_Libs/Dev/Storage/Storage.vcxproj b/Windows_Libs/Dev/Storage/Storage.vcxproj index 93cd0c8..6f3032a 100644 --- a/Windows_Libs/Dev/Storage/Storage.vcxproj +++ b/Windows_Libs/Dev/Storage/Storage.vcxproj @@ -48,7 +48,7 @@ StaticLibrary false - v110 + v145 true Unicode diff --git a/Windows_Libs/Dev/Storage/Storage.vcxproj.filters b/Windows_Libs/Dev/Storage/Storage.vcxproj.filters index 948d4cf..85c3541 100644 --- a/Windows_Libs/Dev/Storage/Storage.vcxproj.filters +++ b/Windows_Libs/Dev/Storage/Storage.vcxproj.filters @@ -9,10 +9,6 @@ {93995380-89BD-4b04-88EB-625FBE52EBFB} h;hh;hpp;hxx;h++;hm;inl;inc;ipp;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 -