<commit_before>/*
 * Copyright (c) 2010-2011 Digital Bazaar, Inc. All rights reserved.
 */
#include "monarch/ws/PathHandler.h"

using namespace monarch::rt;
using namespace monarch::ws;

PathHandler::PathHandler(bool secureOnly) :
   mSecureOnly(secureOnly),
   mExceptionHandler(this),
   mExceptionHandlerRef(NULL)
{
}

PathHandler::~PathHandler()
{
}

bool PathHandler::canHandleRequest(ServiceChannel* ch)
{
   return checkAuthentication(ch);
}

bool PathHandler::checkAuthentication(ServiceChannel* ch)
{
   bool rval = false;

   // no authentication methods
   if(mAuthMethods.size() == 0)
   {
      rval = true;
   }
   else
   {
      // check all authentication methods, save last exception for failed
      // attempt
      ExceptionRef e(NULL);
      RequestAuthenticator::Result rc;
      bool denied = false;
      for(RequestAuthList::iterator i = mAuthMethods.begin();
          !denied && i != mAuthMethods.end(); ++i)
      {
         // clear exceptions from previous failures
         Exception::clear();

         // check authentication method
         rc = (*i)->checkAuthentication(ch);

         // if authentication passed, set rval to true if not yet set
         if(rc == RequestAuthenticator::Success && !rval)
         {
            rval = true;
         }
         // authentication was attempted by client but failed, save exception
         else if(rc == RequestAuthenticator::Failure)
         {
            e = Exception::get();
         }
         // request was denied, save exception
         else if(rc == RequestAuthenticator::Deny)
         {
            rval = false;
            e = Exception::get();
         }
      }

      /* Special case: If an authentication method was attempted by a client
         (vs. not attempted by the client) and it failed *and* the only method
         that passed was NULL (anonymous), then fail. */
      if(!e.isNull() && rval && ch->getAuthenticationMethod() == NULL)
      {
         Exception::set(e);
         rval = false;
      }
   }

   if(!rval)
   {
      // set default HTTP response code if not yet set
      if(ch->getResponse()->getHeader()->getStatusCode() == 0)
      {
         // FIXME: change to 401 Unauthorized? currently not used because
         // spec seems to indicate that the client could send WWW-Authenticate
         // which is not necessarily the method of authentication used
         ch->getResponse()->getHeader()->setStatus(400, "Bad Request");
      }

      // set top-level exception
      ExceptionRef e = new Exception(
         "WebService authentication failed. Access denied.",
         "monarch.ws.AccessDenied");
      e->getDetails()["httpStatusCode"] = 403;
      e->getDetails()["public"] = true;
      e->getDetails()["path"] = ch->getRequest()->getHeader()->getPath();
      Exception::push(e);
   }

   return rval;
}

void PathHandler::handleRequest(ServiceChannel* ch)
{
   // default handler sends not found
   ch->getResponse()->getHeader()->setStatus(404, "Not Found");
   ch->sendNoContent();
}

void PathHandler::operator()(ServiceChannel* ch)
{
   // enforce secure connection if appropriate
   if(mSecureOnly && !ch->getRequest()->getConnection()->isSecure())
   {
      // send 404
      ch->getResponse()->getHeader()->setStatus(404, "Not Found");
      ch->sendNoContent();
   }
   // try to handle request
   else if(canHandleRequest(ch))
   {
      handleRequest(ch);
   }
   // exception, could not handle request
   else
   {
      ExceptionRef e = Exception::get();
      handleChannelException(ch, e);
   }
}

bool PathHandler::secureConnectionRequired()
{
   return mSecureOnly;
}

void PathHandler::addRequestAuthenticator(RequestAuthenticatorRef method)
{
   // handle anonymous
   if(method.isNull())
   {
      method = new RequestAuthenticator();
   }

   // add method
   mAuthMethods.push_back(method);
}

void PathHandler::setExceptionHandler(ChannelExceptionHandler* h, bool cleanup)
{
   if(cleanup)
   {
      setExceptionHandlerRef(h);
   }
   else
   {
      mExceptionHandlerRef.setNull();
      mExceptionHandler = h;
   }
}

void PathHandler::setExceptionHandlerRef(ChannelExceptionHandlerRef h)
{
   mExceptionHandlerRef = h;
   mExceptionHandler = &(*mExceptionHandlerRef);
}

void PathHandler::handleChannelException(
   ServiceChannel* ch, ExceptionRef& e)
{
   // exception will only be null if a developer has failed to set one when
   // an error condition occurred
   if(e.isNull())
   {
      e = new monarch::rt::Exception(
         "An unspecified error occurred. "
         "No exception was set detailing the error.",
         "monarch.ws.WebServiceError");
      e->getDetails()["httpStatusCode"] = 500;
      e->getDetails()["path"] = ch->getPath();
      monarch::rt::Exception::set(e);
   }

   // use default handler
   if(mExceptionHandler == this)
   {
      ChannelExceptionHandler::handleChannelException(ch, e);
   }
   // use custom handler
   else
   {
      mExceptionHandler->handleChannelException(ch, e);
   }
}
<commit_msg>Handle Deny authenticator results correctly.<commit_after>/*
 * Copyright (c) 2010-2011 Digital Bazaar, Inc. All rights reserved.
 */
#include "monarch/ws/PathHandler.h"

using namespace monarch::rt;
using namespace monarch::ws;

PathHandler::PathHandler(bool secureOnly) :
   mSecureOnly(secureOnly),
   mExceptionHandler(this),
   mExceptionHandlerRef(NULL)
{
}

PathHandler::~PathHandler()
{
}

bool PathHandler::canHandleRequest(ServiceChannel* ch)
{
   return checkAuthentication(ch);
}

bool PathHandler::checkAuthentication(ServiceChannel* ch)
{
   bool rval = false;

   // no authentication methods
   if(mAuthMethods.size() == 0)
   {
      rval = true;
   }
   else
   {
      // check all authentication methods unless denied
      // save last exception for failed attempt
      ExceptionRef e(NULL);
      RequestAuthenticator::Result rc;
      bool denied = false;
      for(RequestAuthList::iterator i = mAuthMethods.begin();
          !denied && i != mAuthMethods.end(); ++i)
      {
         // clear exceptions from previous failures
         Exception::clear();

         // check authentication method
         rc = (*i)->checkAuthentication(ch);

         // if authentication passed, set rval to true if not yet set
         if(rc == RequestAuthenticator::Success && !rval)
         {
            rval = true;
         }
         // authentication was attempted by client but failed, save exception
         else if(rc == RequestAuthenticator::Failure)
         {
            e = Exception::get();
         }
         // request was denied, save exception
         else if(rc == RequestAuthenticator::Deny)
         {
            denied = true;
            e = Exception::get();
            rval = false;
         }
      }

      /* Special case: If an authentication method was attempted by a client
         (vs. not attempted by the client) and it failed *and* the only method
         that passed was NULL (anonymous), then fail. */
      if(!e.isNull() && rval && ch->getAuthenticationMethod() == NULL)
      {
         Exception::set(e);
         rval = false;
      }
   }

   if(!rval)
   {
      // set default HTTP response code if not yet set
      if(ch->getResponse()->getHeader()->getStatusCode() == 0)
      {
         // FIXME: change to 401 Unauthorized? currently not used because
         // spec seems to indicate that the client could send WWW-Authenticate
         // which is not necessarily the method of authentication used
         ch->getResponse()->getHeader()->setStatus(400, "Bad Request");
      }

      // set top-level exception
      ExceptionRef e = new Exception(
         "WebService authentication failed. Access denied.",
         "monarch.ws.AccessDenied");
      e->getDetails()["httpStatusCode"] = 403;
      e->getDetails()["public"] = true;
      e->getDetails()["path"] = ch->getRequest()->getHeader()->getPath();
      Exception::push(e);
   }

   return rval;
}

void PathHandler::handleRequest(ServiceChannel* ch)
{
   // default handler sends not found
   ch->getResponse()->getHeader()->setStatus(404, "Not Found");
   ch->sendNoContent();
}

void PathHandler::operator()(ServiceChannel* ch)
{
   // enforce secure connection if appropriate
   if(mSecureOnly && !ch->getRequest()->getConnection()->isSecure())
   {
      // send 404
      ch->getResponse()->getHeader()->setStatus(404, "Not Found");
      ch->sendNoContent();
   }
   // try to handle request
   else if(canHandleRequest(ch))
   {
      handleRequest(ch);
   }
   // exception, could not handle request
   else
   {
      ExceptionRef e = Exception::get();
      handleChannelException(ch, e);
   }
}

bool PathHandler::secureConnectionRequired()
{
   return mSecureOnly;
}

void PathHandler::addRequestAuthenticator(RequestAuthenticatorRef method)
{
   // handle anonymous
   if(method.isNull())
   {
      method = new RequestAuthenticator();
   }

   // add method
   mAuthMethods.push_back(method);
}

void PathHandler::setExceptionHandler(ChannelExceptionHandler* h, bool cleanup)
{
   if(cleanup)
   {
      setExceptionHandlerRef(h);
   }
   else
   {
      mExceptionHandlerRef.setNull();
      mExceptionHandler = h;
   }
}

void PathHandler::setExceptionHandlerRef(ChannelExceptionHandlerRef h)
{
   mExceptionHandlerRef = h;
   mExceptionHandler = &(*mExceptionHandlerRef);
}

void PathHandler::handleChannelException(
   ServiceChannel* ch, ExceptionRef& e)
{
   // exception will only be null if a developer has failed to set one when
   // an error condition occurred
   if(e.isNull())
   {
      e = new monarch::rt::Exception(
         "An unspecified error occurred. "
         "No exception was set detailing the error.",
         "monarch.ws.WebServiceError");
      e->getDetails()["httpStatusCode"] = 500;
      e->getDetails()["path"] = ch->getPath();
      monarch::rt::Exception::set(e);
   }

   // use default handler
   if(mExceptionHandler == this)
   {
      ChannelExceptionHandler::handleChannelException(ch, e);
   }
   // use custom handler
   else
   {
      mExceptionHandler->handleChannelException(ch, e);
   }
}
<|endoftext|>


