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 #include "DjVuAnno.h"
00065 #include "GContainer.h"
00066 #include "GException.h"
00067 #include "IFFByteStream.h"
00068 #include "BSByteStream.h"
00069 #include "GMapAreas.h"
00070
00071 #include "debug.h"
00072
00073 #include <ctype.h>
00074
00075
00076 #ifdef HAVE_NAMESPACES
00077 namespace DJVU {
00078 # ifdef NOT_DEFINED // Just to fool emacs c++ mode
00079 }
00080 #endif
00081 #endif
00082
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 class GLObject : public GPEnabled
00095 {
00096 public:
00097 enum GLObjectType { INVALID=0, NUMBER=1, STRING=2, SYMBOL=3, LIST=4 };
00098 static const char * const GLObjectString[LIST+1];
00099
00100 GLObject(int _number=0);
00101 GLObject(GLObjectType type, const char * str);
00102 GLObject(const char * name, const GPList<GLObject> & list);
00103 virtual ~GLObject(void);
00104
00105 int get_number(void) const;
00106 GUTF8String get_string(void) const;
00107 GUTF8String get_symbol(void) const;
00108 GPList<GLObject> & get_list(void);
00109 GP<GLObject> operator[](int n) const;
00110
00111 GLObjectType get_type(void) const;
00112 GUTF8String get_name(void) const;
00113 void print(ByteStream & str, int compact=1, int indent=0, int * cur_pos=0) const;
00114 private:
00115 GLObjectType type;
00116 GUTF8String name;
00117
00118 int number;
00119 GUTF8String string;
00120 GUTF8String symbol;
00121 GPList<GLObject> list;
00122 void throw_can_not_convert_to(const GLObjectType to) const;
00123 };
00124
00125 const char * const GLObject::GLObjectString[]=
00126 {"invalid", "number", "string", "symbol", "list"};
00127
00128 inline GLObject::GLObjectType
00129 GLObject::get_type(void) const { return type; }
00130
00131 inline
00132 GLObject::~GLObject(void) {}
00133
00134 class GLToken
00135 {
00136 public:
00137 enum GLTokenType { OPEN_PAR, CLOSE_PAR, OBJECT };
00138 GLTokenType type;
00139 GP<GLObject> object;
00140
00141 GLToken(GLTokenType type, const GP<GLObject> & object);
00142 };
00143
00144 inline
00145 GLToken::GLToken(GLTokenType xtype, const GP<GLObject> & xobject) :
00146 type(xtype), object(xobject) {}
00147
00148 class GLParser
00149 {
00150 public:
00151 void parse(const char * str);
00152 GPList<GLObject> & get_list(void);
00153 GP<GLObject> get_object(const char * name, bool last=true);
00154 void print(ByteStream & str, int compact=1);
00155
00156 GLParser(void);
00157 GLParser(const char * str);
00158 ~GLParser(void);
00159 private:
00160 GPList<GLObject> list;
00161
00162 bool compat;
00163 void skip_white_space(const char * & start);
00164 void check_compat(const char *str);
00165 GLToken get_token(const char * & start);
00166 void parse(const char * cur_name, GPList<GLObject> & list,
00167 const char * & start);
00168 };
00169
00170 GLParser::GLParser(void)
00171 : compat(false)
00172 {
00173 }
00174
00175 GLParser::~GLParser(void)
00176 {
00177 }
00178
00179 GPList<GLObject> &
00180 GLParser::get_list(void)
00181 {
00182 return list;
00183 }
00184
00185 GLParser::GLParser(const char * str)
00186 : compat(false)
00187 {
00188 parse(str);
00189 }
00190
00191
00192
00193
00194
00195
00196
00197 GLObject::GLObject(int xnumber) : type(NUMBER), number(xnumber) {}
00198
00199 GLObject::GLObject(GLObjectType xtype, const char * str) : type(xtype)
00200 {
00201 if (type!=STRING && type!=SYMBOL)
00202 G_THROW( ERR_MSG("DjVuAnno.bad_type") );
00203 if (type==STRING)
00204 string=str;
00205 else symbol=str;
00206 }
00207
00208 GLObject::GLObject(const char * xname, const GPList<GLObject> & xlist) :
00209 type(LIST), name(xname), list(xlist) {}
00210
00211 void
00212 GLObject::print(ByteStream & str, int compact, int indent, int * cur_pos) const
00213 {
00214 int local_cur_pos = 0;
00215 if (!cur_pos) { cur_pos = &local_cur_pos; }
00216
00217 GUTF8String buffer;
00218 const char * to_print=0;
00219 switch(type)
00220 {
00221 case NUMBER:
00222 to_print=buffer.format("%d",number);
00223 break;
00224 case STRING:
00225 {
00226 int length = string.length();
00227 const char *data = (const char*)string;
00228 buffer = GUTF8String("\"");
00229 while (*data && length>0)
00230 {
00231 int span = 0;
00232 while (span<length && (unsigned char)(data[span])>=0x20 &&
00233 data[span]!=0x7f && data[span]!='"' && data[span]!='\\' )
00234 span++;
00235 if (span > 0)
00236 {
00237 buffer = buffer + GUTF8String(data, span);
00238 data += span;
00239 length -= span;
00240 }
00241 else
00242 {
00243 char buf[8];
00244 static char *tr1 = "\"\\tnrbf";
00245 static char *tr2 = "\"\\\t\n\r\b\f";
00246 sprintf(buf,"\\%03o", (int)(((unsigned char*)data)[span]));
00247 for (int i=0; tr2[i]; i++)
00248 if (data[span] == tr2[i])
00249 buf[1] = tr1[i];
00250 if (buf[1]<'0' || buf[1]>'3')
00251 buf[2] = 0;
00252 buffer = buffer + GUTF8String(buf);
00253 data += 1;
00254 length -= 1;
00255 }
00256 }
00257 buffer = buffer + GUTF8String("\"");
00258 to_print = buffer;
00259 }
00260 break;
00261 case SYMBOL:
00262 to_print=buffer.format("%s",(const char *)symbol);
00263 break;
00264 case LIST:
00265 to_print=buffer.format("(%s",(const char *)name);
00266 break;
00267 case INVALID:
00268 break;
00269 }
00270 if (!compact && *cur_pos+strlen(to_print)>70)
00271 {
00272 char ch='\n';
00273 str.write(&ch, 1);
00274 ch=' ';
00275 for(int i=0;i<indent;i++) str.write(&ch, 1);
00276 *cur_pos=indent;
00277 }
00278 str.write(to_print, strlen(to_print));
00279 char ch=' ';
00280 str.write(&ch, 1);
00281 *cur_pos+=strlen(to_print)+1;
00282 if (type==LIST)
00283 {
00284 int indent=*cur_pos-strlen(to_print);
00285 for(GPosition pos=list;pos;++pos)
00286 list[pos]->print(str, compact, indent, cur_pos);
00287 str.write(") ", 2);
00288 *cur_pos+=2;
00289 }
00290 }
00291
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 void
00306 GLObject::throw_can_not_convert_to(const GLObjectType to) const
00307 {
00308 static const GUTF8String two('2');
00309 static const GUTF8String tab('\t');
00310 GUTF8String mesg("DjVuAnno.");
00311 switch(type)
00312 {
00313 case NUMBER:
00314 mesg+=GLObjectString[NUMBER]+two+GLObjectString[to]+tab+GUTF8String(number);
00315 break;
00316 case STRING:
00317 mesg+=GLObjectString[STRING]+two+GLObjectString[to]+tab+string;
00318 break;
00319 case SYMBOL:
00320 mesg+=GLObjectString[SYMBOL]+two+GLObjectString[to]+tab+symbol;
00321 break;
00322 case LIST:
00323 mesg+=GLObjectString[LIST]+two+GLObjectString[to]+tab+name;
00324 break;
00325 default:
00326 mesg+=GLObjectString[INVALID]+two+GLObjectString[to];
00327 break;
00328 }
00329 G_THROW(mesg);
00330 }
00331
00332 GUTF8String
00333 GLObject::get_string(void) const
00334 {
00335 if (type!=STRING)
00336 {
00337 throw_can_not_convert_to(STRING);
00338 }
00339 return string;
00340 }
00341
00342 GUTF8String
00343 GLObject::get_symbol(void) const
00344 {
00345 if (type!=SYMBOL)
00346 {
00347 throw_can_not_convert_to(SYMBOL);
00348 }
00349 return symbol;
00350 }
00351
00352 int
00353 GLObject::get_number(void) const
00354 {
00355 if (type!=NUMBER)
00356 {
00357 throw_can_not_convert_to(NUMBER);
00358 }
00359 return number;
00360 }
00361
00362 GUTF8String
00363 GLObject::get_name(void) const
00364 {
00365 if (type!=LIST)
00366 {
00367 throw_can_not_convert_to(LIST);
00368 }
00369 return name;
00370 }
00371
00372 GP<GLObject>
00373 GLObject::operator[](int n) const
00374 {
00375 if (type!=LIST)
00376 {
00377 throw_can_not_convert_to(LIST);
00378 }
00379 if (n>=list.size()) G_THROW( ERR_MSG("DjVuAnno.too_few") "\t"+name);
00380 int i;
00381 GPosition pos;
00382 for(i=0, pos=list;i<n && pos;i++, ++pos)
00383 continue;
00384 return list[pos];
00385 }
00386
00387 GPList<GLObject> &
00388 GLObject::get_list(void)
00389 {
00390 if (type!=LIST)
00391 {
00392 throw_can_not_convert_to(LIST);
00393 }
00394 return list;
00395 }
00396
00397
00398
00399 void
00400 GLParser::skip_white_space(const char * & start)
00401 {
00402 while(*start && isspace(*start)) start++;
00403 if (!*start)
00404 G_THROW( ByteStream::EndOfFile );
00405 }
00406
00407 GLToken
00408 GLParser::get_token(const char * & start)
00409 {
00410 skip_white_space(start);
00411 char c = *start;
00412 if (c == '(')
00413 {
00414 start++;
00415 return GLToken(GLToken::OPEN_PAR, 0);
00416 }
00417 else if (c == ')')
00418 {
00419 start++;
00420 return GLToken(GLToken::CLOSE_PAR, 0);
00421 }
00422 else if (c=='-' || (c>='0' && c<='9'))
00423 {
00424 return GLToken(GLToken::OBJECT,
00425 new GLObject(strtol(start, (char **) &start, 10)));
00426 }
00427 else if (c=='"')
00428 {
00429 GUTF8String str;
00430 start++;
00431 while(1)
00432 {
00433 int span = 0;
00434 while (start[span] && start[span]!='\\' && start[span]!='\"')
00435 span++;
00436 if (span > 0)
00437 {
00438 str = str + GUTF8String(start,span);
00439 start += span;
00440 }
00441 else if (start[0]=='\"')
00442 {
00443 start += 1;
00444 break;
00445 }
00446 else if (start[0]=='\\' && compat)
00447 {
00448 char c = start[1];
00449 if (c == '\"')
00450 {
00451 start += 2;
00452 str += '\"';
00453 }
00454 else
00455 {
00456 start += 1;
00457 str += '\\';
00458 }
00459 }
00460 else if (start[0]=='\\' && start[1])
00461 {
00462 char c = *++start;
00463 if (c>='0' && c<='7')
00464 {
00465 int x = 0;
00466 for (int i=0; i<3 && c>='0' && c<='7'; i++)
00467 {
00468 x = x * 8 + c - '0';
00469 c = *++start;
00470 }
00471 str += (char)(x & 0xff);
00472 }
00473 else
00474 {
00475 static char *tr1 = "tnrbfva";
00476 static char *tr2 = "\t\n\r\b\f\013\007";
00477 for (int i=0; tr1[i]; i++)
00478 if (c == tr1[i])
00479 c = tr2[i];
00480 start += 1;
00481 str += c;
00482 }
00483 }
00484 else
00485 {
00486 G_THROW( ByteStream::EndOfFile );
00487 }
00488 }
00489 return GLToken(GLToken::OBJECT,
00490 new GLObject(GLObject::STRING, str));
00491 }
00492 else
00493 {
00494 GUTF8String str;
00495 while(1)
00496 {
00497 char ch=*start++;
00498 if (!ch)
00499 G_THROW( ByteStream::EndOfFile );
00500 if (ch==')') { start--; break; }
00501 if (isspace(ch)) break;
00502 str+=ch;
00503 }
00504 return GLToken(GLToken::OBJECT, new GLObject(GLObject::SYMBOL, str));
00505 }
00506 }
00507
00508 void
00509 GLParser::parse(const char * cur_name, GPList<GLObject> & list,
00510 const char * & start)
00511 {
00512 DEBUG_MSG("GLParse::parse(): Parsing contents of object '" << cur_name << "'\n");
00513 DEBUG_MAKE_INDENT(3);
00514
00515 while(1)
00516 {
00517 GLToken token=get_token(start);
00518 if (token.type==GLToken::OPEN_PAR)
00519 {
00520 if (isspace(*start))
00521 {
00522 GUTF8String mesg=GUTF8String( ERR_MSG("DjVuAnno.paren") "\t")+cur_name;
00523 G_THROW(mesg);
00524 }
00525
00526 GLToken tok=get_token(start);
00527 GP<GLObject> object=tok.object;
00528
00529 if (tok.type!=GLToken::OBJECT || object->get_type()!=GLObject::SYMBOL)
00530 {
00531 if (tok.type==GLToken::OPEN_PAR ||
00532 tok.type==GLToken::CLOSE_PAR)
00533 {
00534 GUTF8String mesg=GUTF8String( ERR_MSG("DjVuAnno.no_paren") "\t")+cur_name;
00535 G_THROW(mesg);
00536 }
00537 if (tok.type==GLToken::OBJECT)
00538 {
00539 GLObject::GLObjectType type=object->get_type();
00540 if (type==GLObject::NUMBER)
00541 {
00542 GUTF8String mesg( ERR_MSG("DjVuAnno.no_number") "\t");
00543 mesg += cur_name;
00544 G_THROW(mesg);
00545 }
00546 else if (type==GLObject::STRING)
00547 {
00548 GUTF8String mesg( ERR_MSG("DjVuAnno.no_string") "\t");
00549 mesg += cur_name;
00550 G_THROW(mesg);
00551 }
00552 }
00553 }
00554
00555
00556 GPList<GLObject> new_list;
00557 G_TRY
00558 {
00559 parse(object->get_symbol(), new_list, start);
00560 }
00561 G_CATCH(exc)
00562 {
00563 if (exc.cmp_cause(ByteStream::EndOfFile))
00564 G_RETHROW;
00565 }
00566 G_ENDCATCH;
00567 list.append(new GLObject(object->get_symbol(), new_list));
00568 continue;
00569 }
00570 if (token.type==GLToken::CLOSE_PAR)
00571 return;
00572 list.append(token.object);
00573 }
00574 }
00575
00576 void
00577 GLParser::check_compat(const char *s)
00578 {
00579 int state = 0;
00580 while (s && *s && !compat)
00581 {
00582 switch(state)
00583 {
00584 case 0:
00585 if (*s == '\"')
00586 state = '\"';
00587 break;
00588 case '\"':
00589 if (*s == '\"')
00590 state = 0;
00591 else if (*s == '\\')
00592 state = '\\';
00593 else if ((unsigned char)(*s)<0x20 || *s==0x7f)
00594 compat = true;
00595 break;
00596 case '\\':
00597 if (!strchr("01234567tnrbfva\"\\",*s))
00598 compat = true;
00599 state = '\"';
00600 break;
00601 }
00602 s += 1;
00603 }
00604 }
00605
00606 void
00607 GLParser::parse(const char * str)
00608 {
00609 DEBUG_MSG("GLParser::parse(): parsing string contents\n");
00610 DEBUG_MAKE_INDENT(3);
00611
00612 G_TRY
00613 {
00614 check_compat(str);
00615 parse("toplevel", list, str);
00616 } G_CATCH(exc)
00617 {
00618 if (exc.cmp_cause(ByteStream::EndOfFile))
00619 G_RETHROW;
00620 } G_ENDCATCH;
00621 }
00622
00623 void
00624 GLParser::print(ByteStream & str, int compact)
00625 {
00626 for(GPosition pos=list;pos;++pos)
00627 list[pos]->print(str, compact);
00628 }
00629
00630 GP<GLObject>
00631 GLParser::get_object(const char * name, bool last)
00632 {
00633 GP<GLObject> object;
00634 for(GPosition pos=list;pos;++pos)
00635 {
00636 GP<GLObject> obj=list[pos];
00637 if (obj->get_type()==GLObject::LIST &&
00638 obj->get_name()==name)
00639 {
00640 object=obj;
00641 if (!last) break;
00642 }
00643 }
00644 return object;
00645 }
00646
00647
00648
00649
00650
00651 static const char *zoom_strings[]={
00652 "default","page","width","one2one","stretch"};
00653 static const int zoom_strings_size=sizeof(zoom_strings)/sizeof(const char *);
00654
00655 static const char *mode_strings[]={
00656 "default","color","fore","back","bw"};
00657 static const int mode_strings_size=sizeof(mode_strings)/sizeof(const char *);
00658
00659 static const char *align_strings[]={
00660 "default","left","center","right","top","bottom"};
00661 static const int align_strings_size=sizeof(align_strings)/sizeof(const char *);
00662
00663 #define PNOTE_TAG "pnote"
00664 #define BACKGROUND_TAG "background"
00665 #define ZOOM_TAG "zoom"
00666 #define MODE_TAG "mode"
00667 #define ALIGN_TAG "align"
00668 #define HALIGN_TAG "halign"
00669 #define VALIGN_TAG "valign"
00670 #define METADATA_TAG "metadata"
00671
00672 static const unsigned long default_bg_color=0xffffffff;
00673
00674 DjVuANT::DjVuANT(void)
00675 {
00676 bg_color=default_bg_color;
00677 zoom=0;
00678 mode=MODE_UNSPEC;
00679 hor_align=ver_align=ALIGN_UNSPEC;
00680 }
00681
00682 DjVuANT::~DjVuANT()
00683 {
00684 }
00685
00686 GUTF8String
00687 DjVuANT::get_paramtags(void) const
00688 {
00689 GUTF8String retval;
00690 if(zoom > 0)
00691 {
00692 retval+="<PARAM name=\"" ZOOM_TAG "\" value=\""+GUTF8String(zoom)+="\" />\n";
00693 }else if(zoom && ((-zoom)<zoom_strings_size))
00694 {
00695 retval+="<PARAM name=\"" ZOOM_TAG "\" value=\""+GUTF8String(zoom_strings[-zoom])+"\" />\n";
00696 }
00697 if((mode>0)&&(mode<mode_strings_size))
00698 {
00699 retval+="<PARAM name=\"" MODE_TAG "\" value=\""+GUTF8String(mode_strings[mode])+"\" />\n";
00700 }
00701 if((hor_align>ALIGN_UNSPEC)&&(hor_align<align_strings_size))
00702 {
00703 retval+="<PARAM name=\"" HALIGN_TAG "\" value=\""+GUTF8String(align_strings[hor_align])+"\" />\n";
00704 }
00705 if((ver_align>ALIGN_UNSPEC)&&(ver_align<align_strings_size))
00706 {
00707 retval+="<PARAM name=\"" VALIGN_TAG "\" value=\""+GUTF8String(align_strings[ver_align])+"\" />\n";
00708 }
00709 if((bg_color&0xffffff) == bg_color)
00710 {
00711 retval+="<PARAM name=\"" BACKGROUND_TAG "\" value=\""+GUTF8String().format("#%06lX",bg_color)+"\" />\n";
00712 }
00713 return retval;
00714 }
00715
00716 void
00717 DjVuANT::writeParam(ByteStream &str_out) const
00718 {
00719 str_out.writestring(get_paramtags());
00720 }
00721
00722 GUTF8String
00723 DjVuANT::get_xmlmap(const GUTF8String &name,const int height) const
00724 {
00725 GUTF8String retval("<MAP name=\""+name.toEscaped()+"\" >\n");
00726 for(GPosition pos(map_areas);pos;++pos)
00727 {
00728 retval+=map_areas[pos]->get_xmltag(height);
00729 }
00730 return retval+"</MAP>\n";
00731 }
00732
00733 void
00734 DjVuANT::writeMap(
00735 ByteStream &str_out,const GUTF8String &name,const int height) const
00736 {
00737 str_out.writestring("<MAP name=\""+name.toEscaped()+"\" >\n");
00738 for(GPosition pos(map_areas);pos;++pos)
00739 {
00740 str_out.writestring(GUTF8String(map_areas[pos]->get_xmltag(height)));
00741 }
00742 str_out.writestring(GUTF8String("</MAP>\n"));
00743 }
00744
00745 GUTF8String
00746 DjVuANT::read_raw(ByteStream & str)
00747 {
00748 GUTF8String raw;
00749 char buffer[1024];
00750 int length;
00751 while((length=str.read(buffer, 1024)))
00752 raw+=GUTF8String(buffer, length);
00753 return raw;
00754 }
00755
00756 void
00757 DjVuANT::decode(class GLParser & parser)
00758 {
00759 bg_color=get_bg_color(parser);
00760 zoom=get_zoom(parser);
00761 mode=get_mode(parser);
00762 hor_align=get_hor_align(parser);
00763 ver_align=get_ver_align(parser);
00764 map_areas=get_map_areas(parser);
00765 #ifndef NO_METADATA_IN_ANT_CHUNK
00766 metadata=get_metadata(parser);
00767 #endif
00768 }
00769
00770
00771 void
00772 DjVuANT::decode(ByteStream & str)
00773 {
00774 GLParser parser(read_raw(str));
00775 decode(parser);
00776 }
00777
00778 void
00779 DjVuANT::merge(ByteStream & str)
00780 {
00781 GLParser parser(encode_raw());
00782 GUTF8String add_raw=read_raw(str);
00783 parser.parse(add_raw);
00784 decode(parser);
00785 }
00786
00787 void
00788 DjVuANT::encode(ByteStream &bs)
00789 {
00790 GUTF8String raw=encode_raw();
00791 bs.writall((const char*) raw, raw.length());
00792 }
00793
00794 unsigned int
00795 DjVuANT::get_memory_usage() const
00796 {
00797 return sizeof(DjVuANT);
00798 }
00799
00800 unsigned char
00801 DjVuANT::decode_comp(char ch1, char ch2)
00802 {
00803 unsigned char dig1=0;
00804 if (ch1)
00805 {
00806 ch1=toupper(ch1);
00807 if (ch1>='0' && ch1<='9') dig1=ch1-'0';
00808 if (ch1>='A' && ch1<='F') dig1=10+ch1-'A';
00809
00810 unsigned char dig2=0;
00811 if (ch2)
00812 {
00813 ch2=toupper(ch2);
00814 if (ch2>='0' && ch2<='9') dig2=ch2-'0';
00815 if (ch2>='A' && ch2<='F') dig2=10+ch2-'A';
00816 return (dig1 << 4) | dig2;
00817 }
00818 return dig1;
00819 }
00820 return 0;
00821 }
00822
00823 unsigned long int
00824 DjVuANT::cvt_color(const char * color, unsigned long int def)
00825 {
00826 if (color[0]!='#') return def;
00827
00828 unsigned long int color_rgb=0;
00829 color++;
00830 const char * start, * end;
00831
00832
00833 end=color+strlen(color); start=end-2;
00834 if (start<color) start=color;
00835 if (end>start)
00836 color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0);
00837
00838
00839 end=color+strlen(color)-2; start=end-2;
00840 if (start<color) start=color;
00841 if (end>start)
00842 color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0) << 8;
00843
00844
00845 end=color+strlen(color)-4; start=end-2;
00846 if (start<color) start=color;
00847 if (end>start)
00848 color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0) << 16;
00849
00850
00851 end=color+strlen(color)-6; start=end-2;
00852 if (start<color) start=color;
00853 if (end>start)
00854 color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0) << 24;
00855
00856 return color_rgb;
00857 }
00858
00859 unsigned long int
00860 DjVuANT::get_bg_color(GLParser & parser)
00861 {
00862 unsigned long retval=default_bg_color;
00863 DEBUG_MSG("DjVuANT::get_bg_color(): getting background color ...\n");
00864 DEBUG_MAKE_INDENT(3);
00865 G_TRY
00866 {
00867 GP<GLObject> obj=parser.get_object(BACKGROUND_TAG);
00868 if (obj && obj->get_list().size()==1)
00869 {
00870 GUTF8String color=(*obj)[0]->get_symbol();
00871 DEBUG_MSG("color='" << color << "'\n");
00872 retval=cvt_color(color, 0xffffff);
00873 }
00874 #ifndef NDEBUG
00875 if(retval == default_bg_color)
00876 {
00877 DEBUG_MSG("can't find any.\n");
00878 }
00879 #endif // NDEBUG
00880 } G_CATCH_ALL {} G_ENDCATCH;
00881 #ifndef NDEBUG
00882 if(retval == default_bg_color)
00883 {
00884 DEBUG_MSG("resetting color to 0xffffffff (UNSPEC)\n");
00885 }
00886 #endif // NDEBUG
00887 return retval;
00888 }
00889
00890 int
00891 DjVuANT::get_zoom(GLParser & parser)
00892
00893
00894
00895
00896 {
00897 int retval=ZOOM_UNSPEC;
00898 DEBUG_MSG("DjVuANT::get_zoom(): getting zoom factor ...\n");
00899 DEBUG_MAKE_INDENT(3);
00900 G_TRY
00901 {
00902 GP<GLObject> obj=parser.get_object(ZOOM_TAG);
00903 if (obj && obj->get_list().size()==1)
00904 {
00905 const GUTF8String zoom((*obj)[0]->get_symbol());
00906 DEBUG_MSG("zoom='" << zoom << "'\n");
00907
00908 for(int i=0;(i<zoom_strings_size);++i)
00909 {
00910 if(zoom == zoom_strings[i])
00911 {
00912 retval=(-i);
00913 break;
00914 }
00915 }
00916 if(retval == ZOOM_UNSPEC)
00917 {
00918 if (zoom[0]!='d')
00919 {
00920 G_THROW( ERR_MSG("DjVuAnno.bad_zoom") );
00921 }else
00922 {
00923 retval=zoom.substr(1, zoom.length()).toInt();
00924 }
00925 }
00926 }
00927 #ifndef NDEBUG
00928 if(retval == ZOOM_UNSPEC)
00929 {
00930 DEBUG_MSG("can't find any.\n");
00931 }
00932 #endif // NDEBUG
00933 } G_CATCH_ALL {} G_ENDCATCH;
00934 #ifndef NDEBUG
00935 if(retval == ZOOM_UNSPEC)
00936 {
00937 DEBUG_MSG("resetting zoom to 0 (UNSPEC)\n");
00938 }
00939 #endif // NDEBUG
00940 return retval;
00941 }
00942
00943 int
00944 DjVuANT::get_mode(GLParser & parser)
00945 {
00946 int retval=MODE_UNSPEC;
00947 DEBUG_MSG("DjVuAnt::get_mode(): getting default mode ...\n");
00948 DEBUG_MAKE_INDENT(3);
00949 G_TRY
00950 {
00951 GP<GLObject> obj=parser.get_object(MODE_TAG);
00952 if (obj && obj->get_list().size()==1)
00953 {
00954 const GUTF8String mode((*obj)[0]->get_symbol());
00955 DEBUG_MSG("mode='" << mode << "'\n");
00956 for(int i=0;(i<mode_strings_size);++i)
00957 {
00958 if(mode == mode_strings[i])
00959 {
00960 retval=i;
00961 break;
00962 }
00963 }
00964 }
00965 #ifndef NDEBUG
00966 if(retval == MODE_UNSPEC)
00967 {
00968 DEBUG_MSG("can't find any.\n");
00969 }
00970 #endif // NDEBUG
00971 } G_CATCH_ALL {} G_ENDCATCH;
00972 #ifndef NDEBUG
00973 if(retval == MODE_UNSPEC)
00974 {
00975 DEBUG_MSG("resetting mode to MODE_UNSPEC\n");
00976 }
00977 #endif // NDEBUG
00978 return retval;
00979 }
00980
00981 static inline DjVuANT::alignment
00982 legal_halign(const int i)
00983 {
00984 DjVuANT::alignment retval;
00985 switch((DjVuANT::alignment)i)
00986 {
00987 case DjVuANT::ALIGN_LEFT:
00988 case DjVuANT::ALIGN_CENTER:
00989 case DjVuANT::ALIGN_RIGHT:
00990 retval=(DjVuANT::alignment)i;
00991 break;
00992 default:
00993 retval=DjVuANT::ALIGN_UNSPEC;
00994 break;
00995 }
00996 return retval;
00997 }
00998
00999 static inline DjVuANT::alignment
01000 legal_valign(const int i)
01001 {
01002 DjVuANT::alignment retval;
01003 switch((DjVuANT::alignment)i)
01004 {
01005 case DjVuANT::ALIGN_CENTER:
01006 case DjVuANT::ALIGN_TOP:
01007 case DjVuANT::ALIGN_BOTTOM:
01008 retval=(DjVuANT::alignment)i;
01009 break;
01010 default:
01011 retval=DjVuANT::ALIGN_UNSPEC;
01012 break;
01013 }
01014 return retval;
01015 }
01016
01017 DjVuANT::alignment
01018 DjVuANT::get_hor_align(GLParser & parser)
01019 {
01020 DEBUG_MSG("DjVuAnt::get_hor_align(): getting hor page alignemnt ...\n");
01021 DEBUG_MAKE_INDENT(3);
01022 alignment retval=ALIGN_UNSPEC;
01023 G_TRY
01024 {
01025 GP<GLObject> obj=parser.get_object(ALIGN_TAG);
01026 if (obj && obj->get_list().size()==2)
01027 {
01028 const GUTF8String align((*obj)[0]->get_symbol());
01029 DEBUG_MSG("hor_align='" << align << "'\n");
01030
01031 for(int i=(int)ALIGN_UNSPEC;(i<align_strings_size);++i)
01032 {
01033 const alignment j=legal_halign(i);
01034 if((i == (int)j)&&(align == align_strings[i]))
01035 {
01036 retval=j;
01037 break;
01038 }
01039 }
01040 }
01041 #ifndef NDEBUG
01042 if(retval == ALIGN_UNSPEC)
01043 {
01044 DEBUG_MSG("can't find any.\n");
01045 }
01046 #endif // NDEBUG
01047 } G_CATCH_ALL {} G_ENDCATCH;
01048 #ifndef NDEBUG
01049 if(retval == ALIGN_UNSPEC)
01050 {
01051 DEBUG_MSG("resetting alignment to ALIGN_UNSPEC\n");
01052 }
01053 #endif // NDEBUG
01054 return retval;
01055 }
01056
01057 DjVuANT::alignment
01058 DjVuANT::get_ver_align(GLParser & parser)
01059 {
01060 DEBUG_MSG("DjVuAnt::get_ver_align(): getting vert page alignemnt ...\n");
01061 DEBUG_MAKE_INDENT(3);
01062 alignment retval=ALIGN_UNSPEC;
01063 G_TRY
01064 {
01065 GP<GLObject> obj=parser.get_object(ALIGN_TAG);
01066 if (obj && obj->get_list().size()==2)
01067 {
01068 const GUTF8String align((*obj)[1]->get_symbol());
01069 DEBUG_MSG("ver_align='" << align << "'\n");
01070 for(int i=(int)ALIGN_UNSPEC;(i<align_strings_size);++i)
01071 {
01072 const alignment j=legal_valign(i);
01073 if((i == (int)j)&&(align == align_strings[i]))
01074 {
01075 retval=j;
01076 break;
01077 }
01078 }
01079 }
01080 #ifndef NDEBUG
01081 if(retval == ALIGN_UNSPEC)
01082 {
01083 DEBUG_MSG("can't find any.\n");
01084 }
01085 #endif // NDEBUG
01086 } G_CATCH_ALL {} G_ENDCATCH;
01087 #ifndef NDEBUG
01088 if(retval == ALIGN_UNSPEC)
01089 {
01090 DEBUG_MSG("resetting alignment to ALIGN_UNSPEC\n");
01091 }
01092 #endif // NDEBUG
01093 return retval;
01094 }
01095
01096 #ifndef NO_METADATA_IN_ANT_CHUNK
01097 GMap<GUTF8String, GUTF8String>
01098 DjVuANT::get_metadata(GLParser & parser)
01099 {
01100 DEBUG_MSG("DjVuANT::get_map_areas(): forming and returning back list of map areas\n");
01101 DEBUG_MAKE_INDENT(3);
01102
01103 GMap<GUTF8String, GUTF8String> mdata;
01104
01105 GPList<GLObject> list=parser.get_list();
01106 for(GPosition pos=list;pos;++pos)
01107 {
01108 GLObject & obj=*list[pos];
01109 if (obj.get_type()==GLObject::LIST && obj.get_name()==METADATA_TAG)
01110 {
01111 G_TRY
01112 {
01113 for(int obj_num=0;obj_num<obj.get_list().size();obj_num++)
01114 {
01115 GLObject & el=*obj[obj_num];
01116 const int type = el.get_type();
01117 if (type == GLObject::LIST)
01118 {
01119 const GUTF8String & name=el.get_name();
01120 mdata[name]=(el[0])->get_string();
01121 }
01122 }
01123 }
01124 G_CATCH_ALL { } G_ENDCATCH;
01125 }
01126 }
01127 return mdata;
01128 }
01129 #endif
01130
01131 GPList<GMapArea>
01132 DjVuANT::get_map_areas(GLParser & parser)
01133 {
01134 DEBUG_MSG("DjVuANT::get_map_areas(): forming and returning back list of map areas\n");
01135 DEBUG_MAKE_INDENT(3);
01136
01137 GPList<GMapArea> map_areas;
01138
01139 GPList<GLObject> list=parser.get_list();
01140
01141 for(GPosition pos=list;pos;++pos)
01142 {
01143 GLObject & obj=*list[pos];
01144 const int type=obj.get_type();
01145 if (type == GLObject::LIST)
01146 {
01147 const GUTF8String name=obj.get_name();
01148 if(name == GMapArea::MAPAREA_TAG)
01149 {
01150 G_TRY {
01151
01152 GUTF8String url;
01153 GUTF8String target=GMapArea::TARGET_SELF;
01154 GLObject & url_obj=*(obj[0]);
01155 if (url_obj.get_type()==GLObject::LIST)
01156 {
01157 if (url_obj.get_name()!=GMapArea::URL_TAG)
01158 G_THROW( ERR_MSG("DjVuAnno.bad_url") );
01159 url=(url_obj[0])->get_string();
01160 target=(url_obj[1])->get_string();
01161 } else url=url_obj.get_string();
01162
01163
01164 GUTF8String comment=(obj[1])->get_string();
01165
01166 DEBUG_MSG("found maparea '" << comment << "' (" <<
01167 url << ":" << target << ")\n");
01168
01169 GLObject * shape=obj[2];
01170 GP<GMapArea> map_area;
01171 if (shape->get_type()==GLObject::LIST)
01172 {
01173 if (shape->get_name()==GMapArea::RECT_TAG)
01174 {
01175 DEBUG_MSG("it's a rectangle.\n");
01176 GRect grect((*shape)[0]->get_number(),
01177 (*shape)[1]->get_number(),
01178 (*shape)[2]->get_number(),
01179 (*shape)[3]->get_number());
01180 GP<GMapRect> map_rect=GMapRect::create(grect);
01181 map_area=(GMapRect *)map_rect;
01182 } else if (shape->get_name()==GMapArea::POLY_TAG)
01183 {
01184 DEBUG_MSG("it's a polygon.\n");
01185 int points=shape->get_list().size()/2;
01186 GTArray<int> xx(points-1), yy(points-1);
01187 for(int i=0;i<points;i++)
01188 {
01189 xx[i]=(*shape)[2*i]->get_number();
01190 yy[i]=(*shape)[2*i+1]->get_number();
01191 }
01192 GP<GMapPoly> map_poly=GMapPoly::create(xx,yy,points);
01193 map_area=(GMapPoly *)map_poly;
01194 } else if (shape->get_name()==GMapArea::OVAL_TAG)
01195 {
01196 DEBUG_MSG("it's an ellipse.\n");
01197 GRect grect((*shape)[0]->get_number(),
01198 (*shape)[1]->get_number(),
01199 (*shape)[2]->get_number(),
01200 (*shape)[3]->get_number());
01201 GP<GMapOval> map_oval=GMapOval::create(grect);
01202 map_area=(GMapOval *)map_oval;
01203 }
01204 }
01205
01206 if (map_area)
01207 {
01208 map_area->url=url;
01209 map_area->target=target;
01210 map_area->comment=comment;
01211 for(int obj_num=3;obj_num<obj.get_list().size();obj_num++)
01212 {
01213 GLObject * el=obj[obj_num];
01214 if (el->get_type()==GLObject::LIST)
01215 {
01216 const GUTF8String & name=el->get_name();
01217 if (name==GMapArea::BORDER_AVIS_TAG)
01218 map_area->border_always_visible=true;
01219 else if (name==GMapArea::HILITE_TAG)
01220 {
01221 GLObject * obj=el->get_list()[el->get_list().firstpos()];
01222 if (obj->get_type()==GLObject::SYMBOL)
01223 map_area->hilite_color=cvt_color(obj->get_symbol(), 0xff);
01224 } else
01225 {
01226 int border_type=
01227 name==GMapArea::NO_BORDER_TAG ? GMapArea::NO_BORDER :
01228 name==GMapArea::XOR_BORDER_TAG ? GMapArea::XOR_BORDER :
01229 name==GMapArea::SOLID_BORDER_TAG ? GMapArea::SOLID_BORDER :
01230 name==GMapArea::SHADOW_IN_BORDER_TAG ? GMapArea::SHADOW_IN_BORDER :
01231 name==GMapArea::SHADOW_OUT_BORDER_TAG ? GMapArea::SHADOW_OUT_BORDER :
01232 name==GMapArea::SHADOW_EIN_BORDER_TAG ? GMapArea::SHADOW_EIN_BORDER :
01233 name==GMapArea::SHADOW_EOUT_BORDER_TAG ? GMapArea::SHADOW_EOUT_BORDER : -1;
01234 if (border_type>=0)
01235 {
01236 map_area->border_type=(GMapArea::BorderType) border_type;
01237 for(GPosition pos=el->get_list();pos;++pos)
01238 {
01239 GLObject * obj=el->get_list()[pos];
01240 if (obj->get_type()==GLObject::SYMBOL)
01241 map_area->border_color=cvt_color(obj->get_symbol(), 0xff);
01242 if (obj->get_type()==GLObject::NUMBER)
01243 map_area->border_width=obj->get_number();
01244 }
01245 }
01246 }
01247 }
01248 }
01249 map_areas.append(map_area);
01250 }
01251 } G_CATCH_ALL {} G_ENDCATCH;
01252 }
01253 }
01254 }
01255
01256 DEBUG_MSG("map area list size = " << list.size() << "\n");
01257
01258 return map_areas;
01259 }
01260
01261 void
01262 DjVuANT::del_all_items(const char * name, GLParser & parser)
01263 {
01264 GPList<GLObject> & list=parser.get_list();
01265 GPosition pos=list;
01266 while(pos)
01267 {
01268 GLObject & obj=*list[pos];
01269 if (obj.get_type()==GLObject::LIST &&
01270 obj.get_name()==name)
01271 {
01272 GPosition this_pos=pos;
01273 ++pos;
01274 list.del(this_pos);
01275 } else ++pos;
01276 }
01277 }
01278
01279 GUTF8String
01280 DjVuANT::encode_raw(void) const
01281 {
01282 GUTF8String buffer;
01283 GLParser parser;
01284
01285
01286 del_all_items(BACKGROUND_TAG, parser);
01287 if (bg_color!=default_bg_color)
01288 {
01289 buffer.format("(" BACKGROUND_TAG " #%02X%02X%02X)",
01290 (unsigned int)((bg_color & 0xff0000) >> 16),
01291 (unsigned int)((bg_color & 0xff00) >> 8),
01292 (unsigned int)(bg_color & 0xff));
01293 parser.parse(buffer);
01294 }
01295
01296
01297 del_all_items(ZOOM_TAG, parser);
01298 if (zoom!=ZOOM_UNSPEC)
01299 {
01300 buffer="(" ZOOM_TAG " ";
01301 const int i=1-zoom;
01302 if((i>=0)&& (i<zoom_strings_size))
01303 {
01304 buffer+=zoom_strings[i];
01305 }else
01306 {
01307 buffer+="d"+GUTF8String(zoom);
01308 }
01309 buffer+=")";
01310 parser.parse(buffer);
01311 }
01312
01313
01314 del_all_items(MODE_TAG, parser);
01315 if (mode!=MODE_UNSPEC)
01316 {
01317 const int i=mode-1;
01318 if((i>=0)&& (i<mode_strings_size))
01319 {
01320 buffer="(" MODE_TAG " " + GUTF8String(mode_strings[mode]) + ")";
01321 }
01322 parser.parse(buffer);
01323 }
01324
01325
01326 del_all_items(ALIGN_TAG, parser);
01327 if (hor_align!=ALIGN_UNSPEC || ver_align!=ALIGN_UNSPEC)
01328 {
01329 buffer= GUTF8String("(" ALIGN_TAG " ")
01330 +align_strings[((hor_align<ALIGN_UNSPEC)||
01331 (hor_align>=align_strings_size))?ALIGN_UNSPEC:hor_align]
01332 +" "+align_strings[((ver_align<ALIGN_UNSPEC)||
01333 (ver_align>=align_strings_size))?ALIGN_UNSPEC:ver_align]+")";
01334 parser.parse(buffer);
01335 }
01336
01337 #ifndef NO_METADATA_IN_ANT_CHUNK
01338 del_all_items(METADATA_TAG, parser);
01339 if (!metadata.isempty())
01340 {
01341 GUTF8String mdatabuffer("(");
01342 mdatabuffer += METADATA_TAG ;
01343 for (GPosition pos=metadata; pos; ++pos)
01344 mdatabuffer +=" (" + metadata.key(pos)+" \""+metadata[pos]+"\")";
01345 mdatabuffer += " )";
01346 parser.parse(mdatabuffer);
01347 }
01348 #endif
01349
01350 del_all_items(GMapArea::MAPAREA_TAG, parser);
01351 for(GPosition pos=map_areas;pos;++pos)
01352 parser.parse(map_areas[pos]->print());
01353
01354 GP<ByteStream> gstr=ByteStream::create();
01355 ByteStream &str=*gstr;
01356 parser.print(str, 1);
01357 GUTF8String ans;
01358 int size = str.size();
01359 str.seek(0);
01360 str.read(ans.getbuf(size), size);
01361 return ans;
01362 }
01363
01364 bool
01365 DjVuANT::is_empty(void) const
01366 {
01367 GUTF8String raw=encode_raw();
01368 for(int i=raw.length()-1;i>=0;i--)
01369 if (isspace(raw[i])) raw.setat(i, 0);
01370 else break;
01371 return raw.length()==0;
01372 }
01373
01374 GP<DjVuANT>
01375 DjVuANT::copy(void) const
01376 {
01377 GP<DjVuANT> ant=new DjVuANT(*this);
01378
01379
01380
01381 ant->map_areas.empty();
01382 for(GPosition pos=map_areas;pos;++pos)
01383 ant->map_areas.append(map_areas[pos]->get_copy());
01384
01385 return ant;
01386 }
01387
01388
01389
01390
01391
01392 GUTF8String
01393 DjVuAnno::get_xmlmap(const GUTF8String &name,const int height) const
01394 {
01395 return ant
01396 ?(ant->get_xmlmap(name,height))
01397 :("<MAP name=\""+name.toEscaped()+"\"/>\n");
01398 }
01399
01400 void
01401 DjVuAnno::writeMap(ByteStream &str_out,const GUTF8String &name,const int height) const
01402 {
01403 if(ant)
01404 {
01405 ant->writeMap(str_out,name,height);
01406 }else
01407 {
01408 str_out.writestring(get_xmlmap(name,height));
01409 }
01410 }
01411
01412 GUTF8String
01413 DjVuAnno::get_paramtags(void) const
01414 {
01415 return ant
01416 ?(ant->get_paramtags())
01417 :GUTF8String();
01418 }
01419
01420 void
01421 DjVuAnno::writeParam(ByteStream &str_out) const
01422 {
01423 str_out.writestring(get_paramtags());
01424 }
01425
01426
01427 void
01428 DjVuAnno::decode(const GP<ByteStream> &gbs)
01429 {
01430 GUTF8String chkid;
01431 GP<IFFByteStream> giff=IFFByteStream::create(gbs);
01432 IFFByteStream &iff=*giff;
01433 while( iff.get_chunk(chkid) )
01434 {
01435 if (chkid == "ANTa")
01436 {
01437 if (ant) {
01438 ant->merge(*iff.get_bytestream());
01439 } else {
01440 ant=DjVuANT::create();
01441 ant->decode(*iff.get_bytestream());
01442 }
01443 }
01444 else if (chkid == "ANTz")
01445 {
01446 GP<ByteStream> gbsiff=BSByteStream::create(giff->get_bytestream());
01447 if (ant) {
01448 ant->merge(*gbsiff);
01449 } else {
01450 ant=DjVuANT::create();
01451 ant->decode(*gbsiff);
01452 }
01453 }
01454
01455 iff.close_chunk();
01456 }
01457 }
01458
01459 void
01460 DjVuAnno::encode(const GP<ByteStream> &gbs)
01461 {
01462 GP<IFFByteStream> giff=IFFByteStream::create(gbs);
01463 IFFByteStream &iff=*giff;
01464 if (ant)
01465 {
01466 #if 0
01467 iff.put_chunk("ANTa");
01468 ant->encode(iff);
01469 iff.close_chunk();
01470 #else
01471 iff.put_chunk("ANTz");
01472 {
01473
01474 GP<ByteStream> bsb = BSByteStream::create(giff->get_bytestream(), 50);
01475 ant->encode(*bsb);
01476 }
01477 iff.close_chunk();
01478 #endif
01479 }
01480
01481 }
01482
01483
01484 GP<DjVuAnno>
01485 DjVuAnno::copy(void) const
01486 {
01487 GP<DjVuAnno> anno= new DjVuAnno;
01488
01489 *anno=*this;
01490
01491 if (ant) anno->ant = ant->copy();
01492 return anno;
01493 }
01494
01495 void
01496 DjVuAnno::merge(const GP<DjVuAnno> & anno)
01497 {
01498 if (anno)
01499 {
01500 GP<ByteStream> gstr=ByteStream::create();
01501 encode(gstr);
01502 anno->encode(gstr);
01503 gstr->seek(0);
01504 decode(gstr);
01505 }
01506 }
01507
01508
01509 #ifdef HAVE_NAMESPACES
01510 }
01511 # ifndef NOT_USING_DJVU_NAMESPACE
01512 using namespace DJVU;
01513 # endif
01514 #endif