325 lines
7.2 KiB
C++
325 lines
7.2 KiB
C++
// $package. http://www.slack.net/~ant/
|
|
|
|
#include "blargg_common.h"
|
|
|
|
/* Copyright (C) 2008-2009 Shay Green. This module is free software; you
|
|
can redistribute it and/or modify it under the terms of the GNU Lesser
|
|
General Public License as published by the Free Software Foundation; either
|
|
version 2.1 of the License, or (at your option) any later version. This
|
|
module is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
|
|
details. You should have received a copy of the GNU Lesser General Public
|
|
License along with this module; if not, write to the Free Software Foundation,
|
|
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
|
|
|
|
#include "blargg_source.h"
|
|
|
|
BLARGG_NAMESPACE_BEGIN
|
|
|
|
// defined here to avoid need for blargg_errors.cpp in simple programs
|
|
blargg_err_def_t blargg_err_memory = BLARGG_ERR_MEMORY;
|
|
|
|
void blargg_vector_::init()
|
|
{
|
|
begin_ = NULL;
|
|
size_ = 0;
|
|
}
|
|
|
|
void blargg_vector_::clear()
|
|
{
|
|
void* p = begin_;
|
|
begin_ = NULL;
|
|
size_ = 0;
|
|
free( p );
|
|
}
|
|
|
|
blargg_err_t blargg_vector_::resize_( size_t n, size_t elem_size )
|
|
{
|
|
if ( n != size_ )
|
|
{
|
|
if ( n == 0 )
|
|
{
|
|
// Simpler to handle explicitly. Realloc will handle a size of 0,
|
|
// but then we have to avoid raising an error for a NULL return.
|
|
clear();
|
|
}
|
|
else
|
|
{
|
|
void* p = realloc( begin_, n * elem_size );
|
|
CHECK_ALLOC( p );
|
|
begin_ = p;
|
|
size_ = n;
|
|
}
|
|
}
|
|
return blargg_ok;
|
|
}
|
|
|
|
static const BOOST::uint8_t mask_tab[6]={0x80,0xE0,0xF0,0xF8,0xFC,0xFE};
|
|
|
|
static const BOOST::uint8_t val_tab[6]={0,0xC0,0xE0,0xF0,0xF8,0xFC};
|
|
|
|
size_t utf8_char_len_from_header( char p_c )
|
|
{
|
|
size_t cnt = 0;
|
|
for(;;)
|
|
{
|
|
if ( ( p_c & mask_tab[cnt] ) == val_tab[cnt] ) break;
|
|
if ( ++cnt >= 6 ) return 0;
|
|
}
|
|
|
|
return cnt + 1;
|
|
}
|
|
|
|
size_t utf8_decode_char( const char *p_utf8, unsigned & wide, size_t mmax )
|
|
{
|
|
const BOOST::uint8_t * utf8 = ( const BOOST::uint8_t* )p_utf8;
|
|
|
|
if ( mmax == 0 )
|
|
{
|
|
wide = 0;
|
|
return 0;
|
|
}
|
|
|
|
if ( utf8[0] < 0x80 )
|
|
{
|
|
wide = utf8[0];
|
|
return utf8[0]>0 ? 1 : 0;
|
|
}
|
|
if ( mmax > 6 ) mmax = 6;
|
|
wide = 0;
|
|
|
|
unsigned res=0;
|
|
unsigned n;
|
|
unsigned cnt=0;
|
|
for(;;)
|
|
{
|
|
if ( ( *utf8 & mask_tab[cnt] ) == val_tab[cnt] ) break;
|
|
if ( ++cnt >= mmax ) return 0;
|
|
}
|
|
cnt++;
|
|
|
|
if ( cnt==2 && !( *utf8 & 0x1E ) ) return 0;
|
|
|
|
if ( cnt == 1 )
|
|
res = *utf8;
|
|
else
|
|
res = ( 0xFF >> ( cnt + 1 ) ) & *utf8;
|
|
|
|
for ( n = 1; n < cnt; n++ )
|
|
{
|
|
if ( ( utf8[n] & 0xC0 ) != 0x80 )
|
|
return 0;
|
|
if ( !res && n == 2 && !( ( utf8[n] & 0x7F ) >> ( 7 - cnt ) ) )
|
|
return 0;
|
|
|
|
res = ( res << 6 ) | ( utf8[n] & 0x3F );
|
|
}
|
|
|
|
wide = res;
|
|
|
|
return cnt;
|
|
}
|
|
|
|
size_t utf8_encode_char( unsigned wide, char * target )
|
|
{
|
|
size_t count;
|
|
|
|
if ( wide < 0x80 )
|
|
count = 1;
|
|
else if ( wide < 0x800 )
|
|
count = 2;
|
|
else if ( wide < 0x10000 )
|
|
count = 3;
|
|
else if ( wide < 0x200000 )
|
|
count = 4;
|
|
else if ( wide < 0x4000000 )
|
|
count = 5;
|
|
else if ( wide <= 0x7FFFFFFF )
|
|
count = 6;
|
|
else
|
|
return 0;
|
|
|
|
if ( target == 0 )
|
|
return count;
|
|
|
|
switch ( count )
|
|
{
|
|
case 6:
|
|
target[5] = 0x80 | ( wide & 0x3F );
|
|
wide = wide >> 6;
|
|
wide |= 0x4000000;
|
|
case 5:
|
|
target[4] = 0x80 | ( wide & 0x3F );
|
|
wide = wide >> 6;
|
|
wide |= 0x200000;
|
|
case 4:
|
|
target[3] = 0x80 | ( wide & 0x3F );
|
|
wide = wide >> 6;
|
|
wide |= 0x10000;
|
|
case 3:
|
|
target[2] = 0x80 | ( wide & 0x3F );
|
|
wide = wide >> 6;
|
|
wide |= 0x800;
|
|
case 2:
|
|
target[1] = 0x80 | ( wide & 0x3F );
|
|
wide = wide >> 6;
|
|
wide |= 0xC0;
|
|
case 1:
|
|
target[0] = wide;
|
|
}
|
|
|
|
return count;
|
|
}
|
|
|
|
size_t utf16_encode_char( unsigned cur_wchar, blargg_wchar_t * out )
|
|
{
|
|
if ( cur_wchar < 0x10000 )
|
|
{
|
|
if ( out ) *out = (blargg_wchar_t) cur_wchar; return 1;
|
|
}
|
|
else if ( cur_wchar < ( 1 << 20 ) )
|
|
{
|
|
unsigned c = cur_wchar - 0x10000;
|
|
//MSDN:
|
|
//The first (high) surrogate is a 16-bit code value in the range U+D800 to U+DBFF. The second (low) surrogate is a 16-bit code value in the range U+DC00 to U+DFFF. Using surrogates, Unicode can support over one million characters. For more details about surrogates, refer to The Unicode Standard, version 2.0.
|
|
if ( out )
|
|
{
|
|
out[0] = ( blargg_wchar_t )( 0xD800 | ( 0x3FF & ( c >> 10 ) ) );
|
|
out[1] = ( blargg_wchar_t )( 0xDC00 | ( 0x3FF & c ) ) ;
|
|
}
|
|
return 2;
|
|
}
|
|
else
|
|
{
|
|
if ( out ) *out = '?'; return 1;
|
|
}
|
|
}
|
|
|
|
size_t utf16_decode_char( const blargg_wchar_t * p_source, unsigned * p_out, size_t p_source_length )
|
|
{
|
|
if ( p_source_length == 0 ) return 0;
|
|
else if ( p_source_length == 1 )
|
|
{
|
|
*p_out = p_source[0];
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
size_t retval = 0;
|
|
unsigned decoded = p_source[0];
|
|
if ( decoded != 0 )
|
|
{
|
|
retval = 1;
|
|
if ( ( decoded & 0xFC00 ) == 0xD800 )
|
|
{
|
|
unsigned low = p_source[1];
|
|
if ( ( low & 0xFC00 ) == 0xDC00 )
|
|
{
|
|
decoded = 0x10000 + ( ( ( decoded & 0x3FF ) << 10 ) | ( low & 0x3FF ) );
|
|
retval = 2;
|
|
}
|
|
}
|
|
}
|
|
*p_out = decoded;
|
|
return retval;
|
|
}
|
|
}
|
|
|
|
// Converts wide-character path to UTF-8. Free result with free(). Only supported on Windows.
|
|
char* blargg_to_utf8( const blargg_wchar_t* wpath )
|
|
{
|
|
if ( wpath == NULL )
|
|
return NULL;
|
|
|
|
size_t needed = 0;
|
|
size_t mmax = blargg_wcslen( wpath );
|
|
if ( mmax <= 0 )
|
|
return NULL;
|
|
|
|
size_t ptr = 0;
|
|
while ( ptr < mmax )
|
|
{
|
|
unsigned wide = 0;
|
|
size_t char_len = utf16_decode_char( wpath + ptr, &wide, mmax - ptr );
|
|
if ( !char_len ) break;
|
|
ptr += char_len;
|
|
needed += utf8_encode_char( wide, 0 );
|
|
}
|
|
if ( needed <= 0 )
|
|
return NULL;
|
|
|
|
char* path = (char*) calloc( needed + 1, 1 );
|
|
if ( path == NULL )
|
|
return NULL;
|
|
|
|
ptr = 0;
|
|
size_t actual = 0;
|
|
while ( ptr < mmax && actual < needed )
|
|
{
|
|
unsigned wide = 0;
|
|
size_t char_len = utf16_decode_char( wpath + ptr, &wide, mmax - ptr );
|
|
if ( !char_len ) break;
|
|
ptr += char_len;
|
|
actual += utf8_encode_char( wide, path + actual );
|
|
}
|
|
|
|
if ( actual == 0 )
|
|
{
|
|
free( path );
|
|
return NULL;
|
|
}
|
|
|
|
assert( actual == needed );
|
|
return path;
|
|
}
|
|
|
|
// Converts UTF-8 path to wide-character. Free result with free() Only supported on Windows.
|
|
blargg_wchar_t* blargg_to_wide( const char* path )
|
|
{
|
|
if ( path == NULL )
|
|
return NULL;
|
|
|
|
size_t mmax = strlen( path );
|
|
if ( mmax <= 0 )
|
|
return NULL;
|
|
|
|
size_t needed = 0;
|
|
size_t ptr = 0;
|
|
while ( ptr < mmax )
|
|
{
|
|
unsigned wide = 0;
|
|
size_t char_len = utf8_decode_char( path + ptr, wide, mmax - ptr );
|
|
if ( !char_len ) break;
|
|
ptr += char_len;
|
|
needed += utf16_encode_char( wide, 0 );
|
|
}
|
|
if ( needed <= 0 )
|
|
return NULL;
|
|
|
|
blargg_wchar_t* wpath = (blargg_wchar_t*) calloc( needed + 1, sizeof *wpath );
|
|
if ( wpath == NULL )
|
|
return NULL;
|
|
|
|
ptr = 0;
|
|
size_t actual = 0;
|
|
while ( ptr < mmax && actual < needed )
|
|
{
|
|
unsigned wide = 0;
|
|
size_t char_len = utf8_decode_char( path + ptr, wide, mmax - ptr );
|
|
if ( !char_len ) break;
|
|
ptr += char_len;
|
|
actual += utf16_encode_char( wide, wpath + actual );
|
|
}
|
|
if ( actual == 0 )
|
|
{
|
|
free( wpath );
|
|
return NULL;
|
|
}
|
|
|
|
assert( actual == needed );
|
|
return wpath;
|
|
}
|
|
|
|
BLARGG_NAMESPACE_END
|