<commit_before>/*
 * nt loader
 *
 * Copyright 2006-2008 Mike McCormack
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>

#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "unicode.h"
#include "ntcall.h"
#include "debug.h"

UINT strlenW(LPCWSTR str)
{
	UINT n = 0;
	while(str[n]) n++;
	return n;
}

LPWSTR strcpyW( LPWSTR dest, LPCWSTR src )
{
	while ((*dest++ = *src++))
		;
	return dest;
}

LPWSTR strcatW( LPWSTR dest, LPCWSTR src )
{
	while (*dest) dest++;
	while ((*dest++ = *src++))
		;
	return dest;
}

unicode_string_t::unicode_string_t() :
	buf(0)
{
	Buffer = 0;
	Length = 0;
	MaximumLength = 0;
}

void unicode_string_t::set( UNICODE_STRING& us )
{
	clear();
	Buffer = us.Buffer;
	Length = us.Length;
	MaximumLength = us.MaximumLength;
}

void unicode_string_t::set( PCWSTR str )
{
	clear();
	Buffer = const_cast<PWSTR>( str );
	Length = strlenW( str ) * 2;
	MaximumLength = 0;
}

NTSTATUS unicode_string_t::copy_from_user(PUNICODE_STRING ptr)
{
	NTSTATUS r = ::copy_from_user( static_cast<UNICODE_STRING*>(this), ptr, sizeof (UNICODE_STRING) );
	if (r != STATUS_SUCCESS)
		return r;
	return copy_wstr_from_user();
}

NTSTATUS unicode_string_t::copy_wstr_from_user()
{
	if (buf)
		delete[] buf;
	buf = 0;
	if (Buffer)
	{
		buf = new WCHAR[ Length/2 ];
		if (!buf)
			return STATUS_NO_MEMORY;
		NTSTATUS r = ::copy_from_user( buf, Buffer, Length );
		if (r != STATUS_SUCCESS)
		{
			delete[] buf;
			buf = 0;
			return r;
		}
		Buffer = buf;
	}
	return STATUS_SUCCESS;
}

NTSTATUS unicode_string_t::copy_wstr_from_user( PWSTR String, ULONG _Length )
{
	Buffer = String;
	Length = _Length;
	return copy_wstr_from_user();
}

NTSTATUS unicode_string_t::copy( const UNICODE_STRING* ptr )
{
	clear();
	Length = ptr->Length;
	MaximumLength = ptr->MaximumLength;
	if (ptr->Buffer)
	{
		buf = new WCHAR[ Length ];
		if (!buf)
			return STATUS_NO_MEMORY;
		memcpy( buf, ptr->Buffer, Length );
		Buffer = buf;
	}
	else
		Buffer = 0;
	return STATUS_SUCCESS;
}

// returned size include nul terminator
ULONG unicode_string_t::utf8_to_wchar( const unsigned char *str, ULONG len, WCHAR *buf )
{
	unsigned int i, n;

	i = 0;
	n = 0;
	while (str[i])
	{
		if ((str[i]&0x80) == 0)
		{
			if (buf)
				buf[n] = str[i];
			n++;
			i++;
			continue;
		}
		if ((str[i]&0xc8) == 0xc0 &&
			(str[i+1]&0xc0) == 0x80)
		{
			if (buf)
				buf[n] = ((str[i]&0x3f)<<6) | (str[i+1]&0x3f);
			i+=2;
			n++;
			continue;
		}
		if ((str[i]&0xf0) == 0xe0 &&
			(str[i+1]&0xc0) == 0x80 &&
			(str[i+2]&0xc0) == 0x80)
		{
			if (buf)
				buf[n] = ((str[i]&0x3f)<<12) | ((str[i+1]&0x3f)<<6) | (str[i+2]&0x3f);
			i+=3;
			n++;
			continue;
		}
		dprintf("invalid utf8 string %02x %02x %02x\n", str[i], str[i+1], str[i+2]);
		break;
	}
	if (buf)
		buf[n] = 0;

	assert( len == 0 || n <= len );

	return n;
}

NTSTATUS unicode_string_t::copy( const char *str )
{
	const unsigned char *ustr = reinterpret_cast<const unsigned char*>(str);
	return copy( ustr );
}

void unicode_string_t::clear()
{
	if (buf)
		delete[] buf;
	buf = 0;
	Length = 0;
	MaximumLength = 0;
	Buffer = 0;
}

NTSTATUS unicode_string_t::copy( const unsigned char *ustr )
{
	clear();
	if (!ustr)
		return STATUS_SUCCESS;
	ULONG len = utf8_to_wchar( ustr, 0, 0 );
	Length = len * sizeof (WCHAR);
	buf = new WCHAR[ len + 1 ];
	if (!buf)
		return STATUS_NO_MEMORY;
	utf8_to_wchar( ustr, len, buf );
	Buffer = buf;
	MaximumLength = 0;
	return STATUS_SUCCESS;
}

NTSTATUS unicode_string_t::copy( PCWSTR str )
{
	clear();
	ULONG n = 0;
	while (str[n])
		n++;
	buf = new WCHAR[n];
	if (!buf)
		return STATUS_NO_MEMORY;
	Length = n*2;
	MaximumLength = Length;
	Buffer = buf;
	memcpy( Buffer, str, Length );
	return STATUS_SUCCESS;
}

bool unicode_string_t::is_equal( PUNICODE_STRING ptr )
{
	if (Length != ptr->Length)
		return false;

	return !memcmp(ptr->Buffer, Buffer, Length);
}

unicode_string_t::~unicode_string_t()
{
	clear();
}

unicode_string_t& unicode_string_t::operator=(const unicode_string_t& in)
{
	// free the old buffer
	if (buf)
		delete[] buf;

	// copy the other string
	Length = in.Length;
	MaximumLength = in.MaximumLength;
	if (in.buf)
	{
		buf = new WCHAR[ Length ];
		memcpy( buf, in.buf, Length );
		Buffer = buf;
	}
	else
		Buffer = 0;
	return *this;
}

// returns TRUE if strings are the same
bool unicode_string_t::compare( PUNICODE_STRING b, BOOLEAN case_insensitive )
{
	if (Length != b->Length)
		return FALSE;
	if (!case_insensitive)
		return (0 == memcmp( Buffer, b->Buffer, Length ));

	// FIXME: should use windows case table
	for ( ULONG i = 0; i < Length/2; i++ )
	{
		WCHAR ai, bi;
		ai = tolower( Buffer[i] );
		bi = tolower( b->Buffer[i] );
		if (ai == bi)
			continue;
		return FALSE;
	}
	return TRUE;
}

object_attributes_t::object_attributes_t()
{
	POBJECT_ATTRIBUTES oa = static_cast<OBJECT_ATTRIBUTES*>( this );
	memset( oa, 0, sizeof *oa );
}

object_attributes_t::~object_attributes_t()
{
}

NTSTATUS object_attributes_t::copy_from_user( POBJECT_ATTRIBUTES oa )
{
	NTSTATUS r;

	r = ::copy_from_user( static_cast<OBJECT_ATTRIBUTES*>( this ), oa, sizeof *oa );
	if (r != STATUS_SUCCESS)
		return r;

	if (Length != sizeof (OBJECT_ATTRIBUTES))
		return STATUS_INVALID_PARAMETER;

	if (ObjectName)
	{
		r = us.copy_from_user( ObjectName );
		if (r != STATUS_SUCCESS)
			return r;
		ObjectName = &us;
	}

	return STATUS_SUCCESS;
}

object_attributes_t& object_attributes_t::operator=(const object_attributes_t& in)
{
	Length = in.Length;
	RootDirectory = in.RootDirectory;
	Attributes = in.Attributes;
	SecurityDescriptor = in.SecurityDescriptor;
	SecurityQualityOfService = in.SecurityQualityOfService;

	us = in.us;
	if (in.ObjectName)
		ObjectName = &us;
	else
		ObjectName = 0;

	return *this;
}

object_attributes_t::object_attributes_t( const WCHAR *str )
{
	us.copy( str );
	Length = sizeof (OBJECT_ATTRIBUTES);
	RootDirectory = 0;
	Attributes = OBJ_CASE_INSENSITIVE;
	SecurityDescriptor = 0;
	SecurityQualityOfService = 0;
	ObjectName = &us;
}
<commit_msg>Avoid buffer overruns on invalid strings<commit_after>/*
 * nt loader
 *
 * Copyright 2006-2008 Mike McCormack
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>

#include "ntstatus.h"
#define WIN32_NO_STATUS
#include "windef.h"
#include "unicode.h"
#include "ntcall.h"
#include "debug.h"

UINT strlenW(LPCWSTR str)
{
	UINT n = 0;
	while(str[n]) n++;
	return n;
}

LPWSTR strcpyW( LPWSTR dest, LPCWSTR src )
{
	while ((*dest++ = *src++))
		;
	return dest;
}

LPWSTR strcatW( LPWSTR dest, LPCWSTR src )
{
	while (*dest) dest++;
	while ((*dest++ = *src++))
		;
	return dest;
}

unicode_string_t::unicode_string_t() :
	buf(0)
{
	Buffer = 0;
	Length = 0;
	MaximumLength = 0;
}

void unicode_string_t::set( UNICODE_STRING& us )
{
	clear();
	Buffer = us.Buffer;
	Length = us.Length;
	MaximumLength = us.MaximumLength;
}

void unicode_string_t::set( PCWSTR str )
{
	clear();
	Buffer = const_cast<PWSTR>( str );
	Length = strlenW( str ) * 2;
	MaximumLength = 0;
}

NTSTATUS unicode_string_t::copy_from_user(PUNICODE_STRING ptr)
{
	NTSTATUS r = ::copy_from_user( static_cast<UNICODE_STRING*>(this), ptr, sizeof (UNICODE_STRING) );
	if (r != STATUS_SUCCESS)
		return r;
	return copy_wstr_from_user();
}

NTSTATUS unicode_string_t::copy_wstr_from_user()
{
	if (buf)
		delete[] buf;
	buf = 0;
	if (Length&1)
		return STATUS_INVALID_PARAMETER;
	if (Buffer)
	{
		buf = new WCHAR[ Length/2 ];
		if (!buf)
			return STATUS_NO_MEMORY;
		NTSTATUS r = ::copy_from_user( buf, Buffer, Length );
		if (r != STATUS_SUCCESS)
		{
			delete[] buf;
			buf = 0;
			return r;
		}
		Buffer = buf;
	}
	return STATUS_SUCCESS;
}

NTSTATUS unicode_string_t::copy_wstr_from_user( PWSTR String, ULONG _Length )
{
	Buffer = String;
	Length = _Length;
	return copy_wstr_from_user();
}

NTSTATUS unicode_string_t::copy( const UNICODE_STRING* ptr )
{
	clear();
	Length = ptr->Length;
	MaximumLength = ptr->MaximumLength;
	if (ptr->Buffer)
	{
		buf = new WCHAR[ Length ];
		if (!buf)
			return STATUS_NO_MEMORY;
		memcpy( buf, ptr->Buffer, Length );
		Buffer = buf;
	}
	else
		Buffer = 0;
	return STATUS_SUCCESS;
}

// returned size include nul terminator
ULONG unicode_string_t::utf8_to_wchar( const unsigned char *str, ULONG len, WCHAR *buf )
{
	unsigned int i, n;

	i = 0;
	n = 0;
	while (str[i])
	{
		if ((str[i]&0x80) == 0)
		{
			if (buf)
				buf[n] = str[i];
			n++;
			i++;
			continue;
		}
		if ((str[i]&0xc8) == 0xc0 &&
			(str[i+1]&0xc0) == 0x80)
		{
			if (buf)
				buf[n] = ((str[i]&0x3f)<<6) | (str[i+1]&0x3f);
			i+=2;
			n++;
			continue;
		}
		if ((str[i]&0xf0) == 0xe0 &&
			(str[i+1]&0xc0) == 0x80 &&
			(str[i+2]&0xc0) == 0x80)
		{
			if (buf)
				buf[n] = ((str[i]&0x3f)<<12) | ((str[i+1]&0x3f)<<6) | (str[i+2]&0x3f);
			i+=3;
			n++;
			continue;
		}
		dprintf("invalid utf8 string %02x %02x %02x\n", str[i], str[i+1], str[i+2]);
		break;
	}
	if (buf)
		buf[n] = 0;

	assert( len == 0 || n <= len );

	return n;
}

NTSTATUS unicode_string_t::copy( const char *str )
{
	const unsigned char *ustr = reinterpret_cast<const unsigned char*>(str);
	return copy( ustr );
}

void unicode_string_t::clear()
{
	if (buf)
		delete[] buf;
	buf = 0;
	Length = 0;
	MaximumLength = 0;
	Buffer = 0;
}

NTSTATUS unicode_string_t::copy( const unsigned char *ustr )
{
	clear();
	if (!ustr)
		return STATUS_SUCCESS;
	ULONG len = utf8_to_wchar( ustr, 0, 0 );
	Length = len * sizeof (WCHAR);
	buf = new WCHAR[ len + 1 ];
	if (!buf)
		return STATUS_NO_MEMORY;
	utf8_to_wchar( ustr, len, buf );
	Buffer = buf;
	MaximumLength = 0;
	return STATUS_SUCCESS;
}

NTSTATUS unicode_string_t::copy( PCWSTR str )
{
	clear();
	ULONG n = 0;
	while (str[n])
		n++;
	buf = new WCHAR[n];
	if (!buf)
		return STATUS_NO_MEMORY;
	Length = n*2;
	MaximumLength = Length;
	Buffer = buf;
	memcpy( Buffer, str, Length );
	return STATUS_SUCCESS;
}

bool unicode_string_t::is_equal( PUNICODE_STRING ptr )
{
	if (Length != ptr->Length)
		return false;

	return !memcmp(ptr->Buffer, Buffer, Length);
}

unicode_string_t::~unicode_string_t()
{
	clear();
}

unicode_string_t& unicode_string_t::operator=(const unicode_string_t& in)
{
	// free the old buffer
	if (buf)
		delete[] buf;

	// copy the other string
	Length = in.Length;
	MaximumLength = in.MaximumLength;
	if (in.buf)
	{
		buf = new WCHAR[ Length ];
		memcpy( buf, in.buf, Length );
		Buffer = buf;
	}
	else
		Buffer = 0;
	return *this;
}

// returns TRUE if strings are the same
bool unicode_string_t::compare( PUNICODE_STRING b, BOOLEAN case_insensitive )
{
	if (Length != b->Length)
		return FALSE;
	if (!case_insensitive)
		return (0 == memcmp( Buffer, b->Buffer, Length ));

	// FIXME: should use windows case table
	for ( ULONG i = 0; i < Length/2; i++ )
	{
		WCHAR ai, bi;
		ai = tolower( Buffer[i] );
		bi = tolower( b->Buffer[i] );
		if (ai == bi)
			continue;
		return FALSE;
	}
	return TRUE;
}

object_attributes_t::object_attributes_t()
{
	POBJECT_ATTRIBUTES oa = static_cast<OBJECT_ATTRIBUTES*>( this );
	memset( oa, 0, sizeof *oa );
}

object_attributes_t::~object_attributes_t()
{
}

NTSTATUS object_attributes_t::copy_from_user( POBJECT_ATTRIBUTES oa )
{
	NTSTATUS r;

	r = ::copy_from_user( static_cast<OBJECT_ATTRIBUTES*>( this ), oa, sizeof *oa );
	if (r != STATUS_SUCCESS)
		return r;

	if (Length != sizeof (OBJECT_ATTRIBUTES))
		return STATUS_INVALID_PARAMETER;

	if (ObjectName)
	{
		r = us.copy_from_user( ObjectName );
		if (r == STATUS_INVALID_PARAMETER)
			r = STATUS_OBJECT_NAME_INVALID;
		if (r != STATUS_SUCCESS)
			return r;
		ObjectName = &us;
	}

	return STATUS_SUCCESS;
}

object_attributes_t& object_attributes_t::operator=(const object_attributes_t& in)
{
	Length = in.Length;
	RootDirectory = in.RootDirectory;
	Attributes = in.Attributes;
	SecurityDescriptor = in.SecurityDescriptor;
	SecurityQualityOfService = in.SecurityQualityOfService;

	us = in.us;
	if (in.ObjectName)
		ObjectName = &us;
	else
		ObjectName = 0;

	return *this;
}

object_attributes_t::object_attributes_t( const WCHAR *str )
{
	us.copy( str );
	Length = sizeof (OBJECT_ATTRIBUTES);
	RootDirectory = 0;
	Attributes = OBJ_CASE_INSENSITIVE;
	SecurityDescriptor = 0;
	SecurityQualityOfService = 0;
	ObjectName = &us;
}
<|endoftext|>


<commit_before>#include "clutter.hpp"

int main(int argc, char* argv[])
{
  init_screen("Particle-Viewer");
  SDL_Event event;
  ticks = SDL_GetTicks();
  gladLoadGLLoader(SDL_GL_GetProcAddress);
  setupGLStuff();

  while (!quit)
  {
  	readInput(event);
    beforeDraw();
    drawFunct();
    SDL_GL_SwapWindow(window);
  }
  cleanup();
  return 0;
}

void beforeDraw()
{

  cam.update(deltaTime);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  manageFPS(ticks,lastticks);
  shader.Use();
  view = cam.setupCam();
  //update positions

}

glm::vec3 translations[1000000];
void setupRender()
{
  GLfloat offset = 0.1f;
  int index = 0;
  for(GLint y = -1000; y < 1000; y += 2)
    {
        for(GLint x = -1000; x < 1000; x += 2)
        {
            glm::vec3 translation;
            translation.x = (GLfloat)x / 10.0f + offset;
            translation.y = (GLfloat)y / 10.0f + offset;
            translation.z = (GLfloat)y * (GLfloat)x * deltaTime / 100000.0f;
            //std::cout << deltaTime << std::endl;
            translations[index++] = translation;
        }
    }

      glGenBuffers(1, &instanceVBO);
      glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
      glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * 1000000, &translations[0],  GL_STATIC_DRAW);
      glBindBuffer(GL_ARRAY_BUFFER, 0);

      glBindVertexArray(quadVAO);
      glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
      glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
      glBindBuffer(GL_ARRAY_BUFFER, 0);
      glBindVertexArray(0);
}

void drawFunct()
{
  setupRender();
  glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
  glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
  glBindVertexArray(quadVAO);
  glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1000000);
  glBindVertexArray(0);
  glDeleteBuffers(1, &instanceVBO);
}

void readInput(SDL_Event &event)
{
  const Uint8 *keystate = SDL_GetKeyboardState(NULL);

  if(keystate[SDL_SCANCODE_W])
  {
    cam.moveForward();
  }
  if(keystate[SDL_SCANCODE_S])
  {
    cam.moveBackward();
  }
  if(keystate[SDL_SCANCODE_A])
  {
    cam.moveLeft();
  }
  if(keystate[SDL_SCANCODE_D])
  {
    cam.moveRight();
  }
  if(keystate[SDL_SCANCODE_I])
  {
    cam.lookUp();
  }
  if(keystate[SDL_SCANCODE_K])
  {
    cam.lookDown();
  }
  if(keystate[SDL_SCANCODE_J])
  {
    cam.lookLeft();
  }
  if(keystate[SDL_SCANCODE_L])
  {
    cam.lookRight();
  }

	while (SDL_PollEvent(&event))
  {
    if (event.type == SDL_QUIT)
    {
      quit = true;
    }
    else if(event.type == SDL_KEYDOWN)
    {
      if(event.key.keysym.sym == SDLK_ESCAPE)
      {
        quit = true;
      }
    }
  }
}

void manageFPS(uint32_t &ticks, uint32_t &lastticks)
{
	ticks = SDL_GetTicks();
  deltaTime = ticks - lastticks;
  if ( ((ticks*10-lastticks*10)) < 167 )
  {
    SDL_Delay( (167-((ticks*10-lastticks*10)))/10 );
  }
  lastticks = SDL_GetTicks();

}

static void sdl_die(const char * message)
{
  fprintf(stderr, "%s: %s\n", message, SDL_GetError());
  exit(2);
}

void init_screen(const char * title)
{
  // Init SDL
  if (SDL_Init(SDL_INIT_VIDEO) < 0) sdl_die("SDL Initialize Failed!");
  atexit (SDL_Quit);

  //loads base GL Libs
  SDL_GL_LoadLibrary(NULL);

  //set base GL stuff
  SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

  //creates the window
  window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL);
  if (window == NULL) sdl_die("Failed to create window!");

  //creates the main GL context
  maincontext = SDL_GL_CreateContext(window);
  if (maincontext == NULL) sdl_die("Failed to create an OpenGL context!");

  gladLoadGLLoader(SDL_GL_GetProcAddress);

  // Use v-sync
  SDL_GL_SetSwapInterval(1);

  int w,h;
  SDL_GetWindowSize(window, &w, &h);
  glViewport(0, 0, w, h);
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}

void setupGLStuff()
{

  glEnable(GL_DEPTH_TEST);
  shader = Shader("../src/shaders/vertex.vs","../src/shaders/fragment.frag");
  projection = glm::perspective(45.0f, (GLfloat)SCREEN_WIDTH / (GLfloat)SCREEN_HEIGHT, 0.1f, 1000.0f);
  glGenBuffers(1, &instanceVBO);
  glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
  glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * 1000000, &translations[0],  GL_STATIC_DRAW);
  glBindBuffer(GL_ARRAY_BUFFER, 0);

  glGenVertexArrays(1, &quadVAO);
  glGenBuffers(1, &quadVBO);
  glBindVertexArray(quadVAO);
  glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
  glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
  glEnableVertexAttribArray(1);
  glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat)));
  // Also set instance data
  glEnableVertexAttribArray(2);

  glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
  glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
  glVertexAttribDivisor(2, 1); // Tell OpenGL this is an instanced vertex attribute.
  glBindVertexArray(0);
}

void cleanup()
{
  glDeleteVertexArrays(1, &VAO);
  glDeleteBuffers(1, &VBO);
  glDeleteBuffers(1, &EBO);
}
<commit_msg>added in a cool sine function based off of time<commit_after>#include "clutter.hpp"

int main(int argc, char* argv[])
{
  init_screen("Particle-Viewer");
  SDL_Event event;
  ticks = SDL_GetTicks();
  gladLoadGLLoader(SDL_GL_GetProcAddress);
  setupGLStuff();

  while (!quit)
  {
  	readInput(event);
    beforeDraw();
    drawFunct();
    SDL_GL_SwapWindow(window);
  }
  cleanup();
  return 0;
}

void beforeDraw()
{

  cam.update(deltaTime);
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
  manageFPS(ticks,lastticks);
  shader.Use();
  view = cam.setupCam();
  //update positions

}

glm::vec3 translations[1000000];
void setupRender()
{
  GLfloat offset = 0.1f;
  int index = 0;
  for(GLint y = -1000; y < 1000; y += 2)
    {
        for(GLint x = -1000; x < 1000; x += 2)
        {
            glm::vec3 translation;
            translation.x = (GLfloat)x / 10.0f + offset;
            translation.y = (GLfloat)y / 10.0f + offset;
            GLfloat z = SDL_GetTicks();
            translation.z = (GLfloat)y * (GLfloat)x * sin(glm::radians(z)) / 100000.0f;
            //std::cout << deltaTime << std::endl;
            translations[index++] = translation;
        }
    }

      glGenBuffers(1, &instanceVBO);
      glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
      glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * 1000000, &translations[0],  GL_STATIC_DRAW);
      glBindBuffer(GL_ARRAY_BUFFER, 0);

      glBindVertexArray(quadVAO);
      glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
      glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
      glBindBuffer(GL_ARRAY_BUFFER, 0);
      glBindVertexArray(0);
}

void drawFunct()
{
  setupRender();
  glUniformMatrix4fv(glGetUniformLocation(shader.Program, "view"), 1, GL_FALSE, glm::value_ptr(view));
  glUniformMatrix4fv(glGetUniformLocation(shader.Program, "projection"), 1, GL_FALSE, glm::value_ptr(projection));
  glBindVertexArray(quadVAO);
  glDrawArraysInstanced(GL_TRIANGLES, 0, 6, 1000000);
  glBindVertexArray(0);
  glDeleteBuffers(1, &instanceVBO);
}

void readInput(SDL_Event &event)
{
  const Uint8 *keystate = SDL_GetKeyboardState(NULL);

  if(keystate[SDL_SCANCODE_W])
  {
    cam.moveForward();
  }
  if(keystate[SDL_SCANCODE_S])
  {
    cam.moveBackward();
  }
  if(keystate[SDL_SCANCODE_A])
  {
    cam.moveLeft();
  }
  if(keystate[SDL_SCANCODE_D])
  {
    cam.moveRight();
  }
  if(keystate[SDL_SCANCODE_I])
  {
    cam.lookUp();
  }
  if(keystate[SDL_SCANCODE_K])
  {
    cam.lookDown();
  }
  if(keystate[SDL_SCANCODE_J])
  {
    cam.lookLeft();
  }
  if(keystate[SDL_SCANCODE_L])
  {
    cam.lookRight();
  }

	while (SDL_PollEvent(&event))
  {
    if (event.type == SDL_QUIT)
    {
      quit = true;
    }
    else if(event.type == SDL_KEYDOWN)
    {
      if(event.key.keysym.sym == SDLK_ESCAPE)
      {
        quit = true;
      }
    }
  }
}

void manageFPS(uint32_t &ticks, uint32_t &lastticks)
{
	ticks = SDL_GetTicks();
  deltaTime = ticks - lastticks;
  if ( ((ticks*10-lastticks*10)) < 167 )
  {
    SDL_Delay( (167-((ticks*10-lastticks*10)))/10 );
  }
  lastticks = SDL_GetTicks();

}

static void sdl_die(const char * message)
{
  fprintf(stderr, "%s: %s\n", message, SDL_GetError());
  exit(2);
}

void init_screen(const char * title)
{
  // Init SDL
  if (SDL_Init(SDL_INIT_VIDEO) < 0) sdl_die("SDL Initialize Failed!");
  atexit (SDL_Quit);

  //loads base GL Libs
  SDL_GL_LoadLibrary(NULL);

  //set base GL stuff
  SDL_GL_SetAttribute(SDL_GL_ACCELERATED_VISUAL, 1);
  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4);
  SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
  SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
  SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);

  //creates the window
  window = SDL_CreateWindow(title, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, SDL_WINDOW_OPENGL);
  if (window == NULL) sdl_die("Failed to create window!");

  //creates the main GL context
  maincontext = SDL_GL_CreateContext(window);
  if (maincontext == NULL) sdl_die("Failed to create an OpenGL context!");

  gladLoadGLLoader(SDL_GL_GetProcAddress);

  // Use v-sync
  SDL_GL_SetSwapInterval(1);

  int w,h;
  SDL_GetWindowSize(window, &w, &h);
  glViewport(0, 0, w, h);
  glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}

void setupGLStuff()
{

  glEnable(GL_DEPTH_TEST);
  shader = Shader("../src/shaders/vertex.vs","../src/shaders/fragment.frag");
  projection = glm::perspective(45.0f, (GLfloat)SCREEN_WIDTH / (GLfloat)SCREEN_HEIGHT, 0.1f, 1000.0f);
  glGenBuffers(1, &instanceVBO);
  glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
  glBufferData(GL_ARRAY_BUFFER, sizeof(glm::vec3) * 1000000, &translations[0],  GL_STATIC_DRAW);
  glBindBuffer(GL_ARRAY_BUFFER, 0);

  glGenVertexArrays(1, &quadVAO);
  glGenBuffers(1, &quadVBO);
  glBindVertexArray(quadVAO);
  glBindBuffer(GL_ARRAY_BUFFER, quadVBO);
  glBufferData(GL_ARRAY_BUFFER, sizeof(quadVertices), quadVertices, GL_STATIC_DRAW);
  glEnableVertexAttribArray(0);
  glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)0);
  glEnableVertexAttribArray(1);
  glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(2 * sizeof(GLfloat)));
  // Also set instance data
  glEnableVertexAttribArray(2);

  glBindBuffer(GL_ARRAY_BUFFER, instanceVBO);
  glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(GLfloat), (GLvoid*)0);
  glBindBuffer(GL_ARRAY_BUFFER, 0);
  glVertexAttribDivisor(2, 1); // Tell OpenGL this is an instanced vertex attribute.
  glBindVertexArray(0);
}

void cleanup()
{
  glDeleteVertexArrays(1, &VAO);
  glDeleteBuffers(1, &VBO);
  glDeleteBuffers(1, &EBO);
}
<|endoftext|>


<commit_before>/****************************************************************************

 This file is part of the GLC-lib library.
 Copyright (C) 2005 Laurent Ribon (laumaya@users.sourceforge.net)
 Version 0.9, packaged on Novemeber, 2005.

 http://glc-lib.sourceforge.net

 GLC-lib 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.

 GLC-lib 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 GLC-lib; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*****************************************************************************/

