Rob ‘Commander’ Pike가 1992년 UTF-8의 실제 설계 과정과 X/Open·IBM·Plan 9과의 관계를 설명한 이메일 기록.
제목: UTF-8 역사 발신: "Rob 'Commander' Pike" 날짜: Wed, 30 Apr 2003 22:32:32 -0700 (Thu 06:32 BST) 수신: mkuhn (at) acm.org, henry (at) spsystems.net 참조: ken (at) entrisphere.com
UTF-8의 배경을 살펴보면, 같은 잘못된 이야기가 반복해서 나오곤 합니다. 잘못된 버전은 다음과 같습니다.
그건 사실이 아닙니다. UTF-8은 1992년 9월 무렵 어느 밤, 뉴저지의 한 다이너에서 식탁 매트 위에 제 눈앞에서 설계되었습니다.
일은 이랬습니다. 우리는 ISO 10646의 원래 UTF를 사용해 Plan 9가 16비트 문자를 지원하도록 했지만, 그걸 몹시 싫어했습니다. 시스템 출시를 코앞에 둔 어느 날 늦은 오후, IBM이었던 것으로 기억되는—오스틴에 있던—사람들에게서 전화가 왔습니다. 그들은 X/Open 위원회 회의 중이었고, 자신들의 FSS/UTF 설계를 Ken과 내가 검토해주길 원했습니다. 그들이 새로운 설계를 도입하려는 이유는 이해했고, 그러자 Ken과 나는 우리가 가진 경험을 활용해 정말 좋은 표준을 설계하고 X/Open 쪽이 그것을 밀어주도록 만들 기회가 있다는 걸 깨달았습니다. 우리가 그렇게 제안했고, 조건은 빨리 끝낼 수 있으면 OK라는 것이었습니다.
그래서 저녁을 먹으러 갔고, Ken이 비트 패킹을 고안했습니다. 저녁 후 연구실로 돌아와 X/Open 사람들에게 전화해 우리의 방식을 설명했습니다. 우리는 그들에게 사양 개요를 메일로 보냈고, 그들은 그것이 자신들의 것보다 낫다고 답장했습니다(사실 나는 그들의 제안을 실제로 본 기억이 없습니다; 지금도 기억나지 않습니다). 그리고 얼마나 빨리 구현할 수 있느냐고 물었습니다. 그날이 아마 수요일 밤이었고, 우리는 월요일까지 완전한 실행 시스템을 약속했습니다. 아마 그들의 큰 표결이 그때였던 것 같습니다.
그날 밤 Ken은 패킹/언패킹 코드를 작성했고, 나는 C와 그래픽 라이브러리를 갈아엎기 시작했습니다. 다음 날에는 모든 코드가 끝났고, 시스템 자체의 텍스트 파일들을 변환하기 시작했습니다. 금요일쯤에는 Plan 9가 소위 UTF-8이라 불릴 것을 구동했고, 오직 그것만으로 동작하고 있었습니다. 우리는 X/Open에 전화를 했고, 나머지는 흔히 말하듯이 약간 손질된 역사로 남았습니다.
왜 그들의 FSS/UTF를 그냥 쓰지 않았느냐고요? 내 기억으로는, 첫 통화 때 내가 이런 인코딩에 필요한 요구사항을 줄줄이 읊었는데, FSS/UTF에는 최소한 하나—바이트 스트림을 중간에서 집어 들어도 한 문자를 온전히 소비하지 않고도 동기화를 맞출 수 있는 능력—가 빠져 있었습니다. 그게 없었기 때문에, 우리는 우리 방식대로 만들 자유가 있다고 느꼈고 실제로 그런 자유를 받았습니다.
“IBM이 설계하고, Plan 9이 구현했다”는 이야기는 RFC 2279에서 비롯된 것으로 봅니다. 당시 우리는 UTF-8이 널리 퍼지는 게 너무 기뻐서 엉뚱한 역사에 대해 아무 말도 하지 않았습니다. 우리 둘 다 이제 연구소에 있지는 않지만, 아카이브 어딘가에 우리의 이야기를 뒷받침할 이메일 스레드가 있을 겁니다. 누군가에게 부탁하면 찾아줄지도 모르죠.
그래서, 기회를 만들고 추진해 준 X/Open과 IBM 쪽에 전적인 공을 돌립니다. 하지만 역사책이 뭐라 하든, Ken이 설계했고 나는 옆에서 응원했습니다.
-rob
날짜: Sat, 07 Jun 2003 18:44:05 -0700 발신: "Rob `Commander' Pike" 수신: Markus Kuhn 참조: henry (at) spsystems.net, ken (at) entrisphere.com, Greger Leijonhufvud 제목: Re: UTF-8 역사
Russ Cox에게 아카이브를 뒤져 달라고 부탁했습니다. 그의 메시지를 첨부합니다. 앞서 보낸 내 이야기를 뒷받침한다고 동의하실 겁니다.
우리가 X/Open에 보낸 메일(그 문서는 Ken이 편집과 발송을 맡았던 것으로 기억합니다)에는 문자 경계 탐지에 관한 새로운 요구사항 #6이 포함되어 있습니다. 원래 X/Open 제안이 우리에게 어느 정도 영향을 미쳤는지는 영원히 알 수 없겠죠. 두 제안은 매우 다르지만 몇 가지 특징을 공유하긴 합니다. 자세히 들여다봤던 기억은 없는데, 너무 오래전 일이라 그렇습니다. Ken이 식탁매트에 쓰던 모습을 아주 또렷이 기억합니다. 그걸 보관해 뒀으면 좋았을 텐데!
-rob
발신: Russ Cox 수신: r (at) google.com 제목: utf 자료 캐기 발신 시각: Saturday, June 07, 2003 7:46 PM -0400
bootes의 /sys/src/libc/port/rune.c는 1992년 9월 4일, 나눗셈 위주였던 옛 utf에서 변경되었습니다. 덤프에 들어간 버전의 타임스탬프는 19:51:55입니다. 다음 날 주석이 추가되었고, 그 외에는 1996년 11월 14일까지 변함이 없었습니다. 그때 runelen이 runetochar의 반환값을 쓰는 대신 룬 값을 직접 검사해 빨라졌습니다. 그 다음이자 마지막 변경은 2001년 5월 26일로, runenlen을 추가했습니다.
아래는 당신들의 메일함에서 utf로 grep해 찾은 메일들입니다. 첫 번째는 utf.c를 가리키는데, 32비트 룬에 대한 6바이트 UTF-8 전체를 다루는 wctomb/mbtowc의 사본입니다. 제어 흐름에 모든 로직이 들어있어 꽤 지저분합니다. 첫 번째 메일의 결과로 그 코드가 제안서의 코드가 되었으리라 짐작합니다.
/usr/ken/utf/xutf 안에서, 원래의 자기 동기화가 되지 않는 인코딩 제안 사본을 찾았고, 끝부분(“We define 7 byte types”부터 시작)에 UTF-8 방식이 덧붙어 있습니다. 그것도 아래에 포함합니다. 아래 보이는 버전은 첫 번째 것으로, 날짜는 9월 2일 23:44:10입니다. 여러 차례의 수정 끝에 9월 8일 아침 두 번째 메일이 되었습니다. 메일 로그는 그 두 번째 메일이 발송되었고 Ken에게 돌아오기까지 시간이 좀 걸렸음을 보여줍니다.
helix: Sep 8 03:22:13: ken: upas/sendmail: remote inet!xopen.co.uk!xojig
From ken Tue Sep 8 03:22:07 EDT 1992 (xojig@xopen.co.uk) 6833 helix: Sep 8 03:22:13: ken: upas/sendmail: delivered rob From ken Tue Sep 8 03:22:07 EDT 1992 6833 helix: Sep 8 03:22:16: ken: upas/sendmail: remote pyxis!andrew From ken Tue Sep 8 03:22:07 EDT 1992 (andrew) 6833 helix: Sep 8 03:22:19: ken: upas/sendmail: remote coma!dmr From ken Tue Sep 8 03:22:07 EDT 1992 (dmr) 6833 helix: Sep 8 03:25:52: ken: upas/sendmail: delivered rob From ken Tue Sep 8 03:24:58 EDT 1992 141 helix: Sep 8 03:36:13: ken: upas/sendmail: delivered ken From ken Tue Sep 8 03:36:12 EDT 1992 6833
enjoy.
From ken Fri Sep 4 03:37:39 EDT 1992 you might want to look at /usr/ken/utf/utf.c and see if you can make it prettier.
From ken Tue Sep 8 03:22:07 EDT 1992 Here is our modified FSS-UTF proposal. The words are the same as on the previous proposal. My apologies to the author. The code has been tested to some degree and should be pretty good shape. We have converted Plan 9 to use this encoding and are about to issue a distribution to an initial set of university users.
ISO/IEC 10646(Unicode)가 국제 표준으로 승인되고 이 유니버설 코드 문자 집합(UCS)이 널리 쓰일 것으로 예상됨에 따라, 역사적으로 ASCII 기반인 운영체제들은 이 새로운 표준이 부호화할 수 있는 방대한 문자 수의 표현과 처리를 다룰 방법을 고안할 필요가 있습니다.
UCS가 제시하는 과제는 역사적 운영체제와 C 언어 프로그래밍 환경에서 해결되어야 합니다. 가장 중요한 과제는 UCS에서 사용하는 인코딩 방식입니다. 더 정확히 말해, UCS 표준을 기존의 프로그래밍 언어 및 운영체제/유틸리티와 결합하는 것이 과제입니다. 프로그래밍 언어와 UCS 표준의 문제는 업계의 다른 활동에서 다루고 있습니다. 그러나 우리는 여전히 역사적 운영체제와 유틸리티에서 UCS를 처리하는 문제와 마주하고 있습니다.
운영체제의 UCS 처리 관심사 중 두드러지는 것은 파일 시스템 내 데이터의 표현입니다. 기본 가정은 기존 운영체제 소프트웨어에 대한 투자를 유지하는 동시에 UCS가 제공하는 방대한 문자 수의 장점을 활용해야 한다는 절대적 요구가 있다는 것입니다. UCS는 단일 부호화 문자 집합 안에 다국어 텍스트를 부호화할 수 있는 능력을 제공합니다. 그러나 UCS와 그 변형 UTF는 널 바이트(null)와 ASCII 슬래시("/")를 보호하지 않기 때문에 이러한 문자 부호화는 기존 Unix 구현과 호환되지 않습니다.
다음 제안은 Unix 시스템이 단일 인코딩으로 다국어 텍스트를 지원할 수 있도록 하는, Unix 호환 UCS 변환 형식을 제공합니다. 이 변환 형식 인코딩은 파일 코드로 사용하도록 의도되었습니다. 이 UCS 변환 형식 인코딩은 완전한 UCS 지원을 향한 중간 단계로 의도되었습니다. 그러나 거의 모든 Unix 구현이 UCS 지원에서 동일한 장애물에 직면해 있으므로, 이 제안은 이 전환 단계에서 공통되고 호환 가능한 인코딩을 제공하려는 것입니다.
역사적 운영체제 파일 시스템에서 UCS를 처리하고 저장하는 데 관한 대부분(또는 전부)의 문제가 이해되었다고 가정할 때, 목적은 역사적 운영체제 파일 시스템에서 비파괴적으로 사용할 수 있는 UCS 변환 형식을 정의하는 것입니다. 의도는 UCS가 변환 형식의 프로세스 코드가 되고, 그 변환 형식은 파일 코드로 사용 가능하도록 하는 것입니다.
아래는 UCS 변환 형식을 정의할 때 사용된 지침입니다.
역사적 파일 시스템과의 호환성: 역사적 파일 시스템은 파일 이름의 일부로 널 바이트와 ASCII 슬래시 문자를 허용하지 않습니다.
기존 프로그램과의 호환성: 멀티바이트 처리의 기존 모델은 멀티바이트 인코딩의 어느 위치에서도 ASCII가 나타나지 않는다는 것입니다. UCS 표현에서 ASCII 문자 집합에 없던 문자의 변환 형식 표현의 어떤 부분에도 ASCII 코드 값이 나타나서는 안 됩니다.
UCS로/로부터의 변환 용이성.
첫 바이트는 멀티바이트 시퀀스에서 뒤따르는 바이트 수를 나타내야 합니다.
변환 형식은 인코딩에 사용되는 바이트 수 측면에서 낭비적이어서는 안 됩니다.
바이트 스트림을 임의의 위치에서 시작하더라도 효율적으로 문자 시작점을 찾을 수 있어야 합니다.
제안하는 UCS 변환 형식은 [0,0x7fffffff] 범위의 UCS 값을 1, 2, 3, 4, 5, 6바이트 길이의 멀티바이트 문자로 부호화합니다. 2바이트 이상 인코딩의 경우, 첫 바이트가 사용되는 바이트 수를 결정하며 각 바이트의 상위 비트가 설정됩니다. 10xxxxxx로 시작하지 않는 모든 바이트는 UCS 문자 시퀀스의 시작입니다. 이 변환 형식을 기억하는 쉬운 방법은, 첫 바이트의 연속된 상위 1의 개수가 멀티바이트 문자의 바이트 수를 나타낸다는 점입니다:
Bits Hex Min Hex Max 이진 바이트 시퀀스 1 7 00000000 0000007f 0vvvvvvv 2 11 00000080 000007FF 110vvvvv 10vvvvvv 3 16 00000800 0000FFFF 1110vvvv 10vvvvvv 10vvvvvv 4 21 00010000 001FFFFF 11110vvv 10vvvvvv 10vvvvvv 10vvvvvv 5 26 00200000 03FFFFFF 111110vv 10vvvvvv 10vvvvvv 10vvvvvv 10vvvvvv 6 31 04000000 7FFFFFFF 1111110v 10vvvvvv 10vvvvvv 10vvvvvv 10vvvvvv 10vvvvvv
UCS 값은 멀티바이트 인코딩에서 v 비트들을 이어붙인 것입니다. 여러 가지로 값을 인코딩할 수 있는 경우(예: UCS 0), 가장 짧은 인코딩만이 허용됩니다.
아래에는 C 표준 함수 wctomb()와 mbtowc()의 예시 구현이 있으며, UCS에서 변환 형식으로, 그리고 변환 형식에서 UCS로 변환하는 알고리즘을 보여 줍니다. 예시 구현에는 일부 불필요할 수도 있는 오류 검사가 포함되어 있습니다.
typedef struct { int cmask; int cval; int shift; long lmask; long lval; } Tab;
static Tab tab[] = { 0x80, 0x00, 06, 0x7F, 0, / 1 byte sequence / 0xE0, 0xC0, 16, 0x7FF, 0x80, /* 2 byte sequence / 0xF0, 0xE0, 26, 0xFFFF, 0x800, /* 3 byte sequence / 0xF8, 0xF0, 36, 0x1FFFFF, 0x10000, /* 4 byte sequence / 0xFC, 0xF8, 46, 0x3FFFFFF, 0x200000, /* 5 byte sequence / 0xFE, 0xFC, 56, 0x7FFFFFFF, 0x4000000, /* 6 byte sequence / 0, / end of table */ };
int mbtowc(wchar_t *p, char *s, size_t n) { long l; int c0, c, nc; Tab *t;
if(s == 0)
return 0;
nc = 0;
if(n <= nc)
return -1;
c0 = *s & 0xff;
l = c0;
for(t=tab; t->cmask; t++){
nc++;
if((c0 & t->cmask) == t->cval){
l &= t->lmask;
if(l < t->lval)
return -1;
*p = l;
return nc;
}
if(n <= nc)
return -1;
s++;
c = (*s ^ 0x80) & 0xFF;
if(c & 0xC0)
return -1;
l = (l<<6) | c;
}
return -1;
}
int wctomb(char *s, wchar_t wc) { long l; int c, nc; Tab *t;
if(s == 0)
return 0;
l = wc;
nc = 0;
for(t=tab; t->cmask; t++){
nc++;
if(l <= t->lmask){
c = t->shift;
*s = t->cval | (l>>c);
while(c > 0){
c -= 6;
s++;
*s = 0x80 | ((l>>c) & 0x3F);
}
return nc;
}
}
return -1;
}
From ken Tue Sep 8 03:24:58 EDT 1992 i mailed it out, but it went into a black hole. i didnt get my copy. it must be hung up on the internat address with coma down or something.
From ken Tue Sep 8 03:42:43 EDT 1992 i finally got my copy.
--- /usr/ken/utf/xutf from dump of Sep 2 1992 ---
ISO/IEC 10646(Unicode)가 국제 표준으로 승인되고 이 유니버설 코드 문자 집합(UCS)이 널리 쓰일 것으로 예상됨에 따라, 역사적으로 ASCII 기반인 운영체제들은 이 새로운 표준이 부호화할 수 있는 방대한 문자 수의 표현과 처리를 다룰 방법을 고안할 필요가 있습니다.
UCS가 제시하는 과제는 역사적 운영체제와 C 언어 프로그래밍 환경에서 해결되어야 합니다. 가장 중요한 과제는 UCS에서 사용하는 인코딩 방식입니다. 더 정확히 말해, UCS 표준을 기존의 프로그래밍 언어 및 운영체제/유틸리티와 결합하는 것이 과제입니다. 프로그래밍 언어와 UCS 표준의 문제는 업계의 다른 활동에서 다루고 있습니다. 그러나 우리는 여전히 역사적 운영체제와 유틸리티에서 UCS를 처리하는 문제와 마주하고 있습니다.
운영체제의 UCS 처리 관심사 중 두드러지는 것은 파일 시스템 내 데이터의 표현입니다. 기본 가정은 기존 운영체제 소프트웨어에 대한 투자를 유지하는 동시에 UCS가 제공하는 방대한 문자 수의 장점을 활용해야 한다는 절대적 요구가 있다는 것입니다. UCS는 단일 부호화 문자 집합 안에 다국어 텍스트를 부호화할 수 있는 능력을 제공합니다. 그러나 UCS와 그 변형 UTF는 널 바이트(null)와 ASCII 슬래시("/")를 보호하지 않기 때문에 이러한 문자 부호화는 기존 Unix 구현과 호환되지 않습니다.
다음 제안은 Unix 시스템이 단일 인코딩으로 다국어 텍스트를 지원할 수 있도록 하는, Unix 호환 UCS 변환 형식을 제공합니다. 이 변환 형식 인코딩은 파일 코드로 사용하도록 의도되었습니다. 이 UCS 변환 형식 인코딩은 완전한 UCS 지원을 향한 중간 단계로 의도되었습니다. 그러나 거의 모든 Unix 구현이 UCS 지원에서 동일한 장애물에 직면해 있으므로, 이 제안은 이 전환 단계에서 공통되고 호환 가능한 인코딩을 제공하려는 것입니다.
역사적 운영체제 파일 시스템에서 UCS를 처리하고 저장하는 데 관한 대부분(또는 전부)의 문제가 이해되었다고 가정할 때, 목적은 역사적 운영체제 파일 시스템에서 비파괴적으로 사용할 수 있는 UCS 변환 형식을 정의하는 것입니다. 의도는 UCS가 변환 형식의 프로세스 코드가 되고, 그 변환 형식은 파일 코드로 사용 가능하도록 하는 것입니다.
아래는 UCS 변환 형식을 정의할 때 사용된 지침입니다.
역사적 파일 시스템과의 호환성: 역사적 파일 시스템은 파일 이름의 일부로 널 바이트와 ASCII 슬래시 문자를 허용하지 않습니다.
기존 프로그램과의 호환성: 멀티바이트 처리의 기존 모델은 멀티바이트 인코딩의 어느 위치에서도 ASCII가 나타나지 않는다는 것입니다. UCS 표현에서 ASCII 문자 집합에 없던 문자의 변환 형식 표현의 어떤 부분에도 ASCII 코드 값이 나타나서는 안 됩니다.
UCS로/로부터의 변환 용이성.
첫 바이트는 멀티바이트 시퀀스에서 뒤따르는 바이트 수를 나타내야 합니다.
변환 형식은 인코딩에 사용되는 바이트 수 측면에서 낭비적이어서는 안 됩니다.
제안하는 UCS 변환 형식은 [0,0x7fffffff] 범위의 UCS 값을 1, 2, 3, 4, 5바이트 길이의 멀티바이트 문자로 부호화합니다. 2바이트 이상 인코딩의 경우, 첫 바이트가 사용되는 바이트 수를 결정하며 각 바이트의 상위 비트가 설정됩니다. 이 변환 형식을 기억하는 쉬운 방법은, 첫 바이트의 연속된 상위 1의 개수가 멀티바이트 문자에서 뒤따르는 바이트 수와 같다는 점입니다:
Bits Hex Min Hex Max 이진 바이트 시퀀스 1 7 00000000 0000007f 0zzzzzzz 2 13 00000080 0000207f 10zzzzzz 1yyyyyyy 3 19 00002080 0008207f 110zzzzz 1yyyyyyy 1xxxxxxx 4 25 00082080 0208207f 1110zzzz 1yyyyyyy 1xxxxxxx 1wwwwwww 5 31 02082080 7fffffff 11110zzz 1yyyyyyy 1xxxxxxx 1wwwwwww 1vvvvvvv
바이트 시퀀스에 포함되는 비트는 최소값에 대해 바이어스되어 있으므로, z, y, x, w, v가 모두 0이면 최소값이 표현됩니다. 바이트 시퀀스에서 최하위 부호화 비트는 마지막 바이트에 있고, 상위 비트(z)는 첫 바이트에 있습니다. 이 변환 형식은 0x80에서 0xff까지의 바이트 값을 멀티바이트 시퀀스의 일부로 전 범위 사용합니다. 바이트당 최대 7비트만 유용하다는 가정하에, 이 변환 형식은 사용 바이트 수 측면에서 거의 최소입니다.
아래에는 C 표준 함수 wctomb()와 mbtowc()의 예시 구현이 있으며, UCS에서 변환 형식으로, 그리고 변환 형식에서 UCS로 변환하는 알고리즘을 보여 줍니다. 예시 구현에는 일부 불필요할 수도 있는 오류 검사가 포함되어 있습니다.
#define OFF1 0x0000080 #define OFF2 0x0002080 #define OFF3 0x0082080 #define OFF4 0x2082080
int wctomb(char s, wchar_t wc) { if (s == 0) return 0; / no shift states / #ifdef wchar_t_is_signed if (wc < 0) goto bad; #endif if (wc <= 0x7f) / fits in 7 bits / { s[0] = wc; return 1; } if (wc <= 0x1fff + OFF1) / fits in 13 bits / { wc -= OFF1; s[0] = 0x80 | (wc >> 7); s[1] = 0x80 | (wc & 0x7f); return 2; } if (wc <= 0x7ffff + OFF2) / fits in 19 bits / { wc -= OFF2; s[0] = 0xc0 | (wc >> 14); s[1] = 0x80 | ((wc >> 7) & 0x7f); s[2] = 0x80 | (wc & 0x7f); return 3; } if (wc <= 0x1ffffff + OFF3) / fits in 25 bits */ { wc -= OFF3; s[0] = 0xe0 | (wc >> 21); s[1] = 0x80 | ((wc >> 14) & 0x7f); s[2] = 0x80 | ((wc >> 7) & 0x7f); s[3] = 0x80 | (wc & 0x7f); return 4; } #if !defined(wchar_t_is_signed) || defined(wchar_t_is_more_than_32_bits) if (wc > 0x7fffffff) goto bad; #endif wc -= OFF4; s[0] = 0xf0 | (wc >> 28); s[1] = 0x80 | ((wc >> 21) & 0x7f); s[2] = 0x80 | ((wc >> 14) & 0x7f); s[3] = 0x80 | ((wc >> 7) & 0x7f); s[4] = 0x80 | (wc & 0x7f); return 5;
bad:; errno = EILSEQ; return -1; }
int mbtowc(wchar_t *p, const char *s, size_t n) { unsigned char uc; / so that all bytes are nonnegative */
if ((uc = (unsigned char *)s) == 0)
return 0; /* no shift states */
if (n == 0)
return -1;
if ((*p = uc[0]) < 0x80)
return uc[0] != '\0'; /* return 0 for '\0', else 1 */
if (uc[0] < 0xc0) {
if (n < 2)
return -1;
if (uc[1] < 0x80)
goto bad;
*p &= 0x3f;
*p <<= 7;
*p |= uc[1] & 0x7f;
*p += OFF1;
return 2;
}
if (uc[0] < 0xe0) {
if (n < 3)
return -1;
if (uc[1] < 0x80 || uc[2] < 0x80)
goto bad;
*p &= 0x1f;
*p <<= 14;
*p |= (uc[1] & 0x7f) << 7;
*p |= uc[2] & 0x7f;
*p += OFF2;
return 3;
}
if (uc[0] < 0xf0) {
if (n < 4)
return -1;
if (uc[1] < 0x80 || uc[2] < 0x80 || uc[3] < 0x80)
goto bad;
*p &= 0x0f;
*p <<= 21;
*p |= (uc[1] & 0x7f) << 14;
*p |= (uc[2] & 0x7f) << 7;
*p |= uc[3] & 0x7f;
*p += OFF3;
return 4;
}
if (uc[0] < 0xf8) {
if (n < 5)
return -1;
if (uc[1] < 0x80 || uc[2] < 0x80 || uc[3] < 0x80 || uc[4] < 0x80)
goto bad;
*p &= 0x07;
*p <<= 28;
*p |= (uc[1] & 0x7f) << 21;
*p |= (uc[2] & 0x7f) << 14;
*p |= (uc[3] & 0x7f) << 7;
*p |= uc[4] & 0x7f;
if (((*p += OFF4) & ~(wchar_t)0x7fffffff) == 0)
return 5;
}
bad:; errno = EILSEQ; return -1; }
우리는 7가지 바이트 유형을 정의합니다: T0 0xxxxxxx 7 free bits Tx 10xxxxxx 6 free bits T1 110xxxxx 5 free bits T2 1110xxxx 4 free bits T3 11110xxx 3 free bits T4 111110xx 2 free bits T5 111111xx 2 free bits
인코딩은 다음과 같습니다.
From hex Thru hex Sequence Bits 00000000 0000007f T0 7 00000080 000007FF T1 Tx 11 00000800 0000FFFF T2 Tx Tx 16 00010000 001FFFFF T3 Tx Tx Tx 21 00200000 03FFFFFF T4 Tx Tx Tx Tx 26 04000000 FFFFFFFF T5 Tx Tx Tx Tx Tx 32
몇 가지 메모: