diff options
Diffstat (limited to 'kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp')
-rw-r--r-- | kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp | 1514 |
1 files changed, 1514 insertions, 0 deletions
diff --git a/kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp b/kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp new file mode 100644 index 00000000..a6772e61 --- /dev/null +++ b/kviewshell/plugins/djvu/libdjvu/DjVuAnno.cpp @@ -0,0 +1,1514 @@ +//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, Version 2. 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 +//C- distributed by Lizardtech Software. On July 19th 2002, Lizardtech +//C- Software authorized us to replace the original DjVu(r) Reference +//C- Library notice by the following text (see doc/lizard2002.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, Version 2. 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- +------------------------------------------------------------------ +// +// $Id: DjVuAnno.cpp,v 1.12 2004/04/17 23:56:11 leonb Exp $ +// $Name: release_3_5_15 $ + +#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 <ctype.h> + + +#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<GLObject> & list); + virtual ~GLObject(void); + + int get_number(void) const; + GUTF8String get_string(void) const; + GUTF8String get_symbol(void) const; + GPList<GLObject> & get_list(void); + GP<GLObject> 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<GLObject> 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<GLObject> object; + + GLToken(GLTokenType type, const GP<GLObject> & object); +}; + +inline +GLToken::GLToken(GLTokenType xtype, const GP<GLObject> & xobject) : + type(xtype), object(xobject) {} + +class GLParser +{ +public: + void parse(const char * str); + GPList<GLObject> & get_list(void); + GP<GLObject> 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<GLObject> 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<GLObject> & list, + const char * & start); +}; + +GLParser::GLParser(void) + : compat(false) +{ +} + +GLParser::~GLParser(void) +{ +} + +GPList<GLObject> & +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<GLObject> & xlist) : + type(LIST), name(xname), list(xlist) {} + +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; + const char * to_print=0; + switch(type) + { + case NUMBER: + to_print=buffer.format("%d",number); + break; + case STRING: + { + int length = string.length(); + const char *data = (const char*)string; + buffer = GUTF8String("\""); + while (*data && length>0) + { + int span = 0; + while (span<length && (unsigned char)(data[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 char *tr1 = "\"\\tnrbf"; + static 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("\""); + to_print = buffer; + } + break; + case SYMBOL: + to_print=buffer.format("%s",(const char *)symbol); + break; + case LIST: + to_print=buffer.format("(%s",(const char *)name); + break; + case INVALID: + break; + } + if (!compact && *cur_pos+strlen(to_print)>70) + { + char ch='\n'; + str.write(&ch, 1); + ch=' '; + for(int i=0;i<indent;i++) str.write(&ch, 1); + *cur_pos=indent; + } + str.write(to_print, strlen(to_print)); + char ch=' '; + str.write(&ch, 1); + *cur_pos+=strlen(to_print)+1; + if (type==LIST) + { + int indent=*cur_pos-strlen(to_print); + for(GPosition pos=list;pos;++pos) + list[pos]->print(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> +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<n && pos;i++, ++pos) + continue; + return list[pos]; +} + +GPList<GLObject> & +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=='-' || (c>='0' && c<='9')) + { + return GLToken(GLToken::OBJECT, + new GLObject(strtol(start, (char **) &start, 10))); + } + 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 char *tr1 = "tnrbfva"; + static 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 + { + GUTF8String str; + while(1) + { + char ch=*start++; + if (!ch) + G_THROW( ByteStream::EndOfFile ); + if (ch==')') { start--; break; } + if (isspace(ch)) break; + str+=ch; + } + return GLToken(GLToken::OBJECT, new GLObject(GLObject::SYMBOL, str)); + } +} + +void +GLParser::parse(const char * cur_name, GPList<GLObject> & 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<GLObject> 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<GLObject> 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<GLObject> +GLParser::get_object(const char * name, bool last) +{ + GP<GLObject> object; + for(GPosition pos=list;pos;++pos) + { + GP<GLObject> 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" + +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+="<PARAM name=\"" ZOOM_TAG "\" value=\""+GUTF8String(zoom)+="\" />\n"; + }else if(zoom && ((-zoom)<zoom_strings_size)) + { + retval+="<PARAM name=\"" ZOOM_TAG "\" value=\""+GUTF8String(zoom_strings[-zoom])+"\" />\n"; + } + if((mode>0)&&(mode<mode_strings_size)) + { + retval+="<PARAM name=\"" MODE_TAG "\" value=\""+GUTF8String(mode_strings[mode])+"\" />\n"; + } + if((hor_align>ALIGN_UNSPEC)&&(hor_align<align_strings_size)) + { + retval+="<PARAM name=\"" HALIGN_TAG "\" value=\""+GUTF8String(align_strings[hor_align])+"\" />\n"; + } + if((ver_align>ALIGN_UNSPEC)&&(ver_align<align_strings_size)) + { + retval+="<PARAM name=\"" VALIGN_TAG "\" value=\""+GUTF8String(align_strings[ver_align])+"\" />\n"; + } + if((bg_color&0xffffff) == bg_color) + { + retval+="<PARAM name=\"" BACKGROUND_TAG "\" value=\""+GUTF8String().format("#%06lX",bg_color)+"\" />\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("<MAP name=\""+name.toEscaped()+"\" >\n"); + for(GPosition pos(map_areas);pos;++pos) + { + retval+=map_areas[pos]->get_xmltag(height); + } + return retval+"</MAP>\n"; +} + +void +DjVuANT::writeMap( + ByteStream &str_out,const GUTF8String &name,const int height) const +{ + str_out.writestring("<MAP name=\""+name.toEscaped()+"\" >\n"); + for(GPosition pos(map_areas);pos;++pos) + { + str_out.writestring(GUTF8String(map_areas[pos]->get_xmltag(height))); + } + str_out.writestring(GUTF8String("</MAP>\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); +#ifndef NO_METADATA_IN_ANT_CHUNK + metadata=get_metadata(parser); +#endif +} + + +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 (start<color) start=color; + if (end>start) + color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0); + + // Do green + end=color+strlen(color)-2; start=end-2; + if (start<color) start=color; + if (end>start) + color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0) << 8; + + // Do red + end=color+strlen(color)-4; start=end-2; + if (start<color) start=color; + if (end>start) + color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0) << 16; + + // Do the fourth byte + end=color+strlen(color)-6; start=end-2; + if (start<color) start=color; + if (end>start) + color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0) << 24; + + return color_rgb; +} + +unsigned long int +DjVuANT::get_bg_color(GLParser & parser) +{ + unsigned long retval=default_bg_color; + DEBUG_MSG("DjVuANT::get_bg_color(): getting background color ...\n"); + DEBUG_MAKE_INDENT(3); + G_TRY + { + GP<GLObject> 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<GLObject> 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<zoom_strings_size);++i) + { + if(zoom == zoom_strings[i]) + { + retval=(-i); + break; + } + } + if(retval == ZOOM_UNSPEC) + { + if (zoom[0]!='d') + { + G_THROW( ERR_MSG("DjVuAnno.bad_zoom") ); + }else + { + retval=zoom.substr(1, zoom.length()).toInt(); //atoi((const char *) zoom+1); + } + } + } +#ifndef NDEBUG + if(retval == ZOOM_UNSPEC) + { + DEBUG_MSG("can't find any.\n"); + } +#endif // NDEBUG + } G_CATCH_ALL {} G_ENDCATCH; +#ifndef NDEBUG + if(retval == ZOOM_UNSPEC) + { + DEBUG_MSG("resetting zoom to 0 (UNSPEC)\n"); + } +#endif // NDEBUG + return retval; +} + +int +DjVuANT::get_mode(GLParser & parser) +{ + int retval=MODE_UNSPEC; + DEBUG_MSG("DjVuAnt::get_mode(): getting default mode ...\n"); + DEBUG_MAKE_INDENT(3); + G_TRY + { + GP<GLObject> 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<mode_strings_size);++i) + { + if(mode == mode_strings[i]) + { + retval=i; + break; + } + } + } +#ifndef NDEBUG + if(retval == MODE_UNSPEC) + { + DEBUG_MSG("can't find any.\n"); + } +#endif // NDEBUG + } G_CATCH_ALL {} G_ENDCATCH; +#ifndef NDEBUG + if(retval == MODE_UNSPEC) + { + DEBUG_MSG("resetting mode to MODE_UNSPEC\n"); + } +#endif // NDEBUG + return retval; +} + +static inline DjVuANT::alignment +legal_halign(const int i) +{ + DjVuANT::alignment retval; + switch((DjVuANT::alignment)i) + { + case DjVuANT::ALIGN_LEFT: + case DjVuANT::ALIGN_CENTER: + case DjVuANT::ALIGN_RIGHT: + retval=(DjVuANT::alignment)i; + break; + default: + retval=DjVuANT::ALIGN_UNSPEC; + break; + } + return retval; +} + +static inline DjVuANT::alignment +legal_valign(const int i) +{ + DjVuANT::alignment retval; + switch((DjVuANT::alignment)i) + { + case DjVuANT::ALIGN_CENTER: + case DjVuANT::ALIGN_TOP: + case DjVuANT::ALIGN_BOTTOM: + retval=(DjVuANT::alignment)i; + break; + default: + retval=DjVuANT::ALIGN_UNSPEC; + break; + } + return retval; +} + +DjVuANT::alignment +DjVuANT::get_hor_align(GLParser & parser) +{ + DEBUG_MSG("DjVuAnt::get_hor_align(): getting hor page alignemnt ...\n"); + DEBUG_MAKE_INDENT(3); + alignment retval=ALIGN_UNSPEC; + G_TRY + { + GP<GLObject> 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<align_strings_size);++i) + { + const alignment j=legal_halign(i); + if((i == (int)j)&&(align == align_strings[i])) + { + retval=j; + break; + } + } + } +#ifndef NDEBUG + if(retval == ALIGN_UNSPEC) + { + DEBUG_MSG("can't find any.\n"); + } +#endif // NDEBUG + } G_CATCH_ALL {} G_ENDCATCH; +#ifndef NDEBUG + if(retval == ALIGN_UNSPEC) + { + DEBUG_MSG("resetting alignment to ALIGN_UNSPEC\n"); + } +#endif // NDEBUG + return retval; +} + +DjVuANT::alignment +DjVuANT::get_ver_align(GLParser & parser) +{ + DEBUG_MSG("DjVuAnt::get_ver_align(): getting vert page alignemnt ...\n"); + DEBUG_MAKE_INDENT(3); + alignment retval=ALIGN_UNSPEC; + G_TRY + { + GP<GLObject> 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<align_strings_size);++i) + { + const alignment j=legal_valign(i); + if((i == (int)j)&&(align == align_strings[i])) + { + retval=j; + break; + } + } + } +#ifndef NDEBUG + if(retval == ALIGN_UNSPEC) + { + DEBUG_MSG("can't find any.\n"); + } +#endif // NDEBUG + } G_CATCH_ALL {} G_ENDCATCH; +#ifndef NDEBUG + if(retval == ALIGN_UNSPEC) + { + DEBUG_MSG("resetting alignment to ALIGN_UNSPEC\n"); + } +#endif // NDEBUG + return retval; +} + +#ifndef NO_METADATA_IN_ANT_CHUNK +GMap<GUTF8String, GUTF8String> +DjVuANT::get_metadata(GLParser & parser) +{ + DEBUG_MSG("DjVuANT::get_map_areas(): forming and returning back list of map areas\n"); + DEBUG_MAKE_INDENT(3); + + GMap<GUTF8String, GUTF8String> mdata; + + GPList<GLObject> 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_num<obj.get_list().size();obj_num++) + { + GLObject & el=*obj[obj_num]; + const int type = el.get_type(); + if (type == GLObject::LIST) + { + const GUTF8String & name=el.get_name(); + mdata[name]=(el[0])->get_string(); + } + } + } + G_CATCH_ALL { } G_ENDCATCH; + } + } + return mdata; +} +#endif + +GPList<GMapArea> +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<GMapArea> map_areas; + + GPList<GLObject> 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<GMapArea> 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<GMapRect> 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<int> xx(points-1), yy(points-1); + for(int i=0;i<points;i++) + { + xx[i]=(*shape)[2*i]->get_number(); + yy[i]=(*shape)[2*i+1]->get_number(); + } + GP<GMapPoly> 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<GMapOval> 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_num<obj.get_list().size();obj_num++) + { + GLObject * el=obj[obj_num]; + if (el->get_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<GLObject> & 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!=ZOOM_UNSPEC) + { + buffer="(" ZOOM_TAG " "; + const int i=1-zoom; + if((i>=0)&& (i<zoom_strings_size)) + { + buffer+=zoom_strings[i]; + }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<mode_strings_size)) + { + buffer="(" MODE_TAG " " + GUTF8String(mode_strings[mode]) + ")"; + } + parser.parse(buffer); + } + + //*** Alignment + del_all_items(ALIGN_TAG, parser); + if (hor_align!=ALIGN_UNSPEC || ver_align!=ALIGN_UNSPEC) + { + buffer= GUTF8String("(" ALIGN_TAG " ") + +align_strings[((hor_align<ALIGN_UNSPEC)|| + (hor_align>=align_strings_size))?ALIGN_UNSPEC:hor_align] + +" "+align_strings[((ver_align<ALIGN_UNSPEC)|| + (ver_align>=align_strings_size))?ALIGN_UNSPEC:ver_align]+")"; + parser.parse(buffer); + } + //*** Metadata +#ifndef NO_METADATA_IN_ANT_CHUNK + del_all_items(METADATA_TAG, parser); + if (!metadata.isempty()) + { + GUTF8String mdatabuffer("("); + mdatabuffer += METADATA_TAG ; + for (GPosition pos=metadata; pos; ++pos) + mdatabuffer +=" (" + metadata.key(pos)+" \""+metadata[pos]+"\")"; + mdatabuffer += " )"; + parser.parse(mdatabuffer); + } +#endif + //*** Mapareas + del_all_items(GMapArea::MAPAREA_TAG, parser); + for(GPosition pos=map_areas;pos;++pos) + parser.parse(map_areas[pos]->print()); + + GP<ByteStream> 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> +DjVuANT::copy(void) const +{ + GP<DjVuANT> 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)) + :("<MAP name=\""+name.toEscaped()+"\"/>\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<ByteStream> &gbs) +{ + GUTF8String chkid; + GP<IFFByteStream> 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<ByteStream> 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<ByteStream> &gbs) +{ + GP<IFFByteStream> 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<ByteStream> bsbinput = giff.get_bytestream(); + GP<ByteStream> bsb = BSByteStream::create(giff->get_bytestream(), 50); + ant->encode(*bsb); + } + iff.close_chunk(); +#endif + } + // Add encoding of other chunks here +} + + +GP<DjVuAnno> +DjVuAnno::copy(void) const +{ + GP<DjVuAnno> 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<DjVuAnno> & anno) +{ + if (anno) + { + GP<ByteStream> 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 |