<commit_before>#include "PaxosAcceptor.h"
#include "PaxosProposer.h"
#include "Framework/Replication/ReplicationConfig.h"

PaxosAcceptor::PaxosAcceptor()
{
    onStateWritten = MFUNC(PaxosAcceptor, OnStateWritten);
}

void PaxosAcceptor::Init(QuorumContext* context_)
{
    context = context_;
    isCommitting = false;

    ReadState();
}

bool PaxosAcceptor::OnPrepareRequest(PaxosMessage& imsg)
{
    bool reject;

    Log_Trace("state.promisedProposalID: %U msg.proposalID: %U",
     state.promisedProposalID, imsg.proposalID);

    reject = TestRejection(imsg);

    if (reject)
    {
        omsg.PrepareRejected(imsg.paxosID, MY_NODEID,
         imsg.proposalID, state.promisedProposalID);
        context->GetTransport()->SendMessage(imsg.nodeID, omsg);
        return true; // msg processed
    }

    AcceptPrepareRequest(imsg);
    return false; // OnMessageProcessed() will be called in OnStateWritten()
}

bool PaxosAcceptor::OnProposeRequest(PaxosMessage& imsg)
{
    bool reject;

    Log_Trace("state.promisedProposalID: %U msg.proposalID: %U",
     state.promisedProposalID, imsg.proposalID);

    reject = TestRejection(imsg);

    if (reject)
    {
        omsg.ProposeRejected(imsg.paxosID, MY_NODEID, imsg.proposalID);
        context->GetTransport()->SendMessage(imsg.nodeID, omsg);
        return true; // msg processed
    }

    AcceptProposeRequest(imsg);
    return false; // OnMessageProcessed() will be called in OnStateWritten()
}

void PaxosAcceptor::OnCatchupStarted()
{
    state.Init();
    context->GetDatabase()->Commit();
}

void PaxosAcceptor::OnCatchupComplete()
{
    ASSERT(!isCommitting);
    ASSERT(!context->GetDatabase()->IsCommitting());

    state.Init();
    WriteState();
    context->GetDatabase()->Commit();
}

void PaxosAcceptor::WriteState()
{
    QuorumDatabase* db;

    db = context->GetDatabase();

    db->SetPaxosID(context->GetPaxosID());
    db->SetAccepted(state.accepted);
    db->SetPromisedProposalID(state.promisedProposalID);
    if (state.accepted)
    {
        db->SetAcceptedRunID(state.acceptedRunID);
        db->SetAcceptedProposalID(state.acceptedProposalID);
        ASSERT(state.acceptedValue.GetLength() > 0);
        db->SetAcceptedValue(context->GetPaxosID(), state.acceptedValue);
    }
}

uint64_t PaxosAcceptor::GetMemoryUsage()
{
    return sizeof(PaxosAcceptor) + state.acceptedValue.GetSize();
}

void PaxosAcceptor::Commit()
{
    ASSERT(!isCommitting);

    writtenPaxosID = context->GetPaxosID();
    isCommitting = true; // reset in OnStateWritten()

    if (context->UseSyncCommit())
    {
        context->GetDatabase()->Commit();
        OnStateWritten();
    }
    else
    {
        context->GetDatabase()->Commit(onStateWritten);
    }
}

void PaxosAcceptor::OnStateWritten()
{
    Log_Trace();

    isCommitting = false;

    if (writtenPaxosID == context->GetPaxosID())
        context->GetTransport()->SendMessage(senderID, omsg);

    context->OnMessageProcessed();
}

void PaxosAcceptor::ReadState()
{
    QuorumDatabase* db;

    db = context->GetDatabase();

    context->SetPaxosID(db->GetPaxosID());
    state.accepted = db->GetAccepted();
    state.promisedProposalID = db->GetPromisedProposalID();
    if (state.accepted)
    {
        state.acceptedRunID = db->GetAcceptedRunID();
        state.acceptedProposalID = db->GetAcceptedProposalID();
        db->GetAcceptedValue(context->GetPaxosID(), state.acceptedValue);
        ASSERT(state.acceptedValue.GetLength() > 0);
    }
}

bool PaxosAcceptor::TestRejection(PaxosMessage& msg)
{
    bool reject;

    reject = false;
    if (msg.paxosID != context->GetPaxosID())
        reject = true;
    if (msg.proposalID < state.promisedProposalID)
        reject = true;
    if (isCommitting)
        reject = true;
    if (context->GetDatabase()->IsCommitting())
        reject = true;
    if (context->IsPaxosBlocked())
        reject = true;

    if (reject)
    {
        Log_Debug("imsg.paxosID = %U", msg.paxosID);
        Log_Debug("context->GetPaxosID() = %U", context->GetPaxosID());
        Log_Debug("imsg.proposalID = %U", msg.proposalID);
        Log_Debug("state.promisedProposalID = %U", state.promisedProposalID);
        Log_Debug("context->GetDatabase()->IsCommitting() = %b", context->GetDatabase()->IsCommitting());
        Log_Debug("context->IsPaxosBlocked() = %b", context->IsPaxosBlocked());
    }

    return reject;
}

void PaxosAcceptor::AcceptPrepareRequest(PaxosMessage& imsg)
{
    state.promisedProposalID = imsg.proposalID;

    senderID = imsg.nodeID;
    if (!state.accepted)
    {
        omsg.PrepareCurrentlyOpen(imsg.paxosID, MY_NODEID, imsg.proposalID);
    }
    else
    {
        ASSERT(state.acceptedValue.GetLength() > 0);
        omsg.PreparePreviouslyAccepted(imsg.paxosID, MY_NODEID,
         imsg.proposalID, state.acceptedProposalID,
         state.acceptedRunID, state.acceptedValue);
    }

    WriteState();
    Commit();
}

void PaxosAcceptor::AcceptProposeRequest(PaxosMessage& imsg)
{
    state.accepted = true;
    state.acceptedProposalID = imsg.proposalID;
    state.acceptedRunID = imsg.runID;
    ASSERT(imsg.value.GetLength() > 0);
    state.acceptedValue.Write(imsg.value);

    senderID = imsg.nodeID;
    omsg.ProposeAccepted(imsg.paxosID, MY_NODEID, imsg.proposalID);

    WriteState();
    Commit();
}
<commit_msg>Fix previous fix for #88.<commit_after>#include "PaxosAcceptor.h"
#include "PaxosProposer.h"
#include "Framework/Replication/ReplicationConfig.h"

PaxosAcceptor::PaxosAcceptor()
{
    onStateWritten = MFUNC(PaxosAcceptor, OnStateWritten);
}

void PaxosAcceptor::Init(QuorumContext* context_)
{
    context = context_;
    isCommitting = false;

    ReadState();
}

bool PaxosAcceptor::OnPrepareRequest(PaxosMessage& imsg)
{
    bool reject;

    Log_Trace("state.promisedProposalID: %U msg.proposalID: %U",
     state.promisedProposalID, imsg.proposalID);

    reject = TestRejection(imsg);

    if (reject)
    {
        omsg.PrepareRejected(imsg.paxosID, MY_NODEID,
         imsg.proposalID, state.promisedProposalID);
        context->GetTransport()->SendMessage(imsg.nodeID, omsg);
        return true; // msg processed
    }

    AcceptPrepareRequest(imsg);
    return false; // OnMessageProcessed() will be called in OnStateWritten()
}

bool PaxosAcceptor::OnProposeRequest(PaxosMessage& imsg)
{
    bool reject;

    Log_Trace("state.promisedProposalID: %U msg.proposalID: %U",
     state.promisedProposalID, imsg.proposalID);

    reject = TestRejection(imsg);

    if (reject)
    {
        omsg.ProposeRejected(imsg.paxosID, MY_NODEID, imsg.proposalID);
        context->GetTransport()->SendMessage(imsg.nodeID, omsg);
        return true; // msg processed
    }

    AcceptProposeRequest(imsg);
    return false; // OnMessageProcessed() will be called in OnStateWritten()
}

void PaxosAcceptor::OnCatchupStarted()
{
    state.Init();
    WriteState();
    context->GetDatabase()->Commit();
}

void PaxosAcceptor::OnCatchupComplete()
{
    ASSERT(!isCommitting);
    ASSERT(!context->GetDatabase()->IsCommitting());

    state.Init();
    WriteState();
    context->GetDatabase()->Commit();
}

void PaxosAcceptor::WriteState()
{
    QuorumDatabase* db;

    db = context->GetDatabase();

    db->SetPaxosID(context->GetPaxosID());
    db->SetAccepted(state.accepted);
    db->SetPromisedProposalID(state.promisedProposalID);
    if (state.accepted)
    {
        db->SetAcceptedRunID(state.acceptedRunID);
        db->SetAcceptedProposalID(state.acceptedProposalID);
        ASSERT(state.acceptedValue.GetLength() > 0);
        db->SetAcceptedValue(context->GetPaxosID(), state.acceptedValue);
    }
}

uint64_t PaxosAcceptor::GetMemoryUsage()
{
    return sizeof(PaxosAcceptor) + state.acceptedValue.GetSize();
}

void PaxosAcceptor::Commit()
{
    ASSERT(!isCommitting);

    writtenPaxosID = context->GetPaxosID();
    isCommitting = true; // reset in OnStateWritten()

    if (context->UseSyncCommit())
    {
        context->GetDatabase()->Commit();
        OnStateWritten();
    }
    else
    {
        context->GetDatabase()->Commit(onStateWritten);
    }
}

void PaxosAcceptor::OnStateWritten()
{
    Log_Trace();

    isCommitting = false;

    if (writtenPaxosID == context->GetPaxosID())
        context->GetTransport()->SendMessage(senderID, omsg);

    context->OnMessageProcessed();
}

void PaxosAcceptor::ReadState()
{
    QuorumDatabase* db;

    db = context->GetDatabase();

    context->SetPaxosID(db->GetPaxosID());
    state.accepted = db->GetAccepted();
    state.promisedProposalID = db->GetPromisedProposalID();
    if (state.accepted)
    {
        state.acceptedRunID = db->GetAcceptedRunID();
        state.acceptedProposalID = db->GetAcceptedProposalID();
        db->GetAcceptedValue(context->GetPaxosID(), state.acceptedValue);
        ASSERT(state.acceptedValue.GetLength() > 0);
    }
}

bool PaxosAcceptor::TestRejection(PaxosMessage& msg)
{
    bool reject;

    reject = false;
    if (msg.paxosID != context->GetPaxosID())
        reject = true;
    if (msg.proposalID < state.promisedProposalID)
        reject = true;
    if (isCommitting)
        reject = true;
    if (context->GetDatabase()->IsCommitting())
        reject = true;
    if (context->IsPaxosBlocked())
        reject = true;

    if (reject)
    {
        Log_Debug("imsg.paxosID = %U", msg.paxosID);
        Log_Debug("context->GetPaxosID() = %U", context->GetPaxosID());
        Log_Debug("imsg.proposalID = %U", msg.proposalID);
        Log_Debug("state.promisedProposalID = %U", state.promisedProposalID);
        Log_Debug("context->GetDatabase()->IsCommitting() = %b", context->GetDatabase()->IsCommitting());
        Log_Debug("context->IsPaxosBlocked() = %b", context->IsPaxosBlocked());
    }

    return reject;
}

