CubismJsonParser.cs 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728
  1. /**
  2. * Copyright(c) Live2D Inc. All rights reserved.
  3. *
  4. * Use of this source code is governed by the Live2D Open Software license
  5. * that can be found at http: //live2d.com/eula/live2d-open-software-license-agreement_en.html.
  6. */
  7. using System;
  8. using System.Collections.Generic;
  9. using System.Text;
  10. namespace Live2D.Cubism.Framework.Json
  11. {
  12. /// <summary>
  13. /// Cubism json parser for loading the configuration file etc.
  14. ///
  15. /// Minimal lightweight JSON parser that only supports Ascii characters.
  16. /// Specification is a subset of JSON.
  17. ///
  18. /// Unsupported item.
  19. /// - Non-ASCII characters such as Japanese.
  20. /// - Exponential representation by e.
  21. /// </summary>
  22. public class CubismJsonParser
  23. {
  24. #region variable
  25. /// <summary>
  26. /// Array of buffer.
  27. /// </summary>
  28. private char[] buffer;
  29. /// <summary>
  30. /// Length of buffer.
  31. /// </summary>
  32. private int length;
  33. /// <summary>
  34. /// For error message.
  35. /// </summary>
  36. private int line_count = 0;
  37. /// <summary>
  38. /// Root node.
  39. /// </summary>
  40. private Value root;
  41. #endregion
  42. /// <summary>
  43. /// Constructor.
  44. /// </summary>
  45. /// <param name"jsonBytes">Byte data.</param>
  46. public CubismJsonParser(char[] jsonBytes)
  47. {
  48. this.buffer = jsonBytes;
  49. this.length = jsonBytes.Length;
  50. }
  51. #region Parse Functionn
  52. /// <summary>
  53. /// Parse JSON.
  54. /// </summary>
  55. /// <returns>Value of parsed from JSON.</returns>
  56. public Value Parse()
  57. // throws Exception.
  58. {
  59. try
  60. {
  61. var ret = new int[1];
  62. root = ParseValue(buffer, length, 0, ret);
  63. return root;
  64. }
  65. catch (Exception e)
  66. {
  67. throw new Exception("json error " + "@line:" + line_count + " / " + e.Message, e);
  68. }
  69. }
  70. /// <summary>
  71. /// Parse JSON from byte data.
  72. /// </summary>
  73. /// <param name="jsonBytes">Byte data.</param>
  74. /// <returns>Value of parsed from JSON.</returns>
  75. public static Value ParseFromBytes(char[] jsonBytes)
  76. // throws Exception.
  77. {
  78. var jp = new CubismJsonParser(jsonBytes);
  79. var ret = jp.Parse();
  80. return ret;
  81. }
  82. /// <summary>
  83. /// Parse JSON from string data.
  84. /// </summary>
  85. /// <param name="jsonString">String data.</param>
  86. /// <returns>Value of parsed from JSON.</returns>
  87. public static Value ParseFromString(String jsonString)
  88. // throws Exception.
  89. {
  90. var buffer = jsonString.ToCharArray();
  91. var jp = new CubismJsonParser(buffer);
  92. var ret = jp.Parse();
  93. return ret;
  94. }
  95. /// <summary>
  96. /// Parse till next.
  97. /// </summary>
  98. /// <param name="buffer">json data buffer.</param>
  99. /// <param name="length">json data buffer length.</param>
  100. /// <param name="pos">Parse position.</param>
  101. /// <param name="endPos">End position.</param>
  102. /// <returns>String of parsed from JSON.</returns>
  103. private static String ParseString(char[] str, int length, int pos, int[] endPos)
  104. // throws Exception.
  105. {
  106. char c, c2;
  107. StringBuilder stringBuffer = null;
  108. var startPos = pos; // start pos of the word which is not in sbuf
  109. for (var i = pos; i < length; i++)
  110. {
  111. c = (char)(str[i] & 0xFF);
  112. switch (c)
  113. {
  114. case '\"': // end " , escape char never comes here.
  115. endPos[0] = i + 1; // next word of "
  116. if (stringBuffer != null)
  117. {
  118. if (i - 1 > startPos) stringBuffer.Append(new string(str, startPos, i - 1 - startPos)); // regist till prev char
  119. return stringBuffer.ToString();
  120. }
  121. else
  122. {
  123. return new string(str, pos, i - pos);
  124. }
  125. case '\\': // escape
  126. if (stringBuffer == null)
  127. {
  128. stringBuffer = new StringBuilder();
  129. }
  130. if (i > startPos) stringBuffer.Append(new string(str, startPos, i - startPos)); // regist till prev char
  131. i++; // 2 chars
  132. if (i < length)
  133. {
  134. c2 = (char)(str[i] & 0xFF);
  135. switch (c2)
  136. {
  137. case '\\': stringBuffer.Append('\\'); break;
  138. case '\"': stringBuffer.Append('\"'); break;
  139. case '/': stringBuffer.Append('/'); break;
  140. case 'b': stringBuffer.Append('\b'); break;
  141. case 'f': stringBuffer.Append('\f'); break;
  142. case 'n': stringBuffer.Append('\n'); break;
  143. case 'r': stringBuffer.Append('\r'); break;
  144. case 't': stringBuffer.Append('\t'); break;
  145. case 'u':
  146. throw new Exception("parse string/unicode escape not supported");
  147. }
  148. }
  149. else
  150. {
  151. throw new Exception("parse string/escape error");
  152. }
  153. startPos = i + 1; // after next to escape char (2chars)
  154. break;
  155. }
  156. }
  157. throw new Exception("parse string/illegal end");
  158. }
  159. /// <summary>
  160. /// Parse object, not include { at pos.
  161. /// </summary>
  162. /// <param name="buffer">json data buffer.</param>
  163. /// <param name="length">json data buffer length.</param>
  164. /// <param name="pos">Parse position.</param>
  165. /// <param name="endPos">End position.</param>
  166. /// <returns>Value of parsed from JSON.</returns>
  167. private Value ParseObject(char[] buffer, int length, int pos, int[] endPos)
  168. // throws Exception.
  169. {
  170. var ret = new Dictionary<String, Value>();
  171. // key : value ,
  172. String key = null;
  173. char c;
  174. var i = pos;
  175. var ret_endPos = new int[1];
  176. var ok = false;
  177. // loop till , is lasting
  178. for (; i < length; i++)
  179. {
  180. // FOR_LOOP1:
  181. for (; i < length; i++)
  182. {
  183. c = (char)(buffer[i] & 0xFF);
  184. switch (c)
  185. {
  186. case '\"':
  187. key = ParseString(buffer, length, i + 1, ret_endPos);
  188. i = ret_endPos[0];
  189. ok = true;
  190. goto EXIT_FOR_LOOP1;
  191. case '}': endPos[0] = i + 1; return new Value(ret); // empty
  192. case ':': throw new Exception("illegal ':' position");
  193. default: break; // skip char
  194. }
  195. }
  196. EXIT_FOR_LOOP1:
  197. if (!ok)
  198. {
  199. throw new Exception("key not found");
  200. }
  201. ok = false;
  202. // check :
  203. // FOR_LOOP2:
  204. for (; i < length; i++)
  205. {
  206. c = (char)(buffer[i] & 0xFF);
  207. switch (c)
  208. {
  209. case ':': ok = true; i++; goto EXIT_FOR_LOOP2;
  210. case '}': throw new Exception("illegal '}' position");
  211. case '\n': line_count++; break;
  212. default: break; // skip char
  213. }
  214. }
  215. EXIT_FOR_LOOP2:
  216. if (!ok)
  217. {
  218. throw new Exception("':' not found");
  219. }
  220. // check :
  221. Value value = ParseValue(buffer, length, i, ret_endPos);
  222. i = ret_endPos[0];
  223. ret.Add(key, value);
  224. // FOR_LOOP3:
  225. for (; i < length; i++)
  226. {
  227. c = (char)(buffer[i] & 0xFF);
  228. switch (c)
  229. {
  230. case ',': goto EXIT_FOR_LOOP3; // next key, value
  231. case '}': endPos[0] = i + 1; return new Value(ret); //finished
  232. case '\n': line_count++; break;
  233. default: break; // skip
  234. }
  235. }
  236. EXIT_FOR_LOOP3: ;
  237. }
  238. throw new Exception("illegal end of ParseObject");
  239. }
  240. /// <summary>
  241. /// Parse Array, not include first[ at pos.
  242. /// </summary>
  243. /// <param name="buffer">json data buffer.</param>
  244. /// <param name="length">json data buffer length.</param>
  245. /// <param name="pos">Parse position.</param>
  246. /// <param name="endPos">End position.</param>
  247. /// <returns>Value of parsed from JSON.</returns>
  248. private Value ParseArray(char[] buffer, int length, int pos, int[] endPos)
  249. // throws Exception.
  250. {
  251. var ret = new List<Value>();
  252. var i = pos;
  253. char c;
  254. var ret_endPos = new int[1];
  255. // loop till, is lasting
  256. for (; i < length; i++)
  257. {
  258. // check :
  259. var value = ParseValue(buffer, length, i, ret_endPos);
  260. i = ret_endPos[0];
  261. if (value != null)
  262. {
  263. ret.Add(value);
  264. }
  265. // FOR_LOOP3:
  266. for (; i < length; i++)
  267. {
  268. c = (char)(buffer[i] & 0xFF);
  269. switch (c)
  270. {
  271. case ',': goto EXIT_FOR_LOOP3; // next key value
  272. case ']': endPos[0] = i + 1; return new Value(ret); // finish
  273. case '\n': line_count++; break;
  274. default: break; // skip
  275. }
  276. }
  277. EXIT_FOR_LOOP3: ;
  278. }
  279. throw new Exception("illegal end of ParseObject");
  280. }
  281. /// <summary>
  282. /// Parse double.
  283. /// </summary>
  284. /// <param name="buffer">json data buffer.</param>
  285. /// <param name="length">json data buffer length.</param>
  286. /// <param name="pos">Parse position.</param>
  287. /// <param name="endPos">End position.</param>
  288. /// <returns>Double of parsed from JSON.</returns>
  289. public static double strToDouble(char[] str, int length, int pos, int[] endPos)
  290. {
  291. // int length = str.length ;
  292. var i = pos;
  293. var minus = false; // minus flag
  294. var period = false;
  295. var v1 = 0.0;
  296. // check minus
  297. var c = (char)(str[i] & 0xFF);
  298. if(c == '-')
  299. {
  300. minus = true;
  301. i++;
  302. }
  303. // check integer part
  304. // FOR_LOOP:
  305. for (; i < length; i++)
  306. {
  307. c = (char)(str[i] & 0xFF);
  308. switch (c)
  309. {
  310. case '0': v1 = v1 * 10; break;
  311. case '1': v1 = v1 * 10 + 1; break;
  312. case '2': v1 = v1 * 10 + 2; break;
  313. case '3': v1 = v1 * 10 + 3; break;
  314. case '4': v1 = v1 * 10 + 4; break;
  315. case '5': v1 = v1 * 10 + 5; break;
  316. case '6': v1 = v1 * 10 + 6; break;
  317. case '7': v1 = v1 * 10 + 7; break;
  318. case '8': v1 = v1 * 10 + 8; break;
  319. case '9': v1 = v1 * 10 + 9; break;
  320. case '.':
  321. period = true;
  322. i++;
  323. goto EXIT_FOR_LOOP;
  324. default: // new line code , and delim
  325. goto EXIT_FOR_LOOP;
  326. }
  327. }
  328. EXIT_FOR_LOOP:
  329. // check floating point part
  330. if (period)
  331. {
  332. var mul = 0.1;
  333. // FOR_LOOP2:
  334. for (; i < length; i++)
  335. {
  336. c = (char)(str[i] & 0xFF);
  337. switch (c)
  338. {
  339. case '0': break;
  340. case '1': v1 += mul * 1; break;
  341. case '2': v1 += mul * 2; break;
  342. case '3': v1 += mul * 3; break;
  343. case '4': v1 += mul * 4; break;
  344. case '5': v1 += mul * 5; break;
  345. case '6': v1 += mul * 6; break;
  346. case '7': v1 += mul * 7; break;
  347. case '8': v1 += mul * 8; break;
  348. case '9': v1 += mul * 9; break;
  349. default: // new line code, and delim
  350. goto EXIT_FOR_LOOP2;
  351. }
  352. mul *= 0.1;
  353. }
  354. EXIT_FOR_LOOP2:;
  355. }
  356. if (minus)
  357. {
  358. v1 = -v1;
  359. }
  360. endPos[0] = i;
  361. return v1;
  362. }
  363. /// <summary>
  364. /// Parse one Value(float, String, Object, Array, null, true, false).
  365. /// </summary>
  366. /// <param name="buffer">json data buffer.</param>
  367. /// <param name="length">json data buffer length.</param>
  368. /// <param name="pos">Parse position.</param>
  369. /// <param name="endPos">End position.</param>
  370. /// <returns>Value of parsed from JSON.</returns>
  371. private Value ParseValue(char[] buffer, int length, int pos, int[] endPos)
  372. // throws Exception.
  373. {
  374. Value obj;
  375. var i = pos;
  376. for (; i < length; i++)
  377. {
  378. var c = (char)(buffer[i] & 0xFF);
  379. switch (c)
  380. {
  381. case '-':
  382. case '.':
  383. case '0':
  384. case '1':
  385. case '2':
  386. case '3':
  387. case '4':
  388. case '5':
  389. case '6':
  390. case '7':
  391. case '8':
  392. case '9':
  393. var f = strToDouble(buffer, length, i, endPos);
  394. return new Value(f);
  395. case '\"':
  396. obj = new Value(ParseString(buffer, length, i + 1, endPos)); // next to \"
  397. return obj;
  398. case '[':
  399. obj = ParseArray(buffer, length, i + 1, endPos);
  400. return obj;
  401. case ']': // It is illegal } but skip it. There seems to be unnecessary at the end of the array
  402. // obj = null;
  403. endPos[0] = i; // Reprocess the same letters
  404. return null;
  405. case '{':
  406. obj = ParseObject(buffer, length, i + 1, endPos);
  407. return obj;
  408. case 'n': // null
  409. if (i + 3 < length) obj = null;
  410. else throw new Exception("parse null");
  411. return obj;
  412. case 't': // true
  413. if (i + 3 < length) obj = new Value(true);
  414. else throw new Exception("parse true");
  415. return obj;
  416. case 'f': // false
  417. if (i + 4 < length) obj = new Value(false);
  418. else throw new Exception("parse false");
  419. return obj;
  420. case ',': // Array separator
  421. throw new Exception("illegal ',' position");
  422. case '\n': line_count++;
  423. break;
  424. case ' ':
  425. case '\t':
  426. case '\r':
  427. default: // skip
  428. break;
  429. }
  430. }
  431. // throw new Exception("illegal end of value");
  432. return null;
  433. }
  434. #endregion
  435. }
  436. /// <summary>
  437. /// Json value.
  438. /// </summary>
  439. public class Value
  440. {
  441. private Object _object;
  442. /// <summary>
  443. /// Get value.
  444. /// </summary>
  445. /// <returns>The JSON value.</returns>
  446. public Value(Object obj)
  447. {
  448. this._object = obj;
  449. }
  450. #region toString
  451. /// <summary>
  452. /// Value to string.
  453. /// </summary>
  454. /// <returns>Value of string type.</returns>
  455. public string toString()
  456. {
  457. return toString("");
  458. }
  459. /// <summary>
  460. /// Value to string.
  461. /// </summary>
  462. /// <returns>Value of string type.</returns>
  463. public string toString(string indent)
  464. {
  465. if (_object is string)
  466. {
  467. return (string)_object;
  468. }
  469. //------------ List ------------
  470. else if (_object is List<Value>)
  471. {
  472. string ret = indent + "[\n";
  473. foreach (Value v in ((List<Value>)_object))
  474. {
  475. ret += indent + " " + v.toString(indent + " ") + "\n";
  476. }
  477. ret += indent + "]\n";
  478. return ret;
  479. }
  480. //------------ Dictionary ------------
  481. else if (_object is Dictionary<string, Value>)
  482. {
  483. string ret = indent + "{\n";
  484. Dictionary<string, Value> vmap = (Dictionary<string, Value>)_object;
  485. foreach (KeyValuePair<string, Value> pair in vmap)
  486. {
  487. Value v = pair.Value;
  488. ret += indent + " " + pair.Key + " : " + v.toString(indent + " ") + "\n";
  489. }
  490. ret += indent + "}\n";
  491. return ret;
  492. }
  493. else
  494. {
  495. return "" + _object;
  496. }
  497. }
  498. #endregion
  499. #region toInt
  500. /// <summary>
  501. /// Value to int.
  502. /// </summary>
  503. /// <returns>Value of int type.</returns>
  504. public int toInt()
  505. {
  506. return toInt(0);
  507. }
  508. /// <summary>
  509. /// Value to int.
  510. /// </summary>
  511. /// <param name="defaultValue">Default value.</param>
  512. /// <returns>Value of int type.</returns>
  513. public int toInt(int defaultValue)
  514. {
  515. return (_object is Double) ? (int)((Double)_object) : defaultValue;
  516. }
  517. #endregion
  518. #region ToFloat
  519. /// <summary>
  520. /// Value to float.
  521. /// </summary>
  522. /// <returns>Value of float type.</returns>
  523. public float ToFloat()
  524. {
  525. return ToFloat(0);
  526. }
  527. /// <summary>
  528. /// Value to float.
  529. /// </summary>
  530. /// <param name="defaultValue">Default value.</param>
  531. /// <returns>Value of float type.</returns>
  532. public float ToFloat(float defaultValue)
  533. {
  534. return (_object is Double) ? (float)((Double)_object) : defaultValue;
  535. }
  536. #endregion
  537. #region ToDouble
  538. /// <summary>
  539. /// Value to double.
  540. /// </summary>
  541. /// <returns>Value of double type.</returns>
  542. public double ToDouble()
  543. {
  544. return ToDouble(0);
  545. }
  546. /// <summary>
  547. /// Value to double.
  548. /// </summary>
  549. /// <param name="defaultValue">Default value.</param>
  550. /// <returns>Value of double type.</returns>
  551. public double ToDouble(double defaultValue)
  552. {
  553. return (_object is Double) ? ((Double)_object) : defaultValue;
  554. }
  555. #endregion
  556. #region toArray
  557. /// <summary>
  558. /// Get list.
  559. /// </summary>
  560. /// <param name="defaultValue">Default value.</param>
  561. /// <returns>Value list.</returns>
  562. public List<Value> GetVector(List<Value> defalutV)
  563. {
  564. return (_object is List<Value>) ? (List<Value>)_object : defalutV;
  565. }
  566. /// <summary>
  567. /// Get from list.
  568. /// </summary>
  569. /// <param name="index">Value index in list.</param>
  570. /// <returns>Value from list.</returns>
  571. public Value Get(int index)
  572. {
  573. return (_object is List<Value>) ? (Value)((List<Value>)_object)[index] : null;
  574. }
  575. #endregion
  576. #region toDictionary
  577. /// <summary>
  578. /// Get Value of dictionary type.
  579. /// </summary>
  580. /// <param name="defaultValue">Default value.</param>
  581. /// <returns>Value of dictionary type.</returns>
  582. public Dictionary<string, Value> GetMap(Dictionary<string, Value> defalutV)
  583. {
  584. return (_object is Dictionary<string, Value>) ? (Dictionary<string, Value>)_object : defalutV;
  585. }
  586. /// <summary>
  587. /// Get data from dictionary.
  588. /// </summary>
  589. /// <param name="key">key.</param>
  590. /// <returns>Key value from dictionary.</returns>
  591. public Value Get(string key)
  592. {
  593. if(_object is Dictionary<string, Value>)
  594. {
  595. if (((Dictionary<string, Value>)_object).ContainsKey(key)) return (Value)((Dictionary<string, Value>)_object)[key];
  596. }
  597. return null;
  598. }
  599. /// <summary>
  600. /// Get key list from dictionary.
  601. /// </summary>
  602. /// <returns>Key list.</returns>
  603. public List<string> KeySet()
  604. {
  605. return (_object is Dictionary<string, Value>) ? new List<string>(((Dictionary<string, Value>)_object).Keys) : null;
  606. }
  607. /// <summary>
  608. /// Get dictionary.
  609. /// </summary>
  610. /// <returns>Value of dictionary type.</returns>
  611. public Dictionary<string, Value> ToMap()
  612. {
  613. return (_object is Dictionary<string, Value>) ? (Dictionary<string, Value>)_object: null;
  614. }
  615. #endregion
  616. #region check type
  617. /// <summary>
  618. /// Confirm the type.
  619. /// </summary>
  620. public bool isNull() { return _object == null; }
  621. public bool isBoolean() { return _object is Boolean; }
  622. public bool isDouble() { return _object is Double; }
  623. public bool isString() { return _object is string; }
  624. public bool isArray() { return _object is List<Value>; }
  625. public bool isMap() { return _object is Dictionary<string, Value>; }
  626. #endregion
  627. }
  628. }