blob: e460910b79f32548b5b2c0b7ad653ed920d26677 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.
*/
#include "UUID.h"
#include <apr_strings.h>
#include <apr_md5.h>
#include <decaf/lang/exceptions/RuntimeException.h>
using namespace std;
using namespace decaf;
using namespace decaf::util;
using namespace decaf::lang;
////////////////////////////////////////////////////////////////////////////////
UUID::UUID( long long mostSigBits, long long leastSigBits ) {
memcpy( &apr_uuid.data[0], &mostSigBits, sizeof( long long ) );
memcpy( &apr_uuid.data[sizeof(long long)], &leastSigBits, sizeof(long long ) );
this->mostSigBits = mostSigBits;
this->leastSigBits = leastSigBits;
// Version indicator, set when a UUID is generated
this->uuidVersion = (int)( mostSigBits & 0x000000000000F000LL ) >> 12;
}
////////////////////////////////////////////////////////////////////////////////
UUID::~UUID() {
}
////////////////////////////////////////////////////////////////////////////////
int UUID::compareTo( const UUID& value ) const {
return apr_strnatcmp( (const char*)this->apr_uuid.data,
(const char*)value.apr_uuid.data );
}
////////////////////////////////////////////////////////////////////////////////
bool UUID::equals( const UUID& value ) const {
return apr_strnatcmp( (const char*)this->apr_uuid.data,
(const char*)value.apr_uuid.data ) == 0 ? true : false;
}
////////////////////////////////////////////////////////////////////////////////
bool UUID::operator==( const UUID& value ) const {
return this->equals( value );
}
////////////////////////////////////////////////////////////////////////////////
bool UUID::operator<( const UUID& value ) const {
return this->compareTo( value ) == -1 ? true : false;
}
////////////////////////////////////////////////////////////////////////////////
std::string UUID::toString() const {
char buffer[APR_UUID_FORMATTED_LENGTH+1] = {0};
apr_uuid_format( &buffer[0], &apr_uuid );
return &buffer[0];
}
////////////////////////////////////////////////////////////////////////////////
long long UUID::getLeastSignificantBits() const {
return this->leastSigBits;
}
////////////////////////////////////////////////////////////////////////////////
long long UUID::getMostSignificantBits() const {
long long result = 0;
memcpy( &result, &this->apr_uuid.data[sizeof(long long)], sizeof(long long) );
return this->mostSigBits;
}
////////////////////////////////////////////////////////////////////////////////
long long UUID::node() throw ( lang::exceptions::UnsupportedOperationException ) {
if( this->version() != 1 ) {
throw exceptions::UnsupportedOperationException(
__FILE__, __LINE__,
"UUID::node - Only a Version 1 UUID supports this operation." );
}
return ( this->leastSigBits & 0x0000FFFFFFFFFFFFULL );
}
////////////////////////////////////////////////////////////////////////////////
long long UUID::timestamp() throw ( lang::exceptions::UnsupportedOperationException ) {
if( this->version() != 1 ) {
throw exceptions::UnsupportedOperationException(
__FILE__, __LINE__,
"UUID::node - Only a Version 1 UUID supports this operation." );
}
// Mask out the version and shift values around to make time.
long long timeLow = ( mostSigBits & 0xFFFFFFFF00000000ULL) >> 32;
long long timeMid = ( mostSigBits & 0x00000000FFFF0000ULL) << 16;
long long timeHigh = ( mostSigBits & 0x0000000000000FFFULL) << 48;
return timeLow | timeMid | timeHigh;
}
////////////////////////////////////////////////////////////////////////////////
int UUID::clockSequence() throw ( lang::exceptions::UnsupportedOperationException ) {
if( this->version() != 1 ) {
throw exceptions::UnsupportedOperationException(
__FILE__, __LINE__,
"UUID::node - Only a Version 1 UUID supports this operation." );
}
return (int)( ( this->leastSigBits & 0x3FFF000000000000ULL ) >> 48 );
}
////////////////////////////////////////////////////////////////////////////////
int UUID::variant() throw ( lang::exceptions::UnsupportedOperationException ) {
// determine variant field
if( ( this->leastSigBits & 0x8000000000000000ULL ) == 0 ) {
// MSB0 not set, NCS backwards compatibility variant
return 0;
} else if( ( this->leastSigBits & 0x4000000000000000ULL ) != 0 ) {
// MSB1 set, either MS reserved or future reserved
return (int)( ( this->leastSigBits & 0xE000000000000000ULL ) >> 61 );
}
// MSB1 not set, RFC 4122 variant
return 2;
}
////////////////////////////////////////////////////////////////////////////////
int UUID::version() throw ( lang::exceptions::UnsupportedOperationException ) {
return this->uuidVersion;
}
////////////////////////////////////////////////////////////////////////////////
UUID UUID::randomUUID() {
apr_uuid_t temp;
// Generate some random bytes.
apr_uuid_get( &temp );
long long msb = 0;
long long lsb = 0;
msb = (temp.data[0] & 0xFFLL) << 56;
msb |= (temp.data[1] & 0xFFLL) << 48;
msb |= (temp.data[2] & 0xFFLL) << 40;
msb |= (temp.data[3] & 0xFFLL) << 32;
msb |= (temp.data[4] & 0xFFLL) << 24;
msb |= (temp.data[5] & 0xFFLL) << 16;
msb |= (temp.data[6] & 0x0FLL) << 8;
msb |= (0x4LL << 12); // set the version to 4
msb |= (temp.data[7] & 0xFFLL);
lsb = (temp.data[8] & 0x3FLL) << 56;
lsb |= (0x2LL << 62); // set the variant to bits 01
lsb |= (temp.data[9] & 0xFFLL) << 48;
lsb |= (temp.data[10] & 0xFFLL) << 40;
lsb |= (temp.data[11] & 0xFFLL) << 32;
lsb |= (temp.data[12] & 0xFFLL) << 24;
lsb |= (temp.data[13] & 0xFFLL) << 16;
lsb |= (temp.data[14] & 0xFFLL) << 8;
lsb |= (temp.data[15] & 0xFFLL);
return UUID( msb, lsb );
}
////////////////////////////////////////////////////////////////////////////////
UUID UUID::nameUUIDFromBytes( const std::vector<char>& name ) {
return UUID::nameUUIDFromBytes( &name[0], name.size() );
}
////////////////////////////////////////////////////////////////////////////////
UUID UUID::nameUUIDFromBytes( const char* name, std::size_t size ) {
apr_uuid_t temp;
if( apr_md5( &temp.data[0], name, size ) != APR_SUCCESS ) {
throw exceptions::RuntimeException(
__FILE__, __LINE__,
"UUID::nameUUIDFromBytes - Failed to run MD5 encoder." );
}
long long msb = 0;
long long lsb = 0;
msb = (temp.data[0] & 0xFFLL) << 56;
msb |= (temp.data[1] & 0xFFLL) << 48;
msb |= (temp.data[2] & 0xFFLL) << 40;
msb |= (temp.data[3] & 0xFFLL) << 32;
msb |= (temp.data[4] & 0xFFLL) << 24;
msb |= (temp.data[5] & 0xFFLL) << 16;
msb |= (temp.data[6] & 0x0FLL) << 8;
msb |= (0x3LL << 12); // set the version to 3
msb |= (temp.data[7] & 0xFFLL);
lsb = (temp.data[8] & 0x3FLL) << 56;
lsb |= (0x2LL << 62); // set the variant to bits 01
lsb |= (temp.data[9] & 0xFFLL) << 48;
lsb |= (temp.data[10] & 0xFFLL) << 40;
lsb |= (temp.data[11] & 0xFFLL) << 32;
lsb |= (temp.data[12] & 0xFFLL) << 24;
lsb |= (temp.data[13] & 0xFFLL) << 16;
lsb |= (temp.data[14] & 0xFFLL) << 8;
lsb |= (temp.data[15] & 0xFFLL);
return UUID( msb, lsb );
}
////////////////////////////////////////////////////////////////////////////////
UUID UUID::fromString( const std::string& name )
throw ( lang::exceptions::IllegalArgumentException ){
apr_uuid_t temp;
if( apr_uuid_parse( &temp, name.c_str() ) != APR_SUCCESS ) {
throw lang::exceptions::IllegalArgumentException(
__FILE__, __LINE__,
"UUID::fromString - Invalid UUID String: ",
name.c_str() );
}
long long mostSigBits = 0;
long long leastSigBits = 0;
// Extract to data from the uuid data
memcpy( &mostSigBits, &temp.data[0], sizeof(long long) );
memcpy( &leastSigBits, &temp.data[sizeof(long long)], sizeof(long long) );
return UUID( mostSigBits, leastSigBits );
}