void PaxosAcceptor::AcceptPrepareRequest(PaxosMessage& imsg)
{
    state.promisedProposalID = imsg.proposalID;

    senderID = imsg.nodeID;
    if (!state.accepted)
    {
        omsg.PrepareCurrentlyOpen(imsg.paxosID, MY_NODEID, imsg.proposalID);
    }
    else
    {
        ASSERT(state.acceptedValue.GetLength() > 0);
        omsg.PreparePreviouslyAccepted(imsg.paxosID, MY_NODEID,
         imsg.proposalID, state.acceptedProposalID,
         state.acceptedRunID, state.acceptedValue);
    }

    WriteState();
    Commit();
}

void PaxosAcceptor::AcceptProposeRequest(PaxosMessage& imsg)
{
    state.accepted = true;
    state.acceptedProposalID = imsg.proposalID;
    state.acceptedRunID = imsg.runID;
    ASSERT(imsg.value.GetLength() > 0);
    state.acceptedValue.Write(imsg.value);

    senderID = imsg.nodeID;
    omsg.ProposeAccepted(imsg.paxosID, MY_NODEID, imsg.proposalID);

    WriteState();
    Commit();
}
<|endoftext|>


<commit_before>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2018, Alex Fuller. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "GafferCycles/IECoreCyclesPreview/GeometryAlgo.h"

#include "IECoreScene/MeshPrimitive.h"
#include "IECoreScene/MeshAlgo.h"

#include "IECore/Interpolator.h"
#include "IECore/SimpleTypedData.h"

// Cycles
#include "kernel/types.h"
#include "scene/geometry.h"
#include "scene/mesh.h"
#include "subd/dice.h"
#include "util/param.h"
#include "util/types.h"

using namespace std;
using namespace Imath;
using namespace IECore;
using namespace IECoreScene;
using namespace IECoreCycles;

namespace
{

ccl::Mesh *convertCommon( const IECoreScene::MeshPrimitive *mesh )
{
	assert( mesh->typeId() == IECoreScene::MeshPrimitive::staticTypeId() );

	// Triangulate if necessary

	ConstMeshPrimitivePtr triangulatedMesh;
	if( mesh->interpolation() != "catmullClark" && mesh->maxVerticesPerFace() > 3 )
	{
		// Polygon meshes in Cycles must consist of triangles only.
		triangulatedMesh = MeshAlgo::triangulate( mesh );
		mesh = triangulatedMesh.get();
	}

	// Convert topology and points

	ccl::Mesh *cmesh = new ccl::Mesh();

	if( mesh->interpolation() == "catmullClark" )
	{
		const size_t numFaces = mesh->numFaces();
		const V3fVectorData *p = mesh->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
		const vector<Imath::V3f> &points = p->readable();
		const vector<int> &vertexIds = mesh->vertexIds()->readable();
		const size_t numVerts = points.size();
		cmesh->set_subdivision_type( (mesh->interpolation() == "catmullClark") ? ccl::Mesh::SUBDIVISION_CATMULL_CLARK : ccl::Mesh::SUBDIVISION_LINEAR );

		cmesh->reserve_mesh( numVerts, numFaces );
		for( size_t i = 0; i < numVerts; i++ )
			cmesh->add_vertex( ccl::make_float3( points[i].x, points[i].y, points[i].z ) );

		const std::vector<int> &vertsPerFace = mesh->verticesPerFace()->readable();
		size_t ngons = 0;
		size_t ncorners = 0;
		for( size_t i = 0; i < vertsPerFace.size(); i++ )
		{
			ngons += ( vertsPerFace[i] == 4 ) ? 0 : 1;
			ncorners += vertsPerFace[i];
		}
		cmesh->reserve_subd_faces(numFaces, ngons, ncorners);

		int indexOffset = 0;
		for( size_t i = 0; i < vertsPerFace.size(); i++ )
		{
			cmesh->add_subd_face(
				const_cast<int*>(&vertexIds[indexOffset]), vertsPerFace[i],
				/* shader = */ 0, /* smooth = */ true
			);
			indexOffset += vertsPerFace[i];
		}

		// Creases
		size_t numEdges = mesh->cornerIds()->readable().size();
		for( int length : mesh->creaseLengths()->readable() )
		{
			numEdges += length - 1;
		}

		if( numEdges )
		{
			cmesh->reserve_subd_creases( numEdges );

			auto id = mesh->creaseIds()->readable().begin();
			auto sharpness = mesh->creaseSharpnesses()->readable().begin();
			for( int length : mesh->creaseLengths()->readable() )
			{
				for( int j = 0; j < length - 1; ++j )
				{
					int v0 = *id++;
					int v1 = *id;
					float weight = (*sharpness) * 0.1f;
					cmesh->add_edge_crease( v0, v1, weight );
				}
				id++;
				sharpness++;
			}

			sharpness = mesh->cornerSharpnesses()->readable().begin();
			for( int cornerId : mesh->cornerIds()->readable() )
			{
				cmesh->add_vertex_crease( cornerId, (*sharpness) * 0.1f );
				sharpness++;
			}
		}
	}
	else
	{
		cmesh->set_subdivision_type( (mesh->interpolation() == "linear") ? ccl::Mesh::SUBDIVISION_LINEAR : ccl::Mesh::SUBDIVISION_NONE );

		const V3fVectorData *p = mesh->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
		const vector<Imath::V3f> &points = p->readable();
		const size_t numVerts = points.size();
		const std::vector<int> &vertexIds = mesh->vertexIds()->readable();

		const size_t numFaces = mesh->numFaces();
		cmesh->reserve_mesh( numVerts, numFaces );

		for( size_t i = 0; i < numVerts; i++ )
			cmesh->add_vertex( ccl::make_float3( points[i].x, points[i].y, points[i].z ) );

		for( size_t i = 0; i < vertexIds.size(); i+= 3 )
			cmesh->add_triangle(
				vertexIds[i], vertexIds[i+1], vertexIds[i+2],
				/* shader = */ 0, /* smooth = */ true
			);
	}

	// Convert primitive variables.

	for( const auto &[name, variable] : mesh->variables )
	{
		if( name == "P" )
		{
			// Converted above already
			continue;
		}
		switch( variable.interpolation )
		{
			case PrimitiveVariable::Constant :
				GeometryAlgo::convertPrimitiveVariable( name, variable, cmesh->attributes, ccl::ATTR_ELEMENT_MESH );
				break;
			case PrimitiveVariable::Uniform :
				GeometryAlgo::convertPrimitiveVariable( name, variable, cmesh->attributes, ccl::ATTR_ELEMENT_FACE );
				break;
			case PrimitiveVariable::Vertex :
			case PrimitiveVariable::Varying :
				GeometryAlgo::convertPrimitiveVariable( name, variable, cmesh->attributes, ccl::ATTR_ELEMENT_VERTEX );
				break;
			case PrimitiveVariable::FaceVarying :
				GeometryAlgo::convertPrimitiveVariable( name, variable, cmesh->attributes, ccl::ATTR_ELEMENT_CORNER );
				break;
			default :
				break;
		}
	}
	return cmesh;
}

ccl::Geometry *convert( const IECoreScene::MeshPrimitive *mesh, const std::string &nodeName, ccl::Scene *scene )
{
	ccl::Mesh *cmesh = convertCommon( mesh );
	cmesh->name = ccl::ustring( nodeName.c_str() );
	return cmesh;
}

ccl::Geometry *convert( const std::vector<const IECoreScene::MeshPrimitive *> &meshes, const std::vector<float> &times, const int frameIdx, const std::string &nodeName, ccl::Scene *scene )
{
	const int numSamples = meshes.size();

	ccl::Mesh *cmesh = nullptr;
	std::vector<const IECoreScene::MeshPrimitive *> samples;
	IECoreScene::MeshPrimitivePtr midMesh;

	if( frameIdx != -1 ) // Start/End frames
	{
		cmesh = convertCommon(meshes[frameIdx]);

		if( numSamples == 2 ) // Make sure we have 3 samples
		{
			const V3fVectorData *p1 = meshes[0]->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
			const V3fVectorData *p2 = meshes[1]->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
			if( p1 && p2 )
			{
				midMesh = meshes[frameIdx]->copy();
				V3fVectorData *midP = midMesh->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
				IECore::LinearInterpolator<std::vector<V3f>>()( p1->readable(), p2->readable(), 0.5f, midP->writable() );
				samples.push_back( midMesh.get() );
			}
		}

		for( int i = 0; i < numSamples; ++i )
		{
			if( i == frameIdx )
				continue;
			samples.push_back( meshes[i] );
		}
	}
	else if( numSamples % 2 ) // Odd numSamples
	{
		int _frameIdx = numSamples / 2;
		cmesh = convertCommon(meshes[_frameIdx]);

		for( int i = 0; i < numSamples; ++i )
		{
			if( i == _frameIdx )
				continue;
			samples.push_back( meshes[i] );
		}
	}
	else // Even numSamples
	{
		int _frameIdx = numSamples / 2 - 1;
		const V3fVectorData *p1 = meshes[_frameIdx]->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
		const V3fVectorData *p2 = meshes[_frameIdx+1]->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
		if( p1 && p2 )
		{
			midMesh = meshes[_frameIdx]->copy();
			V3fVectorData *midP = midMesh->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
			IECore::LinearInterpolator<std::vector<V3f>>()( p1->readable(), p2->readable(), 0.5f, midP->writable() );
			cmesh = convertCommon( midMesh.get() );
		}

		for( int i = 0; i < numSamples; ++i )
		{
			samples.push_back( meshes[i] );
		}
	}

	// Add the motion position attributes
	cmesh->set_use_motion_blur( true );
	cmesh->set_motion_steps( samples.size() + 1 );
	ccl::Attribute *attr_mP = cmesh->attributes.add( ccl::ATTR_STD_MOTION_VERTEX_POSITION, ccl::ustring("motion_P") );
	ccl::float3 *mP = attr_mP->data_float3();

	for( size_t i = 0; i < samples.size(); ++i )
	{
		PrimitiveVariableMap::const_iterator pIt = samples[i]->variables.find( "P" );
		if( pIt != samples[i]->variables.end() )
		{
			const V3fVectorData *p = runTimeCast<const V3fVectorData>( pIt->second.data.get() );
			if( p )
			{
				PrimitiveVariable::Interpolation pInterpolation = pIt->second.interpolation;
				if( pInterpolation == PrimitiveVariable::Varying || pInterpolation == PrimitiveVariable::Vertex || pInterpolation == PrimitiveVariable::FaceVarying )
				{
					// Vertex positions
					const V3fVectorData *p = samples[i]->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
					const std::vector<V3f> &points = p->readable();
					size_t numVerts = p->readable().size();

					for( size_t j = 0; j < numVerts; ++j, ++mP )
						*mP = ccl::make_float3( points[j].x, points[j].y, points[j].z );
				}
				else
				{
					msg( Msg::Warning, "IECoreCyles::MeshAlgo::convert", "Variable \"Position\" has unsupported interpolation type - not generating sampled Position." );
					cmesh->attributes.remove( attr_mP );
					cmesh->set_motion_steps( 0 );
					cmesh->set_use_motion_blur( false );
				}
			}
			else
			{
				msg( Msg::Warning, "IECoreCyles::MeshAlgo::convert", boost::format( "Variable \"Position\" has unsupported type \"%s\" (expected V3fVectorData)." ) % pIt->second.data->typeName() );
				cmesh->attributes.remove( attr_mP );
				cmesh->set_motion_steps( 0) ;
				cmesh->set_use_motion_blur( true );
			}
		}
	}

	cmesh->name = ccl::ustring( nodeName.c_str() );
	return cmesh;
}

GeometryAlgo::ConverterDescription<MeshPrimitive> g_description( convert, convert );

} // namespace
<commit_msg>Cycles MeshAlgo : Remove redundant comparison<commit_after>//////////////////////////////////////////////////////////////////////////
//
//  Copyright (c) 2018, Alex Fuller. All rights reserved.
//
//  Redistribution and use in source and binary forms, with or without
//  modification, are permitted provided that the following conditions are
//  met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//
//     * Neither the name of Image Engine Design nor the names of any
//       other contributors to this software may be used to endorse or
//       promote products derived from this software without specific prior
//       written permission.
//
//  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
//  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
//  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
//  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
//  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
//  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
//  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
//  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
//  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
//  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
//
//////////////////////////////////////////////////////////////////////////

#include "GafferCycles/IECoreCyclesPreview/GeometryAlgo.h"

#include "IECoreScene/MeshPrimitive.h"
#include "IECoreScene/MeshAlgo.h"

#include "IECore/Interpolator.h"
#include "IECore/SimpleTypedData.h"

// Cycles
#include "kernel/types.h"
#include "scene/geometry.h"
#include "scene/mesh.h"
#include "subd/dice.h"
#include "util/param.h"
#include "util/types.h"

using namespace std;
using namespace Imath;
using namespace IECore;
using namespace IECoreScene;
using namespace IECoreCycles;

namespace
{

ccl::Mesh *convertCommon( const IECoreScene::MeshPrimitive *mesh )
{
	assert( mesh->typeId() == IECoreScene::MeshPrimitive::staticTypeId() );

	// Triangulate if necessary

	ConstMeshPrimitivePtr triangulatedMesh;
	if( mesh->interpolation() != "catmullClark" && mesh->maxVerticesPerFace() > 3 )
	{
		// Polygon meshes in Cycles must consist of triangles only.
		triangulatedMesh = MeshAlgo::triangulate( mesh );
		mesh = triangulatedMesh.get();
	}

	// Convert topology and points

	ccl::Mesh *cmesh = new ccl::Mesh();

	if( mesh->interpolation() == "catmullClark" )
	{
		cmesh->set_subdivision_type( ccl::Mesh::SUBDIVISION_CATMULL_CLARK );

		const size_t numFaces = mesh->numFaces();
		const V3fVectorData *p = mesh->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
		const vector<Imath::V3f> &points = p->readable();
		const vector<int> &vertexIds = mesh->vertexIds()->readable();
		const size_t numVerts = points.size();

		cmesh->reserve_mesh( numVerts, numFaces );
		for( size_t i = 0; i < numVerts; i++ )
			cmesh->add_vertex( ccl::make_float3( points[i].x, points[i].y, points[i].z ) );

		const std::vector<int> &vertsPerFace = mesh->verticesPerFace()->readable();
		size_t ngons = 0;
		size_t ncorners = 0;
		for( size_t i = 0; i < vertsPerFace.size(); i++ )
		{
			ngons += ( vertsPerFace[i] == 4 ) ? 0 : 1;
			ncorners += vertsPerFace[i];
		}
		cmesh->reserve_subd_faces(numFaces, ngons, ncorners);

		int indexOffset = 0;
		for( size_t i = 0; i < vertsPerFace.size(); i++ )
		{
			cmesh->add_subd_face(
				const_cast<int*>(&vertexIds[indexOffset]), vertsPerFace[i],
				/* shader = */ 0, /* smooth = */ true
			);
			indexOffset += vertsPerFace[i];
		}

		// Creases
		size_t numEdges = mesh->cornerIds()->readable().size();
		for( int length : mesh->creaseLengths()->readable() )
		{
			numEdges += length - 1;
		}

		if( numEdges )
		{
			cmesh->reserve_subd_creases( numEdges );

			auto id = mesh->creaseIds()->readable().begin();
			auto sharpness = mesh->creaseSharpnesses()->readable().begin();
			for( int length : mesh->creaseLengths()->readable() )
			{
				for( int j = 0; j < length - 1; ++j )
				{
					int v0 = *id++;
					int v1 = *id;
					float weight = (*sharpness) * 0.1f;
					cmesh->add_edge_crease( v0, v1, weight );
				}
				id++;
				sharpness++;
			}

			sharpness = mesh->cornerSharpnesses()->readable().begin();
			for( int cornerId : mesh->cornerIds()->readable() )
			{
				cmesh->add_vertex_crease( cornerId, (*sharpness) * 0.1f );
				sharpness++;
			}
		}
	}
	else
	{
		cmesh->set_subdivision_type( (mesh->interpolation() == "linear") ? ccl::Mesh::SUBDIVISION_LINEAR : ccl::Mesh::SUBDIVISION_NONE );

		const V3fVectorData *p = mesh->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
		const vector<Imath::V3f> &points = p->readable();
		const size_t numVerts = points.size();
		const std::vector<int> &vertexIds = mesh->vertexIds()->readable();

		const size_t numFaces = mesh->numFaces();
		cmesh->reserve_mesh( numVerts, numFaces );

		for( size_t i = 0; i < numVerts; i++ )
			cmesh->add_vertex( ccl::make_float3( points[i].x, points[i].y, points[i].z ) );

		for( size_t i = 0; i < vertexIds.size(); i+= 3 )
			cmesh->add_triangle(
				vertexIds[i], vertexIds[i+1], vertexIds[i+2],
				/* shader = */ 0, /* smooth = */ true
			);
	}

	// Convert primitive variables.

	for( const auto &[name, variable] : mesh->variables )
	{
		if( name == "P" )
		{
			// Converted above already
			continue;
		}
		switch( variable.interpolation )
		{
			case PrimitiveVariable::Constant :
				GeometryAlgo::convertPrimitiveVariable( name, variable, cmesh->attributes, ccl::ATTR_ELEMENT_MESH );
				break;
			case PrimitiveVariable::Uniform :
				GeometryAlgo::convertPrimitiveVariable( name, variable, cmesh->attributes, ccl::ATTR_ELEMENT_FACE );
				break;
			case PrimitiveVariable::Vertex :
			case PrimitiveVariable::Varying :
				GeometryAlgo::convertPrimitiveVariable( name, variable, cmesh->attributes, ccl::ATTR_ELEMENT_VERTEX );
				break;
			case PrimitiveVariable::FaceVarying :
				GeometryAlgo::convertPrimitiveVariable( name, variable, cmesh->attributes, ccl::ATTR_ELEMENT_CORNER );
				break;
			default :
				break;
		}
	}
	return cmesh;
}

ccl::Geometry *convert( const IECoreScene::MeshPrimitive *mesh, const std::string &nodeName, ccl::Scene *scene )
{
	ccl::Mesh *cmesh = convertCommon( mesh );
	cmesh->name = ccl::ustring( nodeName.c_str() );
	return cmesh;
}

ccl::Geometry *convert( const std::vector<const IECoreScene::MeshPrimitive *> &meshes, const std::vector<float> &times, const int frameIdx, const std::string &nodeName, ccl::Scene *scene )
{
	const int numSamples = meshes.size();

	ccl::Mesh *cmesh = nullptr;
	std::vector<const IECoreScene::MeshPrimitive *> samples;
	IECoreScene::MeshPrimitivePtr midMesh;

	if( frameIdx != -1 ) // Start/End frames
	{
		cmesh = convertCommon(meshes[frameIdx]);

		if( numSamples == 2 ) // Make sure we have 3 samples
		{
			const V3fVectorData *p1 = meshes[0]->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
			const V3fVectorData *p2 = meshes[1]->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
			if( p1 && p2 )
			{
				midMesh = meshes[frameIdx]->copy();
				V3fVectorData *midP = midMesh->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
				IECore::LinearInterpolator<std::vector<V3f>>()( p1->readable(), p2->readable(), 0.5f, midP->writable() );
				samples.push_back( midMesh.get() );
			}
		}

		for( int i = 0; i < numSamples; ++i )
		{
			if( i == frameIdx )
				continue;
			samples.push_back( meshes[i] );
		}
	}
	else if( numSamples % 2 ) // Odd numSamples
	{
		int _frameIdx = numSamples / 2;
		cmesh = convertCommon(meshes[_frameIdx]);

		for( int i = 0; i < numSamples; ++i )
		{
			if( i == _frameIdx )
				continue;
			samples.push_back( meshes[i] );
		}
	}
	else // Even numSamples
	{
		int _frameIdx = numSamples / 2 - 1;
		const V3fVectorData *p1 = meshes[_frameIdx]->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
		const V3fVectorData *p2 = meshes[_frameIdx+1]->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
		if( p1 && p2 )
		{
			midMesh = meshes[_frameIdx]->copy();
			V3fVectorData *midP = midMesh->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
			IECore::LinearInterpolator<std::vector<V3f>>()( p1->readable(), p2->readable(), 0.5f, midP->writable() );
			cmesh = convertCommon( midMesh.get() );
		}

		for( int i = 0; i < numSamples; ++i )
		{
			samples.push_back( meshes[i] );
		}
	}

	// Add the motion position attributes
	cmesh->set_use_motion_blur( true );
	cmesh->set_motion_steps( samples.size() + 1 );
	ccl::Attribute *attr_mP = cmesh->attributes.add( ccl::ATTR_STD_MOTION_VERTEX_POSITION, ccl::ustring("motion_P") );
	ccl::float3 *mP = attr_mP->data_float3();

	for( size_t i = 0; i < samples.size(); ++i )
	{
		PrimitiveVariableMap::const_iterator pIt = samples[i]->variables.find( "P" );
		if( pIt != samples[i]->variables.end() )
		{
			const V3fVectorData *p = runTimeCast<const V3fVectorData>( pIt->second.data.get() );
			if( p )
			{
				PrimitiveVariable::Interpolation pInterpolation = pIt->second.interpolation;
				if( pInterpolation == PrimitiveVariable::Varying || pInterpolation == PrimitiveVariable::Vertex || pInterpolation == PrimitiveVariable::FaceVarying )
				{
					// Vertex positions
					const V3fVectorData *p = samples[i]->variableData<V3fVectorData>( "P", PrimitiveVariable::Vertex );
					const std::vector<V3f> &points = p->readable();
					size_t numVerts = p->readable().size();

					for( size_t j = 0; j < numVerts; ++j, ++mP )
						*mP = ccl::make_float3( points[j].x, points[j].y, points[j].z );
				}
				else
				{
					msg( Msg::Warning, "IECoreCyles::MeshAlgo::convert", "Variable \"Position\" has unsupported interpolation type - not generating sampled Position." );
					cmesh->attributes.remove( attr_mP );
					cmesh->set_motion_steps( 0 );
					cmesh->set_use_motion_blur( false );
				}
			}
			else
			{
				msg( Msg::Warning, "IECoreCyles::MeshAlgo::convert", boost::format( "Variable \"Position\" has unsupported type \"%s\" (expected V3fVectorData)." ) % pIt->second.data->typeName() );
				cmesh->attributes.remove( attr_mP );
				cmesh->set_motion_steps( 0) ;
				cmesh->set_use_motion_blur( true );
			}
		}
	}

	cmesh->name = ccl::ustring( nodeName.c_str() );
	return cmesh;
}

GeometryAlgo::ConverterDescription<MeshPrimitive> g_description( convert, convert );

} // namespace
<|endoftext|>


