苹果配置中大量用到了plist,使用开源的C语言的库libplist可以读取解析,但是纯C的写起来非常蛋疼。
于是用C++封装了一下(c++ wrapper),但是plist的本质还是xml,读取起来还是略有繁琐,于是转为json结构,就可以直接使用了(依赖jsoncpp库)。
plist内部是有PLIST_UID、PLIST_DICT、PLIST_ARRAY等复杂的结构,支持xml和binary(bplist)两种格式,支持uid自动解析处理关联,支持NS.objects、NS.keys、NSDictionary、NSArray、NSMutableDictionary、NSMutableArray等结构自动处理,使用起来就非常方便了。
header only引用:plistObject.h
#pragma once
#include <json/json.h>
#include <plist/plist++.h>
#include "base64.h"
//屏蔽掉调试输出
//#define _bplist_printf
class CPlistObject : public Json::Value
{
public:
template <class T>
static Json::Value Plist2Json(const T& filepath)
{
CPlistObject plist;
if (plist.OpenPlistFile(filepath))
return std::move(plist);
return {};
}
static Json::Value PlistBuf2Json(const std::string &buf)
{
CPlistObject plist;
if (plist.OpenPlistBuf(buf))
return std::move(plist);
return {};
}
CPlistObject(bool bConvertDataPlist = false)
{
m_plistMain = NULL;
m_pArray = NULL;
m_bConvertDataPlist = bConvertDataPlist;
}
~CPlistObject()
{
Close();
}
void Close()
{
if (m_plistMain)
{
plist_free(m_plistMain);
m_plistMain = NULL;
}
}
//打开plist内存缓冲区
bool OpenPlistBuf(const void* lpBuffer, size_t nBufLen)
{
if (memcmp(lpBuffer, "bplist00", 8) == 0)
plist_from_bin((const char*)lpBuffer, (uint32_t)nBufLen, &m_plistMain);
else //if (memcmp(lpBuffer, "<?xml", 5) == 0)
plist_from_xml((const char*)lpBuffer, (uint32_t)nBufLen, &m_plistMain);
if (!m_plistMain)
return false;
if (!_ConvertPlistObject(*this))
return false;
return true;
}
bool OpenPlistBuf(const std::string& buf)
{
return OpenPlistBuf(buf.c_str(), buf.length());
}
//打开plist文件
template <class T>
bool OpenPlistFile(const T& filepath)
{
std::ifstream ifs(filepath, std::ios::binary);
if (!ifs.is_open())
return false;
unsigned char header[4] = { 0 };
ifs.read((char*)header, 3);
//兼容win utf8 bom 0xEFBBBF
if (header[0] == 0xEF && header[1] == 0xBB && header[2] == 0xBF)
{
//貌似不需要处理啥
}
else
{
//指针回到开头
ifs.seekg(0, std::ios::beg);
}
//读取文件内容
std::ostringstream sstr;
sstr << ifs.rdbuf();
std::string buf = sstr.str();
//读文件失败了
if (buf.empty())
return false;
return OpenPlistBuf(buf.c_str(), buf.length());
}
//转换plist为json
// bool ConvertPlistObject(bool bConvertDataPlist = false)
// {
// if (bConvertDataPlist)
// return _ConvertPlistObject(m_jsonValues);
// }
private:
bool _ConvertPlistObject(Json::Value& jsonObject)
{
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 (!jsonObject.isNull());
}
}
}
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
{
SetValue(m_plistMain, jsonObject);
}
return (!jsonObject.isNull());
}
plist_t GetNodeByUidDict(plist_t pDict)
{
if (!pDict)
return NULL;
plist_type 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_t)val);
return pRet;
}
std::string GetDictClassName(plist_t pDict)
{
std::string 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)
{
uint64_t sLen = 0;
const char* pszName = plist_get_string_ptr(pName, &sLen);
if (pszName)
strRet = pszName;
}
}
}
return strRet;
}
void SetValue(plist_t pValue, Json::Value& jsonValue)
{
int nType = plist_get_node_type(pValue);
switch (nType)
{
case PLIST_BOOLEAN:
{
uint8_t nValue8 = 0;
plist_get_bool_val(pValue, &nValue8);
//_bplist_printf("val(bool):%d \n", nValue8);
jsonValue = nValue8;
break;
}
case PLIST_UINT:
{
uint64_t nValue64 = 0;
plist_get_uint_val(pValue, (uint64_t*)&nValue64);
//_bplist_printf("val(uint):%llu \n", nValue64);
jsonValue = nValue64;
break;
}
case PLIST_REAL:
{
double dValue = 0;
plist_get_real_val(pValue, &dValue);
//_bplist_printf("val(real):%f \n", dValue);
jsonValue = dValue;
break;
}
case PLIST_STRING:
{
uint64_t sLen = 0;
const char* pszStr = plist_get_string_ptr(pValue, &sLen);
if (pszStr)
jsonValue = pszStr;
else
jsonValue = "";
break;
}
case PLIST_DATE:
{
int32_t nSec, nMSec;
plist_get_date_val(pValue, &nSec, &nMSec);
uint32_t dwSec = nSec + 978278400; //Represents the number of seconds since 01/01/2001
jsonValue = dwSec;
break;
}
case PLIST_DATA:
{
uint64_t nDataLen = 0;
const char* pszData = plist_get_data_ptr(pValue, &nDataLen);
if (nDataLen > 0)
{
//add by fenlog 2019.11.07 转义data中的plist
if (m_bConvertDataPlist && nDataLen > 16 && (memcmp(pszData, "bplist00", 8) == 0 || memcmp(pszData, "<?xml", 5) == 0))
{
CPlistObject mSubPlist(true);
if (mSubPlist.OpenPlistBuf(pszData, (size_t)nDataLen))
{
jsonValue = mSubPlist;
return;
}
}
}
jsonValue = base64_encode((const unsigned char*)pszData, (size_t)nDataLen);
break;
}
default:
break;
}
}
bool CheckItemType(plist_t pNode, plist_type nType)
{
if (pNode && plist_get_node_type(pNode) == nType)
return true;
return false;
}
void EnumDictNSMutableArray(plist_t pDictObject, Json::Value& jsonValue)
{
plist_t pNSObjects = plist_dict_get_item(pDictObject, "NS.objects");
if (CheckItemType(pNSObjects, PLIST_ARRAY))
{
uint32_t nObjects = plist_array_get_size(pNSObjects);
for (uint32_t i = 0; i < nObjects; i++)
{
plist_t pValue = GetNodeByUidDict(plist_array_get_item(pNSObjects, i));
if (pValue)
{
plist_type nType = plist_get_node_type(pValue);
//_bplist_printf("%d - type %d ", i, nType);
if (nType == PLIST_DICT)
{
//_bplist_printf("\n");
ConvertDict(pValue, jsonValue[i]);
}
else
{
SetValue(pValue, jsonValue[i]);
}
}
}
}
}
void 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))
{
uint32_t nKeys = plist_array_get_size(pNSKeys);
if (plist_array_get_size(pNSObjects) == nKeys)
{
for (uint32_t 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
plist_type nKeyType = plist_get_node_type(pKey);
plist_type nValueType = plist_get_node_type(pValue);
if (nKeyType == PLIST_STRING)
{
uint64_t sLen = 0;
const char* pszKey = plist_get_string_ptr(pKey, &sLen);
if (pszKey)
{
//_bplist_printf("%s - type %d ", pszKey, nValueType);
if (nValueType == PLIST_DICT)
{
//_bplist_printf("\n");
ConvertDict(pValue, jsonValue[pszKey]);
}
else
{
SetValue(pValue, jsonValue[pszKey]);
}
}
}
else if (nKeyType == PLIST_UINT)
{
uint64_t nKeyValue = 0;
plist_get_uint_val(pKey, &nKeyValue);
//_bplist_printf("%llu - type %d ", nKeyValue, nValueType);
if (nValueType == PLIST_DICT)
{
//_bplist_printf("\n");
ConvertDict(pValue, jsonValue[std::to_string(nKeyValue)]);
}
else
{
SetValue(pValue, jsonValue[std::to_string(nKeyValue)]);
}
}
else if (nKeyType == PLIST_DICT)
{
std::string index = std::to_string(i);
ConvertDict(pKey, jsonValue[index]["key"]);
if (nValueType == PLIST_DICT)
ConvertDict(pValue, jsonValue[index]["value"]);
else
SetValue(pValue, jsonValue[index]["value"]);
}
else
{
//_bplist_printf("unknow type %d \n", nKeyType);
}
}
}
}
}
}
void EnumArray(plist_t pArrObject, Json::Value& jsonValue)
{
plist_type nType = plist_get_node_type(pArrObject);
if (nType != PLIST_ARRAY)
return;
uint32_t nArrayCount = plist_array_get_size(pArrObject);
for (uint32_t 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 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);
}
//_bplist_printf("%s - type %d \n", key, nType);
if (nType == PLIST_DICT)
{
//_bplist_printf("\n");
ConvertDict(subnode, jsonValue[key]);
}
else if (nType == PLIST_ARRAY)
{
EnumArray(subnode, jsonValue[key]);
}
else
{
SetValue(subnode, jsonValue[key]);
}
subnode = NULL;
plist_to_bin_free(key); //没有plist_mem_free,临时用这个代替
key = NULL;
plist_dict_next_item(pDictObject, it, &key, &subnode);
}
plist_to_bin_free((char*)it);//没有plist_mem_free,临时用这个代替
}
void ConvertDict(plist_t pDict, Json::Value& jsonValue)
{
//如果是dict 可能是对象描述
plist_t pDictObject = plist_dict_get_item(pDict, "$class");
if (pDictObject)
{
std::string strClassName = GetDictClassName(pDictObject);
//一般这里都不会为空
if (!strClassName.empty())
{
//_bplist_printf("Get Class:%s \n", strClassName.c_str());
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);
}
}
std::string ConvertPlistToXML(plist_t plist = NULL)
{
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;
plist_to_xml_free(pszMsg);
}
return strRet;
}
plist_t m_plistMain;
plist_t m_pArray;
bool m_bConvertDataPlist;
};
比如一个示例的plist:demo.plist
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>$version</key>
<integer>100000</integer>
<key>$archiver</key>
<string>NSKeyedArchiver</string>
<key>$top</key>
<dict>
<key>root</key>
<dict>
<key>CF$UID</key>
<integer>1</integer>
</dict>
</dict>
<key>$objects</key>
<array>
<string>$null</string>
<dict>
<key>_closeLevel</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_intimateRelationDark</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_sex</key>
<dict>
<key>CF$UID</key>
<integer>9</integer>
</dict>
<key>_gameLastLoginTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_closeDays</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_chatHotLevel</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_isFriendDontDisturb</key>
<dict>
<key>CF$UID</key>
<integer>10</integer>
</dict>
<key>_magicFontOpenFlagUpdateTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_onlineMusicRemainingTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_needShowFriendTreeAnimation</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_onlineMusicEndTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_interactiveSignMode</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_friendTreeLastChatTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_richOnlineState</key>
<dict>
<key>CF$UID</key>
<integer>5</integer>
</dict>
<key>_ctType</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_needShipAnimation</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_friendTreePreLevel</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_vipInfoDic</key>
<dict>
<key>CF$UID</key>
<integer>15</integer>
</dict>
<key>_intimateRelationFlag</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_network</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_lastGetCustomStateTime</key>
<dict>
<key>CF$UID</key>
<integer>20</integer>
</dict>
<key>_enableQSL</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_QQRobert</key>
<dict>
<key>CF$UID</key>
<integer>3</integer>
</dict>
<key>_avatarIdUpdateTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_isMatchRealNick</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_shouldShowCustomState</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_status</key>
<dict>
<key>CF$UID</key>
<integer>6</integer>
</dict>
<key>_magicFontType</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_cSpecialFlag</key>
<dict>
<key>CF$UID</key>
<integer>3</integer>
</dict>
<key>_specialCareZone</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_qzoneLevel</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_gameAppId</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_createTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_nameplateVipType</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_eIconType</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_isShortcutEnable</key>
<dict>
<key>CF$UID</key>
<integer>2</integer>
</dict>
<key>_memberLevel</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_isFriendMask</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_isMatchUIN</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_friendTreeFlag</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_loverKeyFlag</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_age</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_fuin</key>
<dict>
<key>CF$UID</key>
<integer>13</integer>
</dict>
<key>_abiFlag</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_priority</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_locationAbility</key>
<dict>
<key>CF$UID</key>
<integer>3</integer>
</dict>
<key>_matchRange</key>
<dict>
<key>CF$UID</key>
<integer>21</integer>
</dict>
<key>_loverKeyLevel</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_intimateRelationLastChatTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_topIdentityInfo</key>
<dict>
<key>CF$UID</key>
<integer>10</integer>
</dict>
<key>_fontIdUpdateTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_lastGetOnlineInfoTime</key>
<dict>
<key>CF$UID</key>
<integer>18</integer>
</dict>
<key>_isEnglishName</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_qslCreateTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_loverKeyTransFlag</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_gameNameplateId</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_notiNoVibrate</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_enableYQHType</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_praiseHotLevel</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_lastKeyTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_praiseHotDays</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_loverFlag</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_avatarId</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_newBoatLevel</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_groupId</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_lastLoginClient</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_extendNameplateId</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_faceAddonId</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_isBlockedMask</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_onlineMusicSourceType</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_lastPraiseTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_colorRingId</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_isShortcutEnableUpdate</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_isBlockMask</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_dstUin</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_terminalDescription</key>
<dict>
<key>CF$UID</key>
<integer>17</integer>
</dict>
<key>_customStateDescription</key>
<dict>
<key>CF$UID</key>
<integer>17</integer>
</dict>
<key>_gameRank</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_intimateRelationLevel</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_friendTreeContinuityDays</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_qzoneDays</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_isRemark</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_holdFlag</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_grayNameplateFlag</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>$class</key>
<dict>
<key>CF$UID</key>
<integer>23</integer>
</dict>
<key>_notiNeedHideSession</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_isFriendSetTop</key>
<dict>
<key>CF$UID</key>
<integer>10</integer>
</dict>
<key>_vipFontId</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_nick</key>
<dict>
<key>CF$UID</key>
<integer>12</integer>
</dict>
<key>_lastChatTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_onlineMusicTotalTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_isSpecialCareOpen</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_pendantIdUpdateTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_head</key>
<dict>
<key>CF$UID</key>
<integer>8</integer>
</dict>
<key>_sqq</key>
<dict>
<key>CF$UID</key>
<integer>3</integer>
</dict>
<key>_isMsfUser</key>
<dict>
<key>CF$UID</key>
<integer>3</integer>
</dict>
<key>_maxGetCustomStateInterval</key>
<dict>
<key>CF$UID</key>
<integer>19</integer>
</dict>
<key>_isQimFriend</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_chatHotDays</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_magicFontTypeUpdateTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_supportVideo</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_isWifi</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_notiNoSound</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_lastQzoneTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_recommendHoldFlag</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_friendTreeNotifyTime</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_bNotShowNetWorkIcon</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_gameIconShowFlag</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_notiNoPreview</key>
<dict>
<key>CF$UID</key>
<integer>4</integer>
</dict>
<key>_maxGetOnlineInfoInterval</key>
<dict>
<key>CF$UID</key>
<integer>19</integer>
</dict>
<key>_lastLoginType</key>
<dict>
<key>CF$UID</key>
<integer>7</integer>
</dict>
<key>_newBoatDays</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_friendTreeLevel</key>
<dict>
<key>CF$UID</key>
<integer>11</integer>
</dict>
<key>_sig</key>
<dict>
<key>CF$UID</key>
<integer>14</integer>
</dict>
<key>_propertyMD5</key>
<dict>
<key>CF$UID</key>
<integer>22</integer>
</dict>
</dict>
<true/>
<integer>0</integer>
<false/>
<integer>65535</integer>
<integer>20</integer>
<integer>0</integer>
<integer>201</integer>
<integer>2</integer>
<integer>-1</integer>
<integer>0</integer>
<string>10001</string>
<string>1000194</string>
<string>U</string>
<dict>
<key>NS.keys</key>
<array>
</array>
<key>NS.objects</key>
<array>
</array>
<key>$class</key>
<dict>
<key>CF$UID</key>
<integer>16</integer>
</dict>
</dict>
<dict>
<key>$classname</key>
<string>NSDictionary</string>
<key>$classes</key>
<array>
<string>NSDictionary</string>
<string>NSObject</string>
</array>
</dict>
<string></string>
<real>1682211584.541188</real>
<real>0.000000</real>
<real>1682211584.541188</real>
<data>
AAAAAAAAAAAAAAAAAAAAAA==
</data>
<string></string>
<dict>
<key>$classname</key>
<string>QQFriendModel</string>
<key>$classes</key>
<array>
<string>QQFriendModel</string>
<string>QQModel</string>
<string>NSObject</string>
</array>
</dict>
</array>
</dict>
</plist>
可以看到里面有很多CF$UID这种UID类型的key值需要重新匹配具体内容,还涉及到NSDictionary等对象,通过类解析后的json结构是:
{
"$class" :
{
"$classes" :
[
"QQFriendModel",
"QQModel",
"NSObject"
],
"$classname" : "QQFriendModel"
},
"_QQRobert" : 0,
"_abiFlag" : 0,
"_age" : 0,
"_avatarId" : 0,
"_avatarIdUpdateTime" : 0,
"_bNotShowNetWorkIcon" : 0,
"_cSpecialFlag" : 0,
"_chatHotDays" : 0,
"_chatHotLevel" : 0,
"_closeDays" : 0,
"_closeLevel" : 0,
"_colorRingId" : 0,
"_createTime" : 0,
"_ctType" : 0,
"_customStateDescription" : "",
"_dstUin" : 0,
"_eIconType" : 0,
"_enableQSL" : 0,
"_enableYQHType" : 0,
"_extendNameplateId" : 0,
"_faceAddonId" : 0,
"_fontIdUpdateTime" : 0,
"_friendTreeContinuityDays" : 0,
"_friendTreeFlag" : 0,
"_friendTreeLastChatTime" : 0,
"_friendTreeLevel" : 0,
"_friendTreeNotifyTime" : 0,
"_friendTreePreLevel" : 0,
"_fuin" : "1000194",
"_gameAppId" : 0,
"_gameIconShowFlag" : 0,
"_gameLastLoginTime" : 0,
"_gameNameplateId" : 0,
"_gameRank" : 0,
"_grayNameplateFlag" : 0,
"_groupId" : 0,
"_head" : 201,
"_holdFlag" : 0,
"_interactiveSignMode" : 0,
"_intimateRelationDark" : 0,
"_intimateRelationFlag" : 0,
"_intimateRelationLastChatTime" : 0,
"_intimateRelationLevel" : 0,
"_isBlockMask" : 0,
"_isBlockedMask" : 0,
"_isEnglishName" : 0,
"_isFriendDontDisturb" : 18446744073709551615,
"_isFriendMask" : 0,
"_isFriendSetTop" : 18446744073709551615,
"_isMatchRealNick" : 0,
"_isMatchUIN" : 0,
"_isMsfUser" : 0,
"_isQimFriend" : 0,
"_isRemark" : 0,
"_isShortcutEnable" : 1,
"_isShortcutEnableUpdate" : 0,
"_isSpecialCareOpen" : 0,
"_isWifi" : 0,
"_lastChatTime" : 0,
"_lastGetCustomStateTime" : 1682211584.541188,
"_lastGetOnlineInfoTime" : 1682211584.541188,
"_lastKeyTime" : 0,
"_lastLoginClient" : 0,
"_lastLoginType" : 0,
"_lastPraiseTime" : 0,
"_lastQzoneTime" : 0,
"_locationAbility" : 0,
"_loverFlag" : 0,
"_loverKeyFlag" : 0,
"_loverKeyLevel" : 0,
"_loverKeyTransFlag" : 0,
"_magicFontOpenFlagUpdateTime" : 0,
"_magicFontType" : 0,
"_magicFontTypeUpdateTime" : 0,
"_matchRange" : "AAAAAAAAAAAAAAAAAAAAAA==",
"_maxGetCustomStateInterval" : 0.0,
"_maxGetOnlineInfoInterval" : 0.0,
"_memberLevel" : 0,
"_nameplateVipType" : 0,
"_needShipAnimation" : 0,
"_needShowFriendTreeAnimation" : 0,
"_network" : 0,
"_newBoatDays" : 0,
"_newBoatLevel" : 0,
"_nick" : "10001",
"_notiNeedHideSession" : 0,
"_notiNoPreview" : 0,
"_notiNoSound" : 0,
"_notiNoVibrate" : 0,
"_onlineMusicEndTime" : 0,
"_onlineMusicRemainingTime" : 0,
"_onlineMusicSourceType" : 0,
"_onlineMusicTotalTime" : 0,
"_pendantIdUpdateTime" : 0,
"_praiseHotDays" : 0,
"_praiseHotLevel" : 0,
"_priority" : 0,
"_propertyMD5" : "",
"_qslCreateTime" : 0,
"_qzoneDays" : 0,
"_qzoneLevel" : 0,
"_recommendHoldFlag" : 0,
"_richOnlineState" : 65535,
"_sex" : 2,
"_shouldShowCustomState" : 0,
"_sig" : "U",
"_specialCareZone" : 0,
"_sqq" : 0,
"_status" : 20,
"_supportVideo" : 0,
"_terminalDescription" : "",
"_topIdentityInfo" : 18446744073709551615,
"_vipFontId" : 0,
"_vipInfoDic" : null
}
比如需要解析并读取"_richOnlineState"字段的值,解析示例代码:
CPlistObject mPlist;
mPlist.OpenPlistFile("demo.plist");
uint32_t v = mPlist["_richOnlineState"].asInt();
嗯,非常简单。最后读取的时候,记得校验字段是否存在,否则jsoncpp可能会抛异常。
2023/12/27 | Tags:plist,json,parser,C wapper | C/C++代码 | 查看评论(0)