//C- -*- C++ -*- //C- ------------------------------------------------------------------- //C- DjVuLibre-3.5 //C- Copyright (c) 2002 Leon Bottou and Yann Le Cun. //C- Copyright (c) 2001 AT&T //C- //C- This software is subject to, and may be distributed under, the //C- GNU General Public License, either Version 2 of the license, //C- or (at your option) any later version. The license should have //C- accompanied the software or you may obtain a copy of the license //C- from the Free Software Foundation at http://www.fsf.org . //C- //C- This program is distributed in the hope that it will be useful, //C- but WITHOUT ANY WARRANTY; without even the implied warranty of //C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //C- GNU General Public License for more details. //C- //C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from //C- Lizardtech Software. Lizardtech Software has authorized us to //C- replace the original DjVu(r) Reference Library notice by the following //C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu): //C- //C- ------------------------------------------------------------------ //C- | DjVu (r) Reference Library (v. 3.5) //C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved. //C- | The DjVu Reference Library is protected by U.S. Pat. No. //C- | 6,058,214 and patents pending. //C- | //C- | This software is subject to, and may be distributed under, the //C- | GNU General Public License, either Version 2 of the license, //C- | or (at your option) any later version. The license should have //C- | accompanied the software or you may obtain a copy of the license //C- | from the Free Software Foundation at http://www.fsf.org . //C- | //C- | The computer code originally released by LizardTech under this //C- | license and unmodified by other parties is deemed "the LIZARDTECH //C- | ORIGINAL CODE." Subject to any third party intellectual property //C- | claims, LizardTech grants recipient a worldwide, royalty-free, //C- | non-exclusive license to make, use, sell, or otherwise dispose of //C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the //C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU //C- | General Public License. This grant only confers the right to //C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to //C- | the extent such infringement is reasonably necessary to enable //C- | recipient to make, have made, practice, sell, or otherwise dispose //C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to //C- | any greater extent that may be necessary to utilize further //C- | modifications or combinations. //C- | //C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY //C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED //C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF //C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. //C- +------------------------------------------------------------------ #ifdef HAVE_CONFIG_H # include "config.h" #endif #if NEED_GNUG_PRAGMAS # pragma implementation #endif #include "DjVuAnno.h" #include "GContainer.h" #include "GException.h" #include "IFFByteStream.h" #include "BSByteStream.h" #include "GMapAreas.h" #include "debug.h" #include #ifdef HAVE_NAMESPACES namespace DJVU { # ifdef NOT_DEFINED // Just to fool emacs c++ mode } #endif #endif // GLParser.h and GLParser.cpp used to be separate files capable to decode // that weird ANTa chunk format into C++ structures and lists. But since // its implementation is temporary and is used only in this file (DjVuAnno.cpp) // it appears reasonable to build it in here. //*************************************************************************** //****************************** GLParser.h ********************************* //*************************************************************************** class GLObject : public GPEnabled { public: enum GLObjectType { INVALID=0, NUMBER=1, STRING=2, SYMBOL=3, LIST=4 }; static const char * const GLObjectString[LIST+1]; GLObject(int _number=0); GLObject(GLObjectType type, const char * str); GLObject(const char * name, const GPList & list); virtual ~GLObject(void); int get_number(void) const; GUTF8String get_string(void) const; GUTF8String get_symbol(void) const; GPList & get_list(void); GP operator[](int n) const; GLObjectType get_type(void) const; GUTF8String get_name(void) const; void print(ByteStream & str, int compact=1, int indent=0, int * cur_pos=0) const; private: GLObjectType type; GUTF8String name; int number; GUTF8String string; GUTF8String symbol; GPList list; void throw_can_not_convert_to(const GLObjectType to) const; }; const char * const GLObject::GLObjectString[]= {"invalid", "number", "string", "symbol", "list"}; inline GLObject::GLObjectType GLObject::get_type(void) const { return type; } inline GLObject::~GLObject(void) {} class GLToken { public: enum GLTokenType { OPEN_PAR, CLOSE_PAR, OBJECT }; GLTokenType type; GP object; GLToken(GLTokenType type, const GP & object); }; inline GLToken::GLToken(GLTokenType xtype, const GP & xobject) : type(xtype), object(xobject) {} class GLParser { public: void parse(const char * str); GPList & get_list(void); GP get_object(const char * name, bool last=true); void print(ByteStream & str, int compact=1); GLParser(void); GLParser(const char * str); ~GLParser(void); private: GPList list; bool compat; void skip_white_space(const char * & start); void check_compat(const char *str); GLToken get_token(const char * & start); void parse(const char * cur_name, GPList & list, const char * & start); }; GLParser::GLParser(void) : compat(false) { } GLParser::~GLParser(void) { } GPList & GLParser::get_list(void) { return list; } GLParser::GLParser(const char * str) : compat(false) { parse(str); } //*************************************************************************** //***************************** GLParser.cpp ******************************** //*************************************************************************** GLObject::GLObject(int xnumber) : type(NUMBER), number(xnumber) {} GLObject::GLObject(GLObjectType xtype, const char * str) : type(xtype) { if (type!=STRING && type!=SYMBOL) G_THROW( ERR_MSG("DjVuAnno.bad_type") ); if (type==STRING) string=str; else symbol=str; } GLObject::GLObject(const char * xname, const GPList & xlist) : type(LIST), name(xname), list(xlist) {} static GUTF8String make_c_string(GUTF8String string) { GUTF8String buffer; const char *data = (const char*)string; int length = string.length(); buffer = GUTF8String("\""); while (*data && length>0) { int span = 0; while (span=0x20 && data[span]!=0x7f && data[span]!='"' && data[span]!='\\' ) span++; if (span > 0) { buffer = buffer + GUTF8String(data, span); data += span; length -= span; } else { char buf[8]; static const char *tr1 = "\"\\tnrbf"; static const char *tr2 = "\"\\\t\n\r\b\f"; sprintf(buf,"\\%03o", (int)(((unsigned char*)data)[span])); for (int i=0; tr2[i]; i++) if (data[span] == tr2[i]) buf[1] = tr1[i]; if (buf[1]<'0' || buf[1]>'3') buf[2] = 0; buffer = buffer + GUTF8String(buf); data += 1; length -= 1; } } buffer = buffer + GUTF8String("\""); return buffer; } void GLObject::print(ByteStream & str, int compact, int indent, int * cur_pos) const { int local_cur_pos = 0; if (!cur_pos) { cur_pos = &local_cur_pos; } GUTF8String buffer; switch(type) { case NUMBER: buffer.format("%d",number); break; case STRING: buffer = make_c_string(string); break; case SYMBOL: buffer.format("%s",(const char *)symbol); break; case LIST: buffer.format("(%s",(const char *)name); break; case INVALID: break; } const char * to_print = (const char*)buffer; if (!compact && *cur_pos+strlen(to_print)>70) { char ch='\n'; str.write(&ch, 1); ch=' '; for(int i=0;iprint(str, compact, indent, cur_pos); str.write(") ", 2); *cur_pos+=2; } } // This function constructs message names for external lookup. // The message names are constructed to avoid the problems of concatenating // phrases (which does not translate well into other languages). The // message names that can be generated are (listed here to appease the // auditing program which reads comments): // ERR_MSG("DjVuAnno.invalid2number"), ERR_MSG("DjVuAnno.string2number"), // ERR_MSG("DjVuAnno.symbol2number"), ERR_MSG("DjVuAnno.list2number") // ERR_MSG("DjVuAnno.invalid2string"), ERR_MSG("DjVuAnno.number2string"), // ERR_MSG("DjVuAnno.symbol2string"), ERR_MSG("DjVuAnno.list2string") // ERR_MSG("DjVuAnno.invalid2symbol"), ERR_MSG("DjVuAnno.number2symbol"), // ERR_MSG("DjVuAnno.string2symbol"), ERR_MSG("DjVuAnno.list2symbol") // ERR_MSG("DjVuAnno.invalid2list"), ERR_MSG("DjVuAnno.number2list"), // ERR_MSG("DjVuAnno.string2list"), ERR_MSG("DjVuAnno.symbol2list") void GLObject::throw_can_not_convert_to(const GLObjectType to) const { static const GUTF8String two('2'); static const GUTF8String tab('\t'); GUTF8String mesg("DjVuAnno."); switch(type) { case NUMBER: mesg+=GLObjectString[NUMBER]+two+GLObjectString[to]+tab+GUTF8String(number); break; case STRING: mesg+=GLObjectString[STRING]+two+GLObjectString[to]+tab+string; break; case SYMBOL: mesg+=GLObjectString[SYMBOL]+two+GLObjectString[to]+tab+symbol; break; case LIST: mesg+=GLObjectString[LIST]+two+GLObjectString[to]+tab+name; break; default: mesg+=GLObjectString[INVALID]+two+GLObjectString[to]; break; } G_THROW(mesg); } GUTF8String GLObject::get_string(void) const { if (type!=STRING) { throw_can_not_convert_to(STRING); } return string; } GUTF8String GLObject::get_symbol(void) const { if (type!=SYMBOL) { throw_can_not_convert_to(SYMBOL); } return symbol; } int GLObject::get_number(void) const { if (type!=NUMBER) { throw_can_not_convert_to(NUMBER); } return number; } GUTF8String GLObject::get_name(void) const { if (type!=LIST) { throw_can_not_convert_to(LIST); } return name; } GP GLObject::operator[](int n) const { if (type!=LIST) { throw_can_not_convert_to(LIST); } if (n>=list.size()) G_THROW( ERR_MSG("DjVuAnno.too_few") "\t"+name); int i; GPosition pos; for(i=0, pos=list;i & GLObject::get_list(void) { if (type!=LIST) { throw_can_not_convert_to(LIST); } return list; } //********************************** GLParser ********************************* void GLParser::skip_white_space(const char * & start) { while(*start && isspace(*start)) start++; if (!*start) G_THROW( ByteStream::EndOfFile ); } GLToken GLParser::get_token(const char * & start) { skip_white_space(start); char c = *start; if (c == '(') { start++; return GLToken(GLToken::OPEN_PAR, 0); } else if (c == ')') { start++; return GLToken(GLToken::CLOSE_PAR, 0); } else if (c == '"') { GUTF8String str; start++; while(1) { int span = 0; while (start[span] && start[span]!='\\' && start[span]!='\"') span++; if (span > 0) { str = str + GUTF8String(start,span); start += span; } else if (start[0]=='\"') { start += 1; break; } else if (start[0]=='\\' && compat) { char c = start[1]; if (c == '\"') { start += 2; str += '\"'; } else { start += 1; str += '\\'; } } else if (start[0]=='\\' && start[1]) { char c = *++start; if (c>='0' && c<='7') { int x = 0; for (int i=0; i<3 && c>='0' && c<='7'; i++) { x = x * 8 + c - '0'; c = *++start; } str += (char)(x & 0xff); } else { static const char *tr1 = "tnrbfva"; static const char *tr2 = "\t\n\r\b\f\013\007"; for (int i=0; tr1[i]; i++) if (c == tr1[i]) c = tr2[i]; start += 1; str += c; } } else { G_THROW( ByteStream::EndOfFile ); } } return GLToken(GLToken::OBJECT, new GLObject(GLObject::STRING, str)); } else if (c=='-' || (c>='0' && c<='9')) { const char *here = start; long val = strtol(start, (char**) &start, 10); if (start > here) return GLToken(GLToken::OBJECT, new GLObject(val)); } GUTF8String str; while(c != 0 && c != ')' && c != '(' && c != '"' && !isspace(c)) { str += c; c = *++start; } if (c == 0) G_THROW(ByteStream::EndOfFile); else return GLToken(GLToken::OBJECT, new GLObject(GLObject::SYMBOL, str)); } void GLParser::parse(const char * cur_name, GPList & list, const char * & start) { DEBUG_MSG("GLParse::parse(): Parsing contents of object '" << cur_name << "'\n"); DEBUG_MAKE_INDENT(3); while(1) { GLToken token=get_token(start); if (token.type==GLToken::OPEN_PAR) { if (isspace(*start)) { GUTF8String mesg=GUTF8String( ERR_MSG("DjVuAnno.paren") "\t")+cur_name; G_THROW(mesg); } GLToken tok=get_token(start); GP object=tok.object; // This object should be SYMBOL // We will convert it to LIST later if (tok.type!=GLToken::OBJECT || object->get_type()!=GLObject::SYMBOL) { if (tok.type==GLToken::OPEN_PAR || tok.type==GLToken::CLOSE_PAR) { GUTF8String mesg=GUTF8String( ERR_MSG("DjVuAnno.no_paren") "\t")+cur_name; G_THROW(mesg); } if (tok.type==GLToken::OBJECT) { GLObject::GLObjectType type=object->get_type(); if (type==GLObject::NUMBER) { GUTF8String mesg( ERR_MSG("DjVuAnno.no_number") "\t"); mesg += cur_name; G_THROW(mesg); } else if (type==GLObject::STRING) { GUTF8String mesg( ERR_MSG("DjVuAnno.no_string") "\t"); mesg += cur_name; G_THROW(mesg); } } } // OK. Get the object contents GPList new_list; G_TRY { parse(object->get_symbol(), new_list, start); } G_CATCH(exc) { if (exc.cmp_cause(ByteStream::EndOfFile)) G_RETHROW; } G_ENDCATCH; list.append(new GLObject(object->get_symbol(), new_list)); continue; } if (token.type==GLToken::CLOSE_PAR) return; list.append(token.object); } } void GLParser::check_compat(const char *s) { int state = 0; while (s && *s && !compat) { switch(state) { case 0: if (*s == '\"') state = '\"'; break; case '\"': if (*s == '\"') state = 0; else if (*s == '\\') state = '\\'; else if ((unsigned char)(*s)<0x20 || *s==0x7f) compat = true; break; case '\\': if (!strchr("01234567tnrbfva\"\\",*s)) compat = true; state = '\"'; break; } s += 1; } } void GLParser::parse(const char * str) { DEBUG_MSG("GLParser::parse(): parsing string contents\n"); DEBUG_MAKE_INDENT(3); G_TRY { check_compat(str); parse("toplevel", list, str); } G_CATCH(exc) { if (exc.cmp_cause(ByteStream::EndOfFile)) G_RETHROW; } G_ENDCATCH; } void GLParser::print(ByteStream & str, int compact) { for(GPosition pos=list;pos;++pos) list[pos]->print(str, compact); } GP GLParser::get_object(const char * name, bool last) { GP object; for(GPosition pos=list;pos;++pos) { GP obj=list[pos]; if (obj->get_type()==GLObject::LIST && obj->get_name()==name) { object=obj; if (!last) break; } } return object; } //*************************************************************************** //********************************** ANT ************************************ //*************************************************************************** static const char *zoom_strings[]={ "default","page","width","one2one","stretch"}; static const int zoom_strings_size=sizeof(zoom_strings)/sizeof(const char *); static const char *mode_strings[]={ "default","color","fore","back","bw"}; static const int mode_strings_size=sizeof(mode_strings)/sizeof(const char *); static const char *align_strings[]={ "default","left","center","right","top","bottom"}; static const int align_strings_size=sizeof(align_strings)/sizeof(const char *); #define PNOTE_TAG "pnote" #define BACKGROUND_TAG "background" #define ZOOM_TAG "zoom" #define MODE_TAG "mode" #define ALIGN_TAG "align" #define HALIGN_TAG "halign" #define VALIGN_TAG "valign" #define METADATA_TAG "metadata" #define XMP_TAG "xmp" static const unsigned long default_bg_color=0xffffffff; DjVuANT::DjVuANT(void) { bg_color=default_bg_color; zoom=0; mode=MODE_UNSPEC; hor_align=ver_align=ALIGN_UNSPEC; } DjVuANT::~DjVuANT() { } GUTF8String DjVuANT::get_paramtags(void) const { GUTF8String retval; if(zoom > 0) { retval+="\n"; }else if(zoom && ((-zoom)\n"; } if((mode>0)&&(mode\n"; } if((hor_align>ALIGN_UNSPEC)&&(hor_align\n"; } if((ver_align>ALIGN_UNSPEC)&&(ver_align\n"; } if((bg_color&0xffffff) == bg_color) { retval+="\n"; } return retval; } void DjVuANT::writeParam(ByteStream &str_out) const { str_out.writestring(get_paramtags()); } GUTF8String DjVuANT::get_xmlmap(const GUTF8String &name,const int height) const { GUTF8String retval("\n"); for(GPosition pos(map_areas);pos;++pos) { retval+=map_areas[pos]->get_xmltag(height); } return retval+"\n"; } void DjVuANT::writeMap( ByteStream &str_out,const GUTF8String &name,const int height) const { str_out.writestring("\n"); for(GPosition pos(map_areas);pos;++pos) { str_out.writestring(GUTF8String(map_areas[pos]->get_xmltag(height))); } str_out.writestring(GUTF8String("\n")); } GUTF8String DjVuANT::read_raw(ByteStream & str) { GUTF8String raw; char buffer[1024]; int length; while((length=str.read(buffer, 1024))) raw+=GUTF8String(buffer, length); return raw; } void DjVuANT::decode(class GLParser & parser) { bg_color=get_bg_color(parser); zoom=get_zoom(parser); mode=get_mode(parser); hor_align=get_hor_align(parser); ver_align=get_ver_align(parser); map_areas=get_map_areas(parser); metadata=get_metadata(parser); xmpmetadata=get_xmpmetadata(parser); } void DjVuANT::decode(ByteStream & str) { GLParser parser(read_raw(str)); decode(parser); } void DjVuANT::merge(ByteStream & str) { GLParser parser(encode_raw()); GUTF8String add_raw=read_raw(str); parser.parse(add_raw); decode(parser); } void DjVuANT::encode(ByteStream &bs) { GUTF8String raw=encode_raw(); bs.writall((const char*) raw, raw.length()); } unsigned int DjVuANT::get_memory_usage() const { return sizeof(DjVuANT); } unsigned char DjVuANT::decode_comp(char ch1, char ch2) { unsigned char dig1=0; if (ch1) { ch1=toupper(ch1); if (ch1>='0' && ch1<='9') dig1=ch1-'0'; if (ch1>='A' && ch1<='F') dig1=10+ch1-'A'; unsigned char dig2=0; if (ch2) { ch2=toupper(ch2); if (ch2>='0' && ch2<='9') dig2=ch2-'0'; if (ch2>='A' && ch2<='F') dig2=10+ch2-'A'; return (dig1 << 4) | dig2; } return dig1; } return 0; } unsigned long int DjVuANT::cvt_color(const char * color, unsigned long int def) { if (color[0]!='#') return def; unsigned long int color_rgb=0; color++; const char * start, * end; // Do blue end=color+strlen(color); start=end-2; if (startstart) color_rgb|=decode_comp(start[0], start+1start) color_rgb|=decode_comp(start[0], start+1start) color_rgb|=decode_comp(start[0], start+1start) color_rgb|=decode_comp(start[0], start+1 obj=parser.get_object(BACKGROUND_TAG); if (obj && obj->get_list().size()==1) { GUTF8String color=(*obj)[0]->get_symbol(); DEBUG_MSG("color='" << color << "'\n"); retval=cvt_color(color, 0xffffff); } #ifndef NDEBUG if(retval == default_bg_color) { DEBUG_MSG("can't find any.\n"); } #endif // NDEBUG } G_CATCH_ALL {} G_ENDCATCH; #ifndef NDEBUG if(retval == default_bg_color) { DEBUG_MSG("resetting color to 0xffffffff (UNSPEC)\n"); } #endif // NDEBUG return retval; } int DjVuANT::get_zoom(GLParser & parser) // Returns: // <0 - special zoom (like ZOOM_STRETCH) // =0 - not set // >0 - numeric zoom (%%) { int retval=ZOOM_UNSPEC; DEBUG_MSG("DjVuANT::get_zoom(): getting zoom factor ...\n"); DEBUG_MAKE_INDENT(3); G_TRY { GP obj=parser.get_object(ZOOM_TAG); if (obj && obj->get_list().size()==1) { const GUTF8String zoom((*obj)[0]->get_symbol()); DEBUG_MSG("zoom='" << zoom << "'\n"); for(int i=0;(i obj=parser.get_object(MODE_TAG); if (obj && obj->get_list().size()==1) { const GUTF8String mode((*obj)[0]->get_symbol()); DEBUG_MSG("mode='" << mode << "'\n"); for(int i=0;(i obj=parser.get_object(ALIGN_TAG); if (obj && obj->get_list().size()==2) { const GUTF8String align((*obj)[0]->get_symbol()); DEBUG_MSG("hor_align='" << align << "'\n"); for(int i=(int)ALIGN_UNSPEC;(i obj=parser.get_object(ALIGN_TAG); if (obj && obj->get_list().size()==2) { const GUTF8String align((*obj)[1]->get_symbol()); DEBUG_MSG("ver_align='" << align << "'\n"); for(int i=(int)ALIGN_UNSPEC;(i DjVuANT::get_metadata(GLParser & parser) { DEBUG_MSG("DjVuANT::get_metadata(): forming and returning metadata table\n"); DEBUG_MAKE_INDENT(3); GMap mdata; GPList list=parser.get_list(); for(GPosition pos=list;pos;++pos) { GLObject & obj=*list[pos]; if (obj.get_type()==GLObject::LIST && obj.get_name()==METADATA_TAG) { G_TRY { for(int obj_num=0;obj_numget_string(); } } } G_CATCH_ALL { } G_ENDCATCH; } } return mdata; } GUTF8String DjVuANT::get_xmpmetadata(GLParser & parser) { DEBUG_MSG("DjVuANT::get_xmpmetadata(): returning xmp metadata string\n"); DEBUG_MAKE_INDENT(3); GUTF8String xmp; GPList list=parser.get_list(); for(GPosition pos=list;pos;++pos) { GLObject &obj = *list[pos]; if (obj.get_type()==GLObject::LIST && obj.get_name()==XMP_TAG) { G_TRY { if (obj.get_list().size() >= 1) { GLObject &el = *obj[0]; xmp = el.get_string(); break; } } G_CATCH_ALL { } G_ENDCATCH; } } return xmp; } GPList DjVuANT::get_map_areas(GLParser & parser) { DEBUG_MSG("DjVuANT::get_map_areas(): forming and returning back list of map areas\n"); DEBUG_MAKE_INDENT(3); GPList map_areas; GPList list=parser.get_list(); for(GPosition pos=list;pos;++pos) { GLObject & obj=*list[pos]; const int type=obj.get_type(); if (type == GLObject::LIST) { const GUTF8String name=obj.get_name(); if(name == GMapArea::MAPAREA_TAG) { G_TRY { // Getting the url GUTF8String url; GUTF8String target=GMapArea::TARGET_SELF; GLObject & url_obj=*(obj[0]); if (url_obj.get_type()==GLObject::LIST) { if (url_obj.get_name()!=GMapArea::URL_TAG) G_THROW( ERR_MSG("DjVuAnno.bad_url") ); url=(url_obj[0])->get_string(); target=(url_obj[1])->get_string(); } else url=url_obj.get_string(); // Getting the comment GUTF8String comment=(obj[1])->get_string(); DEBUG_MSG("found maparea '" << comment << "' (" << url << ":" << target << ")\n"); GLObject * shape=obj[2]; GP map_area; if (shape->get_type()==GLObject::LIST) { if (shape->get_name()==GMapArea::RECT_TAG) { DEBUG_MSG("it's a rectangle.\n"); GRect grect((*shape)[0]->get_number(), (*shape)[1]->get_number(), (*shape)[2]->get_number(), (*shape)[3]->get_number()); GP map_rect=GMapRect::create(grect); map_area=(GMapRect *)map_rect; } else if (shape->get_name()==GMapArea::POLY_TAG) { DEBUG_MSG("it's a polygon.\n"); int points=shape->get_list().size()/2; GTArray xx(points-1), yy(points-1); for(int i=0;iget_number(); yy[i]=(*shape)[2*i+1]->get_number(); } GP map_poly=GMapPoly::create(xx,yy,points); map_area=(GMapPoly *)map_poly; } else if (shape->get_name()==GMapArea::OVAL_TAG) { DEBUG_MSG("it's an ellipse.\n"); GRect grect((*shape)[0]->get_number(), (*shape)[1]->get_number(), (*shape)[2]->get_number(), (*shape)[3]->get_number()); GP map_oval=GMapOval::create(grect); map_area=(GMapOval *)map_oval; } } if (map_area) { map_area->url=url; map_area->target=target; map_area->comment=comment; for(int obj_num=3;obj_numget_type()==GLObject::LIST) { const GUTF8String & name=el->get_name(); if (name==GMapArea::BORDER_AVIS_TAG) map_area->border_always_visible=true; else if (name==GMapArea::HILITE_TAG) { GLObject * obj=el->get_list()[el->get_list().firstpos()]; if (obj->get_type()==GLObject::SYMBOL) map_area->hilite_color=cvt_color(obj->get_symbol(), 0xff); } else { int border_type= name==GMapArea::NO_BORDER_TAG ? GMapArea::NO_BORDER : name==GMapArea::XOR_BORDER_TAG ? GMapArea::XOR_BORDER : name==GMapArea::SOLID_BORDER_TAG ? GMapArea::SOLID_BORDER : name==GMapArea::SHADOW_IN_BORDER_TAG ? GMapArea::SHADOW_IN_BORDER : name==GMapArea::SHADOW_OUT_BORDER_TAG ? GMapArea::SHADOW_OUT_BORDER : name==GMapArea::SHADOW_EIN_BORDER_TAG ? GMapArea::SHADOW_EIN_BORDER : name==GMapArea::SHADOW_EOUT_BORDER_TAG ? GMapArea::SHADOW_EOUT_BORDER : -1; if (border_type>=0) { map_area->border_type=(GMapArea::BorderType) border_type; for(GPosition pos=el->get_list();pos;++pos) { GLObject * obj=el->get_list()[pos]; if (obj->get_type()==GLObject::SYMBOL) map_area->border_color=cvt_color(obj->get_symbol(), 0xff); if (obj->get_type()==GLObject::NUMBER) map_area->border_width=obj->get_number(); } } } } // if (el->get_type()==...) } // for(int obj_num=...) map_areas.append(map_area); } // if (map_area) ... } G_CATCH_ALL {} G_ENDCATCH; } } } // while(item==...) DEBUG_MSG("map area list size = " << list.size() << "\n"); return map_areas; } void DjVuANT::del_all_items(const char * name, GLParser & parser) { GPList & list=parser.get_list(); GPosition pos=list; while(pos) { GLObject & obj=*list[pos]; if (obj.get_type()==GLObject::LIST && obj.get_name()==name) { GPosition this_pos=pos; ++pos; list.del(this_pos); } else ++pos; } } GUTF8String DjVuANT::encode_raw(void) const { GUTF8String buffer; GLParser parser; //*** Background color del_all_items(BACKGROUND_TAG, parser); if (bg_color!=default_bg_color) { buffer.format("(" BACKGROUND_TAG " #%02X%02X%02X)", (unsigned int)((bg_color & 0xff0000) >> 16), (unsigned int)((bg_color & 0xff00) >> 8), (unsigned int)(bg_color & 0xff)); parser.parse(buffer); } //*** Zoom del_all_items(ZOOM_TAG, parser); if (zoom>0 || (zoom>=ZOOM_STRETCH && zoom<=ZOOM_PAGE)) { buffer="(" ZOOM_TAG " "; if (zoom < 0) buffer += zoom_strings[-zoom]; else buffer += "d"+GUTF8String(zoom); buffer+=")"; parser.parse(buffer); } //*** Mode del_all_items(MODE_TAG, parser); if (mode!=MODE_UNSPEC) { const int i=mode-1; if((i>=0)&& (i=align_strings_size))?ALIGN_UNSPEC:hor_align] +" "+align_strings[((ver_align=align_strings_size))?ALIGN_UNSPEC:ver_align]+")"; parser.parse(buffer); } //*** Metadata del_all_items(METADATA_TAG, parser); if (!metadata.isempty()) { GUTF8String mdatabuffer("("); mdatabuffer += METADATA_TAG ; for (GPosition pos=metadata; pos; ++pos) mdatabuffer +=" (" + metadata.key(pos) + " " + make_c_string(metadata[pos]) + ")"; mdatabuffer += " )"; parser.parse(mdatabuffer); } //*** XMP Metadata del_all_items(XMP_TAG, parser); if (!!xmpmetadata) { GUTF8String mdatabuffer("("); mdatabuffer += XMP_TAG; mdatabuffer += " " + make_c_string(xmpmetadata) + ")"; parser.parse(mdatabuffer); } //*** Mapareas del_all_items(GMapArea::MAPAREA_TAG, parser); for(GPosition pos=map_areas;pos;++pos) { GUTF8String mapareabuffer = map_areas[pos]->print(); parser.parse(mapareabuffer); } GP gstr=ByteStream::create(); ByteStream &str=*gstr; parser.print(str, 1); GUTF8String ans; int size = str.size(); str.seek(0); str.read(ans.getbuf(size), size); return ans; } bool DjVuANT::is_empty(void) const { GUTF8String raw=encode_raw(); for(int i=raw.length()-1;i>=0;i--) if (isspace(raw[i])) raw.setat(i, 0); else break; return raw.length()==0; } GP DjVuANT::copy(void) const { GP ant=new DjVuANT(*this); // Now process the list of hyperlinks. ant->map_areas.empty(); for(GPosition pos=map_areas;pos;++pos) ant->map_areas.append(map_areas[pos]->get_copy()); return ant; } //*************************************************************************** //******************************** DjVuAnno ********************************* //*************************************************************************** GUTF8String DjVuAnno::get_xmlmap(const GUTF8String &name,const int height) const { return ant ?(ant->get_xmlmap(name,height)) :("\n"); } void DjVuAnno::writeMap(ByteStream &str_out,const GUTF8String &name,const int height) const { if(ant) { ant->writeMap(str_out,name,height); }else { str_out.writestring(get_xmlmap(name,height)); } } GUTF8String DjVuAnno::get_paramtags(void) const { return ant ?(ant->get_paramtags()) :GUTF8String(); } void DjVuAnno::writeParam(ByteStream &str_out) const { str_out.writestring(get_paramtags()); } void DjVuAnno::decode(const GP &gbs) { GUTF8String chkid; GP giff=IFFByteStream::create(gbs); IFFByteStream &iff=*giff; while( iff.get_chunk(chkid) ) { if (chkid == "ANTa") { if (ant) { ant->merge(*iff.get_bytestream()); } else { ant=DjVuANT::create(); ant->decode(*iff.get_bytestream()); } } else if (chkid == "ANTz") { GP gbsiff=BSByteStream::create(giff->get_bytestream()); if (ant) { ant->merge(*gbsiff); } else { ant=DjVuANT::create(); ant->decode(*gbsiff); } } // Add decoding of other chunks here iff.close_chunk(); } } void DjVuAnno::encode(const GP &gbs) { GP giff=IFFByteStream::create(gbs); IFFByteStream &iff=*giff; if (ant) { #if 0 iff.put_chunk("ANTa"); ant->encode(iff); iff.close_chunk(); #else iff.put_chunk("ANTz"); { // GP bsbinput = giff.get_bytestream(); GP bsb = BSByteStream::create(giff->get_bytestream(), 50); ant->encode(*bsb); } iff.close_chunk(); #endif } // Add encoding of other chunks here } GP DjVuAnno::copy(void) const { GP anno= new DjVuAnno; // Copy any primitives (if any) *anno=*this; // Copy each substructure if (ant) anno->ant = ant->copy(); return anno; } void DjVuAnno::merge(const GP & anno) { if (anno) { GP gstr=ByteStream::create(); encode(gstr); anno->encode(gstr); gstr->seek(0); decode(gstr); } } #ifdef HAVE_NAMESPACES } # ifndef NOT_USING_DJVU_NAMESPACE using namespace DJVU; # endif #endif