aboutsummaryrefslogtreecommitdiff
path: root/project/src/wtest.c
diff options
context:
space:
mode:
authorroot <root@dc13.lemmi>2020-07-21 10:00:46 +0200
committerroot <root@dc13.lemmi>2020-07-21 10:00:46 +0200
commit1192c4575ea7afdf38e3fa0df4587a08620af11e (patch)
tree6910a62487c282d0840d2e668aa7eb40b7c8a3fd /project/src/wtest.c
parent76de8a89f7c1d1b4522eb66e8f89d248e8c1781f (diff)
SZS v2.18a
Diffstat (limited to '')
-rw-r--r--project/src/wtest.c3935
1 files changed, 3935 insertions, 0 deletions
diff --git a/project/src/wtest.c b/project/src/wtest.c
new file mode 100644
index 0000000..7d94158
--- /dev/null
+++ b/project/src/wtest.c
@@ -0,0 +1,3935 @@
+
+/***************************************************************************
+ * _______ _______ _______ *
+ * | ___ |____ | ___ | *
+ * | | |_| / /| | |_| *
+ * | |_____ / / | |_____ *
+ * |_____ | / / |_____ | *
+ * _ | | / / _ | | *
+ * | |___| |/ /____| |___| | *
+ * |_______|_______|_______| *
+ * *
+ * Wiimms SZS Tools *
+ * https://szs.wiimm.de/ *
+ * *
+ ***************************************************************************
+ * *
+ * This file is part of the SZS project. *
+ * Visit https://szs.wiimm.de/ for project details and sources. *
+ * *
+ * Copyright (c) 2011-2020 by Dirk Clemens <wiimm@wiimm.de> *
+ * *
+ ***************************************************************************
+ * *
+ * This program is free software; you can redistribute it and/or modify *
+ * it under the terms of the GNU General Public License as published by *
+ * the Free Software Foundation; either version 2 of the License, or *
+ * (at your option) any later version. *
+ * *
+ * This program is distributed in the hope that it will be useful, *
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
+ * GNU General Public License for more details. *
+ * *
+ * See file gpl-2.0.txt or http://www.gnu.org/licenses/gpl-2.0.txt *
+ * *
+ ***************************************************************************/
+
+#define _GNU_SOURCE 1
+
+#include <math.h>
+#include <dirent.h>
+#include <stddef.h>
+#include <time.h>
+//#include <sys/stat.h>
+//#include <fcntl.h>
+
+#include "dclib-debug.h"
+#include "version.h"
+#include "lib-std.h"
+#include "lib-image.h"
+#include "lib-object.h"
+#include "lib-kmp.h"
+#include "lib-brres.h"
+#include "lib-mdl.h"
+#include "lib-bzip2.h"
+#include "lib-mkw.h"
+#include "lib-bmg.h"
+#include "lib-lecode.h"
+#include "lib-common.h"
+
+#define CMD1_FW 13
+
+#if HAVE_PCRE || 1
+ #include "dclib-regex.h"
+#endif
+
+#ifdef HAVE_WIIMM_EXT
+ #include "wtest+.c"
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+
+#define NAME "wtest"
+#undef TITLE
+#define TITLE NAME " v" VERSION " r" REVISION " " SYSTEM " - " AUTHOR " - " DATE
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// helpers ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static void print_title ( FILE * f )
+{
+ static bool done = false;
+ if (!done)
+ {
+ done = true;
+ if ( verbose >= 1 && f == stdout )
+ fprintf(f,"\n%s\n\n",TITLE);
+ else
+ fprintf(f,"***** %s *****\n",TITLE);
+ }
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_float() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_float ( int argc, char ** argv )
+{
+ uint i;
+ for ( i = 1; i < argc; i++ )
+ {
+ char buf[5];
+ memset(buf,0,sizeof(buf));
+ strncpy(buf,argv[i],4);
+ float f = bef4(buf);
+ printf(" |%s| %11.8f %11.8e %11.8a |%.4s|\n",buf,f,f,f,(ccp)&f);
+ }
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// create_float_tab() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError create_float_tab()
+{
+ union { float f; u32 i; } u;
+ uint i;
+ for ( i = 1; i <= 100; i += 5 )
+ {
+ uint j;
+ for ( j = i; j <i+5; j++ )
+ {
+ u.f = j;
+ printf("0x%8x, ",u.i);
+ }
+ printf(" // %2u .. %2u\n",i,i+4);
+ }
+
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_matrix() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static inline double GetRandomD ( double range )
+{
+ return ( MyRandom(200000001) * 1e-8 - 1.0 ) * range;
+}
+
+static double3 GetRandomD3 ( double range )
+{
+ double3 res;
+ res.x = GetRandomD(range);
+ res.y = GetRandomD(range);
+ res.z = GetRandomD(range);
+ return res;
+}
+
+static double3 GetRandomD3nn ( double range ) // 'nn' : not null
+{
+ double3 res;
+ res.x = GetRandomD(range); if ( fabs(res.x) < 1e-2 ) res.x = 1.0;
+ res.y = GetRandomD(range); if ( fabs(res.y) < 1e-2 ) res.y = 1.0;
+ res.z = GetRandomD(range); if ( fabs(res.z) < 1e-2 ) res.z = 1.0;
+ return res;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int test_matrix ( int argc, char ** argv )
+{
+ //--- scan param
+
+ uint n_pass = 10;
+ bool verbose = false;
+
+ uint i;
+ for ( i = 1; i < argc; i++ )
+ {
+ if (!strcmp(argv[i],"-v"))
+ verbose = true;
+ else if ( argv[i][0] != '-' )
+ {
+ uint num = strtoul(argv[1],0,10);
+ if ( num > 0 )
+ n_pass = num < 1000000000 ? num : 1000000000;
+ }
+ }
+
+
+ //--- setup test vectors
+
+ PATCH_FILE_MODE = 0; // disable logging
+
+ double3 d = GetRandomD3(15000);
+ double dtab[] = { -10000, -5000, -10000/3.0, 0, 10000.0/3.0,
+ 5000, 10000, d.x, d.y, d.z };
+ #undef N_NUM
+ #define N_NUM (sizeof(dtab)/sizeof(*dtab))
+ #define N_VEC (N_NUM*N_NUM*N_NUM)
+ double3 vtab[N_VEC], *vptr;
+
+ printf("n(numbers)=%zu, n(vectors)=%zu, n(pass)=%u\n",N_NUM,N_VEC,n_pass);
+
+ uint x, y, z;
+ vptr = vtab;
+ for ( x = 0; x < N_NUM; x++ )
+ {
+ printf(" num[%u] = %11.3f\n",x,dtab[x]);
+ for ( y = 0; y < N_NUM; y++ )
+ {
+ for ( z = 0; z < N_NUM; z++ )
+ {
+ DASSERT( vptr < vtab+N_VEC );
+ vptr->x = dtab[x];
+ vptr->y = dtab[y];
+ vptr->z = dtab[z];
+ vptr++;
+ }
+ }
+ }
+ fflush(stdout);
+ DASSERT( vptr == vtab+N_VEC );
+
+ //---
+
+ uint pass, err_count = 0, total_count = 0;
+ for ( pass = 0; pass < n_pass; pass++ )
+ {
+ ResetTransformation();
+ if (pass)
+ {
+ // random setup
+ double3 val, origin;
+
+ val = GetRandomD3nn(10.0);
+ origin = GetRandomD3(1e5);
+ SetScaleMatrixD(&opt_transform,&val,&origin);
+
+ val = GetRandomD3(1e5);
+ SetShiftMatrixD(&opt_transform,&val);
+
+ val = GetRandomD3(1e5);
+ SetTranslateMatrixD(&opt_transform,&val);
+
+ val = GetRandomD3(1000.0);
+ uint xyz;
+ for ( xyz = 0; xyz < 3; xyz++ )
+ {
+ origin = GetRandomD3(1e4);
+ SetRotateMatrixD(&opt_transform,xyz,val.v[xyz],0.0,&origin);
+ }
+ }
+ CloseTransformation();
+ global_check_mode = opt_no_check
+ ? 0
+ : GetCheckMode(false,brief_count>0,!verbose,long_count>0);
+
+ if (verbose)
+ {
+ char buf[60];
+ uint len = snprintf(buf,sizeof(buf),"##### PASS %u/%u [err=%u] #####",
+ pass+1 ,n_pass, err_count );
+ printf("\n%.*s\n%s\n%.*s\n",len,Hash200,buf,len,Hash200);
+ PrintTestMatrix(true);
+ }
+ else if ( pass % 1000 == 999 )
+ printf("##### PASS %u/%u [err=%u] #####\n",pass+1,n_pass,err_count);
+ fflush(stdout);
+
+ int i, fail = -1;
+ for ( i = 0; i < N_VEC; i++ )
+ {
+ total_count++;
+ if (!TestMatrix(vtab+i,1,true))
+ {
+ err_count++;
+ fail = i;
+ }
+ }
+
+ if ( fail >= 0 )
+ {
+ MatrixD_t *m = &opt_transform;
+ printf("\n\n"
+ " --scale %5.3f,%5.3f,%5.3f@%5.3f,%5.3f,%5.3f"
+ " --shift %5.3f,%5.3f,%5.3f"
+ " --xrot %5.3f@%5.3f,%5.3f,%5.3f"
+ " --yrot %5.3f@%5.3f,%5.3f,%5.3f"
+ " --zrot %5.3f@%5.3f,%5.3f,%5.3f"
+ " --translate %5.3f,%5.3f,%5.3f"
+ " %5.3f,%5.3f,%5.3f"
+ "\n\n",
+ m->scale.x, m->scale.y, m->scale.z,
+ m->scale_origin.x, m->scale_origin.y, m->scale_origin.z,
+ m->shift.x, m->shift.y, m->shift.z,
+ m->rotate_deg.v[0], m->rotate_origin[0].x,
+ m->rotate_origin[0].y, m->rotate_origin[0].z,
+ m->rotate_deg.v[1], m->rotate_origin[1].x,
+ m->rotate_origin[1].y, m->rotate_origin[1].z,
+ m->rotate_deg.v[2], m->rotate_origin[2].x,
+ m->rotate_origin[2].y, m->rotate_origin[2].z,
+ m->translate.x, m->translate.y, m->translate.z,
+ vtab[fail].x, vtab[fail].y, vtab[fail].z );
+ }
+ }
+
+ printf("\nerr=%u, total=%u\n",err_count,total_count);
+ if ( err_count && max_error < ERR_DIFFER )
+ max_error = ERR_DIFFER;
+ return 0;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_match_pattern() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_match_pattern ( int argc, char ** argv )
+{
+ int i, j, i_end = argc, j_start = 1;
+ for ( i = 1; i < argc; i++ )
+ if (!strcmp(argv[i],"-"))
+ {
+ i_end = i;
+ j_start = i + 1;
+ break;
+ }
+
+ for ( i = 1; i < i_end; i++ )
+ for ( j = j_start; j < argc; j++ )
+ printf("%u |%s|%s|\n",MatchPattern(argv[i],argv[j],'/'),argv[i],argv[j]);
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_median_cut() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static void call_mc ( const u32 * tab, uint ntab, uint max_pal )
+{
+ u32 pal[0x200];
+ u16 *res = (u16*)iobuf;
+
+ ASSERT( ntab <= sizeof(iobuf)/sizeof(*tab) );
+ ASSERT( max_pal <= sizeof(pal)/sizeof(*pal) );
+
+ u64 usec = GetTimerUSec();
+ const uint npal = MedianCut(tab,res,ntab,0,1,pal,max_pal);
+ usec = GetTimerUSec() - usec;
+
+ printf("\n*** %u palettes calculated in %llu usec ***",npal,usec);
+
+ uint i;
+ for ( i = 0; i < npal; i++ )
+ printf("%c%08x", i&7 ? ' ' : '\n', pal[i] );
+
+ for ( i = 0; i < ntab; i++ )
+ printf("%s%02x", !(i&15) ? "\n" : i&3 ? " " : " ", res[i] );
+ putchar('\n');
+}
+
+#define MC_CALL(t,n) call_mc(t,sizeof(t)/sizeof(u32),n);
+
+///////////////////////////////////////////////////////////////////////////////
+
+static u32 mctab_4[] = { 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff };
+
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_median_cut ( int argc, char ** argv )
+{
+ uint done_count = 0, wrong_arg_count = 0;
+
+ int i;
+ for ( i = 1; i < argc; i++ )
+ {
+ char *end;
+ uint num = strtoul(argv[i],&end,10);
+ if ( *end || end == argv[i] )
+ num = 0;
+
+ done_count++;
+ switch(num)
+ {
+ case 1: MC_CALL(mctab_4,256); break;
+ case 2: MC_CALL(mctab_4,2); break;
+ case 3: MC_CALL(mctab_4,3); break;
+
+ default:
+ printf("Syntax error: %s\n",argv[i]);
+ wrong_arg_count++;
+ break;
+ }
+ }
+
+ if ( !done_count || wrong_arg_count )
+ fprintf(stderr,
+ "\n"
+ "usage: %s median-cut mode...\n"
+ " 1: 4 -> 256\n"
+ " 2: 4 -> 2\n"
+ " 3: 4 -> 3\n"
+ "\n",
+ NAME );
+
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_cmpr() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static uint calc_distance ( const u8 * v1, const u8 * v2 )
+{
+ const int d0 = (int)*v1++ - (int)*v2++;
+ const int d1 = (int)*v1++ - (int)*v2++;
+ const int d2 = (int)*v1++ - (int)*v2++;
+ return abs(d0) + abs(d1) + abs(d2);
+}
+
+//-----------------------------------------------------------------------------
+
+static uint calc_distance_square ( const u8 * v1, const u8 * v2 )
+{
+ const int d0 = (int)*v1++ - (int)*v2++;
+ const int d1 = (int)*v1++ - (int)*v2++;
+ const int d2 = (int)*v1++ - (int)*v2++;
+ return d0*d0 + d1*d1 + d2*d2;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+void CMPR_distance
+(
+ const u8 *data, // source data
+ cmpr_info_t *info, // info data structure
+ bool square_dist // true: use square distance
+)
+{
+ DASSERT(info);
+ memset(info,0,sizeof(*info));
+
+ uint (*dist_func) ( const u8 * v1, const u8 * v2 );
+ if ( square_dist)
+ {
+ dist_func = calc_distance_square;
+ info->name = "Dist^2";
+ }
+ else
+ {
+ dist_func = calc_distance;
+ info->name = "Dist";
+ }
+
+ //--- analyze data (algorithm adapted from Chadderz CTools)
+
+ uint opaque_count = 0;
+ int max_dist = -1;
+
+ const u8 *data_end = data + CMPR_DATA_SIZE;
+ const u8 *pal0 = data; // palette entry #0
+ const u8 *pal1 = data; // palette entry #1
+
+ const u8 *d1;
+ for ( d1 = data; d1 < data_end; d1 += 4 )
+ {
+ if ( d1[3] & 0x80 )
+ {
+ if (!opaque_count++)
+ pal0 = pal1 = data;
+ const u8 *d2;
+ for ( d2 = d1+4; d2 < data_end; d2 += 4 )
+ {
+ if ( d2[3] & 0x80 )
+ {
+ const int dist = dist_func(d1,d2);
+ if ( max_dist < dist )
+ {
+ max_dist = dist;
+ pal0 = d1;
+ pal1 = d2;
+ }
+ }
+ }
+ }
+ }
+
+
+ //--- calculate and assign values
+
+ info->opaque_count = opaque_count;
+ if (opaque_count)
+ {
+ memcpy(info->p[0],pal0,4);
+ memcpy(info->p[1],pal1,4);
+ }
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static ccp print_col ( const u8 * val )
+{
+ if ( val[3] < 0x80 )
+ return "-transp-";
+
+ static char buf[10];
+ snprintf(buf,sizeof(buf),"%02x-%02x-%02x",val[0],val[1],val[2]);
+ return buf;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_cmpr ( int argc, char ** argv )
+{
+ if ( argc < 2 )
+ {
+ fprintf(stderr,
+ "\n"
+ "usage: %s cmpr [color]...\n"
+ " color: 6 hexdigit color, each channel 00..ff\n"
+ " or the keyword 't' -> transparent pixel\n"
+ "\n",
+ NAME );
+ return ERR_OK;
+ }
+
+
+ //--- scan params
+
+ u8 vector[CMPR_MAX_COL][4];
+ memset(vector,0,sizeof(vector));
+ uint n_vector = 0;
+
+ int i;
+ for ( i = 1; i < argc && n_vector < CMPR_MAX_COL; i++ )
+ {
+ ccp arg = argv[i];
+ if ( *arg == 't' || *arg == 'T' )
+ n_vector++;
+ else
+ {
+ uint num = strtoul(arg,0,16);
+ if ( num < 0x1000000 && n_vector < CMPR_MAX_COL )
+ {
+ u8 *v = vector[n_vector++];
+ *v++ = num >> 16;
+ *v++ = num >> 8;
+ *v++ = num;
+ *v++ = 0xff;
+ }
+ }
+ }
+
+ if ( n_vector > 0 )
+ while ( n_vector < CMPR_MAX_COL )
+ {
+ u8 *v = vector[n_vector];
+ memcpy(v,v-4,4);
+ n_vector++;
+ }
+
+
+ //---- collect data
+
+ const uint n_info = 3;
+ cmpr_info_t info_tab[n_info];
+
+ const uint N_LOOP = 100000;
+ for ( i = 0; i < n_info; i++ )
+ {
+ cmpr_info_t *info = info_tab + i;
+ const u64 usec = GetTimerUSec();
+ uint n = N_LOOP;
+ while ( n-- > 0 )
+ switch (i)
+ {
+ case 0: CMPR_distance(vector[0],info,false); break;
+ case 1: CMPR_distance(vector[0],info,true); break;
+ case 2: CMPR_wiimm(vector[0],info); break;
+ default: ASSERT(0);
+ }
+ info->usec = GetTimerUSec() - usec;
+ CMPR_close_info(vector[0],info,info->cmpr,true);
+ }
+
+
+ //---- print out
+
+ const uint seplen = 9 + 9 * n_info;
+ printf("%.*s\n ",seplen,Minus300);
+
+ for ( i = 0; i < n_info; i++ )
+ printf(" %8.8s",info_tab[i].name);
+ printf("\n%.*s\n",seplen,Minus300);
+
+ uint v;
+ for ( v = 0; v < 2; v++ )
+ {
+ printf("result-%u:",v);
+ for ( i = 0; i < n_info; i++ )
+ {
+ u8 *c = info_tab[i].cmpr + 4*v;
+ printf(" %02x%02x%02x%02x",c[0],c[1],c[2],c[3]);
+ }
+ putchar('\n');
+ }
+ printf("%.*s\n",seplen,Minus300);
+
+ for ( v = 0; v < 4; v++ )
+ {
+ printf(" P%u:",v);
+ for ( i = 0; i < n_info; i++ )
+ printf(" %s",print_col(info_tab[i].p[v]));
+ putchar('\n');
+ }
+ printf("%.*s\n",seplen,Minus300);
+
+ for ( v = 0; v < n_vector; v++ )
+ {
+ printf("%s:",print_col(vector[v]));
+ for ( i = 0; i < n_info; i++ )
+ {
+ cmpr_info_t *info = info_tab + i;
+ printf("%6u,%u ",info->dist[v],info->index[v]);
+ }
+ putchar('\n');
+ }
+
+ printf("%.*s\nsum-dist:",seplen,Minus300);
+ for ( i = 0; i < n_info; i++ )
+ printf("%8u ",info_tab[i].total_dist);
+ printf("\n nanosec:");
+ for ( i = 0; i < n_info; i++ )
+ printf("%8llu ",info_tab[i].usec * 1000 / N_LOOP );
+ printf("\n%.*s\n",seplen,Minus300);
+
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// create_images() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+#undef SETUP_PART
+#define SETUP_PART(a,b) x1=(a)*wd+2; x2=x1+wd-4; y1=(b)*ht+2; y2=y1+ht-4;
+
+static void CreateTestImage ( ccp dest_path )
+{
+ //--- setup
+
+ const uint N = 4;
+ const uint wd = 100;
+ const uint ht = 100;
+ int x1, x2, y1, y2, i, j, x, y;
+
+ Color_t white, black, red, blue, col1[5], col2[5];
+ //SETCOLOR(trans,0xff,0xff,0xff,0x00);
+ SETCOLOR(white,0xff,0xff,0xff,0xff);
+ SETCOLOR(black,0x00,0x00,0x00,0xff);
+ SETCOLOR(red, 0xff,0x00,0x00,0xff);
+ SETCOLOR(blue, 0x00,0x00,0xff,0xff);
+ SETCOLOR(col1[0],0x00,0x00,0x00,0xff);
+ SETCOLOR(col1[1],0xff,0x00,0x00,0xff);
+ SETCOLOR(col1[2],0x00,0xff,0x00,0xff);
+ SETCOLOR(col1[3],0x00,0x00,0xff,0xff);
+ SETCOLOR(col1[4],0xff,0xff,0xff,0xff);
+ SETCOLOR(col2[0],0x00,0x00,0x00,0x00);
+ SETCOLOR(col2[1],0xff,0x00,0x00,0x00);
+ SETCOLOR(col2[2],0x00,0xff,0x00,0x00);
+ SETCOLOR(col2[3],0x00,0x00,0xff,0x00);
+ SETCOLOR(col2[4],0xff,0xff,0xff,0x00);
+
+ Image_t img;
+ InitializeIMG(&img);
+ CreateIMG(&img,true,N*wd,N*ht,white);
+
+
+ //--- stripes, wd=1
+
+ SETUP_PART(0,0);
+ x = x1+1;
+ for ( ; x < x2; x += 3 )
+ DrawVLineIMG(&img, x, y1, y2, black );
+
+ SETUP_PART(1,0);
+ y = y1+1;
+ for ( ; y < y2; y += 3 )
+ DrawHLineIMG(&img, x1, x2, y, black );
+
+ SETUP_PART(2,0);
+ x = x1+1; y = y1+1;
+ for ( ; x < x2; x += 3, y += 3 )
+ {
+ DrawHLineIMG(&img, x1, x2, y, black );
+ DrawVLineIMG(&img, x, y1, y2, black );
+ }
+
+
+ //--- stripes, wd=1..3
+
+ SETUP_PART(0,1);
+ x = x1+3;
+ for ( i = 1; x+i < x2; i++ )
+ {
+ for ( j = 0; j < 4 && x+i < x2; j++ )
+ {
+ FillRectIMG(&img,x,y1,x+i,y2,black,false);
+ x += 2*i;
+ }
+ x += 3;
+ }
+
+ SETUP_PART(1,1);
+ y = y1+3;
+ for ( i = 1; y+i < y2; i++ )
+ {
+ for ( j = 0; j < 4 && y+i < y2; j++ )
+ {
+ FillRectIMG(&img,x1,y,x2,y+i,black,false);
+ y += 2*i;
+ }
+ y += 3;
+ }
+
+ SETUP_PART(2,1);
+ x = x1+3; y = y1+3;
+ for ( i = 1; x+i < x2 && y+i < y2; i++ )
+ {
+ for ( j = 0; j < 4 && x+i < x2 && y+i < y2; j++ )
+ {
+ FillRectIMG(&img,x,y1,x+i,y2,black,false);
+ FillRectIMG(&img,x1,y,x2,y+i,black,false);
+ x += 2*i;
+ y += 2*i;
+ }
+ x += 3;
+ y += 3;
+ }
+
+
+ //--- gradients
+
+ SETUP_PART(0,2);
+ x = x1 + wd/10;
+ for ( i = 0; i < 4; i++ )
+ {
+ FillVGradientIMG(&img,x,y1,x+wd/10,y2,col1[i],white);
+ x += wd/5;
+ }
+
+ SETUP_PART(1,2);
+ y = y1 + wd/10;
+ for ( i = 0; i < 4; i++ )
+ {
+ FillHGradientIMG(&img,x1,y,x2,y+wd/10,col1[i],white);
+ y += wd/5;
+ }
+
+ SETUP_PART(2,2);
+ x = x1 + wd/10;
+ y = y1 + wd/10;
+ for ( i = 0; i < 4; i++ )
+ {
+ FillVGradientIMG(&img,x,y1,x+wd/10,y2,col1[i],white);
+ FillHGradientIMG(&img,x1,y,x2,y+wd/10,col1[i],white);
+ x += wd/5;
+ y += wd/5;
+ }
+
+
+ //--- transparent gradients
+
+ SETUP_PART(0,3);
+ x = x1 + wd/10;
+ for ( i = 0; i < 4; i++ )
+ {
+ FillVGradientIMG(&img,x,y1,x+wd/10,y2,col1[i],col2[i]);
+ x += wd/5;
+ }
+
+ SETUP_PART(1,3);
+ y = y1 + wd/10;
+ for ( i = 0; i < 4; i++ )
+ {
+ FillHGradientIMG(&img,x1,y,x2,y+wd/10,col1[i],col2[i]);
+ y += wd/5;
+ }
+
+ SETUP_PART(2,3);
+ x = x1 + wd/10;
+ y = y1 + wd/10;
+ for ( i = 0; i < 4; i++ )
+ {
+ FillVGradientIMG(&img,x,y1,x+wd/10,y2,col1[i],col2[i]);
+ FillHGradientIMG(&img,x1,y,x2,y+wd/10,col1[i],col2[i]);
+ x += wd/5;
+ y += wd/5;
+ }
+
+
+ //--- rhombus
+
+ SETUP_PART(3,0);
+ x = x1 + wd/2;
+ for ( i = 0; i < wd/2-1; i++ )
+ {
+ DrawHLineIMG(&img, x-i, x+i+1, y1+i, black );
+ DrawHLineIMG(&img, x-i, x+i+1, y2-i, black );
+ }
+
+ SETUP_PART(3,1);
+ x = x1 + wd/2;
+ for ( i = 0; i < wd/2-1; i++ )
+ {
+ DrawHLineIMG(&img, x-i/2, x+i/2+1, y1+i, blue );
+ DrawHLineIMG(&img, x-i/2, x+i/2+1, y2-i, blue );
+ }
+
+ SETUP_PART(3,2);
+ y = y1 + wd/2;
+ for ( i = 0; i < wd/2-1; i++ )
+ {
+ DrawVLineIMG(&img, x1+i, y-i/2, y+i/2+1, red );
+ DrawVLineIMG(&img, x2-i, y-i/2, y+i/2+1, red );
+ }
+
+
+ //--- circle
+
+ Image_t circ;
+ InitializeIMG(&circ);
+ CreateIMG(&circ,true,1000,1000,white);
+ x1 = circ.width/2;
+ y1 = circ.height/2;
+
+ int r = circ.width/2 - 50;
+ x = r;
+ y = 0;
+ r *= r;
+ int r2 = r;
+
+ while ( x >= 0 )
+ {
+ DrawHLineIMG(&circ, x1-x, x1+x, y1-y, black );
+ DrawHLineIMG(&circ, x1-x, x1+x, y1+y, black );
+ if ( r > r2 )
+ {
+ x--;
+ r -= 2*x + 1;
+ }
+ else
+ {
+ y++;
+ r += 2*y + 1;
+ }
+ }
+
+ SmartResizeIMG(&circ,false,0,wd,ht);
+ SETUP_PART(3,3);
+ CopyRectIMG(&img,x1,y1, &circ,0,0, wd,ht, PIM_COPY );
+
+
+ //--- terminate
+
+ SavePNG(&img,true,dest_path,"test-image.png",0,true,0);
+ ResetIMG(&img);
+}
+
+#undef SETUP_PART
+
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError save_image
+(
+ Image_t * img, // pointer to valid img
+ ccp path1, // NULL or part #1 of path
+ ccp path2, // NULL or part #2 of path
+ Color_t line_col // color of lines
+)
+{
+ DASSERT(img);
+
+ DrawFrameIMG(img,0,0,img->width-1,img->height-1,line_col);
+ DrawHLineIMG(img,0,img->width,img->height/2,line_col);
+ DrawVLineIMG(img,img->width/2,0,img->height,line_col);
+
+ return SavePNG(img,true,path1,path2,0,true,0);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int create_images ( int argc, char ** argv )
+{
+ if ( argc != 2 )
+ {
+ fprintf(stderr,"Usage: %s CREATE-IMAGES destdir\n",NAME);
+ return ERR_SYNTAX;
+ }
+
+ Color_t base, col1, col2;
+ SETCOLOR(base,0xff,0xff,0xff,0x00);
+
+ const uint len1 = 201;
+ const uint size1 = 20;
+ const uint next1 = 30;
+ const uint beg1 = ( len1 - 5 * next1 - size1 ) / 2;
+
+ const uint len2 = 391;
+ const uint beg2 = 5;
+ const uint end2 = len2 - beg2;
+
+ uint pos;
+
+
+ //--- bg-temp.png
+
+ Image_t bg_img;
+ SETCOLOR(col1,0xff,0xff,0xff,0xff);
+ CreateIMG(&bg_img,true,len1+len2,len1+len2,col1);
+
+ const uint bg_step = 16;
+ SETCOLOR(col1,0xc0,0xc0,0xc0,0xff);
+ int y, xstart = 0;
+ for ( y = -4; y < (int)bg_img.height; y += bg_step )
+ {
+ xstart = bg_step - xstart;
+ int x;
+ for ( x = xstart-4; x < (int)bg_img.width; x += 2*bg_step )
+ FillRectIMG(&bg_img,x,y,x+bg_step,y+bg_step,col1,true);
+ }
+ SavePNG(&bg_img,true,argv[1],"bg-temp.png",0,true,0);
+
+
+ //--- blue-temp.png
+
+ Image_t blue_img;
+ CreateIMG(&blue_img,true,len1,len2,base);
+
+ pos = beg1;
+ SETCOLOR(col1,0x00,0x00,0xff,0xff);
+ FillRectIMG(&blue_img,pos,beg2,pos+size1,end2,col1,true);
+
+ pos += next1;
+ SETCOLOR(col1,0x00,0x00,0xff,0xff);
+ SETCOLOR(col2,0x00,0x00,0x00,0xff);
+ FillVGradientIMG(&blue_img,pos,beg2,pos+size1,end2,col1,col2);
+
+ pos += next1;
+ SETCOLOR(col1,0x00,0x00,0xff,0xff);
+ SETCOLOR(col2,0x00,0x00,0xff,0x00);
+ FillVGradientIMG(&blue_img,pos,beg2,pos+size1,end2,col1,col2);
+
+ pos += next1;
+ SETCOLOR(col1,0x00,0x00,0x00,0xff);
+ SETCOLOR(col2,0xff,0xff,0xff,0xff);
+ FillVGradientIMG(&blue_img,pos,beg2,pos+size1,end2,col1,col2);
+
+ pos += next1;
+ SETCOLOR(col1,0x00,0x00,0x00,0xff);
+ SETCOLOR(col2,0x00,0x00,0x00,0x00);
+ FillVGradientIMG(&blue_img,pos,beg2,pos+size1,end2,col1,col2);
+
+ SETCOLOR(col1,0x00,0x00,0x80,0xff);
+ save_image(&blue_img,argv[1],"blue-temp.png",col1);
+
+
+ //--- red-temp.png
+
+ Image_t red_img;
+ CreateIMG(&red_img,true,len2,len1,base);
+
+ pos = beg1;
+ SETCOLOR(col1,0xff,0x00,0x00,0xff);
+ FillRectIMG(&red_img,beg2,pos,end2,pos+size1,col1,true);
+
+ pos += next1;
+ SETCOLOR(col1,0xff,0x00,0x00,0xff);
+ SETCOLOR(col2,0x00,0x00,0x00,0xff);
+ FillHGradientIMG(&red_img,beg2,pos,end2,pos+size1,col1,col2);
+
+ pos += next1;
+ SETCOLOR(col1,0xff,0x00,0x00,0xff);
+ SETCOLOR(col2,0xff,0x00,0x00,0x00);
+ FillHGradientIMG(&red_img,beg2,pos,end2,pos+size1,col1,col2);
+
+ pos += next1;
+ SETCOLOR(col1,0x00,0x00,0x00,0xff);
+ SETCOLOR(col2,0xff,0xff,0xff,0xff);
+ FillHGradientIMG(&red_img,beg2,pos,end2,pos+size1,col1,col2);
+
+ pos += next1;
+ SETCOLOR(col1,0x00,0x00,0x00,0xff);
+ SETCOLOR(col2,0x00,0x00,0x00,0x00);
+ FillHGradientIMG(&red_img,beg2,pos,end2,pos+size1,col1,col2);
+
+ SETCOLOR(col1,0x80,0x00,0x00,0xff);
+ save_image(&red_img,argv[1],"red-temp.png",col1);
+
+
+ //--- mix image
+
+ Image_t mix_img;
+ InitializeIMG(&mix_img);
+
+ PatchIMG(&mix_img,&blue_img,&red_img,PIM_COPY);
+ PatchIMG(&mix_img,&mix_img,&bg_img,PIM_BACKGROUND);
+ SavePNG(&mix_img,true,argv[1],"mode-copy-temp.png",0,true,0);
+
+ PatchIMG(&mix_img,&blue_img,&red_img,PIM_FOREGROUND);
+ PatchIMG(&mix_img,&mix_img,&bg_img,PIM_BACKGROUND);
+ SavePNG(&mix_img,true,argv[1],"mode-foreground-temp.png",0,true,0);
+
+ PatchIMG(&mix_img,&blue_img,&red_img,PIM_BACKGROUND);
+ PatchIMG(&mix_img,&mix_img,&bg_img,PIM_BACKGROUND);
+ SavePNG(&mix_img,true,argv[1],"mode-background-temp.png",0,true,0);
+
+ PatchIMG(&mix_img,&blue_img,&red_img,PIM_MIX);
+ PatchIMG(&mix_img,&mix_img,&bg_img,PIM_BACKGROUND);
+ SavePNG(&mix_img,true,argv[1],"mode-mix-temp.png",0,true,0);
+
+
+ PatchIMG(&mix_img,&blue_img,&red_img,PIM_COPY|PIM_INS_LEFT|PIM_GROW);
+ PatchIMG(&mix_img,&mix_img,&bg_img,PIM_BACKGROUND);
+ SavePNG(&mix_img,true,argv[1],"insert-left-temp.png",0,true,0);
+
+ PatchIMG(&mix_img,&blue_img,&red_img,PIM_COPY|PIM_INS_RIGHT|PIM_GROW);
+ PatchIMG(&mix_img,&mix_img,&bg_img,PIM_BACKGROUND);
+ SavePNG(&mix_img,true,argv[1],"insert-right-temp.png",0,true,0);
+
+ PatchIMG(&mix_img,&blue_img,&red_img,PIM_COPY|PIM_INS_TOP|PIM_GROW);
+ PatchIMG(&mix_img,&mix_img,&bg_img,PIM_BACKGROUND);
+ SavePNG(&mix_img,true,argv[1],"insert-top-temp.png",0,true,0);
+
+ PatchIMG(&mix_img,&blue_img,&red_img,PIM_COPY|PIM_INS_BOTTOM|PIM_GROW);
+ PatchIMG(&mix_img,&mix_img,&bg_img,PIM_BACKGROUND);
+ SavePNG(&mix_img,true,argv[1],"insert-bottom-temp.png",0,true,0);
+
+ PatchIMG(&mix_img,&blue_img,&red_img,PIM_COPY|PIM_INS_TOP|PIM_INS_RIGHT|PIM_GROW);
+ PatchIMG(&mix_img,&mix_img,&bg_img,PIM_BACKGROUND);
+ SavePNG(&mix_img,true,argv[1],"insert-top_right-temp.png",0,true,0);
+
+ PatchIMG(&mix_img,&blue_img,&red_img,PIM_COPY|PIM_INS_BOTTOM|PIM_INS_LEFT|PIM_GROW);
+ PatchIMG(&mix_img,&mix_img,&bg_img,PIM_BACKGROUND);
+ SavePNG(&mix_img,true,argv[1],"insert-bottom_left-temp.png",0,true,0);
+
+
+ //--- test image
+
+ CreateTestImage(argv[1]);
+
+
+ //--- term
+
+ ResetIMG(&bg_img);
+ ResetIMG(&blue_img);
+ ResetIMG(&red_img);
+ ResetIMG(&mix_img);
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_resize() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static int test_resize ( int argc, char ** argv )
+{
+ if ( argc != 3 )
+ {
+ fprintf(stderr,"\n"
+ "Usage: %s RESIZE old-size new-size\n\n"
+ ,NAME);
+ return ERR_SYNTAX;
+ }
+
+ uint src_size = strtoul(argv[1],0,10);
+ uint dest_size = strtoul(argv[2],0,10);
+
+ ResizeHelper_t r;
+ InitializeResize(&r,src_size,dest_size);
+ printf("\nRESIZE: %u -> %u, step: %u + %u/%u, sum_factor: %u\n\n",
+ r.src_size, r.dest_size,
+ r.idx_inc, r.frac_inc, r.frac_next,
+ r.sum_factor );
+
+ bool stat;
+ for ( stat = FirstResize(&r); stat; stat = NextResize(&r) )
+ {
+ printf(" %5u -> %5u", r.src_idx, r.dest_idx );
+ ResizeElement_t *re;
+ for ( re = r.elem; re->n_elem; re++ )
+ printf(" | %4u*%4u", re->n_elem, re->factor );
+ putchar('\n');
+ }
+ putchar('\n');
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// resize_image() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static int resize_image ( int argc, char ** argv )
+{
+ if ( argc < 4 )
+ {
+ fprintf(stderr,"\n"
+ "Usage: %s RESIZE-IMAGE new_width['%%']"
+ " ('w'|'a'|new_height['%%']) img-file...\n\n"
+ ,NAME);
+ return ERR_SYNTAX;
+ }
+
+ u32 wd_param = 0, ht_param = 0;
+ char *end = ScanNumU32(argv[1],0,&wd_param,0,1000);
+ const bool wd_percent = end && *end == '%';
+
+ const bool aspect = argv[2][0] == 'a' || argv[2][0] == 'A';
+ end = ScanNumU32(argv[2],0,&ht_param,0,1000);
+ bool ht_percent = end && *end == '%';
+ if ( argv[2][0] == 'w' || argv[2][0] == 'W' )
+ {
+ ht_param = wd_param;
+ ht_percent = wd_percent;
+ }
+
+ uint i;
+ for ( i = 3; i < argc; i++ )
+ {
+ Image_t img1;
+ enumError err = LoadIMG(&img1,true,argv[i],0,false,true,false);
+ if (err)
+ return ERR_WARNING;
+
+ const uint wd = wd_percent ? ( img1.width * wd_param + 50 ) / 100 : wd_param;
+ const uint ht = aspect
+ ? img1.height * wd / img1.width
+ : ht_percent
+ ? ( img1.height * ht_param + 50 ) / 100
+ : ht_param;
+
+ printf("NEW SIZE: %u*%u -> %u*%u: %s\n",
+ img1.width, img1.height, wd, ht, argv[i] );
+
+ Image_t img2;
+ u64 time = GetTimeUSec(false);
+ err = SmartResizeIMG(&img2,true,&img1,wd,ht);
+ time = GetTimeUSec(false) - time;
+ printf("S2: %5llu usec [smart resize, new image]\n",time);
+ if (err)
+ return ERR_WARNING;
+
+ Image_t img3;
+ time = GetTimeUSec(false);
+ err = FastResizeIMG(&img3,true,&img1,wd,ht);
+ time = GetTimeUSec(false) - time;
+ printf("F3: %5llu usec [fast resize, new image]\n",time);
+ if (err)
+ return ERR_WARNING;
+
+ time = GetTimeUSec(false);
+ err = SmartResizeIMG(&img1,false,0,wd,ht);
+ time = GetTimeUSec(false) - time;
+ printf("S1: %5llu usec [smart resize, inplace image]\n",time);
+ if (err)
+ return ERR_WARNING;
+
+ char path[PATH_MAX];
+ NewFileExtS(path,sizeof(path),argv[i],"1smart.png");
+ err = SavePNG(&img1,false,path,0,true,true,0);
+ if (err)
+ return ERR_WARNING;
+
+ NewFileExtS(path,sizeof(path),argv[i],"2smart.png");
+ err = SavePNG(&img2,false,path,0,true,true,0);
+ if (err)
+ return ERR_WARNING;
+
+ NewFileExtS(path,sizeof(path),argv[i],"3fast.png");
+ err = SavePNG(&img3,false,path,0,true,true,0);
+ if (err)
+ return ERR_WARNING;
+
+ ResetIMG(&img1);
+ ResetIMG(&img2);
+ ResetIMG(&img3);
+ }
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_scan_text() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static int test_scan_text ( int argc, char ** argv )
+{
+ uint i;
+ for ( i = 1; i < argc; i++ )
+ {
+ ccp src = argv[i];
+ char *dest = iobuf;
+ char *end = iobuf + sizeof(iobuf) - 1;
+ while ( *src && dest < end )
+ {
+ const char ch = *src++;
+ *dest++ = ch == '|' ? '\n' : ch;
+ }
+ *dest = 0;
+
+ printf("* %s\n",argv[i]);
+ ScanInfo_t si;
+ InitializeSI(&si,iobuf,dest-iobuf,argv[i],0);
+ #if HAVE_PRINT
+ si.debug = 1;
+ #endif
+ for(;;)
+ {
+ NextCharSI(&si,true);
+ ScanFile_t *sf = si.cur_file;
+ DASSERT(sf);
+ //PRINT(" >%s\n",sf->ptr);
+
+ ccp beg = sf->ptr;
+ while (NextCharSI(&si,false))
+ sf->ptr++;
+ if ( beg == sf->ptr )
+ break;
+ printf(" #%u \"%.*s\"\n",
+ sf->line, (int)( sf->ptr - beg ), argv[i] + ( beg - sf->data ) );
+ }
+ ResetSI(&si);
+ }
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_scan_string() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static int test_scan_string ( int argc, char ** argv )
+{
+ uint i;
+ for ( i = 1; i < argc; i++ )
+ {
+ uint len1;
+ char buf[1000];
+ ScanEscapedString(buf,sizeof(buf),argv[i],-1,true,0,&len1);
+
+ uint len2;
+ char out[1000];
+ PrintEscapedString(out,sizeof(out),buf,-1,CHMD__ALL,0,&len2);
+
+ printf("\nsrc: %3u |%s|\ndest: %3u |%s|\n",len1,argv[i],len2,out);
+ }
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_scan_file() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static int test_scan_file ( int argc, char ** argv )
+{
+ static VarMap_t vm = {0};
+ if (!vm.used)
+ DefineParserVars(&vm);
+
+ uint i;
+ for ( i = 1; i < argc; i++ )
+ {
+ ccp fname = argv[i];
+ File_t F;
+ enumError err = OpenFILE(&F,true,fname,false,false);
+ if (err)
+ return err;
+
+ uint data_size = F.st.st_size;
+ PRINT("LOAD FILE: size = %#x = %u\n",data_size,data_size);
+ char * data = MALLOC(data_size+1);
+ data[data_size] = 0; // termination for text files
+
+ if ( fread(data,1,data_size,F.f) != data_size )
+ {
+ err = FILEERROR1(&F,ERR_READ_FAILED,"Read failed: %s\n",fname);
+ ResetFile(&F,false);
+ return err;
+ }
+ ResetFile(&F,false);
+
+ printf("* %s\n",argv[i]);
+
+ ScanInfo_t si;
+ InitializeSI(&si,data,data_size,fname,0);
+ si.predef = &vm;
+ #if HAVE_PRINT
+ si.debug = 1;
+ #endif
+
+ #if 1
+ while (NextLineSI(&si,false,true))
+ if (NextCharSI(&si,false))
+ {
+ ccp ptr = si.cur_file->ptr;
+ ccp eol = FindNextLineFeedSI(&si,true);
+ int len = eol - ptr;
+ ccp post = "";
+ if ( len > 50 )
+ {
+ len = 50;
+ post = "...";
+ }
+ ERROR0(ERR_WARNING,"Line ignored: %.*s%s\n",len,ptr,post);
+ GotoEolSI(&si);
+ }
+ #else
+ uint n;
+ for ( n = 0; n < 3; n++ )
+ {
+ NextCharSI(&si,true);
+ u32 num;
+ enumError err = ScanU32SI(&si,&num,1,0);
+ printf("\t\t%2u: err=%3u, line=%3u, num=%8u = %6x\n",
+ n, err, si.cur_file->line, num, num );
+ }
+ #endif
+ ResetSI(&si);
+ }
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_filename() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static int test_filename ( int argc, char ** argv )
+{
+ uint i;
+ for ( i = 1; i < argc; i++ )
+ {
+ ParamList_t param;
+ memset(&param,0,sizeof(param));
+ param.arg = STRDUP(argv[i]);
+ printf("\nsrc: %s\n",param.arg);
+
+ char dest[PATH_MAX];
+ uint stat = NumberedFilename(dest,sizeof(dest),param.arg,0,0,true);
+ printf("num: %s [%u]\n",dest,stat);
+
+ SubstDest( dest, sizeof(dest), param.arg,
+ opt_dest && *opt_dest ? opt_dest : "\1P/\1N\1?T", "\1N\1?T",
+ GetExtFF(FF_BZ,FF_WU8), false );
+ printf("dest: %s\n",dest);
+
+ NORMALIZE_FILENAME_PARAM(&param);
+ printf("norm: %s\n",param.arg);
+ SubstDest( dest, sizeof(dest), param.arg,
+ opt_dest && *opt_dest ? opt_dest : "\1P/\1N\1?T", "\1N\1?T",
+ GetExtFF(FF_BZ,FF_WU8), false );
+ printf("dest: %s\n",dest);
+
+ stat = NumberedFilename(dest,sizeof(dest),dest,0,0,true);
+ printf("num: %s [%u]\n",dest,stat);
+
+ FREE(param.arg);
+ }
+ putchar('\n');
+ return 0;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// draw_startpos() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError save_img ( Image_t *img, char type, uint n )
+{
+ DASSERT(img);
+
+ char fname[100];
+ snprintf(fname,sizeof(fname),"./_start-pos.tmp/start-pos-%c-%02u.png",type,n);
+ enumError err = SavePNG(img,false,fname,0,0,true,0);
+ if (!err)
+ printf("Image %s created.\n",fname);
+ return err;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError draw_startpos_helper ( uint n )
+{
+ double3 tab_w[12], tab_n[12];
+
+ GetStartPosKMP(tab_w,n,false,false,0,0);
+ GetStartPosKMP(tab_n,n,false,true,0,0);
+
+ int i, z1;
+ const int xmid = 1200;
+ const int zmid = 300;
+ const int zmax = 5600;
+ const double scale = 1/20.0;
+
+ Image_t imgw, imgn, imgx;
+ Color_t col1, col2;
+ col1.val = 0xff600000;
+
+ enumError err1 = CreateIMG(&imgw,true,2*xmid*scale,(zmid+zmax)*scale,col1);
+ enumError err2 = CreateIMG(&imgn,true,2*xmid*scale,(zmid+zmax)*scale,col1);
+ enumError err3 = CreateIMG(&imgx,true,2*xmid*scale,(zmid+zmax)*scale,col1);
+ if (err1||err2||err3)
+ goto abort;
+
+ //--- draw vertical `500´ lines
+
+ col1.val = 0xff804000;
+ z1 = zmid * scale;
+
+ for ( i = -500; i <= 500; i += 1000 )
+ {
+ uint x = ( xmid + i ) * scale;
+ FillRectIMG( &imgw, x-1, z1, x, imgw.height, col1, true );
+ }
+
+
+ //--- draw horizontal `500´ lines
+
+ for ( i = zmid+500; i < zmid+zmax; i += 1000 )
+ {
+ uint z = i * scale;
+ FillRectIMG( &imgw, 0, z-1, imgw.width, z, col1, true );
+ }
+
+
+ //--- draw vertical `1000´ lines
+
+ col1.val = 0xff808000;
+ z1 = zmid * scale;
+
+ for ( i = -1000; i <= 1000; i += 1000 )
+ {
+ uint x = ( xmid + i ) * scale;
+ FillRectIMG( &imgw, x-1, z1, x+1, imgw.height, col1, true );
+ }
+
+
+ //--- draw horizontal `1000´ lines
+
+ for ( i = zmid; i < zmid+zmax; i += 1000 )
+ {
+ uint z = i * scale;
+ FillRectIMG( &imgw, 0, z-1, imgw.width, z+1, col1, true );
+ }
+
+
+ //--- draw finisch line
+
+ col1.val = 0xff0000ff;
+ FillRectIMG( &imgw, 0,
+ (zmid-25)*scale,
+ imgw.width,
+ (zmid+25)*scale,
+ col1, true );
+
+
+ //--- copy the images
+
+ CopyIMG(&imgn,false,&imgw,false);
+ CopyIMG(&imgx,false,&imgw,false);
+
+
+ //--- draw start positions
+
+ col1.val = 0xff00ffff;
+ col2.val = 0xff0080ff;
+
+ for ( i = 0; i < n; i++ )
+ {
+
+ //--- draw narrow
+
+ const double3 *d = tab_n + i;
+ FillRectIMG( &imgn,
+ (xmid+d->x-100)*scale,
+ (zmid+d->z-180)*scale,
+ (xmid+d->x+100)*scale,
+ (zmid+d->z+180)*scale,
+ col1, true );
+
+ FillRectIMG( &imgx,
+ (xmid+d->x-100)*scale,
+ (zmid+d->z-180)*scale,
+ (xmid+d->x+100)*scale,
+ (zmid+d->z+180)*scale,
+ col2, true );
+
+ //--- draw wide
+
+ d = tab_w + i;
+ FillRectIMG( &imgw,
+ (xmid+d->x-100)*scale,
+ (zmid+d->z-180)*scale,
+ (xmid+d->x+100)*scale,
+ (zmid+d->z+180)*scale,
+ col1, true );
+
+ FillRectIMG( &imgx,
+ (xmid+d->x-100)*scale,
+ (zmid+d->z-180)*scale,
+ (xmid+d->x+100)*scale,
+ (zmid+d->z+180)*scale,
+ col1, true );
+ }
+
+
+ //--- draw defined start position
+
+ col1.val = 0xff0000ff;
+
+ FillRectIMG( &imgw, (xmid-80)*scale,
+ (zmid-80)*scale,
+ (xmid+80)*scale,
+ (zmid+80)*scale,
+ col1, true );
+
+ FillRectIMG( &imgn, (xmid-80)*scale,
+ (zmid-80)*scale,
+ (xmid+80)*scale,
+ (zmid+80)*scale,
+ col1, true );
+
+ FillRectIMG( &imgx, (xmid-80)*scale,
+ (zmid-80)*scale,
+ (xmid+80)*scale,
+ (zmid+80)*scale,
+ col1, true );
+
+ //--- save the images
+
+ err1 = save_img(&imgw,'w',n);
+ err2 = save_img(&imgn,'n',n);
+ err3 = save_img(&imgx,'x',n);
+
+ MARK_USED(col2);
+
+ abort:
+ ResetIMG(&imgw);
+ ResetIMG(&imgn);
+ ResetIMG(&imgx);
+ return err1 || err2 || err3 ? ERR_ERROR : ERR_OK;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static int draw_startpos ( int argc, char ** argv )
+{
+ opt_mkdir = true;
+
+ uint n;
+ for ( n = 1; n<= 12; n++ )
+ draw_startpos_helper(n);
+ return 0;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// draw_startpos() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static uint sort_mode = 0;
+
+//-----------------------------------------------------------------------------
+
+static int sort_path_cmp ( ccp *p1, ccp *p2 )
+{
+ return PathCmp(*p1,*p2,sort_mode);
+}
+
+//-----------------------------------------------------------------------------
+
+static int test_path_cmp ( int argc, char ** argv )
+{
+ if ( argc < 3 )
+ {
+ fprintf(stderr,"Usage: PATH-CMP mode string1 string2 [stringx]...\n");
+ return ERR_SYNTAX;
+ }
+
+ sort_mode = strtoul(argv[1],0,0) & 7;
+ argc -= 2;
+ argv += 2;
+
+ printf("* Sort %u strings with mode %u\n",argc,sort_mode);
+ qsort( argv, argc, sizeof(*argv), (qsort_func)sort_path_cmp );
+
+ uint i;
+ for ( i = 0; i < argc; i++ )
+ printf("%5u. %s\n",i,argv[i]);
+ return 0;
+}
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// ana_file_objflow() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static ccp print16 ( u16 val )
+{
+ if (!val)
+ return "-";
+
+ static char buf[10];
+ snprintf(buf,sizeof(buf),"%x",val);
+ return buf;
+}
+
+//-----------------------------------------------------------------------------
+
+static int ana_file_objflow ( int argc, char ** argv )
+{
+ char buf[20];
+
+ uint i;
+ for ( i = 1; i < argc; i++ )
+ {
+ u8 *raw_data;
+ uint data_size;
+ enumError err = OpenReadFILE(argv[i],0,false,&raw_data,&data_size,0,0);
+ if (err)
+ return err;
+ printf("* %s\n",argv[i]);
+ objflow_bin_t *odata = (objflow_bin_t*)(raw_data+2);
+
+ #undef PLEN
+ #define PLEN ( sizeof(odata->param) / sizeof(*odata->param) )
+ uint param_fw[PLEN];
+ memset(param_fw,0,sizeof(param_fw));
+
+ uint max_name_size = 4, max_resources_size = 4;
+ const uint N = be16(raw_data);
+ objflow_bin_t *ptr, *end = odata + N;
+ for ( ptr = odata; ptr < end && ptr->id != 0xffff; ptr++ )
+ {
+ uint len = strlen(ptr->name);
+ if ( max_name_size < len )
+ max_name_size = len;
+ len = strlen(ptr->resources);
+ if ( max_resources_size < len )
+ max_resources_size = len;
+
+ ptr->id = be16(&ptr->id);
+ uint p;
+ for ( p = 0; p < PLEN; p++ )
+ {
+ u32 val = be16(ptr->param+p);
+ ptr->param[p] = val;
+ if ( param_fw[p] < val )
+ param_fw[p] = val; // store max value first
+ }
+ }
+ if ( max_name_size > sizeof(odata->name) - 1 )
+ max_name_size = sizeof(odata->name) - 1;
+ if ( max_resources_size > sizeof(odata->resources) - 1 )
+ max_resources_size = sizeof(odata->resources) - 1;
+
+ uint linelen = printf(" Pos ID %-*s", max_name_size, "Name" )
+ + max_resources_size + 3;
+ uint p;
+ for ( p = 0; p < PLEN; p++ )
+ if (param_fw[p])
+ {
+ uint fw = snprintf(buf,sizeof(buf),"%3x",param_fw[p]);
+ param_fw[p] = fw > 3 ? fw : 3;
+ linelen += printf("%*s%u",param_fw[p],"P",p);
+ }
+ printf(" Resources\n%.*s\n", linelen, Minus300);
+
+ for ( ptr = odata; ptr < end && ptr->id != 0xffff; ptr++ )
+ {
+ printf(" %3zu %03x %-*s", ptr-odata, ptr->id, max_name_size, ptr->name );
+ for ( p = 0; p < PLEN; p++ )
+ if (param_fw[p])
+ printf(" %*s",param_fw[p],print16(ptr->param[p]));
+ printf(" %s\n",ptr->resources);
+ }
+
+ #undef PLEN
+
+ FREE(raw_data);
+ }
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_line() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError scan_double
+ ( double * pt, int n_dim, ScanInfo_t *si, double def_x, double def_y )
+{
+ DASSERT(pt);
+ DASSERT(si);
+ DASSERT( n_dim == 2 || n_dim == 3 );
+
+ // set defaults
+ pt[0] = def_x;
+ pt[1] = def_y;
+ if ( n_dim == 3 )
+ pt[2] = 0.0;
+
+ char ch = NextCharSI(si,false);
+ if ( ch == ',' )
+ {
+ si->cur_file->ptr++;
+ ch = NextCharSI(si,false);
+ }
+
+ if ( ch == '.' )
+ {
+ si->cur_file->ptr++;
+ return ERR_OK;
+ }
+
+ uint dim;
+ for ( dim=0; dim < n_dim; dim++ )
+ {
+ double d;
+ enumError err = ScanDValueSI(si,&d);
+ if (err)
+ return err;
+
+ pt[dim] = d;
+ char ch = NextCharSI(si,false);
+ if ( !ch || ch == ',' )
+ break;
+ }
+
+ return ERR_OK;
+}
+
+//-----------------------------------------------------------------------------
+
+static enumError scan_float
+ ( float * pt, int n_dim, ScanInfo_t *si, double def_x, double def_y )
+{
+ DASSERT(pt);
+ DASSERT(si);
+
+ DASSERT( n_dim <= 10 );
+ double temp[10];
+ enumError err = scan_double(temp,n_dim,si,def_x,def_y);
+ uint i;
+ for ( i = 0; i < n_dim; i++ )
+ pt[i] = temp[i];
+
+ return err;
+}
+
+//-----------------------------------------------------------------------------
+
+static void print_double_vec ( double *pt, int n_dim, ccp title )
+{
+ if ( n_dim == 3 )
+ printf("%s%9.3f %9.3f %9.3f\n",title,pt[0],pt[1],pt[2]);
+ else
+ printf("%s%9.3f %9.3f\n",title,pt[0],pt[1]);
+}
+
+//-----------------------------------------------------------------------------
+
+static void print_float_vec ( float *pt, int n_dim, ccp title )
+{
+ if ( n_dim == 3 )
+ printf("%s%9.3f %9.3f %9.3f\n",title,pt[0],pt[1],pt[2]);
+ else
+ printf("%s%9.3f %9.3f\n",title,pt[0],pt[1]);
+}
+
+//-----------------------------------------------------------------------------
+
+static int test_line ( int n_dim, int argc, char ** argv )
+{
+ n_dim = n_dim == 3 ? 3 : 2;
+ if ( argc < 2 )
+ {
+ fprintf(stderr,
+ "\n"
+ "Usage: %s 'LINE2' N [,P1] [,P2] [,Pa] [,Pb]\n"
+ "\n"
+ " 'Px' is a point with %u dimensions, missing dimensions are filled with 0.\n"
+ " A point means: default value (P1=0, P2=1000, P3=P4=500 500)\n"
+ "\n"
+ " => Create a line with N points from P1..P2.\n"
+ " Pa and Pb are helpers for Bézier curves.\n"
+ "\n"
+ " Linear: B(t) = (1-t)*P1 + t*P2\n"
+ " Quadratic: B(t) = (1-t)^2*P1 + 2*(1-t)*t*Pa + t^2*P2\n"
+ " Cubic: B(t) = (1-t)^3*P1 + 3*(1-t)^2*t*Pa\n"
+ " + 3*(1-t)*t^2*Pb + t^3*P2\n"
+ " where t=0.0 .. 1.0\n"
+ "\n"
+ ,NAME, n_dim );
+ return ERR_SYNTAX;
+ }
+
+ uint i;
+ for ( i = 1; i < argc; i++ )
+ {
+ ScanInfo_t si;
+ InitializeSI(&si,argv[i],strlen(argv[i]),"arg",0);
+
+ Line_t lin;
+ InitializeLine(&lin);
+
+ long n;
+ enumError err = ScanUValueSI(&si,&n,false);
+ if (err)
+ return err;
+ lin.n = n;
+
+ float p1[3] = { 0.0, 0.0, 0.0 };
+ if (NextCharSI(&si,false))
+ {
+ err = scan_float(p1,n_dim,&si,0.0,0.0);
+ if (err)
+ return err;
+ }
+
+ float p2[3] = { 1000.0, 0.0, 0.0 };
+ if (NextCharSI(&si,false))
+ {
+ err = scan_float(p2,n_dim,&si,1000.0,0.0);
+ if (err)
+ return err;
+ }
+
+ while ( lin.n_pt < 2 && NextCharSI(&si,false) )
+ {
+ err = scan_double(lin.pt[lin.n_pt],n_dim,&si,500.0,500.0);
+ if (err)
+ return err;
+ lin.n_pt++;
+ }
+
+ printf("\n-----------------------------------------------\n");
+ print_float_vec(p1,n_dim," P1: ");
+ if ( lin.n_pt >= 1 )
+ print_double_vec(lin.pt[0],n_dim," Pa: ");
+ if ( lin.n_pt >= 2 )
+ print_double_vec(lin.pt[1],n_dim," Pb: ");
+ print_float_vec(p2,n_dim," P2: ");
+ printf("-----------------------------------------------\n");
+ uint p;
+ for ( p = 0; p <= lin.n; p++ )
+ {
+ float pt[3];
+ CalcLine(&lin,pt,p1,p2,n_dim,p);
+ printf(" -> %2u: ",p);
+ print_float_vec(pt,n_dim,"");
+ }
+ printf("-----------------------------------------------\n");
+ }
+ return ERR_OK;
+}
+
+#if 0
+ enumError err = n_dim == 3
+ ? ScanLine3(&lin,&si,true)
+ : ScanLine2(&lin,&si,true);
+ if (err)
+ continue;
+#endif
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+int test ( int argc, char ** argv )
+{
+ printf("sizeof: Color_t=%zu\n",sizeof(Color_t));
+ Color_t c;
+ c.r = 0x01;
+ c.g = 0x02;
+ c.b = 0x03;
+ c.a = 0x04;
+ printf("col=%x\n",c.val);
+
+ return 0;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_memfile() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_memfile ( int argc, char ** argv )
+{
+ MemFile_t mf;
+ InitializeMemFile(&mf,1000,0x100000);
+ mf.err_name = "TEST";
+ DumpMemFile(stdout,2,&mf);
+
+ WriteMemFile(&mf,"Hallo Dirk\n",11);
+ WriteMemFile(&mf,"Hallo Dirk\n",11);
+ WriteMemFileAt(&mf,4,"xxx",2);
+ WriteMemFile(&mf,"yyy",2);
+ DumpMemFile(stdout,2,&mf);
+ SaveMemFile(&mf,0,"memfile1.tmp",FM_OVERWRITE,false);
+
+ WriteMemFileAt(&mf,20,"|Hallo Dirk\n",12);
+ DumpMemFile(stdout,2,&mf);
+ SaveMemFile(&mf,0,"memfile2.tmp",FM_OVERWRITE,false);
+ ResetMemFile(&mf);
+
+ LoadMemFile(&mf,false,0,"memfile1.tmp",1,0,false);
+ SaveMemFile(&mf,0,"memfile3.tmp",FM_OVERWRITE,false);
+
+ WriteMemFileAt(&mf,0x10080,"a",1);
+ WriteMemFileAt(&mf,0x20080,"",0);
+ SaveMemFile(&mf,0,"sparse.tmp",FM_OVERWRITE,true);
+
+ for(;;)
+ {
+ char buf[5];
+ uint size = ReadMemFile(&mf,buf,sizeof(buf));
+ if (!size)
+ break;
+ fwrite(buf,1,size,stdout);
+ }
+ ResetMemFile(&mf);
+
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_find_dol() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_find_dol ( int argc, char ** argv )
+{
+ if ( argc < 3 )
+ {
+ fprintf(stderr,"params: main.dol size...\n");
+ return ERR_SYNTAX;
+ }
+
+ dol_header_t dh;
+ enumError err = LoadFILE(argv[1],0,0,&dh,sizeof(dh),1,false,false);
+ if (err)
+ return err;
+
+ dh.bss_size = htonl(0x2000000);
+ DumpDolHeader(stdout,3,&dh,0,2);
+
+ uint i;
+ for ( i = 2; i < argc; i++ )
+ {
+ const uint size = str2ul(argv[i],0,10);
+ u32 space, addr = FindFreeBssSpaceDOL(&dh,size,32,&space);
+ printf("%s %8x => %8x + %8x\n",argv[1],size,addr,space);
+ }
+
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_subfile() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static int SubFileIt
+(
+ SubFileIterator_t *sfi, // iterator data
+ uint mode, // 0:file, 1:open dir, 2:close dir
+ SubDir_t *dir, // current directory
+ SubFile_t *file // NULL or current file
+)
+{
+ printf("%*s%u %s\n",sfi->depth,"",mode,sfi->path);
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_subfile ( int argc, char ** argv )
+{
+ SubDir_t dir;
+ InitializeSubDir(&dir);
+
+ uint i;
+ for ( i = 1; i < argc; i++ )
+ {
+ ccp arg = argv[i];
+ bool new;
+ SubFile_t *sf = InsertSubFile(&dir,MemByString(arg),&new);
+ printf("%6s: %s\n",!sf?"FAIL":new?"INSERT":"FOUND",arg);
+ }
+
+ putchar('\n');
+ DumpSubDir(stdout,2,&dir);
+
+ SubFileIterator_t it;
+ memset(&it,0,sizeof(it));
+ it.func = SubFileIt;
+ IterateSubDir(&dir,&it);
+
+ SaveSubFiles(&dir,"_subfile.tmp");
+
+ for ( i = 1; i < argc; i++ )
+ {
+ ccp arg = argv[i];
+ SubFile_t *sf = FindSubFile(&dir,MemByString(arg));
+ if (sf)
+ printf("FOUND: %s -> %s\n",arg,sf->fname);
+ else
+ printf("NOT FOUND: %s\n",arg);
+ }
+
+ ResetSubDir(&dir);
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_str_list() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_str_list ( int argc, char ** argv )
+{
+ if ( argc < 2 )
+ {
+ printf( "STR-LIST | STR [option|string]...\n"
+ " -a : sort by ascii -> strcmp() [DEFAULT]\n"
+ " -i : sort 'ignore case'-> strcasecmp()\n"
+ " -n : sort numeric -> StrNumCmp()\n"
+ );
+ return ERR_OK;
+ }
+
+ StringField_t sf;
+ InitializeStringField(&sf);
+
+ uint i;
+ for ( i = 1; i < argc; i++ )
+ {
+ ccp arg = argv[i];
+ if (!strcmp(arg,"-a"))
+ {
+ WriteStringField(stdout,"stdout",&sf,"\t",0);
+ fputs("-----\n",stdout);
+ sf.func_cmp = strcmp;
+ SortStringField(&sf);
+ }
+ else if (!strcmp(arg,"-i"))
+ {
+ WriteStringField(stdout,"stdout",&sf,"\t",0);
+ fputs("-----\n",stdout);
+ sf.func_cmp = strcasecmp;
+ SortStringField(&sf);
+ }
+ else if (!strcmp(arg,"-n"))
+ {
+ WriteStringField(stdout,"stdout",&sf,"\t",0);
+ fputs("-----\n",stdout);
+ sf.func_cmp = StrNumCmp;
+ SortStringField(&sf);
+ }
+ else
+ InsertStringField(&sf,arg,false);
+ }
+
+ WriteStringField(stdout,"stdout",&sf,"\t",0);
+ ResetStringField(&sf);
+
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_container() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_container_data ( int mode, ContainerData_t *cdata, uint modify )
+{
+ Container_t c;
+ CatchContainerData(&c,true,cdata);
+ if ( mode >= 0 )
+ DumpInfoContainer(stdout,colout,2,"FUNC: ",&c, mode > 0 ? 32 : 0 );
+
+ if ( modify == 1 )
+ {
+ ModifyAllContainer(&c);
+ if ( c.cdata && c.cdata->data )
+ StringCopyS((char*)c.cdata->data,c.cdata->size,"MODIFIED!");
+ DumpInfoContainer(stdout,colout,2,"-MOD: ",&c, mode > 0 ? 32 : 0 );
+ }
+ else if ( modify == 2 && c.cdata && c.cdata->size > 20 )
+ {
+ char *data = (char*)c.cdata->data + 2;
+ if (ModifyContainer(&c,data,12,CPM_COPY))
+ data = (char*)c.cdata->data;
+ StringCopyE(data,(ccp)c.cdata->data+c.cdata->size,"EXTRACT!");
+ DumpInfoContainer(stdout,colout,2,"-EXT: ",&c, mode > 0 ? 32 : 0 );
+ }
+ ResetContainer(&c);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_container ( int argc, char ** argv )
+{
+ //-----------------------------------------------------------------------------
+ // to test
+ //-----------------------------------------------------------------------------
+ // + Container_t * CreateContainer ( Container_t, protect, data,size, CopyMode_t )
+ // - Container_t * InheritContainer ( Container_t cur, protect, Container_t parent, data,size )
+ // + bool AssignContainer ( Container_t, protect, data,size, CopyMode_t )
+ // + void ResetContainer ( Container_t )
+ // / void DeleteContainer ( Container_t )
+ // + void UnlinkContainerData ( Container_t )
+ // + ContainerData_t * LinkContainerData ( Container_t )
+ // + ContainerData_t * MoveContainerData ( Container_t )
+ // + Container_t * CatchContainerData ( Container_t, int protect, ContainerData_t )
+ //------------
+ // - ContainerData_t DisjoinContainerData ( Container_t )
+ // - void JoinContainerData ( Container_t, ContainerData_t )
+ // + void FreeContainerData ( ContainerData_t )
+ //------------
+ // + static inline bool ModificationAllowed ( const Container_t )
+ // + void ModifyAllContainer ( Container_t )
+ // + void ModifyContainer ( Container_t, data, size, CopyMode_t )
+ // + int SetProtectContainer ( Container_t, int new_protect )
+ // + static inline int AddProtectContainer ( Container_t, int add_protect )
+ // - static inline bool InContainerP ( const Container_t, cvp ptr )
+ // + static inline bool InContainerS ( const Container_t, cvp ptr, uint size )
+ // - static inline bool InContainerE ( const Container_t, cvp ptr, cvp end )
+ // + uint DumpInfoContainer ( f,col,indent,prefix, Container_t, hexdump_len )
+ // + uint DumpInfoContainerData ( f,col,indent,prefix, CData_t, hex_len, hex_indent )
+ //-----------------------------------------------------------------------------
+
+ if ( argc < 2 )
+ {
+ printf( "Syntax: CONTAINTER [['-'|'+']command]...\n"
+ "\n"
+ "Commands:\n"
+ "\n"
+ " dump : do nothing, dump only.\n"
+ " dump2 : do nothing, dump only second container.\n"
+ " unlink2 : unlink second container.\n"
+ "\n"
+ " inherit : inherit base data.\n"
+ " assign : re-assign base data.\n"
+ " free : free linked data.\n"
+ " catch : catch by second container.\n"
+ " reset : reset second container.\n"
+ "\n"
+ " p0..p2 : set protection level\n"
+ " p- p+ : decrement or increment protection level\n"
+ "\n"
+ " null : call function & use NULL\n"
+ " link : call function & use LinkContainerData()\n"
+ " link+ : call function & use LinkContainerData() & modify\n"
+ " link++ : call function & use LinkContainerData() & extract\n"
+ " move : call function & use MoveContainerData()\n"
+ " move+ : call function & use MoveContainerData() & modify\n"
+ " move++ : call function & use MoveContainerData() & extract\n"
+ "\n"
+ "The base container is automatically recreated if empty.\n"
+ "\n"
+ "Command prefix:\n"
+ " - : silent = Don't dump.\n"
+ " + : verbose = include hex dump.\n"
+ "\n"
+ );
+ return 0;
+ }
+
+ char buf[1000];
+ memset(buf,0,sizeof(buf));
+ strcpy(buf,"0123456789 init");
+ Container_t c, cc;
+ CreateContainer(&c,true,buf,sizeof(buf),CPM_LINK);
+ CreateContainer(&cc,true,0,0,0);
+ DumpInfoContainer(stdout,colout,2,"BASE: ",&c,32);
+
+ uint i;
+ for ( i = 1; i < argc; i++ )
+ {
+ ccp arg = argv[i];
+ if ( !arg || !*arg )
+ continue;
+ int mode = 0;
+ if ( *arg == '-' )
+ mode--, arg++;
+ else if ( *arg == '+' )
+ mode++, arg++;
+
+ if ( mode >= 0 )
+ printf("-------------------- %d. |%s| --------------------\n",i,arg);
+
+ if (!strcasecmp(arg,"p0"))
+ SetProtectContainer(&c,0);
+ else if (!strcasecmp(arg,"p1"))
+ SetProtectContainer(&c,1);
+ else if (!strcasecmp(arg,"p2"))
+ SetProtectContainer(&c,2);
+ else if (!strcasecmp(arg,"p-"))
+ AddProtectContainer(&c,-1);
+ else if (!strcasecmp(arg,"p+"))
+ AddProtectContainer(&c,1);
+
+ else if (!strcasecmp(arg,"null"))
+ test_container_data(mode,0,0);
+
+ else if (!strcasecmp(arg,"link"))
+ test_container_data(mode,LinkContainerData(&c),0);
+ else if (!strcasecmp(arg,"link+"))
+ test_container_data(mode,LinkContainerData(&c),1);
+ else if (!strcasecmp(arg,"link++"))
+ test_container_data(mode,LinkContainerData(&c),2);
+
+ else if (!strcasecmp(arg,"move"))
+ test_container_data(mode,MoveContainerData(&c),0);
+ else if (!strcasecmp(arg,"move+"))
+ test_container_data(mode,MoveContainerData(&c),1);
+ else if (!strcasecmp(arg,"move++"))
+ test_container_data(mode,MoveContainerData(&c),2);
+
+ else if (!strcasecmp(arg,"unlink2"))
+ {
+ UnlinkContainerData(&cc);
+ }
+ else if (!strcasecmp(arg,"inherit"))
+ {
+ InheritContainer(&cc,2,&c,buf+5,3);
+ if ( mode >= 0 )
+ DumpInfoContainer(stdout,colout,2,"C2: ",&cc, mode > 0 ? 32 : 0 );
+ }
+ else if (!strcasecmp(arg,"assign"))
+ {
+ memset(buf,0,sizeof(buf));
+ strcpy(buf,"0123456789 init");
+ AssignContainer(&c,true,buf,sizeof(buf),CPM_LINK);
+ }
+ else if (!strcasecmp(arg,"free"))
+ {
+ FreeContainerData(LinkContainerData(&c));
+ }
+ else if (!strcasecmp(arg,"catch"))
+ {
+ ResetContainer(&cc);
+ CatchContainerData(&cc,true,LinkContainerData(&c));
+ if ( mode >= 0 )
+ DumpInfoContainer(stdout,colout,2,"C2: ",&cc, mode > 0 ? 32 : 0 );
+ }
+ else if (!strcasecmp(arg,"reset"))
+ {
+ ResetContainer(&cc);
+ if ( mode >= 0 )
+ DumpInfoContainer(stdout,colout,2,"C2: ",&cc, mode > 0 ? 32 : 0 );
+ }
+ else if (strcasecmp(arg,"dump"))
+ {
+ printf(" >>> IGNORED!\n");
+ continue;
+ }
+ else if (strcasecmp(arg,"dump2"))
+ {
+ DumpInfoContainer(stdout,colout,2,"C2: ",&cc, mode > 0 ? 32 : 0 );
+ continue;
+ }
+
+ if ( mode >= 0 )
+ DumpInfoContainer(stdout,colout,2,"BACK: ",&c, mode > 0 ? 32 : 0 );
+
+ if (!c.cdata)
+ {
+ memset(buf,0,sizeof(buf));
+ strcpy(buf,"0123456789 init");
+ AssignContainer(&c,true,buf,sizeof(buf),CPM_LINK);
+ }
+ }
+
+ ResetContainer(&c);
+ ResetContainer(&cc);
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_uuid() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_uuid ( int argc, char ** argv )
+{
+ uint i;
+ char buf[100];
+
+ printf("\n--- test ReadFromUrandom()\n");
+ for ( i = 0; i < 5; i++ )
+ {
+ uint stat = ReadFromUrandom(buf,15);
+ HexDump16(stdout,4,0,buf,stat);
+ }
+
+ printf("\n--- test CreateUUID() & MyRandom(1000000)\n");
+ for ( i = 0; i < 5; i++ )
+ {
+ uint stat = CreateTextUUID(buf,sizeof(buf));
+ printf(" %u: %s %6u [avail=%d,use=%d]\n",
+ stat, buf, MyRandom(1000000),
+ urandom_available, use_urandom_for_myrandom );
+ }
+
+ printf("\n--- test ScanUUID()\n");
+ for ( i = 1; i < argc; i++ )
+ {
+ uuid_buf_t uuid;
+ ccp stat = ScanUUID(uuid,argv[i]);
+ PrintUUID(buf,sizeof(buf),uuid);
+ printf("%s %s<= %s\n", buf, stat==argv[i] ? "FAILED! " : "", argv[i] );
+ }
+
+ putchar('\n');
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_analyse_magic() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_analyse_magic ( int argc, char ** argv )
+{
+ uint i;
+ u8 magic[8];
+
+ printf("\n--- test AnalyseMagic() + RepairMagic()\n");
+ for ( i = 1; i < argc; i++ )
+ {
+ ccp fname = argv[i];
+ printf("\n%s\n", fname );
+
+ u8 *data;
+ uint data_size;
+ enumError err = OpenReadFILE(fname,0,false,&data,&data_size,0,0);
+ if ( err || data_size < sizeof(magic) )
+ return err;
+
+ memcpy(magic,data,sizeof(magic));
+
+ repair_ff_t rep;
+ AnalyseMagic(&rep,data,data_size,data_size,FF_UNKNOWN,fname,false);
+ printf("\t\e[35;1m=> Ana0: %s\e[0m\n",GetRepairMagicInfo(&rep));
+ RepairMagic(&rep,data,data_size,data_size,FF_UNKNOWN,fname,false);
+ printf("\t\e[35;1m=> Rep0: %s\e[0m\n",GetRepairMagicInfo(&rep));
+
+ memcpy(data,magic,sizeof(magic));
+ AnalyseMagic(&rep,data,data_size,data_size,FF_UNKNOWN,fname,true);
+ printf("\t\e[35;1m=> Ana1: %s\e[0m\n",GetRepairMagicInfo(&rep));
+ RepairMagic(&rep,data,data_size,data_size,FF_UNKNOWN,fname,true);
+ printf("\t\e[35;1m=> Rep1: %s\e[0m\n",GetRepairMagicInfo(&rep));
+
+ if (rep.magic_len)
+ {
+ fputs("\t\e[35;1m=> magic0:",stdout);
+ uint i;
+ for ( i = 0; i < rep.magic_len; i++ )
+ printf(" %02x",magic[i]);
+ fputs("\e[0m\n\t\e[35;1m=> magic1:",stdout);
+ for ( i = 0; i < rep.magic_len; i++ )
+ printf(" %02x",data[i]);
+ fputs("\e[0m\n",stdout);
+ }
+ FREE(data);
+ }
+
+ putchar('\n');
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_vr() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+// get VR diff by b-spline curve (by chadders, outdated (not exact))
+// https://www.desmos.com/calculator/gr17y7d944
+
+static double GetVrDiffBSpline ( double d )
+{
+ //-------------------------------------------
+ // x = loser - winner
+ //
+ // f(x):
+ // (0..1( : 1/6 * (3x^3 - 6x^2 + 4 )
+ // (1..2( : 1/6 * (2-x)^3
+ // else : 0
+ //
+ //-------------------------------------------
+
+ if ( d >= 0.0 && d < 1.0 )
+ return ( 3*d*d*d - 6*d*d + 4 )/6.0;
+
+ if ( d >= 1.0 && d < 2.0 )
+ {
+ d = 2 - d;
+ return d*d*d/6.0;
+ }
+
+ return 0;
+}
+
+
+double GetVrDiffD ( int diff )
+{
+ // diff := Pwinner - Plooser
+
+
+ //-- cut differences
+
+ if ( diff > 9998 )
+ diff = 9998;
+ else if ( diff < -9998 )
+ diff = -9998;
+
+
+ //-- calculate rating as sum of 10 knots
+
+ double sum = 0;
+ int j;
+ for ( j = 0; j < 10; j++ )
+ {
+ static int knot[] = {0,0,0,1,8,50,125,125,125,125};
+ const double temp = fabs( (2-diff)/5000.0 - ( j - 4 ) );
+ sum += GetVrDiffBSpline(temp) * knot[j];
+ }
+
+ return sum;
+}
+
+static inline int GetVrDiffI ( int diff )
+ { return floor(GetVrDiffD(diff)); }
+
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_vr ( int argc, char ** argv )
+{
+ const struct pair { int delta; int vr_add; } known[] =
+ {
+ {-20000, 112 },
+ { -9998, 112 },
+ { -9980, 112 },
+ { -9890, 111 },
+ { -9190, 105 },
+ { -8000, 92 },
+ { -6000, 67 },
+ { -4000, 44 },
+ { -2000, 26 },
+ { -1000, 19 },
+ { 0, 13 },
+ { 2000, 6 },
+ { 4000, 2 },
+ { 6000, 1 },
+ { 8000, 0 },
+ { 9980, 0 },
+ { 9998, 0 },
+ { 20000, 0 },
+ {-1,-1}
+ };
+
+ int i;
+ for ( i = 1; i < argc; i++ )
+ {
+ bool verbose = !strcmp(argv[i],"test+");
+ if ( verbose || !strcmp(argv[i],"test") )
+ {
+ fputs("\n"
+ " delta : result : tab : good : status\n"
+ "-------------------------------------------\n",stdout);
+ int count = 0, total = 0;
+ const struct pair *ptr;
+ for ( ptr = known; ptr->vr_add != -1; ptr++ )
+ {
+ total++;
+ double r = GetVrDiffD(ptr->delta);
+ int i = floor(r);
+ int j = GetVrDiffByTab(ptr->delta);
+ bool differ = i != ptr->vr_add || i != j;
+ count += differ;
+ if ( differ || verbose )
+ printf("%8d : %8.4f : %4d : %4d %s\n",
+ ptr->delta, r, j, ptr->vr_add,
+ differ ? " : DIFFER" : "" );
+ }
+ printf("-------------------------------------------\n"
+ " >>> %u of %u differ,%s\n",
+ count, total,
+ verbose ? "" : " [use test+ to show all]" );
+ continue;
+ }
+
+ if (!strcmp(argv[i],"table3"))
+ {
+ fputs("\n"
+ "\t// winner-loser add\n"
+ "\t// from, to, vr // N\n"
+ "\t//------------------------------\n",stdout);
+
+ int diff = -10000, max_diff = 10000, n_record = 0;
+
+ for ( ; diff < max_diff; diff++ )
+ {
+ int start = diff, val = GetVrDiffI(diff);
+ while ( diff < max_diff && GetVrDiffI(diff) == val )
+ diff++;
+ printf("\t{ %6d, %5d, %3d }, // %4u\n",
+ start, diff, val, diff-start+1 );
+ n_record++;
+ }
+ printf("\t// %u records total\n",n_record);
+ continue;
+ }
+
+ if ( !strcmp(argv[i],"table2") || !strcmp(argv[i],"table") )
+ {
+ fputs("\n"
+ "\t// delta, +vr // N\n"
+ "\t//------------------------------\n",stdout);
+
+ int diff = -10000, max_diff = 10000, n_record = 0;
+
+ for ( ; diff < max_diff; diff++ )
+ {
+ int start = diff, val = GetVrDiffI(diff);
+ while ( diff < max_diff && GetVrDiffI(diff) == val )
+ diff++;
+ printf("\t{ %6d, %3d }, // %4u\n",
+ start, val, diff-start+1 );
+ n_record++;
+ }
+ fputs("\t{ 10000, 0 } // upper border\n",stdout);
+ printf("\t// %u+1 records total\n",n_record);
+ continue;
+ }
+
+ int d = str2l(argv[i],0,10);
+ double r = GetVrDiffD(d);
+ printf("%8d -> %10.4f\n",d,r);
+ }
+ putchar('\n');
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_vr2() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+typedef struct vr1_diff_t
+{
+ s16 diff;
+ s16 add_vr;
+}
+vr1_diff_t;
+
+//-----------------------------------------------------------------------------
+
+static const vr1_diff_t vr1_diff_tab[] =
+{
+ // delta, +vr // N
+ //------------------------------
+ { -10000, 112 }, // 68
+ { -9932, 111 }, // 127
+ { -9805, 110 }, // 122
+ { -9683, 109 }, // 116
+ { -9567, 108 }, // 113
+ { -9454, 107 }, // 110
+ { -9344, 106 }, // 106
+ { -9238, 105 }, // 104
+ { -9134, 104 }, // 101
+ { -9033, 103 }, // 99
+ { -8934, 102 }, // 97
+ { -8837, 101 }, // 95
+ { -8742, 100 }, // 94
+ { -8648, 99 }, // 92
+ { -8556, 98 }, // 91
+ { -8465, 97 }, // 89
+ { -8376, 96 }, // 89
+ { -8287, 95 }, // 87
+ { -8200, 94 }, // 87
+ { -8113, 93 }, // 85
+ { -8028, 92 }, // 85
+ { -7943, 91 }, // 84
+ { -7859, 90 }, // 84
+ { -7775, 89 }, // 83
+ { -7692, 88 }, // 82
+ { -7610, 87 }, // 81
+ { -7529, 86 }, // 82
+ { -7447, 85 }, // 81
+ { -7366, 84 }, // 80
+ { -7286, 83 }, // 80
+ { -7206, 82 }, // 80
+ { -7126, 81 }, // 79
+ { -7047, 80 }, // 80
+ { -6967, 79 }, // 79
+ { -6888, 78 }, // 79
+ { -6809, 77 }, // 79
+ { -6730, 76 }, // 78
+ { -6652, 75 }, // 79
+ { -6573, 74 }, // 79
+ { -6494, 73 }, // 78
+ { -6416, 72 }, // 79
+ { -6337, 71 }, // 79
+ { -6258, 70 }, // 79
+ { -6179, 69 }, // 79
+ { -6100, 68 }, // 79
+ { -6021, 67 }, // 80
+ { -5941, 66 }, // 79
+ { -5862, 65 }, // 80
+ { -5782, 64 }, // 81
+ { -5701, 63 }, // 80
+ { -5621, 62 }, // 82
+ { -5539, 61 }, // 81
+ { -5458, 60 }, // 82
+ { -5376, 59 }, // 83
+ { -5293, 58 }, // 83
+ { -5210, 57 }, // 84
+ { -5126, 56 }, // 85
+ { -5041, 55 }, // 85
+ { -4956, 54 }, // 87
+ { -4869, 53 }, // 87
+ { -4782, 52 }, // 88
+ { -4694, 51 }, // 89
+ { -4605, 50 }, // 90
+ { -4515, 49 }, // 91
+ { -4424, 48 }, // 91
+ { -4333, 47 }, // 93
+ { -4240, 46 }, // 94
+ { -4146, 45 }, // 96
+ { -4050, 44 }, // 96
+ { -3954, 43 }, // 98
+ { -3856, 42 }, // 98
+ { -3758, 41 }, // 101
+ { -3657, 40 }, // 101
+ { -3556, 39 }, // 103
+ { -3453, 38 }, // 105
+ { -3348, 37 }, // 106
+ { -3242, 36 }, // 107
+ { -3135, 35 }, // 110
+ { -3025, 34 }, // 111
+ { -2914, 33 }, // 113
+ { -2801, 32 }, // 115
+ { -2686, 31 }, // 118
+ { -2568, 30 }, // 119
+ { -2449, 29 }, // 122
+ { -2327, 28 }, // 125
+ { -2202, 27 }, // 127
+ { -2075, 26 }, // 130
+ { -1945, 25 }, // 133
+ { -1812, 24 }, // 137
+ { -1675, 23 }, // 140
+ { -1535, 22 }, // 144
+ { -1391, 21 }, // 149
+ { -1242, 20 }, // 153
+ { -1089, 19 }, // 159
+ { -930, 18 }, // 164
+ { -766, 17 }, // 171
+ { -595, 16 }, // 178
+ { -417, 15 }, // 187
+ { -230, 14 }, // 197
+ { -33, 13 }, // 208
+ { 175, 12 }, // 221
+ { 396, 11 }, // 238
+ { 634, 10 }, // 256
+ { 890, 9 }, // 279
+ { 1169, 8 }, // 308
+ { 1477, 7 }, // 343
+ { 1820, 6 }, // 393
+ { 2213, 5 }, // 459
+ { 2672, 4 }, // 562
+ { 3234, 3 }, // 730
+ { 3964, 2 }, // 1036
+ { 5000, 1 }, // 1599
+ { 6599, 0 }, // 3401
+ { 10000, 0 } // upper border
+ // 113+1 records total
+};
+
+//-----------------------------------------------------------------------------
+
+int GetVr1DiffByTab ( int diff ) // diff = VR(winner) - VR(loser)
+{
+ int i = 0;
+ int j = sizeof(vr1_diff_tab) / sizeof(*vr1_diff_tab) - 2;
+ DASSERT( vr1_diff_tab[i].diff == -10000 );
+ DASSERT( vr1_diff_tab[j+1].diff == 10000 );
+
+ #if HAVE_PRINT
+ {
+ static int done = 0;
+ PRINT_IF(!done++,
+ "vr1_diff_tab: %d,%d => %d,%d / %d,%d\n",
+ vr1_diff_tab[i].diff, vr1_diff_tab[i].add_vr,
+ vr1_diff_tab[j].diff, vr1_diff_tab[j].add_vr,
+ vr1_diff_tab[j+1].diff, vr1_diff_tab[j+1].add_vr );
+ }
+ #endif
+
+ if ( diff <= -10000 )
+ return vr1_diff_tab[0].add_vr;
+ if ( diff >= 10000 )
+ return vr1_diff_tab[j].add_vr;
+
+ while ( i < j )
+ {
+ const int k = (i+j)/2;
+ if ( diff < vr1_diff_tab[k].diff )
+ j = k-1;
+ else if ( diff >= vr1_diff_tab[k+1].diff )
+ i = k+1;
+ else
+ return vr1_diff_tab[k].add_vr;
+ }
+
+ return vr1_diff_tab[i].add_vr;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static const s16 vr2_diff_tab[112] =
+{
+ 6598, 4999, 3963, 3233, 2671, 2212, 1819, 1476, // 0 .. 7
+ 1168, 889, 633, 395, 174, -34, -231, -418, // 8 .. 15
+ -596, -767, -931, -1090, -1243, -1392, -1536, -1676, // 16 .. 23
+ -1813, -1946, -2076, -2203, -2328, -2450, -2569, -2687, // 24 .. 31
+ -2802, -2915, -3026, -3136, -3243, -3349, -3454, -3557, // 32 .. 39
+ -3658, -3759, -3857, -3955, -4051, -4147, -4241, -4334, // 40 .. 47
+ -4425, -4516, -4606, -4695, -4783, -4870, -4957, -5042, // 48 .. 55
+ -5127, -5211, -5294, -5377, -5459, -5540, -5622, -5702, // 56 .. 63
+ -5783, -5863, -5942, -6022, -6101, -6180, -6259, -6338, // 64 .. 71
+ -6417, -6495, -6574, -6653, -6731, -6810, -6889, -6968, // 72 .. 79
+ -7048, -7127, -7207, -7287, -7367, -7448, -7530, -7611, // 80 .. 87
+ -7693, -7776, -7860, -7944, -8029, -8114, -8201, -8288, // 88 .. 95
+ -8377, -8466, -8557, -8649, -8743, -8838, -8935, -9034, // 96 .. 103
+ -9135, -9239, -9345, -9455, -9568, -9684, -9806, -9933, // 104 .. 111
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+int GetVr2DiffByTab ( int diff ) // diff = VR(winner) - VR(loser)
+{
+ if ( diff > 6598 )
+ return 0;
+ if ( diff < -9933 )
+ return 112;
+
+ const s16 search = diff;
+ int i = 0, j = sizeof(vr2_diff_tab) / sizeof(*vr2_diff_tab) - 1;
+
+ while ( i < j )
+ {
+ const int k = (i+j)/2;
+ if ( search > vr2_diff_tab[k] )
+ j = k-1;
+ else if ( search <= vr2_diff_tab[k+1] )
+ i = k+1;
+ else
+ return k+1;
+ }
+
+ return i+1;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_vr2 ( int argc, char ** argv )
+{
+ if ( argc > 1 && !strcmp(argv[1],"-c") )
+ {
+ int i, j, vr = 0, n = sizeof(vr1_diff_tab) / sizeof(*vr1_diff_tab) - 1;
+ printf("\nstatic const int16_t vr2_diff_tab[%u] =\n{\n",n-1);
+
+ for ( i = n-1; i > 0; i -= 8, vr += 8 )
+ {
+ putchar('\t');
+ for ( j = 0; j < 8; j++ )
+ {
+ int idx = i - j;
+ if ( idx > 0 )
+ printf("%6d,", vr1_diff_tab[idx].diff - 1 );
+ }
+ printf(" // %3u .. %3u\n",vr,vr+7);
+ }
+ printf("};\n\n");
+ return ERR_OK;
+ }
+
+ const int from = -10000;
+ const int to = 10000;
+ printf(">>> Compare 3x VR from %d to %d <<<\n",from,to);
+
+ int diff, err_count = 0;
+ for ( diff = from; diff <= to; diff++ )
+ {
+ const int vr0 = GetVrDiffByTab(diff);
+ const int vr1 = GetVr1DiffByTab(diff);
+ const int vr2 = GetVr2DiffByTab(diff);
+
+ if ( vr0 != vr1 || vr1 != vr2 )
+ {
+ if ( ++err_count < 20 )
+ printf("ERR: diff %6d : vr012 %3d %3d %3d\n",diff,vr0,vr1,vr2);
+ }
+ }
+
+ if (err_count)
+ printf("!!! %u error%s total!\n",err_count,err_count==1?"":"s");
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_regex() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_regex ( int argc, char ** argv )
+{
+ if ( argc < 2 )
+ {
+ fprintf(stderr,"\nUsage: wtest RE|REGEXP reg_expr string...\n\n");
+ return ERR_SYNTAX;
+ }
+
+ Regex_t re;
+ enumError err = ScanRegex(&re,true,argv[1]);
+ if ( err || !re.valid )
+ return ERROR0(err,"Invalid regex: %s\n",argv[1]);
+
+ struct { FastBuf_t b; char space[500]; } res;
+ InitializeFastBuf(&res,sizeof(res));
+
+ int i;
+ for ( i = 2; i < argc; i++ )
+ {
+ ccp arg = argv[i];
+ int stat = ReplaceRegex(&re,&res.b,arg,-1);
+ printf("\n%s\n -> [%d] %s\n",arg,stat,GetFastBufString(&res.b));
+ }
+
+ putchar('\n');
+ ResetFastBuf(&res.b);
+ ResetRegex(&re);
+
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_ct_mode() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_ct_mode_helper ( ct_mode_t mode, bool show_id )
+{
+ ct_bmg_t ctb;
+ SetupCtBMG(&ctb,mode,mode);
+ putchar('\n');
+ if (show_id)
+ printf("%s\n",GetCtBMGIdentification(&ctb,true));
+ DumpCtBMG(stdout,0,&ctb);
+}
+
+static enumError test_ct_mode ( int argc, char ** argv )
+{
+ bool show_id = false;
+ int i;
+ for ( i = 1; i < argc; i++ )
+ {
+ ccp arg = argv[i];
+ if (!strcmp(arg,"-l"))
+ show_id = true;
+ }
+
+ test_ct_mode_helper(CTM_NINTENDO,show_id);
+ test_ct_mode_helper(CTM_CTCODE,show_id);
+ test_ct_mode_helper(CTM_LECODE1,show_id);
+ test_ct_mode_helper(CTM_LECODE2,show_id);
+ putchar('\n');
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_scan_hex() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_scan_hex ( int argc, char ** argv )
+{
+ PRINT_SIZEOF1(VarMode_t);
+ PRINT_SIZEOF1(IntMode_t);
+ PRINT_SIZEOF1(Var_t);
+ PRINT_SIZEOF1(FastBuf_t);
+
+ PRINT1("offsetof(Var_t,name) = %zu\n",offsetof(Var_t,name));
+ PRINT1("offsetof(Var_t,mode) = %zu\n",offsetof(Var_t,mode));
+ PRINT1("offsetof(Var_t,int_mode) = %zu\n",offsetof(Var_t,int_mode));
+ PRINT1("offsetof(Var_t,i) = %zu\n",offsetof(Var_t,i));
+
+ FastBuf_t fb;
+ InitializeFastBuf(&fb,1000);
+
+ int i;
+ for ( i = 1; i < argc; i++ )
+ {
+ char name[20];
+ snprintf(name,sizeof(name),"Param #%u",i);
+
+ ScanInfo_t si;
+ InitializeSI(&si,argv[i],strlen(argv[i]),name,0);
+
+ ClearFastBuf(&fb);
+ ScanHexlineSI(&si,&fb,true);
+ HexDump16(stdout,0,0,fb.buf,fb.ptr-fb.buf);
+ putchar('\n');
+ CheckEolSI(&si);
+ ResetSI(&si);
+ }
+
+ ResetFastBuf(&fb);
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_shift_jis() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_shift_jis ( int argc, char ** argv )
+{
+ printf("\nShift-JIS: %s\n\n",GetShiftJISStatistics());
+
+ {
+ static char info[] = "|\x82\x4a|\x82\x50|";
+ HexDump16(stdout,0,0,info,sizeof(info));
+
+ cucp src0 = (cucp)info;
+ cucp src1 = (cucp)info;
+ cucp end1 = src1 + strlen(info);
+ while ( *src0 || *src1 )
+ {
+ u16 code0 = ScanShiftJISChar(&src0);
+ u16 code1 = ScanShiftJISCharE(&src1,end1);
+ u16 ch0 = GetShiftJISChar(code0);
+ u16 ch1 = GetShiftJISChar(code1);
+
+ printf("%4x %4x : %3zd %3zd : %4x %4x\n",
+ code0, code1, src0-(cucp)info, src1-(cucp)info, ch0, ch1 );
+ }
+ }
+
+ printf("\n------------------------------------------\n");
+
+ {
+ static u16 info2[] = { 0x7199, 0xff10, 0xff80, 0xff9f, 0xffff, 0 };
+ char buf[100], *dest = buf;
+
+ const u16 *p;
+ for ( p = info2; *p; p++ )
+ {
+ u16 code = GetShiftJISChar(*p);
+ printf("%4x -> %4x\n",*p,code);
+
+ if ( code >= 0x100 )
+ {
+ write_be16(dest,code);
+ dest += 2;
+ }
+ else if ( code > 0 )
+ *dest++ = code;
+ }
+ *dest++= 0;
+ HexDump16(stdout,0,0,buf,dest-buf);
+
+ cucp ptr = (cucp)buf;
+ while (*ptr)
+ {
+ u16 code = ScanShiftJISChar(&ptr);
+ u16 ch = GetShiftJISChar(code);
+
+ printf("%4x : %3zd : %4x\n", code, ptr-(cucp)buf, ch );
+ }
+ }
+
+ printf("\n------------------------------------------\n");
+
+ {
+ static char info[] = "|\xff\x80|";
+ HexDump16(stdout,0,0,info,sizeof(info));
+
+ cucp src0 = (cucp)info;
+ cucp src1 = (cucp)info;
+ cucp end1 = src1 + strlen(info);
+ while ( *src0 || *src1 )
+ {
+ u16 beg0 = be16(src0);
+ u16 beg1 = be16(src1);
+ u16 code0 = ScanShiftJISChar(&src0);
+ u16 code1 = ScanShiftJISCharE(&src1,end1);
+ u16 ch0 = GetShiftJISChar(code0);
+ u16 ch1 = GetShiftJISChar(code1);
+
+ printf(" %4x %4x : %4x %4x : %3zd %3zd : %4x %4x\n",
+ beg0, beg1, code0, code1,
+ src0-(cucp)info, src1-(cucp)info, ch0, ch1 );
+ }
+ }
+
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_item_slot() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_item_slot ( int argc, char ** argv )
+{
+ int i;
+ for ( i = 1; i < argc; i++ )
+ {
+ u8 *data;
+ uint size;
+ ccp fname;
+ enumError err = OpenReadFILE(argv[i],0,false,&data,&size,&fname,0);
+ if (err)
+ continue;
+
+ printf("\n\e[36;1m----- %s [%u] -----\e[0m\n",fname,size);
+ u8 *ptr = data;
+ u8 *end = data+size;
+ uint n_tab = *ptr++;
+ printf("%u tables\n",n_tab);
+ uint t;
+ for ( t = 0; t < n_tab; t++ )
+ {
+ uint tabsize = ptr[0] * ptr[1];
+ u8 *nexttab = ptr + tabsize + 2;
+ if ( nexttab > end )
+ break;
+
+ printf("%2u/%u: %2u*%-2u %03zx..%03zx/%x\n",
+ t, n_tab, ptr[0], ptr[1], ptr - data, nexttab - data, size );
+ ptr = nexttab;
+ }
+ FREE(data);
+ }
+
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// Since 2001 ///////////////
+///////////////////////////////////////////////////////////////////////////////
+// hour support
+
+#if 0 // [[?]] ???
+int hour2elapsed ( $hour = NULL, $ref_time = NULL )
+{
+ if (!$ref_time)
+ $ref_time = time();
+ $ref = self::time2hour($ref_time);
+ if ( !isset($hour) || $hour == $ref )
+ return ( $ref_time - self::hour2time($ref) ) / self::DUR_HOUR;
+
+ return $hour < $ref ? 1.0 : 0.0;
+}
+#endif
+
+//
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+// day support
+
+#if 0 // [[?]] ???
+int day2elapsed ( $day = NULL, $ref_time = NULL )
+{
+ if (!$ref_time)
+ $ref_time = time();
+ $ref = self::time2day($ref_time);
+ if ( !isset($day) || $day == $ref )
+ return ( $ref_time - self::day2time($ref) ) / self::DUR_DAY;
+
+ return $day < $ref ? 1.0 : 0.0;
+}
+#endif
+
+//
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+// week support
+
+#if 0 // [[?]] ???
+int week2elapsed ( $week = NULL, $ref_time = NULL )
+{
+ if (!$ref_time)
+ $ref_time = time();
+ $ref = self::time2week($ref_time);
+ if ( !isset($week) || $week == $ref )
+ return ( $ref_time - self::week2time($ref) ) / self::DUR_WEEK;
+
+ return $week < $ref ? 1.0 : 0.0;
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+
+#if 0 // [[?]] ???
+int GetWeekInfoByYear ( $year )
+{
+ $r = new \stdClass;
+ $r->year = intval($year);
+
+ $tim = gmmktime( 12,0,0, 1,4,$r->year );
+ $r->first_week = self::time2week($tim);
+
+ $tim = gmmktime( 12,0,0, 12,28,$r->year );
+ $r->last_week = self::time2week($tim);
+
+ return $r;
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+
+#if 0 // [[?]] ???
+int GetWeekYearByWeek ( $week )
+{
+ $l = explode(',',gmstrftime('%G,%V',
+ self::week2time($week) + self::DUR_DAY*3 ));
+
+ $r = new \stdClass;
+ $r->year = intval($l[0]); // real year number
+ $r->week = intval($l[1]); // 1..12
+ return $r;
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////
+
+#if 0 // [[?]] ???
+int GetWeekYearByTime ( $time )
+{
+ $l = explode(',',gmstrftime('%G,%V,%u',$time));
+
+ $r = new \stdClass;
+ $r->year = intval($l[0]); // real year number
+ $r->week = intval($l[1]); // 1..12
+ $r->weekday = intval($l[2]); // 1=monday .. 7=sunday
+ return $r;
+}
+#endif
+
+//
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+// month support
+
+#if 0 // [[?]] ???
+int month2elapsed ( $month = NULL, $ref_time = NULL )
+{
+ if (!$ref_time)
+ $ref_time = time($ref_time);
+ $ref = self::time2month($ref_time);
+ if ( !isset($month) || $month == $ref )
+ {
+ $beg = self::month2time($ref);
+ return ( $ref_time - $beg ) / ( self::month2time($ref+1) - $beg );
+ }
+
+ return $month < $ref ? 1.0 : 0.0;
+}
+#endif
+
+//
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+// quarter support
+
+#if 0 // [[?]] ???
+int quarter2elapsed ( $quarter = NULL, $ref_time = NULL )
+{
+ if (!$ref_time)
+ $ref_time = time();
+ $ref = self::time2quarter($ref_time);
+ if ( !isset($quarter) || $quarter == $ref )
+ {
+ $beg = self::quarter2time($ref);
+ return ( $ref_time - $beg ) / ( self::quarter2time($ref+1) - $beg );
+ }
+
+ return $quarter < $ref ? 1.0 : 0.0;
+}
+#endif
+
+//
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+// year support
+
+#if 0 // [[?]] ???
+int year2elapsed ( $year = NULL, $ref_time = NULL )
+{
+ if (!$ref_time)
+ $ref_time = time($ref_time);
+ $ref = self::time2year($ref_time);
+ if ( !isset($year) || $year == $ref )
+ {
+ $beg = self::year2time($ref);
+ return ( $ref_time - $beg ) / ( self::year2time($ref+1) - $beg );
+ }
+
+ return $year < $ref ? 1.0 : 0.0;
+}
+#endif
+
+//
+///////////////////////////////////////////////////////////////////////////
+///////////////////////////////////////////////////////////////////////////
+// misc
+
+#if 0 // [[?]] ???
+int GetAverageDuration ( $period )
+{
+ // Values for day and week are exact.
+ // Values for month, quarter and year are based on 365.2425 days/year.
+
+ switch ($period)
+ {
+ case 'hour': return self::DUR_HOUR; break;
+ case 'day': return self::DUR_DAY; break;
+ case 'week': return self::DUR_WEEK; break;
+ case 'month': return self::DUR_MONTH; break;
+ case 'quarter': return self::DUR_QUARTER; break;
+ case 'year': return self::DUR_YEAR; break;
+ }
+ return false;
+}
+#endif
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_since2001() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_since2001 ( int argc, char ** argv )
+{
+ uint i;
+ for ( i = 1; i < argc; i++ )
+ {
+ s64 time0 = argv[i][0] == 'n' ? GetTimeSec(false)
+ : argv[i][0] == '+' ? 978307200
+ : str2l(argv[i],0,10);
+ printf("\n\e[36m %s -> %lld -> %s \e[0m\n",
+ argv[i], time0, PrintTimeByFormat("%F %T",time0) );
+
+ int num;
+ s64 tim;
+ ccp t1, t2, format = "%c:%7d %-10s %-13s %-19s %9u\n";
+
+ //--- hour
+
+ num = time2hour(time0);
+ tim = hour2time(num);
+ t1 = hour2text(num,0,0,0);
+ t2 = hour2text(num,99,0,0);
+ printf(format,'H',num,t1,t2,
+ PrintTimeByFormat("%F %T",tim),
+ hour2duration(num));
+
+ t1 = hour2text(num,10,0,0);
+ t2 = hour2text(num,11,0,0);
+ printf(format,'H',num,t1,t2,
+ PrintTimeByFormat("%F %T",tim),
+ hour2duration(num));
+
+ //--- day
+
+ num = time2day(time0);
+ tim = day2time(num);
+ t1 = day2text(num,0,0,0);
+ t2 = day2text(num,99,0,0);
+ printf(format,'D',num,t1,t2,
+ PrintTimeByFormat("%F %T",tim),
+ day2duration(num));
+
+ //--- week
+
+ num = time2week(time0);
+ tim = week2time(num);
+ t1 = week2text(num,0,0,0);
+ t2 = week2text(num,99,0,0);
+ printf(format,'W',num,t1,t2,
+ PrintTimeByFormat("%F %T",tim),
+ week2duration(num));
+
+ //--- month
+
+ num = time2month(time0);
+ tim = month2time(num);
+ t1 = month2text(num,0,0,0);
+ t2 = month2text(num,99,0,0);
+ printf(format,'M',num,t1,t2,
+ PrintTimeByFormat("%F %T",tim),
+ month2duration(num));
+
+ //--- quarter
+
+ num = time2quarter(time0);
+ tim = quarter2time(num);
+ t1 = quarter2text(num,0,0,0);
+ t2 = quarter2text(num,99,0,0);
+ printf(format,'Q',num,t1,t2,
+ PrintTimeByFormat("%F %T",tim),
+ quarter2duration(num));
+
+ //--- year
+
+ num = time2year(time0);
+ tim = year2time(num);
+ t1 = year2text(num,0,0,0);
+ t2 = year2text(num,99,0,0);
+ printf(format,'Y',num,t1,t2,
+ PrintTimeByFormat("%F %T",tim),
+ year2duration(num));
+ }
+ return 0;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_timezone() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_timezone ( int argc, char ** argv )
+{
+ printf("\nEndless timezone test with interval of 30 minutes started (pid=%u)\n",
+ getpid() );
+ printf("Typical usage: nohup ./%s TIMEZONE >>timezone-test.tmp 2>&1 &\n\n",progname);
+
+ for(;;)
+ {
+ u_usec_t start = GetTimerUSec();
+ ccp t1 = PrintTimevalByFormatUTC("%F %T.@@@@@@ %z",0);
+ ccp t2 = PrintTimevalByFormat("%F %T.@@@@@@ %z",0);
+ u_usec_t dur = GetTimerUSec() - start;
+ printf("%s : %s : in %llu usec\n",t1,t2,dur);
+ fflush(stdout);
+ sleep(1800);
+ }
+ return 0;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_condition() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_condition ( int argc, char ** argv )
+{
+ if ( argc < 2 )
+ {
+ fprintf(stderr,
+ "\n"
+ "Usage: wtest 'CO' arg...\n"
+ " or: wtest 'CONDITION' arg...\n"
+ "ARG is one of: hex | 'r' | 's<NUM>' | 'max' \n"
+ "\n"
+ );
+ return 0;
+ }
+
+ int setting = -1;
+ uint argi;
+ for ( argi = 1; argi < argc; argi++ )
+ {
+ ccp arg = argv[argi];
+ if ( *arg == 's' )
+ {
+ setting = strtol(arg+1,0,10);
+ continue;
+ }
+
+ if (!strcmp(arg,"max"))
+ {
+ uint max = 0, mask;
+ for ( mask = 0; mask <= 0xffff; mask++ )
+ {
+ gobj_condition_set_t gcs;
+ const uint n = GetGobjConditions(&gcs,setting,mask);
+ if ( max < n )
+ max = n;
+ }
+ printf("Max conditions for setting %2d: %u/%u\n",
+ setting, max, GOBJ_COND_SET_MAX );
+ continue;
+ }
+
+ const u16 mask = strcmp(arg,"r") ? str2ul(arg,0,16) : MyRandom(0x10000);
+ gobj_condition_set_t gcs;
+ const uint n = GetGobjConditions(&gcs,setting,mask);
+ printf("\n0x%04x = %u [setting %d -> %02x]\n",
+ mask, mask, setting, gcs.setting_mask );
+
+ uint i;
+ for ( i = 0; i < n; i++ )
+ {
+ const gobj_condition_t *c = gcs.cond+i;
+ printf(" %04x.%02x %2d : %2d..%-2d %2d..%-2d : %s\n",
+ c->mask,
+ c->setting,
+ c->bitnum,
+ c->min_offline,
+ c->max_offline,
+ c->min_online,
+ c->max_online,
+ c->info );
+ }
+ }
+ putchar('\n');
+ return 0;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_xbit() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+int GetXPFBitNum ( int is_online, int n_offline, int n_online )
+{
+ if ( is_online > 0 )
+ {
+ int base = n_online < 7 ? 4
+ : n_online < 10 ? 6
+ : n_online < 13 ? 8
+ : n_online < 19 ? 10
+ : 12;
+ return base + ( n_offline > 1 );
+ }
+ else
+ {
+ return n_offline < 2 ? 0
+ : n_offline > 4 ? 3
+ : n_offline - 1;
+ }
+}
+
+//-----------------------------------------------------------------------------
+
+static enumError test_xbit ( int argc, char ** argv )
+{
+ if ( argc < 2 )
+ {
+ fprintf(stderr,
+ "\n"
+ "Usage: wtest 'XBIT' tupel..\n"
+ "TUPEL is: id_online,n_offline,n_online\n"
+ "Default is 0 for each param.\n"
+ "\n"
+ );
+ return 0;
+ }
+
+ uint argi;
+ for ( argi = 1; argi < argc; argi++ )
+ {
+ int is_online = 0, n_offline = 0, n_online = 0;
+
+ ccp arg = argv[argi];
+ is_online = str2l(arg,0,10);
+ arg = strchr(arg,',');
+ if (arg)
+ {
+ n_offline = str2l(arg+1,0,10);
+ arg = strchr(arg+1,',');
+ if (arg)
+ n_online = str2l(arg+1,0,10);
+ }
+
+ int bitnum = GetXPFBitNum(is_online,n_offline,n_online);
+ printf("%3d %3d %3d => %2d\n",is_online,n_offline,n_online,bitnum);
+ }
+ putchar('\n');
+ return 0;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// test_in_arch() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError test_in_arch ( int argc, char ** argv )
+{
+ int total = 0, differ = 0;
+ const DbFileFILE_t *ptr;
+ for ( ptr = DbFileFILE; ptr->file; ptr++ )
+ {
+ total++;
+ bool old = OLD_DBF_IN_ARCHIVE(ptr->flags);
+ bool new = DBF_ARCH_REQUIRED(ptr->flags);
+ if ( old != new )
+ {
+ differ++;
+ printf("old=%d, new=%d : %05x : %s\n",
+ old, new, ptr->flags, ptr->file );
+ }
+ }
+ printf(" %u/%u differ\n",differ,total);
+ return 0;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// develop() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+static void test_dropfastbuf ( FastBuf_t *fb, int index, int size )
+{
+ AssignFastBuf(fb,"0123456789",-1);
+ DropFastBuf(fb,index,size);
+ printf("DROP(,%d,%d): %s: %s\n",
+ index, size, GetFastBufStatus(fb), GetFastBufString(fb) );
+}
+
+//-----------------------------------------------------------------------------
+
+const gobj_cond_ref_t * FindConditionRef2 ( u16 ref_id )
+{
+ const gobj_cond_ref_t *rc = cond_ref_tab;
+ for ( ; rc->ref_id; rc++ )
+ if ( rc->ref_id == ref_id )
+ return rc;
+ return 0;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+
+static enumError develop ( int argc, char ** argv )
+{
+ #if 1
+ static const u16 tab[] = { 0x1000,0x103f, 0x1900,0x193f, 0 };
+ const u16 *ptr;
+
+ #if 1
+ fputs("\nCompare results of FindConditionRef() and FindConditionRef2()\n",stdout);
+ for ( ptr = tab; *ptr; ptr += 2 )
+ {
+ u16 ref_id;
+ for ( ref_id = ptr[0]; ref_id <= ptr[1]; ref_id++ )
+ {
+ const gobj_cond_ref_t *r1 = FindConditionRef(ref_id);
+ const gobj_cond_ref_t *r2 = FindConditionRef2(ref_id);
+ if ( r1 != r2 )
+ printf("DIFFER: %#06x : %#6x %#6x\n",
+ ref_id, r1 ? r1->ref_id : 0, r2 ? r2->ref_id : 0 );
+ }
+ }
+ #endif
+ putchar('\n');
+
+ const int N1000 = 100;
+ for ( ptr = tab; *ptr; ptr += 2 )
+ {
+ uint i;
+ u64 duration;
+
+ duration = -GetTimerUSec();
+ for ( i = 0; i < 1000*N1000; i++ )
+ {
+ u16 ref_id;
+ for ( ref_id = ptr[0]; ref_id <= ptr[1]; ref_id++ )
+ FindConditionRef(ref_id);
+ }
+ duration += GetTimerUSec();
+ printf( " %s total, %s/1000, %u*1000 * FindConditionRef (%#x..%#x)\n",
+ PrintTimerUSec6(0,0,duration,true),
+ PrintTimerUSec6(0,0,duration/N1000/(ptr[1]-ptr[0]+1),true),
+ N1000, ptr[0], ptr[1] );
+
+ duration = -GetTimerUSec();
+ for ( i = 0; i < 1000*N1000; i++ )
+ {
+ u16 ref_id;
+ for ( ref_id = ptr[0]; ref_id <= ptr[1]; ref_id++ )
+ FindConditionRef2(ref_id);
+ }
+ duration += GetTimerUSec();
+ printf( " %s total, %s/1000, %u*1000 * FindConditionRef2(%#x..%#x)\n",
+ PrintTimerUSec6(0,0,duration,true),
+ PrintTimerUSec6(0,0,duration/N1000/(ptr[1]-ptr[0]+1),true),
+ N1000, ptr[0], ptr[1] );
+ }
+ putchar('\n');
+
+ #elif 1
+ static int ff_list[] = { FF_CHR, FF_CLR, FF_MDL, FF_PAT, FF_SCN, FF_SHP,
+ FF_SRT, FF_TEX, FF_TEX_CT, 0 };
+ int *ff;
+ for ( ff = ff_list; *ff; ff++ )
+ {
+ printf("--- %s ---\n",GetNameFF(0,*ff));
+ int v;
+ for ( v = 0; v < 20; v++ )
+ {
+ const brsub_info_t *bi = GetInfoBRSUB(*ff,v);
+ int ns = GetKnownSectionNumBRSUB(*ff,v);
+ if ( ( bi ? bi->n_sect : -1 ) != ns )
+ printf("FAIL: %s v%u: %d != %d\n",
+ GetNameFF(0,*ff), v,
+ bi ? bi->n_sect : -1, ns );
+ }
+ }
+
+ #elif 1
+
+ kmp_special_t special;
+ memset(special,0,sizeof(special));
+ u8 *ptr = (u8*)special;
+ ptr[0] = 1;
+ ptr[1] = 2;
+ printf("size=%zd : %zd : %d,%d: %d,%d\n",
+ sizeof(special), (u8*)(special+1) - (u8*)(special),
+ special[0], special[1], ptr[0], ptr[1] );
+
+ #elif 1
+
+ FastBuf_t fb1;
+ InitializeFastBuf(&fb1,sizeof(fb1));
+ printf("fb1: %s\n",GetFastBufStatus(&fb1));
+
+ struct { FastBuf_t b; char space[2000]; } fb2;
+ InitializeFastBuf(&fb2,sizeof(fb2));
+ printf("fb2: %s\n",GetFastBufStatus(&fb2.b));
+
+ char fb3x[2000];
+ FastBuf_t *fb3 = InitializeFastBuf(&fb3x,sizeof(fb3x));
+ printf("fb3: %s\n",GetFastBufStatus(fb3));
+
+ AppendFastBuf(&fb1,"aaa",-1); printf("fb1: %s: %s\n",GetFastBufStatus(&fb1),fb1.buf);
+ AppendFastBuf(&fb1,"BB",-1); printf("fb1: %s: %s\n",GetFastBufStatus(&fb1),fb1.buf);
+ InsertFastBuf(&fb1,1,"111",-1); printf("fb1: %s: %s\n",GetFastBufStatus(&fb1),fb1.buf);
+ InsertFastBuf(&fb1,-1,"222",-1); printf("fb1: %s: %s\n",GetFastBufStatus(&fb1),fb1.buf);
+
+ test_dropfastbuf(&fb1,12,4);
+ test_dropfastbuf(&fb1, 8,4);
+ test_dropfastbuf(&fb1, 3,4);
+ test_dropfastbuf(&fb1,-9,4);
+ test_dropfastbuf(&fb1,-15,4);
+ test_dropfastbuf(&fb1,5,-3);
+ test_dropfastbuf(&fb1,5,-8);
+
+ #elif 1
+ if ( argc > 2 )
+ {
+ double d1 = strtod(argv[1],0);
+ double d2 = strtod(argv[2],0);
+
+ int i;
+ for ( i = -5; i< 60; i += 5 )
+ {
+ bool sf = IsSameF(d1,d2,i);
+ bool sd = IsSameD(d1,d2,i);
+ printf(" %3i: %d %d %12.10f %12.10f\n",
+ i, sf, sd, d1, d2 );
+ }
+ }
+
+ #else
+ int i;
+ for ( i = 1; i < argc; i++ )
+ {
+ char buf[1000];
+ uint len = EncodeBase64(buf,sizeof(buf),argv[i],strlen(argv[i]),
+ TableEncode64x, true, "\n\t", 10 );
+ printf("-----\n%s [%zu->%u]\n\t%s\n",argv[i],strlen(argv[i]),len,buf);
+ }
+ #endif
+ return ERR_OK;
+}
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// command definitions ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+enum
+{
+ CMD_HELP, // help_exit()
+ CMD_TEST, // test()
+ CMD_DEVELOP, // develop(argc,argv)
+ CMD_WIIMM, // test_wiimm(argc,argv)
+
+ CMD_FLOAT, // test_float(argc,argv)
+ CMD_FLOAT_TAB, // create_float_tab()
+ CMD_MATRIX, // test_matrix(argc,argv)
+ CMD_MATCH_PATTERN, // test_match_pattern(argc,argv)
+ CMD_MEDIAN_CUT, // test_median_cut(argc,argv)
+ CMD_CMPR, // test_cmpr(argc,argv)
+ CMD_CREATE_IMAGES, // create_images(argc,argv)
+ CMD_RESIZE, // test_resize(argc,argv)
+ CMD_RESIZE_IMAGE, // resize_image(argc,argv)
+ CMD_SCAN_TEXT, // test_scan_text(argc,argv)
+ CMD_SCAN_STRING, // test_scan_string(argc,argv)
+ CMD_SCAN_FILE, // test_scan_file(argc,argv)
+ CMD_FILENAME, // test_filename(argc,argv)
+ CMD_DRAW_STARTPOS, // draw_startpos(argc,argv)
+ CMD_PATH_CMP, // test_path_cmp(argc,argv)
+ CMD_LINE2, // test_line(2,argc,argv)
+ CMD_LINE3, // test_line(3,argc,argv)
+ CMD_OBJFLOW, // ana_file_objflow(argc,argv)
+ CMD_MEMFILE, // test_memfile(argc,argv)
+ CMD_FIND_DOL, // test_find_dol(argc,argv)
+ CMD_SUBFILE, // test_subfile(argc,argv)
+ CMD_STR_LIST, // test_str_list(argc,argv)
+ CMD_CONTAINER, // test_container(argc,argv)
+ CMD_UUID, // test_uuid(argc,argv)
+ CMD_ANA_MAGIC, // test_analyse_magic(argc,argv)
+ CMD_VR, // test_vr(argc,argv)
+ CMD_VR2, // test_vr2(argc,argv)
+ CMD_REGEX, // test_regex(argc,argv)
+ CMD_CT_MODE, // test_ct_mode(argc,argv)
+ CMD_SCAN_HEX, // test_scan_hex(argc,argv)
+ CMD_SHIFT_JIS, // test_shift_jis(argc,argv)
+ CMD_ITEMSLOT, // test_item_slot(argc,argv)
+ CMD_SINCE2001, // test_since2001(argc,argv)
+ CMD_TIMEZONE, // test_timezone(argc,argv)
+ CMD_CONDITION, // test_condition(argc,argv)
+ CMD_XBIT, // test_xbit(argc,argv)
+ CMD_IN_ARCH, // test_in_arch(argc,argv)
+
+ CMD__N
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static const KeywordTab_t CommandTab[] =
+{
+ { CMD_HELP, "HELP", "?", 0 },
+ { CMD_TEST, "TEST", "T", 0 },
+ { CMD_DEVELOP, "DEVELOP", "D", 0 },
+
+ #ifdef HAVE_WIIMM_EXT
+ { CMD_WIIMM, "WIIMM", "W", 0 },
+ #endif
+
+ { CMD_FLOAT, "FLOAT", "F", 0 },
+ { CMD_FLOAT_TAB, "FLOAT-TAB", "FT", 0 },
+ { CMD_MATRIX, "MATRIX", 0, 0 },
+ { CMD_MATCH_PATTERN, "MATCH", 0, 0 },
+ { CMD_MEDIAN_CUT, "MEDIAN-CUT", "MC", 0 },
+ { CMD_CMPR, "CMPR", 0, 0 },
+ { CMD_CREATE_IMAGES, "CREATE-IMAGES","CI", 0 },
+ { CMD_RESIZE, "RESIZE", "RES", 0 },
+ { CMD_RESIZE_IMAGE, "RESIZE-IMAGE", "RI", 0 },
+ { CMD_SCAN_TEXT, "SCAN-TEXT", "ST", 0 },
+ { CMD_SCAN_STRING, "SCAN-STRING", "SS", 0 },
+ { CMD_SCAN_FILE, "SCAN-FILE", "SF", 0 },
+ { CMD_FILENAME, "FILENAME", "FNAME", 0 },
+ { CMD_DRAW_STARTPOS, "DRAW-STARTPOS","DSP", 0 },
+ { CMD_PATH_CMP, "PATH-CMP", "PC", 0 },
+ { CMD_LINE2, "LINE2", "L2", 0 },
+ { CMD_LINE3, "LINE3", "L3", 0 },
+ { CMD_OBJFLOW, "ANA-OBJFLOW", "AOF", 0 },
+ { CMD_MEMFILE, "MEMFILE", "MF", 0 },
+ { CMD_FIND_DOL, "FIND-DOL", "FD", 0 },
+ { CMD_SUBFILE, "SUBFILE", 0, 0 },
+ { CMD_STR_LIST, "STR-LIST", "SL", 0 },
+ { CMD_CONTAINER, "CONTAINER", 0, 0 },
+ { CMD_UUID, "UUID", 0, 0 },
+ { CMD_ANA_MAGIC, "ANA-MAGIC", "ANAMAGIC", 0 },
+ { CMD_VR, "VR", 0, 0 },
+ { CMD_VR2, "VR2", 0, 0 },
+ { CMD_REGEX, "REGEXP", "RE", 0 },
+ { CMD_CT_MODE, "CT-MODE", "CTM", 0 },
+ { CMD_SCAN_HEX, "SCAN-HEX", "SH", 0 },
+ { CMD_SHIFT_JIS, "SHIFT-JIS", "SJIS", 0 },
+ { CMD_ITEMSLOT, "ITEM-SLOT", "IS", 0 },
+ { CMD_SINCE2001, "SINCE2001", "S2", 0 },
+ { CMD_TIMEZONE, "TIMEZONE", "TZ", 0 },
+ { CMD_CONDITION, "CONDITION", "CO", 0 },
+ { CMD_XBIT, "XBIT", 0, 0 },
+ { CMD_IN_ARCH, "IN-ARCH", "INARCH", 0 },
+
+ { CMD__N,0,0,0 }
+};
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// help_exit() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+void help_exit()
+{
+ printf("\nCommands:\n\n");
+ const KeywordTab_t * cmd;
+ for ( cmd = CommandTab; cmd->name1; cmd++ )
+ if (cmd->name2)
+ printf(" %-*s | %s\n",CMD1_FW,cmd->name1,cmd->name2);
+ else
+ printf(" %s\n",cmd->name1);
+ putchar('\n');
+ #ifdef HAVE_WIIMM_EXT
+ wiimm_help_exit(false);
+ #endif
+ exit(ERR_SYNTAX);
+};
+
+//
+///////////////////////////////////////////////////////////////////////////////
+/////////////// main() ///////////////
+///////////////////////////////////////////////////////////////////////////////
+
+//#define XXX 0x123
+//#define MM1(a) #a
+//#define MM2(a) MM1(a)
+
+void AddOne ( double m[3][4] )
+{
+ m[0][0] += 1.0;
+ m[1][1] += 1.0;
+ m[2][2] += 1.0;
+}
+
+int main ( int argc, char ** argv )
+{
+ printf("***** %s *****\n",TITLE);
+ print_title_func = print_title;
+ SetupLib(argc,argv,NAME);
+ fflush(stdout);
+
+ //printf(" |" MM1(XXX) "|" MM2(XXX) "\n");
+
+ if (0)
+ {
+ double34 x;
+ x.m[0][0] = 10.0;
+ x.m[1][1] = 20.0;
+ x.m[2][2] = 30.0;
+ printf(" %6.2f %6.2f %6.2f\n",x.m[0][0],x.m[1][1],x.m[2][2]);
+ AddOne(x.m);
+ printf(" %6.2f %6.2f %6.2f\n",x.m[0][0],x.m[1][1],x.m[2][2]);
+ }
+
+ printf("term width = %d\n",GetTermWidth(80,0));
+
+ if ( argc < 2 )
+ help_exit();
+
+ int cmd_stat;
+ const KeywordTab_t * cmd_ct = ScanKeyword(&cmd_stat,argv[1],CommandTab);
+ if (!cmd_ct)
+ {
+ PrintKeywordError(CommandTab,argv[1],cmd_stat,0,0);
+ help_exit();
+ }
+
+ argv[1] = argv[0];
+ argv++;
+ argc--;
+
+ switch(cmd_ct->id)
+ {
+ case CMD_TEST: test(argc,argv); break;
+ case CMD_DEVELOP: develop(argc,argv); break;
+
+ #ifdef HAVE_WIIMM_EXT
+ case CMD_WIIMM: test_wiimm(argc,argv); break;
+ #endif
+
+ case CMD_FLOAT: test_float(argc,argv); break;
+ case CMD_FLOAT_TAB: create_float_tab(); break;
+ case CMD_MATRIX: test_matrix(argc,argv); break;
+ case CMD_MATCH_PATTERN: test_match_pattern(argc,argv); break;
+ case CMD_MEDIAN_CUT: test_median_cut(argc,argv); break;
+ case CMD_CMPR: test_cmpr(argc,argv); break;
+ case CMD_CREATE_IMAGES: create_images(argc,argv); break;
+ case CMD_RESIZE: test_resize(argc,argv); break;
+ case CMD_RESIZE_IMAGE: resize_image(argc,argv); break;
+ case CMD_SCAN_TEXT: test_scan_text(argc,argv); break;
+ case CMD_SCAN_STRING: test_scan_string(argc,argv); break;
+ case CMD_SCAN_FILE: test_scan_file(argc,argv); break;
+ case CMD_FILENAME: test_filename(argc,argv); break;
+ case CMD_DRAW_STARTPOS: draw_startpos(argc,argv); break;
+ case CMD_PATH_CMP: test_path_cmp(argc,argv); break;
+ case CMD_LINE2: test_line(2,argc,argv); break;
+ case CMD_LINE3: test_line(3,argc,argv); break;
+ case CMD_OBJFLOW: ana_file_objflow(argc,argv); break;
+ case CMD_MEMFILE: test_memfile(argc,argv); break;
+ case CMD_FIND_DOL: test_find_dol(argc,argv); break;
+ case CMD_SUBFILE: test_subfile(argc,argv); break;
+ case CMD_STR_LIST: test_str_list(argc,argv); break;
+ case CMD_CONTAINER: test_container(argc,argv); break;
+ case CMD_UUID: test_uuid(argc,argv); break;
+ case CMD_ANA_MAGIC: test_analyse_magic(argc,argv); break;
+ case CMD_VR: test_vr(argc,argv); break;
+ case CMD_VR2: test_vr2(argc,argv); break;
+ case CMD_REGEX: test_regex(argc,argv); break;
+ case CMD_CT_MODE: test_ct_mode(argc,argv); break;
+ case CMD_SCAN_HEX: test_scan_hex(argc,argv); break;
+ case CMD_SHIFT_JIS: test_shift_jis(argc,argv); break;
+ case CMD_ITEMSLOT: test_item_slot(argc,argv); break;
+ case CMD_SINCE2001: test_since2001(argc,argv); break;
+ case CMD_TIMEZONE: test_timezone(argc,argv); break;
+ case CMD_CONDITION: test_condition(argc,argv); break;
+ case CMD_XBIT: test_xbit(argc,argv); break;
+ case CMD_IN_ARCH: test_in_arch(argc,argv); break;
+ //case CMD_HELP:
+ default:
+ help_exit();
+ }
+
+ if (SIGINT_level)
+ ERROR0(ERR_INTERRUPT,"Program interrupted by user.");
+
+ return max_error;
+}
+
+///////////////////////////////////////////////////////////////////////////////