1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254 |
- /***************************************************************************
- * *
- * _____ ____ *
- * | __ \ / __ \ _ _ _____ *
- * | | \ \ / / \_\ | | | | _ \ *
- * | | \ \| | | | | | |_| | *
- * | | | || | | | | | ___/ *
- * | | / /| | __ | | | | _ \ *
- * | |__/ / \ \__/ / | |___| | |_| | *
- * |_____/ \____/ |_____|_|_____/ *
- * *
- * Wiimms source code library *
- * *
- ***************************************************************************
- * *
- * Copyright (c) 2012-2022 by Dirk Clemens <wiimm@wiimm.de> *
- * *
- ***************************************************************************
- * *
- * This library is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This library is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt *
- * *
- ***************************************************************************/
- #define _GNU_SOURCE 1
- #include <stdio.h>
- #include <stddef.h>
- #include "dclib-xdump.h"
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// data ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- const ccp XDumpCommandName[XDUMPC__N] =
- {
- "DUMP",
- "DIFF",
- "SCAN",
- };
- //-----------------------------------------------------------------------------
- const ccp XDumpFormatName[XDUMPF__N] =
- {
- "AUTO",
- "INT_1",
- "INT_2",
- "INT_3",
- "INT_4",
- "INT_5",
- "INT_6",
- "INT_7",
- "INT_8",
- "FLOAT",
- "DOUBLE",
- };
- const char XDumpFormatOption[XDUMPF__N+1] = "A12345678FD";
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// output helpers ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- static bool PrintFormat
- (
- struct XDump_t *xd, // internal copy of params
- int force // >0: ignore 'format_printed'
- // >1: print always
- )
- {
- DASSERT(xd);
- if ( !xd->f || !xd->format_name )
- return false;
- if ( force > 1
- || ( force > 0 && xd->print_format )
- || ( xd->print_format && !xd->format_printed )
- )
- {
- xd->format_printed = true;
- fprintf(xd->f,"%s%*s%sFORMAT: %s",
- xd->prefix, xd->indent,"",
- xd->mode_c ? "//" : "#",
- xd->format_name );
- if ( xd->format > XDUMPF_INT_1 )
- fprintf(xd->f," %s%s",
- xd->endian == DC_BIG_ENDIAN ? "BE" : "LE",
- xd->eol );
- else
- fputs(xd->eol,xd->f);
- return true;
- }
- return false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- int XDumpStandardOutput
- (
- struct XDump_t *xd, // internal copy of params
- ccp prefix, // NULL or additional prefix (used by diff)
- ccp dump, // dump to print
- ccp text // NULL or text to print
- )
- {
- DASSERT(xd);
- DASSERT(dump);
- if (xd->f)
- {
- fprintf(xd->f,"%s%*s%s",
- xd->prefix, xd->indent,"", prefix ? prefix : "" );
- if (xd->print_addr)
- {
- if (xd->mode_c)
- fprintf(xd->f,"/*%*llx*/ ",xd->addr_fw,xd->addr);
- else
- fprintf(xd->f,"%*llx:%s",
- xd->addr_fw, xd->addr,
- xd->extra_space >= 0 ? " " : "" );
- }
- if (xd->print_number)
- {
- if (xd->min_number_fw)
- fprintf(xd->f,"%-*s",xd->min_number_fw,dump);
- else
- fputs(dump,xd->f);
- }
- if ( text && xd->print_text )
- {
- if (xd->mode_c)
- fprintf(xd->f," // %s",text);
- else
- fprintf(xd->f,"%s :%s:",
- xd->extra_space >= 0 ? " " : "", text );
- }
- fputs(xd->eol,xd->f);
- }
- return 0;
- }
- ///////////////////////////////////////////////////////////////////////////////
- static void print_text ( char *buf, const u8 *data, int n )
- {
- while ( n-- > 0 )
- {
- const u8 ch = *data++;
- *buf++ = ch >= ' ' && ch < 0x7f ? ch : '.';
- }
- *buf = 0;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// XParam_t ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- // [[XParam_t]]
- typedef struct XParam_t
- {
- const u8 *d; // pointer to input data
- const u8 *end; // end of input data
- uint size; // size of data to dump
- bool term; // true: data complete
- bool recalc_align; // true: recalculate alignment
- bool next_line; // true: continue at next line
- const u64 *addr_break; // NULL or pointer to next break
- uint skip; // number of columns to skip
- uint line_size; // current line size (source bytes)
- uint max_col; // max number of columns to print
- int extra_space; // extra space counter
- // buffers
- char text_buf[XDUMP_GOOD_TEXT_BUF_SIZE];
- char num_buf[XDUMP_GOOD_NUM_BUF_SIZE];
- }
- XParam_t;
- ///////////////////////////////////////////////////////////////////////////////
- static void SetupXParam
- ( XParam_t *p, XDump_t *xd, cvp data, uint size, bool term )
- {
- DASSERT(p);
- DASSERT(xd);
- DASSERT(data);
- if ( size > INT_MAX )
- {
- size = INT_MAX; // limit because of return value
- term = false;
- }
- memset( p, 0, offsetof(XParam_t,num_buf) + 15 & ~7 );
- p->size = size;
- p->term = term;
- p->d = data;
- p->end = p->d + size;
- p->recalc_align = xd->mode_align;
- p->addr_break = xd->addr_break;
- }
- ///////////////////////////////////////////////////////////////////////////////
- static uint SetupXParamLine ( XParam_t *p, XDump_t *xd )
- {
- DASSERT(p);
- DASSERT(xd);
- if ( p->recalc_align )
- {
- p->recalc_align = false;
- p->skip = ( xd->addr % xd->bytes_per_line ) / xd->bytes_per_col;
- const int delta = p->skip * xd->bytes_per_col;
- xd->addr -= delta;
- if (xd->print_number)
- p->size += delta;
- }
- p->next_line = false;
- p->line_size = xd->bytes_per_line < p->size
- ? xd->bytes_per_line
- : p->term ? p->size : 0;
- if ( p->addr_break )
- {
- while ( *p->addr_break && xd->addr >= *p->addr_break )
- p->addr_break++;
- if (!*p->addr_break)
- p->addr_break = 0;
- else
- {
- const s64 max = *p->addr_break - xd->addr;
- if ( p->line_size > max )
- p->line_size = max;
- }
- }
- p->max_col = p->line_size / xd->bytes_per_col;
- p->line_size = p->max_col * xd->bytes_per_col;
- p->extra_space = xd->col_space ? xd->col_space+1 : 0;
- if (xd->print_text)
- {
- if (p->skip)
- {
- const uint skip_size = p->skip * xd->bytes_per_col;
- if ( skip_size < p->line_size )
- {
- memset(p->text_buf,' ',skip_size);
- print_text(p->text_buf+skip_size,p->d,p->line_size-skip_size);
- }
- else
- *p->text_buf = 0; // should never happen!
- }
- else
- print_text(p->text_buf,p->d,p->line_size);
- }
- return p->max_col;
- }
- ///////////////////////////////////////////////////////////////////////////////
- static bool PrintNullSummary ( XDump_t *xd )
- {
- if ( !xd->null_lines || !xd->out_func )
- return false;
- char buf[100];
- const uint skipped = xd->null_lines * xd->bytes_per_line;
- snprintf(buf,sizeof(buf),"%s#NULL: 0x%x bytes",
- xd->extra_space >= 0 ? " " : "", skipped );
- xd->addr -= skipped;
- xd->out_func(xd,0,buf,0);
- xd->addr += skipped;
- xd->null_lines = 0;
- return true;
- }
- ///////////////////////////////////////////////////////////////////////////////
- static bool CheckXParamNull ( XParam_t *p, XDump_t *xd )
- {
- DASSERT(p);
- DASSERT(xd);
- static u8 nullbuf[XDUMP_MAX_BYTES_PER_LINE] = {};
- const bool skip = p->line_size == xd->bytes_per_line
- && !memcmp(p->d,nullbuf,xd->bytes_per_line);
- if (skip)
- {
- xd->null_lines++;
- xd->addr += p->line_size;
- p->d += p->line_size;
- p->size -= p->line_size;
- return true;
- }
- if ( xd->null_lines && ( !skip || p->size <= xd->bytes_per_line ))
- PrintNullSummary(xd);
- return skip;
- }
- ///////////////////////////////////////////////////////////////////////////////
- static void AbortXParamLine ( XParam_t *p, XDump_t *xd, uint col )
- {
- const uint col1 = col + 1;
- if ( col1 < p->max_col )
- {
- p->max_col = col1;
- p->line_size = col1 * xd->bytes_per_col;
- p->text_buf[p->line_size] = 0;
- p->recalc_align = xd->mode_align;
- p->next_line = true;
- }
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// output functions ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- static int DumpInt32
- (
- // returns <0 on error, or number of dumped bytes
- XDump_t *xd, // current params
- const void *p_data, // data to dump
- uint p_size, // size of 'p_data'
- bool p_term // false: print only whole lines
- // true: print complete data
- )
- {
- DASSERT(xd);
- if ( !p_data || !xd->out_func )
- return 0;
- XParam_t p;
- SetupXParam(&p,xd,p_data,p_size,p_term);
- while(SetupXParamLine(&p,xd))
- {
- if ( xd->mode_ignore && CheckXParamNull(&p,xd) )
- continue;
- if (xd->print_number)
- {
- char *num = p.num_buf;
- uint col;
- for ( col = 0; col < xd->cols_per_line; col++ )
- {
- if (!--p.extra_space)
- {
- p.extra_space = xd->col_space;
- *num++ = ' ';
- }
- if ( p.skip > 0 )
- {
- p.skip--;
- memset(num,' ',xd->num_format_fw);
- num += xd->num_format_fw;
- }
- else if ( col < p.max_col )
- {
- u32 val;
- switch(xd->bytes_per_col)
- {
- case 2: val = xd->endian_func->rd16(p.d); p.d += 2; break;
- case 3: val = xd->endian_func->rd24(p.d); p.d += 3; break;
- case 4: val = xd->endian_func->rd32(p.d); p.d += 4; break;
- default: val = *p.d++; break;
- }
- num += sprintf(num,xd->num_format1,val);
- if ( xd->have_trigger && val == (u32)xd->trigger )
- AbortXParamLine(&p,xd,col);
- }
- else if ( p.term && !p.next_line && !xd->mode_c )
- {
- if ( p.d < p.end )
- num += sprintf(num, "%*c%u", xd->num_format_fw-1,
- '>', (int)(p.end-p.d) );
- else if ( xd->print_endmarker )
- num += sprintf(num,"%*c", xd->num_format_fw, '/' );
- else if ( xd->print_text )
- {
- memset(num,' ',xd->num_format_fw);
- num += xd->num_format_fw;
- }
- p.term = false; // print only once
- }
- else if ( xd->print_text )
- {
- memset(num,' ',xd->num_format_fw);
- num += xd->num_format_fw;
- }
- }
- if (!xd->print_text)
- while ( num > p.num_buf && num[-1] == ' ' )
- num--;
- *num = 0;
- ASSERT( num < p.num_buf + sizeof(p.num_buf));
- xd->last_number_fw = num - p.num_buf;
- }
- else
- {
- p.d += p.line_size - p.skip * xd->bytes_per_col;
- p.skip = 0;
- }
- int stat = xd->out_func(xd,0,p.num_buf,p.text_buf);
- if ( stat < 0 )
- return stat;
- xd->addr += p.line_size;
- p.size -= p.line_size;
- }
- const uint written = p.d - (u8*)p_data;
- xd->written += written;
- return written;
- }
- ///////////////////////////////////////////////////////////////////////////////
- static int DumpInt64
- (
- // returns <0 on error, or number of dumped bytes
- XDump_t *xd, // current params
- const void *p_data, // data to dump
- uint p_size, // size of 'p_data'
- bool p_term // false: print only whole lines
- // true: print complete data
- )
- {
- DASSERT(xd);
- if ( !p_data || !xd->out_func )
- return 0;
- XParam_t p;
- SetupXParam(&p,xd,p_data,p_size,p_term);
- while(SetupXParamLine(&p,xd))
- {
- if ( xd->mode_ignore && CheckXParamNull(&p,xd) )
- continue;
- if (xd->print_number)
- {
- char *num = p.num_buf;
- uint col;
- for ( col = 0; col < xd->cols_per_line; col++ )
- {
- if (!--p.extra_space)
- {
- p.extra_space = xd->col_space;
- *num++ = ' ';
- }
- if ( p.skip > 0 )
- {
- p.skip--;
- memset(num,' ',xd->num_format_fw);
- num += xd->num_format_fw;
- }
- else if ( col < p.max_col )
- {
- u64 val;
- switch(xd->bytes_per_col)
- {
- case 5: val = xd->endian_func->rd40(p.d); p.d += 5; break;
- case 6: val = xd->endian_func->rd48(p.d); p.d += 6; break;
- case 7: val = xd->endian_func->rd56(p.d); p.d += 7; break;
- default: val = xd->endian_func->rd64(p.d); p.d += 8; break;
- }
- num += sprintf(num,xd->num_format1,val);
- if ( xd->have_trigger && val == (u32)xd->trigger )
- AbortXParamLine(&p,xd,col);
- }
- else if ( p.term && !p.next_line && !xd->mode_c )
- {
- if ( p.d < p.end )
- num += sprintf(num, "%*c%u", xd->num_format_fw-1,
- '>', (int)(p.end-p.d) );
- else if ( xd->print_endmarker )
- num += sprintf(num,"%*c", xd->num_format_fw, '/' );
- else if (xd->print_text)
- {
- memset(num,' ',xd->num_format_fw);
- num += xd->num_format_fw;
- }
- p.term = false; // print only once
- }
- else if (xd->print_text)
- {
- memset(num,' ',xd->num_format_fw);
- num += xd->num_format_fw;
- }
- }
- *num = 0;
- ASSERT( num < p.num_buf + sizeof(p.num_buf));
- xd->last_number_fw = num - p.num_buf;
- }
- else
- {
- p.d += p.line_size - p.skip * xd->bytes_per_col;
- p.skip = 0;
- }
- int stat = xd->out_func(xd,0,p.num_buf,p.text_buf);
- if ( stat < 0 )
- return stat;
- xd->addr += p.line_size;
- p.size -= p.line_size;
- }
- const uint written = p.d - (u8*)p_data;
- xd->written += written;
- return written;
- }
- ///////////////////////////////////////////////////////////////////////////////
- static int DumpFloat
- (
- // returns <0 on error, or number of dumped bytes
- XDump_t *xd, // current params
- const void *p_data, // data to dump
- uint p_size, // size of 'p_data'
- bool p_term // false: print only whole lines
- // true: print complete data
- )
- {
- DASSERT(xd);
- if ( !p_data || !xd->out_func )
- return 0;
- XParam_t p;
- SetupXParam(&p,xd,p_data,p_size,p_term);
- while(SetupXParamLine(&p,xd))
- {
- if ( xd->mode_ignore && CheckXParamNull(&p,xd) )
- continue;
- if (xd->print_number)
- {
- char *num = p.num_buf;
- uint col;
- for ( col = 0; col < xd->cols_per_line; col++ )
- {
- if (!--p.extra_space)
- {
- p.extra_space = xd->col_space;
- *num++ = ' ';
- }
- if ( p.skip > 0 )
- {
- p.skip--;
- memset(num,' ',xd->num_format_fw);
- num += xd->num_format_fw;
- }
- else if ( col < p.max_col )
- {
- double val;
- ccp format;
- if ( xd->bytes_per_col == 4 )
- {
- val = xd->endian_func->rdf4(p.d);
- format = fabs(val) <= 9999.0 && fabs(val) >= 1e-3
- ? xd->num_format1 : xd->num_format2;
- p.d += 4;
- }
- else
- {
- val = xd->endian_func->rdf8(p.d);
- format = fabs(val) <= 999999999.0 && fabs(val) >= 1e-6
- ? xd->num_format1 : xd->num_format2;
- p.d += 8;
- }
- num += sprintf(num,format,val);
- }
- else if ( p.term && !p.next_line && !xd->mode_c )
- {
- if ( p.d < p.end )
- num += sprintf(num, "%*c%u", xd->num_format_fw-1,
- '>', (int)(p.end-p.d) );
- else if ( xd->print_text )
- num += sprintf(num,"%*c", xd->num_format_fw, '/' );
- else if (xd->print_text)
- {
- memset(num,' ',xd->num_format_fw);
- num += xd->num_format_fw;
- }
- p.term = false; // print only once
- }
- else if (xd->print_text)
- {
- memset(num,' ',xd->num_format_fw);
- num += xd->num_format_fw;
- }
- }
- *num = 0;
- ASSERT( num < p.num_buf + sizeof(p.num_buf));
- xd->last_number_fw = num - p.num_buf;
- }
- else
- {
- p.d += p.line_size - p.skip * xd->bytes_per_col;
- p.skip = 0;
- }
- int stat = xd->out_func(xd,0,p.num_buf,p.text_buf);
- if ( stat < 0 )
- return stat;
- xd->addr += p.line_size;
- p.size -= p.line_size;
- }
- const uint written = p.d - (u8*)p_data;
- xd->written += written;
- return written;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// setup ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- void InitializeXDump ( XDump_t *xd )
- {
- DASSERT(xd);
- memset(xd,0,sizeof(*xd));
- xd->f = stdout;
- xd->print_format =
- xd->print_addr =
- xd->print_number =
- xd->print_endmarker =
- xd->print_text =
- xd->print_diff_sep =
- xd->print_summary = true;
- }
- ///////////////////////////////////////////////////////////////////////////////
- ccp hexdump_prefix = "";
- ccp hexdump_eol = "\n";
- bool hexdump_align = false;
- //-----------------------------------------------------------------------------
- void InitializeXDumpEx
- (
- XDump_t *xd,
- FILE *f,
- int indent,
- u64 addr,
- int addr_fw,
- int row_len
- )
- {
- DASSERT(xd);
- InitializeXDump(xd);
- xd->f = f;
- xd->prefix = hexdump_prefix;
- xd->eol = hexdump_eol;
- xd->mode_align = hexdump_align;
- xd->indent = indent;
- xd->start_addr = addr;
- xd->min_addr_fw = addr_fw;
- xd->min_width = row_len;
- xd->format = XDUMPF_INT_1;
- xd->print_format = false;
- xd->print_summary = false;
- xd->print_diff_sep = false;
- hexdump_prefix = EmptyString;
- hexdump_eol = "\n";
- hexdump_align = false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- void SetupXDump ( XDump_t *xd, XDumpCommand_t cmd )
- {
- DASSERT(xd);
- char buf[100];
- xd->cmd = (uint)cmd < XDUMPC__N ? cmd : XDUMPC_DIFF;
- if ( xd->endian != DC_SECOND_ENDIAN )
- xd->endian = DC_DEFAULT_ENDIAN;
- xd->endian_func = xd->endian == DC_LITTLE_ENDIAN ? &le_func : &be_func;
- //--- address field width
- xd->addr = xd->start_addr;
- xd->addr_fw = xd->min_addr_fw;
- if ( !xd->min_addr_fw || xd->addr_fw < xd->min_addr_fw )
- {
- uint len = snprintf(buf,sizeof(buf),"%llx",xd->addr);
- if ( xd->addr_fw < len )
- xd->addr_fw = len;
- const u64 size = xd->assumed_size ? xd->assumed_size : 0x100;
- len = snprintf(buf,sizeof(buf),"%llx", xd->addr + size - 1 );
- if ( xd->addr_fw < len )
- xd->addr_fw = len;
- if (xd->max_addr_fw)
- {
- if ( xd->addr_fw > xd->max_addr_fw )
- xd->addr_fw = xd->max_addr_fw;
- if ( xd->addr_fw < xd->min_addr_fw )
- xd->addr_fw = xd->min_addr_fw;
- }
- }
- //--- misc
- xd->indent = NormalizeIndent(xd->indent);
- if (!xd->out_func)
- xd->out_func = XDumpStandardOutput;
- if (!xd->prefix)
- xd->prefix = EmptyString;
- if (!xd->eol)
- xd->eol = "\n";
- xd->num_format2 = 0;
- xd->format_printed = 0;
- //--- format
- if ( (uint)xd->format >= XDUMPF__N )
- xd->format = XDUMPF_AUTO;
- if ( xd->format == XDUMPF_AUTO && xd->cmd != XDUMPC_SCAN )
- xd->format = XDUMPF_INT_1;
- switch(xd->format)
- {
- case XDUMPF_INT_2:
- xd->bytes_per_col = 2;
- xd->dump_func = DumpInt32;
- xd->format_name = xd->mode_dec ? "DEC2" : "HEX2";
- xd->max_format_fw = 7;
- xd->num_format1
- = xd->mode_c ? ( xd->mode_dec ? "%5u," : "0x%04x," )
- : xd->mode_zero ? ( xd->mode_dec ? " %05u" : " %04x" )
- : ( xd->mode_dec ? " %5u" : " %4x" );
- xd->num_format_fw = snprintf(buf,sizeof(buf),xd->num_format1,1);
- break;
- case XDUMPF_INT_3:
- xd->bytes_per_col = 3;
- xd->dump_func = DumpInt32;
- xd->format_name = xd->mode_dec ? "DEC3" : "HEX3";
- xd->max_format_fw = 9;
- xd->num_format1
- = xd->mode_c ? ( xd->mode_dec ? "%8u," : "0x%06x," )
- : xd->mode_zero ? ( xd->mode_dec ? " %08u" : " %06x" )
- : ( xd->mode_dec ? " %8u" : " %6x" );
- xd->num_format_fw = snprintf(buf,sizeof(buf),xd->num_format1,1);
- break;
- case XDUMPF_INT_4:
- xd->bytes_per_col = 4;
- xd->dump_func = DumpInt32;
- xd->format_name = xd->mode_dec ? "DEC4" : "HEX4";
- xd->max_format_fw = 11;
- xd->num_format1
- = xd->mode_c ? ( xd->mode_dec ? "%10u," : "0x%08x," )
- : xd->mode_zero ? ( xd->mode_dec ? " %010u" : " %08x" )
- : ( xd->mode_dec ? " %10u" : " %8x" );
- xd->num_format_fw = snprintf(buf,sizeof(buf),xd->num_format1,1);
- break;
- case XDUMPF_INT_5:
- xd->bytes_per_col = 5;
- xd->dump_func = DumpInt64;
- xd->format_name = xd->mode_dec ? "DEC5" : "HEX5";
- xd->max_format_fw = 13;
- xd->num_format1
- = xd->mode_c ? ( xd->mode_dec ? "%12llu," : "0x%010llx," )
- : xd->mode_zero ? ( xd->mode_dec ? " %012llu" : " %010llx" )
- : ( xd->mode_dec ? " %12llu" : " %10llx" );
- xd->num_format_fw = snprintf(buf,sizeof(buf),xd->num_format1,1ull);
- break;
- case XDUMPF_INT_6:
- xd->bytes_per_col = 6;
- xd->dump_func = DumpInt64;
- xd->format_name = xd->mode_dec ? "DEC6" : "HEX6";
- xd->max_format_fw = 16;
- xd->num_format1
- = xd->mode_c ? ( xd->mode_dec ? "%15llu," : "0x%012llx," )
- : xd->mode_zero ? ( xd->mode_dec ? " %015llu" : " %012llx" )
- : ( xd->mode_dec ? " %15llu" : " %12llx" );
- xd->num_format_fw = snprintf(buf,sizeof(buf),xd->num_format1,1ull);
- break;
- case XDUMPF_INT_7:
- xd->bytes_per_col = 7;
- xd->dump_func = DumpInt64;
- xd->format_name = xd->mode_dec ? "DEC7" : "HEX7";
- xd->max_format_fw = 18;
- xd->num_format1
- = xd->mode_c ? ( xd->mode_dec ? "%17llu," : "0x%014llx," )
- : xd->mode_zero ? ( xd->mode_dec ? " %017llu" : " %014llx" )
- : ( xd->mode_dec ? " %17llu" : " %14llx" );
- xd->num_format_fw = snprintf(buf,sizeof(buf),xd->num_format1,1ull);
- break;
- case XDUMPF_INT_8:
- xd->bytes_per_col = 8;
- xd->dump_func = DumpInt64;
- xd->format_name = xd->mode_dec ? "DEC8" : "HEX8";
- xd->max_format_fw = 20;
- xd->num_format1
- = xd->mode_c ? ( xd->mode_dec ? "%19llu," : "0x%016llx," )
- : xd->mode_zero ? ( xd->mode_dec ? " %019llu" : " %016llx" )
- : ( xd->mode_dec ? " %19llu" : " %16llx" );
- xd->num_format_fw = snprintf(buf,sizeof(buf),xd->num_format1,1ull);
- break;
- case XDUMPF_FLOAT:
- xd->bytes_per_col = 4;
- xd->dump_func = DumpFloat;
- xd->format_name = "FLOAT";
- xd->max_format_fw = 12;
- xd->num_format1 = xd->mode_c ? "%11.5g," : " %11.5f";
- xd->num_format2 = xd->mode_c ? "%11.5g," : " %11.5g";
- xd->num_format_fw = snprintf(buf,sizeof(buf),xd->num_format1,1.1);
- break;
- case XDUMPF_DOUBLE:
- xd->bytes_per_col = 8;
- xd->dump_func = DumpFloat;
- xd->format_name = "DOUBLE";
- xd->max_format_fw = 21;
- xd->num_format1 = xd->mode_c ? "%20.8g," : " %20.8f";
- xd->num_format2 = xd->mode_c ? "%20.8g," : " %20.8g";
- xd->num_format_fw = snprintf(buf,sizeof(buf),xd->num_format1,1.1);
- break;
- default:
- //case XDUMPF_AUTO:
- //case XDUMPF_INT_1:
- xd->bytes_per_col = 1;
- xd->dump_func = DumpInt32;
- xd->format_name = xd->mode_dec ? "DEC1" : "HEX1";
- xd->max_format_fw = 5;
- xd->num_format1
- = xd->mode_c ? ( xd->mode_dec ? "%3u," : "0x%02x," )
- : xd->mode_zero ? ( xd->mode_dec ? " %03u" : " %02x" )
- : ( xd->mode_dec ? " %3u" : " %2x" );
- xd->num_format_fw = snprintf(buf,sizeof(buf),xd->num_format1,1);
- break;
- }
- //--- bytes per line
- uint min = xd->min_width ? xd->min_width : 16;
- uint max = xd->max_width ? xd->max_width : min + 2*xd->bytes_per_col/3;
- if ( max > XDUMP_MAX_BYTES_PER_LINE )
- max = XDUMP_MAX_BYTES_PER_LINE;
- if ( min > max || !xd->min_width )
- min = max;
- uint ncols = ( min + xd->bytes_per_col - 1 ) / xd->bytes_per_col;
- uint ncols_max = max / xd->bytes_per_col;
- if ( ncols > ncols_max )
- ncols = ncols_max;
- xd->cols_per_line = ncols ? ncols : 1;
- xd->bytes_per_line = xd->cols_per_line * xd->bytes_per_col;
- //--- extra space
- if ( xd->extra_space < 0 || xd->cols_per_line <= 3 )
- xd->col_space = 0;
- else
- {
- xd->col_space = xd->extra_space;
- if (!xd->col_space)
- {
- xd->col_space = 4 / xd->bytes_per_col;
- if ( xd->col_space < 2 )
- xd->col_space = 2;
- }
- if ( xd->col_space >= xd->cols_per_line )
- xd->col_space = 0;
- }
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// print xdump params ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- void PrintXDumpParam
- (
- FILE *f, // output file, abort if NULL
- int indent, // indention
- const ColorSet_t *colset, // NULL or color set
- const XDump_t *xd // data to print
- )
- {
- if ( !f || !xd )
- return;
- indent = NormalizeIndent(indent);
- if (!colset)
- colset = GetColorSet0();
- fprintf(f,
- "%*s%s" "Command: %s%s%s\n"
- "%*s%s" "Format: %s%s, %s%s%s => %s%s\n"
- "%*s%s" "Endian: %s%s%s\n",
- indent,"", colset->name, colset->value,
- (uint)xd->cmd < XDUMPC__N ? XDumpCommandName[xd->cmd] : "?",
- colset->reset,
- indent,"", colset->name, colset->value,
- (uint)xd->format < XDUMPF__N ? XDumpFormatName[xd->format] : "?",
- xd->mode_dec ? "decimal" : "hexadecimal",
- xd->mode_zero ? " with leading zeros" : "",
- xd->mode_c ? ", print in C syntax" : "",
- xd->format_name ? xd->format_name : "?",
- colset->reset,
- indent,"", colset->name, colset->value,
- xd->endian == DC_LITTLE_ENDIAN ? "LITTLE"
- : xd->endian == DC_BIG_ENDIAN ? "BIG" : "?",
- colset->reset );
- if (xd->num_format2)
- fprintf(f,
- "%*s%s" "Num format: %s'%s' & '%s' (fw=%u,max=%u)%s\n",
- indent,"", colset->name, colset->value,
- xd->num_format1 ? xd->num_format1 : "?",
- xd->num_format2, xd->num_format_fw, xd->max_format_fw,
- colset->reset );
- else
- fprintf(f,
- "%*s%s" "Num format: %s'%s' (fw=%u,max=%u)%s\n",
- indent,"", colset->name, colset->value,
- xd->num_format1 ? xd->num_format1 : "?",
- xd->num_format_fw, xd->max_format_fw,
- colset->reset );
- if (xd->assumed_size)
- fprintf(f, "%*s%s"
- "Address: %sstart=0x%llx, current=0x%llx, size=0x%llx%s%s\n",
- indent,"", colset->name, colset->value,
- xd->start_addr, xd->addr, xd->assumed_size,
- xd->mode_align ? ", aligned" : "",
- colset->reset );
- else
- fprintf(f, "%*s%s"
- "Address: %sstart=0x%llx, current=0x%llx%s%s\n",
- indent,"", colset->name, colset->value,
- xd->start_addr, xd->addr,
- xd->mode_align ? ", aligned" : "",
- colset->reset );
- if (xd->have_trigger)
- fprintf(f, "%*s%s"
- "Line trigger: %s%llu = 0x%llx%s%s\n",
- indent,"", colset->name, colset->value,
- xd->trigger, xd->trigger,
- xd->trigger == '\n' ? " (LF)" :
- xd->trigger == '\r' ? " (CR)" :
- xd->trigger == '\t' ? " (TAB)" :
- xd->trigger == ' ' ? " (SPACE)" :
- xd->trigger == 0 ? " (NULL)" :
- "",
- colset->reset );
- fprintf(f,
- "%*s%s" "Address fw: %smin=%u, max=%u, active=%u%s\n",
- indent,"", colset->name, colset->value,
- xd->min_addr_fw, xd->max_addr_fw, xd->addr_fw,
- colset->reset );
- fprintf(f,
- "%*s%s" "Print: %s%sformat, %saddress, %snumbers, %stext, %ssummary, %sseparator%s\n",
- indent,"", colset->name, colset->value,
- xd->print_format ? "" : "no ",
- xd->print_addr ? "" : "no ",
- xd->print_number ? "" : "no ",
- xd->print_text ? "" : "no ",
- xd->print_summary ? "" : "no ",
- xd->print_diff_sep ? "" : "no ",
- colset->reset );
- fprintf(f,
- "%*s%s" "Output file: %s%s, indent=%d, prefix=%s, eol=%s%s\n",
- indent,"", colset->name, colset->value,
- xd->f == stdout ? "STDOUT"
- : xd->f == stderr ? "STDERR"
- : xd->f ? "FILE" : "NONE",
- xd->indent,
- !xd->prefix ? "NULL" : !*xd->prefix ? "EMPTY" : "DEFINED",
- !xd->eol ? "NULL"
- : !*xd->eol ? "EMPTY"
- : !strcmp(xd->eol,"\n") ? "LF"
- : !strcmp(xd->eol,"\r") ? "CR"
- : !strcmp(xd->eol,"\r\n") ? "CR+LF"
- : "DEFINED",
- colset->reset );
- fprintf(f,
- "%*s%s" "Bytes/line: %smin=%u, max=%u%s\n"
- "%*s%s" " =>: %sbytes/column = %u, columns/line = %u, bytes/line = %u%s\n"
- "%*s%s" "Extra space: %severy %u column => every %u column%s\n",
- indent,"", colset->name, colset->value,
- xd->min_width, xd->max_width,
- colset->reset,
- indent,"", colset->name, colset->value,
- xd->bytes_per_col, xd->cols_per_line, xd->bytes_per_line,
- colset->reset,
- indent,"", colset->name, colset->value,
- xd->extra_space, xd->col_space,
- colset->reset );
- if (xd->mode_ignore)
- fprintf(f,
- "%*s" "%sNULL bytes: %sPrint a summary for lines with NULL bytes only.%s\n",
- indent,"", colset->name, colset->value, colset->reset );
- fprintf(f,
- "%*s%s" "Functions: %sdump=%s, output=%s, endian=%s%s\n",
- indent,"", colset->name, colset->value,
- !xd->dump_func ? "-" : "SET",
- !xd->out_func ? "-"
- : xd->out_func == XDumpStandardOutput
- ? "STANDARD" : "SET",
- !xd->endian_func ? "-"
- : xd->endian_func == &le_func ? "LITTLE"
- : xd->endian_func == &be_func ? "BIG"
- : "SET",
- colset->reset );
- fprintf(f,
- "%*s%s" "User param: %sint=%d, ptr=%s%s\n",
- indent,"", colset->name, colset->value,
- xd->user_int, xd->user_ptr ? "SET" : "-",
- colset->reset );
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// dump interface ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- static void SetupRemainder
- ( XDump_t *xd, const XDump_t *src, XDumpCommand_t cmd, uint size )
- {
- DASSERT(xd);
- DASSERT(src);
- memcpy(xd,src,sizeof(*xd));
- xd->format = XDUMPF_INT_1;
- xd->start_addr = xd->addr;
- xd->assumed_size = size;
- xd->min_width = size;
- xd->max_width = size;
- xd->extra_space = 0;
- xd->mode_align = false;
- xd->mode_ignore = false;
- if (xd->print_text)
- xd->min_number_fw = xd->last_number_fw;
- SetupXDump(xd,cmd);
- }
- ///////////////////////////////////////////////////////////////////////////////
- static int XDumpHelper
- (
- // returns <0 on error, or number of dumped bytes
- XDump_t *xd, // params; SetupXDump() already done!
- const void *data, // data to dump
- uint size, // size of 'data'
- bool term // false: print only whole lines
- // true: print complete data
- )
- {
- DASSERT(xd);
- DASSERT(data||!size);
- PrintFormat(xd,0);
- int stat = xd->dump_func(xd,data,size,term);
- if ( stat < 0 )
- return stat;
- if (term)
- {
- PrintNullSummary(xd);
- if ( stat < size )
- {
- XDump_t local;
- SetupRemainder(&local,xd,XDUMPC_DUMP,size-stat);
- PrintFormat(&local,0);
- int stat2 = local.dump_func(&local,data+stat,local.min_width,term);
- xd->addr = local.addr;
- xd->written = local.written;
- if ( stat2 < 0 )
- return stat2;
- stat += stat2;
- }
- if ( xd->f && xd->print_summary )
- {
- fprintf(xd->f,"%s%*s",xd->prefix,xd->indent,"");
- if ( xd->print_addr )
- {
- if (xd->mode_c)
- fprintf(xd->f,"//%*llx// [%llu Bytes]%s",
- xd->addr_fw, xd->addr,
- xd->written, xd->eol );
- else
- fprintf(xd->f,"%*llx:%s [%llu Bytes]%s",
- xd->addr_fw, xd->addr,
- xd->extra_space >= 0 ? " " : "",
- xd->written, xd->eol );
- }
- else
- {
- if (xd->mode_c)
- fprintf(xd->f,"// [%llu Bytes]%s",
- xd->written, xd->eol );
- else
- fprintf(xd->f,"%s [%llu Bytes]%s",
- xd->extra_space >= 0 ? " " : "",
- xd->written, xd->eol );
- }
- }
- }
- return stat;
- }
- ///////////////////////////////////////////////////////////////////////////////
- int XDump
- (
- // returns <0 on error, or number of dumped bytes
- XDump_t *xd, // params; if NULL: use local version
- const void *data, // data to dump
- uint size, // size of 'data'
- bool term // false: print only whole lines
- // true: print complete data
- )
- {
- XDump_t local_xd;
- if (!xd)
- {
- InitializeXDump(&local_xd);
- xd = &local_xd;
- }
- SetupXDump(xd,XDUMPC_DUMP);
- return XDumpHelper(xd,data,size,term);
- }
- ///////////////////////////////////////////////////////////////////////////////
- int XDumpByFile
- (
- // returns <0 on error, or number of dumped bytes
- XDump_t *xd, // params; if NULL: use local version
- FILE *f, // input file
- u64 max_size // >0: limit size to print
- )
- {
- DASSERT(f);
- XDump_t local_xd;
- if (!xd)
- {
- InitializeXDump(&local_xd);
- xd = &local_xd;
- }
- SetupXDump(xd,XDUMPC_DUMP);
- char buf[0x4100];
- uint start = 0;
- if (!max_size)
- max_size = M1(max_size);
- uint count = 0;
- while ( max_size > 0 )
- {
- uint max_read = ( sizeof(buf) - start ) / 0x1000 * 0x1000;
- if ( max_read > max_size )
- max_read = max_size;
- size_t stat = fread(buf+start,1,max_read,f);
- if (!stat)
- break;
- max_size -= stat;
- stat += start;
- int dstat = XDumpHelper(xd,buf,stat,false);
- if ( dstat < 0 )
- return dstat;
- count += dstat;
- start = stat - dstat;
- if (start)
- memmove(buf,buf+dstat,start);
- }
- int dstat = XDumpHelper(xd,buf,start,true);
- return dstat < 0 ? dstat : count + dstat;
- }
- ///////////////////////////////////////////////////////////////////////////////
- int XDump16 // wrapper for a standard hexdump
- (
- // returns <0 on error, or number of dumped bytes
- FILE *f_out, // output file
- int indent, // indention
- u64 addr, // start address
- const void *data, // data
- uint size // size of 'data'
- )
- {
- XDump_t xd;
- InitializeXDump(&xd);
- xd.f = f_out;
- xd.indent = indent;
- xd.start_addr = addr;
- xd.assumed_size = size;
- return XDump(&xd,data,size,true);
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// diff interface ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- typedef struct XDiff_t
- {
- const void *data; // data to compare
- uint size; // size of 'data'
- bool term; // 'data' reached end
- XDump_t xd; // dump parameters
- //--- buffers to catch output
- char num_buf[XDUMP_GOOD_NUM_BUF_SIZE+4];
- char text_buf[XDUMP_GOOD_TEXT_BUF_SIZE];
- }
- XDiff_t;
- ///////////////////////////////////////////////////////////////////////////////
- static int XDiffCatchOutput
- (
- struct XDump_t *xd, // internal copy of params
- ccp prefix, // NULL or additional prefix (used by diff)
- ccp dump, // dump to print
- ccp text // text to print
- )
- {
- DASSERT(xd);
- DASSERT(dump);
- DASSERT(text);
- XDiff_t *diff = xd->user_ptr;
- DASSERT(diff);
- StringCopyS(diff->num_buf,sizeof(diff->num_buf),dump);
- StringCopyS(diff->text_buf,sizeof(diff->text_buf),text);
- return 0;
- }
- ///////////////////////////////////////////////////////////////////////////////
- static void SetupXDiff
- (
- XDiff_t *xdiff, // data to setup
- XDump_t *xd, // NULL or template
- const void *data, // data to compare
- uint size, // size of 'data'
- bool term // 'data' reached end
- )
- {
- DASSERT(xdiff);
- xdiff->data = data;
- xdiff->size = size;
- xdiff->term = term;
- *xdiff->num_buf = *xdiff->text_buf = 0;
- if (xd)
- memcpy(&xdiff->xd,xd,sizeof(xdiff->xd));
- else
- InitializeXDump(&xdiff->xd);
- xd = &xdiff->xd;
- SetupXDump(xd,XDUMPC_DIFF);
- xd->user_ptr = xdiff;
- xd->out_func = XDiffCatchOutput;
- xd->mode_ignore = false;
- }
- ///////////////////////////////////////////////////////////////////////////////
- static bool XDiffText
- (
- // returns true if differ
- XDump_t *xd, // original params; SetupXDump() already done!
- XDiff_t *d1, // first diff file
- XDiff_t *d2, // second diff file
- bool colorize // true: use red and green on output
- )
- {
- DASSERT(xd);
- DASSERT(d1);
- DASSERT(d2);
- char *n1 = d1->num_buf;
- char *n2 = d2->num_buf;
- int len1 = strlen(n1);
- int len2 = strlen(n2);
- if ( len1 < len2 )
- {
- memset( n1 + len1, ' ', len2-len1 );
- n1[len2] = 0;
- len1 = len2;
- }
- else if ( len1 > len2 )
- {
- memset( n2 + len2, ' ', len1-len2 );
- n2[len1] = 0;
- }
- if ( xd->min_number_fw < len1 )
- xd->min_number_fw = len1;
- if (!strcmp(n1,n2))
- return false;
- for(;;)
- {
- while ( *n1 == ' ' && *n2 == ' ' )
- n1++, n2++;
- if ( !*n1 || !*n2 )
- break;
- char *x = n2;
- while ( (u8)*n2 > ' ' && *n1 == *n2 && *n2 != '/' && *n2 != '/' )
- n1++, n2++;
- if ( n2 > x && (u8)*n2 <= ' ' )
- {
- while ( x < n2 )
- *x++ = ' ';
- x[-1] = '.';
- }
- else
- while ( (u8)*n1 > ' ' || (u8)*n2 > ' ' )
- n1++, n2++;
- }
- xd->out_func(xd,"< ",d1->num_buf,d1->text_buf);
- xd->out_func(xd,"> ",d2->num_buf,d2->text_buf);
- if ( xd->f && xd->print_diff_sep )
- fputs(xd->eol,xd->f);
- xd->diff_count++;
- return true;
- }
- ///////////////////////////////////////////////////////////////////////////////
- #undef OPTIMIZED_SEARCH
- #define OPTIMIZED_SEARCH 0
- static int XDiffHelper
- (
- // returns <0 on error, or number of dumped bytes
- XDump_t *xd, // original params; SetupXDump() already done!
- XDiff_t *d1, // first diff file
- XDiff_t *d2, // second diff file
- uint limit_lines, // >0: limit number of differ-lines
- bool colorize // true: use red and green on output
- )
- {
- DASSERT(xd);
- DASSERT(d1);
- DASSERT(d2);
- DASSERT( d1->xd.bytes_per_col == d1->xd.bytes_per_col );
- DASSERT( d1->xd.bytes_per_line == d1->xd.bytes_per_line );
- DASSERT( d1->xd.format == d1->xd.format );
- //--- size calculations & setup
- uint count = 0;
- int size1 = d1->size;
- int size2 = d2->size;
- if ( !d1->term && !d2->term )
- {
- if ( size1 < size2 )
- size2 = size1;
- else if ( size1 > size2 )
- size1 = size2;
- }
- if (!d1->term)
- size1 = size1 / xd->bytes_per_line * xd->bytes_per_line;
- if (!d2->term)
- size2 = size2 / xd->bytes_per_line * xd->bytes_per_line;
- const u8 *p1 = d1->data;
- const u8 *p2 = d2->data;
- const u64 *save_addr_break = xd->addr_break;
- const u64 *addr_break = save_addr_break;
- xd->addr_break = 0;
- //--- main loop
- int done = 0;
- while ( size1 > 0 && size2 > 0
- || !done && ( size1 > 0 || size2 > 0 ) )
- {
- //--- optimized search
- #if OPTIMIZED_SEARCH
- uint same = CountEqual(p1,p2, size1 < size2 ? size1 : size2 );
- if ( same >= xd->bytes_per_line )
- {
- same = same / xd->bytes_per_line * xd->bytes_per_line;
- p1 += same;
- p2 += same;
- xd->addr += same;
- count += same;
- size1 -= same;
- size2 -= same;
- }
- #endif
- //---
- int dumpsize1 = size1 < (int)xd->bytes_per_line ? size1 : xd->bytes_per_line;
- int dumpsize2 = size2 < (int)xd->bytes_per_line ? size2 : xd->bytes_per_line;
- bool have_break = false;
- if (addr_break)
- {
- while ( *addr_break && xd->addr >= *addr_break )
- addr_break++;
- if (!*addr_break)
- addr_break = 0;
- else
- {
- const s64 max = *addr_break - xd->addr;
- if ( dumpsize1 > max || dumpsize2 > max )
- {
- have_break = true;
- if ( dumpsize1 > max ) dumpsize1 = max;
- if ( dumpsize2 > max ) dumpsize2 = max;
- }
- }
- }
- #if !OPTIMIZED_SEARCH
- const uint diffsize = dumpsize1 < dumpsize2 ? dumpsize1 : dumpsize2;
- #endif
- uint donesize = dumpsize1 > dumpsize2 ? dumpsize1 : dumpsize2;
- //DEL fprintf(stderr,">>> %d,%d done=%d, donesize=%d, diffsize=%d\n",size1,size2,done,donesize,diffsize);
- #if !OPTIMIZED_SEARCH
- if ( diffsize > 0
- && ( diffsize < xd->bytes_per_line || memcmp(p1,p2,diffsize) ))
- #endif
- {
- if ( dumpsize1 != dumpsize2 && !xd->diff_size )
- {
- xd->diff_size = dumpsize1 - dumpsize2;
- if (xd->diff_size)
- xd->diff_count++;
- }
- if ( dumpsize1 >= (int)xd->bytes_per_col )
- {
- const int stat = xd->dump_func(&d1->xd,p1,dumpsize1,true);
- if ( stat >= 0 && stat < dumpsize1 && donesize > stat )
- donesize = stat;
- }
- else if ( dumpsize1 > 0 )
- {
- SetupRemainder(&d1->xd,&d1->xd,XDUMPC_DIFF,dumpsize1);
- d1->xd.dump_func(&d1->xd,p1,dumpsize1,true);
- }
- else
- {
- done++;
- strcpy(d1->num_buf,"/");
- *d1->text_buf = 0;
- }
- if ( dumpsize2 >= (int)xd->bytes_per_col )
- {
- const int stat = xd->dump_func(&d2->xd,p2,dumpsize2,true);
- if ( stat >= 0 && stat < dumpsize2 && donesize > stat )
- donesize = stat;
- }
- else if ( dumpsize2 > 0 )
- {
- SetupRemainder(&d2->xd,&d2->xd,XDUMPC_DIFF,dumpsize2);
- d2->xd.dump_func(&d2->xd,p2,dumpsize2,true);
- }
- else
- {
- done++;
- strcpy(d2->num_buf,"/");
- *d2->text_buf = 0;
- }
- XDiffText(xd,d1,d2,colorize);
- if ( limit_lines && !--limit_lines )
- break;
- }
- p1 += donesize;
- p2 += donesize;
- xd->addr += donesize;
- count += donesize;
- size1 -= donesize;
- size2 -= donesize;
- if (have_break)
- {
- if (!d1->term)
- size1 = size1 / xd->bytes_per_line * xd->bytes_per_line;
- if (!d2->term)
- size2 = size2 / xd->bytes_per_line * xd->bytes_per_line;
- }
- }
- xd->addr_break = save_addr_break;
- return count;
- }
- ///////////////////////////////////////////////////////////////////////////////
- int XDiff
- (
- // returns <0 on error, or number of dumped bytes
- XDump_t *xd, // params; if NULL: use local version
- const void *data1, // data1 to compare
- uint size1, // size of 'data1'
- bool term1, // true: 'data1' completed
- const void *data2, // data2 to compare
- uint size2, // size of 'data2'
- bool term2, // true: 'data2' completed
- uint limit_lines, // >0: limit number of differ-lines
- bool colorize // true: use red and green on output
- )
- {
- // fast test for identical data
- if ( term1 && term2 && size1 == size2 && ( !size1 || !memcmp(data1,data2,size1) ))
- return 0;
- XDump_t local_xd;
- if (!xd)
- {
- InitializeXDump(&local_xd);
- xd = &local_xd;
- }
- SetupXDump(xd,XDUMPC_DIFF);
- XDiff_t diff1, diff2;
- SetupXDiff(&diff1,xd,data1,size1,term1);
- SetupXDiff(&diff2,xd,data2,size2,term2);
- return XDiffHelper(xd,&diff1,&diff2,limit_lines,colorize);
- }
- ///////////////////////////////////////////////////////////////////////////////
- int XDiffByFile
- (
- // returns <0 on error, or number of dumped bytes
- XDump_t *xd, // params; if NULL: use local version
- FILE *f1, // first input file
- FILE *f2, // second input file
- u64 max_size, // >0: limit comparing size
- uint limit_lines, // >0: limit number of differ-lines
- bool colorize // true: use red and green on output
- )
- {
- DASSERT(f1);
- DASSERT(f2);
- XDump_t local_xd;
- if (!xd)
- {
- InitializeXDump(&local_xd);
- xd = &local_xd;
- }
- SetupXDump(xd,XDUMPC_DIFF);
- char buf1[0x4100];
- char buf2[sizeof(buf1)];
- XDiff_t diff1, diff2;
- SetupXDiff(&diff1,xd,buf1,0,false);
- SetupXDiff(&diff2,xd,buf2,0,false);
- uint start1 = 0, start2 = 0;
- if (!max_size)
- max_size = M1(max_size);
- uint count = 0;
- while ( max_size > 0 )
- {
- uint max_read1 = ( sizeof(buf1) - start1 ) / 0x1000 * 0x1000;
- if ( max_read1 > max_size )
- max_read1 = max_size;
- size_t stat1 = fread(buf1+start1,1,max_read1,f1);
- uint max_read2 = ( sizeof(buf2) - start2 ) / 0x1000 * 0x1000;
- if ( max_read2 > max_size )
- max_read2 = max_size;
- size_t stat2 = fread(buf2+start2,1,max_read2,f2);
- uint stat = stat1 < stat2 ? stat1 : stat2;
- max_size -= stat;
- diff1.size = stat1 + start1;
- diff1.term = !stat1;
- diff2.size = stat2 + start2;
- diff2.term = !stat2;
- int dstat = XDiffHelper(xd,&diff1,&diff2,limit_lines,colorize);
- if ( dstat <= 0 )
- return dstat;
- count += dstat;
- if (xd->diff_size)
- return count;
- start1 = stat1 + start1 - dstat;
- if (start1)
- memmove(buf1,buf1+dstat,start1);
- start2 = stat2 + start2 - dstat;
- if (start2)
- memmove(buf2,buf2+dstat,start2);
- }
- return count;
- }
- ///////////////////////////////////////////////////////////////////////////////
- int XDiff16
- (
- // returns <0 on error, or number of dumped bytes
- FILE *f_out, // output file
- int indent, // indention
- u64 addr, // start address
- const void *data1, // data
- uint size1, // size of 'data'
- const void *data2, // data
- uint size2, // size of 'data'
- uint limit_lines, // >0: limit number of differ-lines
- bool colorize // true: use red and green on output
- )
- {
- XDump_t xd;
- InitializeXDump(&xd);
- xd.f = f_out;
- xd.indent = indent;
- xd.start_addr = addr;
- xd.assumed_size = size1 > size2 ? size1 : size2;
- return XDiff( &xd, data1,size1,true,
- data2,size2,true, limit_lines, colorize );
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// scan interface ///////////////
- ///////////////////////////////////////////////////////////////////////////////
- // [[XScan_t]]
- typedef struct XScan_t
- {
- FastBuf_t *dest; // not NULL: append scanned data here & ignore 'fout'
- FILE *fout; // valid output file
- u64 written; // number of written bytes
- bool auto_format; // true: detect '#FORMAT:'
- XDumpFormat_t format; // current scan format
- dcEndian_t endian; // current endian
- uint num_base; // 8:octal, 10:decimal, 16:hexadecimal
- ccp num_allowed; // string with allowed first characters
- ccp prefix; // not NULL: skip this prefix
- uint prefix_len; // length of prefix
- const endian_func_t *endian_func; // endian functions
- }
- XScan_t;
- ///////////////////////////////////////////////////////////////////////////////
- static void UpdateXScan ( XScan_t *scan )
- {
- DASSERT(scan);
- if ( !scan->dest && !scan->fout )
- scan->fout = stdout;
- if (scan->prefix)
- {
- ccp prefix = scan->prefix;
- while ( *prefix > 0 && *prefix <= ' ' )
- prefix++;
- scan->prefix = *prefix ? prefix : 0;
- scan->prefix_len = strlen(prefix);
- }
- else
- scan->prefix_len = 0;
- scan->endian_func = scan->endian == DC_LITTLE_ENDIAN ? &le_func : &be_func;
- if ( scan->format == XDUMPF_AUTO )
- scan->format = XDUMPF_INT_1;
- if ( scan->num_base < 2 || scan->num_base > 36 )
- scan->num_base = 16;
- scan->num_allowed
- = scan->format == XDUMPF_FLOAT || scan->format == XDUMPF_DOUBLE
- ? "+-."
- : "+-~!";
- }
- ///////////////////////////////////////////////////////////////////////////////
- static void SetupXScan
- (
- XScan_t *scan, // data to setup
- XDump_t *xd, // NULL or template
- FastBuf_t *dest // not NULL: append scanned data here
- )
- {
- DASSERT(scan);
- memset(scan,0,sizeof(*scan));
- if (xd)
- {
- scan->fout = xd->f;
- scan->auto_format = xd->format == XDUMPF_AUTO;
- scan->format = xd->format;
- scan->endian = xd->endian;
- scan->num_base = xd->mode_dec ? 10 : 16;
- scan->prefix = xd->prefix;
- }
- else
- {
- scan->fout = stdout;
- scan->auto_format = true;
- scan->format = XDUMPF_INT_1;
- scan->endian = DC_DEFAULT_ENDIAN;
- scan->num_base = 16;
- scan->prefix = 0;
- }
- scan->dest = dest;
- UpdateXScan(scan);
- }
- ///////////////////////////////////////////////////////////////////////////////
- static void XScanFormat
- (
- // returns <0 on error, or number of dumped bytes
- XScan_t *scan, // valid scan parameters
- ccp src, // source pointer
- ccp eol // end of line
- )
- {
- DASSERT(scan);
- DASSERT(src);
- DASSERT(eol);
- DASSERT( src <= eol );
- noPRINT(stderr,"FORMAT: %.*s\n",(int)(eol-src),src);
- enum { MD_HEX, MD_DEC, MD_OCT, MD_NUM, MD_ENDIAN };
- static const KeywordTab_t keytab[] =
- {
- { MD_HEX, "HEX", 0, XDUMPF_AUTO },
- { MD_HEX, "HEX-1", "HEX1", XDUMPF_INT_1 },
- { MD_HEX, "HEX-2", "HEX2", XDUMPF_INT_2 },
- { MD_HEX, "HEX-3", "HEX3", XDUMPF_INT_3 },
- { MD_HEX, "HEX-4", "HEX4", XDUMPF_INT_4 },
- { MD_HEX, "HEX-5", "HEX5", XDUMPF_INT_5 },
- { MD_HEX, "HEX-6", "HEX6", XDUMPF_INT_6 },
- { MD_HEX, "HEX-7", "HEX7", XDUMPF_INT_7 },
- { MD_HEX, "HEX-8", "HEX8", XDUMPF_INT_8 },
- { MD_DEC, "DEC", 0, XDUMPF_AUTO },
- { MD_DEC, "DEC-1", "DEC1", XDUMPF_INT_1 },
- { MD_DEC, "DEC-2", "DEC2", XDUMPF_INT_2 },
- { MD_DEC, "DEC-3", "DEC3", XDUMPF_INT_3 },
- { MD_DEC, "DEC-4", "DEC4", XDUMPF_INT_4 },
- { MD_DEC, "DEC-5", "DEC5", XDUMPF_INT_5 },
- { MD_DEC, "DEC-6", "DEC6", XDUMPF_INT_6 },
- { MD_DEC, "DEC-7", "DEC7", XDUMPF_INT_7 },
- { MD_DEC, "DEC-8", "DEC8", XDUMPF_INT_8 },
- { MD_OCT, "OCT", 0, XDUMPF_AUTO },
- { MD_OCT, "OCT-1", "OCT1", XDUMPF_INT_1 },
- { MD_OCT, "OCT-2", "OCT2", XDUMPF_INT_2 },
- { MD_OCT, "OCT-3", "OCT3", XDUMPF_INT_3 },
- { MD_OCT, "OCT-4", "OCT4", XDUMPF_INT_4 },
- { MD_OCT, "OCT-5", "OCT5", XDUMPF_INT_5 },
- { MD_OCT, "OCT-6", "OCT6", XDUMPF_INT_6 },
- { MD_OCT, "OCT-7", "OCT7", XDUMPF_INT_7 },
- { MD_OCT, "OCT-8", "OCT8", XDUMPF_INT_8 },
- { MD_NUM, "1", 0, XDUMPF_INT_1 },
- { MD_NUM, "2", 0, XDUMPF_INT_2 },
- { MD_NUM, "3", 0, XDUMPF_INT_3 },
- { MD_NUM, "4", 0, XDUMPF_INT_4 },
- { MD_NUM, "5", 0, XDUMPF_INT_5 },
- { MD_NUM, "6", 0, XDUMPF_INT_6 },
- { MD_NUM, "7", 0, XDUMPF_INT_7 },
- { MD_NUM, "8", 0, XDUMPF_INT_8 },
- { MD_NUM, "FLOAT", 0, XDUMPF_FLOAT },
- { MD_NUM, "DOUBLE", 0, XDUMPF_DOUBLE },
- { MD_ENDIAN, "LE", "LITTLE", DC_LITTLE_ENDIAN },
- { MD_ENDIAN, "BE", "BIG", DC_BIG_ENDIAN },
- {0,0,0,0}
- };
- for(;;)
- {
- while ( src < eol && !isalnum((int)*src) )
- src++;
- char namebuf[20], *name = namebuf;
- while ( src < eol && (u8)*src > ' ' )
- {
- if ( name < namebuf + sizeof(namebuf) - 1 )
- *name++ = toupper((int)*src);
- src++;
- }
- *name = 0;
- if ( name == namebuf )
- break;
- noPRINT(stderr,"SCAN FORMAT: %s\n",namebuf);
- const KeywordTab_t *key = ScanKeyword(0,namebuf,keytab);
- if (!key)
- continue;
- XDumpFormat_t format = key->opt;
- switch(key->id)
- {
- case MD_HEX:
- scan->num_base = 16;
- break;
- case MD_DEC:
- scan->num_base = 10;
- break;
- case MD_OCT:
- scan->num_base = 8;
- break;
- case MD_NUM:
- break;
- case MD_ENDIAN:
- scan->endian = key->opt;
- format = XDUMPF_AUTO;
- break;
- }
- if ( format != XDUMPF_AUTO )
- scan->format = format;
- noPRINT(stderr,"F: %lld %lld => base=%d, format=%d, endian=%d\n",
- key->id, key->opt,
- scan->num_base, scan->format, scan->endian );
- }
- UpdateXScan(scan);
- }
- ///////////////////////////////////////////////////////////////////////////////
- static size_t XScanHelper
- (
- // returns <0 on error, or number of dumped bytes
- XScan_t *scan, // valid scan parameters
- ccp source, // source pointer
- ccp end, // end of source
- bool term, // true: accept uncomplete last line
- u64 max_size // >0: limit output size
- )
- {
- DASSERT(scan);
- DASSERT( scan->dest || scan->fout );
- DASSERT(source);
- DASSERT(end);
- DASSERT( source <= end );
- if (!max_size)
- max_size = M1(max_size);
- max_size -= scan->written;
- ccp src = source;
- u8 destbuf[0x4000+10];
- u8 *destmax = destbuf + sizeof(destbuf) - 10;
- u8 *dest = destbuf;
- while ( src < end && max_size > 0 )
- {
- //--- skip all leading contral characters
- while ( src < end && (u8)*src <= ' ' )
- src++;
- //--- find end of line
- bool found_eol = term;
- ccp eol = src;
- while ( eol < end )
- {
- const u8 ch = *eol;
- if ( !ch || ch == '\n' || ch == '\r' )
- {
- found_eol = true;
- break;
- }
- eol++;
- }
- if (!found_eol)
- break;
- PRINT0("LINE: |%.*s|\n",(int)(eol-src),src);
- //--- skip prefix
- if ( scan->prefix_len
- && scan->prefix_len <= eol-src
- && !memcmp(scan->prefix,src,scan->prefix_len) )
- {
- src += scan->prefix_len;
- while ( src < eol && (u8)*src <= ' ' )
- src++;
- }
- if ( src == eol )
- continue;
- //--- check for "#FORMAT:"
- if (!strncasecmp(src,"#FORMAT:",8))
- {
- if (scan->auto_format)
- XScanFormat(scan,src+8,eol);
- src = eol;
- continue;
- }
- //--- skip address column
- ccp ptr = src;
- while ( ptr < eol && isalnum((int)*ptr) )
- ptr++;
- noPRINT(stderr,"ADDR: |%.*s|\n",(int)(ptr-src),src);
- if ( ptr > src && ptr < eol && *ptr == ':' )
- src = ptr + 1;
- //--- scan numbers until unknown character
- noPRINT(stderr,"SCAN: |%.*s| base=%d\n",(int)(eol-src),src,scan->num_base);
- for(;;)
- {
- while ( src < eol && ( (u8)*src <= ' ' || *src == ',' ) )
- src++;
- if ( src == eol
- || (u8)TableNumbers[(u8)*src] >= scan->num_base
- && !strchr(scan->num_allowed,*src) )
- {
- break;
- }
- if ( dest >= destmax )
- {
- size_t len = dest - destbuf;
- if ( len > max_size )
- len = max_size;
- if (scan->dest)
- AppendFastBuf(scan->dest,destbuf,len);
- else
- fwrite(destbuf,1,len,scan->fout);
- max_size -= len;
- scan->written += len;
- dest = destbuf;
- }
- //u64 num;
- //double d;
- char *end;
- switch(scan->format)
- {
- case XDUMPF_INT_2:
- scan->endian_func->wr16(dest,str2ll(src,&end,scan->num_base));
- dest += 2;
- break;
- case XDUMPF_INT_3:
- scan->endian_func->wr24(dest,str2ll(src,&end,scan->num_base));
- dest += 3;
- break;
- case XDUMPF_INT_4:
- scan->endian_func->wr32(dest,str2ll(src,&end,scan->num_base));
- dest += 4;
- break;
- case XDUMPF_INT_5:
- scan->endian_func->wr40(dest,str2ll(src,&end,scan->num_base));
- dest += 5;
- break;
- case XDUMPF_INT_6:
- scan->endian_func->wr48(dest,str2ll(src,&end,scan->num_base));
- dest += 6;
- break;
- case XDUMPF_INT_7:
- scan->endian_func->wr56(dest,str2ll(src,&end,scan->num_base));
- dest += 7;
- break;
- case XDUMPF_INT_8:
- scan->endian_func->wr64(dest,str2ll(src,&end,scan->num_base));
- dest += 8;
- break;
- case XDUMPF_FLOAT:
- scan->endian_func->wrf4(dest,strtod(src,&end));
- dest += 4;
- break;
- case XDUMPF_DOUBLE:
- scan->endian_func->wrf8(dest,strtod(src,&end));
- dest += 8;
- break;
- default:
- *dest++ = str2ll(src,&end,scan->num_base);
- break;
- }
- if ( src == end )
- break;
- src = end;
- }
- //--- prepare next line
- src = eol;
- }
- if ( dest > destbuf )
- {
- size_t len = dest - destbuf;
- if ( len > max_size )
- len = max_size;
- if (scan->dest)
- AppendFastBuf(scan->dest,destbuf,len);
- else
- fwrite(destbuf,1,len,scan->fout);
- scan->written += len;
- }
- return src - source;
- }
- ///////////////////////////////////////////////////////////////////////////////
- int XScan
- (
- // returns <0 on error, or number of dumped bytes
- XDump_t *xd, // params; if NULL: use local version
- FastBuf_t *dest, // not NULL: append scanned data here
- const void *data, // data to scan
- uint size, // size of 'data'
- bool term, // true: accept uncomplete last line
- u64 max_size // >0: limit output size
- )
- {
- if ( !data || !size )
- return 0;
- XScan_t scan;
- SetupXScan(&scan,xd,dest);
- return XScanHelper(&scan,data,data+size,term,max_size);
- }
- ///////////////////////////////////////////////////////////////////////////////
- s64 XScanByFile
- (
- // returns <0 on error, or number of written bytes
- XDump_t *xd, // params; if NULL: use local version
- FastBuf_t *dest, // not NULL: append scanned data here
- FILE *f, // input file
- u64 max_size // >0: limit output size
- )
- {
- if (!f)
- return 0;
- if (!max_size)
- max_size = M1(max_size);
- XScan_t scan;
- SetupXScan(&scan,xd,dest);
- char buf[0x4100];
- uint start = 0;
- while ( scan.written < max_size )
- {
- const uint max_read = ( sizeof(buf) - start ) / 0x1000 * 0x1000;
- size_t stat = fread(buf+start,1,max_read,f);
- if (!stat)
- break;
- stat += start;
- const bool eof = feof(f) != 0;
- int scanstat = XScanHelper(&scan,buf,buf+stat,eof,max_size);
- if ( scanstat < 0 )
- return scanstat;
- start = stat - scanstat;
- if (start)
- memmove(buf,buf+scanstat,start);
- if (eof)
- break;
- }
- if (start)
- {
- int scanstat = XScanHelper(&scan,buf,buf+start,true,max_size);
- if ( scanstat < 0 )
- return scanstat;
- }
- return scan.written;
- }
- //
- ///////////////////////////////////////////////////////////////////////////////
- /////////////// END ///////////////
- ///////////////////////////////////////////////////////////////////////////////
|