<commit_before>/**
 * This code is auto-generated; unless you know what you're doing, do not modify!
 **/
#include <v8.h>
#include <node.h>
#include <string>

#include "../include/wrapper.h"
#include "node_buffer.h"

using namespace v8;
using namespace node;

Wrapper::Wrapper(void *raw) {
  this->raw = raw;
}

void Wrapper::Initialize(Handle<v8::Object> target) {
  HandleScope scope;

  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);

  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  tpl->SetClassName(String::NewSymbol("Wrapper"));

  NODE_SET_PROTOTYPE_METHOD(tpl, "toBuffer", ToBuffer);

  constructor_template = Persistent<Function>::New(tpl->GetFunction());
  target->Set(String::NewSymbol("Wrapper"), constructor_template);
}

Handle<Value> Wrapper::New(const Arguments& args) {
  HandleScope scope;

  if (args.Length() == 0 || !args[0]->IsExternal()) {
    return ThrowException(Exception::Error(String::New("void * is required.")));
  }

  Wrapper* object = new Wrapper(External::Unwrap(args[0]));
  object->Wrap(args.This());

  return scope.Close(args.This());
}

Handle<Value> Wrapper::New(void *raw) {
  HandleScope scope;

  Handle<Value> argv[1] = { External::New((void *)raw) };
  return scope.Close(Wrapper::constructor_template->NewInstance(1, argv));
}

void *Wrapper::GetValue() {
  return this->raw;
}

Handle<Value> Wrapper::ToBuffer(const Arguments& args) {
  HandleScope scope;

  if(args.Length() == 0 || !args[0]->IsNumber()) {
    return ThrowException(Exception::Error(String::New("Number is required.")));
  }

  int len = args[0]->ToNumber()->Value();

  Local<Function> bufferConstructor = Local<Function>::Cast(
    Context::GetCurrent()->Global()->Get(String::New("Buffer")));

  Handle<Value> constructorArgs[1] = { Integer::New(len) };
  Local<Object> nodeBuffer = bufferConstructor->NewInstance(1, constructorArgs);

  memcpy(node::Buffer::Data(nodeBuffer), ObjectWrap::Unwrap<Wrapper>(args.This())->GetValue(), len);

  return scope.Close(nodeBuffer);
}

Persistent<Function> Wrapper::constructor_template;
<commit_msg>Fixed compile error: memcpy not defined<commit_after>/**
 * This code is auto-generated; unless you know what you're doing, do not modify!
 **/
#include <v8.h>
#include <node.h>
#include <string>
#include <cstring>

#include "../include/wrapper.h"
#include "node_buffer.h"

using namespace v8;
using namespace node;

Wrapper::Wrapper(void *raw) {
  this->raw = raw;
}

void Wrapper::Initialize(Handle<v8::Object> target) {
  HandleScope scope;

  Local<FunctionTemplate> tpl = FunctionTemplate::New(New);

  tpl->InstanceTemplate()->SetInternalFieldCount(1);
  tpl->SetClassName(String::NewSymbol("Wrapper"));

  NODE_SET_PROTOTYPE_METHOD(tpl, "toBuffer", ToBuffer);

  constructor_template = Persistent<Function>::New(tpl->GetFunction());
  target->Set(String::NewSymbol("Wrapper"), constructor_template);
}

Handle<Value> Wrapper::New(const Arguments& args) {
  HandleScope scope;

  if (args.Length() == 0 || !args[0]->IsExternal()) {
    return ThrowException(Exception::Error(String::New("void * is required.")));
  }

  Wrapper* object = new Wrapper(External::Unwrap(args[0]));
  object->Wrap(args.This());

  return scope.Close(args.This());
}

Handle<Value> Wrapper::New(void *raw) {
  HandleScope scope;

  Handle<Value> argv[1] = { External::New((void *)raw) };
  return scope.Close(Wrapper::constructor_template->NewInstance(1, argv));
}

void *Wrapper::GetValue() {
  return this->raw;
}

Handle<Value> Wrapper::ToBuffer(const Arguments& args) {
  HandleScope scope;

  if(args.Length() == 0 || !args[0]->IsNumber()) {
    return ThrowException(Exception::Error(String::New("Number is required.")));
  }

  int len = args[0]->ToNumber()->Value();

  Local<Function> bufferConstructor = Local<Function>::Cast(
    Context::GetCurrent()->Global()->Get(String::New("Buffer")));

  Handle<Value> constructorArgs[1] = { Integer::New(len) };
  Local<Object> nodeBuffer = bufferConstructor->NewInstance(1, constructorArgs);

  std::memcpy(node::Buffer::Data(nodeBuffer), ObjectWrap::Unwrap<Wrapper>(args.This())->GetValue(), len);

  return scope.Close(nodeBuffer);
}

Persistent<Function> Wrapper::constructor_template;
<|endoftext|>


<commit_before>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "DMSrcSink.h"
#include "DMSrcSinkAndroid.h"

#include "SkAndroidSDKCanvas.h"
#include "SkCanvas.h"
#include "SkiaCanvasProxy.h"
#include "SkStream.h"
#include <utils/TestWindowContext.h>

/* These functions are only compiled in the Android Framework. */

namespace DM {

Error HWUISink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
    android::uirenderer::TestWindowContext renderer;
    renderer.initialize(src.size().width(), src.size().height());
    SkCanvas* canvas = renderer.prepareToDraw();
    Error err = src.draw(canvas);
    if (!err.isEmpty()) {
        return err;
    }
    renderer.finishDrawing();
    renderer.fence();
    renderer.capturePixels(dst);
    return "";
}

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

ViaAndroidSDK::ViaAndroidSDK(Sink* sink) : fSink(sink) { }

Error ViaAndroidSDK::draw(const Src& src,
                          SkBitmap* bitmap,
                          SkWStream* stream,
                          SkString* log) const {
    struct ProxySrc : public Src {
        const Src& fSrc;
        ProxySrc(const Src& src)
            : fSrc(src) {}

        Error draw(SkCanvas* canvas) const override {
            // Pass through HWUI's upper layers to get operational transforms
            std::unique_ptr<android::Canvas> ac(android::Canvas::create_canvas(canvas));
            sk_sp<android::uirenderer::SkiaCanvasProxy> scProxy
                (new android::uirenderer::SkiaCanvasProxy(ac.get()));

            // Pass through another proxy to get paint transforms
            SkAndroidSDKCanvas fc;
            fc.reset(scProxy.get());

            fSrc.draw(&fc);

            return "";
        }
        SkISize size() const override { return fSrc.size(); }
        Name name() const override { sk_throw(); return ""; }
    } proxy(src);

    return fSink->draw(proxy, bitmap, stream, log);
}

}  // namespace DM
<commit_msg>don't rely on canvas being reference counted<commit_after>/*
 * Copyright 2015 Google Inc.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

#include "DMSrcSink.h"
#include "DMSrcSinkAndroid.h"

#include "SkAndroidSDKCanvas.h"
#include "SkCanvas.h"
#include "SkiaCanvasProxy.h"
#include "SkStream.h"
#include <utils/TestWindowContext.h>

/* These functions are only compiled in the Android Framework. */

namespace DM {

Error HWUISink::draw(const Src& src, SkBitmap* dst, SkWStream*, SkString*) const {
    android::uirenderer::TestWindowContext renderer;
    renderer.initialize(src.size().width(), src.size().height());
    SkCanvas* canvas = renderer.prepareToDraw();
    Error err = src.draw(canvas);
    if (!err.isEmpty()) {
        return err;
    }
    renderer.finishDrawing();
    renderer.fence();
    renderer.capturePixels(dst);
    return "";
}

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

ViaAndroidSDK::ViaAndroidSDK(Sink* sink) : fSink(sink) { }

Error ViaAndroidSDK::draw(const Src& src,
                          SkBitmap* bitmap,
                          SkWStream* stream,
                          SkString* log) const {
    struct ProxySrc : public Src {
        const Src& fSrc;
        ProxySrc(const Src& src)
            : fSrc(src) {}

        Error draw(SkCanvas* canvas) const override {
            // Pass through HWUI's upper layers to get operational transforms
            std::unique_ptr<android::Canvas> ac(android::Canvas::create_canvas(canvas));
            std::unique_ptr<android::uirenderer::SkiaCanvasProxy> scProxy
                (new android::uirenderer::SkiaCanvasProxy(ac.get()));

            // Pass through another proxy to get paint transforms
            SkAndroidSDKCanvas fc;
            fc.reset(scProxy.get());

            fSrc.draw(&fc);

            return "";
        }
        SkISize size() const override { return fSrc.size(); }
        Name name() const override { sk_throw(); return ""; }
    } proxy(src);

    return fSink->draw(proxy, bitmap, stream, log);
}

}  // namespace DM
<|endoftext|>


<commit_before>/**
 * Copyright (C) 2003-2006 Funambol
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include "base/fscapi.h"
#include "base/Log.h"
#include "base/util/XMLProcessor.h"
#include "syncml/formatter/Formatter.h"
#include "spds/FileData.h"
#include "base/quoted-printable.h"

#define FILE_ITEM       TEXT("File")
#define FILE_HIDDEN     T("h")
#define FILE_SYSTEM     T("s")
#define FILE_ARCHIVED   T("a")
#define FILE_DELETE     T("d")
#define FILE_WRITABLE   T("w")
#define FILE_READABLE   T("r")
#define FILE_EXECUTABLE T("e")
#define FILE_ACCESSED   T("accessed")
#define FILE_ATTRIBUTES T("attributes")
#define FILE_BODY       T("body")
#define FILE_CTTYTPE    T("cttype")
#define FILE_ENC        T("enc")
#define FILE_MODIFIED   T("modified")
#define FILE_NAME       T("name")
#define FILE_SIZE       T("size")
#define FILE_CREATED    T("created")

FileData::FileData()
{
    size = 0;
	hidden = false;
	system = false;
	archived = false;
	deleted = false;
	writable = false;
	readable = false;
	executable = false;
    isHiddenPresent = false;
    isSystemPresent = false;
    isArchivedPresent = false;
    isDeletedPresent = false;
    isWritablePresent = false;
    isReadablePresent = false;
    isExecutablePresent = false;

}

FileData::~FileData()
{
    accessed.reset();
    attributes.reset();
    enc.reset();
    file.reset();
    modified.reset();
    name.reset();
    created.reset();
    body.reset();
    cttype.reset();

}
int FileData::parse(const char *syncmlData, size_t len)
{
    int ret = 0;
    unsigned int start, end;
    StringBuffer* s = new StringBuffer(syncmlData, len);
    StringBuffer bodyattr;

    // FIXME: remove these replace once the server has fixed the message.
    s->replaceAll(T("<"), T("<"));
    s->replaceAll(T(">"), T(">"));
    s->replaceAll(T("&"), T("&"));

    // Get the CDATA content
    if(XMLProcessor::getElementContent(s->c_str(), T("CDATA"), NULL, &start, &end) == 0) {
        LOG.error(T("FileData: can't find outer CDATA section."));
        return -1;
    }
    StringBuffer msg = s->substr(start, end-start);

    delete s;

    // Get attributes
    if( XMLProcessor::getElementContent (msg, FILE_HIDDEN, NULL, &start, &end) ) {
        hidden = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isHiddenPresent = true;
    }
    else hidden = false;

    if( XMLProcessor::getElementContent (msg, FILE_SYSTEM, NULL, &start, &end) ) {
        system = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isSystemPresent = true;
    }
    else system = false;

    if( XMLProcessor::getElementContent (msg, FILE_ARCHIVED, NULL, &start, &end) ) {
        archived = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isArchivedPresent = true;
    }
    else archived = false;

    if( XMLProcessor::getElementContent (msg, FILE_DELETE, NULL, &start, &end) ) {
        deleted = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isDeletedPresent = true;
    }
    else deleted = false;

    if( XMLProcessor::getElementContent (msg, FILE_WRITABLE, NULL, &start, &end) ) {
        writable = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isWritablePresent = true;
    }
    else writable = false;

    if( XMLProcessor::getElementContent (msg, FILE_READABLE, NULL, &start, &end) ) {
        readable = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isReadablePresent = true;
    }
    else readable = false;

    if( XMLProcessor::getElementContent (msg, FILE_EXECUTABLE, NULL, &start, &end) ) {
        executable = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isExecutablePresent = true;
    }
    else executable = false;

    if( XMLProcessor::getElementContent (msg, FILE_ACCESSED, NULL, &start, &end) ) {
        accessed = msg.substr(start, end-start);
    }
    else accessed = TEXT("");

    if( XMLProcessor::getElementContent (msg, FILE_MODIFIED, NULL, &start, &end) ) {
        modified = msg.substr(start, end-start);
    }
    else modified = TEXT("");

    if( XMLProcessor::getElementContent (msg, FILE_CREATED, NULL, &start, &end) ) {
        created = msg.substr(start, end-start);
    }
    else created = TEXT("");

    if ( XMLProcessor::getElementContent (msg, FILE_SIZE, NULL, &start, &end) ) {
        size = atoi(msg.substr(start, end-start));
    }

    if( XMLProcessor::getElementContent (msg, FILE_BODY, NULL, &start, &end) ) {
        body = msg.substr(start, end-start);
    }
    else body = "";
    if ( XMLProcessor::getElementAttributes (msg, FILE_BODY, &start, &end) ) {
        bodyattr = msg.substr(start, end-start);
        size_t attrstart = bodyattr.ifind("enc");
        if (attrstart!= StringBuffer::npos) {
            enc = bodyattr.substr(attrstart + 4);
            if (!enc.empty() && (enc != TEXT("\"base64\"")) &&
                (enc != TEXT("\"quoted-printable\"")))
            {
                enc = TEXT("");
            }
            else
            {
                int repNo = enc.replaceAll(TEXT("\""),TEXT(""));
            }
        }
        else
            enc = TEXT("");
    }
    else
        enc = TEXT("");

    if (!enc.empty() && (enc == TEXT("base64")))
    {
        int len = b64_decode((void *)body.c_str(), body.c_str());
    }

    if (!enc.empty() && (enc == TEXT("quoted-printable")))
    {
        body = qp_decode(body.c_str());
    }

    if( XMLProcessor::getElementContent (msg, FILE_NAME, NULL, &start, &end) ) {
        name = msg.substr(start, end-start);
    }
    else name = TEXT("");

    return ret;
}

void FileData::setBody(const char* v, int len)
{
    if (size == 0)
    {
        body = v;
    }
    else
    {
        char*   base64    = NULL;
        int     encodeLen = lengthForB64(len);
        base64 = new char[encodeLen + 1];
        memset(base64, 0, encodeLen + 1);
        b64_encode(base64, (char*)v, len);
        body = base64;
    }
}

char* FileData::format() {

    StringBuffer out;

    out.reserve(150);

    out = T("<File>\n");
    if (name.length() > 0)
        out += XMLProcessor::makeElement(FILE_NAME, _wcc(name));
    if (created.length() > 0)
        out += XMLProcessor::makeElement(FILE_CREATED, _wcc(created));
    if (modified.length() > 0)
        out += XMLProcessor::makeElement(FILE_MODIFIED, _wcc(modified));
    if (accessed.length() > 0)
        out += XMLProcessor::makeElement(FILE_ACCESSED, _wcc(accessed));

    StringBuffer attributes;

    if (isHiddenPresent)
        attributes += XMLProcessor::makeElement(FILE_HIDDEN, hidden);
    if (isSystemPresent)
        attributes += XMLProcessor::makeElement(FILE_SYSTEM, system);
    if (isArchivedPresent)
        attributes += XMLProcessor::makeElement(FILE_ARCHIVED, archived);
    if (isDeletedPresent)
        attributes += XMLProcessor::makeElement(FILE_DELETE, deleted);
    if (isWritablePresent)
        attributes += XMLProcessor::makeElement(FILE_WRITABLE, writable);
    if (isReadablePresent)
        attributes += XMLProcessor::makeElement(FILE_READABLE, readable);
    if (isExecutablePresent)
        attributes += XMLProcessor::makeElement(FILE_EXECUTABLE, executable);
    if (!attributes.empty())
        out += XMLProcessor::makeElement(FILE_ATTRIBUTES, attributes);

    if (enc.empty()){
        int len = b64_decode((void*)body.c_str(), body.c_str());
        out += XMLProcessor::makeElement(FILE_BODY, body);
    }
    else
    {
        ArrayList attrList;
        KeyValuePair attr("enc", _wcc(enc.c_str()));
        attrList.add(attr);
        out += XMLProcessor::makeElement(FILE_BODY, body.c_str(), attrList);
    }
    if (size > 0)
        out += XMLProcessor::makeElement(FILE_SIZE, size);
    out += T("</File>\n");
    return stringdup(out.c_str());
}

int FileData::lengthForB64(int len) {

    int modules = 0;
    int ret     = 0;

    modules = len % 3;
    if (modules == 0) {
        ret = 4 * (len / 3);

    } else {
        ret = 4 * ((len/3) + 1);

    }
    return ret;

}
<commit_msg>modified parse() function, added handling for <File> item, for fixing the case of new/updated Files from server<commit_after>/**
 * Copyright (C) 2003-2006 Funambol
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 * MA 02111-1307 USA
 */

#include "base/fscapi.h"
#include "base/Log.h"
#include "base/util/XMLProcessor.h"
#include "syncml/formatter/Formatter.h"
#include "spds/FileData.h"
#include "base/quoted-printable.h"

#define FILE_ITEM       TEXT("File")
#define FILE_HIDDEN     T("h")
#define FILE_SYSTEM     T("s")
#define FILE_ARCHIVED   T("a")
#define FILE_DELETE     T("d")
#define FILE_WRITABLE   T("w")
#define FILE_READABLE   T("r")
#define FILE_EXECUTABLE T("e")
#define FILE_ACCESSED   T("accessed")
#define FILE_ATTRIBUTES T("attributes")
#define FILE_BODY       T("body")
#define FILE_CTTYTPE    T("cttype")
#define FILE_ENC        T("enc")
#define FILE_MODIFIED   T("modified")
#define FILE_NAME       T("name")
#define FILE_SIZE       T("size")
#define FILE_CREATED    T("created")

FileData::FileData()
{
    size = 0;
	hidden = false;
	system = false;
	archived = false;
	deleted = false;
	writable = false;
	readable = false;
	executable = false;
    isHiddenPresent = false;
    isSystemPresent = false;
    isArchivedPresent = false;
    isDeletedPresent = false;
    isWritablePresent = false;
    isReadablePresent = false;
    isExecutablePresent = false;

}