//! \file glc_mesh.cpp implementation of the GLC_Mesh class.

#include <QtDebug>
#include "glc_mesh.h"

//////////////////////////////////////////////////////////////////////
// Constructor Destructor
//////////////////////////////////////////////////////////////////////
GLC_Mesh::GLC_Mesh(const char *pName, const GLfloat *pColor)
:GLC_Geometry(pName, pColor)
, m_nNbrFaces(0)
{

}

// Copy Constructor
GLC_Mesh::GLC_Mesh(GLC_Mesh *pMesh)
:GLC_Geometry(pMesh->GetName(), pMesh->GetfRGBA())
, m_nNbrFaces(0)

{
	GLC_Face *pFace;
	for (int i = 0; i < pMesh->m_pFaceList.size(); ++i)
	{
		pFace= new GLC_Face(pMesh->m_pFaceList.at(i));
		AddFace(pFace);
	}

	SetMaterial(pMesh->GetMaterial());
	SetMatrix(pMesh->GetMatrix());
}

GLC_Mesh::~GLC_Mesh(void)
{
	while (!m_pFaceList.isEmpty())
		delete m_pFaceList.takeFirst();
	m_nNbrFaces= 0;

}
/////////////////////////////////////////////////////////////////////
// Set Functions
//////////////////////////////////////////////////////////////////////

// Add a face to the Mesh
void GLC_Mesh::AddFace(GLC_Face* pFace)
{
	m_pFaceList.append(pFace);
	m_nNbrFaces++;
}

//////////////////////////////////////////////////////////////////////
// OpenGL Functions
//////////////////////////////////////////////////////////////////////

// Virtual interface for OpenGL Geometry set up.
void GLC_Mesh::GlDraw()
{
    for (int i = 0; i < m_pFaceList.size(); ++i)
    {
    	m_pFaceList.at(i)->GlDraw();
    }

}

// Virtual interface for OpenGL Geomtry properties.
void GLC_Mesh::GlPropGeom()
{
		//! Change the current matrix
		glMultMatrixd(m_MatPos.Return_dMat());
		if(!m_pMaterial || (m_PolyMode != GL_FILL))
		{
			glDisable(GL_TEXTURE_2D);
			glDisable(GL_LIGHTING);

			if (m_IsBlended)
			{
				glEnable(GL_BLEND);
				glDepthMask(GL_FALSE);
			}
			else
			{
				glDisable(GL_BLEND);
			}

			glColor4fv(GetfRGBA());			// is color
		}
		else if (m_pMaterial->GetAddRgbaTexture())
		{
			glEnable(GL_TEXTURE_2D);
			glEnable(GL_LIGHTING);

			if (m_IsBlended)
			{
				glEnable(GL_BLEND);
				glDepthMask(GL_FALSE);
			}
			else
			{
				glDisable(GL_BLEND);
			}

			m_pMaterial->GlExecute();
		}
		else
		{
			glDisable(GL_TEXTURE_2D);
			glEnable(GL_LIGHTING);

			if (m_IsBlended)
			{
				glEnable(GL_BLEND);
				glDepthMask(GL_FALSE);
			}
			else
			{
				glDisable(GL_BLEND);
			}

			m_pMaterial->GlExecute();
		}

		glLineWidth(GetThickness());	// is thikness

		// Polygons display mode
		glPolygonMode(m_PolyFace, m_PolyMode);

}
<commit_msg>Minor change to GlPropGeom method The blending test is do once.<commit_after>/****************************************************************************

 This file is part of the GLC-lib library.
 Copyright (C) 2005 Laurent Ribon (laumaya@users.sourceforge.net)
 Version 0.9, packaged on Novemeber, 2005.

 http://glc-lib.sourceforge.net

 GLC-lib 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.

 GLC-lib 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 GLC-lib; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*****************************************************************************/

//! \file glc_mesh.cpp implementation of the GLC_Mesh class.

#include <QtDebug>
#include "glc_mesh.h"

//////////////////////////////////////////////////////////////////////
// Constructor Destructor
//////////////////////////////////////////////////////////////////////
GLC_Mesh::GLC_Mesh(const char *pName, const GLfloat *pColor)
:GLC_Geometry(pName, pColor)
, m_nNbrFaces(0)
{

}

// Copy Constructor
GLC_Mesh::GLC_Mesh(GLC_Mesh *pMesh)
:GLC_Geometry(pMesh->GetName(), pMesh->GetfRGBA())
, m_nNbrFaces(0)

{
	GLC_Face *pFace;
	for (int i = 0; i < pMesh->m_pFaceList.size(); ++i)
	{
		pFace= new GLC_Face(pMesh->m_pFaceList.at(i));
		AddFace(pFace);
	}

	SetMaterial(pMesh->GetMaterial());
	SetMatrix(pMesh->GetMatrix());
}

GLC_Mesh::~GLC_Mesh(void)
{
	while (!m_pFaceList.isEmpty())
		delete m_pFaceList.takeFirst();
	m_nNbrFaces= 0;

}
/////////////////////////////////////////////////////////////////////
// Set Functions
//////////////////////////////////////////////////////////////////////

// Add a face to the Mesh
void GLC_Mesh::AddFace(GLC_Face* pFace)
{
	m_pFaceList.append(pFace);
	m_nNbrFaces++;
}

//////////////////////////////////////////////////////////////////////
// OpenGL Functions
//////////////////////////////////////////////////////////////////////

// Virtual interface for OpenGL Geometry set up.
void GLC_Mesh::GlDraw()
{
    for (int i = 0; i < m_pFaceList.size(); ++i)
    {
    	m_pFaceList.at(i)->GlDraw();
    }

}

// Virtual interface for OpenGL Geomtry properties.
void GLC_Mesh::GlPropGeom()
{
		//! Change the current matrix
		glMultMatrixd(m_MatPos.Return_dMat());

		if (m_IsBlended)
		{
			glEnable(GL_BLEND);
			glDepthMask(GL_FALSE);
		}
		else
		{
			glDisable(GL_BLEND);
		}

		if(!m_pMaterial || (m_PolyMode != GL_FILL))
		{
			qDebug() << "GLC_Mesh::GlPropGeom : Wireframe Mode";
			glDisable(GL_TEXTURE_2D);
			glDisable(GL_LIGHTING);
			glColor4fv(GetfRGBA());			// is color
		}
		else if (m_pMaterial->GetAddRgbaTexture())
		{
			glEnable(GL_TEXTURE_2D);
			glEnable(GL_LIGHTING);
			m_pMaterial->GlExecute();
		}
		else
		{
			glDisable(GL_TEXTURE_2D);
			glEnable(GL_LIGHTING);
			m_pMaterial->GlExecute();
		}

		glLineWidth(GetThickness());	// is thikness

		// Polygons display mode
		glPolygonMode(m_PolyFace, m_PolyMode);

}
<|endoftext|>


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

// STL
#include <memory>
#include <string>

// po6
#include <po6/net/ipaddr.h>
#include <po6/net/location.h>

// e
#include <e/convert.h>
#include <e/timer.h>

// HyperDex
#include <hyperclient/client.h>

const char* colnames[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                          "11", "12", "13", "14", "15", "16", "17", "18", "19",
                          "20", "21", "22", "23", "24", "25", "26", "27", "28",
                          "29", "30", "31", "32"};

static int
usage();

void
handle_put(hyperclient::returncode ret)
{
    if (ret != hyperclient::SUCCESS)
    {
        std::cerr << "Put returned " << ret << "." << std::endl;
    }
}

void
handle_search(size_t* count,
              const e::buffer& expected_key,
              hyperclient::returncode ret,
              const e::buffer& key,
              const std::vector<e::buffer>& value)
{
    ++*count;

    if (expected_key != key)
    {
        std::cerr << "Equality returned unexpected key:  "
                  << expected_key.size() << ":" << expected_key.hex()
                  << " != " << key.size() << ":" << key.hex() << std::endl;
    }
}

void
handle_range(size_t* count,
             const e::buffer& expected_key,
             hyperclient::returncode ret,
             const e::buffer& key,
             const std::vector<e::buffer>& value)
{
    ++*count;

    if (expected_key != key)
    {
        std::cerr << "Range returned unexpected key:  "
                  << expected_key.size() << ":" << expected_key.hex()
                  << " != " << key.size() << ":" << key.hex() << std::endl;
    }
}

int
main(int argc, char* argv[])
{
    if (argc != 5)
    {
        return usage();
    }

    po6::net::ipaddr ip;
    uint16_t port;
    std::string space = argv[3];
    uint32_t numbers;

    try
    {
        ip = argv[1];
    }
    catch (std::invalid_argument& e)
    {
        std::cerr << "The IP address must be an IPv4 or IPv6 address." << std::endl;
        return EXIT_FAILURE;
    }

    try
    {
        port = e::convert::to_uint16_t(argv[2]);
    }
    catch (std::domain_error& e)
    {
        std::cerr << "The port number must be an integer." << std::endl;
        return EXIT_FAILURE;
    }
    catch (std::out_of_range& e)
    {
        std::cerr << "The port number must be suitably small." << std::endl;
        return EXIT_FAILURE;
    }

    try
    {
        numbers = e::convert::to_uint32_t(argv[4]);
    }
    catch (std::domain_error& e)
    {
        std::cerr << "The number must be an integer." << std::endl;
        return EXIT_FAILURE;
    }
    catch (std::out_of_range& e)
    {
        std::cerr << "The number must be suitably small." << std::endl;
        return EXIT_FAILURE;
    }

    try
    {
        hyperclient::client cl(po6::net::location(ip, port));
        cl.connect();
        e::buffer one("one", 3);
        e::buffer zero("zero", 4);

        for (uint32_t num = 0; num < numbers; ++num)
        {
            e::buffer key;
            key.pack() << num;
            std::vector<e::buffer> value;

            for (size_t i = 0; i < 32; ++i)
            {
                value.push_back(e::buffer());

                if ((num & (1 << i)))
                {
                    value.back() = one;
                }
                else
                {
                    value.back() = zero;
                }
            }

            char buf[4];
            memmove(buf, &num, sizeof(4));
            value.push_back(e::buffer(buf, 4));

            cl.put(space, key, value, handle_put);

            if (cl.outstanding() > 1000)
            {
                cl.flush(-1);
            }
        }

        cl.flush(-1);
        e::sleep_ms(1, 0);
        std::cerr << "Starting searches." << std::endl;
        timespec start;
        timespec end;

        clock_gettime(CLOCK_REALTIME, &start);

        for (uint32_t num = 0; num < numbers; ++num)
        {
            e::buffer key;
            key.pack() << num;
            std::map<std::string, e::buffer> search;

            for (size_t i = 0; i < 32; ++i)
            {
                if ((num & (1 << i)))
                {
                    search.insert(std::make_pair(colnames[i], one));
                }
                else
                {
                    search.insert(std::make_pair(colnames[i], zero));
                }
            }

            using std::tr1::bind;
            using std::tr1::placeholders::_1;
            using std::tr1::placeholders::_2;
            using std::tr1::placeholders::_3;
            size_t count = 0;
            cl.search(argv[3], search, std::tr1::bind(handle_search, &count, key, _1, _2, _3));
            cl.flush(100);

            if (count < 1)
            {
                std::cerr << "Equality returned less than 1 result." << std::endl;
            }

            if (count > 1)
            {
                std::cerr << "Equality returned more than 1 result." << std::endl;
            }

            count = 0;
            std::map<std::string, std::pair<uint64_t, uint64_t> > range;
            range.insert(std::make_pair("range", std::make_pair(num, num + 1)));
            cl.search(argv[3], range, std::tr1::bind(handle_range, &count, key, _1, _2, _3));
            cl.flush(100);

            if (count < 1)
            {
                std::cerr << "Range returned less than 1 result." << std::endl;
            }

            if (count > 1)
            {
                std::cerr << "Range returned more than 1 result." << std::endl;
            }
        }

        clock_gettime(CLOCK_REALTIME, &end);
        timespec diff;

        if ((end.tv_nsec < start.tv_nsec) < 0)
        {
            diff.tv_sec = end.tv_sec - start.tv_sec - 1;
            diff.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
        }
        else
        {
            diff.tv_sec = end.tv_sec - start.tv_sec;
            diff.tv_nsec = end.tv_nsec - start.tv_nsec;
        }

        uint64_t nanosecs = diff.tv_sec * 1000000000 + diff.tv_nsec;
        std::cerr << "test took " << nanosecs << " nanoseconds for " << numbers << " searches" << std::endl;
    }
    catch (po6::error& e)
    {
        std::cerr << "There was a system error:  " << e.what();
        return EXIT_FAILURE;
    }
    catch (std::runtime_error& e)
    {
        std::cerr << "There was a runtime error:  " << e.what();
        return EXIT_FAILURE;
    }
    catch (std::bad_alloc& e)
    {
        std::cerr << "There was a memory allocation error:  " << e.what();
        return EXIT_FAILURE;
    }
    catch (std::exception& e)
    {
        std::cerr << "There was a generic error:  " << e.what();
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

int
usage()
{
    std::cerr << "Usage:  binary <coordinator ip> <coordinator port> <space name> <numbers>\n"
              << "This will create <numbers> points whose key is a number [0, <numbers>) and "
              << "then perform searches over the bits of the number.  The space should have 32 "
              << "secondary dimensions so that all bits of a number may be stored."
              << std::endl;
    return EXIT_FAILURE;
}
<commit_msg>Output from binary-test when searches fail.<commit_after>// Copyright (c) 2011, Cornell University
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
//     * Redistributions of source code must retain the above copyright notice,
//       this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above copyright
//       notice, this list of conditions and the following disclaimer in the
//       documentation and/or other materials provided with the distribution.
//     * Neither the name of HyperDex nor the names of its contributors may be
//       used to endorse or promote products derived from this software without
//       specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.

// STL
#include <memory>
#include <string>

// po6
#include <po6/net/ipaddr.h>
#include <po6/net/location.h>

// e
#include <e/convert.h>
#include <e/timer.h>

// HyperDex
#include <hyperclient/client.h>

const char* colnames[] = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10",
                          "11", "12", "13", "14", "15", "16", "17", "18", "19",
                          "20", "21", "22", "23", "24", "25", "26", "27", "28",
                          "29", "30", "31", "32"};

static int
usage();

void
handle_put(hyperclient::returncode ret)
{
    if (ret != hyperclient::SUCCESS)
    {
        std::cerr << "Put returned " << ret << "." << std::endl;
    }
}

void
handle_search(size_t* count,
              const e::buffer& expected_key,
              hyperclient::returncode ret,
              const e::buffer& key,
              const std::vector<e::buffer>& value)
{
    if (ret != hyperclient::SUCCESS)
    {
        std::cerr << "Equality returned !SUCCESS:  " << ret << std::endl;
        return;
    }

    ++*count;

    if (expected_key != key)
    {
        std::cerr << "Equality returned unexpected key:  "
                  << expected_key.size() << ":" << expected_key.hex()
                  << " != " << key.size() << ":" << key.hex() << std::endl;
    }
}

void
handle_range(size_t* count,
             const e::buffer& expected_key,
             hyperclient::returncode ret,
             const e::buffer& key,
             const std::vector<e::buffer>& value)
{
    if (ret != hyperclient::SUCCESS)
    {
        std::cerr << "Range returned !SUCCESS:  " << ret << std::endl;
        return;
    }

    ++*count;

    if (expected_key != key)
    {
        std::cerr << "Range returned unexpected key:  "
                  << expected_key.size() << ":" << expected_key.hex()
                  << " != " << key.size() << ":" << key.hex() << std::endl;
    }
}

int
main(int argc, char* argv[])
{
    if (argc != 5)
    {
        return usage();
    }

    po6::net::ipaddr ip;
    uint16_t port;
    std::string space = argv[3];
    uint32_t numbers;

    try
    {
        ip = argv[1];
    }
    catch (std::invalid_argument& e)
    {
        std::cerr << "The IP address must be an IPv4 or IPv6 address." << std::endl;
        return EXIT_FAILURE;
    }

    try
    {
        port = e::convert::to_uint16_t(argv[2]);
    }
    catch (std::domain_error& e)
    {
        std::cerr << "The port number must be an integer." << std::endl;
        return EXIT_FAILURE;
    }
    catch (std::out_of_range& e)
    {
        std::cerr << "The port number must be suitably small." << std::endl;
        return EXIT_FAILURE;
    }

    try
    {
        numbers = e::convert::to_uint32_t(argv[4]);
    }
    catch (std::domain_error& e)
    {
        std::cerr << "The number must be an integer." << std::endl;
        return EXIT_FAILURE;
    }
    catch (std::out_of_range& e)
    {
        std::cerr << "The number must be suitably small." << std::endl;
        return EXIT_FAILURE;
    }

    try
    {
        hyperclient::client cl(po6::net::location(ip, port));
        cl.connect();
        e::buffer one("one", 3);
        e::buffer zero("zero", 4);

        for (uint32_t num = 0; num < numbers; ++num)
        {
            e::buffer key;
            key.pack() << num;
            std::vector<e::buffer> value;

            for (size_t i = 0; i < 32; ++i)
            {
                value.push_back(e::buffer());

                if ((num & (1 << i)))
                {
                    value.back() = one;
                }
                else
                {
                    value.back() = zero;
                }
            }

            char buf[4];
            memmove(buf, &num, sizeof(4));
            value.push_back(e::buffer(buf, 4));

            cl.put(space, key, value, handle_put);

            if (cl.outstanding() > 1000)
            {
                cl.flush(-1);
            }
        }

        cl.flush(-1);
        e::sleep_ms(1, 0);
        std::cerr << "Starting searches." << std::endl;
        timespec start;
        timespec end;

        clock_gettime(CLOCK_REALTIME, &start);

        for (uint32_t num = 0; num < numbers; ++num)
        {
            e::buffer key;
            key.pack() << num;
            std::map<std::string, e::buffer> search;

            for (size_t i = 0; i < 32; ++i)
            {
                if ((num & (1 << i)))
                {
                    search.insert(std::make_pair(colnames[i], one));
                }
                else
                {
                    search.insert(std::make_pair(colnames[i], zero));
                }
            }

            using std::tr1::bind;
            using std::tr1::placeholders::_1;
            using std::tr1::placeholders::_2;
            using std::tr1::placeholders::_3;
            size_t count = 0;
            cl.search(argv[3], search, std::tr1::bind(handle_search, &count, key, _1, _2, _3));
            cl.flush(100);

            if (count < 1)
            {
                std::cerr << "Equality returned less than 1 result." << std::endl;
            }

            if (count > 1)
            {
                std::cerr << "Equality returned more than 1 result." << std::endl;
            }

            count = 0;
            std::map<std::string, std::pair<uint64_t, uint64_t> > range;
            range.insert(std::make_pair("range", std::make_pair(num, num + 1)));
            cl.search(argv[3], range, std::tr1::bind(handle_range, &count, key, _1, _2, _3));
            cl.flush(100);

            if (count < 1)
            {
                std::cerr << "Range returned less than 1 result." << std::endl;
            }

            if (count > 1)
            {
                std::cerr << "Range returned more than 1 result." << std::endl;
            }
        }

        clock_gettime(CLOCK_REALTIME, &end);
        timespec diff;

        if ((end.tv_nsec < start.tv_nsec) < 0)
        {
            diff.tv_sec = end.tv_sec - start.tv_sec - 1;
            diff.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
        }
        else
        {
            diff.tv_sec = end.tv_sec - start.tv_sec;
            diff.tv_nsec = end.tv_nsec - start.tv_nsec;
        }

        uint64_t nanosecs = diff.tv_sec * 1000000000 + diff.tv_nsec;
        std::cerr << "test took " << nanosecs << " nanoseconds for " << numbers << " searches" << std::endl;
    }
    catch (po6::error& e)
    {
        std::cerr << "There was a system error:  " << e.what();
        return EXIT_FAILURE;
    }
    catch (std::runtime_error& e)
    {
        std::cerr << "There was a runtime error:  " << e.what();
        return EXIT_FAILURE;
    }
    catch (std::bad_alloc& e)
    {
        std::cerr << "There was a memory allocation error:  " << e.what();
        return EXIT_FAILURE;
    }
    catch (std::exception& e)
    {
        std::cerr << "There was a generic error:  " << e.what();
        return EXIT_FAILURE;
    }

    return EXIT_SUCCESS;
}

int
usage()
{
    std::cerr << "Usage:  binary <coordinator ip> <coordinator port> <space name> <numbers>\n"
              << "This will create <numbers> points whose key is a number [0, <numbers>) and "
              << "then perform searches over the bits of the number.  The space should have 32 "
              << "secondary dimensions so that all bits of a number may be stored."
              << std::endl;
    return EXIT_FAILURE;
}
<|endoftext|>


<commit_before>#include "scene.h"

#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <time.h>

#include <allegro5/allegro.h>
#include <allegro5/allegro_acodec.h>
#include <allegro5/allegro_audio.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_ttf.h>

bool done;
ALLEGRO_EVENT_QUEUE *event_queue;
ALLEGRO_TIMER *timer;
ALLEGRO_DISPLAY *display;
ALLEGRO_FONT *font;

void abort_game(const char *message) {
  printf("%s \n", message);
  exit(1);
}

void init(void) {
  if (!al_init())
    abort_game("Failed to initialize allegro");

  if (!al_install_keyboard())
    abort_game("Failed to install keyboard");
  if (!al_init_primitives_addon())
    abort_game("Failed to install primitives");
  al_init_font_addon(); // initialize the font addon
  al_init_ttf_addon();  // initialize the ttf (True Type Font) addon

  if (!al_install_audio()) {
    abort_game("failed to initialize audio!\n");
  }

  if (!al_init_acodec_addon()) {
    abort_game("failed to initialize audio codecs!\n");
  }

  if (!al_reserve_samples(10)) {
    abort_game("failed to reserve samples!\n");
  }

  if (!al_init_image_addon()) {
    abort_game("failed to init image addon!\n");
  }

//  timer = al_create_timer(1.0 / 60);
//  if (!timer)
//    abort_game("Failed to create timer");

  ALLEGRO_DISPLAY_MODE disp_data;
  al_get_display_mode(0, &disp_data);

  al_set_new_display_flags(ALLEGRO_WINDOWED);
  // display = al_create_display(disp_data.width, disp_data.height);
  display = al_create_display(320, 200);
  if (!display)
    abort_game("Failed to create display");

  event_queue = al_create_event_queue();
  if (!event_queue)
    abort_game("Failed to create event queue");

  al_register_event_source(event_queue, al_get_keyboard_event_source());
//  al_register_event_source(event_queue, al_get_timer_event_source(timer));
  al_register_event_source(event_queue, al_get_display_event_source(display));

  al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);

  font = al_load_ttf_font("src/Atari_Full.ttf", 8, 0);

  done = false;
}

void shutdown(void) {
  if (timer)
    al_destroy_timer(timer);

  if (display)
    al_destroy_display(display);

  if (event_queue)
    al_destroy_event_queue(event_queue);

  al_shutdown_primitives_addon();
}

void game_loop(void) {
  Scene scene;
  scene.font = font;
  ALLEGRO_KEYBOARD_STATE kbd_state;

  bool key_pressed[ALLEGRO_KEY_MAX] = {0};
  bool key_down[ALLEGRO_KEY_MAX] = {0};

  double key_time[ALLEGRO_KEY_MAX] = {0};

  bool key_repeat[ALLEGRO_KEY_MAX] = {0};
  bool key_repeat_first[ALLEGRO_KEY_MAX] = {0};

  constexpr double KEY_REP_TIME = 0.1;
  constexpr double KEY_REP_TIME_FIRST = 0.2;

  while (!done) {
    ALLEGRO_EVENT ev;
    double now = al_get_time();

    while (al_get_next_event(event_queue, &ev)) {
      if (ev.type == ALLEGRO_EVENT_KEY_DOWN) {
        key_pressed[ev.keyboard.keycode] = true;
        key_down[ev.keyboard.keycode] = true;
        key_time[ev.keyboard.keycode] = now;
        key_repeat_first[ev.keyboard.keycode] = true;
      } else if (ev.type == ALLEGRO_EVENT_KEY_UP) {
        key_down[ev.keyboard.keycode] = false;
        key_repeat_first[ev.keyboard.keycode] = false;
        key_repeat[ev.keyboard.keycode] = false;
      } else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
        done = true;
      }
    }

    if (key_down[ALLEGRO_KEY_ESCAPE])
      done = true;

    for (int i = 0; i < ALLEGRO_KEY_MAX; i++) {
      double rep_time = key_repeat_first[i] ? KEY_REP_TIME_FIRST : KEY_REP_TIME;
      if (key_down[i] && (now - key_time[i] >= rep_time)) {
        key_time[i] = now;
        key_repeat[i] = true;
        key_repeat_first[i] = false;
      }
    }

    scene.tick(key_pressed, key_repeat);
    al_clear_to_color(al_map_rgb(0,0,0));
    scene.draw();
    al_flip_display();

    for (auto &pressed : key_pressed)
      pressed = false;

    for (auto &rep : key_repeat)
      rep = false;
  }
}

int main(int argc, char *argv[]) {
  init();
  game_loop();
  shutdown();
}
<commit_msg>Tweak keyrepeat time<commit_after>#include "scene.h"

#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <time.h>

#include <allegro5/allegro.h>
#include <allegro5/allegro_acodec.h>
#include <allegro5/allegro_audio.h>
#include <allegro5/allegro_font.h>
#include <allegro5/allegro_image.h>
#include <allegro5/allegro_primitives.h>
#include <allegro5/allegro_ttf.h>

bool done;
ALLEGRO_EVENT_QUEUE *event_queue;
ALLEGRO_TIMER *timer;
ALLEGRO_DISPLAY *display;
ALLEGRO_FONT *font;

void abort_game(const char *message) {
  printf("%s \n", message);
  exit(1);
}

void init(void) {
  if (!al_init())
    abort_game("Failed to initialize allegro");

  if (!al_install_keyboard())
    abort_game("Failed to install keyboard");
  if (!al_init_primitives_addon())
    abort_game("Failed to install primitives");
  al_init_font_addon(); // initialize the font addon
  al_init_ttf_addon();  // initialize the ttf (True Type Font) addon

  if (!al_install_audio()) {
    abort_game("failed to initialize audio!\n");
  }

  if (!al_init_acodec_addon()) {
    abort_game("failed to initialize audio codecs!\n");
  }

  if (!al_reserve_samples(10)) {
    abort_game("failed to reserve samples!\n");
  }

  if (!al_init_image_addon()) {
    abort_game("failed to init image addon!\n");
  }

//  timer = al_create_timer(1.0 / 60);
//  if (!timer)
//    abort_game("Failed to create timer");

  ALLEGRO_DISPLAY_MODE disp_data;
  al_get_display_mode(0, &disp_data);

  al_set_new_display_flags(ALLEGRO_WINDOWED);
  // display = al_create_display(disp_data.width, disp_data.height);
  display = al_create_display(320, 200);
  if (!display)
    abort_game("Failed to create display");

  event_queue = al_create_event_queue();
  if (!event_queue)
    abort_game("Failed to create event queue");

  al_register_event_source(event_queue, al_get_keyboard_event_source());
//  al_register_event_source(event_queue, al_get_timer_event_source(timer));
  al_register_event_source(event_queue, al_get_display_event_source(display));

  al_set_blender(ALLEGRO_ADD, ALLEGRO_ALPHA, ALLEGRO_INVERSE_ALPHA);

  font = al_load_ttf_font("src/Atari_Full.ttf", 8, 0);

  done = false;
}

