fixed undefined signed integer overflow for expression "1 << 31"
[rocksndiamonds.git] / src / files.c
index 919b7f85533df569af308d0aefebc2646bfd471c..5d8f6479387a22bd0ec5c25424e865265bc37418 100644 (file)
@@ -60,7 +60,6 @@
 
 #define TAPE_CHUNK_VERS_SIZE   8       // size of file version chunk
 #define TAPE_CHUNK_HEAD_SIZE   20      // size of tape file header
-#define TAPE_CHUNK_HEAD_UNUSED 1       // unused tape header bytes
 #define TAPE_CHUNK_SCRN_SIZE   2       // size of screen size chunk
 
 #define SCORE_CHUNK_VERS_SIZE  8       // size of file version chunk
@@ -2849,7 +2848,7 @@ static int LoadLevel_CUS3(File *file, int chunk_size, struct LevelInfo *level)
     // bits 0 - 31 of "has_event[]"
     event_bits = getFile32BitBE(file);
     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
-      if (event_bits & (1 << j))
+      if (event_bits & (1u << j))
        ei->change->has_event[j] = TRUE;
 
     ei->change->target_element = getMappedElement(getFile16BitBE(file));
@@ -2985,7 +2984,7 @@ static int LoadLevel_CUS4(File *file, int chunk_size, struct LevelInfo *level)
     // bits 0 - 31 of "has_event[]" ...
     event_bits = getFile32BitBE(file);
     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
-      if (event_bits & (1 << j))
+      if (event_bits & (1u << j))
        change->has_event[j] = TRUE;
 
     change->target_element = getMappedElement(getFile16BitBE(file));
@@ -3026,7 +3025,7 @@ static int LoadLevel_CUS4(File *file, int chunk_size, struct LevelInfo *level)
     // ... bits 32 - 39 of "has_event[]" (not nice, but downward compatible)
     event_bits = getFile8Bit(file);
     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
-      if (event_bits & (1 << (j - 32)))
+      if (event_bits & (1u << (j - 32)))
        change->has_event[j] = TRUE;
   }
 
@@ -3355,6 +3354,10 @@ static int LoadLevel_CUSX(File *file, int chunk_size, struct LevelInfo *level)
 
   while (!checkEndOfFile(file))
   {
+    // level file might contain invalid change page number
+    if (xx_current_change_page >= ei->num_change_pages)
+      break;
+
     struct ElementChangeInfo *change = &ei->change_page[xx_current_change_page];
 
     xx_change = *change;       // copy change data into temporary buffer
@@ -3384,6 +3387,9 @@ static int LoadLevel_GRPX(File *file, int chunk_size, struct LevelInfo *level)
   struct ElementInfo *ei = &element_info[element];
   struct ElementGroupInfo *group = ei->group;
 
+  if (group == NULL)
+    return -1;
+
   xx_ei = *ei;         // copy element data into temporary buffer
   xx_group = *group;   // copy group data into temporary buffer
 
@@ -3584,6 +3590,14 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
        int chunk_size_expected =
          (chunk_info[i].loader)(file, chunk_size, level);
 
+       if (chunk_size_expected < 0)
+       {
+         Warn("error reading chunk '%s' in level file '%s'",
+              chunk_name, filename);
+
+         break;
+       }
+
        // the size of some chunks cannot be checked before reading other
        // chunks first (like "HEAD" and "BODY") that contain some header
        // information, so check them here
@@ -3591,6 +3605,8 @@ static void LoadLevelFromFileInfo_RND(struct LevelInfo *level,
        {
          Warn("wrong size (%d) of chunk '%s' in level file '%s'",
               chunk_size, chunk_name, filename);
+
+         break;
        }
       }
     }
@@ -7311,7 +7327,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
     event_bits = 0;
     for (j = 0; j < MIN(NUM_CHANGE_EVENTS, 32); j++)
       if (change->has_event[j])
-       event_bits |= (1 << j);
+       event_bits |= (1u << j);
     putFile32BitBE(file, event_bits);
 
     putFile16BitBE(file, change->target_element);
@@ -7351,7 +7367,7 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element)
     event_bits = 0;
     for (j = 32; j < NUM_CHANGE_EVENTS; j++)
       if (change->has_event[j])
-       event_bits |= (1 << (j - 32));
+       event_bits |= (1u << (j - 32));
     putFile8Bit(file, event_bits);
   }
 }
@@ -7798,6 +7814,28 @@ void DumpLevel(struct LevelInfo *level)
   Print("use step counter: %s\n", (level->use_step_counter ? "yes" : "no"));
   Print("rate time over score: %s\n", (level->rate_time_over_score ? "yes" : "no"));
 
+  if (options.debug)
+  {
+    int i, j;
+
+    for (i = 0; i < NUM_ENVELOPES; i++)
+    {
+      char *text = level->envelope[i].text;
+      int text_len = strlen(text);
+      boolean has_text = FALSE;
+
+      for (j = 0; j < text_len; j++)
+       if (text[j] != ' ' && text[j] != '\n')
+         has_text = TRUE;
+
+      if (has_text)
+      {
+       Print("\n");
+       Print("Envelope %d:\n'%s'\n", i + 1, text);
+      }
+    }
+  }
+
   PrintLine("-", 79);
 }
 
@@ -7848,6 +7886,7 @@ static void setTapeInfoToDefaults(void)
   tape.level_nr = level_nr;
   tape.counter = 0;
   tape.changed = FALSE;
+  tape.solved = FALSE;
 
   tape.recording = FALSE;
   tape.playing = FALSE;
@@ -7934,8 +7973,7 @@ static int LoadTape_HEAD(File *file, int chunk_size, struct TapeInfo *tape)
     setTapeActionFlags(tape, getFile8Bit(file));
 
     tape->property_bits = getFile8Bit(file);
-
-    ReadUnusedBytesFromFile(file, TAPE_CHUNK_HEAD_UNUSED);
+    tape->solved = getFile8Bit(file);
 
     engine_version = getFileVersion(file);
     if (engine_version > 0)
@@ -8380,9 +8418,7 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
   putFile8Bit(file, getTapeActionValue(tape));
 
   putFile8Bit(file, tape->property_bits);
-
-  // unused bytes not at the end here for 4-byte alignment of engine_version
-  WriteUnusedBytesToFile(file, TAPE_CHUNK_HEAD_UNUSED);
+  putFile8Bit(file, tape->solved);
 
   putFileVersion(file, tape->engine_version);
 }
@@ -8564,6 +8600,10 @@ void DumpTape(struct TapeInfo *tape)
        tape->engine_version);
   Print("Level series identifier: '%s'\n", tape->level_identifier);
 
+  Print("Solution tape: %s\n",
+       tape->solved ? "yes" :
+       tape->game_version < VERSION_IDENT(4,3,2,3) ? "unknown" : "no");
+
   Print("Special tape properties: ");
   if (tape->property_bits == TAPE_PROPERTY_NONE)
     Print("[none]");
@@ -8693,7 +8733,9 @@ static void setScoreInfoToDefaultsExt(struct ScoreInfo *scores)
   // The following values are intentionally not reset here:
   // - last_level_nr
   // - last_entry_nr
+  // - next_level_nr
   // - continue_playing
+  // - continue_on_return
 }
 
 static void setScoreInfoToDefaults(void)
@@ -9637,6 +9679,10 @@ static struct TokenInfo global_setup_tokens[] =
     TYPE_INTEGER,
     &setup.touch.grid_ysize[1],                        "touch.virtual_buttons.1.ysize"
   },
+  {
+    TYPE_SWITCH,
+    &setup.touch.overlay_buttons,              "touch.overlay_buttons"
+  },
 };
 
 static struct TokenInfo auto_setup_tokens[] =
@@ -10377,6 +10423,8 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
 
   si->touch.grid_initialized           = video.initialized;
 
+  si->touch.overlay_buttons            = FALSE;
+
   si->editor.el_boulderdash            = TRUE;
   si->editor.el_emerald_mine           = TRUE;
   si->editor.el_emerald_mine_club      = TRUE;