FileData::~FileData()
{
    accessed.reset();
    attributes.reset();
    enc.reset();
    file.reset();
    modified.reset();
    name.reset();
    created.reset();
    body.reset();
    cttype.reset();

}
int FileData::parse(const char *syncmlData, size_t len)
{
    int ret = 0;
    unsigned int start, end;
    StringBuffer* s = new StringBuffer(syncmlData, len);
    StringBuffer bodyattr;

    // FIXME: remove these replace once the server has fixed the message.
    s->replaceAll(T("<"), T("<"));
    s->replaceAll(T(">"), T(">"));
    s->replaceAll(T("&"), T("&"));

	/*
    // Get the CDATA content
    if(XMLProcessor::getElementContent(s->c_str(), T("CDATA"), NULL, &start, &end) == 0) {
        LOG.error(T("FileData: can't find outer CDATA section."));
        return -1;
    }
    StringBuffer msg = s->substr(start, end-start);

    delete s;
	*/

	if(XMLProcessor::getElementContent(s->c_str(), T("File"), NULL, &start, &end) == 0) {
		LOG.error(T("FileData: can't find outer FILE section."));
		return -1;
	}
	StringBuffer msg = s->substr(start, end-start);

    // Get attributes
    if( XMLProcessor::getElementContent (msg, FILE_HIDDEN, NULL, &start, &end) ) {
        hidden = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isHiddenPresent = true;
    }
    else hidden = false;

    if( XMLProcessor::getElementContent (msg, FILE_SYSTEM, NULL, &start, &end) ) {
        system = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isSystemPresent = true;
    }
    else system = false;

    if( XMLProcessor::getElementContent (msg, FILE_ARCHIVED, NULL, &start, &end) ) {
        archived = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isArchivedPresent = true;
    }
    else archived = false;

    if( XMLProcessor::getElementContent (msg, FILE_DELETE, NULL, &start, &end) ) {
        deleted = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isDeletedPresent = true;
    }
    else deleted = false;

    if( XMLProcessor::getElementContent (msg, FILE_WRITABLE, NULL, &start, &end) ) {
        writable = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isWritablePresent = true;
    }
    else writable = false;

    if( XMLProcessor::getElementContent (msg, FILE_READABLE, NULL, &start, &end) ) {
        readable = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isReadablePresent = true;
    }
    else readable = false;

    if( XMLProcessor::getElementContent (msg, FILE_EXECUTABLE, NULL, &start, &end) ) {
        executable = ( strncmp(msg.c_str()+start, T("true"), end-start) == 0 ) ;
        isExecutablePresent = true;
    }
    else executable = false;

    if( XMLProcessor::getElementContent (msg, FILE_ACCESSED, NULL, &start, &end) ) {
        accessed = msg.substr(start, end-start);
    }
    else accessed = TEXT("");

    if( XMLProcessor::getElementContent (msg, FILE_MODIFIED, NULL, &start, &end) ) {
        modified = msg.substr(start, end-start);
    }
    else modified = TEXT("");

    if( XMLProcessor::getElementContent (msg, FILE_CREATED, NULL, &start, &end) ) {
        created = msg.substr(start, end-start);
    }
    else created = TEXT("");

    if ( XMLProcessor::getElementContent (msg, FILE_SIZE, NULL, &start, &end) ) {
        size = atoi(msg.substr(start, end-start));
    }

    if( XMLProcessor::getElementContent (msg, FILE_BODY, NULL, &start, &end) ) {
        body = msg.substr(start, end-start);
    }
    else body = "";
    if ( XMLProcessor::getElementAttributes (msg, FILE_BODY, &start, &end) ) {
        bodyattr = msg.substr(start, end-start);
        size_t attrstart = bodyattr.ifind("enc");
        if (attrstart!= StringBuffer::npos) {
            enc = bodyattr.substr(attrstart + 4);
            if (!enc.empty() && (enc != TEXT("\"base64\"")) &&
                (enc != TEXT("\"quoted-printable\"")))
            {
                enc = TEXT("");
            }
            else
            {
                int repNo = enc.replaceAll(TEXT("\""),TEXT(""));
            }
        }
        else
            enc = TEXT("");
    }
    else
        enc = TEXT("");

    if (!enc.empty() && (enc == TEXT("base64")))
    {
        int len = b64_decode((void *)body.c_str(), body.c_str());
    }

    if (!enc.empty() && (enc == TEXT("quoted-printable")))
    {
        body = qp_decode(body.c_str());
    }

    if( XMLProcessor::getElementContent (msg, FILE_NAME, NULL, &start, &end) ) {
        name = msg.substr(start, end-start);
    }
    else name = TEXT("");

	delete s;

    return ret;
}

void FileData::setBody(const char* v, int len)
{
    if (size == 0)
    {
        body = v;
    }
    else
    {
        char*   base64    = NULL;
        int     encodeLen = lengthForB64(len);
        base64 = new char[encodeLen + 1];
        memset(base64, 0, encodeLen + 1);
        b64_encode(base64, (char*)v, len);
        body = base64;
    }
}

char* FileData::format() {

    StringBuffer out;

    out.reserve(150);

    out = T("<File>\n");
    if (name.length() > 0)
        out += XMLProcessor::makeElement(FILE_NAME, _wcc(name));
    if (created.length() > 0)
        out += XMLProcessor::makeElement(FILE_CREATED, _wcc(created));
    if (modified.length() > 0)
        out += XMLProcessor::makeElement(FILE_MODIFIED, _wcc(modified));
    if (accessed.length() > 0)
        out += XMLProcessor::makeElement(FILE_ACCESSED, _wcc(accessed));

    StringBuffer attributes;

    if (isHiddenPresent)
        attributes += XMLProcessor::makeElement(FILE_HIDDEN, hidden);
    if (isSystemPresent)
        attributes += XMLProcessor::makeElement(FILE_SYSTEM, system);
    if (isArchivedPresent)
        attributes += XMLProcessor::makeElement(FILE_ARCHIVED, archived);
    if (isDeletedPresent)
        attributes += XMLProcessor::makeElement(FILE_DELETE, deleted);
    if (isWritablePresent)
        attributes += XMLProcessor::makeElement(FILE_WRITABLE, writable);
    if (isReadablePresent)
        attributes += XMLProcessor::makeElement(FILE_READABLE, readable);
    if (isExecutablePresent)
        attributes += XMLProcessor::makeElement(FILE_EXECUTABLE, executable);
    if (!attributes.empty())
        out += XMLProcessor::makeElement(FILE_ATTRIBUTES, attributes);

    if (enc.empty()){
        int len = b64_decode((void*)body.c_str(), body.c_str());
        out += XMLProcessor::makeElement(FILE_BODY, body);
    }
    else
    {
        ArrayList attrList;
        KeyValuePair attr("enc", _wcc(enc.c_str()));
        attrList.add(attr);
        out += XMLProcessor::makeElement(FILE_BODY, body.c_str(), attrList);
    }
    if (size > 0)
        out += XMLProcessor::makeElement(FILE_SIZE, size);
    out += T("</File>\n");
    return stringdup(out.c_str());
}

int FileData::lengthForB64(int len) {

    int modules = 0;
    int ret     = 0;

    modules = len % 3;
    if (modules == 0) {
        ret = 4 * (len / 3);

    } else {
        ret = 4 * ((len/3) + 1);

    }
    return ret;

}
<|endoftext|>


<commit_before> /*
 * Copyright (C) 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY, TITLE, NONINFRINGEMENT or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307  USA
*/

#include "vocl/WinItem.h"

using namespace std;

// Init static member.
wstring WinItem::badString = L"<NULL>";

// Constructor
WinItem::WinItem() {}

// Destructor
WinItem::~WinItem() {}

// Sets a value into propertyMap.
void WinItem::setProperty(const wstring propertyName, const wstring propertyValue) {
    propertyMap[propertyName] = propertyValue;
}

// Gets a value from propertyMap.
bool WinItem::getProperty(const wstring propertyName, wstring& propertyValue){

    map<wstring,wstring>::iterator it = propertyMap.find(propertyName);
    if (it != propertyMap.end()) {
        // Found
        propertyValue = it->second;
        return true;
    }
    else {
        // Not found
        propertyValue = L"";
        return false;
    }
}

// Gets a value from propertyMap.
wstring& WinItem::getPropertyRef(const wstring propertyName, bool* found) {

    map<wstring,wstring>::iterator it = propertyMap.find(propertyName);
    if (it != propertyMap.end()) {
        // Found
        *found = true;
        return it->second;
    }
    else {
        // Not found
        *found = false;
        return badString;
    }
}

int WinItem::getPropertyMapSize() {
    return propertyMap.size();
}

void WinItem::resetPropertyMap() {
    propertyMap.clear();
}

void WinItem::removeElement(wstring key) {

    propertyMap.erase(key);
}

void WinItem::resetAllValues() {

    map<wstring,wstring>::iterator it = propertyMap.begin();
    while (it != propertyMap.end()) {
        it->second = L"";
        it ++;
    }
}

long WinItem::getCRC() {

    wstring values;

    map<wstring,wstring>::iterator it = propertyMap.begin();
    while (it != propertyMap.end()) {
        values.append(it->second);
        it ++;
    }
    const WCHAR* s = values.c_str();
    unsigned long crc32Table[256] =
    {
        0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
        0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
        0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
        0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
        0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
        0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
        0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
        0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
        0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
        0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
        0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
        0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
        0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
        0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
        0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
        0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,

        0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
        0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
        0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
        0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
        0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
        0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
        0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
        0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
        0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
        0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
        0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
        0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
        0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
        0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
        0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
        0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,

        0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
        0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
        0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
        0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
        0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
        0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
        0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
        0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
        0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
        0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
        0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
        0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
        0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
        0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
        0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
        0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,

        0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
        0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
        0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
        0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
        0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
        0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
        0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
        0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
        0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
        0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
        0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
        0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
        0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
        0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
        0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
        0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
    };

    unsigned long crc32 = 0;
    unsigned long dwErrorCode = NO_ERROR;
    unsigned char byte = 0;

    crc32 = 0xFFFFFFFF;
    while(*s != TEXT('\0')) {
        byte = (unsigned char) *s;
        crc32 = ((crc32) >> 8) ^ crc32Table[(byte) ^ ((crc32) & 0x000000FF)];
        s++;
    }
    crc32 = ~crc32;

    return crc32;

}<commit_msg>added getVObjectPropertyValue(), used by many derived classes<commit_after> /*
 * Copyright (C) 2007 Funambol, Inc.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 as
 * published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY, TITLE, NONINFRINGEMENT or FITNESS FOR A PARTICULAR
 * PURPOSE.  See the GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
 * 02111-1307  USA
*/

#include "vocl/WinItem.h"

using namespace std;

// Init static member.
wstring WinItem::badString = L"<NULL>";

// Constructor
WinItem::WinItem() {}

// Destructor
WinItem::~WinItem() {}

// Sets a value into propertyMap.
void WinItem::setProperty(const wstring propertyName, const wstring propertyValue) {
    propertyMap[propertyName] = propertyValue;
}

// Gets a value from propertyMap.
bool WinItem::getProperty(const wstring propertyName, wstring& propertyValue){

    map<wstring,wstring>::iterator it = propertyMap.find(propertyName);
    if (it != propertyMap.end()) {
        // Found
        propertyValue = it->second;
        return true;
    }
    else {
        // Not found
        propertyValue = L"";
        return false;
    }
}

// Gets a value from propertyMap.
wstring& WinItem::getPropertyRef(const wstring propertyName, bool* found) {

    map<wstring,wstring>::iterator it = propertyMap.find(propertyName);
    if (it != propertyMap.end()) {
        // Found
        *found = true;
        return it->second;
    }
    else {
        // Not found
        *found = false;
        return badString;
    }
}

int WinItem::getPropertyMapSize() {
    return propertyMap.size();
}

void WinItem::resetPropertyMap() {
    propertyMap.clear();
}

void WinItem::removeElement(wstring key) {

    propertyMap.erase(key);
}

