void lt_XMLParser::Impl::ChangeAnno( const int width, const int height, DjVuFile &dfile, const lt_XMLTags &map ) { dfile.resume_decode(true); const GP<DjVuInfo> info(dfile.info); const GP<DjVuAnno> ganno(DjVuAnno::create()); DjVuAnno &anno=*ganno; GPosition map_pos; map_pos=map.contains(areatag); if(dfile.contains_anno()) { GP<ByteStream> annobs=dfile.get_merged_anno(); if(annobs) { anno.decode(annobs); if(anno.ant && info) { anno.ant->map_areas.empty(); } } // dfile.remove_anno(); } if(info && map_pos) { const int h=info->height; const int w=info->width; double ws=1.0; double hs=1.0; if(width && width != w) { ws=((double)w)/((double)width); } if(height && height != h) { hs=((double)h)/((double)height); } if(!anno.ant) { anno.ant=DjVuANT::create(); } GPList<GMapArea> &map_areas=anno.ant->map_areas; map_areas.empty(); GPList<lt_XMLTags> gareas=map[map_pos]; for(GPosition pos=gareas;pos;++pos) { if(gareas[pos]) { lt_XMLTags &areas=*(gareas[pos]); GMap<GUTF8String,GUTF8String> args(areas.get_args()); GList<int> coords; // ****************************************************** // Parse the coords attribute: first read the raw data into // a list, then scale the x, y data into another list. For // circles, you also get a radius element with (looks like an x // with no matching y). // ****************************************************** { GPosition coords_pos=args.contains("coords"); if(coords_pos) { GList<int> raw_coords; intList(args[coords_pos],raw_coords); for(GPosition raw_pos=raw_coords;raw_pos;++raw_pos) { const int r=raw_coords[raw_pos]; const int x=(int)(ws*(double)r+0.5); coords.append(x); int y=h-1; if(! ++raw_pos) { y-=(int)(hs*(double)r+0.5); }else { y-=(int)(hs*(double)raw_coords[raw_pos]+0.5); } coords.append(y); // DjVuPrintMessage("Coords (%d,%d)\n",x,y); } } } GUTF8String shape; { GPosition shape_pos=args.contains("shape"); if(shape_pos) { shape=args[shape_pos]; } } GP<GMapArea> a; if(shape == "default") { GRect rect(0,0,w,h); a=GMapRect::create(rect); }else if(!shape.length() || shape == "rect") { int xx[4]; int i=0; for(GPosition rect_pos=coords;(rect_pos)&&(i<4);++rect_pos,++i) { xx[i]=coords[rect_pos]; } if(i!=4) { G_THROW( ERR_MSG("XMLAnno.bad_rect") ); } int xmin,xmax; if(xx[0]>xx[2]) { xmax=xx[0]; xmin=xx[2]; }else { xmin=xx[0]; xmax=xx[2]; } int ymin,ymax; if(xx[1]>xx[3]) { ymax=xx[1]; ymin=xx[3]; }else { ymin=xx[1]; ymax=xx[3]; } GRect rect(xmin,ymin,xmax-xmin,ymax-ymin); a=GMapRect::create(rect); }else if(shape == "circle") { int xx[4]; int i=0; GPosition rect_pos=coords.lastpos(); if(rect_pos) { coords.append(coords[rect_pos]); for(rect_pos=coords;(rect_pos)&&(i<4);++rect_pos) { xx[i++]=coords[rect_pos]; } } if(i!=4) { G_THROW( ERR_MSG("XMLAnno.bad_circle") ); } int x=xx[0],y=xx[1],rx=xx[2],ry=(h-xx[3])-1; GRect rect(x-rx,y-ry,2*rx,2*ry); a=GMapOval::create(rect); }else if(shape == "oval") { int xx[4]; int i=0; for(GPosition rect_pos=coords;(rect_pos)&&(i<4);++rect_pos,++i) { xx[i]=coords[rect_pos]; } if(i!=4) { G_THROW( ERR_MSG("XMLAnno.bad_oval") ); } int xmin,xmax; if(xx[0]>xx[2]) { xmax=xx[0]; xmin=xx[2]; }else { xmin=xx[0]; xmax=xx[2]; } int ymin,ymax; if(xx[1]>xx[3]) { ymax=xx[1]; ymin=xx[3]; }else { ymin=xx[1]; ymax=xx[3]; } GRect rect(xmin,ymin,xmax-xmin,ymax-ymin); a=GMapOval::create(rect); }else if(shape == "poly") { GP<GMapPoly> p=GMapPoly::create(); for(GPosition poly_pos=coords;poly_pos;++poly_pos) { int x=coords[poly_pos]; if(! ++poly_pos) break; int y=coords[poly_pos]; p->add_vertex(x,y); } p->close_poly(); a=p; }else { G_THROW( ( ERR_MSG("XMLAnno.unknown_shape") "\t")+shape ); } if(a) { GPosition pos; if((pos=args.contains("href"))) { a->url=args[pos]; } if((pos=args.contains("target"))) { a->target=args[pos]; } if((pos=args.contains("alt"))) { a->comment=args[pos]; } if((pos=args.contains("bordertype"))) { GUTF8String b=args[pos]; static const GMap<GUTF8String,GMapArea::BorderType> typeMap=BorderTypeMap(); if((pos=typeMap.contains(b))) { a->border_type=typeMap[pos]; }else { G_THROW( (ERR_MSG("XMLAnno.unknown_border") "\t")+b ); } } a->border_always_visible=!!args.contains("visible"); if((pos=args.contains("bordercolor"))) { a->border_color=convertToColor(args[pos]); } if((pos=args.contains("highlight"))) { a->hilite_color=convertToColor(args[pos]); } if((pos=args.contains("border"))) { a->border_width=args[pos].toInt(); //atoi(args[pos]); } map_areas.append(a); } } } } dfile.set_modified(true); dfile.anno=ByteStream::create(); anno.encode(dfile.anno); }
static GUTF8String getbodies( GList<GURL> &paths, const GUTF8String &MessageFileName, GPList<lt_XMLTags> &body, GMap<GUTF8String, void *> & map ) { GUTF8String errors; bool isdone=false; GPosition firstpathpos=paths; for(GPosition pathpos=firstpathpos;!isdone && pathpos;++pathpos) { const GURL::UTF8 url(MessageFileName,paths[pathpos]); if(url.is_file()) { map[MessageFileName]=0; GP<lt_XMLTags> gtags; { GP<ByteStream> bs=ByteStream::create(url,"rb"); G_TRY { gtags=lt_XMLTags::create(bs); } G_CATCH(ex) { GUTF8String mesg(failed_to_parse_XML+("\t"+url.get_string())); if(errors.length()) { errors+="\n"+mesg; }else { errors=mesg; } errors+="\n"+GUTF8String(ex.get_cause()); } G_ENDCATCH; } if(gtags) { lt_XMLTags &tags=*gtags; GPList<lt_XMLTags> Bodies=tags.get_Tags(bodystring); if(! Bodies.isempty()) { isdone=true; for(GPosition pos=Bodies;pos;++pos) { body.append(Bodies[pos]); } } GPList<lt_XMLTags> Head=tags.get_Tags(headstring); if(! Head.isempty()) { isdone=true; GMap<GUTF8String, GP<lt_XMLTags> > includes; lt_XMLTags::get_Maps(includestring,namestring,Head,includes); for(GPosition pos=includes;pos;++pos) { const GUTF8String file=includes.key(pos); if(! map.contains(file)) { GList<GURL> xpaths; xpaths.append(url.base()); const GUTF8String err2(getbodies(xpaths,file,body,map)); if(err2.length()) { if(errors.length()) { errors+="\n"+err2; }else { errors=err2; } } } } } } } }
GList<GURL> DjVuMessage::GetProfilePaths(void) { static bool first=true; static GList<GURL> realpaths; if(first) { first=false; GMap<GUTF8String,void *> pathsmap; GList<GURL> paths; GURL path; const GUTF8String envp(GOS::getenv(DjVuEnv)); if(envp.length()) appendPath(GURL::Filename::UTF8(envp),pathsmap,paths); #if defined(WIN32) || defined(UNIX) GURL mpath(GetModulePath()); if(!mpath.is_empty() && mpath.is_dir()) { #if defined(UNIX) && !defined(AUTOCONF) && !defined(NDEBUG) appendPath(GURL::UTF8(DebugModuleDjVuDir,mpath),pathsmap,paths); #endif appendPath(mpath,pathsmap,paths); appendPath(GURL::UTF8(ModuleDjVuDir,mpath),pathsmap,paths); appendPath(GURL::UTF8(ProfilesDjVuDir,mpath),pathsmap,paths); mpath=mpath.base(); appendPath(GURL::UTF8(ModuleDjVuDir,mpath),pathsmap,paths); appendPath(GURL::UTF8(ProfilesDjVuDir,mpath),pathsmap,paths); mpath=mpath.base(); appendPath(GURL::UTF8(ModuleDjVuDir,mpath),pathsmap,paths); appendPath(GURL::UTF8(ProfilesDjVuDir,mpath),pathsmap,paths); mpath=mpath.base(); appendPath(GURL::UTF8(ModuleDjVuDir,mpath),pathsmap,paths); appendPath(GURL::UTF8(ProfilesDjVuDir,mpath),pathsmap,paths); } #endif #if defined(AUTOCONF) GURL dpath = GURL::Filename::UTF8(DjVuDataDir); appendPath(dpath,pathsmap,paths); #endif #ifdef WIN32 appendPath(RegOpenReadConfig(HKEY_CURRENT_USER),pathsmap,paths); appendPath(RegOpenReadConfig(HKEY_LOCAL_MACHINE),pathsmap,paths); #else GUTF8String home=GOS::getenv("HOME"); # if HAVE_GETPWUID if (! home.length()) { struct passwd *pw=0; if ((pw = getpwuid(getuid()))) home=GNativeString(pw->pw_dir); } # endif if (home.length()) { GURL hpath = GURL::UTF8(LocalDjVuDir,GURL::Filename::UTF8(home)); appendPath(hpath,pathsmap,paths); } #endif #ifdef LT_DEFAULT_PREFIX appendPath(GURL::Filename::UTF8(DjVuPrefixDir),pathsmap,paths); #endif appendPath(GURL::Filename::UTF8(RootDjVuDir),pathsmap,paths); pathsmap.empty(); GPosition pos; GList< GMap<GUTF8String,GP<lt_XMLTags> > > localemaps; for(pos=paths;pos;++pos) { path=GURL::UTF8(LanguageFile,paths[pos]); if(path.is_file()) { const GP<lt_XMLTags> xml(lt_XMLTags::create(ByteStream::create(path,"rb"))); const GPList<lt_XMLTags> Body(xml->get_Tags(bodystring)); GPosition pos=Body; if(!pos || (pos != Body.lastpos())) { G_THROW( ERR_MSG("XMLAnno.extra_body") ); } const GP<lt_XMLTags> GBody(Body[pos]); if(!GBody) { G_THROW( ERR_MSG("XMLAnno.no_body") ); } GMap<GUTF8String,GP<lt_XMLTags> > localemap; lt_XMLTags::get_Maps(languagestring,localestring,Body,localemap); localemaps.append(localemap); } } GList<GURL> localepaths; // Need to do it the right way! GUTF8String defaultlocale = getenv("LANGUAGE"); if (! defaultlocale) { const GUTF8String oldlocale(setlocale(LC_MESSAGES,0)); defaultlocale = setlocale(LC_MESSAGES,""); setlocale(LC_MESSAGES,(const char *)oldlocale); } // Unfathomable search. for(int loop=0; loop<2; loop++) { static const char sepchars[]=" _.@"; const char *p=sepchars+sizeof(sepchars)-1; do { int sepcharpos=p[0]?defaultlocale.search(p[0]):defaultlocale.length(); if(sepcharpos > 0) { const GUTF8String sublocale(defaultlocale,sepcharpos); const GUTF8String downcasesublocale("downcase^"+sublocale.downcase()); for(pos=localemaps;pos;++pos) { const GMap<GUTF8String,GP<lt_XMLTags> > &localemap=localemaps[pos]; GPosition pos=localemap.contains(sublocale); if(!pos) pos=localemap.contains(downcasesublocale); if(pos) { const GMap<GUTF8String,GUTF8String>&args = localemap[pos]->get_args(); pos = args.contains(srcstring); if (pos) { const GUTF8String src(args[pos]); for(pos=paths;pos;++pos) { path=GURL::UTF8(src,paths[pos]); if(path.is_dir()) localepaths.append(path); } } // We don't need to check anymore language files. p=sepchars; break; } } if(!pos) { for(pos=paths;pos;++pos) { path=GURL::UTF8(sublocale,paths[pos]); if(path.is_dir()) localepaths.append(path); } } } } while(p-- != sepchars); if((GPosition) localepaths) break; defaultlocale="C"; } for(pos=localepaths;pos;++pos) appendPath(localepaths[pos],pathsmap,realpaths); for(pos=paths;pos;++pos) appendPath(paths[pos],pathsmap,realpaths); } return realpaths; }
static inline bool isspaces(const GUTF8String &raw) { return (raw.nextNonSpace() == (int)raw.length()); }
void GIFFManager::add_chunk(GUTF8String parent_name, const GP<GIFFChunk> & chunk, int pos) // parent_name is the fully qualified name of the PARENT // IT MAY BE EMPTY // All the required chunks will be created // pos=-1 means to append the chunk { DEBUG_MSG("GIFFManager::add_chunk(): Adding chunk to name='" << parent_name << "'\n"); DEBUG_MAKE_INDENT(3); if (!top_level->get_name().length()) { if ((!parent_name.length())||(parent_name[0]!='.')) G_THROW( ERR_MSG("GIFFManager.no_top_name") ); if (parent_name.length() < 2) { // 'chunk' is actually the new top-level chunk DEBUG_MSG("since parent_name=='.', making the chunk top-level\n"); if (!chunk->is_container()) G_THROW( ERR_MSG("GIFFManager.no_top_cont") ); top_level=chunk; return; } DEBUG_MSG("Setting the name of the top-level chunk\n"); const int next_dot=parent_name.search('.',1); if(next_dot>=0) { top_level->set_name(parent_name.substr(1,next_dot-1)); }else { top_level->set_name(parent_name.substr(1,(unsigned int)-1)); } } DEBUG_MSG("top level chunk name='" << top_level->get_name() << "'\n"); if (parent_name.length() && parent_name[0] == '.') { int next_dot=parent_name.search('.',1); if(next_dot<0) { next_dot=parent_name.length(); } GUTF8String top_name=parent_name.substr(1,next_dot-1); if (!top_level->check_name(top_name)) G_THROW( ERR_MSG("GIFFManager.wrong_name") "\t"+top_name); parent_name=parent_name.substr(next_dot,(unsigned int)-1); } GP<GIFFChunk> cur_sec=top_level; const char * start, * end=(const char *)parent_name-1; do { for(start=++end;*end&&(*end!='.');end++) EMPTY_LOOP; if (end>start) { GUTF8String name(start,end-start); GUTF8String short_name; int number=0; const int obracket=name.search('['); if (obracket >= 0) { const int cbracket=name.search(']',obracket+1); if (cbracket < 0) G_THROW( ERR_MSG("GIFFManager.unmatched") ); // number=atoi((const char *)name.substr(obracket+1,cbracket-obracket-1)); number = name.substr(obracket+1,cbracket-obracket-1).toInt(); short_name=name.substr(0,obracket); }else { short_name=name; } for(int i=cur_sec->get_chunks_number(short_name);i<number+1;i++) cur_sec->add_chunk(GIFFChunk::create(short_name)); cur_sec=cur_sec->get_chunk(name); if (!cur_sec) G_THROW( ERR_MSG("GIFFManager.unknown") "\t"+name); } } while(*end); cur_sec->add_chunk(chunk, pos); }
// Insert a string into the message text. Will insert into any field // description. Except for an ArgId of zero (message number), if the ArgId // is not found, the routine adds a line with the parameter so information // will not be lost. void DjVuMessageLite::InsertArg( GUTF8String &message, const int ArgId, const GUTF8String &arg ) const { // argument target string const GUTF8String target= "%"+GUTF8String(ArgId)+"!"; // location of target string int format_start = message.search( (const char *)target ); if( format_start >= 0 ) { do { const int n=format_start+target.length()+1; const int format_end=message.search((unsigned long)'!',n); if(format_end > format_start) { const int len=1+format_end-n; if(len && isascii(message[n-1])) { GUTF8String narg; GUTF8String format="%"+message.substr(n-1,len); switch(format[len]) { case 'd': case 'i': narg.format((const char *)format,arg.toInt()); break; case 'u': case 'o': case 'x': case 'X': narg.format((const char *)format,(unsigned int)arg.toInt()); break; case 'f': case 'g': case 'e': { int endpos; narg.format((const char *)format, arg.toDouble(0,endpos)); if( endpos < 0 ) narg = arg; } break; default: narg.format((const char *)format,(const char *)arg); break; } message = message.substr( 0, format_start )+narg +message.substr( format_end+1, -1 ); }else { message = message.substr( 0, format_start )+arg +message.substr( format_end+1, -1 ); } } format_start=message.search((const char*)target, format_start+arg.length()); } while(format_start >= 0); } else { // Not found, fake it if( ArgId != 0 ) { message += "\n"+LookUpSingle(uparameter+("\t"+arg)); } } }