XMLParser.cpp
上传用户:hmc_gdtv
上传日期:2013-08-04
资源大小:798k
文件大小:46k
源码类别:

Windows Mobile

开发平台:

Visual C++

  1. /*
  2.  * Copyright (c) 2001,2002,2003 Mike Matsnev.  All Rights Reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions
  6.  * are met:
  7.  *
  8.  * 1. Redistributions of source code must retain the above copyright
  9.  *    notice immediately at the beginning of the file, without modification,
  10.  *    this list of conditions, and the following disclaimer.
  11.  * 2. Redistributions in binary form must reproduce the above copyright
  12.  *    notice, this list of conditions and the following disclaimer in the
  13.  *    documentation and/or other materials provided with the distribution.
  14.  * 3. Absolutely no warranty of function or purpose is made by the author
  15.  *    Mike Matsnev.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  * 
  28.  * $Id: XMLParser.cpp,v 1.106.2.12 2004/10/13 13:50:55 mike Exp $
  29.  * 
  30.  */
  31. #include <afxwin.h>
  32. #include <afxtempl.h>
  33. #include <setjmp.h>
  34. #include "FastArray.h"
  35. #include "TextParser.h"
  36. #include "XMLParser.h"
  37. #include "TextViewNG.h"
  38. #include "Unicode.h"
  39. #include "StrBuf.h"
  40. #include "WMap.h"
  41. #include "Image.h"
  42. #include "xscanf.h"
  43. #include "expat.h"
  44. #define FB_NS   L"http://www.gribuser.ru/xml/fictionbook/2.0"
  45. #define FB_NS_LEN (sizeof(FB_NS)/sizeof(wchar_t)-1)
  46. #define XLINK_NS  L"http://www.w3.org/1999/xlink"
  47. #define HR_STYLE  L"text/css"
  48. enum {
  49.   CDATA=0x1000000,
  50.   LEADSP=0x2000000,
  51.   LOCAL=0x4000000,
  52.   REALLYLOCAL = 0x8000000,
  53.   TRAILSP = 0x10000000,
  54.   // PE flags
  55.   PE_IMAGE=0x80000000,
  56. };
  57. enum { MAX_CONTENTS_LEN=80 };
  58. enum {
  59.   ERR_NOTFB2=1
  60. };
  61. struct CFMT {
  62.   Attr   attr;
  63.   int   lindent;
  64.   int   rindent;
  65.   int   findent;
  66.   BYTE   flags;
  67. };
  68. struct CachedImage {
  69.   CachedImage       *next;
  70.   HBITMAP       hBmp;
  71.   int       width;
  72.   int       height;
  73.   int       maxwidth;
  74.   int       maxheight;
  75.   int       rotation;
  76.   const wchar_t     *name;
  77.   CachedImage() : hBmp(NULL), name(NULL), next(NULL) { }
  78.   void       Release() { if (hBmp) DeleteObject(hBmp); name=NULL; hBmp=NULL; }
  79. };
  80. class ImageCache {
  81.   CachedImage       *m_head,*m_tail;
  82.   int       m_count;
  83.   int       m_max;
  84. public:
  85.   ImageCache(int max=4) : m_head(NULL), m_tail(NULL), m_count(0), m_max(max) { }
  86.   ~ImageCache() { RemoveAll(); }
  87.   CachedImage       *Lookup(const wchar_t *name,bool& alloc);
  88.   void       Remove(CachedImage *img);
  89.   void       RemoveAll() {
  90.     while (m_head) {
  91.       CachedImage *next=m_head->next;
  92.       m_head->Release();
  93.       delete m_head;
  94.       m_head=next;
  95.     }
  96.     m_count=0;
  97.     m_head=m_tail=NULL;
  98.   }
  99. };
  100. CachedImage   *ImageCache::Lookup(const wchar_t *name,bool& alloc) {
  101.   CachedImage *img;
  102.   alloc=false;
  103.   for (img=m_head;img;img=img->next)
  104.     if (!wcscmp(name,img->name))
  105.       return img;
  106.   alloc=true;
  107.   // not found, try to allocate new
  108.   if (m_count<m_max) {
  109.     img=new CachedImage;
  110.     ++m_count;
  111.     img->name=name;
  112.     if (m_tail) {
  113.       m_tail->next=img;
  114.       m_tail=img;
  115.     } else
  116.       m_head=m_tail=img;
  117.     return img;
  118.   }
  119.   // too many entries, reuse head
  120.   ASSERT(m_head!=NULL);
  121.   img=m_head;
  122.   if (m_head!=m_tail)
  123.     m_head=m_head->next;
  124.   img->Release();
  125.   img->name=name;
  126.   img->next=NULL;
  127.   if (img!=m_tail)
  128.     m_tail->next=img;
  129.   m_tail=img;
  130.   return img;
  131. }
  132. void  ImageCache::Remove(CachedImage *img) {
  133.   img->Release();
  134.   if (img==m_head) {
  135.     m_head=m_head->next;
  136.     if (img==m_tail)
  137.       m_tail=NULL;
  138.   } else { // tough, will have to traverse the list
  139.     CachedImage *tmp=NULL;
  140.     for (tmp=m_head;tmp;tmp=tmp->next)
  141.       if (tmp->next==img)
  142. break;
  143.     tmp->next=img->next;
  144.     if (img==m_tail)
  145.       m_tail=tmp;
  146.   }
  147.   delete img;
  148.   --m_count;
  149. }
  150. class XMLParserImp: public XMLParser {
  151. public:
  152.   struct SP_State {
  153.     enum {
  154.       START,
  155.       NAME,
  156.       FLAGS,
  157.       FM,LM,RM,SIZE,COLOR
  158.     };
  159.     wchar_t stylename[128];
  160.     int stylenameptr;
  161.     ElemFmt format;
  162.     int state;
  163.     int num;
  164.     bool sign;
  165.     void Init() { stylenameptr=0; format.Clear(); state=START; }
  166.     void NAdd(wchar_t ch) {
  167.       if (stylenameptr<sizeof(stylename)/sizeof(wchar_t)-1)
  168. stylename[stylenameptr++]=ch;
  169.     }
  170.   };
  171.   struct ParseState {
  172.     enum { MAX_NEST=64 };
  173.     int len; // current len
  174.     int start;
  175.     DWORD attr;
  176.     Attr last_frag_fmt;
  177.     bool last_frag_trailsp;
  178.     bool root_element;
  179.     CFMT cfmt;
  180.     CFMT attr_stack[MAX_NEST];
  181.     int attr_stack_ptr;
  182.     int acch_lev,in_stylesheet;
  183.     int enable;
  184.     int section_nest;
  185.     int title_start;
  186.     int link_start;
  187.     const wchar_t *link_name;
  188.     int pf_start,pl_start,numfrags;
  189.     int binary;
  190.     FmtArray *styles;
  191.     WMap *stylemap;
  192.     jmp_buf jout;
  193.     void PushA() {
  194.       if (attr_stack_ptr<MAX_NEST)
  195. attr_stack[attr_stack_ptr++]=cfmt;
  196.     }
  197.     void PopA() {
  198.       if (attr_stack_ptr>0)
  199. cfmt=attr_stack[--attr_stack_ptr];
  200.     }
  201.     DWORD Att() { return attr|cfmt.attr.wa; }
  202.     void  ApplyFmt(ElemFmt *e,int nest=0);
  203.   };
  204.   struct Frag {    // smallest element - character data
  205.     union {
  206.       DWORD     fpos;    // offset into the file
  207.       const wchar_t *str;    // pointer to a cached value
  208.       wchar_t     local[2]; // cached right here
  209.     };
  210.     DWORD   len;    // raw char count
  211.     DWORD   attr;   // attributes of this run
  212.   };
  213.   struct PE { // paragraph
  214.     enum {
  215.       FRAGBITS=10,
  216.       MAXFRAGS=1<<FRAGBITS,
  217.       FRAGSHIFT=32-FRAGBITS,
  218.       IDXMASK=(1<<FRAGSHIFT)-1
  219.     };
  220.     union {
  221.       DWORD   idx_nf; // offset into m_frags
  222.       const wchar_t   *name; // on an image name
  223.     };
  224.     int   start; // start of parsed paragraph
  225.     DWORD   linkidx_nl; // offset into m_links
  226.     DWORD   indent; // left, right and first line indentation
  227.     DWORD   flags;
  228.     DWORD   nfrags() { return idx_nf>>FRAGSHIFT; }
  229.     DWORD   idx() { return idx_nf&IDXMASK; }
  230.     DWORD   nlinks() { return linkidx_nl>>FRAGSHIFT; }
  231.     DWORD   lidx() { return linkidx_nl&IDXMASK; }
  232.     DWORD   li() { return (indent>>10)&0x2ff; }
  233.     DWORD   ri() { return indent&0x2ff; }
  234.     DWORD   fi() { return (indent>>20)&0x2ff; }
  235.     void   setidx_nf(DWORD idx,DWORD nf) { idx_nf=(idx&IDXMASK)|(nf<<FRAGSHIFT); }
  236.     void   setidx_nl(DWORD idx,DWORD nf) { linkidx_nl=(idx&IDXMASK)|(nf<<FRAGSHIFT); }
  237.     void   setindent(DWORD l,DWORD r,DWORD f) { indent=((f&0x2ff)<<20)|((l&0x2ff)<<10)|(r&0x2ff); }
  238.     void   Zero() { memset(this,0,sizeof(*this)); }
  239.   };
  240.   struct Document { // subdocument
  241.     int     start; // start paragraph
  242.     int     length; // length in paragraphs
  243.     CString name;
  244.   };
  245.   struct Link {
  246.     int   start;
  247.     int   length;
  248.     const wchar_t *target;
  249.   };
  250.   struct Binary {
  251.     wchar_t       *id;
  252.     wchar_t       *type;
  253.     int       numfrags;
  254.     int       startfrag;
  255.   };
  256.   friend class Base64BinReader;
  257.   FastArray<Frag> m_frags;
  258.   FastArray<PE> m_pp;
  259.   FastArray<Link> m_links;
  260.   FastArray<Binary> m_binarystorage;
  261.   FastArray<const wchar_t *> m_inline_images;
  262.   StrBuf m_buffer;
  263.   XML_Parser m_parser;
  264.   CArray<Document,Document&> m_docs;
  265.   WMap m_references;
  266.   WMap m_binaries;
  267.   ParseState *m_ps;
  268.   SP_State *m_sps;
  269.   CString m_cover;
  270.   ImageCache m_imcache;
  271.   Paragraph GetParagraphImp(int idx);
  272.   // paragraphs
  273.   virtual Paragraph GetParagraph(int docid,int para);
  274.   virtual int Length(int docid); // in paragraphs
  275.   virtual int GetPLength(int docid,int para);
  276.   virtual int GetPStart(int docid,int para);
  277.   virtual int GetTotalLength(int docid);
  278.   virtual int LookupParagraph(int docid,int charpos);
  279.   // documents
  280.   virtual int GetSubDocCount() { return m_docs.GetSize(); }
  281.   virtual CString GetSubDocName(int docid);
  282.   // links
  283.   virtual bool LookupReference(const wchar_t *name,FilePos& dest);
  284.   // images
  285.   virtual bool GetImage(const wchar_t *name,HDC hDC,int maxwidth,
  286.     int maxheight,int rotation,Image& img);
  287.   virtual void InvalidateImageCache() { m_imcache.RemoveAll(); }
  288.   // construction and destruction
  289. XMLParserImp(Meter *m,CBufFile *fp,Bookmarks *bmk,
  290.      HANDLE heap);
  291.   virtual ~XMLParserImp();
  292.   virtual bool ParseFile(int encoding);
  293.   // paragraphs
  294.   void AddP(int pstart,int lstart,int start,int len,CFMT& fmt);
  295.   void AddImage(const wchar_t *href,int start,CFMT& fmt);
  296.   void AddQ(int start);
  297.   void AddToc(FilePos pos,int level);
  298.   void PushWS(); // check for leading spaces/format flags
  299.   // stylesheet
  300.   void ParseStylesheet(const wchar_t *text,int len);
  301.   // callbacks
  302.   void StartElement(const wchar_t *name,const wchar_t **attr);
  303.   void EndElement(const wchar_t *name);
  304.   void CharData(const wchar_t *text,int len);
  305.   // expat callacks
  306.   static void StartElementCB(void *udata,const wchar_t *name,
  307.        const wchar_t **attr);
  308.   static void EndElementCB(void *udata,const wchar_t *name);
  309.   static void CharDataCB(void *udata,const wchar_t *text,int len);
  310.   static int UnknownEncodingCB(void *data,const wchar_t *name,
  311.   XML_Encoding *info);
  312.   static void StartCDataCB(void *udata);
  313.   static void EndCDataCB(void *udata);
  314.   // binary access
  315.   ImageLoader::BinReader *OpenBinary(const wchar_t *name,const wchar_t **type,
  316.     const wchar_t **vname);
  317. };
  318. const TCHAR   *XMLParser::ElemFmt::flag_names=_T("apofestcdlqxrivbgh");
  319. XMLParserImp::XMLParserImp(Meter *m,CBufFile *fp,Bookmarks *bmk,HANDLE heap) :
  320.   XMLParser(m,fp,heap,bmk), m_parser(NULL), m_pp(heap), m_frags(heap),
  321.   m_links(heap), m_buffer(heap), m_references(heap), m_binaries(heap),
  322.   m_binarystorage(heap), m_inline_images(heap)
  323. {
  324. }
  325. XMLParserImp::~XMLParserImp() {
  326.   // destroy parser, if any
  327.   if (m_parser)
  328.     XML_ParserFree((XML_Parser)m_parser);
  329.   // destroy image cache if any
  330. }
  331. int   XMLParserImp::Length(int docid) {
  332.   return docid<0 || docid>=m_docs.GetSize() ? 0 : m_docs[docid].length;
  333. }
  334. #define   SHY 0xAD
  335. Paragraph XMLParserImp::GetParagraph(int docid,int para) {
  336.   if (docid<0 || docid>=m_docs.GetSize() ||
  337.       para<0 || para>=m_docs[docid].length)
  338.     return Paragraph();
  339.   return GetParagraphImp(m_docs[docid].start+para);
  340. }
  341. CString XMLParserImp::GetSubDocName(int docid) {
  342.   if (docid<0 || docid>=m_docs.GetSize())
  343.     return CString();
  344.   if (docid==0 && m_docs[docid].name.GetLength()==0)
  345.     return _T("Main");
  346.   return m_docs[docid].name;
  347. }
  348. static int  RClamp(int v,int min,int max) {
  349.   if (v<min)
  350.     return min;
  351.   if (v>max)
  352.     return max;
  353.   return v;
  354. }
  355. Paragraph XMLParserImp::GetParagraphImp(int idx) {
  356.   if (m_pp[idx].flags&PE_IMAGE) { // a very special case
  357.     Paragraph p(ImageLoader::IMAGE_VSIZE);
  358.     p.flags=(BYTE)m_pp[idx].flags;
  359.     p.lindent=m_pp[idx].li();
  360.     p.rindent=m_pp[idx].ri();
  361.     p.findent=m_pp[idx].fi();
  362.     for (int i=0;i<ImageLoader::IMAGE_VSIZE;++i) {
  363.       p.str[i]=L' ';
  364.       p.cflags[i].wa=0;
  365.     }
  366.     // abuse links for image href
  367.     p.links=Buffer<Paragraph::Link>(1);
  368.     p.links[0].off=0;
  369.     p.links[0].len=ImageLoader::IMAGE_VSIZE;
  370.     p.links[0].target=m_pp[idx].name;
  371.     p.flags|=Paragraph::image;
  372.     return p;
  373.   }
  374.   // here we have to read the paragraphs from file
  375.   int       len=m_pp[idx+1].start-m_pp[idx].start,np=m_pp[idx].nfrags();
  376.   int       fragbase=m_pp[idx].idx();
  377.   Paragraph   p(len);
  378.   p.flags=(BYTE)m_pp[idx].flags;
  379.   p.lindent=m_pp[idx].li();
  380.   p.rindent=m_pp[idx].ri();
  381.   p.findent=m_pp[idx].fi();
  382.   // check for inline images
  383.   int ilinks=0;
  384.   for (int ii=0;ii<np;++ii)
  385.     if (m_frags[ii+fragbase].attr & PE_IMAGE)
  386.       ++ilinks;
  387.   // add links if any
  388.   int nlinks=m_pp[idx].nlinks();
  389.   if (nlinks+ilinks) {
  390.     int       off=m_pp[idx].lidx();
  391.     Buffer<Paragraph::Link>   links(nlinks+ilinks);
  392.     for (int link=0;link<nlinks;++link) {
  393.       links[link].off=m_links[off+link].start;
  394.       links[link].len=m_links[off+link].length;
  395.       links[link].target=m_links[off+link].target;
  396.     }
  397.     p.links=links;
  398.   }
  399.   ilinks=0;
  400.   // add character data
  401.   wchar_t     *bp=p.str;
  402.   wchar_t     *be=bp+len;
  403.   wchar_t     *bs=bp;
  404.   Attr       *ap=p.cflags;
  405.   for (int f=0;f<np && bp<be;++f) {
  406.     Frag    *fp=&m_frags[f+fragbase];
  407.     // add a space if needed
  408.     if (fp->attr&LEADSP) {
  409.       *bp++=' ';
  410.       (*ap++).wa=(WORD)fp->attr;
  411.     }
  412.     if (fp->attr&PE_IMAGE) { // inline image
  413.       int     globidx=fp->local[0] | ((unsigned int)fp->local[1]<<16);
  414.       p.links[nlinks+ilinks].off=p.links[nlinks+ilinks].len=0;
  415.       p.links[nlinks+ilinks].target=m_inline_images[globidx];
  416.       if (bp<be) {
  417. *bp++=nlinks+ilinks;
  418. (*ap++).wa=(WORD)fp->attr;
  419.       }
  420.       ++ilinks;
  421.     } else if (fp->attr&(LOCAL|REALLYLOCAL)) { // cached value
  422.       const wchar_t   *wp=fp->attr & REALLYLOCAL ? fp->local : fp->str;
  423.       const wchar_t   *we=wp+fp->len;
  424.       while (bp<be && wp<we) {
  425. *bp++=*wp++;
  426. (*ap++).wa=(WORD)fp->attr;
  427.       }
  428.     } else {
  429.       Buffer<char>    buf(fp->len);
  430.       m_fp->seek(fp->fpos);
  431.       if (m_fp->read(buf,fp->len)!=(int)fp->len) {
  432. ASSERT(0);
  433. break;
  434.       }
  435.       Buffer<wchar_t> wbuf(fp->len);
  436.       char     *cp=buf;
  437.       int ul;
  438.       if (fp->attr&CDATA)
  439. ul=XML_ConvertCharacterData((XML_Parser)m_parser,&cp,fp->len,wbuf,fp->len);
  440.       else
  441. ul=XML_ParseCharacterData((XML_Parser)m_parser,&cp,fp->len,wbuf,fp->len);
  442.       if (ul<0) // xml parser returned an error
  443. break;
  444.       wchar_t     *wp=wbuf,*we=wbuf+ul;
  445.       // skip leading ws
  446.       while (wp<we && (*wp<=32 || *wp==SHY))
  447. ++wp;
  448.       goto in;
  449.       while (bp<be && wp<we) { // copy, compacting whitespace
  450. // add a space
  451. *bp++=L' ';
  452. (*ap++).wa=(WORD)fp->attr;
  453.   in:
  454. // copy non-ws
  455. while (bp<be && wp<we && *wp>32)
  456.   if (*wp==SHY) {
  457.     if (bp>bs)
  458.       ap[-1].hyphen=true;
  459.     ++wp;
  460.   } else {
  461.     *bp++=*wp++;
  462.     (*ap++).wa=(WORD)fp->attr;
  463.   }
  464. // skip over spaces
  465. while (wp<we && (*wp<=32 || *wp==SHY))
  466.   ++wp;
  467.       }
  468.     }
  469.     // add a trailing space if required
  470.     if (fp->attr&TRAILSP && bp<be) {
  471.       *bp++=L' ';
  472.       (*ap++).wa=(WORD)fp->attr;
  473.     }
  474.   }
  475.   // to avoid endless loops later, we have to pad the paragraph up to the
  476.   // advertised length
  477.   while (bp-bs<len) {
  478.     *bp++=L' ';
  479.     (*ap++).wa=0;
  480.   }
  481.   p.str.setsize(len);
  482.   p.cflags.setsize(len);
  483.   p.len=len;
  484.   p.links.setsize(nlinks+ilinks);
  485.   return p;
  486. }
  487. int   XMLParserImp::GetPStart(int docid,int para) {
  488.   if (docid<0 || docid>=m_docs.GetSize() || para<0)
  489.     return 0;
  490.   if (para>=m_docs[docid].length)
  491.     return m_pp[m_docs[docid].start+m_docs[docid].length].start;
  492.   return m_pp[m_docs[docid].start+para].start;
  493. }
  494. int   XMLParserImp::GetPLength(int docid,int para) {
  495.   if (docid<0 || docid>=m_docs.GetSize() || para<0 || para>=m_docs[docid].length)
  496.     return 0;
  497.   int idx=m_docs[docid].start+para;
  498.   return m_pp[idx+1].start-m_pp[idx].start;
  499. }
  500. int   XMLParserImp::GetTotalLength(int docid) {
  501.   if (docid<0 || docid>=m_docs.GetSize())
  502.     return 0;
  503.   return m_pp[m_docs[docid].start+m_docs[docid].length].start;
  504. }
  505. int   XMLParserImp::LookupParagraph(int docid,int charpos) {
  506.   if (docid<0 || docid>=m_docs.GetSize())
  507.     return 0;
  508.   int i=m_docs[docid].start,j=i+m_docs[docid].length;
  509.   if (charpos<0 || charpos>m_pp[j].start)
  510.     return 0;
  511.   if (charpos==m_pp[j].start)
  512.     return j-i;
  513.   --j;
  514.   while (i<=j) {
  515.     int   m=(i+j)>>1;
  516.     if (charpos<m_pp[m].start)
  517.       j=m-1;
  518.     else if (charpos>=m_pp[m+1].start)
  519.       i=m+1;
  520.     else
  521.       return m-m_docs[docid].start;
  522.   }
  523.   return 0;
  524. }
  525. bool   XMLParserImp::LookupReference(const wchar_t *name,FilePos& dest) {
  526.   void   *data;
  527.   if (!m_references.Lookup(name,data))
  528.     return false;
  529.   int   para=(int)data;
  530.   // find the docid
  531.   for (int docid=0;docid<m_docs.GetSize();++docid)
  532.     if (para>=m_docs[docid].start && para<m_docs[docid].start+m_docs[docid].length) {
  533.       dest.para=para-m_docs[docid].start;
  534.       dest.off=0;
  535.       dest.docid=docid;
  536.       return true;
  537.     }
  538.   // should not happen
  539.   return false;
  540. }
  541. bool   XMLParserImp::GetImage(const wchar_t *name,HDC hDC,int maxwidth,
  542.  int maxheight,int rotation,Image& img)
  543. {
  544.   bool alloc;
  545.   CachedImage *cim=m_imcache.Lookup(name,alloc);
  546.   if (!alloc && cim->hBmp && (cim->maxwidth==maxwidth ||
  547.       (cim->width<cim->maxwidth && cim->width<maxwidth)) &&
  548.       (cim->maxheight==maxheight || (cim->height<cim->maxheight &&
  549.       cim->height<maxheight)) &&
  550.     cim->rotation==rotation)
  551.   {
  552.     img.hBmp=cim->hBmp;
  553.     img.height=cim->height;
  554.     img.width=cim->width;
  555.     return true;
  556.   }
  557.   const wchar_t   *type,*vname;
  558.   ImageLoader::BinReader  *rdr;
  559.   if (rdr=OpenBinary(name,&type,&vname)) {
  560.     int   width,height;
  561.     HBITMAP  hBmp;
  562.     bool ret=ImageLoader::Load(hDC,type,rdr,maxwidth,maxheight,rotation,hBmp,width,height);
  563.     delete rdr;
  564.     if (ret) {
  565.       cim->maxwidth=maxwidth;
  566.       cim->maxheight=maxheight;
  567.       cim->rotation=rotation;
  568.       cim->width=width;
  569.       cim->height=height;
  570.       cim->hBmp=hBmp;
  571.       cim->name=vname;
  572.       img.hBmp=hBmp;
  573.       img.width=width;
  574.       img.height=height;
  575.       return true;
  576.     }
  577.   }
  578.   m_imcache.Remove(cim);
  579.   return false;
  580. }
  581. void   XMLParserImp::AddQ(int start) {
  582.   PE pe;
  583.   pe.Zero();
  584.   pe.start=start;
  585.   m_pp.Add(pe);
  586. }
  587. void   XMLParserImp::AddToc(FilePos pos,int level) {
  588.   if (m_bmk) {
  589.     FilePos ref(pos);
  590.     ref.off=0;
  591.     m_bmk->AddTocEnt(pos.para,pos.off,pos.docid,ref,level);
  592.   }
  593. }
  594. void   XMLParserImp::AddP(int pstart,int lstart,int start,int len,CFMT& fmt)
  595. {
  596.   if (pstart==m_frags.GetSize() || len==0) {
  597.     AddQ(start);
  598.     return;
  599.   }
  600.   PE pe;
  601.   pe.setidx_nf(pstart,m_frags.GetSize()-pstart);
  602.   pe.setidx_nl(lstart,m_links.GetSize()-lstart);
  603.   pe.start=start;
  604.   pe.flags=fmt.flags;
  605.   pe.setindent(RClamp(fmt.lindent,0,500),RClamp(fmt.rindent,0,500),
  606.     RClamp(fmt.findent,0,500));
  607.   m_pp.Add(pe);
  608. }
  609. void   XMLParserImp::AddImage(const wchar_t *href,int start,CFMT& fmt)
  610. {
  611.   PE pe;
  612.   pe.name=m_buffer.Append(href,wcslen(href)+1);
  613.   pe.flags=fmt.flags|PE_IMAGE;
  614.   pe.setidx_nl(0,0);
  615.   pe.start=start;
  616.   pe.setindent(RClamp(fmt.lindent,0,500),RClamp(fmt.rindent,0,500),
  617.     RClamp(fmt.findent,0,500));
  618.   m_pp.Add(pe);
  619. }
  620. void   XMLParserImp::PushWS() {
  621.   Frag    f;
  622.   // if we already have a leading space, but its charformat differs from current
  623.   // we have to create a fully whitespace frag
  624.   if (m_ps->attr&LEADSP && m_ps->last_frag_fmt!=m_ps->cfmt.attr) {
  625.     f.attr=m_ps->last_frag_fmt.wa|REALLYLOCAL;
  626.     f.len=1;
  627.     f.local[0]=L' ';
  628.     m_frags.Add(f);
  629.     m_ps->numfrags++;
  630.     m_ps->len++;
  631.     m_ps->attr&=~LEADSP;
  632.   }
  633. }
  634. class Base64BinReader: public ImageLoader::BinReader {
  635.   enum { FEOF=65535 };
  636.   XMLParserImp   *m_parser;
  637.   Buffer<wchar_t> m_fragbuf;
  638.   int   m_maxfragsize;
  639.   int   m_ptr;
  640.   int   m_fragptr;
  641.   int   m_fragtop;
  642.   unsigned int   m_chunk;
  643.   int   m_chunkbytes;
  644.   bool   NextFrag();
  645.   wchar_t   NextFragChar();
  646.   wchar_t   Char() { return m_ptr<m_fragbuf.size() ?
  647.     m_fragbuf[m_ptr++] : NextFragChar(); }
  648. public:
  649.   Base64BinReader(XMLParserImp *xp,XMLParserImp::Binary *b) :
  650.       m_parser(xp), m_maxfragsize(0), m_ptr(0),
  651.       m_fragptr(b->startfrag), m_fragtop(b->startfrag+b->numfrags),
  652.       m_chunk(0), m_chunkbytes(0) { }
  653.   virtual int   Read(void *buffer,int count);
  654. };
  655. ImageLoader::BinReader *XMLParserImp::OpenBinary(const wchar_t *name,
  656.   const wchar_t **type,
  657.   const wchar_t **vname) {
  658.   void       *ptr;
  659.   if (!m_binaries.Lookup(name,ptr))
  660.     return NULL;
  661.   Binary      *b=(Binary*)ptr;
  662.   if (type)
  663.     *type=b->type;
  664.   if (vname)
  665.     *vname=b->id;
  666.   // we only support base64
  667.   return new Base64BinReader(this,b);
  668. }
  669. bool  Base64BinReader::NextFrag() {
  670.   if (m_fragptr>=m_fragtop)
  671.     return false;
  672.   XMLParserImp::Frag    *fp=&m_parser->m_frags[m_fragptr];
  673.   if ((int)fp->len>m_maxfragsize) {
  674.     m_maxfragsize=fp->len;
  675.     m_fragbuf=Buffer<wchar_t>(m_maxfragsize);
  676.   }
  677.   if (fp->attr&REALLYLOCAL) {
  678.     m_fragbuf.setsize(fp->len);
  679.     memcpy(m_fragbuf,fp->local,fp->len*sizeof(wchar_t));
  680.   } else if (fp->attr&LOCAL) {
  681.     m_fragbuf.setsize(fp->len);
  682.     memcpy(m_fragbuf,fp->str,fp->len*sizeof(wchar_t));
  683.   } else {
  684.     Buffer<char>    buf(fp->len);
  685.     m_parser->m_fp->seek(fp->fpos);
  686.     if (m_parser->m_fp->read(buf,fp->len)!=(int)fp->len) {
  687.       ASSERT(0);
  688.       return false;
  689.     }
  690.     char     *cp=buf;
  691.     int ul;
  692.     if (fp->attr&CDATA)
  693.       ul=XML_ConvertCharacterData((XML_Parser)m_parser->m_parser,&cp,fp->len,m_fragbuf,fp->len);
  694.     else
  695.       ul=XML_ParseCharacterData((XML_Parser)m_parser->m_parser,&cp,fp->len,m_fragbuf,fp->len);
  696.     if (ul<0) // xml parser returned an error
  697.       return false;
  698.     m_fragbuf.setsize(ul);
  699.   }
  700.   ++m_fragptr;
  701.   m_ptr=0;
  702.   return true;
  703. }
  704. wchar_t Base64BinReader::NextFragChar() {
  705.   if (!NextFrag())
  706.     return FEOF;
  707.   return m_ptr<m_fragbuf.size() ? m_fragbuf[m_ptr++] : FEOF;
  708. }
  709. int   Base64BinReader::Read(void *buffer,int count) {
  710.   char *dest=(char*)buffer;
  711.   char *de=dest+count,*ds=dest;
  712.   do {
  713.     // store accumulated bytes
  714.     while (m_chunkbytes>0 && ds<de) {
  715.       *ds++=((char*)&m_chunk)[2];
  716.       m_chunkbytes--;
  717.       m_chunk<<=8;
  718.     }
  719.     if (ds>=de)
  720.       break;
  721.     // fill in three more octets
  722.     m_chunk=0; m_chunkbytes=3;
  723.     int i=18;
  724.     do {
  725.       wchar_t c=Char();
  726.       if (c==FEOF) {
  727. m_chunkbytes=0;
  728. break;
  729.       }
  730.       if (c>='A' && c<='Z')
  731. m_chunk|=(unsigned int)(c-'A')<<i;
  732.       else if (c>='a' && c<='z')
  733. m_chunk|=(unsigned int)(c-'a'+26)<<i;
  734.       else if (c>='0' && c<='9')
  735. m_chunk|=(unsigned int)(c-'0'+52)<<i;
  736.       else if (c=='+')
  737. m_chunk|=62<<i;
  738.       else if (c=='/')
  739. m_chunk|=63<<i;
  740.       else if (c=='=') {
  741. if (i==6)
  742.   m_chunkbytes=1;
  743. else if (i==0)
  744.   m_chunkbytes=2;
  745. // force eof
  746. m_fragtop=m_fragptr;
  747. m_fragbuf.setsize(0);
  748. break;
  749.       } else
  750. continue; // silently ignore all other chars
  751.       i-=6;
  752.     } while (i>=0);
  753.     if (!m_chunkbytes) // EOF
  754.       break;
  755.   } while (ds<de);
  756.   return ds-dest;
  757. }
  758. static void   *my_malloc(void *priv,size_t size) {
  759.   return HeapAlloc((HANDLE)priv,HEAP_NO_SERIALIZE,size);
  760. }
  761. static void   *my_realloc(void *priv,void *ptr,size_t size) {
  762.   return HeapReAlloc((HANDLE)priv,HEAP_NO_SERIALIZE,ptr,size);
  763. }
  764. static void   my_free(void *priv,void *ptr) {
  765.   HeapFree((HANDLE)priv,HEAP_NO_SERIALIZE,ptr);
  766. }
  767. static void normalize_space(wchar_t *dest,int dlen,const wchar_t *s,int len)
  768. {
  769.   wchar_t *q=dest+dlen;
  770.   const wchar_t *e=s+len;
  771.   while (s<e && *s<=32)
  772.       ++s;
  773.   goto in;
  774.   while (s<e && dest<q) {
  775.     while (s<e && *s<=32)
  776.       ++s;
  777.     if (s<e)
  778.       *dest++=L' ';
  779. in:
  780.     while (s<e && dest<q && *s>32)
  781.       *dest++=*s++;
  782.   }
  783. }
  784. static int    normalized_length(const wchar_t *s,int len) {
  785.   const wchar_t *e=s+len;
  786.   int       nl=0;
  787.   while (s<e && *s<=32)
  788.     ++s;
  789.   goto in;
  790.   while (s<e) {
  791.     while (s<e && *s<=32)
  792.       ++s;
  793.     if (s<e)
  794.       ++nl;
  795. in:
  796.     while (s<e && *s>32)
  797.       ++nl,++s;
  798.   }
  799.   return nl;
  800. }
  801. static bool iswhitespace(const wchar_t *text,int len) {
  802.   const wchar_t *end=text+len;
  803.   while (text<end) {
  804.     if (*text!=0x0d && *text!=0x0a && *text!=0x20 && *text!=0x09)
  805.       return false;
  806.     ++text;
  807.   }
  808.   return true;
  809. }
  810. static XMLParser::FmtArray g_eformat;
  811. static WMap *g_elements;
  812. static struct Cleaner {
  813.   ~Cleaner() { delete g_elements; }
  814. } g_cleaner;
  815. static XMLParser::ElemFmt    *LookupElem(const wchar_t *name) {
  816.   void *data;
  817.   if (name && g_elements->Lookup(name,data))
  818.     return &g_eformat[(int)data];
  819.   return &g_eformat[0]; // default
  820. }
  821. static const wchar_t       *LocalName(const wchar_t *name) {
  822.   const wchar_t   *end=wcschr(name,L'|');
  823.   return end ? end+1 : name;
  824. }
  825. void XMLParserImp::ParseState::ApplyFmt(ElemFmt *e,int nest) {
  826.   PushA();
  827.   if (e->fsz!=XMLParser::ElemFmt::NOCHG)
  828.     cfmt.attr.fsize=nest ? max(e->fsz-nest,1) : e->fsz;
  829.   if (e->bold!=XMLParser::ElemFmt::NOCHG)
  830.     cfmt.attr.bold=e->bold;
  831.   if (e->italic!=XMLParser::ElemFmt::NOCHG)
  832.     cfmt.attr.italic=e->italic;
  833.   if (e->underline!=XMLParser::ElemFmt::NOCHG)
  834.     cfmt.attr.underline=e->underline;
  835.   if (e->color!=XMLParser::ElemFmt::NOCHG)
  836.     cfmt.attr.color=e->color;
  837.   if (e->align!=XMLParser::ElemFmt::NOCHG)
  838.     cfmt.flags=(cfmt.flags & ~Paragraph::align_mask) | (e->align & Paragraph::align_mask);
  839.   if (e->lindent!=XMLParser::ElemFmt::NOCHG) {
  840.     if (e->lindent<0)
  841.       cfmt.lindent-=e->lindent;
  842.     else
  843.       cfmt.lindent=e->lindent;
  844.   }
  845.   if (e->rindent!=XMLParser::ElemFmt::NOCHG) {
  846.     if (e->rindent<0)
  847.       cfmt.rindent-=e->rindent;
  848.     else
  849.       cfmt.rindent=e->rindent;
  850.   }
  851.   if (e->findent!=XMLParser::ElemFmt::NOCHG) {
  852.     if (e->findent<0)
  853.       cfmt.findent-=e->findent;
  854.     else
  855.       cfmt.findent=e->findent;
  856.   }
  857. }
  858. const wchar_t *GetAttr(const wchar_t **attr,const wchar_t *name,const wchar_t *def=NULL)
  859. {
  860.   while (*attr) {
  861.     if (!wcscmp(name,*attr))
  862.       return attr[1];
  863.     attr+=2;
  864.   }
  865.   return def;
  866. }
  867. void XMLParserImp::StartElement(const wchar_t *ns_name,const wchar_t **attr) {
  868.   if (!m_ps->root_element) { // special case for root
  869.     const wchar_t *p = ns_name;
  870.     const wchar_t *q = FB_NS;
  871.     const wchar_t *e = q + FB_NS_LEN - 1;
  872.     while (*p && q < e)
  873.       if (*p++ != *q++)
  874. longjmp(m_ps->jout,ERR_NOTFB2);
  875.     if (!p[0] || wcscmp(p+1,L"|FictionBook")!=0)
  876.       longjmp(m_ps->jout,ERR_NOTFB2);
  877.     m_ps->root_element=true;
  878.   }
  879.   ElemFmt *elem=LookupElem(ns_name);
  880.   if (elem->flags&ElemFmt::DOCUMENT) {
  881.     if (m_docs.GetSize()==0)
  882.       AddQ(m_ps->start);
  883.     Document  d;
  884.     d.start=m_pp.GetSize();
  885.     d.length=0;
  886.     d.name=GetAttr(attr,L"name",L"");
  887.     m_docs.Add(d);
  888.     m_ps->start=0;
  889.     // add a cover page if it was present
  890.     if (m_docs.GetSize()==1 && m_cover.GetLength()>0) {
  891.       AddImage(m_cover,m_ps->start,m_ps->cfmt);
  892.       m_ps->start+=ImageLoader::IMAGE_VSIZE;
  893.     }
  894.   }
  895.   if (elem->flags&ElemFmt::ENABLE)
  896.     ++m_ps->enable;
  897.   if (elem->flags&ElemFmt::SECTION)
  898.     m_ps->section_nest++;
  899.   if (elem->flags&ElemFmt::ELINE)
  900.     AddQ(m_ps->start);
  901.   if (elem->flags&ElemFmt::FMT) // apply formatting
  902.     m_ps->ApplyFmt(elem);
  903.   if (elem->flags&ElemFmt::STYLE) {
  904.     const wchar_t   *style=GetAttr(attr,L"name");
  905.     void     *val;
  906.     if (style && m_ps->stylemap->Lookup(style,val))
  907.       m_ps->ApplyFmt(&m_ps->styles->operator[]((int)val));
  908.     else
  909.       m_ps->PushA();
  910.   }
  911.   if (elem->flags&ElemFmt::HEADER) {
  912.     m_ps->PushA();
  913.     m_ps->cfmt.flags |= Paragraph::header;
  914.   }
  915.   if (elem->flags&ElemFmt::STYLESHEET) {
  916.     const wchar_t *type=GetAttr(attr,L"type");
  917.     if (m_ps->in_stylesheet || (type && !wcscmp(type,HR_STYLE)))
  918.       if (!m_ps->in_stylesheet++)
  919. m_sps->Init();
  920.   }
  921.   if (elem->flags&ElemFmt::TITLE) // start a toc entry
  922.     m_ps->title_start=m_pp.GetSize();
  923.   if (elem->flags&ElemFmt::LINKDEST) { // link destination
  924.     const wchar_t *id=GetAttr(attr,L"id");
  925.     if (id) {
  926.       wchar_t *copy=m_buffer.Append(id,wcslen(id)+1);
  927.       m_references.Add(copy,(void*)m_pp.GetSize());
  928.     }
  929.   }
  930.   if (elem->flags&ElemFmt::LINK) { // link
  931.     const wchar_t   *dest=GetAttr(attr,XLINK_NS L"|href");
  932.     const wchar_t   *type=GetAttr(attr,L"type");
  933.     ElemFmt     *linkformat;
  934.     if (type && !wcscmp(type,L"note"))
  935.       linkformat=LookupElem(L"|>footnote");
  936.     else
  937.       linkformat=LookupElem(L"|>link");
  938.     m_ps->ApplyFmt(linkformat);
  939.     if (dest) {
  940.       m_ps->link_start=m_ps->len;
  941.       m_ps->link_name=m_buffer.Append(dest,wcslen(dest)+1);
  942.     } else
  943.       m_ps->link_name=NULL;
  944.   }
  945.   if ((m_ps->enable && elem->flags&ElemFmt::PARA) ||
  946.       elem->flags&ElemFmt::DESCCAT)
  947.   { // start a new paragraph
  948.     m_ps->attr&=~(LEADSP|TRAILSP);
  949.     m_ps->acch_lev++;
  950.     m_ps->pf_start=m_frags.GetSize();
  951.     m_ps->pl_start=m_links.GetSize();
  952.     m_ps->numfrags=0;
  953.     m_ps->len=0;
  954.     m_ps->last_frag_trailsp=false;
  955.     m_ps->last_frag_fmt=m_ps->cfmt.attr;
  956.   }
  957.   if (elem->flags&(ElemFmt::DESCCAT|ElemFmt::DESCITEM)) {
  958.     Frag   f;
  959.     if (elem->flags&ElemFmt::DESCITEM) { // add a few nbsps
  960.       f.attr=m_ps->Att()|REALLYLOCAL;
  961.       f.len=2;
  962.       f.local[0]=f.local[1]=0xa0; // nbsp
  963.       m_frags.Add(f);
  964.       ++m_ps->numfrags;
  965.       m_ps->len+=f.len;
  966.     }
  967.     // add an element name
  968.     m_ps->ApplyFmt(LookupElem(L">keyword"));
  969.     const wchar_t   *ln=LocalName(ns_name);
  970.     f.len=wcslen(ln);
  971.     f.attr=m_ps->Att()|LOCAL;
  972.     f.str=m_buffer.Append(ln,f.len);
  973.     m_frags.Add(f);
  974.     ++m_ps->numfrags;
  975.     m_ps->len+=f.len;
  976.     m_ps->PopA();
  977.     if (elem->flags&ElemFmt::DESCITEM && attr && *attr) { // print attributes as well
  978.       // add " ("
  979.       f.attr=m_ps->Att()|REALLYLOCAL;
  980.       f.len=2;
  981.       f.local[0]=L' '; f.local[1]=L'(';
  982.       m_frags.Add(f);
  983.       ++m_ps->numfrags;
  984.       m_ps->len+=f.len;
  985.       // iterate over attrbutes
  986.       while (*attr) {
  987. //attr name
  988. f.attr=m_ps->Att()|LOCAL;
  989. ln=LocalName(*attr);
  990. f.len=wcslen(ln);
  991. f.str=m_buffer.Append(ln,f.len);
  992. m_frags.Add(f);
  993. ++m_ps->numfrags;
  994. m_ps->len+=f.len;
  995. // "="
  996. f.attr=m_ps->Att()|REALLYLOCAL;
  997. f.len=1;
  998. f.local[0]=L'=';
  999. m_frags.Add(f);
  1000. ++m_ps->numfrags;
  1001. ++m_ps->len;
  1002. // value
  1003. f.attr=m_ps->Att()|LOCAL;
  1004. f.len=wcslen(attr[1]);
  1005. f.str=m_buffer.Append(attr[1],f.len);
  1006. m_frags.Add(f);
  1007. ++m_ps->numfrags;
  1008. m_ps->len+=f.len;
  1009. attr+=2;
  1010.       }
  1011.       // add ")"
  1012.       f.attr=m_ps->Att()|REALLYLOCAL;
  1013.       f.len=1;
  1014.       f.local[0]=L')';
  1015.       m_frags.Add(f);
  1016.       ++m_ps->numfrags;
  1017.       m_ps->len+=f.len;
  1018.     }
  1019.     if (elem->flags&ElemFmt::DESCCAT) {
  1020.       // if last frag is a trailsp, then discard the last space
  1021.       if (m_ps->last_frag_trailsp) {
  1022. m_ps->len--;
  1023. m_frags[m_frags.GetSize()-1].attr&=~TRAILSP;
  1024.       }
  1025.       AddP(m_ps->pf_start,m_ps->pl_start,m_ps->start,m_ps->len,m_ps->cfmt);
  1026.       m_ps->start+=m_ps->len;
  1027.       m_ps->acch_lev--;
  1028.     } else { // add a ": "
  1029.       f.attr=m_ps->Att()|REALLYLOCAL;
  1030.       f.len=2;
  1031.       f.local[0]=L':'; f.local[1]=L' ';
  1032.       m_frags.Add(f);
  1033.       ++m_ps->numfrags;
  1034.       m_ps->len+=f.len;
  1035.     }
  1036.   }
  1037.   if (elem->flags&ElemFmt::BINARY) {
  1038.     const wchar_t *id=GetAttr(attr,L"id");
  1039.     const wchar_t *type=GetAttr(attr,L"content-type");
  1040.     if (id && type) {
  1041.       m_ps->binary=1;
  1042.       Binary  *b=m_binarystorage.Get();
  1043.       b->id=m_buffer.Append(id,wcslen(id)+1);
  1044.       b->type=m_buffer.Append(type,wcslen(type)+1);
  1045.       b->startfrag=m_frags.GetSize();
  1046.       b->numfrags=0;
  1047.       m_binaries.Add(b->id,(void*)b);
  1048.     }
  1049.   }
  1050.   if (elem->flags&ElemFmt::IMAGE) {
  1051.     const wchar_t *href=GetAttr(attr,XLINK_NS L"|href");
  1052.     if (href && href[0]==L'#') {
  1053.       if (m_ps->acch_lev) { // inline image
  1054. const wchar_t *hcopy=m_buffer.Append(href+1,wcslen(href));
  1055. int       index=m_inline_images.GetSize();
  1056. m_inline_images.Add(hcopy);
  1057. PushWS();
  1058. if (m_ps->attr&LEADSP)
  1059.   ++m_ps->len;
  1060. Frag    f;
  1061. m_ps->cfmt.attr.img=1;
  1062. f.attr=m_ps->Att()|PE_IMAGE;
  1063. m_ps->cfmt.attr.img=0;
  1064. f.len=1;
  1065. f.local[0]=index;
  1066. f.local[1]=index>>16;
  1067. m_frags.Add(f);
  1068. ++m_ps->numfrags;
  1069. ++m_ps->len;
  1070. m_ps->last_frag_trailsp=0;
  1071. m_ps->attr&=~(LEADSP|TRAILSP);
  1072. m_ps->last_frag_fmt=m_ps->cfmt.attr;
  1073.       } else {
  1074. AddImage(href+1,m_ps->start,m_ps->cfmt);
  1075. // image virtual size is always the same
  1076. m_ps->start+=ImageLoader::IMAGE_VSIZE;
  1077. if (m_docs.GetSize() == 0)
  1078.   m_cover = href+1;
  1079.       }
  1080.     }
  1081.   }
  1082. }
  1083. void XMLParserImp::EndElement(const wchar_t *ns_name) {
  1084.   ProgSetCur(XML_GetCurrentByteIndex(m_parser));
  1085.   ElemFmt   *elem=LookupElem(ns_name);
  1086.   if (m_ps->enable && elem->flags&ElemFmt::PARA) { // end a paragraph
  1087.     // if last frag is a trailsp, then discard the last space
  1088.     if (m_ps->last_frag_trailsp) {
  1089.       m_ps->len--;
  1090.       m_frags[m_frags.GetSize()-1].attr&=~TRAILSP;
  1091.     }
  1092.     AddP(m_ps->pf_start,m_ps->pl_start,m_ps->start,m_ps->len,m_ps->cfmt);
  1093.     m_ps->start+=m_ps->len;
  1094.     m_ps->acch_lev--;
  1095.   }
  1096.   if (elem->flags&ElemFmt::HEADER)
  1097.     m_ps->PopA();
  1098.   if (elem->flags&ElemFmt::STYLE)
  1099.     m_ps->PopA();
  1100.   if (elem->flags&ElemFmt::STYLESHEET && m_ps->in_stylesheet)
  1101.       --m_ps->in_stylesheet;
  1102.   if (elem->flags&ElemFmt::FMT) // apply formatting
  1103.     m_ps->PopA();
  1104.   if (elem->flags&ElemFmt::LINK) { // link
  1105.     if (m_ps->link_name) {
  1106.       XMLParserImp::Link link;
  1107.       link.start=m_ps->link_start;
  1108.       link.length=m_ps->len-m_ps->link_start;
  1109.       link.target=m_ps->link_name;
  1110.       m_links.Add(link);
  1111.     }
  1112.     m_ps->PopA();
  1113.   }
  1114.   if (elem->flags&ElemFmt::SECTION) // snag title attribute
  1115.     m_ps->section_nest--;
  1116.   if (elem->flags&ElemFmt::SPACE) // add spaces after this element
  1117.     m_ps->attr|=LEADSP;
  1118.   if (elem->flags&ElemFmt::TITLE) {
  1119.     if (m_docs.GetSize()>0 && m_ps->section_nest)
  1120.       AddToc(
  1121. FilePos(
  1122.   m_ps->title_start-m_docs[m_docs.GetSize()-1].start,
  1123.   m_pp.GetSize()-m_ps->title_start,
  1124.   m_docs.GetSize()-1
  1125. ),
  1126. m_ps->section_nest
  1127.       );
  1128.   }
  1129.   if (elem->flags&ElemFmt::AELINE) // add an empty line after the element
  1130.     AddQ(m_ps->start);
  1131.   if (elem->flags&ElemFmt::ENABLE)
  1132.     --m_ps->enable;
  1133.   if (elem->flags&ElemFmt::DOCUMENT) {
  1134.     if (m_docs.GetSize()>0)
  1135.       m_docs[m_docs.GetSize()-1].length=
  1136. m_pp.GetSize()-m_docs[m_docs.GetSize()-1].start;
  1137.     AddQ(m_ps->start);
  1138.   }
  1139.   if (elem->flags&ElemFmt::BINARY && m_ps->binary) {
  1140.     m_ps->binary=0;
  1141.     int   idx=m_binarystorage.GetSize()-1;
  1142.     m_binarystorage[idx].numfrags=m_frags.GetSize()-m_binarystorage[idx].startfrag;
  1143.   }
  1144. }
  1145. void XMLParserImp::CharData(const wchar_t *text,int len) {
  1146.   if (m_ps->acch_lev && len) {
  1147.     int l=normalized_length(text,len);
  1148.     if (!l) { // whitespace frag, try to add a leading space to the next frag
  1149.       if (m_ps->numfrags) {
  1150. m_ps->attr|=LEADSP;
  1151. m_ps->last_frag_fmt=m_ps->cfmt.attr;
  1152.       }
  1153.       return;
  1154.     }
  1155.     PushWS();
  1156.     if (*text<=32 && m_ps->numfrags)
  1157.       m_ps->attr|=LEADSP;
  1158.     if (text[len-1]<=32) {
  1159.       m_ps->attr|=TRAILSP;
  1160.       m_ps->len++;
  1161.     }
  1162.     m_ps->len+=l;
  1163.     if (m_ps->attr&LEADSP)
  1164.       m_ps->len++;
  1165.     // here we check the previous frag and if it has TRAILSP and this has a LEADSP,
  1166.     // and their charformats are the same, then we can discard current LEADSP
  1167.     if (m_ps->numfrags && m_ps->last_frag_trailsp && m_ps->attr&LEADSP &&
  1168. m_ps->last_frag_fmt==m_ps->cfmt.attr)
  1169.     {
  1170.       m_ps->attr&=~LEADSP;
  1171.       m_ps->len--;
  1172.     }
  1173.     Frag    f;
  1174.     f.attr=m_ps->Att();
  1175.     if (l<5 || XML_IsExpanding(m_parser)) { // cache short fragments
  1176.       wchar_t *buf;
  1177.       if (l <= sizeof(f.local)/sizeof(wchar_t)) {
  1178. f.attr|=REALLYLOCAL;
  1179. buf=f.local;
  1180.       } else {
  1181. f.attr|=LOCAL;
  1182. buf=m_buffer.Get(l);
  1183.       }
  1184.       f.str=buf;
  1185.       f.len=l;
  1186.       normalize_space(buf,l,text,len);
  1187.     } else {
  1188.       f.len=XML_GetCurrentByteCount(m_parser);
  1189.       f.fpos=XML_GetCurrentByteIndex(m_parser);
  1190.     }
  1191.     m_frags.Add(f);
  1192.     ++m_ps->numfrags;
  1193.     m_ps->last_frag_trailsp=(m_ps->attr&TRAILSP)!=0;
  1194.     m_ps->attr&=~(LEADSP|TRAILSP);
  1195.     m_ps->last_frag_fmt=m_ps->cfmt.attr;
  1196.   }
  1197.   if (m_ps->in_stylesheet && len)
  1198.     ParseStylesheet(text,len);
  1199.   if (m_ps->binary && len && !iswhitespace(text,len)) {
  1200.     Frag  f;
  1201.     f.attr=m_ps->attr&CDATA; // text attrs are not needed in this context
  1202.     if (XML_IsExpanding(m_parser)) {
  1203.       f.str=m_buffer.Get(len);
  1204.       memcpy((wchar_t*)f.str,text,len*sizeof(wchar_t));
  1205.       f.attr|=LOCAL;
  1206.     } else {
  1207.       f.len=XML_GetCurrentByteCount(m_parser);
  1208.       f.fpos=XML_GetCurrentByteIndex(m_parser);
  1209.     }
  1210.     m_frags.Add(f);
  1211.   }
  1212. }
  1213. // expat callbacks
  1214. void   XMLParserImp::StartElementCB(void *udata,const wchar_t *name,
  1215.        const wchar_t **attr)
  1216. {
  1217.   ((XMLParserImp*)udata)->StartElement(name,attr);
  1218. }
  1219. void   XMLParserImp::EndElementCB(void *udata,const wchar_t *name) {
  1220.   ((XMLParserImp*)udata)->EndElement(name);
  1221. }
  1222. void   XMLParserImp::CharDataCB(void *udata,const wchar_t *text,int len) {
  1223.   ((XMLParserImp*)udata)->CharData(text,len);
  1224. }
  1225. void   XMLParserImp::StartCDataCB(void *udata) {
  1226.   ((XMLParserImp*)udata)->m_ps->attr|=CDATA;
  1227. }
  1228. void   XMLParserImp::EndCDataCB(void *udata) {
  1229.   ((XMLParserImp*)udata)->m_ps->attr&=~CDATA;
  1230. }
  1231. int XMLParserImp::UnknownEncodingCB(void *data,const wchar_t *name,
  1232.     XML_Encoding *info)
  1233. {
  1234.   int cp=Unicode::FindCodePage(Unicode::ToCS(name,wcslen(name)));
  1235.   const wchar_t *tab=NULL;
  1236.   if (cp>=0)
  1237.     tab=Unicode::GetTable(cp);
  1238.   if (!tab)
  1239.     return 0;
  1240.   info->data=NULL;
  1241.   info->convert=NULL;
  1242.   info->release=NULL;
  1243.   for (int i=0;i<256;++i)
  1244.     info->map[i]=tab[i];
  1245.   ((XMLParserImp*)data)->m_encoding=cp;
  1246.   return 1;
  1247. }
  1248. bool   XMLParserImp::ParseFile(int encoding) {
  1249.   XML_Memory_Handling_Suite  xmm={ my_malloc, my_realloc, my_free };
  1250.   xmm.priv=(void*)m_heap;
  1251.   ParseState     pstate;
  1252.   memset(&pstate,0,sizeof(pstate));
  1253.   m_ps=&pstate;
  1254.   FmtArray     docstyles;
  1255.   docstyles.SetSize(0,64);
  1256.   WMap     docstylemap(m_heap,true);
  1257.   pstate.styles=&docstyles;
  1258.   pstate.stylemap=&docstylemap;
  1259.   SP_State     spstate;
  1260.   m_sps=&spstate;
  1261.   const wchar_t *enc=NULL;
  1262.   if (encoding>=0) {
  1263.     enc=Unicode::GetCodePageNameW(encoding);
  1264.     if (!enc)
  1265.       encoding=-1;
  1266.   }
  1267.   if (!(m_parser=XML_ParserCreate_MM(enc,&xmm,L"|")))
  1268.     return false;
  1269.   XML_SetElementHandler(m_parser,XMLParserImp::StartElementCB,
  1270.     XMLParserImp::EndElementCB);
  1271.   XML_SetCharacterDataHandler(m_parser,XMLParserImp::CharDataCB);
  1272.   XML_SetCdataSectionHandler(m_parser,StartCDataCB,EndCDataCB);
  1273.   XML_SetUnknownEncodingHandler(m_parser,XMLParserImp::UnknownEncodingCB,this);
  1274.   XML_SetUserData(m_parser,this);
  1275.   m_encoding=-1;
  1276.   // now suck in the file
  1277.   m_fp->seek(0);
  1278.   switch (setjmp(pstate.jout)) {
  1279.   case 0:
  1280.     for (;;) {
  1281.       void    *buf=(char*)XML_GetBuffer(m_parser,RFile::BSZ);
  1282.       if (!buf) {
  1283. CTVApp::Barf(_T("XML parser: Out of memory"));
  1284. goto fail;
  1285.       }
  1286.       int     nr=m_fp->read(buf,RFile::BSZ);
  1287.       if (!XML_ParseBuffer(m_parser,nr,nr<RFile::BSZ)) {
  1288. CTVApp::Barf(
  1289.   #ifdef UNICODE
  1290.   _T("XML parse error: %s at line %d, column %d"),
  1291.   #else
  1292.   _T("XML parse error: %S at line %d, column %d"),
  1293.   #endif
  1294.   XML_ErrorString(XML_GetErrorCode(m_parser)),
  1295.   XML_GetCurrentLineNumber(m_parser),XML_GetCurrentColumnNumber(m_parser)+1);
  1296. goto fail;
  1297.       }
  1298.       if (nr<RFile::BSZ)
  1299. break;
  1300.     }
  1301.     break;
  1302.   case ERR_NOTFB2:
  1303.     CTVApp::Barf(_T("Not a FictionBook2 document"));
  1304.     goto fail;
  1305.   }
  1306.   if (m_docs.GetSize()>0) {
  1307.     Document    d;
  1308.     d.start=0;
  1309.     d.length=m_docs[0].start-1;
  1310.     d.name=_T("#Description");
  1311.     m_docs.Add(d);
  1312.   }
  1313.   return true;
  1314. fail:
  1315.   //XML_ParserFree(m_parser);
  1316.   // parser is now destroyed in the XMLParserImp destructor
  1317.   return false;
  1318. }
  1319. XMLParser *XMLParser::MakeParser(Meter *m,CBufFile *fp,Bookmarks *bmk,HANDLE heap) {
  1320.   return new XMLParserImp(m,fp,bmk,heap);
  1321. }
  1322. void   XMLParserImp::ParseStylesheet(const wchar_t *text,int len) {
  1323.   wchar_t   ch;
  1324.   while (len--) {
  1325.     ch=*text++;
  1326.     switch (m_sps->state) {
  1327.     case SP_State::START:
  1328.       if (!iswspace(ch)) {
  1329. m_sps->NAdd(ch);
  1330. m_sps->state=SP_State::NAME;
  1331.       }
  1332.       break;
  1333.     case SP_State::NAME:
  1334.       if (!iswspace(ch))
  1335. m_sps->NAdd(ch);
  1336.       else
  1337. m_sps->state=SP_State::FLAGS;
  1338.       break;
  1339.     case SP_State::FLAGS:
  1340. flags:
  1341.       switch (ch) {
  1342.       case L'b':
  1343. m_sps->format.bold=1;
  1344. break;
  1345.       case L'B':
  1346. m_sps->format.bold=0;
  1347. break;
  1348.       case L'i':
  1349. m_sps->format.italic=1;
  1350. break;
  1351.       case L'I':
  1352. m_sps->format.italic=0;
  1353. break;
  1354.       case L'u':
  1355. m_sps->format.underline=1;
  1356. break;
  1357.       case L'U':
  1358. m_sps->format.underline=0;
  1359. break;
  1360.       case L'r':
  1361. m_sps->format.align=Paragraph::right;
  1362. break;
  1363.       case L'c':
  1364. m_sps->format.align=Paragraph::center;
  1365. break;
  1366.       case L'j':
  1367. m_sps->format.align=Paragraph::justify;
  1368. break;
  1369.       case L'l':
  1370. m_sps->format.align=0;
  1371. break;
  1372.       case L'h':
  1373. m_sps->state=SP_State::COLOR;
  1374. m_sps->num=0; m_sps->sign=false;
  1375. break;
  1376.       case L'L':
  1377. m_sps->state=SP_State::LM;
  1378. m_sps->num=0; m_sps->sign=false;
  1379. break;
  1380.       case L'R':
  1381. m_sps->state=SP_State::RM;
  1382. m_sps->num=0; m_sps->sign=false;
  1383. break;
  1384.       case L'F':
  1385. m_sps->state=SP_State::FM;
  1386. m_sps->num=0; m_sps->sign=false;
  1387. break;
  1388.       case L'S':
  1389. m_sps->state=SP_State::SIZE;
  1390. m_sps->num=0; m_sps->sign=false;
  1391. break;
  1392.       case L';':
  1393. m_sps->stylename[m_sps->stylenameptr]=L'';
  1394. m_ps->stylemap->AddCopy(m_sps->stylename,(void*)m_ps->styles->GetSize());
  1395. m_ps->styles->Add(m_sps->format);
  1396. m_sps->Init();
  1397. break;
  1398.       }
  1399.       break;
  1400.     case SP_State::FM:
  1401.     case SP_State::LM:
  1402.     case SP_State::RM:
  1403.     case SP_State::SIZE:
  1404.     case SP_State::COLOR:
  1405.       if (iswdigit(ch)) {
  1406. m_sps->num=m_sps->num*10+ch-L'0';
  1407.       } else if (ch=='-') 
  1408. m_sps->sign=1;
  1409.       else { // end of spec
  1410. int   val=m_sps->num;
  1411. if (m_sps->sign)
  1412.   val=-val;
  1413. switch (m_sps->state) {
  1414. case SP_State::FM:
  1415.   val=RClamp(val,-100,100);
  1416.   m_sps->format.findent=val;
  1417.   break;
  1418. case SP_State::LM:
  1419.   val=RClamp(val,-100,100);
  1420.   m_sps->format.lindent=val;
  1421.   break;
  1422. case SP_State::RM:
  1423.   val=RClamp(val,-100,100);
  1424.   m_sps->format.rindent=val;
  1425.   break;
  1426. case SP_State::COLOR:
  1427.   val=RClamp(val,0,7);
  1428.   m_sps->format.color=val;
  1429.   break;
  1430. case SP_State::SIZE:
  1431.   val=RClamp(val,-100,100);
  1432.   m_sps->format.fsz=val;
  1433.   break;
  1434. }
  1435. m_sps->state=SP_State::FLAGS;
  1436. goto flags;
  1437.       }
  1438.       break;
  1439.     }
  1440.   }
  1441. }
  1442. void XMLParser::SaveStyles() {
  1443.   for (int i=0;i<g_eformat.GetSize();++i)
  1444.     if (g_eformat[i].name.GetLength() && g_eformat[i].name[0]!=_T('*')) {
  1445.       CString str;
  1446.       str.Format(_T("%d,%d,%d,%d,%d,%d,%d,%d,%d"),
  1447. g_eformat[i].fsz,
  1448. g_eformat[i].bold,
  1449. g_eformat[i].italic,
  1450. g_eformat[i].underline,
  1451. g_eformat[i].color,
  1452. g_eformat[i].align,
  1453. g_eformat[i].lindent,
  1454. g_eformat[i].rindent,
  1455. g_eformat[i].findent);
  1456.       AfxGetApp()->WriteProfileString(_T("Styles"),g_eformat[i].name,str);
  1457.     }
  1458. }
  1459. static void AddElement(const wchar_t *name,int namelen,int id) {
  1460.   wchar_t   buf[128];
  1461.   wcscpy(buf,FB_NS);
  1462.   buf[FB_NS_LEN]=L'|';
  1463.   if (namelen>sizeof(buf)/sizeof(wchar_t)-2-FB_NS_LEN)
  1464.     namelen=sizeof(buf)/sizeof(wchar_t)-2-FB_NS_LEN;
  1465.   wcsncpy(buf+FB_NS_LEN+1,name,namelen);
  1466.   buf[FB_NS_LEN+1+namelen]=L'';
  1467.   g_elements->AddCopy(buf,(void*)id);
  1468.   g_elements->AddCopy(buf+FB_NS_LEN,(void*)id);
  1469.   g_elements->AddCopy(buf+FB_NS_LEN+1,(void*)id);
  1470. }
  1471. static inline int FLAG(wchar_t x) {
  1472.   return x==L'+' ? 1 : x==L'-' ? 0 : XMLParser::ElemFmt::NOCHG;
  1473. }
  1474. static void ParseXMLSettings(const wchar_t *fmt,DWORD sz) {
  1475.   const wchar_t  *p=fmt;
  1476.   const wchar_t  *e=fmt+sz;
  1477.   const wchar_t  *le;
  1478.   wchar_t  *q;
  1479.   if (p<e && *p==0xFEFF)
  1480.     ++p;
  1481.   while (p<e) {
  1482.     for (le=p;le<e && *le!=L'r' && *le!=L'n';++le) ;
  1483.     // process line here
  1484.     if (p!=le && *p!=L'#' && *p!=L' ' && *p!=L't') {
  1485.       XMLParser::ElemFmt fe;
  1486.       wchar_t *name=NULL;
  1487.       int size;
  1488.       wchar_t bold,italic,underline;
  1489.       int color;
  1490.       wchar_t align;
  1491.       int leftm,rightm,firstm;
  1492.       wchar_t *action=NULL,*elements=NULL;
  1493.       int fields;
  1494.       if (Scan::xscanf(p,le-p,L"%S %-100,100,127d "
  1495. L"%c %c %c %0,8,127d %c %-100,100,127d "
  1496. L"%-100,100,127d %-100,100,127d %S %S",NULL,&fields,
  1497. &name,&size,&bold,&italic,&underline,
  1498. &color,&align,&leftm,&rightm,&firstm,
  1499. &action,&elements)==0 && fields==12)
  1500.       {
  1501. for (q=name;*q;++q)
  1502.   if (*q==L'_')
  1503.     *q=L' ';
  1504. fe.name=name;
  1505. fe.fsz=size;
  1506. fe.bold=FLAG(bold);
  1507. fe.italic=FLAG(italic);
  1508. fe.underline=FLAG(underline);
  1509. fe.color=color;
  1510. switch (align) {
  1511. case 'R':
  1512.   fe.align=Paragraph::right;
  1513.   break;
  1514. case 'C':
  1515.   fe.align=Paragraph::center;
  1516.   break;
  1517. case 'J':
  1518.   fe.align=Paragraph::justify;
  1519.   break;
  1520. default:
  1521.   fe.align=XMLParser::ElemFmt::NOCHG;
  1522.   break;
  1523. }
  1524. fe.lindent=leftm;
  1525. fe.rindent=rightm;
  1526. fe.findent=firstm;
  1527. fe.flags=0;
  1528. for (q=action;*q;++q) {
  1529.   const TCHAR *fp=XMLParser::ElemFmt::flag_names;
  1530.   for (int flags=1;*fp;flags<<=1,++fp)
  1531.     if (*fp==*q) {
  1532.       fe.flags|=flags;
  1533.       break;
  1534.     }
  1535. }
  1536. for (p=elements;*p;) {
  1537.   const wchar_t *q; // XXX
  1538.   for (q=p;*q && *q!=L',';++q) ;
  1539.   if (q!=p)
  1540.     AddElement(p,q-p,g_eformat.GetSize());
  1541.   p=q;
  1542.   if (*p==L',')
  1543.     ++p;
  1544. }
  1545. // ok, insert it now
  1546. g_eformat.Add(fe);
  1547.       }
  1548.       delete[] name;
  1549.       delete[] action;
  1550.       delete[] elements;
  1551.     }
  1552.     // skip end of line
  1553.     for (p=le;p<e && (*p=='r' || *p=='n');++p) ;
  1554.   }
  1555. }
  1556. void XMLParser::LoadStyles() {
  1557.   ElemFmt ef;
  1558.   // delete all elements
  1559.   g_eformat.RemoveAll();
  1560.   delete g_elements;
  1561.   g_elements=new WMap(GetProcessHeap(),true);
  1562.   // always initialize a default element
  1563.   ef.Clear();
  1564.   g_eformat.Add(ef);
  1565.   // read parser settings from a resource
  1566.   HMODULE hMod=AfxGetResourceHandle();
  1567.   HRSRC   hRes=FindResource(hMod,_T("xml_elements"),RT_RCDATA);
  1568.   if (hRes) {
  1569.     DWORD   rsize=SizeofResource(hMod,hRes);
  1570.     HGLOBAL hGlob=LoadResource(hMod,hRes);
  1571.     if (hGlob) {
  1572.       void  *res=LockResource(hGlob);
  1573.       if (res) {
  1574. ParseXMLSettings((const wchar_t *)res,rsize/sizeof(wchar_t));
  1575. UnlockResource(hGlob);
  1576.       }
  1577.       FreeResource(hGlob);
  1578.     }
  1579.   }
  1580.   // adjust formatting from registry
  1581.   for (int fnum=0;fnum<g_eformat.GetSize();++fnum)
  1582.     if (g_eformat[fnum].name.GetLength()>0 && g_eformat[fnum].name[0]!=_T('*')) {
  1583.       CString str=AfxGetApp()->GetProfileString(_T("Styles"),g_eformat[fnum].name);
  1584.       int f,b,i,c,a,li,ri,fi,u;
  1585.       if (_stscanf(str,_T("%d,%d,%d,%d,%d,%d,%d,%d,%d"),&f,&b,&i,&u,&c,&a,&li,&ri,&fi)==9) {
  1586. g_eformat[fnum].fsz=f;
  1587. g_eformat[fnum].bold=b;
  1588. g_eformat[fnum].italic=i;
  1589. g_eformat[fnum].underline=u;
  1590. g_eformat[fnum].color=c;
  1591. g_eformat[fnum].align=a;
  1592. g_eformat[fnum].lindent=li;
  1593. g_eformat[fnum].rindent=ri;
  1594. g_eformat[fnum].findent=fi;
  1595.       }
  1596.     }
  1597. }
  1598. XMLParser::FmtArray&  XMLParser::GetXMLStyles() {
  1599.   return g_eformat;
  1600. }
  1601. void XMLParser::ElemFmt::Clear() {
  1602.     fsz=NOCHG;
  1603.     bold=NOCHG;
  1604.     italic=NOCHG;
  1605.     color=NOCHG;
  1606.     align=NOCHG;
  1607.     underline=NOCHG;
  1608.     flags=0;
  1609.     lindent=NOCHG;
  1610.     rindent=NOCHG;
  1611.     findent=NOCHG;
  1612.     name.Empty();
  1613. }