00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 module mango.xcode.Utf8;
00037
00038 private import mango.xcode.Transcoder;
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070 class TranscoderUtf8 : Transcoder
00071 {
00072
00073
00074
00075
00076 char[] toString ()
00077 {
00078 return "utf-8";
00079 }
00080
00081
00082
00083
00084
00085
00086
00087
00088
00089 char[] encode (dchar[] input, char[] output, out uint consumed)
00090 {
00091 char* pOut;
00092 uint eaten;
00093 int space;
00094
00095 pOut = output;
00096 space = output.length;
00097 foreach (dchar b; input)
00098 {
00099 if (b < 0x80)
00100 {
00101 if (space--)
00102 *pOut++ = b;
00103 else
00104 break;
00105 }
00106 else
00107 if (b < 0x8000)
00108 {
00109 if ((space -= 2) < 0)
00110 break;
00111
00112 pOut[0] = 0xc0 | ((b >> 6) & 0x3f);
00113 pOut[1] = 0x80 | (b & 0x3f);
00114 pOut += 2;
00115 }
00116 else
00117 if (b < 0x80000)
00118 {
00119 if ((space -= 3) < 0)
00120 break;
00121
00122 pOut[0] = 0xe0 | ((b >> 12) & 0x3f);
00123 pOut[1] = 0x80 | ((b >> 6) & 0x3f);
00124 pOut[2] = 0x80 | (b & 0x3f);
00125 pOut += 3;
00126 }
00127 else
00128 if (b < 0x110000)
00129 {
00130 if ((space -= 4) < 0)
00131 break;
00132
00133 pOut[0] = 0xf0 | ((b >> 18) & 0x3f);
00134 pOut[1] = 0x80 | ((b >> 12) & 0x3f);
00135 pOut[2] = 0x80 | ((b >> 6) & 0x3f);
00136 pOut[3] = 0x80 | (b & 0x3f);
00137 pOut += 4;
00138 }
00139 else
00140 {
00141 fault ("invalid input while encoding");
00142 return null;
00143 }
00144 ++eaten;
00145 }
00146
00147 consumed = eaten;
00148 return output [0..(pOut - &output[0])];
00149 }
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159 dchar[] decode (char[] input, dchar[] output, out uint consumed)
00160 {
00161 uint produced;
00162 uint available;
00163 char* pIn = input;
00164
00165 available = input.length;
00166 foreach (inout dchar d; output)
00167 {
00168 if (! available--)
00169 break;
00170
00171 dchar b = cast(dchar) *pIn;
00172 if (b & 0x80)
00173 {
00174 if (b < 0xe0)
00175 {
00176 if (! available--)
00177 break;
00178
00179 b &= 0x1f;
00180 b = (b << 6) | (*++pIn & 0x3f);
00181 }
00182 else
00183 if (b < 0xf0)
00184 {
00185 if (available < 2)
00186 break;
00187
00188 b &= 0x0f;
00189 b = (b << 6) | (pIn[1] & 0x3f);
00190 b = (b << 6) | (pIn[2] & 0x3f);
00191 available -= 2;
00192 pIn += 2;
00193 }
00194 else
00195 {
00196 if (available < 3)
00197 break;
00198
00199 b &= 0x07;
00200 b = (b << 6) | (pIn[1] & 0x3f);
00201 b = (b << 6) | (pIn[2] & 0x3f);
00202 b = (b << 6) | (pIn[3] & 0x3f);
00203 available -= 3;
00204 pIn += 3;
00205 }
00206 }
00207
00208 d = b;
00209 ++pIn;
00210 ++produced;
00211 }
00212
00213 consumed = pIn - &input[0];
00214 return output [0..produced];
00215 }
00216 }
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227 class TranscoderUtf8Checked : TranscoderUtf8
00228 {
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243 dchar[] decode (char[] input, dchar[] output, out uint consumed)
00244 {
00245 uint produced;
00246 uint available;
00247 char* pIn = input;
00248
00249 available = input.length;
00250 foreach (inout dchar d; output)
00251 {
00252 if (! available)
00253 break;
00254
00255 dchar b = cast(dchar) *pIn;
00256 if (b & 0x80)
00257 {
00258 uint len = b < 0xe0 ? 1 : (b < 0xf0 ? 2 : 3);
00259 if (available > len)
00260 {
00261 available -= len;
00262 b &= ((1 << (6 - len)) - 1);
00263
00264 do {
00265 char c = *++pIn;
00266 if ((c & 0xc0) != 0x80)
00267 fault ("invalid input sequence");
00268
00269 b = (b << 6) | (c & 0x3f);
00270 } while (--len);
00271
00272 if (!(b < 0xd800 ||
00273 (b > 0xdfff && b <= 0x10ffff &&
00274 b != 0xfffe && b != 0xffff)))
00275 fault ("invalid unicode character");
00276 }
00277 else
00278 break;
00279 }
00280
00281 --available;
00282 d = b;
00283 ++pIn;
00284 ++produced;
00285 }
00286
00287 consumed = pIn - &input[0];
00288 return output [0..produced];
00289 }
00290 }