1685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
2bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com/*
3685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Copyright 2007 The Android Open Source Project
4bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com *
5685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * Use of this source code is governed by a BSD-style license that can be
6685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com * found in the LICENSE file.
7bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com */
8685cfc0ee13d7c355ae2f4f3d225ad45e945763fepoger@google.com
9bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com// Author: cevans@google.com (Chris Evans)
10bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
11bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com#include "bmpdecoderhelper.h"
12bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
13bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comnamespace image_codec {
14bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
15bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic const int kBmpHeaderSize = 14;
16bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic const int kBmpInfoSize = 40;
17bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic const int kBmpOS2InfoSize = 12;
18bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comstatic const int kMaxDim = SHRT_MAX / 2;
19bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
20bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.combool BmpDecoderHelper::DecodeImage(const char* p,
21bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                   int len,
22bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                   int max_pixels,
23bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com                                   BmpDecoderCallback* callback) {
24bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  data_ = reinterpret_cast<const uint8*>(p);
25bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  pos_ = 0;
26bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  len_ = len;
27bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  inverted_ = true;
28bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  // Parse the header structure.
29bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (len < kBmpHeaderSize + 4) {
30bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return false;
31bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
32bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  GetShort();  // Signature.
33bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  GetInt();  // Size.
34bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  GetInt();  // Reserved.
35bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int offset = GetInt();
36bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  // Parse the info structure.
37bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int infoSize = GetInt();
38bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (infoSize != kBmpOS2InfoSize && infoSize < kBmpInfoSize) {
39bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return false;
40bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
41bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int cols = 0;
42bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int comp = 0;
43bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int colLen = 4;
44bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (infoSize >= kBmpInfoSize) {
45bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (len < kBmpHeaderSize + kBmpInfoSize) {
46bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      return false;
47bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
48bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    width_ = GetInt();
49bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    height_ = GetInt();
50bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    GetShort();  // Planes.
51bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    bpp_ = GetShort();
52bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    comp = GetInt();
53bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    GetInt();  // Size.
54bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    GetInt();  // XPPM.
55bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    GetInt();  // YPPM.
56bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    cols = GetInt();
57bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    GetInt();  // Important colours.
58bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  } else {
59bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (len < kBmpHeaderSize + kBmpOS2InfoSize) {
60bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      return false;
61bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
62bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    colLen = 3;
63bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    width_ = GetShort();
64bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    height_ = GetShort();
65bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    GetShort();  // Planes.
66bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    bpp_ = GetShort();
67bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
68bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (height_ < 0) {
69bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    height_ = -height_;
70bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    inverted_ = false;
71bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
72bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (width_ <= 0 || width_ > kMaxDim || height_ <= 0 || height_ > kMaxDim) {
73bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return false;
74bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
75bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (width_ * height_ > max_pixels) {
76bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return false;
77bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
78bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (cols < 0 || cols > 256) {
79bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return false;
80bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
81bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  // Allocate then read in the colour map.
82bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (cols == 0 && bpp_ <= 8) {
83bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    cols = 1 << bpp_;
84bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
85bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (bpp_ <= 8 || cols > 0) {
86bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint8* colBuf = new uint8[256 * 3];
87bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    memset(colBuf, '\0', 256 * 3);
88bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    colTab_.reset(colBuf);
89bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
90bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (cols > 0) {
91bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (pos_ + (cols * colLen) > len_) {
92bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      return false;
93bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
94bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    for (int i = 0; i < cols; ++i) {
95bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      int base = i * 3;
96bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      colTab_[base + 2] = GetByte();
97bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      colTab_[base + 1] = GetByte();
98bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      colTab_[base] = GetByte();
99bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      if (colLen == 4) {
100bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        GetByte();
101bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      }
102bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
103bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
104bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  // Read in the compression data if necessary.
105bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  redBits_ = 0x7c00;
106bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  greenBits_ = 0x03e0;
107bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  blueBits_ = 0x001f;
108bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  bool rle = false;
109bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (comp == 1 || comp == 2) {
110bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rle = true;
111bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  } else if (comp == 3) {
112bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (pos_ + 12 > len_) {
113bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      return false;
114bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
115bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    redBits_ = GetInt() & 0xffff;
116bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    greenBits_ = GetInt() & 0xffff;
117bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    blueBits_ = GetInt() & 0xffff;
118bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
119bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  redShiftRight_ = CalcShiftRight(redBits_);
120bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  greenShiftRight_ = CalcShiftRight(greenBits_);
121bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  blueShiftRight_ = CalcShiftRight(blueBits_);
122bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  redShiftLeft_ = CalcShiftLeft(redBits_);
123bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  greenShiftLeft_ = CalcShiftLeft(greenBits_);
124bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  blueShiftLeft_ = CalcShiftLeft(blueBits_);
125bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  rowPad_ = 0;
126bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  pixelPad_ = 0;
127bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int rowLen;
128bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (bpp_ == 32) {
129bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rowLen = width_ * 4;
130bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    pixelPad_ = 1;
131bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  } else if (bpp_ == 24) {
132bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rowLen = width_ * 3;
133bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  } else if (bpp_ == 16) {
134bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rowLen = width_ * 2;
135bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  } else if (bpp_ == 8) {
136bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rowLen = width_;
137bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  } else if (bpp_ == 4) {
138bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rowLen = width_ / 2;
139bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (width_ & 1) {
140bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      rowLen++;
141bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
142bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  } else if (bpp_ == 1) {
143bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rowLen = width_ / 8;
144bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (width_ & 7) {
145bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      rowLen++;
146bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
147bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  } else {
148bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return false;
149bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
150bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  // Round the rowLen up to a multiple of 4.
151bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (rowLen % 4 != 0) {
152bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rowPad_ = 4 - (rowLen % 4);
153bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    rowLen += rowPad_;
154bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
155bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
156bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (offset > 0 && offset > pos_ && offset < len_) {
157bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    pos_ = offset;
158bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
159bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  // Deliberately off-by-one; a load of BMPs seem to have their last byte
160bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  // missing.
161bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (!rle && (pos_ + (rowLen * height_) > len_ + 1)) {
162bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return false;
163bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
164bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
165bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  output_ = callback->SetSize(width_, height_);
166bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (NULL == output_) {
167bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return true;  // meaning we succeeded, but they want us to stop now
168bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
169bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
170bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (rle && (bpp_ == 4 || bpp_ == 8)) {
171bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    DoRLEDecode();
172bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  } else {
173bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    DoStandardDecode();
174bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
175bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  return true;
176bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
177bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
178bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid BmpDecoderHelper::DoRLEDecode() {
179bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  static const uint8 RLE_ESCAPE = 0;
180bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  static const uint8 RLE_EOL = 0;
181bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  static const uint8 RLE_EOF = 1;
182bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  static const uint8 RLE_DELTA = 2;
183bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int x = 0;
184bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int y = height_ - 1;
185bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  while (pos_ < len_ - 1) {
186bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint8 cmd = GetByte();
187bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (cmd != RLE_ESCAPE) {
188bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      uint8 pixels = GetByte();
189bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      int num = 0;
190bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      uint8 col = pixels;
191bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      while (cmd-- && x < width_) {
192bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (bpp_ == 4) {
193bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          if (num & 1) {
194bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            col = pixels & 0xf;
195bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          } else {
196bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            col = pixels >> 4;
197bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          }
198bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
199bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        PutPixel(x++, y, col);
200bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        num++;
201bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      }
202bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    } else {
203bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      cmd = GetByte();
204bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      if (cmd == RLE_EOF) {
205bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        return;
206bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      } else if (cmd == RLE_EOL) {
207bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        x = 0;
208bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        y--;
209bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (y < 0) {
210bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          return;
211bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
212bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      } else if (cmd == RLE_DELTA) {
213bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (pos_ < len_ - 1) {
214bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          uint8 dx = GetByte();
215bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          uint8 dy = GetByte();
216bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          x += dx;
217bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          if (x > width_) {
218bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            x = width_;
219bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          }
220bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          y -= dy;
221bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          if (y < 0) {
222bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            return;
223bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          }
224bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
225bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      } else {
226bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int num = 0;
227bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int bytesRead = 0;
228bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        uint8 val = 0;
229bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        while (cmd-- && pos_ < len_) {
230bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          if (bpp_ == 8 || !(num & 1)) {
231bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            val = GetByte();
232bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            bytesRead++;
233bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          }
234bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          uint8 col = val;
235bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          if (bpp_ == 4) {
236bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            if (num & 1) {
237bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com              col = col & 0xf;
238bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            } else {
239bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com              col >>= 4;
240bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            }
241bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          }
242bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          if (x < width_) {
243bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            PutPixel(x++, y, col);
244bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          }
245bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          num++;
246bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
247bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // All pixel runs must be an even number of bytes - skip a byte if we
248bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        // read an odd number.
249bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if ((bytesRead & 1) && pos_ < len_) {
250bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          GetByte();
251bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
252bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      }
253bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
254bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
255bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
256bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
257bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid BmpDecoderHelper::PutPixel(int x, int y, uint8 col) {
258bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  CHECK(x >= 0 && x < width_);
259bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  CHECK(y >= 0 && y < height_);
260bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (!inverted_) {
261bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    y = height_ - (y + 1);
262bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
263bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
264bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int base = ((y * width_) + x) * 3;
265bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int colBase = col * 3;
266bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  output_[base] = colTab_[colBase];
267bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  output_[base + 1] = colTab_[colBase + 1];
268bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  output_[base + 2] = colTab_[colBase + 2];
269bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
270bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
271bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comvoid BmpDecoderHelper::DoStandardDecode() {
272bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int row = 0;
273bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  uint8 currVal = 0;
274bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  for (int h = height_ - 1; h >= 0; h--, row++) {
275bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    int realH = h;
276bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    if (!inverted_) {
277bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      realH = height_ - (h + 1);
278bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
279bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    uint8* line = output_ + (3 * width_ * realH);
280bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    for (int w = 0; w < width_; w++) {
281bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      if (bpp_ >= 24) {
282bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        line[2] = GetByte();
283bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        line[1] = GetByte();
284bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        line[0] = GetByte();
285bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      } else if (bpp_ == 16) {
286bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        uint32 val = GetShort();
287bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        line[0] = ((val & redBits_) >> redShiftRight_) << redShiftLeft_;
288bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        line[1] = ((val & greenBits_) >> greenShiftRight_) << greenShiftLeft_;
289bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        line[2] = ((val & blueBits_) >> blueShiftRight_) << blueShiftLeft_;
290bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      } else if (bpp_ <= 8) {
291bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        uint8 col;
292bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        if (bpp_ == 8) {
293bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          col = GetByte();
294bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        } else if (bpp_ == 4) {
295bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          if ((w % 2) == 0) {
296bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            currVal = GetByte();
297bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            col = currVal >> 4;
298bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          } else {
299bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            col = currVal & 0xf;
300bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          }
301bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        } else {
302bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          if ((w % 8) == 0) {
303bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com            currVal = GetByte();
304bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          }
305bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          int bit = w & 7;
306bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com          col = ((currVal >> (7 - bit)) & 1);
307bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        }
308bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        int base = col * 3;
309bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        line[0] = colTab_[base];
310bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        line[1] = colTab_[base + 1];
311bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        line[2] = colTab_[base + 2];
312bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      }
313bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      line += 3;
314bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      for (int i = 0; i < pixelPad_; ++i) {
315bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com        GetByte();
316bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      }
317bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
318bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    for (int i = 0; i < rowPad_; ++i) {
319bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com      GetByte();
320bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    }
321bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
322bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
323bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
324bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comint BmpDecoderHelper::GetInt() {
325bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  uint8 b1 = GetByte();
326bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  uint8 b2 = GetByte();
327bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  uint8 b3 = GetByte();
328bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  uint8 b4 = GetByte();
329bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  return b1 | (b2 << 8) | (b3 << 16) | (b4 << 24);
330bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
331bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
332bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comint BmpDecoderHelper::GetShort() {
333bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  uint8 b1 = GetByte();
334bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  uint8 b2 = GetByte();
335bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  return b1 | (b2 << 8);
336bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
337bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
338bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comuint8 BmpDecoderHelper::GetByte() {
339bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  CHECK(pos_ >= 0 && pos_ <= len_);
340bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  // We deliberately allow this off-by-one access to cater for BMPs with their
341bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  // last byte missing.
342bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  if (pos_ == len_) {
343bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    return 0;
344bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
345bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  return data_[pos_++];
346bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
347bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
348bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comint BmpDecoderHelper::CalcShiftRight(uint32 mask) {
349bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int ret = 0;
350bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  while (mask != 0 && !(mask & 1)) {
351bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    mask >>= 1;
352bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    ret++;
353bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
354bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  return ret;
355bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
356bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
357bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.comint BmpDecoderHelper::CalcShiftLeft(uint32 mask) {
358bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  int ret = 0;
359bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  while (mask != 0 && !(mask & 1)) {
360bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    mask >>= 1;
361bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
362bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  while (mask != 0 && !(mask & 0x80)) {
363bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    mask <<= 1;
364bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com    ret++;
365bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  }
366bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com  return ret;
367bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}
368bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com
369bcd4d5ab12df062500a4df90ec90d0f2d764931reed@android.com}  // namespace image_codec
370