<commit_before>
#include <nan.h>
#include <Windows.h>
#include <map>

namespace demo
{

using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Array;
using v8::Boolean;
using v8::Number;
using v8::Exception;

std::map<int,std::wstring> standardFormats;

void initFormats() {
	standardFormats[ 2 ] = std::wstring( L"CF_BITMAP" );
	standardFormats[ 8 ] = std::wstring( L"CF_DIB" );
	standardFormats[ 17 ] = std::wstring( L"CF_DIBV5" );
	standardFormats[ 5 ] = std::wstring( L"CF_DIF" );
	standardFormats[ 0x0082 ] = std::wstring( L"CF_DSPBITMAP" );
	standardFormats[ 0x008E ] = std::wstring( L"CF_DSPENHMETAFILE" );
	standardFormats[ 0x0083 ] = std::wstring( L"CF_DSPMETAFILEPICT" );
	standardFormats[ 0x0081 ] = std::wstring( L"CF_DSPTEXT" );
	standardFormats[ 14 ] = std::wstring( L"CF_ENHMETAFILE" );
	standardFormats[ 0x0300 ] = std::wstring( L"CF_GDIOBJFIRST" );
	standardFormats[ 0x03FF ] = std::wstring( L"CF_GDIOBJLAST" );
	standardFormats[ 15 ] = std::wstring( L"CF_HDROP" );
	standardFormats[ 16 ] = std::wstring( L"CF_LOCALE" );
	standardFormats[ 3 ] = std::wstring( L"CF_METAFILEPICT" );
	standardFormats[ 7 ] = std::wstring( L"CF_OEMTEXT" );
	standardFormats[ 0x0080 ] = std::wstring( L"CF_OWNERDISPLAY" );
	standardFormats[ 9 ] = std::wstring( L"CF_PALETTE" );
	standardFormats[ 10 ] = std::wstring( L"CF_PENDATA" );
	standardFormats[ 0x0200 ] = std::wstring( L"CF_PRIVATEFIRST" );
	standardFormats[ 0x02FF ] = std::wstring( L"CF_PRIVATELAST" );
	standardFormats[ 11 ] = std::wstring( L"CF_RIFF" );
	standardFormats[ 4 ] = std::wstring( L"CF_SYLK" );
	standardFormats[ 1 ] = std::wstring( L"CF_TEXT" );
	standardFormats[ 6 ] = std::wstring( L"CF_TIFF" );
	standardFormats[ 13 ] = std::wstring( L"CF_UNICODETEXT" );
	standardFormats[ 12 ] = std::wstring( L"CF_WAVE" );
}

// A quick and dirty method to convert UTF16 to UTF8 - http://stackoverflow.com/questions/215963/how-do-you-properly-use-widechartomultibyte
// Convert a wide Unicode string to an UTF8 string
std::string utf8_encode(const std::wstring &wstr)
{
    if( wstr.empty() ) return std::string();
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string strTo( size_needed, 0 );
    WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
    return strTo;
}

// Convert an UTF8 string to a wide Unicode String
std::wstring utf8_decode(const std::string &str)
{
    if( str.empty() ) return std::wstring();
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo( size_needed, 0 );
    MultiByteToWideChar                  (CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

void GetUser(const FunctionCallbackInfo<Value> &args)
{
	const unsigned int BUFFER_SIZE = 255;
	DWORD userNameLength = BUFFER_SIZE - 1;
	BOOL res = false;
	wchar_t userName[ BUFFER_SIZE ];
	memset( userName, 0, sizeof( WCHAR ) * userNameLength );

	res = GetUserNameW( userName, &userNameLength );

    Isolate *isolate = args.GetIsolate();

	if ( res ) {
		args.GetReturnValue().Set(String::NewFromUtf8(isolate, utf8_encode( userName ).c_str()));
	} else {
		args.GetReturnValue().Set(Boolean::New(isolate, false));
	}
}

void ClearClipboard( const FunctionCallbackInfo<Value> &args ) {
	BOOL ret = true;

	if ( !OpenClipboard( NULL ) ) {
		ret = false;
	}

	EmptyClipboard();
	CloseClipboard();

	Isolate *isolate = args.GetIsolate();
	args.GetReturnValue().Set(Boolean::New(isolate, ret));
}

void GetClipboardFormats( const FunctionCallbackInfo<Value> &args ) {
	Isolate *isolate = args.GetIsolate();
	Local<Array> arr = Array::New( isolate );

	int formatsCount = CountClipboardFormats();
	BOOL clipboardReady = false;
	const int BUFFER_LENGTH = 255;

	std::vector<UINT> types( formatsCount );

	if ( !formatsCount ) {
		// Early return, there's no need to open clipboard and do all this jazz.
		return;
	}

	clipboardReady = OpenClipboard( NULL );

	if ( !clipboardReady ) {
		return;
	}

	for ( int i = 0; i < formatsCount; i++ ) {
		// For first iteration 0 needs to be passed, for any subsequent call a previous
		// id should be provided.
		types[ i ] = EnumClipboardFormats( i == 0 ? 0 : types[ i-1 ] );

		std::wstring out;

		// Check for predefined formats.
		if ( standardFormats.count( types[ i ] ) ) {
			out = standardFormats[ types[ i ] ];
		} else {
			// Else pick it up from WINAPI.
			TCHAR curName[ BUFFER_LENGTH ];
			memset( curName, 0, sizeof( TCHAR ) * BUFFER_LENGTH );

			GetClipboardFormatName( types[ i ], curName, BUFFER_LENGTH - 1 );

			out = std::wstring( curName );
		}

		#ifdef UNICODE
			arr->Set( i, String::NewFromUtf8(isolate, utf8_encode( out ).c_str()) );
		#else
			arr->Set( i, String::NewFromOneByte( isolate, curName ) );
		#endif
	}

	args.GetReturnValue().Set( arr );

	CloseClipboard();
}

void getClipboardData( const FunctionCallbackInfo<Value> &args ) {
	Isolate *isolate = args.GetIsolate();
	Local<v8::Object> ret;

	if ( args.Length() < 1 ) {
	    isolate->ThrowException(Exception::TypeError(
			String::NewFromUtf8(isolate, "Missing argument 1")));
	    return;
	}

	if ( !args[0]->IsString() ) {
	    isolate->ThrowException(Exception::TypeError(
			String::NewFromUtf8(isolate, "Argument 1 must be a string")));
	    return;
	}

	OpenClipboard( NULL );

	v8::String::Utf8Value formatRawName( args[ 0 ] );
	std::wstring formatNameUtf16 = utf8_decode( *formatRawName );

	UINT formatId = 0;

	for (auto& item: standardFormats) {
		if ( item.second.compare( formatNameUtf16 ) == 0 ) {
			formatId = item.first;
		}
	}

	// @todo if no formatId was found it can still be a custom format.

	if ( formatId != 0 ) {
		HGLOBAL clipboardDataHandle = GetClipboardData( formatId );

		if ( clipboardDataHandle != NULL ) {
			LPVOID data = GlobalLock( clipboardDataHandle );

			if ( data != NULL ) {
				SIZE_T clipboardBytes = GlobalSize( clipboardDataHandle );

				// It copies data, so no worry about WINAPI cleaning it up on it's own.
				ret = Nan::CopyBuffer( (const char*)data, clipboardBytes ).ToLocalChecked();

				GlobalUnlock( clipboardDataHandle );
			} else {
				formatId = 0;
			}
		} else {
			formatId = 0;
		}
	}

	CloseClipboard();

	Local<Number> tmpRet = Number::New( isolate, formatId );

	if ( formatId != 0 ) {
		// args.GetReturnValue().Set( tmpRet );
		args.GetReturnValue().Set( ret );
	} else {
		// Format not found.
		args.GetReturnValue().Set( Nan::Null() );
	}
}

void init(Local<Object> exports)
{
	initFormats();

    NODE_SET_METHOD(exports, "getUser", GetUser);
	NODE_SET_METHOD(exports, "clear", ClearClipboard);
	NODE_SET_METHOD(exports, "getFormats", GetClipboardFormats);
	NODE_SET_METHOD(exports, "getData", getClipboardData);
}

NODE_MODULE(addon, init)

} // namespace demo<commit_msg>Added support for custom formats in GetData.<commit_after>
#include <nan.h>
#include <Windows.h>
#include <map>

namespace demo
{

using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Object;
using v8::String;
using v8::Value;
using v8::Array;
using v8::Boolean;
using v8::Number;
using v8::Exception;

std::map<int,std::wstring> standardFormats;

void initFormats() {
	standardFormats[ 2 ] = std::wstring( L"CF_BITMAP" );
	standardFormats[ 8 ] = std::wstring( L"CF_DIB" );
	standardFormats[ 17 ] = std::wstring( L"CF_DIBV5" );
	standardFormats[ 5 ] = std::wstring( L"CF_DIF" );
	standardFormats[ 0x0082 ] = std::wstring( L"CF_DSPBITMAP" );
	standardFormats[ 0x008E ] = std::wstring( L"CF_DSPENHMETAFILE" );
	standardFormats[ 0x0083 ] = std::wstring( L"CF_DSPMETAFILEPICT" );
	standardFormats[ 0x0081 ] = std::wstring( L"CF_DSPTEXT" );
	standardFormats[ 14 ] = std::wstring( L"CF_ENHMETAFILE" );
	standardFormats[ 0x0300 ] = std::wstring( L"CF_GDIOBJFIRST" );
	standardFormats[ 0x03FF ] = std::wstring( L"CF_GDIOBJLAST" );
	standardFormats[ 15 ] = std::wstring( L"CF_HDROP" );
	standardFormats[ 16 ] = std::wstring( L"CF_LOCALE" );
	standardFormats[ 3 ] = std::wstring( L"CF_METAFILEPICT" );
	standardFormats[ 7 ] = std::wstring( L"CF_OEMTEXT" );
	standardFormats[ 0x0080 ] = std::wstring( L"CF_OWNERDISPLAY" );
	standardFormats[ 9 ] = std::wstring( L"CF_PALETTE" );
	standardFormats[ 10 ] = std::wstring( L"CF_PENDATA" );
	standardFormats[ 0x0200 ] = std::wstring( L"CF_PRIVATEFIRST" );
	standardFormats[ 0x02FF ] = std::wstring( L"CF_PRIVATELAST" );
	standardFormats[ 11 ] = std::wstring( L"CF_RIFF" );
	standardFormats[ 4 ] = std::wstring( L"CF_SYLK" );
	standardFormats[ 1 ] = std::wstring( L"CF_TEXT" );
	standardFormats[ 6 ] = std::wstring( L"CF_TIFF" );
	standardFormats[ 13 ] = std::wstring( L"CF_UNICODETEXT" );
	standardFormats[ 12 ] = std::wstring( L"CF_WAVE" );
}

// A quick and dirty method to convert UTF16 to UTF8 - http://stackoverflow.com/questions/215963/how-do-you-properly-use-widechartomultibyte
// Convert a wide Unicode string to an UTF8 string
std::string utf8_encode(const std::wstring &wstr)
{
    if( wstr.empty() ) return std::string();
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string strTo( size_needed, 0 );
    WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
    return strTo;
}

// Convert an UTF8 string to a wide Unicode String
std::wstring utf8_decode(const std::string &str)
{
    if( str.empty() ) return std::wstring();
    int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], (int)str.size(), NULL, 0);
    std::wstring wstrTo( size_needed, 0 );
    MultiByteToWideChar                  (CP_UTF8, 0, &str[0], (int)str.size(), &wstrTo[0], size_needed);
    return wstrTo;
}

void GetUser(const FunctionCallbackInfo<Value> &args)
{
	const unsigned int BUFFER_SIZE = 255;
	DWORD userNameLength = BUFFER_SIZE - 1;
	BOOL res = false;
	wchar_t userName[ BUFFER_SIZE ];
	memset( userName, 0, sizeof( WCHAR ) * userNameLength );

	res = GetUserNameW( userName, &userNameLength );

    Isolate *isolate = args.GetIsolate();

	if ( res ) {
		args.GetReturnValue().Set(String::NewFromUtf8(isolate, utf8_encode( userName ).c_str()));
	} else {
		args.GetReturnValue().Set(Boolean::New(isolate, false));
	}
}

void ClearClipboard( const FunctionCallbackInfo<Value> &args ) {
	BOOL ret = true;

	if ( !OpenClipboard( NULL ) ) {
		ret = false;
	}

	EmptyClipboard();
	CloseClipboard();

	Isolate *isolate = args.GetIsolate();
	args.GetReturnValue().Set(Boolean::New(isolate, ret));
}

void GetClipboardFormats( const FunctionCallbackInfo<Value> &args ) {
	Isolate *isolate = args.GetIsolate();
	Local<Array> arr = Array::New( isolate );

	int formatsCount = CountClipboardFormats();
	BOOL clipboardReady = false;
	const int BUFFER_LENGTH = 255;

	std::vector<UINT> types( formatsCount );

	if ( !formatsCount ) {
		// Early return, there's no need to open clipboard and do all this jazz.
		return;
	}

	clipboardReady = OpenClipboard( NULL );

	if ( !clipboardReady ) {
		return;
	}

	for ( int i = 0; i < formatsCount; i++ ) {
		// For first iteration 0 needs to be passed, for any subsequent call a previous
		// id should be provided.
		types[ i ] = EnumClipboardFormats( i == 0 ? 0 : types[ i-1 ] );

		std::wstring out;

		// Check for predefined formats.
		if ( standardFormats.count( types[ i ] ) ) {
			out = standardFormats[ types[ i ] ];
		} else {
			// Else pick it up from WINAPI.
			TCHAR curName[ BUFFER_LENGTH ];
			memset( curName, 0, sizeof( TCHAR ) * BUFFER_LENGTH );

			GetClipboardFormatName( types[ i ], curName, BUFFER_LENGTH - 1 );

			out = std::wstring( curName );
		}

		#ifdef UNICODE
			arr->Set( i, String::NewFromUtf8(isolate, utf8_encode( out ).c_str()) );
		#else
			arr->Set( i, String::NewFromOneByte( isolate, curName ) );
		#endif
	}

	args.GetReturnValue().Set( arr );

	CloseClipboard();
}

void GetData( const FunctionCallbackInfo<Value> &args ) {
	Isolate *isolate = args.GetIsolate();
	Local<v8::Object> ret;

	if ( args.Length() < 1 ) {
	    isolate->ThrowException(Exception::TypeError(
			String::NewFromUtf8(isolate, "Missing argument 1")));
	    return;
	}

	if ( !args[0]->IsString() ) {
	    isolate->ThrowException(Exception::TypeError(
			String::NewFromUtf8(isolate, "Argument 1 must be a string")));
	    return;
	}

	OpenClipboard( NULL );

	v8::String::Utf8Value formatRawName( args[ 0 ] );
	std::wstring formatNameUtf16 = utf8_decode( *formatRawName );

	UINT formatId = 0;

	for (auto& item: standardFormats) {
		if ( item.second.compare( formatNameUtf16 ) == 0 ) {
			formatId = item.first;
		}
	}

	if ( formatId == 0 ) {
		int formatsCount = CountClipboardFormats();
		UINT lastClipboardFormat = 0;
		const UINT BUFFER_LENGTH = 256;
		std::vector<TCHAR> buffer( BUFFER_LENGTH, TEXT('\0') );

		for ( int i = 0; i < formatsCount && formatId == 0; i++ ) {
			// For first iteration 0 needs to be passed, for any subsequent call a previous
			// id should be provided.
			lastClipboardFormat = EnumClipboardFormats( lastClipboardFormat );

			// Check only for custom types, as predefined were already tested.
			if ( standardFormats.count( lastClipboardFormat ) == 0 ) {
				GetClipboardFormatName( lastClipboardFormat, &buffer[ 0 ], BUFFER_LENGTH );

				// Compare...
				if ( formatNameUtf16.compare( &buffer[ 0 ] ) == 0 ) {
					// Matched!
					formatId = lastClipboardFormat;
				}

				// Zero used buffer.
				memset( &buffer[ 0 ], TEXT('\0'), sizeof( TCHAR ) * BUFFER_LENGTH );
			}
		}
	}

	if ( formatId != 0 ) {
		HGLOBAL clipboardDataHandle = GetClipboardData( formatId );

		if ( clipboardDataHandle != NULL ) {
			LPVOID data = GlobalLock( clipboardDataHandle );

			if ( data != NULL ) {
				SIZE_T clipboardBytes = GlobalSize( clipboardDataHandle );

				// It copies data, so no worry about WINAPI cleaning it up on it's own.
				ret = Nan::CopyBuffer( (const char*)data, clipboardBytes ).ToLocalChecked();

				GlobalUnlock( clipboardDataHandle );
			} else {
				formatId = 0;
			}
		} else {
			formatId = 0;
		}
	}

	CloseClipboard();

	Local<Number> tmpRet = Number::New( isolate, formatId );

	if ( formatId != 0 ) {
		// args.GetReturnValue().Set( tmpRet );
		args.GetReturnValue().Set( ret );
	} else {
		// Format not found.
		args.GetReturnValue().Set( Nan::Null() );
	}
}

void init(Local<Object> exports)
{
	initFormats();

    NODE_SET_METHOD(exports, "getUser", GetUser);
	NODE_SET_METHOD(exports, "clear", ClearClipboard);
	NODE_SET_METHOD(exports, "getFormats", GetClipboardFormats);
	NODE_SET_METHOD(exports, "getData", GetData);
}

NODE_MODULE(addon, init)

} // namespace demo<|endoftext|>


