<commit_before>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 <NAME>
    Copyright (C) 2015-2017 <NAME>
    Copyright (C) 2017 <NAME>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decoders/Cr2Decoder.h"
#include "common/Point.h"                      // for iPoint2D
#include "common/RawspeedException.h"          // for RawspeedException
#include "decoders/RawDecoderException.h"      // for ThrowRDE
#include "decompressors/Cr2Decompressor.h"     // for Cr2Decompressor, Cr2S...
#include "interpolators/Cr2sRawInterpolator.h" // for Cr2sRawInterpolator
#include "io/Buffer.h"                         // for Buffer, DataBuffer
#include "io/ByteStream.h"                     // for ByteStream
#include "io/Endianness.h"                     // for Endianness, Endiannes...
#include "metadata/Camera.h"                   // for Hints
#include "metadata/ColorFilterArray.h"         // for CFA_GREEN, CFA_BLUE
#include "parsers/TiffParserException.h"       // for ThrowTPE
#include "tiff/TiffEntry.h"                    // for TiffEntry, TIFF_SHORT
#include "tiff/TiffTag.h"                      // for TiffTag, CANONCOLORDATA
#include <array>                               // for array
#include <cassert>                             // for assert
#include <cstdint>                             // for uint32_t, uint16_t
#include <memory>                              // for unique_ptr, allocator...
#include <string>                              // for operator==, string
#include <vector>                              // for vector
// IWYU pragma: no_include <ext/alloc_traits.h>

using std::string;

namespace rawspeed {

bool Cr2Decoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
                                      const Buffer* file) {
  const auto id = rootIFD->getID();
  const std::string& make = id.make;
  const std::string& model = id.model;

  // FIXME: magic

  return make == "Canon" ||
         (make == "Kodak" && (model == "DCS520C" || model == "DCS560C"));
}

RawImage Cr2Decoder::decodeOldFormat() {
  uint32_t offset = 0;
  if (mRootIFD->getEntryRecursive(CANON_RAW_DATA_OFFSET))
    offset = mRootIFD->getEntryRecursive(CANON_RAW_DATA_OFFSET)->getU32();
  else {
    // D2000 is oh so special...
    const auto* ifd = mRootIFD->getIFDWithTag(CFAPATTERN);
    if (! ifd->hasEntry(STRIPOFFSETS))
      ThrowRDE("Couldn't find offset");

    offset = ifd->getEntry(STRIPOFFSETS)->getU32();
  }

  ByteStream b(DataBuffer(mFile->getSubView(offset), Endianness::big));
  b.skipBytes(41);
  int height = b.getU16();
  int width = b.getU16();

  // some old models (1D/1DS/D2000C) encode two lines as one
  // see: FIX_CANON_HALF_HEIGHT_DOUBLE_WIDTH
  if (width > 2*height) {
    height *= 2;
    width /= 2;
  }
  width *= 2; // components

  mRaw->dim = {width, height};

  const ByteStream bs(
      DataBuffer(mFile->getSubView(offset), Endianness::little));

  Cr2Decompressor l(bs, mRaw);
  mRaw->createData();

  Cr2Slicing slicing(/*numSlices=*/1, /*sliceWidth=don't care*/ 0,
                     /*lastSliceWidth=*/width);
  l.decode(slicing);

  // deal with D2000 GrayResponseCurve
  TiffEntry* curve = mRootIFD->getEntryRecursive(static_cast<TiffTag>(0x123));
  if (curve && curve->type == TIFF_SHORT && curve->count == 4096) {
    auto table = curve->getU16Array(curve->count);
    RawImageCurveGuard curveHandler(&mRaw, table, uncorrectedRawValues);

    // Apply table
    if (!uncorrectedRawValues)
      mRaw->sixteenBitLookup();
  }

  return mRaw;
}

// for technical details about Cr2 mRAW/sRAW, see http://lclevy.free.fr/cr2/

RawImage Cr2Decoder::decodeNewFormat() {
  TiffEntry* sensorInfoE = mRootIFD->getEntryRecursive(CANON_SENSOR_INFO);
  if (!sensorInfoE)
    ThrowTPE("failed to get SensorInfo from MakerNote");

  assert(sensorInfoE != nullptr);

  if (isSubSampled() != (getSubSampling() != iPoint2D{1, 1}))
    ThrowTPE("Subsampling sanity check failed");

  mRaw->dim = {sensorInfoE->getU16(1), sensorInfoE->getU16(2)};
  mRaw->setCpp(1);
  mRaw->isCFA = !isSubSampled();

  if (isSubSampled()) {
    iPoint2D& subSampling = mRaw->metadata.subsampling;
    subSampling = getSubSampling();
    if (!(subSampling.x > 1 || subSampling.y > 1))
      ThrowRDE("RAW is expected to be subsampled, but it's not");

    assert(mRaw->dim.x % subSampling.x == 0);
    mRaw->dim.x /= subSampling.x;

    assert(mRaw->dim.y % subSampling.y == 0);
    mRaw->dim.y /= subSampling.y;

    mRaw->dim.x *= 2 + subSampling.x * subSampling.y;
  }

  TiffIFD* raw = mRootIFD->getSubIFDs()[3].get();

  Cr2Slicing slicing;
  // there are four cases:
  // * there is a tag with three components,
  //   $ last two components are non-zero: all fine then.
  //   $ first two components are zero, last component is non-zero
  //     we let Cr2Decompressor guess it (it'll throw if fails)
  //   $ else the image is considered corrupt.
  // * there is a tag with not three components, the image is considered
  // corrupt. $ there is no tag, we let Cr2Decompressor guess it (it'll throw if
  // fails)
  TiffEntry* cr2SliceEntry = raw->getEntryRecursive(CANONCR2SLICE);
  if (cr2SliceEntry) {
    if (cr2SliceEntry->count != 3) {
      ThrowRDE("Found RawImageSegmentation tag with %d elements, should be 3.",
               cr2SliceEntry->count);
    }<commit_msg>Cr2Decoder::decodeNewFormat(): actually ensure that subsampled image dims are multiples of subsampling factor<commit_after>/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009-2014 <NAME>
    Copyright (C) 2015-2017 <NAME>
    Copyright (C) 2017 <NAME>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/

#include "decoders/Cr2Decoder.h"
#include "common/Point.h"                      // for iPoint2D
#include "common/RawspeedException.h"          // for RawspeedException
#include "decoders/RawDecoderException.h"      // for ThrowRDE
#include "decompressors/Cr2Decompressor.h"     // for Cr2Decompressor, Cr2S...
#include "interpolators/Cr2sRawInterpolator.h" // for Cr2sRawInterpolator
#include "io/Buffer.h"                         // for Buffer, DataBuffer
#include "io/ByteStream.h"                     // for ByteStream
#include "io/Endianness.h"                     // for Endianness, Endiannes...
#include "metadata/Camera.h"                   // for Hints
#include "metadata/ColorFilterArray.h"         // for CFA_GREEN, CFA_BLUE
#include "parsers/TiffParserException.h"       // for ThrowTPE
#include "tiff/TiffEntry.h"                    // for TiffEntry, TIFF_SHORT
#include "tiff/TiffTag.h"                      // for TiffTag, CANONCOLORDATA
#include <array>                               // for array
#include <cassert>                             // for assert
#include <cstdint>                             // for uint32_t, uint16_t
#include <memory>                              // for unique_ptr, allocator...
#include <string>                              // for operator==, string
#include <vector>                              // for vector
// IWYU pragma: no_include <ext/alloc_traits.h>

using std::string;

namespace rawspeed {

bool Cr2Decoder::isAppropriateDecoder(const TiffRootIFD* rootIFD,
                                      const Buffer* file) {
  const auto id = rootIFD->getID();
  const std::string& make = id.make;
  const std::string& model = id.model;

  // FIXME: magic

  return make == "Canon" ||
         (make == "Kodak" && (model == "DCS520C" || model == "DCS560C"));
}

RawImage Cr2Decoder::decodeOldFormat() {
  uint32_t offset = 0;
  if (mRootIFD->getEntryRecursive(CANON_RAW_DATA_OFFSET))
    offset = mRootIFD->getEntryRecursive(CANON_RAW_DATA_OFFSET)->getU32();
  else {
    // D2000 is oh so special...
    const auto* ifd = mRootIFD->getIFDWithTag(CFAPATTERN);
    if (! ifd->hasEntry(STRIPOFFSETS))
      ThrowRDE("Couldn't find offset");

    offset = ifd->getEntry(STRIPOFFSETS)->getU32();
  }

  ByteStream b(DataBuffer(mFile->getSubView(offset), Endianness::big));
  b.skipBytes(41);
  int height = b.getU16();
  int width = b.getU16();

  // some old models (1D/1DS/D2000C) encode two lines as one
  // see: FIX_CANON_HALF_HEIGHT_DOUBLE_WIDTH
  if (width > 2*height) {
    height *= 2;
    width /= 2;
  }
  width *= 2; // components

  mRaw->dim = {width, height};

  const ByteStream bs(
      DataBuffer(mFile->getSubView(offset), Endianness::little));

  Cr2Decompressor l(bs, mRaw);
  mRaw->createData();

  Cr2Slicing slicing(/*numSlices=*/1, /*sliceWidth=don't care*/ 0,
                     /*lastSliceWidth=*/width);
  l.decode(slicing);

  // deal with D2000 GrayResponseCurve
  TiffEntry* curve = mRootIFD->getEntryRecursive(static_cast<TiffTag>(0x123));
  if (curve && curve->type == TIFF_SHORT && curve->count == 4096) {
    auto table = curve->getU16Array(curve->count);
    RawImageCurveGuard curveHandler(&mRaw, table, uncorrectedRawValues);

    // Apply table
    if (!uncorrectedRawValues)
      mRaw->sixteenBitLookup();
  }

  return mRaw;
}

// for technical details about Cr2 mRAW/sRAW, see http://lclevy.free.fr/cr2/

RawImage Cr2Decoder::decodeNewFormat() {
  TiffEntry* sensorInfoE = mRootIFD->getEntryRecursive(CANON_SENSOR_INFO);
  if (!sensorInfoE)
    ThrowTPE("failed to get SensorInfo from MakerNote");

  assert(sensorInfoE != nullptr);

  if (isSubSampled() != (getSubSampling() != iPoint2D{1, 1}))
    ThrowTPE("Subsampling sanity check failed");

  mRaw->dim = {sensorInfoE->getU16(1), sensorInfoE->getU16(2)};
  mRaw->setCpp(1);
  mRaw->isCFA = !isSubSampled();

  if (isSubSampled()) {
    iPoint2D& subSampling = mRaw->metadata.subsampling;
    subSampling = getSubSampling();
    if (!(subSampling.x > 1 || subSampling.y > 1))
      ThrowRDE("RAW is expected to be subsampled, but it's not");

    if (mRaw->dim.x % subSampling.x != 0)
      ThrowRDE("Raw width is not a multiple of horizontal subsampling factor");
    mRaw->dim.x /= subSampling.x;

    if (mRaw->dim.y % subSampling.y != 0)
      ThrowRDE("Raw height is not a multiple of vertical subsampling factor");
    mRaw->dim.y /= subSampling.y;

    mRaw->dim.x *= 2 + subSampling.x * subSampling.y;
  }

  TiffIFD* raw = mRootIFD->getSubIFDs()[3].get();

  Cr2Slicing slicing;
  // there are four cases:
  // * there is a tag with three components,
  //   $ last two components are non-zero: all fine then.
  //   $ first two components are zero, last component is non-zero
  //     we let Cr2Decompressor guess it (it'll throw if fails)
  //   $ else the image is considered corrupt.
  // * there is a tag with not three components, the image is considered
  // corrupt. $ there is no tag, we let Cr2Decompressor guess it (it'll throw if
  // fails)
  TiffEntry* cr2SliceEntry = raw->getEntryRecursive(CANONCR2SLICE);
  if (cr2SliceEntry) {
    if (cr2SliceEntry->count != 3) {
      ThrowRDE("Found RawImageSegmentation tag with %d elements, should be 3.",
               cr2SliceEntry->count);
    }
{'fraction_non_alphanumeric': 0.11837930192824017, 'fraction_numerical': 0.020584167276869254, 'mean_word_length': 2.779827798277983, 'pattern_counts': {'":': 0, '<': 25, '<?xml version=': 0, '>': 99, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 14, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3505918', 'n_tokens_mistral': 4149, 'n_tokens_neox': 3893, 'n_words': 1085}