void WinItem::resetAllValues() {

    map<wstring,wstring>::iterator it = propertyMap.begin();
    while (it != propertyMap.end()) {
        it->second = L"";
        it ++;
    }
}

long WinItem::getCRC() {

    wstring values;

    map<wstring,wstring>::iterator it = propertyMap.begin();
    while (it != propertyMap.end()) {
        values.append(it->second);
        it ++;
    }
    const WCHAR* s = values.c_str();
    unsigned long crc32Table[256] =
    {
        0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA,
        0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3,
        0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988,
        0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91,
        0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
        0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7,
        0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
        0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5,
        0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172,
        0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
        0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940,
        0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59,
        0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116,
        0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
        0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
        0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D,

        0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A,
        0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433,
        0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818,
        0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
        0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
        0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457,
        0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C,
        0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65,
        0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
        0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB,
        0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0,
        0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
        0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086,
        0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
        0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4,
        0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD,

        0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A,
        0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683,
        0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
        0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1,
        0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE,
        0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7,
        0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC,
        0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
        0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252,
        0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
        0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60,
        0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79,
        0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
        0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F,
        0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04,
        0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D,

        0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
        0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
        0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38,
        0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21,
        0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E,
        0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777,
        0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
        0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
        0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2,
        0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB,
        0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0,
        0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
        0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6,
        0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF,
        0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
        0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D,
    };

    unsigned long crc32 = 0;
    unsigned long dwErrorCode = NO_ERROR;
    unsigned char byte = 0;

    crc32 = 0xFFFFFFFF;
    while(*s != TEXT('\0')) {
        byte = (unsigned char) *s;
        crc32 = ((crc32) >> 8) ^ crc32Table[(byte) ^ ((crc32) & 0x000000FF)];
        s++;
    }
    crc32 = ~crc32;

    return crc32;
}

// Utility to safe-retrieve the property value inside VObject 'vo'.
WCHAR* WinItem::getVObjectPropertyValue(VObject* vo, const WCHAR* propertyName) {

    WCHAR* propertyValue = NULL;
    VProperty* vprop = vo->getProperty(propertyName);
    if (vprop && vprop->getValue()) {
        propertyValue = vprop->getValue();
    }
    return propertyValue;
}<|endoftext|>


<commit_before>
#include <libclientserver.h>

ServerTCPPolledListener::ServerTCPPolledListener(ServerTCPPolled *Server)
{
	m_Server = Server;
}

ServerTCPPolledListener::~ServerTCPPolledListener()
{
	if (close(m_fd) < 0)
		abort();
}

void ServerTCPPolledListener::Init(int port, const std::string &address)
{
	m_port = port;
	m_addr = address;

	struct sockaddr_in addr;
	size_t addr_len = sizeof(addr);

	m_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (m_fd < 0) {
		std::string err = strerror(errno);
		throw(err);
	}

	int enable = 1;
	if (setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
		std::string err = "setsockopt(SO_REUSEADDR): " + std::string(strerror(errno));
		throw(std::runtime_error("setsockopt(SO_REUSEADDR) failed"));
	}

	memset(&addr, 0, addr_len);

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(address.c_str());
	addr.sin_port = htons(port);

	if(bind(m_fd, (struct sockaddr *) &addr, addr_len) < 0)
	{
		std::string err = "bind: " + std::string(strerror(errno));
		if (close(m_fd) < 0)
			abort();
		throw(std::runtime_error(err));
	}

	if(listen(m_fd, 512) < 0) {
		std::string err = "listen: " + std::string(strerror(errno));
		if (close(m_fd) < 0)
			abort();
		throw(std::runtime_error(err));
	}
}

bool ServerTCPPolledListener::CanRead(const Poller *)
{
	return true;
}

bool ServerTCPPolledListener::CanWrite(const Poller *)
{
	return false;
}

bool ServerTCPPolledListener::CanExcept(const Poller *)
{
	return false;
}

bool ServerTCPPolledListener::CanTimeout(const Poller *)
{
	return false;
}

void ServerTCPPolledListener::DoRead(Poller *sel)
{
	struct sockaddr_un addr;
	socklen_t addr_len = sizeof(addr);

	int fd = accept(m_fd, (struct sockaddr *) &addr, &addr_len);
	if (fd < 0)
		return;

	m_Server->CreateNewConnection(fd);
}

void ServerTCPPolledListener::DoWrite(Poller *)
{
	//Should never be called
}

void ServerTCPPolledListener::DoExcept(Poller *)
{
	//Should never be called
}

void ServerTCPPolledListener::DoTimeout(Poller *)
{
	//Should never be called
}

void ServerTCPPolledListener::DoClose(Poller *sel)
{
}

int ServerTCPPolledListener::GetFD(const Poller *)
{
	return m_fd;
}

void ServerTCPPolledListener::GetTimeout(const Poller *, struct timespec *tv)
{
	//Should never be called
}

<commit_msg>Fixed error handling, Fixed socket issue<commit_after>
#include <libclientserver.h>

ServerTCPPolledListener::ServerTCPPolledListener(ServerTCPPolled *Server)
{
	m_Server = Server;
}

ServerTCPPolledListener::~ServerTCPPolledListener()
{
	if (close(m_fd) < 0)
		abort();
}

void ServerTCPPolledListener::Init(int port, const std::string &address)
{
	m_port = port;
	m_addr = address;

	struct sockaddr_in addr;
	size_t addr_len = sizeof(addr);

	m_fd = socket(AF_INET, SOCK_STREAM, 0);
	if (m_fd < 0) {
		std::string err = strerror(errno);
		throw(err);
	}

	int enable = 1;
	if (setsockopt(m_fd, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(int)) < 0) {
		std::string err = "setsockopt(SO_REUSEADDR): " + std::string(strerror(errno));
		throw(std::runtime_error(err));
	}

	memset(&addr, 0, addr_len);

	addr.sin_family = AF_INET;
	addr.sin_addr.s_addr = inet_addr(address.c_str());
	addr.sin_port = htons(port);

	if(bind(m_fd, (struct sockaddr *) &addr, addr_len) < 0)
	{
		std::string err = "bind: " + std::string(strerror(errno));
		if (close(m_fd) < 0)
			abort();
		throw(std::runtime_error(err));
	}

	if(listen(m_fd, 512) < 0) {
		std::string err = "listen: " + std::string(strerror(errno));
		if (close(m_fd) < 0)
			abort();
		throw(std::runtime_error(err));
	}
}

bool ServerTCPPolledListener::CanRead(const Poller *)
{
	return true;
}

bool ServerTCPPolledListener::CanWrite(const Poller *)
{
	return false;
}

bool ServerTCPPolledListener::CanExcept(const Poller *)
{
	return false;
}

bool ServerTCPPolledListener::CanTimeout(const Poller *)
{
	return false;
}

void ServerTCPPolledListener::DoRead(Poller *sel)
{
	struct sockaddr_in addr;
	socklen_t addr_len = sizeof(addr);

	int fd = accept(m_fd, (struct sockaddr *) &addr, &addr_len);
	if (fd < 0)
		return;

	m_Server->CreateNewConnection(fd);
}

void ServerTCPPolledListener::DoWrite(Poller *)
{
	//Should never be called
}

void ServerTCPPolledListener::DoExcept(Poller *)
{
	//Should never be called
}

void ServerTCPPolledListener::DoTimeout(Poller *)
{
	//Should never be called
}

void ServerTCPPolledListener::DoClose(Poller *sel)
{
}

int ServerTCPPolledListener::GetFD(const Poller *)
{
	return m_fd;
}

void ServerTCPPolledListener::GetTimeout(const Poller *, struct timespec *tv)
{
	//Should never be called
}

<|endoftext|>


<commit_before>// Simple startrails composition program using OpenCV
// Copyright 2018 Jarno Paananen <jarno.paananen@gmail.com>
// Based on script by Thomas Jacquin
// SPDX-License-Identifier: MIT

#include <getopt.h>
#include <glob.h>
#include <unistd.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>

#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
#define KYEL "\x1B[33m"
#define KBLU "\x1B[34m"
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"

//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------

void usage_and_exit(int x) {
  std::cout << "Usage: startrails [-v] -d <dir> -e <ext> [-b <brightness> -o "
               "<output> | -s]"
            << std::endl;
  if (x) {
    std::cout << KRED
              << "Source directory and file extension are always required."
              << std::endl;
    std::cout << "brightness threshold and output file are required to render "
                 "startrails"
              << KNRM << std::endl;
  }

  std::cout << std::endl << "Arguments:" << std::endl;
  std::cout << "-h : display this help, then exit" << std::endl;
  std::cout << "-v : increase log verbosity" << std::endl;
  std::cout << "-s : print image directory statistics without producing image."
            << std::endl;
  std::cout << "-d <str> : directory from which to read images" << std::endl;
  std::cout << "-e <str> : filter images to just this extension" << std::endl;
  std::cout << "-o <str> : output image filename" << std::endl;
  std::cout << "-S <int>x<int> : restrict processed images to this size"
            << std::endl;
  std::cout << "-b <float> : ranges from 0 (black) to 1 (white)" << std::endl;
  std::cout << "\tA moonless sky may be as low as 0.05 while full moon can be "
               "as high as 0.4"
            << std::endl;
  std::cout << std::endl
            << "ex: startrails -b 0.07 -d ../images/20180208/ -e jpg -o "
               "startrails.jpg"
            << std::endl;
  exit(x);
}

