diff --git a/rtengine/canon_cr3_decoder.cc b/rtengine/canon_cr3_decoder.cc index 359243ed5..6274154cb 100644 --- a/rtengine/canon_cr3_decoder.cc +++ b/rtengine/canon_cr3_decoder.cc @@ -1,5 +1,25 @@ -/* -*- C++ -*- - * +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2019 RawTherapee development team + * + * RawTherapee is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * RawTherapee 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with RawTherapee. If not, see . + */ + +// Code adapted from ART +/* + * * This file is part of ART. * * ART is free software: you can redistribute it and/or modify @@ -16,15 +36,6 @@ * along with ART. If not, see . */ -#include -#include "dcraw.h" -#ifdef __GNUC__ // silence warning -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wsign-compare" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#endif - // Code adapted from libraw /* -*- C++ -*- * Copyright 2019 LibRaw LLC (info@libraw.org) @@ -40,570 +51,589 @@ */ +#include +#include +#include +#include +#include + +#include "dcraw.h" + +#include "rt_math.h" void DCraw::parse_canon_cr3() { - int err; - unsigned long long szAtomList; + strncpy(make, "Canon", sizeof(make)); + + unsigned long long szAtomList = ifp->size; short nesting = -1; - short nTrack = -1; - short TrackType; char AtomNameStack[128]; - strcpy(make, "Canon"); + unsigned short nTrack = 0; + short TrackType; - szAtomList = ifp->size; - err = parseCR3(0ULL, szAtomList, nesting, AtomNameStack, nTrack, TrackType); - if ((err == 0 || err == -14) && - nTrack >= 0) // no error, or too deep nesting + const int err = parseCR3(0, szAtomList, nesting, AtomNameStack, nTrack, TrackType); + + if (err == 0 || err == -14) { // no error, or too deep nesting selectCRXTrack(nTrack); + } } -#define LIBRAW_CRXTRACKS_MAXCOUNT RT_canon_CR3_data.CRXTRACKS_MAXCOUNT - -void DCraw::selectCRXTrack(short maxTrack) +void DCraw::selectCRXTrack(unsigned short maxTrack) { - if (maxTrack < 0) - return; - INT64 bitcounts[LIBRAW_CRXTRACKS_MAXCOUNT], maxbitcount = 0; - uint32_t maxjpegbytes = 0; - memset(bitcounts, 0, sizeof(bitcounts)); - for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++) - { - CanonCR3Data::crx_data_header_t *d = &RT_canon_CR3_data.crx_header[i]; - if (d->MediaType == 1) // RAW - { - bitcounts[i] = INT64(d->nBits) * INT64(d->f_width) * INT64(d->f_height); - if (bitcounts[i] > maxbitcount) - maxbitcount = bitcounts[i]; - } - else if (d->MediaType == 2) // JPEG - { - if (d->MediaSize > maxjpegbytes) - { - maxjpegbytes = d->MediaSize; - thumb_offset = d->MediaOffset; - thumb_length = d->MediaSize; - } - } - } - if (maxbitcount < 8) - return; - int framei = -1, framecnt = 0; - for (int i = 0; i <= maxTrack && i < LIBRAW_CRXTRACKS_MAXCOUNT; i++) - { - if (bitcounts[i] == maxbitcount) - { - if (framecnt <= shot_select) - framei = i; - framecnt++; - } - } - is_raw = framecnt; - if (framei >= 0 && framei < LIBRAW_CRXTRACKS_MAXCOUNT) - { - CanonCR3Data::crx_data_header_t *d = - &RT_canon_CR3_data.crx_header[framei]; - data_offset = d->MediaOffset; - //data_size = d->MediaSize; - raw_width = d->f_width; - raw_height = d->f_height; - load_raw = &DCraw::crxLoadRaw; - switch (d->cfaLayout) - { - case 0: - filters = 0x94949494; - break; - case 1: - filters = 0x61616161; - break; - case 2: - filters = 0x49494949; - break; - case 3: - filters = 0x16161616; - break; - } + std::int64_t bitcounts[CanonCR3Data::CRXTRACKS_MAXCOUNT] = {}; + std::int64_t maxbitcount = 0; + std::uint32_t maxjpegbytes = 0; - RT_canon_CR3_data.crx_track_selected = framei; + for (unsigned int i = 0; i <= maxTrack && i < RT_canon_CR3_data.CRXTRACKS_MAXCOUNT; ++i) { + CanonCR3Data::crx_data_header_t* const d = &RT_canon_CR3_data.crx_header[i]; - int tiff_idx = -1; - INT64 tpixels = 0; - for (int i = 0; i < tiff_nifds; i++) - if (INT64(tiff_ifd[i].height) * INT64(tiff_ifd[i].height) > tpixels) - { - tpixels = INT64(tiff_ifd[i].height) * INT64(tiff_ifd[i].height); - tiff_idx = i; - } - if (tiff_idx >= 0) - flip = tiff_ifd[tiff_idx].flip; - } -} + if (d->MediaType == 1) { // RAW + bitcounts[i] = std::int64_t(d->nBits) * std::int64_t(d->f_width) * std::int64_t(d->f_height); -#define FORC4 for (c=0; c < 4; c++) - -#define bad_hdr \ - (((order != 0x4d4d) && (order != 0x4949)) || (get2() != 0x002a) || \ - (get4() != 0x00000008)) -int DCraw::parseCR3(unsigned long long oAtomList, - unsigned long long szAtomList, short &nesting, - char *AtomNameStack, short &nTrack, short &TrackType) -{ - /* - Atom starts with 4 bytes for Atom size and 4 bytes containing Atom name - Atom size includes the length of the header and the size of all "contained" - Atoms if Atom size == 1, Atom has the extended size stored in 8 bytes located - after the Atom name if Atom size == 0, it is the last top-level Atom extending - to the end of the file Atom name is often a 4 symbol mnemonic, but can be a - 4-byte integer - */ - const char UIID_Canon[17] = - "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48"; - const char UIID_Preview[17] = - "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16"; - - /* - AtomType = 0 - unknown: "unk." - AtomType = 1 - container atom: "cont" - AtomType = 2 - leaf atom: "leaf" - AtomType = 3 - can be container, can be leaf: "both" - */ - const char sAtomeType[4][5] = {"unk.", "cont", "leaf", "both"}; - short AtomType; - static const struct - { - char AtomName[5]; - short AtomType; - } AtomNamesList[] = { - {"dinf", 1}, - {"edts", 1}, - {"fiin", 1}, - {"ipro", 1}, - {"iprp", 1}, - {"mdia", 1}, - {"meco", 1}, - {"mere", 1}, - {"mfra", 1}, - {"minf", 1}, - {"moof", 1}, - {"moov", 1}, - {"mvex", 1}, - {"paen", 1}, - {"schi", 1}, - {"sinf", 1}, - {"skip", 1}, - {"stbl", 1}, - {"stsd", 1}, - {"strk", 1}, - {"tapt", 1}, - {"traf", 1}, - {"trak", 1}, - - {"cdsc", 2}, - {"colr", 2}, - {"dimg", 2}, - // {"dref", 2}, - {"free", 2}, - {"frma", 2}, - {"ftyp", 2}, - {"hdlr", 2}, - {"hvcC", 2}, - {"iinf", 2}, - {"iloc", 2}, - {"infe", 2}, - {"ipco", 2}, - {"ipma", 2}, - {"iref", 2}, - {"irot", 2}, - {"ispe", 2}, - {"meta", 2}, - {"mvhd", 2}, - {"pitm", 2}, - {"pixi", 2}, - {"schm", 2}, - {"thmb", 2}, - {"tkhd", 2}, - {"url ", 2}, - {"urn ", 2}, - - {"CCTP", 1}, - {"CRAW", 1}, - - {"JPEG", 2}, - {"CDI1", 2}, - {"CMP1", 2}, - - {"CNCV", 2}, - {"CCDT", 2}, - {"CTBO", 2}, - {"CMT1", 2}, - {"CMT2", 2}, - {"CMT3", 2}, - {"CMT4", 2}, - {"THMB", 2}, - {"co64", 2}, - {"mdat", 2}, - {"mdhd", 2}, - {"nmhd", 2}, - {"stsc", 2}, - {"stsz", 2}, - {"stts", 2}, - {"vmhd", 2}, - - {"dref", 3}, - {"uuid", 3}, - }; - - const char sHandlerType[5][5] = {"unk.", "soun", "vide", "hint", "meta"}; - - int c, err = 0; - - ushort tL; // Atom length represented in 4 or 8 bytes - char nmAtom[5]; // Atom name - unsigned long long oAtom, szAtom; // Atom offset and Atom size - unsigned long long oAtomContent, - szAtomContent; // offset and size of Atom content - unsigned long long lHdr; - - char UIID[16]; - uchar CMP1[36]; - char HandlerType[5], MediaFormatID[5]; - unsigned ImageWidth, ImageHeight; - long relpos_inDir, relpos_inBox; - unsigned szItem, Tag, lTag; - ushort tItem; - - nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0'; - strcpy(HandlerType, sHandlerType[0]); - ImageWidth = ImageHeight = 0U; - oAtom = oAtomList; - nesting++; - if (nesting > 31) - return -14; // too deep nesting - short s_order = order; - - while ((oAtom + 8ULL) <= (oAtomList + szAtomList)) - { - lHdr = 0ULL; - err = 0; - order = 0x4d4d; - fseek(ifp, oAtom, SEEK_SET); - szAtom = get4(); - FORC4 nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp); - AtomNameStack[(nesting + 1) * 4] = '\0'; - tL = 4; - AtomType = 0; - - for (c = 0; c < sizeof AtomNamesList / sizeof *AtomNamesList; c++) - if (!strcmp(nmAtom, AtomNamesList[c].AtomName)) - { - AtomType = AtomNamesList[c].AtomType; - break; - } - - if (!AtomType) - { - err = 1; - } - - if (szAtom == 0ULL) - { - if (nesting != 0) - { - err = -2; - goto fin; - } - szAtom = szAtomList - oAtom; - oAtomContent = oAtom + 8ULL; - szAtomContent = szAtom - 8ULL; - } - else if (szAtom == 1ULL) - { - if ((oAtom + 16ULL) > (oAtomList + szAtomList)) - { - err = -3; - goto fin; - } - tL = 8; - szAtom = (((unsigned long long)get4()) << 32) | get4(); - oAtomContent = oAtom + 16ULL; - szAtomContent = szAtom - 16ULL; - } - else - { - oAtomContent = oAtom + 8ULL; - szAtomContent = szAtom - 8ULL; - } - - if (!strcmp(nmAtom, "trak")) - { - nTrack++; - TrackType = 0; - if (nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT) - break; - } - if (!strcmp(AtomNameStack, "moovuuid")) - { - lHdr = 16ULL; - fread(UIID, 1, lHdr, ifp); - if (!strncmp(UIID, UIID_Canon, lHdr)) - { - AtomType = 1; - } - else - fseek(ifp, -lHdr, SEEK_CUR); - } - else if (!strcmp(AtomNameStack, "moovuuidCCTP")) - { - lHdr = 12ULL; - } - else if (!strcmp(AtomNameStack, "moovuuidCMT1")) - { - short q_order = order; - order = get2(); - if ((tL != 4) || bad_hdr) - { - err = -4; - goto fin; - } - parse_tiff_ifd(oAtomContent); - order = q_order; - } - else if (!strcmp(AtomNameStack, "moovuuidCMT2")) - { - short q_order = order; - order = get2(); - if ((tL != 4) || bad_hdr) - { - err = -5; - goto fin; - } - parse_exif(oAtomContent); - order = q_order; - } - else if (!strcmp(AtomNameStack, "moovuuidCMT3")) - { - short q_order = order; - order = get2(); - if ((tL != 4) || bad_hdr) - { - err = -6; - goto fin; - } - fseek(ifp, -12L, SEEK_CUR); - parse_makernote(oAtomContent, 0); - order = q_order; - } - else if (!strcmp(AtomNameStack, "moovuuidCMT4")) - { - short q_order = order; - order = get2(); - if ((tL != 4) || bad_hdr) - { - err = -6; - goto fin; - } - INT64 off = ftell(ifp); - parse_gps(oAtomContent); - fseek(ifp, off, SEEK_SET); -// parse_gps_libraw(oAtomContent); - order = q_order; - } - else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr")) - { - fseek(ifp, 8L, SEEK_CUR); - FORC4 HandlerType[c] = fgetc(ifp); - for (c = 1; c < sizeof sHandlerType / sizeof *sHandlerType; c++) - if (!strcmp(HandlerType, sHandlerType[c])) - { - TrackType = c; - break; - } - } - else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd")) - { - if (szAtomContent >= 16) - { - fseek(ifp, 12L, SEEK_CUR); - lHdr = 8; - } - else - { - err = -7; - goto fin; - } - FORC4 MediaFormatID[c] = fgetc(ifp); - if ((TrackType == 2) && (!strcmp(MediaFormatID, "CRAW"))) - { - if (szAtomContent >= 44) - fseek(ifp, 24L, SEEK_CUR); - else - { - err = -8; - goto fin; - } - } - else - { - AtomType = 2; // only continue for CRAW - lHdr = 0; - } -#define current_track RT_canon_CR3_data.crx_header[nTrack] - - ImageWidth = get2(); - ImageHeight = get2(); - } - else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW")) - { - lHdr = 82; - } - else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1")) - { - if (szAtomContent >= 40) - fread(CMP1, 1, 36, ifp); - else - { - err = -7; - goto fin; - } - if (!crxParseImageHeader(CMP1, nTrack)) - current_track.MediaType = 1; - } - else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG")) - { - current_track.MediaType = 2; - } - else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz")) - { - if (szAtomContent == 12) - fseek(ifp, 4L, SEEK_CUR); - else if (szAtomContent == 16) - fseek(ifp, 12L, SEEK_CUR); - else - { - err = -9; - goto fin; - } - current_track.MediaSize = get4(); - } - else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64")) - { - if (szAtomContent == 16) - fseek(ifp, 8L, SEEK_CUR); - else - { - err = -10; - goto fin; - } - current_track.MediaOffset = (((unsigned long long)get4()) << 32) | get4(); - } - - if (current_track.MediaSize && current_track.MediaOffset && - ((oAtom + szAtom) >= (oAtomList + szAtomList)) && - !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20)) - { - if ((TrackType == 4) && (!strcmp(MediaFormatID, "CTMD"))) - { - order = 0x4949; - relpos_inDir = 0L; - while (relpos_inDir + 6 < current_track.MediaSize) - { - fseek(ifp, current_track.MediaOffset + relpos_inDir, SEEK_SET); - szItem = get4(); - tItem = get2(); - if ((relpos_inDir + szItem) > current_track.MediaSize) - { - err = -11; - goto fin; - } - if ((tItem == 7) || (tItem == 8) || (tItem == 9)) - { - relpos_inBox = relpos_inDir + 12L; - while (relpos_inBox + 8 < relpos_inDir + szItem) - { - fseek(ifp, current_track.MediaOffset + relpos_inBox, SEEK_SET); - lTag = get4(); - Tag = get4(); - if (lTag < 8) - { - err = -12; - goto fin; - } - else if ((relpos_inBox + lTag) > (relpos_inDir + szItem)) - { - err = -11; - goto fin; - } - if ((Tag == 0x927c) && ((tItem == 7) || (tItem == 8))) - { - fseek(ifp, current_track.MediaOffset + relpos_inBox + 8L, - SEEK_SET); - short q_order = order; - order = get2(); - if (bad_hdr) - { - err = -13; - goto fin; - } - fseek(ifp, -8L, SEEK_CUR); - RT_canon_CR3_data.CR3_CTMDtag = 1; - parse_makernote(current_track.MediaOffset + relpos_inBox + 8, - 0); - RT_canon_CR3_data.CR3_CTMDtag = 0; - order = q_order; - } - relpos_inBox += lTag; + if (bitcounts[i] > maxbitcount) { + maxbitcount = bitcounts[i]; + } + } else if (d->MediaType == 2) { // JPEG + if (d->MediaSize > maxjpegbytes) { + maxjpegbytes = d->MediaSize; + thumb_offset = d->MediaOffset; + thumb_length = d->MediaSize; } - } - relpos_inDir += szItem; } - order = 0x4d4d; - } } -#undef current_track - if (AtomType == 1) - { - err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting, - AtomNameStack, nTrack, TrackType); - if (err) - goto fin; + + if (maxbitcount < 8) { + return; + } + + bool has_framei = false; + unsigned int framei = 0; + unsigned int framecnt = 0; + + for (unsigned int i = 0; i <= maxTrack && i < RT_canon_CR3_data.CRXTRACKS_MAXCOUNT; ++i) { + if (bitcounts[i] == maxbitcount) { + if (framecnt <= shot_select) { + has_framei = true; + framei = i; + } + + framecnt++; + } + } + + is_raw = framecnt; + + if (has_framei) { + CanonCR3Data::crx_data_header_t* const d = &RT_canon_CR3_data.crx_header[framei]; + data_offset = d->MediaOffset; + // data_size = d->MediaSize; + raw_width = d->f_width; + raw_height = d->f_height; + load_raw = &DCraw::crxLoadRaw; + + switch (d->cfaLayout) { + case 0: { + filters = 0x94949494; + break; + } + + case 1: { + filters = 0x61616161; + break; + } + + case 2: { + filters = 0x49494949; + break; + } + + case 3: { + filters = 0x16161616; + break; + } + } + + RT_canon_CR3_data.crx_track_selected = framei; + + int tiff_idx = -1; + std::int64_t tpixels = 0; + + for (unsigned int i = 0; i < tiff_nifds; ++i) { + if (std::int64_t(tiff_ifd[i].height) * std::int64_t(tiff_ifd[i].height) > tpixels) { + tpixels = std::int64_t(tiff_ifd[i].height) * std::int64_t(tiff_ifd[i].height); + tiff_idx = i; + } + } + + if (tiff_idx >= 0) { + flip = tiff_ifd[tiff_idx].flip; + } + } +} + +int DCraw::parseCR3( + unsigned long long oAtomList, + unsigned long long szAtomList, + short& nesting, + char* AtomNameStack, + unsigned short& nTrack, + short& TrackType +) +{ + /* + Atom starts with 4 bytes for Atom size and 4 bytes containing Atom name + Atom size includes the length of the header and the size of all "contained" + Atoms if Atom size == 1, Atom has the extended size stored in 8 bytes located + after the Atom name if Atom size == 0, it is the last top-level Atom extending + to the end of the file Atom name is often a 4 symbol mnemonic, but can be a + 4-byte integer + */ + const char UIID_Canon[17] = + "\x85\xc0\xb6\x87\x82\x0f\x11\xe0\x81\x11\xf4\xce\x46\x2b\x6a\x48"; +// const char UIID_Preview[17] = +// "\xea\xf4\x2b\x5e\x1c\x98\x4b\x88\xb9\xfb\xb7\xdc\x40\x6e\x4d\x16"; + + /* + AtomType = 0 - unknown: "unk." + AtomType = 1 - container atom: "cont" + AtomType = 2 - leaf atom: "leaf" + AtomType = 3 - can be container, can be leaf: "both" + */ +// const char sAtomeType[4][5] = {"unk.", "cont", "leaf", "both"}; + short AtomType; + static const struct { + char AtomName[5]; + short AtomType; + } AtomNamesList[] = { + {"dinf", 1}, + {"edts", 1}, + {"fiin", 1}, + {"ipro", 1}, + {"iprp", 1}, + {"mdia", 1}, + {"meco", 1}, + {"mere", 1}, + {"mfra", 1}, + {"minf", 1}, + {"moof", 1}, + {"moov", 1}, + {"mvex", 1}, + {"paen", 1}, + {"schi", 1}, + {"sinf", 1}, + {"skip", 1}, + {"stbl", 1}, + {"stsd", 1}, + {"strk", 1}, + {"tapt", 1}, + {"traf", 1}, + {"trak", 1}, + + {"cdsc", 2}, + {"colr", 2}, + {"dimg", 2}, + // {"dref", 2}, + {"free", 2}, + {"frma", 2}, + {"ftyp", 2}, + {"hdlr", 2}, + {"hvcC", 2}, + {"iinf", 2}, + {"iloc", 2}, + {"infe", 2}, + {"ipco", 2}, + {"ipma", 2}, + {"iref", 2}, + {"irot", 2}, + {"ispe", 2}, + {"meta", 2}, + {"mvhd", 2}, + {"pitm", 2}, + {"pixi", 2}, + {"schm", 2}, + {"thmb", 2}, + {"tkhd", 2}, + {"url ", 2}, + {"urn ", 2}, + + {"CCTP", 1}, + {"CRAW", 1}, + + {"JPEG", 2}, + {"CDI1", 2}, + {"CMP1", 2}, + + {"CNCV", 2}, + {"CCDT", 2}, + {"CTBO", 2}, + {"CMT1", 2}, + {"CMT2", 2}, + {"CMT3", 2}, + {"CMT4", 2}, + {"THMB", 2}, + {"co64", 2}, + {"mdat", 2}, + {"mdhd", 2}, + {"nmhd", 2}, + {"stsc", 2}, + {"stsz", 2}, + {"stts", 2}, + {"vmhd", 2}, + + {"dref", 3}, + {"uuid", 3}, + }; + + const char sHandlerType[5][5] = { + "unk.", + "soun", + "vide", + "hint", + "meta" + }; + + int err = 0; + + unsigned short tL; // Atom length represented in 4 or 8 bytes + char nmAtom[5]; // Atom name + unsigned long long oAtom; + unsigned long long szAtom; // Atom offset and Atom size + unsigned long long oAtomContent; + unsigned long long szAtomContent; // offset and size of Atom content + unsigned long long lHdr; + + char UIID[16]; + uchar CMP1[36]; + char HandlerType[5]; + char MediaFormatID[5]; +// unsigned int ImageWidth, ImageHeight; + unsigned long relpos_inDir; + unsigned long relpos_inBox; + unsigned int szItem; + unsigned int Tag; + unsigned int lTag; + unsigned short tItem; + + nmAtom[0] = MediaFormatID[0] = nmAtom[4] = MediaFormatID[4] = '\0'; + strncpy(HandlerType, sHandlerType[0], sizeof(HandlerType)); +// ImageWidth = ImageHeight = 0U; + oAtom = oAtomList; + ++nesting; + + if (nesting > 31) { + return -14; // too deep nesting + } + + short s_order = order; + + const auto is_bad_header = + [this]() -> bool + { + return + ( + order != 0x4D4D + && order != 0x4949 + ) + || get2() != 0x002A + || get4() != 0x00000008; + }; + + while ((oAtom + 8) <= (oAtomList + szAtomList)) { + lHdr = 0U; + err = 0; + order = 0x4D4D; + fseek(ifp, oAtom, SEEK_SET); + szAtom = get4(); + for (unsigned int c = 0; c < 4; ++c) { + nmAtom[c] = AtomNameStack[nesting * 4 + c] = fgetc(ifp); + } + AtomNameStack[(nesting + 1) * 4] = '\0'; + tL = 4; + AtomType = 0; + + for (const auto& atom : AtomNamesList) { + if (!strcmp(nmAtom, atom.AtomName)) { + AtomType = atom.AtomType; + break; + } + } + + if (!AtomType) { + err = 1; + } + + if (szAtom == 0) { + if (nesting != 0) { + err = -2; + goto fin; + } + + szAtom = szAtomList - oAtom; + oAtomContent = oAtom + 8; + szAtomContent = szAtom - 8; + } else if (szAtom == 1) { + if ((oAtom + 16) > (oAtomList + szAtomList)) { + err = -3; + goto fin; + } + + tL = 8; + szAtom = (static_cast(get4()) << 32) | get4(); + oAtomContent = oAtom + 16; + szAtomContent = szAtom - 16; + } else { + oAtomContent = oAtom + 8; + szAtomContent = szAtom - 8; + } + + if (!strcmp(nmAtom, "trak")) { + nTrack++; + TrackType = 0; + + if (nTrack >= RT_canon_CR3_data.CRXTRACKS_MAXCOUNT) { + break; + } + } + + if (!strcmp(AtomNameStack, "moovuuid")) { + lHdr = 16; + fread(UIID, 1, lHdr, ifp); + + if (!strncmp(UIID, UIID_Canon, lHdr)) { + AtomType = 1; + } else { + fseek(ifp, -lHdr, SEEK_CUR); + } + } else if (!strcmp(AtomNameStack, "moovuuidCCTP")) { + lHdr = 12; + } else if (!strcmp(AtomNameStack, "moovuuidCMT1")) { + const short q_order = order; + order = get2(); + + if (tL != 4 || is_bad_header()) { + err = -4; + goto fin; + } + + parse_tiff_ifd(oAtomContent); + order = q_order; + } else if (!strcmp(AtomNameStack, "moovuuidCMT2")) { + const short q_order = order; + order = get2(); + + if (tL != 4 || is_bad_header()) { + err = -5; + goto fin; + } + + parse_exif(oAtomContent); + order = q_order; + } else if (!strcmp(AtomNameStack, "moovuuidCMT3")) { + const short q_order = order; + order = get2(); + + if (tL != 4 || is_bad_header()) { + err = -6; + goto fin; + } + + fseek(ifp, -12L, SEEK_CUR); + parse_makernote(oAtomContent, 0); + order = q_order; + } else if (!strcmp(AtomNameStack, "moovuuidCMT4")) { + const short q_order = order; + order = get2(); + + if (tL != 4 || is_bad_header()) { + err = -6; + goto fin; + } + + const long off = ftell(ifp); + parse_gps(oAtomContent); + fseek(ifp, off, SEEK_SET); +// parse_gps_libraw(oAtomContent); + order = q_order; + } else if (!strcmp(AtomNameStack, "moovtrakmdiahdlr")) { + fseek(ifp, 8, SEEK_CUR); + for (unsigned int c = 0; c < 4; ++c) { + HandlerType[c] = fgetc(ifp); + } + + for (unsigned int c = 1; c < sizeof(sHandlerType) / sizeof(*sHandlerType); ++c) { + if (!strcmp(HandlerType, sHandlerType[c])) { + TrackType = c; + break; + } + } + } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsd")) { + if (szAtomContent >= 16) { + fseek(ifp, 12, SEEK_CUR); + lHdr = 8; + } else { + err = -7; + goto fin; + } + + for (unsigned int c = 0; c < 4; ++c) { + MediaFormatID[c] = fgetc(ifp); + } + + if (TrackType == 2 && !strcmp(MediaFormatID, "CRAW")) { + if (szAtomContent >= 44) { + fseek(ifp, 24, SEEK_CUR); + } else { + err = -8; + goto fin; + } + } else { + AtomType = 2; // only continue for CRAW + lHdr = 0; + } + + /*ImageWidth = */ get2(); + /*ImageHeight = */ get2(); + } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAW")) { + lHdr = 82; + } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWCMP1")) { + if (szAtomContent >= 40) { + fread(CMP1, 1, 36, ifp); + } else { + err = -7; + goto fin; + } + + if (crxParseImageHeader(CMP1, nTrack)) { + RT_canon_CR3_data.crx_header[nTrack].MediaType = 1; + } + } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsdCRAWJPEG")) { + RT_canon_CR3_data.crx_header[nTrack].MediaType = 2; + } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblstsz")) { + if (szAtomContent == 12) { + fseek(ifp, 4, SEEK_CUR); + } else if (szAtomContent == 16) { + fseek(ifp, 12, SEEK_CUR); + } else { + err = -9; + goto fin; + } + + RT_canon_CR3_data.crx_header[nTrack].MediaSize = get4(); + } else if (!strcmp(AtomNameStack, "moovtrakmdiaminfstblco64")) { + if (szAtomContent == 16) { + fseek(ifp, 8, SEEK_CUR); + } else { + err = -10; + goto fin; + } + + RT_canon_CR3_data.crx_header[nTrack].MediaOffset = (static_cast(get4()) << 32) | get4(); + } + + if ( + RT_canon_CR3_data.crx_header[nTrack].MediaSize + && RT_canon_CR3_data.crx_header[nTrack].MediaOffset + && oAtom + szAtom >= oAtomList + szAtomList + && !strncmp(AtomNameStack, "moovtrakmdiaminfstbl", 20) + ) { + if (TrackType == 4 && !strcmp(MediaFormatID, "CTMD")) { + order = 0x4949; + relpos_inDir = 0; + + while (relpos_inDir + 6 < RT_canon_CR3_data.crx_header[nTrack].MediaSize) { + fseek(ifp, RT_canon_CR3_data.crx_header[nTrack].MediaOffset + relpos_inDir, SEEK_SET); + szItem = get4(); + tItem = get2(); + + if ((relpos_inDir + szItem) > RT_canon_CR3_data.crx_header[nTrack].MediaSize) { + err = -11; + goto fin; + } + + if ( + tItem == 7 + || tItem == 8 + || tItem == 9 + ) { + relpos_inBox = relpos_inDir + 12; + + while (relpos_inBox + 8 < relpos_inDir + szItem) { + fseek(ifp, RT_canon_CR3_data.crx_header[nTrack].MediaOffset + relpos_inBox, SEEK_SET); + lTag = get4(); + Tag = get4(); + + if (lTag < 8) { + err = -12; + goto fin; + } else if (relpos_inBox + lTag > relpos_inDir + szItem) { + err = -11; + goto fin; + } + + if ( + Tag == 0x927C + && ( + tItem == 7 + || tItem == 8 + ) + ) { + fseek(ifp, RT_canon_CR3_data.crx_header[nTrack].MediaOffset + relpos_inBox + 8, SEEK_SET); + const short q_order = order; + order = get2(); + + if (is_bad_header()) { + err = -13; + goto fin; + } + + fseek(ifp, -8, SEEK_CUR); + RT_canon_CR3_data.CR3_CTMDtag = 1; + parse_makernote(RT_canon_CR3_data.crx_header[nTrack].MediaOffset + relpos_inBox + 8, 0); + RT_canon_CR3_data.CR3_CTMDtag = 0; + order = q_order; + } + + relpos_inBox += lTag; + } + } + + relpos_inDir += szItem; + } + + order = 0x4D4D; + } + } + + if (AtomType == 1) { + err = parseCR3(oAtomContent + lHdr, szAtomContent - lHdr, nesting, AtomNameStack, nTrack, TrackType); + + if (err) { + goto fin; + } + } + + oAtom += szAtom; } - oAtom += szAtom; - } fin: - nesting--; - if (nesting >= 0) - AtomNameStack[nesting * 4] = '\0'; - order = s_order; - return err; + --nesting; + + if (nesting >= 0) { + AtomNameStack[nesting * 4] = '\0'; + } + + order = s_order; + return err; } -#undef bad_hdr +// ----------------------------------------------------------------------------- -//----------------------------------------------------------------------------- - -#ifdef _abs -#undef _abs -#undef _min -#undef _constrain -#endif -#define _abs(x) (((x) ^ ((int32_t)(x) >> 31)) - ((int32_t)(x) >> 31)) -#define _min(a, b) ((a) < (b) ? (a) : (b)) -#define _constrain(x, l, u) ((x) < (l) ? (l) : ((x) > (u) ? (u) : (x))) - -#if defined(__clang__) || defined(__GNUG__) -#define libraw_inline inline __attribute__((always_inline)) -#elif defined(_MSC_VER) && _MSC_VER > 1400 -#define libraw_inline __forceinline -#else -#define libraw_inline inline -#endif - -namespace { - -static unsigned sgetn (int n, unsigned char *s) +namespace { - unsigned result = 0; + +unsigned int sgetn(int n, unsigned char* s) +{ + unsigned int result = 0; while (n-- > 0) { result = (result << 8) | (*s++); @@ -613,143 +643,147 @@ static unsigned sgetn (int n, unsigned char *s) } // this should be divisible by 4 -#define CRX_BUF_SIZE 0x10000 -#if !defined(_WIN32) || (defined (__GNUC__) && !defined(__INTRINSIC_SPECIAL__BitScanReverse)) +constexpr std::uint64_t CRX_BUF_SIZE = 0x10000; + +#if !defined (_WIN32) || (defined (__GNUC__) && !defined (__INTRINSIC_SPECIAL__BitScanReverse)) /* __INTRINSIC_SPECIAL__BitScanReverse found in MinGW32-W64 v7.30 headers, may be there is a better solution? */ -typedef uint32_t DWORD; -typedef uint8_t byte; -libraw_inline void _BitScanReverse(DWORD *Index, unsigned long Mask) +inline void _BitScanReverse(std::uint32_t* Index, unsigned long Mask) { - *Index = sizeof(unsigned long) * 8 - 1 - __builtin_clzl(Mask); + *Index = sizeof(unsigned long) * 8 - 1 - __builtin_clzl(Mask); +} +std::uint32_t _byteswap_ulong(std::uint32_t x) +{ +#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + return x; +#else + return __builtin_bswap32(x); +#endif } -#define _byteswap_ulong(x) __builtin_bswap32(x) #endif - -#define LIBRAW_EXCEPTION_IO_EOF std::exception() - struct LibRaw_abstract_datastream { - IMFILE *ifp; - - void lock() {} - void unlock() {} - void seek(int p, int how) { fseek(ifp, p, how); } + IMFILE* ifp; + + void lock() + { + } + void unlock() + { + } + void seek(long p, int how) + { + fseek(ifp, p, how); + } int read(void* dst, int es, int count) - { return fread(dst, es, count, ifp); } + { + return fread(dst, es, count, ifp); + } }; -struct CrxBitstream -{ - uint8_t mdatBuf[CRX_BUF_SIZE]; - uint64_t mdatSize; - uint64_t curBufOffset; - uint32_t curPos; - uint32_t curBufSize; - uint32_t bitData; - int32_t bitsLeft; - LibRaw_abstract_datastream *input; +struct CrxBitstream { + std::uint8_t mdatBuf[CRX_BUF_SIZE]; + std::uint64_t mdatSize; + std::uint64_t curBufOffset; + std::uint32_t curPos; + std::uint32_t curBufSize; + std::uint32_t bitData; + std::int32_t bitsLeft; + LibRaw_abstract_datastream* input; }; -struct CrxBandParam -{ - CrxBitstream bitStream; - int16_t subbandWidth; - int16_t subbandHeight; - int32_t roundedBitsMask; - int32_t roundedBits; - int16_t curLine; - int32_t *lineBuf0; - int32_t *lineBuf1; - int32_t *lineBuf2; - int32_t sParam; - int32_t kParam; - int32_t *paramData; - int32_t *nonProgrData; - int8_t supportsPartial; +struct CrxBandParam { + CrxBitstream bitStream; + std::int16_t subbandWidth; + std::int16_t subbandHeight; + std::int32_t roundedBitsMask; + std::int32_t roundedBits; + std::int16_t curLine; + std::int32_t* lineBuf0; + std::int32_t* lineBuf1; + std::int32_t* lineBuf2; + std::int32_t sParam; + std::int32_t kParam; + std::int32_t* paramData; + std::int32_t* nonProgrData; + bool supportsPartial; }; -struct CrxWaveletTransform -{ - int32_t *subband0Buf; - int32_t *subband1Buf; - int32_t *subband2Buf; - int32_t *subband3Buf; - int32_t *lineBuf[8]; - int16_t curLine; - int16_t curH; - int8_t fltTapH; - int16_t height; - int16_t width; +struct CrxWaveletTransform { + std::int32_t* subband0Buf; + std::int32_t* subband1Buf; + std::int32_t* subband2Buf; + std::int32_t* subband3Buf; + std::int32_t* lineBuf[8]; + std::int16_t curLine; + std::int16_t curH; + std::int8_t fltTapH; + std::int16_t height; + std::int16_t width; }; -struct CrxSubband -{ - CrxBandParam *bandParam; - uint64_t mdatOffset; - uint8_t *bandBuf; - int32_t bandSize; - uint64_t dataSize; - int8_t supportsPartial; - int32_t quantValue; - uint16_t width; - uint16_t height; - int32_t paramK; - int64_t dataOffset; +struct CrxSubband { + CrxBandParam* bandParam; + std::uint64_t mdatOffset; + std::uint8_t* bandBuf; + std::int32_t bandSize; + std::uint64_t dataSize; + bool supportsPartial; + std::int32_t quantValue; + std::uint16_t width; + std::uint16_t height; + std::int32_t paramK; + std::int64_t dataOffset; }; -struct CrxPlaneComp -{ - byte *compBuf; - CrxSubband *subBands; - CrxWaveletTransform *waveletTransform; - int8_t compNumber; - int64_t dataOffset; - int32_t compSize; - int8_t supportsPartial; - int32_t roundedBitsMask; - int8_t tileFlag; +struct CrxPlaneComp { + std::uint8_t* compBuf; + CrxSubband* subBands; + CrxWaveletTransform* waveletTransform; + std::int8_t compNumber; + std::int64_t dataOffset; + std::int32_t compSize; + bool supportsPartial; + std::int32_t roundedBitsMask; + std::int8_t tileFlag; }; -struct CrxTile -{ - CrxPlaneComp *comps; - int8_t tileFlag; - int8_t tileNumber; - int64_t dataOffset; - int32_t tileSize; - uint16_t width; - uint16_t height; +struct CrxTile { + CrxPlaneComp* comps; + std::int8_t tileFlag; + std::int8_t tileNumber; + std::int64_t dataOffset; + std::int32_t tileSize; + std::uint16_t width; + std::uint16_t height; }; -struct CrxImage -{ - uint8_t nPlanes; - uint16_t planeWidth; - uint16_t planeHeight; - uint8_t samplePrecision; - uint8_t subbandCount; - uint8_t levels; - uint8_t nBits; - uint8_t encType; - uint8_t tileCols; - uint8_t tileRows; - CrxTile *tiles; - uint64_t mdatOffset; - uint64_t mdatSize; - int16_t *outBufs[4]; // one per plane - int16_t *planeBuf; - LibRaw_abstract_datastream *input; +struct CrxImage { + std::uint8_t nPlanes; + std::uint16_t planeWidth; + std::uint16_t planeHeight; + std::uint8_t samplePrecision; + std::uint8_t subbandCount; + std::uint8_t levels; + std::uint8_t nBits; + std::uint8_t encType; + std::uint8_t tileCols; + std::uint8_t tileRows; + CrxTile* tiles; + std::uint64_t mdatOffset; + std::uint64_t mdatSize; + std::int16_t* outBufs[4]; // one per plane + std::int16_t* planeBuf; + LibRaw_abstract_datastream* input; }; -enum TileFlags -{ - E_HAS_TILES_ON_THE_RIGHT = 1, - E_HAS_TILES_ON_THE_LEFT = 2, - E_HAS_TILES_ON_THE_BOTTOM = 4, - E_HAS_TILES_ON_THE_TOP = 8 +enum TileFlags { + E_HAS_TILES_ON_THE_RIGHT = 1, + E_HAS_TILES_ON_THE_LEFT = 2, + E_HAS_TILES_ON_THE_BOTTOM = 4, + E_HAS_TILES_ON_THE_TOP = 8 }; -int32_t exCoefNumTbl[0x120] = { +const std::int32_t exCoefNumTbl[0x120] = { // level 1 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, @@ -766,2351 +800,2442 @@ int32_t exCoefNumTbl[0x120] = { 1, 1, 7, 7, 1, 1, 3, 3, 1, 1, 1, 1, 1, 0, 7, 6, 1, 0, 3, 2, 1, 0, 1, 0, 1, 2, 10, 10, 2, 2, 5, 4, 2, 1, 2, 1, 1, 1, 10, 9, 1, 2, 4, 4, 2, 1, 2, 1, 1, 1, 9, 9, 1, 2, 4, 4, 2, 1, 2, 1, 1, 0, 9, 8, 1, 1, 4, 3, 1, 1, 1, 1, 1, 2, - 8, 8, 2, 1, 4, 3, 1, 1, 1, 1, 1, 1, 8, 7, 1, 1, 3, 3, 1, 1, 1, 1}; + 8, 8, 2, 1, 4, 3, 1, 1, 1, 1, 1, 1, 8, 7, 1, 1, 3, 3, 1, 1, 1, 1 +}; -uint32_t JS[32] = {1, 1, 1, 1, 2, 2, 2, 2, - 4, 4, 4, 4, 8, 8, 8, 8, - 0x10, 0x10, 0x20, 0x20, 0x40, 0x40, 0x80, 0x80, - 0x100, 0x200, 0x400, 0x800, 0x1000, 0x2000, 0x4000, 0x8000}; +const std::uint32_t JS[32] = { + 0x0001, 0x0001, 0x0001, 0x0001, 0x0002, 0x0002, 0x0002, 0x0002, + 0x0004, 0x0004, 0x0004, 0x0004, 0x0008, 0x0008, 0x0008, 0x0008, + 0x0010, 0x0010, 0x0020, 0x0020, 0x0040, 0x0040, 0x0080, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000, 0x8000 +}; -uint32_t J[32] = {0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, - 2, 3, 3, 3, 3, 4, 4, 5, 5, 6, 6, - 7, 7, 8, 9, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F}; +const std::uint32_t J[32] = { + 0x0, 0x0, 0x0, 0x0, 0x1, 0x1, 0x1, 0x1, 0x2, 0x2, 0x2, + 0x2, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x5, 0x5, 0x6, 0x6, + 0x7, 0x7, 0x8, 0x9, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF +}; -static inline void crxFillBuffer(CrxBitstream *bitStrm) +inline void crxFillBuffer(CrxBitstream* bitStrm) { - if (bitStrm->curPos >= bitStrm->curBufSize && bitStrm->mdatSize) - { - bitStrm->curPos = 0; - bitStrm->curBufOffset += bitStrm->curBufSize; + if (bitStrm->curPos >= bitStrm->curBufSize && bitStrm->mdatSize) { + bitStrm->curPos = 0; + bitStrm->curBufOffset += bitStrm->curBufSize; #ifdef _OPENMP -#pragma omp critical + #pragma omp critical #endif - { + { #ifndef _OPENMP - bitStrm->input->lock(); + bitStrm->input->lock(); #endif - bitStrm->input->seek(bitStrm->curBufOffset, SEEK_SET); - bitStrm->curBufSize = bitStrm->input->read( - bitStrm->mdatBuf, 1, _min(bitStrm->mdatSize, CRX_BUF_SIZE)); + bitStrm->input->seek(bitStrm->curBufOffset, SEEK_SET); + bitStrm->curBufSize = bitStrm->input->read(bitStrm->mdatBuf, 1, std::min(bitStrm->mdatSize, CRX_BUF_SIZE)); #ifndef _OPENMP - bitStrm->input->unlock(); + bitStrm->input->unlock(); #endif - if (bitStrm->curBufSize < 1) // nothing read - throw LIBRAW_EXCEPTION_IO_EOF; - bitStrm->mdatSize -= bitStrm->curBufSize; - } - } -} -libraw_inline int crxBitstreamGetZeros(CrxBitstream *bitStrm) -{ - uint32_t bitData = bitStrm->bitData; - uint32_t nonZeroBit = 0; - uint64_t nextData = 0; - int32_t result = 0; - - if (bitStrm->bitData) - { - _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)bitStrm->bitData); - result = 31 - nonZeroBit; - bitStrm->bitData <<= 32 - nonZeroBit; - bitStrm->bitsLeft -= 32 - nonZeroBit; - } - else - { - uint32_t bitsLeft = bitStrm->bitsLeft; - while (1) - { - while (bitStrm->curPos + 4 <= bitStrm->curBufSize) - { - nextData = - _byteswap_ulong(*(uint32_t *)(bitStrm->mdatBuf + bitStrm->curPos)); - bitStrm->curPos += 4; - crxFillBuffer(bitStrm); - if (nextData) - { - _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)nextData); - result = bitsLeft + 31 - nonZeroBit; - bitStrm->bitData = nextData << (32 - nonZeroBit); - bitStrm->bitsLeft = nonZeroBit; - return result; - } - bitsLeft += 32; - } - if (bitStrm->curBufSize < bitStrm->curPos + 1) - break; // error - nextData = bitStrm->mdatBuf[bitStrm->curPos++]; - crxFillBuffer(bitStrm); - if (nextData) - break; - bitsLeft += 8; - } - _BitScanReverse((DWORD *)&nonZeroBit, (DWORD)nextData); - result = (uint32_t)(bitsLeft + 7 - nonZeroBit); - bitStrm->bitData = nextData << (32 - nonZeroBit); - bitStrm->bitsLeft = nonZeroBit; - } - return result; -} - -libraw_inline uint32_t crxBitstreamGetBits(CrxBitstream *bitStrm, int bits) -{ - int bitsLeft = bitStrm->bitsLeft; - uint32_t bitData = bitStrm->bitData; - uint32_t nextWord; - uint8_t nextByte; - uint32_t result; - - if (bitsLeft < bits) - { - // get them from stream - if (bitStrm->curPos + 4 <= bitStrm->curBufSize) - { - nextWord = - _byteswap_ulong(*(uint32_t *)(bitStrm->mdatBuf + bitStrm->curPos)); - bitStrm->curPos += 4; - crxFillBuffer(bitStrm); - bitStrm->bitsLeft = 32 - (bits - bitsLeft); - result = ((nextWord >> bitsLeft) | bitData) >> (32 - bits); - bitStrm->bitData = nextWord << (bits - bitsLeft); - return result; - } - // less than a word left - read byte at a time - do - { - if (bitStrm->curPos >= bitStrm->curBufSize) - break; // error - bitsLeft += 8; - nextByte = bitStrm->mdatBuf[bitStrm->curPos++]; - crxFillBuffer(bitStrm); - bitData |= nextByte << (32 - bitsLeft); - } while (bitsLeft < bits); - } - result = bitData >> (32 - bits); // 32-bits - bitStrm->bitData = bitData << bits; - bitStrm->bitsLeft = bitsLeft - bits; - return result; -} - -libraw_inline int crxPredictKParameter(int32_t prevK, int32_t bitCode, - int32_t maxVal = 0) -{ - int32_t newKParam = prevK - (bitCode < (1 << prevK >> 1)) + - ((bitCode >> prevK) > 2) + ((bitCode >> prevK) > 5); - - return !maxVal || newKParam < maxVal ? newKParam : maxVal; -} - -libraw_inline void crxDecodeSymbolL1(CrxBandParam *param, - int32_t doMedianPrediction, - int32_t notEOL = 0) -{ - if (doMedianPrediction) - { - int32_t symb[4]; - - int32_t delta = param->lineBuf0[1] - param->lineBuf0[0]; - symb[2] = param->lineBuf1[0]; - symb[0] = symb[1] = delta + symb[2]; - symb[3] = param->lineBuf0[1]; - - param->lineBuf1[1] = - symb[(((param->lineBuf0[0] < param->lineBuf1[0]) ^ (delta < 0)) << 1) + - ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (delta < 0))]; - } - else - param->lineBuf1[1] = param->lineBuf0[1]; - - // get next error symbol - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - - // add converted (+/-) error code to predicted value - param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); - - // for not end of the line - use one symbol ahead to estimate next K - if (notEOL) - { - int32_t nextDelta = (param->lineBuf0[2] - param->lineBuf0[1]) << 1; - bitCode = (bitCode + _abs(nextDelta)) >> 1; - ++param->lineBuf0; - } - - // update K parameter - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - - ++param->lineBuf1; -} - -int crxDecodeLine(CrxBandParam *param) -{ - int length = param->subbandWidth; - - param->lineBuf1[0] = param->lineBuf0[1]; - for (; length > 1; --length) - { - if (param->lineBuf1[0] != param->lineBuf0[1] || - param->lineBuf1[0] != param->lineBuf0[2]) - { - crxDecodeSymbolL1(param, 1, 1); - } - else - { - int nSyms = 0; - if (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms = 1; - while (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms += JS[param->sParam]; - if (nSyms > length) - { - nSyms = length; - break; - } - if (param->sParam < 31) - ++param->sParam; - if (nSyms == length) - break; - } - - if (nSyms < length) - { - if (J[param->sParam]) - nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); - if (param->sParam > 0) - --param->sParam; - if (nSyms > length) - return -1; - } - - length -= nSyms; - - // copy symbol nSyms times - param->lineBuf0 += nSyms; - - // copy symbol nSyms times - while (nSyms-- > 0) - { - param->lineBuf1[1] = param->lineBuf1[0]; - ++param->lineBuf1; - } - } - - if (length > 0) - crxDecodeSymbolL1(param, 0, (length > 1)); - } - } - - if (length == 1) - crxDecodeSymbolL1(param, 1, 0); - - param->lineBuf1[1] = param->lineBuf1[0] + 1; - - return 0; -} - -libraw_inline void crxDecodeSymbolL1Rounded(CrxBandParam *param, - int32_t doSym = 1, - int32_t doCode = 1) -{ - int32_t sym = param->lineBuf0[1]; - - if (doSym) - { - // calculate the next symbol gradient - int32_t symb[4]; - int32_t deltaH = param->lineBuf0[1] - param->lineBuf0[0]; - symb[2] = param->lineBuf1[0]; - symb[0] = symb[1] = deltaH + symb[2]; - symb[3] = param->lineBuf0[1]; - sym = - symb[(((param->lineBuf0[0] < param->lineBuf1[0]) ^ (deltaH < 0)) << 1) + - ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (deltaH < 0))]; - } - - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - int32_t code = -(bitCode & 1) ^ (bitCode >> 1); - param->lineBuf1[1] = param->roundedBitsMask * 2 * code + (code >> 31) + sym; - - if (doCode) - { - if (param->lineBuf0[2] > param->lineBuf0[1]) - code = (param->lineBuf0[2] - param->lineBuf0[1] + param->roundedBitsMask - - 1) >> - param->roundedBits; - else - code = -( - (param->lineBuf0[1] - param->lineBuf0[2] + param->roundedBitsMask) >> - param->roundedBits); - - param->kParam = crxPredictKParameter(param->kParam, - (bitCode + 2 * _abs(code)) >> 1, 15); - } - else - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - - ++param->lineBuf1; -} - -int crxDecodeLineRounded(CrxBandParam *param) -{ - int32_t valueReached = 0; - - param->lineBuf0[0] = param->lineBuf0[1]; - param->lineBuf1[0] = param->lineBuf0[1]; - int32_t length = param->subbandWidth; - - for (; length > 1; --length) - { - if (_abs(param->lineBuf0[2] - param->lineBuf0[1]) > param->roundedBitsMask) - { - crxDecodeSymbolL1Rounded(param); - ++param->lineBuf0; - valueReached = 1; - } - else if (valueReached || _abs(param->lineBuf0[0] - param->lineBuf1[0]) > - param->roundedBitsMask) - { - crxDecodeSymbolL1Rounded(param); - ++param->lineBuf0; - valueReached = 0; - } - else - { - int nSyms = 0; - if (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms = 1; - while (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms += JS[param->sParam]; - if (nSyms > length) - { - nSyms = length; - break; - } - if (param->sParam < 31) - ++param->sParam; - if (nSyms == length) - break; - } - if (nSyms < length) - { - if (J[param->sParam]) - nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); - if (param->sParam > 0) - --param->sParam; - } - if (nSyms > length) - return -1; - } - length -= nSyms; - - // copy symbol nSyms times - param->lineBuf0 += nSyms; - - // copy symbol nSyms times - while (nSyms-- > 0) - { - param->lineBuf1[1] = param->lineBuf1[0]; - ++param->lineBuf1; - } - - if (length > 1) - { - crxDecodeSymbolL1Rounded(param, 0); - ++param->lineBuf0; - valueReached = _abs(param->lineBuf0[1] - param->lineBuf0[0]) > - param->roundedBitsMask; - } - else if (length == 1) - crxDecodeSymbolL1Rounded(param, 0, 0); - } - } - if (length == 1) - crxDecodeSymbolL1Rounded(param, 1, 0); - - param->lineBuf1[1] = param->lineBuf1[0] + 1; - - return 0; -} - -int crxDecodeLineNoRefPrevLine(CrxBandParam *param) -{ - int32_t i = 0; - - for (; i < param->subbandWidth - 1; i++) - { - if (param->lineBuf0[i + 2] | param->lineBuf0[i + 1] | param->lineBuf1[i]) - { - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode); - if (param->lineBuf2[i + 1] - param->kParam <= 1) - { - if (param->kParam >= 15) - param->kParam = 15; - } - else - ++param->kParam; - } - else - { - int nSyms = 0; - if (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms = 1; - if (i != param->subbandWidth - 1) - { - while (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms += JS[param->sParam]; - if (i + nSyms > param->subbandWidth) - { - nSyms = param->subbandWidth - i; - break; + if (bitStrm->curBufSize < 1) { // nothing read + throw std::exception(); } - if (param->sParam < 31) - ++param->sParam; - if (i + nSyms == param->subbandWidth) - break; - } - if (i + nSyms < param->subbandWidth) - { - if (J[param->sParam]) - nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); - if (param->sParam > 0) - --param->sParam; - } - if (i + nSyms > param->subbandWidth) - return -1; + + bitStrm->mdatSize -= bitStrm->curBufSize; } - } - else if (i > param->subbandWidth) - return -1; + } +} - if (nSyms > 0) - { - memset(param->lineBuf1 + i + 1, 0, nSyms * sizeof(int32_t)); - memset(param->lineBuf2 + i, 0, nSyms * sizeof(int32_t)); - i += nSyms; - } +inline int crxBitstreamGetZeros(CrxBitstream* bitStrm) +{ +// std::uint32_t bitData = bitStrm->bitData; + std::uint32_t nonZeroBit = 0; + std::uint64_t nextData = 0; + std::int32_t result = 0; - if (i >= param->subbandWidth - 1) - { - if (i == param->subbandWidth - 1) - { - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) + if (bitStrm->bitData) { + _BitScanReverse(&nonZeroBit, bitStrm->bitData); + result = 31 - nonZeroBit; + bitStrm->bitData <<= 32 - nonZeroBit; + bitStrm->bitsLeft -= 32 - nonZeroBit; + } else { + std::uint32_t bitsLeft = bitStrm->bitsLeft; + + while (true) { + while (bitStrm->curPos + 4 <= bitStrm->curBufSize) { + nextData = _byteswap_ulong(*reinterpret_cast(bitStrm->mdatBuf + bitStrm->curPos)); + bitStrm->curPos += 4; + crxFillBuffer(bitStrm); + + if (nextData) { + _BitScanReverse(&nonZeroBit, static_cast(nextData)); + result = bitsLeft + 31 - nonZeroBit; + bitStrm->bitData = nextData << (32 - nonZeroBit); + bitStrm->bitsLeft = nonZeroBit; + return result; + } + + bitsLeft += 32; + } + + if (bitStrm->curBufSize < bitStrm->curPos + 1) { + break; // error + } + + nextData = bitStrm->mdatBuf[bitStrm->curPos++]; + crxFillBuffer(bitStrm); + + if (nextData) { + break; + } + + bitsLeft += 8; + } + + _BitScanReverse(&nonZeroBit, static_cast(nextData)); + result = static_cast(bitsLeft + 7 - nonZeroBit); + bitStrm->bitData = nextData << (32 - nonZeroBit); + bitStrm->bitsLeft = nonZeroBit; + } + + return result; +} + +inline std::uint32_t crxBitstreamGetBits(CrxBitstream* bitStrm, int bits) +{ + int bitsLeft = bitStrm->bitsLeft; + std::uint32_t bitData = bitStrm->bitData; + std::uint32_t nextWord; + std::uint8_t nextByte; + std::uint32_t result; + + if (bitsLeft < bits) { + // get them from stream + if (bitStrm->curPos + 4 <= bitStrm->curBufSize) { + nextWord = _byteswap_ulong(*reinterpret_cast(bitStrm->mdatBuf + bitStrm->curPos)); + bitStrm->curPos += 4; + crxFillBuffer(bitStrm); + bitStrm->bitsLeft = 32 - (bits - bitsLeft); + result = ((nextWord >> bitsLeft) | bitData) >> (32 - bits); + bitStrm->bitData = nextWord << (bits - bitsLeft); + return result; + } + + // less than a word left - read byte at a time + do { + if (bitStrm->curPos >= bitStrm->curBufSize) { + break; // error + } + + bitsLeft += 8; + nextByte = bitStrm->mdatBuf[bitStrm->curPos++]; + crxFillBuffer(bitStrm); + bitData |= nextByte << (32 - bitsLeft); + } while (bitsLeft < bits); + } + + result = bitData >> (32 - bits); // 32-bits + bitStrm->bitData = bitData << bits; + bitStrm->bitsLeft = bitsLeft - bits; + return result; +} + +inline std::int32_t crxPredictKParameter(std::int32_t prevK, std::int32_t bitCode, std::int32_t maxVal = 0) +{ + const std::int32_t newKParam = + prevK + - (bitCode < (1 << prevK >> 1)) + + ((bitCode >> prevK) > 2) + ((bitCode >> prevK) > 5); + + return + !maxVal || newKParam < maxVal + ? newKParam + : maxVal; +} + +inline void crxDecodeSymbolL1(CrxBandParam* param, bool doMedianPrediction, bool notEOL = false) +{ + if (doMedianPrediction) { + const std::int32_t delta = param->lineBuf0[1] - param->lineBuf0[0]; + const std::int32_t symb[4] = { + delta + param->lineBuf1[0], + delta + param->lineBuf1[0], + param->lineBuf1[0], + param->lineBuf0[1] + }; + + param->lineBuf1[1] = symb[ + (((param->lineBuf0[0] < param->lineBuf1[0]) ^ (delta < 0)) << 1) + + ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (delta < 0)) + ]; + } else { + param->lineBuf1[1] = param->lineBuf0[1]; + } + + // get next error symbol + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + // add converted (+/-) error code to predicted value + param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); + + // for not end of the line - use one symbol ahead to estimate next K + if (notEOL) { + const std::int32_t nextDelta = (param->lineBuf0[2] - param->lineBuf0[1]) << 1; + bitCode = (bitCode + std::abs(nextDelta)) >> 1; + ++param->lineBuf0; + } + + // update K parameter + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + + ++param->lineBuf1; +} + +bool crxDecodeLine(CrxBandParam* param) +{ + int length = param->subbandWidth; + + param->lineBuf1[0] = param->lineBuf0[1]; + + for (; length > 1; --length) { + if (param->lineBuf1[0] != param->lineBuf0[1] || param->lineBuf1[0] != param->lineBuf0[2]) { + crxDecodeSymbolL1(param, true, true); + } else { + if (crxBitstreamGetBits(¶m->bitStream, 1)) { + int nSyms = 1; + + while (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms += JS[param->sParam]; + + if (nSyms > length) { + nSyms = length; + break; + } + + if (param->sParam < 31) { + ++param->sParam; + } + + if (nSyms == length) { + break; + } + } + + if (nSyms < length) { + if (J[param->sParam]) { + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + } + + if (param->sParam > 0) { + --param->sParam; + } + + if (nSyms > length) { + return false; + } + } + + length -= nSyms; + + // copy symbol nSyms times + param->lineBuf0 += nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + } + + if (length > 0) { + crxDecodeSymbolL1(param, false, length > 1); + } + } + } + + if (length == 1) { + crxDecodeSymbolL1(param, true, false); + } + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return true; +} + +inline void crxDecodeSymbolL1Rounded(CrxBandParam* param, bool doSym = true, bool doCode = true) +{ + std::int32_t sym = param->lineBuf0[1]; + + if (doSym) { + // calculate the next symbol gradient + const std::int32_t deltaH = param->lineBuf0[1] - param->lineBuf0[0]; + const std::int32_t symb[4] = { + deltaH + param->lineBuf1[0], + deltaH + param->lineBuf1[0], + param->lineBuf1[0], + param->lineBuf0[1] + }; + sym = symb[ + (((param->lineBuf0[0] < param->lineBuf1[0]) ^ (deltaH < 0)) << 1) + + ((param->lineBuf1[0] < param->lineBuf0[1]) ^ (deltaH < 0)) + ]; + } + + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + std::int32_t code = -(bitCode & 1) ^ (bitCode >> 1); + param->lineBuf1[1] = param->roundedBitsMask * 2 * code + (code < 0) + sym; + + if (doCode) { + if (param->lineBuf0[2] > param->lineBuf0[1]) { + code = (param->lineBuf0[2] - param->lineBuf0[1] + param->roundedBitsMask - 1) >> param->roundedBits; + } else { + code = -((param->lineBuf0[1] - param->lineBuf0[2] + param->roundedBitsMask) >> param->roundedBits); + } + + param->kParam = crxPredictKParameter(param->kParam, (bitCode + 2 * std::abs(code)) >> 1, 15); + } else { + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + } + + ++param->lineBuf1; +} + +bool crxDecodeLineRounded(CrxBandParam* param) +{ + bool valueReached = false; + + param->lineBuf0[0] = param->lineBuf0[1]; + param->lineBuf1[0] = param->lineBuf0[1]; + std::int32_t length = param->subbandWidth; + + for (; length > 1; --length) { + if (std::abs(param->lineBuf0[2] - param->lineBuf0[1]) > param->roundedBitsMask) { + crxDecodeSymbolL1Rounded(param); + ++param->lineBuf0; + valueReached = true; + } else if (valueReached || std::abs(param->lineBuf0[0] - param->lineBuf1[0]) > param->roundedBitsMask) { + crxDecodeSymbolL1Rounded(param); + ++param->lineBuf0; + valueReached = false; + } else { + int nSyms = 0; + + if (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms = 1; + + while (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms += JS[param->sParam]; + + if (nSyms > length) { + nSyms = length; + break; + } + + if (param->sParam < 31) { + ++param->sParam; + } + + if (nSyms == length) { + break; + } + } + + if (nSyms < length) { + if (J[param->sParam]) { + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + } + + if (param->sParam > 0) { + --param->sParam; + } + } + + if (nSyms > length) { + return false; + } + } + + length -= nSyms; + + // copy symbol nSyms times + param->lineBuf0 += nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + + if (length > 1) { + crxDecodeSymbolL1Rounded(param, false); + ++param->lineBuf0; + valueReached = std::abs(param->lineBuf0[1] - param->lineBuf0[0]) > param->roundedBitsMask; + } else if (length == 1) { + crxDecodeSymbolL1Rounded(param, false, false); + } + } + } + + if (length == 1) { + crxDecodeSymbolL1Rounded(param, true, false); + } + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return true; +} + +bool crxDecodeLineNoRefPrevLine(CrxBandParam* param) +{ + std::int32_t i = 0; + + for (; i < param->subbandWidth - 1; ++i) { + if (param->lineBuf0[i + 2] || param->lineBuf0[i + 1] || param->lineBuf1[i]) { + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode); + + if (param->lineBuf2[i + 1] - param->kParam <= 1) { + if (param->kParam >= 15) { + param->kParam = 15; + } + } else { + ++param->kParam; + } + } else { + int nSyms = 0; + + if (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms = 1; + + if (i != param->subbandWidth - 1) { + while (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms += JS[param->sParam]; + + if (i + nSyms > param->subbandWidth) { + nSyms = param->subbandWidth - i; + break; + } + + if (param->sParam < 31) { + ++param->sParam; + } + + if (i + nSyms == param->subbandWidth) { + break; + } + } + + if (i + nSyms < param->subbandWidth) { + if (J[param->sParam]) { + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + } + + if (param->sParam > 0) { + --param->sParam; + } + } + + if (i + nSyms > param->subbandWidth) { + return false; + } + } + } else if (i > param->subbandWidth) { + return false; + } + + if (nSyms > 0) { + memset(param->lineBuf1 + i + 1, 0, nSyms * sizeof(std::int32_t)); + memset(param->lineBuf2 + i, 0, nSyms * sizeof(std::int32_t)); + i += nSyms; + } + + if (i >= param->subbandWidth - 1) { + if (i == param->subbandWidth - 1) { + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + param->lineBuf2[i] = param->kParam; + } + + continue; + } else { + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode); + + if (param->lineBuf2[i + 1] - param->kParam <= 1) { + if (param->kParam >= 15) { + param->kParam = 15; + } + } else { + ++param->kParam; + } + } + } + + param->lineBuf2[i] = param->kParam; + } + + if (i == param->subbandWidth - 1) { + std::int32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - param->lineBuf2[i] = param->kParam; - } - continue; - } - else - { - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[i + 1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode); - if (param->lineBuf2[i + 1] - param->kParam <= 1) - { - if (param->kParam >= 15) - param->kParam = 15; - } - else - ++param->kParam; - } - } - param->lineBuf2[i] = param->kParam; - } - if (i == param->subbandWidth - 1) - { - int32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - param->lineBuf2[i] = param->kParam; - } - - return 0; -} - -int crxDecodeTopLine(CrxBandParam *param) -{ - param->lineBuf1[0] = 0; - - int32_t length = param->subbandWidth; - - // read the line from bitstream - for (; length > 1; --length) - { - if (param->lineBuf1[0]) - param->lineBuf1[1] = param->lineBuf1[0]; - else - { - int nSyms = 0; - if (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms = 1; - while (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms += JS[param->sParam]; - if (nSyms > length) - { - nSyms = length; - break; - } - if (param->sParam < 31) - ++param->sParam; - if (nSyms == length) - break; - } - if (nSyms < length) - { - if (J[param->sParam]) - nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); - if (param->sParam > 0) - --param->sParam; - if (nSyms > length) - return -1; + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); } - length -= nSyms; - - // copy symbol nSyms times - while (nSyms-- > 0) - { - param->lineBuf1[1] = param->lineBuf1[0]; - ++param->lineBuf1; - } - - if (length <= 0) - break; - } - - param->lineBuf1[1] = 0; + param->lineBuf1[i + 1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + param->lineBuf2[i] = param->kParam; } - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - ++param->lineBuf1; - } - - if (length == 1) - { - param->lineBuf1[1] = param->lineBuf1[0]; - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - ++param->lineBuf1; - } - - param->lineBuf1[1] = param->lineBuf1[0] + 1; - - return 0; + return true; } -int crxDecodeTopLineRounded(CrxBandParam *param) +bool crxDecodeTopLine(CrxBandParam* param) { - param->lineBuf1[0] = 0; + param->lineBuf1[0] = 0; - int32_t length = param->subbandWidth; + std::int32_t length = param->subbandWidth; - // read the line from bitstream - for (; length > 1; --length) - { - if (_abs(param->lineBuf1[0]) > param->roundedBitsMask) - param->lineBuf1[1] = param->lineBuf1[0]; - else - { - int nSyms = 0; - if (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms = 1; - while (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms += JS[param->sParam]; - if (nSyms > length) - { - nSyms = length; - break; - } - if (param->sParam < 31) - ++param->sParam; - if (nSyms == length) - break; + // read the line from bitstream + for (; length > 1; --length) { + if (param->lineBuf1[0]) { + param->lineBuf1[1] = param->lineBuf1[0]; + } else { + if (crxBitstreamGetBits(¶m->bitStream, 1)) { + int nSyms = 1; + + while (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms += JS[param->sParam]; + + if (nSyms > length) { + nSyms = length; + break; + } + + if (param->sParam < 31) { + ++param->sParam; + } + + if (nSyms == length) { + break; + } + } + + if (nSyms < length) { + if (J[param->sParam]) { + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + } + + if (param->sParam > 0) { + --param->sParam; + } + + if (nSyms > length) { + return false; + } + } + + length -= nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + + if (length <= 0) { + break; + } + } + + param->lineBuf1[1] = 0; } - if (nSyms < length) - { - if (J[param->sParam]) - nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); - if (param->sParam > 0) - --param->sParam; - if (nSyms > length) - return -1; + + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); } - } - length -= nSyms; + param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; + } - // copy symbol nSyms times - while (nSyms-- > 0) - { + if (length == 1) { param->lineBuf1[1] = param->lineBuf1[0]; + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + param->lineBuf1[1] += -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); ++param->lineBuf1; - } - - if (length <= 0) - break; - - param->lineBuf1[1] = 0; } - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); + param->lineBuf1[1] = param->lineBuf1[0] + 1; - int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1); - param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - ++param->lineBuf1; - } - - if (length == 1) - { - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1); - param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - ++param->lineBuf1; - } - - param->lineBuf1[1] = param->lineBuf1[0] + 1; - - return 0; + return true; } -int crxDecodeTopLineNoRefPrevLine(CrxBandParam *param) +bool crxDecodeTopLineRounded(CrxBandParam* param) { - param->lineBuf0[0] = 0; - param->lineBuf1[0] = 0; - int32_t length = param->subbandWidth; - for (; length > 1; --length) - { - if (param->lineBuf1[0]) - { - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - } - else - { - int nSyms = 0; - if (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms = 1; - while (crxBitstreamGetBits(¶m->bitStream, 1)) - { - nSyms += JS[param->sParam]; - if (nSyms > length) - { - nSyms = length; - break; - } - if (param->sParam < 31) - ++param->sParam; - if (nSyms == length) - break; - } - if (nSyms < length) - { - if (J[param->sParam]) - nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); - if (param->sParam > 0) - --param->sParam; - if (nSyms > length) - return -1; - } - } + param->lineBuf1[0] = 0; - length -= nSyms; + std::int32_t length = param->subbandWidth; - // copy symbol nSyms times - while (nSyms-- > 0) - { - param->lineBuf2[0] = 0; - param->lineBuf1[1] = 0; + // read the line from bitstream + for (; length > 1; --length) { + if (std::abs(param->lineBuf1[0]) > param->roundedBitsMask) { + param->lineBuf1[1] = param->lineBuf1[0]; + } else { + int nSyms = 0; + + if (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms = 1; + + while (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms += JS[param->sParam]; + + if (nSyms > length) { + nSyms = length; + break; + } + + if (param->sParam < 31) { + ++param->sParam; + } + + if (nSyms == length) { + break; + } + } + + if (nSyms < length) { + if (J[param->sParam]) { + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + } + + if (param->sParam > 0) { + --param->sParam; + } + + if (nSyms > length) { + return false; + } + } + } + + length -= nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) { + param->lineBuf1[1] = param->lineBuf1[0]; + ++param->lineBuf1; + } + + if (length <= 0) { + break; + } + + param->lineBuf1[1] = 0; + } + + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + const std::int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1); + param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); ++param->lineBuf1; + } + + if (length == 1) { + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + const std::int32_t sVal = -(bitCode & 1) ^ (bitCode >> 1); + param->lineBuf1[1] += param->roundedBitsMask * 2 * sVal + (sVal >> 31); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; + } + + param->lineBuf1[1] = param->lineBuf1[0] + 1; + + return true; +} + +bool crxDecodeTopLineNoRefPrevLine(CrxBandParam* param) +{ + param->lineBuf0[0] = 0; + param->lineBuf1[0] = 0; + std::int32_t length = param->subbandWidth; + + for (; length > 1; --length) { + if (param->lineBuf1[0]) { + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + } else { + int nSyms = 0; + + if (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms = 1; + + while (crxBitstreamGetBits(¶m->bitStream, 1)) { + nSyms += JS[param->sParam]; + + if (nSyms > length) { + nSyms = length; + break; + } + + if (param->sParam < 31) { + ++param->sParam; + } + + if (nSyms == length) { + break; + } + } + + if (nSyms < length) { + if (J[param->sParam]) { + nSyms += crxBitstreamGetBits(¶m->bitStream, J[param->sParam]); + } + + if (param->sParam > 0) { + --param->sParam; + } + + if (nSyms > length) { + return false; + } + } + } + + length -= nSyms; + + // copy symbol nSyms times + while (nSyms-- > 0) { + param->lineBuf2[0] = 0; + param->lineBuf1[1] = 0; + ++param->lineBuf1; + ++param->lineBuf2; + } + + if (length <= 0) { + break; + } + + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); + + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); + } + + param->lineBuf1[1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + } + + param->lineBuf2[0] = param->kParam; ++param->lineBuf2; - } - - if (length <= 0) - break; - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[1] = -((bitCode + 1) & 1) ^ ((bitCode + 1) >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + ++param->lineBuf1; } - param->lineBuf2[0] = param->kParam; - ++param->lineBuf2; - ++param->lineBuf1; - } - if (length == 1) - { - uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - if (bitCode >= 41) - bitCode = crxBitstreamGetBits(¶m->bitStream, 21); - else if (param->kParam) - bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | - (bitCode << param->kParam); - param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1); - param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); - param->lineBuf2[0] = param->kParam; - ++param->lineBuf1; - } + if (length == 1) { + std::uint32_t bitCode = crxBitstreamGetZeros(¶m->bitStream); - param->lineBuf1[1] = 0; - - return 0; -} - -int crxDecodeLine(CrxBandParam *param, uint8_t *bandBuf) -{ - if (!param || !bandBuf) - return -1; - if (param->curLine >= param->subbandHeight) - return -1; - - if (param->curLine == 0) - { - int32_t lineLength = param->subbandWidth + 2; - - param->sParam = 0; - param->kParam = 0; - if (param->supportsPartial) - { - if (param->roundedBitsMask <= 0) - { - param->lineBuf0 = (int32_t *)param->paramData; - param->lineBuf1 = param->lineBuf0 + lineLength; - int32_t *lineBuf = param->lineBuf1 + 1; - if (crxDecodeTopLine(param)) - return -1; - memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); - ++param->curLine; - } - else - { - param->roundedBits = 1; - if (param->roundedBitsMask & ~1) - { - while (param->roundedBitsMask >> param->roundedBits) - ++param->roundedBits; + if (bitCode >= 41) { + bitCode = crxBitstreamGetBits(¶m->bitStream, 21); + } else if (param->kParam) { + bitCode = crxBitstreamGetBits(¶m->bitStream, param->kParam) | (bitCode << param->kParam); } - param->lineBuf0 = (int32_t *)param->paramData; - param->lineBuf1 = param->lineBuf0 + lineLength; - int32_t *lineBuf = param->lineBuf1 + 1; - if (crxDecodeTopLineRounded(param)) - return -1; - memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); - ++param->curLine; - } + + param->lineBuf1[1] = -(bitCode & 1) ^ (bitCode >> 1); + param->kParam = crxPredictKParameter(param->kParam, bitCode, 15); + param->lineBuf2[0] = param->kParam; + ++param->lineBuf1; } - else - { - param->lineBuf2 = (int32_t *)param->nonProgrData; - param->lineBuf0 = (int32_t *)param->paramData; - param->lineBuf1 = param->lineBuf0 + lineLength; - int32_t *lineBuf = param->lineBuf1 + 1; - if (crxDecodeTopLineNoRefPrevLine(param)) - return -1; - memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); - ++param->curLine; - } - } - else if (!param->supportsPartial) - { - int32_t lineLength = param->subbandWidth + 2; - param->lineBuf2 = (int32_t *)param->nonProgrData; - if (param->curLine & 1) - { - param->lineBuf1 = (int32_t *)param->paramData; - param->lineBuf0 = param->lineBuf1 + lineLength; - } - else - { - param->lineBuf0 = (int32_t *)param->paramData; - param->lineBuf1 = param->lineBuf0 + lineLength; - } - int32_t *lineBuf = param->lineBuf1 + 1; - if (crxDecodeLineNoRefPrevLine(param)) - return -1; - memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); - ++param->curLine; - } - else if (param->roundedBitsMask <= 0) - { - int32_t lineLength = param->subbandWidth + 2; - if (param->curLine & 1) - { - param->lineBuf1 = (int32_t *)param->paramData; - param->lineBuf0 = param->lineBuf1 + lineLength; - } - else - { - param->lineBuf0 = (int32_t *)param->paramData; - param->lineBuf1 = param->lineBuf0 + lineLength; - } - int32_t *lineBuf = param->lineBuf1 + 1; - if (crxDecodeLine(param)) - return -1; - memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); - ++param->curLine; - } - else - { - int32_t lineLength = param->subbandWidth + 2; - if (param->curLine & 1) - { - param->lineBuf1 = (int32_t *)param->paramData; - param->lineBuf0 = param->lineBuf1 + lineLength; - } - else - { - param->lineBuf0 = (int32_t *)param->paramData; - param->lineBuf1 = param->lineBuf0 + lineLength; - } - int32_t *lineBuf = param->lineBuf1 + 1; - if (crxDecodeLineRounded(param)) - return -1; - memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(int32_t)); - ++param->curLine; - } - return 0; + + param->lineBuf1[1] = 0; + + return true; } -int crxDecodeLineWithIQuantization(CrxSubband *subband) +bool crxDecodeLine(CrxBandParam* param, std::uint8_t* bandBuf) { - int32_t q_step_tbl[6] = {0x28, 0x2D, 0x33, 0x39, 0x40, 0x48}; - - if (!subband->dataSize) - { - memset(subband->bandBuf, 0, subband->bandSize); - return 0; - } - - if (subband->supportsPartial) - { - uint32_t bitCode = crxBitstreamGetZeros(&subband->bandParam->bitStream); - if (bitCode >= 23) - bitCode = crxBitstreamGetBits(&subband->bandParam->bitStream, 8); - else if (subband->paramK) - bitCode = - crxBitstreamGetBits(&subband->bandParam->bitStream, subband->paramK) | - (bitCode << subband->paramK); - - subband->quantValue += - -(bitCode & 1) ^ (bitCode >> 1); // converting encoded to signed integer - subband->paramK = crxPredictKParameter(subband->paramK, bitCode); - if (subband->paramK > 7) - return -1; - } - if (crxDecodeLine(subband->bandParam, subband->bandBuf)) - return -1; - - if (subband->width <= 0) - return 0LL; - - // update subband buffers - int32_t *bandBuf = (int32_t *)subband->bandBuf; - int32_t qScale = - q_step_tbl[subband->quantValue % 6] >> (6 - subband->quantValue / 6); - if (subband->quantValue / 6 >= 6) - qScale = q_step_tbl[subband->quantValue % 6] * - (1 << (subband->quantValue / 6 + 26)); - - if (qScale != 1) - for (int32_t i = 0; i < subband->width; i++) - bandBuf[i] *= qScale; - - return 0; -} - -void crxHorizontal53(int32_t *lineBufLA, int32_t *lineBufLB, - CrxWaveletTransform *wavelet, uint32_t tileFlag) -{ - int32_t *band0Buf = wavelet->subband0Buf; - int32_t *band1Buf = wavelet->subband1Buf; - int32_t *band2Buf = wavelet->subband2Buf; - int32_t *band3Buf = wavelet->subband3Buf; - - if (wavelet->width <= 1) - { - lineBufLA[0] = band0Buf[0]; - lineBufLB[0] = band2Buf[0]; - } - else - { - if (tileFlag & E_HAS_TILES_ON_THE_LEFT) - { - lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - ++band1Buf; - ++band3Buf; + if (!param || !bandBuf) { + return false; } - else - { - lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + + if (param->curLine >= param->subbandHeight) { + return false; } - ++band0Buf; - ++band2Buf; - for (int i = 0; i < wavelet->width - 3; i += 2) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufLA[1] = band1Buf[0] + ((delta + lineBufLA[0]) >> 1); - lineBufLA[2] = delta; + if (param->curLine == 0) { + const std::int32_t lineLength = param->subbandWidth + 2; - delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - lineBufLB[1] = band3Buf[0] + ((delta + lineBufLB[0]) >> 1); - lineBufLB[2] = delta; + param->sParam = 0; + param->kParam = 0; - ++band0Buf; - ++band1Buf; - ++band2Buf; - ++band3Buf; - lineBufLA += 2; - lineBufLB += 2; - } - if (tileFlag & E_HAS_TILES_ON_THE_RIGHT) - { - int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufLA[1] = band1Buf[0] + ((deltaA + lineBufLA[0]) >> 1); + if (param->supportsPartial) { + if (param->roundedBitsMask <= 0) { + param->lineBuf0 = param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + const std::int32_t* const lineBuf = param->lineBuf1 + 1; - int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - lineBufLB[1] = band3Buf[0] + ((deltaB + lineBufLB[0]) >> 1); + if (!crxDecodeTopLine(param)) { + return false; + } - if (wavelet->width & 1) - { - lineBufLA[2] = deltaA; - lineBufLB[2] = deltaB; - } - } - else if (wavelet->width & 1) - { - lineBufLA[1] = - band1Buf[0] + - ((lineBufLA[0] + band0Buf[0] - ((band1Buf[0] + 1) >> 1)) >> 1); - lineBufLA[2] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t)); + ++param->curLine; + } else { + param->roundedBits = 1; - lineBufLB[1] = - band3Buf[0] + - ((lineBufLB[0] + band2Buf[0] - ((band3Buf[0] + 1) >> 1)) >> 1); - lineBufLB[2] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); - } - else - { - lineBufLA[1] = lineBufLA[0] + band1Buf[0]; - lineBufLB[1] = lineBufLB[0] + band3Buf[0]; - } - } -} + if (param->roundedBitsMask & ~1) { + while (param->roundedBitsMask >> param->roundedBits) { + ++param->roundedBits; + } + } -int32_t *crxIdwt53FilterGetLine(CrxPlaneComp *comp, int32_t level) -{ - int32_t *result = comp->waveletTransform[level] - .lineBuf[(comp->waveletTransform[level].fltTapH - - comp->waveletTransform[level].curH + 5) % - 5 + - 3]; - comp->waveletTransform[level].curH--; - return result; -} + param->lineBuf0 = param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + const std::int32_t* const lineBuf = param->lineBuf1 + 1; -int crxIdwt53FilterDecode(CrxPlaneComp *comp, int32_t level) -{ - if (comp->waveletTransform[level].curH) - return 0; + if (!crxDecodeTopLineRounded(param)) { + return false; + } - CrxSubband *sband = comp->subBands + 3 * level; + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t)); + ++param->curLine; + } + } else { + param->lineBuf2 = param->nonProgrData; + param->lineBuf0 = param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + const std::int32_t* const lineBuf = param->lineBuf1 + 1; - if (comp->waveletTransform[level].height - 3 <= - comp->waveletTransform[level].curLine && - !(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) - { - if (comp->waveletTransform[level].height & 1) - { - if (level) - { - if (crxIdwt53FilterDecode(comp, level - 1)) - return -1; - } - else if (crxDecodeLineWithIQuantization(sband)) - return -1; + if (!crxDecodeTopLineNoRefPrevLine(param)) { + return false; + } - if (crxDecodeLineWithIQuantization(sband + 1)) - return -1; - } - } - else - { - if (level) - { - if (crxIdwt53FilterDecode(comp, level - 1)) - return -1; - } - else if (crxDecodeLineWithIQuantization(sband)) // LL band - return -1; - - if (crxDecodeLineWithIQuantization(sband + 1) || // HL band - crxDecodeLineWithIQuantization(sband + 2) || // LH band - crxDecodeLineWithIQuantization(sband + 3)) // HH band - return -1; - } - - return 0; -} - -int crxIdwt53FilterTransform(CrxPlaneComp *comp, uint32_t level) -{ - CrxWaveletTransform *wavelet = comp->waveletTransform + level; - - if (wavelet->curH) - return 0; - - if (wavelet->curLine >= wavelet->height - 3) - { - if (!(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) - { - if (wavelet->height & 1) - { - if (level) - { - if (!wavelet[-1].curH) - if (crxIdwt53FilterTransform(comp, level - 1)) - return -1; - wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1); + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t)); + ++param->curLine; } - int32_t *band0Buf = wavelet->subband0Buf; - int32_t *band1Buf = wavelet->subband1Buf; - int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; - int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; - int32_t *lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3]; + } else if (!param->supportsPartial) { + const std::int32_t lineLength = param->subbandWidth + 2; + param->lineBuf2 = param->nonProgrData; + + if (param->curLine & 1) { + param->lineBuf1 = param->paramData; + param->lineBuf0 = param->lineBuf1 + lineLength; + } else { + param->lineBuf0 = param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + } + + const std::int32_t* const lineBuf = param->lineBuf1 + 1; + + if (!crxDecodeLineNoRefPrevLine(param)) { + return false; + } + + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t)); + ++param->curLine; + } else if (param->roundedBitsMask <= 0) { + const std::int32_t lineLength = param->subbandWidth + 2; + + if (param->curLine & 1) { + param->lineBuf1 = param->paramData; + param->lineBuf0 = param->lineBuf1 + lineLength; + } else { + param->lineBuf0 = param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + } + + const std::int32_t* const lineBuf = param->lineBuf1 + 1; + + if (!crxDecodeLine(param)) { + return false; + } + + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t)); + ++param->curLine; + } else { + const std::int32_t lineLength = param->subbandWidth + 2; + + if (param->curLine & 1) { + param->lineBuf1 = param->paramData; + param->lineBuf0 = param->lineBuf1 + lineLength; + } else { + param->lineBuf0 = param->paramData; + param->lineBuf1 = param->lineBuf0 + lineLength; + } + + const std::int32_t* const lineBuf = param->lineBuf1 + 1; + + if (!crxDecodeLineRounded(param)) { + return false; + } + + memcpy(bandBuf, lineBuf, param->subbandWidth * sizeof(std::int32_t)); + ++param->curLine; + } + + return true; +} + +bool crxDecodeLineWithIQuantization(CrxSubband* subband) +{ + constexpr std::int32_t q_step_tbl[6] = {0x28, 0x2D, 0x33, 0x39, 0x40, 0x48}; + + if (!subband->dataSize) { + memset(subband->bandBuf, 0, subband->bandSize); + return true; + } + + if (subband->supportsPartial) { + std::uint32_t bitCode = crxBitstreamGetZeros(&subband->bandParam->bitStream); + + if (bitCode >= 23) { + bitCode = crxBitstreamGetBits(&subband->bandParam->bitStream, 8); + } else if (subband->paramK) { + bitCode = crxBitstreamGetBits(&subband->bandParam->bitStream, subband->paramK) | (bitCode << subband->paramK); + } + + subband->quantValue += -(bitCode & 1) ^ (bitCode >> 1); // converting encoded to signed integer + subband->paramK = crxPredictKParameter(subband->paramK, bitCode); + + if (subband->paramK > 7) { + return false; + } + } + + if (!crxDecodeLine(subband->bandParam, subband->bandBuf)) { + return false; + } + + if (subband->width == 0) { + return true; + } + + // update subband buffers + std::int32_t* const bandBuf = reinterpret_cast(subband->bandBuf); + std::int32_t qScale = q_step_tbl[subband->quantValue % 6] >> (6 - subband->quantValue / 6); + + if (subband->quantValue / 6 >= 6) { + qScale = q_step_tbl[subband->quantValue % 6] * (1 << (subband->quantValue / 6 + 26)); + } + + if (qScale != 1) { + for (std::int32_t i = 0; i < subband->width; ++i) { + bandBuf[i] *= qScale; + } + } + + return true; +} + +void crxHorizontal53( + std::int32_t* lineBufLA, + std::int32_t* lineBufLB, + CrxWaveletTransform* wavelet, + std::uint32_t tileFlag +) +{ + std::int32_t* band0Buf = wavelet->subband0Buf; + std::int32_t* band1Buf = wavelet->subband1Buf; + std::int32_t* band2Buf = wavelet->subband2Buf; + std::int32_t* band3Buf = wavelet->subband3Buf; + + if (wavelet->width <= 1) { + lineBufLA[0] = band0Buf[0]; + lineBufLB[0] = band2Buf[0]; + } else { + if (tileFlag & E_HAS_TILES_ON_THE_LEFT) { + lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + ++band1Buf; + ++band3Buf; + } else { + lineBufLA[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufLB[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } + + ++band0Buf; + ++band2Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) { + std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufLA[1] = band1Buf[0] + ((delta + lineBufLA[0]) >> 1); + lineBufLA[2] = delta; + + delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufLB[1] = band3Buf[0] + ((delta + lineBufLB[0]) >> 1); + lineBufLB[2] = delta; + + ++band0Buf; + ++band1Buf; + ++band2Buf; + ++band3Buf; + lineBufLA += 2; + lineBufLB += 2; + } + + if (tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + const std::int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufLA[1] = band1Buf[0] + ((deltaA + lineBufLA[0]) >> 1); + + const std::int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufLB[1] = band3Buf[0] + ((deltaB + lineBufLB[0]) >> 1); + + if (wavelet->width & 1) { + lineBufLA[2] = deltaA; + lineBufLB[2] = deltaB; + } + } else if (wavelet->width & 1) { + lineBufLA[1] = band1Buf[0] + ((lineBufLA[0] + band0Buf[0] - ((band1Buf[0] + 1) >> 1)) >> 1); + lineBufLA[2] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + + lineBufLB[1] = band3Buf[0] + ((lineBufLB[0] + band2Buf[0] - ((band3Buf[0] + 1) >> 1)) >> 1); + lineBufLB[2] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } else { + lineBufLA[1] = lineBufLA[0] + band1Buf[0]; + lineBufLB[1] = lineBufLB[0] + band3Buf[0]; + } + } +} + +std::int32_t* crxIdwt53FilterGetLine(CrxPlaneComp* comp, std::int32_t level) +{ + std::int32_t* const result = comp->waveletTransform[level].lineBuf[ + (comp->waveletTransform[level].fltTapH - comp->waveletTransform[level].curH + 5) % 5 + 3 + ]; + --comp->waveletTransform[level].curH; + return result; +} + +bool crxIdwt53FilterDecode(CrxPlaneComp* comp, std::int32_t level) +{ + if (comp->waveletTransform[level].curH) { + return true; + } + + CrxSubband* const sband = comp->subBands + 3 * level; + + if (comp->waveletTransform[level].height - 3 <= comp->waveletTransform[level].curLine && !(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) { + if (comp->waveletTransform[level].height & 1) { + if (level) { + if (!crxIdwt53FilterDecode(comp, level - 1)) { + return false; + } + } else if (!crxDecodeLineWithIQuantization(sband)) { + return false; + } + + if (!crxDecodeLineWithIQuantization(sband + 1)) { + return false; + } + } + } else { + if (level) { + if (!crxIdwt53FilterDecode(comp, level - 1)) { + return false; + } + } else if (!crxDecodeLineWithIQuantization(sband)) { // LL band + return false; + } + + if ( + !crxDecodeLineWithIQuantization(sband + 1) // HL band + || !crxDecodeLineWithIQuantization(sband + 2) // LH band + || !crxDecodeLineWithIQuantization(sband + 3) // HH band + ) { + return false; + } + } + + return true; +} + +bool crxIdwt53FilterTransform(CrxPlaneComp* comp, std::uint32_t level) +{ + CrxWaveletTransform* const wavelet = comp->waveletTransform + level; + + if (wavelet->curH) { + return true; + } + + if (wavelet->curLine >= wavelet->height - 3) { + if (!(comp->tileFlag & E_HAS_TILES_ON_THE_BOTTOM)) { + if (wavelet->height & 1) { + if (level) { + if (!wavelet[-1].curH) { + if (!crxIdwt53FilterTransform(comp, level - 1)) { + return false; + } + } + + wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1); + } + + const std::int32_t* band0Buf = wavelet->subband0Buf; + const std::int32_t* band1Buf = wavelet->subband1Buf; + const std::int32_t* const lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + std::int32_t* const lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; + std::int32_t* const lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3]; + + std::int32_t* lineBufL0 = wavelet->lineBuf[0]; + std::int32_t* lineBufL1 = wavelet->lineBuf[1]; + wavelet->lineBuf[1] = wavelet->lineBuf[2]; + wavelet->lineBuf[2] = lineBufL1; + + // process L bands + if (wavelet->width <= 1) { + lineBufL0[0] = band0Buf[0]; + } else { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + ++band1Buf; + } else { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + } + + ++band0Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) { + const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); + lineBufL0[2] = delta; + ++band0Buf; + ++band1Buf; + lineBufL0 += 2; + } + + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); + + if (wavelet->width & 1) { + lineBufL0[2] = delta; + } + } else if (wavelet->width & 1) { + const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); + lineBufL0[2] = delta; + } else { + lineBufL0[1] = band1Buf[0] + lineBufL0[0]; + } + } + + // process H bands + lineBufL0 = wavelet->lineBuf[0]; + lineBufL1 = wavelet->lineBuf[1]; + + for (std::int32_t i = 0; i < wavelet->width; ++i) { + const std::int32_t delta = lineBufL0[i] - ((lineBufL1[i] + 1) >> 1); + lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1); + lineBufH2[i] = delta; + } + + wavelet->curH += 3; + wavelet->curLine += 3; + wavelet->fltTapH = (wavelet->fltTapH + 3) % 5; + } else { + std::int32_t* const lineBufL2 = wavelet->lineBuf[2]; + const std::int32_t* const lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + std::int32_t* const lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; + wavelet->lineBuf[1] = lineBufL2; + wavelet->lineBuf[2] = wavelet->lineBuf[1]; + + for (std::int32_t i = 0; i < wavelet->width; ++i) { + lineBufH1[i] = lineBufH0[i] + lineBufL2[i]; + } + + wavelet->curH += 2; + wavelet->curLine += 2; + wavelet->fltTapH = (wavelet->fltTapH + 2) % 5; + } + } + } else { + if (level) { + if (!wavelet[-1].curH && !crxIdwt53FilterTransform(comp, level - 1)) { + return false; + } + + wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1); + } + + const std::int32_t* band0Buf = wavelet->subband0Buf; + const std::int32_t* band1Buf = wavelet->subband1Buf; + const std::int32_t* band2Buf = wavelet->subband2Buf; + const std::int32_t* band3Buf = wavelet->subband3Buf; + + std::int32_t* lineBufL0 = wavelet->lineBuf[0]; + std::int32_t* lineBufL1 = wavelet->lineBuf[1]; + const std::int32_t* const lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + std::int32_t* const lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; + std::int32_t* const lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3]; - int32_t *lineBufL0 = wavelet->lineBuf[0]; - int32_t *lineBufL1 = wavelet->lineBuf[1]; wavelet->lineBuf[1] = wavelet->lineBuf[2]; wavelet->lineBuf[2] = lineBufL1; // process L bands - if (wavelet->width <= 1) - { - lineBufL0[0] = band0Buf[0]; - } - else - { - if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) - { - lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - ++band1Buf; - } - else - { - lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - } - ++band0Buf; - for (int i = 0; i < wavelet->width - 3; i += 2) - { - int32_t delta = - band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); - lineBufL0[2] = delta; + if (wavelet->width <= 1) { + lineBufL0[0] = band0Buf[0]; + lineBufL1[0] = band2Buf[0]; + } else { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + ++band1Buf; + ++band3Buf; + } else { + lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } + ++band0Buf; - ++band1Buf; - lineBufL0 += 2; - } - if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) - { - int32_t delta = - band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); - if (wavelet->width & 1) - lineBufL0[2] = delta; - } - else if (wavelet->width & 1) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - lineBufL0[1] = band1Buf[0] + ((lineBufL0[0] + delta) >> 1); - lineBufL0[2] = delta; - } - else - lineBufL0[1] = band1Buf[0] + lineBufL0[0]; + ++band2Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) { + std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1); + lineBufL0[2] = delta; + + delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1); + lineBufL1[2] = delta; + + ++band0Buf; + ++band1Buf; + ++band2Buf; + ++band3Buf; + lineBufL0 += 2; + lineBufL1 += 2; + } + + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + const std::int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufL0[1] = band1Buf[0] + ((deltaA + lineBufL0[0]) >> 1); + + const std::int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL1[1] = band3Buf[0] + ((deltaB + lineBufL1[0]) >> 1); + + if (wavelet->width & 1) { + lineBufL0[2] = deltaA; + lineBufL1[2] = deltaB; + } + } else if (wavelet->width & 1) { + std::int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1); + lineBufL0[2] = delta; + + delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1); + lineBufL1[2] = delta; + } else { + lineBufL0[1] = lineBufL0[0] + band1Buf[0]; + lineBufL1[1] = lineBufL1[0] + band3Buf[0]; + } } // process H bands lineBufL0 = wavelet->lineBuf[0]; lineBufL1 = wavelet->lineBuf[1]; - for (int32_t i = 0; i < wavelet->width; i++) - { - int32_t delta = lineBufL0[i] - ((lineBufL1[i] + 1) >> 1); - lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1); - lineBufH2[i] = delta; + const std::int32_t* lineBufL2 = wavelet->lineBuf[2]; + + for (std::int32_t i = 0; i < wavelet->width; ++i) { + const std::int32_t delta = lineBufL0[i] - ((lineBufL2[i] + lineBufL1[i] + 2) >> 2); + lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1); + lineBufH2[i] = delta; } - wavelet->curH += 3; - wavelet->curLine += 3; - wavelet->fltTapH = (wavelet->fltTapH + 3) % 5; - } - else - { - int32_t *lineBufL2 = wavelet->lineBuf[2]; - int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; - int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; - wavelet->lineBuf[1] = lineBufL2; - wavelet->lineBuf[2] = wavelet->lineBuf[1]; - for (int32_t i = 0; i < wavelet->width; i++) - lineBufH1[i] = lineBufH0[i] + lineBufL2[i]; - - wavelet->curH += 2; - wavelet->curLine += 2; - wavelet->fltTapH = (wavelet->fltTapH + 2) % 5; - } - } - } - else - { - if (level) - { - if (!wavelet[-1].curH && crxIdwt53FilterTransform(comp, level - 1)) - return -1; - wavelet->subband0Buf = crxIdwt53FilterGetLine(comp, level - 1); - } - - int32_t *band0Buf = wavelet->subband0Buf; - int32_t *band1Buf = wavelet->subband1Buf; - int32_t *band2Buf = wavelet->subband2Buf; - int32_t *band3Buf = wavelet->subband3Buf; - - int32_t *lineBufL0 = wavelet->lineBuf[0]; - int32_t *lineBufL1 = wavelet->lineBuf[1]; - int32_t *lineBufL2 = wavelet->lineBuf[2]; - int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; - int32_t *lineBufH1 = wavelet->lineBuf[(wavelet->fltTapH + 1) % 5 + 3]; - int32_t *lineBufH2 = wavelet->lineBuf[(wavelet->fltTapH + 2) % 5 + 3]; - - wavelet->lineBuf[1] = wavelet->lineBuf[2]; - wavelet->lineBuf[2] = lineBufL1; - - // process L bands - if (wavelet->width <= 1) - { - lineBufL0[0] = band0Buf[0]; - lineBufL1[0] = band2Buf[0]; - } - else - { - if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) - { - lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - ++band1Buf; - ++band3Buf; - } - else - { - lineBufL0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - lineBufL1[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); - } - ++band0Buf; - ++band2Buf; - for (int i = 0; i < wavelet->width - 3; i += 2) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1); - lineBufL0[2] = delta; - - delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1); - lineBufL1[2] = delta; - - ++band0Buf; - ++band1Buf; - ++band2Buf; - ++band3Buf; - lineBufL0 += 2; - lineBufL1 += 2; - } - if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) - { - int32_t deltaA = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufL0[1] = band1Buf[0] + ((deltaA + lineBufL0[0]) >> 1); - - int32_t deltaB = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - lineBufL1[1] = band3Buf[0] + ((deltaB + lineBufL1[0]) >> 1); - - if (wavelet->width & 1) - { - lineBufL0[2] = deltaA; - lineBufL1[2] = deltaB; + if (wavelet->curLine >= wavelet->height - 3 && (wavelet->height & 1)) { + wavelet->curH += 3; + wavelet->curLine += 3; + wavelet->fltTapH = (wavelet->fltTapH + 3) % 5; + } else { + wavelet->curH += 2; + wavelet->curLine += 2; + wavelet->fltTapH = (wavelet->fltTapH + 2) % 5; } - } - else if (wavelet->width & 1) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - lineBufL0[1] = band1Buf[0] + ((delta + lineBufL0[0]) >> 1); - lineBufL0[2] = delta; - - delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1); - lineBufL1[1] = band3Buf[0] + ((delta + lineBufL1[0]) >> 1); - lineBufL1[2] = delta; - } - else - { - lineBufL0[1] = lineBufL0[0] + band1Buf[0]; - lineBufL1[1] = lineBufL1[0] + band3Buf[0]; - } } - // process H bands - lineBufL0 = wavelet->lineBuf[0]; - lineBufL1 = wavelet->lineBuf[1]; - lineBufL2 = wavelet->lineBuf[2]; - for (int32_t i = 0; i < wavelet->width; i++) - { - int32_t delta = lineBufL0[i] - ((lineBufL2[i] + lineBufL1[i] + 2) >> 2); - lineBufH1[i] = lineBufL1[i] + ((delta + lineBufH0[i]) >> 1); - lineBufH2[i] = delta; - } - if (wavelet->curLine >= wavelet->height - 3 && wavelet->height & 1) - { - wavelet->curH += 3; - wavelet->curLine += 3; - wavelet->fltTapH = (wavelet->fltTapH + 3) % 5; - } - else - { - wavelet->curH += 2; - wavelet->curLine += 2; - wavelet->fltTapH = (wavelet->fltTapH + 2) % 5; - } - } - - return 0; + return true; } -int crxIdwt53FilterInitialize(CrxPlaneComp *comp, int32_t prevLevel) +bool crxIdwt53FilterInitialize(CrxPlaneComp* comp, std::int32_t prevLevel) { - if (prevLevel < 0) - return 0; + if (prevLevel < 0) { + return true; + } - for (int curLevel = 0, curBand = 0; curLevel < prevLevel + 1; - curLevel++, curBand += 3) - { - CrxWaveletTransform *wavelet = comp->waveletTransform + curLevel; - if (curLevel) - wavelet[0].subband0Buf = crxIdwt53FilterGetLine(comp, curLevel - 1); - else if (crxDecodeLineWithIQuantization(comp->subBands + curBand)) - return -1; + for (int curLevel = 0, curBand = 0; curLevel < prevLevel + 1; ++curLevel, curBand += 3) { + CrxWaveletTransform* const wavelet = comp->waveletTransform + curLevel; - int32_t *lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; - if (wavelet->height > 1) - { - if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 1) || - crxDecodeLineWithIQuantization(comp->subBands + curBand + 2) || - crxDecodeLineWithIQuantization(comp->subBands + curBand + 3)) - return -1; - - int32_t *lineBufL0 = wavelet->lineBuf[0]; - int32_t *lineBufL1 = wavelet->lineBuf[1]; - int32_t *lineBufL2 = wavelet->lineBuf[2]; - - if (comp->tileFlag & E_HAS_TILES_ON_THE_TOP) - { - crxHorizontal53(lineBufL0, wavelet->lineBuf[1], wavelet, - comp->tileFlag); - if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 3) || - crxDecodeLineWithIQuantization(comp->subBands + curBand + 2)) - return -1; - - int32_t *band2Buf = wavelet->subband2Buf; - int32_t *band3Buf = wavelet->subband3Buf; - - // process L band - if (wavelet->width <= 1) - lineBufL2[0] = band2Buf[0]; - else - { - if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) - { - lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - ++band3Buf; - } - else - lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); - - ++band2Buf; - - for (int i = 0; i < wavelet->width - 3; i += 2) - { - int32_t delta = - band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); - lineBufL2[2] = delta; - - ++band2Buf; - ++band3Buf; - lineBufL2 += 2; - } - if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) - { - int32_t delta = - band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); - lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); - if (wavelet->width & 1) - lineBufL2[2] = delta; - } - else if (wavelet->width & 1) - { - int32_t delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1); - - lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); - lineBufL2[2] = delta; - } - else - { - lineBufL2[1] = band3Buf[0] + lineBufL2[0]; - } + if (curLevel) { + wavelet[0].subband0Buf = crxIdwt53FilterGetLine(comp, curLevel - 1); + } else if (!crxDecodeLineWithIQuantization(comp->subBands + curBand)) { + return false; } - // process H band - for (int32_t i = 0; i < wavelet->width; i++) - lineBufH0[i] = - lineBufL0[i] - ((lineBufL1[i] + lineBufL2[i] + 2) >> 2); - } - else - { - crxHorizontal53(lineBufL0, wavelet->lineBuf[2], wavelet, - comp->tileFlag); - for (int i = 0; i < wavelet->width; i++) - lineBufH0[i] = lineBufL0[i] - ((lineBufL2[i] + 1) >> 1); - } - - if (crxIdwt53FilterDecode(comp, curLevel) || - crxIdwt53FilterTransform(comp, curLevel)) - return -1; - } - else - { - if (crxDecodeLineWithIQuantization(comp->subBands + curBand + 1)) - return -1; - - int32_t *band0Buf = wavelet->subband0Buf; - int32_t *band1Buf = wavelet->subband1Buf; - - // process H band - if (wavelet->width <= 1) - lineBufH0[0] = band0Buf[0]; - else - { - if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) - { - lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - ++band1Buf; - } - else - lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - - ++band0Buf; - - for (int i = 0; i < wavelet->width - 3; i += 2) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); - lineBufH0[2] = delta; - - ++band0Buf; - ++band1Buf; - lineBufH0 += 2; - } - - if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); - lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); - lineBufH0[2] = delta; - } - else if (wavelet->width & 1) - { - int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); - lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); - lineBufH0[2] = delta; - } - else - { - lineBufH0[1] = band1Buf[0] + lineBufH0[0]; - } - } - ++wavelet->curLine; - ++wavelet->curH; - wavelet->fltTapH = (wavelet->fltTapH + 1) % 5; - } - } - - return 0; -} - -void crxFreeSubbandData(CrxImage *image, CrxPlaneComp *comp) -{ - if (comp->compBuf) - { - free(comp->compBuf); - comp->compBuf = 0; - } - - if (!comp->subBands) - return; - - for (int32_t i = 0; i < image->subbandCount; i++) - { - if (comp->subBands[i].bandParam) - { - free(comp->subBands[i].bandParam); - comp->subBands[i].bandParam = 0LL; - } - comp->subBands[i].bandBuf = 0; - comp->subBands[i].bandSize = 0; - } -} - -void crxConvertPlaneLine(CrxImage *img, int imageRow, int imageCol = 0, - int plane = 0, int32_t *lineData = 0, - int lineLength = 0) -{ - if (lineData) - { - uint64_t rawOffset = 4 * img->planeWidth * imageRow + 2 * imageCol; - if (img->encType == 1) - { - int32_t maxVal = 1 << (img->nBits - 1); - int32_t minVal = -maxVal; - --maxVal; - for (int i = 0; i < lineLength; i++) - img->outBufs[plane][rawOffset + 2 * i] = - _constrain(lineData[i], minVal, maxVal); - } - else if (img->encType == 3) - { - // copy to intermediate planeBuf - rawOffset = plane * img->planeWidth * img->planeHeight + - img->planeWidth * imageRow + imageCol; - for (int i = 0; i < lineLength; i++) - img->planeBuf[rawOffset + i] = lineData[i]; - } - else if (img->nPlanes == 4) - { - int32_t median = 1 << (img->nBits - 1); - int32_t maxVal = (1 << img->nBits) - 1; - for (int i = 0; i < lineLength; i++) - img->outBufs[plane][rawOffset + 2 * i] = - _constrain(median + lineData[i], 0, maxVal); - } - else if (img->nPlanes == 1) - { - int32_t maxVal = (1 << img->nBits) - 1; - int32_t median = 1 << (img->nBits - 1); - rawOffset = img->planeWidth * imageRow + imageCol; - for (int i = 0; i < lineLength; i++) - img->outBufs[0][rawOffset + i] = - _constrain(median + lineData[i], 0, maxVal); - } - } - else if (img->encType == 3 && img->planeBuf) - { - int32_t planeSize = img->planeWidth * img->planeHeight; - int16_t *plane0 = img->planeBuf + imageRow * img->planeWidth; - int16_t *plane1 = plane0 + planeSize; - int16_t *plane2 = plane1 + planeSize; - int16_t *plane3 = plane2 + planeSize; - - int32_t median = 1 << (img->nBits - 1) << 10; - int32_t maxVal = (1 << img->nBits) - 1; - uint32_t rawLineOffset = 4 * img->planeWidth * imageRow; - - // for this stage - all except imageRow is ignored - for (int i = 0; i < img->planeWidth; i++) - { - int32_t gr = - median + (plane0[i] << 10) - 168 * plane1[i] - 585 * plane3[i]; - int32_t val = 0; - if (gr < 0) - gr = -(((_abs(gr) + 512) >> 9) & ~1); - else - gr = ((_abs(gr) + 512) >> 9) & ~1; - - // Essentially R = round(median + P0 + 1.474*P3) - val = (median + (plane0[i] << 10) + 1510 * plane3[i] + 512) >> 10; - img->outBufs[0][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); - // Essentially G1 = round(median + P0 + P2 - 0.164*P1 - 0.571*P3) - val = (plane2[i] + gr + 1) >> 1; - img->outBufs[1][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); - // Essentially G1 = round(median + P0 - P2 - 0.164*P1 - 0.571*P3) - val = (gr - plane2[i] + 1) >> 1; - img->outBufs[2][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); - // Essentially B = round(median + P0 + 1.881*P1) - val = (median + (plane0[i] << 10) + 1927 * plane1[i] + 512) >> 10; - img->outBufs[3][rawLineOffset + 2 * i] = _constrain(val, 0, maxVal); - } - } -} - -int crxParamInit(CrxBandParam **param, uint64_t subbandMdatOffset, - uint64_t subbandDataSize, uint32_t subbandWidth, - uint32_t subbandHeight, int32_t supportsPartial, - uint32_t roundedBitsMask, LibRaw_abstract_datastream *input) -{ - int32_t progrDataSize = supportsPartial ? 0 : sizeof(int32_t) * subbandWidth; - int32_t paramLength = 2 * subbandWidth + 4; - uint8_t *paramBuf = (uint8_t *)calloc( - 1, sizeof(CrxBandParam) + sizeof(int32_t) * paramLength + progrDataSize); - - if (!paramBuf) - return -1; - - *param = (CrxBandParam *)paramBuf; - - paramBuf += sizeof(CrxBandParam); - - (*param)->paramData = (int32_t *)paramBuf; - (*param)->nonProgrData = - progrDataSize ? (*param)->paramData + paramLength : 0; - (*param)->subbandWidth = subbandWidth; - (*param)->subbandHeight = subbandHeight; - (*param)->roundedBits = 0; - (*param)->curLine = 0; - (*param)->roundedBitsMask = roundedBitsMask; - (*param)->supportsPartial = supportsPartial; - (*param)->bitStream.bitData = 0; - (*param)->bitStream.bitsLeft = 0; - (*param)->bitStream.mdatSize = subbandDataSize; - (*param)->bitStream.curPos = 0; - (*param)->bitStream.curBufSize = 0; - (*param)->bitStream.curBufOffset = subbandMdatOffset; - (*param)->bitStream.input = input; - - crxFillBuffer(&(*param)->bitStream); - - return 0; -} - -int crxSetupSubbandData(CrxImage *img, CrxPlaneComp *planeComp, - const CrxTile *tile, uint32_t mdatOffset) -{ - long compDataSize = 0; - long waveletDataOffset = 0; - long compCoeffDataOffset = 0; - int32_t toSubbands = 3 * img->levels + 1; - int32_t transformWidth = 0; - - CrxSubband *subbands = planeComp->subBands; - - // calculate sizes - for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++) - { - subbands[subbandNum].bandSize = - subbands[subbandNum].width * sizeof(int32_t); // 4bytes - compDataSize += subbands[subbandNum].bandSize; - } - - if (img->levels) - { - int32_t encLevels = img->levels ? img->levels : 1; - waveletDataOffset = (compDataSize + 7) & ~7; - compDataSize = - (sizeof(CrxWaveletTransform) * encLevels + waveletDataOffset + 7) & ~7; - compCoeffDataOffset = compDataSize; - - // calc wavelet line buffer sizes (always at one level up from current) - for (int level = 0; level < img->levels; ++level) - if (level < img->levels - 1) - compDataSize += 8 * sizeof(int32_t) * - planeComp->subBands[3 * (level + 1) + 2].width; - else - compDataSize += 8 * sizeof(int32_t) * tile->width; - } - - // buffer allocation - planeComp->compBuf = (uint8_t *)malloc(compDataSize); - if (!planeComp->compBuf) - return -1; - - // subbands buffer and sizes initialisation - uint64_t subbandMdatOffset = img->mdatOffset + mdatOffset; - uint8_t *subbandBuf = planeComp->compBuf; - - for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++) - { - subbands[subbandNum].bandBuf = subbandBuf; - subbandBuf += subbands[subbandNum].bandSize; - subbands[subbandNum].mdatOffset = - subbandMdatOffset + subbands[subbandNum].dataOffset; - } - - // wavelet data initialisation - if (img->levels) - { - CrxWaveletTransform *waveletTransforms = - (CrxWaveletTransform *)(planeComp->compBuf + waveletDataOffset); - int32_t *paramData = (int32_t *)(planeComp->compBuf + compCoeffDataOffset); - - planeComp->waveletTransform = waveletTransforms; - waveletTransforms[0].subband0Buf = (int32_t *)subbands->bandBuf; - - for (int level = 0; level < img->levels; ++level) - { - int32_t band = 3 * level + 1; - - if (level >= img->levels - 1) - { - waveletTransforms[level].height = tile->height; - transformWidth = tile->width; - } - else - { - waveletTransforms[level].height = subbands[band + 3].height; - transformWidth = subbands[band + 4].width; - } - waveletTransforms[level].width = transformWidth; - waveletTransforms[level].lineBuf[0] = paramData; - waveletTransforms[level].lineBuf[1] = - waveletTransforms[level].lineBuf[0] + transformWidth; - waveletTransforms[level].lineBuf[2] = - waveletTransforms[level].lineBuf[1] + transformWidth; - waveletTransforms[level].lineBuf[3] = - waveletTransforms[level].lineBuf[2] + transformWidth; - waveletTransforms[level].lineBuf[4] = - waveletTransforms[level].lineBuf[3] + transformWidth; - waveletTransforms[level].lineBuf[5] = - waveletTransforms[level].lineBuf[4] + transformWidth; - waveletTransforms[level].lineBuf[6] = - waveletTransforms[level].lineBuf[5] + transformWidth; - waveletTransforms[level].lineBuf[7] = - waveletTransforms[level].lineBuf[6] + transformWidth; - waveletTransforms[level].curLine = 0; - waveletTransforms[level].curH = 0; - waveletTransforms[level].fltTapH = 0; - waveletTransforms[level].subband1Buf = (int32_t *)subbands[band].bandBuf; - waveletTransforms[level].subband2Buf = - (int32_t *)subbands[band + 1].bandBuf; - waveletTransforms[level].subband3Buf = - (int32_t *)subbands[band + 2].bandBuf; - - paramData = waveletTransforms[level].lineBuf[7] + transformWidth; - } - } - - // decoding params and bitstream initialisation - for (int32_t subbandNum = 0; subbandNum < toSubbands; subbandNum++) - { - if (subbands[subbandNum].dataSize) - { - int32_t supportsPartial = 0; - uint32_t roundedBitsMask = 0; - - if (planeComp->supportsPartial && subbandNum == 0) - { - roundedBitsMask = planeComp->roundedBitsMask; - supportsPartial = 1; - } - if (crxParamInit(&subbands[subbandNum].bandParam, - subbands[subbandNum].mdatOffset, - subbands[subbandNum].dataSize, - subbands[subbandNum].width, subbands[subbandNum].height, - supportsPartial, roundedBitsMask, img->input)) - return -1; - } - } - - return 0; -} - -} // namespace - - -int DCraw::crxDecodePlane(void *p, uint32_t planeNumber) -{ - CrxImage *img = (CrxImage *)p; - int imageRow = 0; - for (int tRow = 0; tRow < img->tileRows; tRow++) - { - int imageCol = 0; - for (int tCol = 0; tCol < img->tileCols; tCol++) - { - CrxTile *tile = img->tiles + tRow * img->tileRows + tCol; - CrxPlaneComp *planeComp = tile->comps + planeNumber; - uint64_t tileMdatOffset = tile->dataOffset + planeComp->dataOffset; - - // decode single tile - if (crxSetupSubbandData(img, planeComp, tile, tileMdatOffset)) - return -1; - - if (img->levels) - { - if (crxIdwt53FilterInitialize(planeComp, img->levels - 1)) - return -1; - for (int i = 0; i < tile->height; ++i) - { - if (crxIdwt53FilterDecode(planeComp, img->levels - 1) || - crxIdwt53FilterTransform(planeComp, img->levels - 1)) - return -1; - int32_t *lineData = - crxIdwt53FilterGetLine(planeComp, img->levels - 1); - crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, - lineData, tile->width); - } - } - else - { - // we have the only subband in this case - if (!planeComp->subBands->dataSize) - { - memset(planeComp->subBands->bandBuf, 0, - planeComp->subBands->bandSize); - return 0; - } - - for (int i = 0; i < tile->height; ++i) - { - if (crxDecodeLine(planeComp->subBands->bandParam, - planeComp->subBands->bandBuf)) - return -1; - int32_t *lineData = (int32_t *)planeComp->subBands->bandBuf; - crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, - lineData, tile->width); - } - } - imageCol += tile->width; - } - imageRow += img->tiles[tRow * img->tileRows].height; - } - - return 0; -} - - -namespace { - -typedef DCraw::CanonCR3Data::crx_data_header_t crx_data_header_t; - - -int crxReadSubbandHeaders(crx_data_header_t *hdr, CrxImage *img, CrxTile *tile, - CrxPlaneComp *comp, uint8_t **subbandMdatPtr, - uint32_t *mdatSize) -{ - CrxSubband *band = comp->subBands + img->subbandCount - 1; // set to last band - uint32_t bandHeight = tile->height; - uint32_t bandWidth = tile->width; - int32_t bandWidthExCoef = 0; - int32_t bandHeightExCoef = 0; - if (img->levels) - { - // Build up subband sequences to crxDecode to a level in a header - - // Coefficient structure is a bit unclear and convoluted: - // 3 levels max - 8 groups (for tile width rounded to 8 bytes) - // of 3 band per level 4 sets of coefficients for each - int32_t *rowExCoef = - exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->width & 7); - int32_t *colExCoef = - exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->height & 7); - for (int level = 0; level < img->levels; ++level) - { - int32_t widthOddPixel = bandWidth & 1; - int32_t heightOddPixel = bandHeight & 1; - bandWidth = (widthOddPixel + bandWidth) >> 1; - bandHeight = (heightOddPixel + bandHeight) >> 1; - - int32_t bandWidthExCoef0 = 0; - int32_t bandWidthExCoef1 = 0; - int32_t bandHeightExCoef0 = 0; - int32_t bandHeightExCoef1 = 0; - if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) - { - bandWidthExCoef0 = rowExCoef[0]; - bandWidthExCoef1 = rowExCoef[1]; - } - if (tile->tileFlag & E_HAS_TILES_ON_THE_LEFT) - ++bandWidthExCoef0; - if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) - { - bandHeightExCoef0 = colExCoef[0]; - bandHeightExCoef1 = colExCoef[1]; - } - if (tile->tileFlag & E_HAS_TILES_ON_THE_TOP) - ++bandHeightExCoef0; - - band[0].width = bandWidth + bandWidthExCoef0 - widthOddPixel; - band[0].height = bandHeight + bandHeightExCoef0 - heightOddPixel; - - band[-1].width = bandWidth + bandWidthExCoef1; - band[-1].height = bandHeight + bandHeightExCoef0 - heightOddPixel; - - band[-2].width = bandWidth + bandWidthExCoef0 - widthOddPixel; - band[-2].height = bandHeight + bandHeightExCoef1; - - rowExCoef += 4; - colExCoef += 4; - band -= 3; - } - bandWidthExCoef = bandHeightExCoef = 0; - if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) - bandWidthExCoef = - exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->width & 7) + - 4 * (img->levels - 1) + 1]; - if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) - bandHeightExCoef = - exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->height & 7) + - 4 * (img->levels - 1) + 1]; - } - band->width = bandWidthExCoef + bandWidth; - band->height = bandHeightExCoef + bandHeight; - - if (!img->subbandCount) - return 0; - int32_t curSubband = 0; - int32_t subbandOffset = 0; - band = comp->subBands; - for (int curSubband = 0; curSubband < img->subbandCount; curSubband++, band++) - { - if (*mdatSize < 0xC) - return -1; - - if (sgetn(2, *subbandMdatPtr) != 0xFF03) - return -1; - - uint32_t bitData = sgetn(4, *subbandMdatPtr + 8); - uint32_t subbandSize = sgetn(4, *subbandMdatPtr + 4); - - if (curSubband != bitData >> 28) - { - band->dataSize = subbandSize; - return -1; - } - band->dataSize = subbandSize - (bitData & 0x7FF); - band->supportsPartial = bitData & 0x8000 ? 1 : 0; - band->dataOffset = subbandOffset; - band->quantValue = (bitData >> 19) & 0xFF; - band->paramK = 0; - band->bandParam = 0; - band->bandBuf = 0; - band->bandSize = 0; - - subbandOffset += subbandSize; - - *subbandMdatPtr += 0xC; - *mdatSize -= 0xC; - } - return 0; -} - -int crxReadImageHeaders(crx_data_header_t *hdr, CrxImage *img, uint8_t *mdatPtr, - uint32_t mdatSize) -{ - int nTiles = img->tileRows * img->tileCols; - - if (!nTiles) - return -1; - - if (!img->tiles) - { - img->tiles = (CrxTile *)malloc( - sizeof(CrxTile) * nTiles + - sizeof(CrxPlaneComp) * nTiles * img->nPlanes + - sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount); - if (!img->tiles) - return -1; - - // memory areas in allocated chunk - CrxTile *tile = img->tiles; - CrxPlaneComp *comps = (CrxPlaneComp *)(tile + nTiles); - CrxSubband *bands = (CrxSubband *)(comps + img->nPlanes * nTiles); - - for (int curTile = 0; curTile < nTiles; curTile++, tile++) - { - tile->tileFlag = 0; // tile neighbouring flags - tile->tileNumber = curTile; - tile->tileSize = 0; - tile->comps = comps + curTile * img->nPlanes; - - if ((curTile + 1) % img->tileCols) - { - // not the last tile in a tile row - tile->width = hdr->tileWidth; - if (img->tileCols > 1) - { - tile->tileFlag = E_HAS_TILES_ON_THE_RIGHT; - if (curTile % img->tileCols) - // not the first tile in tile row - tile->tileFlag |= E_HAS_TILES_ON_THE_LEFT; - } - } - else - { - // last tile in a tile row - tile->width = img->planeWidth - hdr->tileWidth * (img->tileCols - 1); - if (img->tileCols > 1) - tile->tileFlag = E_HAS_TILES_ON_THE_LEFT; - } - if (curTile < nTiles - img->tileCols) - { - // in first tile row - tile->height = hdr->tileHeight; - if (img->tileRows > 1) - { - tile->tileFlag |= E_HAS_TILES_ON_THE_BOTTOM; - if (curTile >= img->tileCols) - tile->tileFlag |= E_HAS_TILES_ON_THE_TOP; - } - } - else - { - // non first tile row - tile->height = img->planeHeight - hdr->tileHeight * (img->tileRows - 1); - if (img->tileRows > 1) - tile->tileFlag |= E_HAS_TILES_ON_THE_TOP; - } - if (img->nPlanes) - { - CrxPlaneComp *comp = tile->comps; - CrxSubband *band = bands + curTile * img->nPlanes * img->subbandCount; - - for (int curComp = 0; curComp < img->nPlanes; curComp++, comp++) - { - comp->compNumber = curComp; - comp->supportsPartial = 1; - comp->tileFlag = tile->tileFlag; - comp->subBands = band; - comp->compBuf = 0; - comp->waveletTransform = 0; - if (img->subbandCount) - { - for (int curBand = 0; curBand < img->subbandCount; - curBand++, band++) - { - band->supportsPartial = 0; - band->quantValue = 4; - band->bandParam = 0; - band->dataSize = 0; + std::int32_t* lineBufH0 = wavelet->lineBuf[wavelet->fltTapH + 3]; + + if (wavelet->height > 1) { + if ( + !crxDecodeLineWithIQuantization(comp->subBands + curBand + 1) + || !crxDecodeLineWithIQuantization(comp->subBands + curBand + 2) + || !crxDecodeLineWithIQuantization(comp->subBands + curBand + 3) + ) { + return false; } - } + + std::int32_t* const lineBufL0 = wavelet->lineBuf[0]; + const std::int32_t* const lineBufL1 = wavelet->lineBuf[1]; + std::int32_t* lineBufL2 = wavelet->lineBuf[2]; + + if (comp->tileFlag & E_HAS_TILES_ON_THE_TOP) { + crxHorizontal53(lineBufL0, wavelet->lineBuf[1], wavelet, comp->tileFlag); + + if (!crxDecodeLineWithIQuantization(comp->subBands + curBand + 3)|| !crxDecodeLineWithIQuantization(comp->subBands + curBand + 2)) { + return false; + } + + const std::int32_t* band2Buf = wavelet->subband2Buf; + const std::int32_t* band3Buf = wavelet->subband3Buf; + + // process L band + if (wavelet->width <= 1) { + lineBufL2[0] = band2Buf[0]; + } else { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) { + lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + ++band3Buf; + } else { + lineBufL2[0] = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + } + + ++band2Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) { + const std::int32_t delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); + lineBufL2[2] = delta; + + ++band2Buf; + ++band3Buf; + lineBufL2 += 2; + } + + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + const std::int32_t delta = band2Buf[0] - ((band3Buf[0] + band3Buf[1] + 2) >> 2); + lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); + + if (wavelet->width & 1) { + lineBufL2[2] = delta; + } + } else if (wavelet->width & 1) { + const std::int32_t delta = band2Buf[0] - ((band3Buf[0] + 1) >> 1); + + lineBufL2[1] = band3Buf[0] + ((lineBufL2[0] + delta) >> 1); + lineBufL2[2] = delta; + } else { + lineBufL2[1] = band3Buf[0] + lineBufL2[0]; + } + } + + // process H band + for (std::int32_t i = 0; i < wavelet->width; ++i) { + lineBufH0[i] = lineBufL0[i] - ((lineBufL1[i] + lineBufL2[i] + 2) >> 2); + } + } else { + crxHorizontal53(lineBufL0, wavelet->lineBuf[2], wavelet, comp->tileFlag); + + for (int i = 0; i < wavelet->width; ++i) { + lineBufH0[i] = lineBufL0[i] - ((lineBufL2[i] + 1) >> 1); + } + } + + if (!crxIdwt53FilterDecode(comp, curLevel) || !crxIdwt53FilterTransform(comp, curLevel)) { + return false; + } + } else { + if (!crxDecodeLineWithIQuantization(comp->subBands + curBand + 1)) { + return false; + } + + const std::int32_t* band0Buf = wavelet->subband0Buf; + const std::int32_t* band1Buf = wavelet->subband1Buf; + + // process H band + if (wavelet->width <= 1) { + lineBufH0[0] = band0Buf[0]; + } else { + if (comp->tileFlag & E_HAS_TILES_ON_THE_LEFT) { + lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + ++band1Buf; + } else { + lineBufH0[0] = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + } + + ++band0Buf; + + for (int i = 0; i < wavelet->width - 3; i += 2) { + std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); + lineBufH0[2] = delta; + + ++band0Buf; + ++band1Buf; + lineBufH0 += 2; + } + + if (comp->tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + band1Buf[1] + 2) >> 2); + lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); + lineBufH0[2] = delta; + } else if (wavelet->width & 1) { + const std::int32_t delta = band0Buf[0] - ((band1Buf[0] + 1) >> 1); + lineBufH0[1] = band1Buf[0] + ((lineBufH0[0] + delta) >> 1); + lineBufH0[2] = delta; + } else { + lineBufH0[1] = band1Buf[0] + lineBufH0[0]; + } + } + + ++wavelet->curLine; + ++wavelet->curH; + wavelet->fltTapH = (wavelet->fltTapH + 1) % 5; } - } } - } - uint32_t tileOffset = 0; - uint32_t dataSize = mdatSize; - uint8_t *dataPtr = mdatPtr; - CrxTile *tile = img->tiles; - - for (int curTile = 0; curTile < nTiles; curTile++, tile++) - { - if (dataSize < 0xC) - return -1; - - if (sgetn(2, dataPtr) != 0xFF01) - return -1; - if (sgetn(2, dataPtr + 8) != curTile) - return -1; - - dataSize -= 0xC; - - tile->tileSize = sgetn(4, dataPtr + 4); - tile->dataOffset = tileOffset; - - int32_t hdrExtraBytes = sgetn(2, dataPtr + 2) - 8; - tileOffset += tile->tileSize; - dataPtr += hdrExtraBytes + 0xC; - dataSize -= hdrExtraBytes; - - uint32_t compOffset = 0; - CrxPlaneComp *comp = tile->comps; - - for (int compNum = 0; compNum < img->nPlanes; compNum++, comp++) - { - if (dataSize < 0xC) - return -1; - - if (sgetn(2, dataPtr) != 0xFF02) - return -1; - if (compNum != dataPtr[8] >> 4) - return -1; - - comp->compSize = sgetn(4, dataPtr + 4); - - int32_t compHdrRoundedBits = (dataPtr[8] >> 1) & 3; - comp->supportsPartial = (dataPtr[8] & 8) != 0; - - comp->dataOffset = compOffset; - comp->tileFlag = tile->tileFlag; - - compOffset += comp->compSize; - dataSize -= 0xC; - dataPtr += 0xC; - - comp->roundedBitsMask = 0; - - if (compHdrRoundedBits) - { - if (img->levels || !comp->supportsPartial) - return -1; - - comp->roundedBitsMask = 1 << (compHdrRoundedBits - 1); - } - - if (crxReadSubbandHeaders(hdr, img, tile, comp, &dataPtr, &dataSize)) - return -1; - } - } - return 0; + return true; } -int crxSetupImageData(crx_data_header_t *hdr, CrxImage *img, int16_t *outBuf, - uint64_t mdatOffset, uint32_t mdatSize, - uint8_t *mdatHdrPtr) +void crxFreeSubbandData(CrxImage* image, CrxPlaneComp* comp) { - int IncrBitTable[32] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 1, 0, - 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 0}; - - img->planeWidth = hdr->f_width; - img->planeHeight = hdr->f_height; - - if (hdr->tileWidth < 0x16 || hdr->tileHeight < 0x16 || - img->planeWidth > 0x7FFF || img->planeHeight > 0x7FFF) - return -1; - - img->tileCols = (img->planeWidth + hdr->tileWidth - 1) / hdr->tileWidth; - img->tileRows = (img->planeHeight + hdr->tileHeight - 1) / hdr->tileHeight; - - if (img->tileCols > 0xFF || img->tileRows > 0xFF || - img->planeWidth - hdr->tileWidth * (img->tileCols - 1) < 0x16 || - img->planeHeight - hdr->tileHeight * (img->tileRows - 1) < 0x16) - return -1; - - img->tiles = 0; - img->levels = hdr->imageLevels; - img->subbandCount = 3 * img->levels + 1; // 3 bands per level + one last LL - img->nPlanes = hdr->nPlanes; - img->nBits = hdr->nBits; - img->encType = hdr->encType; - img->samplePrecision = hdr->nBits + IncrBitTable[4 * hdr->encType + 2] + 1; - img->mdatOffset = mdatOffset + hdr->mdatHdrSize; - img->mdatSize = mdatSize; - img->planeBuf = 0; - img->outBufs[0] = img->outBufs[1] = img->outBufs[2] = img->outBufs[3] = 0; - - // The encoding type 3 needs all 4 planes to be decoded to generate row of - // RGGB values. It seems to be using some other colour space for raw encoding - // It is a massive buffer so ideallly it will need a different approach: - // decode planes line by line and convert single line then without - // intermediate plane buffer. At the moment though it's too many changes so - // left as is. - if (img->encType == 3 && img->nPlanes == 4 && img->nBits > 8) - { - img->planeBuf = - (int16_t *)malloc(img->planeHeight * img->planeWidth * img->nPlanes * - ((img->samplePrecision + 7) >> 3)); - if (!img->planeBuf) - return -1; - } - - int32_t rowSize = 2 * img->planeWidth; - - if (img->nPlanes == 1) - img->outBufs[0] = outBuf; - else - switch (hdr->cfaLayout) - { - case 0: - // R G - // G B - img->outBufs[0] = outBuf; - img->outBufs[1] = outBuf + 1; - img->outBufs[2] = outBuf + rowSize; - img->outBufs[3] = img->outBufs[2] + 1; - break; - case 1: - // G R - // B G - img->outBufs[1] = outBuf; - img->outBufs[0] = outBuf + 1; - img->outBufs[3] = outBuf + rowSize; - img->outBufs[2] = img->outBufs[3] + 1; - break; - case 2: - // G B - // R G - img->outBufs[2] = outBuf; - img->outBufs[3] = outBuf + 1; - img->outBufs[0] = outBuf + rowSize; - img->outBufs[1] = img->outBufs[0] + 1; - break; - case 3: - // B G - // G R - img->outBufs[3] = outBuf; - img->outBufs[2] = outBuf + 1; - img->outBufs[1] = outBuf + rowSize; - img->outBufs[0] = img->outBufs[1] + 1; - break; + if (comp->compBuf) { + free(comp->compBuf); + comp->compBuf = nullptr; } - // read header - return crxReadImageHeaders(hdr, img, mdatHdrPtr, mdatSize); + if (!comp->subBands) { + return; + } + + for (std::int32_t i = 0; i < image->subbandCount; ++i) { + if (comp->subBands[i].bandParam) { + free(comp->subBands[i].bandParam); + comp->subBands[i].bandParam = nullptr; + } + + comp->subBands[i].bandBuf = nullptr; + comp->subBands[i].bandSize = 0; + } } -int crxFreeImageData(CrxImage *img) +void crxConvertPlaneLine( + CrxImage* img, + int imageRow, + int imageCol = 0, + int plane = 0, + const std::int32_t* lineData = nullptr, + int lineLength = 0 +) { - CrxTile *tile = img->tiles; - int nTiles = img->tileRows * img->tileCols; + if (lineData) { + std::uint64_t rawOffset = 4 * img->planeWidth * imageRow + 2 * imageCol; - if (img->tiles) - { - for (int32_t curTile = 0; curTile < nTiles; curTile++, tile++) - if (tile[curTile].comps) - for (int32_t curPlane = 0; curPlane < img->nPlanes; curPlane++) - crxFreeSubbandData(img, tile[curTile].comps + curPlane); - free(img->tiles); - img->tiles = 0; - } + if (img->encType == 1) { + const std::int32_t maxVal = 1 << (img->nBits - 1); + const std::int32_t minVal = -maxVal; - if (img->planeBuf) - { - free(img->planeBuf); - img->planeBuf = 0; - } + for (int i = 0; i < lineLength; ++i) { + img->outBufs[plane][rawOffset + 2 * i] = rtengine::LIM(lineData[i], minVal, maxVal - 1); + } + } else if (img->encType == 3) { + // copy to intermediate planeBuf + rawOffset = plane * img->planeWidth * img->planeHeight + img->planeWidth * imageRow + imageCol; - return 0; + for (int i = 0; i < lineLength; ++i) { + img->planeBuf[rawOffset + i] = lineData[i]; + } + } else if (img->nPlanes == 4) { + const std::int32_t median = 1 << (img->nBits - 1); + const std::int32_t maxVal = (1 << img->nBits) - 1; + + for (int i = 0; i < lineLength; ++i) { + img->outBufs[plane][rawOffset + 2 * i] = rtengine::LIM(median + lineData[i], 0, maxVal); + } + } else if (img->nPlanes == 1) { + const std::int32_t maxVal = (1 << img->nBits) - 1; + const std::int32_t median = 1 << (img->nBits - 1); + + rawOffset = img->planeWidth * imageRow + imageCol; + + for (int i = 0; i < lineLength; ++i) { + img->outBufs[0][rawOffset + i] = rtengine::LIM(median + lineData[i], 0, maxVal); + } + } + } else if (img->encType == 3 && img->planeBuf) { + const std::int32_t planeSize = img->planeWidth * img->planeHeight; + const std::int16_t* const plane0 = img->planeBuf + imageRow * img->planeWidth; + const std::int16_t* const plane1 = plane0 + planeSize; + const std::int16_t* const plane2 = plane1 + planeSize; + const std::int16_t* const plane3 = plane2 + planeSize; + + const std::int32_t median = 1 << (img->nBits - 1) << 10; + const std::int32_t maxVal = (1 << img->nBits) - 1; + const std::uint32_t rawLineOffset = 4 * img->planeWidth * imageRow; + + // for this stage - all except imageRow is ignored + for (int i = 0; i < img->planeWidth; ++i) { + std::int32_t gr = median + (plane0[i] << 10) - 168 * plane1[i] - 585 * plane3[i]; + + if (gr < 0) { + gr = -(((std::abs(gr) + 512) >> 9) & ~1); + } else { + gr = ((std::abs(gr) + 512) >> 9) & ~1; + } + + // Essentially R = round(median + P0 + 1.474*P3) + std::int32_t val = (median + (plane0[i] << 10) + 1510 * plane3[i] + 512) >> 10; + img->outBufs[0][rawLineOffset + 2 * i] = rtengine::LIM(val, 0, maxVal); + // Essentially G1 = round(median + P0 + P2 - 0.164*P1 - 0.571*P3) + val = (plane2[i] + gr + 1) >> 1; + img->outBufs[1][rawLineOffset + 2 * i] = rtengine::LIM(val, 0, maxVal); + // Essentially G1 = round(median + P0 - P2 - 0.164*P1 - 0.571*P3) + val = (gr - plane2[i] + 1) >> 1; + img->outBufs[2][rawLineOffset + 2 * i] = rtengine::LIM(val, 0, maxVal); + // Essentially B = round(median + P0 + 1.881*P1) + val = (median + (plane0[i] << 10) + 1927 * plane1[i] + 512) >> 10; + img->outBufs[3][rawLineOffset + 2 * i] = rtengine::LIM(val, 0, maxVal); + } + } +} + +bool crxParamInit( + CrxBandParam** param, + std::uint64_t subbandMdatOffset, + std::uint64_t subbandDataSize, + std::uint32_t subbandWidth, + std::uint32_t subbandHeight, + bool supportsPartial, + std::uint32_t roundedBitsMask, + LibRaw_abstract_datastream* input +) +{ + const std::int32_t progrDataSize = + supportsPartial + ? 0 + : sizeof(std::int32_t) * subbandWidth; + const std::int32_t paramLength = 2 * subbandWidth + 4; + + std::uint8_t* paramBuf = static_cast(calloc(1, sizeof(CrxBandParam) + sizeof(std::int32_t) * paramLength + progrDataSize)); + + if (!paramBuf) { + return false; + } + + *param = reinterpret_cast(paramBuf); + + paramBuf += sizeof(CrxBandParam); + + (*param)->paramData = reinterpret_cast(paramBuf); + (*param)->nonProgrData = + progrDataSize + ? (*param)->paramData + paramLength + : nullptr; + (*param)->subbandWidth = subbandWidth; + (*param)->subbandHeight = subbandHeight; + (*param)->roundedBits = 0; + (*param)->curLine = 0; + (*param)->roundedBitsMask = roundedBitsMask; + (*param)->supportsPartial = supportsPartial; + (*param)->bitStream.bitData = 0; + (*param)->bitStream.bitsLeft = 0; + (*param)->bitStream.mdatSize = subbandDataSize; + (*param)->bitStream.curPos = 0; + (*param)->bitStream.curBufSize = 0; + (*param)->bitStream.curBufOffset = subbandMdatOffset; + (*param)->bitStream.input = input; + + crxFillBuffer(&(*param)->bitStream); + + return true; +} + +bool crxSetupSubbandData( + CrxImage* img, + CrxPlaneComp* planeComp, + const CrxTile* tile, + std::uint32_t mdatOffset +) +{ + long compDataSize = 0; + long waveletDataOffset = 0; + long compCoeffDataOffset = 0; + const std::int32_t toSubbands = 3 * img->levels + 1; + + CrxSubband* const subbands = planeComp->subBands; + + // calculate sizes + for (std::int32_t subbandNum = 0; subbandNum < toSubbands; ++subbandNum) { + subbands[subbandNum].bandSize = subbands[subbandNum].width * sizeof(std::int32_t); // 4 bytes + compDataSize += subbands[subbandNum].bandSize; + } + + if (img->levels) { + const std::int32_t encLevels = + img->levels + ? img->levels + : 1; + waveletDataOffset = (compDataSize + 7) & ~7; + compDataSize = (sizeof(CrxWaveletTransform) * encLevels + waveletDataOffset + 7) & ~7; + compCoeffDataOffset = compDataSize; + + // calc wavelet line buffer sizes (always at one level up from current) + for (int level = 0; level < img->levels; ++level) { + if (level < img->levels - 1) { + compDataSize += 8 * sizeof(std::int32_t) * planeComp->subBands[3 * (level + 1) + 2].width; + } else { + compDataSize += 8 * sizeof(std::int32_t) * tile->width; + } + } + } + + // buffer allocation + planeComp->compBuf = static_cast(malloc(compDataSize)); + + if (!planeComp->compBuf) { + return false; + } + + // subbands buffer and sizes initialisation + const std::uint64_t subbandMdatOffset = img->mdatOffset + mdatOffset; + std::uint8_t* subbandBuf = planeComp->compBuf; + + for (std::int32_t subbandNum = 0; subbandNum < toSubbands; ++subbandNum) { + subbands[subbandNum].bandBuf = subbandBuf; + subbandBuf += subbands[subbandNum].bandSize; + subbands[subbandNum].mdatOffset = subbandMdatOffset + subbands[subbandNum].dataOffset; + } + + // wavelet data initialisation + if (img->levels) { + CrxWaveletTransform* const waveletTransforms = reinterpret_cast(planeComp->compBuf + waveletDataOffset); + std::int32_t* paramData = reinterpret_cast(planeComp->compBuf + compCoeffDataOffset); + + planeComp->waveletTransform = waveletTransforms; + waveletTransforms[0].subband0Buf = reinterpret_cast(subbands->bandBuf); + + for (int level = 0; level < img->levels; ++level) { + const std::int32_t band = 3 * level + 1; + + std::int32_t transformWidth = 0; + + if (level >= img->levels - 1) { + waveletTransforms[level].height = tile->height; + transformWidth = tile->width; + } else { + waveletTransforms[level].height = subbands[band + 3].height; + transformWidth = subbands[band + 4].width; + } + + waveletTransforms[level].width = transformWidth; + waveletTransforms[level].lineBuf[0] = paramData; + waveletTransforms[level].lineBuf[1] = waveletTransforms[level].lineBuf[0] + transformWidth; + waveletTransforms[level].lineBuf[2] = waveletTransforms[level].lineBuf[1] + transformWidth; + waveletTransforms[level].lineBuf[3] = waveletTransforms[level].lineBuf[2] + transformWidth; + waveletTransforms[level].lineBuf[4] = waveletTransforms[level].lineBuf[3] + transformWidth; + waveletTransforms[level].lineBuf[5] = waveletTransforms[level].lineBuf[4] + transformWidth; + waveletTransforms[level].lineBuf[6] = waveletTransforms[level].lineBuf[5] + transformWidth; + waveletTransforms[level].lineBuf[7] = waveletTransforms[level].lineBuf[6] + transformWidth; + waveletTransforms[level].curLine = 0; + waveletTransforms[level].curH = 0; + waveletTransforms[level].fltTapH = 0; + waveletTransforms[level].subband1Buf = reinterpret_cast(subbands[band].bandBuf); + waveletTransforms[level].subband2Buf = reinterpret_cast(subbands[band + 1].bandBuf); + waveletTransforms[level].subband3Buf = reinterpret_cast(subbands[band + 2].bandBuf); + + paramData = waveletTransforms[level].lineBuf[7] + transformWidth; + } + } + + // decoding params and bitstream initialisation + for (std::int32_t subbandNum = 0; subbandNum < toSubbands; ++subbandNum) { + if (subbands[subbandNum].dataSize) { + bool supportsPartial = false; + std::uint32_t roundedBitsMask = 0; + + if (planeComp->supportsPartial && subbandNum == 0) { + roundedBitsMask = planeComp->roundedBitsMask; + supportsPartial = true; + } + + if ( + !crxParamInit( + &subbands[subbandNum].bandParam, + subbands[subbandNum].mdatOffset, + subbands[subbandNum].dataSize, + subbands[subbandNum].width, + subbands[subbandNum].height, + supportsPartial, + roundedBitsMask, + img->input + ) + ) { + return false; + } + } + } + + return true; } } // namespace -void DCraw::crxLoadDecodeLoop(void *img, int nPlanes) +bool DCraw::crxDecodePlane(void* p, std::uint32_t planeNumber) +{ + CrxImage* const img = static_cast(p); + int imageRow = 0; + + for (int tRow = 0; tRow < img->tileRows; ++tRow) { + int imageCol = 0; + + for (int tCol = 0; tCol < img->tileCols; ++tCol) { + const CrxTile* const tile = img->tiles + tRow * img->tileRows + tCol; + CrxPlaneComp* const planeComp = tile->comps + planeNumber; + const std::uint64_t tileMdatOffset = tile->dataOffset + planeComp->dataOffset; + + // decode single tile + if (!crxSetupSubbandData(img, planeComp, tile, tileMdatOffset)) { + return false; + } + + if (img->levels) { + if (!crxIdwt53FilterInitialize(planeComp, img->levels - 1)) { + return false; + } + + for (int i = 0; i < tile->height; ++i) { + if (!crxIdwt53FilterDecode(planeComp, img->levels - 1) || !crxIdwt53FilterTransform(planeComp, img->levels - 1)) { + return false; + } + + const std::int32_t* const lineData = crxIdwt53FilterGetLine(planeComp, img->levels - 1); + crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, lineData, tile->width); + } + } else { + // we have the only subband in this case + if (!planeComp->subBands->dataSize) { + memset(planeComp->subBands->bandBuf, 0, planeComp->subBands->bandSize); + return true; + } + + for (int i = 0; i < tile->height; ++i) { + if (!crxDecodeLine(planeComp->subBands->bandParam, planeComp->subBands->bandBuf)) { + return false; + } + + const std::int32_t* const lineData = reinterpret_cast(planeComp->subBands->bandBuf); + crxConvertPlaneLine(img, imageRow + i, imageCol, planeNumber, lineData, tile->width); + } + } + + imageCol += tile->width; + } + + imageRow += img->tiles[tRow * img->tileRows].height; + } + + return true; +} + +namespace +{ + +using crx_data_header_t = DCraw::CanonCR3Data::crx_data_header_t; + +bool crxReadSubbandHeaders( + CrxImage* img, + CrxTile* tile, + CrxPlaneComp* comp, + std::uint8_t** subbandMdatPtr, + std::uint32_t* mdatSize +) +{ + CrxSubband* band = comp->subBands + img->subbandCount - 1; // set to last band + std::uint32_t bandHeight = tile->height; + std::uint32_t bandWidth = tile->width; + std::int32_t bandWidthExCoef = 0; + std::int32_t bandHeightExCoef = 0; + + if (img->levels) { + // Build up subband sequences to crxDecode to a level in a header + + // Coefficient structure is a bit unclear and convoluted: + // 3 levels max - 8 groups (for tile width rounded to 8 bytes) + // of 3 band per level 4 sets of coefficients for each + const std::int32_t* rowExCoef = exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->width & 7); + const std::int32_t* colExCoef = exCoefNumTbl + 0x60 * (img->levels - 1) + 12 * (tile->height & 7); + + for (int level = 0; level < img->levels; ++level) { + const std::int32_t widthOddPixel = bandWidth & 1; + const std::int32_t heightOddPixel = bandHeight & 1; + bandWidth = (widthOddPixel + bandWidth) >> 1; + bandHeight = (heightOddPixel + bandHeight) >> 1; + + std::int32_t bandWidthExCoef0 = 0; + std::int32_t bandWidthExCoef1 = 0; + std::int32_t bandHeightExCoef0 = 0; + std::int32_t bandHeightExCoef1 = 0; + + if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + bandWidthExCoef0 = rowExCoef[0]; + bandWidthExCoef1 = rowExCoef[1]; + } + + if (tile->tileFlag & E_HAS_TILES_ON_THE_LEFT) { + ++bandWidthExCoef0; + } + + if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) { + bandHeightExCoef0 = colExCoef[0]; + bandHeightExCoef1 = colExCoef[1]; + } + + if (tile->tileFlag & E_HAS_TILES_ON_THE_TOP) { + ++bandHeightExCoef0; + } + + band[0].width = bandWidth + bandWidthExCoef0 - widthOddPixel; + band[0].height = bandHeight + bandHeightExCoef0 - heightOddPixel; + + band[-1].width = bandWidth + bandWidthExCoef1; + band[-1].height = bandHeight + bandHeightExCoef0 - heightOddPixel; + + band[-2].width = bandWidth + bandWidthExCoef0 - widthOddPixel; + band[-2].height = bandHeight + bandHeightExCoef1; + + rowExCoef += 4; + colExCoef += 4; + band -= 3; + } + + bandWidthExCoef = 0; + bandHeightExCoef = 0; + + if (tile->tileFlag & E_HAS_TILES_ON_THE_RIGHT) { + bandWidthExCoef = exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->width & 7) + 4 * (img->levels - 1) + 1]; + } + + if (tile->tileFlag & E_HAS_TILES_ON_THE_BOTTOM) { + bandHeightExCoef = exCoefNumTbl[0x60 * (img->levels - 1) + 12 * (tile->height & 7) + 4 * (img->levels - 1) + 1]; + } + } + + band->width = bandWidthExCoef + bandWidth; + band->height = bandHeightExCoef + bandHeight; + + if (!img->subbandCount) { + return true; + } + + std::int32_t subbandOffset = 0; + band = comp->subBands; + + for (unsigned int curSubband = 0; curSubband < img->subbandCount; curSubband++, band++) { + if (*mdatSize < 0xC) { + return false; + } + + if (sgetn(2, *subbandMdatPtr) != 0xFF03) { + return false; + } + + const std::uint32_t bitData = sgetn(4, *subbandMdatPtr + 8); + const std::uint32_t subbandSize = sgetn(4, *subbandMdatPtr + 4); + + if (curSubband != bitData >> 28) { + band->dataSize = subbandSize; + return false; + } + + band->dataSize = subbandSize - (bitData & 0x7FF); + band->supportsPartial = bitData & 0x8000; + band->dataOffset = subbandOffset; + band->quantValue = (bitData >> 19) & 0xFF; + band->paramK = 0; + band->bandParam = nullptr; + band->bandBuf = nullptr; + band->bandSize = 0; + + subbandOffset += subbandSize; + + *subbandMdatPtr += 0xC; + *mdatSize -= 0xC; + } + + return true; +} + +bool crxReadImageHeaders( + crx_data_header_t* hdr, + CrxImage* img, + std::uint8_t* mdatPtr, + std::uint32_t mdatSize +) +{ + const unsigned int nTiles = img->tileRows * img->tileCols; + + if (!nTiles) { + return false; + } + + if (!img->tiles) { + img->tiles = static_cast( + malloc( + sizeof(CrxTile) * nTiles + + sizeof(CrxPlaneComp) * nTiles * img->nPlanes + + sizeof(CrxSubband) * nTiles * img->nPlanes * img->subbandCount + ) + ); + + if (!img->tiles) { + return false; + } + + // memory areas in allocated chunk + CrxTile* tile = img->tiles; + CrxPlaneComp* const comps = reinterpret_cast(tile + nTiles); + CrxSubband* const bands = reinterpret_cast(comps + img->nPlanes * nTiles); + + for (unsigned int curTile = 0; curTile < nTiles; curTile++, tile++) { + tile->tileFlag = 0; // tile neighbouring flags + tile->tileNumber = curTile; + tile->tileSize = 0; + tile->comps = comps + curTile * img->nPlanes; + + if ((curTile + 1) % img->tileCols) { + // not the last tile in a tile row + tile->width = hdr->tileWidth; + + if (img->tileCols > 1) { + tile->tileFlag = E_HAS_TILES_ON_THE_RIGHT; + + if (curTile % img->tileCols) { + // not the first tile in tile row + tile->tileFlag |= E_HAS_TILES_ON_THE_LEFT; + } + } + } else { + // last tile in a tile row + tile->width = img->planeWidth - hdr->tileWidth * (img->tileCols - 1); + + if (img->tileCols > 1) { + tile->tileFlag = E_HAS_TILES_ON_THE_LEFT; + } + } + + if (curTile < nTiles - img->tileCols) { + // in first tile row + tile->height = hdr->tileHeight; + + if (img->tileRows > 1) { + tile->tileFlag |= E_HAS_TILES_ON_THE_BOTTOM; + + if (curTile >= img->tileCols) { + tile->tileFlag |= E_HAS_TILES_ON_THE_TOP; + } + } + } else { + // non first tile row + tile->height = img->planeHeight - hdr->tileHeight * (img->tileRows - 1); + + if (img->tileRows > 1) { + tile->tileFlag |= E_HAS_TILES_ON_THE_TOP; + } + } + + if (img->nPlanes) { + CrxPlaneComp* comp = tile->comps; + CrxSubband* band = bands + curTile * img->nPlanes * img->subbandCount; + + for (int curComp = 0; curComp < img->nPlanes; curComp++, comp++) { + comp->compNumber = curComp; + comp->supportsPartial = true; + comp->tileFlag = tile->tileFlag; + comp->subBands = band; + comp->compBuf = nullptr; + comp->waveletTransform = nullptr; + + if (img->subbandCount) { + for (int curBand = 0; curBand < img->subbandCount; curBand++, band++) { + band->supportsPartial = false; + band->quantValue = 4; + band->bandParam = nullptr; + band->dataSize = 0; + } + } + } + } + } + } + + std::uint32_t tileOffset = 0; + std::uint32_t dataSize = mdatSize; + std::uint8_t* dataPtr = mdatPtr; + CrxTile* tile = img->tiles; + + for (unsigned int curTile = 0; curTile < nTiles; curTile++, tile++) { + if (dataSize < 0xC) { + return false; + } + + if (sgetn(2, dataPtr) != 0xFF01) { + return false; + } + + if (sgetn(2, dataPtr + 8) != curTile) { + return false; + } + + dataSize -= 0xC; + + tile->tileSize = sgetn(4, dataPtr + 4); + tile->dataOffset = tileOffset; + + const std::int32_t hdrExtraBytes = sgetn(2, dataPtr + 2) - 8; + tileOffset += tile->tileSize; + dataPtr += hdrExtraBytes + 0xC; + dataSize -= hdrExtraBytes; + + std::uint32_t compOffset = 0; + CrxPlaneComp* comp = tile->comps; + + for (int compNum = 0; compNum < img->nPlanes; compNum++, comp++) { + if (dataSize < 0xC) { + return false; + } + + if (sgetn(2, dataPtr) != 0xFF02) { + return false; + } + + if (compNum != dataPtr[8] >> 4) { + return false; + } + + comp->compSize = sgetn(4, dataPtr + 4); + + std::int32_t compHdrRoundedBits = (dataPtr[8] >> 1) & 3; + comp->supportsPartial = (dataPtr[8] & 8) != 0; + + comp->dataOffset = compOffset; + comp->tileFlag = tile->tileFlag; + + compOffset += comp->compSize; + dataSize -= 0xC; + dataPtr += 0xC; + + comp->roundedBitsMask = 0; + + if (compHdrRoundedBits) { + if (img->levels || !comp->supportsPartial) { + return false; + } + + comp->roundedBitsMask = 1 << (compHdrRoundedBits - 1); + } + + if (!crxReadSubbandHeaders(img, tile, comp, &dataPtr, &dataSize)) { + return false; + } + } + } + + return true; +} + +bool crxSetupImageData( + crx_data_header_t* hdr, + CrxImage* img, + std::int16_t* outBuf, + std::uint64_t mdatOffset, + std::uint32_t mdatSize, + std::uint8_t* mdatHdrPtr +) +{ + constexpr bool IncrBitTable[32] = { + false, false, false, false, false, false, false, false, false, true, true, false, false, false, true, false, + false, false, true, false, false, true, true, true, false, true, true, true, false, false, false, false + }; + + img->planeWidth = hdr->f_width; + img->planeHeight = hdr->f_height; + + if ( + hdr->tileWidth < 0x16 + || hdr->tileHeight < 0x16 + || img->planeWidth > 0x7FFF + || img->planeHeight > 0x7FFF + ) { + return false; + } + + img->tileCols = (img->planeWidth + hdr->tileWidth - 1) / hdr->tileWidth; + img->tileRows = (img->planeHeight + hdr->tileHeight - 1) / hdr->tileHeight; + + if (img->planeWidth - hdr->tileWidth * (img->tileCols - 1) < 0x16 || img->planeHeight - hdr->tileHeight * (img->tileRows - 1) < 0x16) { + return false; + } + + img->tiles = nullptr; + img->levels = hdr->imageLevels; + img->subbandCount = 3 * img->levels + 1; // 3 bands per level + one last LL + img->nPlanes = hdr->nPlanes; + img->nBits = hdr->nBits; + img->encType = hdr->encType; + img->samplePrecision = hdr->nBits + IncrBitTable[4 * hdr->encType + 2] + 1; + img->mdatOffset = mdatOffset + hdr->mdatHdrSize; + img->mdatSize = mdatSize; + img->planeBuf = nullptr; + img->outBufs[0] = img->outBufs[1] = img->outBufs[2] = img->outBufs[3] = nullptr; + + // The encoding type 3 needs all 4 planes to be decoded to generate row of + // RGGB values. It seems to be using some other colour space for raw encoding + // It is a massive buffer so ideallly it will need a different approach: + // decode planes line by line and convert single line then without + // intermediate plane buffer. At the moment though it's too many changes so + // left as is. + if (img->encType == 3 && img->nPlanes == 4 && img->nBits > 8) { + img->planeBuf = static_cast( + malloc(img->planeHeight * img->planeWidth * img->nPlanes * ((img->samplePrecision + 7) >> 3)) + ); + + if (!img->planeBuf) { + return false; + } + } + + const std::int32_t rowSize = 2 * img->planeWidth; + + if (img->nPlanes == 1) { + img->outBufs[0] = outBuf; + } else { + switch (hdr->cfaLayout) { + case 0: { + // R G + // G B + img->outBufs[0] = outBuf; + img->outBufs[1] = outBuf + 1; + img->outBufs[2] = outBuf + rowSize; + img->outBufs[3] = img->outBufs[2] + 1; + break; + } + + case 1: { + // G R + // B G + img->outBufs[1] = outBuf; + img->outBufs[0] = outBuf + 1; + img->outBufs[3] = outBuf + rowSize; + img->outBufs[2] = img->outBufs[3] + 1; + break; + } + + case 2: { + // G B + // R G + img->outBufs[2] = outBuf; + img->outBufs[3] = outBuf + 1; + img->outBufs[0] = outBuf + rowSize; + img->outBufs[1] = img->outBufs[0] + 1; + break; + } + + case 3: { + // B G + // G R + img->outBufs[3] = outBuf; + img->outBufs[2] = outBuf + 1; + img->outBufs[1] = outBuf + rowSize; + img->outBufs[0] = img->outBufs[1] + 1; + break; + } + } + } + + // read header + return crxReadImageHeaders(hdr, img, mdatHdrPtr, mdatSize); +} + +void crxFreeImageData(CrxImage* img) +{ + CrxTile* tile = img->tiles; + const int nTiles = img->tileRows * img->tileCols; + + if (img->tiles) { + for (std::int32_t curTile = 0; curTile < nTiles; curTile++, tile++) { + if (tile[curTile].comps) { + for (std::int32_t curPlane = 0; curPlane < img->nPlanes; ++curPlane) { + crxFreeSubbandData(img, tile[curTile].comps + curPlane); + } + } + } + + free(img->tiles); + img->tiles = nullptr; + } + + if (img->planeBuf) { + free(img->planeBuf); + img->planeBuf = nullptr; + } +} + +} // namespace + +void DCraw::crxLoadDecodeLoop(void* img, int nPlanes) { #ifdef _OPENMP - int results[4]; // nPlanes is always <= 4 -#pragma omp parallel for - for (int32_t plane = 0; plane < nPlanes; ++plane) - results[plane] = crxDecodePlane(img, plane); + bool results[4]; // nPlanes is always <= 4 + #pragma omp parallel for + + for (std::int32_t plane = 0; plane < nPlanes; ++plane) { + results[plane] = crxDecodePlane(img, plane); + } + + for (std::int32_t plane = 0; plane < nPlanes; ++plane) { + if (!results[plane]) { + derror(); + } + } - for (int32_t plane = 0; plane < nPlanes; ++plane) - if (results[plane]) - derror(); #else - for (int32_t plane = 0; plane < nPlanes; ++plane) - if (crxDecodePlane(img, plane)) - derror(); + + for (std::int32_t plane = 0; plane < nPlanes; ++plane) { + if (!crxDecodePlane(img, plane)) { + derror(); + } + } + #endif } -void DCraw::crxConvertPlaneLineDf(void *p, int imageRow) +void DCraw::crxConvertPlaneLineDf(void* p, int imageRow) { - crxConvertPlaneLine((CrxImage *)p, imageRow); + crxConvertPlaneLine(static_cast(p), imageRow); } -void DCraw::crxLoadFinalizeLoopE3(void *p, int planeHeight) +void DCraw::crxLoadFinalizeLoopE3(void* p, int planeHeight) { #ifdef _OPENMP -#pragma omp parallel for + #pragma omp parallel for #endif - for (int i = 0; i < planeHeight; ++i) - crxConvertPlaneLineDf(p, i); + + for (int i = 0; i < planeHeight; ++i) { + crxConvertPlaneLineDf(p, i); + } } void DCraw::crxLoadRaw() { - CrxImage img; - if (RT_canon_CR3_data.crx_track_selected < 0 || - RT_canon_CR3_data.crx_track_selected >= - LIBRAW_CRXTRACKS_MAXCOUNT) - derror(); - crx_data_header_t hdr = - RT_canon_CR3_data - .crx_header[RT_canon_CR3_data.crx_track_selected]; + CrxImage img; - LibRaw_abstract_datastream input = { ifp }; - img.input = &input; //libraw_internal_data.internal_data.input; + if (RT_canon_CR3_data.crx_track_selected >= RT_canon_CR3_data.CRXTRACKS_MAXCOUNT) { + derror(); + } - // update sizes for the planes - if (hdr.nPlanes == 4) - { - hdr.f_width >>= 1; - hdr.f_height >>= 1; - hdr.tileWidth >>= 1; - hdr.tileHeight >>= 1; - } + crx_data_header_t hdr = RT_canon_CR3_data.crx_header[RT_canon_CR3_data.crx_track_selected]; + + LibRaw_abstract_datastream input = {ifp}; + img.input = &input; // libraw_internal_data.internal_data.input; + + // update sizes for the planes + if (hdr.nPlanes == 4) { + hdr.f_width >>= 1; + hdr.f_height >>= 1; + hdr.tileWidth >>= 1; + hdr.tileHeight >>= 1; + } // /*imgdata.color.*/maximum = (1 << hdr.nBits) - 1; - uint8_t *hdrBuf = (uint8_t *)malloc(hdr.mdatHdrSize); + std::uint8_t* const hdrBuf = static_cast(malloc(hdr.mdatHdrSize)); - // read image header + // read image header #ifdef _OPENMP -#pragma omp critical + #pragma omp critical #endif - { + { #ifndef _OPENMP - /*libraw_internal_data.internal_data.input->*/input.lock(); + /*libraw_internal_data.internal_data.input->*/ input.lock(); #endif - /*libraw_internal_data.internal_data.input->*/input.seek( - data_offset, SEEK_SET); - /*libraw_internal_data.internal_data.input->*/input.read(hdrBuf, 1, hdr.mdatHdrSize); + /*libraw_internal_data.internal_data.input->*/ input.seek(data_offset, SEEK_SET); + /*libraw_internal_data.internal_data.input->*/ input.read(hdrBuf, 1, hdr.mdatHdrSize); #ifndef _OPENMP - /*libraw_internal_data.internal_data.input->*/input.unlock(); + /*libraw_internal_data.internal_data.input->*/ input.unlock(); #endif - } + } - // parse and setup the image data - if (crxSetupImageData(&hdr, &img, (int16_t *)raw_image, - hdr.MediaOffset/*data_offset*/, - hdr.MediaSize/*RT_canon_CR3_data.data_size*/, hdrBuf)) - derror(); - free(hdrBuf); + // parse and setup the image data + if (!crxSetupImageData(&hdr, &img, reinterpret_cast(raw_image), hdr.MediaOffset /*data_offset*/, hdr.MediaSize /*RT_canon_CR3_data.data_size*/, hdrBuf)) { + derror(); + } - crxLoadDecodeLoop(&img, hdr.nPlanes); + free(hdrBuf); - if (img.encType == 3) - crxLoadFinalizeLoopE3(&img, img.planeHeight); + crxLoadDecodeLoop(&img, hdr.nPlanes); - crxFreeImageData(&img); + if (img.encType == 3) { + crxLoadFinalizeLoopE3(&img, img.planeHeight); + } + + crxFreeImageData(&img); } -int DCraw::crxParseImageHeader(uchar *cmp1TagData, int nTrack) +bool DCraw::crxParseImageHeader(uchar* cmp1TagData, unsigned int nTrack) { - if (nTrack < 0 || nTrack >= LIBRAW_CRXTRACKS_MAXCOUNT) - return -1; - if (!cmp1TagData) - return -1; + if (nTrack >= RT_canon_CR3_data.CRXTRACKS_MAXCOUNT) { + return false; + } - crx_data_header_t *hdr = - &RT_canon_CR3_data.crx_header[nTrack]; + if (!cmp1TagData) { + return false; + } - hdr->version = sgetn(2, cmp1TagData + 4); - hdr->f_width = sgetn(4, cmp1TagData + 8); - hdr->f_height = sgetn(4, cmp1TagData + 12); - hdr->tileWidth = sgetn(4, cmp1TagData + 16); - hdr->tileHeight = sgetn(4, cmp1TagData + 20); - hdr->nBits = cmp1TagData[24]; - hdr->nPlanes = cmp1TagData[25] >> 4; - hdr->cfaLayout = cmp1TagData[25] & 0xF; - hdr->encType = cmp1TagData[26] >> 4; - hdr->imageLevels = cmp1TagData[26] & 0xF; - hdr->hasTileCols = cmp1TagData[27] >> 7; - hdr->hasTileRows = (cmp1TagData[27] >> 6) & 1; - hdr->mdatHdrSize = sgetn(4, cmp1TagData + 28); + crx_data_header_t* const hdr = &RT_canon_CR3_data.crx_header[nTrack]; - // validation - if (hdr->version != 0x100 || !hdr->mdatHdrSize) - return -1; - if (hdr->encType == 1) - { - if (hdr->nBits > 15) - return -1; - } - else - { - if (hdr->encType && hdr->encType != 3) - return -1; - if (hdr->nBits > 14) - return -1; - } + hdr->version = sgetn(2, cmp1TagData + 4); + hdr->f_width = sgetn(4, cmp1TagData + 8); + hdr->f_height = sgetn(4, cmp1TagData + 12); + hdr->tileWidth = sgetn(4, cmp1TagData + 16); + hdr->tileHeight = sgetn(4, cmp1TagData + 20); + hdr->nBits = cmp1TagData[24]; + hdr->nPlanes = cmp1TagData[25] >> 4; + hdr->cfaLayout = cmp1TagData[25] & 0xF; + hdr->encType = cmp1TagData[26] >> 4; + hdr->imageLevels = cmp1TagData[26] & 0xF; + hdr->hasTileCols = cmp1TagData[27] >> 7; + hdr->hasTileRows = (cmp1TagData[27] >> 6) & 1; + hdr->mdatHdrSize = sgetn(4, cmp1TagData + 28); - if (hdr->nPlanes == 1) - { - if (hdr->cfaLayout || hdr->encType) - return -1; - if (hdr->nBits != 8) - return -1; - } - else if (hdr->nPlanes != 4 || hdr->f_width & 1 || hdr->f_height & 1 || - hdr->tileWidth & 1 || hdr->tileHeight & 1 || hdr->cfaLayout > 3u || - (hdr->encType && hdr->encType != 1 && hdr->encType != 3) || - hdr->nBits == 8) - return -1; + // validation + if (hdr->version != 0x100 || !hdr->mdatHdrSize) { + return false; + } - if (hdr->tileWidth > hdr->f_width || hdr->tileHeight > hdr->f_height) - return -1; + if (hdr->encType == 1) { + if (hdr->nBits > 15) { + return false; + } + } else { + if (hdr->encType && hdr->encType != 3) { + return false; + } - if (hdr->imageLevels > 3 || hdr->hasTileCols > 1 || hdr->hasTileRows > 1) - return -1; - return 0; + if (hdr->nBits > 14) { + return false; + } + } + + if (hdr->nPlanes == 1) { + if (hdr->cfaLayout || hdr->encType) { + return false; + } + + if (hdr->nBits != 8) { + return false; + } + } else if ( + hdr->nPlanes != 4 + || (hdr->f_width & 1) + || (hdr->f_height & 1) + || (hdr->tileWidth & 1) + || (hdr->tileHeight & 1) + || hdr->cfaLayout > 3 + || ( + hdr->encType + && hdr->encType != 1 + && hdr->encType != 3 + ) + || hdr->nBits == 8 + ) { + return false; + } + + if (hdr->tileWidth > hdr->f_width || hdr->tileHeight > hdr->f_height) { + return false; + } + + if (hdr->imageLevels > 3 || hdr->hasTileCols > 1 || hdr->hasTileRows > 1) { + return false; + } + + return true; } - -#undef _abs -#undef _min -#undef _constrain -#undef libraw_inline -#undef LIBRAW_CRXTRACKS_MAXCOUNT - -#ifdef __GNUC__ // silence warning -#pragma GCC diagnostic pop -#endif diff --git a/rtengine/dcraw.h b/rtengine/dcraw.h index 0265219c7..89c1fcaff 100644 --- a/rtengine/dcraw.h +++ b/rtengine/dcraw.h @@ -184,12 +184,12 @@ public: int32_t mdatHdrSize; // Not from header, but from datastream uint32_t MediaSize; - INT64 MediaOffset; + int64_t MediaOffset; uint32_t MediaType; /* 1 -> /C/RAW, 2-> JPEG */ }; static constexpr size_t CRXTRACKS_MAXCOUNT = 16; crx_data_header_t crx_header[CRXTRACKS_MAXCOUNT]; - int crx_track_selected; + unsigned int crx_track_selected; short CR3_CTMDtag; }; protected: @@ -563,16 +563,16 @@ void nikon_14bit_load_raw(); // ported from LibRaw // Canon CR3 support ported from LibRaw //----------------------------------------------------------------------------- void parse_canon_cr3(); -void selectCRXTrack(short maxTrack); +void selectCRXTrack(unsigned short maxTrack); int parseCR3(unsigned long long oAtomList, unsigned long long szAtomList, short &nesting, - char *AtomNameStack, short &nTrack, short &TrackType); -int crxDecodePlane(void *p, uint32_t planeNumber); + char *AtomNameStack, unsigned short &nTrack, short &TrackType); +bool crxDecodePlane(void *p, uint32_t planeNumber); void crxLoadDecodeLoop(void *img, int nPlanes); void crxConvertPlaneLineDf(void *p, int imageRow); void crxLoadFinalizeLoopE3(void *p, int planeHeight); void crxLoadRaw(); -int crxParseImageHeader(uchar *cmp1TagData, int nTrack); +bool crxParseImageHeader(uchar *cmp1TagData, unsigned int nTrack); //----------------------------------------------------------------------------- }; diff --git a/rtengine/myfile.h b/rtengine/myfile.h index 7c498e556..423edea9a 100644 --- a/rtengine/myfile.h +++ b/rtengine/myfile.h @@ -56,28 +56,26 @@ IMFILE* fopen (const char* fname); IMFILE* gfopen (const char* fname); IMFILE* fopen (unsigned* buf, int size); void fclose (IMFILE* f); -inline int ftell (IMFILE* f) +inline long ftell (IMFILE* f) { - return f->pos; } inline int feof (IMFILE* f) { - return f->eof; } -inline void fseek (IMFILE* f, int p, int how) +inline void fseek (IMFILE* f, long p, int how) { - int fpos = f->pos; + ssize_t fpos = f->pos; if (how == SEEK_SET) { f->pos = p; } else if (how == SEEK_CUR) { f->pos += p; } else if (how == SEEK_END) { - if(p <= 0 && -p <= f->size) { + if (p <= 0 && -p <= f->size) { f->pos = f->size + p; } return;