| I first saw the term "UTF8" when I was learning Cocoa 
    programming for Mac OSX. It appeared to me that Cocoa was using term UTF8 
    for char *; I thought that UTF8 was just a new name for the ASCII code. We 
    used to call 8-bit text as ASCII text. Win32 API later started calling it 
    ANSI. I was not keeping track of what happened to ASCII. I thought Apple 
    just wanted to give it a different name for it. In Cocoa, NSString class 
    represents a text string, and it internally stores a string in Unicode. It 
    has a function that converts NSString to UTF8 string. I wondered what was 
    going to happen if I converted an NSString that includes multi-byte 
    characters into UTF8 string and then converted it back to NSString.  
    The following test code can be compiled from Terminal by typing: g++ conv.m 
    -framework Cocoa 
      List: conv.m 
        
          | #import <Cocoa/Cocoa.h>
int main(void)
{
    int i;
    NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
    unsigned char utf16[]={0x5c,0x71,0x5d,0xdd,0x03,0xc0,0x00,'A',0x03,0x94,0,0};
    NSString *rawString=[[NSString alloc] 
          initWithBytes:utf16 
          length:10 
          encoding:NSUTF16BigEndianStringEncoding];
    printf("Original Unicode:\n");
    for(i=0; i<[rawString length]; i++)
    {
        printf("%04x ",[rawString characterAtIndex:i]);
    }
    printf("\n");
    const char *utf8=[rawString UTF8String];
    // You will see two kanji characters, greek letter pi, alphabet A, and greek 
    // letter Delta, if the terminal supports UTF8.
    printf("UTF8: %s\n",utf8);
    for(i=0; 0!=utf8[i]; i++)
    {
        int c=utf8[i];
        c&=0xff;
        printf("%02x ",c);
    }
    printf("\n");
    printf("Recovered Unicode:\n");
    NSString *verifyString=[[NSString alloc] initWithUTF8String:utf8];
    for(i=0; i<[verifyString length]; i++)
    {
        printf("%04x ",[verifyString characterAtIndex:i]);
    }
    printf("\n");
    [rawString release];
    [verifyString release];
    [pool release];
    return 0;
} |  To my surprise, NSString translated Kanji characters (which are clearly 
    multi-byte characters) into strange code, and it was able to convert it back 
    to NSString without loss. Wow! That was great. I didn't have to do something 
    special for dealing with non-English characters. But, I was still thinking 
    it was Apple's original extension. By the way, I am using a sort of brute-force method to localize YSFLIGHT. 
    I am storing all the UI messages in PNG bitmap files. I used to make each 
    PNG bitmap by Paint Brush, but it was becoming too painful. I decided to 
    make a program that reads a text file with PNG file names and messages and 
    outputs UI PNG files. I was working on Japanese localization of YSFLIGHT 
    Scenery Editor, and I didn't want to make all the PNG bitmap files by hand. I didn't have to make this program cross platform. Once I make UI bitmaps 
    on Windows, I could use them in Mac OSX and Linux. I didn't want to spend 
    too much time on this program, so initially I really did a quick-and-dirty 
    programming with no effort to make it cross platform. But, later I thought 
    that since there are such strong YSFLIGHT user communities, if I make this 
    program available, they may generate localization files for many other 
    languages. So, I made it less dirty and re-wrote some part. In process of cleaning my program, I reviewed my code used in Blue 
    Impulse 3D Graphics SDK, which I developed through my master's research 
    project. I had been thinking that if I were able to write a class that 
    generated an off-screen bitmap from a Unicode text, I could use it 
    everywhere. Here's what I recalled from my old code. To create an off-screen bitmap 
    (called Device Independent Bitmap or DIB) in Windows, I needed to use a 
    function called CreateCompatibleDC, but I needed to pass a valid 
    Device-Context handle to CreateCompatibleDC, and to get a valid 
    Device-Context handle, I had to create a window. As far as I remembered, 
    CreateCompatibleDC used to crash if I gave a NULL pointer as a source 
    Device-Context handle. The problem was, as soon as I needed a window, I 
    either needed to get the main Window handle from the application, or I 
    needed to create a dummy window. If I use the main Window handle from the 
    application, the application becomes Windows dependent. I need to assume 
    that the program has a main window, which is not good in many ways. If I 
    make a dummy window, I can keep the window hidden (SW_HIDE state), and keep 
    the presence of my dummy window secret from the user. But, it didn't seem to 
    me a nice clean solution. But, nowadays necessity of the off-screen bitmap 
    is much higher than before. Win32 API might have been changed so that 
    CreateCompatibleDC can take a NULL pointer. I went to MSDN, and searched for 
    CreateCompatibleDC. I made a good guess! CreateCompatibleDC can now take a NULL pointer and 
    creates a memory device context. I don't know when Microsoft made this 
    change. At least I remembered the program crashed when I was programming in 
    Windows 3.1. I couldn't give NULL pointer as a source Device-Context handle 
    to CreateCompatibleDC. Maybe I was wrong.  My program might have been 
    crashing for the different purpose, and for some reason it didn't crash when 
    I gave a non-NULL pointer to CreateCompatibleDC.  I don't have Windows 
    3.1 PC any more and cannot verify whether I was really not able to give NULL 
    pointer to CreateCompatibleDC. That time Game SDK was called WinG. I was fully expecting that WinG was 
    going to support 3D graphics and was utterly disappointed because it didn't. 
    Nonetheless, support for game programming lead to the dominance of Windows 
    95 and 98. It was mid 1990s and Unix people and Mac people were thinking 
    gaming was ignoble. They were essentially on denial. They thought that 
    computing was for royal purposes such as scientific calculation. Watching 
    videos, playing music, and 3D graphics were all dirty technologies for them. 
    Mac was a little different from Unix though. In my impression, Apple liked 
    some multi-media stuff, but they were thinking desktop publishing was 
    everything. It was hell difficult to write a game program in Mac OS then. 
    That's how they lost Microsoft. Things are so much different now as you 
    know. Microsoft is slowly losing the dominance, and Apple has the momentum. 
    And, Linux is .... slightly better. At least I can install Ubuntu by myself. 
    Anyways, it's not a main topic of this page. So, I realized that I could write a program that creates an off-screen 
    bitmap and draws a Unicode characters and returns the array of bitmaps. So, 
    I wrote a simple test program as follows. You can compile from Visual Studio 
    command prompt as: 
      cl font.cpp kernel32.lib user32.lib gdi32.lib List: font.cpp 
        
          | // cl font.cpp kernel32.lib user32.lib gdi32.lib
//   or
// cl font.cpp kernel32.lib user32.lib gdi32.lib /DUNICODE <- This way this code can be checked against default-unicode environment.
#include <windows.h>
#include <stdio.h>
#include <string.h>
static int CALLBACK EnumFontFamExProc(
    const LOGFONTA *fontInfo,
    const TEXTMETRICA *textMetric,
    DWORD fontType,
    LPARAM lParam)
{
    printf("%s\n",fontInfo->lfFaceName);
    return 1;
}
void EnumerateFont(HDC hDC)
{
    LOGFONTA fontInfo;
    fontInfo.lfCharSet=DEFAULT_CHARSET;
    fontInfo.lfFaceName[0]=0;
    fontInfo.lfPitchAndFamily=0;
    EnumFontFamiliesExA(hDC,&fontInfo,EnumFontFamExProc,(LPARAM)0,0);
}
int main(void)
{
    HDC hDC=CreateCompatibleDC(NULL);
    EnumerateFont(hDC);
    LOGFONTW logFont;
    ZeroMemory(&logFont,sizeof(logFont));
    logFont.lfHeight=-12; // 12 pixels (Positive 12 for 12 points)
    logFont.lfWeight=FW_DONTCARE;
    logFont.lfCharSet=DEFAULT_CHARSET;
    logFont.lfOutPrecision=OUT_TT_PRECIS;
    logFont.lfClipPrecision=CLIP_DEFAULT_PRECIS;
    logFont.lfQuality=DEFAULT_QUALITY;
    logFont.lfPitchAndFamily=DEFAULT_PITCH;
    wcscpy(logFont.lfFaceName,L"Arial"); // Up to LF_FACESIZE chars.
    HFONT hFont=CreateFontIndirectW(&logFont);
    HGDIOBJ hPrevFont=NULL;
    if(NULL!=hFont)
    {
        printf("Font Created.\n");
        hPrevFont=SelectObject(hDC,(HGDIOBJ)hFont);
    }
    RECT rect;
    rect.left=0;
    rect.top=0;
    rect.right=100;
    rect.bottom=100;
    SetTextAlign(hDC,TA_LEFT|TA_TOP|TA_NOUPDATECP);  // Prerequisite for DrawTextEx
    wchar_t str[]={0x5c71,0x5ddd,0x03c0,'A',0x0394,0};
    DrawTextExW(hDC,str,4,&rect,DT_TOP|DT_LEFT|DT_CALCRECT,NULL);
    const int wid=rect.right;
    const int hei=rect.bottom;
    const int bitPerPixel=24;
    printf("Width=%d Height=%d\n",wid,hei);
    BITMAPINFOHEADER hdr=
    {
        sizeof(BITMAPINFOHEADER),
        0,0,1,8,BI_RGB,0,0,0,0,0
    };
    hdr.biWidth=wid;
    hdr.biHeight=-hei;
    hdr.biBitCount=bitPerPixel;
    hdr.biCompression=BI_RGB;
    void *bit;
    HBITMAP hBmp=CreateDIBSection(hDC,(BITMAPINFO *)&hdr,DIB_RGB_COLORS,&bit,NULL,0);
    HGDIOBJ hPrevBmp;
    hPrevBmp=SelectObject(hDC,hBmp);
    int bytePerLine=((wid+3)/4)*4*bitPerPixel/8;
    unsigned char *dat=(unsigned char *)bit;
    int i;
    for(i=0; i<bytePerLine*hei; i++)
    {
        dat[i]=0;
    }
    SetTextColor(hDC,RGB(255,255,255));
    SetBkColor(hDC,RGB(0,0,0));
    SetBkMode(hDC,OPAQUE);
    SetDCPenColor(hDC,RGB(255,0,0));
    rect.left=0;
    rect.top=0;
    rect.right=wid;
    rect.bottom=hei;
    DrawTextExW(hDC,str,4,&rect,DT_TOP|DT_LEFT,NULL);
    int x,y;
    unsigned char *lineTop=dat;
    for(y=0; y<hei; y++)
    {
        for(x=0; x<wid; x++)
        {
            if(0!=lineTop[x*3])
            {
                printf("1");
            }
            else
            {
                printf("0");
            }
        }
        lineTop+=bytePerLine;
        printf("\n");
    }
    if(NULL!=hPrevFont)
    {
        printf("Reset font.\n");
        SelectObject(hDC,hPrevFont);
    }
    if(NULL!=hPrevBmp)
    {
        printf("Reset bmp.\n");
        SelectObject(hDC,hPrevBmp);
    }
    DeleteObject(hBmp);
    DeleteDC(hDC);
    return 0;
} |  Then I needed to do the same on Mac OSX and Linux to support majority of 
    the popular operating systems. It was easy on Mac OSX. It took a while to 
    see the resolution (DPI) of NSBitmapImageRep, but I later realized that it 
    was by default 1 pixel == 1 point. I think it is a common struggle for 
    programmers that we need to specify the font size by points not pixels no 
    matter where you are writing your font. It makes sense to specify font size 
    by pixels when I am writing font on the monitor. But, since default 
    NSBitmapImageRep's resolution is 72 DPI, I didn't have to worry about point 
    to pixel unit conversion. Another issue was the usage of NSAttributedString. 
    For this, sample codes in "Cocoa & Objective-C: Up and Running" (Scott 
    Stevenson, O'Reilly) around page 360 helped me a lot. You can compile the 
    following sample code by: 
      g++ font.m –framework Cocoa List: font.m 
        
          | #import <Cocoa/Cocoa.h>
int main(void)
{
    NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
    NSFontManager *fontManager=[NSFontManager sharedFontManager];
    if(NULL==fontManager)
    {
        printf("No font manager is present.\n");
    }
    else
    {
        NSArray *availableFonts=[fontManager availableFonts];
        int i;
        for(i=0; i<[availableFonts count]; i++)
        {
            NSString *str=[availableFonts objectAtIndex:i];
            printf("[%d] %s\n",i,[str UTF8String]);
        }
    }
    float fontSize=20.0f;
    NSFont *font=[NSFont fontWithName:@"Times-Roman" size:fontSize];
    NSMutableParagraphStyle *parag=[[NSMutableParagraphStyle alloc] init];
    [parag setMaximumLineHeight:fontSize];
    printf("line spacing %f\n",[[NSParagraphStyle defaultParagraphStyle] lineSpacing]);
    printf("paragraph spacing %f\n",[[NSParagraphStyle defaultParagraphStyle] paragraphSpacing]);
    printf("paragraph spacing before %f\n",[[NSParagraphStyle defaultParagraphStyle] paragraphSpacingBefore]);
    printf("minimum line height %f\n",[[NSParagraphStyle defaultParagraphStyle] minimumLineHeight]);
    printf("maximum line height %f\n",[[NSParagraphStyle defaultParagraphStyle] maximumLineHeight]);
    printf("line height multiplet %f\n",[[NSParagraphStyle defaultParagraphStyle] lineHeightMultiple]);
    NSRect rect;
    NSMutableDictionary *attributes=[NSMutableDictionary dictionary];
    [attributes setObject:font forKey:NSFontAttributeName];
    [attributes setObject:[NSNumber numberWithFloat:0.0] forKey:NSKernAttributeName];
    [attributes setObject:parag forKey:NSParagraphStyleAttributeName];
    [attributes setObject:[NSColor whiteColor] forKey:NSForegroundColorAttributeName];
    [attributes setObject:[NSColor blackColor] forKey:NSBackgroundColorAttributeName];
    unsigned char utf16[]={0x5c,0x71,0x5d,0xdd,0x03,0xc0,0x00,'A',0x03,0x94,0,0};
    NSString *rawString=[[NSString alloc] initWithBytes:utf16 length:10 encoding:NSUTF16BigEndianStringEncoding];
    NSAttributedString *string=[[NSAttributedString alloc] initWithString:rawString attributes:attributes];
    NSSize stringSize=[string size];
    printf("Size %f %f\n",stringSize.width,stringSize.height);
    NSBitmapImageRep *bmpImg=[[NSBitmapImageRep alloc] 
         initWithBitmapDataPlanes:NULL
         pixelsWide:(int)stringSize.width
         pixelsHigh:(int)stringSize.height
         bitsPerSample:8 // 8 bit per component
         samplesPerPixel:3 // 3 components
         hasAlpha:NO
         isPlanar:NO
         colorSpaceName:NSDeviceRGBColorSpace
         bytesPerRow:0
         bitsPerPixel:32];
    // The following commented-out block is optional since the resolution of 
    // a bitmap seems tobe 72 DPI by default, which makes 1 pixel per 1 point.
    /* int pixelsWide=[bmpImg pixelsWide],pixelsHigh=[bmpImg pixelsHigh];
    printf("BMP Pix =%d %d\n",pixelsWide,pixelsHigh);
    NSSize sizeInPoint={pixelsWide,pixelsHigh};
    [bmpImg setSize:sizeInPoint]; // This makes 1 point per pixel
    sizeInPoint=[bmpImg size];
    printf("BMP Size=%f %f\n",sizeInPoint.width,sizeInPoint.height); */
    NSGraphicsContext *gc=[NSGraphicsContext 
              graphicsContextWithBitmapImageRep:bmpImg];
    NSGraphicsContext *prevGc=[NSGraphicsContext currentContext];
    [NSGraphicsContext setCurrentContext:gc];
    [gc setShouldAntialias:NO];
    [[NSColor darkGrayColor] set];
    rect.origin.x=0;
    rect.origin.y=0;
    rect.size.width=stringSize.width;
    rect.size.height=stringSize.height;
    NSRectFill(rect);
    [[NSColor whiteColor] set];
    rect.origin.x=0;
    rect.origin.y=0;
    rect.size.width=stringSize.width;
    rect.size.height=stringSize.height;
    [string drawWithRect:rect options:NSStringDrawingUsesLineFragmentOrigin];
    unsigned char *dat=[bmpImg bitmapData];
    unsigned int bytesPerRow=[bmpImg bytesPerRow];
    printf("bytesPerRow %d\n",bytesPerRow);
    int y;
    for(y=0; y<(int)stringSize.height; y++)
    {
        int x;
        for(x=0; x<(int)stringSize.width; x++)
        {
            if(0==dat[y*bytesPerRow+x*4])
            {
                printf("0");
            }
            else
            {
                printf("1");
            }
        }
        printf("\n");
    }
    [NSGraphicsContext setCurrentContext:prevGc];
    [parag release];
    [string release];
    [rawString release];
    [bmpImg release];
    [pool release];
    return 0;
} |  It appeared that I was getting closer to terminate my brute-force (PNG 
    based) localization soon. But, the problem was Unicode. I thought there were 
    no standardized Unicode text-file format. I remembered that my favorite text editor gave me a choice of text 
    encoding like EUC, Shift-JIS (both are for Japanese characters), and 
    Unicode. I got curious what kind of binary I would get if I choose Unicode 
    as text encoding. I opened up the text editor, and chose "Save As", and 
    opened the "Encoding" drop list. Then I saw "Unicode (UTF-8)". What? UTF-8 
    is supposed to be 8-bit encoding. How can it store multi-byte characters? 
    .... Suddenly the strange code from [NSString UTF8String] flashed back, and 
    I understood what they were. That was not Apple's original extension. UTF8 
    was a standard encoding for a Unicode text. I felt I was too far away from 
    the localization business too long.  Then I searched on Wikipedia and 
    found how I could convert wchar to/from UTF8. (http://en.wikipedia.org/wiki/UTF-8). 
    It's easy. I could write two-way converter in a few minutes. 
      List: Sample UTF8 <-> WChar conversion functions. 
        
          | #include <stdio.h>
// Reference: http://en.wikipedia.org/wiki/UTF-8
template <class WCHAR_TYPE>
size_t UnicodeWChar2UTF8(size_t lOut,char out[],WCHAR_TYPE in[])
{
    unsigned int iPtr=0,oPtr=0;
    unsigned char *uOut=(unsigned char *)out;
    while(oPtr<lOut-1 && 0!=in[iPtr])
    {
        if(in[iPtr]<=0x7f)
        {
            uOut[oPtr]=(unsigned char)in[iPtr];
            oPtr++;
        }
        else if(in[iPtr]<=0x7ff)
        {
            if(lOut-2<=oPtr)
            {
                // Buffer overrun.  Cannot put zero at the end.
                break;
            }
            unsigned int low6=in[iPtr]&0x3f;
            unsigned int high5=(in[iPtr]>>6)&0x1f;
            uOut[oPtr++]=(unsigned char)(0xc0|high5);
            uOut[oPtr++]=(unsigned char)(0x80|low6);
        }
        else if(in[iPtr]<=0xffff)
        {
            if(lOut-3<=oPtr)
            {
                // Buffer overrun.  Cannot put zero at the end.
                break;
            }
            unsigned int low6=in[iPtr]&0x3f;
            unsigned int mid6=(in[iPtr]>>6)&0x3f;
            unsigned int high4=(in[iPtr]>>12)&0x0f;
            uOut[oPtr++]=(unsigned char)(0xe0|high4);
            uOut[oPtr++]=(unsigned char)(0x80|mid6);
            uOut[oPtr++]=(unsigned char)(0x80|low6);
        }
        else // The following block will never be used unless wchar_t is greater than 16-bit.
        {
            unsigned long inChar=in[iPtr];
            unsigned int bit00to05=inChar&0x3f;
            unsigned int bit06to11=(inChar>>6)&0x3f;
            unsigned int bit12to17=(inChar>>12)&0x3f;
            unsigned int bit18to23=(inChar>>18)&0x3f;
            unsigned int bit24to29=(inChar>>24)&0x3f;
            unsigned int bit30=(inChar>>30)&0x01;
            if(in[iPtr]<=0x1fffff)
            {
                if(lOut-4<=oPtr)
                {
                    // Buffer overrun.  Cannot put zero at the end.
                    break;
                }
                uOut[oPtr++]=(unsigned char)(0xf0|(bit18to23&0x07));
                uOut[oPtr++]=(unsigned char)(0x80|bit12to17);
                uOut[oPtr++]=(unsigned char)(0x80|bit06to11);
                uOut[oPtr++]=(unsigned char)(0x80|bit00to05);
            }
            else if(in[iPtr]<=0x3ffffff)
            {
                if(lOut-5<=oPtr)
                {
                    // Buffer overrun.  Cannot put zero at the end.
                    break;
                }
                uOut[oPtr++]=(unsigned char)(0xf8|(bit24to29&0x03));
                uOut[oPtr++]=(unsigned char)(0x80|bit18to23);
                uOut[oPtr++]=(unsigned char)(0x80|bit12to17);
                uOut[oPtr++]=(unsigned char)(0x80|bit06to11);
                uOut[oPtr++]=(unsigned char)(0x80|bit00to05);
            }
            else if(in[iPtr]<=0x7fffffff)
            {
                if(lOut-6<=oPtr)
                {
                    // Buffer overrun.  Cannot put zero at the end.
                    break;
                }
                uOut[oPtr++]=(unsigned char)(0xfc|bit30);
                uOut[oPtr++]=(unsigned char)(0x80|bit24to29);
                uOut[oPtr++]=(unsigned char)(0x80|bit18to23);
                uOut[oPtr++]=(unsigned char)(0x80|bit12to17);
                uOut[oPtr++]=(unsigned char)(0x80|bit06to11);
                uOut[oPtr++]=(unsigned char)(0x80|bit00to05);
            }
        }
        iPtr++;
    }
    if(oPtr<lOut)
    {
        out[oPtr]=0;
        oPtr++;
    }
    return oPtr;
}
template <class WCHAR_TYPE>
size_t UnicodeUTF8toWChar(size_t lOut,WCHAR_TYPE out[],const char in[])
{
    unsigned int iPtr=0,oPtr=0;
    unsigned char *uIn=(unsigned char *)in;
    while(oPtr<lOut-1 && 0!=uIn[iPtr])
    {
        if(0==(uIn[iPtr]&0x80))
        {
            out[oPtr]=uIn[iPtr];
            iPtr++;
        }
        else if(0xc0==(uIn[iPtr]&0xe0))
        {
            if(0==uIn[iPtr+1])
            {
                // Pre-mature termination.
                break;
            }
            unsigned int high5=uIn[iPtr]&0x1f;
            unsigned int low6=uIn[iPtr+1]&0x3f;
            out[oPtr]=(WCHAR_TYPE)((high5<<6)|low6);
            iPtr+=2;
        }
        else if(0xe0==(uIn[iPtr]&0xf0))
        {
            if(0==uIn[iPtr+1] || 0==uIn[iPtr+2])
            {
                // Pre-mature termination.
                break;
            }
            unsigned int high4=uIn[iPtr]&0x0f;
            unsigned int mid6=uIn[iPtr+1]&0x3f;
            unsigned int low6=uIn[iPtr+2]&0x3f;
            out[oPtr]=(WCHAR_TYPE)((high4<<12)|(mid6<<6)|low6);
            iPtr+=3;
        }
        else if(0xf0==(uIn[iPtr]&0xf8))
        {
            if(0==uIn[iPtr+1] || 0==uIn[iPtr+2] || 0==uIn[iPtr+3])
            {
                // Pre-mature termination.
                break;
            }
            unsigned int bit18to20=uIn[iPtr]&0x07;
            unsigned int bit12to17=uIn[iPtr+1]&0x3f;
            unsigned int bit06to11=uIn[iPtr+2]&0x3f;
            unsigned int bit00to05=uIn[iPtr+3]&0x3f;
            out[oPtr]=(WCHAR_TYPE)((bit18to20<<18)|(bit12to17<<12)|(bit06to11<<6)|bit00to05);
            iPtr+=4;
        }
        else if(0xf8==(uIn[iPtr]&0xfc))
        {
            if(0==uIn[iPtr+1] || 0==uIn[iPtr+2] || 0==uIn[iPtr+3] || 0==uIn[iPtr+4])
            {
                // Pre-mature termination.
                break;
            }
            unsigned int bit24to25=uIn[iPtr]&0x03;
            unsigned int bit18to23=uIn[iPtr+1]&0x3f;
            unsigned int bit12to17=uIn[iPtr+2]&0x3f;
            unsigned int bit06to11=uIn[iPtr+3]&0x3f;
            unsigned int bit00to05=uIn[iPtr+4]&0x3f;
            out[oPtr]=(WCHAR_TYPE)((bit24to25<<24)|(bit18to23<<18)|(bit12to17<<12)|(bit06to11<<6)|bit00to05);
            iPtr+=5;
        }
        else if(0xfc==(uIn[iPtr]&0xfe))
        {
            if(0==uIn[iPtr+1] || 0==uIn[iPtr+2] || 0==uIn[iPtr+3] || 0==uIn[iPtr+4])
            {
                // Pre-mature termination.
                break;
            }
            unsigned int bit30=uIn[iPtr]&0x01;
            unsigned int bit24to29=uIn[iPtr+1]&0x3f;
            unsigned int bit18to23=uIn[iPtr+2]&0x3f;
            unsigned int bit12to17=uIn[iPtr+3]&0x3f;
            unsigned int bit06to11=uIn[iPtr+4]&0x3f;
            unsigned int bit00to05=uIn[iPtr+5]&0x3f;
            out[oPtr]=(WCHAR_TYPE)((bit30<<30)|(bit24to29<<24)|(bit18to23<<18)|(bit12to17<<12)|(bit06to11<<6)|bit00to05);
            iPtr+=6;
        }
        else
        {
            // Invalid utf8 string
            break;
        }
        oPtr++;
    }
    if(oPtr<lOut)
    {
        out[oPtr]=0;
        oPtr++;
    }
    return oPtr;
}
// Should be encoded to  E5 B1 B1  E5  B7 9D  CF 80
int main(void)
{
    wchar_t in[]={0x5c71,0x5ddd,0x03c0,0};
    char utf8[256];
    int i;
    for(i=0; 0!=in[i]; i++)
    {
        printf("%04x ",in[i]);
    }
    printf("\n");
    size_t bytes=UnicodeWChar2UTF8 <wchar_t> (256,utf8,in);
    printf("Encoded to %d bytes (including the last zero terminator).\n",bytes);
    for(i=0; 0!=utf8[i]; i++)
    {
        printf("%02x ",((unsigned char *)utf8)[i]);
    }
    printf("\n");
    wchar_t backConv[256];
    size_t wchars=UnicodeUTF8toWChar <wchar_t> (256,backConv,utf8);
    printf("Decoded to %d wchars (including the last zero terminator).\n",wchars);
    for(i=0; 0!=backConv[i]; i++)
    {
        printf("%04x ",backConv[i]);
    }
    printf("\n");
    return 0;
} |  Unicode problem solved. I knew how to make an off-screen bitmap from a Unicode string in Windows 
    and Mac OSX. iOS is almost same as Mac OSX. So, if I found how to do the 
    same in Linux, I could support most of the major operating systems. But, doing it in X-Window was the most difficult among three systems. 
    X-Window is obsolete. I want to avoid if I can. But, it comes with Linux by 
    default. If I want to support Linux, I cannot avoid it. What surprised me was organization of the off-screen bitmap. If I made a 
    24-bit bitmap, and if I pick three consecutive bytes, I expect that three 
    bytes will give red, green, and blue component. That's the case in Windows 
    and Mac OSX. But, when I made a bitmap (called pixmap in X) and retrieved a 
    bitmap, first of the 24 bits were packed in a sequence, followed by the 
    second, third, ..., 24th bits. I first wrote a program that draws "Text" in black color on white 
    background. The first byte of the bitmap was $E0. I wondered why the hell I 
    was getting a byte other than $00 and $FF? I couldn't solve the mystery for 
    an hour or so. Then I gave up and took a shower. When I was taking a shower, 
    I noticed the first 5 bits of $E0 were zero. Maybe the top bar of letter T 
    was expanded to five pixels, and that's why I was getting $E0. So, I scanned 
    bit by bit and printed 1 and 0 on the console, and I saw the pattern that I 
    expected. It reminded me of the structure of the Video-RAM of my very first 
    8-bit computer. It's ok. In X-Window, you can experience how people used to 
    do things decades ago. You can learn history. That's the joy of X-Window. At 
    least I figured how to do it in X-Window.  You can compile the 
    following program by: g++ font.cpp -lX11 
      List: font.cpp 
        
          | #include <stdio.h>
#include <string.h>
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xlocale.h>
/* Memo for future reference
Meaning of font string.
  http://en.wikipedia.org/wiki/X_logical_font_description
X-Window drawing functions
  http://www-yano.is.tokushima-u.ac.jp/~mituhara/software_e/draw.html
XwcDrawString sample code
  http://homepage3.nifty.com/rio_i/lab/xlib/011mbcs.htm
    This page suggests:
    - Environment variable LANG should be set.
    - A function call setlocale(LC_CTYPE,""); is required.
May also be possible to use XLoadFont, XSetFont
  Font font=XLoadFont(ysXDsp,"6x10");
*/
int main(void)
{
    Display *dsp=XOpenDisplay(NULL);
    if(NULL!=dsp)
    {
        printf("Display Opened. (Depth=%d)\n",DefaultDepth(dsp,0));
        Window rootWin=DefaultRootWindow(dsp);
        int nFont;
        char **fontList=XListFonts(dsp,"*iso10646*",1024,&nFont);
        int i;
        for(i=0; i<nFont; i++)
        {
            printf("[%d] %s\n",i,fontList[i]);
        }
        const char *baseFontName=
            "-*-*-*-*-*-*-16-*-*-*-*-*-iso8859-1,"
            "-*-*-*-*-*-*-16-*-*-*-*-*-iso8859-2,"
            "-*-*-*-*-*-*-16-*-*-*-*-*-iso8859-4,"
            "-*-*-*-*-*-*-16-*-*-*-*-*-iso8859-5,"
            "-*-*-*-*-*-*-16-*-*-*-*-*-iso8859-6,"
            "-*-*-*-*-*-*-16-*-*-*-*-*-iso8859-7,"
            "-*-*-*-*-*-*-16-*-*-*-*-*-iso8859-8,"
            "-*-*-*-*-*-*-16-*-*-*-*-*-iso8859-9,"
            "-*-*-*-*-*-*-16-*-*-*-*-*-iso8859-15,"
            "-*-*-*-*-*-*-16-*-*-*-*-*-iso10646-1";
        const char *localeStr=setlocale(LC_CTYPE,"");
        if(NULL==localeStr || True!=XSupportsLocale())
        {
            setlocale(LC_CTYPE,"en_US.UTF-8");  // Desperate attempt!
        }
        int missCharSetCount;
        char *defStr,**missCharSet;
        XFontSet fontSet=XCreateFontSet(
        dsp,
        baseFontName,
        &missCharSet,
        &missCharSetCount,
        &defStr);
        if(NULL!=fontSet)
        {
            printf("Acquired font set (Missing=%d)\n",missCharSetCount);
            wchar_t str[]={0x5c71,0x5ddd,0x03c0,'A',0x0394,0};
            XRectangle inkRect,logRect;
            int ext=XwcTextExtents(fontSet,str,5,&inkRect,&logRect);
            printf("Extent %d\n",ext);
            printf("Ink Rect %d %d %d %d\n",inkRect.x,inkRect.y,inkRect.width,inkRect.height);
            printf("Log Rect %d %d %d %d\n",logRect.x,logRect.y,logRect.width,logRect.height);
            int bmpWid=ext,bmpHei=logRect.height;
            int depth=DefaultDepth(dsp,0);
            Pixmap pixmap=XCreatePixmap(dsp,rootWin,bmpWid,bmpHei,depth);
            GC gc=XCreateGC(dsp,pixmap,0,0);
            XSetForeground(dsp,gc,BlackPixel(dsp,0));
            XFillRectangle(dsp,pixmap,gc,0,0,bmpWid,bmpHei);
            XSetForeground(dsp,gc,WhitePixel(dsp,0));
            XwcDrawString(dsp,pixmap,fontSet,gc,0,bmpHei-1,str,5);
            XImage *image=XGetImage(dsp,pixmap,0,0,bmpWid,bmpHei,~0,XYPixmap);
            if(NULL!=image)
            {
                printf("Acquired Image %dx%d\n",image->width,image->height);
                printf("Bitmap Unit=%d\n",image->bitmap_unit);
                printf("Bytes per line=%d\n",image->bytes_per_line);
                printf("Depth=%d\n",image->depth);
                int x,y;
                for(y=0; y<image->height; y++)
                {
                    unsigned char mask=1;
                    unsigned char *byteTop=(unsigned char *)
                    image->data+y*image->bytes_per_line;
                    for(x=0; x<image->width; x++)
                    {
                        if((*byteTop)&mask)
                        {
                            printf("1");
                        }
                        else
                        {
                            printf("0");
                        }
                        if(0!=(mask&0x80))
                        {
                            byteTop++;
                            mask=1;
                        }
                        else
                        {
                            mask<<=1;
                        }
                    }
                    printf("\n");
                }
                /* Attempt 1 Failed. Apparently, each of 24 layers is
                packed contiguously.  I was forgetting X-Window is from the stone age.
                int byte_per_pixel=image->bitmap_unit/8;
                for(y=0; y<image->height; y++)
                {
                    for(x=0; x<20; x++)
                    {
                        int offset=y*(64*byte_per_pixel)+x*byte_per_pixel;
                        unsigned char *ptr=(unsigned char *)image->data+offset;
                        printf("%02x%02x%02x ",ptr[0],ptr[1],ptr[2]);
                    }
                    printf("\n");
                } */
            }
            XDestroyImage(image);
            XFreeGC(dsp,gc);
            XFreePixmap(dsp,pixmap);
            XFreeFontSet(dsp,fontSet);
        }
        XCloseDisplay(dsp);
    }
} |  Now I know how to do it in Windows, Mac OSX, and Linux. Next thing is to 
    make a class that has a set of interfaces that allows the application to 
    access these features. Then I will be able to get rid of brute-force PNG-based 
    localization. 04/26/2011 |