2013-09-28 03:24:46 +00:00
// $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 ;
}
2015-11-27 10:02:41 +00:00
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 ;
}
2013-09-28 03:24:46 +00:00
BLARGG_NAMESPACE_END