BlackFeather'S Blog

首页 | |

plist转json解析类plist2json(libplist C++封装类)


苹果配置中大量用到了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)

相关文章:

Powered By Z-Blog  触屏版 | WAP版 | 电脑版