Free Hero Mesh

Check-in [7dab93e8a9]
Login
This is a mirror of the main repository for Free Hero Mesh. New tickets and changes will not be accepted at this mirror.
Overview
Comment:Change read_lump function; also add read_userstate and write_userstate.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 7dab93e8a98d70a74c3f38362a39fd1ca53f47d1
User & Date: user on 2021-01-08 00:32:14
Other Links: manifest | tags
Context
2021-01-08
02:29
Implement loading/saving the move list check-in: eb23399aef user: user tags: trunk
00:32
Change read_lump function; also add read_userstate and write_userstate. check-in: 7dab93e8a9 user: user tags: trunk
2021-01-07
07:42
Add a placeholder icon for the new move at the end of the move list check-in: 7a6ec6b4a1 user: user tags: trunk
Changes

Modified class.c from [a9810d154f] to [234c623d64].

1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
  }
  free(hash);
}

static void load_class_numbers(void) {
  int i,n;
  long size=0;
  unsigned char*data=read_lump(FIL_LEVEL,LUMP_CLASS_DEF,&size,0);
  unsigned char*p;
  if(!data) return;
  for(i=0;i<size-3;) {
    n=data[i]|(data[i+1]<<8);
    if(!n) break;
    if(n>=0x4000) fatal("Malformed CLASS.DEF lump\n");
    i+=2;







|







1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
  }
  free(hash);
}

static void load_class_numbers(void) {
  int i,n;
  long size=0;
  unsigned char*data=read_lump(FIL_LEVEL,LUMP_CLASS_DEF,&size);
  unsigned char*p;
  if(!data) return;
  for(i=0;i<size-3;) {
    n=data[i]|(data[i+1]<<8);
    if(!n) break;
    if(n>=0x4000) fatal("Malformed CLASS.DEF lump\n");
    i+=2;

Modified heromesh.h from [97fa5dbd0e] to [c906f5298c].

65
66
67
68
69
70
71
72
73

74
75
76
77
78
79
80
81
82



83
84
85
86
87
88
89
  }) : \
  stack_protect_mode=='!' ? 1 : \
0))
#else
#define StackProtection() 0
#endif

unsigned char*read_lump(int sol,int lvl,long*sz,sqlite3_value**us);
void write_lump(int sol,int lvl,long sz,const unsigned char*data);

const char*load_level(int lvl);
void set_cursor(int id);
const char*log_if_error(const char*t);

#define FIL_SOLUTION 1
#define FIL_LEVEL 0
#define LUMP_LEVEL_IDX (-1)
#define LUMP_CLASS_DEF (-2)




// == picture ==

extern SDL_Surface*screen;
extern Uint16 picture_size;
extern int left_margin;

// Use only when screen is unlocked







|

>









>
>
>







65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
  }) : \
  stack_protect_mode=='!' ? 1 : \
0))
#else
#define StackProtection() 0
#endif

unsigned char*read_lump_or_userstate(int sol,int lvl,long*sz,char us);
void write_lump(int sol,int lvl,long sz,const unsigned char*data);
void write_userstate(int sol,int lvl,long sz,const unsigned char*data);
const char*load_level(int lvl);
void set_cursor(int id);
const char*log_if_error(const char*t);

#define FIL_SOLUTION 1
#define FIL_LEVEL 0
#define LUMP_LEVEL_IDX (-1)
#define LUMP_CLASS_DEF (-2)

#define read_lump(a,b,c) read_lump_or_userstate(a,b,c,0)
#define read_userstate(a,b,c) read_lump_or_userstate(a,b,c,1)

// == picture ==

extern SDL_Surface*screen;
extern Uint16 picture_size;
extern int left_margin;

// Use only when screen is unlocked

Modified main.c from [f7a8e77b3c] to [926b9dec50].

126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141

142
143
144
145
146
147
148
149


150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183













184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
    fseek(fp,t,SEEK_CUR);
  }
  done:
  sqlite3_finalize(st);
  return id;
}

unsigned char*read_lump(int sol,int lvl,long*sz,sqlite3_value**us) {
  // Returns a pointer to the data; must be freed using free().
  // If there is no data, returns null and sets *sz and *us to zero.
  // Third argument is a pointer to a variable to store the data size (must be not null).
  // Fourth argument may be null, and is user state (use sqlite3_value_free() to free it).
  unsigned char*buf=0;
  sqlite3_reset(readusercachest);
  sqlite3_bind_int64(readusercachest,1,sol?solutionuc:leveluc);
  sqlite3_bind_int(readusercachest,2,lvl);

  if(sqlite3_step(readusercachest)==SQLITE_ROW) {
    if(us) *us=sqlite3_value_dup(sqlite3_column_value(readusercachest,6));
    if(sqlite3_column_type(readusercachest,5)==SQLITE_BLOB) {
      const unsigned char*con=sqlite3_column_blob(readusercachest,5);
      *sz=sqlite3_column_bytes(readusercachest,5);
      buf=malloc(*sz);
      if(*sz && !buf) fatal("Allocation failed\n");
      memcpy(buf,con,*sz);


    } else {
      FILE*fp=sol?solutionfp:levelfp;
      rewind(fp);
      fseek(fp,sqlite3_column_int64(readusercachest,4)-4,SEEK_SET);
      *sz=fgetc(fp)<<16; *sz|=fgetc(fp)<<24; *sz|=fgetc(fp); *sz|=fgetc(fp)<<8;
      if(feof(fp) || *sz<0) fatal("Invalid Hamster archive\n");
      buf=malloc(*sz);
      if(!buf) fatal("Allocation failed\n");
      if(!fread(buf,1,*sz,fp)) fatal("Unable to read data\n");
      rewind(fp);
    }
  } else {
    *sz=0;
    if(us) *us=0;
  }
  sqlite3_reset(readusercachest);
  return buf;
}

void write_lump(int sol,int lvl,long sz,const unsigned char*data) {
  // Writes a lump to the user cache.
  // The actual Hamster archive files will be updated when the program terminates.
  sqlite3_stmt*st;
  int e;
  if(e=sqlite3_prepare_v2(userdb,"INSERT INTO `USERCACHEDATA`(`FILE`,`LEVEL`,`NAME`,`DATA`) VALUES(?1,?2,CASE WHEN ?2 < 0 THEN ?3 ELSE ?2 || ?3 END,?4)"
   " ON CONFLICT(`FILE`,`LEVEL`) DO UPDATE SET `DATA` = ?4;",-1,&st,0)) fatal("SQL error (%d): %s\n",e,sqlite3_errmsg(userdb));
  sqlite3_bind_int64(st,1,sol?solutionuc:leveluc);
  sqlite3_bind_int(st,2,lvl);
  sqlite3_bind_text(st,3,lvl==LUMP_CLASS_DEF?"CLASS.DEF":lvl==LUMP_LEVEL_IDX?"LEVEL.IDX":sol?".SOL":".LVL",-1,SQLITE_STATIC);
  sqlite3_bind_blob64(st,4,data,sz,0);
  while((e=sqlite3_step(st))==SQLITE_ROW);
  if(e!=SQLITE_DONE) fatal("SQL error (%d): %s\n",e,sqlite3_errmsg(userdb));
  sqlite3_finalize(st);
}














static void load_level_index(void) {
  long sz;
  int i;
  unsigned char*data=read_lump(0,LUMP_LEVEL_IDX,&sz,0);
  if(!data) return;
  if(sz>65536) fatal("Too many levels\n");
  level_index=malloc((level_nindex=sz>>1)*sizeof(Uint16));
  if(!level_index) fatal("Allocation failed\n");
  for(i=0;i<level_nindex;i++) level_index[i]=data[i+i]|(data[i+i+1]<<8);
  free(data);
}

const char*load_level(int lvl) {
  // Load level by ID. Returns null pointer if successful, or an error message if it failed.
  long sz=0;
  unsigned char*buf=lvl>=0?read_lump(FIL_LEVEL,lvl,&sz,0):0;
  unsigned char*p=buf;
  unsigned char*end=buf+sz;
  unsigned char*q;
  int i,n,x,y,z;
  Uint16 lo=0;
  Uint32 o;
  Uint32 mru[2];
  if(lvl<0 && level_index && -lvl<=level_nindex) {
    lo=-lvl;
    lvl=level_index[~lvl];
    p=buf=read_lump(FIL_LEVEL,lvl,&sz,0);
    end=buf+sz;
  }
  if(lvl<0) return "Invalid level ID";
  if(!buf) return "Cannot find level";
  free(level_title);
  level_title=0;
  annihilate();







|



|




>

<
|
|
|



>
>



|









<




















>
>
>
>
>
>
>
>
>
>
>
>
>




|











|










|







126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143

144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164

165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
    fseek(fp,t,SEEK_CUR);
  }
  done:
  sqlite3_finalize(st);
  return id;
}

unsigned char*read_lump_or_userstate(int sol,int lvl,long*sz,char us) {
  // Returns a pointer to the data; must be freed using free().
  // If there is no data, returns null and sets *sz and *us to zero.
  // Third argument is a pointer to a variable to store the data size (must be not null).
  // Fourth argument is 1 for user state or 0 for lump data.
  unsigned char*buf=0;
  sqlite3_reset(readusercachest);
  sqlite3_bind_int64(readusercachest,1,sol?solutionuc:leveluc);
  sqlite3_bind_int(readusercachest,2,lvl);
  sqlite3_bind_int(readusercachest,3,us);
  if(sqlite3_step(readusercachest)==SQLITE_ROW) {

    if(sqlite3_column_type(readusercachest,1)==SQLITE_BLOB) {
      const unsigned char*con=sqlite3_column_blob(readusercachest,1);
      *sz=sqlite3_column_bytes(readusercachest,1);
      buf=malloc(*sz);
      if(*sz && !buf) fatal("Allocation failed\n");
      memcpy(buf,con,*sz);
    } else if(us) {
      *sz=0;
    } else {
      FILE*fp=sol?solutionfp:levelfp;
      rewind(fp);
      fseek(fp,sqlite3_column_int64(readusercachest,0)-4,SEEK_SET);
      *sz=fgetc(fp)<<16; *sz|=fgetc(fp)<<24; *sz|=fgetc(fp); *sz|=fgetc(fp)<<8;
      if(feof(fp) || *sz<0) fatal("Invalid Hamster archive\n");
      buf=malloc(*sz);
      if(!buf) fatal("Allocation failed\n");
      if(!fread(buf,1,*sz,fp)) fatal("Unable to read data\n");
      rewind(fp);
    }
  } else {
    *sz=0;

  }
  sqlite3_reset(readusercachest);
  return buf;
}

void write_lump(int sol,int lvl,long sz,const unsigned char*data) {
  // Writes a lump to the user cache.
  // The actual Hamster archive files will be updated when the program terminates.
  sqlite3_stmt*st;
  int e;
  if(e=sqlite3_prepare_v2(userdb,"INSERT INTO `USERCACHEDATA`(`FILE`,`LEVEL`,`NAME`,`DATA`) VALUES(?1,?2,CASE WHEN ?2 < 0 THEN ?3 ELSE ?2 || ?3 END,?4)"
   " ON CONFLICT(`FILE`,`LEVEL`) DO UPDATE SET `DATA` = ?4;",-1,&st,0)) fatal("SQL error (%d): %s\n",e,sqlite3_errmsg(userdb));
  sqlite3_bind_int64(st,1,sol?solutionuc:leveluc);
  sqlite3_bind_int(st,2,lvl);
  sqlite3_bind_text(st,3,lvl==LUMP_CLASS_DEF?"CLASS.DEF":lvl==LUMP_LEVEL_IDX?"LEVEL.IDX":sol?".SOL":".LVL",-1,SQLITE_STATIC);
  sqlite3_bind_blob64(st,4,data,sz,0);
  while((e=sqlite3_step(st))==SQLITE_ROW);
  if(e!=SQLITE_DONE) fatal("SQL error (%d): %s\n",e,sqlite3_errmsg(userdb));
  sqlite3_finalize(st);
}

void write_userstate(int sol,int lvl,long sz,const unsigned char*data) {
  sqlite3_stmt*st;
  int e;
  if(e=sqlite3_prepare_v2(userdb,"UPDATE `USERCACHEDATA` SET `USERSTATE` = ?3"
   " WHERE `FILE` = ?1 AND `LEVEL` = ?2;",-1,&st,0)) fatal("SQL error (%d): %s\n",e,sqlite3_errmsg(userdb));
  sqlite3_bind_int64(st,1,sol?solutionuc:leveluc);
  sqlite3_bind_int(st,2,lvl);
  sqlite3_bind_blob64(st,3,data,sz,0);
  while((e=sqlite3_step(st))==SQLITE_ROW);
  if(e!=SQLITE_DONE) fatal("SQL error (%d): %s\n",e,sqlite3_errmsg(userdb));
  sqlite3_finalize(st);
}