<commit_before>/*
 * Copyright 2001,2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Id$
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/validators/datatype/ListDatatypeValidator.hpp>
#include <xercesc/validators/datatype/InvalidDatatypeFacetException.hpp>
#include <xercesc/validators/datatype/InvalidDatatypeValueException.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>

XERCES_CPP_NAMESPACE_BEGIN

static const int BUF_LEN = 64;

// ---------------------------------------------------------------------------
//  Constructors and Destructor
// ---------------------------------------------------------------------------
ListDatatypeValidator::ListDatatypeValidator(MemoryManager* const manager)
:AbstractStringValidator(0, 0, 0, DatatypeValidator::List, manager)
,fContent(0)
{}

ListDatatypeValidator::ListDatatypeValidator(
                          DatatypeValidator*            const baseValidator
                        , RefHashTableOf<KVStringPair>* const facets
                        , RefArrayVectorOf<XMLCh>*           const enums
                        , const int                           finalSet
                        , MemoryManager* const manager)
:AbstractStringValidator(baseValidator, facets, finalSet, DatatypeValidator::List, manager)
,fContent(0)
{
    //
    // baseValidator shall either
    // an atomic DTV which servers as itemType, or
    // another ListDTV from which, this ListDTV is derived by restriction.
    //
    // In either case, it shall be not null
    //
    if (!baseValidator)
        ThrowXMLwithMemMgr(InvalidDatatypeFacetException, XMLExcepts::FACET_List_Null_baseValidator, manager);

    init(enums, manager);
}

ListDatatypeValidator::~ListDatatypeValidator()
{}

DatatypeValidator* ListDatatypeValidator::newInstance
(
      RefHashTableOf<KVStringPair>* const facets
    , RefArrayVectorOf<XMLCh>* const      enums
    , const int                           finalSet
    , MemoryManager* const                manager
)
{
    return (DatatypeValidator*) new (manager) ListDatatypeValidator(this, facets, enums, finalSet, manager);
}

int ListDatatypeValidator::compare(const XMLCh*     const lValue
                                 , const XMLCh*     const rValue
                                 , MemoryManager*   const manager)
{
    DatatypeValidator* theItemTypeDTV = getItemTypeDTV();
    BaseRefVectorOf<XMLCh>* lVector = XMLString::tokenizeString(lValue, manager);
    Janitor<BaseRefVectorOf<XMLCh> > janl(lVector);
    BaseRefVectorOf<XMLCh>* rVector = XMLString::tokenizeString(rValue, manager);
    Janitor<BaseRefVectorOf<XMLCh> > janr(rVector);

    int lNumberOfTokens = lVector->size();
    int rNumberOfTokens = rVector->size();

    if (lNumberOfTokens < rNumberOfTokens)
        return -1;
    else if (lNumberOfTokens > rNumberOfTokens)
        return 1;
    else
    { //compare each token
        for ( int i = 0; i < lNumberOfTokens; i++)
        {
            int returnValue = theItemTypeDTV->compare(lVector->elementAt(i), rVector->elementAt(i), manager);
            if (returnValue != 0)
                return returnValue; //REVISIT: does it make sense to return -1 or +1..?
        }
        return 0;
    }

}

void ListDatatypeValidator::validate( const XMLCh*             const content
                                    ,       ValidationContext* const context
                                    ,       MemoryManager*     const manager)
{
    setContent(content);
    BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(content, manager);
    Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector);
    checkContent(tokenVector, content, context, false, manager);
}

void ListDatatypeValidator::checkContent( const XMLCh*             const content
                                         ,      ValidationContext* const context
                                         ,      bool                     asBase
                                         ,      MemoryManager*     const manager)
{
    setContent(content);
    BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(content, manager);
    Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector);
    checkContent(tokenVector, content, context, asBase, manager);
}

//
// here content is a list of items
//
void ListDatatypeValidator::checkContent(       BaseRefVectorOf<XMLCh>*       tokenVector
                                        , const XMLCh*                  const content
                                        ,       ValidationContext*      const context
                                        ,       bool                          asBase
                                        ,       MemoryManager*          const manager)
{
    DatatypeValidator* bv = getBaseValidator();

    if (bv->getType() == DatatypeValidator::List)
        ((ListDatatypeValidator*)bv)->checkContent(tokenVector, content, context, true, manager);
    else
    {   // the ultimate itemType DTV
        for (unsigned int i = 0; i < tokenVector->size(); i++)
            bv->validate(tokenVector->elementAt(i), context, manager);
    }

    int thisFacetsDefined = getFacetsDefined();

    // we check pattern first
    if ( (thisFacetsDefined & DatatypeValidator::FACET_PATTERN ) != 0 )
    {
        // lazy construction
        if (getRegex() == 0)
        {
            try {
                setRegex(new (fMemoryManager) RegularExpression(getPattern(), SchemaSymbols::fgRegEx_XOption, fMemoryManager));
            }
            catch (XMLException &e)
            {
                ThrowXMLwithMemMgr1(InvalidDatatypeValueException, XMLExcepts::RethrowError, e.getMessage(), manager);
            }
        }

        //check every item in the list as a whole
        if (getRegex()->matches(content, manager) == false)
        {
            ThrowXMLwithMemMgr2(InvalidDatatypeValueException
                    , XMLExcepts::VALUE_NotMatch_Pattern
                    , content
                    , getPattern()
                    , manager);
        }

    }

    // if this is a base validator, we only need to check pattern facet
    // all other facet were inherited by the derived type
    if (asBase)
        return;

    unsigned int tokenNumber = tokenVector->size();

    if (((thisFacetsDefined & DatatypeValidator::FACET_MAXLENGTH) != 0) &&
        (tokenNumber > getMaxLength()))
    {
        XMLCh value1[BUF_LEN+1];
        XMLCh value2[BUF_LEN+1];
        XMLString::binToText(tokenNumber, value1, BUF_LEN, 10, manager);
        XMLString::binToText(getMaxLength(), value2, BUF_LEN, 10, manager);

        ThrowXMLwithMemMgr3(InvalidDatatypeValueException
                , XMLExcepts::VALUE_GT_maxLen
                , getContent()
                , value1
                , value2
                , manager);
    }

    if (((thisFacetsDefined & DatatypeValidator::FACET_MINLENGTH) != 0) &&
        (tokenNumber < getMinLength()))
    {
        XMLCh value1[BUF_LEN+1];
        XMLCh value2[BUF_LEN+1];
        XMLString::binToText(tokenNumber, value1, BUF_LEN, 10, manager);
        XMLString::binToText(getMinLength(), value2, BUF_LEN, 10, manager);

        ThrowXMLwithMemMgr3(InvalidDatatypeValueException
                , XMLExcepts::VALUE_LT_minLen
                , getContent()
                , value1
                , value2
                , manager);
    }

    if (((thisFacetsDefined & DatatypeValidator::FACET_LENGTH) != 0) &&
        (tokenNumber != AbstractStringValidator::getLength()))
    {
        XMLCh value1[BUF_LEN+1];
        XMLCh value2[BUF_LEN+1];
        XMLString::binToText(tokenNumber, value1, BUF_LEN, 10, manager);
        XMLString::binToText(AbstractStringValidator::getLength(), value2, BUF_LEN, 10, manager);

        ThrowXMLwithMemMgr3(InvalidDatatypeValueException
                , XMLExcepts::VALUE_NE_Len
                , getContent()
                , value1
                , value2
                , manager);
    }

    if ((thisFacetsDefined & DatatypeValidator::FACET_ENUMERATION) != 0 &&
        (getEnumeration() != 0))
    {
        int i;
        int enumLength = getEnumeration()->size();

        for ( i = 0; i < enumLength; i++)
        {
            //optimization: we do a lexical comparision first
            // this may be faster for string and its derived
            if (XMLString::equals(getEnumeration()->elementAt(i), getContent()))
                break; // a match found

            // do a value space check
            // this is needed for decimal (and probably other types
            // such as datetime related)
            // eg.
            // tokenVector = "1 2 3.0 4" vs enumeration = "1 2 3 4.0"
            //
            if (valueSpaceCheck(tokenVector, getEnumeration()->elementAt(i), manager))
                break;
        }

        if (i == enumLength)
            ThrowXMLwithMemMgr1(InvalidDatatypeValueException, XMLExcepts::VALUE_NotIn_Enumeration, getContent(), manager);

    } // enumeration

}

bool ListDatatypeValidator::valueSpaceCheck(BaseRefVectorOf<XMLCh>* tokenVector
                                          , const XMLCh*    const  enumStr
                                          , MemoryManager*  const  manager) const
{
    DatatypeValidator* theItemTypeDTV = getItemTypeDTV();
    BaseRefVectorOf<XMLCh>* enumVector = XMLString::tokenizeString(enumStr, manager);
    Janitor<BaseRefVectorOf<XMLCh> > janName(enumVector);

    if (tokenVector->size() != enumVector->size())
        return false;

    for ( unsigned int j = 0; j < tokenVector->size(); j++ )
    {
        if (theItemTypeDTV->compare(tokenVector->elementAt(j), enumVector->elementAt(j), manager) != 0)
            return false;
    }

    return true;
}

DatatypeValidator* ListDatatypeValidator::getItemTypeDTV() const
{
    DatatypeValidator* bdv = this->getBaseValidator();

    while (bdv->getType() == DatatypeValidator::List)
        bdv = bdv->getBaseValidator();

    return bdv;
}

// ---------------------------------------------------------------------------
//  Utilities
// ---------------------------------------------------------------------------

void ListDatatypeValidator::checkValueSpace(const XMLCh* const
                                            , MemoryManager* const)
{}

int ListDatatypeValidator::getLength(const XMLCh* const content
                                     , MemoryManager* const manager) const
{
    BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(content, manager);
    Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector);

    return tokenVector->size();
}

void ListDatatypeValidator::inspectFacetBase(MemoryManager* const manager)
{

    //
    // we are pretty sure baseValidator is not null
    //

    if (getBaseValidator()->getType() == DatatypeValidator::List)
    {
        AbstractStringValidator::inspectFacetBase(manager);
    }
    else
    {
        // the first level ListDTV
        // check 4.3.5.c0 must: enumeration values from the value space of base
        if ( ((getFacetsDefined() & DatatypeValidator::FACET_ENUMERATION) != 0) &&
             (getEnumeration() !=0)                                              )
        {
            int i;
            int enumLength = getEnumeration()->size();
            try
            {
                for ( i = 0; i < enumLength; i++)
                {
                    // ask the itemType for a complete check
                    BaseRefVectorOf<XMLCh>* tempList = XMLString::tokenizeString(getEnumeration()->elementAt(i), manager);
                    Janitor<BaseRefVectorOf<XMLCh> >    jan(tempList);
                    int tokenNumber = tempList->size();

                    try
                    {
                        for ( int j = 0; j < tokenNumber; j++)
                            getBaseValidator()->validate(tempList->elementAt(j), (ValidationContext*)0, manager);
                    }
                    catch(const OutOfMemoryException&)
                    {
                        jan.release();

                        throw;
                    }

                    // enum shall pass this->checkContent() as well.
                    checkContent(getEnumeration()->elementAt(i), (ValidationContext*)0, false, manager);
                }
            }

            catch ( XMLException& )
            {
                ThrowXMLwithMemMgr1(InvalidDatatypeFacetException
                        , XMLExcepts::FACET_enum_base
                        , getEnumeration()->elementAt(i)
                        , manager);
            }

        }

    }

}// End of inspectFacetBase()

void ListDatatypeValidator::inheritFacet()
{

    //iff the base validator is List, then we inherit
    //
    if (getBaseValidator()->getType() == DatatypeValidator::List)
    {
        AbstractStringValidator::inheritFacet();
    }

}

/***
 * 2.5.1.2 List datatypes
 *
 * The canonical-lexical-representation for the �list� datatype is defined as
 * the lexical form in which each item in the �list� has the canonical
 * lexical representation of its �itemType�.
 ***/
const XMLCh* ListDatatypeValidator::getCanonicalRepresentation(const XMLCh*         const rawData
                                                             ,       MemoryManager* const memMgr
                                                             ,       bool                 toValidate) const
{
    MemoryManager* toUse = memMgr? memMgr : getMemoryManager();
    ListDatatypeValidator* temp = (ListDatatypeValidator*) this;
    temp->setContent(rawData);
    BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(rawData, toUse);
    Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector);

    if (toValidate)
    {
        try
        {
            temp->checkContent(tokenVector, rawData, 0, false, toUse);
        }
        catch (...)
        {
            return 0;
        }
    }

    unsigned int  retBufSize = 2 * XMLString::stringLen(rawData);
    XMLCh* retBuf = (XMLCh*) toUse->allocate(retBufSize * sizeof(XMLCh));
    retBuf[0] = 0;
    XMLCh* retBufPtr = retBuf;
    DatatypeValidator* itemDv = this->getItemTypeDTV();

    try
    {
        for (unsigned int i = 0; i < tokenVector->size(); i++)
        {
            XMLCh* itemCanRep = (XMLCh*) itemDv->getCanonicalRepresentation(tokenVector->elementAt(i), toUse, false);
            unsigned int itemLen = XMLString::stringLen(itemCanRep);

            if(retBufPtr+itemLen+2 >= retBuf+retBufSize)
            {
                // need to resize
                XMLCh * oldBuf = retBuf;
                retBuf = (XMLCh*) toUse->allocate(retBufSize * sizeof(XMLCh) * 4);
                memcpy(retBuf, oldBuf, retBufSize * sizeof(XMLCh ));
                retBufPtr = (retBufPtr - oldBuf) + retBuf;
                toUse->deallocate(oldBuf);
                retBufSize <<= 2;
            }

            XMLString::catString(retBufPtr, itemCanRep);
            retBufPtr = retBufPtr + itemLen + 1;
            *(retBufPtr++) = chSpace;
            *(retBufPtr) = chNull;
            toUse->deallocate(itemCanRep);
        }

        return retBuf;

    }
    catch (...)
    {
        return 0;
    }
}

/***
 * Support for Serialization/De-serialization
 ***/

IMPL_XSERIALIZABLE_TOCREATE(ListDatatypeValidator)

void ListDatatypeValidator::serialize(XSerializeEngine& serEng)
{
    AbstractStringValidator::serialize(serEng);

    //don't serialize fContent, since it is NOT owned and
    //will be reset each time validate()/checkContent() invoked.
}

XERCES_CPP_NAMESPACE_END

/**
  * End of file ListDatatypeValidator.cpp
  */
