SIOJsonObject.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569
  1. // Modifications Copyright 2018-current Getnamo. All Rights Reserved
  2. // Copyright 2014 Vladimir Alyamkin. All Rights Reserved.
  3. #include "SIOJsonObject.h"
  4. #include "SIOJsonValue.h"
  5. #include "ISIOJson.h"
  6. #include "Misc/Base64.h"
  7. #include "Policies/CondensedJsonPrintPolicy.h"
  8. #include "Serialization/JsonWriter.h"
  9. #include "Serialization/JsonSerializer.h"
  10. typedef TJsonWriterFactory< TCHAR, TCondensedJsonPrintPolicy<TCHAR> > FCondensedJsonStringWriterFactory;
  11. typedef TJsonWriter< TCHAR, TCondensedJsonPrintPolicy<TCHAR> > FCondensedJsonStringWriter;
  12. USIOJsonObject::USIOJsonObject(const class FObjectInitializer& PCIP)
  13. : Super(PCIP)
  14. {
  15. Reset();
  16. }
  17. USIOJsonObject* USIOJsonObject::ConstructJsonObject(UObject* WorldContextObject)
  18. {
  19. return NewObject<USIOJsonObject>();
  20. }
  21. void USIOJsonObject::Reset()
  22. {
  23. if (JsonObj.IsValid())
  24. {
  25. JsonObj.Reset();
  26. }
  27. JsonObj = MakeShareable(new FJsonObject());
  28. }
  29. TSharedPtr<FJsonObject>& USIOJsonObject::GetRootObject()
  30. {
  31. return JsonObj;
  32. }
  33. void USIOJsonObject::SetRootObject(const TSharedPtr<FJsonObject>& JsonObject)
  34. {
  35. JsonObj = JsonObject;
  36. }
  37. //////////////////////////////////////////////////////////////////////////
  38. // Serialization
  39. FString USIOJsonObject::EncodeJson() const
  40. {
  41. if (!JsonObj.IsValid())
  42. {
  43. return TEXT("");
  44. }
  45. FString OutputString;
  46. TSharedRef< FCondensedJsonStringWriter > Writer = FCondensedJsonStringWriterFactory::Create(&OutputString);
  47. FJsonSerializer::Serialize(JsonObj.ToSharedRef(), Writer);
  48. return OutputString;
  49. }
  50. FString USIOJsonObject::EncodeJsonToSingleString() const
  51. {
  52. FString OutputString = EncodeJson();
  53. // Remove line terminators
  54. (void)OutputString.Replace(LINE_TERMINATOR, TEXT(""));
  55. // Remove tabs
  56. (void)OutputString.Replace(LINE_TERMINATOR, TEXT("\t"));
  57. return OutputString;
  58. }
  59. bool USIOJsonObject::DecodeJson(const FString& JsonString)
  60. {
  61. TSharedRef< TJsonReader<> > Reader = TJsonReaderFactory<>::Create(*JsonString);
  62. if (FJsonSerializer::Deserialize(Reader, JsonObj) && JsonObj.IsValid())
  63. {
  64. return true;
  65. }
  66. // If we've failed to deserialize the string, we should clear our internal data
  67. Reset();
  68. UE_LOG(LogSIOJ, Error, TEXT("Json decoding failed for: %s"), *JsonString);
  69. return false;
  70. }
  71. //////////////////////////////////////////////////////////////////////////
  72. // FJsonObject API
  73. TArray<FString> USIOJsonObject::GetFieldNames()
  74. {
  75. TArray<FString> Result;
  76. if (!JsonObj.IsValid())
  77. {
  78. return Result;
  79. }
  80. JsonObj->Values.GetKeys(Result);
  81. return Result;
  82. }
  83. bool USIOJsonObject::HasField(const FString& FieldName) const
  84. {
  85. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  86. {
  87. return false;
  88. }
  89. return JsonObj->HasField(FieldName);
  90. }
  91. void USIOJsonObject::RemoveField(const FString& FieldName)
  92. {
  93. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  94. {
  95. return;
  96. }
  97. JsonObj->RemoveField(FieldName);
  98. }
  99. USIOJsonValue* USIOJsonObject::GetField(const FString& FieldName) const
  100. {
  101. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  102. {
  103. return nullptr;
  104. }
  105. TSharedPtr<FJsonValue> NewVal = JsonObj->TryGetField(FieldName);
  106. if (NewVal.IsValid())
  107. {
  108. USIOJsonValue* NewValue = NewObject<USIOJsonValue>();
  109. NewValue->SetRootValue(NewVal);
  110. return NewValue;
  111. }
  112. return nullptr;
  113. }
  114. void USIOJsonObject::SetField(const FString& FieldName, USIOJsonValue* JsonValue)
  115. {
  116. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  117. {
  118. return;
  119. }
  120. JsonObj->SetField(FieldName, JsonValue->GetRootValue());
  121. }
  122. //////////////////////////////////////////////////////////////////////////
  123. // FJsonObject API Helpers (easy to use with simple Json objects)
  124. float USIOJsonObject::GetNumberField(const FString& FieldName) const
  125. {
  126. if (!JsonObj.IsValid() || !JsonObj->HasTypedField<EJson::Number>(FieldName))
  127. {
  128. UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Number"), *FieldName);
  129. return 0.0f;
  130. }
  131. return JsonObj->GetNumberField(FieldName);
  132. }
  133. void USIOJsonObject::SetNumberField(const FString& FieldName, float Number)
  134. {
  135. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  136. {
  137. return;
  138. }
  139. JsonObj->SetNumberField(FieldName, Number);
  140. }
  141. FString USIOJsonObject::GetStringField(const FString& FieldName) const
  142. {
  143. if (!JsonObj.IsValid() || !JsonObj->HasTypedField<EJson::String>(FieldName))
  144. {
  145. UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type String"), *FieldName);
  146. return TEXT("");
  147. }
  148. return JsonObj->GetStringField(FieldName);
  149. }
  150. void USIOJsonObject::SetStringField(const FString& FieldName, const FString& StringValue)
  151. {
  152. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  153. {
  154. return;
  155. }
  156. JsonObj->SetStringField(FieldName, StringValue);
  157. }
  158. bool USIOJsonObject::GetBoolField(const FString& FieldName) const
  159. {
  160. if (!JsonObj.IsValid() || !JsonObj->HasTypedField<EJson::Boolean>(FieldName))
  161. {
  162. UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Boolean"), *FieldName);
  163. return false;
  164. }
  165. return JsonObj->GetBoolField(FieldName);
  166. }
  167. void USIOJsonObject::SetBoolField(const FString& FieldName, bool InValue)
  168. {
  169. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  170. {
  171. return;
  172. }
  173. JsonObj->SetBoolField(FieldName, InValue);
  174. }
  175. TArray<USIOJsonValue*> USIOJsonObject::GetArrayField(const FString& FieldName)
  176. {
  177. if (!JsonObj->HasTypedField<EJson::Array>(FieldName))
  178. {
  179. UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Array"), *FieldName);
  180. }
  181. TArray<USIOJsonValue*> OutArray;
  182. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  183. {
  184. return OutArray;
  185. }
  186. TArray< TSharedPtr<FJsonValue> > ValArray = JsonObj->GetArrayField(FieldName);
  187. for (auto Value : ValArray)
  188. {
  189. USIOJsonValue* NewValue = NewObject<USIOJsonValue>();
  190. NewValue->SetRootValue(Value);
  191. OutArray.Add(NewValue);
  192. }
  193. return OutArray;
  194. }
  195. void USIOJsonObject::SetArrayField(const FString& FieldName, const TArray<USIOJsonValue*>& InArray)
  196. {
  197. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  198. {
  199. return;
  200. }
  201. TArray< TSharedPtr<FJsonValue> > ValArray;
  202. // Process input array and COPY original values
  203. for (auto InVal : InArray)
  204. {
  205. TSharedPtr<FJsonValue> JsonVal = InVal->GetRootValue();
  206. switch (InVal->GetType())
  207. {
  208. case ESIOJson::None:
  209. break;
  210. case ESIOJson::Null:
  211. ValArray.Add(MakeShareable(new FJsonValueNull()));
  212. break;
  213. case ESIOJson::String:
  214. ValArray.Add(MakeShareable(new FJsonValueString(JsonVal->AsString())));
  215. break;
  216. case ESIOJson::Number:
  217. ValArray.Add(MakeShareable(new FJsonValueNumber(JsonVal->AsNumber())));
  218. break;
  219. case ESIOJson::Boolean:
  220. ValArray.Add(MakeShareable(new FJsonValueBoolean(JsonVal->AsBool())));
  221. break;
  222. case ESIOJson::Array:
  223. ValArray.Add(MakeShareable(new FJsonValueArray(JsonVal->AsArray())));
  224. break;
  225. case ESIOJson::Object:
  226. ValArray.Add(MakeShareable(new FJsonValueObject(JsonVal->AsObject())));
  227. break;
  228. default:
  229. break;
  230. }
  231. }
  232. JsonObj->SetArrayField(FieldName, ValArray);
  233. }
  234. void USIOJsonObject::MergeJsonObject(USIOJsonObject* InJsonObject, bool Overwrite)
  235. {
  236. TArray<FString> Keys = InJsonObject->GetFieldNames();
  237. for (auto Key : Keys)
  238. {
  239. if (Overwrite == false && HasField(Key))
  240. {
  241. continue;
  242. }
  243. SetField(Key, InJsonObject->GetField(Key));
  244. }
  245. }
  246. USIOJsonObject* USIOJsonObject::GetObjectField(const FString& FieldName) const
  247. {
  248. if (!JsonObj.IsValid() || !JsonObj->HasTypedField<EJson::Object>(FieldName))
  249. {
  250. UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Object"), *FieldName);
  251. return nullptr;
  252. }
  253. TSharedPtr<FJsonObject> JsonObjField = JsonObj->GetObjectField(FieldName);
  254. USIOJsonObject* OutRestJsonObj = NewObject<USIOJsonObject>();
  255. OutRestJsonObj->SetRootObject(JsonObjField);
  256. return OutRestJsonObj;
  257. }
  258. void USIOJsonObject::SetObjectField(const FString& FieldName, USIOJsonObject* JsonObject)
  259. {
  260. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  261. {
  262. return;
  263. }
  264. JsonObj->SetObjectField(FieldName, JsonObject->GetRootObject());
  265. }
  266. void USIOJsonObject::GetBinaryField(const FString& FieldName, TArray<uint8>& OutBinary) const
  267. {
  268. if (!JsonObj->HasTypedField<EJson::String>(FieldName))
  269. {
  270. UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type String"), *FieldName);
  271. }
  272. TSharedPtr<FJsonValue> JsonValue = JsonObj->TryGetField(FieldName);
  273. if (FJsonValueBinary::IsBinary(JsonValue))
  274. {
  275. OutBinary = FJsonValueBinary::AsBinary(JsonValue);
  276. }
  277. else if (JsonValue->Type == EJson::String)
  278. {
  279. //If we got a string that isn't detected as a binary via socket.io protocol hack
  280. //then we need to decode this string as base 64
  281. TArray<uint8> DecodedArray;
  282. bool bDidDecodeCorrectly = FBase64::Decode(JsonValue->AsString(), DecodedArray);
  283. if (!bDidDecodeCorrectly)
  284. {
  285. UE_LOG(LogSIOJ, Warning, TEXT("USIOJsonObject::GetBinaryField couldn't decode %s as a binary."), *JsonValue->AsString());
  286. }
  287. OutBinary = DecodedArray;
  288. }
  289. else
  290. {
  291. TArray<uint8> EmptyArray;
  292. OutBinary = EmptyArray;
  293. }
  294. }
  295. void USIOJsonObject::SetBinaryField(const FString& FieldName, const TArray<uint8>& Bytes)
  296. {
  297. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  298. {
  299. return;
  300. }
  301. TSharedPtr<FJsonValueBinary> JsonValue = MakeShareable(new FJsonValueBinary(Bytes));
  302. JsonObj->SetField(FieldName, JsonValue);
  303. }
  304. //////////////////////////////////////////////////////////////////////////
  305. // Array fields helpers (uniform arrays)
  306. TArray<float> USIOJsonObject::GetNumberArrayField(const FString& FieldName)
  307. {
  308. if (!JsonObj->HasTypedField<EJson::Array>(FieldName))
  309. {
  310. UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Array"), *FieldName);
  311. }
  312. TArray<float> NumberArray;
  313. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  314. {
  315. return NumberArray;
  316. }
  317. TArray<TSharedPtr<FJsonValue> > JsonArrayValues = JsonObj->GetArrayField(FieldName);
  318. for (TArray<TSharedPtr<FJsonValue> >::TConstIterator It(JsonArrayValues); It; ++It)
  319. {
  320. auto Value = (*It).Get();
  321. if (Value->Type != EJson::Number)
  322. {
  323. UE_LOG(LogSIOJ, Error, TEXT("Not Number element in array with field name %s"), *FieldName);
  324. }
  325. NumberArray.Add((*It)->AsNumber());
  326. }
  327. return NumberArray;
  328. }
  329. void USIOJsonObject::SetNumberArrayField(const FString& FieldName, const TArray<float>& NumberArray)
  330. {
  331. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  332. {
  333. return;
  334. }
  335. TArray< TSharedPtr<FJsonValue> > EntriesArray;
  336. for (auto Number : NumberArray)
  337. {
  338. EntriesArray.Add(MakeShareable(new FJsonValueNumber(Number)));
  339. }
  340. JsonObj->SetArrayField(FieldName, EntriesArray);
  341. }
  342. TArray<FString> USIOJsonObject::GetStringArrayField(const FString& FieldName)
  343. {
  344. if (!JsonObj->HasTypedField<EJson::Array>(FieldName))
  345. {
  346. UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Array"), *FieldName);
  347. }
  348. TArray<FString> StringArray;
  349. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  350. {
  351. return StringArray;
  352. }
  353. TArray<TSharedPtr<FJsonValue> > JsonArrayValues = JsonObj->GetArrayField(FieldName);
  354. for (TArray<TSharedPtr<FJsonValue> >::TConstIterator It(JsonArrayValues); It; ++It)
  355. {
  356. auto Value = (*It).Get();
  357. if (Value->Type != EJson::String)
  358. {
  359. UE_LOG(LogSIOJ, Error, TEXT("Not String element in array with field name %s"), *FieldName);
  360. }
  361. StringArray.Add((*It)->AsString());
  362. }
  363. return StringArray;
  364. }
  365. void USIOJsonObject::SetStringArrayField(const FString& FieldName, const TArray<FString>& StringArray)
  366. {
  367. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  368. {
  369. return;
  370. }
  371. TArray< TSharedPtr<FJsonValue> > EntriesArray;
  372. for (auto String : StringArray)
  373. {
  374. EntriesArray.Add(MakeShareable(new FJsonValueString(String)));
  375. }
  376. JsonObj->SetArrayField(FieldName, EntriesArray);
  377. }
  378. TArray<bool> USIOJsonObject::GetBoolArrayField(const FString& FieldName)
  379. {
  380. if (!JsonObj->HasTypedField<EJson::Array>(FieldName))
  381. {
  382. UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Array"), *FieldName);
  383. }
  384. TArray<bool> BoolArray;
  385. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  386. {
  387. return BoolArray;
  388. }
  389. TArray<TSharedPtr<FJsonValue> > JsonArrayValues = JsonObj->GetArrayField(FieldName);
  390. for (TArray<TSharedPtr<FJsonValue> >::TConstIterator It(JsonArrayValues); It; ++It)
  391. {
  392. auto Value = (*It).Get();
  393. if (Value->Type != EJson::Boolean)
  394. {
  395. UE_LOG(LogSIOJ, Error, TEXT("Not Boolean element in array with field name %s"), *FieldName);
  396. }
  397. BoolArray.Add((*It)->AsBool());
  398. }
  399. return BoolArray;
  400. }
  401. void USIOJsonObject::SetBoolArrayField(const FString& FieldName, const TArray<bool>& BoolArray)
  402. {
  403. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  404. {
  405. return;
  406. }
  407. TArray< TSharedPtr<FJsonValue> > EntriesArray;
  408. for (auto Boolean : BoolArray)
  409. {
  410. EntriesArray.Add(MakeShareable(new FJsonValueBoolean(Boolean)));
  411. }
  412. JsonObj->SetArrayField(FieldName, EntriesArray);
  413. }
  414. TArray<USIOJsonObject*> USIOJsonObject::GetObjectArrayField(const FString& FieldName)
  415. {
  416. if (!JsonObj->HasTypedField<EJson::Array>(FieldName))
  417. {
  418. UE_LOG(LogSIOJ, Warning, TEXT("No field with name %s of type Array"), *FieldName);
  419. }
  420. TArray<USIOJsonObject*> OutArray;
  421. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  422. {
  423. return OutArray;
  424. }
  425. TArray< TSharedPtr<FJsonValue> > ValArray = JsonObj->GetArrayField(FieldName);
  426. for (auto Value : ValArray)
  427. {
  428. if (Value->Type != EJson::Object)
  429. {
  430. UE_LOG(LogSIOJ, Error, TEXT("Not Object element in array with field name %s"), *FieldName);
  431. }
  432. TSharedPtr<FJsonObject> NewObj = Value->AsObject();
  433. USIOJsonObject* NewJson = NewObject<USIOJsonObject>();
  434. NewJson->SetRootObject(NewObj);
  435. OutArray.Add(NewJson);
  436. }
  437. return OutArray;
  438. }
  439. void USIOJsonObject::SetObjectArrayField(const FString& FieldName, const TArray<USIOJsonObject*>& ObjectArray)
  440. {
  441. if (!JsonObj.IsValid() || FieldName.IsEmpty())
  442. {
  443. return;
  444. }
  445. TArray< TSharedPtr<FJsonValue> > EntriesArray;
  446. for (auto Value : ObjectArray)
  447. {
  448. EntriesArray.Add(MakeShareable(new FJsonValueObject(Value->GetRootObject())));
  449. }
  450. JsonObj->SetArrayField(FieldName, EntriesArray);
  451. }