static void load_level_index(void) {
  long sz;
  int i;
  unsigned char*data=read_lump(FIL_LEVEL,LUMP_LEVEL_IDX,&sz);
  if(!data) return;
  if(sz>65536) fatal("Too many levels\n");
  level_index=malloc((level_nindex=sz>>1)*sizeof(Uint16));
  if(!level_index) fatal("Allocation failed\n");
  for(i=0;i<level_nindex;i++) level_index[i]=data[i+i]|(data[i+i+1]<<8);
  free(data);
}

const char*load_level(int lvl) {
  // Load level by ID. Returns null pointer if successful, or an error message if it failed.
  long sz=0;
  unsigned char*buf=lvl>=0?read_lump(FIL_LEVEL,lvl,&sz):0;
  unsigned char*p=buf;
  unsigned char*end=buf+sz;
  unsigned char*q;
  int i,n,x,y,z;
  Uint16 lo=0;
  Uint32 o;
  Uint32 mru[2];
  if(lvl<0 && level_index && -lvl<=level_nindex) {
    lo=-lvl;
    lvl=level_index[~lvl];
    p=buf=read_lump(FIL_LEVEL,lvl,&sz);
    end=buf+sz;
  }
  if(lvl<0) return "Invalid level ID";
  if(!buf) return "Cannot find level";
  free(level_title);
  level_title=0;
  annihilate();
493
494
495
496
497
498
499

500
501
502
503
504
505
506
507
  if(stat(nam2,&fst)) fatal("Unable to stat '%s': %m\n",nam2);
  if(!fst.st_size) fatal("File '%s' has zero size\n",nam2);
  if(fst.st_mtime>t1 || fst.st_ctime>t1) leveluc=reset_usercache(levelfp,nam2,&fst,".LVL");
  if(stat(nam3,&fst)) fatal("Unable to stat '%s': %m\n",nam3);
  if(fst.st_mtime>t2 || fst.st_ctime>t2) solutionuc=reset_usercache(solutionfp,nam3,&fst,".SOL");
  free(nam2);
  free(nam3);

  if(z=sqlite3_prepare_v3(userdb,"SELECT * FROM `USERCACHEDATA` WHERE `FILE` = ?1 AND `LEVEL` = ?2;",-1,SQLITE_PREPARE_PERSISTENT,&readusercachest,0)) {
    fatal("SQL error (%d): %s\n",z,sqlite3_errmsg(userdb));
  }
  if(z=sqlite3_exec(userdb,"COMMIT;",0,0,0)) fatal("SQL error (%d): %s\n",z,sqlite3_errmsg(userdb));
  fprintf(stderr,"Done\n");
}

static void init_sql(void) {







>
|







507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
  if(stat(nam2,&fst)) fatal("Unable to stat '%s': %m\n",nam2);
  if(!fst.st_size) fatal("File '%s' has zero size\n",nam2);
  if(fst.st_mtime>t1 || fst.st_ctime>t1) leveluc=reset_usercache(levelfp,nam2,&fst,".LVL");
  if(stat(nam3,&fst)) fatal("Unable to stat '%s': %m\n",nam3);
  if(fst.st_mtime>t2 || fst.st_ctime>t2) solutionuc=reset_usercache(solutionfp,nam3,&fst,".SOL");
  free(nam2);
  free(nam3);
  if(z=sqlite3_prepare_v3(userdb,"SELECT `OFFSET`, CASE WHEN ?3 THEN `DATA` ELSE `USERSTATE` END "
   "FROM `USERCACHEDATA` WHERE `FILE` = ?1 AND `LEVEL` = ?2;",-1,SQLITE_PREPARE_PERSISTENT,&readusercachest,0)) {
    fatal("SQL error (%d): %s\n",z,sqlite3_errmsg(userdb));
  }
  if(z=sqlite3_exec(userdb,"COMMIT;",0,0,0)) fatal("SQL error (%d): %s\n",z,sqlite3_errmsg(userdb));
  fprintf(stderr,"Done\n");
}

static void init_sql(void) {