<commit_msg>Fix for jira bug 1546.  Canonical value of list was putting in an extra null character.<commit_after>/*
 * Copyright 2001,2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Id$
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <xercesc/validators/datatype/ListDatatypeValidator.hpp>
#include <xercesc/validators/datatype/InvalidDatatypeFacetException.hpp>
#include <xercesc/validators/datatype/InvalidDatatypeValueException.hpp>
#include <xercesc/util/OutOfMemoryException.hpp>

XERCES_CPP_NAMESPACE_BEGIN

static const int BUF_LEN = 64;

// ---------------------------------------------------------------------------
//  Constructors and Destructor
// ---------------------------------------------------------------------------
ListDatatypeValidator::ListDatatypeValidator(MemoryManager* const manager)
:AbstractStringValidator(0, 0, 0, DatatypeValidator::List, manager)
,fContent(0)
{}

ListDatatypeValidator::ListDatatypeValidator(
                          DatatypeValidator*            const baseValidator
                        , RefHashTableOf<KVStringPair>* const facets
                        , RefArrayVectorOf<XMLCh>*           const enums
                        , const int                           finalSet
                        , MemoryManager* const manager)
:AbstractStringValidator(baseValidator, facets, finalSet, DatatypeValidator::List, manager)
,fContent(0)
{
    //
    // baseValidator shall either
    // an atomic DTV which servers as itemType, or
    // another ListDTV from which, this ListDTV is derived by restriction.
    //
    // In either case, it shall be not null
    //
    if (!baseValidator)
        ThrowXMLwithMemMgr(InvalidDatatypeFacetException, XMLExcepts::FACET_List_Null_baseValidator, manager);

    init(enums, manager);
}

ListDatatypeValidator::~ListDatatypeValidator()
{}

DatatypeValidator* ListDatatypeValidator::newInstance
(
      RefHashTableOf<KVStringPair>* const facets
    , RefArrayVectorOf<XMLCh>* const      enums
    , const int                           finalSet
    , MemoryManager* const                manager
)
{
    return (DatatypeValidator*) new (manager) ListDatatypeValidator(this, facets, enums, finalSet, manager);
}

int ListDatatypeValidator::compare(const XMLCh*     const lValue
                                 , const XMLCh*     const rValue
                                 , MemoryManager*   const manager)
{
    DatatypeValidator* theItemTypeDTV = getItemTypeDTV();
    BaseRefVectorOf<XMLCh>* lVector = XMLString::tokenizeString(lValue, manager);
    Janitor<BaseRefVectorOf<XMLCh> > janl(lVector);
    BaseRefVectorOf<XMLCh>* rVector = XMLString::tokenizeString(rValue, manager);
    Janitor<BaseRefVectorOf<XMLCh> > janr(rVector);

    int lNumberOfTokens = lVector->size();
    int rNumberOfTokens = rVector->size();

    if (lNumberOfTokens < rNumberOfTokens)
        return -1;
    else if (lNumberOfTokens > rNumberOfTokens)
        return 1;
    else
    { //compare each token
        for ( int i = 0; i < lNumberOfTokens; i++)
        {
            int returnValue = theItemTypeDTV->compare(lVector->elementAt(i), rVector->elementAt(i), manager);
            if (returnValue != 0)
                return returnValue; //REVISIT: does it make sense to return -1 or +1..?
        }
        return 0;
    }

}

void ListDatatypeValidator::validate( const XMLCh*             const content
                                    ,       ValidationContext* const context
                                    ,       MemoryManager*     const manager)
{
    setContent(content);
    BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(content, manager);
    Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector);
    checkContent(tokenVector, content, context, false, manager);
}

void ListDatatypeValidator::checkContent( const XMLCh*             const content
                                         ,      ValidationContext* const context
                                         ,      bool                     asBase
                                         ,      MemoryManager*     const manager)
{
    setContent(content);
    BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(content, manager);
    Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector);
    checkContent(tokenVector, content, context, asBase, manager);
}

//
// here content is a list of items
//
void ListDatatypeValidator::checkContent(       BaseRefVectorOf<XMLCh>*       tokenVector
                                        , const XMLCh*                  const content
                                        ,       ValidationContext*      const context
                                        ,       bool                          asBase
                                        ,       MemoryManager*          const manager)
{
    DatatypeValidator* bv = getBaseValidator();

    if (bv->getType() == DatatypeValidator::List)
        ((ListDatatypeValidator*)bv)->checkContent(tokenVector, content, context, true, manager);
    else
    {   // the ultimate itemType DTV
        for (unsigned int i = 0; i < tokenVector->size(); i++)
            bv->validate(tokenVector->elementAt(i), context, manager);
    }

    int thisFacetsDefined = getFacetsDefined();

    // we check pattern first
    if ( (thisFacetsDefined & DatatypeValidator::FACET_PATTERN ) != 0 )
    {
        // lazy construction
        if (getRegex() == 0)
        {
            try {
                setRegex(new (fMemoryManager) RegularExpression(getPattern(), SchemaSymbols::fgRegEx_XOption, fMemoryManager));
            }
            catch (XMLException &e)
            {
                ThrowXMLwithMemMgr1(InvalidDatatypeValueException, XMLExcepts::RethrowError, e.getMessage(), manager);
            }
        }

        //check every item in the list as a whole
        if (getRegex()->matches(content, manager) == false)
        {
            ThrowXMLwithMemMgr2(InvalidDatatypeValueException
                    , XMLExcepts::VALUE_NotMatch_Pattern
                    , content
                    , getPattern()
                    , manager);
        }

    }

    // if this is a base validator, we only need to check pattern facet
    // all other facet were inherited by the derived type
    if (asBase)
        return;

    unsigned int tokenNumber = tokenVector->size();

    if (((thisFacetsDefined & DatatypeValidator::FACET_MAXLENGTH) != 0) &&
        (tokenNumber > getMaxLength()))
    {
        XMLCh value1[BUF_LEN+1];
        XMLCh value2[BUF_LEN+1];
        XMLString::binToText(tokenNumber, value1, BUF_LEN, 10, manager);
        XMLString::binToText(getMaxLength(), value2, BUF_LEN, 10, manager);

        ThrowXMLwithMemMgr3(InvalidDatatypeValueException
                , XMLExcepts::VALUE_GT_maxLen
                , getContent()
                , value1
                , value2
                , manager);
    }

    if (((thisFacetsDefined & DatatypeValidator::FACET_MINLENGTH) != 0) &&
        (tokenNumber < getMinLength()))
    {
        XMLCh value1[BUF_LEN+1];
        XMLCh value2[BUF_LEN+1];
        XMLString::binToText(tokenNumber, value1, BUF_LEN, 10, manager);
        XMLString::binToText(getMinLength(), value2, BUF_LEN, 10, manager);

        ThrowXMLwithMemMgr3(InvalidDatatypeValueException
                , XMLExcepts::VALUE_LT_minLen
                , getContent()
                , value1
                , value2
                , manager);
    }

    if (((thisFacetsDefined & DatatypeValidator::FACET_LENGTH) != 0) &&
        (tokenNumber != AbstractStringValidator::getLength()))
    {
        XMLCh value1[BUF_LEN+1];
        XMLCh value2[BUF_LEN+1];
        XMLString::binToText(tokenNumber, value1, BUF_LEN, 10, manager);
        XMLString::binToText(AbstractStringValidator::getLength(), value2, BUF_LEN, 10, manager);

        ThrowXMLwithMemMgr3(InvalidDatatypeValueException
                , XMLExcepts::VALUE_NE_Len
                , getContent()
                , value1
                , value2
                , manager);
    }

    if ((thisFacetsDefined & DatatypeValidator::FACET_ENUMERATION) != 0 &&
        (getEnumeration() != 0))
    {
        int i;
        int enumLength = getEnumeration()->size();

        for ( i = 0; i < enumLength; i++)
        {
            //optimization: we do a lexical comparision first
            // this may be faster for string and its derived
            if (XMLString::equals(getEnumeration()->elementAt(i), getContent()))
                break; // a match found

            // do a value space check
            // this is needed for decimal (and probably other types
            // such as datetime related)
            // eg.
            // tokenVector = "1 2 3.0 4" vs enumeration = "1 2 3 4.0"
            //
            if (valueSpaceCheck(tokenVector, getEnumeration()->elementAt(i), manager))
                break;
        }

        if (i == enumLength)
            ThrowXMLwithMemMgr1(InvalidDatatypeValueException, XMLExcepts::VALUE_NotIn_Enumeration, getContent(), manager);

    } // enumeration

}

bool ListDatatypeValidator::valueSpaceCheck(BaseRefVectorOf<XMLCh>* tokenVector
                                          , const XMLCh*    const  enumStr
                                          , MemoryManager*  const  manager) const
{
    DatatypeValidator* theItemTypeDTV = getItemTypeDTV();
    BaseRefVectorOf<XMLCh>* enumVector = XMLString::tokenizeString(enumStr, manager);
    Janitor<BaseRefVectorOf<XMLCh> > janName(enumVector);

    if (tokenVector->size() != enumVector->size())
        return false;

    for ( unsigned int j = 0; j < tokenVector->size(); j++ )
    {
        if (theItemTypeDTV->compare(tokenVector->elementAt(j), enumVector->elementAt(j), manager) != 0)
            return false;
    }

    return true;
}

DatatypeValidator* ListDatatypeValidator::getItemTypeDTV() const
{
    DatatypeValidator* bdv = this->getBaseValidator();

    while (bdv->getType() == DatatypeValidator::List)
        bdv = bdv->getBaseValidator();

    return bdv;
}

// ---------------------------------------------------------------------------
//  Utilities
// ---------------------------------------------------------------------------

void ListDatatypeValidator::checkValueSpace(const XMLCh* const
                                            , MemoryManager* const)
{}

int ListDatatypeValidator::getLength(const XMLCh* const content
                                     , MemoryManager* const manager) const
{
    BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(content, manager);
    Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector);

    return tokenVector->size();
}

void ListDatatypeValidator::inspectFacetBase(MemoryManager* const manager)
{

    //
    // we are pretty sure baseValidator is not null
    //

    if (getBaseValidator()->getType() == DatatypeValidator::List)
    {
        AbstractStringValidator::inspectFacetBase(manager);
    }
    else
    {
        // the first level ListDTV
        // check 4.3.5.c0 must: enumeration values from the value space of base
        if ( ((getFacetsDefined() & DatatypeValidator::FACET_ENUMERATION) != 0) &&
             (getEnumeration() !=0)                                              )
        {
            int i;
            int enumLength = getEnumeration()->size();
            try
            {
                for ( i = 0; i < enumLength; i++)
                {
                    // ask the itemType for a complete check
                    BaseRefVectorOf<XMLCh>* tempList = XMLString::tokenizeString(getEnumeration()->elementAt(i), manager);
                    Janitor<BaseRefVectorOf<XMLCh> >    jan(tempList);
                    int tokenNumber = tempList->size();

                    try
                    {
                        for ( int j = 0; j < tokenNumber; j++)
                            getBaseValidator()->validate(tempList->elementAt(j), (ValidationContext*)0, manager);
                    }
                    catch(const OutOfMemoryException&)
                    {
                        jan.release();

                        throw;
                    }

                    // enum shall pass this->checkContent() as well.
                    checkContent(getEnumeration()->elementAt(i), (ValidationContext*)0, false, manager);
                }
            }

            catch ( XMLException& )
            {
                ThrowXMLwithMemMgr1(InvalidDatatypeFacetException
                        , XMLExcepts::FACET_enum_base
                        , getEnumeration()->elementAt(i)
                        , manager);
            }

        }

    }

}// End of inspectFacetBase()

void ListDatatypeValidator::inheritFacet()
{

    //iff the base validator is List, then we inherit
    //
    if (getBaseValidator()->getType() == DatatypeValidator::List)
    {
        AbstractStringValidator::inheritFacet();
    }

}

/***
 * 2.5.1.2 List datatypes
 *
 * The canonical-lexical-representation for the �list� datatype is defined as
 * the lexical form in which each item in the �list� has the canonical
 * lexical representation of its �itemType�.
 ***/
const XMLCh* ListDatatypeValidator::getCanonicalRepresentation(const XMLCh*         const rawData
                                                             ,       MemoryManager* const memMgr
                                                             ,       bool                 toValidate) const
{
    MemoryManager* toUse = memMgr? memMgr : getMemoryManager();
    ListDatatypeValidator* temp = (ListDatatypeValidator*) this;
    temp->setContent(rawData);
    BaseRefVectorOf<XMLCh>* tokenVector = XMLString::tokenizeString(rawData, toUse);
    Janitor<BaseRefVectorOf<XMLCh> > janName(tokenVector);

    if (toValidate)
    {
        try
        {
            temp->checkContent(tokenVector, rawData, 0, false, toUse);
        }
        catch (...)
        {
            return 0;
        }
    }

    unsigned int  retBufSize = 2 * XMLString::stringLen(rawData);
    XMLCh* retBuf = (XMLCh*) toUse->allocate(retBufSize * sizeof(XMLCh));
    retBuf[0] = 0;
    XMLCh* retBufPtr = retBuf;
    DatatypeValidator* itemDv = this->getItemTypeDTV();

    try
    {
        for (unsigned int i = 0; i < tokenVector->size(); i++)
        {
            XMLCh* itemCanRep = (XMLCh*) itemDv->getCanonicalRepresentation(tokenVector->elementAt(i), toUse, false);
            unsigned int itemLen = XMLString::stringLen(itemCanRep);

            if(retBufPtr+itemLen+2 >= retBuf+retBufSize)
            {
                // need to resize
                XMLCh * oldBuf = retBuf;
                retBuf = (XMLCh*) toUse->allocate(retBufSize * sizeof(XMLCh) * 4);
                memcpy(retBuf, oldBuf, retBufSize * sizeof(XMLCh ));
                retBufPtr = (retBufPtr - oldBuf) + retBuf;
                toUse->deallocate(oldBuf);
                retBufSize <<= 2;
            }

            XMLString::catString(retBufPtr, itemCanRep);
            retBufPtr = retBufPtr + itemLen;
            *(retBufPtr++) = chSpace;
            *(retBufPtr) = chNull;
            toUse->deallocate(itemCanRep);
        }

        return retBuf;

    }
    catch (...)
    {
        return 0;
    }
}

