<commit_before>/*
 * Copyright 2014 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Author: <NAME>

#include "pagespeed/kernel/image/gif_square.h"

#include <math.h>

#include <algorithm>
#include <cstddef>
#include <cstdio>
#include <vector>

#include "base/logging.h"
#include "pagespeed/kernel/base/message_handler.h"
#include "pagespeed/kernel/base/string.h"

using net_instaweb::MessageHandler;

namespace pagespeed {
namespace image_compression {

const GifColorType GifSquare::kGifWhite = {0xFF, 0xFF, 0xFF};
const GifColorType GifSquare::kGifBlack = {0x00, 0x00, 0x00};
const GifColorType GifSquare::kGifGray = {0xF0, 0xF0, 0xF0};
const GifColorType GifSquare::kGifRed = {0xFF, 0x00, 0x00};
const GifColorType GifSquare::kGifGreen = {0x00, 0xFF, 0x00};
const GifColorType GifSquare::kGifBlue = {0x00, 0x00, 0xFF};
const GifColorType GifSquare::kGifYellow = {0xFF, 0xFF, 0x00};

#define LOBYTE(x)       ((x) & 0xff)
#define HIBYTE(x)       (((x) >> 8) & 0xff)

#if GIFLIB_MAJOR < 5
namespace {
// Later versions of gif_lib use a Gif prefix for these functions.

// In particular, the google3 version has the prefix but the    // [google3]
// open-source pagespeed version does not.                      // [google3]
ColorMapObject* (*GifMakeMapObject)(int, const GifColorType*) =
    MakeMapObject;
void (*GifFreeMapObject)(ColorMapObject*) = FreeMapObject;

// Borrowed from later versions of giflib.
typedef struct GraphicsControlBlock {
  int DisposalMode;
#define DISPOSAL_UNSPECIFIED      0       /* No disposal specified. */
#define DISPOSE_DO_NOT            1       /* Leave image in place */
#define DISPOSE_BACKGROUND        2       /* Set area too background color */
#define DISPOSE_PREVIOUS          3       /* Restore to previous content */
  bool UserInputFlag;      /* User confirmation required before disposal */
  int DelayTime;           /* pre-display delay in 0.01sec units */
  int TransparentColor;    /* Palette index for transparency, -1 if none */
#define NO_TRANSPARENT_COLOR    -1
} GraphicsControlBlock;

size_t EGifGCBToExtension(const GraphicsControlBlock *GCB,
                          GifByteType *GifExtension) {
  GifExtension[0] = 0;
  GifExtension[0] |= (GCB->TransparentColor == NO_TRANSPARENT_COLOR) ?
      0x00 : 0x01;
  GifExtension[0] |= GCB->UserInputFlag ? 0x02 : 0x00;
  GifExtension[0] |= ((GCB->DisposalMode & 0x07) << 2);
  GifExtension[1] = LOBYTE(GCB->DelayTime);
  GifExtension[2] = HIBYTE(GCB->DelayTime);
  GifExtension[3] = static_cast<char>(GCB->TransparentColor);
  return 4;
}
}  // namespace
#endif

GifSquare::GifSquare(bool manual_gcb,
                     MessageHandler* handler) :
    manual_gcb_(manual_gcb),
    handler_(handler),
    success_(true), gif_file_(NULL),
    num_images_(0), closed_(false) {
}

GifSquare::~GifSquare() {
  Close();
  for_each(colormaps_.begin(), colormaps_.end(), GifFreeMapObject);
  colormaps_.clear();
}

bool GifSquare::Open(const GoogleString& filename) {
#if GIFLIB_MAJOR >= 5
  int status = 0;
  gif_file_ = EGifOpenFileName(filename.c_str(), false,
                               &status);
  if (status != 0) {
    return Fail("EGifOpenFileName", GifErrorString(status));
  }
  return true;
#else
  gif_file_ = EGifOpenFileName(filename.c_str(), false);
  return Log(gif_file_ != NULL, "EGifOpenFileName");
#endif
}

