 src/index.cpp              | 192 ++++++++++++++++++++++-----------------------
 src/search.js              |  10 ++-
 src/search_functions.php   |   2 +-
 src/search_functions_php.h |   2 +-
 src/search_js.h            |  10 ++-
 src/searchindex.cpp        | 121 +++++++++++++++++++---------
 src/util.cpp               |  73 +++++++++++++++++
 src/util.h                 |   8 ++
 8 files changed, 278 insertions(+), 140 deletions(-)

diff --git a/src/index.cpp b/src/index.cpp
index 944d5db..7e3aed7 100644
--- a/src/index.cpp
+++ b/src/index.cpp
@@ -25,6 +25,8 @@
 #include <qdatetime.h>
 #include <qdir.h>
 #include <qregexp.h>
+#include <qmap.h>
+#include <qvaluelist.h>
 
 #include "message.h"
 #include "index.h"
@@ -51,7 +53,6 @@
 #define MAX_ITEMS_BEFORE_MULTIPAGE_INDEX 200
 #define MAX_ITEMS_BEFORE_QUICK_INDEX 30
 
-
 int annotatedClasses;
 int annotatedClassesPrinted;
 int hierarchyClasses;
@@ -129,13 +130,12 @@ class MemberIndexList : public QList<MemberDef>
     }
 };
 
-#define MEMBER_INDEX_ENTRIES 256
-
-static MemberIndexList g_memberIndexLetterUsed[CMHL_Total][MEMBER_INDEX_ENTRIES];
-static MemberIndexList g_fileIndexLetterUsed[FMHL_Total][MEMBER_INDEX_ENTRIES];
-static MemberIndexList g_namespaceIndexLetterUsed[NMHL_Total][MEMBER_INDEX_ENTRIES];
+/*! Dictionary from character identifier as unicode to member list for index */
+typedef QMap<uint, MemberIndexList> CharToMemberIndexList;
 
-//static bool g_classIndexLetterUsed[CHL_Total][256];
+static CharToMemberIndexList g_memberIndexLetterUsed[CMHL_Total];
+static CharToMemberIndexList g_fileIndexLetterUsed[FMHL_Total];
+static CharToMemberIndexList g_namespaceIndexLetterUsed[NMHL_Total];
 
 const int maxItemsBeforeQuickIndex = MAX_ITEMS_BEFORE_QUICK_INDEX;
 
@@ -1690,12 +1690,34 @@ static void writeAnnotatedClassList(OutputList &ol)
   ol.endIndexList();
 }
 
-static QCString letterToLabel(char startLetter)
+
+/*! Generate the string used to postfix the anchor label
+
+If given value makes isId() returns false, this function returns "0xHH".
+Otherwise, this function returns utf-8 string.
+
+Currently isId() returns true when the value over 0x7F is given.
+
+for HTML5, there is no limit to use any character with "id" attribute.
+"name" attribute cannot contain non ASCII chararters, but major browsers
+can support and "name" is deprecated (should be replaced with "id").
+
+@param startLetter The integer represents a unicode character, 0 - MAX_UNICODE_CODEPOINT
+@return The utf-8 string to append to anchor label "letter_"
+*/
+static QCString letterToLabel(uint startLetter)
 {
   QCString s(5); 
   if (isId(startLetter))
   {
-    s[0]=startLetter; s[1]=0;
+    if ( startLetter < 0x7f )
+    {
+      s[0]=startLetter; s[1]=0;
+    }
+    else
+    {
+      s = QString( QChar( startLetter ) ).utf8();
+    }
   }
   else
   {
@@ -1709,6 +1731,7 @@ static QCString letterToLabel(char startLetter)
   return s;
 }
 
+
 //----------------------------------------------------------------------------
 
 /** Special class list where sorting takes IGNORE_PREFIX into account. */
@@ -1730,19 +1753,19 @@ public:
 class AlphaIndexTableCell
 {
   public:
-    AlphaIndexTableCell(int row,int col,uchar letter,ClassDef *cd) : 
+    AlphaIndexTableCell(int row,int col,uint letter,ClassDef *cd) : 
       m_letter(letter), m_class(cd), m_row(row), m_col(col) 
     { //printf("AlphaIndexTableCell(%d,%d,%c,%s)\n",row,col,letter!=0 ? letter: '-',
       //       cd!=(ClassDef*)0x8 ? cd->name().data() : "<null>"); 
     }
 
     ClassDef *classDef() const { return m_class; }
-    uchar letter()       const { return m_letter; }
+    uint  letter()       const { return m_letter; }
     int row()            const { return m_row; }
     int column()         const { return m_col; }
 
   private:
-    uchar m_letter;
+    uint m_letter;
     ClassDef *m_class;
     int m_row;
     int m_col;
@@ -1774,9 +1797,8 @@ class AlphaIndexTableColumns : public QList<AlphaIndexTableRows>
 static void writeAlphabeticalClassList(OutputList &ol)
 {
   // What starting letters are used
-  bool indexLetterUsed[256];
-  memset (indexLetterUsed, 0, sizeof (indexLetterUsed));
-
+  QValueList<uint> indexLetterUsed;
+  
   // first count the number of headers
   ClassSDict::Iterator cli(*Doxygen::classSDict);
   ClassDef *cd;
@@ -1788,26 +1810,26 @@ static void writeAlphabeticalClassList(OutputList &ol)
     {
       if (cd->getLanguage()==SrcLangExt_VHDL && !((VhdlDocGen::VhdlClasses)cd->protection()==VhdlDocGen::ENTITYCLASS ))// no architecture
         continue;
-	     
+
       int index = getPrefixIndex(cd->className());
       //printf("name=%s index=%d %d\n",cd->className().data(),index,cd->protection());
-      startLetter=toupper(cd->className().at(index))&0xFF;
-      indexLetterUsed[startLetter] = true;
+      startLetter=getNextUtf8OrToUpper( cd->className(), index );
+      indexLetterUsed.append( startLetter );
     }
   }
 
   // write quick link index (row of letters)
   QCString alphaLinks = "<div class=\"qindex\">";
-  int l;
-  for (l=0; l<256; l++)
+  uint l;
+  for (l=0; l<=MAX_UNICODE_CODEPOINT; l++)
   {
-    if (indexLetterUsed[l])
+    if ( indexLetterUsed.find(l) != indexLetterUsed.end() )
     {
       if (headerItems) alphaLinks += "&#160;|&#160;";
       headerItems++;
+      QCString lc = QString( QChar( l ) ).utf8();
       alphaLinks += (QCString)"<a class=\"qindex\" href=\"#letter_" + 
-                    (char)l + "\">" + 
-                    (char)l + "</a>";
+                    lc + "\">" + lc + "</a>";
     }
   }
   alphaLinks += "</div>\n";
@@ -1825,7 +1847,7 @@ static void writeAlphabeticalClassList(OutputList &ol)
   //    headerItems,totalItems,columns,rows,itemsInLastRow);
 
   // Keep a list of classes for each starting letter
-  PrefixIgnoreClassList classesByLetter[256];
+  QMap<uint, PrefixIgnoreClassList> classesByLetter;
   AlphaIndexTableColumns tableColumns;
 
   // fill the columns with the class list (row elements in each column,
@@ -1841,7 +1863,7 @@ static void writeAlphabeticalClassList(OutputList &ol)
     if (cd->isLinkableInProject() && cd->templateMaster()==0)
     {
       int index = getPrefixIndex(cd->className());
-      startLetter=toupper(cd->className().at(index))&0xFF;
+      startLetter=getNextUtf8OrToUpper(cd->className(),index);
       // Do some sorting again, since the classes are sorted by name with 
       // prefix, which should be ignored really.
       if (cd->getLanguage()==SrcLangExt_VHDL)
@@ -1871,12 +1893,12 @@ static void writeAlphabeticalClassList(OutputList &ol)
   AlphaIndexTableRows *tableRows = new AlphaIndexTableRows;
   tableColumns.append(tableRows);
   int col=0,row=0,maxRows=0;
-  for (l=0; l<256; l++)
+  for (l=0; l<=MAX_UNICODE_CODEPOINT; l++)
   {
-    if (classesByLetter[l].count()>0)
+    if (classesByLetter.find(l) != classesByLetter.end())
     {
       // add special header cell
-      tableRows->append(new AlphaIndexTableCell(row,col,(uchar)l,(ClassDef*)0x8));
+      tableRows->append(new AlphaIndexTableCell(row,col,l,(ClassDef*)0x8));
       row++;
       tableRows->append(new AlphaIndexTableCell(row,col,0,(ClassDef*)0x8));
       row++;
@@ -2163,15 +2185,16 @@ static void writeNamespaceLinkForMember(OutputList &ol,MemberDef *md,const char
   }
 }
 
+
 static void writeMemberList(OutputList &ol,bool useSections,int page,
-                            MemberIndexList memberLists[MEMBER_INDEX_ENTRIES],
+                            CharToMemberIndexList& memberLists,
                             DefinitionIntf::DefType type)
 {
-  int pi;
+  uint pi;
   // page==-1 => write all member indices to one page (used when total members is small)
   // page!=-1 => write all member for this page only (used when total member is large)
-  int startIndex = page==-1 ? 0                      : page;
-  int endIndex   = page==-1 ? MEMBER_INDEX_ENTRIES-1 : page;
+  uint startIndex = page==-1 ? 0                       : page;
+  uint endIndex   = page==-1 ? MAX_UNICODE_CODEPOINT+1 : page;
   ASSERT((int)type<3);
 
   typedef void (*writeLinkForMember_t)(OutputList &ol,MemberDef *md,const char *separator,
@@ -2189,10 +2212,13 @@ static void writeMemberList(OutputList &ol,bool useSections,int page,
   bool first=TRUE;
   bool firstSection=TRUE;
   bool firstItem=TRUE;
-  for (pi=startIndex; pi<=endIndex; pi++) // page==-1 => pi=[0..127], page!=-1 => pi=page 
+  for (pi=startIndex; pi<=endIndex; pi++) // page==-1 => pi=[0..MAX_UNICODE_CODEPOINT], page!=-1 => pi=page 
   {
+    if ( memberLists.find(pi) == memberLists.end() )
+    {
+      continue;
+    }
     MemberIndexList *ml = &memberLists[pi];
-    if (ml->count()==0) continue;
     ml->sort();
     QListIterator<MemberDef> mli(*ml);
     MemberDef *md;
@@ -2205,18 +2231,16 @@ static void writeMemberList(OutputList &ol,bool useSections,int page,
       int startIndex = getPrefixIndex(name);
       if (QCString(name.data()+startIndex)!=prevName) // new entry
       {
+        const uint newHeadChar = getNextUtf8OrToLower( name, startIndex );
         if ((prevName.isEmpty() || 
-            tolower(name.at(startIndex))!=tolower(prevName.at(0))) && 
+            newHeadChar != getNextUtf8OrToLower(prevName , 0) ) && 
             useSections) // new section
         {
           if (!firstItem)    ol.endItemListItem();
           if (!firstSection) ol.endItemList();
-          char cl[2];
-          cl[0] = tolower(name.at(startIndex));
-          cl[1] = 0;
-          QCString cs = letterToLabel(cl[0]);
+          QCString cs = letterToLabel( newHeadChar );
           QCString anchor=(QCString)"index_"+cs;
-          QCString title=(QCString)"- "+cl+" -";
+          QCString title= (QString("- ")+QChar(newHeadChar)+" -").utf8();
           ol.startSection(anchor,title,SectionInfo::Subsection);
           ol.docify(title);
           ol.endSection(anchor,SectionInfo::Subsection);
@@ -2265,20 +2289,15 @@ void initClassMemberIndices()
   for (j=0;j<CMHL_Total;j++)
   {
     documentedClassMembers[j]=0;
-    for (i=0;i<MEMBER_INDEX_ENTRIES;i++) 
-    {
-      g_memberIndexLetterUsed[j][i].clear();
-    }
+    g_memberIndexLetterUsed[j].clear();
   }
 }
 
+
 void addClassMemberNameToIndex(MemberDef *md)
 {
   static bool hideFriendCompounds = Config_getBool("HIDE_FRIEND_COMPOUNDS");
   ClassDef *cd=0;
-
- 
-  
   if (md->isLinkableInProject() && 
       (cd=md->getClassDef())    && 
       cd->isLinkableInProject() &&
@@ -2286,8 +2305,7 @@ void addClassMemberNameToIndex(MemberDef *md)
   {
     QCString n = md->name();
     int index = getPrefixIndex(n);
-    uchar charCode = (uchar)n.at(index);
-    uint letter = charCode<128 ? tolower(charCode) : charCode;
+    uint letter = getNextUtf8OrToLower( n, index );
     if (!n.isEmpty()) 
     {
       bool isFriendToHide = hideFriendCompounds &&
@@ -2299,7 +2317,7 @@ void addClassMemberNameToIndex(MemberDef *md)
         g_memberIndexLetterUsed[CMHL_All][letter].append(md);
         documentedClassMembers[CMHL_All]++;
       }
-      if (md->isFunction()  || md->isSlot() || md->isSignal())
+      if (md->isFunction() || md->isSlot() || md->isSignal())
       {
         g_memberIndexLetterUsed[CMHL_Functions][letter].append(md);
         documentedClassMembers[CMHL_Functions]++;
@@ -2348,15 +2366,11 @@ void addClassMemberNameToIndex(MemberDef *md)
 
 void initNamespaceMemberIndices()
 {
-  int i=0;
   int j=0;
   for (j=0;j<NMHL_Total;j++)
   {
     documentedNamespaceMembers[j]=0;
-    for (i=0;i<MEMBER_INDEX_ENTRIES;i++) 
-    {
-      g_namespaceIndexLetterUsed[j][i].clear();
-    }
+    g_namespaceIndexLetterUsed[j].clear();
   }
 }
 
@@ -2367,8 +2381,7 @@ void addNamespaceMemberNameToIndex(MemberDef *md)
   {
     QCString n = md->name();
     int index = getPrefixIndex(n);
-    uchar charCode = (uchar)n.at(index);
-    uint letter = charCode<128 ? tolower(charCode) : charCode;
+    uint letter = getNextUtf8OrToLower( n, index );
     if (!n.isEmpty()) 
     {
       g_namespaceIndexLetterUsed[NMHL_All][letter].append(md);
@@ -2407,15 +2420,11 @@ void addNamespaceMemberNameToIndex(MemberDef *md)
 
 void initFileMemberIndices()
 {
-  int i=0;
   int j=0;
   for (j=0;j<NMHL_Total;j++)
   {
     documentedFileMembers[j]=0;
-    for (i=0;i<MEMBER_INDEX_ENTRIES;i++) 
-    {
-      g_fileIndexLetterUsed[j][i].clear();
-    }
+    g_fileIndexLetterUsed[j].clear();
   }
 }
 
@@ -2426,8 +2435,7 @@ void addFileMemberNameToIndex(MemberDef *md)
   {
     QCString n = md->name();
     int index = getPrefixIndex(n);
-    uchar charCode = (uchar)n.at(index);
-    uint letter = charCode<128 ? tolower(charCode) : charCode;
+    uint letter = getNextUtf8OrToLower( n, index );
     if (!n.isEmpty()) 
     {
       g_fileIndexLetterUsed[FMHL_All][letter].append(md);
@@ -2470,18 +2478,18 @@ void addFileMemberNameToIndex(MemberDef *md)
 //----------------------------------------------------------------------------
 
 static void writeQuickMemberIndex(OutputList &ol,
-    MemberIndexList charUsed[MEMBER_INDEX_ENTRIES],int page,
+    const CharToMemberIndexList& charUsed,uint page,
     QCString fullName,bool multiPage)
 {
   bool first=TRUE;
-  int i;
+  uint i;
   startQuickIndexList(ol,TRUE);
-  for (i=33;i<127;i++)
+  for (i=33;i<=MAX_UNICODE_CODEPOINT;i++)
   {
-    char is[2];is[0]=(char)i;is[1]='\0';
-    QCString ci = letterToLabel((char)i);
-    if (charUsed[i].count()>0)
+    if ( charUsed.find(i) != charUsed.end() )
     {
+      QCString ci = letterToLabel(i);
+      QCString is = QString( QChar( i ) ).utf8();
       QCString anchor;
       QCString extension=Doxygen::htmlFileExtension;
       if (!multiPage)
@@ -2538,11 +2546,11 @@ static void writeClassMemberIndexFiltered(OutputList &ol, ClassMemberHighlight h
   static bool disableIndex     = Config_getBool("DISABLE_INDEX");
 
   bool multiPageIndex=FALSE;
-  int numPages=1;
+  uint numPages=1;
   if (documentedClassMembers[hl]>MAX_ITEMS_BEFORE_MULTIPAGE_INDEX)
   {
     multiPageIndex=TRUE;
-    numPages=127;
+    numPages=MAX_UNICODE_CODEPOINT+1;
   }
 
   ol.pushGeneratorState();
@@ -2561,11 +2569,11 @@ static void writeClassMemberIndexFiltered(OutputList &ol, ClassMemberHighlight h
     if (multiPageIndex) Doxygen::indexList->incContentsDepth();
   }
 
-  int page;
+  uint page;
   bool first=TRUE;
   for (page=0;page<numPages;page++)
   {
-    if (!multiPageIndex || g_memberIndexLetterUsed[hl][page].count()>0)
+    if (!multiPageIndex || g_memberIndexLetterUsed[hl].find(page) != g_memberIndexLetterUsed[hl].end() )
     {
       QCString fileName = getCmhlInfo(hl)->fname;
       if (multiPageIndex)
@@ -2574,12 +2582,9 @@ static void writeClassMemberIndexFiltered(OutputList &ol, ClassMemberHighlight h
         {
           fileName+=QCString().sprintf("_0x%02x",page);
         }
-        char cs[2];
-        cs[0]=page;
-        cs[1]=0;
         if (addToIndex)
         {
-          Doxygen::indexList->addContentsItem(FALSE,cs,0,fileName,0,FALSE,TRUE);
+          Doxygen::indexList->addContentsItem(FALSE,QString( QChar( page ) ).utf8(),0,fileName,0,FALSE,TRUE);
         }
       }
       bool quickIndex = documentedClassMembers[hl]>maxItemsBeforeQuickIndex;
@@ -2720,7 +2725,7 @@ static void writeFileMemberIndexFiltered(OutputList &ol, FileMemberHighlight hl)
   if (documentedFileMembers[hl]>MAX_ITEMS_BEFORE_MULTIPAGE_INDEX)
   {
     multiPageIndex=TRUE;
-    numPages=127;
+    numPages=MAX_UNICODE_CODEPOINT+1;
   }
 
   ol.pushGeneratorState();
@@ -2742,7 +2747,7 @@ static void writeFileMemberIndexFiltered(OutputList &ol, FileMemberHighlight hl)
   bool first=TRUE;
   for (page=0;page<numPages;page++)
   {
-    if (!multiPageIndex || g_fileIndexLetterUsed[hl][page].count()>0)
+    if (!multiPageIndex || g_fileIndexLetterUsed[hl].find(page) != g_fileIndexLetterUsed[hl].end() )
     {
       QCString fileName = getFmhlInfo(hl)->fname;
       if (multiPageIndex)
@@ -2751,12 +2756,9 @@ static void writeFileMemberIndexFiltered(OutputList &ol, FileMemberHighlight hl)
         {
           fileName+=QCString().sprintf("_0x%02x",page);
         }
-        char cs[2];
-        cs[0]=page;
-        cs[1]=0;
         if (addToIndex)
         {
-          Doxygen::indexList->addContentsItem(FALSE,cs,0,fileName,0,FALSE,TRUE);
+          Doxygen::indexList->addContentsItem(FALSE,QString( QChar( page ) ).utf8(),0,fileName,0,FALSE,TRUE);
         }
       }
       bool quickIndex = documentedFileMembers[hl]>maxItemsBeforeQuickIndex;
@@ -2894,7 +2896,7 @@ static void writeNamespaceMemberIndexFiltered(OutputList &ol,
   if (documentedNamespaceMembers[hl]>MAX_ITEMS_BEFORE_MULTIPAGE_INDEX)
   {
     multiPageIndex=TRUE;
-    numPages=127;
+    numPages=MAX_UNICODE_CODEPOINT+1;
   }
 
   ol.pushGeneratorState();
@@ -2916,7 +2918,7 @@ static void writeNamespaceMemberIndexFiltered(OutputList &ol,
   bool first=TRUE;
   for (page=0;page<numPages;page++)
   {
-    if (!multiPageIndex || g_namespaceIndexLetterUsed[hl][page].count()>0)
+    if (!multiPageIndex || g_namespaceIndexLetterUsed[hl].find(page) != g_namespaceIndexLetterUsed[hl].end() )
     {
       QCString fileName = getNmhlInfo(hl)->fname;
       if (multiPageIndex)
@@ -2925,12 +2927,9 @@ static void writeNamespaceMemberIndexFiltered(OutputList &ol,
         {
           fileName+=QCString().sprintf("_0x%02x",page);
         }
-        char cs[2];
-        cs[0]=page;
-        cs[1]=0;
         if (addToIndex)
         {
-          Doxygen::indexList->addContentsItem(FALSE,cs,0,fileName,0,FALSE,TRUE);
+          Doxygen::indexList->addContentsItem(FALSE,QString( QChar( page ) ).utf8(),0,fileName,0,FALSE,TRUE);
         }
       }
       bool quickIndex = documentedNamespaceMembers[hl]>maxItemsBeforeQuickIndex;
@@ -3100,7 +3099,7 @@ bool writeMemberNavIndex(FTextStream &t,
                          int indent,
                          int n,
                          int documentedMembers[],
-                         MemberIndexList indexLetterUsed[][MEMBER_INDEX_ENTRIES],
+                         CharToMemberIndexList indexLetterUsed[],
                          const T *(*getInfo)(int),
                          bool &first
                         )
@@ -3136,10 +3135,10 @@ bool writeMemberNavIndex(FTextStream &t,
       if (quickIndex)
       {
         t << "[ " << endl;
-        int j;
-        for (j=33;j<127;j++)
+        uint j;
+        for (j=33;j<=MAX_UNICODE_CODEPOINT;j++)
         {
-          if (indexLetterUsed[i][j].count()>0)
+          if (indexLetterUsed[i].find(j) != indexLetterUsed[i].end() )
           {
             if (!firstPage) t << "," << endl;
             QCString fullName = getInfo(i)->fname;
@@ -3149,8 +3148,9 @@ bool writeMemberNavIndex(FTextStream &t,
               anchor=fullName+extension+"#index_";
             else 
               anchor=fullName+QCString().sprintf("_0x%02x",j)+extension+"#index_";
-            char is[2];is[0]=(char)j;is[1]='\0';
-            QCString ci = letterToLabel((char)j);
+            QString iss( QChar( j ) );
+            QCString is = iss.utf8();
+            QCString ci = letterToLabel(j);
             t << indentStr << "    [ ";
             t << "\"" << is << "\", ";
             t << "\"" << anchor << ci << "\", null ]";
diff --git a/src/search.js b/src/search.js
index 3ed3f90..e279aeb 100644
--- a/src/search.js
+++ b/src/search.js
@@ -5,7 +5,7 @@ function convertToId(search)
   {
     var c = search.charAt(i);
     var cn = c.charCodeAt(0);
-    if (c.match(/[a-z0-9]/))
+    if (c.match(/[a-z0-9\u0080-\uFFFF]/))
     {
       result+=c;
     }
@@ -310,6 +310,12 @@ function SearchBox(name, resultsPath, inFrame, label)
     var searchValue = this.DOMSearchField().value.replace(/^ +/, "");
 
     var code = searchValue.toLowerCase().charCodeAt(0);
+    var idxChar = searchValue.substr(0, 1).toLowerCase();
+    if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1)
+    {
+      code = 0x10000 + ( code - 0xD800 ) * 0x400 + searchValue.charCodeAt(1) - 0xDC00;
+      idxChar = searchValue.substr(0, 2);
+    }
     var hexCode;
     if (code<16) 
     {
@@ -324,7 +330,7 @@ function SearchBox(name, resultsPath, inFrame, label)
     var resultsPageWithSearch;
     var hasResultsPage;
 
-    if (indexSectionsWithContent[this.searchIndex].charAt(code) == '1')
+    if (indexSectionsWithContent[this.searchIndex].indexOf(idxChar) != -1)
     {
        resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';
        resultsPageWithSearch = resultsPage+'?'+escape(searchValue);
diff --git a/src/search_functions.php b/src/search_functions.php
index acd7f3c..5ad2e5d 100644
--- a/src/search_functions.php
+++ b/src/search_functions.php
@@ -358,7 +358,7 @@ function main()
   $sorted = run_query($query);
   // Now output the HTML stuff...
   // End the HTML form
-  end_form(preg_replace("/[^a-zA-Z0-9\-\_\.]/i", " ", $query ));
+  end_form(preg_replace("/[^a-zA-Z0-9\-\_\.\x80-\xFF]/i", " ", $query ));
   // report results to the user
   report_results($sorted);
   end_page();
diff --git a/src/search_functions_php.h b/src/search_functions_php.h
index b09c259..9c7c3e3 100644
--- a/src/search_functions_php.h
+++ b/src/search_functions_php.h
@@ -358,7 +358,7 @@
 "  $sorted = run_query($query);\n"
 "  // Now output the HTML stuff...\n"
 "  // End the HTML form\n"
-"  end_form(preg_replace(\"/[^a-zA-Z0-9\\-\\_\\.]/i\", \" \", $query ));\n"
+"  end_form(preg_replace(\"/[^a-zA-Z0-9\\-\\_\\.\\x80-\\xFF]/i\", \" \", $query ));\n"
 "  // report results to the user\n"
 "  report_results($sorted);\n"
 "  end_page();\n"
diff --git a/src/search_js.h b/src/search_js.h
index 985d03c..37940de 100644
--- a/src/search_js.h
+++ b/src/search_js.h
@@ -5,7 +5,7 @@
 "  {\n"
 "    var c = search.charAt(i);\n"
 "    var cn = c.charCodeAt(0);\n"
-"    if (c.match(/[a-z0-9]/))\n"
+"    if (c.match(/[a-z0-9\\u0080-\\uFFFF]/))\n"
 "    {\n"
 "      result+=c;\n"
 "    }\n"
@@ -310,6 +310,12 @@
 "    var searchValue = this.DOMSearchField().value.replace(/^ +/, \"\");\n"
 "\n"
 "    var code = searchValue.toLowerCase().charCodeAt(0);\n"
+"    var idxChar = searchValue.substr(0, 1).toLowerCase();\n"
+"    if ( 0xD800 <= code && code <= 0xDBFF && searchValue > 1)\n"
+"    {\n"
+"      code = 0x10000 + ( code - 0xD800 ) * 0x400 + searchValue.charCodeAt(1) - 0xDC00;\n"
+"      idxChar = searchValue.substr(0, 2);\n"
+"    }\n"
 "    var hexCode;\n"
 "    if (code<16) \n"
 "    {\n"
@@ -324,7 +330,7 @@
 "    var resultsPageWithSearch;\n"
 "    var hasResultsPage;\n"
 "\n"
-"    if (indexSectionsWithContent[this.searchIndex].charAt(code) == '1')\n"
+"    if (indexSectionsWithContent[this.searchIndex].indexOf(idxChar) != -1)\n"
 "    {\n"
 "       resultsPage = this.resultsPath + '/' + indexSectionNames[this.searchIndex] + '_' + hexCode + '.html';\n"
 "       resultsPageWithSearch = resultsPage+'?'+escape(searchValue);\n"
diff --git a/src/searchindex.cpp b/src/searchindex.cpp
index 0380b33..9c19d7b 100644
--- a/src/searchindex.cpp
+++ b/src/searchindex.cpp
@@ -20,6 +20,7 @@
 
 #include <qfile.h>
 #include <qregexp.h>
+#include <qintdict.h>
 
 #include "searchindex.h"
 #include "config.h"
@@ -37,7 +38,7 @@
 #include "filename.h"
 #include "membername.h"
 
-// file format: (all multi-byte values are stored in big endian format)
+// file format: (all multi-byte intergers are stored in big endian format)
 //   4 byte header
 //   256*256*4 byte index (4 bytes)
 //   for each index entry: a zero terminated list of words 
@@ -586,9 +587,6 @@ void SearchIndexExternal::write(const char *fileName)
 static const char search_script[]=
 #include "search_js.h"
 ;
-
-#define MEMBER_INDEX_ENTRIES   256
-
 #define SEARCH_INDEX_ALL         0
 #define SEARCH_INDEX_CLASSES     1
 #define SEARCH_INDEX_NAMESPACES  2
@@ -634,8 +632,50 @@ class SearchIndexList : public SDict< QList<Definition> >
     }
 };
 
+
+class CharToSearchIndexList : protected QIntDict< SearchIndexList >
+{
+public:
+    typedef SearchIndexList* fake_iterator;
+    CharToSearchIndexList() : QIntDict< SearchIndexList >()
+    {
+        setAutoDelete(true);
+    }
+    virtual ~CharToSearchIndexList() { }
+    SearchIndexList& operator [] ( const uint key )
+    {
+        SearchIndexList* ptr = find( key );
+        if ( ptr != end() ) { return *ptr; }
+        ptr = new SearchIndexList;
+        insert( key, ptr );
+        return *ptr;
+    }
+    const SearchIndexList& operator [] ( const uint key ) const
+    {
+        SearchIndexList* ptr = find( key );
+        if ( ptr != end() ) { return *ptr; }
+        printf("!!! CharToSearchIndexList::operator[] const illegally called.\n");
+        static SearchIndexList dummy;
+        return dummy;
+    }
+    fake_iterator find( const uint key ) const
+    {
+        return QIntDict< SearchIndexList >::find( key );
+    }
+    fake_iterator end() const { return 0; }
+    void sortAllLists()
+    {
+        for (uint p=0;p<=MAX_UNICODE_CODEPOINT;p++)
+        {
+            fake_iterator it = find(p);
+            if (it != end()) { it->sort(); }
+        }
+    }
+};
+
+
 static void addMemberToSearchIndex(
-         SearchIndexList symbols[NUM_SEARCH_INDICES][MEMBER_INDEX_ENTRIES],
+         CharToSearchIndexList* symbols,
          int symbolCount[NUM_SEARCH_INDICES],
          MemberDef *md)
 {
@@ -653,10 +693,9 @@ static void addMemberToSearchIndex(
      )
   {
     QCString n = md->name();
-    uchar charCode = (uchar)n.at(0);
-    uint letter = charCode<128 ? tolower(charCode) : charCode;
     if (!n.isEmpty()) 
     {
+      uint letter = getNextUtf8OrToLower(n, 0);
       bool isFriendToHide = hideFriendCompounds &&
         (QCString(md->typeString())=="friend class" || 
          QCString(md->typeString())=="friend struct" ||
@@ -716,10 +755,9 @@ static void addMemberToSearchIndex(
      )
   {
     QCString n = md->name();
-    uchar charCode = (uchar)n.at(0);
-    uint letter = charCode<128 ? tolower(charCode) : charCode;
     if (!n.isEmpty()) 
     {
+      uint letter = getNextUtf8OrToLower(n, 0);
       symbols[SEARCH_INDEX_ALL][letter].append(md);
       symbolCount[SEARCH_INDEX_ALL]++;
 
@@ -765,9 +803,20 @@ static QCString searchId(const QCString &s)
   for (i=0;i<s.length();i++)
   {
     c=s.at(i);
-    if ((c>='0' && c<='9') || (c>='A' && c<='Z') || (c>='a' && c<='z'))
+    if (c>0x7f || c<0)
     {
-      result+=(char)tolower(c);
+      result+=s.at(i);
+    }
+    else if (isalnum(c))
+    {
+      if (isupper(c))
+      {
+        result+=(char)tolower(c);
+      }
+      else
+      {
+        result+=s.at(i);
+      }
     }
     else
     {
@@ -780,7 +829,7 @@ static QCString searchId(const QCString &s)
 }
 
 static int g_searchIndexCount[NUM_SEARCH_INDICES];
-static SearchIndexList g_searchIndexSymbols[NUM_SEARCH_INDICES][MEMBER_INDEX_ENTRIES];
+static CharToSearchIndexList g_searchIndexSymbols[NUM_SEARCH_INDICES];
 static const char *g_searchIndexName[NUM_SEARCH_INDICES] = 
 { 
     "all",
@@ -834,8 +883,7 @@ void writeJavascriptSearchIndex()
   ClassDef *cd;
   for (;(cd=cli.current());++cli)
   {
-    uchar charCode = (uchar)cd->localName().at(0);
-    uint letter = charCode<128 ? tolower(charCode) : charCode;
+    uint letter = getNextUtf8OrToLower( cd->localName(), 0 );
     if (cd->isLinkable() && isId(letter))
     {
       g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(cd);
@@ -850,8 +898,7 @@ void writeJavascriptSearchIndex()
   NamespaceDef *nd;
   for (;(nd=nli.current());++nli)
   {
-    uchar charCode = (uchar)nd->name().at(0);
-    uint letter = charCode<128 ? tolower(charCode) : charCode;
+    uint letter = getNextUtf8OrToLower( nd->name(), 0 );
     if (nd->isLinkable() && isId(letter))
     {
       g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(nd);
@@ -870,8 +917,7 @@ void writeJavascriptSearchIndex()
     FileDef *fd;
     for (;(fd=fni.current());++fni)
     {
-      uchar charCode = (uchar)fd->name().at(0);
-      uint letter = charCode<128 ? tolower(charCode) : charCode;
+      uint letter = getNextUtf8OrToLower(fd->name(), 0);
       if (fd->isLinkable() && isId(letter))
       {
         g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(fd);
@@ -926,8 +972,7 @@ void writeJavascriptSearchIndex()
       QCString title = gd->groupTitle();
       if (!title.isEmpty()) // TODO: able searching for all word in the title
       {
-        uchar charCode = title.at(0);
-        uint letter = charCode<128 ? tolower(charCode) : charCode;
+        uint letter = getNextUtf8OrToLower(title, 0);
         if (isId(letter))
         {
           g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(gd);
@@ -949,8 +994,7 @@ void writeJavascriptSearchIndex()
       QCString title = pd->title();
       if (!title.isEmpty())
       {
-        uchar charCode = title.at(0);
-        uint letter = charCode<128 ? tolower(charCode) : charCode;
+        uint letter = getNextUtf8OrToLower(title, 0);
         if (isId(letter))
         {
           g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(pd);
@@ -966,8 +1010,7 @@ void writeJavascriptSearchIndex()
     QCString title = Doxygen::mainPage->title();
     if (!title.isEmpty())
     {
-      uchar charCode = title.at(0);
-      uint letter = charCode<128 ? tolower(charCode) : charCode;
+      uint letter = getNextUtf8OrToLower(title, 0);
       if (isId(letter))
       {
         g_searchIndexSymbols[SEARCH_INDEX_ALL][letter].append(Doxygen::mainPage);
@@ -979,26 +1022,22 @@ void writeJavascriptSearchIndex()
   }
   
   // sort all lists
-  int i,p;
+  int i;
   for (i=0;i<NUM_SEARCH_INDICES;i++)
   {
-    for (p=0;p<MEMBER_INDEX_ENTRIES;p++)
-    {
-      if (g_searchIndexSymbols[i][p].count()>0)
-      {
-        g_searchIndexSymbols[i][p].sort();
-      }
-    }
+    g_searchIndexSymbols[i].sortAllLists();
   }
 
   // write index files
   QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search";
-
+  int p;
   for (i=0;i<NUM_SEARCH_INDICES;i++)
   {
-    for (p=0;p<MEMBER_INDEX_ENTRIES;p++)
+    CharToSearchIndexList& li = g_searchIndexSymbols[i];
+    for (p=0;p<=MAX_UNICODE_CODEPOINT;p++)
     {
-      if (g_searchIndexSymbols[i][p].count()>0)
+      CharToSearchIndexList::fake_iterator it = li.find(p);
+      if (it != li.end())
       {
         QCString baseName;
         baseName.sprintf("%s_%02x",g_searchIndexName[i],p);
@@ -1060,7 +1099,7 @@ void writeJavascriptSearchIndex()
           ti << "[" << endl;
           bool firstEntry=TRUE;
 
-          SDict<QList<Definition> >::Iterator li(g_searchIndexSymbols[i][p]);
+          SDict<QList<Definition> >::Iterator li(*it);
           QList<Definition> *dl;
           int itemCount=0;
           for (li.toFirst();(dl=li.current());++li)
@@ -1275,9 +1314,15 @@ void writeJavascriptSearchIndex()
         {
           if (!first) t << "," << endl;
           t << "  " << j << ": \"";
-          for (p=0;p<MEMBER_INDEX_ENTRIES;p++)
+  
+          CharToSearchIndexList& li = g_searchIndexSymbols[i];
+          for (p=0;p<=MAX_UNICODE_CODEPOINT;p++)
           {
-            t << (g_searchIndexSymbols[i][p].count()>0 ? "1" : "0");
+            CharToSearchIndexList::fake_iterator it = li.find(p);
+            if (it != li.end())
+            {
+              t << QString( QChar( p ) ).utf8();
+            }
           }
           t << "\"";
           first=FALSE;
diff --git a/src/util.cpp b/src/util.cpp
index f135fe4..c76beff 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -6990,6 +6990,79 @@ QCString parseCommentAsText(const Definition *scope,const MemberDef *md,
 
 //--------------------------------------------------------------------------------------
 
+/*! @brief Pick one unicode character as interger from utf-8 string
+
+Called from index.cpp and searchindex.cpp through
+getNextUtf8OrToLower() or getNextUtf8OrToUpper().
+
+@param s utf-8 string
+@param idx pick up position of given string \a s.
+@return the unicode codepoint, 0 - MAX_UNICODE_CODEPOINT
+@see getNextUtf8OrToLower()
+@see getNextUtf8OrToUpper()
+*/
+uint getNextUtf8Code( const QCString& s, int idx )
+{
+  const int length = s.length();
+  if (idx >= length) { return 0; }
+  const uint c0 = (uchar)s.at(idx);
+  if ( c0 < 0xC2 || c0 >= 0xF8 )
+  {
+    return c0;
+  }
+  if (idx+1 >= length) { return 0; }
+  const uint c1 = ((uchar)s.at(idx+1)) & 0x3f;
+  if ( c0 < 0xE0 )
+  {
+    return ((c0 & 0x1f) << 6) | c1;
+  }
+  if (idx+2 >= length) { return 0; }
+  const uint c2 = ((uchar)s.at(idx+2)) & 0x3f;
+  if ( c0 < 0xF0 )
+  {
+    return ((c0 & 0x0f) << 12) | (c1 << 6) | c2;
+  }
+  if (idx+3 >= length) { return 0; }
+  const uint c3 = ((uchar)s.at(idx+3)) & 0x3f;
+  return ((c0 & 0x07) << 18) | (c1 << 12) | (c2 << 6) | c3;
+}
+
+
+/*! @brief Pick one unicode character as interger from utf-8 string
+
+Called from index.cpp and searchindex.cpp
+
+@param s utf-8 string
+@param idx pick up position of given string \a s.
+@return the unicode codepoint, 0 - MAX_UNICODE_CODEPOINT, excludes 'A'-'Z'
+@see getNextUtf8Code()
+@see getNextUtf8OrToUpper()
+*/
+uint getNextUtf8OrToLower( const QCString& s, int idx )
+{
+  const uint v = getNextUtf8Code( s, idx );
+  return v < 0x7f ? tolower( v ) : v;
+}
+
+
+/*! @brief Pick one unicode character as interger from utf-8 string
+
+Called from index.cpp.
+
+@param s utf-8 string
+@param idx pick up position of given string \a s.
+@return the unicode codepoint, 0 - MAX_UNICODE_CODEPOINT, excludes 'a'-'z'
+@see getNextUtf8Code()
+@see getNextUtf8OrToUpper()
+*/
+uint getNextUtf8OrToUpper( const QCString& s, int idx )
+{
+  const uint v = getNextUtf8Code( s, idx );
+  return v < 0x7f ? toupper( v ) : v;
+}
+
+//--------------------------------------------------------------------------------------
+
 static QDict<void> aliasesProcessed;
 
 static QCString expandAliasRec(const QCString s);
diff --git a/src/util.h b/src/util.h
index 1aba005..2f4ea4b 100644
--- a/src/util.h
+++ b/src/util.h
@@ -383,6 +383,14 @@ QCString externalRef(const QCString &relPath,const QCString &ref,bool href);
 int nextUtf8CharPosition(const QCString &utf8Str,int len,int startPos);
 const char *writeUtf8Char(FTextStream &t,const char *s);
 
+uint getNextUtf8Code( const QCString& s, int idx );
+uint getNextUtf8OrToLower( const QCString& s, int idx );
+uint getNextUtf8OrToUpper( const QCString& s, int idx );
+
+#ifndef MAX_UNICODE_CODEPOINT
+#define MAX_UNICODE_CODEPOINT (0x10FFFF)
+#endif
+
 /** Data associated with a HSV colored image. */
 struct ColoredImgDataItem
 {