/***
 * Support for Serialization/De-serialization
 ***/

IMPL_XSERIALIZABLE_TOCREATE(ListDatatypeValidator)

void ListDatatypeValidator::serialize(XSerializeEngine& serEng)
{
    AbstractStringValidator::serialize(serEng);

    //don't serialize fContent, since it is NOT owned and
    //will be reset each time validate()/checkContent() invoked.
}

XERCES_CPP_NAMESPACE_END

/**
  * End of file ListDatatypeValidator.cpp
  */
<|endoftext|>


<commit_before>/**
 * @file      joy_remote.cpp
 * @brief     Joystick remote control node
 * @author    Alejandro Bordallo <alex.bordallo@ed.ac.uk>
 * @date      2015-05-22
 * @copyright (MIT) 2015 Edinferno
 */

#include "motion/joy_remote.hpp"

JoyRemote::JoyRemote(ros::NodeHandle* nh) {
  nh_ = nh;
  joy_sub_ = nh_->subscribe("joy", 1000, &JoyRemote::joyCallback, this);
  moveTowardClient = nh_->serviceClient<motion_msgs::MoveToward>(
                       "/motion/move_toward", true);
  moveTowardClient.waitForExistence();
  wakeUpClient = nh_->serviceClient<std_srvs::Empty>(
                   "/motion/wake_up", true);
  wakeUpClient.waitForExistence();
  moveInitClient = nh_->serviceClient<std_srvs::Empty>(
                     "/motion/move_init", true);
  moveInitClient.waitForExistence();
  standClient = nh_->serviceClient<motion_msgs::SetPosture>(
                  "/motion/goto_posture", true);
  standClient.waitForExistence();
  restClient = nh_->serviceClient<std_srvs::Empty>(
                 "/motion/rest", true);
  restClient.waitForExistence();
  stopMoveClient = nh_->serviceClient<std_srvs::Empty>(
                     "/motion/stop_move", true);
  stopMoveClient.waitForExistence();
  changeAnglesClient = nh_->serviceClient<motion_msgs::ChangeAngles>(
                         "/motion/change_angles", true);
  changeAnglesClient.waitForExistence();
  ROS_INFO_STREAM("Joystick remote node initialised");
  wakeUpFlag = false;
  moveInitFlag = false;
  standFlag = false;
  restFlag = false;
  standSrv.request.speed = 0.5f;
  headSrv.request.names.push_back("HeadYaw");
  headSrv.request.names.push_back("HeadPitch");
  headSrv.request.changes.resize(2);
  headSrv.request.fraction_max_speed = 0.1f;
}

JoyRemote::~JoyRemote() {
}

void JoyRemote::joyCallback(const sensor_msgs::Joy::ConstPtr& msg) {
  if (msg->buttons[1]) {
    wakeUpFlag = true;
  } else if (msg->buttons[2]) {
    moveInitFlag = true;
  } else if (msg->buttons[3]) {
    standFlag = true;
  } else if (msg->buttons[0]) {
    restFlag = true;
  } else {
    float x = msg->axes[1];
    float y = msg->axes[0];
    float theta = msg->axes[3];
    moveSrv.request.norm_velocity.x = x;
    moveSrv.request.norm_velocity.y = y;
    moveSrv.request.norm_velocity.theta = theta;
    float headYawAngle = msg->axes[6];
    float headPitchAngle = msg->axes[7];
    headSrv.request.changes[0] = headYawAngle;
    headSrv.request.changes[1] = headPitchAngle * -1;
  }
}

void JoyRemote::sendCmd() {
  if (wakeUpFlag) {
    this->wakeUp();
  } else if (moveInitFlag) {
    this->moveInit();
  } else if (standFlag) {
    this->stand();
  } else if (restFlag) {
    this->rest();
  } else {
    moveTowardClient.call(moveSrv);
    changeAnglesClient.call(headSrv);
  }
}

void JoyRemote::wakeUp() {
  wakeUpClient.call(wakeUpSrv);
  wakeUpFlag = false;
}

void JoyRemote::moveInit() {
  moveInitClient.call(moveInitSrv);
  moveInitFlag = false;
}

void JoyRemote::stand() {
  wakeUpClient.call(wakeUpSrv);
  standSrv.request.posture_name = "Stand";
  standClient.call(standSrv);
  standFlag = false;
}

void JoyRemote::rest() {
  stopMoveClient.call(stopSrv);
  sleep(0.25);
  moveInitClient.call(moveInitSrv);
  sleep(0.25);
  restClient.call(restSrv);
  restFlag = false;
}

int main(int argc, char* argv[]) {
  ros::init(argc, argv, "JoyRemote");
  ros::NodeHandle nh;

  JoyRemote joyTest(&nh);

  ros::Rate r(10);

  while (ros::ok()) {
    joyTest.sendCmd();
    ros::spinOnce();
    r.sleep();
  }

  ros::shutdown();

  return 0;
}

<commit_msg>Fix service guards on JoyRemote code<commit_after>/**
 * @file      joy_remote.cpp
 * @brief     Joystick remote control node
 * @author    Alejandro Bordallo <alex.bordallo@ed.ac.uk>
 * @date      2015-05-22
 * @copyright (MIT) 2015 Edinferno
 */

#include "motion/joy_remote.hpp"

JoyRemote::JoyRemote(ros::NodeHandle* nh) {
  nh_ = nh;
  joy_sub_ = nh_->subscribe("joy", 1000, &JoyRemote::joyCallback, this);
  ros::service::waitForService("motion/move_toward");
  moveTowardClient = nh_->serviceClient<motion_msgs::MoveToward>(
                       "/motion/move_toward", true);
  ros::service::waitForService("/motion/wake_up");
  wakeUpClient = nh_->serviceClient<std_srvs::Empty>(
                   "/motion/wake_up", true);
  ros::service::waitForService("/motion/move_init");
  moveInitClient = nh_->serviceClient<std_srvs::Empty>(
                     "/motion/move_init", true);
  ros::service::waitForService("/motion/goto_posture");
  standClient = nh_->serviceClient<motion_msgs::SetPosture>(
                  "/motion/goto_posture", true);
  ros::service::waitForService("/motion/rest");
  restClient = nh_->serviceClient<std_srvs::Empty>(
                 "/motion/rest", true);
  ros::service::waitForService("/motion/stop_move");
  stopMoveClient = nh_->serviceClient<std_srvs::Empty>(
                     "/motion/stop_move", true);
  ros::service::waitForService("/motion/change_angles");
  changeAnglesClient = nh_->serviceClient<motion_msgs::ChangeAngles>(
                         "/motion/change_angles", true);
  ROS_INFO_STREAM("Joystick remote node initialised");
  wakeUpFlag = false;
  moveInitFlag = false;
  standFlag = false;
  restFlag = false;
  standSrv.request.speed = 0.5f;
  headSrv.request.names.push_back("HeadYaw");
  headSrv.request.names.push_back("HeadPitch");
  headSrv.request.changes.resize(2);
  headSrv.request.fraction_max_speed = 0.1f;
}

JoyRemote::~JoyRemote() {
}

void JoyRemote::joyCallback(const sensor_msgs::Joy::ConstPtr& msg) {
  if (msg->buttons[1]) {
    wakeUpFlag = true;
  } else if (msg->buttons[2]) {
    moveInitFlag = true;
  } else if (msg->buttons[3]) {
    standFlag = true;
  } else if (msg->buttons[0]) {
    restFlag = true;
  } else {
    float x = msg->axes[1];
    float y = msg->axes[0];
    float theta = msg->axes[3];
    moveSrv.request.norm_velocity.x = x;
    moveSrv.request.norm_velocity.y = y;
    moveSrv.request.norm_velocity.theta = theta;
    float headYawAngle = msg->axes[6];
    float headPitchAngle = msg->axes[7];
    headSrv.request.changes[0] = headYawAngle;
    headSrv.request.changes[1] = headPitchAngle * -1;
  }
}

void JoyRemote::sendCmd() {
  if (wakeUpFlag) {
    this->wakeUp();
  } else if (moveInitFlag) {
    this->moveInit();
  } else if (standFlag) {
    this->stand();
  } else if (restFlag) {
    this->rest();
  } else {
    moveTowardClient.call(moveSrv);
    changeAnglesClient.call(headSrv);
  }
}

void JoyRemote::wakeUp() {
  wakeUpClient.call(wakeUpSrv);
  wakeUpFlag = false;
}

void JoyRemote::moveInit() {
  moveInitClient.call(moveInitSrv);
  moveInitFlag = false;
}

void JoyRemote::stand() {
  wakeUpClient.call(wakeUpSrv);
  standSrv.request.posture_name = "Stand";
  standClient.call(standSrv);
  standFlag = false;
}

void JoyRemote::rest() {
  stopMoveClient.call(stopSrv);
  sleep(0.25);
  moveInitClient.call(moveInitSrv);
  sleep(0.25);
  restClient.call(restSrv);
  restFlag = false;
}

int main(int argc, char* argv[]) {
  ros::init(argc, argv, "JoyRemote");
  ros::NodeHandle nh;

  JoyRemote joyTest(&nh);

  ros::Rate r(10);

  while (ros::ok()) {
    joyTest.sendCmd();
    ros::spinOnce();
    r.sleep();
  }

  ros::shutdown();

  return 0;
}

<|endoftext|>


<commit_before>#include "kk_generator.h"

#include "kk_answer.h"
#include "kk_field.h"

#include <vector>

