source: trunk/libdjvu/DjVuAnno.cpp @ 15

Last change on this file since 15 was 15, checked in by Eugene Romanenko, 15 years ago

needed libs update

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