int main(int argc, char* argv[]) {
  std::string directory, extension, outputfile;
  double threshold = -1;
  int verbose = 0, stats_only = 0, height = 0, width = 0;
  int c;

  while ((c = getopt(argc, argv, "hvsb:d:e:o:S:")) != -1) {
    switch (c) {
      case 'h':
        usage_and_exit(0);
        // NOTREACHED
        break;
      case 'v':
        verbose++;
        break;
      case 's':
        stats_only = 1;
        break;
      case 'S':
        sscanf(optarg, "%dx%d", &width, &height);
        // 122.8Mpx should be enough for anybody.
        if (height < 0 || height > 9600 || width < 0 || width > 12800)
          height = width = 0;
        break;
      case 'b':
        double tf;
        tf = atof(optarg);
        if (tf >= 0 && tf <= 1.0)
          threshold = tf;
        break;
      case 'd':
        directory = optarg;
        break;
      case 'e':
        extension = optarg;
        break;
      case 'o':
        outputfile = optarg;
        break;
      default:
        break;
    }
  }

  if (stats_only) {
    threshold = 0;
    outputfile = "/dev/null";
  }

  if (directory.empty() || extension.empty() || outputfile.empty() ||
      threshold < 0)
    usage_and_exit(3);

  // Find files
  glob_t files;
  std::string wildcard = directory + "/*." + extension;
  glob(wildcard.c_str(), 0, NULL, &files);
  if (files.gl_pathc == 0) {
    globfree(&files);
    std::cout << "No images found, exiting." << std::endl;
    return 0;
  }

  cv::Mat accumulated;

  // Create space for statistics
  cv::Mat stats;
  stats.create(1, files.gl_pathc, CV_64F);
  int nchan = 0;

  for (size_t f = 0; f < files.gl_pathc; f++) {
    cv::Mat image = cv::imread(files.gl_pathv[f], cv::IMREAD_UNCHANGED);
    if (!image.data) {
      std::cout << "Error reading file " << basename(files.gl_pathv[f])
                << std::endl;
      stats.col(f) = 1.0;  // mark as invalid
      continue;
    }

    if (height && width && (image.cols != width || image.rows != height)) {
      fprintf(stderr, "%s size %dx%d != %dx%d\n", files.gl_pathv[f], image.cols,
              image.cols, width, height);
      continue;
    }

    // first valid image sets the number of channels we expect
    if (nchan == 0 && image.channels())
      nchan = image.channels();

    cv::Scalar mean_scalar = cv::mean(image);
    double mean;
    switch (image.channels()) {
      default:  // mono case
        mean = mean_scalar.val[0];
        break;
      case 3:  // for color choose maximum channel
      case 4:
        mean = cv::max(mean_scalar[0], cv::max(mean_scalar[1], mean_scalar[2]));
        break;
    }
    // Scale to 0-1 range
    switch (image.depth()) {
      case CV_8U:
        mean /= 255.0;
        break;
      case CV_16U:
        mean /= 65535.0;
        break;
    }
    if (verbose)
      std::cout << "[" << f + 1 << "/" << files.gl_pathc << "] "
                << basename(files.gl_pathv[f]) << " " << mean << std::endl;

    stats.col(f) = mean;

    if (!stats_only && mean <= threshold) {
      if (image.channels() != nchan) {
        if (verbose)
          fprintf(stderr, "repairing channel mismatch: %d != %d\n",
                  image.channels(), nchan);
        if (image.channels() < nchan)
          cv::cvtColor(image, image, CV_GRAY2BGR, nchan);
        else if (image.channels() > nchan)
          cv::cvtColor(image, image, CV_BGR2GRAY, nchan);
      }
      if (accumulated.empty()) {
        image.copyTo(accumulated);
      } else {
        accumulated = cv::max(accumulated, image);
      }
    }
  }

  // Calculate some statistics
  double min_mean, max_mean;
  cv::Point min_loc;
  cv::minMaxLoc(stats, &min_mean, &max_mean, &min_loc);
  double mean_mean = cv::mean(stats)[0];

  // For median, do partial sort and take middle value
  std::vector<double> vec;
  stats.copyTo(vec);
  std::nth_element(vec.begin(), vec.begin() + (vec.size() / 2), vec.end());
  double median_mean = vec[vec.size() / 2];

  std::cout << "Minimum: " << min_mean << " maximum: " << max_mean
            << " mean: " << mean_mean << " median: " << median_mean
            << std::endl;

  // If we still don't have an image (no images below threshold), copy the
  // minimum mean image so we see why
  if (!stats_only) {
    if (accumulated.empty()) {
      std::cout << "No images below threshold, writing the minimum image only"
                << std::endl;
      accumulated = cv::imread(files.gl_pathv[min_loc.x], cv::IMREAD_UNCHANGED);
    }

    std::vector<int> compression_params;
    compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION);
    compression_params.push_back(9);
    compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
    compression_params.push_back(95);

    cv::imwrite(outputfile, accumulated, compression_params);
  }
  globfree(&files);
  return 0;
}
<commit_msg>missed in rebase<commit_after>// Simple startrails composition program using OpenCV
// Copyright 2018 Jarno Paananen <jarno.paananen@gmail.com>
// Based on script by Thomas Jacquin
// SPDX-License-Identifier: MIT

#include <getopt.h>
#include <glob.h>
#include <unistd.h>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <string>
#include <vector>

#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>

#define KNRM "\x1B[0m"
#define KRED "\x1B[31m"
#define KGRN "\x1B[32m"
#define KYEL "\x1B[33m"
#define KBLU "\x1B[34m"
#define KMAG "\x1B[35m"
#define KCYN "\x1B[36m"
#define KWHT "\x1B[37m"

//-------------------------------------------------------------------------------------------------------
//-------------------------------------------------------------------------------------------------------

void usage_and_exit(int x) {
  std::cout << "Usage: startrails [-v] -d <dir> -e <ext> [-b <brightness> -o "
               "<output> | -s]"
            << std::endl;
  if (x) {
    std::cout << KRED
              << "Source directory and file extension are always required."
              << std::endl;
    std::cout << "brightness threshold and output file are required to render "
                 "startrails"
              << KNRM << std::endl;
  }

  std::cout << std::endl << "Arguments:" << std::endl;
  std::cout << "-h : display this help, then exit" << std::endl;
  std::cout << "-v : increase log verbosity" << std::endl;
  std::cout << "-s : print image directory statistics without producing image."
            << std::endl;
  std::cout << "-d <str> : directory from which to read images" << std::endl;
  std::cout << "-e <str> : filter images to just this extension" << std::endl;
  std::cout << "-o <str> : output image filename" << std::endl;
  std::cout << "-S <int>x<int> : restrict processed images to this size"
            << std::endl;
  std::cout << "-b <float> : ranges from 0 (black) to 1 (white)" << std::endl;
  std::cout << "\tA moonless sky may be as low as 0.05 while full moon can be "
               "as high as 0.4"
            << std::endl;
  std::cout << std::endl
            << "ex: startrails -b 0.07 -d ../images/20180208/ -e jpg -o "
               "startrails.jpg"
            << std::endl;
  exit(x);
}

int main(int argc, char* argv[]) {
  std::string directory, extension, outputfile;
  double threshold = -1;
  int verbose = 0, stats_only = 0, height = 0, width = 0;
  int c;

  while ((c = getopt(argc, argv, "hvsb:d:e:o:S:")) != -1) {
    switch (c) {
      case 'h':
        usage_and_exit(0);
        // NOTREACHED
        break;
      case 'v':
        verbose++;
        break;
      case 's':
        stats_only = 1;
        break;
      case 'S':
        sscanf(optarg, "%dx%d", &width, &height);
        // 122.8Mpx should be enough for anybody.
        if (height < 0 || height > 9600 || width < 0 || width > 12800)
          height = width = 0;
        break;
      case 'b':
        double tf;
        tf = atof(optarg);
        if (tf >= 0 && tf <= 1.0)
          threshold = tf;
        break;
      case 'd':
        directory = optarg;
        break;
      case 'e':
        extension = optarg;
        break;
      case 'o':
        outputfile = optarg;
        break;
      default:
        break;
    }
  }

  if (stats_only) {
    threshold = 0;
    outputfile = "/dev/null";
  }

  if (directory.empty() || extension.empty() || outputfile.empty() ||
      threshold < 0)
    usage_and_exit(3);

  // Find files
  glob_t files;
  std::string wildcard = directory + "/*." + extension;
  glob(wildcard.c_str(), 0, NULL, &files);
  if (files.gl_pathc == 0) {
    globfree(&files);
    std::cout << "No images found, exiting." << std::endl;
    return 0;
  }

  cv::Mat accumulated;

  // Create space for statistics
  cv::Mat stats;
  stats.create(1, files.gl_pathc, CV_64F);
  int nchan = 0;

  for (size_t f = 0; f < files.gl_pathc; f++) {
    cv::Mat image = cv::imread(files.gl_pathv[f], cv::IMREAD_UNCHANGED);
    if (!image.data) {
      std::cout << "Error reading file " << basename(files.gl_pathv[f])
                << std::endl;
      stats.col(f) = 1.0;  // mark as invalid
      continue;
    }

    if (height && width && (image.cols != width || image.rows != height)) {
      fprintf(stderr, "%s size %dx%d != %dx%d\n", files.gl_pathv[f], image.cols,
              image.cols, width, height);
      continue;
    }

    // first valid image sets the number of channels we expect
    if (nchan == 0 && image.channels())
      nchan = image.channels();

    cv::Scalar mean_scalar = cv::mean(image);
    double mean;
    switch (image.channels()) {
      default:  // mono case
        mean = mean_scalar.val[0];
        break;
      case 3:  // for color choose maximum channel
      case 4:
        mean = cv::max(mean_scalar[0], cv::max(mean_scalar[1], mean_scalar[2]));
        break;
    }
    // Scale to 0-1 range
    switch (image.depth()) {
      case CV_8U:
        mean /= 255.0;
        break;
      case CV_16U:
        mean /= 65535.0;
        break;
    }
    if (verbose)
      std::cout << "[" << f + 1 << "/" << files.gl_pathc << "] "
                << basename(files.gl_pathv[f]) << " " << mean << std::endl;

    stats.col(f) = mean;

    if (!stats_only && mean <= threshold) {
      if (image.channels() != nchan) {
        if (verbose)
          fprintf(stderr, "repairing channel mismatch: %d != %d\n",
                  image.channels(), nchan);
        if (image.channels() < nchan)
          cv::cvtColor(image, image, cv::COLOR_GRAY2BGR, nchan);
        else if (image.channels() > nchan)
          cv::cvtColor(image, image, cv::COLOR_BGR2GRAY, nchan);
      }
      if (accumulated.empty()) {
        image.copyTo(accumulated);
      } else {
        accumulated = cv::max(accumulated, image);
      }
    }
  }

  // Calculate some statistics
  double min_mean, max_mean;
  cv::Point min_loc;
  cv::minMaxLoc(stats, &min_mean, &max_mean, &min_loc);
  double mean_mean = cv::mean(stats)[0];

  // For median, do partial sort and take middle value
  std::vector<double> vec;
  stats.copyTo(vec);
  std::nth_element(vec.begin(), vec.begin() + (vec.size() / 2), vec.end());
  double median_mean = vec[vec.size() / 2];

  std::cout << "Minimum: " << min_mean << " maximum: " << max_mean
            << " mean: " << mean_mean << " median: " << median_mean
            << std::endl;

  // If we still don't have an image (no images below threshold), copy the
  // minimum mean image so we see why
  if (!stats_only) {
    if (accumulated.empty()) {
      std::cout << "No images below threshold, writing the minimum image only"
                << std::endl;
      accumulated = cv::imread(files.gl_pathv[min_loc.x], cv::IMREAD_UNCHANGED);
    }

    std::vector<int> compression_params;
    compression_params.push_back(cv::IMWRITE_PNG_COMPRESSION);
    compression_params.push_back(9);
    compression_params.push_back(cv::IMWRITE_JPEG_QUALITY);
    compression_params.push_back(95);

    cv::imwrite(outputfile, accumulated, compression_params);
  }
  globfree(&files);
  return 0;
}
<|endoftext|>