00001
00002 #include <Base64.h>
00003
00004 #include "Robot.h"
00005 #include "CodeTool.h"
00006
00007 #define DEB(x) x; fflush(stdout);
00008
00009
00010 CodeTool::CodeTool(RobotXMLFile& ref) : m_config(ref)
00011 ,m_robot(NULL)
00012 ,m_codesize(0)
00013 ,m_code(NULL)
00014
00015 ,m_ptr(0)
00016 ,m_register1(0)
00017 ,m_register2(0)
00018 ,m_loop(NULL)
00019 ,m_loop_init(false)
00020 {
00021 Base64 bb;
00022 std::string codestr64 = m_config.GetString("code");
00023 bb.decode(codestr64, NULL, m_codesize);
00024 m_code = new unsigned char[m_codesize + 1];
00025 bb.decode(codestr64, m_code, m_codesize);
00026 m_config.GetMethods( m_methodmap );
00027 m_config.GetVariables( m_variables );
00028
00029 m_opcode[0x01] = "ld ";
00030 m_opcode[0x02] = "push ";
00031 m_opcode[0x03] = "ld ";
00032 m_opcode[0x04] = "pop ";
00033 m_opcode[0x05] = "add ";
00034 m_opcode[0x06] = "sub ";
00035 m_opcode[0x07] = "mul ";
00036 m_opcode[0x08] = "div ";
00037 m_opcode[0x09] = "eq ";
00038 m_opcode[0x0a] = "jz ";
00039 m_opcode[0x0b] = "jnz ";
00040 m_opcode[0x0c] = "ld ";
00041 m_opcode[0x0d] = "st ";
00042 m_opcode[0x0e] = "call ";
00043 m_opcode[0x0f] = "st ";
00044
00045 m_opcode[0x10] = "ld ";
00046 m_opcode[0x11] = "init ";
00047 m_opcode[0x12] = "not ";
00048 m_opcode[0x13] = "neq ";
00049 m_opcode[0x14] = "and ";
00050 m_opcode[0x15] = "or ";
00051
00052 m_opcode[0x21] = "ld ";
00053 m_opcode[0x22] = "push ";
00054 m_opcode[0x23] = "ld ";
00055 m_opcode[0x24] = "pop ";
00056 m_opcode[0x25] = "add ";
00057 m_opcode[0x26] = "sub ";
00058 m_opcode[0x27] = "mul ";
00059 m_opcode[0x28] = "div ";
00060 m_opcode[0x29] = "eq ";
00061 m_opcode[0x2a] = "jz ";
00062 m_opcode[0x2b] = "jnz ";
00063 m_opcode[0x2c] = "ld ";
00064 m_opcode[0x2d] = "st ";
00065 m_opcode[0x2e] = "call ";
00066 m_opcode[0x2f] = "st ";
00067
00068 m_opcode[0x32] = "not ";
00069 m_opcode[0x33] = "neq ";
00070 m_opcode[0x34] = "and ";
00071 m_opcode[0x35] = "or ";
00072
00073 m_opcode[0x81] = "jmp ";
00074 m_opcode[0x82] = "init ";
00075 m_opcode[0x83] = "loop ";
00076 m_opcode[0x84] = "ret ";
00077
00078 for (int opcode = 0; opcode < 256; opcode++)
00079 {
00080 int opsize = -1;
00081 switch (opcode)
00082 {
00083
00084 case 0x01:
00085 opsize = 2;
00086 break;
00087 case 0x02:
00088 opsize = 0;
00089 break;
00090 case 0x03:
00091 opsize = 4;
00092 break;
00093 case 0x04:
00094 case 0x05:
00095 case 0x06:
00096 case 0x07:
00097 case 0x08:
00098 case 0x09:
00099 opsize = 0;
00100 break;
00101 case 0x0a:
00102 case 0x0b:
00103 case 0x0c:
00104 case 0x0d:
00105 case 0x0e:
00106 case 0x0f:
00107 opsize = 2;
00108 break;
00109 case 0x10:
00110 case 0x11:
00111 opsize = -2;
00112 break;
00113 case 0x12:
00114 case 0x13:
00115 case 0x14:
00116 case 0x15:
00117 opsize = 0;
00118 break;
00119
00120 case 0x21:
00121 opsize = 2;
00122 break;
00123 case 0x22:
00124 opsize = 0;
00125 break;
00126 case 0x23:
00127 opsize = 4;
00128 break;
00129 case 0x24:
00130 case 0x25:
00131 case 0x26:
00132 case 0x27:
00133 case 0x28:
00134 case 0x29:
00135 opsize = 0;
00136 break;
00137 case 0x2a:
00138 case 0x2b:
00139 case 0x2c:
00140 case 0x2d:
00141 case 0x2e:
00142 case 0x2f:
00143 opsize = 2;
00144 break;
00145
00146 case 0x32:
00147 case 0x33:
00148 case 0x34:
00149 case 0x35:
00150 opsize = 0;
00151 break;
00152
00153 case 0x81:
00154 case 0x82:
00155 case 0x83:
00156 opsize = 2;
00157 break;
00158 case 0x84:
00159 opsize = 0;
00160 break;
00161
00162 }
00163 m_opsize[opcode] = opsize;
00164 }
00165 }
00166
00167
00168 CodeTool::~CodeTool()
00169 {
00170 delete m_code;
00171 for (std::vector<VARIABLE *>::iterator it = m_variables.begin(); it != m_variables.end(); it++)
00172 {
00173 VARIABLE *p = *it;
00174 delete p;
00175 }
00176 }
00177
00178
00179 void CodeTool::Call(const std::string& method)
00180 {
00181 for (std::map<std::string,int>::iterator it = m_methodmap.begin(); it != m_methodmap.end(); it++)
00182 {
00183 std::string name = (*it).first;
00184 int entry = (*it).second;
00185 if (name == method)
00186 {
00187
00188 m_ptr = entry;
00189 unsigned char c = Execute();
00190 while (c && c != 0x84)
00191 {
00192 c = Execute();
00193 }
00194 }
00195 }
00196 }
00197
00198
00199 bool CodeTool::Sane()
00200 {
00201 size_t ptr = 0;
00202 while (ptr < m_codesize)
00203 {
00204 unsigned char opcode = m_code[ptr++];
00205 int opsize = m_opsize[opcode];
00206 if (opsize == -1)
00207 {
00208 return false;
00209 }
00210 else
00211 if (opsize == -2)
00212 {
00213 ptr += 2;
00214 unsigned char len = m_code[ptr++];
00215 ptr += len;
00216 }
00217 else
00218 {
00219 ptr += opsize;
00220 }
00221 if (opcode == 0x11 || opcode == 0x82)
00222 {
00223 ptr += 2;
00224 }
00225 }
00226 return true;
00227 }
00228
00229
00230 unsigned char CodeTool::Execute()
00231 {
00232 if (m_ptr >= m_codesize)
00233 return 0;
00234 unsigned char opcode = m_code[m_ptr++];
00235 int opsize = m_opsize[opcode];
00236 if (opsize == -1)
00237 {
00238 return 0;
00239 }
00240 std::string tmpstr;
00241 short tmpvals = 0;
00242 long tmpvall = 0;
00243 short bodylen = 0;
00244 if (opsize == -2)
00245 {
00246 tmpvals = m_code[m_ptr++];
00247 tmpvals *= 256;
00248 tmpvals += m_code[m_ptr++];
00249 unsigned char tmplen = m_code[m_ptr++];
00250 char slask[256];
00251 memcpy(slask,m_code + m_ptr,tmplen);
00252 slask[tmplen] = 0;
00253 tmpstr = slask;
00254 m_ptr += tmplen;
00255 }
00256 else
00257 if (opsize == 2)
00258 {
00259 tmpvals = m_code[m_ptr++];
00260 tmpvals *= 256;
00261 tmpvals += m_code[m_ptr++];
00262 }
00263 else
00264 if (opsize == 4)
00265 {
00266 tmpvall = m_code[m_ptr++];
00267 tmpvall *= 256;
00268 tmpvall += m_code[m_ptr++];
00269 tmpvall *= 256;
00270 tmpvall += m_code[m_ptr++];
00271 tmpvall *= 256;
00272 tmpvall += m_code[m_ptr++];
00273 }
00274 if (opcode == 0x11 || opcode == 0x82)
00275 {
00276 bodylen = m_code[m_ptr++];
00277 bodylen *= 256;
00278 bodylen += m_code[m_ptr++];
00279 }
00280 int objx = tmpvals / 256;
00281 int prop = tmpvals % 256;
00282 int stacksize = m_stack.size();
00283 switch (opcode)
00284 {
00285 case 0x01:
00286 m_register1 = get_property(objx, prop);
00287 break;
00288 case 0x02:
00289 m_stack.push_back(m_register1);
00290 break;
00291 case 0x03:
00292 m_register1 = tmpvall;
00293 break;
00294 case 0x04:
00295 if (stacksize)
00296 {
00297 m_register1 = m_stack[stacksize - 1];
00298 for (stack_v::iterator it = m_stack.begin(); it != m_stack.end(); it++)
00299 {
00300 if (stacksize-- == 1)
00301 {
00302 m_stack.erase(it);
00303 break;
00304 }
00305 }
00306 }
00307 break;
00308 case 0x05:
00309 m_register1 += m_register1;
00310 break;
00311 case 0x06:
00312 m_register1 -= m_register1;
00313 break;
00314 case 0x07:
00315 m_register1 *= m_register1;
00316 break;
00317 case 0x08:
00318 if (m_register1)
00319 {
00320 m_register1 /= m_register1;
00321 }
00322 break;
00323 case 0x09:
00324 m_register1 = m_register1 == m_register1;
00325 break;
00326 case 0x0a:
00327 if (!m_register1)
00328 {
00329 Jump(tmpvals);
00330 }
00331 break;
00332 case 0x0b:
00333 if (m_register1)
00334 {
00335 Jump(tmpvals);
00336 }
00337 break;
00338 case 0x0c:
00339 if (tmpvals >= 0 && tmpvals < (int)m_variables.size())
00340 {
00341 m_register1 = m_variables[tmpvals] -> value;
00342 }
00343 else
00344 {
00345 printf("Bad variable index: %d\n",tmpvals);
00346 }
00347 break;
00348 case 0x0d:
00349 if (tmpvals >= 0 && tmpvals < (int)m_variables.size())
00350 {
00351 m_variables[tmpvals] -> value = m_register1;
00352 }
00353 else
00354 {
00355 printf("Bad variable index: %d\n",tmpvals);
00356 }
00357 break;
00358 case 0x0e:
00359 m_register1 = call_method(objx, prop);
00360 break;
00361 case 0x0f:
00362 set_property(objx, prop, m_register1);
00363 break;
00364
00365 case 0x10:
00366 if (tmpvals >= 0 && tmpvals < (int)m_variables.size())
00367 {
00368 VARIABLE *p = m_variables[tmpvals];
00369 if (p -> type == 2)
00370 {
00371 MapObject *p2 = dynamic_cast<MapObject *>(p -> object);
00372 if (p2)
00373 {
00374 m_register1 = p2 -> get_property( tmpstr );
00375 }
00376 }
00377 }
00378 else
00379 {
00380 printf("Bad variable index: %d\n",tmpvals);
00381 }
00382 break;
00383 case 0x11:
00384
00385
00386
00387
00388
00389 break;
00390 case 0x12:
00391 m_register1 = !m_register1;
00392 break;
00393 case 0x13:
00394 m_register1 = m_register1 != m_register1;
00395 break;
00396 case 0x14:
00397 m_register1 = m_register1 && m_register1;
00398 break;
00399 case 0x15:
00400 m_register1 = m_register1 || m_register1;
00401 break;
00402
00403 case 0x21:
00404 m_register2 = get_property(objx, prop);
00405 break;
00406 case 0x22:
00407 m_stack.push_back(m_register2);
00408 break;
00409 case 0x23:
00410 m_register2 = tmpvall;
00411 break;
00412 case 0x24:
00413 if (stacksize)
00414 {
00415 m_register2 = m_stack[stacksize - 1];
00416 for (stack_v::iterator it = m_stack.begin(); it != m_stack.end(); it++)
00417 {
00418 if (stacksize-- == 1)
00419 {
00420 m_stack.erase(it);
00421 break;
00422 }
00423 }
00424 }
00425 break;
00426 case 0x25:
00427 m_register1 += m_register2;
00428 break;
00429 case 0x26:
00430 m_register1 -= m_register2;
00431 break;
00432 case 0x27:
00433 m_register1 *= m_register2;
00434 break;
00435 case 0x28:
00436 if (m_register2)
00437 {
00438 m_register1 /= m_register2;
00439 }
00440 else
00441 {
00442 m_register1 = 0;
00443 }
00444 break;
00445 case 0x29:
00446 m_register1 = m_register1 == m_register2;
00447 break;
00448 case 0x2a:
00449 if (!m_register2)
00450 {
00451 Jump(tmpvals);
00452 }
00453 break;
00454 case 0x2b:
00455 if (m_register2)
00456 {
00457 Jump(tmpvals);
00458 }
00459 break;
00460 case 0x2c:
00461 if (tmpvals >= 0 && tmpvals < (int)m_variables.size())
00462 {
00463 m_register2 = m_variables[tmpvals] -> value;
00464 }
00465 else
00466 {
00467 printf("Bad variable index: %d\n",tmpvals);
00468 }
00469 break;
00470 case 0x2d:
00471 if (tmpvals >= 0 && tmpvals < (int)m_variables.size())
00472 {
00473 m_variables[tmpvals] -> value = m_register2;
00474 }
00475 else
00476 {
00477 printf("Bad variable index: %d\n",tmpvals);
00478 }
00479 break;
00480 case 0x2e:
00481 m_register2 = call_method(objx, prop);
00482 break;
00483 case 0x2f:
00484 set_property(objx, prop, m_register2);
00485 break;
00486
00487 case 0x32:
00488 m_register1 = !m_register2;
00489 break;
00490 case 0x33:
00491 m_register1 = m_register1 != m_register2;
00492 break;
00493 case 0x34:
00494 m_register1 = m_register1 && m_register2;
00495 break;
00496 case 0x35:
00497 m_register1 = m_register1 || m_register2;
00498 break;
00499
00500 case 0x81:
00501 Jump(tmpvals);
00502 break;
00503 case 0x82:
00504
00505
00506
00507
00508
00509 if (objx == ROBOTOBJECT_ROBOT && prop == 4)
00510 {
00511 if (m_robot)
00512 {
00513 m_loop = &m_robot -> GetInventory();
00514 m_loop_iterator = m_loop -> begin();
00515 m_loop_init = true;
00516 }
00517 }
00518 break;
00519 case 0x83:
00520 if (m_loop_init)
00521 {
00522 if (tmpvals >= 0 && tmpvals < (int)m_variables.size())
00523 {
00524 if (m_loop_iterator != m_loop -> end())
00525 {
00526 m_variables[tmpvals] -> object = *m_loop_iterator;
00527 m_loop_iterator++;
00528 m_register1 = 1;
00529 }
00530 else
00531 {
00532 m_register1 = 0;
00533 m_loop_init = false;
00534 }
00535 }
00536 else
00537 {
00538 printf("Bad variable index: %d\n",tmpvals);
00539 }
00540 }
00541 break;
00542 case 0x84:
00543 break;
00544
00545 default:
00546 return 0;
00547 }
00548 return opcode;
00549 }
00550
00551
00552 void CodeTool::Jump(short tmpvals)
00553 {
00554 if (tmpvals & 0x8000)
00555 {
00556 tmpvals &= 0x7fff;
00557 m_ptr -= tmpvals;
00558 m_ptr -= 3;
00559 }
00560 else
00561 {
00562 m_ptr += tmpvals;
00563 }
00564 }
00565
00566
00567 long CodeTool::get_property(int obj,int prop)
00568 {
00569 if (!m_robot)
00570 return 0;
00571 switch (obj)
00572 {
00573 case ROBOTOBJECT_ROBOT:
00574 return m_robot -> get_property( prop );
00575 case ROBOTOBJECT_RADAR:
00576 return m_robot -> PartRadar().get_property( prop );
00577 case ROBOTOBJECT_TURRET:
00578 return m_robot -> PartTurret().get_property( prop );
00579 case ROBOTOBJECT_GUN:
00580 return m_robot -> PartGun().get_property( prop );
00581 case ROBOTOBJECT_SHIELDS:
00582 return m_robot -> PartShields().get_property( prop );
00583 }
00584 printf("Bad object: %d\n",obj);
00585 return 0;
00586 }
00587
00588
00589 void CodeTool::set_property(int obj,int prop,long value)
00590 {
00591 if (!m_robot)
00592 return;
00593 switch (obj)
00594 {
00595 case ROBOTOBJECT_ROBOT:
00596 m_robot -> set_property( prop, value );
00597 break;
00598 case ROBOTOBJECT_RADAR:
00599 m_robot -> PartRadar().set_property( prop, value );
00600 break;
00601 case ROBOTOBJECT_TURRET:
00602 m_robot -> PartTurret().set_property( prop, value );
00603 break;
00604 case ROBOTOBJECT_GUN:
00605 m_robot -> PartGun().set_property( prop, value );
00606 break;
00607 case ROBOTOBJECT_SHIELDS:
00608 m_robot -> PartShields().set_property( prop, value );
00609 break;
00610 default:
00611 printf("Bad object: %d\n",obj);
00612 }
00613 }
00614
00615
00616 long CodeTool::call_method(int obj,int method)
00617 {
00618 if (!m_robot)
00619 return 0;
00620 switch (obj)
00621 {
00622 case ROBOTOBJECT_ROBOT:
00623 return m_robot -> call_method( method, m_stack );
00624 case ROBOTOBJECT_RADAR:
00625 return m_robot -> PartRadar().call_method( method, m_stack );
00626 case ROBOTOBJECT_TURRET:
00627 return m_robot -> PartTurret().call_method( method, m_stack );
00628 case ROBOTOBJECT_GUN:
00629 return m_robot -> PartGun().call_method( method, m_stack );
00630 case ROBOTOBJECT_SHIELDS:
00631 return m_robot -> PartShields().call_method( method, m_stack );
00632 }
00633 printf("Bad object: %d\n",obj);
00634 return 0;
00635 }
00636
00637