@@ -10519,6 +10567,7 @@ static void setSetupInfoToDefaults(struct SetupInfo *si)
 
 #if defined(PLATFORM_ANDROID)
   si->fullscreen = TRUE;
+  si->touch.overlay_buttons = TRUE;
 #endif
 
   setHideSetupEntry(&setup.debug.xsn_mode);
@@ -13422,8 +13471,25 @@ void CreateCollectElementImages(void)
   int dst_width  = anim_width * 2;
   int dst_height = anim_height * num_collect_images / 2;
   Bitmap *dst_bitmap = CreateBitmap(dst_width, dst_height, DEFAULT_DEPTH);
-  char *basename = "RocksCollect.bmp";
-  char *filename = getPath2(global.create_collect_images_dir, basename);
+  char *basename_bmp = "RocksCollect.bmp";
+  char *basename_png = "RocksCollect.png";
+  char *filename_bmp = getPath2(global.create_collect_images_dir, basename_bmp);
+  char *filename_png = getPath2(global.create_collect_images_dir, basename_png);
+  int len_filename_bmp = strlen(filename_bmp);
+  int len_filename_png = strlen(filename_png);
+  int max_command_len = MAX_FILENAME_LEN + len_filename_bmp + len_filename_png;
+  char cmd_convert[max_command_len];
+
+  snprintf(cmd_convert, max_command_len, "convert \"%s\" \"%s\"",
+          filename_bmp,
+          filename_png);
+
+  // force using RGBA surface for destination bitmap
+  SDL_SetColorKey(dst_bitmap->surface, SET_TRANSPARENT_PIXEL,
+                 SDL_MapRGB(dst_bitmap->surface->format, 0x00, 0x00, 0x00));
+
+  dst_bitmap->surface =
+    SDL_ConvertSurfaceFormat(dst_bitmap->surface, SDL_PIXELFORMAT_ARGB8888, 0);
 
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -13445,6 +13511,13 @@ void CreateCollectElementImages(void)
     BlitBitmap(src_bitmap, tmp_bitmap, src_x, src_y,
               tile_size, tile_size, 0, 0);
 
+    // force using RGBA surface for temporary bitmap (using transparent black)
+    SDL_SetColorKey(tmp_bitmap->surface, SET_TRANSPARENT_PIXEL,
+                   SDL_MapRGB(tmp_bitmap->surface->format, 0x00, 0x00, 0x00));
+
+    tmp_bitmap->surface =
+      SDL_ConvertSurfaceFormat(tmp_bitmap->surface, SDL_PIXELFORMAT_ARGB8888, 0);
+
     tmp_bitmap->surface_masked = tmp_bitmap->surface;
 
     for (j = 0; j < anim_frames; j++)
@@ -13465,9 +13538,9 @@ void CreateCollectElementImages(void)
        frame_bitmap = half_bitmap;
       }
 
-      BlitBitmap(frame_bitmap, dst_bitmap, 0, 0,
-                frame_size_final, frame_size_final,
-                dst_x + j * tile_size + offset, dst_y + offset);
+      BlitBitmapMasked(frame_bitmap, dst_bitmap, 0, 0,
+                      frame_size_final, frame_size_final,
+                      dst_x + j * tile_size + offset, dst_y + offset);
 
       FreeBitmap(frame_bitmap);
     }
@@ -13479,11 +13552,18 @@ void CreateCollectElementImages(void)
     pos_collect_images++;
   }
 
-  if (SDL_SaveBMP(dst_bitmap->surface, filename) != 0)
-    Fail("cannot save element collecting image file '%s'", filename);
+  if (SDL_SaveBMP(dst_bitmap->surface, filename_bmp) != 0)
+    Fail("cannot save element collecting image file '%s'", filename_bmp);
 
   FreeBitmap(dst_bitmap);
 
+  Info("Converting image file from BMP to PNG ...");
+
+  if (system(cmd_convert) != 0)
+    Fail("converting image file failed");
+
+  unlink(filename_bmp);
+
   Info("Done.");
 
   CloseAllAndExit(0);