00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <stdlib.h>
00022 #include <string.h>
00023
00024 #include "blockop.h"
00025 #include "cmds.h"
00026 #include "htatom.h"
00027 #include "htctrl.h"
00028 #include "htendian.h"
00029 #include "hteval.h"
00030 #include "htexcept.h"
00031 #include "hthist.h"
00032 #include "htiobox.h"
00033 #include "htkeyb.h"
00034 #include "htstring.h"
00035 #include "process.h"
00036 #include "snprintf.h"
00037
00038 #include "evalx.h"
00039
00040
00041
00042
00043
00044 void ht_blockop_dialog::init(bounds *b, FILEOFS pstart, FILEOFS pend, ht_list *history)
00045 {
00046 ht_dialog::init(b, "operate on block", FS_TITLE | FS_KILLER | FS_MOVE);
00047 bounds c;
00048
00049 bool prerange=(pend>pstart);
00050
00051 ht_statictext *text;
00052
00053 ht_label *s;
00054
00055 ht_list *addrhist=(ht_list*)find_atom(HISTATOM_GOTO);
00056
00057 c=*b;
00058 c.h=1;
00059 c.w=13;
00060 c.x=7;
00061 c.y=1;
00062 start=new ht_strinputfield();
00063 start->init(&c, 64, addrhist);
00064 insert(start);
00065 if (prerange) {
00066 char t[16];
00067 ht_snprintf(t, sizeof t, "0x%x", pstart);
00068 ht_inputfield_data d;
00069 d.textlen=strlen(t);
00070 d.text=(byte*)t;
00071 start->databuf_set(&d, sizeof d);
00072 }
00073
00074
00075 c.x=1;
00076 c.w=6;
00077 s=new ht_label();
00078 s->init(&c, "~start", start);
00079 insert(s);
00080
00081
00082 c=*b;
00083 c.h=1;
00084 c.w=13;
00085 c.x=27;
00086 c.y=1;
00087 end=new ht_strinputfield();
00088 end->init(&c, 64, addrhist);
00089 insert(end);
00090 if (prerange) {
00091 char t[16];
00092 ht_snprintf(t, sizeof t, "0x%x", pend);
00093 ht_inputfield_data d;
00094 d.textlen=strlen(t);
00095 d.text=(byte*)t;
00096 end->databuf_set(&d, sizeof d);
00097 }
00098
00099
00100
00101 c.x=23;
00102 c.w=3;
00103 s=new ht_label();
00104 s->init(&c, "~end", end);
00105 insert(s);
00106
00107
00108 c=*b;
00109 c.h=1;
00110 c.w=16;
00111 c.x=7;
00112 c.y=3;
00113 mode=new ht_listpopup();
00114 mode->init(&c);
00115 mode->insertstring("byte (8-bit)");
00116 mode->insertstring("word (16-bit)");
00117 mode->insertstring("dword (32-bit)");
00118 mode->insertstring("string");
00119 insert(mode);
00120
00121
00122 c.x=1;
00123 c.w=12;
00124 c.y=3;
00125 s=new ht_label();
00126 s->init(&c, "~mode", mode);
00127 insert(s);
00128
00129
00130 c=*b;
00131 c.x=1;
00132 c.y=5;
00133 c.w-=3;
00134 c.h=1;
00135 text=new ht_statictext();
00136 text->init(&c, "set each element to", align_left);
00137 insert(text);
00138
00139
00140 ht_list *ehist=(ht_list*)find_atom(HISTATOM_EVAL_EXPR);
00141
00142 c=*b;
00143 c.h=1;
00144 c.w=40;
00145 c.x=7;
00146 c.y=6;
00147 action=new ht_strinputfield();
00148 action->init(&c, 4096, ehist);
00149 insert(action);
00150
00151
00152 c.x=1;
00153 c.w=27;
00154 c.y=6;
00155 s=new ht_label();
00156 s->init(&c, "e~xpr", action);
00157 insert(s);
00158
00159
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169
00170
00171
00172 ht_button *bhelp = new ht_button();
00173 c = *b;
00174 c.x = 1;
00175 c.y = 8;
00176 c.w = 11;
00177 c.h = 1;
00178 bhelp->init(&c, "~Functions", 100);
00179 insert(bhelp);
00180 }
00181
00182 void ht_blockop_dialog::done()
00183 {
00184 ht_dialog::done();
00185 }
00186
00187 struct ht_blockop_dialog_data {
00188 ht_inputfield_data start;
00189 ht_inputfield_data end;
00190 ht_listpopup_data mode;
00191 ht_inputfield_data action;
00192 };
00193
00194
00195
00196
00197
00198 static dword blockop_i;
00199 static dword blockop_o;
00200 static bool blockop_expr_is_const;
00201
00202 static int blockop_symbol_eval(eval_scalar *r, char *symbol)
00203 {
00204 if (strcmp(symbol, "i")==0) {
00205 r->type=SCALAR_INT;
00206 r->scalar.integer.value=to_qword(blockop_i);
00207 r->scalar.integer.type=TYPE_UNKNOWN;
00208 blockop_expr_is_const=false;
00209 return 1;
00210 } else if (strcmp(symbol, "o")==0) {
00211 r->type=SCALAR_INT;
00212 r->scalar.integer.value=to_qword(blockop_o);
00213 r->scalar.integer.type=TYPE_UNKNOWN;
00214 blockop_expr_is_const=false;
00215 return 1;
00216 }
00217 return 0;
00218 }
00219
00220 static int func_readint(eval_scalar *result, eval_int *offset, int size, endianess e)
00221 {
00222 ht_streamfile *f=(ht_streamfile*)eval_get_context();
00223 byte buf[4];
00224 int read = 0;
00225 if ((f->seek(QWORD_GET_INT(offset->value))!=0) ||
00226 ((read = f->read(buf, size)) != size)) {
00227 set_eval_error("i/o error (requested %d, read %d from ofs %08x)", size, read, offset->value);
00228 return 0;
00229 }
00230 scalar_create_int_c(result, create_host_int(buf, size, e));
00231 return 1;
00232 }
00233
00234 static int func_readbyte(eval_scalar *result, eval_int *offset)
00235 {
00236 return func_readint(result, offset, 1, little_endian);
00237 }
00238
00239 static int func_read16le(eval_scalar *result, eval_int *offset)
00240 {
00241 return func_readint(result, offset, 2, little_endian);
00242 }
00243
00244 static int func_read32le(eval_scalar *result, eval_int *offset)
00245 {
00246 return func_readint(result, offset, 4, little_endian);
00247 }
00248
00249 static int func_read16be(eval_scalar *result, eval_int *offset)
00250 {
00251 return func_readint(result, offset, 2, big_endian);
00252 }
00253
00254 static int func_read32be(eval_scalar *result, eval_int *offset)
00255 {
00256 return func_readint(result, offset, 4, big_endian);
00257 }
00258
00259 static int func_readstring(eval_scalar *result, eval_int *offset, eval_int *len)
00260 {
00261 ht_streamfile *f=(ht_streamfile*)eval_get_context();
00262
00263 UINT l=QWORD_GET_INT(len->value);
00264 void *buf=malloc(l);
00265
00266 if (buf) {
00267 eval_str s;
00268 UINT c = 0;
00269 if ((f->seek(QWORD_GET_INT(offset->value))!=0) || ( (c=f->read(buf, l)) !=l)) {
00270 free(buf);
00271 set_eval_error("i/o error (requested %d, read %d from ofs %08x)", l, c, offset->value);
00272 return 0;
00273 }
00274 s.value=(char*)buf;
00275 s.len=l;
00276 scalar_create_str(result, &s);
00277 free(buf);
00278 return 1;
00279 }
00280 set_eval_error("out of memory");
00281 return 0;
00282 }
00283
00284 static int blockop_func_eval(eval_scalar *result, char *name, eval_scalarlist *params)
00285 {
00286
00287
00288 eval_func myfuncs[] = {
00289 {"readbyte", (void*)&func_readbyte, {SCALAR_INT}},
00290 {"read16le", (void*)&func_read16le, {SCALAR_INT}},
00291 {"read32le", (void*)&func_read32le, {SCALAR_INT}},
00292 {"read16be", (void*)&func_read16be, {SCALAR_INT}},
00293 {"read32be", (void*)&func_read32be, {SCALAR_INT}},
00294 {"readstring", (void*)&func_readstring, {SCALAR_INT, SCALAR_INT}},
00295 {NULL}
00296 };
00297
00298 blockop_expr_is_const=false;
00299
00300 return std_eval_func_handler(result, name, params, myfuncs);
00301 }
00302
00303
00304
00305
00306
00307 class ht_blockop_str_context: public Object {
00308 public:
00309 ht_streamfile *file;
00310
00311 FILEOFS ofs;
00312 UINT len;
00313
00314 UINT size;
00315 bool netendian;
00316
00317 char *action;
00318
00319 UINT i;
00320 FILEOFS o;
00321
00322 bool expr_const;
00323 eval_str v;
00324
00325 ~ht_blockop_str_context()
00326 {
00327 free(action);
00328 if (expr_const) string_destroy(&v);
00329 }
00330 };
00331
00332 Object *create_blockop_str_context(ht_streamfile *file, FILEOFS ofs, UINT len, UINT size, bool netendian, char *action)
00333 {
00334 ht_blockop_str_context *ctx = new ht_blockop_str_context();
00335 ctx->file = file;
00336 ctx->ofs = ofs;
00337 ctx->len = len;
00338 ctx->size = size;
00339 ctx->netendian = netendian;
00340 ctx->action = strdup(action);
00341
00342 ctx->i = 0;
00343 ctx->o = ofs;
00344
00345 blockop_expr_is_const = true;
00346
00347
00348 blockop_i = ctx->i;
00349 blockop_o = ctx->o;
00350 eval_scalar r;
00351 if (!eval(&r, action, blockop_func_eval, blockop_symbol_eval, file)) {
00352 char *s;
00353 int p;
00354 get_eval_error(&s, &p);
00355 throw new ht_io_exception("error evaluating '%s': %s at %d", action, s, p);
00356 }
00357
00358 ctx->expr_const = blockop_expr_is_const;
00359
00360 if (ctx->expr_const) {
00361 scalar_context_str(&r, &ctx->v);
00362 }
00363 scalar_destroy(&r);
00364 return ctx;
00365 }
00366
00367 #define BLOCKOP_STR_MAX_ITERATIONS 1024
00368 bool blockop_str_process(Object *context, ht_text *progress_indicator)
00369 {
00370 char status[64];
00371 ht_blockop_str_context *ctx = (ht_blockop_str_context*)context;
00372 if (ctx->expr_const) {
00373 ht_snprintf(status, sizeof status, "operating (constant string)... %d%% complete", (int)(((double)(ctx->o-ctx->ofs)) * 100 / ctx->len));
00374 progress_indicator->settext(status);
00375 for (UINT i=0; i < BLOCKOP_STR_MAX_ITERATIONS; i++)
00376 if (ctx->o < ctx->ofs + ctx->len) {
00377 UINT s = ctx->v.len;
00378 if (ctx->o + s > ctx->ofs + ctx->len) s = ctx->ofs + ctx->len - ctx->o;
00379
00380 ctx->file->seek(ctx->o);
00381 if (ctx->file->write(ctx->v.value, s)!=s) {
00382 throw new ht_io_exception("blockop_str(): write error at pos %08x, size %08x", ctx->o, s);
00383 }
00384 ctx->o += s;
00385 } else {
00386 return false;
00387 }
00388 } else {
00389 ht_snprintf(status, sizeof status, "operating (variable string)... %d%% complete", (int)(((double)(ctx->o-ctx->ofs)) * 100 / ctx->len));
00390 progress_indicator->settext(status);
00391 eval_scalar r;
00392 eval_str sr;
00393 for (UINT i=0; i < BLOCKOP_STR_MAX_ITERATIONS; i++)
00394 if (ctx->o < ctx->ofs + ctx->len) {
00395 blockop_i = ctx->i;
00396 blockop_o = ctx->o;
00397 if (!eval(&r, ctx->action, blockop_func_eval, blockop_symbol_eval, ctx->file)) {
00398 char *s;
00399 int p;
00400 get_eval_error(&s, &p);
00401 throw new ht_io_exception("error evaluating '%s': %s at %d", ctx->action, s, p);
00402 }
00403 scalar_context_str(&r, &sr);
00404 scalar_destroy(&r);
00405
00406 UINT s = sr.len;
00407 if (ctx->o+s > ctx->ofs+ctx->len) s = ctx->ofs+ctx->len-ctx->o;
00408
00409 ctx->file->seek(ctx->o);
00410 if (ctx->file->write(sr.value, s)!=s) {
00411 throw new ht_io_exception("blockop_str(): write error at pos %08x, size %08x", ctx->o, s);
00412 }
00413 string_destroy(&sr);
00414 ctx->o += s;
00415 ctx->i++;
00416 } else {
00417 return false;
00418 }
00419 }
00420 return true;
00421 }
00422
00423
00424
00425
00426
00427 class ht_blockop_int_context: public Object {
00428 public:
00429 ht_streamfile *file;
00430
00431 FILEOFS ofs;
00432 UINT len;
00433
00434 UINT size;
00435 endianess endian;
00436
00437 char *action;
00438
00439 UINT i;
00440 FILEOFS o;
00441
00442 bool expr_const;
00443 UINT v;
00444
00445 ~ht_blockop_int_context()
00446 {
00447 free(action);
00448 }
00449 };
00450
00451 Object *create_blockop_int_context(ht_streamfile *file, FILEOFS ofs, UINT len, UINT size, endianess endian, char *action)
00452 {
00453 ht_blockop_int_context *ctx = new ht_blockop_int_context();
00454 ctx->file = file;
00455 ctx->ofs = ofs;
00456 ctx->len = len;
00457 ctx->size = size;
00458 ctx->endian = endian;
00459 ctx->action = ht_strdup(action);
00460
00461 ctx->i = 0;
00462 ctx->o = ofs;
00463
00464 blockop_expr_is_const = true;
00465
00466
00467 blockop_i = ctx->i;
00468 blockop_o = ctx->o;
00469 eval_scalar r;
00470 eval_int ir;
00471 if (!eval(&r, action, blockop_func_eval, blockop_symbol_eval, file)) {
00472 char *s;
00473 int p;
00474 get_eval_error(&s, &p);
00475 throw new ht_io_exception("error evaluating '%s': %s at %d", action, s, p);
00476 }
00477
00478 ctx->expr_const = blockop_expr_is_const;
00479
00480 if (ctx->expr_const) {
00481 scalar_context_int(&r, &ir);
00482 ctx->v = QWORD_GET_INT(ir.value);
00483 }
00484 scalar_destroy(&r);
00485 return ctx;
00486 }
00487
00488 #define BLOCKOP_INT_MAX_ITERATIONS 1024
00489 bool blockop_int_process(Object *context, ht_text *progress_indicator)
00490 {
00491 ht_blockop_int_context *ctx = (ht_blockop_int_context*)context;
00492 char status[64];
00493 if (ctx->expr_const) {
00494 ht_snprintf(status, sizeof status, "operating (constant integer)... %d%% complete", (int)(((double)(ctx->o-ctx->ofs)) * 100 / ctx->len));
00495 progress_indicator->settext(status);
00496 byte ibuf[4];
00497 create_foreign_int(ibuf, ctx->v, ctx->size, ctx->endian);
00498 ctx->file->seek(ctx->o);
00499 for (UINT i=0; i < BLOCKOP_INT_MAX_ITERATIONS; i++)
00500 if (ctx->o < ctx->ofs + ctx->len) {
00501 UINT s = ctx->size;
00502 if (ctx->o + s > ctx->ofs + ctx->len) s = ctx->ofs + ctx->len - ctx->o;
00503 if (ctx->file->write(ibuf, s)!=s) {
00504 throw new ht_io_exception("blockop_int(): write error at pos %08x, size %08x", ctx->o, s);
00505 }
00506 ctx->o += s;
00507 } else {
00508 return false;
00509 }
00510 } else {
00511 ht_snprintf(status, sizeof status, "operating (variable integer)... %d%% complete", (int)(((double)(ctx->o-ctx->ofs)) * 100 / ctx->len));
00512 progress_indicator->settext(status);
00513 eval_scalar r;
00514 eval_int ir;
00515 for (UINT i=0; i < BLOCKOP_INT_MAX_ITERATIONS; i++)
00516 if (ctx->o < ctx->ofs + ctx->len) {
00517 blockop_o = ctx->o;
00518 blockop_i = ctx->i;
00519 if (!eval(&r, ctx->action, blockop_func_eval, blockop_symbol_eval, ctx->file)) {
00520 char *s;
00521 int p;
00522 get_eval_error(&s, &p);
00523 throw new ht_io_exception("error evaluating '%s': %s at %d", ctx->action, s, p);
00524 }
00525 scalar_context_int(&r, &ir);
00526 scalar_destroy(&r);
00527 ctx->v=QWORD_GET_INT(ir.value);
00528
00529 UINT s = ctx->size;
00530 if (ctx->o+s > ctx->ofs+ctx->len) s = ctx->ofs+ctx->len-ctx->o;
00531
00532 byte ibuf[4];
00533 create_foreign_int(ibuf, ctx->v, ctx->size, ctx->endian);
00534 if ((ctx->file->seek(ctx->o) != 0) || (ctx->file->write(ibuf, s)!=s)) {
00535 throw new ht_io_exception("blockop_int(): write error at pos %08x, size %08x", ctx->o, s);
00536 }
00537 ctx->o += s;
00538 ctx->i++;
00539 } else {
00540 return false;
00541 }
00542 }
00543 return true;
00544 }
00545
00546
00547
00548
00549
00550 bool format_string_to_offset_if_avail(ht_format_viewer *format, byte *string, int stringlen, const char *string_desc, FILEOFS *ofs)
00551 {
00552 if (string && *string && stringlen<64) {
00553 char str[64];
00554 memmove(str, string, stringlen);
00555 str[stringlen]=0;
00556 if (!format->string_to_offset(str, ofs)) {
00557 errorbox("%s: '%s' doesn't seem to be a valid offset", string_desc, &str);
00558 return false;
00559 }
00560 return true;
00561 }
00562 return false;
00563 }
00564
00565
00566 void blockop_dialog(ht_format_viewer *format, FILEOFS pstart, FILEOFS pend)
00567 {
00568 bounds b;
00569 b.w=65;
00570 b.h=15;
00571 b.x=(screen->size.w-b.w)/2;
00572 b.y=(screen->size.h-b.h)/2;
00573
00574 ht_blockop_dialog *d=new ht_blockop_dialog();
00575 d->init(&b, pstart, pend, 0);
00576 bool run = true;
00577 int r;
00578 while (run && ((r = d->run(false)) != button_cancel)) {
00579 switch (r) {
00580 case 100:
00581 dialog_eval_help(blockop_func_eval, blockop_symbol_eval, NULL);
00582 break;
00583 default:
00584 {
00585 ht_blockop_dialog_data t;
00586 d->databuf_get(&t, sizeof t);
00587
00588 ht_streamfile *file=format->get_file();
00589
00590 baseview->sendmsg(cmd_edit_mode_i, file, NULL);
00591
00592 if (file->get_access_mode() & FAM_WRITE) {
00593 FILEOFS start=pstart, end=pend;
00594
00595 if (format_string_to_offset_if_avail(format, t.start.text, t.start.textlen, "start", &start) &&
00596 format_string_to_offset_if_avail(format, t.end.text, t.end.textlen, "end", &end)) {
00597 if (end > start) {
00598 int esize=0;
00599 int esizes[3]={4, 2, 1};
00600 switch (t.mode.cursor_pos) {
00601
00602 case 0: esize++;
00603
00604 case 1: esize++;
00605
00606 case 2: {
00607 char a[4096];
00608 bin2str(a, t.action.text, MIN(sizeof a, t.action.textlen));
00609 insert_history_entry((ht_list*)find_atom(HISTATOM_EVAL_EXPR), a, NULL);
00610
00611 char addr[128];
00612 bin2str(addr, t.start.text, MIN(sizeof addr, t.start.textlen));
00613 insert_history_entry((ht_list*)find_atom(HISTATOM_GOTO), addr, NULL);
00614 bin2str(addr, t.end.text, MIN(sizeof addr, t.end.textlen));
00615 insert_history_entry((ht_list*)find_atom(HISTATOM_GOTO), addr, NULL);
00616
00617 esize = esizes[esize];
00618 Object *ctx = NULL;
00619 try {
00620 ctx = create_blockop_int_context(file, start, end-start, esize, little_endian, a);
00621 if (ctx) {
00622 execute_process(blockop_int_process, ctx);
00623 }
00624 } catch (ht_exception *e) {
00625 errorbox("error: %s", e->what());
00626 }
00627 if (ctx) delete ctx;
00628 break;
00629 }
00630
00631 case 3: {
00632 char a[256];
00633 bin2str(a, t.action.text, MIN(sizeof a, t.action.textlen));
00634 insert_history_entry((ht_list*)find_atom(HISTATOM_EVAL_EXPR), a, NULL);
00635
00636 char addr[128];
00637 bin2str(addr, t.start.text, MIN(sizeof addr, t.start.textlen));
00638 insert_history_entry((ht_list*)find_atom(HISTATOM_GOTO), addr, NULL);
00639 bin2str(addr, t.end.text, MIN(sizeof addr, t.end.textlen));
00640 insert_history_entry((ht_list*)find_atom(HISTATOM_GOTO), addr, NULL);
00641
00642 Object *ctx = NULL;
00643 try {
00644 ctx = create_blockop_str_context(file, start, end-start, esize, little_endian, a);
00645 if (ctx) {
00646 execute_process(blockop_str_process, ctx);
00647 }
00648 } catch (ht_exception *e) {
00649 errorbox("error: %s", e->what());
00650 }
00651 if (ctx) delete ctx;
00652 break;
00653 }
00654 default:
00655 errorbox("mode %d not supported", t.mode.cursor_pos);
00656 }
00657 } else {
00658 errorbox("end offset must be greater than start offset");
00659 }
00660 }
00661 }
00662 run = false;
00663 }
00664 }
00665 }
00666
00667 d->done();
00668 delete d;
00669 }
00670