namespace
{
int UndecidedCells(const penciloid::kakuro::Field &field)
{
	using namespace penciloid;
	int ret = 0;
	for (Y y(0); y < field.height(); ++y) {
		for (X x(0); x < field.width(); ++x) {
			if (field.GetCell(CellPosition(y, x)) == kakuro::Field::kCellUndecided) {
				++ret;
			}
		}
	}
	return ret;
}
double ComputeEnergy(const penciloid::kakuro::Field &field)
{
	using namespace penciloid;
	double ret = 0.0;
	for (Y y(0); y < field.height(); ++y) {
		for (X x(0); x < field.width(); ++x) {
			if (field.GetCell(CellPosition(y, x)) != kakuro::Field::kCellClue && field.GetCell(CellPosition(y, x)) != kakuro::Field::kCellUndecided) {
				ret += 1.0;
			}
		}
	}
	return -ret;
}
}
namespace penciloid
{
namespace kakuro
{
bool GenerateByLocalSearch(Problem &frame, Dictionary *dic, std::mt19937 *rnd, Problem *ret)
{
	Y height = frame.height();
	X width = frame.width();
	Answer current_answer(height, width); double current_energy = 0.0;
	int max_step = static_cast<int>(height) * static_cast<int>(width) * 10;
	int step = 0;
	double temperature = 10.0;
	std::uniform_real_distribution<double> real_dist(0.0, 1.0);

	// TODO: initial answer
	for (Y y(0); y < height; ++y) {
		for (X x(0); x < width; ++x) {
			if (frame.GetClue(CellPosition(y, x)) == kEmptyCell) {
				current_answer.SetValue(CellPosition(y, x), 1 + (static_cast<int>(y) + static_cast<int>(x)) % 9);
			} else {
				current_answer.SetValue(CellPosition(y, x), Answer::kClueCell);
			}
		}
	}
	for (; step < max_step; ++step) {
		std::vector<std::pair<CellPosition, int> > candidate;
		for (Y y(0); y < height; ++y) {
			for (X x(0); x < width; ++x) {
				CellPosition pos(y, x);
				int current_val = current_answer.GetValue(pos);
				if (current_val == Answer::kClueCell) continue;

				for (int n = 1; n <= 9; ++n) if (n != current_val) {
					bool isok = true;
					for (Direction d : k4Neighborhood) {
						for (CellPosition pos2 = pos + d; 0 <= pos2.y && pos2.y < height && 0 <= pos2.x && pos2.x < width; pos2 = pos2 + d) {
							if (current_answer.GetValue(pos2) == n) {
								isok = false;
								break;
							} else if (current_answer.GetValue(pos2) == Answer::kClueCell) {
								break;
							}
						}
					}
					if (isok) {
						candidate.push_back({ pos, n });
					}
				}
			}
		}
		shuffle(candidate.begin(), candidate.end(), *rnd);

		for (auto c : candidate) {
			CellPosition pos = c.first; int val = c.second;
			int previous_val = current_answer.GetValue(pos);
			current_answer.SetValue(pos, val);

			Problem problem = current_answer.ExtractProblem();
			Field field(problem, dic);
			field.CheckGroupAll();
			bool transition = false;

			if (!field.IsInconsistent()) {
				if (UndecidedCells(field) == 0) {
					*ret = problem;
					return true;
				}
				double next_energy = ComputeEnergy(field);
				if (current_energy > next_energy) transition = true;
				else {
					double threshold = exp((current_energy - next_energy) / temperature);
					if (real_dist(*rnd) < threshold) transition = true;
				}

				if (transition) current_energy = next_energy;
			}

			if (transition) {
				break;
			} else {
				current_answer.SetValue(pos, previous_val);
			}
		}
		temperature *= 0.995;
	}

	return false;
}
}
}<commit_msg>Kakuro: use the total number of possible candidates as a measure of goodness of an answer in GenerateByLocalSearch<commit_after>#include "kk_generator.h"

#include "kk_answer.h"
#include "kk_field.h"

#include <vector>

namespace
{
int UndecidedCells(const penciloid::kakuro::Field &field)
{
	using namespace penciloid;
	int ret = 0;
	for (Y y(0); y < field.height(); ++y) {
		for (X x(0); x < field.width(); ++x) {
			if (field.GetCell(CellPosition(y, x)) == kakuro::Field::kCellUndecided) {
				++ret;
			}
		}
	}
	return ret;
}
double ComputeEnergy(const penciloid::kakuro::Field &field)
{
	using namespace penciloid;
	double ret = 0.0;
	for (Y y(0); y < field.height(); ++y) {
		for (X x(0); x < field.width(); ++x) {
			if (field.GetCell(CellPosition(y, x)) != kakuro::Field::kCellClue) {
			//	ret += 1.0;
				ret += __popcnt(field.GetCandidateBits(CellPosition(y, x)));
			}
		}
	}
	return ret;
}
}
namespace penciloid
{
namespace kakuro
{
bool GenerateByLocalSearch(Problem &frame, Dictionary *dic, std::mt19937 *rnd, Problem *ret)
{
	Y height = frame.height();
	X width = frame.width();
	Answer current_answer(height, width); double current_energy = 0.0;
	int max_step = static_cast<int>(height) * static_cast<int>(width) * 10;
	int step = 0;
	double temperature = 10.0;
	std::uniform_real_distribution<double> real_dist(0.0, 1.0);

	// TODO: initial answer
	for (Y y(0); y < height; ++y) {
		for (X x(0); x < width; ++x) {
			if (frame.GetClue(CellPosition(y, x)) == kEmptyCell) {
				current_answer.SetValue(CellPosition(y, x), 1 + (static_cast<int>(y) + static_cast<int>(x)) % 9);
			} else {
				current_answer.SetValue(CellPosition(y, x), Answer::kClueCell);
			}
		}
	}
	Problem problem = current_answer.ExtractProblem();
	Field field(problem, dic);
	field.CheckGroupAll();
	current_energy = ComputeEnergy(field);

	for (; step < max_step; ++step) {
		std::vector<std::pair<CellPosition, int> > candidate;
		for (Y y(0); y < height; ++y) {
			for (X x(0); x < width; ++x) {
				CellPosition pos(y, x);
				int current_val = current_answer.GetValue(pos);
				if (current_val == Answer::kClueCell) continue;

				for (int n = 1; n <= 9; ++n) if (n != current_val) {
					bool isok = true;
					for (Direction d : k4Neighborhood) {
						for (CellPosition pos2 = pos + d; 0 <= pos2.y && pos2.y < height && 0 <= pos2.x && pos2.x < width; pos2 = pos2 + d) {
							if (current_answer.GetValue(pos2) == n) {
								isok = false;
								break;
							} else if (current_answer.GetValue(pos2) == Answer::kClueCell) {
								break;
							}
						}
					}
					if (isok) {
						candidate.push_back({ pos, n });
					}
				}
			}
		}
		shuffle(candidate.begin(), candidate.end(), *rnd);

		for (auto c : candidate) {
			CellPosition pos = c.first; int val = c.second;
			int previous_val = current_answer.GetValue(pos);
			current_answer.SetValue(pos, val);

			Problem problem = current_answer.ExtractProblem();
			Field field(problem, dic);
			field.CheckGroupAll();
			bool transition = false;

			if (!field.IsInconsistent()) {
				if (UndecidedCells(field) == 0) {
					*ret = problem;
					return true;
				}
				double next_energy = ComputeEnergy(field);
				if (current_energy > next_energy) transition = true;
				else {
					double threshold = exp((current_energy - next_energy) / temperature);
					if (real_dist(*rnd) < threshold) transition = true;
				}

				if (transition) current_energy = next_energy;
			}

			if (transition) {
				break;
			} else {
				current_answer.SetValue(pos, previous_val);
			}
		}
		temperature *= 0.995;
	}

	return false;
}
}
}<|endoftext|>


<commit_before>#include <ORM/backends/MySql.hpp>
orm::MySqlDB def("root","toor","test");
//orm::MySqlDB def("root","root","test");

//#include <ORM/backends/Sqlite3.hpp>
//orm::Sqlite3DB def("./test.db");

orm::DB& orm::DB::Default = def;

#include <ORM/fields.hpp>
#include <ORM/fields/ManyToMany.hpp>
#include <ORM/models/SqlObject.hpp>
#include <ORM/backends/op.hpp>

#include <iostream>

class Spell : public orm::SqlObject<Spell>
{
    public:
        Spell();
        orm::CharField<255> name;
        orm::IntegerField element;

        MAKE_STATIC_COLUMN(name,element);

};
REGISTER_AND_CONSTRUCT(Spell,"spell",name,"name",element,"element")

class Stats : public orm::SqlObject<Stats>
{
    public:
        Stats();
        orm::IntegerField pv;
        orm::IntegerField pi;
        /*orm::IntegerField intelligence;
        orm::IntegerField force;
        orm::IntegerField defence;
        orm::IntegerField vattaque;
        orm::IntegerField esquive;
        orm::IntegerField chance;
        orm::IntegerField charme;
        orm::IntegerField mouvement;*/

        MAKE_STATIC_COLUMN(pv,pi/*,intelligence,force,defence,vattaque,esquive,chance,charme,mouvement*/)
};
REGISTER_AND_CONSTRUCT(Stats,"stats",pv,"pv",pi,"pi"/*,intelligence,"int",force,"force",defence,"def",vattaque,"vatq",esquive,"esq",chance,"chance",charme,"charme",mouvement,"mouvement"*/)

class Perso : public orm::SqlObject<Perso>
{
    public:
        Perso();
        orm::CharField<255> name;
        orm::IntegerField lvl;
        orm::FK<Stats,false> stats;
        orm::FK<Stats,false> stats2;
        orm::FK<Perso,true> maitre;

        orm::ManyToMany<Perso,Spell> spells;

        MAKE_STATIC_COLUMN(name,lvl,stats,stats2,maitre)
};
M2M_REGISTER(Perso,spells,Spell,"perso_spell","perso_id","spell_id")
REGISTER(Perso,"perso",name,"name",lvl,"lvl",stats,"stats",stats2,"stats_tmp",maitre,"master")
Perso::Perso() : name(Perso::_name), lvl(Perso::_lvl), stats(Perso::_stats),stats2(Perso::_stats2), maitre(_maitre), spells(*this)
{
    name.registerAttr(*this);
    lvl.registerAttr(*this);
    stats.registerAttr(*this);
    stats2.registerAttr(*this);
    maitre.registerAttr(*this);
}
//REGISTER_AND_CONSTRUCT(Perso,"perso",name,"name",lvl,"lvl",stats,"stats",stats2,"stats_tmp",maitre,"master")

class TestTypes : public orm::SqlObject<TestTypes>
{
    public:
    TestTypes();

    orm::FK<TestTypes> fk;

    orm::BooleanField           booleanField;
    orm::CharField<255>         charField;
    orm::DateTimeField          datetimeField;
    orm::AutoDateTimeField      autodatetimeField;
    orm::AutoNowDateTimeField   autonowdatetimeField;
    orm::IntegerField           integerField;
    orm::FloatField             floatField;
    orm::DoubleField            doubleField;
    orm::TextField              textField;

    MAKE_STATIC_COLUMN(\
                       fk,\
                       booleanField,\
                       charField,\
                       datetimeField,\
                       autodatetimeField,\
                       autonowdatetimeField,\
                       integerField,\
                       floatField,\
                       doubleField,\
                       textField\
                      )
};
REGISTER_AND_CONSTRUCT(TestTypes,"test_types",\
                       fk,"fk",\
                       booleanField,"booleanField",\
                       charField,"charField",\
                       datetimeField, "datetimeField",\
                       autodatetimeField, "autodatetimeField",\
                       autonowdatetimeField, "autonowdatetimeField",\
                       integerField,"integerField",\
                       floatField,"floatField",\
                       doubleField,"doubleField",\
                       textField,"textField"\
                      )
//merge all colums
class TestMergeHeritage : public TestTypes
{
    public:
        TestMergeHeritage();

        orm::BooleanField   b;

        MAKE_STATIC_COLUMN(b)
};
REGISTER_AND_CONSTRUCT(TestMergeHeritage,"TestMergeHeritage",b,"b")
//REGISTER_TABLE(TestMergeHeritage,"TestMergeHeritage")

using namespace orm;
using namespace std;

void testDate()
{

    std::cout<<"date tests"<<std::endl;
    std::cout<<"1 month: "<<orm::DateTimeField::month(1)
    <<"\n 2 months: "<<orm::DateTimeField::month(2)
    <<"\n 1+1 months: "<<orm::DateTimeField::month(1) + orm::DateTimeField::month(1)
    <<"\n now: "<<orm::DateTimeField::now()
    <<"\n now + 30 day: "<<orm::DateTimeField::now() + orm::DateTimeField::day(30)
    <<"\n 1 hour: "<<orm::DateTimeField::time(1,0,0)
    <<"\n 2 hour: "<<orm::DateTimeField::time(2,0,0)
    <<"\n 1+1 hour: "<<orm::DateTimeField::time(1,0,0) + orm::DateTimeField::time(1,0,0)
    <<"\n 1 day: "<<orm::DateTimeField::date(0,0,1)
    <<"\n 1 day + 1 hour: "<<orm::DateTimeField::normalize(orm::DateTimeField::date(0,0,1) + orm::DateTimeField::time(1,0,0))
    <<"\n 1 day + 1 now: "<<orm::DateTimeField::normalize(orm::DateTimeField::date(0,0,1) + orm::DateTimeField::now())
    <<"\n 1 day + 1 hour + 1 now: "<<orm::DateTimeField::normalize(orm::DateTimeField::date(0,0,1) + orm::DateTimeField::time(1,0,0)+orm::DateTimeField::now())
    <<std::endl;
}

int main(int argc,char* argv[])
{

    orm::DB::Default.connect();

    //REGISTER_DB(Perso,orm::DB::Default)

    DB* con2 = orm::DB::Default.clone();
    con2->connect();

    //orm::Tables::drop();
    orm::Tables::create();

    {
        std::cout<<"======= TestTypes ======="<<std::endl;
        TestTypes test;
        test.booleanField = false;
        test.charField = "test";
        test.datetimeField = orm::DateTimeField::now();
        test.integerField = 42;
        test.floatField = 4.2;
        test.doubleField = 4.2;
        test.textField = "this is a long text for testing";

        cout<<"Current test"<<test<<endl;
        test.save();
        cout<<"Save current"<<endl;

        std::list<std::shared_ptr<TestTypes>> lis;
        TestTypes::query()
            .filter(orm::Q<TestTypes>(orm::DateTimeField::now()-orm::DateTimeField::day(1),orm::op::gt,TestTypes::_datetimeField))
            .get(lis);

        cout<<"All tests with DateTimeField > now - 1 day"<<endl;
        for(auto u : lis)
        {
            cout<<u.get()<<std::endl;
            cout<<*u<<endl;
        }

        cout<<"All tests with DateTimeField > now - 1 day (with ref to value)"<<endl;
        TestTypes test2;
        test2.datetimeField = test.datetimeField - orm::DateTimeField::day(1);

        lis.clear();
        TestTypes::query()
            .filter(orm::Q<TestTypes>(test2.datetimeField.value(),orm::op::gt,TestTypes::_datetimeField))
            .get(lis);
        //.__print__();
        for(auto u : lis)
        {
            cout<<u.get()<<std::endl;
            cout<<*u<<endl;
        }

    }
return 0;

    std::cout<<"=============="<<std::endl;
    {
        auto p1 = Perso::get(1,*con2);
        cout<<"Current perso1 "<<*p1<<endl;
        cout<<" add 1 to lvl"<<endl;
        p1->lvl = p1->lvl + 1;
        cout<<"Current perso1 "<<*p1<<endl;
        cout<<"save it"<<endl;
        cout<<"current lvl: "<<p1->lvl<<endl;
        p1->save();

        cout<<"Current perso1 "<<*p1<<endl;
        cout<<" add 2 to stats.pv"<<endl;
        p1->stats->pv += 2;
        cout<<"Current perso1 "<<*p1<<endl;
        p1->save();
        cout<<"Current perso1 "<<*p1<<endl;

        cout<<"delete p1->master->master"<<endl;
        p1->maitre->maitre.del(true);
        cout<<"Current perso1 "<<*p1<<endl;

        auto lis = p1->spells.all();
        std::cout<<"All his spells"<<std::endl;
        for(auto u : lis)
        {
            cout<<*u<<endl;
        }
            //.filter("test",orm::op::exact,Spell::_name);
            //.get(lis);

        std::cout<<"Add spell s1"<<std::endl;
        Spell s1;
        s1.name = "s1";
        s1.element = 1;
        s1.save();
        p1->spells.add(s1);

        std::cout<<"Add spell s2"<<std::endl;
        Spell s2;
        s2.name = "s2";
        s2.element = 2;
        s2.save();
        p1->spells.add(s2);

        std::cout<<"All his spells"<<std::endl;
        lis.clear();
        lis = p1->spells.all();
        for(auto u : lis)
        {
            cout<<*u<<endl;
        }

        std::cout<<"All his spells with name s2 ("<<p1->getPk()<<",s2"<<")"<<std::endl;
        lis.clear();
        p1->spells.query()
        .filter(std::string("s2"),orm::op::exact,Spell::_name)
            .get(lis);
        for(auto& u : lis)
        {
            cout<<*u<<endl;
        }

    }
    std::cout<<"=============="<<std::endl;

   {
       cout<<"All persos"<<endl;
       std::list<Cache<Perso>::type_ptr> lis= Perso::all();
       for(auto u : lis)
       {
            cout<<*u<<endl;
       }
   }
    std::cout<<"=============="<<std::endl;

   {
       cout<<"Create Perso"<<endl;
       Perso p2;// = new Perso;

       p2.name = "test insert";
       p2.lvl = 75;
       p2.save();

       cout<<"Change PV to +=20"<<endl;
       p2.stats->pv+= 20;
       cout<<p2<<endl;

       cout<<"save it"<<endl;
       p2.save();

       cout<<"All persos (current="<<p2<<")"<<endl;
       std::list<std::shared_ptr<Perso> > lis= Perso::all();
       for(auto u : lis)
       {
            cout<<*u<<endl;
       }

   }
    std::cout<<"=============="<<std::endl;
   {
       Perso p2;

       Perso::query()
           .filter(Q<Perso>(4,orm::op::gt,Perso::_lvl)
                   and Q<Perso>(42,orm::op::gte,Perso::_lvl)
                   and not Q<Perso>(4,orm::op::lt,Perso::_lvl)
                  )
           .orderBy(Perso::_name)
           .get(p2);
       std::cout<<p2<<std::endl;

      // Chained way for same result
      // Perso::query()
      //  .filter(4,orm::op::gt,Perso::_lvl)
      //  .filter(42,orm::op::gte,Perso::_lvl)
      //  .exclude(4,orm::op::lt,Perso::_lvl)
      //  .orderBy(Perso::_name)
      //  .get(p2);
      //

       std::list<Cache<Perso>::type_ptr> results;
       //Perso p;// = new Perso;
       //p.name="test";
       //p.maitre->name="test master";
       //p.maitre->lvl = 5;
       //p.save();

       //std::cout<<p<<std::endl;

       //Perso::query()
       //    .filter(4,orm::op::gt,Perso::_maitre,Perso::_lvl)
       //    .orderBy(Perso::_name)
       //    .get(results);
       //for(auto& perso : results)
       //    cout<<*perso<<endl;

       //results.clear();

       cout<<"All perso"<<endl;
       Perso::query().get(results);
       for(auto& perso : results)
       {
           cout<<perso.get()<<std::endl;
           std::cout<<*perso<<endl;
       }

       results.clear();

       cout<<"All perso where lvl < 200"<<endl;
       Perso::query().filter(200,orm::op::lt,Perso::_lvl).get(results);
       for(auto& perso : results)
       {
           cout<<perso.get()<<std::endl;
           std::cout<<*perso<<endl;
       }

   }
    std::cout<<"=============="<<std::endl;
   {

       std::list<std::shared_ptr<Perso>> lis;
       Perso::query().filter(string("test"),orm::op::startswith,Perso::_name).get(lis);
       for(auto u : lis)
           cout<<*u<<endl;
   }

    std::cout<<"=============="<<std::endl;

   /*{
       auto& p1 = Perso::get(1);
       const std::list<std::shared_ptr<Spell> >& spells = p1->spells.all();
       for(auto u : spells)
           cout<<*u<<endl;
   }

    std::cout<<"=============="<<std::endl;

    {
       std::list<std::shared_ptr<Spell>> list;
       Spell::query().get(list);
       for(auto u : list)
           cout<<*u<<endl;
    }

    std::cout<<"=============="<<std::endl;
    {
        auto& p1 = Perso::get(1);
        std::cout<<"perso pk=1:\n"<<*p1<<std::endl;

        auto& stats = Stats::get(1);
        p1->stats = stats;

        std::list<std::shared_ptr<Spell>> list;
        p1->spells.query()\
          .filter(2,"exact",Spell::_element)\
          .get(list);

        cout<<"sorts d'element == 2"<<endl;
        for(auto u : list)
            cout<<*u<<endl;

        cout<<"sorts du perso"<<endl;
        for(auto u : p1->spells.all())
            cout<<*u<<endl;

        auto& sort = Spell::get(1);
        cout<<"sort pk = 1.\n"<<*sort<<endl;

        p1->spells.add(sort);
        p1->spells.remove(sort);

    }*/

    std::cout<<"=============="<<std::endl;

    DB::Default.disconnect();
    return 0;
};
<commit_msg>Make example with Sqlite3<commit_after>//#include <ORM/backends/MySql.hpp>
//orm::MySqlDB def("root","toor","test");
//orm::MySqlDB def("root","root","test");

#include <ORM/backends/Sqlite3.hpp>
orm::Sqlite3DB def("./test.db");

orm::DB& orm::DB::Default = def;

#include <ORM/fields.hpp>
#include <ORM/fields/ManyToMany.hpp>
#include <ORM/models/SqlObject.hpp>
#include <ORM/backends/op.hpp>

#include <iostream>

class Spell : public orm::SqlObject<Spell>
{
    public:
        Spell();
        orm::CharField<255> name;
        orm::IntegerField element;

        MAKE_STATIC_COLUMN(name,element);

};
REGISTER_AND_CONSTRUCT(Spell,"spell",name,"name",element,"element")

class Stats : public orm::SqlObject<Stats>
{
    public:
        Stats();
        orm::IntegerField pv;
        orm::IntegerField pi;
        /*orm::IntegerField intelligence;
        orm::IntegerField force;
        orm::IntegerField defence;
        orm::IntegerField vattaque;
        orm::IntegerField esquive;
        orm::IntegerField chance;
        orm::IntegerField charme;
        orm::IntegerField mouvement;*/

        MAKE_STATIC_COLUMN(pv,pi/*,intelligence,force,defence,vattaque,esquive,chance,charme,mouvement*/)
};
REGISTER_AND_CONSTRUCT(Stats,"stats",pv,"pv",pi,"pi"/*,intelligence,"int",force,"force",defence,"def",vattaque,"vatq",esquive,"esq",chance,"chance",charme,"charme",mouvement,"mouvement"*/)

class Perso : public orm::SqlObject<Perso>
{
    public:
        Perso();
        orm::CharField<255> name;
        orm::IntegerField lvl;
        orm::FK<Stats,false> stats;
        orm::FK<Stats,false> stats2;
        orm::FK<Perso,true> maitre;

        orm::ManyToMany<Perso,Spell> spells;

        MAKE_STATIC_COLUMN(name,lvl,stats,stats2,maitre)
};
M2M_REGISTER(Perso,spells,Spell,"perso_spell","perso_id","spell_id")
REGISTER(Perso,"perso",name,"name",lvl,"lvl",stats,"stats",stats2,"stats_tmp",maitre,"master")
Perso::Perso() : name(Perso::_name), lvl(Perso::_lvl), stats(Perso::_stats),stats2(Perso::_stats2), maitre(_maitre), spells(*this)
{
    name.registerAttr(*this);
    lvl.registerAttr(*this);
    stats.registerAttr(*this);
    stats2.registerAttr(*this);
    maitre.registerAttr(*this);
}
//REGISTER_AND_CONSTRUCT(Perso,"perso",name,"name",lvl,"lvl",stats,"stats",stats2,"stats_tmp",maitre,"master")

