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

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: TextParser.cpp,v 1.53.2.4 2003/10/21 23:26:24 mike Exp $
  29.  * 
  30.  */
  31. #include <afxtempl.h>
  32. #include <afxcmn.h>
  33. #include "TextParser.h"
  34. #include "XMLParser.h"
  35. #include "Unicode.h"
  36. #include "FastArray.h"
  37. #include "Image.h"
  38. #ifdef _DEBUG
  39. #undef THIS_FILE
  40. static char THIS_FILE[]=__FILE__;
  41. #define new DEBUG_NEW
  42. #endif
  43. struct Para { // paragraph reference
  44.   DWORD     off; // offset into file
  45.   DWORD     start; // start of parsed para
  46.   DWORD     rlen; // raw length
  47. };
  48. typedef FastArray<Para> PArray;
  49. struct SimpleFormat {
  50.   const TCHAR *name;
  51.   DWORD mask,cmp;
  52. };
  53. #define MAXPLEN 4096
  54. // soft hyphen
  55. #define SHY 0x00AD
  56. // Moshkov's formatting
  57. #define STARTBOLD 20
  58. #define ENDBOLD 21
  59. // formats list
  60. static SimpleFormat g_simple_formats[]={
  61.   { _T("Line per paragraph"), 0xff, 0x0a },
  62.   { _T("Indented first line"), 0xffff, 0x0a20 },
  63.   { _T("MAC Line per paragraph"), 0xff, 0x0d },
  64.   { _T("MAC Indented first line"), 0xffff, 0x0d20 }
  65. };
  66. #define NUM_SIMPLE_FORMATS  (sizeof(g_simple_formats)/sizeof(g_simple_formats[0]))
  67. static const TCHAR *g_ext_formats[]={
  68.   _T("XML"),
  69.   _T("PNG"),
  70.   _T("JPEG")
  71. };
  72. #define NUM_EXT_FORMATS  (sizeof(g_ext_formats)/sizeof(g_ext_formats[0]))
  73. #define XML_FORMAT  (NUM_SIMPLE_FORMATS)
  74. #define PNG_FORMAT  (NUM_SIMPLE_FORMATS+1)
  75. #define JPEG_FORMAT  (NUM_SIMPLE_FORMATS+2)
  76. TextParser::~TextParser() {
  77.   if (m_heap)
  78.     HeapDestroy(m_heap);
  79. }
  80. class SimpleTextParser : public TextParser {
  81. protected:
  82.   PArray m_pp; // paragraph list
  83.   SimpleFormat *m_sf;
  84.   void     GenericFileParse(CBufFile *fp,PArray& pp,DWORD mask,DWORD cmp);
  85.   Paragraph GenericBufParse(CBufFile *fp,const Para& p,int len);
  86. public:
  87.   SimpleTextParser(Meter *m,CBufFile *fp,HANDLE heap,int format,int encoding,Bookmarks *bmk) :
  88.       TextParser(m,fp,heap,bmk), m_sf(&g_simple_formats[format]), m_pp(heap)
  89.   {
  90.     m_format=format;
  91.     m_encoding=encoding;
  92.     if (m_encoding<0) {
  93.       char    tmp[1024];
  94.       DWORD   sp=m_fp->pos();
  95.       int nb=m_fp->read(tmp,sizeof(tmp));
  96.       m_encoding=Unicode::DetectCodePage(tmp,nb);
  97.   m_fp->seek(sp);
  98.     }
  99.     GenericFileParse(m_fp,m_pp,m_sf->mask,m_sf->cmp);
  100.     if (bmk) {
  101.       for (int i=0;i<Length(0)-1;++i)
  102. if ((i==0 || GetPLength(0,i-1)==0) && GetPLength(0,i+1)==0 &&
  103.     GetPLength(0,i)>0 && GetPLength(0,i)<90)
  104.   bmk->AddTocEnt(i,1,0,FilePos(i,0,0),0);
  105.     }
  106.   }
  107.   // paragraphs
  108.   virtual int Length(int docid) { return m_pp.GetSize()-1; } // in paragraphs
  109.   virtual Paragraph GetParagraph(int docid,int para) {
  110.     if (para>=0 && para<m_pp.GetSize()-1)
  111.       return GenericBufParse(m_fp,m_pp[para],m_pp[para+1].start-m_pp[para].start);
  112.     return Paragraph();
  113.   }
  114.   virtual int GetPLength(int docid,int para) {
  115.     if (para<0 || para>=m_pp.GetSize()-1)
  116.       return 0;
  117.     return m_pp[para+1].start-m_pp[para].start;
  118.   }
  119.   virtual int GetPStart(int docid,int para) {
  120.     if (para<0)
  121.       return 0;
  122.     if (para>=m_pp.GetSize()-1)
  123.       return m_pp[m_pp.GetSize()-1].start;
  124.     return m_pp[para].start;
  125.   }
  126.   virtual int GetTotalLength(int docid) {
  127.     return m_pp[m_pp.GetSize()-1].start;
  128.   }
  129.   virtual int LookupParagraph(int docid,int charpos);
  130. };
  131. int   SimpleTextParser::LookupParagraph(int docid,int charpos) {
  132.   if (charpos<0 || charpos>(int)m_pp[m_pp.GetSize()-1].start)
  133.     return 0;
  134.   if (charpos==(int)m_pp[m_pp.GetSize()-1].start)
  135.     return m_pp.GetSize()-1;
  136.   int i=0,j=m_pp.GetSize()-1;
  137.   while (i<=j) {
  138.     int   m=(i+j)>>1;
  139.     if (charpos<(int)m_pp[m].start)
  140.       j=m-1;
  141.     else if (charpos>=(int)m_pp[m+1].start)
  142.       i=m+1;
  143.     else
  144.       return m;
  145.   }
  146.   return 0;
  147. }
  148. #define RSPACE(x)   ((x)<=32)
  149. #define SPACE(x)    (RSPACE(x) || (x)==SHY)
  150. static void Addpara(int enc,PArray& pp,Buffer<char>& b,
  151.     int& parsed_start,int len,DWORD start)
  152. {
  153.   // convert to unicode
  154.   int     wclen=Unicode::WCLength(enc,b,len);
  155.   Buffer<wchar_t>   wb(wclen);
  156.   Unicode::ToWC(enc,b,len,wb,wclen);
  157.   // now count length
  158.   int     i,plen=0;
  159.   // skip leading spaces
  160.   for (i=0;i<wclen && SPACE(wb[i]);++i);
  161.   // count length
  162.   while (i<wclen) {
  163.     // word
  164.     while (i<wclen && !RSPACE(wb[i])) {
  165.       if (wb[i]!=SHY)
  166. ++plen;
  167.       ++i;
  168.     }
  169.     // spaces
  170.     while (i<wclen && SPACE(wb[i]))
  171.       ++i;
  172.     if (i<wclen) // this was not trailing space
  173.       ++plen;
  174.   }
  175.   Para p;
  176.   p.start=parsed_start;
  177.   p.rlen=len;
  178.   p.off=start;
  179.   pp.Add(p);
  180.   parsed_start+=plen;
  181. }
  182. void   SimpleTextParser::GenericFileParse(CBufFile *fp,PArray& pp,DWORD mask,DWORD cmp) {
  183.   int   ch;
  184.   DWORD   hist=0;
  185.   Buffer<char>   b(MAXPLEN);
  186.   int   rlen=0;
  187.   DWORD   start=fp->pos();
  188.   int   parsed_start=0;
  189.   for (;;) {
  190.     if ((ch=fp->ch())==BEOF) {
  191.       Addpara(m_encoding,pp,b,parsed_start,rlen,start);
  192.       break;
  193.     }
  194.     hist=hist<<8|ch;
  195.     if ((hist&0xffff)==0x0a0a || hist==0x0d0a0d0a || (hist&0xffff)==0x0d0d ||
  196. (hist&mask)==cmp || rlen>=MAXPLEN)
  197.     {
  198.       bool f=rlen>=MAXPLEN;
  199.       ProgSetCur(fp->pos());
  200.       Addpara(m_encoding,pp,b,parsed_start,rlen,start);
  201.       rlen=0;
  202.       start=m_fp->pos();
  203.       if (f)
  204. b[rlen++]=ch;
  205.     } else
  206.       b[rlen++]=ch;
  207.   }
  208.   Para p;
  209.   p.off=0;
  210.   p.rlen=0;
  211.   p.start=parsed_start;
  212.   pp.Add(p);
  213. }
  214. // generic buffer parser for all simple formats
  215. Paragraph  SimpleTextParser::GenericBufParse(CBufFile *fp,const Para& p,int len) {
  216.   if (!len)
  217.     return Paragraph();
  218.   // read entire buffer
  219.   Buffer<char>   mbbuf(p.rlen);
  220.   fp->seek(p.off);
  221.   int   nread=fp->read(mbbuf,p.rlen);
  222.   ASSERT(nread==(int)p.rlen);
  223.   // convert to unicode here
  224.   int   wclen=Unicode::WCLength(m_encoding,mbbuf,nread);
  225.   Buffer<wchar_t> wcbuf(wclen);
  226.   Unicode::ToWC(m_encoding,mbbuf,nread,wcbuf,wclen);
  227.   // strip whitespace and soft hyphens
  228.   Paragraph   ret(len);
  229.   wchar_t   *bp=ret.str;
  230.   Attr   *cfp=ret.cflags;
  231.   Attr   fmt;
  232.   int   count=0;
  233.   int   i;
  234.   ret.cflags.Zero();
  235.   fmt.wa=0;
  236.   // skip leading spaces
  237.   for (i=0;i<wclen && SPACE(wcbuf[i]);++i);
  238.   // copy text
  239.   while (i<wclen && count<len) {
  240.     // copy word
  241.     while (i<wclen && count<len && !RSPACE(wcbuf[i])) {
  242.       if (wcbuf[i]!=SHY)
  243. bp[count++]=wcbuf[i];
  244.       else { // handle hyphenation
  245. // XXX
  246.       }
  247.       ++i;
  248.     }
  249.     // skip spaces
  250.     while (i<wclen && SPACE(wcbuf[i]))
  251.       ++i;
  252.     if (i<wclen && count<len) // not a trailing space
  253.       bp[count++]=' ';
  254.   }
  255.   ASSERT(len==count);
  256.   //p.len=count; // update paragraph length
  257.   ret.str.setsize(len);
  258.   ret.len=len;
  259.   ret.findent=3; // XXX
  260.   return ret;
  261. }
  262. // XXX depends on the order of records in g_simple_formats
  263. int TextParser::DetectFormat(CBufFile *fp) {
  264.   int lines,ws,chars,check=_T('n'),base=0;
  265.   Buffer<BYTE> buf(2048);
  266.   int nb;
  267.   fp->seek(0);
  268.   nb=fp->read(buf,2048);
  269.   /* check if this is some sort of xml */
  270.   if (nb>8 && (memcmp("<?xml",buf,5)==0 || memcmp("xefxbbxbf<?xml",buf,8)==0))
  271.     return XML_FORMAT;
  272.   /* check for png */
  273.   if (nb>=4 && memcmp("x89PNG",buf,4)==0)
  274.     return PNG_FORMAT;
  275.   /* check for jpeg */
  276.   if (nb>=10 && buf[0]==0xff && buf[1]==0xd8 &&
  277.       (memcmp("JFIF",buf+6,4)==0 || memcmp("Exif",buf+6,4)==0))
  278.     return JPEG_FORMAT;
  279.   /* check if this is macintosh crap with their CR madness */
  280.   for (chars=0;chars<nb;++chars) {
  281.     if (buf[chars]=='n')
  282.       goto ok;
  283.   }
  284.   check='r';
  285.   base=2;
  286. ok:
  287.   /* we read first 50 lines and if more than 3 of them start with spaces,
  288.   and there are no lines longer than 80 chars, then this a spaced format */
  289.   int n=0;
  290.   for (lines=ws=0;lines<50;++lines) {
  291.     for (chars=0;;++chars) {
  292.       if (n>=nb) {
  293. ++lines;
  294. goto done;
  295.       }
  296.       int     ch=buf[n++];
  297.       if (chars==0 && ch==_T(' '))
  298. ++ws;
  299.       if (ch==check)
  300. break;
  301.     }
  302.     if (chars>80 && lines>5) /* got a long line, but after the first five */
  303.       return base;
  304.   }
  305. done:
  306.   if (lines>10 && ws>3)
  307.     return base+1;
  308.   return base;
  309. }
  310. int TextParser::GetNumFormats() {
  311.   return NUM_SIMPLE_FORMATS+1;
  312. }
  313. const TCHAR *TextParser::GetFormatName(int format) {
  314.   if (format<0 || format>=NUM_SIMPLE_FORMATS+NUM_EXT_FORMATS)
  315.     return _T("Invalid format ID");
  316.   if (format>=NUM_SIMPLE_FORMATS)
  317.     return g_ext_formats[format-NUM_SIMPLE_FORMATS];
  318.   return g_simple_formats[format].name;
  319. }
  320. /* Image parser */
  321. class ImageParser : public TextParser, public ImageLoader::BinReader {
  322. protected:
  323.   Image   m_cache;
  324.   int   m_crot,m_cmaxw,m_cmaxh;
  325. public:
  326.   ImageParser(Meter *m,CBufFile *fp,HANDLE heap,int format,int encoding,Bookmarks *bmk) :
  327.       TextParser(m,fp,heap,bmk)
  328.   {
  329.     m_format=format;
  330.     m_encoding=encoding;
  331.     m_cache.hBmp=0;
  332.   }
  333.   ~ImageParser() {
  334.     if (m_cache.hBmp)
  335.       DeleteObject(m_cache.hBmp);
  336.   }
  337.   // paragraphs
  338.   virtual int Length(int docid) { return 1; } // in paragraphs
  339.   virtual Paragraph GetParagraph(int docid,int para);
  340.   virtual int GetPLength(int docid,int para) { return para==0 ? 32 : 0; }
  341.   virtual int GetPStart(int docid,int para) { return 0; }
  342.   virtual int GetTotalLength(int docid) { return 32; }
  343.   virtual int LookupParagraph(int docid,int charpos) { return 0; }
  344.   // images
  345.   virtual bool GetImage(const wchar_t *name,HDC hDC,
  346.   int maxwidth,int maxheight,int rotation,Image& img);
  347.   virtual void InvalidateImageCache() {
  348.     if (m_cache.hBmp) {
  349.       DeleteObject(m_cache.hBmp);
  350.       m_cache.hBmp=0;
  351.     }
  352.   }
  353.   virtual bool IsImage() { return true; }
  354.   // BinReader interface
  355.   virtual int Read(void *buffer,int count) {
  356.     return m_fp->read(buffer,count);
  357.   }
  358. };
  359. Paragraph ImageParser::GetParagraph(int docid,int para) {
  360.   if (para!=0)
  361.     return Paragraph();
  362.   Paragraph p(ImageLoader::IMAGE_VSIZE);
  363.   p.lindent=p.rindent=p.findent=0;
  364.   for (int i=0;i<ImageLoader::IMAGE_VSIZE;++i) {
  365.     p.str[i]=L' ';
  366.     p.cflags[i].wa=0;
  367.   }
  368.   // abuse links for image href
  369.   p.links=Buffer<Paragraph::Link>(1);
  370.   p.links[0].off=0;
  371.   p.links[0].len=ImageLoader::IMAGE_VSIZE;
  372.   p.links[0].target=L"1";
  373.   p.flags=Paragraph::image;
  374.   return p;
  375. }
  376. bool ImageParser::GetImage(const wchar_t *name,HDC hDC,
  377.   int maxwidth,int maxheight,int rotation,Image& img)
  378. {
  379.   if (!name || wcscmp(name,L"1"))
  380.     return false;
  381.   if (m_cache.hBmp &&
  382.       (m_cmaxw==maxwidth || (m_cache.width<m_cmaxw && m_cache.width<maxwidth)) &&
  383.       (m_cmaxh==maxheight || (m_cache.height<m_cmaxh && m_cache.height<maxheight)) &&
  384.       m_crot==rotation)
  385.   {
  386.     img=m_cache;
  387.     return true;
  388.   }
  389.   if (m_cache.hBmp) {
  390.     DeleteObject(m_cache.hBmp);
  391.     m_cache.hBmp=0;
  392.   }
  393.   m_fp->seek(0);
  394.   bool ret=ImageLoader::Load(hDC,
  395.     m_format==PNG_FORMAT ? L"image/png" : L"image/jpeg",
  396.     this,maxwidth,maxheight,rotation,
  397.     m_cache.hBmp,m_cache.width,m_cache.height);
  398.   if (ret) {
  399.     img=m_cache;
  400.     m_crot=rotation;
  401.     m_cmaxh=maxheight;
  402.     m_cmaxw=maxwidth;
  403.   } else
  404.     m_cache.hBmp=0;
  405.   return ret;
  406. }
  407. TextParser *TextParser::Create(Meter *m,CBufFile *fp,int format,int encoding,Bookmarks *bmk) {
  408.   if (format<0)
  409.     return NULL;
  410.   HANDLE    heap;
  411.   heap=HeapCreate(HEAP_NO_SERIALIZE,1048576*4,0); // reserve up to 4 megs of ram
  412.   if (!heap)
  413.     return NULL;
  414.   TRY {
  415.     if (format<NUM_SIMPLE_FORMATS) {
  416.       fp->seek(0);
  417.       return new SimpleTextParser(m,fp,heap,format,encoding,bmk);
  418.     } else if (format==XML_FORMAT) { /* XML */
  419.       XMLParser *p=XMLParser::MakeParser(m,fp,bmk,heap);
  420.       p->m_format=NUM_SIMPLE_FORMATS;
  421.       if (p->ParseFile(encoding))
  422. return p;
  423.       delete p;
  424.     } else if (format==PNG_FORMAT || format==JPEG_FORMAT) { /* Images */
  425.       return new ImageParser(m,fp,heap,format,encoding,bmk);
  426.     }
  427.   } CATCH_ALL(e) {
  428.     HeapDestroy(heap);
  429.     THROW_LAST();
  430.   }
  431.   END_CATCH_ALL
  432.   return NULL;
  433. }
  434. // hyphenation code by Mark Lipsman, modified my Mike
  435. static BYTE   vlist[0x92]={
  436. //0 1 2 3 4 5 6 7 8 9 a b c d e f
  437.   0,1,0,0,1,0,1,1,0,0,0,0,0,0,1,0, // 0x400-0x40f
  438.   1,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0, // 0x410-0x41f
  439.   0,0,0,1,0,0,0,0,0,0,2,1,3,1,1,1, // 0x420-0x42f
  440.   1,0,0,0,0,1,0,0,1,0,0,0,0,0,1,0, // 0x430-0x43f
  441.   0,0,0,1,0,0,0,0,0,0,2,1,3,1,1,1, // 0x440-0x44f
  442.   0,1,0,0,1,0,1,1,0,0,0,0,0,0,1,0, // 0x450-0x45f
  443. };
  444. #define isLetter(ch) ((ch)>=0x0401 && (ch)<=0x0491)
  445. #define isVowel(ch) (vlist[(ch)-0x400]==1)
  446. #define isHardSign(ch) (vlist[(ch)-0x400]==2) 
  447. #define isSoftSign(ch) (vlist[(ch)-0x400]==3)
  448. #define isConsonant(ch) (vlist[(ch)-0x400]==0)
  449. void  Paragraph::Hyphenate() {
  450.   if (flags&hypdone)
  451.     return;
  452.   flags|=hypdone;
  453.   DWORD len=str.size();
  454.   if (!len)
  455.     return;
  456.   const wchar_t *s=str;
  457.   Attr *a=cflags;
  458.   DWORD start,end,i,j;
  459.   for (start=0;start<len;) {
  460.     // find start of word
  461.     while (start<len && !isLetter(s[start]))
  462.       ++start;
  463.     // find end of word
  464.     for (end=start+1;end<len && isLetter(s[end]);++end) ;
  465.     // now look over word, placing hyphens
  466.     if (end-start>3) // word must be long enough
  467.       for (i=start;i<end-3;++i)
  468. if (isVowel(s[i]))
  469.   for (j=i+1;j<end;++j)
  470.     if (isVowel(s[j])) {
  471.       if (isConsonant(s[i+1]) && isConsonant(s[i+2]))
  472. ++i;
  473.       else if (isConsonant(s[i+1]) && 
  474. (isHardSign(s[i+2]) || isSoftSign(s[i+2])))
  475. i+=2;
  476.       if (i-start>1 && end-i>2)
  477. a[i+1].hyphen=true;
  478.       break;
  479.     }
  480.     start=end;
  481.   }
  482. }