From: didg Date: Sun, 9 Mar 2003 19:55:33 +0000 (+0000) Subject: add utf8 support for AFP3 X-Git-Tag: netatalk-2-0-alpha1~213 X-Git-Url: https://arthur.barton.de/cgi-bin/gitweb.cgi?p=netatalk.git;a=commitdiff_plain;h=62182ed80f098b859c8db943b4399f396048faa6 add utf8 support for AFP3 --- diff --git a/config/AppleVolumes.default b/config/AppleVolumes.default index 9c0a5c52..3777e65c 100644 --- a/config/AppleVolumes.default +++ b/config/AppleVolumes.default @@ -47,6 +47,7 @@ # noadouble -> don't create .AppleDouble unless a resource # fork needs to be created. # ro -> mount the volume as read-only. +# utf8 -> use precomposed utf8 filenames # mswindows -> enforce filename restrictions imposed by MS # Windows. this will also invoke a default # codepage (iso8859-1) if one isn't already diff --git a/configure.in b/configure.in index 2151c670..872332a5 100644 --- a/configure.in +++ b/configure.in @@ -1,4 +1,4 @@ -dnl $Id: configure.in,v 1.178 2003-01-29 00:16:23 srittau Exp $ +dnl $Id: configure.in,v 1.179 2003-03-09 19:55:33 didg Exp $ dnl configure.in for netatalk AC_INIT(bin/adv1tov2/adv1tov2.c) @@ -197,6 +197,7 @@ AC_ARG_ENABLE(afp3, ) if test "$afp3" = "yes"; then + AM_ICONV AC_SYS_LARGEFILE fi diff --git a/etc/afpd/Makefile.am b/etc/afpd/Makefile.am index c96ea44b..d7ad7cac 100644 --- a/etc/afpd/Makefile.am +++ b/etc/afpd/Makefile.am @@ -11,7 +11,7 @@ afpd_SOURCES = unix.c ofork.c main.c switch.c auth.c volume.c directory.c \ file.c enumerate.c desktop.c filedir.c fork.c appl.c gettok.c \ mangle.c status.c afp_options.c afp_asp.c afp_dsi.c messages.c \ afp_config.c nfsquota.c codepage.c quota.c uam.c afs.c uid.c \ - afp_util.c catsearch.c + afp_util.c catsearch.c precompose.c afpd_LDADD = $(top_builddir)/libatalk/libatalk.la afpd_LDFLAGS = -export-dynamic diff --git a/etc/afpd/desktop.c b/etc/afpd/desktop.c index e91478c6..a329bec8 100644 --- a/etc/afpd/desktop.c +++ b/etc/afpd/desktop.c @@ -1,5 +1,5 @@ /* - * $Id: desktop.c,v 1.23 2003-02-16 12:35:04 didg Exp $ + * $Id: desktop.c,v 1.24 2003-03-09 19:55:33 didg Exp $ * * See COPYRIGHT. * @@ -45,10 +45,15 @@ #include "fork.h" #include "globals.h" #include "desktop.h" + #ifdef FILE_MANGLING #include "mangle.h" #endif /* CNID_DB */ +#ifdef AFP3x +#include +#endif + int afp_opendt(obj, ibuf, ibuflen, rbuf, rbuflen ) AFPObj *obj; char *ibuf, *rbuf; @@ -609,27 +614,19 @@ char *dtfile(const struct vol *vol, u_char creator[], char *ext ) return( path ); } -/* +/* --------------------------- * mpath is only a filename */ -char *mtoupath(const struct vol *vol, char *mpath) +static char upath[ MAXPATHLEN + 1]; +static char mpath[ MAXPATHLEN + 1]; +static char ucs2[ MAXPATHLEN + 1]; + +static char *old_mtoupath(const struct vol *vol, char *mpath) { - static char upath[ MAXPATHLEN + 1]; char *m, *u; int i = 0; int changed = 0; - if ( *mpath == '\0' ) { - return( "." ); - } - -#ifdef FILE_MANGLING - m = demangle(vol, mpath); - if (m != mpath) { - changed = 1; - mpath = m; - } -#endif /* FILE_MANGLING */ m = mpath; u = upath; while ( *m != '\0' ) { @@ -651,7 +648,7 @@ char *mtoupath(const struct vol *vol, char *mpath) * H.P. Jansen */ #ifdef DEBUG LOG(log_debug, logtype_afpd, "mtoupath: hex encode: 0x%x", (unsigned char) *m); -#endif /* DEBUG */ +#endif *u++ = ':'; *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ]; *u = hexdig[ *m & 0x0f ]; @@ -662,12 +659,12 @@ char *mtoupath(const struct vol *vol, char *mpath) (!isascii(*m) || *m == '/')) || (((vol->v_flags & AFPVOL_USEDOTS) == 0) && ( i == 0 && (*m == '.' )))) { -#else /* AD_VERSION == AD_VERSION1 */ +#else if ((((vol->v_flags & AFPVOL_NOHEX) == 0) && (!isprint(*m) || *m == '/')) || (((vol->v_flags & AFPVOL_USEDOTS) == 0) && ( i == 0 && (*m == '.' )))) { -#endif /* AD_VERSION == AD_VERSION1 */ +#endif /* do hex conversion. */ *u++ = ':'; *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ]; @@ -689,12 +686,12 @@ char *mtoupath(const struct vol *vol, char *mpath) return( (changed)?upath:mpath ); } +/* ---------------------------- */ #define hextoint( c ) ( isdigit( c ) ? c - '0' : c + 10 - 'a' ) #define islxdigit(x) (!isupper(x)&&isxdigit(x)) -char *utompath(const struct vol *vol, char *upath) +static char *old_utompath(const struct vol *vol, char *upath) { - static char mpath[ MAXPATHLEN + 1]; char *m, *u; int h; int changed = 0; @@ -704,13 +701,11 @@ char *utompath(const struct vol *vol, char *upath) m = mpath; while ( *u != '\0' ) { /* we have a code page */ -#if 1 if (vol->v_utompage && ((*u & 0x80) || (vol->v_flags & AFPVOL_MAPASCII))) { *m = vol->v_utompage->map[(unsigned char) *u].value; changed = 1; } else -#endif /* 1 */ if ( *u == ':' && *(u+1) != '\0' && islxdigit( *(u+1)) && *(u+2) != '\0' && islxdigit( *(u+2))) { ++u; @@ -735,7 +730,7 @@ char *utompath(const struct vol *vol, char *upath) m = mpath; #ifdef FILE_MANGLING - m = mangle(vol, mpath); + m = mangle(vol, mpath, upath, 0); if (m != mpath) { changed = 1; } @@ -748,6 +743,252 @@ char *utompath(const struct vol *vol, char *upath) return((changed)? m:upath ); } +/* --------------- */ +extern unsigned int do_precomposition(unsigned int base, unsigned int comb); + +static char comp[MAXPATHLEN +1]; + +static char *precompose(u_int16_t *name, size_t inplen, size_t *outlen) +{ +size_t i; +u_int16_t base, comb; +u_int16_t *in, *out; +u_int16_t result; + + if (!inplen || (inplen & 1) || inplen > sizeof(comp)/sizeof(u_int16_t)) + return NULL; + i = 0; + in = name; + out = (u_int16_t *)comp; + *outlen = 0; + + base = *in; + while (1) { + i += 2; + in++; + if (i == inplen) { + *out = base; + *outlen += 2; + return comp; + } + comb = *in; + if (comb >= 0x300 && (result = do_precomposition(base, comb))) { + *out = result; + out++; + *outlen += 2; + i += 2; + in++; + if (i == inplen) + return comp; + base = *in; + } + else { + *out = base; + out++; + *outlen += 2; + base = comb; + } + } +} + +/* --------------- */ +extern unsigned int do_decomposition(unsigned int base); + +static char *decompose(u_int16_t *name, size_t inplen, size_t *outlen) +{ +size_t i; +u_int16_t base; +u_int16_t *in, *out; +unsigned int result; + + if (!inplen || (inplen & 1)) + return NULL; + i = 0; + in = name; + out = (u_int16_t *)comp; + *outlen = 0; + + while (i < inplen) { + if (*outlen >= sizeof(comp)/sizeof(u_int16_t) +2) { + return NULL; + } + base = *in; + if ((result = do_decomposition(base))) { + *out = result >> 16; + out++; + *outlen += 2; + *out = result & 0xffff; + out++; + *outlen += 2; + } + else { + *out = base; + out++; + *outlen += 2; + } + i += 2; + in++; + } + return comp; +} + +/* --------------------------- */ +char *mtoupath(const struct vol *vol, char *mpath, int utf8) +{ + char *m, *u, *r; + int i = 0; + size_t inplen; + size_t outlen; + + if ( *mpath == '\0' ) { + return( "." ); + } + +#ifdef FILE_MANGLING + m = demangle(vol, mpath); + if (m != mpath) { + return m; + } +#endif /* FILE_MANGLING */ + + if (!vol_utf8(vol)) + return old_mtoupath(vol, mpath); + + m = mpath; + u = upath; + while ( *m != '\0' ) { + if ( (!(vol->v_flags & AFPVOL_NOHEX) && *m == '/') || + (!(vol->v_flags & AFPVOL_USEDOTS) && i == 0 && *m == '.') || + (!utf8 && (unsigned char)*m == 0xf0) /* Apple logo */ + ) { + /* do hex conversion. */ + *u++ = ':'; + *u++ = hexdig[ ( *m & 0xf0 ) >> 4 ]; + *u = hexdig[ *m & 0x0f ]; + } else + *u = *m; + u++; + i++; + m++; + } + *u = '\0'; + u = upath; +#ifdef AFP3x + inplen = strlen(u); + outlen = MAXPATHLEN; + r = ucs2; + if (!utf8) { + if ((size_t)(-1) == iconv(vol->v_mactoutf8, 0,0,0,0) ) + return NULL; + /* assume precompose */ + if ((size_t)(-1) == iconv(vol->v_mactoutf8, &u, &inplen, &r, &outlen)) + return NULL; + u = ucs2; + } + else { + if ((size_t)(-1) == iconv(vol->v_utf8toucs2, 0,0,0,0) ) + return NULL; + + if ((size_t)(-1) == iconv(vol->v_utf8toucs2, &u, &inplen, &r, &outlen)) + return NULL; + + u = precompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen); + + if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, 0,0,0,0)) + return NULL; + + outlen = MAXPATHLEN; + r = upath; + if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, &u, &inplen, &r, &outlen)) + return NULL; + u = upath; + } + u[MAXPATHLEN -outlen] = 0; +#endif +#ifdef DEBUG + LOG(log_debug, logtype_afpd, "mtoupath: '%s':'%s'", mpath, upath); +#endif /* DEBUG */ + return( u ); +} + +/* --------------- */ +char *utompath(const struct vol *vol, char *upath, int utf8) +{ + char *m, *u, *r; + int h; + int mangleflag = 0; + size_t inplen; + size_t outlen; + + if (!vol_utf8(vol)) + return old_utompath(vol, upath); + /* do the hex conversion */ + u = upath; + m = mpath; + while ( *u != '\0' ) { + if ( *u == ':' && islxdigit( *(u+1)) && islxdigit( *(u+2))) { + ++u; + h = hextoint( *u ) << 4; + ++u; + h |= hextoint( *u ); + *m = h; + } else + *m = *u; + u++; + m++; + } + *m = '\0'; + m = mpath; +#ifdef AFP3x + if ((size_t)(-1) == iconv(vol->v_utf8toucs2, 0,0,0,0) ) + return NULL; + inplen = strlen(mpath); + outlen = MAXPATHLEN; + r = ucs2; + if ((size_t)(-1) == iconv(vol->v_utf8toucs2, &m, &inplen, &r, &outlen)) + return NULL; + + if (utf8) { + if ( NULL == (m = decompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen))) + return NULL; + + if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, 0,0,0,0)) + return NULL; + + outlen = MAXPATHLEN; + r = mpath; + if ((size_t)(-1) == iconv(vol->v_ucs2toutf8, &m, &inplen, &r, &outlen)) + return NULL; + } + else { + m = precompose((u_int16_t *)ucs2, MAXPATHLEN -outlen, &inplen); + + if ((size_t)(-1) == iconv(vol->v_ucs2tomac, 0,0,0,0)) + return NULL; + + outlen = MAXPATHLEN; + r = mpath; + if ((size_t)(-1) == iconv(vol->v_ucs2tomac, &m, &inplen, &r, &outlen)) { + switch (errno) { + case EILSEQ: + if (outlen != MAXPATHLEN) { + mangleflag = 1; + } + default: + return NULL; + } + } + } + mpath[MAXPATHLEN -outlen] = 0; +#endif +#ifdef FILE_MANGLING + m = mangle(vol, mpath, upath, mangleflag); +#endif /* FILE_MANGLING */ + + return(m); +} + +/* ----------------------------- */ int afp_addcomment(obj, ibuf, ibuflen, rbuf, rbuflen ) AFPObj *obj; char *ibuf, *rbuf; diff --git a/etc/afpd/desktop.h b/etc/afpd/desktop.h index 1f636272..f766c757 100644 --- a/etc/afpd/desktop.h +++ b/etc/afpd/desktop.h @@ -1,5 +1,5 @@ /* - * $Id: desktop.h,v 1.2 2001-06-20 18:33:04 rufustfirefly Exp $ + * $Id: desktop.h,v 1.3 2003-03-09 19:55:33 didg Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. @@ -46,8 +46,8 @@ struct savedt { typedef unsigned char CreatorType[4]; extern char *dtfile __P((const struct vol *, u_char [], char *)); -extern char *mtoupath __P((const struct vol *, char *)); -extern char *utompath __P((const struct vol *, char *)); +extern char *mtoupath __P((const struct vol *, char *, int utf8)); +extern char *utompath __P((const struct vol *, char *, int utf8)); extern u_char ucreator[]; #define validupath(vol, name) ((((vol)->v_flags & AFPVOL_USEDOTS) ? \ diff --git a/etc/afpd/directory.c b/etc/afpd/directory.c index aeab2c83..14a0a149 100644 --- a/etc/afpd/directory.c +++ b/etc/afpd/directory.c @@ -1,5 +1,5 @@ /* - * $Id: directory.c,v 1.62 2003-02-16 12:35:04 didg Exp $ + * $Id: directory.c,v 1.63 2003-03-09 19:55:33 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -182,7 +182,10 @@ u_int32_t did; return NULL; } ptr = path + MAXPATHLEN; - mpath = utompath(vol, upath); + if (NULL == ( mpath = utompath(vol, upath, utf8_encoding()) ) ) { + afp_errno = AFPERR_NOOBJ; + return NULL; + } len = strlen(mpath); pathlen = len; /* no 0 in the last part */ len++; @@ -193,11 +196,14 @@ u_int32_t did; if (ret != NULL) { break; } - if (NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, buflen))) { + if ( NULL == (upath = cnid_resolve(vol->v_db, &id, buffer, buflen)) + || + NULL == (mpath = utompath(vol, upath, utf8_encoding())) + ) { afp_errno = AFPERR_NOOBJ; return NULL; } - mpath = utompath(vol, upath); + len = strlen(mpath) + 1; pathlen += len; if (pathlen > 255) { @@ -528,10 +534,13 @@ struct vol *vol; struct dir *dir; struct path *path; { - char *p; + path->u_name = mtoupath(vol, path->m_name, utf8_encoding() ); - path->u_name = p = mtoupath(vol, path->m_name ); - if ( of_stat( path ) != 0 ) { + if ( path->u_name == NULL) { + afp_errno = AFPERR_PARAM; + return NULL; + } + if (of_stat( path ) != 0 ) { return( NULL ); } @@ -1051,7 +1060,7 @@ char **cpath; if ( cdir == NULL ) { - if ( len > 0 ) { + if ( len > 0 || !ret.u_name) { return NULL; } @@ -1348,12 +1357,12 @@ int getdirparams(const struct vol *vol, if ( l_nameoff ) { ashort = htons( data - buf ); memcpy( l_nameoff, &ashort, sizeof( ashort )); - data = set_name(data, dir->d_m_name, 0); + data = set_name(vol, data, dir->d_m_name, 0); } if ( utf_nameoff ) { ashort = htons( data - buf ); memcpy( utf_nameoff, &ashort, sizeof( ashort )); - data = set_name(data, dir->d_m_name, utf8); + data = set_name(vol, data, dir->d_m_name, utf8); } if ( isad ) { ad_close( &ad, ADFLAGS_HF ); diff --git a/etc/afpd/directory.h b/etc/afpd/directory.h index f978c340..c7cfc6ac 100644 --- a/etc/afpd/directory.h +++ b/etc/afpd/directory.h @@ -1,5 +1,5 @@ /* - * $Id: directory.h,v 1.10 2003-01-26 10:42:40 didg Exp $ + * $Id: directory.h,v 1.11 2003-03-09 19:55:34 didg Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. @@ -55,7 +55,7 @@ struct dir { time_t ctime; /* inode ctime */ int offcnt; /* offspring count */ - char *d_m_name; /* mac name */ + char *d_m_name; /* mac name */ char *d_u_name; /* unix name */ }; @@ -175,6 +175,7 @@ struct maccess { #define AR_UOWN (1<<7) extern struct dir *dirnew __P((const char *, const char *)); +extern void dirfreename __P((struct dir *)); extern void dirfree __P((struct dir *)); extern struct dir *dirsearch __P((const struct vol *, u_int32_t)); extern struct dir *dirlookup __P((const struct vol *, u_int32_t)); diff --git a/etc/afpd/enumerate.c b/etc/afpd/enumerate.c index 8c161d8d..0bb64e46 100644 --- a/etc/afpd/enumerate.c +++ b/etc/afpd/enumerate.c @@ -1,5 +1,5 @@ /* - * $Id: enumerate.c,v 1.34 2003-02-16 12:35:04 didg Exp $ + * $Id: enumerate.c,v 1.35 2003-03-09 19:55:34 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -47,9 +47,6 @@ struct path *path; int upathlen; char *name; char *upath; -#ifndef USE_LASTDID - struct stat lst, *lstp; -#endif /* USE_LASTDID */ struct stat *st; upath = path->u_name; @@ -61,38 +58,9 @@ struct path *path; return NULL; } - cdir->d_did = 0; - -#ifdef CNID_DB - /* add to cnid db */ - cdir->d_did = cnid_add(vol->v_db, st, dir->d_did, upath, - upathlen, cdir->d_did); - /* Fail out if things go bad with CNID. */ - if (cdir->d_did == CNID_INVALID) { - switch (errno) { - case CNID_ERR_CLOSE: /* the db is closed */ - break; - case CNID_ERR_PARAM: - LOG(log_error, logtype_afpd, "adddir: Incorrect parameters passed to cnid_add"); - return NULL; - case CNID_ERR_PATH: - case CNID_ERR_DB: - case CNID_ERR_MAX: - return NULL; - } - } -#endif /* CNID_DB */ - - if (cdir->d_did == 0) { -#ifdef USE_LASTDID - /* last way of doing DIDs */ - cdir->d_did = htonl( vol->v_lastdid++ ); -#else /* USE_LASTDID */ - lstp = lstat(upath, &lst) < 0 ? st : &lst; - /* the old way of doing DIDs (default) */ - cdir->d_did = htonl( CNID(lstp, 0) ); -#endif /* USE_LASTDID */ - } + cdir->d_did = get_id(vol, NULL, st, dir->d_did, upath, upathlen); + if (cdir->d_did == 0) + return NULL; if ((edir = dirinsert( vol, cdir ))) { /* it's not possible with LASTDID @@ -195,9 +163,11 @@ char *check_dirent(const struct vol *vol, char *name) /* check for vetoed filenames */ if (veto_file(vol->v_veto, name)) return NULL; + if (NULL == (m_name = utompath(vol, name, utf8_encoding()))) + return NULL; /* now check against too big a file */ - if (strlen(m_name = utompath(vol, name)) > vol->max_filename) + if (strlen(m_name) > vol->max_filename) return NULL; return m_name; @@ -444,8 +414,8 @@ int ext; } dir = dirsearch_byname(curdir, s_path.u_name); if (!dir) { - s_path.m_name = utompath(vol, s_path.u_name); - if ((dir = adddir( vol, curdir, &s_path)) == NULL) { + s_path.m_name = utompath(vol, s_path.u_name, utf8_encoding() ); + if (s_path.m_name == NULL || (dir = adddir( vol, curdir, &s_path)) == NULL) { return AFPERR_MISC; } } @@ -462,7 +432,10 @@ int ext; sd.sd_last += len + 1; continue; } - s_path.m_name = utompath(vol, s_path.u_name); + s_path.m_name = utompath(vol, s_path.u_name, utf8_encoding()); + if (s_path.m_name == NULL ) { + return AFPERR_MISC; + } if (AFP_OK != ( ret = getfilparams(vol, fbitmap, &s_path, curdir, data + header , &esz )) ) { return( ret ); diff --git a/etc/afpd/file.c b/etc/afpd/file.c index b395d8b3..f88976bf 100644 --- a/etc/afpd/file.c +++ b/etc/afpd/file.c @@ -1,5 +1,5 @@ /* - * $Id: file.c,v 1.86 2003-02-19 18:59:52 jmarcus Exp $ + * $Id: file.c,v 1.87 2003-03-09 19:55:34 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -108,15 +108,29 @@ void *get_finderinfo(const char *mpath, struct adouble *adp, void *data) /* --------------------- */ -char *set_name(char *data, const char *name, u_int32_t utf8) +char *set_name(const struct vol *vol, char *data, char *name, u_int32_t utf8) { - u_int32_t aint; - + u_int32_t aint; + char *tp = NULL; + char *src = name; aint = strlen( name ); if (!utf8) { - if (afp_version >= 30) { - /* the name is in utf8 */ + /* want mac name */ + if (utf8_encoding()) { + /* but name is an utf8 mac name */ + char *u, *m; + + /* global static variable... */ + tp = strdup(name); + if (!(u = mtoupath(vol, name, 1)) || !(m = utompath(vol, u, 0))) { + aint = 0; + } + else { + aint = strlen(m); + src = m; + } + } if (aint > MACFILELEN) aint = MACFILELEN; @@ -137,9 +151,12 @@ char *set_name(char *data, const char *name, u_int32_t utf8) data += sizeof(temp); } - memcpy( data, name, aint ); + memcpy( data, src, aint ); data += aint; - + if (tp) { + strcpy(name, tp); + free(tp); + } return data; } @@ -155,16 +172,88 @@ char *set_name(char *data, const char *name, u_int32_t utf8) (1 << FILPBIT_EXTRFLEN) |\ (1 << FILPBIT_PDINFO))) +/* -------------------------- */ +u_int32_t get_id(struct vol *vol, struct adouble *adp, const struct stat *st, + const cnid_t did, const char *upath, const int len) +{ +u_int32_t aint = 0; + +#ifdef CNID_DB + + aint = cnid_add(vol->v_db, st, did, upath, len, aint); + /* Throw errors if cnid_add fails. */ + if (aint == CNID_INVALID) { + switch (errno) { + case CNID_ERR_CLOSE: /* the db is closed */ + break; + case CNID_ERR_PARAM: + LOG(log_error, logtype_afpd, "get_id: Incorrect parameters passed to cnid_add"); + afp_errno = AFPERR_PARAM; + return CNID_INVALID; + case CNID_ERR_PATH: + afp_errno = AFPERR_PARAM; + return CNID_INVALID; + default: + afp_errno = AFPERR_MISC; + return CNID_INVALID; + } + } +#endif /* CNID_DB */ + + if (aint == 0) { + /* + * First thing: DID and FNUMs are + * in the same space for purposes of enumerate (and several + * other wierd places). While we consider this Apple's bug, + * this is the work-around: In order to maintain constant and + * unique DIDs and FNUMs, we monotonically generate the DIDs + * during the session, and derive the FNUMs from the filesystem. + * Since the DIDs are small, we insure that the FNUMs are fairly + * large by setting thier high bits to the device number. + * + * AFS already does something very similar to this for the + * inode number, so we don't repeat the procedure. + * + * new algorithm: + * due to complaints over did's being non-persistent, + * here's the current hack to provide semi-persistent + * did's: + * 1) we reserve the first bit for file ids. + * 2) the next 7 bits are for the device. + * 3) the remaining 24 bits are for the inode. + * + * both the inode and device information are actually hashes + * that are then truncated to the requisite bit length. + * + * it should be okay to use lstat to deal with symlinks. + */ +#ifdef USE_LASTDID + if ( S_ISDIR(st->st_mode)) { + aint = htonl( vol->v_lastdid++ ); + } + else + { + aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff)); + } +#else /* USE_LASTDID */ + { + struct stat lst; + const struct stat *lstp; + lstp = lstat(upath, &lst) < 0 ? st : &lst; + aint = htonl(CNID(lstp, 1)); + } +#endif /* USE_LASTDID */ + } + return aint; +} + /* -------------------------- */ int getmetadata(struct vol *vol, u_int16_t bitmap, struct path *path, struct dir *dir, char *buf, int *buflen, struct adouble *adp, int attrbits ) { -#ifndef USE_LASTDID - struct stat lst, *lstp; -#endif /* USE_LASTDID */ char *data, *l_nameoff = NULL, *upath; char *utf_nameoff = NULL; int bit = 0; @@ -252,7 +341,6 @@ int getmetadata(struct vol *vol, memcpy(data + FINDERINFO_FRFLAGOFF, &ashort, sizeof(ashort)); } } - data += 32; break; @@ -267,66 +355,9 @@ int getmetadata(struct vol *vol, break; case FILPBIT_FNUM : - aint = 0; -#if AD_VERSION > AD_VERSION1 - /* look in AD v2 header */ - if (adp) - memcpy(&aint, ad_entry(adp, ADEID_DID), sizeof(aint)); -#endif /* AD_VERSION > AD_VERSION1 */ - -#ifdef CNID_DB - aint = cnid_add(vol->v_db, st, dir->d_did, upath, - strlen(upath), aint); - /* Throw errors if cnid_add fails. */ - if (aint == CNID_INVALID) { - switch (errno) { - case CNID_ERR_PARAM: - LOG(log_error, logtype_afpd, "getfilparams: Incorrect parameters passed to cnid_add"); - return(AFPERR_PARAM); - case CNID_ERR_PATH: - return(AFPERR_PARAM); - case CNID_ERR_DB: - case CNID_ERR_MAX: - return(AFPERR_MISC); - } - } -#endif /* CNID_DB */ - - if (aint == 0) { - /* - * What a fucking mess. First thing: DID and FNUMs are - * in the same space for purposes of enumerate (and several - * other wierd places). While we consider this Apple's bug, - * this is the work-around: In order to maintain constant and - * unique DIDs and FNUMs, we monotonically generate the DIDs - * during the session, and derive the FNUMs from the filesystem. - * Since the DIDs are small, we insure that the FNUMs are fairly - * large by setting thier high bits to the device number. - * - * AFS already does something very similar to this for the - * inode number, so we don't repeat the procedure. - * - * new algorithm: - * due to complaints over did's being non-persistent, - * here's the current hack to provide semi-persistent - * did's: - * 1) we reserve the first bit for file ids. - * 2) the next 7 bits are for the device. - * 3) the remaining 24 bits are for the inode. - * - * both the inode and device information are actually hashes - * that are then truncated to the requisite bit length. - * - * it should be okay to use lstat to deal with symlinks. - */ -#ifdef USE_LASTDID - aint = htonl(( st->st_dev << 16 ) | (st->st_ino & 0x0000ffff)); -#else /* USE_LASTDID */ - lstp = lstat(upath, &lst) < 0 ? st : &lst; - aint = htonl(CNID(lstp, 1)); -#endif /* USE_LASTDID */ - } - + aint = get_id(vol, adp, st, dir->d_did, upath, strlen(upath)); + if (aint == 0) + return afp_errno; memcpy(data, &aint, sizeof( aint )); data += sizeof( aint ); break; @@ -438,12 +469,12 @@ int getmetadata(struct vol *vol, if ( l_nameoff ) { ashort = htons( data - buf ); memcpy(l_nameoff, &ashort, sizeof( ashort )); - data = set_name(data, path->m_name, 0); + data = set_name(vol, data, path->m_name, 0); } if ( utf_nameoff ) { ashort = htons( data - buf ); memcpy(utf_nameoff, &ashort, sizeof( ashort )); - data = set_name(data, path->m_name, utf8); + data = set_name(vol, data, path->m_name, utf8); } *buflen = data - buf; return (AFP_OK); @@ -1119,7 +1150,9 @@ int ibuflen, *rbuflen; return( AFPERR_PARAM ); } - upath = mtoupath(vol, newname); + if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))) { + return( AFPERR_PARAM ); + } if ( (err = copyfile(p, upath , newname, vol_noadouble(vol))) < 0 ) { return err; } @@ -1414,9 +1447,6 @@ char *ibuf, *rbuf; int ibuflen, *rbuflen; { struct stat *st; -#if AD_VERSION > AD_VERSION1 - struct adouble ad; -#endif struct vol *vol; struct dir *dir; char *upath; @@ -1430,6 +1460,7 @@ int ibuflen, *rbuflen; #endif /* DEBUG */ *rbuflen = 0; + ibuf += 2; memcpy(&vid, ibuf, sizeof(vid)); @@ -1439,6 +1470,10 @@ int ibuflen, *rbuflen; return( AFPERR_PARAM); } + if (vol->v_db == NULL) { + return AFPERR_NOOP; + } + if (vol->v_flags & AFPVOL_RO) return AFPERR_VLOCK; @@ -1476,15 +1511,7 @@ int ibuflen, *rbuflen; return AFPERR_EXISTID; } -#if AD_VERSION > AD_VERSION1 - memset(&ad, 0, sizeof(ad)); - if (ad_open( upath, ADFLAGS_HF, O_RDONLY, 0, &ad ) >= 0) { - memcpy(&id, ad_entry(&ad, ADEID_DID), sizeof(id)); - ad_close(&ad, ADFLAGS_HF); - } -#endif /* AD_VERSION > AD_VERSION1 */ - - if ((id = cnid_add(vol->v_db, st, did, upath, len, id)) != CNID_INVALID) { + if ((id = get_id(vol, NULL, st, did, upath, len)) != CNID_INVALID) { memcpy(rbuf, &id, sizeof(id)); *rbuflen = sizeof(id); return AFP_OK; @@ -1493,19 +1520,7 @@ int ibuflen, *rbuflen; #ifdef DEBUG LOG(log_info, logtype_afpd, "ending afp_createid...:"); #endif /* DEBUG */ - - switch (errno) { - case EROFS: - return AFPERR_VLOCK; - break; - case EPERM: - case EACCES: - return AFPERR_ACCESS; - break; - default: - LOG(log_error, logtype_afpd, "afp_createid: cnid_add: %s", strerror(errno)); - return AFPERR_PARAM; - } + return afp_errno; } /* ------------------------------ @@ -1540,6 +1555,10 @@ int ibuflen, *rbuflen; return( AFPERR_PARAM); } + if (vol->v_db == NULL) { + return AFPERR_NOOP; + } + memcpy(&id, ibuf, sizeof( id )); ibuf += sizeof(id); @@ -1568,7 +1587,9 @@ int ibuflen, *rbuflen; memcpy(&bitmap, ibuf, sizeof(bitmap)); bitmap = ntohs( bitmap ); - path.m_name = utompath(vol, upath); + if (NULL == (path.m_name = utompath(vol, upath, utf8_encoding()))) { + return AFPERR_NOID; + } if (AFP_OK != (err = getfilparams(vol, bitmap, &path , curdir, rbuf + sizeof(bitmap), &buflen))) { return err; @@ -1614,6 +1635,10 @@ int ibuflen, *rbuflen; return( AFPERR_PARAM); } + if (vol->v_db == NULL) { + return AFPERR_NOOP; + } + if (vol->v_flags & AFPVOL_RO) return AFPERR_VLOCK; diff --git a/etc/afpd/file.h b/etc/afpd/file.h index 2c523b8e..f97ce03b 100644 --- a/etc/afpd/file.h +++ b/etc/afpd/file.h @@ -1,5 +1,5 @@ /* - * $Id: file.h,v 1.15 2003-02-16 12:35:04 didg Exp $ + * $Id: file.h,v 1.16 2003-03-09 19:55:34 didg Exp $ * * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. @@ -74,7 +74,7 @@ struct extmap { }; #define kTextEncodingUTF8 0x08000103 -extern char *set_name __P((char *, const char *, u_int32_t ) ); +extern char *set_name __P((const struct vol *, char *, char *, u_int32_t ) ); extern struct extmap *getextmap __P((const char *)); extern struct extmap *getdefextmap __P((void)); @@ -90,6 +90,9 @@ extern int deletefile __P((struct vol *, char *, int)); extern void *get_finderinfo __P((const char *, struct adouble *, void *)); extern int copy_path_name __P((char *, char *i)); +extern u_int32_t get_id __P((struct vol *, struct adouble *, const struct stat *, + const cnid_t , const char *, const int )); + /* FP functions */ extern int afp_exchangefiles __P((AFPObj *, char *, int, char *, int *)); extern int afp_setfilparams __P((AFPObj *, char *, int, char *, int *)); diff --git a/etc/afpd/filedir.c b/etc/afpd/filedir.c index de03e292..dd2795af 100644 --- a/etc/afpd/filedir.c +++ b/etc/afpd/filedir.c @@ -1,5 +1,5 @@ /* - * $Id: filedir.c,v 1.41 2003-02-16 12:35:04 didg Exp $ + * $Id: filedir.c,v 1.42 2003-03-09 19:55:34 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -361,7 +361,10 @@ int isdir; if (!isdir) { #ifdef CNID_DB - p = mtoupath(vol, oldname); + p = mtoupath(vol, oldname, utf8_encoding()); + if (!p) { + return AFPERR_PARAM; /* can't convert */ + } id = cnid_get(vol->v_db, sdir->d_did, p, strlen(p)); #endif /* CNID_DB */ p = ctoupath( vol, sdir, oldname ); @@ -400,7 +403,9 @@ int isdir; return(AFPERR_OLOCK); } - upath = mtoupath(vol, newname); + if (NULL == (upath = mtoupath(vol, newname, utf8_encoding()))){ + return AFPERR_PARAM; + } path.u_name = upath; st = &path.st; if (0 != (rc = check_name(vol, upath))) { @@ -609,6 +614,9 @@ char *u; char *p; int len; + if (u == NULL) + return NULL; + p = path + sizeof( path ) - 1; *p = '\0'; len = strlen( u ); @@ -643,7 +651,7 @@ const struct vol *vol; struct dir *dir; char *name; { - return absupath(vol, dir, mtoupath(vol, name)); + return absupath(vol, dir, mtoupath(vol, name, utf8_encoding())); } /* ------------------------- */ @@ -735,8 +743,11 @@ int ibuflen, *rbuflen; rc = moveandrename(vol, sdir, oldname, newname, isdir); if ( rc == AFP_OK ) { - char *upath = mtoupath(vol, newname); - + char *upath = mtoupath(vol, newname, utf8_encoding()); + + if (NULL == upath) { + return AFPERR_PARAM; + } curdir->offcnt++; sdir->offcnt--; #ifdef DROPKLUDGE diff --git a/etc/afpd/fork.c b/etc/afpd/fork.c index 53779a02..0430e1a0 100644 --- a/etc/afpd/fork.c +++ b/etc/afpd/fork.c @@ -1,5 +1,5 @@ /* - * $Id: fork.c,v 1.49 2003-02-16 12:35:04 didg Exp $ + * $Id: fork.c,v 1.50 2003-03-09 19:55:35 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -86,7 +86,9 @@ const u_int16_t attrbits; vol = ofork->of_vol; dir = ofork->of_dir; - path.u_name = mtoupath(vol, ofork->of_name); + if (NULL == (path.u_name = mtoupath(vol, ofork->of_name, utf8_encoding()))) { + return( AFPERR_MISC ); + } path.m_name = ofork->of_name; st = &path.st; if ( bitmap & ( (1<max_filename) { + if (!flags && strlen(filename) <= vol->max_filename) { return filename; } - - /* First, attmept to locate a file extension. */ + /* First, attempt to locate a file extension. */ if (NULL != (ext = strrchr(filename, '.')) ) { ext_len = strlen(ext); if (ext_len > MAX_EXT_LENGTH) { @@ -86,7 +91,7 @@ mangle(const struct vol *vol, char *filename) { } tf = cnid_mangle_get(vol->v_db, m); - if (tf == NULL || (strcmp(tf, filename)) == 0) { + if (tf == NULL || (strcmp(tf, uname)) == 0) { break; } else { @@ -97,7 +102,7 @@ mangle(const struct vol *vol, char *filename) { } } - if (cnid_mangle_add(vol->v_db, m, filename) < 0) { + if (cnid_mangle_add(vol->v_db, m, uname) < 0) { return filename; } diff --git a/etc/afpd/mangle.h b/etc/afpd/mangle.h index 2d80c8a3..ac01a7a6 100644 --- a/etc/afpd/mangle.h +++ b/etc/afpd/mangle.h @@ -1,5 +1,5 @@ /* - * $Id: mangle.h,v 1.3 2002-10-17 18:01:54 didg Exp $ + * $Id: mangle.h,v 1.4 2003-03-09 19:55:35 didg Exp $ * */ @@ -9,6 +9,8 @@ #include #include #include + +#include #ifdef CNID_DB #include #endif /* CNID_DB */ @@ -24,7 +26,7 @@ #define MAX_EXT_LENGTH 4 /* XXX This cannot be greater than 27 */ #define MAX_LENGTH MACFILELEN -extern char *mangle __P((const struct vol *, char *)); +extern char *mangle __P((const struct vol *, char *, char *, int)); extern char *demangle __P((const struct vol *, char *)); #endif /* AFPD_MANGLE_H */ diff --git a/etc/afpd/precompose.c b/etc/afpd/precompose.c new file mode 100644 index 00000000..95147268 --- /dev/null +++ b/etc/afpd/precompose.c @@ -0,0 +1,2043 @@ +/* + * Canonical Compositions + * + */ +/* $XFree86: xc/programs/xterm/precompose.c,v 1.2 2000/11/01 01:12:41 dawes Exp $ */ + +static const struct { + unsigned int replacement; + unsigned int base; + unsigned int comb; +} precompositions[] = { +{ 0x226E, 0x003C, 0x0338}, +{ 0x2260, 0x003D, 0x0338}, +{ 0x226F, 0x003E, 0x0338}, +{ 0x00C0, 0x0041, 0x0300}, +{ 0x00C1, 0x0041, 0x0301}, +{ 0x00C2, 0x0041, 0x0302}, +{ 0x00C3, 0x0041, 0x0303}, +{ 0x0100, 0x0041, 0x0304}, +{ 0x0102, 0x0041, 0x0306}, +{ 0x0226, 0x0041, 0x0307}, +{ 0x00C4, 0x0041, 0x0308}, +{ 0x1EA2, 0x0041, 0x0309}, +{ 0x00C5, 0x0041, 0x030A}, +{ 0x01CD, 0x0041, 0x030C}, +{ 0x0200, 0x0041, 0x030F}, +{ 0x0202, 0x0041, 0x0311}, +{ 0x1EA0, 0x0041, 0x0323}, +{ 0x1E00, 0x0041, 0x0325}, +{ 0x0104, 0x0041, 0x0328}, +{ 0x1E02, 0x0042, 0x0307}, +{ 0x1E04, 0x0042, 0x0323}, +{ 0x1E06, 0x0042, 0x0331}, +{ 0x0106, 0x0043, 0x0301}, +{ 0x0108, 0x0043, 0x0302}, +{ 0x010A, 0x0043, 0x0307}, +{ 0x010C, 0x0043, 0x030C}, +{ 0x00C7, 0x0043, 0x0327}, +{ 0x1E0A, 0x0044, 0x0307}, +{ 0x010E, 0x0044, 0x030C}, +{ 0x1E0C, 0x0044, 0x0323}, +{ 0x1E10, 0x0044, 0x0327}, +{ 0x1E12, 0x0044, 0x032D}, +{ 0x1E0E, 0x0044, 0x0331}, +{ 0x00C8, 0x0045, 0x0300}, +{ 0x00C9, 0x0045, 0x0301}, +{ 0x00CA, 0x0045, 0x0302}, +{ 0x1EBC, 0x0045, 0x0303}, +{ 0x0112, 0x0045, 0x0304}, +{ 0x0114, 0x0045, 0x0306}, +{ 0x0116, 0x0045, 0x0307}, +{ 0x00CB, 0x0045, 0x0308}, +{ 0x1EBA, 0x0045, 0x0309}, +{ 0x011A, 0x0045, 0x030C}, +{ 0x0204, 0x0045, 0x030F}, +{ 0x0206, 0x0045, 0x0311}, +{ 0x1EB8, 0x0045, 0x0323}, +{ 0x0228, 0x0045, 0x0327}, +{ 0x0118, 0x0045, 0x0328}, +{ 0x1E18, 0x0045, 0x032D}, +{ 0x1E1A, 0x0045, 0x0330}, +{ 0x1E1E, 0x0046, 0x0307}, +{ 0x01F4, 0x0047, 0x0301}, +{ 0x011C, 0x0047, 0x0302}, +{ 0x1E20, 0x0047, 0x0304}, +{ 0x011E, 0x0047, 0x0306}, +{ 0x0120, 0x0047, 0x0307}, +{ 0x01E6, 0x0047, 0x030C}, +{ 0x0122, 0x0047, 0x0327}, +{ 0x0124, 0x0048, 0x0302}, +{ 0x1E22, 0x0048, 0x0307}, +{ 0x1E26, 0x0048, 0x0308}, +{ 0x021E, 0x0048, 0x030C}, +{ 0x1E24, 0x0048, 0x0323}, +{ 0x1E28, 0x0048, 0x0327}, +{ 0x1E2A, 0x0048, 0x032E}, +{ 0x00CC, 0x0049, 0x0300}, +{ 0x00CD, 0x0049, 0x0301}, +{ 0x00CE, 0x0049, 0x0302}, +{ 0x0128, 0x0049, 0x0303}, +{ 0x012A, 0x0049, 0x0304}, +{ 0x012C, 0x0049, 0x0306}, +{ 0x0130, 0x0049, 0x0307}, +{ 0x00CF, 0x0049, 0x0308}, +{ 0x1EC8, 0x0049, 0x0309}, +{ 0x01CF, 0x0049, 0x030C}, +{ 0x0208, 0x0049, 0x030F}, +{ 0x020A, 0x0049, 0x0311}, +{ 0x1ECA, 0x0049, 0x0323}, +{ 0x012E, 0x0049, 0x0328}, +{ 0x1E2C, 0x0049, 0x0330}, +{ 0x0134, 0x004A, 0x0302}, +{ 0x1E30, 0x004B, 0x0301}, +{ 0x01E8, 0x004B, 0x030C}, +{ 0x1E32, 0x004B, 0x0323}, +{ 0x0136, 0x004B, 0x0327}, +{ 0x1E34, 0x004B, 0x0331}, +{ 0x0139, 0x004C, 0x0301}, +{ 0x013D, 0x004C, 0x030C}, +{ 0x1E36, 0x004C, 0x0323}, +{ 0x013B, 0x004C, 0x0327}, +{ 0x1E3C, 0x004C, 0x032D}, +{ 0x1E3A, 0x004C, 0x0331}, +{ 0x1E3E, 0x004D, 0x0301}, +{ 0x1E40, 0x004D, 0x0307}, +{ 0x1E42, 0x004D, 0x0323}, +{ 0x01F8, 0x004E, 0x0300}, +{ 0x0143, 0x004E, 0x0301}, +{ 0x00D1, 0x004E, 0x0303}, +{ 0x1E44, 0x004E, 0x0307}, +{ 0x0147, 0x004E, 0x030C}, +{ 0x1E46, 0x004E, 0x0323}, +{ 0x0145, 0x004E, 0x0327}, +{ 0x1E4A, 0x004E, 0x032D}, +{ 0x1E48, 0x004E, 0x0331}, +{ 0x00D2, 0x004F, 0x0300}, +{ 0x00D3, 0x004F, 0x0301}, +{ 0x00D4, 0x004F, 0x0302}, +{ 0x00D5, 0x004F, 0x0303}, +{ 0x014C, 0x004F, 0x0304}, +{ 0x014E, 0x004F, 0x0306}, +{ 0x022E, 0x004F, 0x0307}, +{ 0x00D6, 0x004F, 0x0308}, +{ 0x1ECE, 0x004F, 0x0309}, +{ 0x0150, 0x004F, 0x030B}, +{ 0x01D1, 0x004F, 0x030C}, +{ 0x020C, 0x004F, 0x030F}, +{ 0x020E, 0x004F, 0x0311}, +{ 0x01A0, 0x004F, 0x031B}, +{ 0x1ECC, 0x004F, 0x0323}, +{ 0x01EA, 0x004F, 0x0328}, +{ 0x1E54, 0x0050, 0x0301}, +{ 0x1E56, 0x0050, 0x0307}, +{ 0x0154, 0x0052, 0x0301}, +{ 0x1E58, 0x0052, 0x0307}, +{ 0x0158, 0x0052, 0x030C}, +{ 0x0210, 0x0052, 0x030F}, +{ 0x0212, 0x0052, 0x0311}, +{ 0x1E5A, 0x0052, 0x0323}, +{ 0x0156, 0x0052, 0x0327}, +{ 0x1E5E, 0x0052, 0x0331}, +{ 0x015A, 0x0053, 0x0301}, +{ 0x015C, 0x0053, 0x0302}, +{ 0x1E60, 0x0053, 0x0307}, +{ 0x0160, 0x0053, 0x030C}, +{ 0x1E62, 0x0053, 0x0323}, +{ 0x0218, 0x0053, 0x0326}, +{ 0x015E, 0x0053, 0x0327}, +{ 0x1E6A, 0x0054, 0x0307}, +{ 0x0164, 0x0054, 0x030C}, +{ 0x1E6C, 0x0054, 0x0323}, +{ 0x021A, 0x0054, 0x0326}, +{ 0x0162, 0x0054, 0x0327}, +{ 0x1E70, 0x0054, 0x032D}, +{ 0x1E6E, 0x0054, 0x0331}, +{ 0x00D9, 0x0055, 0x0300}, +{ 0x00DA, 0x0055, 0x0301}, +{ 0x00DB, 0x0055, 0x0302}, +{ 0x0168, 0x0055, 0x0303}, +{ 0x016A, 0x0055, 0x0304}, +{ 0x016C, 0x0055, 0x0306}, +{ 0x00DC, 0x0055, 0x0308}, +{ 0x1EE6, 0x0055, 0x0309}, +{ 0x016E, 0x0055, 0x030A}, +{ 0x0170, 0x0055, 0x030B}, +{ 0x01D3, 0x0055, 0x030C}, +{ 0x0214, 0x0055, 0x030F}, +{ 0x0216, 0x0055, 0x0311}, +{ 0x01AF, 0x0055, 0x031B}, +{ 0x1EE4, 0x0055, 0x0323}, +{ 0x1E72, 0x0055, 0x0324}, +{ 0x0172, 0x0055, 0x0328}, +{ 0x1E76, 0x0055, 0x032D}, +{ 0x1E74, 0x0055, 0x0330}, +{ 0x1E7C, 0x0056, 0x0303}, +{ 0x1E7E, 0x0056, 0x0323}, +{ 0x1E80, 0x0057, 0x0300}, +{ 0x1E82, 0x0057, 0x0301}, +{ 0x0174, 0x0057, 0x0302}, +{ 0x1E86, 0x0057, 0x0307}, +{ 0x1E84, 0x0057, 0x0308}, +{ 0x1E88, 0x0057, 0x0323}, +{ 0x1E8A, 0x0058, 0x0307}, +{ 0x1E8C, 0x0058, 0x0308}, +{ 0x1EF2, 0x0059, 0x0300}, +{ 0x00DD, 0x0059, 0x0301}, +{ 0x0176, 0x0059, 0x0302}, +{ 0x1EF8, 0x0059, 0x0303}, +{ 0x0232, 0x0059, 0x0304}, +{ 0x1E8E, 0x0059, 0x0307}, +{ 0x0178, 0x0059, 0x0308}, +{ 0x1EF6, 0x0059, 0x0309}, +{ 0x1EF4, 0x0059, 0x0323}, +{ 0x0179, 0x005A, 0x0301}, +{ 0x1E90, 0x005A, 0x0302}, +{ 0x017B, 0x005A, 0x0307}, +{ 0x017D, 0x005A, 0x030C}, +{ 0x1E92, 0x005A, 0x0323}, +{ 0x1E94, 0x005A, 0x0331}, +{ 0x00E0, 0x0061, 0x0300}, +{ 0x00E1, 0x0061, 0x0301}, +{ 0x00E2, 0x0061, 0x0302}, +{ 0x00E3, 0x0061, 0x0303}, +{ 0x0101, 0x0061, 0x0304}, +{ 0x0103, 0x0061, 0x0306}, +{ 0x0227, 0x0061, 0x0307}, +{ 0x00E4, 0x0061, 0x0308}, +{ 0x1EA3, 0x0061, 0x0309}, +{ 0x00E5, 0x0061, 0x030A}, +{ 0x01CE, 0x0061, 0x030C}, +{ 0x0201, 0x0061, 0x030F}, +{ 0x0203, 0x0061, 0x0311}, +{ 0x1EA1, 0x0061, 0x0323}, +{ 0x1E01, 0x0061, 0x0325}, +{ 0x0105, 0x0061, 0x0328}, +{ 0x1E03, 0x0062, 0x0307}, +{ 0x1E05, 0x0062, 0x0323}, +{ 0x1E07, 0x0062, 0x0331}, +{ 0x0107, 0x0063, 0x0301}, +{ 0x0109, 0x0063, 0x0302}, +{ 0x010B, 0x0063, 0x0307}, +{ 0x010D, 0x0063, 0x030C}, +{ 0x00E7, 0x0063, 0x0327}, +{ 0x1E0B, 0x0064, 0x0307}, +{ 0x010F, 0x0064, 0x030C}, +{ 0x1E0D, 0x0064, 0x0323}, +{ 0x1E11, 0x0064, 0x0327}, +{ 0x1E13, 0x0064, 0x032D}, +{ 0x1E0F, 0x0064, 0x0331}, +{ 0x00E8, 0x0065, 0x0300}, +{ 0x00E9, 0x0065, 0x0301}, +{ 0x00EA, 0x0065, 0x0302}, +{ 0x1EBD, 0x0065, 0x0303}, +{ 0x0113, 0x0065, 0x0304}, +{ 0x0115, 0x0065, 0x0306}, +{ 0x0117, 0x0065, 0x0307}, +{ 0x00EB, 0x0065, 0x0308}, +{ 0x1EBB, 0x0065, 0x0309}, +{ 0x011B, 0x0065, 0x030C}, +{ 0x0205, 0x0065, 0x030F}, +{ 0x0207, 0x0065, 0x0311}, +{ 0x1EB9, 0x0065, 0x0323}, +{ 0x0229, 0x0065, 0x0327}, +{ 0x0119, 0x0065, 0x0328}, +{ 0x1E19, 0x0065, 0x032D}, +{ 0x1E1B, 0x0065, 0x0330}, +{ 0x1E1F, 0x0066, 0x0307}, +{ 0x01F5, 0x0067, 0x0301}, +{ 0x011D, 0x0067, 0x0302}, +{ 0x1E21, 0x0067, 0x0304}, +{ 0x011F, 0x0067, 0x0306}, +{ 0x0121, 0x0067, 0x0307}, +{ 0x01E7, 0x0067, 0x030C}, +{ 0x0123, 0x0067, 0x0327}, +{ 0x0125, 0x0068, 0x0302}, +{ 0x1E23, 0x0068, 0x0307}, +{ 0x1E27, 0x0068, 0x0308}, +{ 0x021F, 0x0068, 0x030C}, +{ 0x1E25, 0x0068, 0x0323}, +{ 0x1E29, 0x0068, 0x0327}, +{ 0x1E2B, 0x0068, 0x032E}, +{ 0x1E96, 0x0068, 0x0331}, +{ 0x00EC, 0x0069, 0x0300}, +{ 0x00ED, 0x0069, 0x0301}, +{ 0x00EE, 0x0069, 0x0302}, +{ 0x0129, 0x0069, 0x0303}, +{ 0x012B, 0x0069, 0x0304}, +{ 0x012D, 0x0069, 0x0306}, +{ 0x00EF, 0x0069, 0x0308}, +{ 0x1EC9, 0x0069, 0x0309}, +{ 0x01D0, 0x0069, 0x030C}, +{ 0x0209, 0x0069, 0x030F}, +{ 0x020B, 0x0069, 0x0311}, +{ 0x1ECB, 0x0069, 0x0323}, +{ 0x012F, 0x0069, 0x0328}, +{ 0x1E2D, 0x0069, 0x0330}, +{ 0x0135, 0x006A, 0x0302}, +{ 0x01F0, 0x006A, 0x030C}, +{ 0x1E31, 0x006B, 0x0301}, +{ 0x01E9, 0x006B, 0x030C}, +{ 0x1E33, 0x006B, 0x0323}, +{ 0x0137, 0x006B, 0x0327}, +{ 0x1E35, 0x006B, 0x0331}, +{ 0x013A, 0x006C, 0x0301}, +{ 0x013E, 0x006C, 0x030C}, +{ 0x1E37, 0x006C, 0x0323}, +{ 0x013C, 0x006C, 0x0327}, +{ 0x1E3D, 0x006C, 0x032D}, +{ 0x1E3B, 0x006C, 0x0331}, +{ 0x1E3F, 0x006D, 0x0301}, +{ 0x1E41, 0x006D, 0x0307}, +{ 0x1E43, 0x006D, 0x0323}, +{ 0x01F9, 0x006E, 0x0300}, +{ 0x0144, 0x006E, 0x0301}, +{ 0x00F1, 0x006E, 0x0303}, +{ 0x1E45, 0x006E, 0x0307}, +{ 0x0148, 0x006E, 0x030C}, +{ 0x1E47, 0x006E, 0x0323}, +{ 0x0146, 0x006E, 0x0327}, +{ 0x1E4B, 0x006E, 0x032D}, +{ 0x1E49, 0x006E, 0x0331}, +{ 0x00F2, 0x006F, 0x0300}, +{ 0x00F3, 0x006F, 0x0301}, +{ 0x00F4, 0x006F, 0x0302}, +{ 0x00F5, 0x006F, 0x0303}, +{ 0x014D, 0x006F, 0x0304}, +{ 0x014F, 0x006F, 0x0306}, +{ 0x022F, 0x006F, 0x0307}, +{ 0x00F6, 0x006F, 0x0308}, +{ 0x1ECF, 0x006F, 0x0309}, +{ 0x0151, 0x006F, 0x030B}, +{ 0x01D2, 0x006F, 0x030C}, +{ 0x020D, 0x006F, 0x030F}, +{ 0x020F, 0x006F, 0x0311}, +{ 0x01A1, 0x006F, 0x031B}, +{ 0x1ECD, 0x006F, 0x0323}, +{ 0x01EB, 0x006F, 0x0328}, +{ 0x1E55, 0x0070, 0x0301}, +{ 0x1E57, 0x0070, 0x0307}, +{ 0x0155, 0x0072, 0x0301}, +{ 0x1E59, 0x0072, 0x0307}, +{ 0x0159, 0x0072, 0x030C}, +{ 0x0211, 0x0072, 0x030F}, +{ 0x0213, 0x0072, 0x0311}, +{ 0x1E5B, 0x0072, 0x0323}, +{ 0x0157, 0x0072, 0x0327}, +{ 0x1E5F, 0x0072, 0x0331}, +{ 0x015B, 0x0073, 0x0301}, +{ 0x015D, 0x0073, 0x0302}, +{ 0x1E61, 0x0073, 0x0307}, +{ 0x0161, 0x0073, 0x030C}, +{ 0x1E63, 0x0073, 0x0323}, +{ 0x0219, 0x0073, 0x0326}, +{ 0x015F, 0x0073, 0x0327}, +{ 0x1E6B, 0x0074, 0x0307}, +{ 0x1E97, 0x0074, 0x0308}, +{ 0x0165, 0x0074, 0x030C}, +{ 0x1E6D, 0x0074, 0x0323}, +{ 0x021B, 0x0074, 0x0326}, +{ 0x0163, 0x0074, 0x0327}, +{ 0x1E71, 0x0074, 0x032D}, +{ 0x1E6F, 0x0074, 0x0331}, +{ 0x00F9, 0x0075, 0x0300}, +{ 0x00FA, 0x0075, 0x0301}, +{ 0x00FB, 0x0075, 0x0302}, +{ 0x0169, 0x0075, 0x0303}, +{ 0x016B, 0x0075, 0x0304}, +{ 0x016D, 0x0075, 0x0306}, +{ 0x00FC, 0x0075, 0x0308}, +{ 0x1EE7, 0x0075, 0x0309}, +{ 0x016F, 0x0075, 0x030A}, +{ 0x0171, 0x0075, 0x030B}, +{ 0x01D4, 0x0075, 0x030C}, +{ 0x0215, 0x0075, 0x030F}, +{ 0x0217, 0x0075, 0x0311}, +{ 0x01B0, 0x0075, 0x031B}, +{ 0x1EE5, 0x0075, 0x0323}, +{ 0x1E73, 0x0075, 0x0324}, +{ 0x0173, 0x0075, 0x0328}, +{ 0x1E77, 0x0075, 0x032D}, +{ 0x1E75, 0x0075, 0x0330}, +{ 0x1E7D, 0x0076, 0x0303}, +{ 0x1E7F, 0x0076, 0x0323}, +{ 0x1E81, 0x0077, 0x0300}, +{ 0x1E83, 0x0077, 0x0301}, +{ 0x0175, 0x0077, 0x0302}, +{ 0x1E87, 0x0077, 0x0307}, +{ 0x1E85, 0x0077, 0x0308}, +{ 0x1E98, 0x0077, 0x030A}, +{ 0x1E89, 0x0077, 0x0323}, +{ 0x1E8B, 0x0078, 0x0307}, +{ 0x1E8D, 0x0078, 0x0308}, +{ 0x1EF3, 0x0079, 0x0300}, +{ 0x00FD, 0x0079, 0x0301}, +{ 0x0177, 0x0079, 0x0302}, +{ 0x1EF9, 0x0079, 0x0303}, +{ 0x0233, 0x0079, 0x0304}, +{ 0x1E8F, 0x0079, 0x0307}, +{ 0x00FF, 0x0079, 0x0308}, +{ 0x1EF7, 0x0079, 0x0309}, +{ 0x1E99, 0x0079, 0x030A}, +{ 0x1EF5, 0x0079, 0x0323}, +{ 0x017A, 0x007A, 0x0301}, +{ 0x1E91, 0x007A, 0x0302}, +{ 0x017C, 0x007A, 0x0307}, +{ 0x017E, 0x007A, 0x030C}, +{ 0x1E93, 0x007A, 0x0323}, +{ 0x1E95, 0x007A, 0x0331}, +{ 0x1FED, 0x00A8, 0x0300}, +{ 0x0385, 0x00A8, 0x0301}, +{ 0x1FC1, 0x00A8, 0x0342}, +{ 0x1EA6, 0x00C2, 0x0300}, +{ 0x1EA4, 0x00C2, 0x0301}, +{ 0x1EAA, 0x00C2, 0x0303}, +{ 0x1EA8, 0x00C2, 0x0309}, +{ 0x01DE, 0x00C4, 0x0304}, +{ 0x01FA, 0x00C5, 0x0301}, +{ 0x01FC, 0x00C6, 0x0301}, +{ 0x01E2, 0x00C6, 0x0304}, +{ 0x1E08, 0x00C7, 0x0301}, +{ 0x1EC0, 0x00CA, 0x0300}, +{ 0x1EBE, 0x00CA, 0x0301}, +{ 0x1EC4, 0x00CA, 0x0303}, +{ 0x1EC2, 0x00CA, 0x0309}, +{ 0x1E2E, 0x00CF, 0x0301}, +{ 0x1ED2, 0x00D4, 0x0300}, +{ 0x1ED0, 0x00D4, 0x0301}, +{ 0x1ED6, 0x00D4, 0x0303}, +{ 0x1ED4, 0x00D4, 0x0309}, +{ 0x1E4C, 0x00D5, 0x0301}, +{ 0x022C, 0x00D5, 0x0304}, +{ 0x1E4E, 0x00D5, 0x0308}, +{ 0x022A, 0x00D6, 0x0304}, +{ 0x01FE, 0x00D8, 0x0301}, +{ 0x01DB, 0x00DC, 0x0300}, +{ 0x01D7, 0x00DC, 0x0301}, +{ 0x01D5, 0x00DC, 0x0304}, +{ 0x01D9, 0x00DC, 0x030C}, +{ 0x1EA7, 0x00E2, 0x0300}, +{ 0x1EA5, 0x00E2, 0x0301}, +{ 0x1EAB, 0x00E2, 0x0303}, +{ 0x1EA9, 0x00E2, 0x0309}, +{ 0x01DF, 0x00E4, 0x0304}, +{ 0x01FB, 0x00E5, 0x0301}, +{ 0x01FD, 0x00E6, 0x0301}, +{ 0x01E3, 0x00E6, 0x0304}, +{ 0x1E09, 0x00E7, 0x0301}, +{ 0x1EC1, 0x00EA, 0x0300}, +{ 0x1EBF, 0x00EA, 0x0301}, +{ 0x1EC5, 0x00EA, 0x0303}, +{ 0x1EC3, 0x00EA, 0x0309}, +{ 0x1E2F, 0x00EF, 0x0301}, +{ 0x1ED3, 0x00F4, 0x0300}, +{ 0x1ED1, 0x00F4, 0x0301}, +{ 0x1ED7, 0x00F4, 0x0303}, +{ 0x1ED5, 0x00F4, 0x0309}, +{ 0x1E4D, 0x00F5, 0x0301}, +{ 0x022D, 0x00F5, 0x0304}, +{ 0x1E4F, 0x00F5, 0x0308}, +{ 0x022B, 0x00F6, 0x0304}, +{ 0x01FF, 0x00F8, 0x0301}, +{ 0x01DC, 0x00FC, 0x0300}, +{ 0x01D8, 0x00FC, 0x0301}, +{ 0x01D6, 0x00FC, 0x0304}, +{ 0x01DA, 0x00FC, 0x030C}, +{ 0x1EB0, 0x0102, 0x0300}, +{ 0x1EAE, 0x0102, 0x0301}, +{ 0x1EB4, 0x0102, 0x0303}, +{ 0x1EB2, 0x0102, 0x0309}, +{ 0x1EB1, 0x0103, 0x0300}, +{ 0x1EAF, 0x0103, 0x0301}, +{ 0x1EB5, 0x0103, 0x0303}, +{ 0x1EB3, 0x0103, 0x0309}, +{ 0x1E14, 0x0112, 0x0300}, +{ 0x1E16, 0x0112, 0x0301}, +{ 0x1E15, 0x0113, 0x0300}, +{ 0x1E17, 0x0113, 0x0301}, +{ 0x1E50, 0x014C, 0x0300}, +{ 0x1E52, 0x014C, 0x0301}, +{ 0x1E51, 0x014D, 0x0300}, +{ 0x1E53, 0x014D, 0x0301}, +{ 0x1E64, 0x015A, 0x0307}, +{ 0x1E65, 0x015B, 0x0307}, +{ 0x1E66, 0x0160, 0x0307}, +{ 0x1E67, 0x0161, 0x0307}, +{ 0x1E78, 0x0168, 0x0301}, +{ 0x1E79, 0x0169, 0x0301}, +{ 0x1E7A, 0x016A, 0x0308}, +{ 0x1E7B, 0x016B, 0x0308}, +{ 0x1E9B, 0x017F, 0x0307}, +{ 0x1EDC, 0x01A0, 0x0300}, +{ 0x1EDA, 0x01A0, 0x0301}, +{ 0x1EE0, 0x01A0, 0x0303}, +{ 0x1EDE, 0x01A0, 0x0309}, +{ 0x1EE2, 0x01A0, 0x0323}, +{ 0x1EDD, 0x01A1, 0x0300}, +{ 0x1EDB, 0x01A1, 0x0301}, +{ 0x1EE1, 0x01A1, 0x0303}, +{ 0x1EDF, 0x01A1, 0x0309}, +{ 0x1EE3, 0x01A1, 0x0323}, +{ 0x1EEA, 0x01AF, 0x0300}, +{ 0x1EE8, 0x01AF, 0x0301}, +{ 0x1EEE, 0x01AF, 0x0303}, +{ 0x1EEC, 0x01AF, 0x0309}, +{ 0x1EF0, 0x01AF, 0x0323}, +{ 0x1EEB, 0x01B0, 0x0300}, +{ 0x1EE9, 0x01B0, 0x0301}, +{ 0x1EEF, 0x01B0, 0x0303}, +{ 0x1EED, 0x01B0, 0x0309}, +{ 0x1EF1, 0x01B0, 0x0323}, +{ 0x01EE, 0x01B7, 0x030C}, +{ 0x01EC, 0x01EA, 0x0304}, +{ 0x01ED, 0x01EB, 0x0304}, +{ 0x01E0, 0x0226, 0x0304}, +{ 0x01E1, 0x0227, 0x0304}, +{ 0x1E1C, 0x0228, 0x0306}, +{ 0x1E1D, 0x0229, 0x0306}, +{ 0x0230, 0x022E, 0x0304}, +{ 0x0231, 0x022F, 0x0304}, +{ 0x01EF, 0x0292, 0x030C}, +{ 0x0344, 0x0308, 0x0301}, +{ 0x1FBA, 0x0391, 0x0300}, +{ 0x0386, 0x0391, 0x0301}, +{ 0x1FB9, 0x0391, 0x0304}, +{ 0x1FB8, 0x0391, 0x0306}, +{ 0x1F08, 0x0391, 0x0313}, +{ 0x1F09, 0x0391, 0x0314}, +{ 0x1FBC, 0x0391, 0x0345}, +{ 0x1FC8, 0x0395, 0x0300}, +{ 0x0388, 0x0395, 0x0301}, +{ 0x1F18, 0x0395, 0x0313}, +{ 0x1F19, 0x0395, 0x0314}, +{ 0x1FCA, 0x0397, 0x0300}, +{ 0x0389, 0x0397, 0x0301}, +{ 0x1F28, 0x0397, 0x0313}, +{ 0x1F29, 0x0397, 0x0314}, +{ 0x1FCC, 0x0397, 0x0345}, +{ 0x1FDA, 0x0399, 0x0300}, +{ 0x038A, 0x0399, 0x0301}, +{ 0x1FD9, 0x0399, 0x0304}, +{ 0x1FD8, 0x0399, 0x0306}, +{ 0x03AA, 0x0399, 0x0308}, +{ 0x1F38, 0x0399, 0x0313}, +{ 0x1F39, 0x0399, 0x0314}, +{ 0x1FF8, 0x039F, 0x0300}, +{ 0x038C, 0x039F, 0x0301}, +{ 0x1F48, 0x039F, 0x0313}, +{ 0x1F49, 0x039F, 0x0314}, +{ 0x1FEC, 0x03A1, 0x0314}, +{ 0x1FEA, 0x03A5, 0x0300}, +{ 0x038E, 0x03A5, 0x0301}, +{ 0x1FE9, 0x03A5, 0x0304}, +{ 0x1FE8, 0x03A5, 0x0306}, +{ 0x03AB, 0x03A5, 0x0308}, +{ 0x1F59, 0x03A5, 0x0314}, +{ 0x1FFA, 0x03A9, 0x0300}, +{ 0x038F, 0x03A9, 0x0301}, +{ 0x1F68, 0x03A9, 0x0313}, +{ 0x1F69, 0x03A9, 0x0314}, +{ 0x1FFC, 0x03A9, 0x0345}, +{ 0x1FB4, 0x03AC, 0x0345}, +{ 0x1FC4, 0x03AE, 0x0345}, +{ 0x1F70, 0x03B1, 0x0300}, +{ 0x03AC, 0x03B1, 0x0301}, +{ 0x1FB1, 0x03B1, 0x0304}, +{ 0x1FB0, 0x03B1, 0x0306}, +{ 0x1F00, 0x03B1, 0x0313}, +{ 0x1F01, 0x03B1, 0x0314}, +{ 0x1FB6, 0x03B1, 0x0342}, +{ 0x1FB3, 0x03B1, 0x0345}, +{ 0x1F72, 0x03B5, 0x0300}, +{ 0x03AD, 0x03B5, 0x0301}, +{ 0x1F10, 0x03B5, 0x0313}, +{ 0x1F11, 0x03B5, 0x0314}, +{ 0x1F74, 0x03B7, 0x0300}, +{ 0x03AE, 0x03B7, 0x0301}, +{ 0x1F20, 0x03B7, 0x0313}, +{ 0x1F21, 0x03B7, 0x0314}, +{ 0x1FC6, 0x03B7, 0x0342}, +{ 0x1FC3, 0x03B7, 0x0345}, +{ 0x1F76, 0x03B9, 0x0300}, +{ 0x03AF, 0x03B9, 0x0301}, +{ 0x1FD1, 0x03B9, 0x0304}, +{ 0x1FD0, 0x03B9, 0x0306}, +{ 0x03CA, 0x03B9, 0x0308}, +{ 0x1F30, 0x03B9, 0x0313}, +{ 0x1F31, 0x03B9, 0x0314}, +{ 0x1FD6, 0x03B9, 0x0342}, +{ 0x1F78, 0x03BF, 0x0300}, +{ 0x03CC, 0x03BF, 0x0301}, +{ 0x1F40, 0x03BF, 0x0313}, +{ 0x1F41, 0x03BF, 0x0314}, +{ 0x1FE4, 0x03C1, 0x0313}, +{ 0x1FE5, 0x03C1, 0x0314}, +{ 0x1F7A, 0x03C5, 0x0300}, +{ 0x03CD, 0x03C5, 0x0301}, +{ 0x1FE1, 0x03C5, 0x0304}, +{ 0x1FE0, 0x03C5, 0x0306}, +{ 0x03CB, 0x03C5, 0x0308}, +{ 0x1F50, 0x03C5, 0x0313}, +{ 0x1F51, 0x03C5, 0x0314}, +{ 0x1FE6, 0x03C5, 0x0342}, +{ 0x1F7C, 0x03C9, 0x0300}, +{ 0x03CE, 0x03C9, 0x0301}, +{ 0x1F60, 0x03C9, 0x0313}, +{ 0x1F61, 0x03C9, 0x0314}, +{ 0x1FF6, 0x03C9, 0x0342}, +{ 0x1FF3, 0x03C9, 0x0345}, +{ 0x1FD2, 0x03CA, 0x0300}, +{ 0x0390, 0x03CA, 0x0301}, +{ 0x1FD7, 0x03CA, 0x0342}, +{ 0x1FE2, 0x03CB, 0x0300}, +{ 0x03B0, 0x03CB, 0x0301}, +{ 0x1FE7, 0x03CB, 0x0342}, +{ 0x1FF4, 0x03CE, 0x0345}, +{ 0x03D3, 0x03D2, 0x0301}, +{ 0x03D4, 0x03D2, 0x0308}, +{ 0x0407, 0x0406, 0x0308}, +{ 0x04D0, 0x0410, 0x0306}, +{ 0x04D2, 0x0410, 0x0308}, +{ 0x0403, 0x0413, 0x0301}, +{ 0x0400, 0x0415, 0x0300}, +{ 0x04D6, 0x0415, 0x0306}, +{ 0x0401, 0x0415, 0x0308}, +{ 0x04C1, 0x0416, 0x0306}, +{ 0x04DC, 0x0416, 0x0308}, +{ 0x04DE, 0x0417, 0x0308}, +{ 0x040D, 0x0418, 0x0300}, +{ 0x04E2, 0x0418, 0x0304}, +{ 0x0419, 0x0418, 0x0306}, +{ 0x04E4, 0x0418, 0x0308}, +{ 0x040C, 0x041A, 0x0301}, +{ 0x04E6, 0x041E, 0x0308}, +{ 0x04EE, 0x0423, 0x0304}, +{ 0x040E, 0x0423, 0x0306}, +{ 0x04F0, 0x0423, 0x0308}, +{ 0x04F2, 0x0423, 0x030B}, +{ 0x04F4, 0x0427, 0x0308}, +{ 0x04F8, 0x042B, 0x0308}, +{ 0x04EC, 0x042D, 0x0308}, +{ 0x04D1, 0x0430, 0x0306}, +{ 0x04D3, 0x0430, 0x0308}, +{ 0x0453, 0x0433, 0x0301}, +{ 0x0450, 0x0435, 0x0300}, +{ 0x04D7, 0x0435, 0x0306}, +{ 0x0451, 0x0435, 0x0308}, +{ 0x04C2, 0x0436, 0x0306}, +{ 0x04DD, 0x0436, 0x0308}, +{ 0x04DF, 0x0437, 0x0308}, +{ 0x045D, 0x0438, 0x0300}, +{ 0x04E3, 0x0438, 0x0304}, +{ 0x0439, 0x0438, 0x0306}, +{ 0x04E5, 0x0438, 0x0308}, +{ 0x045C, 0x043A, 0x0301}, +{ 0x04E7, 0x043E, 0x0308}, +{ 0x04EF, 0x0443, 0x0304}, +{ 0x045E, 0x0443, 0x0306}, +{ 0x04F1, 0x0443, 0x0308}, +{ 0x04F3, 0x0443, 0x030B}, +{ 0x04F5, 0x0447, 0x0308}, +{ 0x04F9, 0x044B, 0x0308}, +{ 0x04ED, 0x044D, 0x0308}, +{ 0x0457, 0x0456, 0x0308}, +{ 0x0476, 0x0474, 0x030F}, +{ 0x0477, 0x0475, 0x030F}, +{ 0x04DA, 0x04D8, 0x0308}, +{ 0x04DB, 0x04D9, 0x0308}, +{ 0x04EA, 0x04E8, 0x0308}, +{ 0x04EB, 0x04E9, 0x0308}, +{ 0xFB2E, 0x05D0, 0x05B7}, +{ 0xFB2F, 0x05D0, 0x05B8}, +{ 0xFB30, 0x05D0, 0x05BC}, +{ 0xFB31, 0x05D1, 0x05BC}, +{ 0xFB4C, 0x05D1, 0x05BF}, +{ 0xFB32, 0x05D2, 0x05BC}, +{ 0xFB33, 0x05D3, 0x05BC}, +{ 0xFB34, 0x05D4, 0x05BC}, +{ 0xFB4B, 0x05D5, 0x05B9}, +{ 0xFB35, 0x05D5, 0x05BC}, +{ 0xFB36, 0x05D6, 0x05BC}, +{ 0xFB38, 0x05D8, 0x05BC}, +{ 0xFB1D, 0x05D9, 0x05B4}, +{ 0xFB39, 0x05D9, 0x05BC}, +{ 0xFB3A, 0x05DA, 0x05BC}, +{ 0xFB3B, 0x05DB, 0x05BC}, +{ 0xFB4D, 0x05DB, 0x05BF}, +{ 0xFB3C, 0x05DC, 0x05BC}, +{ 0xFB3E, 0x05DE, 0x05BC}, +{ 0xFB40, 0x05E0, 0x05BC}, +{ 0xFB41, 0x05E1, 0x05BC}, +{ 0xFB43, 0x05E3, 0x05BC}, +{ 0xFB44, 0x05E4, 0x05BC}, +{ 0xFB4E, 0x05E4, 0x05BF}, +{ 0xFB46, 0x05E6, 0x05BC}, +{ 0xFB47, 0x05E7, 0x05BC}, +{ 0xFB48, 0x05E8, 0x05BC}, +{ 0xFB49, 0x05E9, 0x05BC}, +{ 0xFB2A, 0x05E9, 0x05C1}, +{ 0xFB2B, 0x05E9, 0x05C2}, +{ 0xFB4A, 0x05EA, 0x05BC}, +{ 0xFB1F, 0x05F2, 0x05B7}, +{ 0x0622, 0x0627, 0x0653}, +{ 0x0623, 0x0627, 0x0654}, +{ 0x0625, 0x0627, 0x0655}, +{ 0x0624, 0x0648, 0x0654}, +{ 0x0626, 0x064A, 0x0654}, +{ 0x06C2, 0x06C1, 0x0654}, +{ 0x06D3, 0x06D2, 0x0654}, +{ 0x06C0, 0x06D5, 0x0654}, +{ 0x0958, 0x0915, 0x093C}, +{ 0x0959, 0x0916, 0x093C}, +{ 0x095A, 0x0917, 0x093C}, +{ 0x095B, 0x091C, 0x093C}, +{ 0x095C, 0x0921, 0x093C}, +{ 0x095D, 0x0922, 0x093C}, +{ 0x0929, 0x0928, 0x093C}, +{ 0x095E, 0x092B, 0x093C}, +{ 0x095F, 0x092F, 0x093C}, +{ 0x0931, 0x0930, 0x093C}, +{ 0x0934, 0x0933, 0x093C}, +{ 0x09DC, 0x09A1, 0x09BC}, +{ 0x09DD, 0x09A2, 0x09BC}, +{ 0x09DF, 0x09AF, 0x09BC}, +{ 0x09CB, 0x09C7, 0x09BE}, +{ 0x09CC, 0x09C7, 0x09D7}, +{ 0x0A59, 0x0A16, 0x0A3C}, +{ 0x0A5A, 0x0A17, 0x0A3C}, +{ 0x0A5B, 0x0A1C, 0x0A3C}, +{ 0x0A5E, 0x0A2B, 0x0A3C}, +{ 0x0A33, 0x0A32, 0x0A3C}, +{ 0x0A36, 0x0A38, 0x0A3C}, +{ 0x0B5C, 0x0B21, 0x0B3C}, +{ 0x0B5D, 0x0B22, 0x0B3C}, +{ 0x0B4B, 0x0B47, 0x0B3E}, +{ 0x0B48, 0x0B47, 0x0B56}, +{ 0x0B4C, 0x0B47, 0x0B57}, +{ 0x0B94, 0x0B92, 0x0BD7}, +{ 0x0BCA, 0x0BC6, 0x0BBE}, +{ 0x0BCC, 0x0BC6, 0x0BD7}, +{ 0x0BCB, 0x0BC7, 0x0BBE}, +{ 0x0C48, 0x0C46, 0x0C56}, +{ 0x0CC0, 0x0CBF, 0x0CD5}, +{ 0x0CCA, 0x0CC6, 0x0CC2}, +{ 0x0CC7, 0x0CC6, 0x0CD5}, +{ 0x0CC8, 0x0CC6, 0x0CD6}, +{ 0x0CCB, 0x0CCA, 0x0CD5}, +{ 0x0D4A, 0x0D46, 0x0D3E}, +{ 0x0D4C, 0x0D46, 0x0D57}, +{ 0x0D4B, 0x0D47, 0x0D3E}, +{ 0x0DDA, 0x0DD9, 0x0DCA}, +{ 0x0DDC, 0x0DD9, 0x0DCF}, +{ 0x0DDE, 0x0DD9, 0x0DDF}, +{ 0x0DDD, 0x0DDC, 0x0DCA}, +{ 0x0F69, 0x0F40, 0x0FB5}, +{ 0x0F43, 0x0F42, 0x0FB7}, +{ 0x0F4D, 0x0F4C, 0x0FB7}, +{ 0x0F52, 0x0F51, 0x0FB7}, +{ 0x0F57, 0x0F56, 0x0FB7}, +{ 0x0F5C, 0x0F5B, 0x0FB7}, +{ 0x0F73, 0x0F71, 0x0F72}, +{ 0x0F75, 0x0F71, 0x0F74}, +{ 0x0F81, 0x0F71, 0x0F80}, +{ 0x0FB9, 0x0F90, 0x0FB5}, +{ 0x0F93, 0x0F92, 0x0FB7}, +{ 0x0F9D, 0x0F9C, 0x0FB7}, +{ 0x0FA2, 0x0FA1, 0x0FB7}, +{ 0x0FA7, 0x0FA6, 0x0FB7}, +{ 0x0FAC, 0x0FAB, 0x0FB7}, +{ 0x0F76, 0x0FB2, 0x0F80}, +{ 0x0F78, 0x0FB3, 0x0F80}, +{ 0x1026, 0x1025, 0x102E}, +{ 0x1E38, 0x1E36, 0x0304}, +{ 0x1E39, 0x1E37, 0x0304}, +{ 0x1E5C, 0x1E5A, 0x0304}, +{ 0x1E5D, 0x1E5B, 0x0304}, +{ 0x1E68, 0x1E62, 0x0307}, +{ 0x1E69, 0x1E63, 0x0307}, +{ 0x1EAC, 0x1EA0, 0x0302}, +{ 0x1EB6, 0x1EA0, 0x0306}, +{ 0x1EAD, 0x1EA1, 0x0302}, +{ 0x1EB7, 0x1EA1, 0x0306}, +{ 0x1EC6, 0x1EB8, 0x0302}, +{ 0x1EC7, 0x1EB9, 0x0302}, +{ 0x1ED8, 0x1ECC, 0x0302}, +{ 0x1ED9, 0x1ECD, 0x0302}, +{ 0x1F02, 0x1F00, 0x0300}, +{ 0x1F04, 0x1F00, 0x0301}, +{ 0x1F06, 0x1F00, 0x0342}, +{ 0x1F80, 0x1F00, 0x0345}, +{ 0x1F03, 0x1F01, 0x0300}, +{ 0x1F05, 0x1F01, 0x0301}, +{ 0x1F07, 0x1F01, 0x0342}, +{ 0x1F81, 0x1F01, 0x0345}, +{ 0x1F82, 0x1F02, 0x0345}, +{ 0x1F83, 0x1F03, 0x0345}, +{ 0x1F84, 0x1F04, 0x0345}, +{ 0x1F85, 0x1F05, 0x0345}, +{ 0x1F86, 0x1F06, 0x0345}, +{ 0x1F87, 0x1F07, 0x0345}, +{ 0x1F0A, 0x1F08, 0x0300}, +{ 0x1F0C, 0x1F08, 0x0301}, +{ 0x1F0E, 0x1F08, 0x0342}, +{ 0x1F88, 0x1F08, 0x0345}, +{ 0x1F0B, 0x1F09, 0x0300}, +{ 0x1F0D, 0x1F09, 0x0301}, +{ 0x1F0F, 0x1F09, 0x0342}, +{ 0x1F89, 0x1F09, 0x0345}, +{ 0x1F8A, 0x1F0A, 0x0345}, +{ 0x1F8B, 0x1F0B, 0x0345}, +{ 0x1F8C, 0x1F0C, 0x0345}, +{ 0x1F8D, 0x1F0D, 0x0345}, +{ 0x1F8E, 0x1F0E, 0x0345}, +{ 0x1F8F, 0x1F0F, 0x0345}, +{ 0x1F12, 0x1F10, 0x0300}, +{ 0x1F14, 0x1F10, 0x0301}, +{ 0x1F13, 0x1F11, 0x0300}, +{ 0x1F15, 0x1F11, 0x0301}, +{ 0x1F1A, 0x1F18, 0x0300}, +{ 0x1F1C, 0x1F18, 0x0301}, +{ 0x1F1B, 0x1F19, 0x0300}, +{ 0x1F1D, 0x1F19, 0x0301}, +{ 0x1F22, 0x1F20, 0x0300}, +{ 0x1F24, 0x1F20, 0x0301}, +{ 0x1F26, 0x1F20, 0x0342}, +{ 0x1F90, 0x1F20, 0x0345}, +{ 0x1F23, 0x1F21, 0x0300}, +{ 0x1F25, 0x1F21, 0x0301}, +{ 0x1F27, 0x1F21, 0x0342}, +{ 0x1F91, 0x1F21, 0x0345}, +{ 0x1F92, 0x1F22, 0x0345}, +{ 0x1F93, 0x1F23, 0x0345}, +{ 0x1F94, 0x1F24, 0x0345}, +{ 0x1F95, 0x1F25, 0x0345}, +{ 0x1F96, 0x1F26, 0x0345}, +{ 0x1F97, 0x1F27, 0x0345}, +{ 0x1F2A, 0x1F28, 0x0300}, +{ 0x1F2C, 0x1F28, 0x0301}, +{ 0x1F2E, 0x1F28, 0x0342}, +{ 0x1F98, 0x1F28, 0x0345}, +{ 0x1F2B, 0x1F29, 0x0300}, +{ 0x1F2D, 0x1F29, 0x0301}, +{ 0x1F2F, 0x1F29, 0x0342}, +{ 0x1F99, 0x1F29, 0x0345}, +{ 0x1F9A, 0x1F2A, 0x0345}, +{ 0x1F9B, 0x1F2B, 0x0345}, +{ 0x1F9C, 0x1F2C, 0x0345}, +{ 0x1F9D, 0x1F2D, 0x0345}, +{ 0x1F9E, 0x1F2E, 0x0345}, +{ 0x1F9F, 0x1F2F, 0x0345}, +{ 0x1F32, 0x1F30, 0x0300}, +{ 0x1F34, 0x1F30, 0x0301}, +{ 0x1F36, 0x1F30, 0x0342}, +{ 0x1F33, 0x1F31, 0x0300}, +{ 0x1F35, 0x1F31, 0x0301}, +{ 0x1F37, 0x1F31, 0x0342}, +{ 0x1F3A, 0x1F38, 0x0300}, +{ 0x1F3C, 0x1F38, 0x0301}, +{ 0x1F3E, 0x1F38, 0x0342}, +{ 0x1F3B, 0x1F39, 0x0300}, +{ 0x1F3D, 0x1F39, 0x0301}, +{ 0x1F3F, 0x1F39, 0x0342}, +{ 0x1F42, 0x1F40, 0x0300}, +{ 0x1F44, 0x1F40, 0x0301}, +{ 0x1F43, 0x1F41, 0x0300}, +{ 0x1F45, 0x1F41, 0x0301}, +{ 0x1F4A, 0x1F48, 0x0300}, +{ 0x1F4C, 0x1F48, 0x0301}, +{ 0x1F4B, 0x1F49, 0x0300}, +{ 0x1F4D, 0x1F49, 0x0301}, +{ 0x1F52, 0x1F50, 0x0300}, +{ 0x1F54, 0x1F50, 0x0301}, +{ 0x1F56, 0x1F50, 0x0342}, +{ 0x1F53, 0x1F51, 0x0300}, +{ 0x1F55, 0x1F51, 0x0301}, +{ 0x1F57, 0x1F51, 0x0342}, +{ 0x1F5B, 0x1F59, 0x0300}, +{ 0x1F5D, 0x1F59, 0x0301}, +{ 0x1F5F, 0x1F59, 0x0342}, +{ 0x1F62, 0x1F60, 0x0300}, +{ 0x1F64, 0x1F60, 0x0301}, +{ 0x1F66, 0x1F60, 0x0342}, +{ 0x1FA0, 0x1F60, 0x0345}, +{ 0x1F63, 0x1F61, 0x0300}, +{ 0x1F65, 0x1F61, 0x0301}, +{ 0x1F67, 0x1F61, 0x0342}, +{ 0x1FA1, 0x1F61, 0x0345}, +{ 0x1FA2, 0x1F62, 0x0345}, +{ 0x1FA3, 0x1F63, 0x0345}, +{ 0x1FA4, 0x1F64, 0x0345}, +{ 0x1FA5, 0x1F65, 0x0345}, +{ 0x1FA6, 0x1F66, 0x0345}, +{ 0x1FA7, 0x1F67, 0x0345}, +{ 0x1F6A, 0x1F68, 0x0300}, +{ 0x1F6C, 0x1F68, 0x0301}, +{ 0x1F6E, 0x1F68, 0x0342}, +{ 0x1FA8, 0x1F68, 0x0345}, +{ 0x1F6B, 0x1F69, 0x0300}, +{ 0x1F6D, 0x1F69, 0x0301}, +{ 0x1F6F, 0x1F69, 0x0342}, +{ 0x1FA9, 0x1F69, 0x0345}, +{ 0x1FAA, 0x1F6A, 0x0345}, +{ 0x1FAB, 0x1F6B, 0x0345}, +{ 0x1FAC, 0x1F6C, 0x0345}, +{ 0x1FAD, 0x1F6D, 0x0345}, +{ 0x1FAE, 0x1F6E, 0x0345}, +{ 0x1FAF, 0x1F6F, 0x0345}, +{ 0x1FB2, 0x1F70, 0x0345}, +{ 0x1FC2, 0x1F74, 0x0345}, +{ 0x1FF2, 0x1F7C, 0x0345}, +{ 0x1FB7, 0x1FB6, 0x0345}, +{ 0x1FCD, 0x1FBF, 0x0300}, +{ 0x1FCE, 0x1FBF, 0x0301}, +{ 0x1FCF, 0x1FBF, 0x0342}, +{ 0x1FC7, 0x1FC6, 0x0345}, +{ 0x1FF7, 0x1FF6, 0x0345}, +{ 0x1FDD, 0x1FFE, 0x0300}, +{ 0x1FDE, 0x1FFE, 0x0301}, +{ 0x1FDF, 0x1FFE, 0x0342}, +{ 0x219A, 0x2190, 0x0338}, +{ 0x219B, 0x2192, 0x0338}, +{ 0x21AE, 0x2194, 0x0338}, +{ 0x21CD, 0x21D0, 0x0338}, +{ 0x21CF, 0x21D2, 0x0338}, +{ 0x21CE, 0x21D4, 0x0338}, +{ 0x2204, 0x2203, 0x0338}, +{ 0x2209, 0x2208, 0x0338}, +{ 0x220C, 0x220B, 0x0338}, +{ 0x2224, 0x2223, 0x0338}, +{ 0x2226, 0x2225, 0x0338}, +{ 0x2241, 0x223C, 0x0338}, +{ 0x2244, 0x2243, 0x0338}, +{ 0x2247, 0x2245, 0x0338}, +{ 0x2249, 0x2248, 0x0338}, +{ 0x226D, 0x224D, 0x0338}, +{ 0x2262, 0x2261, 0x0338}, +{ 0x2270, 0x2264, 0x0338}, +{ 0x2271, 0x2265, 0x0338}, +{ 0x2274, 0x2272, 0x0338}, +{ 0x2275, 0x2273, 0x0338}, +{ 0x2278, 0x2276, 0x0338}, +{ 0x2279, 0x2277, 0x0338}, +{ 0x2280, 0x227A, 0x0338}, +{ 0x2281, 0x227B, 0x0338}, +{ 0x22E0, 0x227C, 0x0338}, +{ 0x22E1, 0x227D, 0x0338}, +{ 0x2284, 0x2282, 0x0338}, +{ 0x2285, 0x2283, 0x0338}, +{ 0x2288, 0x2286, 0x0338}, +{ 0x2289, 0x2287, 0x0338}, +{ 0x22E2, 0x2291, 0x0338}, +{ 0x22E3, 0x2292, 0x0338}, +{ 0x22AC, 0x22A2, 0x0338}, +{ 0x22AD, 0x22A8, 0x0338}, +{ 0x22AE, 0x22A9, 0x0338}, +{ 0x22AF, 0x22AB, 0x0338}, +{ 0x22EA, 0x22B2, 0x0338}, +{ 0x22EB, 0x22B3, 0x0338}, +{ 0x22EC, 0x22B4, 0x0338}, +{ 0x22ED, 0x22B5, 0x0338}, +{ 0x3094, 0x3046, 0x3099}, +{ 0x304C, 0x304B, 0x3099}, +{ 0x304E, 0x304D, 0x3099}, +{ 0x3050, 0x304F, 0x3099}, +{ 0x3052, 0x3051, 0x3099}, +{ 0x3054, 0x3053, 0x3099}, +{ 0x3056, 0x3055, 0x3099}, +{ 0x3058, 0x3057, 0x3099}, +{ 0x305A, 0x3059, 0x3099}, +{ 0x305C, 0x305B, 0x3099}, +{ 0x305E, 0x305D, 0x3099}, +{ 0x3060, 0x305F, 0x3099}, +{ 0x3062, 0x3061, 0x3099}, +{ 0x3065, 0x3064, 0x3099}, +{ 0x3067, 0x3066, 0x3099}, +{ 0x3069, 0x3068, 0x3099}, +{ 0x3070, 0x306F, 0x3099}, +{ 0x3071, 0x306F, 0x309A}, +{ 0x3073, 0x3072, 0x3099}, +{ 0x3074, 0x3072, 0x309A}, +{ 0x3076, 0x3075, 0x3099}, +{ 0x3077, 0x3075, 0x309A}, +{ 0x3079, 0x3078, 0x3099}, +{ 0x307A, 0x3078, 0x309A}, +{ 0x307C, 0x307B, 0x3099}, +{ 0x307D, 0x307B, 0x309A}, +{ 0x309E, 0x309D, 0x3099}, +{ 0x30F4, 0x30A6, 0x3099}, +{ 0x30AC, 0x30AB, 0x3099}, +{ 0x30AE, 0x30AD, 0x3099}, +{ 0x30B0, 0x30AF, 0x3099}, +{ 0x30B2, 0x30B1, 0x3099}, +{ 0x30B4, 0x30B3, 0x3099}, +{ 0x30B6, 0x30B5, 0x3099}, +{ 0x30B8, 0x30B7, 0x3099}, +{ 0x30BA, 0x30B9, 0x3099}, +{ 0x30BC, 0x30BB, 0x3099}, +{ 0x30BE, 0x30BD, 0x3099}, +{ 0x30C0, 0x30BF, 0x3099}, +{ 0x30C2, 0x30C1, 0x3099}, +{ 0x30C5, 0x30C4, 0x3099}, +{ 0x30C7, 0x30C6, 0x3099}, +{ 0x30C9, 0x30C8, 0x3099}, +{ 0x30D0, 0x30CF, 0x3099}, +{ 0x30D1, 0x30CF, 0x309A}, +{ 0x30D3, 0x30D2, 0x3099}, +{ 0x30D4, 0x30D2, 0x309A}, +{ 0x30D6, 0x30D5, 0x3099}, +{ 0x30D7, 0x30D5, 0x309A}, +{ 0x30D9, 0x30D8, 0x3099}, +{ 0x30DA, 0x30D8, 0x309A}, +{ 0x30DC, 0x30DB, 0x3099}, +{ 0x30DD, 0x30DB, 0x309A}, +{ 0x30F7, 0x30EF, 0x3099}, +{ 0x30F8, 0x30F0, 0x3099}, +{ 0x30F9, 0x30F1, 0x3099}, +{ 0x30FA, 0x30F2, 0x3099}, +{ 0x30FE, 0x30FD, 0x3099}, +{ 0xFB2C, 0xFB49, 0x05C1}, +{ 0xFB2D, 0xFB49, 0x05C2}, +}; + +static const struct { + unsigned int replacement; + unsigned int base; + unsigned int comb; +} decompositions[] = { +{ 0x00C0, 0x0041, 0x0300}, +{ 0x00C1, 0x0041, 0x0301}, +{ 0x00C2, 0x0041, 0x0302}, +{ 0x00C3, 0x0041, 0x0303}, +{ 0x00C4, 0x0041, 0x0308}, +{ 0x00C5, 0x0041, 0x030A}, +{ 0x00C7, 0x0043, 0x0327}, +{ 0x00C8, 0x0045, 0x0300}, +{ 0x00C9, 0x0045, 0x0301}, +{ 0x00CA, 0x0045, 0x0302}, +{ 0x00CB, 0x0045, 0x0308}, +{ 0x00CC, 0x0049, 0x0300}, +{ 0x00CD, 0x0049, 0x0301}, +{ 0x00CE, 0x0049, 0x0302}, +{ 0x00CF, 0x0049, 0x0308}, +{ 0x00D1, 0x004E, 0x0303}, +{ 0x00D2, 0x004F, 0x0300}, +{ 0x00D3, 0x004F, 0x0301}, +{ 0x00D4, 0x004F, 0x0302}, +{ 0x00D5, 0x004F, 0x0303}, +{ 0x00D6, 0x004F, 0x0308}, +{ 0x00D9, 0x0055, 0x0300}, +{ 0x00DA, 0x0055, 0x0301}, +{ 0x00DB, 0x0055, 0x0302}, +{ 0x00DC, 0x0055, 0x0308}, +{ 0x00DD, 0x0059, 0x0301}, +{ 0x00E0, 0x0061, 0x0300}, +{ 0x00E1, 0x0061, 0x0301}, +{ 0x00E2, 0x0061, 0x0302}, +{ 0x00E3, 0x0061, 0x0303}, +{ 0x00E4, 0x0061, 0x0308}, +{ 0x00E5, 0x0061, 0x030A}, +{ 0x00E7, 0x0063, 0x0327}, +{ 0x00E8, 0x0065, 0x0300}, +{ 0x00E9, 0x0065, 0x0301}, +{ 0x00EA, 0x0065, 0x0302}, +{ 0x00EB, 0x0065, 0x0308}, +{ 0x00EC, 0x0069, 0x0300}, +{ 0x00ED, 0x0069, 0x0301}, +{ 0x00EE, 0x0069, 0x0302}, +{ 0x00EF, 0x0069, 0x0308}, +{ 0x00F1, 0x006E, 0x0303}, +{ 0x00F2, 0x006F, 0x0300}, +{ 0x00F3, 0x006F, 0x0301}, +{ 0x00F4, 0x006F, 0x0302}, +{ 0x00F5, 0x006F, 0x0303}, +{ 0x00F6, 0x006F, 0x0308}, +{ 0x00F9, 0x0075, 0x0300}, +{ 0x00FA, 0x0075, 0x0301}, +{ 0x00FB, 0x0075, 0x0302}, +{ 0x00FC, 0x0075, 0x0308}, +{ 0x00FD, 0x0079, 0x0301}, +{ 0x00FF, 0x0079, 0x0308}, +{ 0x0100, 0x0041, 0x0304}, +{ 0x0101, 0x0061, 0x0304}, +{ 0x0102, 0x0041, 0x0306}, +{ 0x0103, 0x0061, 0x0306}, +{ 0x0104, 0x0041, 0x0328}, +{ 0x0105, 0x0061, 0x0328}, +{ 0x0106, 0x0043, 0x0301}, +{ 0x0107, 0x0063, 0x0301}, +{ 0x0108, 0x0043, 0x0302}, +{ 0x0109, 0x0063, 0x0302}, +{ 0x010A, 0x0043, 0x0307}, +{ 0x010B, 0x0063, 0x0307}, +{ 0x010C, 0x0043, 0x030C}, +{ 0x010D, 0x0063, 0x030C}, +{ 0x010E, 0x0044, 0x030C}, +{ 0x010F, 0x0064, 0x030C}, +{ 0x0112, 0x0045, 0x0304}, +{ 0x0113, 0x0065, 0x0304}, +{ 0x0114, 0x0045, 0x0306}, +{ 0x0115, 0x0065, 0x0306}, +{ 0x0116, 0x0045, 0x0307}, +{ 0x0117, 0x0065, 0x0307}, +{ 0x0118, 0x0045, 0x0328}, +{ 0x0119, 0x0065, 0x0328}, +{ 0x011A, 0x0045, 0x030C}, +{ 0x011B, 0x0065, 0x030C}, +{ 0x011C, 0x0047, 0x0302}, +{ 0x011D, 0x0067, 0x0302}, +{ 0x011E, 0x0047, 0x0306}, +{ 0x011F, 0x0067, 0x0306}, +{ 0x0120, 0x0047, 0x0307}, +{ 0x0121, 0x0067, 0x0307}, +{ 0x0122, 0x0047, 0x0327}, +{ 0x0123, 0x0067, 0x0327}, +{ 0x0124, 0x0048, 0x0302}, +{ 0x0125, 0x0068, 0x0302}, +{ 0x0128, 0x0049, 0x0303}, +{ 0x0129, 0x0069, 0x0303}, +{ 0x012A, 0x0049, 0x0304}, +{ 0x012B, 0x0069, 0x0304}, +{ 0x012C, 0x0049, 0x0306}, +{ 0x012D, 0x0069, 0x0306}, +{ 0x012E, 0x0049, 0x0328}, +{ 0x012F, 0x0069, 0x0328}, +{ 0x0130, 0x0049, 0x0307}, +{ 0x0134, 0x004A, 0x0302}, +{ 0x0135, 0x006A, 0x0302}, +{ 0x0136, 0x004B, 0x0327}, +{ 0x0137, 0x006B, 0x0327}, +{ 0x0139, 0x004C, 0x0301}, +{ 0x013A, 0x006C, 0x0301}, +{ 0x013B, 0x004C, 0x0327}, +{ 0x013C, 0x006C, 0x0327}, +{ 0x013D, 0x004C, 0x030C}, +{ 0x013E, 0x006C, 0x030C}, +{ 0x0143, 0x004E, 0x0301}, +{ 0x0144, 0x006E, 0x0301}, +{ 0x0145, 0x004E, 0x0327}, +{ 0x0146, 0x006E, 0x0327}, +{ 0x0147, 0x004E, 0x030C}, +{ 0x0148, 0x006E, 0x030C}, +{ 0x014C, 0x004F, 0x0304}, +{ 0x014D, 0x006F, 0x0304}, +{ 0x014E, 0x004F, 0x0306}, +{ 0x014F, 0x006F, 0x0306}, +{ 0x0150, 0x004F, 0x030B}, +{ 0x0151, 0x006F, 0x030B}, +{ 0x0154, 0x0052, 0x0301}, +{ 0x0155, 0x0072, 0x0301}, +{ 0x0156, 0x0052, 0x0327}, +{ 0x0157, 0x0072, 0x0327}, +{ 0x0158, 0x0052, 0x030C}, +{ 0x0159, 0x0072, 0x030C}, +{ 0x015A, 0x0053, 0x0301}, +{ 0x015B, 0x0073, 0x0301}, +{ 0x015C, 0x0053, 0x0302}, +{ 0x015D, 0x0073, 0x0302}, +{ 0x015E, 0x0053, 0x0327}, +{ 0x015F, 0x0073, 0x0327}, +{ 0x0160, 0x0053, 0x030C}, +{ 0x0161, 0x0073, 0x030C}, +{ 0x0162, 0x0054, 0x0327}, +{ 0x0163, 0x0074, 0x0327}, +{ 0x0164, 0x0054, 0x030C}, +{ 0x0165, 0x0074, 0x030C}, +{ 0x0168, 0x0055, 0x0303}, +{ 0x0169, 0x0075, 0x0303}, +{ 0x016A, 0x0055, 0x0304}, +{ 0x016B, 0x0075, 0x0304}, +{ 0x016C, 0x0055, 0x0306}, +{ 0x016D, 0x0075, 0x0306}, +{ 0x016E, 0x0055, 0x030A}, +{ 0x016F, 0x0075, 0x030A}, +{ 0x0170, 0x0055, 0x030B}, +{ 0x0171, 0x0075, 0x030B}, +{ 0x0172, 0x0055, 0x0328}, +{ 0x0173, 0x0075, 0x0328}, +{ 0x0174, 0x0057, 0x0302}, +{ 0x0175, 0x0077, 0x0302}, +{ 0x0176, 0x0059, 0x0302}, +{ 0x0177, 0x0079, 0x0302}, +{ 0x0178, 0x0059, 0x0308}, +{ 0x0179, 0x005A, 0x0301}, +{ 0x017A, 0x007A, 0x0301}, +{ 0x017B, 0x005A, 0x0307}, +{ 0x017C, 0x007A, 0x0307}, +{ 0x017D, 0x005A, 0x030C}, +{ 0x017E, 0x007A, 0x030C}, +{ 0x01A0, 0x004F, 0x031B}, +{ 0x01A1, 0x006F, 0x031B}, +{ 0x01AF, 0x0055, 0x031B}, +{ 0x01B0, 0x0075, 0x031B}, +{ 0x01CD, 0x0041, 0x030C}, +{ 0x01CE, 0x0061, 0x030C}, +{ 0x01CF, 0x0049, 0x030C}, +{ 0x01D0, 0x0069, 0x030C}, +{ 0x01D1, 0x004F, 0x030C}, +{ 0x01D2, 0x006F, 0x030C}, +{ 0x01D3, 0x0055, 0x030C}, +{ 0x01D4, 0x0075, 0x030C}, +{ 0x01D5, 0x00DC, 0x0304}, +{ 0x01D6, 0x00FC, 0x0304}, +{ 0x01D7, 0x00DC, 0x0301}, +{ 0x01D8, 0x00FC, 0x0301}, +{ 0x01D9, 0x00DC, 0x030C}, +{ 0x01DA, 0x00FC, 0x030C}, +{ 0x01DB, 0x00DC, 0x0300}, +{ 0x01DC, 0x00FC, 0x0300}, +{ 0x01DE, 0x00C4, 0x0304}, +{ 0x01DF, 0x00E4, 0x0304}, +{ 0x01E0, 0x0226, 0x0304}, +{ 0x01E1, 0x0227, 0x0304}, +{ 0x01E2, 0x00C6, 0x0304}, +{ 0x01E3, 0x00E6, 0x0304}, +{ 0x01E6, 0x0047, 0x030C}, +{ 0x01E7, 0x0067, 0x030C}, +{ 0x01E8, 0x004B, 0x030C}, +{ 0x01E9, 0x006B, 0x030C}, +{ 0x01EA, 0x004F, 0x0328}, +{ 0x01EB, 0x006F, 0x0328}, +{ 0x01EC, 0x01EA, 0x0304}, +{ 0x01ED, 0x01EB, 0x0304}, +{ 0x01EE, 0x01B7, 0x030C}, +{ 0x01EF, 0x0292, 0x030C}, +{ 0x01F0, 0x006A, 0x030C}, +{ 0x01F4, 0x0047, 0x0301}, +{ 0x01F5, 0x0067, 0x0301}, +{ 0x01F8, 0x004E, 0x0300}, +{ 0x01F9, 0x006E, 0x0300}, +{ 0x01FA, 0x00C5, 0x0301}, +{ 0x01FB, 0x00E5, 0x0301}, +{ 0x01FC, 0x00C6, 0x0301}, +{ 0x01FD, 0x00E6, 0x0301}, +{ 0x01FE, 0x00D8, 0x0301}, +{ 0x01FF, 0x00F8, 0x0301}, +{ 0x0200, 0x0041, 0x030F}, +{ 0x0201, 0x0061, 0x030F}, +{ 0x0202, 0x0041, 0x0311}, +{ 0x0203, 0x0061, 0x0311}, +{ 0x0204, 0x0045, 0x030F}, +{ 0x0205, 0x0065, 0x030F}, +{ 0x0206, 0x0045, 0x0311}, +{ 0x0207, 0x0065, 0x0311}, +{ 0x0208, 0x0049, 0x030F}, +{ 0x0209, 0x0069, 0x030F}, +{ 0x020A, 0x0049, 0x0311}, +{ 0x020B, 0x0069, 0x0311}, +{ 0x020C, 0x004F, 0x030F}, +{ 0x020D, 0x006F, 0x030F}, +{ 0x020E, 0x004F, 0x0311}, +{ 0x020F, 0x006F, 0x0311}, +{ 0x0210, 0x0052, 0x030F}, +{ 0x0211, 0x0072, 0x030F}, +{ 0x0212, 0x0052, 0x0311}, +{ 0x0213, 0x0072, 0x0311}, +{ 0x0214, 0x0055, 0x030F}, +{ 0x0215, 0x0075, 0x030F}, +{ 0x0216, 0x0055, 0x0311}, +{ 0x0217, 0x0075, 0x0311}, +{ 0x0218, 0x0053, 0x0326}, +{ 0x0219, 0x0073, 0x0326}, +{ 0x021A, 0x0054, 0x0326}, +{ 0x021B, 0x0074, 0x0326}, +{ 0x021E, 0x0048, 0x030C}, +{ 0x021F, 0x0068, 0x030C}, +{ 0x0226, 0x0041, 0x0307}, +{ 0x0227, 0x0061, 0x0307}, +{ 0x0228, 0x0045, 0x0327}, +{ 0x0229, 0x0065, 0x0327}, +{ 0x022A, 0x00D6, 0x0304}, +{ 0x022B, 0x00F6, 0x0304}, +{ 0x022C, 0x00D5, 0x0304}, +{ 0x022D, 0x00F5, 0x0304}, +{ 0x022E, 0x004F, 0x0307}, +{ 0x022F, 0x006F, 0x0307}, +{ 0x0230, 0x022E, 0x0304}, +{ 0x0231, 0x022F, 0x0304}, +{ 0x0232, 0x0059, 0x0304}, +{ 0x0233, 0x0079, 0x0304}, +{ 0x0344, 0x0308, 0x0301}, +{ 0x0385, 0x00A8, 0x0301}, +{ 0x0386, 0x0391, 0x0301}, +{ 0x0388, 0x0395, 0x0301}, +{ 0x0389, 0x0397, 0x0301}, +{ 0x038A, 0x0399, 0x0301}, +{ 0x038C, 0x039F, 0x0301}, +{ 0x038E, 0x03A5, 0x0301}, +{ 0x038F, 0x03A9, 0x0301}, +{ 0x0390, 0x03CA, 0x0301}, +{ 0x03AA, 0x0399, 0x0308}, +{ 0x03AB, 0x03A5, 0x0308}, +{ 0x03AC, 0x03B1, 0x0301}, +{ 0x03AD, 0x03B5, 0x0301}, +{ 0x03AE, 0x03B7, 0x0301}, +{ 0x03AF, 0x03B9, 0x0301}, +{ 0x03B0, 0x03CB, 0x0301}, +{ 0x03CA, 0x03B9, 0x0308}, +{ 0x03CB, 0x03C5, 0x0308}, +{ 0x03CC, 0x03BF, 0x0301}, +{ 0x03CD, 0x03C5, 0x0301}, +{ 0x03CE, 0x03C9, 0x0301}, +{ 0x03D3, 0x03D2, 0x0301}, +{ 0x03D4, 0x03D2, 0x0308}, +{ 0x0400, 0x0415, 0x0300}, +{ 0x0401, 0x0415, 0x0308}, +{ 0x0403, 0x0413, 0x0301}, +{ 0x0407, 0x0406, 0x0308}, +{ 0x040C, 0x041A, 0x0301}, +{ 0x040D, 0x0418, 0x0300}, +{ 0x040E, 0x0423, 0x0306}, +{ 0x0419, 0x0418, 0x0306}, +{ 0x0439, 0x0438, 0x0306}, +{ 0x0450, 0x0435, 0x0300}, +{ 0x0451, 0x0435, 0x0308}, +{ 0x0453, 0x0433, 0x0301}, +{ 0x0457, 0x0456, 0x0308}, +{ 0x045C, 0x043A, 0x0301}, +{ 0x045D, 0x0438, 0x0300}, +{ 0x045E, 0x0443, 0x0306}, +{ 0x0476, 0x0474, 0x030F}, +{ 0x0477, 0x0475, 0x030F}, +{ 0x04C1, 0x0416, 0x0306}, +{ 0x04C2, 0x0436, 0x0306}, +{ 0x04D0, 0x0410, 0x0306}, +{ 0x04D1, 0x0430, 0x0306}, +{ 0x04D2, 0x0410, 0x0308}, +{ 0x04D3, 0x0430, 0x0308}, +{ 0x04D6, 0x0415, 0x0306}, +{ 0x04D7, 0x0435, 0x0306}, +{ 0x04DA, 0x04D8, 0x0308}, +{ 0x04DB, 0x04D9, 0x0308}, +{ 0x04DC, 0x0416, 0x0308}, +{ 0x04DD, 0x0436, 0x0308}, +{ 0x04DE, 0x0417, 0x0308}, +{ 0x04DF, 0x0437, 0x0308}, +{ 0x04E2, 0x0418, 0x0304}, +{ 0x04E3, 0x0438, 0x0304}, +{ 0x04E4, 0x0418, 0x0308}, +{ 0x04E5, 0x0438, 0x0308}, +{ 0x04E6, 0x041E, 0x0308}, +{ 0x04E7, 0x043E, 0x0308}, +{ 0x04EA, 0x04E8, 0x0308}, +{ 0x04EB, 0x04E9, 0x0308}, +{ 0x04EC, 0x042D, 0x0308}, +{ 0x04ED, 0x044D, 0x0308}, +{ 0x04EE, 0x0423, 0x0304}, +{ 0x04EF, 0x0443, 0x0304}, +{ 0x04F0, 0x0423, 0x0308}, +{ 0x04F1, 0x0443, 0x0308}, +{ 0x04F2, 0x0423, 0x030B}, +{ 0x04F3, 0x0443, 0x030B}, +{ 0x04F4, 0x0427, 0x0308}, +{ 0x04F5, 0x0447, 0x0308}, +{ 0x04F8, 0x042B, 0x0308}, +{ 0x04F9, 0x044B, 0x0308}, +{ 0x0622, 0x0627, 0x0653}, +{ 0x0623, 0x0627, 0x0654}, +{ 0x0624, 0x0648, 0x0654}, +{ 0x0625, 0x0627, 0x0655}, +{ 0x0626, 0x064A, 0x0654}, +{ 0x06C0, 0x06D5, 0x0654}, +{ 0x06C2, 0x06C1, 0x0654}, +{ 0x06D3, 0x06D2, 0x0654}, +{ 0x0929, 0x0928, 0x093C}, +{ 0x0931, 0x0930, 0x093C}, +{ 0x0934, 0x0933, 0x093C}, +{ 0x0958, 0x0915, 0x093C}, +{ 0x0959, 0x0916, 0x093C}, +{ 0x095A, 0x0917, 0x093C}, +{ 0x095B, 0x091C, 0x093C}, +{ 0x095C, 0x0921, 0x093C}, +{ 0x095D, 0x0922, 0x093C}, +{ 0x095E, 0x092B, 0x093C}, +{ 0x095F, 0x092F, 0x093C}, +{ 0x09CB, 0x09C7, 0x09BE}, +{ 0x09CC, 0x09C7, 0x09D7}, +{ 0x09DC, 0x09A1, 0x09BC}, +{ 0x09DD, 0x09A2, 0x09BC}, +{ 0x09DF, 0x09AF, 0x09BC}, +{ 0x0A33, 0x0A32, 0x0A3C}, +{ 0x0A36, 0x0A38, 0x0A3C}, +{ 0x0A59, 0x0A16, 0x0A3C}, +{ 0x0A5A, 0x0A17, 0x0A3C}, +{ 0x0A5B, 0x0A1C, 0x0A3C}, +{ 0x0A5E, 0x0A2B, 0x0A3C}, +{ 0x0B48, 0x0B47, 0x0B56}, +{ 0x0B4B, 0x0B47, 0x0B3E}, +{ 0x0B4C, 0x0B47, 0x0B57}, +{ 0x0B5C, 0x0B21, 0x0B3C}, +{ 0x0B5D, 0x0B22, 0x0B3C}, +{ 0x0B94, 0x0B92, 0x0BD7}, +{ 0x0BCA, 0x0BC6, 0x0BBE}, +{ 0x0BCB, 0x0BC7, 0x0BBE}, +{ 0x0BCC, 0x0BC6, 0x0BD7}, +{ 0x0C48, 0x0C46, 0x0C56}, +{ 0x0CC0, 0x0CBF, 0x0CD5}, +{ 0x0CC7, 0x0CC6, 0x0CD5}, +{ 0x0CC8, 0x0CC6, 0x0CD6}, +{ 0x0CCA, 0x0CC6, 0x0CC2}, +{ 0x0CCB, 0x0CCA, 0x0CD5}, +{ 0x0D4A, 0x0D46, 0x0D3E}, +{ 0x0D4B, 0x0D47, 0x0D3E}, +{ 0x0D4C, 0x0D46, 0x0D57}, +{ 0x0DDA, 0x0DD9, 0x0DCA}, +{ 0x0DDC, 0x0DD9, 0x0DCF}, +{ 0x0DDD, 0x0DDC, 0x0DCA}, +{ 0x0DDE, 0x0DD9, 0x0DDF}, +{ 0x0F43, 0x0F42, 0x0FB7}, +{ 0x0F4D, 0x0F4C, 0x0FB7}, +{ 0x0F52, 0x0F51, 0x0FB7}, +{ 0x0F57, 0x0F56, 0x0FB7}, +{ 0x0F5C, 0x0F5B, 0x0FB7}, +{ 0x0F69, 0x0F40, 0x0FB5}, +{ 0x0F73, 0x0F71, 0x0F72}, +{ 0x0F75, 0x0F71, 0x0F74}, +{ 0x0F76, 0x0FB2, 0x0F80}, +{ 0x0F78, 0x0FB3, 0x0F80}, +{ 0x0F81, 0x0F71, 0x0F80}, +{ 0x0F93, 0x0F92, 0x0FB7}, +{ 0x0F9D, 0x0F9C, 0x0FB7}, +{ 0x0FA2, 0x0FA1, 0x0FB7}, +{ 0x0FA7, 0x0FA6, 0x0FB7}, +{ 0x0FAC, 0x0FAB, 0x0FB7}, +{ 0x0FB9, 0x0F90, 0x0FB5}, +{ 0x1026, 0x1025, 0x102E}, +{ 0x1E00, 0x0041, 0x0325}, +{ 0x1E01, 0x0061, 0x0325}, +{ 0x1E02, 0x0042, 0x0307}, +{ 0x1E03, 0x0062, 0x0307}, +{ 0x1E04, 0x0042, 0x0323}, +{ 0x1E05, 0x0062, 0x0323}, +{ 0x1E06, 0x0042, 0x0331}, +{ 0x1E07, 0x0062, 0x0331}, +{ 0x1E08, 0x00C7, 0x0301}, +{ 0x1E09, 0x00E7, 0x0301}, +{ 0x1E0A, 0x0044, 0x0307}, +{ 0x1E0B, 0x0064, 0x0307}, +{ 0x1E0C, 0x0044, 0x0323}, +{ 0x1E0D, 0x0064, 0x0323}, +{ 0x1E0E, 0x0044, 0x0331}, +{ 0x1E0F, 0x0064, 0x0331}, +{ 0x1E10, 0x0044, 0x0327}, +{ 0x1E11, 0x0064, 0x0327}, +{ 0x1E12, 0x0044, 0x032D}, +{ 0x1E13, 0x0064, 0x032D}, +{ 0x1E14, 0x0112, 0x0300}, +{ 0x1E15, 0x0113, 0x0300}, +{ 0x1E16, 0x0112, 0x0301}, +{ 0x1E17, 0x0113, 0x0301}, +{ 0x1E18, 0x0045, 0x032D}, +{ 0x1E19, 0x0065, 0x032D}, +{ 0x1E1A, 0x0045, 0x0330}, +{ 0x1E1B, 0x0065, 0x0330}, +{ 0x1E1C, 0x0228, 0x0306}, +{ 0x1E1D, 0x0229, 0x0306}, +{ 0x1E1E, 0x0046, 0x0307}, +{ 0x1E1F, 0x0066, 0x0307}, +{ 0x1E20, 0x0047, 0x0304}, +{ 0x1E21, 0x0067, 0x0304}, +{ 0x1E22, 0x0048, 0x0307}, +{ 0x1E23, 0x0068, 0x0307}, +{ 0x1E24, 0x0048, 0x0323}, +{ 0x1E25, 0x0068, 0x0323}, +{ 0x1E26, 0x0048, 0x0308}, +{ 0x1E27, 0x0068, 0x0308}, +{ 0x1E28, 0x0048, 0x0327}, +{ 0x1E29, 0x0068, 0x0327}, +{ 0x1E2A, 0x0048, 0x032E}, +{ 0x1E2B, 0x0068, 0x032E}, +{ 0x1E2C, 0x0049, 0x0330}, +{ 0x1E2D, 0x0069, 0x0330}, +{ 0x1E2E, 0x00CF, 0x0301}, +{ 0x1E2F, 0x00EF, 0x0301}, +{ 0x1E30, 0x004B, 0x0301}, +{ 0x1E31, 0x006B, 0x0301}, +{ 0x1E32, 0x004B, 0x0323}, +{ 0x1E33, 0x006B, 0x0323}, +{ 0x1E34, 0x004B, 0x0331}, +{ 0x1E35, 0x006B, 0x0331}, +{ 0x1E36, 0x004C, 0x0323}, +{ 0x1E37, 0x006C, 0x0323}, +{ 0x1E38, 0x1E36, 0x0304}, +{ 0x1E39, 0x1E37, 0x0304}, +{ 0x1E3A, 0x004C, 0x0331}, +{ 0x1E3B, 0x006C, 0x0331}, +{ 0x1E3C, 0x004C, 0x032D}, +{ 0x1E3D, 0x006C, 0x032D}, +{ 0x1E3E, 0x004D, 0x0301}, +{ 0x1E3F, 0x006D, 0x0301}, +{ 0x1E40, 0x004D, 0x0307}, +{ 0x1E41, 0x006D, 0x0307}, +{ 0x1E42, 0x004D, 0x0323}, +{ 0x1E43, 0x006D, 0x0323}, +{ 0x1E44, 0x004E, 0x0307}, +{ 0x1E45, 0x006E, 0x0307}, +{ 0x1E46, 0x004E, 0x0323}, +{ 0x1E47, 0x006E, 0x0323}, +{ 0x1E48, 0x004E, 0x0331}, +{ 0x1E49, 0x006E, 0x0331}, +{ 0x1E4A, 0x004E, 0x032D}, +{ 0x1E4B, 0x006E, 0x032D}, +{ 0x1E4C, 0x00D5, 0x0301}, +{ 0x1E4D, 0x00F5, 0x0301}, +{ 0x1E4E, 0x00D5, 0x0308}, +{ 0x1E4F, 0x00F5, 0x0308}, +{ 0x1E50, 0x014C, 0x0300}, +{ 0x1E51, 0x014D, 0x0300}, +{ 0x1E52, 0x014C, 0x0301}, +{ 0x1E53, 0x014D, 0x0301}, +{ 0x1E54, 0x0050, 0x0301}, +{ 0x1E55, 0x0070, 0x0301}, +{ 0x1E56, 0x0050, 0x0307}, +{ 0x1E57, 0x0070, 0x0307}, +{ 0x1E58, 0x0052, 0x0307}, +{ 0x1E59, 0x0072, 0x0307}, +{ 0x1E5A, 0x0052, 0x0323}, +{ 0x1E5B, 0x0072, 0x0323}, +{ 0x1E5C, 0x1E5A, 0x0304}, +{ 0x1E5D, 0x1E5B, 0x0304}, +{ 0x1E5E, 0x0052, 0x0331}, +{ 0x1E5F, 0x0072, 0x0331}, +{ 0x1E60, 0x0053, 0x0307}, +{ 0x1E61, 0x0073, 0x0307}, +{ 0x1E62, 0x0053, 0x0323}, +{ 0x1E63, 0x0073, 0x0323}, +{ 0x1E64, 0x015A, 0x0307}, +{ 0x1E65, 0x015B, 0x0307}, +{ 0x1E66, 0x0160, 0x0307}, +{ 0x1E67, 0x0161, 0x0307}, +{ 0x1E68, 0x1E62, 0x0307}, +{ 0x1E69, 0x1E63, 0x0307}, +{ 0x1E6A, 0x0054, 0x0307}, +{ 0x1E6B, 0x0074, 0x0307}, +{ 0x1E6C, 0x0054, 0x0323}, +{ 0x1E6D, 0x0074, 0x0323}, +{ 0x1E6E, 0x0054, 0x0331}, +{ 0x1E6F, 0x0074, 0x0331}, +{ 0x1E70, 0x0054, 0x032D}, +{ 0x1E71, 0x0074, 0x032D}, +{ 0x1E72, 0x0055, 0x0324}, +{ 0x1E73, 0x0075, 0x0324}, +{ 0x1E74, 0x0055, 0x0330}, +{ 0x1E75, 0x0075, 0x0330}, +{ 0x1E76, 0x0055, 0x032D}, +{ 0x1E77, 0x0075, 0x032D}, +{ 0x1E78, 0x0168, 0x0301}, +{ 0x1E79, 0x0169, 0x0301}, +{ 0x1E7A, 0x016A, 0x0308}, +{ 0x1E7B, 0x016B, 0x0308}, +{ 0x1E7C, 0x0056, 0x0303}, +{ 0x1E7D, 0x0076, 0x0303}, +{ 0x1E7E, 0x0056, 0x0323}, +{ 0x1E7F, 0x0076, 0x0323}, +{ 0x1E80, 0x0057, 0x0300}, +{ 0x1E81, 0x0077, 0x0300}, +{ 0x1E82, 0x0057, 0x0301}, +{ 0x1E83, 0x0077, 0x0301}, +{ 0x1E84, 0x0057, 0x0308}, +{ 0x1E85, 0x0077, 0x0308}, +{ 0x1E86, 0x0057, 0x0307}, +{ 0x1E87, 0x0077, 0x0307}, +{ 0x1E88, 0x0057, 0x0323}, +{ 0x1E89, 0x0077, 0x0323}, +{ 0x1E8A, 0x0058, 0x0307}, +{ 0x1E8B, 0x0078, 0x0307}, +{ 0x1E8C, 0x0058, 0x0308}, +{ 0x1E8D, 0x0078, 0x0308}, +{ 0x1E8E, 0x0059, 0x0307}, +{ 0x1E8F, 0x0079, 0x0307}, +{ 0x1E90, 0x005A, 0x0302}, +{ 0x1E91, 0x007A, 0x0302}, +{ 0x1E92, 0x005A, 0x0323}, +{ 0x1E93, 0x007A, 0x0323}, +{ 0x1E94, 0x005A, 0x0331}, +{ 0x1E95, 0x007A, 0x0331}, +{ 0x1E96, 0x0068, 0x0331}, +{ 0x1E97, 0x0074, 0x0308}, +{ 0x1E98, 0x0077, 0x030A}, +{ 0x1E99, 0x0079, 0x030A}, +{ 0x1E9B, 0x017F, 0x0307}, +{ 0x1EA0, 0x0041, 0x0323}, +{ 0x1EA1, 0x0061, 0x0323}, +{ 0x1EA2, 0x0041, 0x0309}, +{ 0x1EA3, 0x0061, 0x0309}, +{ 0x1EA4, 0x00C2, 0x0301}, +{ 0x1EA5, 0x00E2, 0x0301}, +{ 0x1EA6, 0x00C2, 0x0300}, +{ 0x1EA7, 0x00E2, 0x0300}, +{ 0x1EA8, 0x00C2, 0x0309}, +{ 0x1EA9, 0x00E2, 0x0309}, +{ 0x1EAA, 0x00C2, 0x0303}, +{ 0x1EAB, 0x00E2, 0x0303}, +{ 0x1EAC, 0x1EA0, 0x0302}, +{ 0x1EAD, 0x1EA1, 0x0302}, +{ 0x1EAE, 0x0102, 0x0301}, +{ 0x1EAF, 0x0103, 0x0301}, +{ 0x1EB0, 0x0102, 0x0300}, +{ 0x1EB1, 0x0103, 0x0300}, +{ 0x1EB2, 0x0102, 0x0309}, +{ 0x1EB3, 0x0103, 0x0309}, +{ 0x1EB4, 0x0102, 0x0303}, +{ 0x1EB5, 0x0103, 0x0303}, +{ 0x1EB6, 0x1EA0, 0x0306}, +{ 0x1EB7, 0x1EA1, 0x0306}, +{ 0x1EB8, 0x0045, 0x0323}, +{ 0x1EB9, 0x0065, 0x0323}, +{ 0x1EBA, 0x0045, 0x0309}, +{ 0x1EBB, 0x0065, 0x0309}, +{ 0x1EBC, 0x0045, 0x0303}, +{ 0x1EBD, 0x0065, 0x0303}, +{ 0x1EBE, 0x00CA, 0x0301}, +{ 0x1EBF, 0x00EA, 0x0301}, +{ 0x1EC0, 0x00CA, 0x0300}, +{ 0x1EC1, 0x00EA, 0x0300}, +{ 0x1EC2, 0x00CA, 0x0309}, +{ 0x1EC3, 0x00EA, 0x0309}, +{ 0x1EC4, 0x00CA, 0x0303}, +{ 0x1EC5, 0x00EA, 0x0303}, +{ 0x1EC6, 0x1EB8, 0x0302}, +{ 0x1EC7, 0x1EB9, 0x0302}, +{ 0x1EC8, 0x0049, 0x0309}, +{ 0x1EC9, 0x0069, 0x0309}, +{ 0x1ECA, 0x0049, 0x0323}, +{ 0x1ECB, 0x0069, 0x0323}, +{ 0x1ECC, 0x004F, 0x0323}, +{ 0x1ECD, 0x006F, 0x0323}, +{ 0x1ECE, 0x004F, 0x0309}, +{ 0x1ECF, 0x006F, 0x0309}, +{ 0x1ED0, 0x00D4, 0x0301}, +{ 0x1ED1, 0x00F4, 0x0301}, +{ 0x1ED2, 0x00D4, 0x0300}, +{ 0x1ED3, 0x00F4, 0x0300}, +{ 0x1ED4, 0x00D4, 0x0309}, +{ 0x1ED5, 0x00F4, 0x0309}, +{ 0x1ED6, 0x00D4, 0x0303}, +{ 0x1ED7, 0x00F4, 0x0303}, +{ 0x1ED8, 0x1ECC, 0x0302}, +{ 0x1ED9, 0x1ECD, 0x0302}, +{ 0x1EDA, 0x01A0, 0x0301}, +{ 0x1EDB, 0x01A1, 0x0301}, +{ 0x1EDC, 0x01A0, 0x0300}, +{ 0x1EDD, 0x01A1, 0x0300}, +{ 0x1EDE, 0x01A0, 0x0309}, +{ 0x1EDF, 0x01A1, 0x0309}, +{ 0x1EE0, 0x01A0, 0x0303}, +{ 0x1EE1, 0x01A1, 0x0303}, +{ 0x1EE2, 0x01A0, 0x0323}, +{ 0x1EE3, 0x01A1, 0x0323}, +{ 0x1EE4, 0x0055, 0x0323}, +{ 0x1EE5, 0x0075, 0x0323}, +{ 0x1EE6, 0x0055, 0x0309}, +{ 0x1EE7, 0x0075, 0x0309}, +{ 0x1EE8, 0x01AF, 0x0301}, +{ 0x1EE9, 0x01B0, 0x0301}, +{ 0x1EEA, 0x01AF, 0x0300}, +{ 0x1EEB, 0x01B0, 0x0300}, +{ 0x1EEC, 0x01AF, 0x0309}, +{ 0x1EED, 0x01B0, 0x0309}, +{ 0x1EEE, 0x01AF, 0x0303}, +{ 0x1EEF, 0x01B0, 0x0303}, +{ 0x1EF0, 0x01AF, 0x0323}, +{ 0x1EF1, 0x01B0, 0x0323}, +{ 0x1EF2, 0x0059, 0x0300}, +{ 0x1EF3, 0x0079, 0x0300}, +{ 0x1EF4, 0x0059, 0x0323}, +{ 0x1EF5, 0x0079, 0x0323}, +{ 0x1EF6, 0x0059, 0x0309}, +{ 0x1EF7, 0x0079, 0x0309}, +{ 0x1EF8, 0x0059, 0x0303}, +{ 0x1EF9, 0x0079, 0x0303}, +{ 0x1F00, 0x03B1, 0x0313}, +{ 0x1F01, 0x03B1, 0x0314}, +{ 0x1F02, 0x1F00, 0x0300}, +{ 0x1F03, 0x1F01, 0x0300}, +{ 0x1F04, 0x1F00, 0x0301}, +{ 0x1F05, 0x1F01, 0x0301}, +{ 0x1F06, 0x1F00, 0x0342}, +{ 0x1F07, 0x1F01, 0x0342}, +{ 0x1F08, 0x0391, 0x0313}, +{ 0x1F09, 0x0391, 0x0314}, +{ 0x1F0A, 0x1F08, 0x0300}, +{ 0x1F0B, 0x1F09, 0x0300}, +{ 0x1F0C, 0x1F08, 0x0301}, +{ 0x1F0D, 0x1F09, 0x0301}, +{ 0x1F0E, 0x1F08, 0x0342}, +{ 0x1F0F, 0x1F09, 0x0342}, +{ 0x1F10, 0x03B5, 0x0313}, +{ 0x1F11, 0x03B5, 0x0314}, +{ 0x1F12, 0x1F10, 0x0300}, +{ 0x1F13, 0x1F11, 0x0300}, +{ 0x1F14, 0x1F10, 0x0301}, +{ 0x1F15, 0x1F11, 0x0301}, +{ 0x1F18, 0x0395, 0x0313}, +{ 0x1F19, 0x0395, 0x0314}, +{ 0x1F1A, 0x1F18, 0x0300}, +{ 0x1F1B, 0x1F19, 0x0300}, +{ 0x1F1C, 0x1F18, 0x0301}, +{ 0x1F1D, 0x1F19, 0x0301}, +{ 0x1F20, 0x03B7, 0x0313}, +{ 0x1F21, 0x03B7, 0x0314}, +{ 0x1F22, 0x1F20, 0x0300}, +{ 0x1F23, 0x1F21, 0x0300}, +{ 0x1F24, 0x1F20, 0x0301}, +{ 0x1F25, 0x1F21, 0x0301}, +{ 0x1F26, 0x1F20, 0x0342}, +{ 0x1F27, 0x1F21, 0x0342}, +{ 0x1F28, 0x0397, 0x0313}, +{ 0x1F29, 0x0397, 0x0314}, +{ 0x1F2A, 0x1F28, 0x0300}, +{ 0x1F2B, 0x1F29, 0x0300}, +{ 0x1F2C, 0x1F28, 0x0301}, +{ 0x1F2D, 0x1F29, 0x0301}, +{ 0x1F2E, 0x1F28, 0x0342}, +{ 0x1F2F, 0x1F29, 0x0342}, +{ 0x1F30, 0x03B9, 0x0313}, +{ 0x1F31, 0x03B9, 0x0314}, +{ 0x1F32, 0x1F30, 0x0300}, +{ 0x1F33, 0x1F31, 0x0300}, +{ 0x1F34, 0x1F30, 0x0301}, +{ 0x1F35, 0x1F31, 0x0301}, +{ 0x1F36, 0x1F30, 0x0342}, +{ 0x1F37, 0x1F31, 0x0342}, +{ 0x1F38, 0x0399, 0x0313}, +{ 0x1F39, 0x0399, 0x0314}, +{ 0x1F3A, 0x1F38, 0x0300}, +{ 0x1F3B, 0x1F39, 0x0300}, +{ 0x1F3C, 0x1F38, 0x0301}, +{ 0x1F3D, 0x1F39, 0x0301}, +{ 0x1F3E, 0x1F38, 0x0342}, +{ 0x1F3F, 0x1F39, 0x0342}, +{ 0x1F40, 0x03BF, 0x0313}, +{ 0x1F41, 0x03BF, 0x0314}, +{ 0x1F42, 0x1F40, 0x0300}, +{ 0x1F43, 0x1F41, 0x0300}, +{ 0x1F44, 0x1F40, 0x0301}, +{ 0x1F45, 0x1F41, 0x0301}, +{ 0x1F48, 0x039F, 0x0313}, +{ 0x1F49, 0x039F, 0x0314}, +{ 0x1F4A, 0x1F48, 0x0300}, +{ 0x1F4B, 0x1F49, 0x0300}, +{ 0x1F4C, 0x1F48, 0x0301}, +{ 0x1F4D, 0x1F49, 0x0301}, +{ 0x1F50, 0x03C5, 0x0313}, +{ 0x1F51, 0x03C5, 0x0314}, +{ 0x1F52, 0x1F50, 0x0300}, +{ 0x1F53, 0x1F51, 0x0300}, +{ 0x1F54, 0x1F50, 0x0301}, +{ 0x1F55, 0x1F51, 0x0301}, +{ 0x1F56, 0x1F50, 0x0342}, +{ 0x1F57, 0x1F51, 0x0342}, +{ 0x1F59, 0x03A5, 0x0314}, +{ 0x1F5B, 0x1F59, 0x0300}, +{ 0x1F5D, 0x1F59, 0x0301}, +{ 0x1F5F, 0x1F59, 0x0342}, +{ 0x1F60, 0x03C9, 0x0313}, +{ 0x1F61, 0x03C9, 0x0314}, +{ 0x1F62, 0x1F60, 0x0300}, +{ 0x1F63, 0x1F61, 0x0300}, +{ 0x1F64, 0x1F60, 0x0301}, +{ 0x1F65, 0x1F61, 0x0301}, +{ 0x1F66, 0x1F60, 0x0342}, +{ 0x1F67, 0x1F61, 0x0342}, +{ 0x1F68, 0x03A9, 0x0313}, +{ 0x1F69, 0x03A9, 0x0314}, +{ 0x1F6A, 0x1F68, 0x0300}, +{ 0x1F6B, 0x1F69, 0x0300}, +{ 0x1F6C, 0x1F68, 0x0301}, +{ 0x1F6D, 0x1F69, 0x0301}, +{ 0x1F6E, 0x1F68, 0x0342}, +{ 0x1F6F, 0x1F69, 0x0342}, +{ 0x1F70, 0x03B1, 0x0300}, +{ 0x1F72, 0x03B5, 0x0300}, +{ 0x1F74, 0x03B7, 0x0300}, +{ 0x1F76, 0x03B9, 0x0300}, +{ 0x1F78, 0x03BF, 0x0300}, +{ 0x1F7A, 0x03C5, 0x0300}, +{ 0x1F7C, 0x03C9, 0x0300}, +{ 0x1F80, 0x1F00, 0x0345}, +{ 0x1F81, 0x1F01, 0x0345}, +{ 0x1F82, 0x1F02, 0x0345}, +{ 0x1F83, 0x1F03, 0x0345}, +{ 0x1F84, 0x1F04, 0x0345}, +{ 0x1F85, 0x1F05, 0x0345}, +{ 0x1F86, 0x1F06, 0x0345}, +{ 0x1F87, 0x1F07, 0x0345}, +{ 0x1F88, 0x1F08, 0x0345}, +{ 0x1F89, 0x1F09, 0x0345}, +{ 0x1F8A, 0x1F0A, 0x0345}, +{ 0x1F8B, 0x1F0B, 0x0345}, +{ 0x1F8C, 0x1F0C, 0x0345}, +{ 0x1F8D, 0x1F0D, 0x0345}, +{ 0x1F8E, 0x1F0E, 0x0345}, +{ 0x1F8F, 0x1F0F, 0x0345}, +{ 0x1F90, 0x1F20, 0x0345}, +{ 0x1F91, 0x1F21, 0x0345}, +{ 0x1F92, 0x1F22, 0x0345}, +{ 0x1F93, 0x1F23, 0x0345}, +{ 0x1F94, 0x1F24, 0x0345}, +{ 0x1F95, 0x1F25, 0x0345}, +{ 0x1F96, 0x1F26, 0x0345}, +{ 0x1F97, 0x1F27, 0x0345}, +{ 0x1F98, 0x1F28, 0x0345}, +{ 0x1F99, 0x1F29, 0x0345}, +{ 0x1F9A, 0x1F2A, 0x0345}, +{ 0x1F9B, 0x1F2B, 0x0345}, +{ 0x1F9C, 0x1F2C, 0x0345}, +{ 0x1F9D, 0x1F2D, 0x0345}, +{ 0x1F9E, 0x1F2E, 0x0345}, +{ 0x1F9F, 0x1F2F, 0x0345}, +{ 0x1FA0, 0x1F60, 0x0345}, +{ 0x1FA1, 0x1F61, 0x0345}, +{ 0x1FA2, 0x1F62, 0x0345}, +{ 0x1FA3, 0x1F63, 0x0345}, +{ 0x1FA4, 0x1F64, 0x0345}, +{ 0x1FA5, 0x1F65, 0x0345}, +{ 0x1FA6, 0x1F66, 0x0345}, +{ 0x1FA7, 0x1F67, 0x0345}, +{ 0x1FA8, 0x1F68, 0x0345}, +{ 0x1FA9, 0x1F69, 0x0345}, +{ 0x1FAA, 0x1F6A, 0x0345}, +{ 0x1FAB, 0x1F6B, 0x0345}, +{ 0x1FAC, 0x1F6C, 0x0345}, +{ 0x1FAD, 0x1F6D, 0x0345}, +{ 0x1FAE, 0x1F6E, 0x0345}, +{ 0x1FAF, 0x1F6F, 0x0345}, +{ 0x1FB0, 0x03B1, 0x0306}, +{ 0x1FB1, 0x03B1, 0x0304}, +{ 0x1FB2, 0x1F70, 0x0345}, +{ 0x1FB3, 0x03B1, 0x0345}, +{ 0x1FB4, 0x03AC, 0x0345}, +{ 0x1FB6, 0x03B1, 0x0342}, +{ 0x1FB7, 0x1FB6, 0x0345}, +{ 0x1FB8, 0x0391, 0x0306}, +{ 0x1FB9, 0x0391, 0x0304}, +{ 0x1FBA, 0x0391, 0x0300}, +{ 0x1FBC, 0x0391, 0x0345}, +{ 0x1FC1, 0x00A8, 0x0342}, +{ 0x1FC2, 0x1F74, 0x0345}, +{ 0x1FC3, 0x03B7, 0x0345}, +{ 0x1FC4, 0x03AE, 0x0345}, +{ 0x1FC6, 0x03B7, 0x0342}, +{ 0x1FC7, 0x1FC6, 0x0345}, +{ 0x1FC8, 0x0395, 0x0300}, +{ 0x1FCA, 0x0397, 0x0300}, +{ 0x1FCC, 0x0397, 0x0345}, +{ 0x1FCD, 0x1FBF, 0x0300}, +{ 0x1FCE, 0x1FBF, 0x0301}, +{ 0x1FCF, 0x1FBF, 0x0342}, +{ 0x1FD0, 0x03B9, 0x0306}, +{ 0x1FD1, 0x03B9, 0x0304}, +{ 0x1FD2, 0x03CA, 0x0300}, +{ 0x1FD6, 0x03B9, 0x0342}, +{ 0x1FD7, 0x03CA, 0x0342}, +{ 0x1FD8, 0x0399, 0x0306}, +{ 0x1FD9, 0x0399, 0x0304}, +{ 0x1FDA, 0x0399, 0x0300}, +{ 0x1FDD, 0x1FFE, 0x0300}, +{ 0x1FDE, 0x1FFE, 0x0301}, +{ 0x1FDF, 0x1FFE, 0x0342}, +{ 0x1FE0, 0x03C5, 0x0306}, +{ 0x1FE1, 0x03C5, 0x0304}, +{ 0x1FE2, 0x03CB, 0x0300}, +{ 0x1FE4, 0x03C1, 0x0313}, +{ 0x1FE5, 0x03C1, 0x0314}, +{ 0x1FE6, 0x03C5, 0x0342}, +{ 0x1FE7, 0x03CB, 0x0342}, +{ 0x1FE8, 0x03A5, 0x0306}, +{ 0x1FE9, 0x03A5, 0x0304}, +{ 0x1FEA, 0x03A5, 0x0300}, +{ 0x1FEC, 0x03A1, 0x0314}, +{ 0x1FED, 0x00A8, 0x0300}, +{ 0x1FF2, 0x1F7C, 0x0345}, +{ 0x1FF3, 0x03C9, 0x0345}, +{ 0x1FF4, 0x03CE, 0x0345}, +{ 0x1FF6, 0x03C9, 0x0342}, +{ 0x1FF7, 0x1FF6, 0x0345}, +{ 0x1FF8, 0x039F, 0x0300}, +{ 0x1FFA, 0x03A9, 0x0300}, +{ 0x1FFC, 0x03A9, 0x0345}, +{ 0x219A, 0x2190, 0x0338}, +{ 0x219B, 0x2192, 0x0338}, +{ 0x21AE, 0x2194, 0x0338}, +{ 0x21CD, 0x21D0, 0x0338}, +{ 0x21CE, 0x21D4, 0x0338}, +{ 0x21CF, 0x21D2, 0x0338}, +{ 0x2204, 0x2203, 0x0338}, +{ 0x2209, 0x2208, 0x0338}, +{ 0x220C, 0x220B, 0x0338}, +{ 0x2224, 0x2223, 0x0338}, +{ 0x2226, 0x2225, 0x0338}, +{ 0x2241, 0x223C, 0x0338}, +{ 0x2244, 0x2243, 0x0338}, +{ 0x2247, 0x2245, 0x0338}, +{ 0x2249, 0x2248, 0x0338}, +{ 0x2260, 0x003D, 0x0338}, +{ 0x2262, 0x2261, 0x0338}, +{ 0x226D, 0x224D, 0x0338}, +{ 0x226E, 0x003C, 0x0338}, +{ 0x226F, 0x003E, 0x0338}, +{ 0x2270, 0x2264, 0x0338}, +{ 0x2271, 0x2265, 0x0338}, +{ 0x2274, 0x2272, 0x0338}, +{ 0x2275, 0x2273, 0x0338}, +{ 0x2278, 0x2276, 0x0338}, +{ 0x2279, 0x2277, 0x0338}, +{ 0x2280, 0x227A, 0x0338}, +{ 0x2281, 0x227B, 0x0338}, +{ 0x2284, 0x2282, 0x0338}, +{ 0x2285, 0x2283, 0x0338}, +{ 0x2288, 0x2286, 0x0338}, +{ 0x2289, 0x2287, 0x0338}, +{ 0x22AC, 0x22A2, 0x0338}, +{ 0x22AD, 0x22A8, 0x0338}, +{ 0x22AE, 0x22A9, 0x0338}, +{ 0x22AF, 0x22AB, 0x0338}, +{ 0x22E0, 0x227C, 0x0338}, +{ 0x22E1, 0x227D, 0x0338}, +{ 0x22E2, 0x2291, 0x0338}, +{ 0x22E3, 0x2292, 0x0338}, +{ 0x22EA, 0x22B2, 0x0338}, +{ 0x22EB, 0x22B3, 0x0338}, +{ 0x22EC, 0x22B4, 0x0338}, +{ 0x22ED, 0x22B5, 0x0338}, +{ 0x304C, 0x304B, 0x3099}, +{ 0x304E, 0x304D, 0x3099}, +{ 0x3050, 0x304F, 0x3099}, +{ 0x3052, 0x3051, 0x3099}, +{ 0x3054, 0x3053, 0x3099}, +{ 0x3056, 0x3055, 0x3099}, +{ 0x3058, 0x3057, 0x3099}, +{ 0x305A, 0x3059, 0x3099}, +{ 0x305C, 0x305B, 0x3099}, +{ 0x305E, 0x305D, 0x3099}, +{ 0x3060, 0x305F, 0x3099}, +{ 0x3062, 0x3061, 0x3099}, +{ 0x3065, 0x3064, 0x3099}, +{ 0x3067, 0x3066, 0x3099}, +{ 0x3069, 0x3068, 0x3099}, +{ 0x3070, 0x306F, 0x3099}, +{ 0x3071, 0x306F, 0x309A}, +{ 0x3073, 0x3072, 0x3099}, +{ 0x3074, 0x3072, 0x309A}, +{ 0x3076, 0x3075, 0x3099}, +{ 0x3077, 0x3075, 0x309A}, +{ 0x3079, 0x3078, 0x3099}, +{ 0x307A, 0x3078, 0x309A}, +{ 0x307C, 0x307B, 0x3099}, +{ 0x307D, 0x307B, 0x309A}, +{ 0x3094, 0x3046, 0x3099}, +{ 0x309E, 0x309D, 0x3099}, +{ 0x30AC, 0x30AB, 0x3099}, +{ 0x30AE, 0x30AD, 0x3099}, +{ 0x30B0, 0x30AF, 0x3099}, +{ 0x30B2, 0x30B1, 0x3099}, +{ 0x30B4, 0x30B3, 0x3099}, +{ 0x30B6, 0x30B5, 0x3099}, +{ 0x30B8, 0x30B7, 0x3099}, +{ 0x30BA, 0x30B9, 0x3099}, +{ 0x30BC, 0x30BB, 0x3099}, +{ 0x30BE, 0x30BD, 0x3099}, +{ 0x30C0, 0x30BF, 0x3099}, +{ 0x30C2, 0x30C1, 0x3099}, +{ 0x30C5, 0x30C4, 0x3099}, +{ 0x30C7, 0x30C6, 0x3099}, +{ 0x30C9, 0x30C8, 0x3099}, +{ 0x30D0, 0x30CF, 0x3099}, +{ 0x30D1, 0x30CF, 0x309A}, +{ 0x30D3, 0x30D2, 0x3099}, +{ 0x30D4, 0x30D2, 0x309A}, +{ 0x30D6, 0x30D5, 0x3099}, +{ 0x30D7, 0x30D5, 0x309A}, +{ 0x30D9, 0x30D8, 0x3099}, +{ 0x30DA, 0x30D8, 0x309A}, +{ 0x30DC, 0x30DB, 0x3099}, +{ 0x30DD, 0x30DB, 0x309A}, +{ 0x30F4, 0x30A6, 0x3099}, +{ 0x30F7, 0x30EF, 0x3099}, +{ 0x30F8, 0x30F0, 0x3099}, +{ 0x30F9, 0x30F1, 0x3099}, +{ 0x30FA, 0x30F2, 0x3099}, +{ 0x30FE, 0x30FD, 0x3099}, +{ 0xFB1D, 0x05D9, 0x05B4}, +{ 0xFB1F, 0x05F2, 0x05B7}, +{ 0xFB2A, 0x05E9, 0x05C1}, +{ 0xFB2B, 0x05E9, 0x05C2}, +{ 0xFB2C, 0xFB49, 0x05C1}, +{ 0xFB2D, 0xFB49, 0x05C2}, +{ 0xFB2E, 0x05D0, 0x05B7}, +{ 0xFB2F, 0x05D0, 0x05B8}, +{ 0xFB30, 0x05D0, 0x05BC}, +{ 0xFB31, 0x05D1, 0x05BC}, +{ 0xFB32, 0x05D2, 0x05BC}, +{ 0xFB33, 0x05D3, 0x05BC}, +{ 0xFB34, 0x05D4, 0x05BC}, +{ 0xFB35, 0x05D5, 0x05BC}, +{ 0xFB36, 0x05D6, 0x05BC}, +{ 0xFB38, 0x05D8, 0x05BC}, +{ 0xFB39, 0x05D9, 0x05BC}, +{ 0xFB3A, 0x05DA, 0x05BC}, +{ 0xFB3B, 0x05DB, 0x05BC}, +{ 0xFB3C, 0x05DC, 0x05BC}, +{ 0xFB3E, 0x05DE, 0x05BC}, +{ 0xFB40, 0x05E0, 0x05BC}, +{ 0xFB41, 0x05E1, 0x05BC}, +{ 0xFB43, 0x05E3, 0x05BC}, +{ 0xFB44, 0x05E4, 0x05BC}, +{ 0xFB46, 0x05E6, 0x05BC}, +{ 0xFB47, 0x05E7, 0x05BC}, +{ 0xFB48, 0x05E8, 0x05BC}, +{ 0xFB49, 0x05E9, 0x05BC}, +{ 0xFB4A, 0x05EA, 0x05BC}, +{ 0xFB4B, 0x05D5, 0x05B9}, +{ 0xFB4C, 0x05D1, 0x05BF}, +{ 0xFB4D, 0x05DB, 0x05BF}, +{ 0xFB4E, 0x05E4, 0x05BF}, +}; + +/* ------------------------ */ +unsigned int do_precomposition(unsigned int base, unsigned int comb) { + int min = 0; + int max = sizeof(precompositions) / sizeof(precompositions[0]) - 1; + int mid; + unsigned int sought = (base << 16) | comb, that; + + /* binary search */ + while (max >= min) { + mid = (min + max) / 2; + that = (precompositions[mid].base << 16) | (precompositions[mid].comb); + if (that < sought) { + min = mid + 1; + } else if (that > sought) { + max = mid - 1; + } else { + return precompositions[mid].replacement; + } + } + /* no match */ + return 0; +} + +/* -------------------------- */ +unsigned int do_decomposition(unsigned int base) { + int min = 0; + int max = sizeof(decompositions) / sizeof(decompositions[0]) - 1; + int mid; + unsigned int sought = base; + unsigned int result, that; + + /* binary search */ + while (max >= min) { + mid = (min + max) / 2; + that = decompositions[mid].replacement; + if (that < sought) { + min = mid + 1; + } else if (that > sought) { + max = mid - 1; + } else { + result = (decompositions[mid].base << 16) | (decompositions[mid].comb); + return result; + } + } + /* no match */ + return 0; +} diff --git a/etc/afpd/unix.c b/etc/afpd/unix.c index a19f644d..72b634e6 100644 --- a/etc/afpd/unix.c +++ b/etc/afpd/unix.c @@ -1,5 +1,5 @@ /* - * $Id: unix.c,v 1.42 2003-01-12 14:40:03 didg Exp $ + * $Id: unix.c,v 1.43 2003-03-09 19:55:35 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -625,6 +625,7 @@ setdirowner_noadouble: return( 0 ); } +#if 0 /* recursive chown()ing of a directory */ static int recursive_chown(const char *path, uid_t uid, gid_t gid) { struct stat sbuf; @@ -669,6 +670,7 @@ recursive_chown_end: } return ret; } +#endif /* This is equivalent of unix rename(). */ int unix_rename(const char *oldpath, const char *newpath) @@ -680,7 +682,7 @@ int unix_rename(const char *oldpath, const char *newpath) if (rename(oldpath, newpath) < 0) return -1; - +#if 0 for (i = 0; i <= PATH_MAX && newpath[i] != '\0'; i++) pd_name[i] = newpath[i]; pd_name[i] = '\0'; @@ -706,7 +708,7 @@ int unix_rename(const char *oldpath, const char *newpath) pd_name, geteuid(), strerror(errno)); seteuid(uid); } - +#endif return 0; } diff --git a/etc/afpd/volume.c b/etc/afpd/volume.c index 0eb1a933..66c9f364 100644 --- a/etc/afpd/volume.c +++ b/etc/afpd/volume.c @@ -1,5 +1,5 @@ /* - * $Id: volume.c,v 1.48 2003-03-05 09:41:34 didg Exp $ + * $Id: volume.c,v 1.49 2003-03-09 19:55:35 didg Exp $ * * Copyright (c) 1990,1993 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -1240,7 +1240,9 @@ int ibuflen, *rbuflen; volume->v_db = NULL; opened = 1; } - + else { + /* FIXME */ + } #ifdef FORCE_UIDGID set_uidgid ( volume ); #endif /* FORCE_UIDGID */ @@ -1277,6 +1279,31 @@ int ibuflen, *rbuflen; rbuf + sizeof(bitmap), &buflen )) != AFP_OK ) { goto openvol_err; } +#ifdef AFP3x + volume->v_utf8toucs2 = (iconv_t)(-1); + volume->v_ucs2toutf8 = (iconv_t)(-1); + volume->v_mactoutf8 = (iconv_t)(-1); + volume->v_ucs2tomac = (iconv_t)(-1); + + if (vol_utf8(volume)) { + if ((iconv_t)(-1) == (volume->v_utf8toucs2 = iconv_open("UCS-2LE", "UTF-8"))) { + LOG(log_error, logtype_afpd, "openvol: no UTF8 to UCS-2LE"); + goto openvol_err; + } + if ((iconv_t)(-1) == (volume->v_ucs2toutf8 = iconv_open("UTF-8", "UCS-2LE"))) { + LOG(log_error, logtype_afpd, "openvol: no UCS-2LE to UTF-8"); + goto openvol_err_iconv; + } + if ((iconv_t)(-1) == (volume->v_mactoutf8 = iconv_open("UTF-8", "MAC"))) { + LOG(log_error, logtype_afpd, "openvol: no MAC to UTF-8"); + goto openvol_err_iconv; + } + if ((iconv_t)(-1) == (volume->v_ucs2tomac = iconv_open("MAC", "UCS-2LE"))) { + LOG(log_error, logtype_afpd, "openvol: no UCS-2LE to MAC"); + goto openvol_err_iconv; + } + } +#endif *rbuflen = buflen + sizeof( bitmap ); bitmap = htons( bitmap ); memcpy(rbuf, &bitmap, sizeof( bitmap )); @@ -1294,7 +1321,17 @@ int ibuflen, *rbuflen; #endif /* CNID_DB */ return( AFP_OK ); - +#ifdef AFP3x +openvol_err_iconv: + if (volume->v_utf8toucs2 != (iconv_t)(-1)) + iconv_close(volume->v_utf8toucs2); + if (volume->v_ucs2toutf8 != (iconv_t)(-1)) + iconv_close(volume->v_ucs2toutf8); + if (volume->v_mactoutf8 != (iconv_t)(-1)) + iconv_close(volume->v_mactoutf8); + if (volume->v_ucs2tomac != (iconv_t)(-1)) + iconv_close(volume->v_ucs2tomac); +#endif openvol_err: #ifdef CNID_DB if (opened && volume->v_db != NULL) { diff --git a/etc/afpd/volume.h b/etc/afpd/volume.h index 7af56340..f173eee1 100644 --- a/etc/afpd/volume.h +++ b/etc/afpd/volume.h @@ -1,5 +1,5 @@ /* - * $Id: volume.h,v 1.17 2003-01-08 15:01:37 didg Exp $ + * $Id: volume.h,v 1.18 2003-03-09 19:55:35 didg Exp $ * * Copyright (c) 1990,1994 Regents of The University of Michigan. * All Rights Reserved. See COPYRIGHT. @@ -12,6 +12,10 @@ #include #include +#ifdef HAVE_USABLE_ICONV +#include +#endif + #include "globals.h" #define AFPVOL_NAMELEN 27 @@ -55,15 +59,25 @@ struct vol { char *v_password; char *v_veto; + #ifdef CNID_DB void *v_db; char *v_dbpath; -#endif /* CNID_DB */ +#endif mode_t v_umask; + #ifdef FORCE_UIDGID - char *v_forceuid; - char *v_forcegid; -#endif /* FORCE_UIDGID */ + char *v_forceuid; + char *v_forcegid; +#endif + +#ifdef HAVE_USABLE_ICONV + iconv_t *v_utf8toucs2; + iconv_t *v_ucs2toutf8; + iconv_t *v_mactoutf8; + iconv_t *v_ucs2tomac; +#endif + }; #ifdef NO_LARGE_VOL_SUPPORT @@ -148,6 +162,14 @@ int wincheck(const struct vol *vol, const char *path); #define vol_noadouble(vol) (((vol)->v_flags & AFPVOL_NOADOUBLE) ? \ ADFLAGS_NOADOUBLE : 0) +#ifdef AFP3x +#define vol_utf8(vol) ((vol)->v_flags & AFPVOL_UTF8) +#define utf8_encoding() (afp_version >= 30) +#else +#define vol_utf8(vol) (0) +#define utf8_encoding() (0) +#endif + extern struct vol *getvolbyvid __P((const u_int16_t)); extern int ustatfs_getvolspace __P((const struct vol *, VolSpace *, VolSpace *, diff --git a/include/atalk/adouble.h b/include/atalk/adouble.h index 23f5fd48..1e72258f 100644 --- a/include/atalk/adouble.h +++ b/include/atalk/adouble.h @@ -1,5 +1,5 @@ /* - * $Id: adouble.h,v 1.20 2003-02-16 12:35:05 didg Exp $ + * $Id: adouble.h,v 1.21 2003-03-09 19:55:35 didg Exp $ * Copyright (c) 1990,1991 Regents of The University of Michigan. * All Rights Reserved. * @@ -184,6 +184,8 @@ static __inline__ int sendfile(int fdout, int fdin, off_t *off, size_t count) #define ADEDOFF_FILEI 541 #endif +typedef u_int32_t cnid_t; + /* * The header of the AppleDouble Header File looks like this: * diff --git a/include/atalk/cnid.h b/include/atalk/cnid.h index 57aa1c7d..f7e676c0 100644 --- a/include/atalk/cnid.h +++ b/include/atalk/cnid.h @@ -21,8 +21,6 @@ #define CNID_ERR_CLOSE 0x80000004 /* the db was not open */ #define CNID_ERR_MAX 0x80000005 -typedef u_int32_t cnid_t; - /* cnid_open.c */ extern void *cnid_open __P((const char *, mode_t)); diff --git a/libatalk/adouble/ad_open.c b/libatalk/adouble/ad_open.c index a1a68983..4d778171 100644 --- a/libatalk/adouble/ad_open.c +++ b/libatalk/adouble/ad_open.c @@ -1,5 +1,5 @@ /* - * $Id: ad_open.c,v 1.28 2003-02-17 06:26:53 didg Exp $ + * $Id: ad_open.c,v 1.29 2003-03-09 19:55:35 didg Exp $ * * Copyright (c) 1999 Adrian Sun (asun@u.washington.edu) * Copyright (c) 1990,1991 Regents of The University of Michigan. @@ -199,7 +199,7 @@ static __inline__ int ad_v1tov2(struct adouble *ad, const char *path) #define SHIFTDATA (AD_DATASZ2 - AD_DATASZ1) /* bail if we can't get a lock */ - if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0) < 0) + if (ad_tmplock(ad, ADEID_RFORK, ADLOCK_WR, 0, 0, 0) < 0) goto bail_err; if ((fd = open(path, O_RDWR)) < 0) @@ -224,6 +224,9 @@ static __inline__ int ad_v1tov2(struct adouble *ad, const char *path) memmove(buf + off + SHIFTDATA, buf + off, ad->ad_eid[ADEID_RFORK].ade_len); + munmap(buf, st.st_size + SHIFTDATA); + close(fd); + /* now, fix up our copy of the header */ memset(ad->ad_filler, 0, sizeof(ad->ad_filler)); @@ -254,7 +257,7 @@ static __inline__ int ad_v1tov2(struct adouble *ad, const char *path) ad->ad_version = AD_VERSION2; /* move our data buffer to make space for the new entries. */ - memmove(buf + ADEDOFF_NAME_V2, buf + ADEDOFF_NAME_V1, + memmove(ad->ad_data + ADEDOFF_NAME_V2, ad->ad_data + ADEDOFF_NAME_V1, ADEDOFF_RFORK_V1 - ADEDOFF_NAME_V1); /* now, fill in the space with appropriate stuff. we're @@ -267,10 +270,8 @@ static __inline__ int ad_v1tov2(struct adouble *ad, const char *path) memset(ad_entry(ad, ADEID_PRODOSFILEI), 0, ADEDLEN_PRODOSFILEI); /* rebuild the header and cleanup */ - ad_rebuild_header(ad); - munmap(buf, st.st_size + SHIFTDATA); - close(fd); - ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0); + ad_flush(ad, ADFLAGS_HF ); + ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0); return 0; @@ -279,7 +280,7 @@ bail_truncate: bail_open: close(fd); bail_lock: - ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0); + ad_tmplock(ad, ADEID_RFORK, ADLOCK_CLR, 0, 0, 0); bail_err: return -1; } diff --git a/libatalk/cnid/cnid_close.c b/libatalk/cnid/cnid_close.c index dab7b8d8..39e07a48 100644 --- a/libatalk/cnid/cnid_close.c +++ b/libatalk/cnid/cnid_close.c @@ -1,5 +1,5 @@ /* - * $Id: cnid_close.c,v 1.28 2003-01-04 20:49:33 jmarcus Exp $ + * $Id: cnid_close.c,v 1.29 2003-03-09 19:55:35 didg Exp $ */ #ifdef HAVE_CONFIG_H @@ -19,9 +19,8 @@ #include #include -#include - #include "cnid_private.h" +#include void cnid_close(void *CNID) { CNID_private *db;