Blame libdjvu/XMLParser.cpp

Packit df99a1
//C-  -*- C++ -*-
Packit df99a1
//C- -------------------------------------------------------------------
Packit df99a1
//C- DjVuLibre-3.5
Packit df99a1
//C- Copyright (c) 2002  Leon Bottou and Yann Le Cun.
Packit df99a1
//C- Copyright (c) 2001  AT&T
Packit df99a1
//C-
Packit df99a1
//C- This software is subject to, and may be distributed under, the
Packit df99a1
//C- GNU General Public License, either Version 2 of the license,
Packit df99a1
//C- or (at your option) any later version. The license should have
Packit df99a1
//C- accompanied the software or you may obtain a copy of the license
Packit df99a1
//C- from the Free Software Foundation at http://www.fsf.org .
Packit df99a1
//C-
Packit df99a1
//C- This program is distributed in the hope that it will be useful,
Packit df99a1
//C- but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit df99a1
//C- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit df99a1
//C- GNU General Public License for more details.
Packit df99a1
//C- 
Packit df99a1
//C- DjVuLibre-3.5 is derived from the DjVu(r) Reference Library from
Packit df99a1
//C- Lizardtech Software.  Lizardtech Software has authorized us to
Packit df99a1
//C- replace the original DjVu(r) Reference Library notice by the following
Packit df99a1
//C- text (see doc/lizard2002.djvu and doc/lizardtech2007.djvu):
Packit df99a1
//C-
Packit df99a1
//C-  ------------------------------------------------------------------
Packit df99a1
//C- | DjVu (r) Reference Library (v. 3.5)
Packit df99a1
//C- | Copyright (c) 1999-2001 LizardTech, Inc. All Rights Reserved.
Packit df99a1
//C- | The DjVu Reference Library is protected by U.S. Pat. No.
Packit df99a1
//C- | 6,058,214 and patents pending.
Packit df99a1
//C- |
Packit df99a1
//C- | This software is subject to, and may be distributed under, the
Packit df99a1
//C- | GNU General Public License, either Version 2 of the license,
Packit df99a1
//C- | or (at your option) any later version. The license should have
Packit df99a1
//C- | accompanied the software or you may obtain a copy of the license
Packit df99a1
//C- | from the Free Software Foundation at http://www.fsf.org .
Packit df99a1
//C- |
Packit df99a1
//C- | The computer code originally released by LizardTech under this
Packit df99a1
//C- | license and unmodified by other parties is deemed "the LIZARDTECH
Packit df99a1
//C- | ORIGINAL CODE."  Subject to any third party intellectual property
Packit df99a1
//C- | claims, LizardTech grants recipient a worldwide, royalty-free, 
Packit df99a1
//C- | non-exclusive license to make, use, sell, or otherwise dispose of 
Packit df99a1
//C- | the LIZARDTECH ORIGINAL CODE or of programs derived from the 
Packit df99a1
//C- | LIZARDTECH ORIGINAL CODE in compliance with the terms of the GNU 
Packit df99a1
//C- | General Public License.   This grant only confers the right to 
Packit df99a1
//C- | infringe patent claims underlying the LIZARDTECH ORIGINAL CODE to 
Packit df99a1
//C- | the extent such infringement is reasonably necessary to enable 
Packit df99a1
//C- | recipient to make, have made, practice, sell, or otherwise dispose 
Packit df99a1
//C- | of the LIZARDTECH ORIGINAL CODE (or portions thereof) and not to 
Packit df99a1
//C- | any greater extent that may be necessary to utilize further 
Packit df99a1
//C- | modifications or combinations.
Packit df99a1
//C- |
Packit df99a1
//C- | The LIZARDTECH ORIGINAL CODE is provided "AS IS" WITHOUT WARRANTY
Packit df99a1
//C- | OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
Packit df99a1
//C- | TO ANY WARRANTY OF NON-INFRINGEMENT, OR ANY IMPLIED WARRANTY OF
Packit df99a1
//C- | MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
Packit df99a1
//C- +------------------------------------------------------------------
Packit df99a1
Packit df99a1
#ifdef HAVE_CONFIG_H
Packit df99a1
# include "config.h"
Packit df99a1
#endif
Packit df99a1
#if NEED_GNUG_PRAGMAS
Packit df99a1
# pragma implementation
Packit df99a1
#endif
Packit df99a1
Packit df99a1
// From: Leon Bottou, 1/31/2002
Packit df99a1
// This is purely Lizardtech stuff.
Packit df99a1
Packit df99a1
#include "XMLParser.h"
Packit df99a1
#include "XMLTags.h"
Packit df99a1
#include "ByteStream.h"
Packit df99a1
#include "GOS.h"
Packit df99a1
#include "DjVuDocument.h"
Packit df99a1
#include "DjVuText.h"
Packit df99a1
#include "DjVuAnno.h"
Packit df99a1
#include "DjVuFile.h"
Packit df99a1
#include "DjVuImage.h"
Packit df99a1
#include "debug.h"
Packit df99a1
#include <stdio.h>
Packit df99a1
#include <ctype.h>
Packit df99a1
#include <stddef.h>
Packit df99a1
#include <stdlib.h>
Packit df99a1
Packit df99a1
Packit df99a1
#ifdef HAVE_NAMESPACES
Packit df99a1
namespace DJVU {
Packit df99a1
# ifdef NOT_DEFINED // Just to fool emacs c++ mode
Packit df99a1
}
Packit df99a1
#endif
Packit df99a1
#endif
Packit df99a1
Packit df99a1
static const char mimetype[]="image/x.djvu";
Packit df99a1
static const char bodytag[]="BODY";
Packit df99a1
static const char areatag[]="AREA";
Packit df99a1
static const char maptag[]="MAP";
Packit df99a1
static const char objecttag[]="OBJECT";
Packit df99a1
static const char paramtag[]="PARAM";
Packit df99a1
static const char charactertag[]="CHARACTER";
Packit df99a1
static const char wordtag[]="WORD";
Packit df99a1
static const char linetag[]="LINE";
Packit df99a1
static const char paragraphtag[]="PARAGRAPH";
Packit df99a1
static const char regiontag[]="REGION";
Packit df99a1
static const char pagecolumntag[]="PAGECOLUMN";
Packit df99a1
static const char hiddentexttag[]="HIDDENTEXT";
Packit df99a1
static const char metadatatag[]="METADATA";
Packit df99a1
Packit df99a1
class lt_XMLParser::Impl : public lt_XMLParser
Packit df99a1
{
Packit df99a1
public:
Packit df99a1
  Impl(void);
Packit df99a1
  virtual ~Impl();
Packit df99a1
  /// Parse the specified bytestream.
Packit df99a1
  virtual void parse(const GP<ByteStream> &bs, GURL *pdjvufile);
Packit df99a1
  /// Parse the specified tags - this one does all the work
Packit df99a1
  virtual void parse(const lt_XMLTags &tags, GURL *pdjvufile);
Packit df99a1
  /// write to disk.
Packit df99a1
  virtual void save(void);
Packit df99a1
  /// erase.
Packit df99a1
  virtual void empty(void);
Packit df99a1
protected:
Packit df99a1
  GP<DjVuFile> get_file(const GURL &url,GUTF8String page);
Packit df99a1
Packit df99a1
  void parse_anno(const int width, const int height,
Packit df99a1
    const lt_XMLTags &GObject,
Packit df99a1
    GMap<GUTF8String,GP<lt_XMLTags> > &Maps, DjVuFile &dfile);
Packit df99a1
Packit df99a1
  void parse_text(const int width, const int height,
Packit df99a1
    const lt_XMLTags &GObject, DjVuFile &dfile);
Packit df99a1
Packit df99a1
  void parse_meta(const lt_XMLTags &GObject, DjVuFile &dfile);
Packit df99a1
Packit df99a1
  void ChangeAnno( const int width, const int height,
Packit df99a1
    DjVuFile &dfile, const lt_XMLTags &map);
Packit df99a1
Packit df99a1
  void ChangeInfo(DjVuFile &dfile,const int dpi,const double gamma);
Packit df99a1
Packit df99a1
  void ChangeText( const int width, const int height,
Packit df99a1
    DjVuFile &dfile, const lt_XMLTags &map);
Packit df99a1
Packit df99a1
  void ChangeMeta( DjVuFile &dfile, const lt_XMLTags &map);
Packit df99a1
Packit df99a1
  void ChangeTextOCR( const GUTF8String &value, 
Packit df99a1
    const int width, const int height,
Packit df99a1
    const GP<DjVuFile> &dfile);
Packit df99a1
Packit df99a1
  // we may want to make these list of modified file static so
Packit df99a1
  // they only needed to be loaded and saved once.
Packit df99a1
Packit df99a1
  GMap<GUTF8String,GP<DjVuFile> > m_files;
Packit df99a1
  GMap<GUTF8String,GP<DjVuDocument> > m_docs;
Packit df99a1
Packit df99a1
  GURL m_codebase; 
Packit df99a1
  GCriticalSection xmlparser_lock;
Packit df99a1
};
Packit df99a1
Packit df99a1
static GP<ByteStream>
Packit df99a1
OCRcallback(
Packit df99a1
  void * const xarg,
Packit df99a1
  lt_XMLParser::mapOCRcallback * const xcallback,
Packit df99a1
  const GUTF8String &value=GUTF8String(),
Packit df99a1
  const GP<DjVuImage> &image=0 );
Packit df99a1
Packit df99a1
static inline GP<ByteStream>
Packit df99a1
OCRcallback(const GUTF8String &value, const GP<DjVuImage> &image)
Packit df99a1
{
Packit df99a1
  return OCRcallback(0,0,value,image);
Packit df99a1
}
Packit df99a1
Packit df99a1
lt_XMLParser::lt_XMLParser() {}
Packit df99a1
lt_XMLParser::~lt_XMLParser() {}
Packit df99a1
lt_XMLParser::Impl::Impl() {}
Packit df99a1
lt_XMLParser::Impl::~Impl() {}
Packit df99a1
Packit df99a1
GP<lt_XMLParser>
Packit df99a1
lt_XMLParser::create(void)
Packit df99a1
{
Packit df99a1
  return new lt_XMLParser::Impl;
Packit df99a1
}
Packit df99a1
Packit df99a1
// helper function for args
Packit df99a1
static void 
Packit df99a1
intList(GUTF8String coords, GList<int> &retval)
Packit df99a1
{
Packit df99a1
  int pos=0;
Packit df99a1
  while(coords.length())
Packit df99a1
  {
Packit df99a1
    int epos;
Packit df99a1
    unsigned long i=coords.toLong(pos,epos,10);
Packit df99a1
    if(epos>=0)
Packit df99a1
    {
Packit df99a1
      retval.append(i);
Packit df99a1
      const int n=coords.nextNonSpace(epos);
Packit df99a1
      if(coords[n] != ',')
Packit df99a1
        break;
Packit df99a1
      pos=n+1;
Packit df99a1
    }
Packit df99a1
  }
Packit df99a1
}
Packit df99a1
Packit df99a1
void 
Packit df99a1
lt_XMLParser::Impl::empty(void)
Packit df99a1
{
Packit df99a1
  GCriticalSectionLock lock(&xmlparser_lock);
Packit df99a1
  m_files.empty();
Packit df99a1
  m_docs.empty();
Packit df99a1
}
Packit df99a1
Packit df99a1
void 
Packit df99a1
lt_XMLParser::Impl::save(void)
Packit df99a1
{
Packit df99a1
  GCriticalSectionLock lock(&xmlparser_lock);
Packit df99a1
  for(GPosition pos=m_docs;pos;++pos)
Packit df99a1
  {
Packit df99a1
    const GP<DjVuDocument> doc(m_docs[pos]);
Packit df99a1
    const GURL url=doc->get_init_url();
Packit df99a1
    
Packit df99a1
    DEBUG_MSG("Saving "<<(const char *)url<<" with new text and annotations\n");
Packit df99a1
    const bool bundle=doc->is_bundled()||(doc->get_doc_type()==DjVuDocument::SINGLE_PAGE);
Packit df99a1
    doc->save_as(url,bundle);
Packit df99a1
  }
Packit df99a1
  empty();
Packit df99a1
}
Packit df99a1
Packit df99a1
void
Packit df99a1
lt_XMLParser::Impl::parse(const GP<ByteStream> &bs, GURL *pdjvufile)
Packit df99a1
{
Packit df99a1
  const GP<lt_XMLTags> tags(lt_XMLTags::create(bs));
Packit df99a1
  parse(*tags, pdjvufile);
Packit df99a1
}
Packit df99a1
  
Packit df99a1
static const GMap<GUTF8String,GMapArea::BorderType> &
Packit df99a1
BorderTypeMap(void)
Packit df99a1
{
Packit df99a1
  static GMap<GUTF8String,GMapArea::BorderType> typeMap;
Packit df99a1
  if (! typeMap.size()) 
Packit df99a1
    {
Packit df99a1
      typeMap["none"]=GMapArea::NO_BORDER;
Packit df99a1
      typeMap["xor"]=GMapArea::XOR_BORDER;
Packit df99a1
      typeMap["solid"]=GMapArea::SOLID_BORDER;
Packit df99a1
      typeMap["default"]=GMapArea::SOLID_BORDER;
Packit df99a1
      typeMap["shadowout"]=GMapArea::SHADOW_OUT_BORDER;
Packit df99a1
      typeMap["shadowin"]=GMapArea::SHADOW_IN_BORDER;
Packit df99a1
      typeMap["etchedin"]=GMapArea::SHADOW_EIN_BORDER;
Packit df99a1
      typeMap["etchedout"]=GMapArea::SHADOW_EOUT_BORDER;
Packit df99a1
    }
Packit df99a1
  return typeMap;
Packit df99a1
}
Packit df99a1
Packit df99a1
static unsigned long
Packit df99a1
convertToColor(const GUTF8String &s)
Packit df99a1
{
Packit df99a1
  unsigned long retval=0;
Packit df99a1
  if(s.length())
Packit df99a1
  {
Packit df99a1
    int endpos = -1;
Packit df99a1
    if(s[0] == '#')
Packit df99a1
    {
Packit df99a1
      retval=s.substr(1,-1).toULong(0,endpos,16);
Packit df99a1
    }
Packit df99a1
    if(endpos < 0)
Packit df99a1
    {
Packit df99a1
      G_THROW( (ERR_MSG("XMLAnno.bad_color") "\t")+s );
Packit df99a1
    }
Packit df99a1
  }
Packit df99a1
  return retval;
Packit df99a1
}
Packit df99a1
Packit df99a1
void
Packit df99a1
lt_XMLParser::Impl::ChangeInfo(DjVuFile &dfile,const int dpi,const double gamma)
Packit df99a1
{
Packit df99a1
  GP<DjVuInfo> info;
Packit df99a1
  if(dpi >= 5 && dpi <= 4800)
Packit df99a1
  {
Packit df99a1
    dfile.resume_decode(true);
Packit df99a1
    if(dfile.info && (dpi != dfile.info->dpi) )
Packit df99a1
    {
Packit df99a1
      info=new DjVuInfo(*dfile.info);
Packit df99a1
      info->dpi=dpi;
Packit df99a1
    }
Packit df99a1
  }
Packit df99a1
  if(gamma >= 0.1 && gamma <= 5.0)
Packit df99a1
  {
Packit df99a1
    dfile.resume_decode(true);
Packit df99a1
    if(dfile.info && (gamma != dfile.info->gamma) )
Packit df99a1
    {
Packit df99a1
      if(!info)
Packit df99a1
        info=new DjVuInfo(*dfile.info);
Packit df99a1
      info->gamma=gamma;
Packit df99a1
    }
Packit df99a1
  }
Packit df99a1
  if(info)
Packit df99a1
  {
Packit df99a1
    dfile.change_info(info);
Packit df99a1
  }
Packit df99a1
}
Packit df99a1
Packit df99a1
void
Packit df99a1
lt_XMLParser::Impl::ChangeAnno(
Packit df99a1
  const int width, const int height,
Packit df99a1
  DjVuFile &dfile, 
Packit df99a1
  const lt_XMLTags &map )
Packit df99a1
{
Packit df99a1
  dfile.resume_decode(true);
Packit df99a1
  const GP<DjVuInfo> info(dfile.info);
Packit df99a1
  const GP<DjVuAnno> ganno(DjVuAnno::create());
Packit df99a1
  DjVuAnno &anno=*ganno;
Packit df99a1
  GPosition map_pos;
Packit df99a1
  map_pos=map.contains(areatag);
Packit df99a1
  if(dfile.contains_anno())
Packit df99a1
  {
Packit df99a1
    GP<ByteStream> annobs=dfile.get_merged_anno();
Packit df99a1
    if(annobs)
Packit df99a1
    {
Packit df99a1
      anno.decode(annobs);
Packit df99a1
      if(anno.ant && info)
Packit df99a1
      {
Packit df99a1
        anno.ant->map_areas.empty();
Packit df99a1
      }
Packit df99a1
    }
Packit df99a1
//    dfile.remove_anno();
Packit df99a1
  }
Packit df99a1
  if(info && map_pos)
Packit df99a1
  {
Packit df99a1
    const int h=info->height;
Packit df99a1
    const int w=info->width;
Packit df99a1
    double ws=1.0;
Packit df99a1
    double hs=1.0;
Packit df99a1
    if(width && width != w)
Packit df99a1
    {
Packit df99a1
      ws=((double)w)/((double)width); 
Packit df99a1
    }
Packit df99a1
    if(height && height != h)
Packit df99a1
    {
Packit df99a1
      hs=((double)h)/((double)height); 
Packit df99a1
    }
Packit df99a1
    if(!anno.ant)
Packit df99a1
    {
Packit df99a1
      anno.ant=DjVuANT::create();
Packit df99a1
    }
Packit df99a1
    GPList<GMapArea> &map_areas=anno.ant->map_areas;
Packit df99a1
    map_areas.empty();
Packit df99a1
    GPList<lt_XMLTags> gareas=map[map_pos];
Packit df99a1
    for(GPosition pos=gareas;pos;++pos)
Packit df99a1
    {
Packit df99a1
      if(gareas[pos])
Packit df99a1
      {
Packit df99a1
        lt_XMLTags &areas=*(gareas[pos]);
Packit df99a1
        GMap<GUTF8String,GUTF8String> args(areas.get_args());
Packit df99a1
        GList<int> coords;
Packit df99a1
        // ******************************************************
Packit df99a1
        // Parse the coords attribute:  first read the raw data into
Packit df99a1
        // a list, then scale the x, y data into another list.  For
Packit df99a1
        // circles, you also get a radius element with (looks like an x
Packit df99a1
        // with no matching y).
Packit df99a1
        // ******************************************************
Packit df99a1
        {
Packit df99a1
          GPosition coords_pos=args.contains("coords");
Packit df99a1
          if(coords_pos)
Packit df99a1
          {
Packit df99a1
            GList<int> raw_coords;
Packit df99a1
            intList(args[coords_pos],raw_coords);
Packit df99a1
            for(GPosition raw_pos=raw_coords;raw_pos;++raw_pos)
Packit df99a1
            {
Packit df99a1
              const int r=raw_coords[raw_pos];
Packit df99a1
              const int x=(int)(ws*(double)r+0.5);
Packit df99a1
              coords.append(x);
Packit df99a1
              int y=h-1;
Packit df99a1
              if(! ++raw_pos)
Packit df99a1
              {
Packit df99a1
                y-=(int)(hs*(double)r+0.5);
Packit df99a1
              }else
Packit df99a1
              {
Packit df99a1
                y-=(int)(hs*(double)raw_coords[raw_pos]+0.5);
Packit df99a1
              }
Packit df99a1
              coords.append(y);
Packit df99a1
//            DjVuPrintMessage("Coords (%d,%d)\n",x,y);
Packit df99a1
            }
Packit df99a1
          }
Packit df99a1
        }
Packit df99a1
        GUTF8String shape;
Packit df99a1
        {
Packit df99a1
          GPosition shape_pos=args.contains("shape");
Packit df99a1
          if(shape_pos)
Packit df99a1
          {
Packit df99a1
            shape=args[shape_pos];
Packit df99a1
          }
Packit df99a1
        }
Packit df99a1
        GP<GMapArea> a;
Packit df99a1
        if(shape == "default")
Packit df99a1
        {
Packit df99a1
          GRect rect(0,0,w,h);
Packit df99a1
          a=GMapRect::create(rect);
Packit df99a1
        }else if(!shape.length() || shape == "rect")
Packit df99a1
        {
Packit df99a1
          int xx[4];
Packit df99a1
          int i=0;
Packit df99a1
          for(GPosition rect_pos=coords;(rect_pos)&&(i<4);++rect_pos,++i)
Packit df99a1
          {
Packit df99a1
            xx[i]=coords[rect_pos];
Packit df99a1
          }
Packit df99a1
          if(i!=4)
Packit df99a1
          {
Packit df99a1
            G_THROW( ERR_MSG("XMLAnno.bad_rect") );
Packit df99a1
          }
Packit df99a1
          int xmin,xmax; 
Packit df99a1
          if(xx[0]>xx[2])
Packit df99a1
          {
Packit df99a1
            xmax=xx[0];
Packit df99a1
            xmin=xx[2];
Packit df99a1
          }else
Packit df99a1
          {
Packit df99a1
            xmin=xx[0];
Packit df99a1
            xmax=xx[2];
Packit df99a1
          }
Packit df99a1
          int ymin,ymax; 
Packit df99a1
          if(xx[1]>xx[3])
Packit df99a1
          {
Packit df99a1
            ymax=xx[1];
Packit df99a1
            ymin=xx[3];
Packit df99a1
          }else
Packit df99a1
          {
Packit df99a1
            ymin=xx[1];
Packit df99a1
            ymax=xx[3];
Packit df99a1
          }
Packit df99a1
          GRect rect(xmin,ymin,xmax-xmin,ymax-ymin);
Packit df99a1
          a=GMapRect::create(rect);
Packit df99a1
        }else if(shape == "circle")
Packit df99a1
        {
Packit df99a1
          int xx[4];
Packit df99a1
          int i=0;
Packit df99a1
          GPosition rect_pos=coords.lastpos();
Packit df99a1
          if(rect_pos)
Packit df99a1
          {
Packit df99a1
            coords.append(coords[rect_pos]);
Packit df99a1
            for(rect_pos=coords;(rect_pos)&&(i<4);++rect_pos)
Packit df99a1
            {
Packit df99a1
              xx[i++]=coords[rect_pos];
Packit df99a1
            }
Packit df99a1
          }
Packit df99a1
          if(i!=4)
Packit df99a1
          {
Packit df99a1
            G_THROW( ERR_MSG("XMLAnno.bad_circle") );
Packit df99a1
          }
Packit df99a1
          int x=xx[0],y=xx[1],rx=xx[2],ry=(h-xx[3])-1;
Packit df99a1
          GRect rect(x-rx,y-ry,2*rx,2*ry);
Packit df99a1
          a=GMapOval::create(rect);
Packit df99a1
        }else if(shape == "oval")
Packit df99a1
        {
Packit df99a1
          int xx[4];
Packit df99a1
          int i=0;
Packit df99a1
          for(GPosition rect_pos=coords;(rect_pos)&&(i<4);++rect_pos,++i)
Packit df99a1
          {
Packit df99a1
            xx[i]=coords[rect_pos];
Packit df99a1
          }
Packit df99a1
          if(i!=4)
Packit df99a1
          {
Packit df99a1
            G_THROW( ERR_MSG("XMLAnno.bad_oval") );
Packit df99a1
          }
Packit df99a1
          int xmin,xmax; 
Packit df99a1
          if(xx[0]>xx[2])
Packit df99a1
          {
Packit df99a1
            xmax=xx[0];
Packit df99a1
            xmin=xx[2];
Packit df99a1
          }else
Packit df99a1
          {
Packit df99a1
            xmin=xx[0];
Packit df99a1
            xmax=xx[2];
Packit df99a1
          }
Packit df99a1
          int ymin,ymax; 
Packit df99a1
          if(xx[1]>xx[3])
Packit df99a1
          {
Packit df99a1
            ymax=xx[1];
Packit df99a1
            ymin=xx[3];
Packit df99a1
          }else
Packit df99a1
          {
Packit df99a1
            ymin=xx[1];
Packit df99a1
            ymax=xx[3];
Packit df99a1
          }
Packit df99a1
          GRect rect(xmin,ymin,xmax-xmin,ymax-ymin);
Packit df99a1
          a=GMapOval::create(rect);
Packit df99a1
        }else if(shape == "poly")
Packit df99a1
        {
Packit df99a1
          GP<GMapPoly> p=GMapPoly::create();
Packit df99a1
          for(GPosition poly_pos=coords;poly_pos;++poly_pos)
Packit df99a1
          {
Packit df99a1
            int x=coords[poly_pos];
Packit df99a1
            if(! ++poly_pos)
Packit df99a1
              break;
Packit df99a1
            int y=coords[poly_pos];
Packit df99a1
            p->add_vertex(x,y);
Packit df99a1
          }
Packit df99a1
          p->close_poly();
Packit df99a1
          a=p;
Packit df99a1
        }else
Packit df99a1
        {
Packit df99a1
          G_THROW( ( ERR_MSG("XMLAnno.unknown_shape") "\t")+shape );
Packit df99a1
        }
Packit df99a1
        if(a)
Packit df99a1
        {
Packit df99a1
          GPosition pos;
Packit df99a1
          if((pos=args.contains("href")))
Packit df99a1
          {
Packit df99a1
            a->url=args[pos];
Packit df99a1
          }
Packit df99a1
          if((pos=args.contains("target")))
Packit df99a1
          {
Packit df99a1
            a->target=args[pos];
Packit df99a1
          }
Packit df99a1
          if((pos=args.contains("alt")))
Packit df99a1
          {
Packit df99a1
            a->comment=args[pos];
Packit df99a1
          }
Packit df99a1
          if((pos=args.contains("bordertype")))
Packit df99a1
          {
Packit df99a1
            GUTF8String b=args[pos];
Packit df99a1
            static const GMap<GUTF8String,GMapArea::BorderType> typeMap=BorderTypeMap();
Packit df99a1
            if((pos=typeMap.contains(b)))
Packit df99a1
            {
Packit df99a1
              a->border_type=typeMap[pos];
Packit df99a1
            }else
Packit df99a1
            {
Packit df99a1
              G_THROW( (ERR_MSG("XMLAnno.unknown_border") "\t")+b );
Packit df99a1
            }
Packit df99a1
          }
Packit df99a1
          a->border_always_visible=!!args.contains("visible");
Packit df99a1
          if((pos=args.contains("bordercolor")))
Packit df99a1
          {
Packit df99a1
            a->border_color=convertToColor(args[pos]);
Packit df99a1
          }
Packit df99a1
          if((pos=args.contains("highlight")))
Packit df99a1
          {
Packit df99a1
            a->hilite_color=convertToColor(args[pos]);
Packit df99a1
          }
Packit df99a1
          if((pos=args.contains("border")))
Packit df99a1
          {
Packit df99a1
             a->border_width=args[pos].toInt(); //atoi(args[pos]);
Packit df99a1
          }
Packit df99a1
          map_areas.append(a);
Packit df99a1
        }
Packit df99a1
      }
Packit df99a1
    }
Packit df99a1
  }
Packit df99a1
  dfile.set_modified(true);
Packit df99a1
  dfile.anno=ByteStream::create();
Packit df99a1
  anno.encode(dfile.anno);
Packit df99a1
}
Packit df99a1
Packit df99a1
GP<DjVuFile>
Packit df99a1
lt_XMLParser::Impl::get_file(const GURL &url,GUTF8String id)
Packit df99a1
{
Packit df99a1
  GP<DjVuFile> dfile;
Packit df99a1
  GP<DjVuDocument> doc;
Packit df99a1
  GCriticalSectionLock lock(&xmlparser_lock);
Packit df99a1
  {
Packit df99a1
    GPosition pos=m_docs.contains(url.get_string());
Packit df99a1
    if(pos)
Packit df99a1
    {
Packit df99a1
      doc=m_docs[pos];
Packit df99a1
    }else
Packit df99a1
    {
Packit df99a1
      doc=DjVuDocument::create_wait(url);
Packit df99a1
      if(! doc->wait_for_complete_init())
Packit df99a1
      {
Packit df99a1
        G_THROW(( ERR_MSG("XMLAnno.fail_init") "\t")+url.get_string() );
Packit df99a1
      }
Packit df99a1
      m_docs[url.get_string()]=doc;
Packit df99a1
    }
Packit df99a1
    if(id.is_int())
Packit df99a1
    {
Packit df99a1
      const int xpage=id.toInt(); //atoi((char const *)page); 
Packit df99a1
      if(xpage>0)
Packit df99a1
        id=doc->page_to_id(xpage-1);
Packit df99a1
    }else if(!id.length())
Packit df99a1
    { 
Packit df99a1
      id=doc->page_to_id(0);
Packit df99a1
    }
Packit df99a1
  }
Packit df99a1
  const GURL fileurl(doc->id_to_url(id));
Packit df99a1
  GPosition dpos(m_files.contains(fileurl.get_string()));
Packit df99a1
  if(!dpos)
Packit df99a1
  {
Packit df99a1
    if(!doc->get_id_list().contains(id))
Packit df99a1
    {
Packit df99a1
      G_THROW( ERR_MSG("XMLAnno.bad_page") );
Packit df99a1
    }
Packit df99a1
    dfile=doc->get_djvu_file(id,false);
Packit df99a1
    if(!dfile)
Packit df99a1
    {
Packit df99a1
      G_THROW( ERR_MSG("XMLAnno.bad_page") );
Packit df99a1
    }
Packit df99a1
    m_files[fileurl.get_string()]=dfile;
Packit df99a1
  }else
Packit df99a1
  {
Packit df99a1
    dfile=m_files[dpos];
Packit df99a1
  }
Packit df99a1
  return dfile;
Packit df99a1
}
Packit df99a1
  
Packit df99a1
void
Packit df99a1
lt_XMLParser::Impl::parse(const lt_XMLTags &tags, GURL *pdjvufile)
Packit df99a1
{
Packit df99a1
  const GPList<lt_XMLTags> Body(tags.get_Tags(bodytag));
Packit df99a1
  GPosition pos=Body;
Packit df99a1
 
Packit df99a1
  if(!pos || (pos != Body.lastpos()))
Packit df99a1
  {
Packit df99a1
    G_THROW( ERR_MSG("XMLAnno.extra_body") );
Packit df99a1
  }
Packit df99a1
  const GP<lt_XMLTags> GBody(Body[pos]);
Packit df99a1
  if(!GBody)
Packit df99a1
  {
Packit df99a1
    G_THROW( ERR_MSG("XMLAnno.no_body") );
Packit df99a1
  }
Packit df99a1
Packit df99a1
  GMap<GUTF8String,GP<lt_XMLTags> > Maps;
Packit df99a1
  lt_XMLTags::get_Maps(maptag,"name",Body,Maps);
Packit df99a1
Packit df99a1
  const GPList<lt_XMLTags> Objects(GBody->get_Tags(objecttag));
Packit df99a1
  lt_XMLTags::get_Maps(maptag,"name",Objects,Maps);
Packit df99a1
Packit df99a1
  for(GPosition Objpos=Objects;Objpos;++Objpos)
Packit df99a1
  {
Packit df99a1
    lt_XMLTags &GObject=*Objects[Objpos];
Packit df99a1
    // Map of attributes to value (e.g. "width" --> "500")
Packit df99a1
    const GMap<GUTF8String,GUTF8String> &args=GObject.get_args();
Packit df99a1
    GURL codebase;
Packit df99a1
    {
Packit df99a1
      DEBUG_MSG("Setting up codebase... m_codebase = " << m_codebase << "\n");
Packit df99a1
      GPosition codebasePos=args.contains("codebase");
Packit df99a1
      // If user specified a codebase attribute, assume it is correct (absolute URL):
Packit df99a1
      //  the GURL constructor will throw an exception if it isn't
Packit df99a1
      if(codebasePos)
Packit df99a1
      {
Packit df99a1
        codebase=GURL::UTF8(args[codebasePos]);
Packit df99a1
      }else if (m_codebase.is_dir())
Packit df99a1
      {
Packit df99a1
        codebase=m_codebase;
Packit df99a1
      }else
Packit df99a1
      {
Packit df99a1
        codebase=GURL::Filename::UTF8(GOS::cwd());
Packit df99a1
      }
Packit df99a1
      DEBUG_MSG("codebase = " << codebase << "\n");
Packit df99a1
    }
Packit df99a1
    // the data attribute specifies the input file.  This can be
Packit df99a1
    //  either an absolute URL (starts with file:/) or a relative
Packit df99a1
    //  URL (for now, just a path and file name).  If it's absolute,
Packit df99a1
    //  our GURL will adequately wrap it.  If it's relative, we need
Packit df99a1
    //  to use the codebase attribute to form an absolute URL first.
Packit df99a1
    GPosition datapos=args.contains("data");
Packit df99a1
    if(datapos)
Packit df99a1
    {
Packit df99a1
      GPosition typePos(args.contains("type"));
Packit df99a1
      if(typePos)
Packit df99a1
        {
Packit df99a1
          if(args[typePos] != mimetype)
Packit df99a1
          continue;
Packit df99a1
        }
Packit df99a1
      const GURL url = (pdjvufile) ? *pdjvufile 
Packit df99a1
        : GURL::UTF8(args[datapos], 
Packit df99a1
                     (args[datapos][0] == '/') ? codebase.base() : codebase);
Packit df99a1
      int width;
Packit df99a1
      {
Packit df99a1
        GPosition widthPos=args.contains("width");
Packit df99a1
        width=(widthPos)?args[widthPos].toInt():0;
Packit df99a1
      }
Packit df99a1
      int height;
Packit df99a1
      {
Packit df99a1
        GPosition heightPos=args.contains("height");
Packit df99a1
        height=(heightPos)?args[heightPos].toInt():0;
Packit df99a1
      }
Packit df99a1
      GUTF8String gamma;
Packit df99a1
      GUTF8String dpi;
Packit df99a1
      GUTF8String page;
Packit df99a1
      GUTF8String do_ocr;
Packit df99a1
      {
Packit df99a1
        GPosition paramPos(GObject.contains(paramtag));
Packit df99a1
        if(paramPos)
Packit df99a1
        {
Packit df99a1
          const GPList<lt_XMLTags> Params(GObject[paramPos]);
Packit df99a1
          for(GPosition loc=Params;loc;++loc)
Packit df99a1
          {
Packit df99a1
            const GMap<GUTF8String,GUTF8String> &pargs=Params[loc]->get_args();
Packit df99a1
            GPosition namepos=pargs.contains("name");
Packit df99a1
            if(namepos)
Packit df99a1
            {
Packit df99a1
              GPosition valuepos=pargs.contains("value");
Packit df99a1
              if(valuepos)
Packit df99a1
              {
Packit df99a1
                const GUTF8String name=pargs[namepos].downcase();
Packit df99a1
                const GUTF8String &value=pargs[valuepos];
Packit df99a1
                if(name == "flags")
Packit df99a1
                {
Packit df99a1
                  GMap<GUTF8String,GUTF8String> args;
Packit df99a1
                  lt_XMLTags::ParseValues(value,args,true);
Packit df99a1
                  if(args.contains("page"))
Packit df99a1
                  {
Packit df99a1
                    page=args["page"];
Packit df99a1
                  }
Packit df99a1
                  if(args.contains("dpi"))
Packit df99a1
                  {
Packit df99a1
                    dpi=args["dpi"];
Packit df99a1
                  }
Packit df99a1
                  if(args.contains("gamma"))
Packit df99a1
                  {
Packit df99a1
                    gamma=args["gamma"];
Packit df99a1
                  }
Packit df99a1
                  if(args.contains("ocr"))
Packit df99a1
                  {
Packit df99a1
                    do_ocr=args["ocr"];
Packit df99a1
                  }
Packit df99a1
                }else if(name == "page")
Packit df99a1
                {
Packit df99a1
                  page=value;
Packit df99a1
                }else if(name == "dpi")
Packit df99a1
                {
Packit df99a1
                  dpi=value;
Packit df99a1
                }else if(name == "gamma")
Packit df99a1
                {
Packit df99a1
                  gamma=value;
Packit df99a1
                }else if(name == "ocr")
Packit df99a1
                {
Packit df99a1
                  do_ocr=value;
Packit df99a1
                }
Packit df99a1
              }
Packit df99a1
            }
Packit df99a1
          }
Packit df99a1
        }
Packit df99a1
      }
Packit df99a1
      const GP<DjVuFile> dfile(get_file(url,page));
Packit df99a1
      if(dpi.is_int() || gamma.is_float())
Packit df99a1
      {
Packit df99a1
        int pos=0;
Packit df99a1
        ChangeInfo(*dfile,dpi.toInt(),gamma.toDouble(pos,pos));
Packit df99a1
      }
Packit df99a1
      parse_anno(width,height,GObject,Maps,*dfile);
Packit df99a1
      parse_meta(GObject,*dfile);
Packit df99a1
      parse_text(width,height,GObject,*dfile);
Packit df99a1
      ChangeTextOCR(do_ocr,width,height,dfile);
Packit df99a1
    }
Packit df99a1
  }
Packit df99a1
}
Packit df99a1
Packit df99a1
void
Packit df99a1
lt_XMLParser::Impl::parse_anno(
Packit df99a1
  const int width,
Packit df99a1
  const int height,
Packit df99a1
  const lt_XMLTags &GObject,
Packit df99a1
  GMap<GUTF8String,GP<lt_XMLTags> > &Maps,
Packit df99a1
  DjVuFile &dfile )
