📄 xmlfile.cpp.svn-base
字号:
}
else
return _T("");
}
CString CXmlNode::GetXML() {
CString strXML;
POSITION pos = GetFirstChildPos();
while (pos != NULL) {
CXmlNode *child = GetNextChild(pos);
CString sName, sAttrs;
CString sTag;
POSITION posAttr;
switch (child->GetType()) {
case CXmlNode::Tag:
sAttrs.Empty();
posAttr = child->Attrs.GetHeadPosition();
while (posAttr != NULL) {
CXmlAttr *attr = child->Attrs.GetNext(posAttr);
CString strPair;
strPair.Format(_T(" %s=\"%s\""), attr->GetName(), attr->GetValue());
sAttrs += strPair;
}
sName = child->GetName();
if (child->GetChildCount() > 0) {
sTag.Format(_T("<%s%s>%s</%s>"), sName, sAttrs, child->GetXML(), sName);
}
else {
sTag.Format(_T("<%s%s/>"), sName, sAttrs);
}
strXML += sTag;
break;
case CXmlNode::Data:
strXML += child->Text;
break;
}
}
strXML.TrimLeft();
strXML.TrimRight();
return strXML;
}
//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////
CXmlFile::CXmlFile() {
RootNode = NULL;
Encoding = NULL;
TempNode = NULL;
}
CXmlFile::~CXmlFile() {
delete RootNode;
if (Encoding != NULL) delete [] Encoding;
}
void CXmlFile::OnStartElement(const char *name, const char **attr) {
// LOG1(1, "OnStart('%s')", name);
CString sName = CharToWChar(name);
CList<CXmlAttr*, CXmlAttr*> arAttrs;
// create array of attributes
for (int i = 0; attr[i]; i += 2)
arAttrs.AddTail(new CXmlAttr(CharToWChar(attr[i]), CharToWChar(attr[i + 1], CP_UTF8)));
CXmlNode *newNode = new CXmlNode(CXmlNode::Tag, TempNode, sName, arAttrs);
if (RootNode == NULL)
RootNode = newNode;
else {
// if (TempNode != NULL) {
CString temp = TempValue;
temp.TrimLeft();
temp.TrimRight();
if (!temp.IsEmpty()) {
TempNode->AddChild(new CXmlNode(CXmlNode::Data, TempNode, TempValue));
}
TempNode->AddChild(newNode);
}
TempNode = newNode;
TempValue.Empty();
}
void CXmlFile::OnEndElement(const char *name) {
// LOG1(1, "OnEnd('%s')", name);
if (TempNode != NULL) {
CXmlNode *node = new CXmlNode(CXmlNode::Data, TempNode, TempValue);
TempNode->AddChild(node);
TempNode = TempNode->GetParentNode();
}
TempValue.Empty();
}
void CXmlFile::OnCharacterData(const char *name, int len) {
// LOG1(1, "CXmlFile::OnCharacterData(, %d)", len);
int wLen = MultiByteToWideChar(CP_UTF8, 0, name, len, NULL, 0);
CString s;
LPTSTR wStr = s.GetBufferSetLength(wLen);
MultiByteToWideChar(CP_UTF8, 0, name, len, wStr, wLen);
TempValue += s;
}
/*void CXmlFile::OnDefault(const XML_Char *s, int len) {
LOG1(1, "CXmlFile::OnDefault(, %d)", len);
char *n = new char [len + 1];
strncpy(n, s, len);
n[len] = '\0';
LOG1(1, "D: '%s'", n);
delete [] n;
}
*/
void CXmlFile::OnDeclaration(const XML_Char *version, const XML_Char *encoding, int standalone) {
LOG3(7, "CXmlFile::OnDeclaration('%s', '%s', %d)", version, encoding, standalone);
if (Encoding != NULL) delete [] Encoding;
if (encoding != NULL) {
Encoding = DuplicateString(encoding);
_strlwr(Encoding);
// crippling pRSSreader: some sites reports iso-8859-1 but they use cp1252 (it is common, to
// treat iso-8859-1 encoded files as cp-1252)
if (strcmp(Encoding, "iso-8859-1") == 0) {
delete [] Encoding;
Encoding = DuplicateString("windows-1252");
}
}
else {
Encoding = DuplicateString(DefaultEncoding);
_strlwr(Encoding);
}
}
int CXmlFile::GetBomLen(char *buffer) {
if (strncmp(buffer, "\x00\x00\xFE\xFF", 4) == 0) return 4; // UTF-32 big-endian
else if (strncmp(buffer, "\xFF\xFE\x00\x00", 4) == 0) return 4; // UTF-32 little-endian
else if (strncmp(buffer, "\xFE\xFF", 2) == 0) return 2; // UTF-16 big-endian
else if (strncmp(buffer, "\xFF\xFE", 2) == 0) return 2; // UTF-16 little-endian
else if (strncmp(buffer, "\xEF\xBB\xBF", 3) == 0) return 3; // UTF-8
else return 0;
}
#define BUFSIZ 16384
// tries to determine XML document encoding from buffer
BOOL CXmlFile::DetermineEncoding(char buffer[], int len) {
LOG0(7, "CXmlFile::DetermineEncoding(, )");
XML_Parser parser;
parser = XML_ParserCreate(NULL);
XML_SetUserData(parser, this);
XML_SetXmlDeclHandler(parser, declHandler);
XML_SetElementHandler(parser, NULL, NULL);
XML_SetCharacterDataHandler(parser, NULL);
XML_SetUnknownEncodingHandler(parser, NULL, 0);
// set default encoding
if (Encoding != NULL) delete [] Encoding;
Encoding = DuplicateString(DefaultEncoding);
BOOL done = FALSE;
XML_Parse(parser, buffer, len, done);
XML_ParserFree(parser);
delete RootNode;
RootNode = TempNode = NULL;
return TRUE;
}
BOOL CXmlFile::LoadFromFile(LPCTSTR fileName) {
LOG1(5, "CXmlFile::LoadFromFile('%S')", fileName);
char buf[BUFSIZ];
BOOL done;
int depth = 0;
HANDLE hFile = CreateFile(fileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
if (hFile == INVALID_HANDLE_VALUE) {
return FALSE;
}
delete RootNode;
RootNode = TempNode = NULL;
int bomLen = 0;
// first get the encoding
// load first 8K (should be enough to determine the encoding)
DWORD read = 0;
if (ReadFile(hFile, buf, BUFSIZ, &read, NULL)) {
bomLen = GetBomLen(buf);
if (!DetermineEncoding(buf + bomLen, BUFSIZ))
return FALSE;
}
else
return FALSE;
BOOL ret = TRUE;
XML_Parser parser = XML_ParserCreate("prssr");
XML_SetUserData(parser, this);
XML_SetXmlDeclHandler(parser, NULL);
XML_SetElementHandler(parser, startElement, endElement);
XML_SetCharacterDataHandler(parser, charDataHandler);
XML_SetUnknownEncodingHandler(parser, unknownEncoding, this);
SetFilePointer(hFile, bomLen, NULL, FILE_BEGIN);
// main load loop with the parsing
do {
DWORD read;
done = FALSE;
if (ReadFile(hFile, buf, BUFSIZ, &read, NULL)) {
done = read < BUFSIZ;
if (XML_Parse(parser, buf, read, done) == XML_STATUS_ERROR) {
LOG2(1, "Error: %s at line %d",
XML_ErrorString(XML_GetErrorCode(parser)),
XML_GetCurrentLineNumber(parser));
ret = FALSE;
delete RootNode;
RootNode = TempNode = NULL;
break;
}
}
} while (!done);
CloseHandle(hFile);
// RootNode = TempNode;
TempNode = NULL;
XML_ParserFree(parser);
return ret;
}
#if defined PRSSR_APP
BOOL CXmlFile::LoadFromMemory(char buffer[], int len) {
LOG0(7, "CXmlFile::LoadFromMemory()");
int depth = 0;
delete RootNode;
RootNode = TempNode = NULL;
int bomLen = GetBomLen(buffer); // FIXME: if buffer is small and no BOM is present
// first get the encoding
if (!DetermineEncoding(buffer + bomLen, min(BUFSIZ, len)))
return FALSE;
// LOG1(7, "Encoding ('%S')", Encoding);
XML_Parser parser = XML_ParserCreate("prssr");
XML_SetUserData(parser, this);
XML_SetXmlDeclHandler(parser, NULL);
XML_SetElementHandler(parser, startElement, endElement);
XML_SetCharacterDataHandler(parser, charDataHandler);
XML_SetUnknownEncodingHandler(parser, unknownEncoding, this);
BOOL ret = TRUE;
// main load loop with the parsing
BOOL done = FALSE;
if (XML_Parse(parser, buffer + bomLen, len, done) == XML_STATUS_ERROR) {
LOG2(7, "Error: %s at line %d",
XML_ErrorString(XML_GetErrorCode(parser)),
XML_GetCurrentLineNumber(parser));
ret = FALSE;
delete RootNode;
RootNode = TempNode = NULL;
}
else {
// RootNode = TempNode;
TempNode = NULL;
}
XML_ParserFree(parser);
return ret;
}
CString CXmlFile::FormatAttributeValue(const CString &value) {
CString s = value;
s.Replace(_T("&"), _T("&"));
s.Replace(_T("<"), _T("<"));
s.Replace(_T("\""), _T("""));
s.Replace(_T(">"), _T(">"));
s.Replace(_T("\t"), _T("	"));
s.Replace(_T("\n"), _T("
"));
s.Replace(_T("\r"), _T("
"));
return s;
}
BOOL CXmlFile::SaveNode(CBufferedFile &file, CXmlNode *node) {
static int depth = 0;
CString indent;
if (depth > 0)
indent = CString('\t', depth);
CString sAttrs;
POSITION posAttr = node->GetFirstAttrPos();
while (posAttr != NULL) {
CXmlAttr *attr = node->GetNextAttr(posAttr);
CString sA;
sA.Format(_T(" %s=\"%s\""), attr->GetName(), FormatAttributeValue(attr->GetValue()));
sAttrs += sA;
}
BOOL ret = TRUE;
CString tag;
if (node->GetValue().GetLength() == 0 && node->GetChildCount() == 0) {
// just to have nice output
if (sAttrs.GetLength() > 0)
sAttrs += ' ';
ret = ret ? WriteFileString(file, indent, CP_UTF8) : FALSE;
tag.Format(_T("<%s%s/>\n"), node->GetName(), sAttrs);
ret = ret ? WriteFileString(file, tag, CP_UTF8) : FALSE;
}
else {
// openning tag
ret = ret ? WriteFileString(file, indent, CP_UTF8) : FALSE;
tag.Format(_T("<%s%s>\n"), node->GetName(), sAttrs);
ret = ret ? WriteFileString(file, tag, CP_UTF8) : FALSE;
if (ret) {
// FIXME: saving the value of the tag
depth++;
POSITION pos = node->GetFirstChildPos();
while (pos != NULL) {
CXmlNode *child = node->GetNextChild(pos);
if (!SaveNode(file, child)) {
ret = FALSE;
break;
}
}
depth--;
}
// closing tag
ret = ret ? WriteFileString(file, indent, CP_UTF8) : FALSE;
tag.Format(_T("</%s>\n"), node->GetName());
ret = ret ? WriteFileString(file, tag, CP_UTF8) : FALSE;
}
return ret;
}
BOOL CXmlFile::Save(LPCTSTR fileName) {
CBufferedFile file;
if (file.Create(fileName, GENERIC_WRITE, 0, CREATE_ALWAYS, 0)) {
BOOL ret = TRUE;
// save xml header
CString hdr;
hdr.Format(_T("<?xml version=\"1.0\" encoding=\"utf-8\"?>\n"));
ret = ret ? WriteFileString(file, hdr, CP_UTF8) : FALSE;
// save xml
ret = ret ? SaveNode(file, RootNode) : FALSE;
file.Close();
return ret;
}
else
return FALSE;
}
#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -