00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
00020 
00021 
00022 
00023 
00024 
00025 
00026 
00027 
00028 
00029 
00030 
00031 
00032 
00033 
00034 
00035 
00036 
00037 
00038 
00039 
00040 
00041 
00042 
00043 
00044 
00045 
00046 
00047 
00048 
00049 
00050 
00051 
00052 
00053 
00054 
00055 
00056 
00057 #ifdef HAVE_CONFIG_H
00058 # include "config.h"
00059 #endif
00060 #if NEED_GNUG_PRAGMAS
00061 # pragma implementation
00062 #endif
00063 
00064 
00065 
00066 
00067 #include "DjVuMessage.h"
00068 #include "GOS.h"
00069 #include "XMLTags.h"
00070 #include "ByteStream.h"
00071 #include "GURL.h"
00072 #include "debug.h"
00073 #include <ctype.h>
00074 #include <string.h>
00075 #include <stdlib.h>
00076 #ifdef WIN32
00077 # include <tchar.h>
00078 # include <atlbase.h>
00079 # include <windows.h>
00080 # include <winreg.h>
00081 #endif
00082 #ifdef UNIX
00083 # include <unistd.h>
00084 # include <pwd.h>
00085 # include <sys/types.h>
00086 #endif
00087 #include <locale.h>
00088 #ifndef LC_MESSAGES
00089 # define LC_MESSAGES LC_ALL
00090 #endif
00091 
00092 
00093 #ifdef HAVE_NAMESPACES
00094 namespace DJVU {
00095 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00096 }
00097 #endif
00098 #endif
00099 
00100 GUTF8String &
00101 DjVuMessage::programname(void)
00102 {
00103   static GUTF8String xprogramname;
00104   use_language();
00105   return xprogramname;
00106 }
00107 
00108 static const char namestring[]="name";
00109 static const char srcstring[]="src";
00110 
00111 static const char *failed_to_parse_XML=ERR_MSG("DjVuMessage.failed_to_parse_XML");
00112 static const char bodystring[]="BODY";
00113 static const char languagestring[]="LANGUAGE";
00114 static const char headstring[]="HEAD";
00115 static const char includestring[]="INCLUDE";
00116 static const char messagestring[]="MESSAGE";
00117 static const char localestring[]="locale";
00118 
00119 
00120 
00121 static const char opensourcedir[]="osi";
00122 #ifdef AUTOCONF
00123 static const char DjVuDataDir[] = DIR_DATADIR "/djvu";
00124 static const char ModuleDjVuDir[] ="share/djvu";
00125 #else 
00126 static const char ModuleDjVuDir[] ="profiles";
00127 #endif 
00128 static const char LocalDjVuDir[] =".DjVu";      
00129 #ifdef LT_DEFAULT_PREFIX
00130 static const char DjVuPrefixDir[] = LT_DEFAULT_PREFIX "/profiles";
00131 #endif
00132 #ifndef NDEBUG
00133 static const char DebugModuleDjVuDir[] ="../TOPDIR/SRCDIR/profiles";
00134 #endif
00135 #ifdef WIN32
00136 static const char RootDjVuDir[] ="C:/Program Files/LizardTech/Profiles";
00137 static const TCHAR registrypath[]= TEXT("Software\\LizardTech\\DjVu\\Profile Path");
00138 #else
00139 static const char RootDjVuDir[] ="/etc/DjVu/";  
00140 #endif
00141 
00142 static const char DjVuEnv[] = "DJVU_CONFIG_DIR";
00143 
00144 
00145 static const char MessageFile[]="messages.xml";
00146 static const char LanguageFile[]="languages.xml";
00147 
00148 #ifdef WIN32
00149 static GURL
00150 RegOpenReadConfig ( HKEY hParentKey )
00151 {
00152   GURL retval;
00153    
00154   LPCTSTR path = registrypath;
00155 
00156   HKEY hKey = 0;
00157   
00158   if (RegOpenKeyEx(hParentKey, path, 0,
00159               KEY_READ, &hKey) == ERROR_SUCCESS )
00160   {
00161     TCHAR path[1024];
00162     
00163     TCHAR *szPathValue = path;
00164     LPCTSTR lpszEntry = (LPCTSTR &)TEXT("");
00165     DWORD dwCount = (sizeof(path)/sizeof(TCHAR))-1;
00166     DWORD dwType;
00167 
00168     LONG lResult = RegQueryValueEx(hKey, lpszEntry, NULL,
00169              &dwType, (LPBYTE) szPathValue, &dwCount);
00170 
00171     RegCloseKey(hKey);
00172 
00173     if ((lResult == ERROR_SUCCESS))
00174     {
00175       szPathValue[dwCount] = 0;
00176       USES_CONVERSION;
00177       retval=GURL::Filename::Native(T2CA(path));
00178     }
00179   } 
00180 
00181   return retval;
00182 }
00183 
00184 static GURL
00185 GetModulePath( void )
00186 {
00187   const GUTF8String cwd(GOS::cwd());
00188   TCHAR path[1024];
00189   DWORD dwCount = (sizeof(path)/sizeof(TCHAR))-1;
00190   GetModuleFileName(0, path, dwCount);
00191   USES_CONVERSION;
00192   GURL retval=GURL::Filename::Native(T2CA(path)).base();
00193   GOS::cwd(cwd);
00194   return retval;
00195 }
00196 #elif defined(UNIX)
00197 
00198 static GList<GURL>
00199 parsePATH(void)
00200 {
00201   GList<GURL> retval;
00202   const char *path=getenv("PATH");
00203   if(path)
00204   {
00205     GNativeString p(path);
00206     int from=0;
00207     for(int to;(to=p.search(':',from))>0;from=to+1)
00208     {
00209       if(to > from)
00210       {
00211         retval.append(GURL::Filename::Native(p.substr(from,to-from)));
00212       }
00213     }
00214     if((from+1)<(int)p.length())
00215     {
00216       retval.append(GURL::Filename::Native(p.substr(from,-1)));
00217     }
00218   }
00219   return retval;
00220 }
00221 
00222 static GURL
00223 GetModulePath( void )
00224 {
00225  GURL retval;
00226  GUTF8String &xprogramname=DjVuMessage::programname();
00227  if(xprogramname.length())
00228  {
00229    if(xprogramname[1]=='/'
00230      ||!xprogramname.cmp("../",3)
00231      ||!xprogramname.cmp("./",2))
00232    {
00233      retval=GURL::Filename::UTF8(xprogramname);
00234    }
00235    if(retval.is_empty() || !retval.is_file())
00236    {
00237      GList<GURL> paths(parsePATH());
00238      GMap<GUTF8String,void *> pathMAP;
00239      for(GPosition pos=paths;pos;++pos)
00240      {
00241        retval=GURL::UTF8(xprogramname,paths[pos]);
00242        const GUTF8String path(retval.get_string());
00243        if(!pathMAP.contains(path))
00244        {
00245          if(retval.is_file())
00246            break;
00247          pathMAP[path]=0;
00248        }
00249      }
00250    }
00251    if (! retval.is_empty() )
00252      retval = retval.follow_symlinks();
00253    if (! retval.is_empty() )
00254      retval = retval.base();
00255  }
00256  return retval;
00257 }
00258 #endif
00259 
00260 static void
00261 appendPath(const GURL &url, 
00262            GMap<GUTF8String,void *> &map,
00263            GList<GURL> &list)
00264 {
00265   if( !url.is_empty() 
00266       && !map.contains(url.get_string()) && url.is_dir() )
00267     {
00268       map[url.get_string()]=0;
00269       list.append(url);
00270     }
00271 }
00272 
00273 GList<GURL>
00274 DjVuMessage::GetProfilePaths(void)
00275 {
00276   static bool first=true;
00277   static GList<GURL> realpaths;
00278   if(first)
00279   {
00280     first=false;
00281     GMap<GUTF8String,void *> pathsmap;
00282     GList<GURL> paths;
00283     GURL path;
00284     const GUTF8String envp(GOS::getenv(DjVuEnv));
00285     if(envp.length())
00286       appendPath(GURL::Filename::UTF8(envp),pathsmap,paths);
00287 #if defined(WIN32) || defined(UNIX)
00288     GURL mpath(GetModulePath());
00289     if(!mpath.is_empty() && mpath.is_dir())
00290     {
00291 #if defined(UNIX) && !defined(AUTOCONF) && !defined(NDEBUG)
00292       appendPath(GURL::UTF8(DebugModuleDjVuDir,mpath),pathsmap,paths);
00293 #endif
00294       appendPath(mpath,pathsmap,paths);
00295       mpath=mpath.base();
00296       appendPath(GURL::UTF8(ModuleDjVuDir,mpath),pathsmap,paths);
00297       mpath=mpath.base();
00298       appendPath(GURL::UTF8(ModuleDjVuDir,mpath),pathsmap,paths);
00299     }
00300 #endif
00301 #if defined(AUTOCONF)
00302     GURL dpath = GURL::Filename::UTF8(DjVuDataDir);
00303     appendPath(dpath,pathsmap,paths);
00304 #endif
00305 #ifdef WIN32
00306     appendPath(RegOpenReadConfig(HKEY_CURRENT_USER),pathsmap,paths);
00307     appendPath(RegOpenReadConfig(HKEY_LOCAL_MACHINE),pathsmap,paths);
00308 #else
00309     GUTF8String home=GOS::getenv("HOME");
00310 # if HAVE_GETPWUID
00311     if (! home.length()) {
00312       struct passwd *pw=0;
00313       if ((pw = getpwuid(getuid())))
00314         home=GNativeString(pw->pw_dir);
00315     }
00316 # endif
00317     if (home.length()) {
00318       GURL hpath = GURL::UTF8(LocalDjVuDir,GURL::Filename::UTF8(home));
00319       appendPath(hpath,pathsmap,paths);
00320     }
00321 #endif
00322 #ifdef LT_DEFAULT_PREFIX
00323     appendPath(GURL::Filename::UTF8(DjVuPrefixDir),pathsmap,paths);
00324 #endif
00325     appendPath(GURL::Filename::UTF8(RootDjVuDir),pathsmap,paths);
00326     pathsmap.empty();
00327 
00328     GPosition pos;
00329     GList< GMap<GUTF8String,GP<lt_XMLTags> > > localemaps;
00330     for(pos=paths;pos;++pos)
00331     {
00332       path=GURL::UTF8(LanguageFile,paths[pos]);
00333       if(path.is_file())
00334       {
00335         const GP<lt_XMLTags> xml(lt_XMLTags::create(ByteStream::create(path,"rb")));
00336         const GPList<lt_XMLTags> Body(xml->get_Tags(bodystring));
00337         GPosition pos=Body;
00338         if(!pos || (pos != Body.lastpos()))
00339         {
00340           G_THROW( ERR_MSG("XMLAnno.extra_body") );
00341         }
00342         const GP<lt_XMLTags> GBody(Body[pos]);
00343         if(!GBody)
00344         {
00345           G_THROW( ERR_MSG("XMLAnno.no_body") );
00346         }
00347         GMap<GUTF8String,GP<lt_XMLTags> > localemap;
00348         lt_XMLTags::get_Maps(languagestring,localestring,Body,localemap);
00349         localemaps.append(localemap);
00350       }
00351     } 
00352     GList<GURL> localepaths;
00353     GList<GURL> osilocalepaths;
00354 
00355     
00356     GUTF8String defaultlocale = getenv("LANGUAGE");
00357     if (! defaultlocale) 
00358       {
00359         const GUTF8String oldlocale(setlocale(LC_MESSAGES,0));
00360         defaultlocale = setlocale(LC_MESSAGES,"");
00361         setlocale(LC_MESSAGES,(const char *)oldlocale);
00362       }
00363     
00364     for(int loop=0; loop<2; loop++)
00365     {
00366       static const char sepchars[]=" _.@";
00367       const char *p=sepchars+sizeof(sepchars)-1;
00368       do
00369       {
00370         int sepcharpos=p[0]?defaultlocale.search(p[0]):defaultlocale.length();
00371         if(sepcharpos > 0)
00372         {
00373           const GUTF8String sublocale(defaultlocale,sepcharpos);
00374           const GUTF8String downcasesublocale("downcase^"+sublocale.downcase());
00375           for(pos=localemaps;pos;++pos) 
00376           {
00377             const GMap<GUTF8String,GP<lt_XMLTags> > &localemap=localemaps[pos];
00378             GPosition pos=localemap.contains(sublocale);
00379             if(!pos)
00380               pos=localemap.contains(downcasesublocale);
00381             if(pos)
00382             {
00383               const GMap<GUTF8String,GUTF8String>&args
00384                 = localemap[pos]->get_args();
00385               pos = args.contains(srcstring);
00386               if (pos)
00387               {
00388                 const GUTF8String src(args[pos]);
00389                 for(pos=paths;pos;++pos)
00390                 {
00391                   path=GURL::UTF8(src,paths[pos]);
00392                   if(path.is_dir())
00393                     localepaths.append(path);
00394                   path=GURL::UTF8(GUTF8String(opensourcedir)+"/"+src,paths[pos]);
00395                   if(path.is_dir())
00396                     osilocalepaths.append(path);
00397                 }
00398               }
00399               
00400               p=sepchars;
00401               break;
00402             }
00403           }
00404           if(!pos)
00405           {
00406             for(pos=paths;pos;++pos)
00407             {
00408               path=GURL::UTF8(sublocale,paths[pos]);
00409               if(path.is_dir())
00410               {
00411                 localepaths.append(path);
00412               }
00413               path=GURL::UTF8(GUTF8String(opensourcedir)+"/"+sublocale,paths[pos]);
00414               if(path.is_dir())
00415               {
00416                 osilocalepaths.append(path);
00417               }
00418             }
00419           }
00420         }
00421       } while(p-- != sepchars);
00422       if((GPosition) localepaths)
00423         break;
00424       defaultlocale="C";
00425     }
00426     for(pos=localepaths;pos;++pos)
00427       appendPath(localepaths[pos],pathsmap,realpaths);
00428     for(pos=paths;pos;++pos)
00429       appendPath(paths[pos],pathsmap,realpaths);
00430     for(pos=osilocalepaths;pos;++pos)
00431       appendPath(osilocalepaths[pos],pathsmap,realpaths);
00432     for(pos=paths;pos;++pos)
00433       {
00434         path=GURL::UTF8(opensourcedir,paths[pos]);
00435         appendPath(path,pathsmap,realpaths);
00436       }
00437   }
00438   return realpaths;
00439 }
00440 
00441 static GUTF8String
00442 getbodies(
00443   GList<GURL> &paths,
00444   const GUTF8String &MessageFileName,
00445   GPList<lt_XMLTags> &body, 
00446   GMap<GUTF8String, void *> & map )
00447 {
00448   GUTF8String errors;
00449   bool isdone=false;
00450   GPosition firstpathpos=paths;
00451   for(GPosition pathpos=firstpathpos;!isdone && pathpos;++pathpos)
00452   {
00453     const GURL::UTF8 url(MessageFileName,paths[pathpos]);
00454     if(url.is_file())
00455     {
00456       map[MessageFileName]=0;
00457       GP<lt_XMLTags> gtags;
00458       {
00459         GP<ByteStream> bs=ByteStream::create(url,"rb");
00460         G_TRY
00461         {
00462           gtags=lt_XMLTags::create(bs);
00463         }
00464         G_CATCH(ex)
00465         {
00466           GUTF8String mesg(failed_to_parse_XML+("\t"+url.get_string()));
00467           if(errors.length())
00468           {
00469             errors+="\n"+mesg;
00470           }else
00471           {
00472             errors=mesg;
00473           }
00474           errors+="\n"+GUTF8String(ex.get_cause());
00475         }
00476         G_ENDCATCH;
00477       }
00478       if(gtags)
00479       {
00480         lt_XMLTags &tags=*gtags;
00481         GPList<lt_XMLTags> Bodies=tags.get_Tags(bodystring);
00482         if(! Bodies.isempty())
00483         {
00484           isdone=true;
00485           for(GPosition pos=Bodies;pos;++pos)
00486           {
00487             body.append(Bodies[pos]);
00488           }
00489         }
00490         GPList<lt_XMLTags> Head=tags.get_Tags(headstring);
00491         if(! Head.isempty())
00492         {
00493           isdone=true;
00494           GMap<GUTF8String, GP<lt_XMLTags> > includes;
00495           lt_XMLTags::get_Maps(includestring,namestring,Head,includes);
00496           for(GPosition pos=includes;pos;++pos)
00497           {
00498             const GUTF8String file=includes.key(pos);
00499             if(! map.contains(file))
00500             {
00501               GList<GURL> xpaths;
00502               xpaths.append(url.base());
00503               const GUTF8String err2(getbodies(xpaths,file,body,map));
00504               if(err2.length())
00505               {
00506                 if(errors.length())
00507                 {
00508                   errors+="\n"+err2;
00509                 }else
00510                 {
00511                   errors=err2;
00512                 }
00513               }
00514             }
00515           }
00516         }
00517       }
00518     }
00519   }
00520   return errors;
00521 }
00522 
00523 static GUTF8String
00524 parse(GMap<GUTF8String,GP<lt_XMLTags> > &retval)
00525 {
00526   GUTF8String errors;
00527   GPList<lt_XMLTags> body;
00528   {
00529     GList<GURL> paths=DjVuMessage::GetProfilePaths();
00530     GMap<GUTF8String, void *> map;
00531     GUTF8String m(MessageFile);
00532     errors=getbodies(paths,m,body,map);
00533   }
00534   if(! body.isempty())
00535   {
00536     lt_XMLTags::get_Maps(messagestring,namestring,body,retval);
00537   }
00538   return errors;
00539 }
00540 
00541 
00542 const DjVuMessageLite &
00543 DjVuMessage::create_full(void)
00544 {
00545   GP<DjVuMessageLite> &static_message=getDjVuMessageLite();
00546   if(!static_message)
00547   {
00548     DjVuMessage *mesg=new DjVuMessage;
00549     static_message=mesg;
00550     mesg->init();
00551   }
00552   return DjVuMessageLite::create_lite();
00553 }
00554 
00555 void
00556 DjVuMessage::set_programname(const GUTF8String &xprogramname)
00557 {
00558   programname()=xprogramname;
00559   DjVuMessageLite::create=create_full; 
00560 }
00561 
00562 void
00563 DjVuMessage::use_language(void)
00564 { 
00565   DjVuMessageLite::create=create_full; 
00566 }
00567 
00568 
00569 
00570 DjVuMessage::DjVuMessage( void ) {}
00571 
00572 void
00573 DjVuMessage::init(void)
00574 {
00575   errors=parse(Map);
00576 }
00577 
00578 
00579 DjVuMessage::~DjVuMessage( )
00580 {
00581 }
00582 
00583 
00584 
00585 
00586 
00587 
00588 void
00589 DjVuMessageLookUpNative( 
00590   char *msg_buffer, const unsigned int buffer_size, const char *message)
00591 {
00592   const GNativeString converted(DjVuMessage::LookUpNative( message ));
00593   if( converted.length() >= buffer_size )
00594     msg_buffer[0] = '\0';
00595   else
00596     strcpy( msg_buffer, converted );
00597 }
00598 
00599 
00600 
00601 
00602 
00603 void
00604 DjVuMessageLookUpUTF8( 
00605   char *msg_buffer, const unsigned int buffer_size, const char *message)
00606 {
00607   const GUTF8String converted(DjVuMessage::LookUpUTF8( message ));
00608   if( converted.length() >= buffer_size )
00609     msg_buffer[0] = '\0';
00610   else
00611     strcpy( msg_buffer, converted );
00612 }
00613 
00614 
00615 
00616 #ifdef HAVE_NAMESPACES
00617 }
00618 # ifndef NOT_USING_DJVU_NAMESPACE
00619 using namespace DJVU;
00620 # endif
00621 #endif
00622 
00623 void
00624 DjVuFormatErrorUTF8( const char *fmt, ... )
00625 {
00626   va_list args;
00627   va_start(args, fmt); 
00628   const GUTF8String message(fmt,args);
00629   DjVuWriteError( message );
00630 }
00631 
00632 void
00633 DjVuFormatErrorNative( const char *fmt, ... )
00634 {
00635   va_list args;
00636   va_start(args, fmt); 
00637   const GNativeString message(fmt,args);
00638   DjVuWriteError( message );
00639 }
00640 
00641 const char *
00642 djvu_programname(const char *xprogramname)
00643 {
00644   if(xprogramname)
00645     DjVuMessage::programname()=GNativeString(xprogramname);
00646   return DjVuMessage::programname();
00647 }