AnInitFile.h
/*
*支持"#"和";"开头注释,链表的方式存储数据
*/
#pragma once
#include "AnHeader.h"
namespace An
{
class InitFileReader;
class InitFileWriter;
struct ElementList;
struct RootNodeList;
struct LineTextList;
//前置声明TEXTCODETYPE,会报错还在找解决方案:https://cloud.tencent.com/developer/ask/51491
code from:https://www.cnblogs.com/rcg714786690/p/14246669.html
//code type
enum TEXTCODETYPE:int
{
TEXT_UNKNOW = 0x0,
TEXT_ANSI = 0x0001,
TEXT_UTF8 = 0x0002,
};
class AnInitFile
{
public:
AnInitFile();
AnInitFile(const char *filePath);
~AnInitFile();
public:
bool Open(const char *filePath);
bool GetParam(const char *root, const char *key,char *value);
bool SetParam(const char *root, const char *key,const char *value,bool autoSave=true);
bool Save(const char *filePath=nullptr, TEXTCODETYPE type= TEXTCODETYPE::TEXT_UTF8);
private:
char defaultFilePath[AN_PARAMLEN_MAX];
InitFileReader *pInitFileReader;
InitFileWriter *pInitFileWriter;
};
class InitFileReader
{
//use friend
friend class AnInitFile;
private:
InitFileReader();
~InitFileReader();
private:
RootNodeList *pRootNodeList;
LineTextList *pLineTextList;
private:
bool Read(const char *filePath);
bool Get(const char *root, const char *key,char *value);
bool Set(const char *root, const char *key, const char *value);
void Analyse();
void Release();
TEXTCODETYPE GetCodeType(const char *filePath);
};
class InitFileWriter
{
//use friend
friend class AnInitFile;
private:
InitFileWriter();
~InitFileWriter();
private:
std::ofstream *writeStream;
private:
bool CreateWriter(const char *path);
wirte
bool Write(const char *data);
bool Write(const char *data,int length);
///save
bool Flush();
bool Flush(LineTextList *pLineTextList,RootNodeList *pRootNodeList);
//sec find
bool Find(const char *root, const char *key, char *value, RootNodeList *pRootNodeList);
};
struct ElementList
{
unsigned char Element[AN_PARAMLEN_MAX];
ElementList *nextElement;
ElementList()
{
memset(Element, 0, AN_PARAMLEN_MAX);
nextElement = nullptr;
}
};
struct RootNodeList
{
unsigned char Root[AN_PARAMLEN_MAX];
ElementList *KeyList;
ElementList *ValList;
RootNodeList *nextRootNode;
RootNodeList()
{
memset(Root, 0, AN_PARAMLEN_MAX);
KeyList = nullptr;
ValList = nullptr;
nextRootNode = nullptr;
}
};
struct
struct LineTextList
{
unsigned int RowNo;
unsigned char Text[AN_PARAMLEN_MAX];
LineTextList *nextLineText;
LineTextList()
{
RowNo = -1;
memset(Text, 0, AN_PARAMLEN_MAX);
nextLineText = nullptr;
}
};
}
AnInitFile.cpp
#include "AnInitFile.h"
#include <string>
#include <fstream>
#include <sstream>
#include <Windows.h>
using namespace An;
int strFind(char key, unsigned char *Src);
void getLine(std::ifstream &stream, unsigned char *line);
std::string UTF8ToGB(const char* str);
///check code type
bool check_utf8_without_bom(std::string &file_name);
TEXTCODETYPE check_text_encode(std::string file_name);
AnInitFile::AnInitFile()
{
pInitFileReader = new InitFileReader();
pInitFileWriter = new InitFileWriter();
memset(defaultFilePath, 0, AN_PARAMLEN_MAX);
}
An::AnInitFile::AnInitFile(const char * filePath)
{
AnInitFile();
Open(filePath);
}
AnInitFile::~AnInitFile()
{
delete pInitFileReader;
delete pInitFileWriter;
pInitFileReader = nullptr;
pInitFileWriter = nullptr;
}
bool AnInitFile::Open(const char * filePath)
{
if (pInitFileReader != nullptr)
{
pInitFileReader->Release();
if (pInitFileReader->Read(filePath))
{
memcpy(defaultFilePath, filePath, AN_PARAMLEN_MAX);
return true;
}
return false;
}
return false;
}
bool An::AnInitFile::GetParam(const char * root, const char * key,char * value)
{
return pInitFileReader->Get(root, key, value);
}
bool An::AnInitFile::SetParam(const char * root, const char * key, const char * value, bool autoSave)
{
if (pInitFileReader->Set(root, key, value))
{
if (autoSave)
{
Save();
return true;
}
}
return false;
}
bool An::AnInitFile::Save(const char * filePath, TEXTCODETYPE type)
{
//暂时仅支持UTF8保存
if(!pInitFileReader||!pInitFileWriter)
return false;
char Path[AN_PARAMLEN_MAX];
if (!filePath)
{
memcpy(Path, defaultFilePath, AN_PARAMLEN_MAX);
}
else
{
memcpy(Path, filePath, AN_PARAMLEN_MAX);
}
if (pInitFileWriter->CreateWriter(Path))
{
pInitFileWriter->Flush(pInitFileReader->pLineTextList, pInitFileReader->pRootNodeList);
return true;
}
return false;
}
InitFileReader::InitFileReader()
{
pRootNodeList = nullptr;
pLineTextList = nullptr;
}
InitFileReader::~InitFileReader()
{
Release();
}
bool InitFileReader::Read(const char * filePath)
{
//check Type
TEXTCODETYPE type=GetCodeType(filePath);
if (type == TEXTCODETYPE::TEXT_UNKNOW)return false;
std::ifstream RStream(filePath);
if (!RStream)return false;//not exist
if (RStream.peek() == EOF)return false;//empty
int Row = 0;
void *pListHeadPtr = nullptr;
//read
while (RStream.peek() != EOF)
{
if (pLineTextList == nullptr)
{
pLineTextList = new LineTextList();
memset(pLineTextList->Text, NULL, AN_PARAMLEN_MAX);
getLine(RStream, pLineTextList->Text);
if (type==TEXTCODETYPE::TEXT_UTF8)
{
std::string gbStr=UTF8ToGB((char *)pLineTextList->Text);
memset(pLineTextList->Text, NULL, AN_PARAMLEN_MAX);
memcpy(pLineTextList->Text, gbStr.c_str(), gbStr.size());
}
Row++;
pLineTextList->RowNo = Row;
pListHeadPtr = pLineTextList;
}
else
{
LineTextList *textList= new LineTextList();
memset(textList->Text, NULL, AN_PARAMLEN_MAX);
getLine(RStream, textList->Text);
if (type == TEXTCODETYPE::TEXT_UTF8)
{
std::string gbStr = UTF8ToGB((char *)textList->Text);
memset(textList->Text, NULL, AN_PARAMLEN_MAX);
memcpy(textList->Text, gbStr.c_str(), gbStr.size());
}
Row++;
textList->RowNo = Row;
pLineTextList->nextLineText = textList;
pLineTextList = textList;
}
}
pLineTextList = (LineTextList*)pListHeadPtr;
RStream.close();
Analyse();
return true;
}
bool InitFileReader::Get(const char * root, const char * key, char * value)
{
if (pRootNodeList == nullptr)
{
value = nullptr;
return false;
}
void *pRootHeadPtr = pRootNodeList;
void *pKeyBeginPtr = pRootNodeList->KeyList;
void *pValBeginPtr = pRootNodeList->ValList;
void *pKeyNextList = nullptr;
void *pValNextList = nullptr;
while (pRootNodeList!=nullptr)
{
if (strcmp((char *)pRootNodeList->Root, root) == 0)
{
while (pRootNodeList->KeyList!=nullptr)
{
if (strcmp((char *)pRootNodeList->KeyList->Element, key) == 0)
{
memcpy(value, pRootNodeList->ValList->Element, AN_PARAMLEN_MAX);
if (pKeyNextList&&pValNextList)
{
pRootNodeList->KeyList = (ElementList*)pKeyNextList;
pRootNodeList->ValList = (ElementList*)pValNextList;
}
pRootNodeList = (RootNodeList*)pRootHeadPtr;
pRootNodeList->KeyList = (ElementList*)pKeyBeginPtr;
pRootNodeList->ValList = (ElementList*)pValBeginPtr;
return true;
}
pRootNodeList->KeyList = pRootNodeList->KeyList->nextElement;
pRootNodeList->ValList = pRootNodeList->ValList->nextElement;
}
}
pRootNodeList = pRootNodeList->nextRootNode;
if (pRootNodeList)
{
pKeyNextList = pRootNodeList->KeyList;
pValNextList = pRootNodeList->ValList;
}
}
pRootNodeList = (RootNodeList*)pRootHeadPtr;
pRootNodeList->KeyList = (ElementList*)pKeyBeginPtr;
pRootNodeList->ValList = (ElementList*)pValBeginPtr;
return false;
}
bool An::InitFileReader::Set(const char * root, const char * key, const char * value)
{
if (pRootNodeList == nullptr)
{
value = nullptr;
return false;
}
void *pRootHeadPtr = pRootNodeList;
void *pKeyBeginPtr = pRootNodeList->KeyList;
void *pValBeginPtr = pRootNodeList->ValList;
void *pKeyNextList = nullptr;
void *pValNextList = nullptr;
while (pRootNodeList!= nullptr)
{
if (strcmp((char *)pRootNodeList->Root, root) == 0)
{
while (pRootNodeList->KeyList!= nullptr)
{
if (strcmp((char *)pRootNodeList->KeyList->Element, key) == 0)
{
memcpy(pRootNodeList->ValList->Element,value,AN_PARAMLEN_MAX);
if (pKeyNextList&&pValNextList)
{
pRootNodeList->KeyList = (ElementList*)pKeyNextList;
pRootNodeList->ValList = (ElementList*)pValNextList;
}
pRootNodeList = (RootNodeList*)pRootHeadPtr;
pRootNodeList->KeyList = (ElementList*)pKeyBeginPtr;
pRootNodeList->ValList = (ElementList*)pValBeginPtr;
return true;
}
pRootNodeList->KeyList = pRootNodeList->KeyList->nextElement;
pRootNodeList->ValList = pRootNodeList->ValList->nextElement;
}
}
pRootNodeList = pRootNodeList->nextRootNode;
if (pRootNodeList)
{
pKeyNextList = pRootNodeList->KeyList;
pValNextList = pRootNodeList->ValList;
}
}
pRootNodeList = (RootNodeList*)pRootHeadPtr;
pRootNodeList->KeyList = (ElementList*)pKeyBeginPtr;
pRootNodeList->ValList = (ElementList*)pValBeginPtr;
return false;
}
void InitFileReader::Analyse()
{
void *pLineBeginPtr = nullptr;
void *pRootBeginPtr = nullptr;
void *pKeyBeginPtr = nullptr;
void *pValBeginPtr = nullptr;
pLineBeginPtr = pLineTextList;
while (pLineTextList!=nullptr)
{
if (pLineTextList->Text[0] == '#' || pLineTextList->Text[0] == ';')
{
pLineTextList = pLineTextList->nextLineText;
continue;
}
int len = strlen((const char *)pLineTextList->Text);
if (pLineTextList->Text[0] == '['&&pLineTextList->Text[len-1]==']')
{
if (pRootNodeList == nullptr)
{
pRootNodeList = new RootNodeList();
pRootBeginPtr = pRootNodeList;
memcpy(pRootNodeList->Root, pLineTextList->Text + 1, len - 2);
}
else
{
if (pRootNodeList->KeyList != nullptr)
{
pRootNodeList->KeyList= (ElementList*)pKeyBeginPtr;
pRootNodeList->ValList= (ElementList*)pValBeginPtr;
}
RootNodeList *rootList=new RootNodeList();
memcpy(rootList->Root, pLineTextList->Text + 1, len - 2);
pRootNodeList->nextRootNode = rootList;
pRootNodeList = rootList;
}
}
else if (strcmp((const char *)pLineTextList->Text, "=") > 0)
{
len = strlen((const char *)pLineTextList->Text);
int Pos = strFind('=', pLineTextList->Text);
if (Pos > 0)
{
if (pRootNodeList->KeyList == nullptr)
{
pRootNodeList->KeyList = new ElementList();
pRootNodeList->ValList = new ElementList();
pKeyBeginPtr = pRootNodeList->KeyList;
pValBeginPtr = pRootNodeList->ValList;
memcpy(pRootNodeList->KeyList->Element, pLineTextList->Text, Pos);
memcpy(pRootNodeList->ValList->Element, pLineTextList->Text+ Pos+1, len-Pos-1);
}
else
{
ElementList *keyList = new ElementList();
ElementList *valList = new ElementList();
memcpy(keyList->Element, pLineTextList->Text, Pos);
memcpy(valList->Element, pLineTextList->Text + Pos + 1, len - Pos - 1);
pRootNodeList->KeyList->nextElement = keyList;
pRootNodeList->ValList->nextElement = valList;
pRootNodeList->KeyList = keyList;
pRootNodeList->ValList = valList;
}
}
}
pLineTextList = pLineTextList->nextLineText;
}
if (pRootNodeList->KeyList != nullptr)
{
pRootNodeList->KeyList = (ElementList*)pKeyBeginPtr;
pRootNodeList->ValList = (ElementList*)pValBeginPtr;
}
pRootNodeList = (RootNodeList*)pRootBeginPtr;
pLineTextList = (LineTextList*)pLineBeginPtr;
}
void InitFileReader::Release()
{
if (pRootNodeList!=nullptr)
{
RootNodeList*n = nullptr, *m = nullptr;
n = pRootNodeList;
while (n!= nullptr)
{
m = n->nextRootNode;
/
ElementList *p = nullptr, *q = nullptr;
p = n->KeyList;
while (p!= nullptr)
{
q = p->nextElement;
delete p;
p = q;
}
///
p = nullptr;
q = nullptr;
p = n->ValList;
while (p!= nullptr)
{
q = p->nextElement;
delete p;
p = q;
}
delete n;
n = m;
}
pRootNodeList = nullptr;
}
if (pLineTextList != nullptr)
{
delete pLineTextList;
pLineTextList = nullptr;
}
}
TEXTCODETYPE InitFileReader::GetCodeType(const char * filePath)
{
TEXTCODETYPE type = TEXTCODETYPE::TEXT_UNKNOW;
type=check_text_encode(filePath);
return type;
}
InitFileWriter::InitFileWriter()
{
writeStream = nullptr;
}
InitFileWriter::~InitFileWriter()
{
if (writeStream != nullptr)
{
delete writeStream;
writeStream = nullptr;
}
}
bool InitFileWriter::CreateWriter(const char * path)
{
if (writeStream != nullptr)
{
delete writeStream;
writeStream = nullptr;
}
writeStream = new std::ofstream();
writeStream->open(path, std::ios::out);
if (writeStream->is_open())
return true;
return false;
}
bool InitFileWriter::Write(const char * data)
{
int len = strlen(data);
return Write(data,len);
}
bool InitFileWriter::Write(const char * data, int length)
{
if (!writeStream || !writeStream->is_open())
return false;
*writeStream << data << std::endl;
//writeStream->write(data, length);
return true;
}
bool InitFileWriter::Flush()
{
if (!writeStream || !writeStream->is_open())
return false;
writeStream->flush();
writeStream->close();
return true;
}
bool InitFileWriter::Flush(LineTextList * pLineTextList, RootNodeList * pRootNodeList)
{
if (!writeStream || !writeStream->is_open()|| !pLineTextList||!pRootNodeList)
return false;
void *pLineBeginPtr = pLineTextList;
void *pRootHeadPtr = pRootNodeList;
char RootName[AN_PARAMLEN_MAX];
while (pLineTextList!=nullptr)
{
if (pLineTextList->Text[0] == '#' || pLineTextList->Text[0] == ';')
{
Write((char *)pLineTextList->Text);
}
else if (pLineTextList->Text[0] == '[')
{
int len = strlen((const char *)pLineTextList->Text);
memset(RootName, 0, AN_PARAMLEN_MAX);
memcpy(RootName, pLineTextList->Text + 1, len - 2);
Write((char *)pLineTextList->Text);
}
else if (strcmp((const char *)pLineTextList->Text, "=") > 0)
{
int len = strlen((const char *)pLineTextList->Text);
int Pos = strFind('=', pLineTextList->Text);
if (Pos > 0)
{
char KeyName[AN_PARAMLEN_MAX],buff[AN_PARAMLEN_MAX];
memset(KeyName,0, AN_PARAMLEN_MAX);
memset(buff, 0, AN_PARAMLEN_MAX);
memcpy(KeyName, pLineTextList->Text, Pos);
if (Find(RootName, KeyName, buff, pRootNodeList))
{
len = strlen(KeyName) + strlen("=") + 1;
strcat_s(KeyName, len, "=");
len = strlen(KeyName) + strlen(buff) + 1;
strcat_s(KeyName, len, buff);
Write(KeyName);
}
}
}
pLineTextList = pLineTextList->nextLineText;
}
Flush();
pLineTextList = (LineTextList *)pLineBeginPtr;
pRootNodeList = (RootNodeList *)pRootHeadPtr;
return true;
}
bool InitFileWriter::Find(const char * root, const char * key, char * value, RootNodeList *pRootNodeList)
{
if (pRootNodeList == nullptr)
{
value = nullptr;
return false;
}
void *pRootHeadPtr = pRootNodeList;
void *pKeyBeginPtr = pRootNodeList->KeyList;
void *pValBeginPtr = pRootNodeList->ValList;
void *pKeyNextList = nullptr;
void *pValNextList = nullptr;
while (pRootNodeList!= nullptr)
{
if (strcmp((char *)pRootNodeList->Root, root) == 0)
{
while (pRootNodeList->KeyList != nullptr)
{
if (strcmp((char *)pRootNodeList->KeyList->Element, key) == 0)
{
memcpy(value, pRootNodeList->ValList->Element, AN_PARAMLEN_MAX);
if (pKeyNextList&&pValNextList)
{
pRootNodeList->KeyList = (ElementList*)pKeyNextList;
pRootNodeList->ValList = (ElementList*)pValNextList;
}
pRootNodeList = (RootNodeList*)pRootHeadPtr;
pRootNodeList->KeyList = (ElementList*)pKeyBeginPtr;
pRootNodeList->ValList = (ElementList*)pValBeginPtr;
return true;
}
pRootNodeList->KeyList = pRootNodeList->KeyList->nextElement;
pRootNodeList->ValList = pRootNodeList->ValList->nextElement;
}
}
pRootNodeList = pRootNodeList->nextRootNode;
if (pRootNodeList)
{
pKeyNextList = pRootNodeList->KeyList;
pValNextList = pRootNodeList->ValList;
}
}
pRootNodeList = (RootNodeList*)pRootHeadPtr;
pRootNodeList->KeyList = (ElementList*)pKeyBeginPtr;
pRootNodeList->ValList = (ElementList*)pValBeginPtr;
return false;
}
int strFind(char key, unsigned char * Src)
{
int len = strlen((const char *)Src);
if (len <= 0)return -1;
for (int i = 0; i < len; i++)
{
if (Src[i] == key)
{
return i;
}
}
return -1;
}
void getLine(std::ifstream & stream, unsigned char * line)
{
int idx = 0;
char temp[AN_PARAMLEN_MAX];
memset(temp, 0, AN_PARAMLEN_MAX);
while (stream.get(temp[idx]) && temp[idx] != '\n')
{
idx++;
}
memcpy(line, temp, idx);
}
std::string UTF8ToGB(const char* str)
{
std::string result;
WCHAR *strSrc;
LPSTR szRes;
//获得临时变量的大小
int i = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
strSrc = new WCHAR[i + 1];
MultiByteToWideChar(CP_UTF8, 0, str, -1, strSrc, i);
//获得临时变量的大小
i = WideCharToMultiByte(CP_ACP, 0, strSrc, -1, NULL, 0, NULL, NULL);
szRes = new CHAR[i + 1];
WideCharToMultiByte(CP_ACP, 0, strSrc, -1, szRes, i, NULL, NULL);
result = szRes;
delete[]strSrc;
delete[]szRes;
return result;
}
///Code From:https://www.cnblogs.com/rcg714786690/p/14246669.html
//检查是否为无BOM的UTF8
bool check_utf8_without_bom(std::string &file_name)
{
std::ifstream file_in;
file_in.open(file_name, std::ios::in);
if (!file_in.is_open())
{
//cout << "打开文件失败" << endl;
return false;
}
std::stringstream buffer;
buffer << file_in.rdbuf();
file_in.close();
std::string text = buffer.str();
size_t len = text.size();
int n = 0;
unsigned char ch;
bool b_all_ascii = true;
//0x00-0x7F为ASCII码范围
for (size_t i = 0; i < len; ++i)
{
ch = text[i];
if ((ch & 0x80) != 0)
{
b_all_ascii = false;
}
if (n == 0)
{
if (ch >= 0x80)
{
if (ch >= 0xFC && ch <= 0xFD)
{
n = 6;
}
else if (ch >= 0xF8)
{
n = 5;
}
else if (ch >= 0xF0)
{
n = 4;
}
else if (ch >= 0xE0)
{
n = 3;
}
else if (ch >= 0xC0)
{
n = 2;
}
else
{
return false;
}
n--;
}
}
else
{
if ((ch & 0xC0) != 0x80)//在UTF-8中,以位模式10开始的所有字节是多字节序列的后续字节
{
return false;
}
n--;
}
}
if (n > 0)
{
return false;
}
if (b_all_ascii)
{
return false;
}
return true;
}
TEXTCODETYPE check_text_encode(std::string file_name)
{
/*
ANSI 无格式定义 对于中文编码格式是GB2312;
Unicode little endian 文本里前两个字节为FF FE 字节流是little endian
Unicode big endian 文本里前两个字节为FE FF 字节流是big endian
UTF-8带BOM 前两字节为EF BB,第三字节为BF 带BOM
UTF-8不带BOM 无格式定义,需另加判断 不带BOM
*/
std::ifstream file_in(file_name, std::ios::binary);
if (!file_in.is_open())
{
//cout << "打开文件失败" << endl;;
return TEXT_UNKNOW;
}
int head;
unsigned char ch;
file_in.read((char*)&ch, sizeof(ch));
head = ch << 8;
file_in.read((char*)&ch, sizeof(ch));
head |= ch;
file_in.close();
TEXTCODETYPE result_code= TEXTCODETYPE::TEXT_UNKNOW;
switch (head)
{
case 0xFFFE:
//result_code = TEXT_UTF16_LE;
break;
case 0xFEFF:
//result_code = TEXT_UTF16_BE;
break;
case 0xEFBB:
//result_code = TEXT_UTF8_BOM;
break;
default:
if (check_utf8_without_bom(file_name))
result_code = TEXTCODETYPE::TEXT_UTF8;
else
result_code = TEXTCODETYPE::TEXT_ANSI;
break;
}
return result_code;
}
main.cpp
#include "AnInitFile.h"
An::AnInitFile cfg;
cfg.Open("config.ini");
char szBuff[AN_PARAMLEN_MAX];
ZeroMemory(szBuff, AN_PARAMLEN_MAX);
cfg.GetParam("Serial", "Com", szBuff);
char szBuff2[10];
ZeroMemory(szBuff2, 10);
cfg.GetParam("Serial", "Com", szBuff2);