Packit df99a1
{
Packit df99a1
  GP<lt_XMLTags> map;
Packit df99a1
  {
Packit df99a1
    GPosition usemappos=GObject.get_args().contains("usemap");
Packit df99a1
    if(usemappos)
Packit df99a1
    {
Packit df99a1
      const GUTF8String mapname(GObject.get_args()[usemappos]);
Packit df99a1
      GPosition mappos=Maps.contains(mapname);
Packit df99a1
      if(!mappos)
Packit df99a1
      {
Packit df99a1
        G_THROW((ERR_MSG("XMLAnno.map_find") "\t")+mapname );
Packit df99a1
      }else
Packit df99a1
      {
Packit df99a1
        map=Maps[mappos];
Packit df99a1
      }
Packit df99a1
    }
Packit df99a1
  }
Packit df99a1
  if(map)
Packit df99a1
  {
Packit df99a1
    ChangeAnno(width,height,dfile,*map);
Packit df99a1
  }
Packit df99a1
}
Packit df99a1
Packit df99a1
#ifdef max
Packit df99a1
#undef max
Packit df99a1
#endif
Packit df99a1
template<class TYPE>
Packit df99a1
static inline TYPE max(TYPE a,TYPE b) { return (a>b)?a:b; }
Packit df99a1
#ifdef min
Packit df99a1
#undef min
Packit df99a1
#endif
Packit df99a1
template<class TYPE>
Packit df99a1
static inline TYPE min(TYPE a,TYPE b) { return (a
Packit df99a1
Packit df99a1
// used to build the zone tree
Packit df99a1
// true is returned if the GRect is known for this object,
Packit df99a1
// and false, if the rectangle's size is just the parent size.
Packit df99a1
static bool
Packit df99a1
make_child_layer(
Packit df99a1
  DjVuTXT::Zone &parent,
Packit df99a1
  const lt_XMLTags &tag, ByteStream &bs,
Packit df99a1
  const int height, const double ws, const double hs)
Packit df99a1
{
Packit df99a1
  bool retval=true;
Packit df99a1
  // the plugin thinks there are only Pages, Lines and Words
Packit df99a1
  // so we don't make Paragraphs, Regions and Columns zones
Packit df99a1
  // if we did the plugin is not able to search the text but 
Packit df99a1
  // DjVuToText writes out all the text anyway
Packit df99a1
  DjVuTXT::Zone *self_ptr;
Packit df99a1
  char sepchar;
Packit df99a1
  const GUTF8String name(tag.get_name());
Packit df99a1
  if(name == charactertag)
Packit df99a1
  {
Packit df99a1
    self_ptr=parent.append_child();
Packit df99a1
    self_ptr->ztype = DjVuTXT::CHARACTER;
Packit df99a1
    sepchar=0;  
Packit df99a1
  }else if(name == wordtag)
Packit df99a1
  {
Packit df99a1
    self_ptr=parent.append_child();
Packit df99a1
    self_ptr->ztype = DjVuTXT::WORD;
Packit df99a1
    sepchar=' ';
Packit df99a1
  }else if(name == linetag)
Packit df99a1
  {
Packit df99a1
    self_ptr=parent.append_child();
Packit df99a1
    self_ptr->ztype = DjVuTXT::LINE;
Packit df99a1
    sepchar=DjVuTXT::end_of_line;
Packit df99a1
  }else if(name == paragraphtag)
Packit df99a1
  {
Packit df99a1
    self_ptr=parent.append_child();
Packit df99a1
    self_ptr->ztype = DjVuTXT::PARAGRAPH;
Packit df99a1
    sepchar=DjVuTXT::end_of_paragraph;
Packit df99a1
  }else if(name == regiontag)
Packit df99a1
  {
Packit df99a1
    self_ptr=parent.append_child();
Packit df99a1
    self_ptr->ztype = DjVuTXT::REGION;
Packit df99a1
    sepchar=DjVuTXT::end_of_region;
Packit df99a1
  }else if(name == pagecolumntag)
Packit df99a1
  {
Packit df99a1
    self_ptr=parent.append_child();
Packit df99a1
    self_ptr->ztype = DjVuTXT::COLUMN;
Packit df99a1
    sepchar=DjVuTXT::end_of_column;
Packit df99a1
  }else
Packit df99a1
  {
Packit df99a1
    self_ptr = &parent;
Packit df99a1
    self_ptr->ztype = DjVuTXT::PAGE;
Packit df99a1
    sepchar=0;
Packit df99a1
  }
Packit df99a1
  DjVuTXT::Zone &self = *self_ptr;
Packit df99a1
  self.text_start = bs.tell();
Packit df99a1
  int &xmin=self.rect.xmin, &ymin=self.rect.ymin, 
Packit df99a1
    &xmax=self.rect.xmax, &ymax=self.rect.ymax;
Packit df99a1
  GRect default_rect;
Packit df99a1
  default_rect.xmin=max(parent.rect.xmax,parent.rect.xmin);
Packit df99a1
  default_rect.xmax=min(parent.rect.xmax,parent.rect.xmin);
Packit df99a1
  default_rect.ymin=max(parent.rect.ymax,parent.rect.ymin);
Packit df99a1
  default_rect.ymax=min(parent.rect.ymax,parent.rect.ymin);
Packit df99a1
  // Now if there are coordinates, use those.
Packit df99a1
  GPosition pos(tag.get_args().contains("coords"));
Packit df99a1
  if(pos)
Packit df99a1
  {
Packit df99a1
    GList<int> rectArgs;
Packit df99a1
    intList(tag.get_args()[pos], rectArgs);
Packit df99a1
    if((pos=rectArgs))
Packit df99a1
    {
Packit df99a1
      xmin=(int)(ws*(double)rectArgs[pos]);
Packit df99a1
      if(++pos)
Packit df99a1
      {
Packit df99a1
        ymin=(height-1)-(int)(hs*(double)rectArgs[pos]);
Packit df99a1
        if(++pos)
Packit df99a1
        {
Packit df99a1
          xmax=(int)(ws*(double)rectArgs[pos]);
Packit df99a1
          if(++pos)
Packit df99a1
          {
Packit df99a1
            ymax=(height-1)-(int)(hs*(double)rectArgs[pos]);
Packit df99a1
            if(xmin>xmax) // Make sure xmin is really minimum
Packit df99a1
            {
Packit df99a1
              const int t=xmin;
Packit df99a1
              xmin=xmax;
Packit df99a1
              xmax=t;
Packit df99a1
            }
Packit df99a1
            if(ymin>ymax) // Make sure ymin is really minimum
Packit df99a1
            {
Packit df99a1
              const int t=ymin;
Packit df99a1
              ymin=ymax;
Packit df99a1
              ymax=t;
Packit df99a1
            }
Packit df99a1
          }
Packit df99a1
        }
Packit df99a1
      }
Packit df99a1
    }
Packit df99a1
  }
Packit df99a1
  if(self.ztype == DjVuTXT::CHARACTER)
Packit df99a1
  {
Packit df99a1
    if(! pos)
Packit df99a1
    {
Packit df99a1
      self.rect=default_rect;
Packit df99a1
      retval=false;
Packit df99a1
    }
Packit df99a1
    const GUTF8String raw(tag.get_raw().fromEscaped());
Packit df99a1
    const int i=raw.nextNonSpace(0);
Packit df99a1
    bs.writestring(raw.substr(i,raw.firstEndSpace(i)-i));
Packit df99a1
    if(sepchar)
Packit df99a1
      bs.write8(sepchar);
Packit df99a1
    self.text_length = bs.tell() - self.text_start;
Packit df99a1
  }else if(pos)
Packit df99a1
  {
Packit df99a1
    pos=tag.get_content();
Packit df99a1
    if(pos)
Packit df99a1
    {
Packit df99a1
      for(pos=tag.get_content(); pos; ++pos)
Packit df99a1
      {
Packit df99a1
        const GP<lt_XMLTags> t(tag.get_content()[pos].tag);
Packit df99a1
        make_child_layer(self, *t, bs, height,ws,hs);
Packit df99a1
      }
Packit df99a1
      if(sepchar)
Packit df99a1
        bs.write8(sepchar);
Packit df99a1
      self.text_length = bs.tell() - self.text_start;
Packit df99a1
    }else
Packit df99a1
    {
Packit df99a1
      const GUTF8String raw(tag.get_raw().fromEscaped());
Packit df99a1
      const int i=raw.nextNonSpace(0);
Packit df99a1
      bs.writestring(raw.substr(i,raw.firstEndSpace(i)-i));
Packit df99a1
      if(sepchar)
Packit df99a1
        bs.write8(sepchar);
Packit df99a1
      self.text_length = bs.tell() - self.text_start;
Packit df99a1
    }
Packit df99a1
  }else
Packit df99a1
  {
Packit df99a1
    self.rect=default_rect;
Packit df99a1
    if((pos=tag.get_content()))
Packit df99a1
    {
Packit df99a1
      do
Packit df99a1
      {
Packit df99a1
        const GP<lt_XMLTags> t(tag.get_content()[pos].tag);
Packit df99a1
        const GRect save_rect(self.rect);
Packit df99a1
        self.rect=default_rect;
Packit df99a1
	if ((retval = make_child_layer(self, *t, bs, height, ws, hs)))
Packit df99a1
        {
Packit df99a1
          xmin=min(save_rect.xmin,xmin);
Packit df99a1
          xmax=max(save_rect.xmax,xmax);
Packit df99a1
          ymin=min(save_rect.ymin,ymin);
Packit df99a1
          ymax=max(save_rect.ymax,ymax);
Packit df99a1
        }else
Packit df99a1
        {
Packit df99a1
          // If the child doesn't have coordinates, we need to use a box
Packit df99a1
          // at least as big as the parent's coordinates.
Packit df99a1
          xmin=min(save_rect.xmin,default_rect.xmax);
Packit df99a1
          xmax=max(save_rect.xmax,default_rect.xmin);
Packit df99a1
          ymin=min(save_rect.ymin,default_rect.ymax);
Packit df99a1
          ymax=max(save_rect.ymax,default_rect.ymin);
Packit df99a1
          for(; pos; ++pos)
Packit df99a1
          {
Packit df99a1
            const GP<lt_XMLTags> t(tag.get_content()[pos].tag);
Packit df99a1
            make_child_layer(self, *t, bs, height,ws,hs);
Packit df99a1
          }
Packit df99a1
          break;
Packit df99a1
        }
Packit df99a1
      } while(++pos);
Packit df99a1
      if(sepchar)
Packit df99a1
        bs.write8(sepchar);
Packit df99a1
      self.text_length = bs.tell() - self.text_start;
Packit df99a1
    }else
Packit df99a1
    {
Packit df99a1
      const GUTF8String raw(tag.get_raw().fromEscaped());
Packit df99a1
      const int i=raw.nextNonSpace(0);
Packit df99a1
      bs.writestring(raw.substr(i,raw.firstEndSpace(i)-i));
Packit df99a1
      if(sepchar)
Packit df99a1
        bs.write8(sepchar);
Packit df99a1
      self.text_length = bs.tell() - self.text_start;
Packit df99a1
    }
Packit df99a1
  }
Packit df99a1
  parent.rect.xmin=min(xmin,parent.rect.xmin);
Packit df99a1
  parent.rect.ymin=min(ymin,parent.rect.ymin);
Packit df99a1
  parent.rect.xmax=max(xmax,parent.rect.xmax);
Packit df99a1
  parent.rect.ymax=max(ymax,parent.rect.ymax);
Packit df99a1
  if(xmin>xmax)
Packit df99a1
  {
Packit df99a1
    const int t=xmin;
Packit df99a1
    xmin=xmax;
Packit df99a1
    xmax=t;
Packit df99a1
  }
Packit df99a1
  if(ymin>ymax)
Packit df99a1
  {
Packit df99a1
    const int t=ymin;
Packit df99a1
    ymin=ymax;
Packit df99a1
    ymax=t;
Packit df99a1
  }
Packit df99a1
//  DjVuPrintMessage("(%d,%d)(%d,%d)<<<\\%o>>>\n",
Packit df99a1
//    xmin,ymin,xmax,ymax, sepchar);
Packit df99a1
  return retval;
Packit df99a1
}
Packit df99a1
Packit df99a1
void 
Packit df99a1
lt_XMLParser::Impl::ChangeTextOCR(
Packit df99a1
  const GUTF8String &value,
Packit df99a1
  const int width,
Packit df99a1
  const int height,
Packit df99a1
  const GP<DjVuFile> &dfile)
Packit df99a1
{
Packit df99a1
  if(value.length() && value.downcase() != "false")
Packit df99a1
  {
Packit df99a1
    const GP<ByteStream> bs=OCRcallback(value,DjVuImage::create(dfile));
Packit df99a1
    if( bs && bs->size() )
Packit df99a1
    {
Packit df99a1
      const GP<lt_XMLTags> tags(lt_XMLTags::create(bs));
Packit df99a1
      ChangeText(width,height,*dfile,*tags);
Packit df99a1
    }
Packit df99a1
  }
Packit df99a1
}
Packit df99a1
Packit df99a1
void 
Packit df99a1
lt_XMLParser::Impl::ChangeMeta(
Packit df99a1
  DjVuFile &dfile, const lt_XMLTags &tags )
Packit df99a1
{
Packit df99a1
  dfile.resume_decode(true);
Packit df99a1
  GP<ByteStream> gbs(ByteStream::create());
Packit df99a1
  tags.write(*gbs,false);
Packit df99a1
  gbs->seek(0L);
Packit df99a1
  GUTF8String raw(gbs->getAsUTF8());
Packit df99a1
  if(raw.length())
Packit df99a1
  {
Packit df99a1
     //GUTF8String gs="<"+(metadatatag+(">"+raw))+"</"+metadatatag+">\n");
Packit df99a1
    dfile.change_meta(raw+"\n");
Packit df99a1
  }else
Packit df99a1
  {
Packit df99a1
    dfile.change_meta(GUTF8String());
Packit df99a1
  }
Packit df99a1
}
Packit df99a1
Packit df99a1
void 
Packit df99a1
lt_XMLParser::Impl::ChangeText(
Packit df99a1
  const int width, const int height,
Packit df99a1
  DjVuFile &dfile, const lt_XMLTags &tags )
Packit df99a1
{
Packit df99a1
  dfile.resume_decode(true);
Packit df99a1
  
Packit df99a1
  GP<DjVuText> text = DjVuText::create();
Packit df99a1
  GP<DjVuTXT> txt = text->txt = DjVuTXT::create();
Packit df99a1
  
Packit df99a1
  // to store the new text
Packit df99a1
  GP<ByteStream> textbs = ByteStream::create(); 
Packit df99a1
  
Packit df99a1
  GP<DjVuInfo> info=(dfile.info);
Packit df99a1
  if(info)
Packit df99a1
  {
Packit df99a1
    const int h=info->height;
Packit df99a1
    const int w=info->width;
Packit df99a1
    txt->page_zone.text_start = 0;
Packit df99a1
    DjVuTXT::Zone &parent=txt->page_zone;
Packit df99a1
    parent.rect.xmin=0;
Packit df99a1
    parent.rect.ymin=0;
Packit df99a1
    parent.rect.ymax=h;
Packit df99a1
    parent.rect.xmax=w;
Packit df99a1
    double ws=1.0;
Packit df99a1
    if(width && width != w)
Packit df99a1
    {
Packit df99a1
      ws=((double)w)/((double)width);
Packit df99a1
    }
Packit df99a1
    double hs=1.0;
Packit df99a1
    if(height && height != h)
Packit df99a1
    {
Packit df99a1
      hs=((double)h)/((double)height);
Packit df99a1
    }
Packit df99a1
    make_child_layer(parent, tags, *textbs, h, ws,hs);
Packit df99a1
    textbs->write8(0);
Packit df99a1
    long len = textbs->tell();
Packit df99a1
    txt->page_zone.text_length = len;
Packit df99a1
    textbs->seek(0,SEEK_SET);
Packit df99a1
    textbs->read(txt->textUTF8.getbuf(len), len);
Packit df99a1
  
Packit df99a1
    dfile.change_text(txt,false);
Packit df99a1
  }
Packit df99a1
}
Packit df99a1
Packit df99a1
void
Packit df99a1
lt_XMLParser::Impl::parse_text(
Packit df99a1
  const int width,
Packit df99a1
  const int height,
Packit df99a1
  const lt_XMLTags &GObject,
Packit df99a1
  DjVuFile &dfile )
Packit df99a1
{
Packit df99a1
  GPosition textPos = GObject.contains(hiddentexttag);
Packit df99a1
  if(textPos)
Packit df99a1
  {
Packit df99a1
    // loop through the hidden text - there should only be one 
Packit df99a1
    // if there are more ??only the last one will be saved??
Packit df99a1
    GPList<lt_XMLTags> textTags = GObject[textPos];
Packit df99a1
    GPosition pos = textTags;
Packit df99a1
    ChangeText(width,height,dfile,*textTags[pos]);
Packit df99a1
  }
Packit df99a1
}
Packit df99a1
Packit df99a1
void
Packit df99a1
lt_XMLParser::Impl::parse_meta(
Packit df99a1
  const lt_XMLTags &GObject,
Packit df99a1
  DjVuFile &dfile )
Packit df99a1
{
Packit df99a1
  GPosition metaPos = GObject.contains(metadatatag);
Packit df99a1
  if(metaPos)
Packit df99a1
  {
Packit df99a1
    // loop through the hidden text - there should only be one 
Packit df99a1
    // if there are more ??only the last one will be saved??
Packit df99a1
    GPList<lt_XMLTags> metaTags = GObject[metaPos];
Packit df99a1
    GPosition pos = metaTags;
Packit df99a1
    ChangeMeta(dfile,*metaTags[pos]);
Packit df99a1
  }
Packit df99a1
}
Packit df99a1
Packit df99a1
static GP<ByteStream>
Packit df99a1
OCRcallback(
Packit df99a1
  void * const xarg,
Packit df99a1
  lt_XMLParser::mapOCRcallback * const xcallback,
Packit df99a1
  const GUTF8String &value,
Packit df99a1
  const GP<DjVuImage> &image )
Packit df99a1
{
Packit df99a1
  GP<ByteStream> retval;
Packit df99a1
  static void *arg=0;
Packit df99a1
  static lt_XMLParser::mapOCRcallback *callback=0;
Packit df99a1
  if(image)
Packit df99a1
  {
Packit df99a1
    if(callback)
Packit df99a1
      retval=callback(arg,value,image);
Packit df99a1
  }else
Packit df99a1
  {
Packit df99a1
    arg=xarg;
Packit df99a1
    callback=xcallback;
Packit df99a1
  }
Packit df99a1
  return retval;
Packit df99a1
}
Packit df99a1
Packit df99a1
void
Packit df99a1
lt_XMLParser::setOCRcallback(
Packit df99a1
  void * const arg,
Packit df99a1
  mapOCRcallback * const callback)
Packit df99a1
{
Packit df99a1
  ::OCRcallback(arg,callback);
Packit df99a1
}
Packit df99a1
Packit df99a1
Packit df99a1
#ifdef HAVE_NAMESPACES
Packit df99a1
}
Packit df99a1
# ifndef NOT_USING_DJVU_NAMESPACE
Packit df99a1
using namespace DJVU;
Packit df99a1
# endif
Packit df99a1
#endif