"Fossies" - the Fresh Open Source Software Archive

Member "darktable-3.6.1/src/external/rawspeed/src/librawspeed/decompressors/AbstractLJpegDecompressor.cpp" (9 Sep 2021, 8557 Bytes) of package /linux/misc/darktable-3.6.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "AbstractLJpegDecompressor.cpp" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.2.1_vs_3.4.0.

    1 /*
    2     RawSpeed - RAW file decoder.
    3 
    4     Copyright (C) 2009-2014 Klaus Post
    5     Copyright (C) 2017 Axel Waggershauser
    6     Copyright (C) 2017 Roman Lebedev
    7 
    8     This library is free software; you can redistribute it and/or
    9     modify it under the terms of the GNU Lesser General Public
   10     License as published by the Free Software Foundation; either
   11     version 2 of the License, or (at your option) any later version.
   12 
   13     This library is distributed in the hope that it will be useful,
   14     but WITHOUT ANY WARRANTY; without even the implied warranty of
   15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   16     Lesser General Public License for more details.
   17 
   18     You should have received a copy of the GNU Lesser General Public
   19     License along with this library; if not, write to the Free Software
   20     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
   21 */
   22 
   23 #include "decompressors/AbstractLJpegDecompressor.h"
   24 #include "common/Point.h"                       // for iPoint2D
   25 #include "decoders/RawDecoderException.h"       // for ThrowRDE
   26 #include "decompressors/AbstractHuffmanTable.h" // for AbstractHuffmanTable
   27 #include "decompressors/HuffmanTable.h"         // for HuffmanTable, Huffma...
   28 #include "io/ByteStream.h"                      // for ByteStream
   29 #include "io/Endianness.h"                      // for Endianness, Endianne...
   30 #include <array>                                // for array
   31 #include <cassert>                              // for assert
   32 #include <memory>                               // for unique_ptr, make_unique
   33 #include <utility>                              // for move
   34 #include <vector>                               // for vector
   35 
   36 namespace rawspeed {
   37 
   38 AbstractLJpegDecompressor::AbstractLJpegDecompressor(ByteStream bs,
   39                                                      const RawImage& img)
   40     : input(std::move(bs)), mRaw(img) {
   41   input.setByteOrder(Endianness::big);
   42 
   43   if (mRaw->dim.x == 0 || mRaw->dim.y == 0)
   44     ThrowRDE("Image has zero size");
   45 
   46 #ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
   47   // Yeah, sure, here it would be just dumb to leave this for production :)
   48   if (mRaw->dim.x > 8896 || mRaw->dim.y > 6304) {
   49     ThrowRDE("Unexpected image dimensions found: (%u; %u)", mRaw->dim.x,
   50              mRaw->dim.y);
   51   }
   52 #endif
   53 }
   54 
   55 void AbstractLJpegDecompressor::decode() {
   56   if (getNextMarker(false) != M_SOI)
   57     ThrowRDE("Image did not start with SOI. Probably not an LJPEG");
   58 
   59   struct FoundMarkers {
   60     bool DHT = false;
   61     bool SOF = false;
   62     bool SOS = false;
   63   } FoundMarkers;
   64 
   65   JpegMarker m;
   66   do {
   67     m = getNextMarker(true);
   68 
   69     if (m == M_EOI)
   70       break;
   71 
   72     ByteStream data(input.getStream(input.peekU16()));
   73     data.skipBytes(2); // headerLength
   74 
   75     switch (m) {
   76     case M_DHT:
   77       if (FoundMarkers.SOS)
   78         ThrowRDE("Found second DHT marker after SOS");
   79       // there can be more than one DHT markers.
   80       // FIXME: do we really want to reparse and use the last one?
   81       parseDHT(data);
   82       FoundMarkers.DHT = true;
   83       break;
   84     case M_SOF3:
   85       if (FoundMarkers.SOS)
   86         ThrowRDE("Found second SOF marker after SOS");
   87       if (FoundMarkers.SOF)
   88         ThrowRDE("Found second SOF marker");
   89       // SOF is not required to be after DHT
   90       parseSOF(data, &frame);
   91       FoundMarkers.SOF = true;
   92       break;
   93     case M_SOS:
   94       if (FoundMarkers.SOS)
   95         ThrowRDE("Found second SOS marker");
   96       if (!FoundMarkers.DHT)
   97         ThrowRDE("Did not find DHT marker before SOS.");
   98       if (!FoundMarkers.SOF)
   99         ThrowRDE("Did not find SOF marker before SOS.");
  100       parseSOS(data);
  101       FoundMarkers.SOS = true;
  102       break;
  103     case M_DQT:
  104       ThrowRDE("Not a valid RAW file.");
  105     default: // Just let it skip to next marker
  106       break;
  107     }
  108   } while (m != M_EOI);
  109 
  110   if (!FoundMarkers.SOS)
  111     ThrowRDE("Did not find SOS marker.");
  112 }
  113 
  114 void AbstractLJpegDecompressor::parseSOF(ByteStream sofInput, SOFInfo* sof) {
  115   sof->prec = sofInput.getByte();
  116   sof->h = sofInput.getU16();
  117   sof->w = sofInput.getU16();
  118   sof->cps = sofInput.getByte();
  119 
  120   if (sof->prec < 2 || sof->prec > 16)
  121     ThrowRDE("Invalid precision (%u).", sof->prec);
  122 
  123   if (sof->h == 0 || sof->w == 0)
  124     ThrowRDE("Frame width or height set to zero");
  125 
  126   if (sof->cps > 4 || sof->cps < 1)
  127     ThrowRDE("Only from 1 to 4 components are supported.");
  128 
  129   if (sof->cps < mRaw->getCpp()) {
  130     ThrowRDE("Component count should be no less than sample count (%u vs %u).",
  131              sof->cps, mRaw->getCpp());
  132   }
  133 
  134   if (sof->cps > static_cast<uint32_t>(mRaw->dim.x)) {
  135     ThrowRDE("Component count should be no greater than row length (%u vs %u).",
  136              sof->cps, mRaw->dim.x);
  137   }
  138 
  139   if (sofInput.getRemainSize() != 3 * sof->cps)
  140     ThrowRDE("Header size mismatch.");
  141 
  142   for (uint32_t i = 0; i < sof->cps; i++) {
  143     sof->compInfo[i].componentId = sofInput.getByte();
  144 
  145     uint32_t subs = sofInput.getByte();
  146     frame.compInfo[i].superV = subs & 0xf;
  147     frame.compInfo[i].superH = subs >> 4;
  148 
  149     if (frame.compInfo[i].superV < 1 || frame.compInfo[i].superV > 4)
  150       ThrowRDE("Horizontal sampling factor is invalid.");
  151 
  152     if (frame.compInfo[i].superH < 1 || frame.compInfo[i].superH > 4)
  153       ThrowRDE("Horizontal sampling factor is invalid.");
  154 
  155     uint32_t Tq = sofInput.getByte();
  156     if (Tq != 0)
  157       ThrowRDE("Quantized components not supported.");
  158   }
  159 
  160   if (static_cast<int>(sof->compInfo[0].superH) !=
  161           mRaw->metadata.subsampling.x ||
  162       static_cast<int>(sof->compInfo[0].superV) != mRaw->metadata.subsampling.y)
  163     ThrowRDE("LJpeg's subsampling does not match image's subsampling.");
  164 
  165   sof->initialized = true;
  166 }
  167 
  168 void AbstractLJpegDecompressor::parseSOS(ByteStream sos) {
  169   assert(frame.initialized);
  170 
  171   if (sos.getRemainSize() != 1 + 2 * frame.cps + 3)
  172     ThrowRDE("Invalid SOS header length.");
  173 
  174   uint32_t soscps = sos.getByte();
  175   if (frame.cps != soscps)
  176     ThrowRDE("Component number mismatch.");
  177 
  178   for (uint32_t i = 0; i < frame.cps; i++) {
  179     uint32_t cs = sos.getByte();
  180     uint32_t td = sos.getByte() >> 4;
  181 
  182     if (td >= huff.size() || !huff[td])
  183       ThrowRDE("Invalid Huffman table selection.");
  184 
  185     int ciIndex = -1;
  186     for (uint32_t j = 0; j < frame.cps; ++j) {
  187       if (frame.compInfo[j].componentId == cs)
  188         ciIndex = j;
  189     }
  190 
  191     if (ciIndex == -1)
  192       ThrowRDE("Invalid Component Selector");
  193 
  194     frame.compInfo[ciIndex].dcTblNo = td;
  195   }
  196 
  197   // Get predictor, see table H.1 from the JPEG spec
  198   predictorMode = sos.getByte();
  199   // The spec says predictoreMode is in [0..7], but Hasselblad uses '8'.
  200   if (predictorMode > 8)
  201     ThrowRDE("Invalid predictor mode.");
  202 
  203   // Se + Ah Not used in LJPEG
  204   if (sos.getByte() != 0)
  205     ThrowRDE("Se/Ah not zero.");
  206 
  207   Pt = sos.getByte(); // Point Transform
  208   if (Pt > 15)
  209     ThrowRDE("Invalid Point transform.");
  210 
  211   decodeScan();
  212 }
  213 
  214 void AbstractLJpegDecompressor::parseDHT(ByteStream dht) {
  215   while (dht.getRemainSize() > 0) {
  216     uint32_t b = dht.getByte();
  217 
  218     uint32_t htClass = b >> 4;
  219     if (htClass != 0)
  220       ThrowRDE("Unsupported Table class.");
  221 
  222     uint32_t htIndex = b & 0xf;
  223     if (htIndex >= huff.size())
  224       ThrowRDE("Invalid huffman table destination id.");
  225 
  226     if (huff[htIndex] != nullptr)
  227       ThrowRDE("Duplicate table definition");
  228 
  229     // copy 16 bytes from input stream to number of codes per length table
  230     uint32_t nCodes = ht_.setNCodesPerLength(dht.getBuffer(16));
  231 
  232     // spec says 16 different codes is max but Hasselblad violates that -> 17
  233     if (nCodes > 17)
  234       ThrowRDE("Invalid DHT table.");
  235 
  236     // copy nCodes bytes from input stream to code values table
  237     ht_.setCodeValues(dht.getBuffer(nCodes));
  238 
  239     // see if we already have a HuffmanTable with the same codes
  240     for (const auto& i : huffmanTableStore)
  241       if (*i == ht_)
  242         huff[htIndex] = i.get();
  243 
  244     if (!huff[htIndex]) {
  245       // setup new ht_ and put it into the store
  246       auto dHT = std::make_unique<HuffmanTable>(ht_);
  247       dHT->setup(fullDecodeHT, fixDng16Bug);
  248       huff[htIndex] = dHT.get();
  249       huffmanTableStore.emplace_back(std::move(dHT));
  250     }
  251   }
  252 }
  253 
  254 JpegMarker AbstractLJpegDecompressor::getNextMarker(bool allowskip) {
  255   uint8_t c0;
  256   uint8_t c1 = input.getByte();
  257   do {
  258     c0 = c1;
  259     c1 = input.getByte();
  260   } while (allowskip && !(c0 == 0xFF && c1 != 0 && c1 != 0xFF));
  261 
  262   if (!(c0 == 0xFF && c1 != 0 && c1 != 0xFF))
  263     ThrowRDE("(Noskip) Expected marker not found. Probably corrupt file.");
  264 
  265   return static_cast<JpegMarker>(c1);
  266 }
  267 
  268 } // namespace rawspeed