/*
* XMLTool.cpp 配置文件解析动态库资源文件
* 主要输出函数接口分别实现对配置文件的读取和写入,针对结果集的复制清空,和两个字符串处理函数
* 读取配置文件接口 :int ReadXMLFile(XML_Node_Vector *XmlNodeVector, string filepath);
* 写入配置文件接口 :int WriteXMLFile(XML_Node_Vector *XmlNodeVector, string filepath,bool is_addend = true);
* 复制结构集接口 :bool VecDataCopy(XML_Node_Vector *XmlNodeVectorDest,const XML_Node_Vector *XmlNodeVectorSource);
* 清空结构集接口 :bool VecDataClean(XML_Node_Vector *XmlNodeVector);
* 字符串安全拷贝接口 :bool strncpy_ex(char *pStrDest,const char *pStrSource,int nDestSize);
* 字符串安全处理接口 :bool printf_ex(char* szBuf,int nDestSize,char *szFormat, ...);
*
* 配置文件信息结构大概如下 注意 <> 符号包括其中的字符串仅为现在说名信息
*
* |[1234<节点头数据>]<节点头>
* |abc<节点前信息体数据>=123<节点后信息体数据>
* |123<节点前信息体数据>=890<节点后信息体数据>
* |
* 注意:
* 0.所有有效行数据必须顶格书写否者将不会读取该行数据,将作为无效数据处理 (所有无效数据将不予读取
* 0.1:不顶格书写
* 0.2:顶格第一个字符为 # 或 $
* 0.3:顶格第一个字符为 =
* 1.节点前信息体数据在读取数据的时候自动舍去空格,而节点后信息体数据不做处理,将原样读取
* 2. # 和 $ 符号为注解符 遇到他们开始的行将不读取他们的数据 或者在不顶行书写
* 3.具体数据结构请对照定义
*
* createtime:2010-1-26
* edittime:2010-1-27
* creator:seky.gu
* editor;seky.gu
* mingyao.gu@hp.com
*/
#include "XMLTool.h"
#include <stdarg.h>
#include <iostream>
#include <fstream>
using namespace std;
//返回值定义
#define RETURN_VALUE_SUCCESS 0//操作成功
#define RETURN_VALUE_PARAMETER_ERROR 1//非法参数
#define RETURN_VALUE_FILEOPEN_ERROR 2//文件打开出错
#define RETURN_VALUE_MEM_OPERATION_ERROR 3//文件打开出错
#define RETURN_VALUE_FILE_OPERATION_ERROR 4//文件内容不能构成至少一个节点
//注解符定义
#define COMMENT_CHAR_1 23 // '#'
#define COMMENT_CHAR_2 24 // '$'
/*定义是否去掉头结点数据中的空格*/
#define COMMENT_CHAR_3 ' ' // 节点头的空格,这样定义将去掉节点头空格 默认去空格
//#define COMMENT_CHAR_3 '/0' // 节点头的空格,这样定义将不会去掉节点头空格
/*定义是否去掉信息体等号前的空格*/
#define COMMENT_CHAR_4 ' ' // 节点信息体等号之前数据的空格,这样定义将去掉空格 默认去空格
//#define COMMENT_CHAR_4 '/0' // 节点信息体等号之前数据的空格,这样定义将保留空格
/*定义是否去掉信息体等号后的空格*/
//#define COMMENT_CHAR_5 ' ' // 节点信息体等号之后数据的空格,这样定义将去掉空格
#define COMMENT_CHAR_5 '/0' // 节点信息体等号之后数据的空格,这样定义将保留空格 默认保留空格
#define ASSERT_STL_EMPTY(item)/
if(0 != item->GetItemCount()) return RETURN_VALUE_PARAMETER_ERROR
#define ASSERT_STL_NOEMPTY(item)/
if(0 == item->GetItemCount()) return RETURN_VALUE_PARAMETER_ERROR
#define ASSERT_STLex_NOEMPTY(item)/
if(0 == item->xml_node_vector.size()) return (RETURN_VALUE_PARAMETER_ERROR-1)
#define ZEROR_PVOID_MEMORY(data)/
memset(data,0,sizeof(data))
#define ZEROR_STRING_MEMORY(data)/
memset(&data,0,sizeof(data))
//函数实现
extern "C"
{
/* 读取配置文件
* int ReadXMLFile(XML_Node_Vector *XmlNodeVector, string filepath)
*
* XmlNodeVector 节点集结构体<具体见定义>
* filepath 文件路径<绝对路径 包含文件名>
*
* return 返回处理结果<详见定义>
*/
DECLDIR int ReadXMLFile(XML_Node_Vector *XmlNodeVector, string filepath)
{
//参数检查
ASSERT_STL_EMPTY(XmlNodeVector);
if(filepath.empty())return RETURN_VALUE_PARAMETER_ERROR;
//打开文件
fstream fs_file(filepath.c_str(),ios::in);
if (fs_file.bad())
{//打开出错处理
return RETURN_VALUE_FILEOPEN_ERROR;
}
//定义中间变量
char str_data[255] = {0};
//char t_data_head[255] = {0};
char t_data_first[255] = {0};
char t_data_second[255] = {0};
ZEROR_PVOID_MEMORY(str_data);
//节点零时载体
string first,second;
XML_Node *temp_node;
//字符定位变量
int i = 0;//标记总字符串
int j = 0;//标记信息体分段
int fh_point = 0;//‘]’符号位标志
int node_number = 0;//节点开始标识
//循环读取文件信息 然后进行解析
while(fs_file)
{
//读取打开文件中一行数据
fs_file.getline(str_data,sizeof(str_data));
if('/0' == str_data[0]||' ' == str_data[0]||'=' == str_data[0]||COMMENT_CHAR_1 == str_data[0]||COMMENT_CHAR_2 == str_data[0])
{//无效行返回
continue;
}
//解析数据
else if('[' == str_data[0])
{//头结点
if(0 != node_number)
{//加入结点
XmlNodeVector->InsertItem(*temp_node);
ZEROR_STRING_MEMORY(temp_node);
}
//重新设置中间变量
i = 0;
j = 0;
fh_point = 0;
//去掉节点头最后一个 ‘]’ 开始之后的字符
while('/0' != str_data[i++])
{
if((COMMENT_CHAR_3==str_data[i])||('/0'==str_data[i]))continue;
str_data[j++] = str_data[i];
if(']' == str_data[i])fh_point = j-1;
}
if(0 >= fh_point)
{
ZEROR_PVOID_MEMORY(str_data);
continue;
} else
{
str_data[fh_point] = '/0';
}
//申请新节点
temp_node = (XML_Node*)new XML_Node;
//设置新节点头
//temp_node->node_title.assign(t_data_head);
temp_node->node_title.assign(str_data);
//中间数据处理
//ZEROR_PVOID_MEMORY(t_data_head);
ZEROR_PVOID_MEMORY(str_data);
node_number++;
}else
{//信息体 没有等号 或者等号在第一位依然属于无效行
//重新设置中间变量
if(0 == node_number)continue;
i = 0;
j = 0;
while(('=' != str_data[i])&&('/0' != str_data[i]))
{
if(COMMENT_CHAR_4!=str_data[i])
t_data_first[j++] = str_data[i];
i++;
}
if((0==i)||('/0' == str_data[i]))
{//没有等号 或者等号在第一位 依然属于无效行 舍弃之前获取的字符
ZEROR_PVOID_MEMORY(t_data_first);
continue;
}else
{//合法信息体读取 ‘=’后面数据
//重新设置中间变量
i++;
j = 0;
while('/0' != str_data[i])
{
(COMMENT_CHAR_5 != str_data[i])?t_data_second[j++]=str_data[i++]:i++;
}
//将有效数据添加进数据集
first.assign(t_data_first);
second.assign(t_data_second);
temp_node->InsertItem(first,second);
ZEROR_STRING_MEMORY(first);
ZEROR_STRING_MEMORY(second);
ZEROR_PVOID_MEMORY(t_data_first);
ZEROR_PVOID_MEMORY(t_data_second);
}
}
}
if(0 < node_number)
{//加入最后一个结点
XmlNodeVector->InsertItem(*temp_node);
ZEROR_STRING_MEMORY(temp_node);
}
//关闭文件流
fs_file.close();
if(0 == XmlNodeVector->GetItemCount())
{//文件内容不能构成至少一个节点
return RETURN_VALUE_FILE_OPERATION_ERROR;
}else
{
return RETURN_VALUE_SUCCESS;
}
}
/* 将节点集数据写入配置文件
* int WriteXMLFile(XML_Node_Vector *XmlNodeVector, string filepath,bool is_addend)
*
* XmlNodeVector 节点集结构体<具体见定义>
* filepath 文件路径<绝对路径 包含文件名>
* is_addend 写入类型<true 在文件末尾继续添加 false 将源文件内容更新为当前数据>
*
* return 返回处理结果<详见定义>
*/
DECLDIR int WriteXMLFile(XML_Node_Vector *XmlNodeVector, string filepath,bool is_addend)
{
//参数检查
ASSERT_STL_NOEMPTY(XmlNodeVector);
if(filepath.empty())return RETURN_VALUE_PARAMETER_ERROR;
//定义文件流对象
fstream fs_file;
//打开文件
if(is_addend)
{
fs_file.open(filepath.c_str(),ios::out|ios::app);
}else
{
fs_file.open(filepath.c_str(),ios::out);
}
if (fs_file.bad())
{//出错处理
return RETURN_VALUE_FILEOPEN_ERROR;
}
//遍历节点将数据写入文件
for(XmlNodeVector->node_item = XmlNodeVector->xml_node_vector.begin();
XmlNodeVector->node_item!=XmlNodeVector->xml_node_vector.end();
XmlNodeVector->node_item++)
{//写入节点头
fs_file<<"["<<XmlNodeVector->node_item->node_title<<"]/n";
for(XmlNodeVector->node_item->boby_item=XmlNodeVector->node_item->xml_body.begin();
XmlNodeVector->node_item->boby_item!=XmlNodeVector->node_item->xml_body.end();
XmlNodeVector->node_item->boby_item++)
{//写入节点数据体
fs_file<<XmlNodeVector->node_item->boby_item->first<<"="<<XmlNodeVector->node_item->boby_item->second<<"/n";
}
}
//关闭文件流
fs_file.close();
return RETURN_VALUE_SUCCESS;
}
/* 复制节点集信息
* int DataCopy(XML_Node_Vector *XmlNodeVectorAim,const XML_Node_Vector *XmlNodeVectorSource);
*
* XmlNodeVectorAim 目标节点集结构体<具体见定义>
* XmlNodeVectorSource 源节点集结构体<具体见定义>
*
* return 返回处理结果<详见定义>
*/
bool VecDataCopy(XML_Node_Vector *XmlNodeVectorDest,const XML_Node_Vector *XmlNodeVectorSource)
{
//参数检查
ASSERT_STL_EMPTY(XmlNodeVectorDest);
ASSERT_STLex_NOEMPTY(XmlNodeVectorSource);
//中间变量
string first,second,title;
XML_Node *temp_node;
//遍历节点将数据写入文件
unsigned int node_size = XmlNodeVectorSource->xml_node_vector.size();
unsigned int data_size = 0;
for(;
node_size > 0;
node_size--)
{//写入节点头
//申请新节点
temp_node = (XML_Node *)new XML_Node;
data_size = XmlNodeVectorSource->xml_node_vector.begin()->xml_body.size();
for(;
data_size > 0;
data_size--)
{//写入节点数据体
//first
first.assign(XmlNodeVectorSource->xml_node_vector.begin()->xml_body.begin()->first.c_str());
//second
second.assign(XmlNodeVectorSource->xml_node_vector.begin()->xml_body.begin()->second.c_str());
//node_title
title.assign(XmlNodeVectorSource->xml_node_vector.begin()->node_title.c_str());
//insert data
temp_node->InsertItem(first,second);
temp_node->node_title.assign(title);
//next
XmlNodeVectorSource->xml_node_vector.begin()->xml_body.begin()++;
}
//insert data
XmlNodeVectorDest->InsertItem(*temp_node);
XmlNodeVectorDest->node_type = XmlNodeVectorSource->node_type;
}
return true;
}
/* 清空节点集信息
* bool VecDataClean(XML_Node_Vector *XmlNodeVector);
*
* XmlNodeVector 待清空的目标节点集结构体<具体见定义>
*
* return 返回处理结果<详见定义>
*/
DECLDIR bool VecDataClean(XML_Node_Vector *XmlNodeVector)
{
XmlNodeVector->xml_node_vector.clear();
XmlNodeVector->node_type = 0;
XmlNodeVector->node_item = XmlNodeVector->xml_node_vector.begin();
return true;
}
/* 字符串安全拷贝函数(该函数检查了目标和源字符串的空间溢出问题,对于源字串长度不够填充目标字串采用0补位)
* bool strncpy_ex(char *pD,const char *pS,int nDestSize);
*
* pStrDest 目标字串<char*>
* pStrSource 源字串<char*>
* nDestSize 从源字符串拷贝到目标字符串的字符串大小<建议传递sizeof(pStrDest)>
*
* return 返回处理结果<详见定义>
*/
bool strncpy_ex(char *pCDest,const char *pCSource,int nDestSize)
{
int nLen=strlen(pCSource)+1;
if(nLen>nDestSize) nLen=nDestSize;//处理源字符串不够长的问题
memcpy(pCDest,pCSource,nLen);
*(pCDest+nLen-1)='/0';//处理源字符串不够长在最后添加结尾符
return true;
}
/* 字符串安全处理函数(该函数检查了目标和源字符串的空间溢出问题,对于源字串长度不够填充目标字串采用0补位)
* bool printf_ex(char* szBuf,int nDestSize,char *szFormat, ...);
*
* szBuf, nDestSize,szFormat,... .. .待处理的参数列表<具体参见 c++ nsprintf(... .. .)函数>
*
* return 返回处理结果<详见定义>
*/
bool printf_ex(char* szBuf,int nDestSize,char *szFormat, ...)
{
int nListCount=0;
va_list pArgList;
va_start (pArgList,szFormat);
nListCount+=_vsnprintf(szBuf+nListCount,
nDestSize-nListCount,szFormat,pArgList);
va_end(pArgList);
*(szBuf+nDestSize-1)='/0';
return strlen(szBuf);
return true;
}
}