Advertisement
Delfigamer

encoding

Sep 26th, 2015
398
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 15.18 KB | None | 0 0
  1. // Text encoding routines
  2. // Uses concepts of separate encoders and decoders
  3. // An encoder is a routine that, given a UCS charcode, attempts to write it into a given byte stream in a specified format
  4. // A decoder is a routine that, given a byte stream, attempts to fetch a code point from it and returns its UCS index
  5. // Their signatures are public, so it's possible to implement additional encoding schemes outside of this unit
  6. // The text conversion routine accepts arbitrary combinations of a decoder and an encoder, including those defined elsewhere
  7. // This unit is used mainly for converting between UTF-8 used by the engine internally and UTF-16 used by Windows API
  8. // Additionally, the UTF-8 decoder is used by a text renderer, to properly fetch characters from a given string
  9.  
  10. #ifndef UTILS_ENCODING_HPP__
  11. #define UTILS_ENCODING_HPP__ 1
  12.  
  13. #include <cinttypes>
  14.  
  15. namespace utils
  16. {
  17.     // on success - return true, *pointlength <- number of bytes written
  18.     // invalid charcode - return false, *pointlength <- 0
  19.     // buffer overrun - return false, *pointlength <- number of bytes that would be written
  20.     // dest may be 0
  21.     // if destsize == 0 && dest == 0, succeeds on a valid charcode
  22.     // if destsize == 0 && dest != 0, always fails
  23.     typedef bool( *encoder_t )( void* dest, uint32_t charcode, size_t destsize, size_t* pointlength );
  24.  
  25.     // on success - return true, *pointlength <- number of bytes consumed
  26.     // invalid stream - return false, *pointlength <- number of bytes consumed
  27.     // buffer overrun - return false, *pointlength <- 0
  28.     // charcode may be nullptr
  29.     // if sourcesize == 0, source is assumed to be unbound
  30.     typedef bool( *decoder_t )( void const* source, uint32_t* charcode, size_t sourcesize, size_t* pointlength );
  31.  
  32.     struct encoding_t
  33.     {
  34.         encoder_t encode;
  35.         decoder_t decode;
  36.         encoding_t( encoder_t _encode, decoder_t _decode )
  37.             : encode( _encode )
  38.             , decode( _decode )
  39.         {
  40.         }
  41.     };
  42.  
  43.     namespace encoding
  44.     {
  45.         extern encoding_t const utf8;
  46.         extern encoding_t const utf16;
  47.         extern encoding_t const utf32;
  48.         extern encoding_t const utf16le;
  49.         extern encoding_t const utf16be;
  50.         extern encoding_t const utf32le;
  51.         extern encoding_t const utf32be;
  52.         enum indices {
  53.             index_utf8 = 0,
  54.             index_utf16 = 1,
  55.             index_utf32 = 2,
  56.             index_utf16le = 3,
  57.             index_utf16be = 4,
  58.             index_utf32le = 5,
  59.             index_utf32be = 6,
  60.         };
  61.     }
  62.  
  63.     struct translation_t
  64.     {
  65.         encoding_t const* senc;
  66.         encoding_t const* denc;
  67.         void const* source;
  68.         void* dest; // may be 0
  69.         size_t sourcesize; // if 0, source is null-terminated
  70.         size_t destsize; // same as with a decoder
  71.         uint32_t defaultchar; // if 0, stops the conversion immediately after a error
  72.             // if invalid, returns immediately
  73.         size_t sourceresult; // out
  74.         size_t destresult; // out
  75.     };
  76.  
  77.     int translatestr( translation_t* translation );
  78.  
  79.     enum
  80.     {
  81.         translate_success = 1,
  82.         translate_failure_source_overrun = 2,
  83.         translate_failure_source_corrupted = 3,
  84.         translate_failure_dest_unsupported = 4,
  85.         translate_failure_dest_overrun = 5,
  86.     };
  87.  
  88.     // C++ -> Lua boilerplate
  89.     // Pointers to these functions are stored in a specially defined struct, which is then passed to Lua state, which uses FFI (http://luajit.org/ext_ffi.html) to actually call them
  90.     extern "C"
  91.     {
  92.         encoding_t const* utils_encoding_getencoding( int index ) noexcept;
  93.         int utils_encoding_translatestr( translation_t* translation ) noexcept;
  94.     }
  95. }
  96.  
  97. #endif
  98.  
  99. ////////////////////////////////////////////////////////////////////////////////
  100.  
  101. #include "encoding.hpp"
  102. #include "cbase.hpp"
  103. #include <stdexcept>
  104.  
  105. namespace utils {
  106.     // returns the expected length of the code point, or 0 on error
  107.     // charcode may be 0
  108.     static inline size_t mbfirst( uint8_t ch, uint32_t* charcode )
  109.     {
  110.         uint32_t code;
  111.         size_t result;
  112.         if( ( ch & 0xe0 ) == 0xc0 )
  113.         {
  114.             code = ch & 0x1f;
  115.             result = 2;
  116.         }
  117.         else if( ( ch & 0xf0 ) == 0xe0 )
  118.         {
  119.             code = ch & 0xf;
  120.             result =  3;
  121.         }
  122.         else if( ( ch & 0xf8 ) == 0xf0 )
  123.         {
  124.             code = ch & 7;
  125.             result =  4;
  126.         }
  127.         else
  128.         {
  129.             return 0;
  130.         }
  131.         if( charcode )
  132.         {
  133.             *charcode = code;
  134.         }
  135.         return result;
  136.     }
  137.  
  138.     static bool utf8_encode( void* dest, uint32_t charcode, size_t destsize, size_t* pointlength )
  139.     {
  140.         size_t length;
  141.         if( charcode <= 0x7f )
  142.         {
  143.             length = 1;
  144.         }
  145.         else if( charcode <= 0x7ff )
  146.         {
  147.             length = 2;
  148.         }
  149.         else if( charcode <= 0xd7ff || ( charcode >= 0xe000 && charcode <= 0xffff ) )
  150.         {
  151.             length = 3;
  152.         }
  153.         else if( charcode <= 0x10ffff )
  154.         {
  155.             length = 4;
  156.         }
  157.         else
  158.         {
  159.             *pointlength = 0;
  160.             return false;
  161.         }
  162.         *pointlength = length;
  163.         if( dest )
  164.         {
  165.             if( destsize >= length )
  166.             {
  167.                 uint8_t* destw = ( uint8_t* )dest;
  168.                 if( length == 1 )
  169.                 {
  170.                     destw[ 0 ] = charcode;
  171.                 }
  172.                 else if( length == 2 )
  173.                 {
  174.                     destw[ 0 ] = 0xc0 | ( 0x1f & charcode >> 6 );
  175.                     destw[ 1 ] = 0x80 | ( 0x3f & charcode );
  176.                 }
  177.                 else if( length == 3 )
  178.                 {
  179.                     destw[ 0 ] = 0xe0 | ( 0xf & charcode >> 12 );
  180.                     destw[ 1 ] = 0x80 | ( 0x3f & charcode >> 6 );
  181.                     destw[ 2 ] = 0x80 | ( 0x3f & charcode );
  182.                 }
  183.                 else if( length == 4 )
  184.                 {
  185.                     destw[ 0 ] = 0xf0 | ( 7 & charcode >> 18 );
  186.                     destw[ 1 ] = 0x80 | ( 0x3f & charcode >> 12 );
  187.                     destw[ 2 ] = 0x80 | ( 0x3f & charcode >> 6 );
  188.                     destw[ 3 ] = 0x80 | ( 0x3f & charcode );
  189.                 }
  190.                 return true;
  191.             }
  192.             else
  193.             {
  194.                 return false;
  195.             }
  196.         }
  197.         else
  198.         {
  199.             return destsize == 0 || destsize >= length;
  200.         }
  201.         return false;
  202.     }
  203.  
  204.     static bool utf8_decode( void const* source, uint32_t* charcode, size_t sourcesize, size_t* pointlength )
  205.     {
  206.         uint8_t const* sourcew = ( uint8_t const* )source;
  207.         if( ( sourcew[ 0 ] & 0x80 ) == 0 )
  208.         {
  209.             if( charcode )
  210.             {
  211.                 *charcode = sourcew[ 0 ];
  212.             }
  213.             *pointlength = 1;
  214.             return true;
  215.         }
  216.         uint32_t code;
  217.         size_t length = mbfirst( sourcew[ 0 ], &code );
  218.         if( length == 0 )
  219.         {
  220.             *pointlength = 1;
  221.             return false;
  222.         }
  223.         else if( sourcesize != 0 && sourcesize < length )
  224.         {
  225.             *pointlength = 0;
  226.             return false;
  227.         }
  228.         for( size_t i = 1; i < length; ++i )
  229.         {
  230.             if( ( sourcew[ i ] & 0xc0 ) == 0x80 )
  231.             {
  232.                 code = code << 6 | ( 0x3f & sourcew[ i ] );
  233.             }
  234.             else
  235.             {
  236.                 *pointlength = i;
  237.                 return false;
  238.             }
  239.         }
  240.         *pointlength = length;
  241.         if( ( code >= 0xd800 && code <= 0xdfff ) || code > 0x10ffff )
  242.         {
  243.             return false;
  244.         }
  245.         if( charcode )
  246.         {
  247.             *charcode = code;
  248.         }
  249.         return true;
  250.     }
  251.  
  252.     static bool utf16_encode( void* dest, uint32_t charcode, size_t destsize, size_t* pointlength )
  253.     {
  254.         if( charcode <= 0xd7ff || ( charcode >= 0xe000 && charcode <= 0xffff ) )
  255.         {
  256.             *pointlength = 2;
  257.             if( dest )
  258.             {
  259.                 if( destsize >= 2 )
  260.                 {
  261.                     uint16_t* destw = ( uint16_t* )dest;
  262.                     destw[ 0 ] = charcode;
  263.                     return true;
  264.                 }
  265.                 else
  266.                 {
  267.                     return false;
  268.                 }
  269.             }
  270.             else
  271.             {
  272.                 return destsize != 1; // destsize == 0 || destsize >= 2;
  273.             }
  274.         }
  275.         else if( charcode <= 0x10ffff )
  276.         {
  277.             *pointlength = 4;
  278.             if( dest )
  279.             {
  280.                 if( destsize >= 4 )
  281.                 {
  282.                     uint16_t* destw = ( uint16_t* )dest;
  283.                     uint32_t value = charcode - 0x10000;
  284.                     destw[ 0 ] = ( value >> 10 ) | 0xd800;
  285.                     destw[ 1 ] = ( value & 0x3ff ) | 0xdc00;
  286.                     return true;
  287.                 }
  288.                 else
  289.                 {
  290.                     return false;
  291.                 }
  292.             }
  293.             else
  294.             {
  295.                 return destsize == 0 || destsize >= 4;
  296.             }
  297.         }
  298.         else
  299.         {
  300.             *pointlength = 0;
  301.             return false;
  302.         }
  303.     }
  304.  
  305.     static bool utf16_decode( void const* source, uint32_t* charcode, size_t sourcesize, size_t* pointlength )
  306.     {
  307.         if( sourcesize == 1 ) // sourcesize != 0 && sourcesize < 2
  308.         {
  309.             *pointlength = 0;
  310.             return false;
  311.         }
  312.         uint16_t const* sourcew = ( uint16_t const* )source;
  313.         uint16_t lead = sourcew[ 0 ];
  314.         if( lead >= 0xdc00 && lead <= 0xdfff )
  315.         {
  316.             *pointlength = 2;
  317.             return false;
  318.         }
  319.         else if( lead >= 0xd800 && lead <= 0xdbff )
  320.         {
  321.             if( sourcesize != 0 && sourcesize < 4 )
  322.             {
  323.                 *pointlength = 0;
  324.                 return false;
  325.             }
  326.             uint16_t low = sourcew[ 1 ];
  327.             if( low >= 0xdc00 && low <= 0xdfff )
  328.             {
  329.                 if( charcode )
  330.                 {
  331.                     low &= 0x3ff;
  332.                     uint32_t high = uint32_t( lead & 0x3ff ) << 10;
  333.                     *charcode = ( high | low ) + 0x10000;
  334.                 }
  335.                 *pointlength = 4;
  336.                 return true;
  337.             }
  338.             else
  339.             {
  340.                 *pointlength = 2;
  341.                 return false;
  342.             }
  343.         }
  344.         else
  345.         {
  346.             if( charcode )
  347.             {
  348.                 *charcode = lead;
  349.             }
  350.             *pointlength = 2;
  351.             return true;
  352.         }
  353.     }
  354.  
  355.     static bool utf32_encode( void* dest, uint32_t charcode, size_t destsize, size_t* pointlength )
  356.     {
  357.         if( ( charcode >= 0xd800 && charcode <= 0xdfff ) || charcode > 0x10ffff )
  358.         {
  359.             *pointlength = 0;
  360.             return false;
  361.         }
  362.         else
  363.         {
  364.             *pointlength = 4;
  365.             if( dest )
  366.             {
  367.                 if( destsize >= 4 )
  368.                 {
  369.                     uint32_t* destw = ( uint32_t* )dest;
  370.                     destw[ 0 ] = charcode;
  371.                     return true;
  372.                 }
  373.                 else
  374.                 {
  375.                     return false;
  376.                 }
  377.             }
  378.             else
  379.             {
  380.                 return destsize == 0 || destsize >= 4;
  381.             }
  382.         }
  383.     }
  384.  
  385.     static bool utf32_decode( void const* source, uint32_t* charcode, size_t sourcesize, size_t* pointlength )
  386.     {
  387.         if( sourcesize != 0 && sourcesize < 4 )
  388.         {
  389.             *pointlength = 0;
  390.             return false;
  391.         }
  392.         *pointlength = 4;
  393.         uint32_t const* sourcew = ( uint32_t const* )source;
  394.         uint32_t code = sourcew[ 0 ];
  395.         *pointlength = 4;
  396.         if( ( code >= 0xd800 && code <= 0xdfff ) || code > 0x10ffff )
  397.         {
  398.             return false;
  399.         }
  400.         if( charcode )
  401.         {
  402.             *charcode = code;
  403.         }
  404.         return true;
  405.     }
  406.  
  407.     template< int bl, int bh >
  408.     static bool utf16xe_encode( void* dest, uint32_t charcode, size_t destsize, size_t* pointlength )
  409.     {
  410.         if( dest )
  411.         {
  412.             uint16_t buffer[ 2 ];
  413.             size_t length;
  414.             bool success = utf16_encode( buffer, charcode, destsize, &length );
  415.             if( success )
  416.             {
  417.                 uint8_t* destw = ( uint8_t* )dest;
  418.                 destw[ bl ] = buffer[ 0 ];
  419.                 destw[ bh ] = buffer[ 0 ] >> 8;
  420.                 if( length == 4 )
  421.                 {
  422.                     destw[ 2 + bl ] = buffer[ 1 ];
  423.                     destw[ 2 + bh ] = buffer[ 1 ] >> 8;
  424.                 }
  425.             }
  426.             *pointlength = length;
  427.             return success;
  428.         }
  429.         else
  430.         {
  431.             return utf16_encode( 0, charcode, destsize, pointlength );
  432.         }
  433.     }
  434.  
  435.     template< int bl, int bh >
  436.     static bool utf16xe_decode( void const* source, uint32_t* charcode, size_t sourcesize, size_t* pointlength )
  437.     {
  438.         uint8_t const* sourcew = ( uint8_t const* )source;
  439.         uint16_t buffer[ 2 ];
  440.         if( sourcesize >= 2 )
  441.         {
  442.             buffer[ 0 ] = uint16_t( sourcew[ bl ] ) | uint16_t( sourcew[ bh ] << 8 );
  443.             if( buffer[ 0 ] >= 0xd800 && buffer[ 0 ] <= 0xdbff && sourcesize >= 4 )
  444.             {
  445.                 buffer[ 1 ] = uint16_t( sourcew[ 2 + bl ] ) | uint16_t( sourcew[ 2 + bh ] << 8 );
  446.             }
  447.         }
  448.         return utf16_decode( buffer, charcode, sourcesize, pointlength );
  449.     }
  450.  
  451.     template< int b1, int b2, int b3, int b4 >
  452.     static bool utf32xe_encode( void* dest, uint32_t charcode, size_t destsize, size_t* pointlength )
  453.     {
  454.         if( dest )
  455.         {
  456.             uint32_t buffer[ 1 ];
  457.             bool success = utf32_encode( buffer, charcode, destsize, pointlength );
  458.             if( success )
  459.             {
  460.                 uint8_t* destw = ( uint8_t* )dest;
  461.                 destw[ b1 ] = buffer[ 0 ];
  462.                 destw[ b2 ] = buffer[ 0 ] >> 8;
  463.                 destw[ b3 ] = buffer[ 0 ] >> 16;
  464.                 destw[ b4 ] = buffer[ 0 ] >> 24;
  465.             }
  466.             return success;
  467.         }
  468.         else
  469.         {
  470.             return utf32_encode( 0, charcode, destsize, pointlength );
  471.         }
  472.     }
  473.  
  474.     template< int b1, int b2, int b3, int b4 >
  475.     static bool utf32xe_decode( void const* source, uint32_t* charcode, size_t sourcesize, size_t* pointlength )
  476.     {
  477.         uint8_t const* sourcew = ( uint8_t const* )source;
  478.         uint32_t buffer[ 1 ];
  479.         if( sourcesize >= 4 )
  480.         {
  481.             buffer[ 0 ] =
  482.                 uint32_t( sourcew[ b1 ] ) |
  483.                 uint32_t( sourcew[ b2 ] << 8 ) |
  484.                 uint32_t( sourcew[ b3 ] << 16 ) |
  485.                 uint32_t( sourcew[ b4 ] << 24 );
  486.             return utf32_decode( buffer, charcode, sourcesize, pointlength );
  487.         }
  488.         else
  489.         {
  490.             return utf32_decode( 0, charcode, sourcesize, pointlength );
  491.         }
  492.     }
  493.  
  494.     namespace encoding
  495.     {
  496.         encoding_t const utf8( &utf8_encode, &utf8_decode );
  497.         encoding_t const utf16( &utf16_encode, &utf16_decode );
  498.         encoding_t const utf32( &utf32_encode, &utf32_decode );
  499. #if defined( _WIN32 ) || defined( _WIN64 )
  500.         encoding_t const utf16le( &utf16_encode, &utf16_decode );
  501.         encoding_t const utf32le( &utf32_encode, &utf32_decode );
  502. #else
  503.         encoding_t const utf16le( &utf16xe_encode< 0, 1 >, &utf16xe_decode< 0, 1 > );
  504.         encoding_t const utf32le( &utf32xe_encode< 0, 1, 2, 3 >, &utf32xe_decode< 0, 1, 2, 3 > );
  505. #endif
  506.         encoding_t const utf16be( &utf16xe_encode< 1, 0 >, &utf16xe_decode< 1, 0 > );
  507.         encoding_t const utf32be( &utf32xe_encode< 3, 2, 1, 0 >, &utf32xe_decode< 3, 2, 1, 0 > );
  508.     }
  509.  
  510.     enum
  511.     {
  512.         sourcesize_zterm = size_t( -1 ),
  513.     };
  514.  
  515.     int translatestr( translation_t* translation )
  516.     {
  517.         encoding_t const* senc = translation->senc;
  518.         encoding_t const* denc = translation->denc;
  519.         uint8_t const* source = ( uint8_t const* )translation->source;
  520.         uint8_t* dest = ( uint8_t* )translation->dest;
  521.         size_t sourcesize = translation->sourcesize;
  522.         if( sourcesize == 0 )
  523.         {
  524.             sourcesize = sourcesize_zterm;
  525.         }
  526.         size_t destsize = translation->destsize;
  527.         uint32_t defaultchar = translation->defaultchar;
  528.         size_t sourceresult = 0;
  529.         size_t destresult = 0;
  530.         int resultcode = translate_success;
  531.         while( sourcesize != 0 )
  532.         {
  533.             uint32_t charcode;
  534.             size_t spointlength;
  535.             if( !senc->decode( source, &charcode, sourcesize == sourcesize_zterm ? 0 : sourcesize, &spointlength ) )
  536.             {
  537.                 if( spointlength == 0 )
  538.                 {
  539.                     resultcode = translate_failure_source_overrun;
  540.                     break;
  541.                 }
  542.                 else
  543.                 {
  544.                     if( defaultchar == 0 )
  545.                     {
  546.                         resultcode = translate_failure_source_corrupted;
  547.                         break;
  548.                     }
  549.                     else
  550.                     {
  551.                         charcode = defaultchar;
  552.                     }
  553.                 }
  554.             }
  555.             source += spointlength;
  556.             if( sourcesize != sourcesize_zterm )
  557.             {
  558.                 sourcesize -= spointlength;
  559.             }
  560.             size_t dpointlength;
  561.             if( !denc->encode( dest, charcode, destsize, &dpointlength ) )
  562.             {
  563.                 if( dpointlength == 0 )
  564.                 {
  565.                     resultcode = translate_failure_dest_unsupported;
  566.                     break;
  567.                 }
  568.                 else
  569.                 {
  570.                     resultcode = translate_failure_dest_overrun;
  571.                     break;
  572.                 }
  573.             }
  574.             if( dest )
  575.             {
  576.                 dest += dpointlength;
  577.             }
  578.             if( destsize != 0 )
  579.             {
  580.                 destsize -= dpointlength;
  581.             }
  582.             sourceresult += spointlength;
  583.             destresult += dpointlength;
  584.             if( sourcesize == sourcesize_zterm && charcode == 0 )
  585.             {
  586.                 break;
  587.             }
  588.         }
  589.         translation->sourceresult = sourceresult;
  590.         translation->destresult = destresult;
  591.         return resultcode;
  592.     }
  593.  
  594.     static encoding_t const* encoding_table[] =
  595.     {
  596.         &encoding::utf8,
  597.         &encoding::utf16,
  598.         &encoding::utf32,
  599.         &encoding::utf16le,
  600.         &encoding::utf16be,
  601.         &encoding::utf32le,
  602.         &encoding::utf32be,
  603.     };
  604.  
  605.     // Defined in "cbase.hpp", CBASE_PROTECT surrounds its argument with special code which catches exceptions and presents them in a form available to Lua
  606.     extern "C"
  607.     {
  608.         encoding_t const* utils_encoding_getencoding( int index ) noexcept
  609.         {
  610.         CBASE_PROTECT(
  611.             if( index < 0 || index >= int( sizeof( encoding_table ) / sizeof( encoding_table[ 0 ] ) ) )
  612.             {
  613.                 throw std::runtime_error( "invalid encoding index" );
  614.             }
  615.             return encoding_table[ index ];
  616.         )
  617.         }
  618.  
  619.         int utils_encoding_translatestr( translation_t* translation ) noexcept
  620.         {
  621.         CBASE_PROTECT(
  622.             return translatestr( translation );
  623.         )
  624.         }
  625.     }
  626. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement