source: trunk/libdjvu/DjVuAnno.cpp @ 269

Last change on this file since 269 was 206, checked in by Eugene Romanenko, 14 years ago

DJVU plugin: djvulibre updated to version 3.5.19

File size: 39.3 KB
Line 
1//C-  -*- C++ -*-
2//C- -------------------------------------------------------------------
3//C- DjVuLibre-3.5
4//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
5//C- Copyright (c) 2001  AT&T
6//C-
7//C- This software is subject to, and may be distributed under, the
8//C- GNU General Public License, either Version 2 of the license,
9//C- or (at your option) any later version. The license should have
10//C- accompanied the software or you may obtain a copy of the license
11//C- from the Free Software Foundation at http://www.fsf.org .
12//C-
13//C- This program is distributed in the hope that it will be useful,
14//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
15//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16//C- GNU General Public License for more details.
17//C-
18//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
19//C- Lizardtech Software.  Lizardtech Software has authorized us to
20//C- replace the original DjVu(r) Reference Library notice by the following
21//C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
22//C-
23//C-  ------------------------------------------------------------------
24//C- | DjVu (r) Reference Library (v. 3.5)
25//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
26//C- | The DjVu Reference Library is protected by U.S. Pat. No.
27//C- | 6,058,214 and patents pending.
28//C- |
29//C- | This software is subject to, and may be distributed under, the
30//C- | GNU General Public License, either Version 2 of the license,
31//C- | or (at your option) any later version. The license should have
32//C- | accompanied the software or you may obtain a copy of the license
33//C- | from the Free Software Foundation at http://www.fsf.org .
34//C- |
35//C- | The computer code originally released by LizardTech under this
36//C- | license and unmodified by other parties is deemed "the LIZARDTECH
37//C- | ORIGINAL CODE."  Subject to any third party intellectual property
38//C- | claims, LizardTech grants recipient a worldwide, royalty-free,
39//C- | non-exclusive license to make, use, sell, or otherwise dispose of
40//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the
41//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU
42//C- | General Public License.   This grant only confers the right to
43//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to
44//C- | the extent such infringement is reasonably necessary to enable
45//C- | recipient to make, have made, practice, sell, or otherwise dispose
46//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to
47//C- | any greater extent that may be necessary to utilize further
48//C- | modifications or combinations.
49//C- |
50//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
51//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
52//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
53//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
54//C- +------------------------------------------------------------------
55//
56// $Id: DjVuAnno.cpp,v 1.14 2007/03/25 20:48:29 leonb Exp $
57// $Name: release_3_5_19 $
58
59#ifdef HAVE_CONFIG_H
60# include "config.h"
61#endif
62#if NEED_GNUG_PRAGMAS
63# pragma implementation
64#endif
65
66#include "DjVuAnno.h"
67#include "GContainer.h"
68#include "GException.h"
69#include "IFFByteStream.h"
70#include "BSByteStream.h"
71#include "GMapAreas.h"
72
73#include "debug.h"
74
75#include <ctype.h>
76
77
78#ifdef HAVE_NAMESPACES
79namespace DJVU {
80# ifdef NOT_DEFINED // Just to fool emacs c++ mode
81}
82#endif
83#endif
84
85
86// GLParser.h and GLParser.cpp used to be separate files capable to decode
87// that weird ANTa chunk format into C++ structures and lists. But since
88// its implementation is temporary and is used only in this file (DjVuAnno.cpp)
89// it appears reasonable to build it in here.
90
91//***************************************************************************
92//****************************** GLParser.h *********************************
93//***************************************************************************
94
95
96class GLObject : public GPEnabled
97{
98public:
99   enum GLObjectType { INVALID=0, NUMBER=1, STRING=2, SYMBOL=3, LIST=4 };
100   static const char * const GLObjectString[LIST+1];
101
102   GLObject(int _number=0);
103   GLObject(GLObjectType type, const char * str);
104   GLObject(const char * name, const GPList<GLObject> & list);
105   virtual ~GLObject(void);
106   
107   int          get_number(void) const;
108   GUTF8String  get_string(void) const;
109   GUTF8String  get_symbol(void) const;
110   GPList<GLObject>     & get_list(void);
111   GP<GLObject> operator[](int n) const;
112   
113   GLObjectType get_type(void) const;
114   GUTF8String  get_name(void) const;
115   void         print(ByteStream & str, int compact=1, int indent=0, int * cur_pos=0) const;
116private:
117   GLObjectType type;
118   GUTF8String  name;
119   
120   int          number;
121   GUTF8String  string;
122   GUTF8String  symbol;
123   GPList<GLObject>     list;
124   void throw_can_not_convert_to(const GLObjectType to) const;
125};
126
127const char * const GLObject::GLObjectString[]=
128  {"invalid", "number", "string", "symbol", "list"};
129
130inline GLObject::GLObjectType
131GLObject::get_type(void) const { return type; }
132
133inline
134GLObject::~GLObject(void) {}
135
136class GLToken
137{
138public:
139   enum GLTokenType { OPEN_PAR, CLOSE_PAR, OBJECT };
140   GLTokenType  type;
141   GP<GLObject> object;
142   
143   GLToken(GLTokenType type, const GP<GLObject> & object);
144};
145
146inline
147GLToken::GLToken(GLTokenType xtype, const GP<GLObject> & xobject) :
148      type(xtype), object(xobject) {}
149
150class GLParser
151{
152public:
153   void         parse(const char * str);
154   GPList<GLObject>     & get_list(void);
155   GP<GLObject>         get_object(const char * name, bool last=true);
156   void         print(ByteStream & str, int compact=1);
157
158   GLParser(void);
159   GLParser(const char * str);
160   ~GLParser(void);
161private:
162   GPList<GLObject>     list;
163
164   bool         compat;
165   void         skip_white_space(const char * & start);
166   void         check_compat(const char *str);
167   GLToken      get_token(const char * & start);
168   void         parse(const char * cur_name, GPList<GLObject> & list,
169                      const char * & start);
170};
171
172GLParser::GLParser(void) 
173  : compat(false)
174{
175}
176
177GLParser::~GLParser(void) 
178{
179}
180
181GPList<GLObject> &
182GLParser::get_list(void) 
183{ 
184  return list; 
185}
186
187GLParser::GLParser(const char * str) 
188  : compat(false)
189{
190  parse(str); 
191}
192
193
194//***************************************************************************
195//***************************** GLParser.cpp ********************************
196//***************************************************************************
197
198
199GLObject::GLObject(int xnumber) : type(NUMBER), number(xnumber) {}
200
201GLObject::GLObject(GLObjectType xtype, const char * str) : type(xtype)
202{
203   if (type!=STRING && type!=SYMBOL)
204      G_THROW( ERR_MSG("DjVuAnno.bad_type") );
205   if (type==STRING) 
206      string=str;
207   else symbol=str;
208}
209
210GLObject::GLObject(const char * xname, const GPList<GLObject> & xlist) :
211      type(LIST), name(xname), list(xlist) {}
212
213void
214GLObject::print(ByteStream & str, int compact, int indent, int * cur_pos) const
215{
216  int local_cur_pos = 0;
217  if (!cur_pos) { cur_pos = &local_cur_pos; }
218 
219  GUTF8String buffer;
220  const char * to_print=0;
221  switch(type)
222  {
223  case NUMBER:
224    to_print=buffer.format("%d",number);
225    break;
226  case STRING:
227    {
228       int length = string.length();
229       const char *data = (const char*)string;
230       buffer = GUTF8String("\"");
231       while (*data && length>0) 
232         {
233           int span = 0;
234           while (span<length && (unsigned char)(data[span])>=0x20 && 
235                  data[span]!=0x7f && data[span]!='"' && data[span]!='\\' )
236             span++;
237           if (span > 0) 
238             { 
239               buffer = buffer + GUTF8String(data, span);
240               data += span;
241               length -= span;
242             } 
243           else 
244             {
245               char buf[8];
246               static char *tr1 = "\"\\tnrbf";
247               static char *tr2 = "\"\\\t\n\r\b\f";
248               sprintf(buf,"\\%03o", (int)(((unsigned char*)data)[span]));
249               for (int i=0; tr2[i]; i++)
250                 if (data[span] == tr2[i])
251                   buf[1] = tr1[i];
252               if (buf[1]<'0' || buf[1]>'3')
253                 buf[2] = 0;
254               buffer = buffer + GUTF8String(buf);
255               data += 1;
256               length -= 1;
257             }
258         }
259       buffer = buffer + GUTF8String("\"");
260       to_print = buffer;
261    }
262    break;
263  case SYMBOL:
264    to_print=buffer.format("%s",(const char *)symbol);
265    break;
266  case LIST:
267    to_print=buffer.format("(%s",(const char *)name);
268    break;
269  case INVALID:
270    break;
271  }
272  if (!compact && *cur_pos+strlen(to_print)>70)
273  {
274    char ch='\n';
275    str.write(&ch, 1);
276    ch=' ';
277    for(int i=0;i<indent;i++) str.write(&ch, 1);
278    *cur_pos=indent;
279  }
280  str.write(to_print, strlen(to_print));
281  char ch=' ';
282  str.write(&ch, 1);
283  *cur_pos+=strlen(to_print)+1;
284  if (type==LIST)
285  {
286    int indent=*cur_pos-strlen(to_print);
287    for(GPosition pos=list;pos;++pos)
288      list[pos]->print(str, compact, indent, cur_pos);
289    str.write(") ", 2);
290    *cur_pos+=2;
291  }
292}
293
294//  This function constructs message names for external lookup.
295//  The message names are constructed to avoid the problems of concatenating
296//  phrases (which does not translate well into other languages). The
297//  message names that can be generated are (listed here to appease the
298//  auditing program which reads comments):
299//    ERR_MSG("DjVuAnno.invalid2number"), ERR_MSG("DjVuAnno.string2number"),
300//    ERR_MSG("DjVuAnno.symbol2number"), ERR_MSG("DjVuAnno.list2number")
301//    ERR_MSG("DjVuAnno.invalid2string"), ERR_MSG("DjVuAnno.number2string"),
302//    ERR_MSG("DjVuAnno.symbol2string"), ERR_MSG("DjVuAnno.list2string")
303//    ERR_MSG("DjVuAnno.invalid2symbol"), ERR_MSG("DjVuAnno.number2symbol"),
304//    ERR_MSG("DjVuAnno.string2symbol"), ERR_MSG("DjVuAnno.list2symbol")
305//    ERR_MSG("DjVuAnno.invalid2list"), ERR_MSG("DjVuAnno.number2list"),
306//    ERR_MSG("DjVuAnno.string2list"), ERR_MSG("DjVuAnno.symbol2list")
307void
308GLObject::throw_can_not_convert_to(const GLObjectType to) const
309{
310  static const GUTF8String two('2');
311  static const GUTF8String tab('\t');
312  GUTF8String mesg("DjVuAnno.");
313  switch(type)
314  {
315    case NUMBER:
316      mesg+=GLObjectString[NUMBER]+two+GLObjectString[to]+tab+GUTF8String(number);
317      break;
318    case STRING:
319      mesg+=GLObjectString[STRING]+two+GLObjectString[to]+tab+string;
320      break;
321    case SYMBOL:
322      mesg+=GLObjectString[SYMBOL]+two+GLObjectString[to]+tab+symbol;
323      break;
324    case LIST:
325      mesg+=GLObjectString[LIST]+two+GLObjectString[to]+tab+name;
326      break;
327    default:
328      mesg+=GLObjectString[INVALID]+two+GLObjectString[to];
329      break;
330  }
331  G_THROW(mesg);
332}
333
334GUTF8String
335GLObject::get_string(void) const
336{
337   if (type!=STRING)
338   {
339      throw_can_not_convert_to(STRING);
340   }
341   return string;
342}
343
344GUTF8String
345GLObject::get_symbol(void) const
346{
347   if (type!=SYMBOL)
348   {
349      throw_can_not_convert_to(SYMBOL);
350   }
351   return symbol;
352}
353
354int
355GLObject::get_number(void) const
356{
357   if (type!=NUMBER)
358   {
359      throw_can_not_convert_to(NUMBER);
360   }
361   return number;
362}
363
364GUTF8String
365GLObject::get_name(void) const
366{
367   if (type!=LIST)
368   {
369      throw_can_not_convert_to(LIST);
370   }
371   return name;
372}
373
374GP<GLObject>
375GLObject::operator[](int n) const
376{
377   if (type!=LIST)
378   {
379      throw_can_not_convert_to(LIST);
380   }
381   if (n>=list.size()) G_THROW( ERR_MSG("DjVuAnno.too_few") "\t"+name);
382   int i;
383   GPosition pos;
384   for(i=0, pos=list;i<n && pos;i++, ++pos)
385                continue;
386   return list[pos];
387}
388
389GPList<GLObject> &
390GLObject::get_list(void)
391{
392   if (type!=LIST)
393   {
394      throw_can_not_convert_to(LIST);
395   }
396   return list;
397}
398
399//********************************** GLParser *********************************
400
401void
402GLParser::skip_white_space(const char * & start)
403{
404   while(*start && isspace(*start)) start++;
405   if (!*start) 
406       G_THROW( ByteStream::EndOfFile );
407}
408
409GLToken
410GLParser::get_token(const char * & start)
411{
412   skip_white_space(start);
413   char c = *start;
414   if (c == '(')
415     {
416       start++;
417       return GLToken(GLToken::OPEN_PAR, 0);
418     }
419   else if (c == ')')
420     {
421       start++;
422       return GLToken(GLToken::CLOSE_PAR, 0);
423     }
424   else if (c=='-' || (c>='0' && c<='9'))
425     {
426       return GLToken(GLToken::OBJECT,
427                      new GLObject(strtol(start, (char **) &start, 10)));
428     }
429   else if (c=='"')
430     {
431       GUTF8String str;
432       start++;
433       while(1)
434         {
435           int span = 0;
436           while (start[span] && start[span]!='\\' && start[span]!='\"')
437             span++;
438           if (span > 0)
439             {
440               str = str + GUTF8String(start,span);
441               start += span;
442             }
443           else if (start[0]=='\"')
444             {
445               start += 1;
446               break;
447             }
448           else if (start[0]=='\\' && compat)
449             {
450               char c = start[1];
451               if (c == '\"')
452                 {
453                   start += 2;
454                   str += '\"';
455                 }
456               else
457                 {
458                   start += 1;
459                   str += '\\';
460                 }
461             }
462           else if (start[0]=='\\' && start[1])
463             {
464               char c = *++start;
465               if (c>='0' && c<='7')
466                 {
467                   int x = 0;
468                   for (int i=0; i<3 && c>='0' && c<='7'; i++) 
469                     {
470                       x = x * 8 + c - '0';
471                       c = *++start;
472                     }
473                   str += (char)(x & 0xff);
474                 }
475               else
476                 {
477                   static char *tr1 = "tnrbfva";
478                   static char *tr2 = "\t\n\r\b\f\013\007";
479                   for (int i=0; tr1[i]; i++)
480                     if (c == tr1[i])
481                       c = tr2[i];
482                   start += 1;
483                   str += c;
484                 }
485             }
486           else 
487             {
488               G_THROW( ByteStream::EndOfFile );
489             }
490         }
491       return GLToken(GLToken::OBJECT, 
492                      new GLObject(GLObject::STRING, str));
493     }
494   else
495     {
496       GUTF8String str;
497       while(1)
498         {
499           char ch=*start++;
500           if (!ch)
501             G_THROW( ByteStream::EndOfFile );
502           if (ch==')') { start--; break; }
503           if (isspace(ch)) break;
504           str+=ch;
505         }
506       return GLToken(GLToken::OBJECT, new GLObject(GLObject::SYMBOL, str));
507     }
508} 
509
510void
511GLParser::parse(const char * cur_name, GPList<GLObject> & list,
512                const char * & start)
513{
514  DEBUG_MSG("GLParse::parse(): Parsing contents of object '" << cur_name << "'\n");
515  DEBUG_MAKE_INDENT(3);
516 
517  while(1)
518  {
519    GLToken token=get_token(start);
520    if (token.type==GLToken::OPEN_PAR)
521    {
522      if (isspace(*start))
523      {
524        GUTF8String mesg=GUTF8String( ERR_MSG("DjVuAnno.paren") "\t")+cur_name;
525        G_THROW(mesg);
526      }
527     
528      GLToken tok=get_token(start);
529      GP<GLObject> object=tok.object;   // This object should be SYMBOL
530      // We will convert it to LIST later
531      if (tok.type!=GLToken::OBJECT || object->get_type()!=GLObject::SYMBOL)
532      {
533        if (tok.type==GLToken::OPEN_PAR ||
534          tok.type==GLToken::CLOSE_PAR)
535        {
536          GUTF8String mesg=GUTF8String( ERR_MSG("DjVuAnno.no_paren") "\t")+cur_name;
537          G_THROW(mesg);
538        }
539        if (tok.type==GLToken::OBJECT)
540        {
541          GLObject::GLObjectType type=object->get_type();
542          if (type==GLObject::NUMBER)
543          {
544            GUTF8String mesg( ERR_MSG("DjVuAnno.no_number") "\t");
545            mesg += cur_name;
546            G_THROW(mesg);
547          }
548          else if (type==GLObject::STRING)
549          {
550            GUTF8String mesg( ERR_MSG("DjVuAnno.no_string") "\t");
551            mesg += cur_name;
552            G_THROW(mesg);
553          }
554        }
555      }
556     
557      // OK. Get the object contents
558      GPList<GLObject> new_list;
559      G_TRY
560      {
561        parse(object->get_symbol(), new_list, start);
562      } 
563      G_CATCH(exc)
564      {
565        if (exc.cmp_cause(ByteStream::EndOfFile))
566          G_RETHROW;
567      } 
568      G_ENDCATCH;
569      list.append(new GLObject(object->get_symbol(), new_list));
570      continue;
571    }
572    if (token.type==GLToken::CLOSE_PAR) 
573      return;
574    list.append(token.object);
575  }
576}
577
578void 
579GLParser::check_compat(const char *s)
580{
581  int state = 0;
582  while (s && *s && !compat)
583    {
584      switch(state)
585        {
586        case 0:
587          if (*s == '\"')
588            state = '\"';
589          break;
590        case '\"':
591          if (*s == '\"')
592            state = 0;
593          else if (*s == '\\')
594            state = '\\';
595          else if ((unsigned char)(*s)<0x20 || *s==0x7f)
596            compat = true;
597          break;
598        case '\\':
599          if (!strchr("01234567tnrbfva\"\\",*s))
600            compat = true;
601          state = '\"';
602          break;
603        }
604      s += 1;
605    }
606}
607
608void
609GLParser::parse(const char * str)
610{
611   DEBUG_MSG("GLParser::parse(): parsing string contents\n");
612   DEBUG_MAKE_INDENT(3);
613   
614   G_TRY
615   {
616      check_compat(str);
617      parse("toplevel", list, str);
618   } G_CATCH(exc)
619   {
620      if (exc.cmp_cause(ByteStream::EndOfFile))
621        G_RETHROW;
622   } G_ENDCATCH;
623}
624
625void
626GLParser::print(ByteStream & str, int compact)
627{
628   for(GPosition pos=list;pos;++pos)
629      list[pos]->print(str, compact);
630}
631
632GP<GLObject>
633GLParser::get_object(const char * name, bool last)
634{
635   GP<GLObject> object;
636   for(GPosition pos=list;pos;++pos)
637   {
638      GP<GLObject> obj=list[pos];
639      if (obj->get_type()==GLObject::LIST &&
640          obj->get_name()==name)
641      {
642         object=obj;
643         if (!last) break;
644      }
645   }
646   return object;
647}
648
649//***************************************************************************
650//********************************** ANT ************************************
651//***************************************************************************
652
653static const char *zoom_strings[]={
654  "default","page","width","one2one","stretch"};
655static const int zoom_strings_size=sizeof(zoom_strings)/sizeof(const char *);
656
657static const char *mode_strings[]={
658  "default","color","fore","back","bw"};
659static const int mode_strings_size=sizeof(mode_strings)/sizeof(const char *);
660
661static const char *align_strings[]={
662  "default","left","center","right","top","bottom"};
663static const int align_strings_size=sizeof(align_strings)/sizeof(const char *);
664
665#define PNOTE_TAG       "pnote"
666#define BACKGROUND_TAG  "background"
667#define ZOOM_TAG        "zoom"
668#define MODE_TAG        "mode"
669#define ALIGN_TAG       "align"
670#define HALIGN_TAG      "halign"
671#define VALIGN_TAG      "valign"
672#define METADATA_TAG    "metadata"
673
674static const unsigned long default_bg_color=0xffffffff;
675
676DjVuANT::DjVuANT(void)
677{
678   bg_color=default_bg_color;
679   zoom=0;
680   mode=MODE_UNSPEC;
681   hor_align=ver_align=ALIGN_UNSPEC;
682}
683
684DjVuANT::~DjVuANT()
685{
686}
687
688GUTF8String
689DjVuANT::get_paramtags(void) const
690{
691  GUTF8String retval;
692  if(zoom > 0)
693  {
694    retval+="<PARAM name=\"" ZOOM_TAG "\" value=\""+GUTF8String(zoom)+="\" />\n";
695  }else if(zoom && ((-zoom)<zoom_strings_size))
696  {
697    retval+="<PARAM name=\"" ZOOM_TAG "\" value=\""+GUTF8String(zoom_strings[-zoom])+"\" />\n";
698  }
699  if((mode>0)&&(mode<mode_strings_size))
700  {
701    retval+="<PARAM name=\"" MODE_TAG "\" value=\""+GUTF8String(mode_strings[mode])+"\" />\n";
702  }
703  if((hor_align>ALIGN_UNSPEC)&&(hor_align<align_strings_size))
704  {
705    retval+="<PARAM name=\"" HALIGN_TAG "\" value=\""+GUTF8String(align_strings[hor_align])+"\" />\n";
706  }
707  if((ver_align>ALIGN_UNSPEC)&&(ver_align<align_strings_size))
708  {
709    retval+="<PARAM name=\"" VALIGN_TAG "\" value=\""+GUTF8String(align_strings[ver_align])+"\" />\n";
710  }
711  if((bg_color&0xffffff) == bg_color)
712  {
713    retval+="<PARAM name=\"" BACKGROUND_TAG "\" value=\""+GUTF8String().format("#%06lX",bg_color)+"\" />\n";
714  }
715  return retval;
716}
717
718void
719DjVuANT::writeParam(ByteStream &str_out) const
720{
721  str_out.writestring(get_paramtags());
722}
723
724GUTF8String
725DjVuANT::get_xmlmap(const GUTF8String &name,const int height) const
726{
727  GUTF8String retval("<MAP name=\""+name.toEscaped()+"\" >\n");
728  for(GPosition pos(map_areas);pos;++pos)
729  {
730    retval+=map_areas[pos]->get_xmltag(height);
731  }
732  return retval+"</MAP>\n";
733}
734
735void
736DjVuANT::writeMap(
737  ByteStream &str_out,const GUTF8String &name,const int height) const
738{
739  str_out.writestring("<MAP name=\""+name.toEscaped()+"\" >\n");
740  for(GPosition pos(map_areas);pos;++pos)
741  {
742    str_out.writestring(GUTF8String(map_areas[pos]->get_xmltag(height)));
743  }
744  str_out.writestring(GUTF8String("</MAP>\n"));
745}
746
747GUTF8String
748DjVuANT::read_raw(ByteStream & str)
749{
750   GUTF8String raw;
751   char buffer[1024];
752   int length;
753   while((length=str.read(buffer, 1024)))
754      raw+=GUTF8String(buffer, length);
755   return raw;
756}
757
758void
759DjVuANT::decode(class GLParser & parser)
760{
761   bg_color=get_bg_color(parser);
762   zoom=get_zoom(parser);
763   mode=get_mode(parser);
764   hor_align=get_hor_align(parser);
765   ver_align=get_ver_align(parser);
766   map_areas=get_map_areas(parser);
767#ifndef NO_METADATA_IN_ANT_CHUNK
768   metadata=get_metadata(parser); 
769#endif
770}
771
772
773void 
774DjVuANT::decode(ByteStream & str)
775{
776   GLParser parser(read_raw(str));
777   decode(parser);
778}
779
780void
781DjVuANT::merge(ByteStream & str)
782{
783   GLParser parser(encode_raw());
784   GUTF8String add_raw=read_raw(str);
785   parser.parse(add_raw);
786   decode(parser);
787}
788
789void
790DjVuANT::encode(ByteStream &bs)
791{
792  GUTF8String raw=encode_raw();
793  bs.writall((const char*) raw, raw.length());
794}
795
796unsigned int 
797DjVuANT::get_memory_usage() const
798{
799  return sizeof(DjVuANT);
800}
801
802unsigned char
803DjVuANT::decode_comp(char ch1, char ch2)
804{
805   unsigned char dig1=0;
806   if (ch1)
807   {
808      ch1=toupper(ch1);
809      if (ch1>='0' && ch1<='9') dig1=ch1-'0';
810      if (ch1>='A' && ch1<='F') dig1=10+ch1-'A';
811     
812      unsigned char dig2=0;
813      if (ch2)
814      {
815         ch2=toupper(ch2);
816         if (ch2>='0' && ch2<='9') dig2=ch2-'0';
817         if (ch2>='A' && ch2<='F') dig2=10+ch2-'A';
818         return (dig1 << 4) | dig2;
819      }
820      return dig1;
821   }
822   return 0;
823}
824
825unsigned long int
826DjVuANT::cvt_color(const char * color, unsigned long int def)
827{
828   if (color[0]!='#') return def;
829
830   unsigned long int color_rgb=0;
831   color++;
832   const char * start, * end;
833   
834      // Do blue
835   end=color+strlen(color); start=end-2;
836   if (start<color) start=color;
837   if (end>start)
838      color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0);
839   
840      // Do green
841   end=color+strlen(color)-2; start=end-2;
842   if (start<color) start=color;
843   if (end>start)
844      color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0) << 8;
845   
846      // Do red
847   end=color+strlen(color)-4; start=end-2;
848   if (start<color) start=color;
849   if (end>start)
850      color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0) << 16;
851
852      // Do the fourth byte
853   end=color+strlen(color)-6; start=end-2;
854   if (start<color) start=color;
855   if (end>start)
856      color_rgb|=decode_comp(start[0], start+1<end ? start[1] : 0) << 24;
857   
858   return color_rgb;
859}
860
861unsigned long int
862DjVuANT::get_bg_color(GLParser & parser)
863{
864  unsigned long retval=default_bg_color;
865  DEBUG_MSG("DjVuANT::get_bg_color(): getting background color ...\n");
866  DEBUG_MAKE_INDENT(3);
867  G_TRY
868  {
869    GP<GLObject> obj=parser.get_object(BACKGROUND_TAG);
870    if (obj && obj->get_list().size()==1)
871    {
872      GUTF8String color=(*obj)[0]->get_symbol();
873      DEBUG_MSG("color='" << color << "'\n");
874      retval=cvt_color(color, 0xffffff);
875    }
876#ifndef NDEBUG
877    if(retval == default_bg_color)
878    {
879      DEBUG_MSG("can't find any.\n");
880    }
881#endif // NDEBUG
882  } G_CATCH_ALL {} G_ENDCATCH;
883#ifndef NDEBUG
884  if(retval == default_bg_color)
885  {
886    DEBUG_MSG("resetting color to 0xffffffff (UNSPEC)\n");
887  }
888#endif // NDEBUG
889  return retval;
890}
891
892int
893DjVuANT::get_zoom(GLParser & parser)
894      // Returns:
895      //   <0 - special zoom (like ZOOM_STRETCH)
896      //   =0 - not set
897      //   >0 - numeric zoom (%%)
898{
899  int retval=ZOOM_UNSPEC;
900  DEBUG_MSG("DjVuANT::get_zoom(): getting zoom factor ...\n");
901  DEBUG_MAKE_INDENT(3);
902  G_TRY
903  {
904    GP<GLObject> obj=parser.get_object(ZOOM_TAG);
905    if (obj && obj->get_list().size()==1)
906    {
907      const GUTF8String zoom((*obj)[0]->get_symbol());
908      DEBUG_MSG("zoom='" << zoom << "'\n");
909     
910      for(int i=0;(i<zoom_strings_size);++i)
911      {
912        if(zoom == zoom_strings[i])
913        {
914          retval=(-i);
915          break;
916        }
917      }
918      if(retval == ZOOM_UNSPEC)
919      {
920        if (zoom[0]!='d')
921        {
922          G_THROW( ERR_MSG("DjVuAnno.bad_zoom") );
923        }else
924        {
925          retval=zoom.substr(1, zoom.length()).toInt(); //atoi((const char *) zoom+1);
926        }
927      }
928    }
929#ifndef NDEBUG
930    if(retval == ZOOM_UNSPEC)
931    {
932      DEBUG_MSG("can't find any.\n");
933    }
934#endif // NDEBUG
935  } G_CATCH_ALL {} G_ENDCATCH;
936#ifndef NDEBUG
937  if(retval == ZOOM_UNSPEC)
938  {
939    DEBUG_MSG("resetting zoom to 0 (UNSPEC)\n");
940  }
941#endif // NDEBUG
942  return retval;
943}
944
945int
946DjVuANT::get_mode(GLParser & parser)
947{
948  int retval=MODE_UNSPEC;
949  DEBUG_MSG("DjVuAnt::get_mode(): getting default mode ...\n");
950  DEBUG_MAKE_INDENT(3);
951  G_TRY
952  {
953    GP<GLObject> obj=parser.get_object(MODE_TAG);
954    if (obj && obj->get_list().size()==1)
955    {
956      const GUTF8String mode((*obj)[0]->get_symbol());
957      DEBUG_MSG("mode='" << mode << "'\n");
958      for(int i=0;(i<mode_strings_size);++i)
959      {
960        if(mode == mode_strings[i])
961        {
962          retval=i;
963          break;
964        }
965      }
966    }
967#ifndef NDEBUG
968    if(retval == MODE_UNSPEC)
969    {
970      DEBUG_MSG("can't find any.\n");
971    }
972#endif // NDEBUG
973  } G_CATCH_ALL {} G_ENDCATCH;
974#ifndef NDEBUG
975  if(retval == MODE_UNSPEC)
976  {
977    DEBUG_MSG("resetting mode to MODE_UNSPEC\n");
978  }
979#endif // NDEBUG
980  return retval;
981}
982
983static inline DjVuANT::alignment
984legal_halign(const int i)
985{
986  DjVuANT::alignment retval;
987  switch((DjVuANT::alignment)i)
988  {
989  case DjVuANT::ALIGN_LEFT:
990  case DjVuANT::ALIGN_CENTER:
991  case DjVuANT::ALIGN_RIGHT:
992    retval=(DjVuANT::alignment)i;
993    break;
994  default:
995    retval=DjVuANT::ALIGN_UNSPEC;
996    break;
997  }
998  return retval;
999}
1000
1001static inline DjVuANT::alignment
1002legal_valign(const int i)
1003{
1004  DjVuANT::alignment retval;
1005  switch((DjVuANT::alignment)i)
1006  {
1007  case DjVuANT::ALIGN_CENTER:
1008  case DjVuANT::ALIGN_TOP:
1009  case DjVuANT::ALIGN_BOTTOM:
1010    retval=(DjVuANT::alignment)i;
1011    break;
1012  default:
1013    retval=DjVuANT::ALIGN_UNSPEC;
1014    break;
1015  }
1016  return retval;
1017}
1018
1019DjVuANT::alignment
1020DjVuANT::get_hor_align(GLParser & parser)
1021{
1022  DEBUG_MSG("DjVuAnt::get_hor_align(): getting hor page alignemnt ...\n");
1023  DEBUG_MAKE_INDENT(3);
1024  alignment retval=ALIGN_UNSPEC;
1025  G_TRY
1026  {
1027    GP<GLObject> obj=parser.get_object(ALIGN_TAG);
1028    if (obj && obj->get_list().size()==2)
1029    {
1030      const GUTF8String align((*obj)[0]->get_symbol());
1031      DEBUG_MSG("hor_align='" << align << "'\n");
1032     
1033      for(int i=(int)ALIGN_UNSPEC;(i<align_strings_size);++i)
1034      {
1035        const alignment j=legal_halign(i);
1036        if((i == (int)j)&&(align == align_strings[i]))
1037        {
1038          retval=j;
1039          break;
1040        }
1041      }
1042    }
1043#ifndef NDEBUG
1044    if(retval == ALIGN_UNSPEC)
1045    {
1046      DEBUG_MSG("can't find any.\n");
1047    }
1048#endif // NDEBUG
1049  } G_CATCH_ALL {} G_ENDCATCH;
1050#ifndef NDEBUG
1051  if(retval == ALIGN_UNSPEC)
1052  {
1053    DEBUG_MSG("resetting alignment to ALIGN_UNSPEC\n");
1054  }
1055#endif // NDEBUG
1056  return retval;
1057}
1058
1059DjVuANT::alignment
1060DjVuANT::get_ver_align(GLParser & parser)
1061{
1062  DEBUG_MSG("DjVuAnt::get_ver_align(): getting vert page alignemnt ...\n");
1063  DEBUG_MAKE_INDENT(3);
1064  alignment retval=ALIGN_UNSPEC;
1065  G_TRY
1066  {
1067    GP<GLObject> obj=parser.get_object(ALIGN_TAG);
1068    if (obj && obj->get_list().size()==2)
1069    {
1070      const GUTF8String align((*obj)[1]->get_symbol());
1071      DEBUG_MSG("ver_align='" << align << "'\n");
1072      for(int i=(int)ALIGN_UNSPEC;(i<align_strings_size);++i)
1073      {
1074        const alignment j=legal_valign(i);
1075        if((i == (int)j)&&(align == align_strings[i]))
1076        {
1077          retval=j;
1078          break;
1079        }
1080      }
1081    }
1082#ifndef NDEBUG
1083    if(retval == ALIGN_UNSPEC)
1084    {
1085      DEBUG_MSG("can't find any.\n");
1086    }
1087#endif // NDEBUG
1088  } G_CATCH_ALL {} G_ENDCATCH;
1089#ifndef NDEBUG
1090  if(retval == ALIGN_UNSPEC)
1091  {
1092    DEBUG_MSG("resetting alignment to ALIGN_UNSPEC\n");
1093  }
1094#endif // NDEBUG
1095  return retval;
1096}
1097
1098#ifndef NO_METADATA_IN_ANT_CHUNK
1099GMap<GUTF8String, GUTF8String>
1100DjVuANT::get_metadata(GLParser & parser)
1101{
1102  DEBUG_MSG("DjVuANT::get_map_areas(): forming and returning back list of map areas\n");
1103  DEBUG_MAKE_INDENT(3);
1104 
1105  GMap<GUTF8String, GUTF8String> mdata;
1106 
1107  GPList<GLObject> list=parser.get_list();
1108  for(GPosition pos=list;pos;++pos)
1109    {
1110      GLObject & obj=*list[pos];
1111      if (obj.get_type()==GLObject::LIST && obj.get_name()==METADATA_TAG) 
1112        { 
1113          G_TRY
1114            {
1115              for(int obj_num=0;obj_num<obj.get_list().size();obj_num++)
1116                {
1117                  GLObject & el=*obj[obj_num];
1118                  const int type = el.get_type();
1119                  if (type == GLObject::LIST)
1120                    { 
1121                      const GUTF8String & name=el.get_name(); 
1122                      mdata[name]=(el[0])->get_string();
1123                    }
1124                }
1125            } 
1126          G_CATCH_ALL { } G_ENDCATCH;
1127        }
1128    }
1129  return mdata;
1130}
1131#endif
1132
1133GPList<GMapArea>
1134DjVuANT::get_map_areas(GLParser & parser)
1135{
1136  DEBUG_MSG("DjVuANT::get_map_areas(): forming and returning back list of map areas\n");
1137  DEBUG_MAKE_INDENT(3);
1138 
1139  GPList<GMapArea> map_areas;
1140 
1141  GPList<GLObject> list=parser.get_list();
1142
1143  for(GPosition pos=list;pos;++pos)
1144  {
1145    GLObject & obj=*list[pos];
1146    const int type=obj.get_type();
1147    if (type == GLObject::LIST)
1148    {
1149      const GUTF8String name=obj.get_name();
1150      if(name == GMapArea::MAPAREA_TAG)
1151      {
1152        G_TRY {
1153               // Getting the url
1154          GUTF8String url;
1155          GUTF8String target=GMapArea::TARGET_SELF;
1156          GLObject & url_obj=*(obj[0]);
1157          if (url_obj.get_type()==GLObject::LIST)
1158          {
1159            if (url_obj.get_name()!=GMapArea::URL_TAG)
1160              G_THROW( ERR_MSG("DjVuAnno.bad_url") );
1161            url=(url_obj[0])->get_string();
1162            target=(url_obj[1])->get_string();
1163          } else url=url_obj.get_string();
1164       
1165               // Getting the comment
1166          GUTF8String comment=(obj[1])->get_string();
1167       
1168          DEBUG_MSG("found maparea '" << comment << "' (" <<
1169            url << ":" << target << ")\n");
1170       
1171          GLObject * shape=obj[2];
1172          GP<GMapArea> map_area;
1173          if (shape->get_type()==GLObject::LIST)
1174          {
1175            if (shape->get_name()==GMapArea::RECT_TAG)
1176            {
1177              DEBUG_MSG("it's a rectangle.\n");
1178              GRect grect((*shape)[0]->get_number(),
1179                          (*shape)[1]->get_number(),
1180                          (*shape)[2]->get_number(),
1181                          (*shape)[3]->get_number());
1182              GP<GMapRect> map_rect=GMapRect::create(grect);
1183              map_area=(GMapRect *)map_rect;
1184            } else if (shape->get_name()==GMapArea::POLY_TAG)
1185            {
1186              DEBUG_MSG("it's a polygon.\n");
1187              int points=shape->get_list().size()/2;
1188              GTArray<int> xx(points-1), yy(points-1);
1189              for(int i=0;i<points;i++)
1190              {
1191                xx[i]=(*shape)[2*i]->get_number();
1192                yy[i]=(*shape)[2*i+1]->get_number();
1193              }
1194              GP<GMapPoly> map_poly=GMapPoly::create(xx,yy,points);
1195              map_area=(GMapPoly *)map_poly;
1196            } else if (shape->get_name()==GMapArea::OVAL_TAG)
1197            {
1198              DEBUG_MSG("it's an ellipse.\n");
1199              GRect grect((*shape)[0]->get_number(),
1200                          (*shape)[1]->get_number(),
1201                          (*shape)[2]->get_number(),
1202                          (*shape)[3]->get_number());
1203              GP<GMapOval> map_oval=GMapOval::create(grect);
1204              map_area=(GMapOval *)map_oval;
1205            }
1206          }
1207       
1208          if (map_area)
1209          {
1210            map_area->url=url;
1211            map_area->target=target;
1212            map_area->comment=comment;
1213            for(int obj_num=3;obj_num<obj.get_list().size();obj_num++)
1214            {
1215              GLObject * el=obj[obj_num];
1216              if (el->get_type()==GLObject::LIST)
1217              {
1218                const GUTF8String & name=el->get_name();
1219                if (name==GMapArea::BORDER_AVIS_TAG)
1220                  map_area->border_always_visible=true;
1221                else if (name==GMapArea::HILITE_TAG)
1222                {
1223                  GLObject * obj=el->get_list()[el->get_list().firstpos()];
1224                  if (obj->get_type()==GLObject::SYMBOL)
1225                    map_area->hilite_color=cvt_color(obj->get_symbol(), 0xff);
1226                } else
1227                {
1228                  int border_type=
1229                    name==GMapArea::NO_BORDER_TAG ? GMapArea::NO_BORDER :
1230                    name==GMapArea::XOR_BORDER_TAG ? GMapArea::XOR_BORDER :
1231                    name==GMapArea::SOLID_BORDER_TAG ? GMapArea::SOLID_BORDER :
1232                    name==GMapArea::SHADOW_IN_BORDER_TAG ? GMapArea::SHADOW_IN_BORDER :
1233                    name==GMapArea::SHADOW_OUT_BORDER_TAG ? GMapArea::SHADOW_OUT_BORDER :
1234                    name==GMapArea::SHADOW_EIN_BORDER_TAG ? GMapArea::SHADOW_EIN_BORDER :
1235                    name==GMapArea::SHADOW_EOUT_BORDER_TAG ? GMapArea::SHADOW_EOUT_BORDER : -1;
1236                  if (border_type>=0)
1237                  {
1238                    map_area->border_type=(GMapArea::BorderType) border_type;
1239                    for(GPosition pos=el->get_list();pos;++pos)
1240                    {
1241                      GLObject * obj=el->get_list()[pos];
1242                      if (obj->get_type()==GLObject::SYMBOL)
1243                        map_area->border_color=cvt_color(obj->get_symbol(), 0xff);
1244                      if (obj->get_type()==GLObject::NUMBER)
1245                        map_area->border_width=obj->get_number();
1246                    }
1247                  }
1248                }           
1249              } // if (el->get_type()==...)
1250            } // for(int obj_num=...)
1251            map_areas.append(map_area);
1252          } // if (map_area) ...
1253        } G_CATCH_ALL {} G_ENDCATCH;
1254      }
1255    }
1256  } // while(item==...)
1257   
1258  DEBUG_MSG("map area list size = " << list.size() << "\n");
1259 
1260  return map_areas;
1261}
1262
1263void
1264DjVuANT::del_all_items(const char * name, GLParser & parser)
1265{
1266   GPList<GLObject> & list=parser.get_list();
1267   GPosition pos=list;
1268   while(pos)
1269   {
1270      GLObject & obj=*list[pos];
1271      if (obj.get_type()==GLObject::LIST &&
1272          obj.get_name()==name)
1273      {
1274         GPosition this_pos=pos;
1275         ++pos;
1276         list.del(this_pos);
1277      } else ++pos;
1278   }
1279}
1280
1281GUTF8String
1282DjVuANT::encode_raw(void) const
1283{
1284   GUTF8String buffer;
1285   GLParser parser;
1286
1287      //*** Background color
1288   del_all_items(BACKGROUND_TAG, parser);
1289   if (bg_color!=default_bg_color)
1290   {
1291      buffer.format("(" BACKGROUND_TAG " #%02X%02X%02X)",
1292              (unsigned int)((bg_color & 0xff0000) >> 16),
1293              (unsigned int)((bg_color & 0xff00) >> 8),
1294              (unsigned int)(bg_color & 0xff));
1295      parser.parse(buffer);
1296   }
1297
1298      //*** Zoom
1299   del_all_items(ZOOM_TAG, parser);
1300   if (zoom>0 || (zoom>=ZOOM_STRETCH && zoom<=ZOOM_PAGE))
1301   {
1302      buffer="(" ZOOM_TAG " ";
1303      if (zoom < 0)
1304        buffer += zoom_strings[-zoom];
1305      else
1306        buffer += "d"+GUTF8String(zoom);
1307      buffer+=")";
1308      parser.parse(buffer);
1309   }
1310
1311      //*** Mode
1312   del_all_items(MODE_TAG, parser);
1313   if (mode!=MODE_UNSPEC)
1314   {
1315      const int i=mode-1;
1316      if((i>=0)&& (i<mode_strings_size))
1317      { 
1318        buffer="(" MODE_TAG " " + GUTF8String(mode_strings[mode]) + ")";
1319      }
1320      parser.parse(buffer);
1321   }
1322
1323      //*** Alignment
1324   del_all_items(ALIGN_TAG, parser);
1325   if (hor_align!=ALIGN_UNSPEC || ver_align!=ALIGN_UNSPEC)
1326   {
1327      buffer= GUTF8String("(" ALIGN_TAG " ")
1328        +align_strings[((hor_align<ALIGN_UNSPEC)||
1329                        (hor_align>=align_strings_size))?ALIGN_UNSPEC:hor_align]
1330        +" "+align_strings[((ver_align<ALIGN_UNSPEC)||
1331                            (ver_align>=align_strings_size))?ALIGN_UNSPEC:ver_align]+")";
1332      parser.parse(buffer);
1333   }
1334      //*** Metadata
1335#ifndef NO_METADATA_IN_ANT_CHUNK
1336   del_all_items(METADATA_TAG, parser);
1337   if (!metadata.isempty())
1338     {
1339       GUTF8String mdatabuffer("(");
1340       mdatabuffer +=  METADATA_TAG ;
1341       for (GPosition pos=metadata; pos; ++pos)
1342         mdatabuffer +=" (" + metadata.key(pos)+" \""+metadata[pos]+"\")";
1343       mdatabuffer += " )";
1344       parser.parse(mdatabuffer);
1345     }
1346#endif   
1347     //*** Mapareas
1348   del_all_items(GMapArea::MAPAREA_TAG, parser);
1349   for(GPosition pos=map_areas;pos;++pos)
1350      parser.parse(map_areas[pos]->print());
1351
1352   GP<ByteStream> gstr=ByteStream::create();
1353   ByteStream &str=*gstr;
1354   parser.print(str, 1);
1355   GUTF8String ans;
1356   int size = str.size();
1357   str.seek(0);
1358   str.read(ans.getbuf(size), size);
1359   return ans;
1360}
1361
1362bool
1363DjVuANT::is_empty(void) const
1364{
1365   GUTF8String raw=encode_raw();
1366   for(int i=raw.length()-1;i>=0;i--)
1367      if (isspace(raw[i])) raw.setat(i, 0);
1368      else break;
1369   return raw.length()==0;
1370}
1371
1372GP<DjVuANT>
1373DjVuANT::copy(void) const
1374{
1375   GP<DjVuANT> ant=new DjVuANT(*this);
1376
1377
1378      // Now process the list of hyperlinks.
1379   ant->map_areas.empty();
1380   for(GPosition pos=map_areas;pos;++pos)
1381      ant->map_areas.append(map_areas[pos]->get_copy());
1382
1383   return ant;
1384}
1385
1386//***************************************************************************
1387//******************************** DjVuAnno *********************************
1388//***************************************************************************
1389
1390GUTF8String
1391DjVuAnno::get_xmlmap(const GUTF8String &name,const int height) const
1392{
1393  return ant
1394    ?(ant->get_xmlmap(name,height))
1395    :("<MAP name=\""+name.toEscaped()+"\"/>\n");
1396}
1397
1398void
1399DjVuAnno::writeMap(ByteStream &str_out,const GUTF8String &name,const int height) const
1400{
1401  if(ant)
1402  {
1403    ant->writeMap(str_out,name,height);
1404  }else
1405  {
1406    str_out.writestring(get_xmlmap(name,height));
1407  }
1408}
1409
1410GUTF8String
1411DjVuAnno::get_paramtags(void) const
1412{
1413  return ant
1414    ?(ant->get_paramtags())
1415    :GUTF8String();
1416}
1417
1418void
1419DjVuAnno::writeParam(ByteStream &str_out) const
1420{
1421  str_out.writestring(get_paramtags());
1422}
1423
1424
1425void
1426DjVuAnno::decode(const GP<ByteStream> &gbs)
1427{
1428  GUTF8String chkid;
1429  GP<IFFByteStream> giff=IFFByteStream::create(gbs);
1430  IFFByteStream &iff=*giff;
1431  while( iff.get_chunk(chkid) )
1432  {
1433    if (chkid == "ANTa")
1434    {
1435      if (ant) {
1436        ant->merge(*iff.get_bytestream());
1437      } else {
1438        ant=DjVuANT::create();
1439        ant->decode(*iff.get_bytestream());
1440      }
1441    }
1442    else if (chkid == "ANTz")
1443    {
1444      GP<ByteStream> gbsiff=BSByteStream::create(giff->get_bytestream());
1445      if (ant) {
1446        ant->merge(*gbsiff);
1447      } else {
1448        ant=DjVuANT::create();
1449        ant->decode(*gbsiff);
1450      }
1451    }
1452    // Add decoding of other chunks here
1453    iff.close_chunk();
1454  }
1455}
1456
1457void
1458DjVuAnno::encode(const GP<ByteStream> &gbs)
1459{
1460  GP<IFFByteStream> giff=IFFByteStream::create(gbs);
1461  IFFByteStream &iff=*giff;
1462  if (ant)
1463    {
1464#if 0
1465      iff.put_chunk("ANTa");
1466      ant->encode(iff);
1467      iff.close_chunk();
1468#else
1469      iff.put_chunk("ANTz");
1470      {
1471//       GP<ByteStream> bsbinput = giff.get_bytestream();
1472         GP<ByteStream> bsb = BSByteStream::create(giff->get_bytestream(), 50);
1473         ant->encode(*bsb);
1474      }
1475      iff.close_chunk();
1476#endif
1477    }
1478  // Add encoding of other chunks here
1479}
1480
1481
1482GP<DjVuAnno>
1483DjVuAnno::copy(void) const
1484{
1485   GP<DjVuAnno> anno= new DjVuAnno;
1486      // Copy any primitives (if any)
1487   *anno=*this;
1488      // Copy each substructure
1489   if (ant) anno->ant = ant->copy();
1490   return anno;
1491}
1492
1493void
1494DjVuAnno::merge(const GP<DjVuAnno> & anno)
1495{
1496   if (anno)
1497   {
1498      GP<ByteStream> gstr=ByteStream::create();
1499      encode(gstr);
1500      anno->encode(gstr);
1501      gstr->seek(0);
1502      decode(gstr);
1503   }
1504}
1505
1506
1507#ifdef HAVE_NAMESPACES
1508}
1509# ifndef NOT_USING_DJVU_NAMESPACE
1510using namespace DJVU;
1511# endif
1512#endif
Note: See TracBrowser for help on using the repository browser.