void shutdown(void) {
  if (timer)
    al_destroy_timer(timer);

  if (display)
    al_destroy_display(display);

  if (event_queue)
    al_destroy_event_queue(event_queue);

  al_shutdown_primitives_addon();
}

void game_loop(void) {
  Scene scene;
  scene.font = font;
  ALLEGRO_KEYBOARD_STATE kbd_state;

  bool key_pressed[ALLEGRO_KEY_MAX] = {0};
  bool key_down[ALLEGRO_KEY_MAX] = {0};

  double key_time[ALLEGRO_KEY_MAX] = {0};

  bool key_repeat[ALLEGRO_KEY_MAX] = {0};
  bool key_repeat_first[ALLEGRO_KEY_MAX] = {0};

  constexpr double KEY_REP_TIME = 0.1;
  constexpr double KEY_REP_TIME_FIRST = 0.35;

  while (!done) {
    ALLEGRO_EVENT ev;
    double now = al_get_time();

    while (al_get_next_event(event_queue, &ev)) {
      if (ev.type == ALLEGRO_EVENT_KEY_DOWN) {
        key_pressed[ev.keyboard.keycode] = true;
        key_down[ev.keyboard.keycode] = true;
        key_time[ev.keyboard.keycode] = now;
        key_repeat_first[ev.keyboard.keycode] = true;
      } else if (ev.type == ALLEGRO_EVENT_KEY_UP) {
        key_down[ev.keyboard.keycode] = false;
        key_repeat_first[ev.keyboard.keycode] = false;
        key_repeat[ev.keyboard.keycode] = false;
      } else if (ev.type == ALLEGRO_EVENT_DISPLAY_CLOSE) {
        done = true;
      }
    }

    if (key_down[ALLEGRO_KEY_ESCAPE])
      done = true;

    for (int i = 0; i < ALLEGRO_KEY_MAX; i++) {
      double rep_time = key_repeat_first[i] ? KEY_REP_TIME_FIRST : KEY_REP_TIME;
      if (key_down[i] && (now - key_time[i] >= rep_time)) {
        key_time[i] = now;
        key_repeat[i] = true;
        key_repeat_first[i] = false;
      }
    }

    scene.tick(key_pressed, key_repeat);
    al_clear_to_color(al_map_rgb(0,0,0));
    scene.draw();
    al_flip_display();

    for (auto &pressed : key_pressed)
      pressed = false;

    for (auto &rep : key_repeat)
      rep = false;
  }
}

int main(int argc, char *argv[]) {
  init();
  game_loop();
  shutdown();
}
<|endoftext|>


<commit_before>#ifndef LOGGER_HPP
#define LOGGER_HPP

#include <fstream>
#include <string>

namespace swift
{
	class Logger
	{
		public:
			explicit Logger(const std::string& header, const std::string& logFile = "./data/swift.log")
			{
				warnings = 0;
				errors = 0;

				fout.open(logFile);

				// Write the first lines
				if(fout.is_open())
				{
					fout << header << "\n\n";
				}
			}

			~Logger()
			{
				if(fout.is_open())
				{
					fout << std::endl << std::endl;

					// Report number of errors and warnings
					fout << warnings << " warnings" << std::endl;
					fout << errors << " errors" << std::endl;

					fout.close();
				}
			}

			// Make it Non Copyable
			Logger(const Logger&) = delete;
			Logger& operator=(const Logger&) = delete;

			Logger& operator<<(char c)
			{
				fout << c;
				return *this;
			}

			Logger& operator<<(const std::string& text)
			{
				fout << text;
				return *this;
			}

			Logger& operator<<(int n)
			{
				fout << n;
				return *this;
			}

			Logger& operator<<(unsigned n)
			{
				fout << n;
				return *this;
			}

			Logger& operator<<(std::size_t n)
			{
				fout << n;
				return *this;
			}

			Logger& operator<<(float n)
			{
				fout << n;
				return *this;
			}

			Logger& operator<<(double n)
			{
				fout << n;
				return *this;
			}

		private:
			std::ofstream fout;

			unsigned warnings;
			unsigned errors;
	};

	extern Logger log;
}

#endif // LOGGER_HPP
<commit_msg>Modified Logger to work as "log" everywhere it is included.<commit_after>#ifndef LOGGER_HPP
#define LOGGER_HPP

#include <fstream>
#include <string>

namespace swift
{
	class Logger
	{
		public:
			explicit Logger(const std::string& header, const std::string& logFile = "./data/swift.log")
			{
				warnings = 0;
				errors = 0;

				fout.open(logFile);

				// Write the first lines
				if(fout.is_open())
				{
					fout << header << "\n\n";
				}
			}

			~Logger()
			{
				if(fout.is_open())
				{
					fout << std::endl << std::endl;

					// Report number of errors and warnings
					fout << warnings << " warnings" << std::endl;
					fout << errors << " errors" << std::endl;

					fout.close();
				}
			}

			// Make it Non Copyable
			Logger(const Logger&) = delete;
			Logger& operator=(const Logger&) = delete;

			Logger& operator<<(char c)
			{
				fout << c;
				return *this;
			}

			Logger& operator<<(const std::string& text)
			{
				fout << text;
				fout.flush();
				return *this;
			}

			Logger& operator<<(int n)
			{
				fout << n;
				return *this;
			}

			Logger& operator<<(unsigned n)
			{
				fout << n;
				return *this;
			}

			Logger& operator<<(std::size_t n)
			{
				fout << n;
				return *this;
			}

			Logger& operator<<(float n)
			{
				fout << n;
				return *this;
			}

			Logger& operator<<(double n)
			{
				fout << n;
				return *this;
			}

		private:
			std::ofstream fout;

			unsigned warnings;
			unsigned errors;
	};

	extern Logger log;
}

#endif // LOGGER_HPP
<|endoftext|>


<commit_before>#include <fps_logger.hpp>
#include "display.hpp"
#include "shader.hpp"
#include "mesh.hpp"

#define SHADER_FOLDER_NAME "./script/"

using namespace std;

int main() {
    Display window(800, 600, "Test");

    Vertex vertices[] = {
            Vertex(vec3(-0.03f, -0.03f, 0.0f)),
            Vertex(vec3(0.03f, -0.03f, 0.0f)),
            Vertex(vec3(0.0f, 0.03f, 0.0f))
    };

    Shader shader(std::string(SHADER_FOLDER_NAME) + std::string("basic_shader"));
    shader.bind();
    Mesh mesh(vertices, (sizeof(vertices) / sizeof(Vertex)));
    Transform transform;

    float angleRad = 0.0f;
    bool isRunning = true;
//    FpsLogger fpsLogger;
    unsigned long frameCount = 0;
    double fps = 0;

    while (isRunning) {
        window.clear(0.15f, 0.15f, 0.15f, 1.0f);
        SDL_Event e;

        if (SDL_PollEvent(&e)) {
            if (e.type == SDL_QUIT) {
                isRunning = false;
            }

            if (e.type == SDL_KEYDOWN && e.key.keysym.scancode == SDL_SCANCODE_ESCAPE) {
                isRunning = false;
            }
        }

        glm::vec3 pos = transform.getPosition();
        float sin_delta = sinf(angleRad);
        float cos_delta = cosf(angleRad);
        pos.x = sin_delta;
        pos.y = cos_delta;
        transform.setPosition(pos);

        shader.update(transform);
        mesh.draw();

        angleRad += 0.03f;
        frameCount++;

//        cout << "Min FPS: " << fpsLogger.getMinFps() << endl;

//        fps = fpsLogger.logAndGetFps(frameCount);
        window.setTitlePostfix(to_string(fps));

        window.swapBuffers();
        SDL_Delay(32);
    }

    return 0;
}
<commit_msg>use FPS logger<commit_after>#include <fps_logger.hpp>
#include "display.hpp"
#include "shader.hpp"
#include "mesh.hpp"

#define SHADER_FOLDER_NAME "./script/"

using namespace std;

int main() {
    Display window(800, 600, "Test");

    Vertex vertices[] = {
            Vertex(vec3(-0.03f, -0.03f, 0.0f)),
            Vertex(vec3(0.03f, -0.03f, 0.0f)),
            Vertex(vec3(0.0f, 0.03f, 0.0f))
    };

    Shader shader(std::string(SHADER_FOLDER_NAME) + std::string("basic_shader"));
    shader.bind();
    Mesh mesh(vertices, (sizeof(vertices) / sizeof(Vertex)));
    Transform transform;

    float angleRad = 0.0f;
    bool isRunning = true;
    FpsLogger fpsLogger;
    unsigned long frameCount = 0;
    double fps = 0;

    while (isRunning) {
        window.clear(0.15f, 0.15f, 0.15f, 1.0f);
        SDL_Event e;

        if (SDL_PollEvent(&e)) {
            if (e.type == SDL_QUIT) {
                isRunning = false;
            }

            if (e.type == SDL_KEYDOWN && e.key.keysym.scancode == SDL_SCANCODE_ESCAPE) {
                isRunning = false;
            }
        }

        glm::vec3 pos = transform.getPosition();
        float sin_delta = sinf(angleRad);
        float cos_delta = cosf(angleRad);
        pos.x = sin_delta;
        pos.y = cos_delta;
        transform.setPosition(pos);

        shader.update(transform);
        mesh.draw();

        angleRad += 0.03f;
        frameCount++;

        cout << "Min FPS: " << fpsLogger.getMinFps() << endl;

        fps = fpsLogger.logAndGetFps(frameCount);
        window.setTitlePostfix(to_string(fps));

        window.swapBuffers();
        SDL_Delay(32);
    }

    return 0;
}
<|endoftext|>


<commit_before>#include "MemAllocHeap.hpp"
#include "Buffer.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

extern "C" {
#include "lua.h"
#include "lauxlib.h"
}

namespace t2
{

struct BufferedWriter
{
  size_t m_Used;
  char m_Buffer[8192];
  FILE* m_File;
};

static void BufferedWriterInit(BufferedWriter* w, FILE* f)
{
  w->m_Used = 0;
  w->m_File = f;
}

static void BufferedWriterFlush(BufferedWriter* w)
{
  size_t remain = w->m_Used;
  const char* src = w->m_Buffer;
  while (remain)
  {
    size_t count = fwrite(src, 1, remain, w->m_File);
    src += count;
    remain -= count;
  }
  w->m_Used = 0;
}

inline void BufferedWriterAppend(BufferedWriter* w, int ch)
{
  size_t pos = w->m_Used;
  if (pos == ARRAY_SIZE(w->m_Buffer))
  {
    BufferedWriterFlush(w);
    pos = 0;
  }
  w->m_Buffer[pos] = (char) ch;
  w->m_Used = pos + 1;
}

static void BufferedWriterAppendString(BufferedWriter* w, const char* str)
{
  for (const char* p = str; *p; ++p)
  {
    BufferedWriterAppend(w, *p);
  }
}

struct LuaJsonWriter
{
  bool           m_FirstElem;
  BufferedWriter m_Writer;
};

static int LuaJsonWriterNew(lua_State* L)
{
  const char* filename = luaL_checkstring(L, 1);
  LuaJsonWriter* self = (LuaJsonWriter*) lua_newuserdata(L, sizeof(LuaJsonWriter));

  memset(self, 0, sizeof *self);

  self->m_FirstElem = true;

  if (FILE* f = fopen(filename, "w"))
  {
    BufferedWriterInit(&self->m_Writer, f);

    luaL_getmetatable(L, "tundra_jsonw");
    lua_setmetatable(L, -2);
    return 1;
  }
  else
  {
    return luaL_error(L, "couldn't open %s for writing", filename);
  }
}

static int LuaJsonGc(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  if (FILE* f = self->m_Writer.m_File)
  {
    BufferedWriterFlush(&self->m_Writer);
    self->m_Writer.m_File = nullptr;
    fclose(f);
  }

  return 0;
}

static void WriteEscapedString(BufferedWriter* w, const char* str)
{
  BufferedWriterAppend(w, '"');

  while (char ch = *str++)
  {
    char escape_code = 0;

    switch (ch)
    {
      case '\r': escape_code = 'r'; break;
      case '\n': escape_code = 'n'; break;
      case '\t': escape_code = 't'; break;
      case '\v': escape_code = 'v'; break;
      case '\f': escape_code = 'f'; break;
      case '\\': escape_code = '\\'; break;
      case '"': escape_code = '"'; break;
    }

    if (escape_code)
    {
      BufferedWriterAppend(w, '\\');
      BufferedWriterAppend(w, escape_code);
    }
    else
    {
      BufferedWriterAppend(w, ch);
    }
  }

  BufferedWriterAppend(w, '"');
}

static void WriteComma(LuaJsonWriter* self)
{
  if (self->m_FirstElem)
  {
    self->m_FirstElem = false;
  }
  else
  {
    BufferedWriterAppend(&self->m_Writer, ',');
  }
}

static void WriteCommon(lua_State* L, LuaJsonWriter* self, int name_index)
{
  WriteComma(self);
  if (lua_gettop(L) >= name_index)
  {
    WriteEscapedString(&self->m_Writer, luaL_checkstring(L, name_index));
    BufferedWriterAppend(&self->m_Writer, ':');
  }
}

static int LuaJsonWriteNumber(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  lua_Number num = luaL_checknumber(L, 2);
  WriteCommon(L, self, 3);

  char buffer[64];
  lua_number2str(buffer, num);
  BufferedWriterAppendString(&self->m_Writer, buffer);
  return 0;
}

static int LuaJsonWriteBool(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  int value = lua_toboolean(L, 2);
  WriteCommon(L, self, 3);
  BufferedWriterAppendString(&self->m_Writer, value ? "true" : "false");
  return 0;
}

static int LuaJsonWriteString(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  const char* value = lua_tostring(L, 2);
  WriteCommon(L, self, 3);
  WriteEscapedString(&self->m_Writer, value);
  return 0;
}

static int LuaJsonBeginObject(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  WriteCommon(L, self, 2);
  BufferedWriterAppend(&self->m_Writer, '{');
  self->m_FirstElem = true;
  return 0;
}

static int LuaJsonEndObject(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  BufferedWriterAppend(&self->m_Writer, '}');
  self->m_FirstElem = false;
  return 0;
}

static int LuaJsonBeginArray(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  WriteCommon(L, self, 2);
  BufferedWriterAppend(&self->m_Writer, '[');
  self->m_FirstElem = true;
  return 0;
}

static int LuaJsonEndArray(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  BufferedWriterAppend(&self->m_Writer, ']');
  self->m_FirstElem = false;
  return 0;
}

void LuaJsonNativeOpen(lua_State* L)
{
  static luaL_Reg functions[] =
  {
    { "new",                        LuaJsonWriterNew },
    { nullptr,                      nullptr }
  };

  static luaL_Reg meta_table[] =
  {
    { "write_number",               LuaJsonWriteNumber },
    { "write_string",               LuaJsonWriteString },
    { "write_bool",                 LuaJsonWriteBool },
    { "begin_object",               LuaJsonBeginObject },
    { "end_object",                 LuaJsonEndObject },
    { "begin_array",                LuaJsonBeginArray },
    { "end_array",                  LuaJsonEndArray },
    { "close",                      LuaJsonGc },
    { "__gc",                       LuaJsonGc },
    { nullptr,                      nullptr }
  };

  luaL_register(L, "tundra.native.json", functions);
  lua_pop(L, 1);

  luaL_newmetatable(L, "tundra_jsonw");
  lua_pushvalue(L, -1);
  lua_setfield(L, -2, "__index");
  luaL_register(L, nullptr, meta_table);
  lua_pop(L, 1);
}

}
<commit_msg>Perf: Speed up JSON string escaping using LUT<commit_after>#include "MemAllocHeap.hpp"
#include "Buffer.hpp"
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

extern "C" {
#include "lua.h"
#include "lauxlib.h"
}

namespace t2
{

struct BufferedWriter
{
  size_t m_Used;
  char m_Buffer[8192];
  FILE* m_File;
};

static void BufferedWriterInit(BufferedWriter* w, FILE* f)
{
  w->m_Used = 0;
  w->m_File = f;
}

static void BufferedWriterFlush(BufferedWriter* w)
{
  size_t remain = w->m_Used;
  const char* src = w->m_Buffer;
  while (remain)
  {
    size_t count = fwrite(src, 1, remain, w->m_File);
    src += count;
    remain -= count;
  }
  w->m_Used = 0;
}

inline void BufferedWriterAppend(BufferedWriter* w, int ch)
{
  size_t pos = w->m_Used;
  if (pos == ARRAY_SIZE(w->m_Buffer))
  {
    BufferedWriterFlush(w);
    pos = 0;
  }
  w->m_Buffer[pos] = (char) ch;
  w->m_Used = pos + 1;
}

static void BufferedWriterAppendString(BufferedWriter* w, const char* str)
{
  for (const char* p = str; *p; ++p)
  {
    BufferedWriterAppend(w, *p);
  }
}

struct LuaJsonWriter
{
  bool           m_FirstElem;
  BufferedWriter m_Writer;
};

static int LuaJsonWriterNew(lua_State* L)
{
  const char* filename = luaL_checkstring(L, 1);
  LuaJsonWriter* self = (LuaJsonWriter*) lua_newuserdata(L, sizeof(LuaJsonWriter));

  memset(self, 0, sizeof *self);

  self->m_FirstElem = true;

  if (FILE* f = fopen(filename, "w"))
  {
    BufferedWriterInit(&self->m_Writer, f);

    luaL_getmetatable(L, "tundra_jsonw");
    lua_setmetatable(L, -2);
    return 1;
  }
  else
  {
    return luaL_error(L, "couldn't open %s for writing", filename);
  }
}

static int LuaJsonGc(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  if (FILE* f = self->m_Writer.m_File)
  {
    BufferedWriterFlush(&self->m_Writer);
    self->m_Writer.m_File = nullptr;
    fclose(f);
  }

  return 0;
}

static char s_EscapeTable[256] = { 0 };

static void WriteEscapedString(BufferedWriter* w, const char* str, size_t len)
{
  BufferedWriterAppend(w, '"');

  for (size_t i = 0; i < len; ++i)
  {
    char ch = str[i];
    char escape_code = s_EscapeTable[(uint32_t) ch];

    if (escape_code)
    {
      BufferedWriterAppend(w, '\\');
      BufferedWriterAppend(w, escape_code);
    }
    else
    {
      BufferedWriterAppend(w, ch);
    }
  }

  BufferedWriterAppend(w, '"');
}

static void WriteComma(LuaJsonWriter* self)
{
  if (self->m_FirstElem)
  {
    self->m_FirstElem = false;
  }
  else
  {
    BufferedWriterAppend(&self->m_Writer, ',');
  }
}

static void WriteCommon(lua_State* L, LuaJsonWriter* self, int name_index)
{
  WriteComma(self);
  if (lua_gettop(L) >= name_index)
  {
    size_t len;
    const char* str = luaL_checklstring(L, name_index, &len);
    WriteEscapedString(&self->m_Writer, str, len);
    BufferedWriterAppend(&self->m_Writer, ':');
  }
}

static int LuaJsonWriteNumber(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  lua_Number num = luaL_checknumber(L, 2);
  WriteCommon(L, self, 3);

  char buffer[64];
  lua_number2str(buffer, num);
  BufferedWriterAppendString(&self->m_Writer, buffer);
  return 0;
}

static int LuaJsonWriteBool(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  int value = lua_toboolean(L, 2);
  WriteCommon(L, self, 3);
  BufferedWriterAppendString(&self->m_Writer, value ? "true" : "false");
  return 0;
}

static int LuaJsonWriteString(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  size_t value_len;
  const char* value = lua_tolstring(L, 2, &value_len);
  WriteCommon(L, self, 3);
  WriteEscapedString(&self->m_Writer, value, value_len);
  return 0;
}

static int LuaJsonBeginObject(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  WriteCommon(L, self, 2);
  BufferedWriterAppend(&self->m_Writer, '{');
  self->m_FirstElem = true;
  return 0;
}

static int LuaJsonEndObject(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  BufferedWriterAppend(&self->m_Writer, '}');
  self->m_FirstElem = false;
  return 0;
}

static int LuaJsonBeginArray(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  WriteCommon(L, self, 2);
  BufferedWriterAppend(&self->m_Writer, '[');
  self->m_FirstElem = true;
  return 0;
}

static int LuaJsonEndArray(lua_State* L)
{
  LuaJsonWriter* self = (LuaJsonWriter*) luaL_checkudata(L, 1, "tundra_jsonw");
  BufferedWriterAppend(&self->m_Writer, ']');
  self->m_FirstElem = false;
  return 0;
}

void LuaJsonNativeOpen(lua_State* L)
{
  static luaL_Reg functions[] =
  {
    { "new",                        LuaJsonWriterNew },
    { nullptr,                      nullptr }
  };

  static luaL_Reg meta_table[] =
  {
    { "write_number",               LuaJsonWriteNumber },
    { "write_string",               LuaJsonWriteString },
    { "write_bool",                 LuaJsonWriteBool },
    { "begin_object",               LuaJsonBeginObject },
    { "end_object",                 LuaJsonEndObject },
    { "begin_array",                LuaJsonBeginArray },
    { "end_array",                  LuaJsonEndArray },
    { "close",                      LuaJsonGc },
    { "__gc",                       LuaJsonGc },
    { nullptr,                      nullptr }
  };

  luaL_register(L, "tundra.native.json", functions);
  lua_pop(L, 1);

  luaL_newmetatable(L, "tundra_jsonw");
  lua_pushvalue(L, -1);
  lua_setfield(L, -2, "__index");
  luaL_register(L, nullptr, meta_table);
  lua_pop(L, 1);

  s_EscapeTable[uint32_t('\n')] = 'n';
  s_EscapeTable[uint32_t('\r')] = 'r';
  s_EscapeTable[uint32_t('\t')] = 't';
  s_EscapeTable[uint32_t('\v')] = 'v';
  s_EscapeTable[uint32_t('\f')] = 'f';
  s_EscapeTable[uint32_t('\\')] = '\\';
  s_EscapeTable[uint32_t('"')] = '"';
}

}
<|endoftext|>