Mercurial > hg > orthanc
comparison Core/Lua/LuaContext.cpp @ 1447:5ba7471780ae
refactoring: HttpToolbox, DumpJson in Lua
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Wed, 01 Jul 2015 17:42:06 +0200 |
parents | af112b7d9cba |
children | 3f7722179467 |
comparison
equal
deleted
inserted
replaced
1446:8dc80ba768aa | 1447:5ba7471780ae |
---|---|
31 | 31 |
32 | 32 |
33 #include "../PrecompiledHeaders.h" | 33 #include "../PrecompiledHeaders.h" |
34 #include "LuaContext.h" | 34 #include "LuaContext.h" |
35 | 35 |
36 #include <set> | |
36 #include <glog/logging.h> | 37 #include <glog/logging.h> |
37 #include <cassert> | 38 #include <cassert> |
39 #include <boost/lexical_cast.hpp> | |
38 | 40 |
39 extern "C" | 41 extern "C" |
40 { | 42 { |
41 #include <lualib.h> | 43 #include <lualib.h> |
42 #include <lauxlib.h> | 44 #include <lauxlib.h> |
88 | 90 |
89 return 0; | 91 return 0; |
90 } | 92 } |
91 | 93 |
92 | 94 |
93 int LuaContext::ParseJsonString(lua_State *state) | 95 int LuaContext::ParseJson(lua_State *state) |
94 { | 96 { |
95 LuaContext& that = GetLuaContext(state); | 97 LuaContext& that = GetLuaContext(state); |
96 | 98 |
97 int nArgs = lua_gettop(state); | 99 int nArgs = lua_gettop(state); |
98 if (nArgs != 1 || | 100 if (nArgs != 1 || |
110 { | 112 { |
111 that.PushJson(value); | 113 that.PushJson(value); |
112 } | 114 } |
113 else | 115 else |
114 { | 116 { |
117 lua_pushnil(state); | |
118 } | |
119 | |
120 return 1; | |
121 } | |
122 | |
123 | |
124 int LuaContext::DumpJson(lua_State *state) | |
125 { | |
126 int nArgs = lua_gettop(state); | |
127 if (nArgs != 1) | |
128 { | |
129 lua_pushnil(state); | |
130 return 1; | |
131 } | |
132 | |
133 Json::Value json; | |
134 if (GetJson(json, state, 1)) | |
135 { | |
136 Json::FastWriter writer; | |
137 std::string s = writer.write(json); | |
138 lua_pushstring(state, s.c_str()); | |
139 } | |
140 else | |
141 { | |
142 LOG(ERROR) << "Lua: Unable to convert a JSON variable to a string"; | |
115 lua_pushnil(state); | 143 lua_pushnil(state); |
116 } | 144 } |
117 | 145 |
118 return 1; | 146 return 1; |
119 } | 147 } |
346 throw LuaException("Unsupported JSON conversion"); | 374 throw LuaException("Unsupported JSON conversion"); |
347 } | 375 } |
348 } | 376 } |
349 | 377 |
350 | 378 |
379 static bool CompactObjectToArray(Json::Value& result, | |
380 const Json::Value& source) | |
381 { | |
382 Json::Value::Members members = source.getMemberNames(); | |
383 | |
384 std::set<size_t> keys; | |
385 for (Json::Value::ArrayIndex i = 0; i < members.size(); i++) | |
386 { | |
387 try | |
388 { | |
389 size_t key = boost::lexical_cast<size_t>(members[i]); | |
390 keys.insert(key); | |
391 } | |
392 catch (boost::bad_lexical_cast&) | |
393 { | |
394 return false; | |
395 } | |
396 } | |
397 | |
398 if (keys.size() != members.size()) | |
399 { | |
400 return false; | |
401 } | |
402 | |
403 for (size_t i = 1; i <= members.size(); i++) | |
404 { | |
405 if (keys.find(i) == keys.end()) | |
406 { | |
407 return false; | |
408 } | |
409 } | |
410 | |
411 result = Json::arrayValue; | |
412 result.resize(members.size()); | |
413 for (size_t i = 0; i < members.size(); i++) | |
414 { | |
415 Json::Value::ArrayIndex key = boost::lexical_cast<Json::Value::ArrayIndex>(members[i]); | |
416 assert(key > 0); | |
417 result[key - 1] = source[members[i]]; | |
418 } | |
419 | |
420 return true; | |
421 } | |
422 | |
423 | |
424 bool LuaContext::GetJson(Json::Value& result, | |
425 lua_State *state, | |
426 int i) | |
427 { | |
428 // Caution: The order of the calls below is important, otherwise | |
429 // Lua considers everything as a string. | |
430 | |
431 if (lua_isnil(state, i)) | |
432 { | |
433 result = Json::nullValue; | |
434 return true; | |
435 } | |
436 | |
437 if (lua_isboolean(state, i)) | |
438 { | |
439 result = lua_toboolean(state, i) ? true : false; | |
440 return true; | |
441 } | |
442 | |
443 if (lua_isnumber(state, i)) | |
444 { | |
445 result = lua_tonumber(state, i); | |
446 return true; | |
447 } | |
448 | |
449 if (lua_isstring(state, i)) | |
450 { | |
451 result = lua_tostring(state, i); | |
452 return true; | |
453 } | |
454 | |
455 if (lua_istable(state, i)) | |
456 { | |
457 result = Json::objectValue; | |
458 | |
459 // http://stackoverflow.com/a/6142700/881731 | |
460 // Push another reference to the table on top of the stack (so we know | |
461 // where it is, and this function can work for negative, positive and | |
462 // pseudo indices | |
463 lua_pushvalue(state, i); | |
464 // stack now contains: -1 => table | |
465 lua_pushnil(state); | |
466 // stack now contains: -1 => nil; -2 => table | |
467 while (lua_next(state, -2)) | |
468 { | |
469 // stack now contains: -1 => value; -2 => key; -3 => table | |
470 // copy the key so that lua_tostring does not modify the original | |
471 lua_pushvalue(state, -2); | |
472 // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table | |
473 const char *key = lua_tostring(state, -1); | |
474 | |
475 Json::Value item; | |
476 if (!GetJson(item, state, -2)) | |
477 { | |
478 lua_pop(state, 3); // TODO IS THIS CORRECT? | |
479 return false; | |
480 } | |
481 | |
482 result[key] = item; | |
483 | |
484 // pop value + copy of key, leaving original key | |
485 lua_pop(state, 2); | |
486 // stack now contains: -1 => key; -2 => table | |
487 } | |
488 // stack now contains: -1 => table (when lua_next returns 0 it pops the key | |
489 // but does not push anything.) | |
490 // Pop table | |
491 lua_pop(state, 1); | |
492 | |
493 // Stack is now the same as it was on entry to this function | |
494 | |
495 Json::Value array; | |
496 if (CompactObjectToArray(array, result)) | |
497 { | |
498 result = array; | |
499 } | |
500 | |
501 return true; | |
502 } | |
503 | |
504 return false; | |
505 } | |
506 | |
507 | |
351 LuaContext::LuaContext() | 508 LuaContext::LuaContext() |
352 { | 509 { |
353 lua_ = luaL_newstate(); | 510 lua_ = luaL_newstate(); |
354 if (!lua_) | 511 if (!lua_) |
355 { | 512 { |
356 throw LuaException("Unable to create the Lua context"); | 513 throw LuaException("Unable to create the Lua context"); |
357 } | 514 } |
358 | 515 |
359 luaL_openlibs(lua_); | 516 luaL_openlibs(lua_); |
360 lua_register(lua_, "print", PrintToLog); | 517 lua_register(lua_, "print", PrintToLog); |
361 lua_register(lua_, "ParseJson", ParseJsonString); | 518 lua_register(lua_, "ParseJson", ParseJson); |
519 lua_register(lua_, "DumpJson", DumpJson); | |
362 lua_register(lua_, "HttpGet", CallHttpGet); | 520 lua_register(lua_, "HttpGet", CallHttpGet); |
363 lua_register(lua_, "HttpPost", CallHttpPost); | 521 lua_register(lua_, "HttpPost", CallHttpPost); |
364 lua_register(lua_, "HttpPut", CallHttpPut); | 522 lua_register(lua_, "HttpPut", CallHttpPut); |
365 lua_register(lua_, "HttpDelete", CallHttpDelete); | 523 lua_register(lua_, "HttpDelete", CallHttpDelete); |
366 lua_register(lua_, "SetHttpCredentials", SetHttpCredentials); | 524 lua_register(lua_, "SetHttpCredentials", SetHttpCredentials); |