180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru/*
380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Copyright 2007 The Android Open Source Project
480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru *
580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * Use of this source code is governed by a BSD-style license that can be
680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru * found in the LICENSE file.
780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru */
880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru// Author: cevans@google.com (Chris Evans)
1080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru#include "bmpdecoderhelper.h"
1280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querunamespace image_codec {
1480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
1580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic const int kBmpHeaderSize = 14;
1680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic const int kBmpInfoSize = 40;
1780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic const int kBmpOS2InfoSize = 12;
1880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querustatic const int kMaxDim = SHRT_MAX / 2;
1980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
2080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Querubool BmpDecoderHelper::DecodeImage(const char* p,
21910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger                                   size_t len,
2280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                   int max_pixels,
2380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru                                   BmpDecoderCallback* callback) {
2480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  data_ = reinterpret_cast<const uint8*>(p);
2580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  pos_ = 0;
2680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  len_ = len;
2780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  inverted_ = true;
2880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // Parse the header structure.
2980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (len < kBmpHeaderSize + 4) {
3080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return false;
3180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
3280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  GetShort();  // Signature.
3380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  GetInt();  // Size.
3480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  GetInt();  // Reserved.
3580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int offset = GetInt();
3680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // Parse the info structure.
3780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int infoSize = GetInt();
3880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (infoSize != kBmpOS2InfoSize && infoSize < kBmpInfoSize) {
3980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return false;
4080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
4180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int cols = 0;
4280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int comp = 0;
4380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int colLen = 4;
4480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (infoSize >= kBmpInfoSize) {
4580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (len < kBmpHeaderSize + kBmpInfoSize) {
4680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      return false;
4780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
4880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    width_ = GetInt();
4980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    height_ = GetInt();
5080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    GetShort();  // Planes.
5180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bpp_ = GetShort();
5280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    comp = GetInt();
5380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    GetInt();  // Size.
5480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    GetInt();  // XPPM.
5580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    GetInt();  // YPPM.
5680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    cols = GetInt();
5780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    GetInt();  // Important colours.
5880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  } else {
5980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (len < kBmpHeaderSize + kBmpOS2InfoSize) {
6080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      return false;
6180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
6280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    colLen = 3;
6380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    width_ = GetShort();
6480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    height_ = GetShort();
6580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    GetShort();  // Planes.
6680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    bpp_ = GetShort();
6780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
6880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (height_ < 0) {
6980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    height_ = -height_;
7080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    inverted_ = false;
7180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
7280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (width_ <= 0 || width_ > kMaxDim || height_ <= 0 || height_ > kMaxDim) {
7380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return false;
7480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
7580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (width_ * height_ > max_pixels) {
7680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return false;
7780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
7880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (cols < 0 || cols > 256) {
7980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return false;
8080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
8180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // Allocate then read in the colour map.
8280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (cols == 0 && bpp_ <= 8) {
8380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    cols = 1 << bpp_;
8480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
8580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (bpp_ <= 8 || cols > 0) {
8680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    uint8* colBuf = new uint8[256 * 3];
8780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    memset(colBuf, '\0', 256 * 3);
8880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    colTab_.reset(colBuf);
8980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
9080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (cols > 0) {
9180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (pos_ + (cols * colLen) > len_) {
9280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      return false;
9380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
9480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for (int i = 0; i < cols; ++i) {
9580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      int base = i * 3;
9680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      colTab_[base + 2] = GetByte();
9780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      colTab_[base + 1] = GetByte();
9880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      colTab_[base] = GetByte();
9980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      if (colLen == 4) {
10080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        GetByte();
10180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      }
10280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
10380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
10480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // Read in the compression data if necessary.
10580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  redBits_ = 0x7c00;
10680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  greenBits_ = 0x03e0;
10780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  blueBits_ = 0x001f;
10880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  bool rle = false;
10980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (comp == 1 || comp == 2) {
11080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    rle = true;
11180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  } else if (comp == 3) {
11280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (pos_ + 12 > len_) {
11380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      return false;
11480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
11580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    redBits_ = GetInt() & 0xffff;
11680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    greenBits_ = GetInt() & 0xffff;
11780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    blueBits_ = GetInt() & 0xffff;
11880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
11980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  redShiftRight_ = CalcShiftRight(redBits_);
12080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  greenShiftRight_ = CalcShiftRight(greenBits_);
12180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  blueShiftRight_ = CalcShiftRight(blueBits_);
12280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  redShiftLeft_ = CalcShiftLeft(redBits_);
12380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  greenShiftLeft_ = CalcShiftLeft(greenBits_);
12480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  blueShiftLeft_ = CalcShiftLeft(blueBits_);
12580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  rowPad_ = 0;
12680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  pixelPad_ = 0;
12780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int rowLen;
12880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (bpp_ == 32) {
12980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    rowLen = width_ * 4;
13080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pixelPad_ = 1;
13180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  } else if (bpp_ == 24) {
13280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    rowLen = width_ * 3;
13380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  } else if (bpp_ == 16) {
13480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    rowLen = width_ * 2;
13580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  } else if (bpp_ == 8) {
13680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    rowLen = width_;
13780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  } else if (bpp_ == 4) {
13880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    rowLen = width_ / 2;
13980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (width_ & 1) {
14080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      rowLen++;
14180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
14280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  } else if (bpp_ == 1) {
14380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    rowLen = width_ / 8;
14480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (width_ & 7) {
14580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      rowLen++;
14680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
14780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  } else {
14880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return false;
14980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
15080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // Round the rowLen up to a multiple of 4.
15180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (rowLen % 4 != 0) {
15280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    rowPad_ = 4 - (rowLen % 4);
15380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    rowLen += rowPad_;
15480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
15580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
156910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger  if (offset > 0 && (size_t)offset > pos_ && (size_t)offset < len_) {
15780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    pos_ = offset;
15880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
15980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // Deliberately off-by-one; a load of BMPs seem to have their last byte
16080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // missing.
16180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (!rle && (pos_ + (rowLen * height_) > len_ + 1)) {
16280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return false;
16380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
16480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
16580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  output_ = callback->SetSize(width_, height_);
16680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (NULL == output_) {
16780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return true;  // meaning we succeeded, but they want us to stop now
16880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
16980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
17080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (rle && (bpp_ == 4 || bpp_ == 8)) {
17180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    DoRLEDecode();
17280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  } else {
17380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    DoStandardDecode();
17480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
17580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return true;
17680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
17780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
17880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid BmpDecoderHelper::DoRLEDecode() {
17980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  static const uint8 RLE_ESCAPE = 0;
18080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  static const uint8 RLE_EOL = 0;
18180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  static const uint8 RLE_EOF = 1;
18280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  static const uint8 RLE_DELTA = 2;
18380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int x = 0;
18480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int y = height_ - 1;
185910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger  while (pos_ + 1 < len_) {
18680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    uint8 cmd = GetByte();
18780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (cmd != RLE_ESCAPE) {
18880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      uint8 pixels = GetByte();
18980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      int num = 0;
19080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      uint8 col = pixels;
19180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      while (cmd-- && x < width_) {
19280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (bpp_ == 4) {
19380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          if (num & 1) {
19480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            col = pixels & 0xf;
19580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          } else {
19680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            col = pixels >> 4;
19780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          }
19880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
19980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        PutPixel(x++, y, col);
20080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        num++;
20180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      }
20280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    } else {
20380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      cmd = GetByte();
20480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      if (cmd == RLE_EOF) {
20580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        return;
20680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      } else if (cmd == RLE_EOL) {
20780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        x = 0;
20880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        y--;
20980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (y < 0) {
21080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          return;
21180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
21280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      } else if (cmd == RLE_DELTA) {
213910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger        if (pos_ + 1 < len_) {
21480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          uint8 dx = GetByte();
21580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          uint8 dy = GetByte();
21680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          x += dx;
21780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          if (x > width_) {
21880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            x = width_;
21980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          }
22080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          y -= dy;
22180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          if (y < 0) {
22280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            return;
22380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          }
22480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
22580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      } else {
22680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        int num = 0;
22780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        int bytesRead = 0;
22880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        uint8 val = 0;
22980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        while (cmd-- && pos_ < len_) {
23080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          if (bpp_ == 8 || !(num & 1)) {
23180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            val = GetByte();
23280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            bytesRead++;
23380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          }
23480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          uint8 col = val;
23580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          if (bpp_ == 4) {
23680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            if (num & 1) {
23780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru              col = col & 0xf;
23880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            } else {
23980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru              col >>= 4;
24080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            }
24180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          }
24280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          if (x < width_) {
24380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            PutPixel(x++, y, col);
24480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          }
24580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          num++;
24680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
24780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // All pixel runs must be an even number of bytes - skip a byte if we
24880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        // read an odd number.
24980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if ((bytesRead & 1) && pos_ < len_) {
25080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          GetByte();
25180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
25280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      }
25380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
25480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
25580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
25680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
25780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid BmpDecoderHelper::PutPixel(int x, int y, uint8 col) {
25880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  CHECK(x >= 0 && x < width_);
25980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  CHECK(y >= 0 && y < height_);
26080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (!inverted_) {
26180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    y = height_ - (y + 1);
26280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
26380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
26480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int base = ((y * width_) + x) * 3;
26580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int colBase = col * 3;
26680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  output_[base] = colTab_[colBase];
26780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  output_[base + 1] = colTab_[colBase + 1];
26880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  output_[base + 2] = colTab_[colBase + 2];
26980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
27080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
27180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruvoid BmpDecoderHelper::DoStandardDecode() {
27280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int row = 0;
27380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  uint8 currVal = 0;
27480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  for (int h = height_ - 1; h >= 0; h--, row++) {
27580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    int realH = h;
27680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    if (!inverted_) {
27780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      realH = height_ - (h + 1);
27880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
27980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    uint8* line = output_ + (3 * width_ * realH);
28080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for (int w = 0; w < width_; w++) {
28180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      if (bpp_ >= 24) {
28280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        line[2] = GetByte();
28380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        line[1] = GetByte();
28480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        line[0] = GetByte();
28580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      } else if (bpp_ == 16) {
28680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        uint32 val = GetShort();
28780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        line[0] = ((val & redBits_) >> redShiftRight_) << redShiftLeft_;
28880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        line[1] = ((val & greenBits_) >> greenShiftRight_) << greenShiftLeft_;
28980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        line[2] = ((val & blueBits_) >> blueShiftRight_) << blueShiftLeft_;
29080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      } else if (bpp_ <= 8) {
29180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        uint8 col;
29280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        if (bpp_ == 8) {
29380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          col = GetByte();
29480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else if (bpp_ == 4) {
29580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          if ((w % 2) == 0) {
29680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            currVal = GetByte();
29780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            col = currVal >> 4;
29880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          } else {
29980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            col = currVal & 0xf;
30080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          }
30180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        } else {
30280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          if ((w % 8) == 0) {
30380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru            currVal = GetByte();
30480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          }
30580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          int bit = w & 7;
30680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru          col = ((currVal >> (7 - bit)) & 1);
30780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        }
30880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        int base = col * 3;
30980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        line[0] = colTab_[base];
31080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        line[1] = colTab_[base + 1];
31180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        line[2] = colTab_[base + 2];
31280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      }
31380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      line += 3;
31480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      for (int i = 0; i < pixelPad_; ++i) {
31580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru        GetByte();
31680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      }
31780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
31880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    for (int i = 0; i < rowPad_; ++i) {
31980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru      GetByte();
32080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    }
32180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
32280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
32380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
32480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint BmpDecoderHelper::GetInt() {
32580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  uint8 b1 = GetByte();
32680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  uint8 b2 = GetByte();
32780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  uint8 b3 = GetByte();
32880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  uint8 b4 = GetByte();
32980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
33080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
33180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
33280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint BmpDecoderHelper::GetShort() {
33380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  uint8 b1 = GetByte();
33480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  uint8 b2 = GetByte();
33580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return b1 | (b2 << 8);
33680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
33780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
33880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruuint8 BmpDecoderHelper::GetByte() {
339910f694aefb0b671dd8522a9afe9b6be645701c1Derek Sollenberger  CHECK(pos_ <= len_);
34080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // We deliberately allow this off-by-one access to cater for BMPs with their
34180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  // last byte missing.
34280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  if (pos_ == len_) {
34380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    return 0;
34480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
34580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return data_[pos_++];
34680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
34780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
34880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint BmpDecoderHelper::CalcShiftRight(uint32 mask) {
34980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int ret = 0;
35080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  while (mask != 0 && !(mask & 1)) {
35180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    mask >>= 1;
35280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    ret++;
35380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
35480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return ret;
35580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
35680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
35780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queruint BmpDecoderHelper::CalcShiftLeft(uint32 mask) {
35880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  int ret = 0;
35980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  while (mask != 0 && !(mask & 1)) {
36080bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    mask >>= 1;
36180bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
36280bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  while (mask != 0 && !(mask & 0x80)) {
36380bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    mask <<= 1;
36480bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru    ret++;
36580bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  }
36680bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru  return ret;
36780bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}
36880bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru
36980bacfeb4bda06541e8695bd502229727bccfeaJean-Baptiste Queru}  // namespace image_codec
370