Fix signedness of height in BMP decoder

Change-Id: I8a17739538a9ecd63d713007550177579c0b72f0
Reviewed-on: https://pdfium-review.googlesource.com/6731
Commit-Queue: dsinclair <dsinclair@chromium.org>
Reviewed-by: dsinclair <dsinclair@chromium.org>
diff --git a/core/fxcodec/codec/ccodec_bmpmodule.cpp b/core/fxcodec/codec/ccodec_bmpmodule.cpp
index 3709196..1c81124 100644
--- a/core/fxcodec/codec/ccodec_bmpmodule.cpp
+++ b/core/fxcodec/codec/ccodec_bmpmodule.cpp
@@ -51,7 +51,7 @@
 
   *width = ctx->m_Bmp.width;
   *height = ctx->m_Bmp.height;
-  *tb_flag = false;
+  *tb_flag = ctx->m_Bmp.imgTB_flag;
   *components = ctx->m_Bmp.components;
   *pal_num = ctx->m_Bmp.pal_num;
   *pal_pp = ctx->m_Bmp.pal_ptr;
diff --git a/core/fxcodec/lbmp/fx_bmp.cpp b/core/fxcodec/lbmp/fx_bmp.cpp
index 62ae681..a4b97ef 100644
--- a/core/fxcodec/lbmp/fx_bmp.cpp
+++ b/core/fxcodec/lbmp/fx_bmp.cpp
@@ -43,6 +43,7 @@
       out_row_bytes(0),
       bitCounts(0),
       color_used(0),
+      imgTB_flag(false),
       pal_num(0),
       pal_type(0),
       pal_ptr(nullptr),
@@ -125,6 +126,7 @@
         bitCounts = GetWord_LSBFirst(
             reinterpret_cast<uint8_t*>(&bmp_core_header_ptr->bcBitCount));
         compress_flag = BMP_RGB;
+        imgTB_flag = false;
       } break;
       case kBmpInfoHeaderSize: {
         BmpInfoHeaderPtr bmp_info_header_ptr = nullptr;
@@ -133,7 +135,8 @@
           return 2;
         }
         width = GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biWidth);
-        height = GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biHeight);
+        int32_t signed_height =
+            GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biHeight);
         bitCounts =
             GetWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biBitCount);
         compress_flag =
@@ -144,6 +147,16 @@
             (uint8_t*)&bmp_info_header_ptr->biXPelsPerMeter);
         dpi_y = (int32_t)GetDWord_LSBFirst(
             (uint8_t*)&bmp_info_header_ptr->biYPelsPerMeter);
+        if (signed_height < 0) {
+          if (signed_height == std::numeric_limits<int>::min()) {
+            Error("Unsupported height");
+            NOTREACHED();
+          }
+          height = -signed_height;
+          imgTB_flag = true;
+        } else {
+          height = signed_height;
+        }
       } break;
       default: {
         if (img_ifh_size >
@@ -155,7 +168,8 @@
           }
           uint16_t biPlanes;
           width = GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biWidth);
-          height = GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biHeight);
+          int32_t signed_height =
+              GetDWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biHeight);
           bitCounts =
               GetWord_LSBFirst((uint8_t*)&bmp_info_header_ptr->biBitCount);
           compress_flag =
@@ -167,6 +181,16 @@
               (uint8_t*)&bmp_info_header_ptr->biXPelsPerMeter);
           dpi_y = GetDWord_LSBFirst(
               (uint8_t*)&bmp_info_header_ptr->biYPelsPerMeter);
+          if (signed_height < 0) {
+            if (signed_height == std::numeric_limits<int>::min()) {
+              Error("Unsupported height");
+              NOTREACHED();
+            }
+            height = -signed_height;
+            imgTB_flag = true;
+          } else {
+            height = signed_height;
+          }
           if (compress_flag == BMP_RGB && biPlanes == 1 && color_used == 0)
             break;
         }
@@ -402,7 +426,8 @@
       if (!ValidateColorIndex(byte))
         return 0;
     }
-    ReadScanline(height - 1 - row_num++, out_row_buffer);
+    ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++),
+                 out_row_buffer);
   }
   SaveDecodingStatus(BMP_D_STATUS_TAIL);
   return 1;
@@ -430,7 +455,8 @@
               Error("The Bmp File Is Corrupt");
               NOTREACHED();
             }
-            ReadScanline(height - 1 - row_num++, out_row_buffer);
+            ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++),
+                         out_row_buffer);
             col_num = 0;
             std::fill(out_row_buffer.begin(), out_row_buffer.end(), 0);
             SaveDecodingStatus(BMP_D_STATUS_DATA);
@@ -438,7 +464,8 @@
           }
           case RLE_EOI: {
             if (row_num < height) {
-              ReadScanline(height - 1 - row_num++, out_row_buffer);
+              ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++),
+                           out_row_buffer);
             }
             SaveDecodingStatus(BMP_D_STATUS_TAIL);
             return 1;
@@ -457,7 +484,8 @@
             }
             while (row_num < bmp_row_num_next) {
               std::fill(out_row_buffer.begin(), out_row_buffer.end(), 0);
-              ReadScanline(height - 1 - row_num++, out_row_buffer);
+              ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++),
+                           out_row_buffer);
             }
           } break;
           default: {
@@ -528,7 +556,8 @@
               Error("The Bmp File Is Corrupt");
               NOTREACHED();
             }
-            ReadScanline(height - 1 - row_num++, out_row_buffer);
+            ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++),
+                         out_row_buffer);
             col_num = 0;
             std::fill(out_row_buffer.begin(), out_row_buffer.end(), 0);
             SaveDecodingStatus(BMP_D_STATUS_DATA);
@@ -536,7 +565,8 @@
           }
           case RLE_EOI: {
             if (row_num < height) {
-              ReadScanline(height - 1 - row_num++, out_row_buffer);
+              ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++),
+                           out_row_buffer);
             }
             SaveDecodingStatus(BMP_D_STATUS_TAIL);
             return 1;
@@ -555,7 +585,8 @@
             }
             while (row_num < bmp_row_num_next) {
               std::fill(out_row_buffer.begin(), out_row_buffer.end(), 0);
-              ReadScanline(height - 1 - row_num++, out_row_buffer);
+              ReadScanline(imgTB_flag ? row_num++ : (height - 1 - row_num++),
+                           out_row_buffer);
             }
           } break;
           default: {
diff --git a/core/fxcodec/lbmp/fx_bmp.h b/core/fxcodec/lbmp/fx_bmp.h
index bf5e94f..e304020 100644
--- a/core/fxcodec/lbmp/fx_bmp.h
+++ b/core/fxcodec/lbmp/fx_bmp.h
@@ -95,6 +95,7 @@
   size_t out_row_bytes;
   uint16_t bitCounts;
   uint32_t color_used;
+  bool imgTB_flag;
   int32_t pal_num;
   int32_t pal_type;
   uint32_t* pal_ptr;