plist是苹果最常用的配置文件存储类型之一,plist实际为xml,xml操作远没有json方便,并且苹果很多应用存储的plist跟NSArray等对象是绑定的,又会设计到了uid重定位等问题,于是写了一个plist转json的类,一次convert,方便受用。
内部基本上都封装完毕,基于libplist和jsoncpp库,支持xml和bplist两种格式,data类型为了考虑十六进制buffer使用了base64编码
使用方法:
CPlistObject mPlistHandler; mPlistHandler.OpenPlist("xxxx.plist"); //也支持从数据流中加载OpenPlist(LPCSTR lpBuffer, int nBufLen); //bConvertDataPlist参数默认为FALSE, TRUE的作用为检测data类型的数据,如果其中的数据是plist的buffer,则再次进行解析(参考代码132行) Json::Value jsonPlist; mPlistHandler.ConvertPlistObject(jsonPlist); //操作值 std::string str = jsonPlist["xxx"].asString();
源码:
BPlist.cpp
#include "stdafx.h" #include "BPlist.h" #include "base64.h" // #ifdef _DEBUG // #pragma comment(lib, "libiconv_d.lib") // #pragma comment(lib, "libxml2_d.lib") // #pragma comment(lib, "libcnary_d.lib") // #pragma comment(lib, "libplist_d.lib") // #else // #pragma comment(lib, "libiconv.lib") // #pragma comment(lib, "libxml2.lib") // #pragma comment(lib, "libcnary.lib") // #pragma comment(lib, "libplist.lib") // #endif // _DEBUG #pragma comment(lib, "libiconv.lib") #pragma comment(lib, "libxml2.lib") #pragma comment(lib, "libcnary.lib") #pragma comment(lib, "libplist.lib") //屏蔽掉调试输出 #define myprintf CPlistObject::CPlistObject() { m_plistMain = NULL; m_pArray = NULL; m_bConvertDataPlist = FALSE; } CPlistObject::~CPlistObject() { Close(); } void CPlistObject::Close() { if (m_plistMain) { plist_free(m_plistMain); m_plistMain = NULL; } } plist_t CPlistObject::GetNodeByUidDict(plist_t pDict) { if (!pDict) return NULL; int nType = plist_get_node_type(pDict); //如果类型不是UID的 直接就返回原元素指针 if (nType != PLIST_UID) return pDict; plist_t pRet = NULL; uint64_t val = 0; plist_get_uid_val(pDict, &val); pRet = plist_array_get_item(m_pArray, (UINT32)val); return pRet; } CStringA CPlistObject::GetDictClassName(plist_t pDict) { CStringA strRet; plist_t pClassName = GetNodeByUidDict(pDict); if (pClassName) { if (plist_get_node_type(pClassName) == PLIST_DICT) { plist_t pName = plist_dict_get_item(pClassName, "$classname"); if (pName) { char *pszName = NULL; plist_get_string_val(pName, &pszName); if (pszName) { strRet = pszName; free(pszName); } } } } return strRet; } void CPlistObject::SetValue(plist_t pValue, Json::Value &jsonValue) { int nType = plist_get_node_type(pValue); if (nType == PLIST_STRING) { char *pszValue = NULL; plist_get_string_val(pValue, &pszValue); if (pszValue) { myprintf("val(str):%s \n", pszValue); jsonValue = pszValue; free(pszValue); } } else if (nType == PLIST_UINT) { UINT64 nValue; plist_get_uint_val(pValue, &nValue); myprintf("val(uint):%I64d \n", nValue); jsonValue = nValue; } else if (nType == PLIST_BOOLEAN) { UINT8 nValue; plist_get_bool_val(pValue, &nValue); myprintf("val(bool):%d \n", nValue); jsonValue = nValue; } else if (nType == PLIST_DATA) { char *pszValue = NULL; uint64_t nDataLen = 0; plist_get_data_val(pValue, &pszValue, &nDataLen); std::string strValue; if (nDataLen > 0) { //add by fenlog 2019.11.07 转义data中的plist if (m_bConvertDataPlist && nDataLen > 16 && (memcmp(pszValue, "bplist00", 8) == 0 || memcmp(pszValue, "<?xml", 5) == 0)) { CPlistObject mPlist; if (mPlist.OpenPlist(pszValue, (int)nDataLen) && mPlist.ConvertPlistObject(TRUE)) { jsonValue = mPlist.m_jsonValues; free(pszValue); return; } } strValue = base64_encode((const unsigned char *)pszValue, (DWORD)nDataLen); } if (pszValue) free(pszValue); myprintf("val(data):%s \n", strValue.c_str()); jsonValue = strValue; } else if (nType == PLIST_REAL) { double nValue; plist_get_real_val(pValue, &nValue); myprintf("val(real):%lf \n", nValue); jsonValue = nValue; } else if (nType == PLIST_DATE) { int nSec, nMSec; plist_get_date_val(pValue, &nSec, &nMSec); UINT dwSec = nSec + 978278400; //Represents the number of seconds since 01/01/2001 jsonValue = dwSec; } else { myprintf("val(%d) \n", nType); } } BOOL CPlistObject::CheckItemType(plist_t pNode, plist_type nType) { if (pNode && plist_get_node_type(pNode) == nType) return TRUE; return FALSE; } void CPlistObject::EnumDictNSMutableArray(plist_t pDictObject, Json::Value &jsonValue) { plist_t pNSObjects = plist_dict_get_item(pDictObject, "NS.objects"); if (CheckItemType(pNSObjects, PLIST_ARRAY)) { int nObjects = plist_array_get_size(pNSObjects); for (int i = 0; i < nObjects; i++) { plist_t pValue = GetNodeByUidDict(plist_array_get_item(pNSObjects, i)); if (pValue) { int nType = plist_get_node_type(pValue); myprintf("%d - type %d ", i, nType); if (nType == PLIST_DICT) { myprintf("\n"); ConvertDict(pValue, jsonValue[i]); } else { SetValue(pValue, jsonValue[i]); } } } } } void CPlistObject::EnumDictNSMutableDictionary(plist_t pDictObject, Json::Value &jsonValue) { plist_t pNSKeys = plist_dict_get_item(pDictObject, "NS.keys"); plist_t pNSObjects = plist_dict_get_item(pDictObject, "NS.objects"); if (CheckItemType(pNSKeys, PLIST_ARRAY) && CheckItemType(pNSObjects, PLIST_ARRAY)) { int nKeys = plist_array_get_size(pNSKeys); if (plist_array_get_size(pNSObjects) == nKeys) { for (int i = 0; i < nKeys; i++) { plist_t pKey = GetNodeByUidDict(plist_array_get_item(pNSKeys, i)); plist_t pValue = GetNodeByUidDict(plist_array_get_item(pNSObjects, i)); if (pKey && pValue) { //modify by fenlog 2019.07.18 int nKeyType = plist_get_node_type(pKey); int nValueType = plist_get_node_type(pValue); if (nKeyType == PLIST_STRING) { char *pszKey = NULL; plist_get_string_val(pKey, &pszKey); if (pszKey) { if (strlen(pszKey) > 0) { myprintf("%s - type %d ", pszKey, nValueType); if (nValueType == PLIST_DICT) { myprintf("\n"); ConvertDict(pValue, jsonValue[pszKey]); } else { SetValue(pValue, jsonValue[pszKey]); } } free(pszKey); } } else if (nKeyType == PLIST_DICT) { char szKey[16]; sprintf(szKey, "%u", i); ConvertDict(pKey, jsonValue[szKey]["key"]); if (nValueType == PLIST_DICT) ConvertDict(pValue, jsonValue[szKey]["value"]); else SetValue(pValue, jsonValue[szKey]["value"]); } else { myprintf("unknow type %d \n", nKeyType); } } } } } } void CPlistObject::EnumArray(plist_t pArrObject, Json::Value &jsonValue) { int nType = plist_get_node_type(pArrObject); if (nType != PLIST_ARRAY) return; int nArrayCount = plist_array_get_size(pArrObject); for (int i = 0; i < nArrayCount; i++) { plist_t pItem = plist_array_get_item(pArrObject, i); nType = plist_get_node_type(pItem); if (nType == PLIST_DICT) { EnumDictKeyValueDefault(pItem, jsonValue[i]); } else if (nType == PLIST_ARRAY) { EnumArray(pItem, jsonValue[i]); } else { SetValue(pItem, jsonValue[i]); } } } void CPlistObject::EnumDictKeyValueDefault(plist_t pDictObject, Json::Value &jsonValue) { plist_dict_iter it = NULL; char* key = NULL; plist_t subnode = NULL; plist_dict_new_iter(pDictObject, &it); plist_dict_next_item(pDictObject, it, &key, &subnode); while (subnode) { int nType = plist_get_node_type(subnode); //UID的重新修正目标指针 if (nType == PLIST_UID) { subnode = GetNodeByUidDict(subnode); //重新读取type if (subnode) nType = plist_get_node_type(subnode); } myprintf("%s - type %d \n", key, nType); if (nType == PLIST_DICT) { myprintf("\n"); ConvertDict(subnode, jsonValue[key]); } else if (nType == PLIST_ARRAY) { EnumArray(subnode, jsonValue[key]); } else { SetValue(subnode, jsonValue[key]); } subnode = NULL; free(key); key = NULL; plist_dict_next_item(pDictObject, it, &key, &subnode); } free(it); } void CPlistObject::ConvertDict(plist_t pDict, Json::Value &jsonValue) { //如果是dict 可能是对象描述 plist_t pDictObject = plist_dict_get_item(pDict, "$class"); if (pDictObject) { CStringA strClassName = GetDictClassName(pDictObject); //一般这里都不会为空 if (!strClassName.IsEmpty()) { myprintf("Get Class:%s \n", strClassName); if (strClassName == "NSMutableDictionary" || strClassName == "NSDictionary") { EnumDictNSMutableDictionary(pDict, jsonValue); } else if (strClassName == "NSMutableArray" || strClassName == "NSArray") { EnumDictNSMutableArray(pDict, jsonValue); } else { //遍历里面的key-value EnumDictKeyValueDefault(pDict, jsonValue); } } } else { EnumDictKeyValueDefault(pDict, jsonValue); } } BOOL CPlistObject::ConvertPlistObject(Json::Value &jsonObject, BOOL bConvertDataPlist/* = FALSE*/) { m_bConvertDataPlist = bConvertDataPlist; m_pArray = plist_dict_get_item(m_plistMain, "$objects"); if (m_pArray && plist_get_node_type(m_pArray) == PLIST_ARRAY) { int nArrayCount = plist_array_get_size(m_pArray); for (int i = 0; i < nArrayCount; i++) { plist_t pItem = plist_array_get_item(m_pArray, i); plist_type nType = plist_get_node_type(pItem); if (nType == PLIST_DICT) { ConvertDict(pItem, jsonObject); return TRUE; } } } int nType = plist_get_node_type(m_plistMain); if (nType == PLIST_DICT) { EnumDictKeyValueDefault(m_plistMain, jsonObject); } else if (nType == PLIST_ARRAY) { EnumArray(m_plistMain, jsonObject); } else { return FALSE; } return TRUE; } BOOL CPlistObject::ConvertPlistObject(BOOL bConvertDataPlist/* = FALSE*/) { m_bConvertDataPlist = bConvertDataPlist; return ConvertPlistObject(m_jsonValues); } std::string CPlistObject::ConvertPlistToXML(plist_t plist) { std::string strRet; if (!plist) { if (!m_plistMain) return strRet; plist = m_plistMain; } char *pszMsg = NULL; uint32_t nMsgLen = 0; plist_to_xml(plist, &pszMsg, &nMsgLen); //printf("%s \n", pszMsg); if (pszMsg) { strRet = pszMsg; free(pszMsg); } return strRet; } BOOL CPlistObject::OpenPlist(LPCTSTR lpFilePath) { char *szBuffer = NULL; DWORD dwBufLen = 0; CFile mFile; if (mFile.Open(lpFilePath, CFile::modeRead)) { dwBufLen = (DWORD)mFile.GetLength(); if (dwBufLen > 8 && dwBufLen < 50 * 1024 * 1024) { szBuffer = new char[dwBufLen + 1]; ZeroMemory(szBuffer, dwBufLen + 1); mFile.Read(szBuffer, dwBufLen); } mFile.Close(); } //读文件失败了 if (!szBuffer) return FALSE; BOOL bRet = OpenPlist(szBuffer, dwBufLen); delete[] szBuffer; return bRet; } BOOL CPlistObject::OpenPlist(LPCSTR lpBuffer, int nBufLen) { if (memcmp(lpBuffer, "bplist00", 8) == 0) plist_from_bin(lpBuffer, nBufLen, &m_plistMain); else //if (memcmp(lpBuffer, "<?xml", 5) == 0) plist_from_xml(lpBuffer, nBufLen, &m_plistMain); if (!m_plistMain) return FALSE; return TRUE; }
BPlist.h
#pragma once #include "plist/plist++.h" class CPlistObject { public: CPlistObject(); ~CPlistObject(); void Close(); plist_t GetNodeByUidDict(plist_t pDict); CStringA GetDictClassName(plist_t pDict); void SetValue(plist_t pValue, Json::Value &jsonValue); BOOL CheckItemType(plist_t pNode, plist_type nType); void EnumDictNSMutableArray(plist_t pDictObject, Json::Value &jsonValue); void EnumDictNSMutableDictionary(plist_t pDictObject, Json::Value &jsonValue); void EnumArray(plist_t pArrObject, Json::Value &jsonValue); void EnumDictKeyValueDefault(plist_t pItem, Json::Value &jsonValue); void ConvertDict(plist_t pDict, Json::Value &jsonValue); BOOL ConvertPlistObject(BOOL bConvertDataPlist = FALSE); BOOL ConvertPlistObject(Json::Value &jsonObject, BOOL bConvertDataPlist = FALSE); std::string ConvertPlistToXML(plist_t plist = NULL); BOOL OpenPlist(LPCTSTR lpFilePath); BOOL OpenPlist(LPCSTR lpBuffer, int nBufLen); Json::Value m_jsonValues; plist_t m_plistMain; plist_t m_pArray; BOOL m_bConvertDataPlist; };