summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Levin <al.le@rockbox.org>2009-04-03 20:25:12 +0000
committerAlexander Levin <al.le@rockbox.org>2009-04-03 20:25:12 +0000
commitb549ce9193b6baead786d1a7b9bec9b9ac70ccc2 (patch)
treef9f47b6ecffcf90fd56e68000b6d5728cb3f7b39
parent64f4b87a7225e01b9eb6288c22c2ae8920719496 (diff)
downloadrockbox-b549ce9193b6baead786d1a7b9bec9b9ac70ccc2.tar.gz
rockbox-b549ce9193b6baead786d1a7b9bec9b9ac70ccc2.zip
Some improvements to rocklife (FS#10087, but slightly less paranoid). Main improvement is that the file loading will not lead to stack overflow or illegal memory access.
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@20610 a1c6a512-1295-4272-9138-f99709370657
-rw-r--r--apps/plugins/rocklife.c212
1 files changed, 115 insertions, 97 deletions
diff --git a/apps/plugins/rocklife.c b/apps/plugins/rocklife.c
index 1929dbc564..2905ab53e2 100644
--- a/apps/plugins/rocklife.c
+++ b/apps/plugins/rocklife.c
@@ -82,61 +82,82 @@ PLUGIN_HEADER
82const struct button_mapping *plugin_contexts[] 82const struct button_mapping *plugin_contexts[]
83= {generic_directions, generic_actions}; 83= {generic_directions, generic_actions};
84 84
85unsigned char grid_a[LCD_WIDTH][LCD_HEIGHT]; 85#define GRID_W LCD_WIDTH
86unsigned char grid_b[LCD_WIDTH][LCD_HEIGHT]; 86#define GRID_H LCD_HEIGHT
87
88unsigned char grid_a[GRID_W][GRID_H];
89unsigned char grid_b[GRID_W][GRID_H];
87int generation = 0; 90int generation = 0;
88int population = 0; 91int population = 0;
89int status_line = 0; 92int status_line = 0;
90char buf[30]; 93char buf[30];
91 94
92static inline void set_cell(int x, int y, char *pgrid){ 95
93 pgrid[x+y*LCD_WIDTH]=1; 96static inline bool is_valid_cell(int x, int y) {
97 return (x >= 0 && x < GRID_W
98 && y >= 0 && y < GRID_H);
99}
100
101static inline void set_cell_age(int x, int y, unsigned char age, char *pgrid) {
102 pgrid[x+y*GRID_W] = age;
103}
104
105static inline void set_cell(int x, int y, char *pgrid) {
106 set_cell_age(x, y, 1, pgrid);
107}
108
109static inline unsigned char get_cell(int x, int y, char *pgrid) {
110 if (x < 0)
111 x += GRID_W;
112 else if (x >= GRID_W)
113 x -= GRID_W;
114
115 if (y < 0)
116 y += GRID_H;
117 else if (y >= GRID_H)
118 y -= GRID_H;
119
120 return pgrid[x+y*GRID_W];
94} 121}
95 122
96/* clear grid */ 123/* clear grid */
97void init_grid(char *pgrid){ 124void init_grid(char *pgrid){
98 int x, y; 125 memset(pgrid, 0, GRID_W * GRID_H);
99
100 for(y=0; y<LCD_HEIGHT; y++){
101 for(x=0; x<LCD_WIDTH; x++){
102 pgrid[x+y*LCD_WIDTH] = 0;
103 }
104 }
105} 126}
106 127
107/*fill grid with pattern from file (viewer mode)*/ 128/*fill grid with pattern from file (viewer mode)*/
108static bool load_cellfile(const char *file, char *pgrid){ 129static bool load_cellfile(const char *file, char *pgrid){
109 int fd, file_size; 130 int fd;
110 fd = rb->open(file, O_RDONLY); 131 fd = rb->open(file, O_RDONLY);
111 if (fd==-1) 132 if (fd==-1)
112 return false; 133 return false;
134
135 init_grid(pgrid);
136
137 char c;
138 int nc, x, y, xmid, ymid;
139 x=0;
140 y=0;
141 xmid = (GRID_W>>1) - 2;
142 ymid = (GRID_H>>1) - 2;
143
144 while (true) {
145 nc = read(fd, &c, 1);
146 if (nc <= 0)
147 break;
113 148
114 file_size = rb->filesize(fd); 149 switch(c) {
115 if (file_size==-1)
116 return false;
117
118 char buf1[file_size];
119 int i, j, k, xmid, ymid;
120 j=0;
121 k=0;
122 xmid = (LCD_WIDTH>>1) - 2;
123 ymid = (LCD_HEIGHT>>1) - 2;
124
125 rb->read(fd, buf1, file_size - 1);
126
127 for(i=0; i<file_size; i++){
128
129 switch(buf1[i]){
130 case '.': 150 case '.':
131 j++; 151 x++;
132 break; 152 break;
133 case 'O': 153 case 'O':
134 set_cell(xmid + j, ymid + k, pgrid); 154 if (is_valid_cell(xmid + x, ymid + y))
135 j++; 155 set_cell(xmid + x, ymid + y, pgrid);
156 x++;
136 break; 157 break;
137 case '\n': 158 case '\n':
138 k++; 159 y++;
139 j=0; 160 x=0;
140 break; 161 break;
141 default: 162 default:
142 break; 163 break;
@@ -151,7 +172,7 @@ static void setup_grid(char *pgrid, int pattern){
151 int n, max; 172 int n, max;
152 int xmid, ymid; 173 int xmid, ymid;
153 174
154 max = LCD_HEIGHT*LCD_WIDTH; 175 max = GRID_W * GRID_H;
155 176
156 switch(pattern){ 177 switch(pattern){
157 case PATTERN_RANDOM: 178 case PATTERN_RANDOM:
@@ -174,8 +195,8 @@ static void setup_grid(char *pgrid, int pattern){
174 195
175 case PATTERN_GROWTH_1: 196 case PATTERN_GROWTH_1:
176 rb->splash(HZ, "Growth"); 197 rb->splash(HZ, "Growth");
177 xmid = (LCD_WIDTH>>1) - 2; 198 xmid = (GRID_W>>1) - 2;
178 ymid = (LCD_HEIGHT>>1) - 2; 199 ymid = (GRID_H>>1) - 2;
179 set_cell(xmid + 6, ymid + 0 , pgrid); 200 set_cell(xmid + 6, ymid + 0 , pgrid);
180 set_cell(xmid + 4, ymid + 1 , pgrid); 201 set_cell(xmid + 4, ymid + 1 , pgrid);
181 set_cell(xmid + 6, ymid + 1 , pgrid); 202 set_cell(xmid + 6, ymid + 1 , pgrid);
@@ -189,8 +210,8 @@ static void setup_grid(char *pgrid, int pattern){
189 break; 210 break;
190 case PATTERN_ACORN: 211 case PATTERN_ACORN:
191 rb->splash(HZ, "Acorn"); 212 rb->splash(HZ, "Acorn");
192 xmid = (LCD_WIDTH>>1) - 3; 213 xmid = (GRID_W>>1) - 3;
193 ymid = (LCD_HEIGHT>>1) - 1; 214 ymid = (GRID_H>>1) - 1;
194 set_cell(xmid + 1, ymid + 0 , pgrid); 215 set_cell(xmid + 1, ymid + 0 , pgrid);
195 set_cell(xmid + 3, ymid + 1 , pgrid); 216 set_cell(xmid + 3, ymid + 1 , pgrid);
196 set_cell(xmid + 0, ymid + 2 , pgrid); 217 set_cell(xmid + 0, ymid + 2 , pgrid);
@@ -201,8 +222,8 @@ static void setup_grid(char *pgrid, int pattern){
201 break; 222 break;
202 case PATTERN_GROWTH_2: 223 case PATTERN_GROWTH_2:
203 rb->splash(HZ, "Growth 2"); 224 rb->splash(HZ, "Growth 2");
204 xmid = (LCD_WIDTH>>1) - 4; 225 xmid = (GRID_W>>1) - 4;
205 ymid = (LCD_HEIGHT>>1) - 1; 226 ymid = (GRID_H>>1) - 1;
206 set_cell(xmid + 0, ymid + 0 , pgrid); 227 set_cell(xmid + 0, ymid + 0 , pgrid);
207 set_cell(xmid + 1, ymid + 0 , pgrid); 228 set_cell(xmid + 1, ymid + 0 , pgrid);
208 set_cell(xmid + 2, ymid + 0 , pgrid); 229 set_cell(xmid + 2, ymid + 0 , pgrid);
@@ -262,14 +283,12 @@ static void setup_grid(char *pgrid, int pattern){
262/* display grid */ 283/* display grid */
263static void show_grid(char *pgrid){ 284static void show_grid(char *pgrid){
264 int x, y; 285 int x, y;
265 int m;
266 unsigned char age; 286 unsigned char age;
267 287
268 rb->lcd_clear_display(); 288 rb->lcd_clear_display();
269 for(y=0; y<LCD_HEIGHT; y++){ 289 for(y=0; y<GRID_H; y++){
270 for(x=0; x<LCD_WIDTH; x++){ 290 for(x=0; x<GRID_W; x++){
271 m = y*LCD_WIDTH+x; 291 age = get_cell(x, y, pgrid);
272 age = pgrid[m];
273 if(age){ 292 if(age){
274#if LCD_DEPTH >= 16 293#if LCD_DEPTH >= 16
275 rb->lcd_set_foreground( LCD_RGBPACK( age, age, age )); 294 rb->lcd_set_foreground( LCD_RGBPACK( age, age, age ));
@@ -291,11 +310,18 @@ static void show_grid(char *pgrid){
291} 310}
292 311
293 312
294/* check state of cell depending on the number of neighbours */ 313/* Calculates whether the cell will be alive in the next generation.
295static inline int check_cell(unsigned char *n){ 314 n is the array with 9 elements that represent the cell itself and its
296 int sum; 315 neighborhood like this (the cell itself is n[4]):
316 0 1 2
317 3 4 5
318 6 7 8
319*/
320static inline bool check_cell(unsigned char *n)
321{
297 int empty_cells = 0; 322 int empty_cells = 0;
298 unsigned char live = 0; 323 int alive_cells;
324 bool result;
299 325
300 /* count empty neighbour cells */ 326 /* count empty neighbour cells */
301 if(n[0]==0) empty_cells++; 327 if(n[0]==0) empty_cells++;
@@ -308,38 +334,32 @@ static inline int check_cell(unsigned char *n){
308 if(n[8]==0) empty_cells++; 334 if(n[8]==0) empty_cells++;
309 335
310 /* now we build the number of non-zero neighbours :-P */ 336 /* now we build the number of non-zero neighbours :-P */
311 sum = 8 - empty_cells; 337 alive_cells = 8 - empty_cells;
312 338
313 /* 1st and 2nd rule*/ 339 if (n[4]) {
314 if (n[4] && (sum<2 || sum>3)) 340 /* If the cell is alive, it stays alive iff it has 2 or 3 alive neighbours */
315 live = false; 341 result = (alive_cells==2 || alive_cells==3);
316 342 }
317 /* 3rd rule */ 343 else {
318 if (n[4] && (sum==2 || sum==3)) 344 /* If the cell is dead, it gets alive iff it has 3 alive neighbours */
319 live = true; 345 result = (alive_cells==3);
320 346 }
321 /* 4rd rule */
322 if (!n[4] && sum==3)
323 live = true;
324 347
325 return live; 348 return result;
326} 349}
327 350
328/* Calculate the next generation of cells 351/* Calculate the next generation of cells
329 * 352 *
330 * The borders of the grid are connected to their opposite sides. 353 * The borders of the grid are connected to their opposite sides.
331 * 354 *
332 *
333 * To avoid multiplications while accessing data in the 2-d grid 355 * To avoid multiplications while accessing data in the 2-d grid
334 * (pgrid) we try to re-use previously accessed neighbourhood 356 * (pgrid) we try to re-use previously accessed neighbourhood
335 * information which is stored in an 3x3 array. 357 * information which is stored in an 3x3 array.
336 *
337 */ 358 */
338static void next_generation(char *pgrid, char *pnext_grid){ 359static void next_generation(char *pgrid, char *pnext_grid){
339 int x, y; 360 int x, y;
340 unsigned char cell; 361 bool cell;
341 int age; 362 unsigned char age;
342 int m;
343 unsigned char n[9]; 363 unsigned char n[9];
344 364
345 rb->memset(n, 0, sizeof(n)); 365 rb->memset(n, 0, sizeof(n));
@@ -357,31 +377,33 @@ static void next_generation(char *pgrid, char *pnext_grid){
357 population = 0; 377 population = 0;
358 378
359 /* go through the grid */ 379 /* go through the grid */
360 for(y=0; y<LCD_HEIGHT; y++){ 380 for(y=0; y<GRID_H; y++){
361 for(x=0; x<LCD_WIDTH; x++){ 381 for(x=0; x<GRID_W; x++){
362 if(y==0 && x==0){ 382 if(y==0 && x==0){
363 /* first cell in first row, we have to load all neighbours */ 383 /* first cell in first row, we have to load all neighbours */
364 n[0] = pgrid[((x+LCD_WIDTH-1)%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH]; 384 n[0] = get_cell(x-1, y-1, pgrid);
365 n[1] = pgrid[((x )%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH]; 385 n[1] = get_cell(x, y-1, pgrid);
366 n[2] = pgrid[((x +1)%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH]; 386 n[2] = get_cell(x+1, y-1, pgrid);
367 n[3] = pgrid[((x+LCD_WIDTH-1)%LCD_WIDTH)+((y )%LCD_HEIGHT)*LCD_WIDTH]; 387 n[3] = get_cell(x-1, y, pgrid);
368 n[5] = pgrid[((x +1)%LCD_WIDTH)+((y )%LCD_HEIGHT)*LCD_WIDTH]; 388 n[4] = get_cell(x, y, pgrid);
369 n[6] = pgrid[((x+LCD_WIDTH-1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; 389 n[5] = get_cell(x+1, y, pgrid);
370 n[7] = pgrid[((x )%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; 390 n[6] = get_cell(x-1, y+1, pgrid);
371 n[8] = pgrid[((x +1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; 391 n[7] = get_cell(x, y+1, pgrid);
392 n[8] = get_cell(x+1, y+1, pgrid);
372 } else { 393 } else {
373 if(x==0){ 394 if(x==0){
374 /* beginning of a row, copy what we know about our predecessor, 395 /* beginning of a row, copy what we know about our predecessor,
375 0, 1, 3 are known, 2, 5, 6, 7, 8 have to be loaded 396 0, 1, 3, 4 are known, 2, 5, 6, 7, 8 have to be loaded
376 */ 397 */
377 n[0] = n[4]; 398 n[0] = n[4];
378 n[1] = n[5]; 399 n[1] = n[5];
379 n[2] = pgrid[((x +1)%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH]; 400 n[2] = get_cell(x+1, y-1, pgrid);
380 n[3] = n[7]; 401 n[3] = n[7];
381 n[5] = pgrid[((x +1)%LCD_WIDTH)+((y )%LCD_HEIGHT)*LCD_WIDTH]; 402 n[4] = n[8];
382 n[6] = pgrid[((x+LCD_WIDTH-1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; 403 n[5] = get_cell(x+1, y, pgrid);
383 n[7] = pgrid[((x )%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; 404 n[6] = get_cell(x-1, y+1, pgrid);
384 n[8] = pgrid[((x +1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; 405 n[7] = get_cell(x, y+1, pgrid);
406 n[8] = get_cell(x+1, y+1, pgrid);
385 } else { 407 } else {
386 /* we are moving right in a row, 408 /* we are moving right in a row,
387 * copy what we know about the neighbours on our left side, 409 * copy what we know about the neighbours on our left side,
@@ -389,19 +411,17 @@ static void next_generation(char *pgrid, char *pnext_grid){
389 */ 411 */
390 n[0] = n[1]; 412 n[0] = n[1];
391 n[1] = n[2]; 413 n[1] = n[2];
392 n[2] = pgrid[((x +1)%LCD_WIDTH)+((y+LCD_HEIGHT-1)%LCD_HEIGHT)*LCD_WIDTH]; 414 n[2] = get_cell(x+1, y-1, pgrid);
393 n[3] = n[4]; 415 n[3] = n[4];
394 n[5] = pgrid[((x +1)%LCD_WIDTH)+((y )%LCD_HEIGHT)*LCD_WIDTH]; 416 n[4] = n[5];
417 n[5] = get_cell(x+1, y, pgrid);
395 n[6] = n[7]; 418 n[6] = n[7];
396 n[7] = n[8]; 419 n[7] = n[8];
397 n[8] = pgrid[((x +1)%LCD_WIDTH)+((y +1)%LCD_HEIGHT)*LCD_WIDTH]; 420 n[8] = get_cell(x+1, y+1, pgrid);
398 } 421 }
399 } 422 }
400 423
401 m = x+y*LCD_WIDTH;
402
403 /* how old is our cell? */ 424 /* how old is our cell? */
404 n[4] = pgrid[m];
405 age = n[4]; 425 age = n[4];
406 426
407 /* calculate the cell based on given neighbour information */ 427 /* calculate the cell based on given neighbour information */
@@ -411,14 +431,12 @@ static void next_generation(char *pgrid, char *pnext_grid){
411 if(cell){ 431 if(cell){
412 population++; 432 population++;
413 /* prevent overflow */ 433 /* prevent overflow */
414 if(age>252){ 434 if(age<252)
415 pnext_grid[m] = 252; 435 age++;
416 } else { 436 set_cell_age(x, y, age, pnext_grid);
417 pnext_grid[m] = age + 1;
418 }
419 } 437 }
420 else 438 else
421 pnext_grid[m] = 0; 439 set_cell_age(x, y, 0, pnext_grid);
422#if 0 440#if 0
423 DEBUGF("x=%d,y=%d\n", x, y); 441 DEBUGF("x=%d,y=%d\n", x, y);
424 DEBUGF("cell: %d\n", cell); 442 DEBUGF("cell: %d\n", cell);
@@ -465,7 +483,7 @@ enum plugin_status plugin_start(const void* parameter)
465 init_grid(pgrid); 483 init_grid(pgrid);
466 484
467 485
468 if( parameter == NULL ) 486 if( parameter == NULL )
469 { 487 {
470 setup_grid(pgrid, pattern++); 488 setup_grid(pgrid, pattern++);
471 } 489 }