From 33ea8d90ca290b7b10cd8c86cc427b016258c74b Mon Sep 17 00:00:00 2001 From: Sergio Valor Date: Sat, 12 Oct 2024 22:25:43 +0200 Subject: [PATCH] =?UTF-8?q?Acabat=20de=20renamar,=20encara=20que=20he=20de?= =?UTF-8?q?scobert=20cosetes=20i=20tindr=C3=A9=20que=20fer=20altra=20pasae?= =?UTF-8?q?ta=20Actualitzat=20stb=5Fimage.h=20a=20la=20=C3=BAltima=20versi?= =?UTF-8?q?=C3=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- source/animated_sprite.cpp | 12 +- source/director.cpp | 14 +- source/director.h | 4 +- source/game.cpp | 4 +- source/item.cpp | 146 +++++----- source/item.h | 59 ++-- source/lang.cpp | 4 +- source/lang.h | 4 +- source/logo.cpp | 104 ++++--- source/logo.h | 30 +- source/manage_hiscore_table.cpp | 70 ++--- source/manage_hiscore_table.h | 6 +- source/options.cpp | 10 +- source/stb_image.h | 487 +++++++++++++++++++------------- source/text.cpp | 2 + source/utils.h | 3 +- 16 files changed, 528 insertions(+), 431 deletions(-) diff --git a/source/animated_sprite.cpp b/source/animated_sprite.cpp index c7b0c05..b087a00 100644 --- a/source/animated_sprite.cpp +++ b/source/animated_sprite.cpp @@ -35,6 +35,10 @@ AnimatedFile loadAnimationFromFile(std::shared_ptr texture, std::string buffer.counter = 0; buffer.current_frame = 0; buffer.completed = false; + buffer.name = ""; + buffer.speed = 5; + buffer.loop = 0; + buffer.frames.clear(); do { @@ -44,7 +48,7 @@ AnimatedFile loadAnimationFromFile(std::shared_ptr texture, std::string int pos = line.find("="); // Procesa las dos subcadenas - if (pos != (int)line.npos) + if (pos != static_cast(line.npos)) { if (line.substr(0, pos) == "name") { @@ -366,6 +370,10 @@ bool AnimatedSprite::loadFromVector(std::vector *source) buffer.counter = 0; buffer.current_frame = 0; buffer.completed = false; + buffer.name = ""; + buffer.speed = 5; + buffer.loop = 0; + buffer.frames.clear(); do { @@ -377,7 +385,7 @@ bool AnimatedSprite::loadFromVector(std::vector *source) int pos = line.find("="); // Procesa las dos subcadenas - if (pos != (int)line.npos) + if (pos != static_cast(line.npos)) { if (line.substr(0, pos) == "name") { diff --git a/source/director.cpp b/source/director.cpp index bbfaf46..987af63 100644 --- a/source/director.cpp +++ b/source/director.cpp @@ -93,7 +93,7 @@ Director::Director(int argc, char *argv[]) dbg_init(renderer_); // Crea los objetos - lang::loadFromFile(getLangFile((lang::lang_e)options.game.language)); + lang::loadFromFile(getLangFile((lang::Code)options.game.language)); Input::init(Asset::get()->get("gamecontrollerdb.txt")); initInput(); @@ -706,20 +706,20 @@ int Director::run() return returnCode; } -// Obtiene una fichero a partir de un lang_e -std::string Director::getLangFile(lang::lang_e lang) +// Obtiene una fichero a partir de un lang::Code +std::string Director::getLangFile(lang::Code code) { - switch (lang) + switch (code) { - case lang::ba_BA: + case lang::Code::ba_BA: return Asset::get()->get("ba_BA.txt"); break; - case lang::es_ES: + case lang::Code::es_ES: return Asset::get()->get("es_ES.txt"); break; - case lang::en_UK: + case lang::Code::en_UK: return Asset::get()->get("en_UK.txt"); break; diff --git a/source/director.h b/source/director.h index 92ead1c..1684638 100644 --- a/source/director.h +++ b/source/director.h @@ -72,8 +72,8 @@ private: // Ejecuta el juego en modo demo void runDemoGame(); - // Obtiene una fichero a partir de un lang_e - std::string getLangFile(lang::lang_e lang); + // Obtiene una fichero a partir de un lang::Code + std::string getLangFile(lang::Code code); public: // Constructor diff --git a/source/game.cpp b/source/game.cpp index 7ce17bc..c3500d7 100644 --- a/source/game.cpp +++ b/source/game.cpp @@ -2418,9 +2418,9 @@ void Game::initPaths() get_ready_bitmap_path_[i] = (int)finish1; } - else + else if (i< STAGE_COUNTER) { - get_ready_bitmap_path_[i] = sin[(int)((i - 150) * 1.8f)]; + get_ready_bitmap_path_[i] = sin[(int)((i - second_part) * 1.8f)]; get_ready_bitmap_path_[i] *= distance2; get_ready_bitmap_path_[i] += finish1; } diff --git a/source/item.cpp b/source/item.cpp index 4a64f3f..a7be78d 100644 --- a/source/item.cpp +++ b/source/item.cpp @@ -5,61 +5,61 @@ class Texture; // Constructor -Item::Item(int kind, float x, float y, SDL_Rect *playArea, std::shared_ptr texture, std::vector *animation) - : kind(kind), playArea(playArea) +Item::Item(int kind, float x, float y, SDL_Rect *play_area, std::shared_ptr texture, std::vector *animation) + : kind_(kind), play_area_(play_area) { - sprite = std::make_unique(texture, "", animation); + sprite_ = std::make_unique(texture, "", animation); - enabled = true; - timeToLive = 600; - accelX = 0.0f; - floorCollision = false; + enabled_ = true; + time_to_live_ = 600; + accel_x_ = 0.0f; + floor_collision_ = false; if (kind == ITEM_COFFEE_MACHINE) { - width = 28; - height = 37; - posX = (((int)x + (playArea->w / 2)) % (playArea->w - width - 5)) + 2; - posY = -height; - velX = 0.0f; - velY = -0.1f; - accelY = 0.1f; - collider.r = 10; + width_ = 28; + height_ = 37; + pos_x_ = (((int)x + (play_area->w / 2)) % (play_area->w - width_ - 5)) + 2; + pos_y_ = -height_; + vel_x_ = 0.0f; + vel_y_ = -0.1f; + accel_y_ = 0.1f; + collider_.r = 10; } else { - width = 20; - height = 20; - posX = x; - posY = y; - velX = -1.0f + ((rand() % 5) * 0.5f); - velY = -4.0f; - accelY = 0.2f; - collider.r = width / 2; + width_ = 20; + height_ = 20; + pos_x_ = x; + pos_y_ = y; + vel_x_ = -1.0f + ((rand() % 5) * 0.5f); + vel_y_ = -4.0f; + accel_y_ = 0.2f; + collider_.r = width_ / 2; } - sprite->setPosX(posX); - sprite->setPosY(posY); + sprite_->setPosX(pos_x_); + sprite_->setPosY(pos_y_); shiftColliders(); } // Centra el objeto en la posición X void Item::allignTo(int x) { - posX = float(x - (width / 2)); + pos_x_ = float(x - (width_ / 2)); - if (posX < param.game.play_area.rect.x) + if (pos_x_ < param.game.play_area.rect.x) { - posX = param.game.play_area.rect.x + 1; + pos_x_ = param.game.play_area.rect.x + 1; } - else if ((posX + width) > playArea->w) + else if ((pos_x_ + width_) > play_area_->w) { - posX = float(playArea->w - width - 1); + pos_x_ = float(play_area_->w - width_ - 1); } // Posición X,Y del sprite - sprite->setPosX(int(posX)); - sprite->setPosY(int(posY)); + sprite_->setPosX(int(pos_x_)); + sprite_->setPosY(int(pos_y_)); // Alinea el circulo de colisión con el objeto shiftColliders(); @@ -68,15 +68,15 @@ void Item::allignTo(int x) // Pinta el objeto en la pantalla void Item::render() { - if (enabled) + if (enabled_) { - if (timeToLive > 200) + if (time_to_live_ > 200) { - sprite->render(); + sprite_->render(); } - else if (timeToLive % 20 > 10) + else if (time_to_live_ % 20 > 10) { - sprite->render(); + sprite_->render(); } } } @@ -84,68 +84,68 @@ void Item::render() // Actualiza la posición y estados del objeto void Item::move() { - floorCollision = false; + floor_collision_ = false; // Calcula la nueva posición - posX += velX; - posY += velY; + pos_x_ += vel_x_; + pos_y_ += vel_y_; // Aplica las aceleraciones a la velocidad - velX += accelX; - velY += accelY; + vel_x_ += accel_x_; + vel_y_ += accel_y_; // Si queda fuera de pantalla, corregimos su posición y cambiamos su sentido - if ((posX < param.game.play_area.rect.x) || (posX + width > playArea->w)) + if ((pos_x_ < param.game.play_area.rect.x) || (pos_x_ + width_ > play_area_->w)) { // Corregir posición - posX -= velX; + pos_x_ -= vel_x_; // Invertir sentido - velX = -velX; + vel_x_ = -vel_x_; } // Si se sale por arriba rebota (excepto la maquina de café) - if ((posY < param.game.play_area.rect.y) && !(kind == ITEM_COFFEE_MACHINE)) + if ((pos_y_ < param.game.play_area.rect.y) && !(kind_ == ITEM_COFFEE_MACHINE)) { // Corrige - posY = param.game.play_area.rect.y; + pos_y_ = param.game.play_area.rect.y; // Invierte el sentido - velY = -velY; + vel_y_ = -vel_y_; } // Si el objeto se sale por la parte inferior - if (posY + height > playArea->h) + if (pos_y_ + height_ > play_area_->h) { // Detiene el objeto - velY = 0; - velX = 0; - accelX = 0; - accelY = 0; - posY = playArea->h - height; - if (kind == ITEM_COFFEE_MACHINE) + vel_y_ = 0; + vel_x_ = 0; + accel_x_ = 0; + accel_y_ = 0; + pos_y_ = play_area_->h - height_; + if (kind_ == ITEM_COFFEE_MACHINE) { - floorCollision = true; + floor_collision_ = true; } } // Actualiza la posición del sprite - sprite->setPosX(int(posX)); - sprite->setPosY(int(posY)); + sprite_->setPosX(int(pos_x_)); + sprite_->setPosY(int(pos_y_)); shiftColliders(); } // Pone a cero todos los valores del objeto void Item::disable() { - enabled = false; + enabled_ = false; } // Actualiza el objeto a su posicion, animación y controla los contadores void Item::update() { move(); - sprite->animate(); + sprite_->animate(); updateTimeToLive(); checkTimeToLive(); } @@ -153,70 +153,70 @@ void Item::update() // Actualiza el contador void Item::updateTimeToLive() { - if (timeToLive > 0) + if (time_to_live_ > 0) { - timeToLive--; + time_to_live_--; } } // Comprueba si el objeto sigue vivo void Item::checkTimeToLive() { - if (timeToLive == 0) + if (time_to_live_ == 0) disable(); } // Obtiene del valor de la variable float Item::getPosX() { - return posX; + return pos_x_; } // Obtiene del valor de la variable float Item::getPosY() { - return posY; + return pos_y_; } // Obtiene del valor de la variable int Item::getWidth() { - return width; + return width_; } // Obtiene del valor de la variable int Item::getHeight() { - return height; + return height_; } // Obtiene del valor de la variable int Item::getClass() { - return kind; + return kind_; } // Obtiene el valor de la variable bool Item::isEnabled() { - return enabled; + return enabled_; } // Obtiene el circulo de colisión Circle &Item::getCollider() { - return collider; + return collider_; } // Alinea el circulo de colisión con la posición del objeto void Item::shiftColliders() { - collider.x = int(posX + (width / 2)); - collider.y = int(posY + (height / 2)); + collider_.x = int(pos_x_ + (width_ / 2)); + collider_.y = int(pos_y_ + (height_ / 2)); } // Informa si el objeto ha colisionado con el suelo bool Item::isOnFloor() { - return floorCollision; + return floor_collision_; } \ No newline at end of file diff --git a/source/item.h b/source/item.h index 6f2af4e..1ec2a1a 100644 --- a/source/item.h +++ b/source/item.h @@ -10,35 +10,36 @@ #include "texture.h" // Tipos de objetos -#define ITEM_POINTS_1_DISK 1 -#define ITEM_POINTS_2_GAVINA 2 -#define ITEM_POINTS_3_PACMAR 3 -#define ITEM_CLOCK 4 -#define ITEM_COFFEE 5 -#define ITEM_COFFEE_MACHINE 6 -#define ITEM_NULL 7 +constexpr int ITEM_POINTS_1_DISK = 1; +constexpr int ITEM_POINTS_2_GAVINA = 2; +constexpr int ITEM_POINTS_3_PACMAR = 3; +constexpr int ITEM_CLOCK = 4; +constexpr int ITEM_COFFEE = 5; +constexpr int ITEM_COFFEE_MACHINE = 6; +constexpr int ITEM_NULL = 7; // Clase Item class Item { private: // Objetos y punteros - std::unique_ptr sprite; // Sprite con los graficos del objeto + std::unique_ptr sprite_; // Sprite con los graficos del objeto // Variables - float posX; // Posición X del objeto - float posY; // Posición Y del objeto - int width; // Ancho del objeto - int height; // Alto del objeto - float velX; // Velocidad en el eje X - float velY; // Velocidad en el eje Y - float accelX; // Aceleración en el eje X - float accelY; // Aceleración en el eje Y - bool floorCollision; // Indica si el objeto colisiona con el suelo - int kind; // Especifica el tipo de objeto que es - bool enabled; // Especifica si el objeto está habilitado - Circle collider; // Circulo de colisión del objeto - SDL_Rect *playArea; // Rectangulo con la zona de juego + float pos_x_; // Posición X del objeto + float pos_y_; // Posición Y del objeto + int width_; // Ancho del objeto + int height_; // Alto del objeto + float vel_x_; // Velocidad en el eje X + float vel_y_; // Velocidad en el eje Y + float accel_x_; // Aceleración en el eje X + float accel_y_; // Aceleración en el eje Y + bool floor_collision_; // Indica si el objeto colisiona con el suelo + int kind_; // Especifica el tipo de objeto que es + bool enabled_; // Especifica si el objeto está habilitado + Circle collider_; // Circulo de colisión del objeto + SDL_Rect *play_area_; // Rectangulo con la zona de juego + Uint16 time_to_live_; // Temporizador con el tiempo que el objeto está presente // Alinea el circulo de colisión con la posición del objeto void shiftColliders(); @@ -46,11 +47,15 @@ private: // Actualiza la posición y estados del objeto void move(); -public: - Uint16 timeToLive; // Temporizador con el tiempo que el objeto está presente + // Actualiza el contador + void updateTimeToLive(); + // Comprueba si el objeto sigue vivo + void checkTimeToLive(); + +public: // Constructor - Item(int kind, float x, float y, SDL_Rect *playArea, std::shared_ptr texture, std::vector *animation); + Item(int kind, float x, float y, SDL_Rect *play_area, std::shared_ptr texture, std::vector *animation); // Destructor ~Item() = default; @@ -67,12 +72,6 @@ public: // Actualiza al objeto a su posicion, animación y controla los contadores void update(); - // Actualiza el contador - void updateTimeToLive(); - - // Comprueba si el objeto sigue vivo - void checkTimeToLive(); - // Obtiene del valor de la variable float getPosX(); diff --git a/source/lang.cpp b/source/lang.cpp index bea1687..0724edd 100644 --- a/source/lang.cpp +++ b/source/lang.cpp @@ -7,13 +7,13 @@ namespace lang std::vector texts; // Vector con los textos // Inicializa los textos del juego en el idioma seleccionado - bool loadFromFile(std::string filePath) + bool loadFromFile(std::string file_path) { texts.clear(); bool success = false; - std::ifstream rfile(filePath); + std::ifstream rfile(file_path); if (rfile.is_open() && rfile.good()) { success = true; diff --git a/source/lang.h b/source/lang.h index 45df38f..441328a 100644 --- a/source/lang.h +++ b/source/lang.h @@ -4,7 +4,7 @@ namespace lang { - enum lang_e + enum class Code : int { es_ES = 0, ba_BA = 1, @@ -12,7 +12,7 @@ namespace lang }; // Inicializa los textos del juego en el idioma seleccionado - bool loadFromFile(std::string filePath); + bool loadFromFile(std::string file_path); // Obtiene la cadena de texto del indice std::string getText(int index); diff --git a/source/logo.cpp b/source/logo.cpp index 68294b7..2c1c52e 100644 --- a/source/logo.cpp +++ b/source/logo.cpp @@ -20,54 +20,48 @@ Logo::Logo() SDL_Renderer *renderer = Screen::get()->getRenderer(); // Reserva memoria para los punteros - jailTexture = std::make_shared(renderer, Asset::get()->get("logo_jailgames.png")); - sinceTexture = std::make_shared(renderer, Asset::get()->get("logo_since_1998.png")); - sinceSprite = std::make_unique((param.game.width - sinceTexture->getWidth()) / 2, 83 + jailTexture->getHeight() + 5, sinceTexture->getWidth(), sinceTexture->getHeight(), sinceTexture); + jail_texture_ = std::make_shared(renderer, Asset::get()->get("logo_jailgames.png")); + since_texture_ = std::make_shared(renderer, Asset::get()->get("logo_since_1998.png")); + since_sprite_ = std::make_unique((param.game.width - since_texture_->getWidth()) / 2, 83 + jail_texture_->getHeight() + 5, since_texture_->getWidth(), since_texture_->getHeight(), since_texture_); // Inicializa variables - counter = 0; + counter_ = 0; section::name = section::Name::LOGO; - ticks = 0; - ticksSpeed = 15; - showSinceSprite_cm = 70; - initFade_cm = 300; - endLogo_cm = 400; - postLogoDuration = 20; - speed = 8; - dest.x = param.game.game_area.center_x - jailTexture->getWidth() / 2; - dest.y = param.game.game_area.center_y - jailTexture->getHeight() / 2; - sinceSprite->setPosY(dest.y + jailTexture->getHeight() + 5); - sinceSprite->setSpriteClip(0, 0, sinceTexture->getWidth(), sinceTexture->getHeight()); - sinceSprite->setEnabled(false); - sinceTexture->setColor(0x00, 0x00, 0x00); // Esto en linux no hace nada ?? + ticks_ = 0; + dest_.x = param.game.game_area.center_x - jail_texture_->getWidth() / 2; + dest_.y = param.game.game_area.center_y - jail_texture_->getHeight() / 2; + since_sprite_->setPosY(dest_.y + jail_texture_->getHeight() + 5); + since_sprite_->setSpriteClip(0, 0, since_texture_->getWidth(), since_texture_->getHeight()); + since_sprite_->setEnabled(false); + since_texture_->setColor(0x00, 0x00, 0x00); // Esto en linux no hace nada ?? // Crea los sprites de cada linea - for (int i = 0; i < jailTexture->getHeight(); ++i) + for (int i = 0; i < jail_texture_->getHeight(); ++i) { - auto temp = std::make_unique(0, i, jailTexture->getWidth(), 1, jailTexture); - temp->setSpriteClip(0, i, jailTexture->getWidth(), 1); - const int posX = (i % 2 == 0) ? param.game.width + (i * 3) : -jailTexture->getWidth() - (i * 3); + auto temp = std::make_unique(0, i, jail_texture_->getWidth(), 1, jail_texture_); + temp->setSpriteClip(0, i, jail_texture_->getWidth(), 1); + const int posX = (i % 2 == 0) ? param.game.width + (i * 3) : -jail_texture_->getWidth() - (i * 3); temp->setPosX(posX); - temp->setPosY(dest.y + i); - jailSprite.push_back(std::move(temp)); + temp->setPosY(dest_.y + i); + jail_sprite_.push_back(std::move(temp)); } // Inicializa el vector de colores - color.push_back({0x00, 0x00, 0x00}); // Black - color.push_back({0x00, 0x00, 0xd8}); // Blue - color.push_back({0xd8, 0x00, 0x00}); // Red - color.push_back({0xd8, 0x00, 0xd8}); // Magenta - color.push_back({0x00, 0xd8, 0x00}); // Green - color.push_back({0x00, 0xd8, 0xd8}); // Cyan - color.push_back({0xd8, 0xd8, 0x00}); // Yellow - color.push_back({0xFF, 0xFF, 0xFF}); // Bright white + color_.push_back({0x00, 0x00, 0x00}); // Black + color_.push_back({0x00, 0x00, 0xd8}); // Blue + color_.push_back({0xd8, 0x00, 0x00}); // Red + color_.push_back({0xd8, 0x00, 0xd8}); // Magenta + color_.push_back({0x00, 0xd8, 0x00}); // Green + color_.push_back({0x00, 0xd8, 0xd8}); // Cyan + color_.push_back({0xd8, 0xd8, 0x00}); // Yellow + color_.push_back({0xFF, 0xFF, 0xFF}); // Bright white } // Recarga todas las texturas void Logo::reloadTextures() { - jailTexture->reLoad(); - sinceTexture->reLoad(); + jail_texture_->reLoad(); + since_texture_->reLoad(); } // Comprueba el manejador de eventos @@ -117,26 +111,26 @@ void Logo::checkInput() // Gestiona el logo de JAILGAME void Logo::updateJAILGAMES() { - if (counter > 30) + if (counter_ > 30) { - for (int i = 0; i < (int)jailSprite.size(); ++i) + for (int i = 0; i < (int)jail_sprite_.size(); ++i) { - if (jailSprite[i]->getPosX() != dest.x) + if (jail_sprite_[i]->getPosX() != dest_.x) { if (i % 2 == 0) { - jailSprite[i]->incPosX(-speed); - if (jailSprite[i]->getPosX() < dest.x) + jail_sprite_[i]->incPosX(-SPEED); + if (jail_sprite_[i]->getPosX() < dest_.x) { - jailSprite[i]->setPosX(dest.x); + jail_sprite_[i]->setPosX(dest_.x); } } else { - jailSprite[i]->incPosX(speed); - if (jailSprite[i]->getPosX() > dest.x) + jail_sprite_[i]->incPosX(SPEED); + if (jail_sprite_[i]->getPosX() > dest_.x) { - jailSprite[i]->setPosX(dest.x); + jail_sprite_[i]->setPosX(dest_.x); } } } @@ -152,19 +146,19 @@ void Logo::updateTextureColors() // Manejo de 'sinceTexture' for (int i = 0; i <= 7; ++i) { - if (counter == showSinceSprite_cm + inc * i) + if (counter_ == SHOW_SINCE_SPRITE_COUNTER_MARK + inc * i) { - sinceTexture->setColor(color[i].r, color[i].g, color[i].b); + since_texture_->setColor(color_[i].r, color_[i].g, color_[i].b); } } // Manejo de 'jailTexture' y 'sinceTexture' en el fade for (int i = 0; i <= 6; ++i) { - if (counter == initFade_cm + inc * i) + if (counter_ == INIT_FADE_COUNTER_MARK + inc * i) { - jailTexture->setColor(color[6 - i].r, color[6 - i].g, color[6 - i].b); - sinceTexture->setColor(color[6 - i].r, color[6 - i].g, color[6 - i].b); + jail_texture_->setColor(color_[6 - i].r, color_[6 - i].g, color_[6 - i].b); + since_texture_->setColor(color_[6 - i].r, color_[6 - i].g, color_[6 - i].b); } } } @@ -173,10 +167,10 @@ void Logo::updateTextureColors() void Logo::update() { // Comprueba que la diferencia de ticks sea mayor a la velocidad del juego - if (SDL_GetTicks() - ticks > ticksSpeed) + if (SDL_GetTicks() - ticks_ > TICKS_SPEED) { // Actualiza el contador de ticks - ticks = SDL_GetTicks(); + ticks_ = SDL_GetTicks(); // Actualiza el objeto screen Screen::get()->update(); @@ -191,18 +185,18 @@ void Logo::update() updateTextureColors(); // Gestiona el contador y sus eventos - counter++; + counter_++; // Comprueba si ha terminado el logo - if (counter == endLogo_cm + postLogoDuration) + if (counter_ == END_LOGO_COUNTER_MARK + POST_LOGO_DURATION) { section::name = section::Name::INTRO; } // Comprueba si se ha de mostrar el sprite - else if (counter == showSinceSprite_cm) + else if (counter_ == SHOW_SINCE_SPRITE_COUNTER_MARK) { - sinceSprite->setEnabled(true); + since_sprite_->setEnabled(true); } } } @@ -217,11 +211,11 @@ void Logo::render() Screen::get()->clean(); // Dibuja los sprites - for (auto &sprite : jailSprite) + for (auto &sprite : jail_sprite_) { sprite->render(); } - sinceSprite->render(); + since_sprite_->render(); // Vuelca el contenido del renderizador en pantalla Screen::get()->blit(); diff --git a/source/logo.h b/source/logo.h index df0a050..e3d872d 100644 --- a/source/logo.h +++ b/source/logo.h @@ -21,23 +21,25 @@ class Logo { private: + // Constantes + static constexpr Uint32 TICKS_SPEED = 15; // Velocidad a la que se repiten los bucles del programa + static constexpr int SHOW_SINCE_SPRITE_COUNTER_MARK = 70; // Tiempo del contador en el que empieza a verse el sprite de "SINCE 1998" + static constexpr int INIT_FADE_COUNTER_MARK = 300; // Tiempo del contador cuando inicia el fade a negro + static constexpr int END_LOGO_COUNTER_MARK = 400; // Tiempo del contador para terminar el logo + static constexpr int POST_LOGO_DURATION = 20; // Tiempo que dura el logo con el fade al maximo + static constexpr int SPEED = 8; // Velocidad de desplazamiento de cada linea + // Objetos y punteros - std::shared_ptr sinceTexture; // Textura con los graficos "Since 1998" - std::unique_ptr sinceSprite; // Sprite para manejar la sinceTexture - std::shared_ptr jailTexture; // Textura con los graficos "JAILGAMES" - std::vector> jailSprite; // Vector con los sprites de cada linea que forman el bitmap JAILGAMES + std::shared_ptr since_texture_; // Textura con los graficos "Since 1998" + std::unique_ptr since_sprite_; // Sprite para manejar la sinceTexture + std::shared_ptr jail_texture_; // Textura con los graficos "JAILGAMES" + std::vector> jail_sprite_; // Vector con los sprites de cada linea que forman el bitmap JAILGAMES // Variables - std::vector color; // Vector con los colores para el fade - int counter; // Contador - Uint32 ticks; // Contador de ticks para ajustar la velocidad del programa - Uint32 ticksSpeed; // Velocidad a la que se repiten los bucles del programa - int showSinceSprite_cm; // Tiempo del contador en el que empieza a verse el sprite de "SINCE 1998" - int initFade_cm; // Tiempo del contador cuando inicia el fade a negro - int endLogo_cm; // Tiempo del contador para terminar el logo - int postLogoDuration; // Tiempo que dura el logo con el fade al maximo - int speed; // Velocidad de desplazamiento de cada linea - SDL_Point dest; // Posición X donde dibujar el logo + std::vector color_; // Vector con los colores para el fade + int counter_; // Contador + Uint32 ticks_; // Contador de ticks para ajustar la velocidad del programa + SDL_Point dest_; // Posición X donde dibujar el logo // Actualiza las variables void update(); diff --git a/source/manage_hiscore_table.cpp b/source/manage_hiscore_table.cpp index b4e0d5b..4c2bdf5 100644 --- a/source/manage_hiscore_table.cpp +++ b/source/manage_hiscore_table.cpp @@ -8,40 +8,40 @@ // Constructor ManageHiScoreTable::ManageHiScoreTable(std::vector *table) - : table(table) {} + : table_(table) {} // Resetea la tabla a los valores por defecto void ManageHiScoreTable::clear() { // Limpia la tabla - table->clear(); + table_->clear(); // Añade 10 entradas predefinidas - table->push_back({"Bry", 1000000}); - table->push_back({"Usufondo", 500000}); - table->push_back({"G.Lucas", 100000}); - table->push_back({"P.Delgat", 50000}); - table->push_back({"P.Arrabalera", 10000}); - table->push_back({"Pelechano", 5000}); - table->push_back({"Sahuquillo", 1000}); - table->push_back({"Bacteriol", 500}); - table->push_back({"Pepe", 200}); - table->push_back({"Rosita", 100}); + table_->push_back({"Bry", 1000000}); + table_->push_back({"Usufondo", 500000}); + table_->push_back({"G.Lucas", 100000}); + table_->push_back({"P.Delgat", 50000}); + table_->push_back({"P.Arrabalera", 10000}); + table_->push_back({"Pelechano", 5000}); + table_->push_back({"Sahuquillo", 1000}); + table_->push_back({"Bacteriol", 500}); + table_->push_back({"Pepe", 200}); + table_->push_back({"Rosita", 100}); } // Añade un elemento a la tabla void ManageHiScoreTable::add(HiScoreEntry entry) { // Añade la entrada a la tabla - table->push_back(entry); + table_->push_back(entry); // Ordena la tabla sort(); // Deja solo las 10 primeras entradas - if ((int)table->size() > 10) + if (static_cast(table_->size()) > 10) { - table->resize(10); + table_->resize(10); } } @@ -51,30 +51,30 @@ void ManageHiScoreTable::sort() struct { bool operator()(HiScoreEntry a, HiScoreEntry b) const { return a.score > b.score; } - } customLess; + } custom_less; - std::sort(table->begin(), table->end(), customLess); + std::sort(table_->begin(), table_->end(), custom_less); } // Carga la tabla con los datos de un fichero -bool ManageHiScoreTable::loadFromFile(std::string filePath) +bool ManageHiScoreTable::loadFromFile(std::string file_path) { clear(); - bool success = true; - const std::string filename = filePath.substr(filePath.find_last_of("\\/") + 1); - SDL_RWops *file = SDL_RWFromFile(filePath.c_str(), "r+b"); + auto success = true; + const std::string filename = file_path.substr(file_path.find_last_of("\\/") + 1); + auto file = SDL_RWFromFile(file_path.c_str(), "r+b"); if (file) { -#ifdef DEBUG +#ifdef VERBOSE std::cout << "Reading file: " << filename.c_str() << std::endl; #endif - for (int i = 0; i < (int)table->size(); ++i) + for (int i = 0; i < (int)table_->size(); ++i) { int nameSize = 0; - if (SDL_RWread(file, &table->at(i).score, sizeof(int), 1) == 0) + if (SDL_RWread(file, &table_->at(i).score, sizeof(int), 1) == 0) { success = false; break; @@ -96,7 +96,7 @@ bool ManageHiScoreTable::loadFromFile(std::string filePath) else { name[nameSize] = 0; - table->at(i).name = name; + table_->at(i).name = name; free(name); } } @@ -113,24 +113,24 @@ bool ManageHiScoreTable::loadFromFile(std::string filePath) } // Guarda la tabla en un fichero -bool ManageHiScoreTable::saveToFile(std::string filePath) +bool ManageHiScoreTable::saveToFile(std::string file_path) { - bool success = true; - const std::string fileName = filePath.substr(filePath.find_last_of("\\/") + 1); - SDL_RWops *file = SDL_RWFromFile(filePath.c_str(), "w+b"); + auto success = true; + const std::string fileName = file_path.substr(file_path.find_last_of("\\/") + 1); + auto file = SDL_RWFromFile(file_path.c_str(), "w+b"); if (file) { // Guarda los datos - for (int i = 0; i < (int)table->size(); ++i) + for (int i = 0; i < (int)table_->size(); ++i) { - SDL_RWwrite(file, &table->at(i).score, sizeof(int), 1); - const int nameSize = (int)table->at(i).name.size(); + SDL_RWwrite(file, &table_->at(i).score, sizeof(int), 1); + const int nameSize = (int)table_->at(i).name.size(); SDL_RWwrite(file, &nameSize, sizeof(int), 1); - SDL_RWwrite(file, table->at(i).name.c_str(), nameSize, 1); + SDL_RWwrite(file, table_->at(i).name.c_str(), nameSize, 1); } -#ifdef DEBUG +#ifdef VERBOSE std::cout << "Writing file: " << fileName.c_str() << std::endl; #endif // Cierra el fichero @@ -138,7 +138,7 @@ bool ManageHiScoreTable::saveToFile(std::string filePath) } else { -#ifdef DEBUG +#ifdef VERBOSE std::cout << "Error: Unable to save " << fileName.c_str() << " file! " << SDL_GetError() << std::endl; #endif } diff --git a/source/manage_hiscore_table.h b/source/manage_hiscore_table.h index d3d8083..525b8fb 100644 --- a/source/manage_hiscore_table.h +++ b/source/manage_hiscore_table.h @@ -17,7 +17,7 @@ class ManageHiScoreTable { private: // Variables - std::vector *table; // Tabla con los records + std::vector *table_; // Tabla con los records // Ordena la tabla void sort(); @@ -36,8 +36,8 @@ public: void add(HiScoreEntry entry); // Carga la tabla con los datos de un fichero - bool loadFromFile(std::string filePath); + bool loadFromFile(std::string file_path); // Guarda la tabla en un fichero - bool saveToFile(std::string filePath); + bool saveToFile(std::string file_path); }; \ No newline at end of file diff --git a/source/options.cpp b/source/options.cpp index 0f2c1cb..0063a20 100644 --- a/source/options.cpp +++ b/source/options.cpp @@ -39,7 +39,7 @@ void initOptions() // Opciones de juego options.game.difficulty = GameDifficulty::NORMAL; - options.game.language = lang::ba_BA; + options.game.language = lang::Code::ba_BA; options.game.autofire = true; // Opciones de control @@ -139,9 +139,9 @@ bool loadOptionsFile(std::string file_path) options.video.window.size = 3; } - if (options.game.language < 0 || options.game.language > 2) + if (options.game.language != lang::Code::en_UK && options.game.language != lang::Code::ba_BA && options.game.language != lang::Code::es_ES) { - options.game.language = lang::en_UK; + options.game.language = lang::Code::en_UK; } return success; @@ -207,7 +207,7 @@ bool saveOptionsFile(std::string file_path) file << "## game.difficulty [" << value_difficulty_easy << ": easy, " << value_difficulty_normal << ": normal, " << value_difficulty_hard << ": hard]\n"; file << "\n"; - file << "game.language=" + std::to_string(options.game.language) + "\n"; + file << "game.language=" + std::to_string(static_cast(options.game.language)) + "\n"; file << "game.difficulty=" + std::to_string(static_cast(options.game.difficulty)) + "\n"; file << "game.autofire=" + boolToString(options.game.autofire) + "\n"; @@ -304,7 +304,7 @@ bool setOptions(std::string var, std::string value) // Opciones de juego else if (var == "game.language") { - options.game.language = std::stoi(value); + options.game.language = static_cast(std::stoi(value)); } else if (var == "game.difficulty") diff --git a/source/stb_image.h b/source/stb_image.h index d60371b..9eedabe 100644 --- a/source/stb_image.h +++ b/source/stb_image.h @@ -1,4 +1,4 @@ -/* stb_image - v2.27 - public domain image loader - http://nothings.org/stb +/* stb_image - v2.30 - public domain image loader - http://nothings.org/stb no warranty implied; use at your own risk Do this: @@ -48,6 +48,9 @@ LICENSE RECENT REVISION HISTORY: + 2.30 (2024-05-31) avoid erroneous gcc warning + 2.29 (2023-05-xx) optimizations + 2.28 (2023-01-29) many error fixes, security errors, just tons of stuff 2.27 (2021-07-11) document stbi_info better, 16-bit PNM support, bug fixes 2.26 (2020-07-13) many minor fixes 2.25 (2020-02-02) fix warnings @@ -108,7 +111,7 @@ RECENT REVISION HISTORY: Cass Everitt Ryamond Barbiero github:grim210 Paul Du Bois Engin Manap Aldo Culquicondor github:sammyhw Philipp Wiesemann Dale Weiler Oriol Ferrer Mesia github:phprus - Josh Tobin Matthew Gregan github:poppolopoppo + Josh Tobin Neil Bickford Matthew Gregan github:poppolopoppo Julian Raschke Gregory Mullen Christian Floisand github:darealshinji Baldur Karlsson Kevin Schmidt JR Smith github:Michaelangel007 Brad Weinberger Matvey Cherevko github:mosra @@ -140,7 +143,7 @@ RECENT REVISION HISTORY: // // ... x = width, y = height, n = # 8-bit components per pixel ... // // ... replace '0' with '1'..'4' to force that many components per pixel // // ... but 'n' will always be the number that it would have been if you said 0 -// stbi_image_free(data) +// stbi_image_free(data); // // Standard parameters: // int *x -- outputs image width in pixels @@ -635,7 +638,7 @@ STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const ch #endif #endif -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__SYMBIAN32__) typedef unsigned short stbi__uint16; typedef signed short stbi__int16; typedef unsigned int stbi__uint32; @@ -1063,6 +1066,23 @@ static void *stbi__malloc_mad4(int a, int b, int c, int d, int add) } #endif +// returns 1 if the sum of two signed ints is valid (between -2^31 and 2^31-1 inclusive), 0 on overflow. +static int stbi__addints_valid(int a, int b) +{ + if ((a >= 0) != (b >= 0)) return 1; // a and b have different signs, so no overflow + if (a < 0 && b < 0) return a >= INT_MIN - b; // same as a + b >= INT_MIN; INT_MIN - b cannot overflow since b < 0. + return a <= INT_MAX - b; +} + +// returns 1 if the product of two ints fits in a signed short, 0 on overflow. +static int stbi__mul2shorts_valid(int a, int b) +{ + if (b == 0 || b == -1) return 1; // multiplication by 0 is always 0; check for -1 so SHRT_MIN/b doesn't overflow + if ((a >= 0) == (b >= 0)) return a <= SHRT_MAX/b; // product is positive, so similar to mul2sizes_valid + if (b < 0) return a <= SHRT_MIN / b; // same as a * b >= SHRT_MIN + return a >= SHRT_MIN / b; +} + // stbi__err - error // stbi__errpf - error returning pointer to float // stbi__errpuc - error returning pointer to unsigned char @@ -1985,9 +2005,12 @@ static int stbi__build_huffman(stbi__huffman *h, int *count) int i,j,k=0; unsigned int code; // build size list for each symbol (from JPEG spec) - for (i=0; i < 16; ++i) - for (j=0; j < count[i]; ++j) + for (i=0; i < 16; ++i) { + for (j=0; j < count[i]; ++j) { h->size[k++] = (stbi_uc) (i+1); + if(k >= 257) return stbi__err("bad size list","Corrupt JPEG"); + } + } h->size[k] = 0; // compute actual symbols (from jpeg spec) @@ -2112,6 +2135,8 @@ stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h) // convert the huffman code to the symbol id c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k]; + if(c < 0 || c >= 256) // symbol id out of bounds! + return -1; STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]); // convert the id to a symbol @@ -2130,6 +2155,7 @@ stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n) unsigned int k; int sgn; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing sgn = j->code_buffer >> 31; // sign bit always in MSB; 0 if MSB clear (positive), 1 if MSB set (negative) k = stbi_lrot(j->code_buffer, n); @@ -2144,6 +2170,7 @@ stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n) { unsigned int k; if (j->code_bits < n) stbi__grow_buffer_unsafe(j); + if (j->code_bits < n) return 0; // ran out of bits from stream, return 0s intead of continuing k = stbi_lrot(j->code_buffer, n); j->code_buffer = k & ~stbi__bmask[n]; k &= stbi__bmask[n]; @@ -2155,6 +2182,7 @@ stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j) { unsigned int k; if (j->code_bits < 1) stbi__grow_buffer_unsafe(j); + if (j->code_bits < 1) return 0; // ran out of bits from stream, return 0s intead of continuing k = j->code_buffer; j->code_buffer <<= 1; --j->code_bits; @@ -2192,8 +2220,10 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman memset(data,0,64*sizeof(data[0])); diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta","Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, dequant[0])) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); data[0] = (short) (dc * dequant[0]); // decode AC components, see JPEG spec @@ -2207,6 +2237,7 @@ static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; // decode into unzigzag'd location @@ -2246,8 +2277,10 @@ static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__ if (t < 0 || t > 15) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); diff = t ? stbi__extend_receive(j, t) : 0; + if (!stbi__addints_valid(j->img_comp[b].dc_pred, diff)) return stbi__err("bad delta", "Corrupt JPEG"); dc = j->img_comp[b].dc_pred + diff; j->img_comp[b].dc_pred = dc; + if (!stbi__mul2shorts_valid(dc, 1 << j->succ_low)) return stbi__err("can't merge dc and ac", "Corrupt JPEG"); data[0] = (short) (dc * (1 << j->succ_low)); } else { // refinement scan for DC coefficient @@ -2282,6 +2315,7 @@ static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__ if (r) { // fast-AC path k += (r >> 4) & 15; // run s = r & 15; // combined length + if (s > j->code_bits) return stbi__err("bad huffman code", "Combined length longer than code bits available"); j->code_buffer <<= s; j->code_bits -= s; zig = stbi__jpeg_dezigzag[k++]; @@ -3102,6 +3136,7 @@ static int stbi__process_marker(stbi__jpeg *z, int m) sizes[i] = stbi__get8(z->s); n += sizes[i]; } + if(n > 256) return stbi__err("bad DHT header","Corrupt JPEG"); // Loop over i < n would write past end of values! L -= 17; if (tc == 0) { if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0; @@ -3351,6 +3386,28 @@ static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan) return 1; } +static stbi_uc stbi__skip_jpeg_junk_at_end(stbi__jpeg *j) +{ + // some JPEGs have junk at end, skip over it but if we find what looks + // like a valid marker, resume there + while (!stbi__at_eof(j->s)) { + stbi_uc x = stbi__get8(j->s); + while (x == 0xff) { // might be a marker + if (stbi__at_eof(j->s)) return STBI__MARKER_none; + x = stbi__get8(j->s); + if (x != 0x00 && x != 0xff) { + // not a stuffed zero or lead-in to another marker, looks + // like an actual marker, return it + return x; + } + // stuffed zero has x=0 now which ends the loop, meaning we go + // back to regular scan loop. + // repeated 0xff keeps trying to read the next byte of the marker. + } + } + return STBI__MARKER_none; +} + // decode image to YCbCr format static int stbi__decode_jpeg_image(stbi__jpeg *j) { @@ -3367,25 +3424,22 @@ static int stbi__decode_jpeg_image(stbi__jpeg *j) if (!stbi__process_scan_header(j)) return 0; if (!stbi__parse_entropy_coded_data(j)) return 0; if (j->marker == STBI__MARKER_none ) { - // handle 0s at the end of image data from IP Kamera 9060 - while (!stbi__at_eof(j->s)) { - int x = stbi__get8(j->s); - if (x == 255) { - j->marker = stbi__get8(j->s); - break; - } - } + j->marker = stbi__skip_jpeg_junk_at_end(j); // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0 } + m = stbi__get_marker(j); + if (STBI__RESTART(m)) + m = stbi__get_marker(j); } else if (stbi__DNL(m)) { int Ld = stbi__get16be(j->s); stbi__uint32 NL = stbi__get16be(j->s); if (Ld != 4) return stbi__err("bad DNL len", "Corrupt JPEG"); if (NL != j->s->img_y) return stbi__err("bad DNL height", "Corrupt JPEG"); + m = stbi__get_marker(j); } else { - if (!stbi__process_marker(j, m)) return 0; + if (!stbi__process_marker(j, m)) return 1; + m = stbi__get_marker(j); } - m = stbi__get_marker(j); } if (j->progressive) stbi__jpeg_finish(j); @@ -3976,6 +4030,7 @@ static void *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int re unsigned char* result; stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg)); if (!j) return stbi__errpuc("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); STBI_NOTUSED(ri); j->s = s; stbi__setup_jpeg(j); @@ -3989,6 +4044,7 @@ static int stbi__jpeg_test(stbi__context *s) int r; stbi__jpeg* j = (stbi__jpeg*)stbi__malloc(sizeof(stbi__jpeg)); if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); j->s = s; stbi__setup_jpeg(j); r = stbi__decode_jpeg_header(j, STBI__SCAN_type); @@ -4014,6 +4070,7 @@ static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp) int result; stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg))); if (!j) return stbi__err("outofmem", "Out of memory"); + memset(j, 0, sizeof(stbi__jpeg)); j->s = s; result = stbi__jpeg_info_raw(j, x, y, comp); STBI_FREE(j); @@ -4121,6 +4178,7 @@ typedef struct { stbi_uc *zbuffer, *zbuffer_end; int num_bits; + int hit_zeof_once; stbi__uint32 code_buffer; char *zout; @@ -4187,9 +4245,20 @@ stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z) int b,s; if (a->num_bits < 16) { if (stbi__zeof(a)) { - return -1; /* report error for unexpected end of data. */ + if (!a->hit_zeof_once) { + // This is the first time we hit eof, insert 16 extra padding btis + // to allow us to keep going; if we actually consume any of them + // though, that is invalid data. This is caught later. + a->hit_zeof_once = 1; + a->num_bits += 16; // add 16 implicit zero bits + } else { + // We already inserted our extra 16 padding bits and are again + // out, this stream is actually prematurely terminated. + return -1; + } + } else { + stbi__fill_bits(a); } - stbi__fill_bits(a); } b = z->fast[a->code_buffer & STBI__ZFAST_MASK]; if (b) { @@ -4254,17 +4323,25 @@ static int stbi__parse_huffman_block(stbi__zbuf *a) int len,dist; if (z == 256) { a->zout = zout; + if (a->hit_zeof_once && a->num_bits < 16) { + // The first time we hit zeof, we inserted 16 extra zero bits into our bit + // buffer so the decoder can just do its speculative decoding. But if we + // actually consumed any of those bits (which is the case when num_bits < 16), + // the stream actually read past the end so it is malformed. + return stbi__err("unexpected end","Corrupt PNG"); + } return 1; } + if (z >= 286) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, length codes 286 and 287 must not appear in compressed data z -= 257; len = stbi__zlength_base[z]; if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]); z = stbi__zhuffman_decode(a, &a->z_distance); - if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); + if (z < 0 || z >= 30) return stbi__err("bad huffman code","Corrupt PNG"); // per DEFLATE, distance codes 30 and 31 must not appear in compressed data dist = stbi__zdist_base[z]; if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]); if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG"); - if (zout + len > a->zout_end) { + if (len > a->zout_end - zout) { if (!stbi__zexpand(a, zout, len)) return 0; zout = a->zout; } @@ -4408,6 +4485,7 @@ static int stbi__parse_zlib(stbi__zbuf *a, int parse_header) if (!stbi__parse_zlib_header(a)) return 0; a->num_bits = 0; a->code_buffer = 0; + a->hit_zeof_once = 0; do { final = stbi__zreceive(a,1); type = stbi__zreceive(a,2); @@ -4563,9 +4641,8 @@ enum { STBI__F_up=2, STBI__F_avg=3, STBI__F_paeth=4, - // synthetic filters used for first scanline to avoid needing a dummy row of 0s - STBI__F_avg_first, - STBI__F_paeth_first + // synthetic filter used for first scanline to avoid needing a dummy row of 0s + STBI__F_avg_first }; static stbi_uc first_row_filter[5] = @@ -4574,29 +4651,56 @@ static stbi_uc first_row_filter[5] = STBI__F_sub, STBI__F_none, STBI__F_avg_first, - STBI__F_paeth_first + STBI__F_sub // Paeth with b=c=0 turns out to be equivalent to sub }; static int stbi__paeth(int a, int b, int c) { - int p = a + b - c; - int pa = abs(p-a); - int pb = abs(p-b); - int pc = abs(p-c); - if (pa <= pb && pa <= pc) return a; - if (pb <= pc) return b; - return c; + // This formulation looks very different from the reference in the PNG spec, but is + // actually equivalent and has favorable data dependencies and admits straightforward + // generation of branch-free code, which helps performance significantly. + int thresh = c*3 - (a + b); + int lo = a < b ? a : b; + int hi = a < b ? b : a; + int t0 = (hi <= thresh) ? lo : c; + int t1 = (thresh <= lo) ? hi : t0; + return t1; } static const stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 }; +// adds an extra all-255 alpha channel +// dest == src is legal +// img_n must be 1 or 3 +static void stbi__create_png_alpha_expand8(stbi_uc *dest, stbi_uc *src, stbi__uint32 x, int img_n) +{ + int i; + // must process data backwards since we allow dest==src + if (img_n == 1) { + for (i=x-1; i >= 0; --i) { + dest[i*2+1] = 255; + dest[i*2+0] = src[i]; + } + } else { + STBI_ASSERT(img_n == 3); + for (i=x-1; i >= 0; --i) { + dest[i*4+3] = 255; + dest[i*4+2] = src[i*3+2]; + dest[i*4+1] = src[i*3+1]; + dest[i*4+0] = src[i*3+0]; + } + } +} + // create the png data from post-deflated data static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color) { - int bytes = (depth == 16? 2 : 1); + int bytes = (depth == 16 ? 2 : 1); stbi__context *s = a->s; stbi__uint32 i,j,stride = x*out_n*bytes; stbi__uint32 img_len, img_width_bytes; + stbi_uc *filter_buf; + int all_ok = 1; int k; int img_n = s->img_n; // copy it into a local for later @@ -4608,8 +4712,11 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r a->out = (stbi_uc *) stbi__malloc_mad3(x, y, output_bytes, 0); // extra bytes to write off the end into if (!a->out) return stbi__err("outofmem", "Out of memory"); + // note: error exits here don't need to clean up a->out individually, + // stbi__do_png always does on error. if (!stbi__mad3sizes_valid(img_n, x, depth, 7)) return stbi__err("too large", "Corrupt PNG"); img_width_bytes = (((img_n * x * depth) + 7) >> 3); + if (!stbi__mad2sizes_valid(img_width_bytes, y, img_width_bytes)) return stbi__err("too large", "Corrupt PNG"); img_len = (img_width_bytes + 1) * y; // we used to check for exact match between raw_len and img_len on non-interlaced PNGs, @@ -4617,189 +4724,137 @@ static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 r // so just check for raw_len < img_len always. if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG"); + // Allocate two scan lines worth of filter workspace buffer. + filter_buf = (stbi_uc *) stbi__malloc_mad2(img_width_bytes, 2, 0); + if (!filter_buf) return stbi__err("outofmem", "Out of memory"); + + // Filtering for low-bit-depth images + if (depth < 8) { + filter_bytes = 1; + width = img_width_bytes; + } + for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *prior; + // cur/prior filter buffers alternate + stbi_uc *cur = filter_buf + (j & 1)*img_width_bytes; + stbi_uc *prior = filter_buf + (~j & 1)*img_width_bytes; + stbi_uc *dest = a->out + stride*j; + int nk = width * filter_bytes; int filter = *raw++; - if (filter > 4) - return stbi__err("invalid filter","Corrupt PNG"); - - if (depth < 8) { - if (img_width_bytes > x) return stbi__err("invalid width","Corrupt PNG"); - cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place - filter_bytes = 1; - width = img_width_bytes; + // check filter type + if (filter > 4) { + all_ok = stbi__err("invalid filter","Corrupt PNG"); + break; } - prior = cur - stride; // bugfix: need to compute this after 'cur +=' computation above // if first row, use special filter that doesn't sample previous row if (j == 0) filter = first_row_filter[filter]; - // handle first byte explicitly - for (k=0; k < filter_bytes; ++k) { - switch (filter) { - case STBI__F_none : cur[k] = raw[k]; break; - case STBI__F_sub : cur[k] = raw[k]; break; - case STBI__F_up : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break; - case STBI__F_avg : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break; - case STBI__F_paeth : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break; - case STBI__F_avg_first : cur[k] = raw[k]; break; - case STBI__F_paeth_first: cur[k] = raw[k]; break; - } + // perform actual filtering + switch (filter) { + case STBI__F_none: + memcpy(cur, raw, nk); + break; + case STBI__F_sub: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); + break; + case STBI__F_up: + for (k = 0; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); + break; + case STBI__F_avg: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); + break; + case STBI__F_paeth: + for (k = 0; k < filter_bytes; ++k) + cur[k] = STBI__BYTECAST(raw[k] + prior[k]); // prior[k] == stbi__paeth(0,prior[k],0) + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes], prior[k], prior[k-filter_bytes])); + break; + case STBI__F_avg_first: + memcpy(cur, raw, filter_bytes); + for (k = filter_bytes; k < nk; ++k) + cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); + break; } - if (depth == 8) { - if (img_n != out_n) - cur[img_n] = 255; // first pixel - raw += img_n; - cur += out_n; - prior += out_n; - } else if (depth == 16) { - if (img_n != out_n) { - cur[filter_bytes] = 255; // first pixel top byte - cur[filter_bytes+1] = 255; // first pixel bottom byte - } - raw += filter_bytes; - cur += output_bytes; - prior += output_bytes; - } else { - raw += 1; - cur += 1; - prior += 1; - } + raw += nk; - // this is a little gross, so that we don't switch per-pixel or per-component - if (depth < 8 || img_n == out_n) { - int nk = (width - 1)*filter_bytes; - #define STBI__CASE(f) \ - case f: \ - for (k=0; k < nk; ++k) - switch (filter) { - // "none" filter turns into a memcpy here; make that explicit. - case STBI__F_none: memcpy(cur, raw, nk); break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break; - } - #undef STBI__CASE - raw += nk; - } else { - STBI_ASSERT(img_n+1 == out_n); - #define STBI__CASE(f) \ - case f: \ - for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \ - for (k=0; k < filter_bytes; ++k) - switch (filter) { - STBI__CASE(STBI__F_none) { cur[k] = raw[k]; } break; - STBI__CASE(STBI__F_sub) { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break; - STBI__CASE(STBI__F_up) { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break; - STBI__CASE(STBI__F_avg) { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break; - STBI__CASE(STBI__F_paeth) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break; - STBI__CASE(STBI__F_avg_first) { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break; - STBI__CASE(STBI__F_paeth_first) { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break; - } - #undef STBI__CASE - - // the loop above sets the high byte of the pixels' alpha, but for - // 16 bit png files we also need the low byte set. we'll do that here. - if (depth == 16) { - cur = a->out + stride*j; // start at the beginning of the row again - for (i=0; i < x; ++i,cur+=output_bytes) { - cur[filter_bytes+1] = 255; - } - } - } - } - - // we make a separate pass to expand bits to pixels; for performance, - // this could run two scanlines behind the above code, so it won't - // intefere with filtering but will still be in the cache. - if (depth < 8) { - for (j=0; j < y; ++j) { - stbi_uc *cur = a->out + stride*j; - stbi_uc *in = a->out + stride*j + x*out_n - img_width_bytes; - // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit - // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop + // expand decoded bits in cur to dest, also adding an extra alpha channel if desired + if (depth < 8) { stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range + stbi_uc *in = cur; + stbi_uc *out = dest; + stbi_uc inb = 0; + stbi__uint32 nsmp = x*img_n; - // note that the final byte might overshoot and write more data than desired. - // we can allocate enough data that this never writes out of memory, but it - // could also overwrite the next scanline. can it overwrite non-empty data - // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel. - // so we need to explicitly clamp the final ones - + // expand bits to bytes first if (depth == 4) { - for (k=x*img_n; k >= 2; k-=2, ++in) { - *cur++ = scale * ((*in >> 4) ); - *cur++ = scale * ((*in ) & 0x0f); + for (i=0; i < nsmp; ++i) { + if ((i & 1) == 0) inb = *in++; + *out++ = scale * (inb >> 4); + inb <<= 4; } - if (k > 0) *cur++ = scale * ((*in >> 4) ); } else if (depth == 2) { - for (k=x*img_n; k >= 4; k-=4, ++in) { - *cur++ = scale * ((*in >> 6) ); - *cur++ = scale * ((*in >> 4) & 0x03); - *cur++ = scale * ((*in >> 2) & 0x03); - *cur++ = scale * ((*in ) & 0x03); + for (i=0; i < nsmp; ++i) { + if ((i & 3) == 0) inb = *in++; + *out++ = scale * (inb >> 6); + inb <<= 2; } - if (k > 0) *cur++ = scale * ((*in >> 6) ); - if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03); - if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03); - } else if (depth == 1) { - for (k=x*img_n; k >= 8; k-=8, ++in) { - *cur++ = scale * ((*in >> 7) ); - *cur++ = scale * ((*in >> 6) & 0x01); - *cur++ = scale * ((*in >> 5) & 0x01); - *cur++ = scale * ((*in >> 4) & 0x01); - *cur++ = scale * ((*in >> 3) & 0x01); - *cur++ = scale * ((*in >> 2) & 0x01); - *cur++ = scale * ((*in >> 1) & 0x01); - *cur++ = scale * ((*in ) & 0x01); + } else { + STBI_ASSERT(depth == 1); + for (i=0; i < nsmp; ++i) { + if ((i & 7) == 0) inb = *in++; + *out++ = scale * (inb >> 7); + inb <<= 1; } - if (k > 0) *cur++ = scale * ((*in >> 7) ); - if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01); - if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01); - if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01); - if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01); - if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01); - if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01); } - if (img_n != out_n) { - int q; - // insert alpha = 255 - cur = a->out + stride*j; + + // insert alpha=255 values if desired + if (img_n != out_n) + stbi__create_png_alpha_expand8(dest, dest, x, img_n); + } else if (depth == 8) { + if (img_n == out_n) + memcpy(dest, cur, x*img_n); + else + stbi__create_png_alpha_expand8(dest, cur, x, img_n); + } else if (depth == 16) { + // convert the image data from big-endian to platform-native + stbi__uint16 *dest16 = (stbi__uint16*)dest; + stbi__uint32 nsmp = x*img_n; + + if (img_n == out_n) { + for (i = 0; i < nsmp; ++i, ++dest16, cur += 2) + *dest16 = (cur[0] << 8) | cur[1]; + } else { + STBI_ASSERT(img_n+1 == out_n); if (img_n == 1) { - for (q=x-1; q >= 0; --q) { - cur[q*2+1] = 255; - cur[q*2+0] = cur[q]; + for (i = 0; i < x; ++i, dest16 += 2, cur += 2) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = 0xffff; } } else { STBI_ASSERT(img_n == 3); - for (q=x-1; q >= 0; --q) { - cur[q*4+3] = 255; - cur[q*4+2] = cur[q*3+2]; - cur[q*4+1] = cur[q*3+1]; - cur[q*4+0] = cur[q*3+0]; + for (i = 0; i < x; ++i, dest16 += 4, cur += 6) { + dest16[0] = (cur[0] << 8) | cur[1]; + dest16[1] = (cur[2] << 8) | cur[3]; + dest16[2] = (cur[4] << 8) | cur[5]; + dest16[3] = 0xffff; } } } } - } else if (depth == 16) { - // force the image data from big-endian to platform-native. - // this is done in a separate pass due to the decoding relying - // on the data being untouched, but could probably be done - // per-line during decode if care is taken. - stbi_uc *cur = a->out; - stbi__uint16 *cur16 = (stbi__uint16*)cur; - - for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) { - *cur16 = (cur[0] << 8) | cur[1]; - } } + STBI_FREE(filter_buf); + if (!all_ok) return 0; + return 1; } @@ -4955,7 +5010,7 @@ STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert) static STBI_THREAD_LOCAL int stbi__unpremultiply_on_load_local, stbi__unpremultiply_on_load_set; static STBI_THREAD_LOCAL int stbi__de_iphone_flag_local, stbi__de_iphone_flag_set; -STBIDEF void stbi__unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) +STBIDEF void stbi_set_unpremultiply_on_load_thread(int flag_true_if_should_unpremultiply) { stbi__unpremultiply_on_load_local = flag_true_if_should_unpremultiply; stbi__unpremultiply_on_load_set = 1; @@ -5064,14 +5119,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!pal_img_n) { s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0); if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode"); - if (scan == STBI__SCAN_header) return 1; } else { // if paletted, then pal_n is our final components, and // img_n is # components to decompress/filter. s->img_n = 1; if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG"); - // if SCAN_header, have to scan to see if we have a tRNS } + // even with SCAN_header, have to scan to see if we have a tRNS break; } @@ -5103,10 +5157,14 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG"); if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG"); has_trans = 1; + // non-paletted with tRNS = constant alpha. if header-scanning, we can stop now. + if (scan == STBI__SCAN_header) { ++s->img_n; return 1; } if (z->depth == 16) { - for (k = 0; k < s->img_n; ++k) tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is + for (k = 0; k < s->img_n && k < 3; ++k) // extra loop test to suppress false GCC warning + tc16[k] = (stbi__uint16)stbi__get16be(s); // copy the values as-is } else { - for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger + for (k = 0; k < s->img_n && k < 3; ++k) + tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger } } break; @@ -5115,7 +5173,13 @@ static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp) case STBI__PNG_TYPE('I','D','A','T'): { if (first) return stbi__err("first not IHDR", "Corrupt PNG"); if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG"); - if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; } + if (scan == STBI__SCAN_header) { + // header scan definitely stops at first IDAT + if (pal_img_n) + s->img_n = pal_img_n; + return 1; + } + if (c.length > (1u << 30)) return stbi__err("IDAT size limit", "IDAT section larger than 2^30 bytes"); if ((int)(ioff + c.length) < (int)ioff) return 0; if (ioff + c.length > idata_limit) { stbi__uint32 idata_limit_old = idata_limit; @@ -5498,8 +5562,22 @@ static void *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req psize = (info.offset - info.extra_read - info.hsz) >> 2; } if (psize == 0) { - if (info.offset != s->callback_already_read + (s->img_buffer - s->img_buffer_original)) { - return stbi__errpuc("bad offset", "Corrupt BMP"); + // accept some number of extra bytes after the header, but if the offset points either to before + // the header ends or implies a large amount of extra data, reject the file as malformed + int bytes_read_so_far = s->callback_already_read + (int)(s->img_buffer - s->img_buffer_original); + int header_limit = 1024; // max we actually read is below 256 bytes currently. + int extra_data_limit = 256*4; // what ordinarily goes here is a palette; 256 entries*4 bytes is its max size. + if (bytes_read_so_far <= 0 || bytes_read_so_far > header_limit) { + return stbi__errpuc("bad header", "Corrupt BMP"); + } + // we established that bytes_read_so_far is positive and sensible. + // the first half of this test rejects offsets that are either too small positives, or + // negative, and guarantees that info.offset >= bytes_read_so_far > 0. this in turn + // ensures the number computed in the second half of the test can't overflow. + if (info.offset < bytes_read_so_far || info.offset - bytes_read_so_far > extra_data_limit) { + return stbi__errpuc("bad offset", "Corrupt BMP"); + } else { + stbi__skip(s, info.offset - bytes_read_so_far); } } @@ -7187,12 +7265,12 @@ static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int re // Run value = stbi__get8(s); count -= 128; - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = value; } else { // Dump - if (count > nleft) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } + if ((count == 0) || (count > nleft)) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("corrupt", "bad RLE data in HDR"); } for (z = 0; z < count; ++z) scanline[i++ * 4 + k] = stbi__get8(s); } @@ -7446,10 +7524,17 @@ static void *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req out = (stbi_uc *) stbi__malloc_mad4(s->img_n, s->img_x, s->img_y, ri->bits_per_channel / 8, 0); if (!out) return stbi__errpuc("outofmem", "Out of memory"); - stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8)); + if (!stbi__getn(s, out, s->img_n * s->img_x * s->img_y * (ri->bits_per_channel / 8))) { + STBI_FREE(out); + return stbi__errpuc("bad PNM", "PNM file truncated"); + } if (req_comp && req_comp != s->img_n) { - out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + if (ri->bits_per_channel == 16) { + out = (stbi_uc *) stbi__convert_format16((stbi__uint16 *) out, s->img_n, req_comp, s->img_x, s->img_y); + } else { + out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y); + } if (out == NULL) return out; // stbi__convert_format frees input on failure } return out; @@ -7486,6 +7571,8 @@ static int stbi__pnm_getinteger(stbi__context *s, char *c) while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) { value = value*10 + (*c - '0'); *c = (char) stbi__get8(s); + if((value > 214748364) || (value == 214748364 && *c > '7')) + return stbi__err("integer parse overflow", "Parsing an integer in the PPM header overflowed a 32-bit int"); } return value; @@ -7516,9 +7603,13 @@ static int stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp) stbi__pnm_skip_whitespace(s, &c); *x = stbi__pnm_getinteger(s, &c); // read width + if(*x == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); *y = stbi__pnm_getinteger(s, &c); // read height + if (*y == 0) + return stbi__err("invalid width", "PPM image header had zero or overflowing width"); stbi__pnm_skip_whitespace(s, &c); maxv = stbi__pnm_getinteger(s, &c); // read max value diff --git a/source/text.cpp b/source/text.cpp index fc346d9..e28c40a 100644 --- a/source/text.cpp +++ b/source/text.cpp @@ -16,6 +16,8 @@ TextFile LoadTextFile(std::string file_path) tf.offset[i].x = 0; tf.offset[i].y = 0; tf.offset[i].w = 0; + tf.box_width = 0; + tf.box_height = 0; } // Abre el fichero para leer los valores diff --git a/source/utils.h b/source/utils.h index f8f9903..e0dc351 100644 --- a/source/utils.h +++ b/source/utils.h @@ -8,6 +8,7 @@ #include // for string, basic_string #include // for vector #include "input.h" // for inputs_e +#include "lang.h" struct JA_Music_t; struct JA_Sound_t; enum class ScreenFilter; @@ -113,7 +114,7 @@ struct OptionsAudio struct OptionsGame { GameDifficulty difficulty; // Dificultad del juego - Uint8 language; // Idioma usado en el juego + lang::Code language; // Idioma usado en el juego bool autofire; // Indica si el jugador ha de pulsar repetidamente para disparar o basta con mantener pulsado std::vector hi_score_table; // Tabla con las mejores puntuaciones };