Mercurial > otakunoraifu
view scn2k/scn2kdump.cc @ 66:d112357a0ec1
Fix a bug with savegames introduced with changeset c7bcc0ec2267.
Warning: savegames created since c7bcc0ec2267 are probably corrupted,
you may have to start the game over.
If you chose not to do so, you should replace all occurrences of 'TextWindow' by 'TextImplWindow',
and 'Text Window' by 'TextImpl Window' in your save files.
author | Thibaut Girka <thib@sitedethib.com> |
---|---|
date | Sat, 11 Dec 2010 18:36:20 +0100 |
parents | 4416cfac86ae |
children | 281dcd7217df |
line wrap: on
line source
/* * * Copyright (C) 2002- Kazunori Ueno(JAGARL) <jagarl@creator.club.ne.jp> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * */ #include <stdlib.h> #include <stdarg.h> #include <stdio.h> #include <string.h> #include <string> #include <vector> #include <map> using namespace std; #include "system/file.h" #include "system/file_impl.h" #include "scn2k.h" #define SCN_DUMP class CmdD : public Cmd { public: CmdD(const Flags& flags, int system_version) : Cmd(flags, system_version) {} //CmdD(const Flags& f) : flags(f) { argc = 0; errorflag = false; cmdstr[0] = 0;} bool ClearError() { /*errorflag = false;*/} static map<int, struct CmdDescrItem*> cmd_descr; const char* CmdDescr(int cmd1, int cmd2, int cmd3, int cmd4); }; int system_version = 0; bool ruby_flag = false; bool ret_flag = false; bool text_flag = false; bool selection_flag = false; inline int eval(int v1, int op, int v2) { switch(op) { case 0: return v1+v2; case 1: return v1-v2; case 2: return v1*v2; case 3: return v2!=0 ? v1/v2 : v1; case 4: return v2!=0 ? v1%v2 : v1; case 5: return v1&v2; case 6: return v1|v2; case 7: return v1^v2; case 8: return v1<<v2; case 9: return v1>>v2; case 40: return v1 == v2; case 41: return v1 != v2; case 42: return v1 <= v2; case 43: return v1 < v2; case 44: return v1 >= v2; case 45: return v1 > v2; case 60: return v1 && v2; case 61: return v1 || v2; } return v2; } void usage(void) { fprintf(stderr,"usage : scn2kdump [inputfile] [outputfile]\n"); fprintf(stderr," inputfile: seen.txt(default)\n"); fprintf(stderr," outputfile: seen.txt_out(default)\n"); exit(-1); } extern int debug_flag; int main(int argc, char** argv) { /* determine file names */ debug_flag = true; bool verbose = false; char* inname = "seen.txt"; char* outname = 0; if (argc > 2 && strcmp(argv[1],"-v") == 0) { int i; for (i=1; i<argc; i++) argv[i] = argv[i+1]; argc--; verbose = true; } switch(argc) { case 1: break; case 2: inname = argv[1]; break; case 3: inname = argv[1]; outname = argv[2]; break; default: usage(); } /* open output file */ FILE* outstream = stdout; /* create archive instance */ SCN2kFILE archive(inname); archive.Init(); if (archive.Deal() == 0) { fprintf(stderr,"Cannot open / Invalid archive file %s\n",inname); usage(); } /* dump files */ archive.InitList(); char* fname; fprintf(stderr,"Dump start\n"); while( (fname = archive.ListItem()) != 0) { ARCINFO* info = archive.Find(fname, ""); if (info == NULL) continue; char* data = info->CopyRead(); char* d = data; char* dend = d + info->Size(); /* version 確認 */ if (read_little_endian_int(d) == 0x1cc) { system_version = 0; } else if (read_little_endian_int(d) == 0x1d0) { system_version = 1; } else { continue; } if (read_little_endian_int(d+4) == 0x1adb2) ; // little busters! else if (read_little_endian_int(d+4) != 0x2712) continue; int header_size; if (system_version == 0) { header_size = 0x1cc + read_little_endian_int(d+0x20) * 4; } else { header_size = read_little_endian_int(d+0x20); } d += header_size; const char* dcur = d; const char* dstart = d; fprintf(stderr,"Dumping %s\n",fname); fprintf(stdout,"Dumping %s\n",fname); { int i; for (i=0; i<100; i++) { int n = read_little_endian_int(data + 0x34 + i*4); if (n != 6) fprintf(stdout,"subroutine table %2d: %6d\n",i,n); }} Flags flags; /* 最初から最後までコマンド取得 -> 出力を繰り返す */ while(dcur<dend) { const char* dprev = dcur; CmdD cmd(flags, system_version); cmd.ClearError(); /* end? */ if (*dcur == -1) { /* 0xff x 32byte + 0x00 : end sign */ int i; for (i=0; i<0x20; i++) if (dcur[i] != -1) break; if (i == 0x20 && dcur[i] == 0) break; } dprintf("%d : ",dcur-dstart); cmd.GetCmd(flags, dcur); if (cmd.IsError()) { fprintf(outstream, "Error at %6d\n",dprev-dstart); while(dcur < dend) { if (*dcur == 0x29 && dcur[1] == 0x0a) {dcur++;break;} if (*dcur == 0 && dcur[1] == 0x0a) {dcur++;break;} if (*dcur == 0 && dcur[1] == 0x23) {dcur++;break;} dcur++; } dprev -= 2*16; int ilen = (dcur-dprev+15)/16; int i; for (i=0; i<ilen; i++) { fprintf(outstream, "%6d: ",dprev-dstart); int j; for (j=0; j<16; j++) { if (dprev >= dend) break; if (dprev < data) continue; fprintf(outstream, "%02x ",*(unsigned char*)(dprev)); dprev++; } fprintf(outstream, "\n"); } } } delete info; } return 0; } /* SetStr 0x23 - cmd 01-0a:0000:00[ 2] args:V<18>[17],"PB47" CatStr 0x23 - cmd 01-0a:0002:00[ 2] args:V<18>[17],V<18>[20] WaitClick 0x23 - cmd 00-03:0011:00[ 0] ChangeFaceGraphics 0x23 - cmd 00-03:03e8:00[ 1] args:V<18>[17] DeleteFaceGraphics 0x23 - cmd 00-03:03e9:01[ 0] KoePlay 0x23 - cmd 01-17:0000:01[ 2] args:100000026,5 DrawGraphics(前景画あり) 0x23 - cmd 01-21:004b:00[ 1] args:V<18>[1],10,kasane. #1 <args:V<18>[17],11> DrawGraphics(背景のみ) 0x23 - cmd 01-21:0049:00[ 2] args:V<18>[1],10 Ruby 0x23 - cmd 00-03:0078:01[ 0] "理由" 0x23 - cmd 00-03:0078:00[ 1] "わけ" SetTitle 0x23 - cmd 01-04:0000:00[ 1] args:"Long Long Time Ago..." WaitTime 0x23 - cmd 01-14:0069:00[ 1] args:3000 ChangeBGM 数値引数はフェードアウト、インの時間と推測 0x23 - cmd 01-14:0000:02[ 3] args:"BGM18",700,700 */ struct CmdDescrItem { CmdDescrItem* next; int cmd4; int cmd1; int cmd2; int cmd3; const char* cmd_descr; }; CmdDescrItem cmd_descr_orig[] = { // scn2k_impl.cc; Scn2k::SysExec() {0,0,0x00,0x01,0x0a, "local return"}, {0,0,0x00,0x01,0x0b, "global jump"}, {0,0,0x00,0x01,0x0c, "global call"}, {0,0,0x00,0x01,0x0d, "global return"}, {0,0,0x00,0x01,0x12, "global call"}, {0,0,0x00,0x01,0x13, "global return(?)"}, {0,0,0x00,0x04,0x0d, "Menu_return"}, {0,0,0x01,0x04,0x00, "SetWindowCaption"}, {0,0,0x01,0x04,0x82, "ClearMousePress"}, {0,0,0x01,0x04,0x83, "GetMouse(2)"}, {0,0,0x01,0x04,0x85, "GetMouse"}, {0,0,0x01,0x04,0x4b0,"QuitGame"}, {0,0,0x01,0x04,0x58d,"PrevSaveNumber"}, {0,0,0x01,0x04,0x585,"SavedDate"}, {0,0,0x01,0x04,0xc23,"Save"}, {0,0,0x01,0x04,0xc25,"Load"}, {0,0,0x01,0x04,0x4b1,"GoMenu"}, {0,0,0x01,0x04,0x4b3,"GoMenu_Badend"}, {0,0,0x01,0x04,0xcc, "ShowMouseCursor"}, {0,0,0x01,0x04,0xcd, "HideMouseCursor"}, {0,0,0x01,0x04,0xcf, "SetCursorType"}, // scn2k_cmd.cc; CmdD::GetCmd() {0,0,0x00,0x01,0, "local jump"}, {0,0,0x00,0x01,1, "local jump-if"}, {0,0,0x00,0x01,2, "local jump-unless"}, {0,0,0x00,0x01,3, "local jump-switch??"}, {0,0,0x00,0x01,4, "local switch"}, {0,0,0x00,0x01,5, "local call"}, {0,0,0x00,0x01,8, "local switch(simple form)"}, {0,0,0x01,0x0b,0, "set multiple variables"}, {0,0,0x01,0x0b,1, "set variables in a range"}, {0,0,0x01,0x0b,4, "clear variables in a range"}, {0,0,0x01,0x0b,0x64, "get summation of variables in a range"}, // scn2k_cmd.cc; Flags::Exec() {0,0,0x01,0x0a,0, "SetStr"}, {0,0,0x01,0x0a,1, "ClearStr"}, {0,0,0x01,0x0a,2, "AppendStr"}, {0,0,0x01,0x0a,3, "StrLen"}, {0,0,0x01,0x0a,4, "StrCmp"}, {0,0,0x01,0x0a,5, "SubStrL"}, {0,0,0x01,0x0a,6, "SubStrR"}, {0,0,0x01,0x0a,7, "StrLenWideChar"}, {0,0,0x01,0x0a,8, "TrimStr"}, {0,0,0x01,0x0a,0x0f, "IntToStr"}, {0,0,0x01,0x0a,0x11, "IntToStr_Fill"}, {0,0,0x01,0x0a,0x64, "ShowStr"}, // scn2k_text.cc; TextImpl::Exec() {0,0,0x01,0x21,0x49, "SetFaceGraphic"}, {0,0,0x01,0x21,0x4b, "SetFaceGraphic"}, {0,0,0x01,0x21,0x4c, "SetFaceGraphic"}, {0,0,0x00,0x03,0x97, "CloseTextWindow"}, {0,0,0x00,0x03,0x11, "WaitText"}, {0,0,0x00,0x03,0x03, "TextReturn"}, {0,0,0x00,0x03,0xc9, "TextReturn"}, {0,0,0x00,0x03,0x3e8,"SetFaceGraphic"}, {0,0,0x00,0x03,0x3e9,"SetFaceGraphic"}, {0,0,0x00,0x03,0x78, "TextRuby"}, {0,0,0x00,0x03,0x66, "SetTextWindowType"}, {0,0,0x00,0x03,0x67, "OpenTextWindow"}, {0,0,0x00,0x03,0x98, "ClearTextWindow"}, {0,0,0x00,0x03,0x68, "ShowText"}, {0,0,0x00,0x02,0x01, "Select"}, {0,0,0x00,0x02,0x03, "Select"}, {0,0,0x00,0x04,0x44c,"TextSkipStart"}, {0,0,0x00,0x04,0x3e8,"CloseTextWindow"}, {0,0,0x01,0x04,0x64, "WaitTime"}, {0,0,0x01,0x04,0x6f, "WaitTime"}, {0,0,0x01,0x04,0x79, "WaitTime"}, {0,0,0x01,0x04,0x65, "WaitTime w/ Cancel"}, {0,0,0x01,0x04,0x70, "WaitTime w/ Cancel"}, {0,0,0x01,0x04,0x1fe,"GetTimer"}, {0,0,0x01,0x04,0x201,"ResetTimer (unsupported; see rldev)"}, {0,0,0x01,0x04,0x202,"ResetTimerAll (unsupported; see rldev)"}, {0,0,0x01,0x04,0x72, "GetTimer"}, {0,0,0x01,0x04,0x7c, "GetTimer(2)"}, {0,0,0x01,0x04,0x6e, "ClearTimer"}, {0,0,0x01,0x04,0x78, "ClearTimer(2)"}, {0,0,0x01,0x04,0x26c,"ClearTimer(multi)"}, {0,0,0x01,0x04,0x270,"ClearTimer(multi)"}, {0,0,0x01,0x04,0x276,"GetTimer(multi)"}, {0,0,0x01,0x04,0x1f4,"SetTimer"}, {0,0,0x01,0x04,0x3e8,"rand(x,y)"}, {0,0,0x01,0x04,0x3ec,"min(x,y)"}, {0,0,0x01,0x04,0x3ef,"min(x,y)"}, {0,0,0x01,0x04,0x320,"range conversion(V,?,ResultMin,ValMin,ValMax,ResultMax,?)"}, {0,0,0x01,0x04,0x3f1,"in_range(x,y,a)"}, {0,0,0x01,0x04,0x16c,"SetCursorType?"}, {0,0,0x01,0x04,0xbc1,"LoadFromMenu"}, {0,0,0x01,0x04,0x8d4,"SetTextWindowColor"}, {0,0,0x01,0x04,0x8d5,"SetTextWindowColor"}, {0,0,0x01,0x04,0x8d6,"SetTextWindowColor"}, {0,0,0x01,0x04,0x8d7,"SetTextWindowColor"}, {0,0,0x01,0x04,0x8d8,"SetTextWindowColor"}, {0,0,0x01,0x04,0x8db,"SetTextWindowColor"}, {0,0,0x01,0x04,0x93f,"SetTextWindowColor"}, {0,0,0x01,0x04,0xa39,"SetTextWindowColor"}, {0,0,0x01,0x04,0xa28,"Get #INIT_MESSAGE_SPEED (original) from gameexe.ini"}, {0,0,0x01,0x04,0xa29,"Get #INIT_MESSAGE_SPEED (original) from gameexe.ini"}, {0,0,0x01,0x04,0xa2c,"Get #MESSAGE_KEY_WAIT_USE (original) from gameexe.ini"}, {0,0,0x01,0x04,0xa2d,"Get #INIT_MESSAGE_SPEED (original) from gameexe.ini"}, {0,0,0x01,0x04,0xa2e,"Get #MESSAGE_KEY_WAIT_TIME (original) from gameexe.ini"}, {0,0,0x01,0x04,0x913,"Get #INIT_MESSAGE_SPEED"}, {0,0,0x01,0x04,0x914,"Get #INIT_MESSAGE_SPEED_MOD"}, {0,0,0x01,0x04,0x92e,"Get #MESSAGE_KEY_WAIT_USE"}, {0,0,0x01,0x04,0x92f,"Get #INIT_MESSAGE_SPEED_MOD"}, {0,0,0x01,0x04,0x930,"Get #MESSAGE_KEY_WAIT_TIME"}, {0,0,0x01,0x04,0x8af,"Set #INIT_MESSAGE_SPEED"}, {0,0,0x01,0x04,0x8b0,"Set #INIT_MESSAGE_SPEED_MOD"}, {0,0,0x01,0x04,0x8ca,"Set #MESSAGE_KEY_WAIT_USE"}, {0,0,0x01,0x04,0x8cb,"Set #INIT_MESSAGE_SPEED_MOD"}, {0,0,0x01,0x04,0x8cc,"Set #MESSAGE_KEY_WAIT_USE"}, {0,0,0x01,0x04,0x51f,"Set Name Text"}, {0,0,0x01,0x04,0x51e,"Get Name Text"}, {0,0,0x01,0x04,0x514,"Get Name Text"}, // scn2k_grp.cc; GrpImpl::Exec() // music commands {0,0,0x01,0x14,0, "PlayBGM"}, {0,0,0x01,0x14,2, "PlayBGM"}, {0,0,0x01,0x14,0x05, "StopBGM"}, {0,0,0x01,0x14,0x69, "FadeBGM"}, {0,0,0x01,0x15,0, "PlaySE"}, {0,0,0x01,0x15,2, "PlaySE"}, {0,0,0x01,0x17,0, "PlayKoe"}, {0,0,0x01,0x1a,1, "PlayMovie"}, {0,0,0x01,0x1a,0x14, "PlayMovie"}, // graphic commands {0,0,0x01,0x1e,0, "GraphicStackClear"}, {0,0,0x01,0x1f,0, "GraphicStackClear"}, {0,0,0x01,0x21,0x46, "LoadSurface"}, {0,0,0x01,0x21,0x49, "LoadBackSurface"}, {0,0,0x01,0x21,0x4b, "LoadForeSurface"}, {0,0,0x01,0x21,0x4c, "LoadSurface"}, {0,0,0x01,0x21,0x64, "CopySurface"}, {0,0,0x01,0x21,0x4b1,"ClearSurface"}, {0,0,0x01,0x21,0x44c,"AlphaCopy"}, {0,0,0x01,0x21,0x640,"SaturateCopy"}, {0,0,0x01,0x21,0x196,"??? grp"}, {0,0,0x01,0x22,0xc30,"ScrollEffect (Princess Bride)"}, {0,0,0x01,0x22,0xc1c,"FallEffect (Princess Bride)"}, {0,0,0x01,0x22,0x835,"FallEffect (Princess Bride)"}, // grphic object commands {0,0,0x01,0x04,0xd2, "??? grp"}, {0,0,0x01,0x04,0xd3, "??? grp"}, {0,0,0x01,0x04,0xd7, "??? grp"}, {0,0,0x01,0x04,0xd8, "??? grp"}, {0,0,0x01,0x04,0x5e0,"GetShownGrpFlag"}, {0,0,0x01,0x3d,0x0a, "ClearGrpObj"}, {0,0,0x01,0x3d,0x0b, "ClearGrpObj"}, {0,0,0x01,0x3e,0x0a, "ClearGrpObj"}, {0,0,0x01,0x3e,0x0a, "ClearGrpObj"}, {0,0,0x01,0x3c,0x01, "??? grp (CLANNAD)"}, {0,0,0x01,0x47,0x3e8,"SetGrpObj_Fname"}, {0,0,0x01,0x47,0x3eb,"SetGrpObj_GANname"}, {0,0,0x01,0x47,0x4b0,"SetGrpObj_Text"}, {0,0,0x01,0x48,0x3e8,"SetGrpObj_ForeGrp?"}, {0,0,0x01,0x49,0, "StopAnimation"}, {0,0,0x01,0x49,3, "QueryExecAnimation"}, {0,0,0x01,0x49,0x7d3,"SetGrpObj_GAN?"}, {0,0,0x01,0x49,0xbb9,"StartAnimation"}, {0,0,0x01,0x49,0xbbb,"StartAnimation"}, {0,0,0x01,0x49,0xbbd,"StartAnimation"}, {0,0,0x01,0x51,0x3e8,"SetGrpObj_xy"}, {0,0,0x01,0x51,0x3e9,"SetGrpObj_x"}, {0,0,0x01,0x51,0x3ea,"SetGrpObj_y"}, {0,0,0x01,0x51,0x3eb,"SetGrpObj_alpha"}, {0,0,0x01,0x51,0x3ec,"SetGrpObj_visible"}, {0,0,0x01,0x51,0x3ee,"SetGrpObj_xy?"}, {0,0,0x01,0x51,0x3fd,"SetGrpObj_centering?"}, {0,0,0x01,0x51,0x401,"SetGrpObj_textsize"}, {0,0,0x01,0x51,0x40a,"SetGrpObj_clipregion"}, {0,0,0x01,0x51,0x40f,"SetGrpObj_surfacenum"}, {0,0,0x01,0x51,0x416,"SetGrpObj_expand"}, {0,0,0x01,0x51,0x419,"SetGrpObj_rotate"}, {0,0,0x01,0x52,0x3e8,"SetGrpObj_xy(2)"}, {0,0,0x01,0x52,0x3ea,"SetGrpObj_y(2)"}, {0,0,0x01,0x52,0x3eb,"SetGrpObj_alpha(2)"}, {0,0,0x01,0x52,0x3ec,"SetGrpObj_visible(2)"}, {0,0,0x01,0x52,0x3ee,"SetGrpObj_xy?(2)"}, {0,0,0x01,0x52,0x3fd,"SetGrpObj_centering?(2)"}, {0,0,0x01,0x52,0x401,"SetGrpObj_textsize(2)"}, {0,0,0x01,0x52,0x408,"SetGrpObj_order (not supported)"}, {0,0,0x01,0x52,0x40a,"SetGrpObj_clipregion(2)"}, {0,0,0x01,0x52,0x40f,"SetGrpObj_surfacenum(2)"}, {0,0,0x01,0x52,0x416,"SetGrpObj_expand(2)"}, {0,0,0x01,0x52,0x419,"SetGrpObj_rotate(2)"}, {0,0,0x01,0x54,0x3e8,"GetGrpObj_xy"}, {0,0,0x01,0x54,0x44c,"GetGrpObj_wh"}, {0,0,0x02,0x3d,0x0a, "ClearGrpObj(2)"}, {0,0,0x02,0x3d,0x0b, "ClearGrpObj(2)"}, {0,0,0x02,0x3e,0x0a, "ClearGrpObj(2)"}, {0,0,0x02,0x3e,0x0a, "ClearGrpObj(2)"}, {0,0,0x02,0x3c,0x01, "??? grp (CLANNAD)(2)"}, {0,0,0x02,0x47,0x3e8,"SetGrpObj_Fname(2)"}, {0,0,0x02,0x47,0x3eb,"SetGrpObj_GANname(2)"}, {0,0,0x02,0x47,0x4b0,"SetGrpObj_Text(2)"}, {0,0,0x02,0x48,0x3e8,"SetGrpObj_ForeGrp?(2)"}, {0,0,0x02,0x49,0, "StopAnimation(2)"}, {0,0,0x02,0x49,3, "QueryExecAnimation(2)"}, {0,0,0x02,0x49,0x7d3,"SetGrpObj_GAN?(2)"}, {0,0,0x02,0x49,0xbb9,"StartAnimation(2)"}, {0,0,0x02,0x49,0xbbb,"StartAnimation(2)"}, {0,0,0x02,0x49,0xbbd,"StartAnimation(2)"}, {0,0,0x02,0x51,0x3e8,"SetGrpObj_xy(2)"}, {0,0,0x02,0x51,0x3ea,"SetGrpObj_y(2)"}, {0,0,0x02,0x51,0x3eb,"SetGrpObj_alpha(2)"}, {0,0,0x02,0x51,0x3ec,"SetGrpObj_visible(2)"}, {0,0,0x02,0x51,0x3ee,"SetGrpObj_xy?(2)"}, {0,0,0x02,0x51,0x3fd,"SetGrpObj_centering?(2)"}, {0,0,0x02,0x51,0x401,"SetGrpObj_textsize(2)"}, {0,0,0x02,0x51,0x40a,"SetGrpObj_clipregion(2)"}, {0,0,0x02,0x51,0x40f,"SetGrpObj_surfacenum(2)"}, {0,0,0x02,0x51,0x416,"SetGrpObj_expand(2)"}, {0,0,0x02,0x51,0x419,"SetGrpObj_rotate(2)"}, {0,0,0x02,0x52,0x3e8,"SetGrpObj_xy(2)(2)"}, {0,0,0x02,0x52,0x3ea,"SetGrpObj_y(2)(2)"}, {0,0,0x02,0x52,0x3eb,"SetGrpObj_alpha(2)(2)"}, {0,0,0x02,0x52,0x3ec,"SetGrpObj_visible(2)(2)"}, {0,0,0x02,0x52,0x3ee,"SetGrpObj_xy?(2)(2)"}, {0,0,0x02,0x52,0x3fd,"SetGrpObj_centering?(2)(2)"}, {0,0,0x02,0x52,0x401,"SetGrpObj_textsize(2)(2)"}, {0,0,0x02,0x52,0x40a,"SetGrpObj_clipregion(2)(2)"}, {0,0,0x02,0x52,0x40f,"SetGrpObj_surfacenum(2)(2)"}, {0,0,0x02,0x52,0x416,"SetGrpObj_expand(2)(2)"}, {0,0,0x02,0x52,0x419,"SetGrpObj_rotate(2)(2)"}, {0,0,0x02,0x54,0x3e8,"GetGrpObj_xy(2)"}, {0,0,0x02,0x54,0x44c,"GetGrpObj_wh(2)"}, {0,0,0,0,0,0} }; map<int, CmdDescrItem*> CmdD::cmd_descr; const char* CmdD::CmdDescr(int cmd1, int cmd2, int cmd3, int cmd4) { if (cmd_descr.empty()) { int i; for (i=0; cmd_descr_orig[i].cmd_descr != 0; i++) { CmdDescrItem& cur = cmd_descr_orig[i]; int item_num = cur.cmd1*1000000+cur.cmd2*10000+cur.cmd3; map<int,CmdDescrItem*>::iterator it = cmd_descr.find(item_num); if (it == cmd_descr.end()) cmd_descr[item_num] = &cur; else { cur.next = it->second; it->second = &cur; } } } int item_num = cmd1*1000000+cmd2*10000+cmd3; map<int,CmdDescrItem*>::iterator it = cmd_descr.find(item_num); if (it == cmd_descr.end()) return "No descr (unsupported)"; CmdDescrItem* cur = it->second; do { if (cur->cmd1 == cmd1 && cur->cmd2 == cmd2 && cur->cmd3 == cmd3) { return cur->cmd_descr; } cur = cur->next; } while(cur != 0); return "No descr (unsupported)"; }