final boolean validateMandatoryTags()

in endorsed/src/org.apache.sis.storage.geotiff/main/org/apache/sis/storage/geotiff/ImageFileDirectory.java [1236:1362]


    final boolean validateMandatoryTags() throws DataStoreContentException {
        if (isValidated) return false;
        if (imageWidth  < 0) throw missingTag((short) TAG_IMAGE_WIDTH);
        if (imageHeight < 0) throw missingTag((short) TAG_IMAGE_LENGTH);
        final short offsetsTag, byteCountsTag;
        switch (tileTagFamily) {
            case JPEG:                      // Handled as strips.
            case STRIP: {
                if (tileWidth  < 0) tileWidth  = Math.toIntExact(imageWidth);
                if (tileHeight < 0) tileHeight = Math.toIntExact(imageHeight);
                offsetsTag    = TAG_STRIP_OFFSETS;
                byteCountsTag = TAG_STRIP_BYTE_COUNTS;
                break;
            }
            case TILE:  {
                offsetsTag    = TAG_TILE_OFFSETS;
                byteCountsTag = TAG_TILE_BYTE_COUNTS;
                break;
            }
            default: {
                throw new DataStoreContentException(reader.resources().getString(
                        Resources.Keys.InconsistentTileStrip_1, filename()));
            }
        }
        if (tileOffsets == null) {
            throw missingTag(offsetsTag);
        }
        if (samplesPerPixel == 0) {
            samplesPerPixel = 1;
            missingTag((short) TAG_SAMPLES_PER_PIXEL, 1, false, false);
        }
        if (bitsPerSample == 0) {
            bitsPerSample = 1;
            missingTag((short) TAG_BITS_PER_SAMPLE, 1, false, false);
        }
        if (colorMap != null) {
            ensureSameLength((short) TAG_COLOR_MAP, (short) TAG_BITS_PER_SAMPLE, colorMap.size(),  3 * (1 << bitsPerSample));
        }
        if (sampleFormat != FLOAT) {
            long minValue, maxValue;
            if (sampleFormat == UNSIGNED) {
                minValue =  0L;
                maxValue = -1L;                 // All bits set to 1.
            } else {
                minValue = Long.MIN_VALUE;
                maxValue = Long.MAX_VALUE;
            }
            final int shift = Long.SIZE - bitsPerSample;
            if (shift >= 0 && shift < Long.SIZE) {
                minValue >>>= shift;
                maxValue >>>= shift;
                if (minValue < maxValue) {      // Exclude the unsigned long case since we cannot represent it.
                    minValues = extremum(minValues, Vector.createSequence(minValue, 0, samplesPerPixel), false);
                    maxValues = extremum(maxValues, Vector.createSequence(maxValue, 0, samplesPerPixel), true);
                }
            }
        }
        /*
         * All of tile width, height and length information should be provided. But if only one of them is missing,
         * we can compute it provided that the file does not use any compression method. If there is a compression,
         * then we set a bit for preventing the `switch` block to perform a calculation but we let the code performs
         * the other checks in order to get an exception thrown with a better message.
         */
        int missing = !isPlanar && compression.equals(Compression.NONE) ? 0 : 0b1000;
        if (tileWidth      < 0)     missing |= 0b0001;
        if (tileHeight     < 0)     missing |= 0b0010;
        if (tileByteCounts == null) missing |= 0b0100;
        switch (missing) {
            case 0:
            case 0b1000: {          // Every thing is ok.
                break;
            }
            case 0b0001: {          // Compute missing tile width.
                tileWidth = computeTileSize(tileHeight);
                missingTag((short) TAG_TILE_WIDTH, tileWidth, true, true);
                break;
            }
            case 0b0010: {          // Compute missing tile height.
                tileHeight = computeTileSize(tileWidth);
                missingTag((short) TAG_TILE_LENGTH, tileHeight, true, true);
                break;
            }
            case 0b0100: {          // Compute missing tile byte count in uncompressed case.
                final long tileByteCount = pixelToByteCount(Math.multiplyExact(tileWidth, tileHeight));
                if (tileByteCount == 0) {
                    throw missingTag(byteCountsTag);
                }
                final long[] tileByteCountArray = new long[tileOffsets.size()];
                Arrays.fill(tileByteCountArray, tileByteCount);
                tileByteCounts = Vector.create(tileByteCountArray, true);
                missingTag(byteCountsTag, tileByteCount, true, true);
                break;
            }
            default: {
                final short tag;
                switch (Integer.lowestOneBit(missing)) {
                    case 0b0001: tag = TAG_TILE_WIDTH;  break;
                    case 0b0010: tag = TAG_TILE_LENGTH; break;
                    default:     tag = byteCountsTag;   break;
                }
                throw missingTag(tag);
            }
        }
        /*
         * Report an error if the tile offset and tile byte count vectors do not have the same length.
         * Then ensure that the number of tiles is equal to the expected number.
         */
        ensureSameLength(byteCountsTag, offsetsTag, tileByteCounts.size(), tileOffsets.size());
        long expectedCount = getNumTiles();
        if (isPlanar) {
            expectedCount = Math.multiplyExact(expectedCount, samplesPerPixel);
        }
        final int actualCount = Math.min(tileOffsets.size(), tileByteCounts.size());
        if (actualCount != expectedCount) {
            throw new DataStoreContentException(reader.resources().getString(Resources.Keys.UnexpectedTileCount_3,
                    filename(), expectedCount, actualCount));
        }
        /*
         * If a "grid to CRS" conversion has been specified with only the scale factor,
         * we need to compute the translation terms now.
         */
        if (referencing != null && !referencing.validateMandatoryTags()) {
            listeners.warning(missingTag((short) TAG_MODEL_TIE_POINT));
        }
        isValidated = true;
        return true;
    }