| /****************************************************************************** | |
| @File PVRTUnicode.cpp | |
| @Title PVRTUnicode | |
| @Version @Version | |
| @Copyright Copyright (c) Imagination Technologies Limited. | |
| @Platform All | |
| @Description A small collection of functions used to decode Unicode formats to | |
| individual code points. | |
| ******************************************************************************/ | |
| #include "PVRTUnicode.h" | |
| #include <string.h> | |
| /**************************************************************************** | |
| ** Constants | |
| ****************************************************************************/ | |
| const PVRTuint32 c_u32ReplChar = 0xFFFD; | |
| #define VALID_ASCII 0x80 | |
| #define TAIL_MASK 0x3F | |
| #define BYTES_PER_TAIL 6 | |
| #define UTF16_SURG_H_MARK 0xD800 | |
| #define UTF16_SURG_H_END 0xDBFF | |
| #define UTF16_SURG_L_MARK 0xDC00 | |
| #define UTF16_SURG_L_END 0xDFFF | |
| #define UNICODE_NONCHAR_MARK 0xFDD0 | |
| #define UNICODE_NONCHAR_END 0xFDEF | |
| #define UNICODE_RESERVED 0xFFFE | |
| #define UNICODE_MAX 0x10FFFF | |
| #define MAX_LEN 0x8FFF | |
| /**************************************************************************** | |
| ** A table which allows quick lookup to determine the number of bytes of a | |
| ** UTF8 code point. | |
| ****************************************************************************/ | |
| const PVRTuint8 c_u8UTF8Lengths[256] = | |
| { | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, | |
| 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, | |
| 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, | |
| 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, | |
| 3,3,3,3,3,3,3,3,0,0,0,0,0,0,0,0, | |
| }; | |
| /**************************************************************************** | |
| ** A table which allows quick lookup to determine whether a UTF8 sequence | |
| ** is 'overlong'. | |
| ****************************************************************************/ | |
| const PVRTuint32 c_u32MinVals[4] = | |
| { | |
| 0x00000000, // 0 tail bytes | |
| 0x00000080, // 1 tail bytes | |
| 0x00000800, // 2 tail bytes | |
| 0x00010000, // 3 tail bytes | |
| }; | |
| /*!*************************************************************************** | |
| @Function CheckGenericUnicode | |
| @Input c32 A UTF32 character/Unicode code point | |
| @Returns Success or failure. | |
| @Description Checks that the decoded code point is valid. | |
| *****************************************************************************/ | |
| static bool CheckGenericUnicode(PVRTuint32 c32) | |
| { | |
| // Check that this value isn't a UTF16 surrogate mask. | |
| if(c32 >= UTF16_SURG_H_MARK && c32 <= UTF16_SURG_L_END) | |
| return false; | |
| // Check non-char values | |
| if(c32 >= UNICODE_NONCHAR_MARK && c32 <= UNICODE_NONCHAR_END) | |
| return false; | |
| // Check reserved values | |
| if((c32 & UNICODE_RESERVED) == UNICODE_RESERVED) | |
| return false; | |
| // Check max value. | |
| if(c32 > UNICODE_MAX) | |
| return false; | |
| return true; | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTUnicodeUTF8ToUTF32 | |
| @Input pUTF8 A UTF8 string, which is null terminated. | |
| @Output aUTF32 An array of Unicode code points. | |
| @Returns Success or failure. | |
| @Description Decodes a UTF8-encoded string in to Unicode code points | |
| (UTF32). If pUTF8 is not null terminated, the results are | |
| undefined. | |
| *****************************************************************************/ | |
| EPVRTError PVRTUnicodeUTF8ToUTF32(const PVRTuint8* const pUTF8, CPVRTArray<PVRTuint32>& aUTF32) | |
| { | |
| unsigned int uiTailLen, uiIndex; | |
| unsigned int uiBytes = (unsigned int) strlen((const char*)pUTF8); | |
| PVRTuint32 c32; | |
| const PVRTuint8* pC = pUTF8; | |
| while(*pC) | |
| { | |
| // Quick optimisation for ASCII characters | |
| while(*pC && *pC < VALID_ASCII) | |
| { | |
| aUTF32.Append(*pC++); | |
| } | |
| // Done | |
| if(!*pC) | |
| break; | |
| c32 = *pC++; | |
| uiTailLen = c_u8UTF8Lengths[c32]; | |
| // Check for invalid tail length. Maximum 4 bytes for each UTF8 character. | |
| // Also check to make sure the tail length is inside the provided buffer. | |
| if(uiTailLen == 0 || (pC + uiTailLen > pUTF8 + uiBytes)) | |
| return PVR_OVERFLOW; | |
| c32 &= (TAIL_MASK >> uiTailLen); // Get the data out of the first byte. This depends on the length of the tail. | |
| // Get the data out of each tail byte | |
| uiIndex = 0; | |
| while(uiIndex < uiTailLen) | |
| { | |
| if((pC[uiIndex] & 0xC0) != 0x80) | |
| return PVR_FAIL; // Invalid tail byte! | |
| c32 = (c32 << BYTES_PER_TAIL) + (pC[uiIndex] & TAIL_MASK); | |
| uiIndex++; | |
| } | |
| pC += uiIndex; | |
| // Check overlong values. | |
| if(c32 < c_u32MinVals[uiTailLen]) | |
| return PVR_FAIL; | |
| if(!CheckGenericUnicode(c32)) | |
| return PVR_FAIL; | |
| // OK | |
| aUTF32.Append(c32); | |
| } | |
| return PVR_SUCCESS; | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTUnicodeUTF16ToUTF32 | |
| @Input pUTF16 A UTF16 string, which is null terminated. | |
| @Output aUTF32 An array of Unicode code points. | |
| @Returns Success or failure. | |
| @Description Decodes a UTF16-encoded string in to Unicode code points | |
| (UTF32). If pUTF16 is not null terminated, the results are | |
| undefined. | |
| *****************************************************************************/ | |
| EPVRTError PVRTUnicodeUTF16ToUTF32(const PVRTuint16* const pUTF16, CPVRTArray<PVRTuint32>& aUTF32) | |
| { | |
| const PVRTuint16* pC = pUTF16; | |
| // Determine the number of shorts | |
| while(*++pC && (pC - pUTF16) < MAX_LEN); | |
| unsigned int uiBufferLen = (unsigned int) (pC - pUTF16); | |
| if(uiBufferLen == MAX_LEN) | |
| return PVR_OVERFLOW; // Probably not NULL terminated. | |
| // Reset to start. | |
| pC = pUTF16; | |
| PVRTuint32 c32; | |
| while(*pC) | |
| { | |
| // Straight copy. We'll check for surrogate pairs next... | |
| c32 = *pC++; | |
| // Check surrogate pair | |
| if(c32 >= UTF16_SURG_H_MARK && c32 <= UTF16_SURG_H_END) | |
| { | |
| // Make sure the next 2 bytes are in range... | |
| if(pC + 1 > pUTF16 + uiBufferLen || *pC == 0) | |
| return PVR_OVERFLOW; | |
| // Check that the next value is in the low surrogate range | |
| if(*pC < UTF16_SURG_L_MARK || *pC > UTF16_SURG_L_END) | |
| return PVR_FAIL; | |
| // Decode | |
| c32 = ((c32 - UTF16_SURG_H_MARK) << 10) + (*pC - UTF16_SURG_L_MARK) + 0x10000; | |
| pC++; | |
| } | |
| if(!CheckGenericUnicode(c32)) | |
| return PVR_FAIL; | |
| // OK | |
| aUTF32.Append(c32); | |
| } | |
| return PVR_SUCCESS; | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTUnicodeUTF8Length | |
| @Input pUTF8 A UTF8 string, which is null terminated. | |
| @Returns The length of the string, in Unicode code points. | |
| @Description Calculates the length of a UTF8 string. If pUTF8 is | |
| not null terminated, the results are undefined. | |
| *****************************************************************************/ | |
| unsigned int PVRTUnicodeUTF8Length(const PVRTuint8* const pUTF8) | |
| { | |
| const PVRTuint8* pC = pUTF8; | |
| unsigned int charCount = 0; | |
| unsigned int mask; | |
| while(*pC) | |
| { | |
| // Quick optimisation for ASCII characters | |
| const PVRTuint8* pStart = pC; | |
| while(*pC && *pC < VALID_ASCII) | |
| pC++; | |
| charCount += (unsigned int) (pC - pStart); | |
| // Done | |
| if(!*pC) | |
| break; | |
| mask = *pC & 0xF0; | |
| switch(mask) | |
| { | |
| case 0xF0: pC++; | |
| case 0xE0: pC++; | |
| case 0xC0: pC++; | |
| break; | |
| default: | |
| _ASSERT(!"Invalid tail byte!"); | |
| return 0; | |
| } | |
| pC++; | |
| charCount++; | |
| } | |
| return charCount; | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTUnicodeUTF16Length | |
| @Input pUTF16 A UTF16 string, which is null terminated. | |
| @Returns The length of the string, in Unicode code points. | |
| @Description Calculates the length of a UTF16 string. | |
| If pUTF16 is not null terminated, the results are | |
| undefined. | |
| *****************************************************************************/ | |
| unsigned int PVRTUnicodeUTF16Length(const PVRTuint16* const pUTF16) | |
| { | |
| const PVRTuint16* pC = pUTF16; | |
| unsigned int charCount = 0; | |
| while(*pC && (pC - pUTF16) < MAX_LEN) | |
| { | |
| if( pC[0] >= UTF16_SURG_H_MARK && pC[0] <= UTF16_SURG_H_END | |
| && pC[1] >= UTF16_SURG_L_MARK && pC[0] <= UTF16_SURG_L_END) | |
| { | |
| pC += 2; | |
| } | |
| else | |
| { | |
| pC += 1; | |
| } | |
| charCount++; | |
| } | |
| return charCount; | |
| } | |
| /*!*************************************************************************** | |
| @Function PVRTUnicodeValidUTF8 | |
| @Input pUTF8 A UTF8 string, which is null terminated. | |
| @Returns true or false | |
| @Description Checks whether the encoding of a UTF8 string is valid. | |
| If pUTF8 is not null terminated, the results are undefined. | |
| *****************************************************************************/ | |
| bool PVRTUnicodeValidUTF8(const PVRTuint8* const pUTF8) | |
| { | |
| unsigned int uiTailLen, uiIndex; | |
| unsigned int uiBytes = (unsigned int) strlen((const char*)pUTF8); | |
| const PVRTuint8* pC = pUTF8; | |
| while(*pC) | |
| { | |
| // Quick optimisation for ASCII characters | |
| while(*pC && *pC < VALID_ASCII) pC++; | |
| // Done? | |
| if(!*pC) | |
| break; | |
| PVRTuint32 c32 = *pC++; | |
| uiTailLen = c_u8UTF8Lengths[c32]; | |
| // Check for invalid tail length. Maximum 4 bytes for each UTF8 character. | |
| // Also check to make sure the tail length is inside the provided buffer. | |
| if(uiTailLen == 0 || (pC + uiTailLen > pUTF8 + uiBytes)) | |
| return false; | |
| // Get the data out of each tail byte | |
| uiIndex = 0; | |
| while(uiIndex < uiTailLen) | |
| { | |
| if((pC[uiIndex] & 0xC0) != 0x80) | |
| return false; // Invalid tail byte! | |
| c32 = (c32 << BYTES_PER_TAIL) + (pC[uiIndex] & TAIL_MASK); | |
| uiIndex++; | |
| } | |
| pC += uiIndex; | |
| // Check overlong values. | |
| if(c32 < c_u32MinVals[uiTailLen]) | |
| return false; | |
| if(!CheckGenericUnicode(c32)) | |
| return false; | |
| } | |
| return true; | |
| } | |
| /***************************************************************************** | |
| End of file (PVRTUnicode.cpp) | |
| *****************************************************************************/ | |