📄 xmlparser.cpp
字号:
f.str=m_buffer.Get(len);
memcpy((wchar_t*)f.str,text,len*sizeof(wchar_t));
f.attr|=LOCAL;
} else {
f.len=XML_GetCurrentByteCount(m_parser);
f.fpos=XML_GetCurrentByteIndex(m_parser);
}
m_frags.Add(f);
}
}
// expat callbacks
void XMLParserImp::StartElementCB(void *udata,const wchar_t *name,
const wchar_t **attr)
{
((XMLParserImp*)udata)->StartElement(name,attr);
}
void XMLParserImp::EndElementCB(void *udata,const wchar_t *name) {
((XMLParserImp*)udata)->EndElement(name);
}
void XMLParserImp::CharDataCB(void *udata,const wchar_t *text,int len) {
((XMLParserImp*)udata)->CharData(text,len);
}
void XMLParserImp::StartCDataCB(void *udata) {
((XMLParserImp*)udata)->m_ps->attr|=CDATA;
}
void XMLParserImp::EndCDataCB(void *udata) {
((XMLParserImp*)udata)->m_ps->attr&=~CDATA;
}
int XMLParserImp::UnknownEncodingCB(void *data,const wchar_t *name,
XML_Encoding *info)
{
int cp=Unicode::FindCodePage(Unicode::ToCS(name,wcslen(name)));
const wchar_t *tab=NULL;
if (cp>=0)
tab=Unicode::GetTable(cp);
if (!tab)
return 0;
info->data=NULL;
info->convert=NULL;
info->release=NULL;
for (int i=0;i<256;++i)
info->map[i]=tab[i];
((XMLParserImp*)data)->m_encoding=cp;
return 1;
}
bool XMLParserImp::ParseFile(int encoding) {
XML_Memory_Handling_Suite xmm={ my_malloc, my_realloc, my_free };
xmm.priv=(void*)m_heap;
ParseState pstate;
memset(&pstate,0,sizeof(pstate));
m_ps=&pstate;
FmtArray docstyles;
docstyles.SetSize(0,64);
WMap docstylemap(m_heap,true);
pstate.styles=&docstyles;
pstate.stylemap=&docstylemap;
SP_State spstate;
m_sps=&spstate;
const wchar_t *enc=NULL;
if (encoding>=0) {
enc=Unicode::GetCodePageNameW(encoding);
if (!enc)
encoding=-1;
}
if (!(m_parser=XML_ParserCreate_MM(enc,&xmm,L"|")))
return false;
XML_SetElementHandler(m_parser,XMLParserImp::StartElementCB,
XMLParserImp::EndElementCB);
XML_SetCharacterDataHandler(m_parser,XMLParserImp::CharDataCB);
XML_SetCdataSectionHandler(m_parser,StartCDataCB,EndCDataCB);
XML_SetUnknownEncodingHandler(m_parser,XMLParserImp::UnknownEncodingCB,this);
XML_SetUserData(m_parser,this);
m_encoding=-1;
// now suck in the file
m_fp->seek(0);
switch (setjmp(pstate.jout)) {
case 0:
for (;;) {
void *buf=(char*)XML_GetBuffer(m_parser,RFile::BSZ);
if (!buf) {
CTVApp::Barf(_T("XML parser: Out of memory"));
goto fail;
}
int nr=m_fp->read(buf,RFile::BSZ);
if (!XML_ParseBuffer(m_parser,nr,nr<RFile::BSZ)) {
CTVApp::Barf(
#ifdef UNICODE
_T("XML parse error: %s at line %d, column %d"),
#else
_T("XML parse error: %S at line %d, column %d"),
#endif
XML_ErrorString(XML_GetErrorCode(m_parser)),
XML_GetCurrentLineNumber(m_parser),XML_GetCurrentColumnNumber(m_parser)+1);
goto fail;
}
if (nr<RFile::BSZ)
break;
}
break;
case ERR_NOTFB2:
CTVApp::Barf(_T("Not a FictionBook2 document"));
goto fail;
}
if (m_docs.GetSize()>0) {
Document d;
d.start=0;
d.length=m_docs[0].start-1;
d.name=_T("#Description");
m_docs.Add(d);
}
return true;
fail:
//XML_ParserFree(m_parser);
// parser is now destroyed in the XMLParserImp destructor
return false;
}
XMLParser *XMLParser::MakeParser(Meter *m,CBufFile *fp,Bookmarks *bmk,HANDLE heap) {
return new XMLParserImp(m,fp,bmk,heap);
}
void XMLParserImp::ParseStylesheet(const wchar_t *text,int len) {
wchar_t ch;
while (len--) {
ch=*text++;
switch (m_sps->state) {
case SP_State::START:
if (!iswspace(ch)) {
m_sps->NAdd(ch);
m_sps->state=SP_State::NAME;
}
break;
case SP_State::NAME:
if (!iswspace(ch))
m_sps->NAdd(ch);
else
m_sps->state=SP_State::FLAGS;
break;
case SP_State::FLAGS:
flags:
switch (ch) {
case L'b':
m_sps->format.bold=1;
break;
case L'B':
m_sps->format.bold=0;
break;
case L'i':
m_sps->format.italic=1;
break;
case L'I':
m_sps->format.italic=0;
break;
case L'u':
m_sps->format.underline=1;
break;
case L'U':
m_sps->format.underline=0;
break;
case L'r':
m_sps->format.align=Paragraph::right;
break;
case L'c':
m_sps->format.align=Paragraph::center;
break;
case L'j':
m_sps->format.align=Paragraph::justify;
break;
case L'l':
m_sps->format.align=0;
break;
case L'h':
m_sps->state=SP_State::COLOR;
m_sps->num=0; m_sps->sign=false;
break;
case L'L':
m_sps->state=SP_State::LM;
m_sps->num=0; m_sps->sign=false;
break;
case L'R':
m_sps->state=SP_State::RM;
m_sps->num=0; m_sps->sign=false;
break;
case L'F':
m_sps->state=SP_State::FM;
m_sps->num=0; m_sps->sign=false;
break;
case L'S':
m_sps->state=SP_State::SIZE;
m_sps->num=0; m_sps->sign=false;
break;
case L';':
m_sps->stylename[m_sps->stylenameptr]=L'\0';
m_ps->stylemap->AddCopy(m_sps->stylename,(void*)m_ps->styles->GetSize());
m_ps->styles->Add(m_sps->format);
m_sps->Init();
break;
}
break;
case SP_State::FM:
case SP_State::LM:
case SP_State::RM:
case SP_State::SIZE:
case SP_State::COLOR:
if (iswdigit(ch)) {
m_sps->num=m_sps->num*10+ch-L'0';
} else if (ch=='-')
m_sps->sign=1;
else { // end of spec
int val=m_sps->num;
if (m_sps->sign)
val=-val;
switch (m_sps->state) {
case SP_State::FM:
val=RClamp(val,-100,100);
m_sps->format.findent=val;
break;
case SP_State::LM:
val=RClamp(val,-100,100);
m_sps->format.lindent=val;
break;
case SP_State::RM:
val=RClamp(val,-100,100);
m_sps->format.rindent=val;
break;
case SP_State::COLOR:
val=RClamp(val,0,7);
m_sps->format.color=val;
break;
case SP_State::SIZE:
val=RClamp(val,-100,100);
m_sps->format.fsz=val;
break;
}
m_sps->state=SP_State::FLAGS;
goto flags;
}
break;
}
}
}
void XMLParser::SaveStyles() {
for (int i=0;i<g_eformat.GetSize();++i)
if (g_eformat[i].name.GetLength() && g_eformat[i].name[0]!=_T('*')) {
CString str;
str.Format(_T("%d,%d,%d,%d,%d,%d,%d,%d,%d"),
g_eformat[i].fsz,
g_eformat[i].bold,
g_eformat[i].italic,
g_eformat[i].underline,
g_eformat[i].color,
g_eformat[i].align,
g_eformat[i].lindent,
g_eformat[i].rindent,
g_eformat[i].findent);
AfxGetApp()->WriteProfileString(_T("Styles"),g_eformat[i].name,str);
}
}
static void AddElement(const wchar_t *name,int namelen,int id) {
wchar_t buf[128];
wcscpy(buf,FB_NS);
buf[FB_NS_LEN]=L'|';
if (namelen>sizeof(buf)/sizeof(wchar_t)-2-FB_NS_LEN)
namelen=sizeof(buf)/sizeof(wchar_t)-2-FB_NS_LEN;
wcsncpy(buf+FB_NS_LEN+1,name,namelen);
buf[FB_NS_LEN+1+namelen]=L'\0';
g_elements->AddCopy(buf,(void*)id);
g_elements->AddCopy(buf+FB_NS_LEN,(void*)id);
g_elements->AddCopy(buf+FB_NS_LEN+1,(void*)id);
}
static inline int FLAG(wchar_t x) {
return x==L'+' ? 1 : x==L'-' ? 0 : XMLParser::ElemFmt::NOCHG;
}
static void ParseXMLSettings(const wchar_t *fmt,DWORD sz) {
const wchar_t *p=fmt;
const wchar_t *e=fmt+sz;
const wchar_t *le;
wchar_t *q;
if (p<e && *p==0xFEFF)
++p;
while (p<e) {
for (le=p;le<e && *le!=L'\r' && *le!=L'\n';++le) ;
// process line here
if (p!=le && *p!=L'#' && *p!=L' ' && *p!=L'\t') {
XMLParser::ElemFmt fe;
wchar_t *name=NULL;
int size;
wchar_t bold,italic,underline;
int color;
wchar_t align;
int leftm,rightm,firstm;
wchar_t *action=NULL,*elements=NULL;
int fields;
if (Scan::xscanf(p,le-p,L"%S %-100,100,127d "
L"%c %c %c %0,8,127d %c %-100,100,127d "
L"%-100,100,127d %-100,100,127d %S %S",NULL,&fields,
&name,&size,&bold,&italic,&underline,
&color,&align,&leftm,&rightm,&firstm,
&action,&elements)==0 && fields==12)
{
for (q=name;*q;++q)
if (*q==L'_')
*q=L' ';
fe.name=name;
fe.fsz=size;
fe.bold=FLAG(bold);
fe.italic=FLAG(italic);
fe.underline=FLAG(underline);
fe.color=color;
switch (align) {
case 'R':
fe.align=Paragraph::right;
break;
case 'C':
fe.align=Paragraph::center;
break;
case 'J':
fe.align=Paragraph::justify;
break;
default:
fe.align=XMLParser::ElemFmt::NOCHG;
break;
}
fe.lindent=leftm;
fe.rindent=rightm;
fe.findent=firstm;
fe.flags=0;
for (q=action;*q;++q) {
const TCHAR *fp=XMLParser::ElemFmt::flag_names;
for (int flags=1;*fp;flags<<=1,++fp)
if (*fp==*q) {
fe.flags|=flags;
break;
}
}
for (p=elements;*p;) {
const wchar_t *q; // XXX
for (q=p;*q && *q!=L',';++q) ;
if (q!=p)
AddElement(p,q-p,g_eformat.GetSize());
p=q;
if (*p==L',')
++p;
}
// ok, insert it now
g_eformat.Add(fe);
}
delete[] name;
delete[] action;
delete[] elements;
}
// skip end of line
for (p=le;p<e && (*p=='\r' || *p=='\n');++p) ;
}
}
void XMLParser::LoadStyles() {
ElemFmt ef;
// delete all elements
g_eformat.RemoveAll();
delete g_elements;
g_elements=new WMap(GetProcessHeap(),true);
// always initialize a default element
ef.Clear();
g_eformat.Add(ef);
// read parser settings from a resource
HMODULE hMod=AfxGetResourceHandle();
HRSRC hRes=FindResource(hMod,_T("xml_elements"),RT_RCDATA);
if (hRes) {
DWORD rsize=SizeofResource(hMod,hRes);
HGLOBAL hGlob=LoadResource(hMod,hRes);
if (hGlob) {
void *res=LockResource(hGlob);
if (res) {
ParseXMLSettings((const wchar_t *)res,rsize/sizeof(wchar_t));
UnlockResource(hGlob);
}
FreeResource(hGlob);
}
}
// adjust formatting from registry
for (int fnum=0;fnum<g_eformat.GetSize();++fnum)
if (g_eformat[fnum].name.GetLength()>0 && g_eformat[fnum].name[0]!=_T('*')) {
CString str=AfxGetApp()->GetProfileString(_T("Styles"),g_eformat[fnum].name);
int f,b,i,c,a,li,ri,fi,u;
if (_stscanf(str,_T("%d,%d,%d,%d,%d,%d,%d,%d,%d"),&f,&b,&i,&u,&c,&a,&li,&ri,&fi)==9) {
g_eformat[fnum].fsz=f;
g_eformat[fnum].bold=b;
g_eformat[fnum].italic=i;
g_eformat[fnum].underline=u;
g_eformat[fnum].color=c;
g_eformat[fnum].align=a;
g_eformat[fnum].lindent=li;
g_eformat[fnum].rindent=ri;
g_eformat[fnum].findent=fi;
}
}
}
XMLParser::FmtArray& XMLParser::GetXMLStyles() {
return g_eformat;
}
void XMLParser::ElemFmt::Clear() {
fsz=NOCHG;
bold=NOCHG;
italic=NOCHG;
color=NOCHG;
align=NOCHG;
underline=NOCHG;
flags=0;
lindent=NOCHG;
rindent=NOCHG;
findent=NOCHG;
name.Empty();
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -