llmessagetemplateparser.cpp
上传用户:king477883
上传日期:2021-03-01
资源大小:9553k
文件大小:16k
源码类别:

游戏引擎

开发平台:

C++ Builder

  1. /** 
  2.  * @file llmessagetemplateparser.cpp
  3.  * @brief LLMessageTemplateParser implementation
  4.  *
  5.  * $LicenseInfo:firstyear=2007&license=viewergpl$
  6.  * 
  7.  * Copyright (c) 2007-2010, Linden Research, Inc.
  8.  * 
  9.  * Second Life Viewer Source Code
  10.  * The source code in this file ("Source Code") is provided by Linden Lab
  11.  * to you under the terms of the GNU General Public License, version 2.0
  12.  * ("GPL"), unless you have obtained a separate licensing agreement
  13.  * ("Other License"), formally executed by you and Linden Lab.  Terms of
  14.  * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15.  * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16.  * 
  17.  * There are special exceptions to the terms and conditions of the GPL as
  18.  * it is applied to this Source Code. View the full text of the exception
  19.  * in the file doc/FLOSS-exception.txt in this software distribution, or
  20.  * online at
  21.  * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22.  * 
  23.  * By copying, modifying or distributing this software, you acknowledge
  24.  * that you have read and understood your obligations described above,
  25.  * and agree to abide by those obligations.
  26.  * 
  27.  * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28.  * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29.  * COMPLETENESS OR PERFORMANCE.
  30.  * $/LicenseInfo$
  31.  */
  32. #include "linden_common.h"
  33. #include "llmessagetemplateparser.h"
  34. #include <boost/tokenizer.hpp>
  35. // What follows is a bunch of C functions to do validation.
  36. // Lets support a small subset of regular expressions here
  37. // Syntax is a string made up of:
  38. // a - checks against alphanumeric ([A-Za-z0-9])
  39. // c - checks against character ([A-Za-z])
  40. // f - checks against first variable character ([A-Za-z_])
  41. // v - checks against variable ([A-Za-z0-9_])
  42. // s - checks against sign of integer ([-0-9])
  43. //  d - checks against integer digit ([0-9])
  44. //  * - repeat last check
  45. // checks 'a'
  46. BOOL b_return_alphanumeric_ok(char c)
  47. {
  48. if (  (  (c < 'A')
  49.    ||(c > 'Z'))
  50. &&(  (c < 'a')
  51.    ||(c > 'z'))
  52. &&(  (c < '0')
  53.    ||(c > '9')))
  54. {
  55. return FALSE;
  56. }
  57. return TRUE;
  58. }
  59. // checks 'c'
  60. BOOL b_return_character_ok(char c)
  61. {
  62. if (  (  (c < 'A')
  63.    ||(c > 'Z'))
  64. &&(  (c < 'a')
  65.    ||(c > 'z')))
  66. {
  67. return FALSE;
  68. }
  69. return TRUE;
  70. }
  71. // checks 'f'
  72. BOOL b_return_first_variable_ok(char c)
  73. {
  74. if (  (  (c < 'A')
  75.    ||(c > 'Z'))
  76. &&(  (c < 'a')
  77.    ||(c > 'z'))
  78. &&(c != '_'))
  79. {
  80. return FALSE;
  81. }
  82. return TRUE;
  83. }
  84. // checks 'v'
  85. BOOL b_return_variable_ok(char c)
  86. {
  87. if (  (  (c < 'A')
  88.    ||(c > 'Z'))
  89. &&(  (c < 'a')
  90.    ||(c > 'z'))
  91. &&(  (c < '0')
  92.    ||(c > '9'))
  93. &&(c != '_'))
  94. {
  95. return FALSE;
  96. }
  97. return TRUE;
  98. }
  99. // checks 's'
  100. BOOL b_return_signed_integer_ok(char c)
  101. {
  102. if (  (  (c < '0')
  103.    ||(c > '9'))
  104. &&(c != '-'))
  105. {
  106. return FALSE;
  107. }
  108. return TRUE;
  109. }
  110. // checks 'd'
  111. BOOL b_return_integer_ok(char c)
  112. {
  113. if (  (c < '0')
  114. ||(c > '9'))
  115. {
  116. return FALSE;
  117. }
  118. return TRUE;
  119. }
  120. BOOL (*gParseCheckCharacters[])(char c) =
  121. {
  122. b_return_alphanumeric_ok,
  123. b_return_character_ok,
  124. b_return_first_variable_ok,
  125. b_return_variable_ok,
  126. b_return_signed_integer_ok,
  127. b_return_integer_ok
  128. };
  129. S32 get_checker_number(char checker)
  130. {
  131. switch(checker)
  132. {
  133. case 'a':
  134. return 0;
  135. case 'c':
  136. return 1;
  137. case 'f':
  138. return 2;
  139. case 'v':
  140. return 3;
  141. case 's':
  142. return 4;
  143. case 'd':
  144. return 5;
  145. case '*':
  146. return 9999;
  147. default:
  148. return -1;
  149. }
  150. }
  151. // check token based on passed simplified regular expression
  152. BOOL b_check_token(const char *token, const char *regexp)
  153. {
  154. S32 tptr, rptr = 0;
  155. S32 current_checker, next_checker = 0;
  156. current_checker = get_checker_number(regexp[rptr++]);
  157. if (current_checker == -1)
  158. {
  159. llerrs << "Invalid regular expression value!" << llendl;
  160. return FALSE;
  161. }
  162. if (current_checker == 9999)
  163. {
  164. llerrs << "Regular expression can't start with *!" << llendl;
  165. return FALSE;
  166. }
  167. for (tptr = 0; token[tptr]; tptr++)
  168. {
  169. if (current_checker == -1)
  170. {
  171. llerrs << "Input exceeds regular expression!nDid you forget a *?" << llendl;
  172. return FALSE;
  173. }
  174. if (!gParseCheckCharacters[current_checker](token[tptr]))
  175. {
  176. return FALSE;
  177. }
  178. if (next_checker != 9999)
  179. {
  180. next_checker = get_checker_number(regexp[rptr++]);
  181. if (next_checker != 9999)
  182. {
  183. current_checker = next_checker;
  184. }
  185. }
  186. }
  187. return TRUE;
  188. }
  189. // C variable can be made up of upper or lower case letters, underscores, or numbers, but can't start with a number
  190. BOOL b_variable_ok(const char *token)
  191. {
  192. if (!b_check_token(token, "fv*"))
  193. {
  194. llwarns << "Token '" << token << "' isn't a variable!" << llendl;
  195. return FALSE;
  196. }
  197. return TRUE;
  198. }
  199. // An integer is made up of the digits 0-9 and may be preceded by a '-'
  200. BOOL b_integer_ok(const char *token)
  201. {
  202. if (!b_check_token(token, "sd*"))
  203. {
  204. llwarns << "Token isn't an integer!" << llendl;
  205. return FALSE;
  206. }
  207. return TRUE;
  208. }
  209. // An integer is made up of the digits 0-9
  210. BOOL b_positive_integer_ok(const char *token)
  211. {
  212. if (!b_check_token(token, "d*"))
  213. {
  214. llwarns << "Token isn't an integer!" << llendl;
  215. return FALSE;
  216. }
  217. return TRUE;
  218. }
  219. // Done with C functions, here's the tokenizer.
  220. typedef boost::tokenizer< boost::char_separator<char> > tokenizer;
  221. LLTemplateTokenizer::LLTemplateTokenizer(const std::string & contents) : mStarted(false), mTokens()
  222. {
  223. boost::char_separator<char> newline("rn", "", boost::keep_empty_tokens);
  224. boost::char_separator<char> spaces(" t");
  225. U32 line_counter = 1;
  226. tokenizer line_tokens(contents, newline);
  227. for(tokenizer::iterator line_iter = line_tokens.begin();
  228. line_iter != line_tokens.end();
  229. ++line_iter, ++line_counter)
  230. {
  231. tokenizer word_tokens(*line_iter, spaces);
  232. for(tokenizer::iterator word_iter = word_tokens.begin();
  233. word_iter != word_tokens.end();
  234. ++word_iter)
  235. {
  236. if((*word_iter)[0] == '/')
  237. {
  238. break;   // skip to end of line on comments
  239. }
  240. positioned_token pt;// = new positioned_token();
  241. pt.str = std::string(*word_iter);
  242. pt.line = line_counter;
  243. mTokens.push_back(pt);
  244. }
  245. }
  246. mCurrent = mTokens.begin();
  247. }
  248. void LLTemplateTokenizer::inc()
  249. {
  250. if(atEOF())
  251. {
  252. error("trying to increment token of EOF");
  253. }
  254. else if(mStarted)
  255. {
  256. ++mCurrent;
  257. }
  258. else
  259. {
  260. mStarted = true;
  261. mCurrent = mTokens.begin();
  262. }
  263. }
  264. void LLTemplateTokenizer::dec()
  265. {
  266. if(mCurrent == mTokens.begin())
  267. {
  268. if(mStarted)
  269. {
  270. mStarted = false;
  271. }
  272. else
  273. {
  274. error("trying to decrement past beginning of file");
  275. }
  276. }
  277. else
  278. {
  279. mCurrent--;
  280. }
  281. }
  282. std::string LLTemplateTokenizer::get() const
  283. {
  284. if(atEOF())
  285. {
  286. error("trying to get EOF");
  287. }
  288. return mCurrent->str;
  289. }
  290. U32 LLTemplateTokenizer::line() const
  291. {
  292. if(atEOF())
  293. {
  294. return 0;
  295. }
  296. return mCurrent->line;
  297. }
  298. bool LLTemplateTokenizer::atEOF() const
  299. {
  300. return mCurrent == mTokens.end();
  301. }
  302. std::string LLTemplateTokenizer::next()
  303. {
  304. inc();
  305. return get();
  306. }
  307. bool LLTemplateTokenizer::want(const std::string & token)
  308. {
  309. if(atEOF()) return false;
  310. inc();
  311. if(atEOF()) return false;
  312. if(get() != token)
  313. {
  314. dec(); // back up a step
  315. return false;
  316. }
  317. return true;
  318. }
  319. bool LLTemplateTokenizer::wantEOF()
  320. {
  321. // see if the next token is EOF
  322. if(atEOF()) return true;
  323. inc();
  324. if(!atEOF())
  325. {
  326. dec(); // back up a step
  327. return false;
  328. }
  329. return true;
  330. }
  331. void LLTemplateTokenizer::error(std::string message) const
  332. {
  333. if(atEOF())
  334. {
  335. llerrs << "Unexpected end of file: " << message << llendl;
  336. }
  337. else
  338. {
  339. llerrs << "Problem parsing message template at line "
  340.    << line() << ", with token '" << get() << "' : "
  341.    << message << llendl;
  342. }
  343. }
  344. // Done with tokenizer, next is the parser.
  345. LLTemplateParser::LLTemplateParser(LLTemplateTokenizer & tokens):
  346. mVersion(0.f),
  347. mMessages()
  348. {
  349. // the version number should be the first thing in the file
  350. if (tokens.want("version"))
  351. {
  352. // version number
  353. std::string vers_string = tokens.next();
  354. mVersion = (F32)atof(vers_string.c_str());
  355. llinfos << "### Message template version " << mVersion << "  ###" << llendl;
  356. }
  357. else
  358. {
  359. llerrs << "Version must be first in the message template, found "
  360.    << tokens.next() << llendl;
  361. }
  362. while(LLMessageTemplate * templatep = parseMessage(tokens))
  363. {
  364. if (templatep->getDeprecation() != MD_DEPRECATED)
  365. {
  366. mMessages.push_back(templatep);
  367. }
  368. else
  369. {
  370. delete templatep;
  371. }
  372. }
  373. if(!tokens.wantEOF())
  374. {
  375. llerrs << "Expected end of template or a message, instead found: "
  376.    << tokens.next() << " at " << tokens.line() << llendl;
  377. }
  378. }
  379. F32 LLTemplateParser::getVersion() const
  380. {
  381. return mVersion;
  382. }
  383. LLTemplateParser::message_iterator LLTemplateParser::getMessagesBegin() const
  384. {
  385. return mMessages.begin();
  386. }
  387. LLTemplateParser::message_iterator LLTemplateParser::getMessagesEnd() const
  388. {
  389. return mMessages.end();
  390. }
  391. // static
  392. LLMessageTemplate * LLTemplateParser::parseMessage(LLTemplateTokenizer & tokens)
  393. {
  394. LLMessageTemplate *templatep = NULL;
  395. if(!tokens.want("{"))
  396. {
  397. return NULL;
  398. }
  399. // name first
  400. std::string template_name = tokens.next();
  401. // is name a legit C variable name
  402. if (!b_variable_ok(template_name.c_str()))
  403. {
  404. llerrs << "Not legit variable name: " << template_name << " at " << tokens.line() << llendl;
  405. }
  406. // ok, now get Frequency ("High", "Medium", or "Low")
  407. EMsgFrequency frequency = MFT_LOW;
  408. std::string freq_string = tokens.next();
  409. if (freq_string == "High")
  410. {
  411. frequency = MFT_HIGH;
  412. }
  413. else if (freq_string == "Medium")
  414. {
  415. frequency = MFT_MEDIUM;
  416. }
  417. else if (freq_string == "Low" || freq_string == "Fixed")
  418. {
  419. frequency = MFT_LOW;
  420. }
  421. else
  422. {
  423. llerrs << "Expected frequency, got " << freq_string << " at " << tokens.line() << llendl;
  424. }
  425. // TODO more explicit checking here pls
  426. U32 message_number = strtoul(tokens.next().c_str(),NULL,0);
  427. switch (frequency) {
  428. case MFT_HIGH:
  429. break;
  430. case MFT_MEDIUM:
  431. message_number = (255 << 8) | message_number;
  432. break;
  433. case MFT_LOW:
  434. message_number = (255 << 24) | (255 << 16) | message_number;
  435. break;
  436. default:
  437. llerrs << "Unknown frequency enum: " << frequency << llendl;
  438. }
  439.    
  440. templatep = new LLMessageTemplate(
  441. template_name.c_str(),
  442. message_number,
  443. frequency);
  444. // Now get trust ("Trusted", "NotTrusted")
  445. std::string trust = tokens.next();
  446. if (trust == "Trusted")
  447. {
  448. templatep->setTrust(MT_TRUST);
  449. }
  450. else if (trust == "NotTrusted")
  451. {
  452. templatep->setTrust(MT_NOTRUST);
  453. }
  454. else
  455. {
  456. llerrs << "Bad trust " << trust << " at " << tokens.line() << llendl;
  457. }
  458. // get encoding
  459. std::string encoding = tokens.next();
  460. if(encoding == "Unencoded")
  461. {
  462. templatep->setEncoding(ME_UNENCODED);
  463. }
  464. else if(encoding == "Zerocoded")
  465. {
  466. templatep->setEncoding(ME_ZEROCODED);
  467. }
  468. else
  469. {
  470. llerrs << "Bad encoding " << encoding << " at " << tokens.line() << llendl;
  471. }
  472. // get deprecation
  473. if(tokens.want("Deprecated"))
  474. {
  475. templatep->setDeprecation(MD_DEPRECATED);
  476. }
  477. else if (tokens.want("UDPDeprecated"))
  478. {
  479. templatep->setDeprecation(MD_UDPDEPRECATED);
  480. }
  481. else if (tokens.want("UDPBlackListed"))
  482. {
  483. templatep->setDeprecation(MD_UDPBLACKLISTED);
  484. }
  485. else if (tokens.want("NotDeprecated"))
  486. {
  487. // this is the default value, but it can't hurt to set it twice
  488. templatep->setDeprecation(MD_NOTDEPRECATED);
  489. }
  490. else {
  491. // It's probably a brace, let's just start block processing
  492. }
  493. while(LLMessageBlock * blockp = parseBlock(tokens))
  494. {
  495. templatep->addBlock(blockp);
  496. }
  497. if(!tokens.want("}"))
  498. {
  499. llerrs << "Expecting closing } for message " << template_name
  500.    << " at " << tokens.line() << llendl;
  501. }
  502. return templatep;
  503. }
  504. // static
  505. LLMessageBlock * LLTemplateParser::parseBlock(LLTemplateTokenizer & tokens)
  506. {
  507. LLMessageBlock * blockp = NULL;
  508. if(!tokens.want("{"))
  509. {
  510. return NULL;
  511. }
  512. // name first
  513. std::string block_name = tokens.next();
  514. // is name a legit C variable name
  515. if (!b_variable_ok(block_name.c_str()))
  516. {
  517. llerrs << "not a legal block name: " << block_name
  518.    << " at " << tokens.line() << llendl;
  519. }
  520. // now, block type ("Single", "Multiple", or "Variable")
  521. std::string block_type = tokens.next();
  522. // which one is it?
  523. if (block_type == "Single")
  524. {
  525. // ok, we can create a block
  526. blockp = new LLMessageBlock(block_name.c_str(), MBT_SINGLE);
  527. }
  528. else if (block_type == "Multiple")
  529. {
  530. // need to get the number of repeats
  531. std::string repeats = tokens.next();
  532. // is it a legal integer
  533. if (!b_positive_integer_ok(repeats.c_str()))
  534. {
  535. llerrs << "not a legal integer for block multiple count: "
  536.    << repeats << " at " << tokens.line() << llendl;
  537. }
  538. // ok, we can create a block
  539. blockp = new LLMessageBlock(block_name.c_str(),
  540. MBT_MULTIPLE,
  541. atoi(repeats.c_str()));
  542. }
  543. else if (block_type == "Variable")
  544. {
  545. // ok, we can create a block
  546. blockp = new LLMessageBlock(block_name.c_str(), MBT_VARIABLE);
  547. }
  548. else
  549. {
  550. llerrs << "bad block type: " << block_type
  551.    << " at " << tokens.line() << llendl;
  552. }
  553. while(LLMessageVariable * varp = parseVariable(tokens))
  554. {
  555. blockp->addVariable(varp->getName(),
  556. varp->getType(),
  557. varp->getSize());
  558. delete varp;
  559. }
  560. if(!tokens.want("}"))
  561. {
  562. llerrs << "Expecting closing } for block " << block_name
  563.    << " at " << tokens.line() << llendl;
  564. }
  565. return blockp;
  566.    
  567. }
  568. // static
  569. LLMessageVariable * LLTemplateParser::parseVariable(LLTemplateTokenizer & tokens)
  570. {
  571. LLMessageVariable * varp = NULL;
  572. if(!tokens.want("{"))
  573. {
  574. return NULL;
  575. }
  576. std::string var_name = tokens.next();
  577. if (!b_variable_ok(var_name.c_str()))
  578. {
  579. llerrs << "Not a legit variable name: " << var_name
  580.    << " at " << tokens.line() << llendl;
  581. }
  582. std::string var_type = tokens.next();
  583. if (var_type == "U8")
  584. {
  585. varp = new LLMessageVariable(var_name.c_str(), MVT_U8, 1);
  586. }
  587. else if (var_type == "U16")
  588. {
  589. varp = new LLMessageVariable(var_name.c_str(), MVT_U16, 2);
  590. }
  591. else if (var_type == "U32")
  592. {
  593. varp = new LLMessageVariable(var_name.c_str(), MVT_U32, 4);
  594. }
  595. else if (var_type == "U64")
  596. {
  597. varp = new LLMessageVariable(var_name.c_str(), MVT_U64, 8);
  598. }
  599. else if (var_type == "S8")
  600. {
  601. varp = new LLMessageVariable(var_name.c_str(), MVT_S8, 1);
  602. }
  603. else if (var_type == "S16")
  604. {
  605. varp = new LLMessageVariable(var_name.c_str(), MVT_S16, 2);
  606. }
  607. else if (var_type == "S32")
  608. {
  609. varp = new LLMessageVariable(var_name.c_str(), MVT_S32, 4);
  610. }
  611. else if (var_type == "S64")
  612. {
  613. varp = new LLMessageVariable(var_name.c_str(), MVT_S64, 8);
  614. }
  615. else if (var_type == "F32")
  616. {
  617. varp = new LLMessageVariable(var_name.c_str(), MVT_F32, 4);
  618. }
  619. else if (var_type == "F64")
  620. {
  621. varp = new LLMessageVariable(var_name.c_str(), MVT_F64, 8);
  622. }
  623. else if (var_type == "LLVector3")
  624. {
  625. varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector3, 12);
  626. }
  627. else if (var_type == "LLVector3d")
  628. {
  629. varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector3d, 24);
  630. }
  631. else if (var_type == "LLVector4")
  632. {
  633. varp = new LLMessageVariable(var_name.c_str(), MVT_LLVector4, 16);
  634. }
  635. else if (var_type == "LLQuaternion")
  636. {
  637. varp = new LLMessageVariable(var_name.c_str(), MVT_LLQuaternion, 12);
  638. }
  639. else if (var_type == "LLUUID")
  640. {
  641. varp = new LLMessageVariable(var_name.c_str(), MVT_LLUUID, 16);
  642. }
  643. else if (var_type == "BOOL")
  644. {
  645. varp = new LLMessageVariable(var_name.c_str(), MVT_BOOL, 1);
  646. }
  647. else if (var_type == "IPADDR")
  648. {
  649. varp = new LLMessageVariable(var_name.c_str(), MVT_IP_ADDR, 4);
  650. }
  651. else if (var_type == "IPPORT")
  652. {
  653. varp = new LLMessageVariable(var_name.c_str(), MVT_IP_PORT, 2);
  654. }
  655. else if (var_type == "Fixed" || var_type == "Variable")
  656. {
  657. std::string variable_size = tokens.next();
  658. if (!b_positive_integer_ok(variable_size.c_str()))
  659. {
  660. llerrs << "not a legal integer variable size: " << variable_size
  661.    << " at " << tokens.line() << llendl;
  662. }
  663. EMsgVariableType type_enum;
  664. if(var_type == "Variable")
  665. {
  666. type_enum = MVT_VARIABLE;
  667. }
  668. else if(var_type == "Fixed")
  669. {
  670. type_enum = MVT_FIXED;
  671. }
  672. else
  673. {
  674. type_enum = MVT_FIXED; // removes a warning
  675. llerrs << "bad variable type: " << var_type
  676.    << " at " << tokens.line() << llendl;
  677. }
  678. varp = new LLMessageVariable(
  679. var_name.c_str(),
  680. type_enum,
  681. atoi(variable_size.c_str()));
  682. }
  683. else
  684. {
  685. llerrs << "bad variable type:" << var_type
  686.    << " at " << tokens.line() << llendl;
  687. }
  688. if(!tokens.want("}"))
  689. {
  690. llerrs << "Expecting closing } for variable " << var_name
  691.    << " at " << tokens.line() << llendl;
  692. }
  693. return varp;
  694. }