class TestTypes : public orm::SqlObject<TestTypes>
{
    public:
    TestTypes();

    orm::FK<TestTypes> fk;

    orm::BooleanField           booleanField;
    orm::CharField<255>         charField;
    orm::DateTimeField          datetimeField;
    orm::AutoDateTimeField      autodatetimeField;
    orm::AutoNowDateTimeField   autonowdatetimeField;
    orm::IntegerField           integerField;
    orm::FloatField             floatField;
    orm::DoubleField            doubleField;
    orm::TextField              textField;

    MAKE_STATIC_COLUMN(\
                       fk,\
                       booleanField,\
                       charField,\
                       datetimeField,\
                       autodatetimeField,\
                       autonowdatetimeField,\
                       integerField,\
                       floatField,\
                       doubleField,\
                       textField\
                      )
};
REGISTER_AND_CONSTRUCT(TestTypes,"test_types",\
                       fk,"fk",\
                       booleanField,"booleanField",\
                       charField,"charField",\
                       datetimeField, "datetimeField",\
                       autodatetimeField, "autodatetimeField",\
                       autonowdatetimeField, "autonowdatetimeField",\
                       integerField,"integerField",\
                       floatField,"floatField",\
                       doubleField,"doubleField",\
                       textField,"textField"\
                      )
//merge all colums
class TestMergeHeritage : public TestTypes
{
    public:
        TestMergeHeritage();

        orm::BooleanField   b;

        MAKE_STATIC_COLUMN(b)
};
REGISTER_AND_CONSTRUCT(TestMergeHeritage,"TestMergeHeritage",b,"b")
//REGISTER_TABLE(TestMergeHeritage,"TestMergeHeritage")

using namespace orm;
using namespace std;

void testDate()
{

    std::cout<<"date tests"<<std::endl;
    std::cout<<"1 month: "<<orm::DateTimeField::month(1)
    <<"\n 2 months: "<<orm::DateTimeField::month(2)
    <<"\n 1+1 months: "<<orm::DateTimeField::month(1) + orm::DateTimeField::month(1)
    <<"\n now: "<<orm::DateTimeField::now()
    <<"\n now + 30 day: "<<orm::DateTimeField::now() + orm::DateTimeField::day(30)
    <<"\n 1 hour: "<<orm::DateTimeField::time(1,0,0)
    <<"\n 2 hour: "<<orm::DateTimeField::time(2,0,0)
    <<"\n 1+1 hour: "<<orm::DateTimeField::time(1,0,0) + orm::DateTimeField::time(1,0,0)
    <<"\n 1 day: "<<orm::DateTimeField::date(0,0,1)
    <<"\n 1 day + 1 hour: "<<orm::DateTimeField::normalize(orm::DateTimeField::date(0,0,1) + orm::DateTimeField::time(1,0,0))
    <<"\n 1 day + 1 now: "<<orm::DateTimeField::normalize(orm::DateTimeField::date(0,0,1) + orm::DateTimeField::now())
    <<"\n 1 day + 1 hour + 1 now: "<<orm::DateTimeField::normalize(orm::DateTimeField::date(0,0,1) + orm::DateTimeField::time(1,0,0)+orm::DateTimeField::now())
    <<std::endl;
}

int main(int argc,char* argv[])
{

    orm::DB::Default.connect();

    //REGISTER_DB(Perso,orm::DB::Default)

    DB* con2 = orm::DB::Default.clone();
    con2->connect();

    orm::Tables::drop();
    orm::Tables::create();

    {
        std::cout<<"======= TestTypes ======="<<std::endl;
        TestTypes test;
        test.booleanField = false;
        test.charField = "test";
        test.datetimeField = orm::DateTimeField::now();
        test.integerField = 42;
        test.floatField = 4.2;
        test.doubleField = 4.2;
        test.textField = "this is a long text for testing";

        cout<<"Current test"<<test<<endl;
        test.save();
        cout<<"Save current"<<endl;

        std::list<std::shared_ptr<TestTypes>> lis;
        TestTypes::query()
            .filter(orm::Q<TestTypes>(orm::DateTimeField::now()-orm::DateTimeField::day(1),orm::op::gt,TestTypes::_datetimeField))
            .get(lis);

        cout<<"All tests with DateTimeField > now - 1 day"<<endl;
        for(auto u : lis)
        {
            cout<<u.get()<<std::endl;
            cout<<*u<<endl;
        }

        cout<<"All tests with DateTimeField > now - 1 day (with ref to value)"<<endl;
        TestTypes test2;
        test2.datetimeField = test.datetimeField - orm::DateTimeField::day(1);

        lis.clear();
        TestTypes::query()
            .filter(orm::Q<TestTypes>(test2.datetimeField.value(),orm::op::gt,TestTypes::_datetimeField))
            .get(lis);
        //.__print__();
        for(auto u : lis)
        {
            cout<<u.get()<<std::endl;
            cout<<*u<<endl;
        }

    }
return 0;

    std::cout<<"=============="<<std::endl;
    {
        auto p1 = Perso::get(1,*con2);
        cout<<"Current perso1 "<<*p1<<endl;
        cout<<" add 1 to lvl"<<endl;
        p1->lvl = p1->lvl + 1;
        cout<<"Current perso1 "<<*p1<<endl;
        cout<<"save it"<<endl;
        cout<<"current lvl: "<<p1->lvl<<endl;
        p1->save();

        cout<<"Current perso1 "<<*p1<<endl;
        cout<<" add 2 to stats.pv"<<endl;
        p1->stats->pv += 2;
        cout<<"Current perso1 "<<*p1<<endl;
        p1->save();
        cout<<"Current perso1 "<<*p1<<endl;

        cout<<"delete p1->master->master"<<endl;
        p1->maitre->maitre.del(true);
        cout<<"Current perso1 "<<*p1<<endl;

        auto lis = p1->spells.all();
        std::cout<<"All his spells"<<std::endl;
        for(auto u : lis)
        {
            cout<<*u<<endl;
        }
            //.filter("test",orm::op::exact,Spell::_name);
            //.get(lis);

        std::cout<<"Add spell s1"<<std::endl;
        Spell s1;
        s1.name = "s1";
        s1.element = 1;
        s1.save();
        p1->spells.add(s1);

        std::cout<<"Add spell s2"<<std::endl;
        Spell s2;
        s2.name = "s2";
        s2.element = 2;
        s2.save();
        p1->spells.add(s2);

        std::cout<<"All his spells"<<std::endl;
        lis.clear();
        lis = p1->spells.all();
        for(auto u : lis)
        {
            cout<<*u<<endl;
        }

        std::cout<<"All his spells with name s2 ("<<p1->getPk()<<",s2"<<")"<<std::endl;
        lis.clear();
        p1->spells.query()
        .filter(std::string("s2"),orm::op::exact,Spell::_name)
            .get(lis);
        for(auto& u : lis)
        {
            cout<<*u<<endl;
        }

    }
    std::cout<<"=============="<<std::endl;

   {
       cout<<"All persos"<<endl;
       std::list<Cache<Perso>::type_ptr> lis= Perso::all();
       for(auto u : lis)
       {
            cout<<*u<<endl;
       }
   }
    std::cout<<"=============="<<std::endl;

   {
       cout<<"Create Perso"<<endl;
       Perso p2;// = new Perso;

       p2.name = "test insert";
       p2.lvl = 75;
       p2.save();

       cout<<"Change PV to +=20"<<endl;
       p2.stats->pv+= 20;
       cout<<p2<<endl;

       cout<<"save it"<<endl;
       p2.save();

       cout<<"All persos (current="<<p2<<")"<<endl;
       std::list<std::shared_ptr<Perso> > lis= Perso::all();
       for(auto u : lis)
       {
            cout<<*u<<endl;
       }

   }
    std::cout<<"=============="<<std::endl;
   {
       Perso p2;

       Perso::query()
           .filter(Q<Perso>(4,orm::op::gt,Perso::_lvl)
                   and Q<Perso>(42,orm::op::gte,Perso::_lvl)
                   and not Q<Perso>(4,orm::op::lt,Perso::_lvl)
                  )
           .orderBy(Perso::_name)
           .get(p2);
       std::cout<<p2<<std::endl;

      // Chained way for same result
      // Perso::query()
      //  .filter(4,orm::op::gt,Perso::_lvl)
      //  .filter(42,orm::op::gte,Perso::_lvl)
      //  .exclude(4,orm::op::lt,Perso::_lvl)
      //  .orderBy(Perso::_name)
      //  .get(p2);
      //

       std::list<Cache<Perso>::type_ptr> results;
       //Perso p;// = new Perso;
       //p.name="test";
       //p.maitre->name="test master";
       //p.maitre->lvl = 5;
       //p.save();

       //std::cout<<p<<std::endl;

       //Perso::query()
       //    .filter(4,orm::op::gt,Perso::_maitre,Perso::_lvl)
       //    .orderBy(Perso::_name)
       //    .get(results);
       //for(auto& perso : results)
       //    cout<<*perso<<endl;

       //results.clear();

       cout<<"All perso"<<endl;
       Perso::query().get(results);
       for(auto& perso : results)
       {
           cout<<perso.get()<<std::endl;
           std::cout<<*perso<<endl;
       }

       results.clear();

       cout<<"All perso where lvl < 200"<<endl;
       Perso::query().filter(200,orm::op::lt,Perso::_lvl).get(results);
       for(auto& perso : results)
       {
           cout<<perso.get()<<std::endl;
           std::cout<<*perso<<endl;
       }

   }
    std::cout<<"=============="<<std::endl;
   {

       std::list<std::shared_ptr<Perso>> lis;
       Perso::query().filter(string("test"),orm::op::startswith,Perso::_name).get(lis);
       for(auto u : lis)
           cout<<*u<<endl;
   }

    std::cout<<"=============="<<std::endl;

   /*{
       auto& p1 = Perso::get(1);
       const std::list<std::shared_ptr<Spell> >& spells = p1->spells.all();
       for(auto u : spells)
           cout<<*u<<endl;
   }

    std::cout<<"=============="<<std::endl;

    {
       std::list<std::shared_ptr<Spell>> list;
       Spell::query().get(list);
       for(auto u : list)
           cout<<*u<<endl;
    }

    std::cout<<"=============="<<std::endl;
    {
        auto& p1 = Perso::get(1);
        std::cout<<"perso pk=1:\n"<<*p1<<std::endl;

        auto& stats = Stats::get(1);
        p1->stats = stats;

        std::list<std::shared_ptr<Spell>> list;
        p1->spells.query()\
          .filter(2,"exact",Spell::_element)\
          .get(list);

        cout<<"sorts d'element == 2"<<endl;
        for(auto u : list)
            cout<<*u<<endl;

        cout<<"sorts du perso"<<endl;
        for(auto u : p1->spells.all())
            cout<<*u<<endl;

        auto& sort = Spell::get(1);
        cout<<"sort pk = 1.\n"<<*sort<<endl;

        p1->spells.add(sort);
        p1->spells.remove(sort);

    }*/

    std::cout<<"=============="<<std::endl;

    DB::Default.disconnect();
    return 0;
};
<|endoftext|>


<commit_before><commit_msg>stop assert on exit from bibliography<commit_after><|endoftext|>