Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

htformat.cc

Go to the documentation of this file.
00001 /*
00002  *      HT Editor
00003  *      htformat.cc
00004  *
00005  *      Copyright (C) 1999-2002 Stefan Weyergraf (stefan@weyergraf.de)
00006  *
00007  *      This program is free software; you can redistribute it and/or modify
00008  *      it under the terms of the GNU General Public License version 2 as
00009  *      published by the Free Software Foundation.
00010  *
00011  *      This program is distributed in the hope that it will be useful,
00012  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *      GNU General Public License for more details.
00015  *
00016  *      You should have received a copy of the GNU General Public License
00017  *      along with this program; if not, write to the Free Software
00018  *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00019  */
00020 
00021 #include "htformat.h"
00022 #include "htsearch.h"
00023 
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #include <time.h>
00027 
00028 #include "blockop.h"
00029 #include "cmds.h"
00030 #include "htapp.h"              // for popup_view_list(..)
00031 #include "htatom.h"
00032 #include "htclipboard.h"
00033 #include "htctrl.h"
00034 #include "htendian.h"
00035 #include "hteval.h"
00036 #include "hthist.h"
00037 #include "htiobox.h"
00038 #include "htkeyb.h"
00039 #include "htpal.h"
00040 #include "httag.h"
00041 #include "textedit.h"
00042 #include "textfile.h"
00043 #include "process.h"
00044 #include "snprintf.h"
00045 #include "tools.h"
00046 
00047 extern "C" {
00048 #include "evalx.h"
00049 #include "regex.h"
00050 }
00051 
00052 /*cmd_rec ht_format_viewer_cmds[] = {
00053         {cmd_file_truncate, true, true, NULL}
00054 };*/
00055 
00056 void clear_line_id(LINE_ID *l)
00057 {
00058         l->id1 = 0;
00059         l->id2 = 0;
00060         l->id3 = 0;
00061         l->id4 = 0;
00062         l->id5 = 0;
00063 }
00064 
00065 bool compeq_line_id(const LINE_ID &a, const LINE_ID &b)
00066 {
00067         return ((a.id1 == b.id1) && (a.id2 == b.id2)
00068                 && (a.id3 == b.id3) && (a.id4 == b.id4)
00069                 && (a.id5 == b.id5));
00070 }
00071 
00072 
00073 /*
00074  *      CLASS ht_search_request
00075  */
00076 
00077 ht_search_request::ht_search_request(UINT _search_class, UINT _type, UINT _flags)
00078 {
00079         search_class=_search_class;
00080         type=_type;
00081         flags=_flags;
00082 }
00083 
00084 /*
00085  *      CLASS ht_search_result
00086  */
00087  
00088 ht_search_result::ht_search_result(UINT _search_class)
00089 {
00090         search_class=_search_class;
00091 }
00092 
00093 /*
00094  *      CLASS ht_physical_search_result
00095  */
00096  
00097 
00098 ht_physical_search_result::ht_physical_search_result() :
00099         ht_search_result(SC_PHYSICAL)
00100 {
00101 }
00102 
00103 /*
00104  *      CLASS ht_visual_search_result
00105  */
00106  
00107 
00108 ht_visual_search_result::ht_visual_search_result() :
00109         ht_search_result(SC_VISUAL)
00110 {
00111 }
00112 
00113 /*
00114  *      CLASS ht_format_group
00115  */
00116 
00117 void ht_format_group::init(bounds *b, int options, const char *desc, ht_streamfile *f, bool own_f, bool editable_f, format_viewer_if **i, ht_format_group *format_group)
00118 {
00119         ht_format_viewer::init(b, desc, 0, f, format_group);
00120         VIEW_DEBUG_NAME("ht_format_group");
00121 
00122         xgroup=new ht_xgroup();
00123         xgroup->init(b, options, desc);
00124         xgroup->group=group;
00125 
00126         format_views=new ht_clist();    // a list of ht_format_viewer_entrys
00127         format_views->init();
00128 
00129         own_file=own_f;
00130         editable_file=editable_f;
00131         if (i) init_ifs(i);
00132 }
00133 
00134 void ht_format_group::done()
00135 {
00136         done_ifs();
00137 
00138         format_views->destroy();
00139         delete format_views;
00140 
00141         xgroup->done();
00142         delete xgroup;
00143 
00144         ht_format_viewer::done();
00145 
00146         if (own_file && file) {
00147                 file->done();
00148                 delete file;
00149         }
00150 }
00151 
00152 int ht_format_group::childcount()
00153 {
00154         return xgroup->childcount();
00155 }
00156 
00157 bool ht_format_group::done_if(format_viewer_if *i, ht_view *v)
00158 {
00159         remove(v);
00160         if (i->done) i->done(v); else {
00161                 v->done();
00162                 delete v;
00163         }
00164         return true;
00165 }
00166 
00167 void ht_format_group::done_ifs()
00168 {
00169         int j=0;
00170         while (1) {
00171                 ht_format_viewer_entry *e=(ht_format_viewer_entry*)format_views->get(j);
00172                 if (!(e && e->instance)) break;
00173                 done_if(e->interface, e->instance);
00174                 j++;
00175         }
00176 }
00177 
00178 bool ht_format_group::edit()
00179 {
00180         return (file->get_access_mode() & FAM_WRITE);
00181 }
00182 
00183 int ht_format_group::focus(ht_view *view)
00184 {
00185         int r=ht_format_viewer::focus(view);
00186         if (!r) r=xgroup->focus(view);
00187         return r;
00188 }
00189 
00190 char *ht_format_group::func(UINT i, bool execute)
00191 {
00192         return ht_format_viewer::func(i, execute);
00193 }
00194 
00195 void ht_format_group::getbounds(bounds *b)
00196 {
00197         xgroup->getbounds(b);
00198 }
00199 
00200 void *ht_format_group::get_shared_data()
00201 {
00202         return shared_data;
00203 }
00204 
00205 ht_view *ht_format_group::getfirstchild()
00206 {
00207         return xgroup->getfirstchild();
00208 }
00209 
00210 ht_view *ht_format_group::getselected()
00211 {
00212         return xgroup->getselected();
00213 }
00214 
00215 void ht_format_group::get_pindicator_str(char *buf)
00216 {
00217         ht_view *c=xgroup->current;
00218         if (c && (c->options & VO_FORMAT_VIEW)) {
00219                 ((ht_format_viewer*)c)->get_pindicator_str(buf);
00220         } else {
00221                 *buf=0;
00222         }
00223 }
00224 
00225 bool ht_format_group::get_hscrollbar_pos(int *pstart, int *psize)
00226 {
00227         ht_view *c=xgroup->current;
00228         if (c && (c->options & VO_FORMAT_VIEW)) {
00229                 return ((ht_format_viewer*)c)->get_hscrollbar_pos(pstart, psize);
00230         }
00231         return false;
00232 }
00233 
00234 bool ht_format_group::get_vscrollbar_pos(int *pstart, int *psize)
00235 {
00236         ht_view *c=xgroup->current;
00237         if (c && (c->options & VO_FORMAT_VIEW)) {
00238                 return ((ht_format_viewer*)c)->get_vscrollbar_pos(pstart, psize);
00239         }
00240         return false;
00241 }
00242 
00243 void ht_format_group::handlemsg(htmsg *msg)
00244 {
00245         switch (msg->msg) {
00246                 case msg_keypressed: {
00247                         int i=0;
00248                         switch (msg->data1.integer) {
00249                                 case K_F12: i++;
00250                                 case K_F11: i++;
00251                                 case K_F10: i++;
00252                                 case K_F9: i++;
00253                                 case K_F8: i++;
00254                                 case K_F7: i++;
00255                                 case K_F6: i++;
00256                                 case K_F5: i++;
00257                                 case K_F4: i++;
00258                                 case K_F3: i++;
00259                                 case K_F2: i++;
00260                                 case K_F1: {
00261                                         i++;
00262                                         htmsg m;
00263                                         m.msg=msg_funcquery;
00264                                         m.type=mt_empty;
00265                                         m.data1.integer=i;
00266                                         sendmsg(&m);
00267                                         if (m.msg==msg_retval) {
00268                                                 sendmsg(msg_funcexec, i);
00269                                                 clearmsg(msg);
00270                                                 return;
00271                                         }
00272                                         break;
00273                                 }
00274                         }
00275                         break;
00276                 }
00277         }
00278         ht_format_viewer::handlemsg(msg);
00279         xgroup->handlemsg(msg);
00280         switch (msg->msg) {
00281                 case msg_funcexec:
00282                         if (func(msg->data1.integer, 1)) {
00283                                 clearmsg(msg);
00284                                 return;
00285                         }
00286                         break;
00287                 case msg_funcquery: {
00288                         char *s=func(msg->data1.integer, 0);
00289                         if (s) {
00290                                 msg->msg=msg_retval;
00291                                 msg->data1.str=s;
00292                         }
00293                         break;
00294                 }
00295         }
00296 }
00297 
00298 bool ht_format_group::init_if(format_viewer_if *i)
00299 {
00300         bounds b;
00301         getbounds(&b);
00302         b.x=0;
00303         b.y=0;
00304         bool r=0;
00305         ht_view *v=0;
00306         
00307 /*     bounds c=*b;
00308 
00309         c.x=c.w-1;
00310         c.y=0;
00311         c.w=1;*/
00312         if (i->init) {
00313                 v=i->init(&b, file, this);
00314                 if (v) {
00315                         v->sendmsg(msg_complete_init, 0);
00316                         insert(v);
00317                         r=1;
00318                 }
00319         }
00320         ht_format_viewer_entry *e=new ht_format_viewer_entry();
00321         e->interface=i;
00322         e->instance=v;
00323         format_views->insert(e);
00324         return r;
00325 }
00326 
00327 void ht_format_group::init_ifs(format_viewer_if **ifs)
00328 {
00329         format_viewer_if **i=ifs;
00330         while (*i) {
00331                 init_if(*i);
00332                 i++;
00333         }
00334         ifs=i;
00335 }
00336 
00337 void ht_format_group::insert(ht_view *view)
00338 {
00339         xgroup->insert(view);
00340 }
00341 
00342 void ht_format_group::move(int rx, int ry)
00343 {
00344         ht_format_viewer::move(rx, ry);
00345         xgroup->move(rx, ry);
00346 }
00347 
00348 void ht_format_group::receivefocus()
00349 {
00350         xgroup->receivefocus();
00351 }
00352 
00353 void ht_format_group::redraw()
00354 {
00355         xgroup->redraw();
00356 }
00357 
00358 void ht_format_group::releasefocus()
00359 {
00360         xgroup->releasefocus();
00361 }
00362 
00363 void ht_format_group::remove(ht_view *view)
00364 {
00365         xgroup->remove(view);
00366 }
00367 
00368 void ht_format_group::resize(int rw, int rh)
00369 {
00370         ht_format_viewer::resize(rw, rh);
00371         xgroup->resize(rw, rh);
00372 }
00373 
00374 void ht_format_group::setgroup(ht_group *_group)
00375 {
00376         xgroup->setgroup(_group);
00377 }
00378 
00379 /*
00380  *      CLASS ht_viewer
00381  */
00382 
00383 void ht_viewer::init(bounds *b, const char *desc, UINT c)
00384 {
00385         ht_view::init(b, VO_OWNBUFFER | VO_BROWSABLE | VO_SELECTABLE | VO_MOVE | VO_RESIZE, desc);
00386         caps = c;
00387         
00388         growmode = MK_GM(GMH_FIT, GMV_FIT);
00389 }
00390 
00391 void ht_viewer::done()
00392 {
00393         ht_view::done();
00394 }
00395 
00396 char *ht_viewer::func(UINT i, bool execute)
00397 {
00398         return 0;
00399 }
00400 
00401 void ht_viewer::handlemsg(htmsg *msg)
00402 {
00403         int i=0;
00404         switch (msg->msg) {
00405                 case msg_keypressed: {
00406                         switch (msg->data1.integer) {
00407                                 case K_F12: i++;
00408                                 case K_F11: i++;
00409                                 case K_F10: i++;
00410                                 case K_F9: i++;
00411                                 case K_F8: i++;
00412                                 case K_F7: i++;
00413                                 case K_F6: i++;
00414                                 case K_F5: i++;
00415                                 case K_F4: i++;
00416                                 case K_F3: i++;
00417                                 case K_F2: i++;
00418                                 case K_F1: {
00419                                         i++;
00420                                         htmsg m;
00421                                         m.msg=msg_funcquery;
00422                                         m.type=mt_empty;
00423                                         m.data1.integer=i;
00424                                         sendmsg(&m);
00425                                         if (m.msg==msg_retval) {
00426                                                 sendmsg(msg_funcexec, i);
00427                                                 clearmsg(msg);
00428                                                 return;
00429                                         }
00430                                         break;
00431                                 }
00432                         }
00433                         break;
00434                 }
00435                 case msg_funcexec:
00436                         if (func(msg->data1.integer, 1)) {
00437                                 clearmsg(msg);
00438                                 return;
00439                         }
00440                         break;
00441                 case msg_funcquery: {
00442                         char *s=func(msg->data1.integer, 0);
00443                         if (s) {
00444                                 msg->msg=msg_retval;
00445                                 msg->data1.str=s;
00446                         }
00447                         break;
00448                 }
00449         }
00450         ht_view::handlemsg(msg);
00451 }
00452 
00453 /*
00454  *      CLASS ht_format_viewer
00455  */
00456 
00457 void ht_format_viewer::init(bounds *b, const char *desc, UINT caps, ht_streamfile *f, ht_format_group *fg)
00458 {
00459         ht_viewer::init(b, desc, caps);
00460         options |= VO_FORMAT_VIEW;
00461         VIEW_DEBUG_NAME("ht_format_viewer");
00462         file = f;
00463         format_group = fg;
00464 
00465         last_search_request = NULL;
00466 
00467 /*      vs_history = new ht_stack();
00468         vs_history->init();*/
00469 }
00470 
00471 void ht_format_viewer::done()
00472 {
00473         if (last_search_request) delete last_search_request;
00474 
00475         ht_view::done();
00476 }
00477 
00478 bool ht_format_viewer::pos_to_offset(viewer_pos pos, FILEOFS *ofs)
00479 {
00480         return false;
00481 }
00482 
00483 void ht_format_viewer::clear_viewer_pos(viewer_pos *p)
00484 {
00485 }
00486 
00487 bool ht_format_viewer::compeq_viewer_pos(viewer_pos *a, viewer_pos *b)
00488 {
00489         return false;
00490 }
00491 
00492 bool ht_format_viewer::continue_search()
00493 {
00494         if (last_search_request) {
00495                 ht_search_result *r = NULL;
00496                 if (last_search_physical) {
00497                         FILEOFS o, no;
00498                         if (get_current_offset(&o)) {
00499                                 try {
00500                                         if (last_search_request->search_class==SC_PHYSICAL) {
00501                                                 if (next_logical_offset(o, &no)) {
00502                                                         r=psearch(last_search_request, no, last_search_end_ofs);
00503                                                 }
00504                                         }
00505                                 } catch (ht_exception *e) {
00506                                         errorbox("error: %s", e->what());
00507                                 }
00508                         }
00509                 } else {
00510                         viewer_pos a, na;
00511                         if (get_current_pos(&a)) {
00512                                 try {
00513                                         if (last_search_request->search_class==SC_VISUAL) {
00514                                                 if (next_logical_pos(a, &na)) {
00515                                                         r=vsearch(last_search_request, na, last_search_end_pos);
00516                                                 }
00517                                         }
00518                                 } catch (ht_exception *e) {
00519                                         errorbox("error: %s", e->what());
00520                                 }
00521                         }
00522                 }
00523                 
00524                 if (r) return show_search_result(r);
00525         }
00526         return false;
00527 }
00528 
00529 int ht_format_viewer::func_handler(eval_scalar *result, char *name, eval_scalarlist *params)
00530 {
00531         return 0;
00532 }
00533 
00534 int ht_format_viewer::symbol_handler(eval_scalar *result, char *name)
00535 {
00536         return 0;
00537 }
00538 
00539 bool ht_format_viewer::get_current_offset(FILEOFS *ofs)
00540 {
00541         return false;
00542 }
00543 
00544 bool ht_format_viewer::get_current_pos(viewer_pos *pos)
00545 {
00546         return false;
00547 }
00548 
00549 bool ht_format_viewer::get_current_real_offset(FILEOFS *ofs)
00550 {
00551         return get_current_offset(ofs);
00552 }
00553 
00554 ht_streamfile *ht_format_viewer::get_file()
00555 {
00556         return file;
00557 }
00558 
00559 void ht_format_viewer::get_pindicator_str(char *buf)
00560 {
00561         *buf=0;
00562 }
00563 
00564 bool ht_format_viewer::get_hscrollbar_pos(int *pstart, int *psize)
00565 {
00566         return false;
00567 }
00568 
00569 bool ht_format_viewer::get_vscrollbar_pos(int *pstart, int *psize)
00570 {
00571         return false;
00572 }
00573 
00574 bool ht_format_viewer::goto_offset(FILEOFS ofs, bool save_vstate)
00575 {
00576         return false;
00577 }
00578 
00579 bool ht_format_viewer::goto_pos(viewer_pos pos, bool save_vstate)
00580 {
00581         return false;
00582 }
00583 
00584 void ht_format_viewer::handlemsg(htmsg *msg)
00585 {
00586         switch (msg->msg) {
00587                 case msg_goto_offset: {
00588                         FILEOFS o = (FILEOFS)msg->data1.integer;        // FIXME: int != FILEOFS
00589                         if (goto_offset(o, false)) {
00590                                 clearmsg(msg);
00591                                 return;
00592                         }
00593                         break;
00594                 }
00595                 case msg_vstate_restore:
00596                         vstate_restore((Object*)msg->data1.ptr);
00597                         clearmsg(msg);
00598                         return;
00599                 case cmd_file_truncate: {
00600                         ht_streamfile *f = (ht_streamfile*)msg->data1.ptr;
00601                         FILEOFS o = (FILEOFS)msg->data2.integer;
00602                         if (file == f) {
00603                                 ht_format_loc loc;
00604                                 loc_enum_start();
00605                                 while (loc_enum_next(&loc)) {
00606                                         if (o < loc.start+loc.length) {
00607                                                 if (confirmbox("truncating at %08x will destroy format '%s', continue ? \n(format ranges from %08x to %08x)", o, loc.name, loc.start, loc.start+loc.length) != button_yes) {
00608                                                         clearmsg(msg);
00609                                                         return;
00610                                                 }
00611                                                 break;
00612                                         }
00613                                 }
00614                         }
00615                         break;
00616                 }
00617                 case cmd_edit_mode_i: {
00618                         if (file/* && (file==msg->data1.ptr)*/) {
00619                                 if (file->set_access_mode(FAM_READ | FAM_WRITE)) {
00620                                         htmsg m;
00621                                         m.msg = cmd_edit_mode;
00622                                         m.type = mt_broadcast;
00623                                         sendmsg(&m);
00624                                 } else errorbox("can't open file %s in write mode ! (error %08x)", file->get_filename(), file->get_error());
00625                         }
00626                         clearmsg(msg);
00627                         return;
00628                 }
00629                 case cmd_view_mode_i:
00630                         if (file /*&& (file==msg->data1.ptr)*/) {
00631                                 UINT size = file->get_size();
00632                                 file->cntl(FCNTL_MODS_INVD);
00633                                 if (file->set_access_mode(FAM_READ)) {
00634                                         htmsg m;
00635                                         m.msg = cmd_view_mode;
00636                                         m.type = mt_broadcast;
00637                                         sendmsg(&m);
00638                                 } else errorbox("can't (re)open file %s in read mode ! (error %08x)", file->get_filename(), file->get_error());
00639                                 if (size != file->get_size()) {
00640                                         htmsg m;
00641                                         m.msg = msg_filesize_changed;
00642                                         m.type = mt_broadcast;
00643                                         sendmsg(&m);
00644                                 }
00645                         }
00646                         clearmsg(msg);
00647                         return;
00648         }
00649         ht_viewer::handlemsg(msg);
00650 }
00651 
00652 void ht_format_viewer::loc_enum_start()
00653 {
00654 }
00655 
00656 bool ht_format_viewer::loc_enum_next(ht_format_loc *loc)
00657 {
00658         return false;
00659 }
00660 
00661 bool ht_format_viewer::next_logical_pos(viewer_pos pos, viewer_pos *npos)
00662 {
00663         return false;
00664 }
00665 
00666 bool ht_format_viewer::next_logical_offset(FILEOFS ofs, FILEOFS *nofs)
00667 {
00668         return false;
00669 }
00670 
00671 bool ht_format_viewer::offset_to_pos(FILEOFS ofs, viewer_pos *pos)
00672 {
00673         return false;
00674 }
00675 
00676 bool ht_format_viewer::vstate_save()
00677 {
00678         Object *vs = vstate_create();
00679         if (vs) {
00680                 htmsg m;
00681                 m.msg = msg_vstate_save;
00682                 m.type = mt_empty;
00683                 m.data1.ptr = vs;
00684                 m.data2.ptr = this;
00685                 app->sendmsg(&m);
00686                 return true;
00687         }
00688         return false;
00689 }
00690 
00691 UINT ht_format_viewer::pread(FILEOFS ofs, void *buf, UINT size)
00692 {
00693         if (file->seek(ofs)==0) {
00694                 return file->read(buf, size);
00695         }
00696         return 0;
00697 }
00698 
00699 ht_search_result *ht_format_viewer::psearch(ht_search_request *search, FILEOFS start, FILEOFS end)
00700 {
00701         return 0;
00702 }
00703 
00704 void ht_format_viewer::pselect_add(FILEOFS start, FILEOFS end)
00705 {
00706 }
00707 
00708 void ht_format_viewer::pselect_get(FILEOFS *start, FILEOFS *end)
00709 {
00710 }
00711 
00712 void ht_format_viewer::pselect_set(FILEOFS start, FILEOFS end)
00713 {
00714 }
00715 
00716 UINT ht_format_viewer::pwrite(FILEOFS ofs, void *buf, UINT size)
00717 {
00718         if (file->seek(ofs)==0) {
00719                 sendmsg(msg_file_changed);
00720                 return file->write(buf, size);
00721         }
00722         return 0;
00723 }
00724 
00725 bool ht_format_viewer::qword_to_offset(qword q, FILEOFS *ofs)
00726 {
00727         return false;
00728 }
00729 
00730 bool ht_format_viewer::qword_to_pos(qword q, viewer_pos *pos)
00731 {
00732         return false;
00733 }
00734 
00735 bool ht_format_viewer::show_search_result(ht_search_result *r)
00736 {
00737         switch (r->search_class) {
00738                 case SC_PHYSICAL: {
00739                         ht_physical_search_result *s=(ht_physical_search_result*)r;
00740                         if (!goto_offset(s->offset, this)) return false;
00741                         pselect_set(s->offset, s->offset+s->size);
00742                         return true;
00743                 }
00744                 case SC_VISUAL: {
00745                         ht_visual_search_result *s=(ht_visual_search_result*)r;
00746                         return goto_pos(s->pos, this);
00747                 }
00748         }
00749         return false;
00750 }
00751 
00752 static int format_viewer_func_handler(eval_scalar *result, char *name, eval_scalarlist *params)
00753 {
00754         ht_format_viewer *viewer = (ht_format_viewer*)eval_get_context();
00755         return viewer->func_handler(result, name, params);
00756 }
00757 
00758 static int format_viewer_symbol_handler(eval_scalar *result, char *name)
00759 {
00760         ht_format_viewer *viewer = (ht_format_viewer*)eval_get_context();
00761         return viewer->symbol_handler(result, name);
00762 }
00763 
00764 bool ht_format_viewer::string_to_qword(char *string, qword *q)
00765 {
00766         eval_scalar r;
00767         if (eval(&r, string, format_viewer_func_handler, format_viewer_symbol_handler, this)) {
00768                 eval_int i;
00769                 scalar_context_int(&r, &i);
00770                 scalar_destroy(&r);
00771                 *q = i.value;
00772                 return true;
00773         } else {
00774                 char *s;
00775                 int p;
00776                 get_eval_error(&s, &p);
00777                 ht_snprintf(globalerror, GLOBAL_ERROR_SIZE, "%s at pos %d", s, p);
00778         }
00779         return false;
00780 }
00781 
00782 bool ht_format_viewer::string_to_pos(char *string, viewer_pos *pos)
00783 {
00784         qword q;
00785         if (!string_to_qword(string, &q)) return false;
00786         return qword_to_pos(q, pos);
00787 }
00788 
00789 bool ht_format_viewer::string_to_offset(char *string, FILEOFS *ofs)
00790 {
00791         qword q;
00792         if (!string_to_qword(string, &q)) return false;
00793         return qword_to_offset(q, ofs);
00794 }
00795 
00796 Object *ht_format_viewer::vstate_create()
00797 {
00798         return NULL;
00799 }
00800 
00801 void ht_format_viewer::vstate_restore(Object *view_state)
00802 {
00803 }
00804 
00805 UINT ht_format_viewer::vread(viewer_pos pos, void *buf, UINT size)
00806 {
00807         FILEOFS o;
00808         if (pos_to_offset(pos, &o)) {
00809                 return pread(o, buf, size);
00810         }
00811         return 0;
00812 }
00813 
00814 ht_search_result *ht_format_viewer::vsearch(ht_search_request *search, viewer_pos start, viewer_pos end)
00815 {
00816         return NULL;
00817 }
00818 
00819 void ht_format_viewer::vselect_add(viewer_pos start, viewer_pos end)
00820 {
00821         FILEOFS so, eo;
00822         if (pos_to_offset(start, &so) && pos_to_offset(end, &eo)) {
00823                 return pselect_add(so, eo);
00824         }
00825 }
00826 
00827 void ht_format_viewer::vselect_get(viewer_pos *start, viewer_pos *end)
00828 {
00829         HT_ERROR("NYI!");
00830 }
00831 
00832 void ht_format_viewer::vselect_set(viewer_pos start, viewer_pos end)
00833 {
00834         FILEOFS so, eo;
00835         if (pos_to_offset(start, &so) && pos_to_offset(end, &eo)) {
00836                 return pselect_set(so, eo);
00837         }
00838 }
00839 
00840 UINT ht_format_viewer::vwrite(viewer_pos pos, void *buf, UINT size)
00841 {
00842         FILEOFS o;
00843         if (pos_to_offset(pos, &o)) {
00844                 return pwrite(o, buf, size);
00845         }
00846         return 0;
00847 }
00848 
00849 /*
00850  *      CLASS ht_uformat_view
00851  */
00852 
00853 class ht_uformat_viewer_vstate: public Object {
00854 public:
00855         int edit;
00856         ht_sub *first_sub, *last_sub;
00857 /* top line position */
00858         uformat_viewer_pos top;
00859 /* cursor line and tag position */
00860         uformat_viewer_pos cursor;
00861         int cursor_state;
00862         int cursor_ypos;
00863 /* selection*/
00864         FILEOFS sel_start;
00865         FILEOFS sel_end;
00866 };
00867 
00868 void ht_uformat_viewer::init(bounds *b, const char *desc, int caps, ht_streamfile *file, ht_format_group *format_group)
00869 {
00870         tagpal.data=NULL;
00871         tagpal.size=0;
00872         ht_format_viewer::init(b, desc, caps, file, format_group);
00873         VIEW_DEBUG_NAME("ht_uformat_view");
00874         first_sub=0;
00875         last_sub=0;
00876         clear_viewer_pos(&top);
00877         clear_viewer_pos(&cursor);
00878         xscroll=0;
00879         cursor_ypos=0;
00880         cursor_visual_length=0;
00881         cursor_visual_xpos=0;
00882         cursor_select=0;
00883         cursor_select_start=0xffffffff;
00884         sel_start=0;
00885         sel_end=0;
00886         isdirty_cursor_line=0;
00887 
00888         search_caps=SEARCHMODE_VREGEX;
00889 
00890         uf_initialized=0;
00891 }
00892 
00893 void ht_uformat_viewer::done()
00894 {
00895         edit_end();
00896         clear_subs();
00897         free(tagpal.data);
00898         ht_format_viewer::done();
00899 }
00900 
00901 int ht_uformat_viewer::address_input(const char *title, char *result, int limit, dword histid)
00902 {
00903         bounds b;
00904         app->getbounds(&b);
00905         b.x = (b.w - 60) / 2,
00906         b.y = (b.h - 8) / 2;
00907         b.w = 60;
00908         b.h = 8;
00909 
00910         ht_dialog *dialog=new ht_dialog();
00911         dialog->init(&b, title, FS_KILLER | FS_TITLE | FS_MOVE | FS_RESIZE);
00912 
00913         ht_strinputfield *input;
00914         char *label = "~Address";
00915 
00916         bounds  b2;
00917         b2.x = 3 + strlen(label);
00918         b2.y = 1;
00919         b2.w = b.w - 3 - b2.x;
00920         b2.h = 1;
00921 
00922         ht_clist *hist = 0;
00923         if (histid) hist = (ht_clist*)find_atom(histid);
00924         input = new ht_strinputfield();
00925         input->init(&b2, limit, hist);
00926         ht_inputfield_data d;
00927         d.text = (byte*)result;
00928         d.textlen = strlen((char*)d.text);
00929         input->databuf_set(&d, sizeof d);
00930         dialog->insert(input);
00931 
00932         if (label) {
00933                 b2.x = 1;
00934                 b2.y = 1;
00935                 b2.w = 3 + strlen(label) - b2.x;
00936                 b2.h = 1;
00937 
00938                 ht_label *lab = new ht_label();
00939                 lab->init(&b2, label, input);
00940                 dialog->insert(lab);
00941         }
00942 
00943         b2.x = b.w - 45;
00944         b2.y = b.h - 5;
00945         b2.w = 10;
00946         b2.h = 2;
00947 
00948         ht_button *bok = new ht_button();
00949         bok->init(&b2, "O~k", button_ok);
00950         dialog->insert(bok);
00951 
00952         b2.x += 12;
00953 
00954         ht_button *bcancel = new ht_button();
00955         bcancel->init(&b2, "~Cancel", button_cancel);
00956         dialog->insert(bcancel);
00957 
00958         b2.x += 12;
00959         b2.w = 14;
00960 
00961         ht_button *bhelp = new ht_button();
00962         bhelp->init(&b2, "~Functions", 100);
00963         dialog->insert(bhelp);
00964         
00965         int r;
00966         bool run = true;
00967         int retval = button_cancel;
00968         while (run && (r = dialog->run(0)) != button_cancel) {
00969                 switch (r) {
00970                         case 100: {
00971                                 dialog_eval_help(format_viewer_func_handler, format_viewer_symbol_handler, this);
00972                                 break;
00973                         }
00974                         case button_ok: {
00975                                 int dsize = input->datasize();
00976                                 ht_inputfield_data *data = (ht_inputfield_data*)malloc(dsize);
00977                                 input->databuf_get(data, dsize);
00978                                 bin2str(result, data->text, data->textlen);
00979                                 delete data;
00980                                 if (hist) insert_history_entry(hist, result, 0);
00981                                 run = false;
00982                                 retval = button_ok;
00983                                 break;
00984                         }
00985                 }
00986         }
00987 
00988         dialog->done();
00989         delete dialog;
00990         return retval;
00991 }
00992 
00993 void ht_uformat_viewer::adjust_cursor_group()
00994 {
00995         cursorline_get();
00996         int g=tag_count_groups(cursor_line);
00997         if (cursor.tag_group>=g) cursor.tag_group=0;
00998 }
00999 
01000 void ht_uformat_viewer::adjust_cursor_idx()
01001 {
01002         cursorline_get();
01003         int c = tag_count_selectable_tags_in_group(cursor_line, cursor.tag_group);
01004         if (cursor.tag_idx > c-1) cursor.tag_idx = c-1;
01005 }
01006 
01007 int ht_uformat_viewer::center_view(viewer_pos p)
01008 {
01009         top = p.u;
01010         int r = prev_line(&top, size.h/2);
01011         cursorline_dirty();
01012         return r;
01013 }
01014 
01015 void ht_uformat_viewer::check_cursor_visibility()
01016 {
01017         if (cursor_state != cursor_state_disabled) {
01018                 if ((cursor_ypos < 0) || (cursor_ypos >= size.h)) {
01019                         cursor_state=cursor_state_invisible;
01020                 } else {
01021                         cursor_state=cursor_state_visible;
01022                 }
01023         }
01024 }
01025 
01026 void ht_uformat_viewer::complete_init()
01027 {
01028         if (uf_initialized) return;
01029         cursor_state=cursor_state_disabled;
01030         if (!first_sub) {
01031                 uf_initialized=1;
01032                 return;
01033         }
01034 /*  initialize top_*  */
01035         clear_viewer_pos(&top);
01036         top.sub = first_sub;
01037         top.sub->first_line_id(&top.line_id);
01038 /*  initialize cursor_*  */
01039         cursor_tag_micropos=0;
01040 
01041         uformat_viewer_pos p;
01042         clear_viewer_pos(&p);
01043         p.sub = first_sub;
01044         p.sub->first_line_id(&p.line_id);
01045         char line[1024];        /* FIXME: possible buffer overflow ! */
01046         cursor_ypos--;
01047         do {
01048                 cursor_ypos++;
01049                 if (!p.sub->getline(line, p.line_id)) break;
01050                 if (tag_count_selectable_tags(line)) {
01051                         if (cursor_ypos<size.h) {
01052                                 cursor_state=cursor_state_visible;
01053                         } else {
01054                                 cursor_state=cursor_state_invisible;
01055                                 cursor_ypos=-1;
01056                         }
01057                         break;
01058                 }
01059         } while ((next_line(&p, 1)) && (cursor_ypos<size.h));
01060         p.tag_idx = 0;
01061         p.tag_group = 0;
01062         if (cursor_state == cursor_state_disabled) {
01063                 p.sub = first_sub;
01064                 p.sub->first_line_id(&p.line_id);
01065                 if (p.sub->getline(line, p.line_id)) {
01066                         cursor_ypos = -1;
01067                         cursor_state = cursor_state_invisible;
01068                 }
01069         }
01070         cursor = p;
01071 /* get cursorline */
01072         cursorline_dirty();
01073         cursorline_get();
01074 /* initialize visual */
01075         update_visual_info();
01076 /* initialize misc */
01077         update_misc_info();
01078 
01079         uf_initialized=1;
01080 }
01081 
01082 int ht_uformat_viewer::cursor_left()
01083 {
01084         if (cursor.tag_idx) {
01085                 cursor.tag_idx--;
01086                 update_visual_info();
01087                 update_misc_info();
01088                 return 1;
01089         } else {
01090                 if (cursor_up(1)) {
01091                         cursor_end();
01092                         return 1;
01093                 }
01094         }
01095         return 0;
01096 }
01097 
01098 int ht_uformat_viewer::cursor_right()
01099 {
01100         cursorline_get();
01101         if (cursor.tag_idx < tag_count_selectable_tags_in_group(cursor_line, cursor.tag_group)-1) {
01102                 cursor.tag_idx++;
01103                 update_visual_info();
01104                 update_misc_info();
01105                 return 1;
01106         } else {
01107                 if (cursor_down(1)) {
01108                         cursor_home();
01109                         return 1;
01110                 }
01111         }
01112         return 0;
01113 }
01114 
01115 int ht_uformat_viewer::cursor_up(int n)
01116 {
01117         switch (cursor_state) {
01118                 case cursor_state_invisible:
01119                 case cursor_state_visible: {
01120                         if ((n==1) && (cursor_state==cursor_state_visible)) {
01121                                 int r = 0;
01122                                 uformat_viewer_pos c;
01123                                 clear_viewer_pos(&c);
01124                                 c = cursor;
01125                                 char c_line[1024];
01126                                 int c_ypos=cursor_ypos;
01127                                 int c_tag_idx=cursor.tag_idx;
01128                                 int c_tag_group=cursor.tag_group;
01129                                 int d_tag_group=cursor.tag_group;
01130 
01131                                 while (prev_line(&c, 1) && (c_ypos>=0)) {
01132                                         c_ypos--;
01133                                         c.sub->getline(c_line, c.line_id);
01134                                         int g=tag_count_groups(c_line);
01135                                         if (d_tag_group<g) c_tag_group=d_tag_group;
01136                                         int s;
01137                                         if (c_tag_group>=g) {
01138                                                 c_tag_group=g-1;
01139                                                 s=tag_count_selectable_tags_in_group(c_line, c_tag_group);
01140                                                 if (s) {
01141                                                         c_tag_idx=s-1;
01142                                                         r = 1;
01143                                                         break;
01144                                                 }
01145                                         } else {
01146                                                 s=tag_count_selectable_tags_in_group(c_line, c_tag_group);
01147                                                 if (s) {
01148                                                         if (c_tag_idx>=s) c_tag_idx=s-1;
01149                                                         r = 1;
01150                                                         break;
01151                                                 }
01152                                         }
01153                                 }
01154                                 if (r) {
01155                                         cursor = c;
01156                                         memmove(cursor_line, c_line, sizeof cursor_line);
01157                                         cursorline_dirty();
01158                                         cursor_ypos=c_ypos;
01159                                         cursor.tag_idx=c_tag_idx;
01160                                         cursor.tag_group=c_tag_group;
01161                                         if (cursor_ypos<=-1) scroll_up(-cursor_ypos);
01162                                         update_misc_info();
01163                                         update_visual_info();
01164                                         if (edit()) update_micropos();
01165                                 } else scroll_up(n);
01166                                 return r;
01167                         } else {
01168                                 int r=0;
01169                                 char c_line[1024];
01170                                 int c_tag_idx=cursor.tag_idx;
01171                                 int c_tag_group=cursor.tag_group;
01172                                 int d_tag_group=cursor.tag_group;
01173                                 uformat_viewer_pos c;
01174                                 int c_ypos;
01175                                 if (cursor_state==cursor_state_invisible) {
01176                                         c = top;
01177                                         c_ypos=0;
01178                                 } else {
01179                                         c = cursor;
01180                                         c_ypos=cursor_ypos;
01181                                 }
01182                                 int nc=prev_line(&c, n);
01183                                 c_ypos-=nc;
01184 
01185                                 while (nc--) {
01186                                         c.sub->getline(c_line, c.line_id);
01187                                         int g=tag_count_groups(c_line);
01188                                         if (d_tag_group<g) c_tag_group=d_tag_group;
01189                                         int s;
01190                                         if (c_tag_group>=g) {
01191                                                 c_tag_group=g-1;
01192                                                 s=tag_count_selectable_tags_in_group(c_line, c_tag_group);
01193                                                 if (s) {
01194                                                         c_tag_idx=s-1;
01195                                                         r=1;
01196                                                         break;
01197                                                 }
01198                                         }
01199                                         s=tag_count_selectable_tags_in_group(c_line, c_tag_group);
01200                                         if (s) {
01201                                                 if (c_tag_idx>=s) c_tag_idx=s-1;
01202                                                 r=1;
01203                                                 break;
01204                                         }
01205                                         if (!next_line(&c, 1)) break;
01206                                         c_ypos++;
01207                                 }
01208                                 if (r) {
01209                                         cursor = c;
01210                                         memmove(cursor_line, c_line, sizeof cursor_line);
01211                                         cursorline_dirty();
01212                                         cursor_ypos=c_ypos;
01213                                         cursor.tag_idx=c_tag_idx;
01214                                         cursor.tag_group=c_tag_group;
01215                                         if (-cursor_ypos+n-nc-1>0) scroll_up(-cursor_ypos+n-nc-1);
01216                                         update_misc_info();
01217                                         update_visual_info();
01218                                         if (edit()) update_micropos();
01219                                 } else {
01220                                         if (cursor_state==cursor_state_invisible) cursor_ypos=-0x80000000;
01221                                         scroll_up(n);
01222                                 }
01223                                 // FIXME: wrong value
01224                                 return 1;
01225                         }
01226                 }
01227                 case cursor_state_disabled:
01228 //                      scroll_up(n);
01229 //                      return n;
01230                         break;
01231         }
01232         return 0;
01233 }
01234 
01235 int ht_uformat_viewer::cursor_down(int n)
01236 {
01237         switch (cursor_state) {
01238                 case cursor_state_invisible:
01239                 case cursor_state_visible: {
01240                         if ((n==1) && (cursor_state==cursor_state_visible)) {
01241                                 int r=0;
01242                                 uformat_viewer_pos c;
01243                                 c = cursor;
01244                                 char c_line[1024];
01245                                 int c_ypos=cursor_ypos;
01246                                 int c_tag_idx=cursor.tag_idx;
01247                                 int c_tag_group=cursor.tag_group;
01248                                 int d_tag_group=cursor.tag_group;
01249                                 int nls;        /* controls scrolling beyond end */
01250 
01251                                 while ((nls=next_line(&c, 1)) && (c_ypos<=size.h-1)) {
01252                                         c_ypos++;
01253                                         c.sub->getline(c_line, c.line_id);
01254                                         int g=tag_count_groups(c_line);
01255                                         if (d_tag_group<g) c_tag_group=d_tag_group;
01256                                         int s;
01257                                         if (c_tag_group>=g) {
01258                                                 c_tag_group=g-1;
01259                                                 s=tag_count_selectable_tags_in_group(c_line, c_tag_group);
01260                                                 if (s) {
01261                                                         c_tag_idx=s-1;
01262                                                         r=1;
01263                                                         break;
01264                                                 }
01265                                         }
01266                                         s=tag_count_selectable_tags_in_group(c_line, c_tag_group);
01267                                         if (s) {
01268                                                 if (c_tag_idx>=s) c_tag_idx=s-1;
01269                                                 r=1;
01270                                                 break;
01271                                         }
01272                                 }
01273                                 if (r) {
01274                                         cursor = c;
01275                                         memmove(cursor_line, c_line, sizeof cursor_line);
01276                                         cursorline_dirty();
01277                                         cursor_ypos=c_ypos;
01278                                         cursor.tag_idx=c_tag_idx;
01279                                         cursor.tag_group=c_tag_group;
01280                                         if (cursor_ypos>=size.h) scroll_down(cursor_ypos-size.h+1);
01281                                         update_misc_info();
01282                                         update_visual_info();
01283                                         if (edit()) update_micropos();
01284                                 } else if (nls) scroll_down(1);
01285                                 return r;
01286                         } else {
01287                                 int r=0;
01288                                 char c_line[1024];
01289                                 int c_tag_idx=cursor.tag_idx;
01290                                 int c_tag_group=cursor.tag_group;
01291                                 int d_tag_group=cursor.tag_group;
01292                                 uformat_viewer_pos c;
01293                                 int c_ypos;
01294                                 if (cursor_state==cursor_state_invisible) {
01295                                         c = top;
01296                                         c_ypos = next_line(&c, size.h-1);
01297                                 } else {
01298                                         c = cursor;
01299                                         c_ypos = cursor_ypos;
01300                                 }
01301 
01302                                 int nc=next_line(&c, n);
01303                                 int onc=c_ypos+nc-size.h+1;
01304                                 c_ypos+=nc;
01305 
01306                                 while (nc--) {
01307                                         c.sub->getline(c_line, c.line_id);
01308                                         int g=tag_count_groups(c_line);
01309                                         if (d_tag_group<g) c_tag_group=d_tag_group;
01310                                         int s;
01311                                         if (c_tag_group>=g) {
01312                                                 c_tag_group=g-1;
01313                                                 s=tag_count_selectable_tags_in_group(c_line, c_tag_group);
01314                                                 if (s) {
01315                                                         c_tag_idx=s-1;
01316                                                         r=1;
01317                                                         break;
01318                                                 }
01319                                         } else {
01320                                                 s=tag_count_selectable_tags_in_group(c_line, c_tag_group);
01321                                                 if (s) {
01322                                                         if (c_tag_idx>=s) c_tag_idx=s-1;
01323                                                         r=1;
01324                                                         break;
01325                                                 }
01326                                         }
01327                                         if (nc) if (!prev_line(&c, 1)) break;
01328                                         c_ypos--;
01329                                 }
01330                                 if (r) {
01331                                         cursor = c;
01332                                         memmove(cursor_line, c_line, sizeof cursor_line);
01333                                         cursorline_dirty();
01334                                         cursor_ypos=c_ypos;
01335                                         cursor.tag_idx=c_tag_idx;
01336                                         cursor.tag_group=c_tag_group;
01337                                         if (cursor_ypos-size.h+1>0) scroll_down(cursor_ypos-size.h+1);
01338                                         update_misc_info();
01339                                         update_visual_info();
01340                                         if (edit()) update_micropos();
01341                                 } else if (onc>0) {
01342                                         if (cursor_state==cursor_state_invisible) cursor_ypos=-0x80000000;
01343                                         scroll_down(onc);
01344                                 }
01345                                 // FIXME: wrong value
01346                                 return 1;
01347                         }
01348                 }
01349                 case cursor_state_disabled:
01350 //                      scroll_down(n);
01351 //                      return n;
01352                         break;
01353         }
01354         return 0;
01355 }
01356 
01357 int ht_uformat_viewer::cursor_home()
01358 {
01359         cursor.tag_idx=0;
01360         if (edit()) cursor_tag_micropos=0;
01361         update_visual_info();
01362         update_misc_info();
01363         return 1;
01364 }
01365 
01366 int ht_uformat_viewer::cursor_end()
01367 {
01368         cursorline_get();
01369         int c = tag_count_selectable_tags_in_group(cursor_line, cursor.tag_group);
01370         cursor.tag_idx = c-1;
01371         if (edit()) {
01372                 char *e=tag_get_selectable_tag(cursor_line, cursor.tag_idx, cursor.tag_group);
01373                 if (e) cursor_tag_micropos=tag_get_microsize(e)-1;
01374         }
01375         update_visual_info();
01376         update_misc_info();
01377         return 1;
01378 }
01379 
01380 void ht_uformat_viewer::cursor_tab()
01381 {
01382         cursor.tag_group++;
01383         adjust_cursor_group();
01384 }
01385 
01386 void ht_uformat_viewer::cursorline_dirty()
01387 {
01388         isdirty_cursor_line=1;
01389 }
01390 
01391 void ht_uformat_viewer::cursorline_get()
01392 {
01393         if (isdirty_cursor_line) {
01394                 if (cursor.sub) cursor.sub->getline(cursor_line, cursor.line_id);
01395                 isdirty_cursor_line=0;
01396         }
01397 }
01398 
01399 int ht_uformat_viewer::cursormicroedit_forward()
01400 {
01401         cursorline_get();
01402         uformat_viewer_pos p;
01403         p = top;
01404         p.tag_group = cursor.tag_group;
01405         UINT cursor_tag_bitidx = 0;
01406 
01407         cursorline_get();
01408         char *e=tag_get_selectable_tag(cursor_line, cursor.tag_idx, cursor.tag_group);
01409         if (e) {
01410                 if (((byte*)e)[1] == HT_TAG_EDIT_BIT) {
01411                         cursor_tag_bitidx = ((ht_tag_edit_bit*)e)->bitidx;
01412                 }
01413         }
01414 
01415         bool cursor_found = false;
01416         char c_line[1024];  /* FIXME: possible buffer overflow ! */
01417         for (int y=0; y<size.h+16; y++) {
01418                 if (!p.sub->getline(c_line, p.line_id)) break;
01419                 int c=tag_count_selectable_tags_in_group(c_line, p.tag_group);
01420                 while (p.tag_idx<c) {
01421                         char *t=tag_get_selectable_tag(c_line, p.tag_idx, p.tag_group);
01422                         if (t && (tag_get_class(t)==tag_class_edit)) {
01423                                 if (cursor_found) {
01424                                         cursor_tag_micropos=0;
01425                                         set_cursor(p);
01426                                         cursorline_dirty();
01427                                         update_misc_info();
01428                                         update_visual_info();
01429                                         return 1;
01430                                 } else if (tag_get_offset(t) == cursor_tag_offset) {
01431                                         if ( ( (((byte*)t)[1] == HT_TAG_EDIT_BIT) &&
01432                                         ( ((ht_tag_edit_bit*)t)->bitidx == cursor_tag_bitidx) ) ||
01433                                         (((byte*)t)[1] != HT_TAG_EDIT_BIT)) {
01434                                                 cursor_found = true;
01435                                                 char *t=tag_get_selectable_tag(c_line, p.tag_idx, p.tag_group);
01436                                                 int s=tag_get_microsize(t);
01437                                                 if (cursor_tag_micropos+1 < s) {
01438                                                         cursor_tag_micropos++;
01439                                                         set_cursor(p);
01440                                                         cursorline_dirty();
01441                                                         update_misc_info();
01442                                                         update_visual_info();
01443                                                         return 1;
01444                                                 }
01445                                         }
01446                                 }
01447                         }
01448                         p.tag_idx++;
01449                 }
01450                 p.tag_idx=0;
01451                 if (!next_line(&p, 1)) break;
01452         }
01453         if (cursor_right()) cursor_tag_micropos=0;
01454         return 0;
01455 }
01456 
01457 int ht_uformat_viewer::cursormicro_forward()
01458 {
01459         cursorline_get();
01460         char *t=tag_get_selectable_tag(cursor_line, cursor.tag_idx, cursor.tag_group);
01461         int s=tag_get_microsize(t);
01462         if (cursor_tag_micropos+1>=s) {
01463                 if (cursor_right()) cursor_tag_micropos=0; else return 0;
01464         } else cursor_tag_micropos++;
01465         return 1;
01466 }
01467 
01468 int ht_uformat_viewer::cursormicro_backward()
01469 {
01470         if (cursor_tag_micropos>0) {
01471                 cursor_tag_micropos--;
01472         } else {
01473                 if (cursor_left()) {
01474                         cursorline_get();
01475                         char *t=tag_get_selectable_tag(cursor_line, cursor.tag_idx, cursor.tag_group);
01476                         cursor_tag_micropos=tag_get_microsize(t)-1;
01477                 } else return 0;
01478         }
01479         return 1;
01480 }
01481 
01482 void ht_uformat_viewer::draw()
01483 {
01484         int sdown_count=0;
01485         if (!uf_initialized) HT_ERROR("complete_init() not called !");
01486 restart:
01487         clear(getcolor(palidx_generic_body));
01488         if (!first_sub) return;
01489         uformat_viewer_pos p = top;
01490         uformat_viewer_pos sp;
01491         clear_viewer_pos(&sp);
01492 
01493         char line[1024];        /* FIXME: possible buffer overflow ! */
01494         bool cursor_in_line;
01495         int cursor_found=-1;
01496         if (focused) hidecursor();
01497         if (!p.sub->getline(line, p.line_id)) {
01498                 if (p.sub->closest_line_id(&p.line_id)) {
01499                         top = p;
01500                 } else return;
01501                 if (!p.sub->getline(line, p.line_id)) return;
01502         }
01503         for (int y=0; y<size.h; y++) {
01504                 if (y == cursor_ypos) sp = p;
01505                 if (!p.sub->getline(line, p.line_id)) break;
01506 
01507 /*              char test[128];
01508                 tag_striptags(test+sprintf(test, "%08x,%08x: ", id1, id2), line);
01509                 fprintf(stdout, "%s\n", test);
01510                 fflush(stdout);*/
01511 
01512 // FIXME: revision
01513                 if ((cursor_state == cursor_state_visible) && (p.sub == cursor.sub)
01514                 && compeq_line_id(p.line_id, cursor.line_id)) {
01515                         cursor_found=y;
01516                         cursorline_dirty();
01517                         update_misc_info();
01518                         int c=tag_count_selectable_tags_in_group(line, cursor.tag_group);
01519                         if (cursor.tag_idx>=c) cursor.tag_idx = c-1;
01520                         if ((cursor_tag_class==tag_class_edit) && (edit())) {
01521                                 char *t=tag_get_selectable_tag(line, cursor.tag_idx, cursor.tag_group);
01522                                 int x=cursor_visual_xpos+tag_get_micropos(t, cursor_tag_micropos)-xscroll;
01523                                 if (focused) if (x>=0) setcursor(x, y);
01524                         }
01525                         cursor_in_line = true;
01526                 } else cursor_in_line = false;
01527                 print_tagstring(0, y, size.w, xscroll, line, cursor_in_line);
01528                 if (xscroll>0)  buf_printchar(0, y, VCP(VC_GREEN, VC_TRANSPARENT), '<');
01529                 if (!next_line(&p, 1)) break;
01530         }
01531         if ((cursor_state==cursor_state_visible) && (cursor_found==-1)) {
01532 #if 1
01533                 if (!sp.sub) sp = top;
01534                 cursor = sp;
01535 #else
01536                 top = cursor;
01537 #endif
01538                 cursorline_dirty();
01539                 update_misc_info();
01540                 int c=tag_count_selectable_tags_in_group(line, cursor.tag_group);
01541                 if (cursor.tag_idx>c-1) cursor.tag_idx=c-1;
01542 
01543                 if (sdown_count++ > 0) goto restart;
01544         }
01545         if (cursor_found != -1) cursor_ypos = cursor_found;
01546 //      buf_printf(1, 1, VCP(VC_GREEN, VC_BLACK), "%s", focused ? "focused" : "unfocused");
01547 //      if (cursor_select) printf(20, 1, VCP(VC_GREEN, VC_BLACK), "start=%08x, l=%08x", cursor_select_start, cursor_select_cursor_length);
01548 //      buf_printf(20, 6, 7, "csize.x=%2d, csize.y=%2d, csize.w=%2d, csize.h=%2d", csize.x, csize.y, csize.w, csize.h);
01549 //      buf_printf(2, 3, 7, "size.x=%2d, size.y=%2d, size.w=%2d, size.h=%2d", size.x, size.y, size.w, size.h);
01550 //      buf_printf(2, 4, 7, "vsize.x=%2d, vsize.y=%2d, vsize.w=%2d, vsize.h=%2d", vsize.x, vsize.y, vsize.w, vsize.h);
01551 //      buf_printf(2, 5, 7, "bsize.x=%2d, bsize.y=%2d, bsize.w=%2d, bsize.h=%2d", buf->size.x, buf->size.y, buf->size.w, buf->size.h);
01552 //      buf_printf(20, 7, 7, "size.x=%2d, size.y=%2d, size.w=%2d, size.h=%2d", group->group->size.x, group->group->size.y, group->group->size.w, group->group->size.h);
01553 //      buf_printf(20, 8, 7, "vsize.x=%2d, vsize.y=%2d, vsize.w=%2d, vsize.h=%2d", group->group->vsize.x, group->group->vsize.y, group->group->vsize.w, group->group->vsize.h);
01554 //      buf_printf(0, 7, 7, "vx=%2d, vl=%2d, ypos=%2d", cursor_visual_xpos, cursor_visual_length, cursor_ypos);
01555 //      buf_printf(0, 2, 7, "cursor_micropos=%d", cursor_tag_micropos);
01556 //      buf_printf(0, 2, 7, "%x, %x, %x, %x, %x, c_tagidx", cursor.line_id.id1, cursor.line_id.id2, cursor.line_id.id3, cursor.line_id.id4, cursor.line_id.id5, cursor.tag_idx);
01557 //      buf_printf(0, 3, 7, "(%c)", "vid"[cursor_state]);
01558 //      buf_printf(0, 6, 7, "cursor.tag_idx=%d", cursor.tag_idx);
01559 /*      if (cursor_tag_class==tag_class_edit) {
01560                 buf_printf(30, 7, 7, "class=edit, addr=%08x", cursor_tag_offset);
01561         } else {
01562                 buf_printf(30, 7, 7, "class=sel, id_low=%08x, id_high=%08x", 0,0);
01563         }*/
01564 }
01565 
01566 bool ht_uformat_viewer::edit()
01567 {
01568         return (file && (file->get_access_mode() & FAM_WRITE));
01569 }
01570 
01571 bool ht_uformat_viewer::edit_end()
01572 {
01573         if (!edit()) {
01574                 hidecursor();
01575                 set_cursor(cursor);
01576 #if 0
01577                 uformat_viewer_pos p = cursor;
01578                 if (find_first_tag(&p, size.h)) {
01579                         set_cursor(p);
01580                 } else {
01581 //                      if (cursor_state!=cursor_state_disabled) {
01582 /* is that all we have to do ??? testing needed */
01583 //                              cursor_state=cursor_state_invisible;
01584 //                              assert(0);      /* FIXME: not yet implemented */
01585 //                      }
01586                 }
01587 #endif
01588                 cursorline_dirty();
01589                 adjust_cursor_idx();
01590                 update_visual_info();
01591                 update_misc_info();
01592                 dirtyview();
01593                 return true;
01594         }
01595         return false;
01596 }
01597 
01598 bool ht_uformat_viewer::edit_input(byte b)
01599 {
01600         cursorline_get();
01601         char *t=tag_get_selectable_tag(cursor_line, cursor.tag_idx, cursor.tag_group);
01602         switch (t[1]) {
01603                 case HT_TAG_EDIT_BYTE:
01604                 case HT_TAG_EDIT_WORD_LE:
01605                 case HT_TAG_EDIT_DWORD_LE:
01606                 case HT_TAG_EDIT_QWORD_LE:
01607                 case HT_TAG_EDIT_WORD_BE:
01608                 case HT_TAG_EDIT_DWORD_BE:
01609                 case HT_TAG_EDIT_QWORD_BE: {
01610                         int nibval=edit_input_c2h(b);
01611                         if (nibval==-1) break;
01612                         
01613                         int size=0;
01614                         bool bigendian = true;
01615                         switch (t[1]) {
01616                                 case HT_TAG_EDIT_BYTE: size=1; break;
01617                                 case HT_TAG_EDIT_WORD_LE: size=2; bigendian=false; break;
01618                                 case HT_TAG_EDIT_DWORD_LE: size=4; bigendian=false; break;
01619                                 case HT_TAG_EDIT_QWORD_LE: size=8; bigendian=false; break;
01620                                 case HT_TAG_EDIT_WORD_BE: size=2; bigendian=true; break;
01621                                 case HT_TAG_EDIT_DWORD_BE: size=4; bigendian=true; break;
01622                                 case HT_TAG_EDIT_QWORD_BE: size=8; bigendian=true; break;
01623                         }
01624                         
01625                         int shift=4-(cursor_tag_micropos&1)*4;
01626                         int m=~(0xf<<shift), o=nibval<<shift;
01627 
01628                         int b;
01629                         if (bigendian)  {
01630                                 b=(cursor_tag_micropos)/2;
01631                         } else {
01632                                 b=size-(cursor_tag_micropos)/2-1;
01633                         }
01634                         
01635                         byte buf;
01636                         pread(cursor_tag_offset+b, &buf, 1);
01637                         buf&=m;
01638                         buf|=o;
01639                         pwrite(cursor_tag_offset+b, &buf, 1);
01640                         cursormicroedit_forward();
01641                         return true;
01642                 }
01643                 case HT_TAG_EDIT_CHAR: {
01644                         if ((char)b>=32) {
01645                                 pwrite(cursor_tag_offset, &b, 1);
01646                                 cursormicroedit_forward();
01647                                 return true;
01648                         }
01649                         break;
01650                 }
01651                 case HT_TAG_EDIT_BIT: {
01652                         if ((b=='1') || (b=='0') || b==' ') {
01653                                 byte d;
01654                                 cursorline_get();
01655                                 char *t=tag_get_selectable_tag(cursor_line, cursor.tag_idx, cursor.tag_group);
01656                                 int shift=((ht_tag_edit_bit*)t)->bitidx;
01657                                 dword mask=1 << (shift%8);
01658                                 int op=shift/8;
01659                                 pread(cursor_tag_offset+op, &d, 1);
01660                                 switch (b) {
01661                                         case '0':
01662                                                 d&=~mask;
01663                                                 break;
01664                                         case '1':
01665                                                 d|=mask;
01666                                                 break;
01667                                         case K_Space:
01668                                                 d^=mask;
01669                                                 break;
01670                                 }
01671                                 pwrite(cursor_tag_offset+op, &d, 1);
01672                                 cursormicroedit_forward();
01673                                 return true;
01674                         }
01675                         break;
01676                 }
01677                 case HT_TAG_EDIT_TIME: {
01678                         dword d;
01679                         int h = edit_input_c2d(b);
01680                                         
01681                         byte buf[4];
01682                         if ((pread(cursor_tag_offset, &buf, 4)==4) && (h!=-1)) {
01683                                 d=(buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0];
01684                                 tm *t = gmtime((time_t*)&d);
01685                                 tm q = *t;
01686                                 int k;
01687                                 bool worked = false;
01688 #define DEC_MASK(value, mask) ((value) - (value) / (mask) % 10 * (mask))
01689                                 switch (cursor_tag_micropos) {
01690                                         case 0:
01691                                                 k = q.tm_hour % 10 + h * 10;
01692                                                 if (k < 24) {
01693                                                         q.tm_hour = k;
01694                                                         worked = true;
01695                                                 }
01696                                                 break;
01697                                         case 1:
01698                                                 k = q.tm_hour - q.tm_hour % 10 + h;
01699                                                 if (k < 24) {
01700                                                         q.tm_hour = k;
01701                                                         worked = true;
01702                                                 }
01703                                                 break;
01704                                         case 2:
01705                                                 k = q.tm_min % 10 + h * 10;
01706                                                 if (k < 60) {
01707                                                         q.tm_min = k;
01708                                                         worked = true;
01709                                                 }
01710                                                 break;
01711                                         case 3:
01712                                                 k = q.tm_min - q.tm_min % 10 + h;
01713                                                 if (k < 60) {
01714                                                         q.tm_min = k;
01715                                                         worked = true;
01716                                                 }
01717                                                 break;
01718                                         case 4:
01719                                                 k = q.tm_sec % 10 + h * 10;
01720                                                 if (k < 60) {
01721                                                         q.tm_sec = k;
01722                                                         worked = true;
01723                                                 }
01724                                                 break;
01725                                         case 5:
01726                                                 k = q.tm_sec - q.tm_sec % 10 + h;
01727                                                 if (k < 60) {
01728                                                         q.tm_sec = k;
01729                                                         worked = true;
01730                                                 }
01731                                                 break;
01732                                         case 6:
01733                                                 k = (q.tm_mday % 10) + h * 10;
01734                                                 if (k <= 31) {
01735                                                         q.tm_mday = k;
01736                                                         worked = true;
01737                                                 }
01738                                                 break;
01739                                         case 7:
01740                                                 k = q.tm_mday - q.tm_mday % 10 + h;
01741                                                 if (k <= 31) {
01742                                                         q.tm_mday = k;
01743                                                         worked = true;
01744                                                 }
01745                                                 break;
01746                                         case 8:
01747                                                 k = (q.tm_mon+1) % 10 + h * 10;
01748                                                 if (k <= 12) {
01749                                                         q.tm_mon = k-1;
01750                                                         worked = true;
01751                                                 }
01752                                                 break;
01753                                         case 9:
01754                                                 k = q.tm_mon - q.tm_mon % 10 + h;
01755                                                 if (k <= 12) {
01756                                                         q.tm_mon = k-1;
01757                                                         worked = true;
01758                                                 }
01759                                                 break;
01760                                         case 10:
01761                                                 k = DEC_MASK(q.tm_year, 1000) + h * 1000;
01762                                                 if ((k+1900 >= 1970 ) && (k+1900 < 2106)) {
01763                                                         q.tm_year = k;
01764                                                         worked = true;
01765                                                 }
01766                                                 break;
01767                                         case 11:
01768                                                 k = DEC_MASK(q.tm_year, 100) + h * 100;
01769                                                 if ((k+1900 >= 1970 ) && (k+1900 < 2106)) {
01770                                                         q.tm_year = k;
01771                                                         worked = true;
01772                                                 }
01773                                                 break;
01774                                         case 12:
01775                                                 k = DEC_MASK(q.tm_year, 10) + h * 10;
01776                                                 if ((k+1900 >= 1970 ) && (k+1900 < 2106)) {
01777                                                         q.tm_year = k;
01778                                                         worked = true;
01779                                                 }
01780                                                 break;
01781                                         case 13:
01782                                                 k = DEC_MASK(q.tm_year, 1) + h * 1;
01783                                                 if ((k+1900 >= 1970 ) && (k+1900 < 2106)) {
01784                                                         q.tm_year = k;
01785                                                         worked = true;
01786                                                 }
01787                                                 break;
01788                                 }
01789                                 /* FIXME: big bad hack... */
01790                                 if (sizeof(dword) == sizeof(time_t))
01791                                 if (worked) {
01792                                 /* FIXME: !!! */
01793                                         dword tz;
01794                                         time_t l = time(NULL);
01795                                         time_t g = l;
01796                                         struct tm *gtm = gmtime(&g);
01797                                         g = mktime(gtm);
01798                                         tz = (dword)difftime(g, l);
01799                                         *(time_t*)&d = mktime(&q);
01800                                         d -= tz;
01801                                         buf[0] = d>>0;
01802                                         buf[1] = d>>8;
01803                                         buf[2] = d>>16;
01804                                         buf[3] = d>>24;
01805                                         pwrite(cursor_tag_offset, &buf, 4);
01806                                         cursormicroedit_forward();
01807                                         return true;
01808                                 }
01809                         }
01810                 }
01811         }
01812         return false;
01813 }
01814 
01815 int ht_uformat_viewer::edit_input_c2h(byte b)
01816 {
01817         int h=-1;
01818         if ((b>='0') && (b<='9')) {
01819                 h=b-'0';
01820         } else if ((b>='a') && (b<='f')) {
01821                 h=b-'a'+10;
01822         } else if ((b>='A') && (b<='F')) {
01823                 h=b-'A'+10;
01824         }
01825         return h;
01826 }
01827 
01828 int ht_uformat_viewer::edit_input_c2d(byte b)
01829 {
01830         int h=-1;
01831         if ((b>='0') && (b<='9')) {
01832                 h=b-'0';
01833         }
01834         return h;
01835 }
01836 
01837 void ht_uformat_viewer::edit_input_correctpos()
01838 {
01839         uformat_viewer_pos p = top;
01840 
01841 /* try finding edited tag by its offset */
01842         char c_line[1024];  /* FIXME: possible buffer overflow ! */
01843         int g=cursor.tag_group;
01844         for (int y=0; y<size.h+10; y++) {
01845                 if (!p.sub->getline(c_line, p.line_id)) break;
01846                 int c=tag_count_selectable_tags_in_group(c_line, cursor.tag_group);
01847                 for (int i=0; i<c; i++) {
01848                         char *t=tag_get_selectable_tag(c_line, i, cursor.tag_group);
01849                         if ((tag_get_class(t)==tag_class_edit) && (tag_get_offset(t)==cursor_tag_offset)) {
01850                                 set_cursor(p);
01851                                 cursorline_dirty();
01852                                 cursor.tag_idx=i;
01853                                 cursor.tag_group=g;
01854                                 update_misc_info();
01855                                 update_visual_info();
01856                                 return;
01857                         }
01858                 }
01859                 if (!next_line(&p, 1)) break;
01860         }
01861 
01862 /* try finding edited tag by cursor_ypos */
01863         p = top;
01864         next_line(&p, cursor_ypos);
01865         int ci = cursor.tag_idx;
01866         set_cursor(p);
01867         cursorline_dirty();
01868         cursorline_get();
01869         int x = tag_count_selectable_tags(cursor_line);
01870         if (ci >= x) ci = x-1;
01871         cursor.tag_idx = ci;
01872         update_misc_info();
01873         update_visual_info();
01874 }
01875 
01876 bool ht_uformat_viewer::edit_start()
01877 {
01878         if (edit() && cursor.sub) {
01879                 cursor_tag_micropos=0;
01880                 cursorline_dirty();
01881                 adjust_cursor_idx();
01882                 update_visual_info();
01883                 update_misc_info();
01884                 dirtyview();
01885                 return true;
01886         }
01887         return false;
01888 }
01889 
01890 bool ht_uformat_viewer::edit_update()
01891 {
01892         if (edit()) {
01893                 file->cntl(FCNTL_MODS_FLUSH);
01894                 dirtyview();
01895                 return true;
01896         }
01897         return false;
01898 }
01899 
01900 bool ht_uformat_viewer::find_first_tag(uformat_viewer_pos *p, int limit)
01901 {
01902         char line[1024];        /* FIXME: possible buffer overflow ! */
01903         int i=0;
01904         uformat_viewer_pos q = *p;
01905         if (!q.sub) return false;
01906         do {
01907                 q.sub->getline(line, q.line_id);
01908                 if (tag_get_selectable_tag(line, 0, 0)) {
01909                         *p = q;
01910                         p->tag_idx = 0;
01911                         p->tag_group = 0;
01912                         return true;
01913                 }
01914         } while ((next_line(&q, 1)) && (i++<limit));
01915         return false;
01916 }
01917 
01918 bool ht_uformat_viewer::find_first_edit_tag_with_offset(uformat_viewer_pos *p, int limit, FILEOFS offset)
01919 {
01920         char line[1024];        /* FIXME: possible buffer overflow ! */
01921         int i=0;
01922         uformat_viewer_pos q = *p;
01923         if (!q.sub) return false;
01924         do {
01925                 q.sub->getline(line, q.line_id);
01926                 int c=tag_count_selectable_tags(line);
01927                 char *t=line;
01928                 for (int j=0; j<c; j++) {
01929                         t=tag_get_selectable_tag(t, 0, -1);
01930                         if ((tag_get_class(t)==tag_class_edit) && (tag_get_offset(t)==offset)) {
01931                                 *p = q;
01932                                 p->tag_idx = j;
01933                                 p->tag_group = 0;
01934                                 /* FIXME: what about groups ??? */
01935                                 return true;
01936                         }
01937                         t+=tag_get_len(t);
01938                 }
01939         } while ((next_line(&q, 1)) && (i++<limit));
01940         return false;
01941 }
01942 
01943 void ht_uformat_viewer::focus_cursor()
01944 {
01945 // why ?
01946 /*      if (cursor_state==cursor_state_invisible) {
01947                 center_view(cursor_sub, cursor_id1, cursor_id2);
01948                 cursor_state=cursor_state_visible;
01949         }*/
01950         update_visual_info();
01951         if (cursor_visual_xpos-xscroll <= 1) {
01952                 if (cursor_visual_xpos>=1) xscroll = cursor_visual_xpos-1; else
01953                         xscroll = 0;
01954         } else if (cursor_visual_xpos+cursor_visual_length-xscroll > size.w-1) {
01955                 xscroll = cursor_visual_xpos+cursor_visual_length-size.w+1;
01956         }
01957 }
01958 
01959 char *ht_uformat_viewer::func(UINT i, bool execute)
01960 {
01961         switch (i) {
01962                 case 2:
01963                         if (caps & VC_EDIT) {
01964                                 if (edit()) {
01965                                         if (execute) app->sendmsg(cmd_file_save);
01966 //                                      if (execute) edit_update();
01967                                         return "save";
01968                                 } else {
01969                                         return "~save";
01970                                 }
01971                         }
01972                         break;
01973 /*              case 3:
01974                         if (caps & VC_REPLACE) {
01975                                 if (edit()) {
01976                                         if (execute) sendmsg(cmd_file_replace);
01977                                         return "replace";
01978                                 } else {
01979                                         return "~replace";
01980                                 }
01981                         }
01982                         break;*/
01983                 case 4:
01984                         if (caps & VC_EDIT) {
01985                                 if (edit()) {
01986                                         if (execute) {
01987                                                 UINT size = file->get_size();
01988                                                 bool isdirty = false;
01989                                                 file->cntl(FCNTL_MODS_IS_DIRTY, 0, file->get_size(), &isdirty);
01990                                                 char q[1024];
01991                                                 if (file->get_filename()) {
01992                                                         ht_snprintf(q, sizeof q,
01993                                                                 "file %s has been modified, apply changes ?",
01994                                                                 file->get_filename());
01995                                                 } else {
01996                                                         ht_snprintf(q, sizeof q,
01997                                                                 "untitled file has been modified, apply changes ?");
01998                                                 }
01999                                                 if (isdirty && (confirmbox(q) == button_yes)) {
02000                                                         file->cntl(FCNTL_MODS_FLUSH);
02001                                                 } else {
02002                                                         file->cntl(FCNTL_MODS_INVD);
02003                                                 }
02004                                                 if (size != file->get_size()) {
02005                                                         htmsg m;
02006                                                         m.msg = msg_filesize_changed;
02007                                                         m.type = mt_broadcast;
02008                                                         sendmsg(&m);
02009                                                 }
02010                                                 baseview->sendmsg(cmd_view_mode_i, file, NULL);
02011                                         }
02012                                         return "view";
02013                                 } else {
02014                                         if (execute) baseview->sendmsg(cmd_edit_mode_i, file, NULL);
02015                                         return "edit";
02016                                 }
02017                         }
02018                         break;
02019                 case 5:
02020                         if (caps & VC_GOTO) {
02021                                 if (execute) sendmsg(cmd_file_goto);
02022                                 return "goto";
02023                         }
02024                         break;
02025                 case 7:
02026                         if (caps & VC_SEARCH) {
02027                                 if (execute) sendmsg(cmd_file_search);
02028                                 return "search";
02029                         }
02030                         break;
02031                 case 8:
02032                         if (caps & VC_RESIZE) {
02033                                 if (edit()) {
02034                                         if (execute) sendmsg(cmd_file_resize);
02035                                         return "resize";
02036                                 } else {
02037                                         return "~resize";
02038                                 }
02039                         }
02040                         break;
02041                 case 9: {
02042                         if (execute) {
02043                                 FILEOFS o;
02044                                 if (get_current_real_offset(&o)) {
02045                                         char title[128];
02046                                         ht_snprintf(title, sizeof title, "view offset %08x in...", o);
02047                                         ht_view *v = ((ht_app*)app)->popup_view_list(title);
02048                                         if (v) {
02049                                                 htmsg m;
02050                                                 m.msg = msg_goto_offset;
02051                                                 m.type = mt_empty;
02052                                                 m.data1.integer = o;    // FIXME: int = FILEOFS
02053                                                 v->sendmsg(&m);
02054                                                 if (m.msg == msg_empty) {
02055                                                         vstate_save();
02056                                                         app->focus(v);
02057                                                 } else {
02058                                                         errorbox("offset %08x is not supported/invalid in '%s'", o, v->desc);
02059                                                 }
02060                                         }
02061                                 }
02062                         }
02063                         return "viewin...";
02064                 }
02065         }
02066         return ht_format_viewer::func(i, execute);
02067 }
02068 
02069 vcp ht_uformat_viewer::getcolor_tag(UINT pal_index)
02070 {
02071         return getcolorv(&tagpal, pal_index);
02072 }
02073 
02074 bool ht_uformat_viewer::get_current_offset(FILEOFS *offset)
02075 {
02076         if ((cursor_state!=cursor_state_disabled) && (cursor_tag_class==tag_class_edit)) {
02077                 *offset=cursor_tag_offset;
02078                 return true;
02079         }
02080         return false;
02081 }
02082 
02083 bool ht_uformat_viewer::get_current_pos(viewer_pos *pos)
02084 {
02085         clear_viewer_pos(pos);
02086         pos->u = cursor;
02087         return true;
02088 }
02089 
02090 int ht_uformat_viewer::get_current_tag(char **tag)
02091 {
02092         cursorline_get();
02093         char *e=tag_get_selectable_tag(cursor_line, cursor.tag_idx, cursor.tag_group);
02094         if (e) {
02095                 *tag=e;
02096                 return 1;
02097         }
02098         return 0;
02099 }
02100 
02101 int ht_uformat_viewer::get_current_tag_size(dword *size)
02102 {
02103         if (cursor_tag_class==tag_class_edit) {
02104                 cursorline_get();
02105                 char *e=tag_get_selectable_tag(cursor_line, cursor.tag_idx, cursor.tag_group);
02106                 if (e) {
02107                         *size=tag_get_size(e);
02108                         return 1;
02109                 }
02110         }
02111         return 0;
02112 }
02113 
02114 void ht_uformat_viewer::handlemsg(htmsg *msg)
02115 {
02116         switch (msg->msg) {
02117                 case msg_get_scrollinfo:
02118                         switch (msg->data1.integer) {
02119                                 case gsi_pindicator: {
02120                                         get_pindicator_str((char*)msg->data2.ptr);
02121                                         clearmsg(msg);
02122                                         return;
02123                                 }
02124                                 case gsi_hscrollbar: {
02125                                         gsi_scrollbar_t *p=(gsi_scrollbar_t*)msg->data2.ptr;
02126                                         if (!get_hscrollbar_pos(&p->pstart, &p->psize)) {
02127                                                 p->pstart = 0;
02128                                                 p->psize = 100;
02129                                         }
02130                                         clearmsg(msg);
02131                                         return;
02132                                 }
02133                                 case gsi_vscrollbar: {
02134                                         gsi_scrollbar_t *p=(gsi_scrollbar_t*)msg->data2.ptr;
02135                                         if (!get_vscrollbar_pos(&p->pstart, &p->psize)) {
02136                                                 p->pstart = 0;
02137                                                 p->psize = 100;
02138                                         }
02139                                         clearmsg(msg);
02140                                         return;
02141                                 }
02142                         }
02143                         break;
02144                 case msg_complete_init:
02145                         complete_init();
02146                         clearmsg(msg);
02147                         return;
02148                 case msg_keypressed:
02149                         switch (msg->data1.integer) {
02150                                 case K_Alt_S:
02151                                         if (cursor_select) {
02152                                             select_mode_off();
02153                                         } else {
02154                                             select_mode_on();
02155                                         }
02156                                         clearmsg(msg);
02157                                         dirtyview();
02158                                         return;
02159                                 case K_Up:
02160                                         select_mode_pre();
02161                                         cursor_up(1);
02162                                         select_mode_post(0);
02163                                         clearmsg(msg);
02164                                         dirtyview();
02165                                         return;
02166                                 case K_Down:
02167                                         select_mode_pre();
02168                                         cursor_down(1);
02169                                         select_mode_post(0);
02170                                         clearmsg(msg);
02171                                         dirtyview();
02172                                         return;
02173                                 case K_PageUp:
02174                                         select_mode_pre();
02175                                         cursor_up(size.h);
02176                                         select_mode_post(0);
02177                                         clearmsg(msg);
02178                                         dirtyview();
02179                                         return;
02180                                 case K_PageDown:
02181                                         select_mode_pre();
02182                                         cursor_down(size.h);
02183                                         select_mode_post(0);
02184                                         clearmsg(msg);
02185                                         dirtyview();
02186                                         return;
02187                                 case K_Left:
02188                                         if (cursor_state!=cursor_state_disabled) {
02189                                                 select_mode_pre();
02190                                                 if (edit()) cursormicro_backward(); else cursor_left();
02191                                                 select_mode_post(0);
02192                                                 focus_cursor();
02193                                                 clearmsg(msg);
02194                                                 dirtyview();
02195                                                 return;
02196                                         }
02197                                         break;
02198                                 case K_Right:
02199                                         if (cursor_state!=cursor_state_disabled) {
02200                                                 int r;
02201                                                 select_mode_pre();
02202                                                 if (edit()) r=cursormicro_forward(); else r=cursor_right();
02203                                                 select_mode_post(!r);
02204                                                 focus_cursor();
02205                                                 clearmsg(msg);
02206                                                 dirtyview();
02207                                                 return;
02208                                         }
02209                                         break;
02210                                 case K_Return:
02211                                         switch (cursor_tag_class) {
02212                                                 case tag_class_sel:
02213                                                         ref();
02214                                                         break;
02215                                                 case tag_class_edit:
02216                                                         if (edit()) {
02217                                                                 edit_input(msg->data1.integer);
02218                                                         }
02219                                                         break;
02220                                         }
02221                                         dirtyview();
02222                                         clearmsg(msg);
02223                                         return;
02224                                 case K_Backspace: {
02225                                         FILEOFS f;
02226                                         if (edit() && (cursor_tag_class == tag_class_edit)
02227                                         && get_current_offset(&f)) {
02228                                                 file->cntl(FCNTL_MODS_CLEAR_DIRTY_RANGE, f, 1);
02229                                                 cursor_left();
02230                                                 focus_cursor();
02231                                                 dirtyview();
02232                                                 clearmsg(msg);
02233                                         }                         
02234                                         return;
02235                                 }
02236                                 case K_Tab: {
02237                                         int c=cursor.tag_group;
02238                                         cursor_tab();
02239                                         if (cursor.tag_group!=c) {
02240                                                 focus_cursor();
02241                                                 update_visual_info();
02242                                                 dirtyview();
02243                                                 clearmsg(msg);
02244                                                 return;
02245                                         }
02246                                         break;
02247                                 }
02248                                 case K_Home:
02249                                         if (cursor_state==cursor_state_visible) {
02250                                                 select_mode_pre();
02251                                                 cursor_home();
02252                                                 select_mode_post(0);
02253                                                 focus_cursor();
02254                                                 clearmsg(msg);
02255                                                 dirtyview();
02256                                                 return;
02257                                         }
02258                                         break;
02259                                 case K_End:
02260                                         if (cursor_state==cursor_state_visible) {
02261                                                 select_mode_pre();
02262                                                 cursor_end();
02263                                                 select_mode_post(0);
02264                                                 focus_cursor();
02265                                                 clearmsg(msg);
02266                                                 dirtyview();
02267                                                 return;
02268                                         }
02269                                         break;
02270                                 case K_Control_Left:
02271                                         xscroll-=2;
02272                                         if (xscroll<0) xscroll=0;
02273                                         dirtyview();
02274                                         clearmsg(msg);
02275                                         return;
02276                                 case K_Control_Right:
02277                                         xscroll+=2;
02278                                         dirtyview();
02279                                         clearmsg(msg);
02280                                         return;
02281                                 case K_Control_PageUp: {
02282                                         top.sub = first_sub;
02283                                         if (top.sub) {
02284                                                 vstate_save();
02285                                                 select_mode_pre();
02286                                                 top.sub->first_line_id(&top.line_id);
02287 
02288                                                 uformat_viewer_pos p = top;
02289                                                 p.tag_group = cursor.tag_group;
02290                                                 if (find_first_tag(&p, size.h)) {
02291                                                         set_cursor(p);
02292                                                 } else {
02293                                                         cursor_ypos=0x7fffffff;
02294                                                         update_misc_info();
02295                                                         update_visual_info();
02296                                                         check_cursor_visibility();
02297                                                 }
02298                                                 select_mode_post(0);
02299                                         }
02300                                         clearmsg(msg);
02301                                         dirtyview();
02302                                         return;
02303                                 }
02304                                 case K_Control_PageDown: {
02305                                         top.sub = last_sub;
02306                                         if (top.sub) {
02307                                                 vstate_save();
02308                                                 select_mode_pre();
02309                                                 top.sub->last_line_id(&top.line_id);
02310 
02311                                                 uformat_viewer_pos p = top;
02312                                                 p.tag_group = cursor.tag_group;
02313                                                 if (find_first_tag(&p, 1)) {
02314                                                         set_cursor(p);
02315                                                 } else {
02316                                                         cursor_ypos=0x7fffffff;
02317                                                         update_misc_info();
02318                                                         update_visual_info();
02319                                                         check_cursor_visibility();
02320                                                 }
02321                                                 
02322                                                 cursor_up(size.h);
02323                                                 cursor_down(size.h);
02324                                                 
02325                                                 select_mode_post(0);
02326                                         }
02327                                         clearmsg(msg);
02328                                         dirtyview();
02329                                         return;
02330                                 }
02331                                 case K_Shift_Up: {
02332                                         focus_cursor();
02333                                         FILEOFS s, e;
02334                                         dword ts;
02335                                         if (cursor_tag_class==tag_class_edit)
02336                                                 s=cursor_tag_offset;
02337                                         else
02338                                                 s=(sel_end>sel_start) ? sel_end : 0xffffffff;
02339                                         e=get_current_tag_size(&ts) ? s+ts : 0xffffffff;
02340                                         cursor_up(1);
02341                                         if (s!=0xffffffff) {
02342                                                 if (cursor_tag_class==tag_class_edit) {
02343                                                         pselect_add(s, cursor_tag_offset);
02344                                                 } else if ((cursor_tag_class==tag_class_sel) && (e!=0xffffffff)) {
02345                                                         pselect_add(s, e);
02346                                                 }
02347                                         }
02348                                         clearmsg(msg);
02349                                         dirtyview();
02350                                         return;
02351                                 }
02352                                 case K_Shift_Down: {
02353                                         focus_cursor();
02354                                         FILEOFS s, e;
02355                                         dword ts;
02356                                         if (cursor_tag_class==tag_class_edit)
02357                                                 s=cursor_tag_offset;
02358                                         else
02359                                                 s=(sel_end>sel_start) ? sel_end : 0xffffffff;
02360                                         e=get_current_tag_size(&ts) ? s+ts : 0xffffffff;
02361                                         cursor_down(1);
02362                                         if (s!=0xffffffff) {
02363                                                 if (cursor_tag_class==tag_class_edit) {
02364                                                         pselect_add(s, cursor_tag_offset);
02365                                                 } else if ((cursor_tag_class==tag_class_sel) && (e!=0xffffffff)) {
02366                                                         pselect_add(s, e);
02367                                                 }
02368                                         }
02369                                         clearmsg(msg);
02370                                         dirtyview();
02371                                         return;
02372                                 }
02373                                 case K_Shift_Left: {
02374                                         focus_cursor();
02375                                         FILEOFS s, e;
02376                                         dword ts;
02377                                         if (cursor_tag_class==tag_class_edit)
02378                                                 s=cursor_tag_offset;
02379                                         else
02380                                                 s=(sel_end>sel_start) ? sel_end : 0xffffffff;
02381                                         e=get_current_tag_size(&ts) ? s+ts : 0xffffffff;
02382                                         int r;
02383                                         if (edit()) r=cursormicro_backward(); else r=cursor_left();
02384                                         if ((s!=0xffffffff) & (r)) {
02385                                                 if (cursor_tag_class==tag_class_edit) {
02386                                                         pselect_add(s, cursor_tag_offset);
02387                                                 } else if ((cursor_tag_class==tag_class_sel) && (e!=0xffffffff)) {
02388                                                         pselect_add(s, e);
02389                                                 }
02390                                         }
02391                                         clearmsg(msg);
02392                                         dirtyview();
02393                                         return;
02394                                 }
02395                                 case K_Shift_Right: {
02396                                         focus_cursor();
02397                                         FILEOFS s, e;
02398                                         dword ts;
02399                                         if (cursor_tag_class==tag_class_edit)
02400                                                 s=cursor_tag_offset;
02401                                         else
02402                                                 s=(sel_end>sel_start) ? sel_end : 0xffffffff;
02403                                         e=get_current_tag_size(&ts) ? s+ts : 0xffffffff;
02404                                         int r;
02405                                         if (edit()) r=cursormicro_forward(); else r=cursor_right();
02406                                         if (s!=0xffffffff) {
02407                                                 if (r) {
02408                                                         if (cursor_tag_class==tag_class_edit) {
02409                                                                 pselect_add(s, cursor_tag_offset);
02410                                                         } else if ((cursor_tag_class==tag_class_sel) && (e!=0xffffffff)) {
02411                                                                 pselect_add(s, e);
02412                                                         }
02413                                                 } else {
02414                                                         if ((cursor_tag_class==tag_class_edit) && (sel_end != e)) {
02415                                                                 pselect_add(s, e);
02416                                                         }
02417                                                 }
02418                                         }
02419                                         clearmsg(msg);
02420                                         dirtyview();
02421                                         return;
02422                                 }
02423                                 case K_Shift_PageUp: {
02424                                         focus_cursor();
02425                                         FILEOFS s, e;
02426                                         dword ts;
02427                                         if (cursor_tag_class==tag_class_edit)
02428                                                 s=cursor_tag_offset;
02429                                         else
02430                                                 s=(sel_end>sel_start) ? sel_end : 0xffffffff;
02431                                         e=get_current_tag_size(&ts) ? s+ts : 0xffffffff;
02432                                         cursor_up(size.h);
02433                                         if (s!=0xffffffff) {
02434                                                 if (cursor_tag_class==tag_class_edit) {
02435                                                         pselect_add(s, cursor_tag_offset);
02436                                                 } else if ((cursor_tag_class==tag_class_sel) && (e!=0xffffffff)) {
02437                                                         pselect_add(s, e);
02438                                                 }
02439                                         }
02440                                         clearmsg(msg);
02441                                         dirtyview();
02442                                         return;
02443                                 }
02444                                 case K_Shift_PageDown: {
02445                                         focus_cursor();
02446                                         FILEOFS s, e;
02447                                         dword ts;
02448                                         if (cursor_tag_class==tag_class_edit)
02449                                                 s=cursor_tag_offset;
02450                                         else
02451                                                 s=(sel_end>sel_start) ? sel_end : 0xffffffff;
02452                                         e=get_current_tag_size(&ts) ? s+ts : 0xffffffff;
02453                                         cursor_down(size.h);
02454                                         if (s!=0xffffffff) {
02455                                                 if (cursor_tag_class==tag_class_edit) {
02456                                                         pselect_add(s, cursor_tag_offset);
02457                                                 } else if ((cursor_tag_class==tag_class_sel) && (e!=0xffffffff)) {
02458                                                         pselect_add(s, e);
02459                                                 }
02460                                         }
02461                                         clearmsg(msg);
02462                                         dirtyview();
02463                                         return;
02464                                 }
02465                                 case K_Shift_Home: {
02466                                         focus_cursor();
02467                                         FILEOFS s, e;
02468                                         dword ts;
02469                                         if (cursor_tag_class==tag_class_edit)
02470                                                 s=cursor_tag_offset;
02471                                         else
02472                                                 s=(sel_end>sel_start) ? sel_end : 0xffffffff;
02473                                         e=get_current_tag_size(&ts) ? s+ts : 0xffffffff;
02474                                         int r=cursor_home();
02475                                         if ((s!=0xffffffff) && (r)) {
02476                                                 if (cursor_tag_class==tag_class_edit) {
02477                                                         pselect_add(cursor_tag_offset, s);
02478                                                 } else if ((cursor_tag_class==tag_class_sel) && (e!=0xffffffff)) {
02479                                                         pselect_add(e, s);
02480                                                 }
02481                                         }
02482                                         clearmsg(msg);
02483                                         dirtyview();
02484                                         return;
02485                                 }
02486                                 case K_Shift_End: {
02487                                         focus_cursor();
02488                                         FILEOFS s, e;
02489                                         dword ts;
02490                                         if (cursor_tag_class==tag_class_edit)
02491                                                 s=cursor_tag_offset;
02492                                         else
02493                                                 s=(sel_end>sel_start) ? sel_end : 0xffffffff;
02494                                         e=get_current_tag_size(&ts) ? s+ts : 0xffffffff;
02495                                         int r=cursor_end();
02496                                         if ((s!=0xffffffff) && (r)){
02497                                                 if (cursor_tag_class==tag_class_edit) {
02498                                                         pselect_add(s, cursor_tag_offset);
02499                                                 } else if ((cursor_tag_class==tag_class_sel) && (e!=0xffffffff)) {
02500                                                         pselect_add(s, e);
02501                                                 }
02502                                         }
02503                                         clearmsg(msg);
02504                                         dirtyview();
02505                                         return;
02506                                 }
02507                                 case K_Control_F:
02508                                         if (caps & VC_SEARCH) {
02509                                                 sendmsg(cmd_file_search);
02510                                                 dirtyview();
02511                                                 clearmsg(msg);
02512                                                 return;
02513                                         }
02514                                         break;
02515                                 case K_Control_L:
02516                                 case K_Shift_F7:
02517                                         if (caps & VC_SEARCH) {
02518                                                 if (!continue_search()) {
02519                                                         if (last_search_request) {
02520                                                                 infobox("no further matches");
02521                                                         } else {
02522                                                                 infobox("you must 'search' first !");
02523                                                         }
02524                                                 }
02525                                                 dirtyview();
02526                                                 clearmsg(msg);
02527                                                 return;
02528                                         }
02529                                         break;
02530                                 case K_Alt_C:
02531                                 case K_Control_Insert:
02532                                         sendmsg(cmd_edit_copy);
02533                                         dirtyview();
02534                                         clearmsg(msg);
02535                                         return;
02536                                 case K_Alt_V:
02537                                 case K_Shift_Insert:
02538                                         sendmsg(cmd_edit_paste);
02539                                         dirtyview();
02540                                         clearmsg(msg);
02541                                         return;
02542                                 case K_Escape:
02543                                         if (caps & VC_EDIT) {
02544                                                 baseview->sendmsg(cmd_view_mode_i, file, NULL);
02545                                                 return;
02546                                         }                                               
02547                                         break;
02548                                 default: {
02549                                         if (((dword)msg->data1.integer<=255) && (edit())) {
02550                                                 if (cursor_tag_class==tag_class_edit) {
02551                                                         focus_cursor();
02552                                                         if (edit_input(msg->data1.integer)) {
02553                                                                 dirtyview();
02554                                                                 clearmsg(msg);
02555                                                                 return;
02556                                                         }
02557                                                 }
02558                                         }
02559                                 }
02560                         }
02561                         break;
02562                 case cmd_edit_copy:
02563                         if (sel_end>sel_start) {
02564                                 char dsc[1024];
02565                                 ht_snprintf(dsc, sizeof dsc, "%s::%s", file->get_filename(), desc);
02566                                 clipboard_copy(dsc, file, sel_start, sel_end-sel_start);
02567                         }
02568                         clearmsg(msg);
02569                         return;
02570                 case cmd_edit_paste:
02571                         FILEOFS ofs;
02572                         if (get_current_offset(&ofs)) {
02573                                 baseview->sendmsg(cmd_edit_mode_i, file, NULL);
02574                                 if (file->get_access_mode() & FAM_WRITE) {
02575                                         dword s=clipboard_paste(file, ofs);
02576                                         if (s) {
02577                                                 pselect_set(ofs, ofs+s);
02578                                                 sendmsg(cmd_edit_mode_i);
02579                                         }
02580                                 }
02581                         }
02582                         dirtyview();
02583                         clearmsg(msg);
02584                         return;
02585                 case cmd_edit_mode:
02586                         edit_start();
02587                         dirtyview();
02588                         return;
02589                 case cmd_view_mode:
02590                         edit_end();
02591                         dirtyview();
02592                         return;
02593                 case cmd_file_goto: {
02594                         char addrstr[1024];
02595                         addrstr[0] = 0;
02596                         while (address_input("goto", addrstr, sizeof addrstr, HISTATOM_GOTO) != button_cancel) {
02597                                 if (addrstr[0]) {
02598                                         viewer_pos pos;
02599                                         globalerror[0] = 0;
02600                                         if (string_to_pos(addrstr, &pos) && goto_pos(pos, this)) {
02601                                                 focus_cursor();
02602                                                 break;
02603                                         }
02604                                         if (globalerror[0]) {
02605                                                 infobox("error: %s\nin '%s'", globalerror, addrstr);
02606                                         } else {
02607                                                 infobox("invalid address: '%s'", addrstr);
02608                                         }
02609                                 }
02610                         }
02611                         clearmsg(msg);
02612                         dirtyview();
02613                         return;
02614                 }
02615                 case cmd_file_search: {
02616                         viewer_pos start_pos, end_pos;
02617                         get_current_pos(&start_pos);
02618                         clear_viewer_pos(&end_pos);
02619                         end_pos.u.sub = last_sub;
02620                         end_pos.u.tag_idx = -1;
02621                         last_sub->last_line_id(&end_pos.u.line_id);
02622                         ht_search_request *request = search_dialog(this, search_caps, &start_pos, &end_pos);
02623                         ht_search_result *result = NULL;
02624                         if (request) {
02625                                 switch (request->search_class) {
02626                                         case SC_PHYSICAL: {
02627                                                 try {
02628                                                         FILEOFS start, end;
02629                                                         if (pos_to_offset(start_pos, &start)
02630                                                         && pos_to_offset(end_pos, &end)) {
02631                                                                 result = psearch(request, start, end);
02632                                                         }
02633                                                 } catch (ht_exception *e) {
02634                                                         errorbox("error: %s", e->what());
02635                                                 }
02636                                                 break;
02637                                         }
02638                                         case SC_VISUAL: {
02639                                                 try {
02640                                                         result = vsearch(request, start_pos, end_pos);
02641                                                 } catch (ht_exception *e) {
02642                                                         errorbox("error: %s", e->what());
02643                                                 }
02644                                                 break;
02645                                         }
02646                                 }
02647                                 delete request;
02648                                 if (result) {
02649                                         // FIXME: !!!!!!!!
02650                                         if (!show_search_result(result)) infobox("couldn't display result (internal error)");
02651                                         delete result;
02652                                 } else infobox("not found");
02653                         }
02654                         clearmsg(msg);
02655                         dirtyview();
02656                         return;
02657                 }
02658                 case cmd_file_replace: {
02659                         sendmsg(cmd_edit_mode_i);
02660                         if (edit()) {
02661                                 bool cancel;
02662                                 UINT s = get_file()->get_size();
02663                                 UINT repls = replace_dialog(this, search_caps, &cancel);
02664                                 if (repls) {
02665                                         if (s != get_file()->get_size()) {
02666                                                 sendmsg(msg_filesize_changed);
02667                                         }
02668                                         infobox("%d replacement(s) made", repls);
02669                                 }
02670                         }
02671                         clearmsg(msg);
02672                         dirtyview();
02673                         return;
02674                 }
02675                 case msg_filesize_changed: {
02676                         htmsg m;
02677                         m.msg=msg_filesize_changed;
02678                         m.type=mt_broadcast;
02679                         sendsubmsg(&m);
02680                         break;
02681                 }
02682                 case cmd_file_save: {
02683                         if (edit()) edit_update();
02684                         clearmsg(msg);
02685                         return;
02686                 }
02687                 case cmd_file_resize: {
02688                         FILEOFS o=0;
02689                         if (get_current_offset(&o)) {
02690                                 dword s;
02691                                 get_current_tag_size(&s);
02692                                 o+=s;
02693                         }
02694                         
02695                         UINT s=file->get_size();
02696 
02697                         char buf[32];
02698                         sprintf(buf, "%d", o);
02699                         if (inputbox("resize", "new file size", buf, sizeof buf, 0)==button_ok) {
02700                                 eval_scalar r;
02701                                 if (eval(&r, buf, NULL, NULL, NULL)) {
02702                                         eval_int i;
02703                                         scalar_context_int(&r, &i);
02704                                         scalar_destroy(&r);
02705                                         o=QWORD_GET_INT(i.value);
02706                                         if (o<s) {
02707                                                 /* truncate */
02708                                                 htmsg m;
02709                         
02710                                                 m.msg=cmd_file_truncate;
02711                                                 m.type=mt_broadcast;
02712                                                 m.data1.ptr=file;
02713                                                 m.data2.integer=o;
02714                                                 baseview->sendmsg(&m);
02715 
02716                                                 m.msg=msg_filesize_changed;
02717                                                 m.type=mt_broadcast;
02718                                                 sendsubmsg(&m);
02719                                                 sendmsg(&m);
02720                                         } else if (o>s) {
02721                                                 /* extend */
02722                                                 htmsg m;
02723                         
02724                                                 m.msg=cmd_file_extend;
02725                                                 m.type=mt_broadcast;
02726                                                 m.data1.ptr=file;
02727                                                 m.data2.integer=o;
02728                                                 baseview->sendmsg(&m);
02729 
02730                                                 m.msg=msg_filesize_changed;
02731                                                 m.type=mt_broadcast;
02732                                                 sendsubmsg(&m);
02733                                                 sendmsg(&m);
02734                                         }
02735                                 } else {
02736                                         char *errmsg="?";
02737                                         int errpos=0;
02738                                         get_eval_error(&errmsg, &errpos);
02739                                         errorbox("eval error: %s at %d\n in '%s'", errmsg, errpos, buf);
02740                                 }
02741                                 update_misc_info();
02742                         }
02743 
02744                         clearmsg(msg);
02745                         dirtyview();
02746                         return;
02747                 }
02748                 case cmd_file_blockop: {
02749                         if (sel_end>sel_start) {
02750                                 blockop_dialog(this, sel_start, sel_end);
02751                         } else {
02752                                 FILEOFS o=0;
02753                                 get_current_offset(&o);
02754                                 blockop_dialog(this, o, file->get_size());
02755                         }
02756                         clearmsg(msg);
02757                         dirtyview();
02758                         return;
02759                 }
02760         }
02761         ht_format_viewer::handlemsg(msg);
02762 }
02763 
02764 void ht_uformat_viewer::insertsub(ht_sub *sub)
02765 {
02766         if (last_sub) last_sub->next=sub;
02767         sub->uformat_viewer=this;
02768         sub->prev=last_sub;
02769         last_sub=sub;
02770         if (!first_sub) first_sub=sub;
02771 }
02772 
02773 bool ht_uformat_viewer::goto_offset(FILEOFS offset, bool save_vstate)
02774 {
02775         uformat_viewer_pos p;
02776         p.sub = first_sub;
02777         p.tag_group = cursor.tag_group;
02778         while (p.sub) {
02779                 if (p.sub->convert_ofs_to_id(offset, &p.line_id)) {
02780                         if (save_vstate) vstate_save();
02781                         switch (cursor_state) {
02782                                 case cursor_state_visible: {
02783                                         select_mode_pre();
02784                                         /* FIXME: magic 42 */
02785                                         if (!find_first_edit_tag_with_offset(&p, 42, offset)
02786                                                 && !find_first_tag(&p, size.h)) break;
02787                                         bool r = set_cursor(p);
02788                                         select_mode_post(false);
02789                                         return r;
02790                                 }
02791                                 case cursor_state_invisible:
02792                                         select_mode_pre();
02793                                         p.tag_group = -1;
02794                                         p.tag_idx = -1;
02795                                         bool r = set_cursor(p);
02796                                         select_mode_post(false);
02797                                         return r;
02798                         }
02799                         break;
02800                 }
02801                 p.sub = p.sub->next;
02802         }
02803         return false;
02804 }
02805 
02806 bool ht_uformat_viewer::goto_pos(viewer_pos pos, bool save_vstate)
02807 {
02808         if (save_vstate) vstate_save();
02809         select_mode_pre();
02810         set_cursor(pos.u);
02811         select_mode_post(false);
02812         return true;
02813 }
02814 
02815 bool ht_uformat_viewer::next_logical_pos(viewer_pos pos, viewer_pos *npos)
02816 {
02817         if (next_line(&pos.u, 1) == 1) {
02818                 *npos = pos;
02819                 return true;
02820         }
02821         return false;
02822 }
02823 
02824 bool ht_uformat_viewer::next_logical_offset(FILEOFS ofs, FILEOFS *nofs)
02825 {
02826         *nofs = ofs + 1;
02827         return true;
02828 }
02829 
02830 int ht_uformat_viewer::next_line(uformat_viewer_pos *p, int n)
02831 {
02832         int n0 = n;
02833         while (n) {
02834                 if (n -= p->sub->next_line_id(&p->line_id, n)) {
02835                         if (!p->sub->next) return n0 - n;
02836                         p->sub = p->sub->next;
02837                         p->sub->first_line_id(&p->line_id);
02838                         p->tag_idx = -1;
02839                         n--;
02840                 }
02841         }
02842         return n0 - n;
02843 }
02844 
02845 int ht_uformat_viewer::prev_line(uformat_viewer_pos *p, int n)
02846 {
02847         int n0 = n;
02848         while (n){
02849                 if (n -= p->sub->prev_line_id(&p->line_id, n)) {
02850                         if (!p->sub->prev) return n0 - n;
02851                         p->sub = p->sub->prev;
02852                         p->sub->last_line_id(&p->line_id);
02853                         p->tag_idx = -1;
02854                         n--;
02855                 }
02856         }
02857         return n0 - n;
02858 }
02859 
02860 vcp ht_uformat_viewer::get_tag_color_edit(FILEOFS tag_offset, UINT size, bool atcursoroffset, bool iscursor)
02861 {
02862         vcp tag_color = getcolor_tag(palidx_tags_edit_tag);
02863         bool isdirty = false;
02864         file->cntl(FCNTL_MODS_IS_DIRTY, tag_offset, size, &isdirty);
02865         if (isdirty) tag_color=vcp_mix(tag_color, getcolor_tag(palidx_tags_edit_tag_modified));
02866         if ((tag_offset>=sel_start) && (tag_offset<sel_end)) tag_color=vcp_mix(tag_color, getcolor_tag(palidx_tags_edit_tag_selected));
02867         if (iscursor) {
02868                 int coloridx;
02869                 if (atcursoroffset) {
02870                         if (edit()) {
02871                                 coloridx=palidx_tags_edit_tag_cursor_edit;
02872                         } else {
02873                                 coloridx=palidx_tags_edit_tag_cursor_select;
02874                         }
02875                 } else {
02876                         coloridx=palidx_tags_edit_tag_cursor_unfocused;
02877                 }
02878                 tag_color=vcp_mix(tag_color, getcolor_tag(coloridx));
02879         }
02880         return tag_color;
02881 }
02882 
02883 void ht_uformat_viewer::render_tagstring_desc(char **string, int *length, vcp *tc, char *tag, UINT size, bool bigendian, bool is_cursor)
02884 {
02885         ID id;
02886         vcp tag_color=getcolor_tag(palidx_tags_sel_tag);
02887         if (is_cursor) tag_color=getcolor_tag(palidx_tags_sel_tag_cursor_focused);
02888         *string="?";
02889         *length=1;
02890         *tc=tag_color;
02891         if (tag_get_desc_id(tag, &id)) {
02892                 int_hash *tbl;
02893                 if ((tbl=(int_hash*)find_atom(id))) {
02894                         char *str;
02895                         qword q;
02896                         q.hi = 0;
02897                         q.lo = 0;
02898                         FILEOFS tag_offset=tag_get_offset(tag);
02899                         byte buf[4];
02900                         
02901                         if (pread(tag_offset, buf, size)==size) {
02902                                 switch (size) {
02903                                         case 1:
02904                                                 q.hi = 0;
02905                                                 q.lo = buf[0];
02906                                                 break;
02907                                         case 2:
02908                                                 q.hi = 0;
02909                                                 if (bigendian) {
02910                                                         q.lo = (buf[0]<<8) | buf[1];
02911                                                 } else {
02912                                                         q.lo = (buf[1]<<8) | buf[0];
02913                                                 }
02914                                                 break;
02915                                         case 4:
02916                                                 q.hi = 0;
02917                                                 if (bigendian) {
02918                                                         q.lo = (buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
02919                                                 } else {
02920                                                         q.lo = (buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0];
02921                                                 }
02922                                                 break;
02923                                         case 8:
02924                                                 if (bigendian) {
02925                                                         q.hi = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
02926                                                         q.lo = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
02927                                                 } else {
02928                                                         q.hi = (buf[7] << 24) | (buf[6] << 16) | (buf[5] << 8) | buf[4];
02929                                                         q.lo = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
02930                                                 }
02931                                                 break;
02932                                 }
02933 /* FIXME: qword ? */
02934                                 if ((str=matchhash(q.lo, tbl))) {
02935                                         *string=str;
02936                                         *length=strlen(*string);
02937                                 }
02938                         } else {
02939                                 *string="?";
02940                                 *length=strlen(*string);
02941                         }
02942                 }
02943         }
02944 }
02945 
02946 void ht_uformat_viewer::reloadpalette()
02947 {
02948         ht_format_viewer::reloadpalette();
02949         if (tagpal.data) {
02950             free(tagpal.data);
02951             tagpal.data = NULL;
02952         }           
02953         load_pal(palclasskey_tags, palkey_tags_default, &tagpal);
02954 }
02955 
02956 UINT ht_uformat_viewer::render_tagstring(char *chars, vcp *colors, UINT maxlen, char *tagstring, bool cursor_in_line)
02957 {
02958         char *n=tagstring;
02959         UINT c=0;
02960         int i=0, g=0;
02961         bool is_cursor;
02962         vcp color_normal=getcolor(palidx_generic_body);
02963         do {
02964                 int l=0;
02965                 while (n[l] && n[l]!='\e') { l++; }
02966                 c+=render_tagstring_single(chars, colors, maxlen, c, n, l, color_normal);
02967                 
02968                 n+=l;
02969                 is_cursor=cursor_in_line && (i==cursor.tag_idx);
02970                 if (*n=='\e') {
02971                         FILEOFS tag_offset;
02972                         vcp tag_color;
02973                         char str[64];
02974                         switch (n[1]) {
02975                                 case HT_TAG_EDIT_BYTE: {
02976                                         byte d;
02977                                         
02978                                         tag_offset=tag_get_offset(n);
02979                                         tag_color=get_tag_color_edit(tag_offset, 1, focused && (g==cursor.tag_group), is_cursor);
02980 
02981                                         if (pread(tag_offset, &d, 1)==1) {
02982                                                 mkhexb(str, d);
02983                                         } else {
02984                                                 strcpy(str, "??");
02985                                         }
02986                                         
02987                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, 2, tag_color);
02988                 
02989                                         n+=HT_TAG_EDIT_BYTE_LEN;
02990                                         break;
02991                                 }
02992                                 case HT_TAG_EDIT_WORD_LE: {
02993                                         word d;
02994                                         
02995                                         tag_offset=tag_get_offset(n);
02996                                         tag_color=get_tag_color_edit(tag_offset, 2, (g==cursor.tag_group), is_cursor);
02997                                         
02998                                         byte buf[2];
02999                                         if (pread(tag_offset, &buf, 2)==2) {
03000                                                 /* little endian */
03001                                                 d=(buf[1] << 8) | buf[0];
03002                                                 mkhexw(str, d);
03003                                         } else {
03004                                                 strcpy(str, "????");
03005                                         }
03006                                         
03007                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, 4, tag_color);
03008                                         n+=HT_TAG_EDIT_WORD_LE_LEN;
03009                                         break;
03010                                 }
03011                                 case HT_TAG_EDIT_DWORD_LE: {
03012                                         dword d;
03013                                         
03014                                         tag_offset=tag_get_offset(n);
03015                                         tag_color=get_tag_color_edit(tag_offset, 4, (g==cursor.tag_group), is_cursor);
03016                                         
03017                                         byte buf[4];
03018                                         if (pread(tag_offset, &buf, 4)==4) {
03019                                                 /* little endian */
03020                                                 d=(buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
03021                                                 mkhexd(str, d);
03022                                         } else {
03023                                                 strcpy(str, "????????");
03024                                         }
03025 
03026                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, 8, tag_color);
03027                                         n+=HT_TAG_EDIT_DWORD_LE_LEN;
03028                                         break;
03029                                 }
03030                                 case HT_TAG_EDIT_QWORD_LE: {
03031                                         qword q;
03032                                         
03033                                         tag_offset=tag_get_offset(n);
03034                                         tag_color=get_tag_color_edit(tag_offset, 8, (g==cursor.tag_group), is_cursor);
03035                                         
03036                                         byte buf[8];
03037                                         if (pread(tag_offset, &buf, 8)==8) {
03038                                                 /* little endian */
03039                                                 q.hi = (buf[7] << 24) | (buf[6] << 16) | (buf[5] << 8) | buf[4];
03040                                                 q.lo = (buf[3] << 24) | (buf[2] << 16) | (buf[1] << 8) | buf[0];
03041                                                 mkhexq(str, q);
03042                                         } else {
03043                                                 strcpy(str, "????????????????");
03044                                         }
03045 
03046                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, 16, tag_color);
03047                                         n+=HT_TAG_EDIT_QWORD_LE_LEN;
03048                                         break;
03049                                 }
03050                                 case HT_TAG_EDIT_WORD_BE: {
03051                                         word d;
03052                                         
03053                                         tag_offset=tag_get_offset(n);
03054                                         tag_color=get_tag_color_edit(tag_offset, 2, (g==cursor.tag_group), is_cursor);
03055                                         
03056                                         byte buf[2];
03057                                         if (pread(tag_offset, &buf, 2)==2) {
03058                                                 /* big endian */
03059                                                 d=(buf[0] << 8) | buf[1];
03060                                                 mkhexw(str, d);
03061                                         } else {
03062                                                 strcpy(str, "????");
03063                                         }
03064                                         
03065                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, 4, tag_color);
03066                                         n+=HT_TAG_EDIT_WORD_BE_LEN;
03067                                         break;
03068                                 }
03069                                 case HT_TAG_EDIT_DWORD_BE: {
03070                                         dword d;
03071                                         
03072                                         tag_offset=tag_get_offset(n);
03073                                         tag_color=get_tag_color_edit(tag_offset, 4, (g==cursor.tag_group), is_cursor);
03074                                         
03075                                         byte buf[4];
03076                                         if (pread(tag_offset, &buf, 4)==4) {
03077                                                 /* big endian */
03078                                                 d=(buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
03079                                                 mkhexd(str, d);
03080                                         } else {
03081                                                 strcpy(str, "????????");
03082                                         }
03083                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, 8, tag_color);
03084                                         n+=HT_TAG_EDIT_DWORD_BE_LEN;
03085                                         break;
03086                                 }
03087                                 case HT_TAG_EDIT_QWORD_BE: {
03088                                         qword q;
03089                                         
03090                                         tag_offset=tag_get_offset(n);
03091                                         tag_color=get_tag_color_edit(tag_offset, 8, (g==cursor.tag_group), is_cursor);
03092                                         
03093                                         byte buf[8];
03094                                         if (pread(tag_offset, &buf, 8)==8) {
03095                                                 /* big endian */
03096                                                 q.hi = (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
03097                                                 q.lo = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7];
03098                                                 mkhexq(str, q);
03099                                         } else {
03100                                                 strcpy(str, "????????????????");
03101                                         }
03102                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, 16, tag_color);
03103                                         n+=HT_TAG_EDIT_QWORD_BE_LEN;
03104                                         break;
03105                                 }
03106                                 case HT_TAG_EDIT_TIME: {
03107                                         dword d;
03108                                         
03109                                         tag_offset=tag_get_offset(n);
03110                                         tag_color=get_tag_color_edit(tag_offset, 4, (g==cursor.tag_group), is_cursor);
03111 
03112                                         byte buf[4];
03113                                         if (pread(tag_offset, &buf, 4)==4) {
03114                                                 d=(buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0];
03115                                                 tm *t=gmtime((time_t*)&d);
03116                                                 sprintf(str, "%02d:%02d:%02d %02d.%02d.%04d +1900", t->tm_hour, t->tm_min, t->tm_sec, t->tm_mday, t->tm_mon+1, t->tm_year);
03117                                         } else {
03118                                                 strcpy(str, "?");
03119                                         }
03120                                         
03121                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, strlen(str), tag_color);
03122                                         n+=HT_TAG_EDIT_TIME_LEN;
03123                                         break;
03124                                 }
03125                                 case HT_TAG_EDIT_CHAR: {
03126                                         char d;
03127                                         
03128                                         tag_offset=tag_get_offset(n);
03129                                         tag_color=get_tag_color_edit(tag_offset, 1, (g==cursor.tag_group), is_cursor);
03130                                         
03131                                         if (pread(tag_offset, &d, 1)!=1) {
03132                                                 d='?';
03133                                         }
03134                                         
03135                                         c+=render_tagstring_single(chars, colors, maxlen, c, &d, 1, tag_color);
03136                                         n+=HT_TAG_EDIT_CHAR_LEN;
03137                                         break;
03138                                 }
03139                                 case HT_TAG_EDIT_BIT: {
03140                                         int shift=((ht_tag_edit_bit*)n)->bitidx;
03141                                         int op=shift/8;
03142                                         byte d;
03143 
03144                                         tag_offset=tag_get_offset(n);
03145                                         tag_color=getcolor_tag(palidx_tags_edit_tag);
03146                                         bool isdirty = false;
03147                                         file->cntl(FCNTL_MODS_IS_DIRTY, tag_offset+op, IS_DIRTY_SINGLEBIT | (shift & 7), &isdirty);
03148                                         if (isdirty) tag_color=vcp_mix(tag_color, getcolor_tag(palidx_tags_edit_tag_modified));
03149                                         if ((tag_offset>=sel_start) && (tag_offset<sel_end)) tag_color=vcp_mix(tag_color, getcolor_tag(palidx_tags_edit_tag_selected));
03150                                         if (is_cursor) tag_color=vcp_mix(tag_color, getcolor_tag(edit() ? palidx_tags_edit_tag_cursor_edit : palidx_tags_edit_tag_cursor_select));
03151 
03152                                         if (pread(tag_offset+op, &d, 1)==1) {
03153                                                 str[0]=(d& (1 << (shift%8))) ? '1' : '0';
03154                                                 str[1]=0;
03155                                         } else {
03156                                                 strcpy(str, "?");
03157                                         }
03158                                         
03159                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, 1, tag_color);
03160                                         n+=HT_TAG_EDIT_BIT_LEN;
03161                                         break;
03162                                 }
03163                                 case HT_TAG_EDIT_SELVIS: {
03164                                         tag_offset=tag_get_offset(n);
03165                                         tag_color=getcolor_tag(palidx_tags_edit_tag);
03166 
03167                                         if ((tag_offset>=sel_start) && (tag_offset<sel_end)) tag_color=vcp_mix(tag_color, getcolor_tag(palidx_tags_edit_tag_selected));
03168 
03169                                         c+=render_tagstring_single(chars, colors, maxlen, c, &((ht_tag_edit_selvis*)n)->ch, 1, tag_color);
03170                                         n+=HT_TAG_EDIT_SELVIS_LEN;
03171                                         continue;
03172                                 }
03173                                 case HT_TAG_SEL: {
03174                                         int tag_textlen = tag_get_seltextlen(n);
03175                                         if (is_cursor) {
03176                                                 tag_color = getcolor_tag(
03177                                                         (focused && (g == cursor.tag_group)) ?
03178                                                         palidx_tags_sel_tag_cursor_focused :
03179                                                         palidx_tags_sel_tag_cursor_unfocused
03180                                                 );
03181                                         } else {
03182                                                 tag_color = getcolor_tag(palidx_tags_sel_tag);
03183                                         }
03184                                         n += HT_TAG_SEL_LEN(0);
03185                                         c += render_tagstring_single(chars, colors, maxlen, c, n, tag_textlen, tag_color);
03186                                         n += tag_textlen;
03187                                         break;
03188                                 }
03189                                 case HT_TAG_DESC_BYTE: {
03190                                         char *str;
03191                                         int l;
03192                                         render_tagstring_desc(&str, &l, &tag_color, n, 1, true, is_cursor);
03193                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, l, tag_color);
03194                                         n+=HT_TAG_DESC_BYTE_LEN;
03195                                         break;
03196                                 }
03197                                 case HT_TAG_DESC_WORD_LE: {
03198                                         char *str;
03199                                         int l;
03200                                         render_tagstring_desc(&str, &l, &tag_color, n, 2, false, is_cursor);
03201                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, l, tag_color);
03202                                         n+=HT_TAG_DESC_WORD_LE_LEN;
03203                                         break;
03204                                 }
03205                                 case HT_TAG_DESC_DWORD_LE: {
03206                                         char *str;
03207                                         int l;
03208                                         render_tagstring_desc(&str, &l, &tag_color, n, 4, false, is_cursor);
03209                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, l, tag_color);
03210                                         n+=HT_TAG_DESC_DWORD_LE_LEN;
03211                                         break;
03212                                 }
03213                                 case HT_TAG_DESC_QWORD_LE: {
03214                                         char *str;
03215                                         int l;
03216                                         render_tagstring_desc(&str, &l, &tag_color, n, 8, false, is_cursor);
03217                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, l, tag_color);
03218                                         n+=HT_TAG_DESC_QWORD_LE_LEN;
03219                                         break;
03220                                 }
03221                                 case HT_TAG_DESC_WORD_BE: {
03222                                         char *str;
03223                                         int l;
03224                                         render_tagstring_desc(&str, &l, &tag_color, n, 2, true, is_cursor);
03225                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, l, tag_color);
03226                                         n+=HT_TAG_DESC_WORD_BE_LEN;
03227                                         break;
03228                                 }
03229                                 case HT_TAG_DESC_DWORD_BE: {
03230                                         char *str;
03231                                         int l;
03232                                         render_tagstring_desc(&str, &l, &tag_color, n, 4, true, is_cursor);
03233                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, l, tag_color);
03234                                         n+=HT_TAG_DESC_DWORD_BE_LEN;
03235                                         break;
03236                                 }
03237                                 case HT_TAG_DESC_QWORD_BE: {
03238                                         char *str;
03239                                         int l;
03240                                         render_tagstring_desc(&str, &l, &tag_color, n, 8, true, is_cursor);
03241                                         c+=render_tagstring_single(chars, colors, maxlen, c, str, l, tag_color);
03242                                         n+=HT_TAG_DESC_DWORD_BE_LEN;
03243                                         break;
03244                                 }
03245                                 case HT_TAG_FLAGS:
03246                                         n+=HT_TAG_FLAGS_LEN;
03247                                         tag_color=getcolor_tag(palidx_tags_sel_tag);
03248                                         if (is_cursor) tag_color=getcolor_tag(palidx_tags_sel_tag_cursor_focused);
03249                                         c+=render_tagstring_single(chars, colors, maxlen, c, "details", 7, tag_color);
03250                                         break;
03251                                 case HT_TAG_GROUP:
03252                                         n+=HT_TAG_GROUP_LEN;
03253                                         g++;
03254                                         i=0;
03255                                         continue;
03256                                 case HT_TAG_COLOR:
03257                                         color_normal = tag_get_color(n);
03258                                         if (color_normal == (int)0xffffffff) {
03259                                                 color_normal = getcolor(palidx_generic_body);
03260                                         }
03261                                         n+=HT_TAG_COLOR_LEN;
03262                                         continue;
03263                                 default: {
03264                                         assert(0);
03265                                 }
03266                         }
03267                 }
03268                 i++;
03269         } while (*n);
03270         return c;
03271 }
03272 
03273 UINT ht_uformat_viewer::render_tagstring_single(char *chars, vcp *colors, UINT maxlen, UINT offset, char *text, UINT len, vcp color)
03274 {
03275         if (chars) chars+=offset;
03276         if (colors) colors+=offset;
03277         maxlen-=offset;
03278         UINT l=(len<maxlen) ? len : maxlen, r=0;
03279         while (l--) {
03280                 if (chars) *(chars++)=*(text++);
03281                 if (colors) *(colors++)=color;
03282                 r++;
03283         }
03284         return r;
03285 }
03286 
03287 #define MAX_PRINT_TAGSTRING_LINELENGTH 256
03288 
03289 void ht_uformat_viewer::print_tagstring(int x, int y, int maxlen, int xscroll, char *tagstring, bool cursor_in_line)
03290 {
03291         char text[MAX_PRINT_TAGSTRING_LINELENGTH], *t=text+xscroll;
03292         vcp color[MAX_PRINT_TAGSTRING_LINELENGTH], *c=color+xscroll;
03293         int l=render_tagstring(text, color,
03294                 (maxlen+xscroll+1>MAX_PRINT_TAGSTRING_LINELENGTH) ? MAX_PRINT_TAGSTRING_LINELENGTH
03295                 : maxlen+xscroll+1, tagstring, cursor_in_line);
03296 
03297         if (l>xscroll) {
03298                 l-=xscroll;
03299                 while (l--) {
03300                         if (x>=size.w) {
03301                                 buf_printchar(x-1, y, VCP(VC_GREEN, VC_TRANSPARENT), '>');
03302                                 break;
03303                         }
03304                         buf_printchar(x, y, *c, (unsigned char)*t);
03305                         t++;
03306                         c++;
03307                         x++;
03308                 }
03309         }
03310 }
03311 
03312 void ht_uformat_viewer::select_mode_off()
03313 {
03314         if (cursor_select) {
03315                 cursor_select=0;
03316         }
03317 }
03318 
03319 void ht_uformat_viewer::select_mode_on()
03320 {
03321         if (!cursor_select) {
03322                 cursor_select=1;
03323         }
03324 }
03325 
03326 void ht_uformat_viewer::select_mode_pre()
03327 {
03328         if (cursor_select) {
03329                 if (cursor_tag_class==tag_class_edit)
03330                         cursor_select_start=cursor_tag_offset;
03331                 else
03332                         cursor_select_start=(sel_end>sel_start) ? sel_end : 0xffffffff;
03333                 if (!get_current_tag_size(&cursor_select_cursor_length)) cursor_select_cursor_length=0xffffffff;
03334         }               
03335 }       
03336         
03337 void ht_uformat_viewer::select_mode_post(bool lastpos)
03338 {
03339         if (cursor_select) {
03340                 if (cursor_select_start!=0xffffffff) {
03341                         if (cursor_tag_class==tag_class_edit) {
03342                                 if ((lastpos) && (cursor_select_cursor_length!=0xffffffff)) {
03343                                         FILEOFS s, e;
03344                                         pselect_get(&s, &e);
03345                                         if (e != cursor_tag_offset+cursor_select_cursor_length) {
03346                                                 pselect_add(cursor_select_start, cursor_tag_offset+cursor_select_cursor_length);
03347                                         }
03348                                 } else {
03349                                         pselect_add(cursor_select_start, cursor_tag_offset);
03350                                 }
03351                         } else if ((cursor_tag_class==tag_class_sel) && (cursor_select_cursor_length!=0xffffffff)) {
03352                                 pselect_add(cursor_select_start, cursor_select_start+cursor_select_cursor_length);
03353                         }
03354                 }
03355         }
03356 }
03357 
03358 UINT ht_uformat_viewer::pwrite(FILEOFS ofs, void *buf, UINT size)
03359 {
03360         cursorline_dirty();
03361         return ht_format_viewer::pwrite(ofs, buf, size);
03362 }
03363 
03364 int ht_uformat_viewer::ref()
03365 {
03366         cursorline_get();
03367         char *e=tag_get_selectable_tag(cursor_line, cursor.tag_idx, cursor.tag_group);
03368         if (!e) return 0;
03369         if (tag_get_class(e)==tag_class_sel) {
03370                 if (!cursor.sub->ref(&cursor_tag_id.id)) {
03371                         switch (e[1]) {
03372                                 case HT_TAG_SEL:
03373                                         return ref_sel(&cursor_tag_id.id);
03374                                 case HT_TAG_FLAGS:
03375                                         return ref_flags(((ht_tag_flags*)e)->offset, ((ht_tag_flags*)e)->id);
03376                                 case HT_TAG_DESC_BYTE:
03377                                         return ref_desc(((ht_tag_desc_byte*)e)->id, ((ht_tag_desc_byte*)e)->offset, 1, true);
03378                                 case HT_TAG_DESC_WORD_LE:
03379                                         return ref_desc(((ht_tag_desc_byte*)e)->id, ((ht_tag_desc_byte*)e)->offset, 2, false);
03380                                 case HT_TAG_DESC_DWORD_LE:
03381                                         return ref_desc(((ht_tag_desc_byte*)e)->id, ((ht_tag_desc_byte*)e)->offset, 4, false);
03382                                 case HT_TAG_DESC_QWORD_LE:
03383                                         return ref_desc(((ht_tag_desc_byte*)e)->id, ((ht_tag_desc_byte*)e)->offset, 8, false);
03384                                 case HT_TAG_DESC_WORD_BE:
03385                                         return ref_desc(((ht_tag_desc_byte*)e)->id, ((ht_tag_desc_byte*)e)->offset, 2, true);
03386                                 case HT_TAG_DESC_DWORD_BE:
03387                                         return ref_desc(((ht_tag_desc_byte*)e)->id, ((ht_tag_desc_byte*)e)->offset, 4, true);
03388                                 case HT_TAG_DESC_QWORD_BE:
03389                                         return ref_desc(((ht_tag_desc_byte*)e)->id, ((ht_tag_desc_byte*)e)->offset, 8, true);
03390                         }
03391                 }
03392         }
03393         return 0;
03394 }
03395 
03396 int ht_uformat_viewer::ref_desc(ID id, FILEOFS offset, UINT size, bool bigendian)
03397 {
03398         endianess end = bigendian ? big_endian : little_endian;
03399         int_hash *desc=(int_hash*)find_atom(id);
03400         if (desc) {
03401                 bounds b;
03402                 b.w=60;
03403                 b.h=14;
03404                 b.x=(screen->size.w-b.w)/2;
03405                 b.y=(screen->size.h-b.h)/2;
03406                 ht_dialog *g=new ht_dialog();
03407                 g->init(&b, "desc", FS_KILLER | FS_MOVE);
03408 
03409                 b.x=0;
03410                 b.y=0;
03411                 b.w-=2;
03412                 b.h-=2;
03413                 ht_itext_listbox *l=new ht_itext_listbox();
03414                 l->init(&b, 2, 1);
03415 
03416                 byte buf[4];
03417                 int curpos=0, i=0;
03418                 int d=0;
03419 
03420                 if (pread(offset, buf, size)!=size) return 0;
03421                 
03422                 switch (size) {
03423                         case 1: d=buf[0]; break;
03424                         case 2:
03425                                 if (bigendian) {
03426                                         d=(buf[0]<<8) | buf[1];
03427                                 } else {
03428                                         d=(buf[1]<<8) | buf[0];
03429                                 }
03430                                 break;
03431                         case 4:
03432                                 if (bigendian) {
03433                                         d=(buf[0]<<24) | (buf[1]<<16) | (buf[2]<<8) | buf[3];
03434                                 } else {
03435                                         d=(buf[3]<<24) | (buf[2]<<16) | (buf[1]<<8) | buf[0];
03436                                 }
03437                                 break;
03438                 }
03439 
03440                 int_hash *dsc=desc;
03441                 while (dsc->desc) {
03442                         char buf[32];
03443                         switch (size) {
03444                                 case 1:
03445                                         sprintf(buf, "0x%02x", dsc->value);
03446                                         break;
03447                                 case 2:
03448                                         sprintf(buf, "0x%04x", dsc->value);
03449                                         break;
03450                                 case 4:
03451                                         sprintf(buf, "0x%08x", dsc->value);
03452                                         break;
03453                         }
03454                         if (dsc->value==d) {
03455                                 curpos=i;
03456                         }
03457                         l->insert_str(i, buf, dsc->desc);
03458                         dsc++;
03459                         i++;
03460                 }
03461 
03462                 l->update();
03463                 l->gotoItemByPosition(curpos);
03464 
03465                 g->insert(l);
03466                 g->setpalette(palkey_generic_window_default);
03467 
03468                 if (g->run(false)==button_ok) {
03469                         ht_listbox_data da;
03470                         l->databuf_get(&da, sizeof da);
03471                         int i = l->getID(da.cursor_ptr);
03472                         if (desc[i].value != d) {
03473                                 baseview->sendmsg(cmd_edit_mode_i, file, NULL);
03474                                 if (edit()) {
03475                                         byte buf[4];
03476                                         uint v = desc[i].value;
03477                                         create_foreign_int(buf, v, size, end);
03478                                         pwrite(offset, buf, size);
03479                                         dirtyview();
03480                                 }                                       
03481                         }
03482                 }
03483 
03484                 g->done();
03485                 delete g;
03486                 return 1;
03487         }
03488         return 0;
03489 }
03490 
03491 int ht_uformat_viewer::ref_flags(ID id, FILEOFS offset)
03492 {
03493         ht_tag_flags_s *flags=(ht_tag_flags_s*)find_atom(id), *fl;
03494         if (flags) {
03495                 bounds b;
03496                 b.w=60;
03497                 b.h=14;
03498                 b.x=(screen->size.w-b.w)/2;
03499                 b.y=(screen->size.h-b.h)/2;
03500                 ht_dialog *d=new ht_dialog();
03501                 d->init(&b, (flags->bitidx==-1) ? flags->desc : 0, FS_KILLER | FS_TITLE | FS_MOVE);
03502 
03503                 b.x=0;
03504                 b.y=0;
03505                 b.w-=2;
03506                 b.h-=2;
03507                 ht_uformat_viewer *u=new ht_uformat_viewer();
03508                 u->init(&b, 0, VC_EDIT, file, 0);
03509 
03510                 ht_mask_sub *m=new ht_mask_sub();
03511                 m->init(file, 0);
03512                 char *t, x[256];
03513 
03514                 int width=0;
03515                 fl=flags;
03516                 if (fl->bitidx==-1) fl++;
03517                 do {
03518                         int l=strlen(fl->desc);
03519                         if (l>width) width=l;
03520                         fl++;
03521                 } while (fl->desc);
03522 
03523                 width=MAX(width, 25);
03524                 width++;
03525 
03526                 fl=flags;
03527                 if (fl->bitidx==-1) fl++;
03528                 do {
03529                         t=x;
03530                         int l=strlen(fl->desc);
03531                         memmove(t, fl->desc, l);
03532                         t+=l;
03533                         while (t<x+width) *(t++)=' ';
03534                         t=tag_make_edit_bit(t, offset, fl->bitidx);
03535                         *t=0;
03536                         m->add_mask(x);
03537                         fl++;
03538                 } while (fl->desc);
03539 
03540 
03541                 u->insertsub(m);
03542                 u->sendmsg(msg_complete_init, 0);
03543                 d->insert(u);
03544 
03545                 d->setpalette(palkey_generic_window_default);
03546 
03547                 UINT pmode=file->get_access_mode() & FAM_WRITE;
03548 
03549                 if (d->run(false)==button_ok) u->edit_update();
03550 
03551                 if (pmode != file->get_access_mode() & FAM_WRITE) {
03552                         if (pmode) {
03553                                 baseview->sendmsg(cmd_view_mode_i, file, NULL);
03554                         } else {
03555                                 baseview->sendmsg(cmd_edit_mode_i, file, NULL);
03556                         }
03557                 }
03558 
03559                 d->done();
03560                 delete d;
03561                 return 1;
03562         }
03563         return 0;
03564 }
03565 
03566 int ht_uformat_viewer::ref_sel(LINE_ID *id)
03567 {
03568         return 0;
03569 }
03570 
03571 ht_search_result *ht_uformat_viewer::psearch(ht_search_request *request, FILEOFS start, FILEOFS end)
03572 {
03573         if (request != last_search_request) {
03574                 if (last_search_request) delete last_search_request;
03575                 last_search_request = (ht_search_request*)request->duplicate();
03576         }
03577         last_search_physical = true;
03578         last_search_end_ofs = end;
03579         
03580         ht_sub *sub=first_sub;
03581         while (sub) {
03582                 ht_search_result *r = sub->search(request, start, end);
03583                 if (r) return r;
03584                 sub = sub->next;
03585         }
03586         return NULL;
03587 }
03588 
03589 ht_search_result *ht_uformat_viewer::vsearch(ht_search_request *request, viewer_pos start, viewer_pos end)
03590 {
03591         if (request != last_search_request) {
03592                 if (last_search_request) delete last_search_request;
03593                 last_search_request = (ht_search_request*)request->duplicate();
03594         }
03595         last_search_physical = false;
03596         last_search_end_pos = end;
03597         
03598         if ((request->search_class==SC_VISUAL) && (request->type==ST_REGEX)) {
03599                 if (!cursor.sub) return 0;
03600                 ht_regex_search_request *s=(ht_regex_search_request*)request;
03601 /* build progress indicator */
03602                 bounds b;
03603                 get_std_progress_indicator_metrics(&b);
03604                 ht_progress_indicator *progress_indicator=new ht_progress_indicator();
03605                 progress_indicator->init(&b, "ESC to cancel");
03606                 UINT lines=0;
03607 
03608                 uformat_viewer_pos p = start.u;
03609                 while (p.sub) {
03610                         do {
03611                                 char line[1024];        /* FIXME: possible buffer overflow ! */
03612                                 if (!p.sub->getline(line, p.line_id)) assert(0);
03613                                 char rdrd[256];
03614                                 int c=render_tagstring(rdrd, 0, 256, line, 0);
03615                                 rdrd[c]=0;
03616                                 regmatch_t pos;
03617                                 if (!regexec(&s->rx, rdrd, 1, &pos, 0)) {
03618                                         ht_visual_search_result *r=new ht_visual_search_result();
03619                                         r->pos.u = p;
03620                                         r->xpos = pos.rm_so;
03621                                         r->length = pos.rm_eo-pos.rm_so;
03622                                         progress_indicator->done();
03623                                         delete progress_indicator;
03624 
03625                                         return r;
03626                                 }
03627                                 lines++;
03628                                 if (lines % 500==0) {
03629                                         if (ht_keypressed()) {
03630                                                 if (ht_getkey()==K_Escape) goto leave;
03631                                         }
03632 
03633                                         char text[256];
03634 /*                                      if (highest_va>lowest_va) {
03635                                                 int p=100*((double)(va-lowest_va))/(highest_va-lowest_va);
03636                                                 sprintf(text, "searching for '%s'... %d%% complete (%d lines)", s->rx_str, p, lines);
03637                                         } else*/ {
03638                                                 ht_snprintf(text, sizeof text, "searching for '%s'... %d lines", s->rx_str, lines);
03639                                         }
03640                                         progress_indicator->settext(text);
03641                                         progress_indicator->sendmsg(msg_draw, 0);
03642                                         screen->show();
03643                                 }
03644                         } while (p.sub->next_line_id(&p.line_id, 1));
03645                         p.sub = p.sub->next;
03646                         if (p.sub) p.sub->first_line_id(&p.line_id);
03647                 }
03648 leave:
03649                 progress_indicator->done();
03650                 delete progress_indicator;
03651         }
03652         return NULL;
03653 }
03654 
03655 void ht_uformat_viewer::pselect_add(FILEOFS start, FILEOFS end)
03656 {
03657         bool downward = (start<end);
03658         if (end<start) {
03659                 FILEOFS temp=start;
03660                 start=end;
03661                 end=temp;
03662         }
03663         if ((end==sel_start) && !downward) {
03664                 sel_start=start;
03665         } else if ((start==sel_end) && downward) {
03666                 sel_end=end;
03667         } else if ((end==sel_end) && !downward) {
03668                 sel_end=start;
03669         } else if ((start==sel_start) && downward) {
03670                 sel_start=end;
03671         } else {
03672                 sel_start=start;
03673                 sel_end=end;
03674         }
03675         if (sel_start>sel_end) {
03676                 FILEOFS temp=sel_start;
03677                 sel_start=sel_end;
03678                 sel_end=temp;
03679         }
03680 }
03681 
03682 void ht_uformat_viewer::pselect_get(FILEOFS *start, FILEOFS *end)
03683 {
03684         *start=sel_start;
03685         *end=sel_end;
03686 }
03687 
03688 void ht_uformat_viewer::pselect_set(FILEOFS start, FILEOFS end)
03689 {
03690         sel_start=start;
03691         sel_end=end;
03692 }
03693 
03694 void ht_uformat_viewer::clear_subs()
03695 {
03696         ht_sub *s=first_sub, *t;
03697         while (s) {
03698                 t=s->next;
03699                 s->done();
03700                 delete s;
03701                 s=t;
03702         }
03703 
03704         uf_initialized=false;
03705         cursor_ypos=0;
03706 
03707         clear_viewer_pos(&top);
03708         clear_viewer_pos(&cursor);
03709         first_sub=0;
03710         last_sub=0;
03711 }
03712 
03713 void ht_uformat_viewer::clear_viewer_pos(viewer_pos *p)
03714 {
03715         clear_viewer_pos(&p->u);
03716 }
03717 
03718 void ht_uformat_viewer::clear_viewer_pos(uformat_viewer_pos *p)
03719 {
03720         p->sub = NULL;
03721         clear_line_id(&p->line_id);
03722         p->tag_idx = 0;
03723         p->tag_group = 0;
03724 }
03725 
03726 bool ht_uformat_viewer::compeq_viewer_pos(viewer_pos *a, viewer_pos *b)
03727 {
03728         return compeq_viewer_pos(&a->u, &b->u);
03729 }
03730         
03731 bool ht_uformat_viewer::compeq_viewer_pos(uformat_viewer_pos *a, uformat_viewer_pos *b)
03732 {
03733         return ((a->sub == b->sub)
03734                    && compeq_line_id(a->line_id, b->line_id)
03735                    && (a->tag_idx == b->tag_idx)
03736                    && (a->tag_group == b->tag_group));
03737 }
03738 
03739 void ht_uformat_viewer::sendsubmsg(int msg)
03740 {
03741         htmsg m;
03742         m.msg = msg;
03743         sendsubmsg(&m);
03744 }
03745 
03746 void ht_uformat_viewer::sendsubmsg(htmsg *msg)
03747 {
03748         if (msg->type==mt_broadcast) {
03749                 ht_sub *s=first_sub;
03750                 while (s) {
03751                         s->handlemsg(msg);
03752                         s=s->next;
03753                 }
03754         } else cursor.sub->handlemsg(msg);
03755 }
03756 
03757 bool ht_uformat_viewer::set_cursor(uformat_viewer_pos p)
03758 {
03759         cursorline_dirty();
03760         uformat_viewer_pos t = top;
03761         int ty = 0;
03762 //     bool hasnext = true;
03763 /* test if cursor is already on screen */
03764 //      if (cursor_state == cursor_state_visible) {
03765                 do {
03766 //                      if (compeq_viewer_pos(&t, &p)) {
03767                         if ((t.sub == p.sub) && compeq_line_id(t.line_id, p.line_id)) {
03768                                 cursor = p;
03769                                 if (p.tag_group != -1) cursor.tag_group = p.tag_group;
03770                                 adjust_cursor_group();
03771                                 if (p.tag_idx !=-1) cursor.tag_idx = p.tag_idx;
03772                                 adjust_cursor_idx();
03773                                 cursor_ypos = ty;
03774                                 update_misc_info();
03775                                 update_visual_info();
03776                                 check_cursor_visibility();
03777                                 cursorline_dirty();
03778                                 dirtyview();
03779                                 return true;
03780                         }
03781                 } while ((/*hasnext = */next_line(&t, 1)) && (ty++ < size.h-1));
03782 //      }
03783 
03784 
03785         char line[1024];        /* FIXME: possible buffer overflow ! */
03786         char *e;
03787         p.sub->getline(line, p.line_id);
03788         e = tag_get_selectable_tag(line, 0, 0);
03789         if (!e) return 0;
03790         cursor = p;
03791         if (p.tag_group != -1) cursor.tag_group = p.tag_group;
03792         adjust_cursor_group();
03793         if (p.tag_idx != -1) cursor.tag_idx = p.tag_idx;
03794         adjust_cursor_idx();
03795         cursor_ypos=0;
03796 //      cursor_ypos=center_view(sub, id1, id2);
03797         top = p;
03798         update_misc_info();
03799         update_visual_info();
03800         check_cursor_visibility();
03801         cursorline_dirty();
03802         dirtyview();
03803         return true;
03804 }
03805 
03806 void ht_uformat_viewer::scroll_up(int n)
03807 {
03808         cursor_ypos += prev_line(&top, n);
03809         cursorline_dirty();
03810         check_cursor_visibility();
03811 }
03812 
03813 void ht_uformat_viewer::scroll_down(int n)
03814 {
03815         cursor_ypos -= next_line(&top, n);
03816         cursorline_dirty();
03817         check_cursor_visibility();
03818 }
03819 
03820 bool ht_uformat_viewer::qword_to_offset(qword q, FILEOFS *ofs)
03821 {
03822 // FIXME: not "The Right Thing(tm)"
03823         *ofs = QWORD_GET_INT(q);
03824         return true;
03825 }
03826 
03827 void ht_uformat_viewer::update_micropos()
03828 {
03829         cursorline_get();
03830         char *e=tag_get_selectable_tag(cursor_line, cursor.tag_idx, cursor.tag_group);
03831         if (e) {
03832                 int s=tag_get_microsize(e);
03833                 if (cursor_tag_micropos>=s) cursor_tag_micropos=s-1;
03834         }
03835 }
03836 
03837 void ht_uformat_viewer::update_misc_info()
03838 {
03839         cursorline_get();
03840         char *e=tag_get_selectable_tag(cursor_line, cursor.tag_idx, cursor.tag_group);
03841         if (e) {
03842                 cursor_tag_class=tag_get_class(e);
03843                 switch (cursor_tag_class) {
03844                         case tag_class_edit:
03845                                 cursor_tag_offset=tag_get_offset(e);
03846                                 break;
03847                         case tag_class_sel:
03848                                 clear_line_id(&cursor_tag_id.id);
03849                                 tag_get_id(e, &cursor_tag_id.id.id1, &cursor_tag_id.id.id2, &cursor_tag_id.id.id3, &cursor_tag_id.id.id4);
03850                                 break;
03851                 }
03852         }
03853 }
03854 
03855 void ht_uformat_viewer::update_visual_info()
03856 {
03857         cursorline_get();
03858         char *s, *t=cursor_line;
03859         int v=0, vl=0;
03860         int i=0, g=0;
03861         while ((s=tag_findnext(t))) {
03862                 int cl=tag_get_class(s);
03863                 if (s[1]==HT_TAG_GROUP) {
03864                         i=0;
03865                         g++;
03866                 }
03867                 v+=s-t;
03868                 vl=tag_get_vlen(s);
03869                 if ((i==cursor.tag_idx) && (g==cursor.tag_group) && (cl!=tag_class_no)) break;
03870                 v+=vl;
03871                 t=s+tag_get_len(s);
03872                 if (cl!=tag_class_no) i++;
03873         }
03874 
03875         if (cursor_tag_micropos > vl-1) cursor_tag_micropos = vl ? vl-1 : 0;
03876         cursor_visual_xpos=v;
03877         cursor_visual_length=vl;
03878 }
03879 
03880 void ht_uformat_viewer::update_ypos()
03881 {
03882         uformat_viewer_pos p = top;
03883         int y=0;
03884         while ((next_line(&p, 1)) && (y<size.h)) {
03885                 if (compeq_viewer_pos(&p, &cursor)) {
03886                         cursor_ypos=y;
03887                         break;
03888                 }
03889                 y++;
03890         }
03891 }
03892 
03893 void ht_uformat_viewer::vstate_restore(Object *data)
03894 {
03895         ht_uformat_viewer_vstate *vs = (ht_uformat_viewer_vstate*)data;
03896         first_sub = vs->first_sub;
03897         last_sub = vs->last_sub;
03898 /* top line position */
03899         top = vs->top;
03900 /* cursor line and tag position */
03901         cursor = vs->cursor;
03902         cursor_state = vs->cursor_state;
03903         cursor_ypos = vs->cursor_ypos;
03904 /* selection*/
03905         sel_start = vs->sel_start;
03906         sel_end = vs->sel_end;
03907 
03908         cursorline_dirty();
03909         update_misc_info();
03910         update_visual_info();
03911 }
03912 
03913 Object *ht_uformat_viewer::vstate_create()
03914 {
03915         ht_uformat_viewer_vstate *vs = new ht_uformat_viewer_vstate();
03916         vs->first_sub = first_sub;
03917         vs->last_sub = last_sub;
03918 /* top line position */
03919         vs->top = top;
03920 /* cursor line and tag position */
03921         vs->cursor = cursor;
03922         vs->cursor_state = cursor_state;
03923         vs->cursor_ypos = cursor_ypos;
03924 /* selection*/
03925         vs->sel_start = sel_start;
03926         vs->sel_end = sel_end;
03927 
03928         return vs;
03929 }
03930 
03931 /*
03932  *      CLASS ht_sub
03933  */
03934 
03935 void ht_sub::init(ht_streamfile *f)
03936 {
03937         Object::init();
03938         uformat_viewer=NULL;
03939         prev=NULL;
03940         next=NULL;
03941         file=f;
03942 }
03943 
03944 void ht_sub::done()
03945 {
03946         Object::done();
03947 }
03948 
03949 bool ht_sub::closest_line_id(LINE_ID *line_id)
03950 {
03951         first_line_id(line_id);
03952         return true;
03953 }
03954 
03955 bool ht_sub::convert_ofs_to_id(const FILEOFS offset, LINE_ID *line_id)
03956 {
03957         return false;
03958 }
03959 
03960 bool ht_sub::convert_id_to_ofs(const LINE_ID line_id, FILEOFS *offset)
03961 {
03962         return false;
03963 }
03964 
03965 bool ht_sub::getline(char *line, const LINE_ID line_id)
03966 {
03967         return false;
03968 }
03969 
03970 void ht_sub::handlemsg(htmsg *msg)
03971 {
03972 }
03973 
03974 void ht_sub::first_line_id(LINE_ID *line_id)
03975 {
03976 }
03977 
03978 void ht_sub::last_line_id(LINE_ID *line_id)
03979 {
03980 }
03981 
03982 int ht_sub::prev_line_id(LINE_ID *line_id, int n)
03983 {
03984         return 0;
03985 }
03986 
03987 int ht_sub::next_line_id(LINE_ID *line_id, int n)
03988 {
03989         return 0;
03990 }
03991 
03992 bool ht_sub::ref(LINE_ID *id)
03993 {
03994         return false;
03995 }
03996 
03997 ht_search_result *ht_sub::search(ht_search_request *search, FILEOFS start, FILEOFS end)
03998 {
03999         return NULL;
04000 }
04001 
04002 /*
04003  *      CLASS ht_linear_sub
04004  */
04005 
04006 void ht_linear_sub::init(ht_streamfile *f, FILEOFS ofs, int size)
04007 {
04008         ht_sub::init(f);
04009         fofs=ofs;
04010         fsize=size;
04011 }
04012 
04013 void ht_linear_sub::done()
04014 {
04015         ht_sub::done();
04016 }
04017 
04018 void ht_linear_sub::handlemsg(htmsg *msg)
04019 {
04020         if (msg->msg==msg_filesize_changed) {
04021                 UINT s=file->get_size();
04022                 if (fofs>s) {
04023                         fsize=0;
04024                 } else if (fofs+fsize>s) {
04025                         fsize=s-fofs;
04026                 }
04027                 return;
04028         }
04029 }
04030 
04031 int ht_linear_func_readbyte(eval_scalar *result, eval_int *offset)
04032 {
04033         struct context_t {
04034                 ht_linear_sub *sub;
04035                 ht_format_viewer *fv;
04036                 int i, o;
04037         };
04038         ht_format_viewer *f=((context_t*)eval_get_context())->fv;
04039         byte b;
04040         if (f->pread(QWORD_GET_INT(offset->value), &b, 1)!=1) {
04041                 set_eval_error("i/o error (requested %d, read %d from ofs %08x)", 1, 0, offset->value);
04042                 return 0;
04043         }
04044         scalar_create_int_c(result, b);
04045         return 1;
04046 }
04047 
04048 int ht_linear_func_readstring(eval_scalar *result, eval_int *offset, eval_int *len)
04049 {
04050         struct context_t {
04051                 ht_linear_sub *sub;
04052                 ht_format_viewer *fv;
04053                 int i, o;
04054         };
04055         ht_format_viewer *f=((context_t*)eval_get_context())->fv;
04056 
04057         UINT l=QWORD_GET_INT(len->value);
04058         void *buf=malloc(l);    /* FIXME: may be too slow... */
04059 
04060         if (buf) {
04061                 eval_str s;
04062                 UINT c=f->pread(QWORD_GET_INT(offset->value), buf, l);
04063                 if (c!=l) {
04064                         free(buf);
04065                         set_eval_error("i/o error (requested %d, read %d from ofs %08x)", l, c, offset->value);
04066                         return 0;
04067                 }
04068                 s.value=(char*)buf;
04069                 s.len=l;
04070                 scalar_create_str(result, &s);
04071                 free(buf);
04072                 return 1;
04073         }
04074         set_eval_error("out of memory");
04075         return 0;
04076 }
04077 
04078 int ht_linear_func_entropy(eval_scalar *result, eval_str *buf)
04079 {
04080         scalar_create_int_c(result, calc_entropy2((byte *)buf->value, buf->len));
04081         return 1;
04082 }
04083 
04084 int ht_linear_func_entropy2(eval_scalar *result, eval_str *buf)
04085 {
04086         scalar_create_float_c(result, calc_entropy((byte *)buf->value, buf->len));
04087         return 1;
04088 }
04089 
04090 struct search_expr_eval_context_t {
04091         ht_sub *sub;
04092         ht_format_viewer *fv;
04093         int i, o;
04094 };
04095 
04096 int ht_linear_sub_func_handler(eval_scalar *result, char *name, eval_scalarlist *params)
04097 {
04098         eval_func myfuncs[] = {
04099                 {"entropy", (void*)&ht_linear_func_entropy, {SCALAR_STR}},
04100                 {"entropy2", (void*)&ht_linear_func_entropy2, {SCALAR_STR}},
04101                 {"readbyte", (void*)&ht_linear_func_readbyte, {SCALAR_INT}},
04102                 {"readstring", (void*)&ht_linear_func_readstring, {SCALAR_INT, SCALAR_INT}},
04103                 {NULL}
04104         };
04105         return std_eval_func_handler(result, name, params, myfuncs);
04106 }
04107 
04108 int ht_linear_sub_symbol_handler(eval_scalar *result, char *name)
04109 {
04110         search_expr_eval_context_t *context =
04111                 (search_expr_eval_context_t*)eval_get_context();
04112         if (strcmp(name, "i")==0) {
04113                 scalar_create_int_c(result, context->i);
04114                 return 1;
04115         } else if (strcmp(name, "o")==0) {
04116                 scalar_create_int_c(result, context->o);
04117                 return 1;
04118         } else return 0;
04119 }
04120 
04121 class ht_expr_search_pcontext: public Object {
04122 public:
04123 /* in */
04124         ht_search_request *request;
04125         ht_sub *sub;
04126         ht_format_viewer *fv;
04127         FILEOFS start;
04128         FILEOFS end;
04129         int i;
04130         FILEOFS o;
04131 /* out */
04132         ht_search_result **result;
04133 };
04134 
04135 bool process_search_expr(Object *ctx, ht_text *progress_indicator)
04136 {
04137 #define PROCESS_EXPR_SEARCH_BYTES_PER_CALL      256
04138         ht_expr_search_pcontext *c=(ht_expr_search_pcontext*)ctx;
04139         ht_expr_search_request *s=(ht_expr_search_request*)c->request;
04140 
04141         search_expr_eval_context_t context;
04142         context.sub = c->sub;
04143         context.fv = c->fv;
04144         int w=PROCESS_EXPR_SEARCH_BYTES_PER_CALL;
04145         while (c->o < c->end) {
04146                 eval_scalar r;
04147                 context.i = c->i;
04148                 context.o = c->o;
04149                 if (eval(&r, s->expr, ht_linear_sub_func_handler, ht_linear_sub_symbol_handler, &context)) {
04150                         eval_int i;
04151                         scalar_context_int(&r, &i);
04152                         if (i.value != to_qword(0)) {
04153                                 ht_physical_search_result *r=new ht_physical_search_result();
04154                                 r->offset = c->o;
04155                                 r->size = 1;
04156                                 *c->result = r;
04157                                 return false;
04158                         }
04159                 } else {
04160                         char *str;
04161                         int pos;
04162                         get_eval_error(&str, &pos);
04163                         throw new ht_io_exception("eval error at pos %d: %s", pos, str);
04164                 }
04165                 c->i++;
04166                 c->o++;
04167                 
04168                 if (!--w) {
04169                         char text[64];
04170                         if (c->end > c->start) {
04171                                 sprintf(text, "%d %% done", (c->o - c->start) * 100 / (c->end - c->start));
04172                         } else {
04173                                 strcpy(text, "? % done");
04174                         }
04175                         progress_indicator->settext(text);
04176         
04177                         return true;
04178                 }
04179         }
04180         return false;
04181 }
04182 
04183 ht_search_result *linear_expr_search(ht_search_request *search, FILEOFS start, FILEOFS end, ht_sub *sub, ht_uformat_viewer *ufv, FILEOFS fofs, dword fsize)
04184 {
04185         if (start<fofs) start=fofs;
04186         if (end>fofs+fsize) end=fofs+fsize;
04187         if (fsize) {
04188                 ht_search_result *r=NULL;
04189                 ht_expr_search_pcontext c;
04190                 c.request=search;
04191                 c.sub=sub;
04192                 c.fv=ufv;
04193                 c.start=start;
04194                 c.end=end;
04195                 c.result=&r;
04196                 c.i=0;
04197                 c.o=start;
04198                 if (execute_process(process_search_expr, &c)) return r;
04199         }
04200         return NULL;
04201 }
04202 
04203 ht_search_result *ht_linear_sub::search(ht_search_request *search, FILEOFS start, FILEOFS end)
04204 {
04205         ht_search_result *r = NULL;
04206         if ((search->search_class==SC_PHYSICAL) && (search->type==ST_EXPR)) {
04207                 r = linear_expr_search(search, start, end, this, uformat_viewer, fofs, fsize);
04208         } else if ((search->search_class==SC_PHYSICAL) && (search->type==ST_FXBIN)) {
04209                 r = linear_bin_search(search, start, end, file, fofs, fsize);
04210         }
04211         return r;
04212 }
04213 
04214 /*
04215  *      CLASS ht_hex_sub
04216  */
04217 
04218 void ht_hex_sub::init(ht_streamfile *f, FILEOFS ofs, dword size, UINT Line_length, UINT u, dword vinc)
04219 {
04220         line_length = Line_length;
04221         ht_linear_sub::init(f, ofs, size);
04222         vaddrinc=vinc;
04223         balign=ofs % line_length;
04224         uid=u;
04225 }
04226 
04227 void ht_hex_sub::done()
04228 {
04229         ht_linear_sub::done();
04230 }
04231 
04232 int     ht_hex_sub::get_line_length()
04233 {
04234         return line_length;
04235 }
04236 
04237 void    ht_hex_sub::set_line_length(int Line_length)
04238 {
04239         if (Line_length>0) {
04240                 line_length = Line_length;
04241 //              dirty_view();
04242 //              redraw();
04243         }
04244 }
04245 
04246 
04247 bool ht_hex_sub::convert_ofs_to_id(const FILEOFS offset, LINE_ID *line_id)
04248 {
04249         if ((offset>=fofs) && (offset<fofs+fsize)) {
04250                 clear_line_id(line_id);
04251                 line_id->id1 = (offset - (offset%line_length)) + balign;
04252                 line_id->id2 = uid;
04253                 return true;
04254         }
04255         return false;
04256 }
04257 
04258 bool ht_hex_sub::convert_id_to_ofs(const LINE_ID line_id, FILEOFS *ofs)
04259 {
04260         *ofs = line_id.id1;
04261         return true;
04262 }
04263 
04264 bool ht_hex_sub::getline(char *line, const LINE_ID line_id)
04265 {
04266         if (line_id.id2 != uid) return false;
04267         ID ofs = line_id.id1;
04268         uint c = MIN(line_length, (fofs+fsize-ofs));
04269         if (c<=0) return false;
04270         c = MIN(line_length, c+ofs%line_length);
04271         char *l=line;
04272         l=mkhexd(l, ofs+vaddrinc);
04273         *l++=' ';
04274         if (ofs % line_length) ofs -= ofs % line_length;
04275         for (dword i=0; i<line_length; i++) {
04276                 if (i<c && ofs+i>=fofs) {
04277                         l=tag_make_edit_byte(l, ofs+i);
04278                 } else {
04279                         *l++=' ';
04280                         *l++=' ';
04281                 }
04282                 if (i+1<c && ofs+i>=fofs) {
04283                         if (i%8==7) {
04284                                 l=tag_make_edit_selvis(l, ofs+i, '-');
04285                         } else {
04286                                 l=tag_make_edit_selvis(l, ofs+i, ' ');
04287                         }
04288                 } else *l++=' ';
04289         }
04290         l=tag_make_group(l);
04291         *l++='|';
04292         for (dword i=0; i<line_length; i++) {
04293                 if (i<c && ofs+i>=fofs) {
04294                         l=tag_make_edit_char(l, ofs+i);
04295                 } else {
04296                         *l++=' ';
04297                 }
04298         }
04299         *l++='|';
04300         *l=0;
04301         return true;
04302 }
04303 
04304 void ht_hex_sub::handlemsg(htmsg *msg)
04305 {
04306         ht_linear_sub::handlemsg(msg);
04307 }
04308 
04309 void ht_hex_sub::first_line_id(LINE_ID *line_id)
04310 {
04311         clear_line_id(line_id);
04312         line_id->id1 = fofs;
04313         line_id->id2 = uid;
04314 }
04315 
04316 void ht_hex_sub::last_line_id(LINE_ID *line_id)
04317 {
04318         clear_line_id(line_id);
04319         if (fsize) {
04320                 int k = fsize + (fofs % line_length);
04321                 line_id->id1 = (k - k%line_length) + (fofs - fofs%line_length);
04322         } else {
04323                 line_id->id1 = fofs;
04324         }
04325         line_id->id2 = uid;
04326 }
04327 
04328 int ht_hex_sub::prev_line_id(LINE_ID *line_id, int n)
04329 {
04330         if (line_id->id2 != uid) return 0;
04331         int c=0;
04332         while (n--) {
04333                 if (!line_id->id1 || line_id->id1 == fofs) break;
04334                 if (line_id->id1-line_length>line_id->id1) {
04335                         line_id->id1 = 0;
04336                 } else {
04337                         if (line_id->id1-line_length<fofs) {
04338                                 line_id->id1 = fofs;
04339                         } else {
04340                                 line_id->id1 -= line_length;
04341                         }
04342                 }
04343                 c++;
04344         }
04345         return c;
04346 }
04347 
04348 int ht_hex_sub::next_line_id(LINE_ID *line_id, int n)
04349 {
04350         if (line_id->id2 != uid) return 0;
04351         int c=0;
04352         while (n--) {
04353                 if (line_id->id1 % line_length) {
04354                         if (line_id->id1+(line_length - line_id->id1 % line_length) >= fofs+fsize) break;
04355                         line_id->id1 += line_length- line_id->id1 % line_length;
04356                 } else {
04357                         if (line_id->id1+line_length>=fofs+fsize) break;
04358                         line_id->id1 += line_length;
04359                 }
04360                 c++;
04361         }
04362         return c;
04363 }
04364 
04365 /*
04366  *      CLASS ht_mask
04367  */
04368 
04369 void ht_mask_sub::init(ht_streamfile *f, UINT u)
04370 {
04371         ht_sub::init(f);
04372         masks = new ht_string_list();
04373         masks->init();
04374         uid = u;
04375 }
04376 
04377 void ht_mask_sub::done()
04378 {
04379         masks->destroy();
04380         delete masks;
04381         ht_sub::done();
04382 }
04383 
04384 void ht_mask_sub::first_line_id(LINE_ID *line_id)
04385 {
04386         clear_line_id(line_id);
04387         line_id->id1 = 0;
04388         line_id->id2 = uid;
04389 }
04390 
04391 bool ht_mask_sub::getline(char *line, const LINE_ID line_id)
04392 {
04393         if (line_id.id2 != uid) return false;
04394         char *s=masks->get_string(line_id.id1);
04395         if (s) {
04396                 tag_strcpy(line, s);
04397                 return true;
04398         }
04399         return false;
04400 }
04401 
04402 void ht_mask_sub::last_line_id(LINE_ID *line_id)
04403 {
04404         clear_line_id(line_id);
04405         line_id->id1 = masks->count()-1;
04406         line_id->id2 = uid;
04407 }
04408 
04409 int ht_mask_sub::next_line_id(LINE_ID *line_id, int n)
04410 {
04411         int r=n;
04412         if (line_id->id2 != uid) return 0;
04413         int c=masks->count();
04414         ID i1 = line_id->id1;
04415         i1+=n;
04416         if ((int)i1>c-1) {
04417                 r-=i1-c+1;
04418                 i1=c-1;
04419         }
04420         if (r) line_id->id1=i1;
04421         return r;
04422 }
04423 
04424 int ht_mask_sub::prev_line_id(LINE_ID *line_id, int n)
04425 {
04426         int r;
04427         if (line_id->id2!=uid) return 0;
04428         ID i1=line_id->id1;
04429         if (i1<(dword)n) {
04430                 r=i1;
04431                 i1=0;
04432         } else {
04433                 r=n;
04434                 i1-=n;
04435         }
04436         if (r) line_id->id1=i1;
04437         return r;
04438 }
04439 
04440 void ht_mask_sub::add_mask(char *tagstr)
04441 {
04442         masks->insert(new ht_data_tagstring(tagstr));
04443 }
04444 
04445 void ht_mask_sub::add_mask_table(char **tagstr)
04446 {
04447         while (*tagstr) add_mask(*(tagstr++));
04448 }
04449 
04450 void ht_mask_sub::add_staticmask(char *statictag_str, FILEOFS reloc, bool std_bigendian)
04451 {
04452         char tag_str[1024];     /* FIXME: possible buffer overflow */
04453         statictag_to_tag(statictag_str, tag_str, reloc, std_bigendian);
04454         masks->insert(new ht_data_tagstring(tag_str));
04455 }
04456 
04457 void ht_mask_sub::add_staticmask_table(char **statictag_table, FILEOFS reloc, bool std_bigendian)
04458 {
04459         while (*statictag_table) add_staticmask(*(statictag_table++), reloc, std_bigendian);
04460 }
04461 
04462 #define ht_MASK_STD_INDENT      50
04463 
04464 void ht_mask_sub::add_staticmask_ptable(ht_mask_ptable *statictag_ptable, FILEOFS reloc, bool std_bigendian)
04465 {
04466         char s[1024]; /* FIXME: possible buffer overflow */
04467         while (statictag_ptable->desc || statictag_ptable->fields) {
04468                 s[0]=0;
04469                 if (statictag_ptable->desc) strcpy(s, statictag_ptable->desc);
04470                 int n=strlen(s);
04471                 while (n<ht_MASK_STD_INDENT) {
04472                         s[n]=' ';
04473                         n++;
04474                 }
04475                 s[n]=0;
04476                 if (statictag_ptable->fields) strcat(s, statictag_ptable->fields);
04477 
04478                 add_staticmask(s, reloc, std_bigendian);
04479                 
04480                 statictag_ptable++;
04481         }
04482 }
04483 
04484 /*
04485  *      CLASS ht_layer_sub
04486  */
04487 
04488 void ht_layer_sub::init(ht_streamfile *file, ht_sub *s, bool own_s=1)
04489 {
04490         ht_sub::init(file);
04491         sub=s;
04492         own_sub=own_s;
04493 }
04494 
04495 void ht_layer_sub::done()
04496 {
04497         if (own_sub) {
04498                 sub->done();
04499                 delete sub;
04500         }
04501         ht_sub::done();
04502 }
04503 
04504 bool ht_layer_sub::closest_line_id(LINE_ID *line_id)
04505 {
04506         return sub->closest_line_id(line_id);
04507 }
04508 
04509 bool ht_layer_sub::convert_ofs_to_id(const FILEOFS offset, LINE_ID *line_id)
04510 {
04511         return sub->convert_ofs_to_id(offset, line_id);
04512 }
04513 
04514 bool ht_layer_sub::convert_id_to_ofs(const LINE_ID line_id, FILEOFS *offset)
04515 {
04516         return sub->convert_id_to_ofs(line_id, offset);
04517 }
04518 
04519 void ht_layer_sub::first_line_id(LINE_ID *line_id)
04520 {
04521         return sub->first_line_id(line_id);
04522 }
04523 
04524 bool ht_layer_sub::getline(char *line, const LINE_ID line_id)
04525 {
04526         return sub->getline(line, line_id);
04527 }
04528 
04529 void ht_layer_sub::handlemsg(htmsg *msg)
04530 {
04531         sub->handlemsg(msg);
04532 }
04533 
04534 void ht_layer_sub::last_line_id(LINE_ID *line_id)
04535 {
04536         return sub->last_line_id(line_id);
04537 }
04538 
04539 int ht_layer_sub::next_line_id(LINE_ID *line_id, int n)
04540 {
04541         return sub->next_line_id(line_id, n);
04542 }
04543 
04544 int ht_layer_sub::prev_line_id(LINE_ID *line_id, int n)
04545 {
04546         return sub->prev_line_id(line_id, n);
04547 }
04548 
04549 bool ht_layer_sub::ref(LINE_ID *id)
04550 {
04551         return sub->ref(id);
04552 }
04553 
04554 ht_search_result *ht_layer_sub::search(ht_search_request *search, FILEOFS start, FILEOFS end)
04555 {
04556         return sub->search(search, start, end);
04557 }
04558 
04559 /*
04560  *      CLASS ht_collapsable_sub
04561  */
04562 
04563 ID ht_collapsable_sub_globalfaddr=0xffffffff;
04564 
04565 void ht_collapsable_sub::init(ht_streamfile *file, ht_sub *sub, bool own_sub, char *ns, bool c)
04566 {
04567         ht_layer_sub::init(file, sub, own_sub);
04568         nodestring = ht_strdup(ns);
04569         collapsed = c;
04570         ht_layer_sub::first_line_id(&fid);
04571 //      myfid1=0x12345678;      // it's kinda magic
04572 //      myfid2=0x35043859;
04573         clear_line_id(&myfid);
04574         myfid.id1 = 0;
04575         myfid.id2 = ht_collapsable_sub_globalfaddr--;
04576 }
04577 
04578 void ht_collapsable_sub::done()
04579 {
04580         if (nodestring) free(nodestring);
04581         ht_layer_sub::done();
04582 }
04583 
04584 bool ht_collapsable_sub::convert_ofs_to_id(const FILEOFS offset, LINE_ID *line_id)
04585 {
04586 /*      if (offset==myfaddr) {
04587                 first_line_id(id1, id2);
04588                 return true;
04589         } else*/
04590 // FIXME: The Right Thing ?
04591         if (!collapsed) {
04592                 return ht_layer_sub::convert_ofs_to_id(offset, line_id);
04593         }
04594         return false;
04595 }
04596 
04597 bool ht_collapsable_sub::convert_id_to_ofs(const LINE_ID line_id, FILEOFS *offset)
04598 {
04599         return ht_layer_sub::convert_id_to_ofs(line_id, offset);
04600 }
04601 
04602 void ht_collapsable_sub::first_line_id(LINE_ID *line_id)
04603 {
04604         clear_line_id(line_id);
04605         *line_id = myfid;
04606 }
04607 
04608 bool ht_collapsable_sub::getline(char *line, const LINE_ID line_id)
04609 {
04610         if (compeq_line_id(line_id, myfid)) {
04611                 line+=sprintf(line, "[%c] ", collapsed ? '+' : '-');
04612                 line=tag_make_ref(line, myfid.id1, myfid.id2, 0, 0, nodestring);
04613                 *line=0;
04614                 return true;
04615         } else if (collapsed) return false;
04616         if (ht_layer_sub::getline(line, line_id)) {
04617                 memmove(line+2, line, tag_strlen(line)+1);
04618                 line[0]=' ';
04619                 line[1]=' ';
04620                 return true;
04621         }
04622         return false;
04623 }
04624 
04625 void ht_collapsable_sub::last_line_id(LINE_ID *line_id)
04626 {
04627         if (collapsed) return first_line_id(line_id); else
04628                 return ht_layer_sub::last_line_id(line_id);
04629 }
04630 
04631 int ht_collapsable_sub::next_line_id(LINE_ID *line_id, int n)
04632 {
04633         if (collapsed) return 0;
04634         int r=0;
04635         LINE_ID t;
04636         if (compeq_line_id(*line_id, myfid)) {
04637                 ht_layer_sub::first_line_id(&t);
04638                 n--;
04639                 r++;
04640         } else {
04641                 t = *line_id;
04642         }
04643         if (n) r+=ht_layer_sub::next_line_id(&t, n);
04644         if (r) {
04645                 *line_id = t;
04646         }
04647         return r;
04648 }
04649 
04650 int ht_collapsable_sub::prev_line_id(LINE_ID *line_id, int n)
04651 {
04652         if (collapsed) return 0;
04653         if (compeq_line_id(*line_id, myfid)) return 0;
04654         int r=ht_layer_sub::prev_line_id(line_id, n);
04655         if (compeq_line_id(*line_id, fid) && (r<n)) {
04656                 *line_id = myfid;
04657                 r++;
04658         }
04659         return r;
04660 }
04661 
04662 bool ht_collapsable_sub::ref(LINE_ID *id)
04663 {
04664         if (compeq_line_id(*id, myfid)) {
04665                 collapsed=!collapsed;
04666                 return true;
04667         }
04668         if (!collapsed) return ht_layer_sub::ref(id);
04669         return false;
04670 }
04671 
04672 ht_search_result *ht_collapsable_sub::search(ht_search_request *search, FILEOFS start, FILEOFS end)
04673 {
04674         if (collapsed) return NULL;
04675         return ht_layer_sub::search(search, start, end);
04676 }
04677 
04678 /*
04679  *      CLASS ht_group_sub
04680  */
04681 
04682 void ht_group_sub::init(ht_streamfile *file)
04683 {
04684         ht_sub::init(file);
04685         subs=new ht_clist();
04686         subs->init();
04687 }
04688 
04689 void ht_group_sub::done()
04690 {
04691         subs->done();
04692         delete subs;
04693         ht_sub::done();
04694 }
04695 
04696 bool ht_group_sub::convert_ofs_to_id(const FILEOFS offset, LINE_ID *line_id)
04697 {
04698         return false;
04699 }
04700 
04701 bool ht_group_sub::convert_id_to_ofs(const LINE_ID line_id, FILEOFS *offset)
04702 {
04703         return false;
04704 }
04705 
04706 void ht_group_sub::first_line_id(LINE_ID *line_id)
04707 {
04708         ht_sub *s = (ht_sub*)subs->get(0);
04709         if (s) s->first_line_id(line_id);
04710 }
04711 
04712 bool ht_group_sub::getline(char *line, const LINE_ID line_id)
04713 {
04714         ht_sub *s;
04715         UINT c=subs->count();
04716         for (UINT i=0; i<c; i++) {
04717                 s=(ht_sub*)subs->get(i);
04718                 if (s->getline(line, line_id)) return true;
04719         }
04720         return false;
04721 }
04722 
04723 void ht_group_sub::handlemsg(htmsg *msg)
04724 {
04725         ht_sub::handlemsg(msg);
04726 }
04727 
04728 void ht_group_sub::last_line_id(LINE_ID *line_id)
04729 {
04730         ht_sub *s = (ht_sub*)subs->get(subs->count()-1);
04731         if (s) s->last_line_id(line_id);
04732 }
04733 
04734 int ht_group_sub::next_line_id(LINE_ID *line_id, int n)
04735 {
04736         ht_sub *s;
04737         UINT c=subs->count();
04738         int on=n;
04739         for (UINT i=0; i<c; i++) {
04740                 s=(ht_sub*)subs->get(i);
04741                 LINE_ID t;
04742                 s->last_line_id(&t);
04743                 if (compeq_line_id(t, *line_id)) {
04744                         s=(ht_sub*)subs->get(i+1);
04745                         if (s) {
04746                                 s->first_line_id(line_id);
04747                                 n--;
04748                         }
04749                 } else {
04750                         n-=s->next_line_id(line_id, n);
04751                 }
04752                 if (!n) break;
04753         }
04754         return on-n;
04755 }
04756 
04757 int ht_group_sub::prev_line_id(LINE_ID *line_id, int n)
04758 {
04759         ht_sub *s;
04760         UINT c=subs->count();
04761         int on=n;
04762         for (UINT i=0; i<c; i++) {
04763                 s=(ht_sub*)subs->get(i);
04764                 LINE_ID t;
04765                 s->first_line_id(&t);
04766                 if (compeq_line_id(t, *line_id)) {
04767                         s=(ht_sub*)subs->get(i-1);
04768                         if (s) {
04769                                 s->last_line_id(line_id);
04770                                 n--;
04771                         }
04772                 } else {
04773                         n-=s->prev_line_id(line_id, n);
04774                 }
04775                 if (!n) break;
04776         }
04777         return on-n;
04778 }
04779 
04780 bool ht_group_sub::ref(LINE_ID *id)
04781 {
04782         ht_sub *s;
04783         UINT c=subs->count();
04784         for (UINT i=0; i<c; i++) {
04785                 s=(ht_sub*)subs->get(i);
04786                 if (s->ref(id)) return true;
04787         }
04788         return false;
04789 }
04790 
04791 ht_search_result *ht_group_sub::search(ht_search_request *search, FILEOFS start, FILEOFS end)
04792 {
04793         return NULL;
04794 }
04795 
04796 void ht_group_sub::insertsub(ht_sub *sub)
04797 {
04798         subs->insert(sub);
04799 }
04800 
04801 /*
04802  *      CLASS ht_data_tagstring
04803  */
04804 
04805 ht_data_tagstring::ht_data_tagstring(char *tagstr)
04806 : ht_data_string()
04807 {
04808         value=tag_strdup(tagstr);
04809 }
04810 
04811 ht_data_tagstring::~ht_data_tagstring()
04812 {
04813 }
04814 
04815 

Generated on Fri May 7 21:15:34 2004 by doxygen 1.3.5