bool GifSquare::PrepareScreen(bool gif89, int width, int height,
                              const GifColorType* color_map, int num_colors,
                              int bg_color_idx, int loop) {
  if (!CanProceed()) {
    return false;
  }

  if (num_colors & (num_colors-1)) {
    return Fail("num_colors", "not a power of 2");
  }
  int color_resolution = static_cast<int>(round(log2(num_colors))) - 1;

  colormaps_.clear();
  colormaps_.push_back(GifMakeMapObject(num_colors, color_map));

#if GIFLIB_MAJOR >= 5
  EGifSetGifVersion(gif_file_, gif89);
#else
  EGifSetGifVersion("89a");
#endif

  if (!Log(EGifPutScreenDesc(gif_file_, width, height,
                             color_resolution, bg_color_idx, colormaps_[0]),
           "EGifPutScreenDesc")) {
    return false;
  }

  if (loop >= 0) {
    // The loop count is encoded as a series of three bytes: a literal
    // '\x01' and then the count in lo-hi order. Cf.
    // http://shortn/_19L2jvGJc9
    static const char* const kAppBlockContentTemplate = "\x01%c%c";
    static const int kLen = 4;
    CHECK(kLen - 1 + 2 == strlen(kAppBlockContentTemplate));
    char app_block_content[kLen];
    snprintf(app_block_content, kLen, kAppBlockContentTemplate,<commit_msg>Change by vchudnov: Fix msan failure triggered by gif_square.<commit_after>/*
 * Copyright 2014 Google Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

// Author: <NAME>

#include "pagespeed/kernel/image/gif_square.h"

#include <math.h>

#include <algorithm>
#include <cstddef>
#include <cstdio>
#include <vector>

#include "base/logging.h"
#include "pagespeed/kernel/base/message_handler.h"
#include "pagespeed/kernel/base/string.h"

using net_instaweb::MessageHandler;

namespace pagespeed {
namespace image_compression {

const GifColorType GifSquare::kGifWhite = {0xFF, 0xFF, 0xFF};
const GifColorType GifSquare::kGifBlack = {0x00, 0x00, 0x00};
const GifColorType GifSquare::kGifGray = {0xF0, 0xF0, 0xF0};
const GifColorType GifSquare::kGifRed = {0xFF, 0x00, 0x00};
const GifColorType GifSquare::kGifGreen = {0x00, 0xFF, 0x00};
const GifColorType GifSquare::kGifBlue = {0x00, 0x00, 0xFF};
const GifColorType GifSquare::kGifYellow = {0xFF, 0xFF, 0x00};

#define LOBYTE(x)       ((x) & 0xff)
#define HIBYTE(x)       (((x) >> 8) & 0xff)

#if GIFLIB_MAJOR < 5
namespace {
// Later versions of gif_lib use a Gif prefix for these functions.

// In particular, the google3 version has the prefix but the    // [google3]
// open-source pagespeed version does not.                      // [google3]
ColorMapObject* (*GifMakeMapObject)(int, const GifColorType*) =
    MakeMapObject;
void (*GifFreeMapObject)(ColorMapObject*) = FreeMapObject;

// Borrowed from later versions of giflib.
typedef struct GraphicsControlBlock {
  int DisposalMode;
#define DISPOSAL_UNSPECIFIED      0       /* No disposal specified. */
#define DISPOSE_DO_NOT            1       /* Leave image in place */
#define DISPOSE_BACKGROUND        2       /* Set area too background color */
#define DISPOSE_PREVIOUS          3       /* Restore to previous content */
  bool UserInputFlag;      /* User confirmation required before disposal */
  int DelayTime;           /* pre-display delay in 0.01sec units */
  int TransparentColor;    /* Palette index for transparency, -1 if none */
#define NO_TRANSPARENT_COLOR    -1
} GraphicsControlBlock;

size_t EGifGCBToExtension(const GraphicsControlBlock *GCB,
                          GifByteType *GifExtension) {
  GifExtension[0] = 0;
  GifExtension[0] |= (GCB->TransparentColor == NO_TRANSPARENT_COLOR) ?
      0x00 : 0x01;
  GifExtension[0] |= GCB->UserInputFlag ? 0x02 : 0x00;
  GifExtension[0] |= ((GCB->DisposalMode & 0x07) << 2);
  GifExtension[1] = LOBYTE(GCB->DelayTime);
  GifExtension[2] = HIBYTE(GCB->DelayTime);
  GifExtension[3] = static_cast<char>(GCB->TransparentColor);
  return 4;
}
}  // namespace
#endif

GifSquare::GifSquare(bool manual_gcb,
                     MessageHandler* handler) :
    manual_gcb_(manual_gcb),
    handler_(handler),
    success_(true), gif_file_(NULL),
    num_images_(0), closed_(false) {
}

GifSquare::~GifSquare() {
  Close();
  for_each(colormaps_.begin(), colormaps_.end(), GifFreeMapObject);
  colormaps_.clear();
}

bool GifSquare::Open(const GoogleString& filename) {
#if GIFLIB_MAJOR >= 5
  int status = 0;
  gif_file_ = EGifOpenFileName(filename.c_str(), false,
                               &status);
  if (status != 0) {
    return Fail("EGifOpenFileName", GifErrorString(status));
  }
  return true;
#else
  gif_file_ = EGifOpenFileName(filename.c_str(), false);
  return Log(gif_file_ != NULL, "EGifOpenFileName");
#endif
}

bool GifSquare::PrepareScreen(bool gif89, int width, int height,
                              const GifColorType* color_map, int num_colors,
                              int bg_color_idx, int loop) {
  if (!CanProceed()) {
    return false;
  }

  if (num_colors & (num_colors-1)) {
    return Fail("num_colors", "not a power of 2");
  }
  int color_resolution = static_cast<int>(round(log2(num_colors))) - 1;

  colormaps_.clear();
  colormaps_.push_back(GifMakeMapObject(num_colors, color_map));

#if GIFLIB_MAJOR >= 5
  colormaps_[0]->SortFlag = 0;  // not initialized above
  EGifSetGifVersion(gif_file_, gif89);
#else
  EGifSetGifVersion("89a");
#endif

  if (!Log(EGifPutScreenDesc(gif_file_, width, height,
                             color_resolution, bg_color_idx, colormaps_[0]),
           "EGifPutScreenDesc")) {
    return false;
  }

  if (loop >= 0) {
    // The loop count is encoded as a series of three bytes: a literal
    // '\x01' and then the count in lo-hi order. Cf.
    // http://shortn/_19L2jvGJc9
    static const char* const kAppBlockContentTemplate = "\x01%c%c";
    static const int kLen = 4;
    CHECK(kLen - 1 + 2 == strlen(kAppBlockContentTemplate));
    char app_block_content[kLen];
    snprintf(app_block_content, kLen, kAppBlockContentTemplate,
{'fraction_non_alphanumeric': 0.11452974861690769, 'fraction_numerical': 0.023682422595360575, 'mean_word_length': 3.5332160140783104, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 42, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5903960', 'n_tokens_mistral': 3620, 'n_tokens_neox': 3442, 'n_words': 902}