LZMAUtils.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one
  3.  * or more contributor license agreements.  See the NOTICE file
  4.  * distributed with this work for additional information
  5.  * regarding copyright ownership.  The ASF licenses this file
  6.  * to you under the Apache License, Version 2.0 (the
  7.  * "License"); you may not use this file except in compliance
  8.  * with the License.  You may obtain a copy of the License at
  9.  *
  10.  * http://www.apache.org/licenses/LICENSE-2.0
  11.  *
  12.  * Unless required by applicable law or agreed to in writing,
  13.  * software distributed under the License is distributed on an
  14.  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  15.  * KIND, either express or implied.  See the License for the
  16.  * specific language governing permissions and limitations
  17.  * under the License.
  18.  */
  19. package org.apache.commons.compress.compressors.lzma;

  20. import java.util.HashMap;
  21. import java.util.Map;

  22. import org.apache.commons.compress.compressors.FileNameUtil;
  23. import org.apache.commons.compress.utils.OsgiUtils;

  24. /**
  25.  * Utility code for the LZMA compression format.
  26.  *
  27.  * @ThreadSafe
  28.  * @since 1.10
  29.  */
  30. public class LZMAUtils {

  31.     enum CachedAvailability {
  32.         DONT_CACHE, CACHED_AVAILABLE, CACHED_UNAVAILABLE
  33.     }

  34.     private static final FileNameUtil fileNameUtil;

  35.     /**
  36.      * LZMA Header Magic Bytes begin a LZMA file.
  37.      */
  38.     private static final byte[] HEADER_MAGIC = { (byte) 0x5D, 0, 0 };

  39.     private static volatile CachedAvailability cachedLZMAAvailability;

  40.     static {
  41.         final Map<String, String> uncompressSuffix = new HashMap<>();
  42.         uncompressSuffix.put(".lzma", "");
  43.         uncompressSuffix.put("-lzma", "");
  44.         fileNameUtil = new FileNameUtil(uncompressSuffix, ".lzma");
  45.         cachedLZMAAvailability = CachedAvailability.DONT_CACHE;
  46.         setCacheLZMAAvailablity(!OsgiUtils.isRunningInOsgiEnvironment());
  47.     }

  48.     // only exists to support unit tests
  49.     static CachedAvailability getCachedLZMAAvailability() {
  50.         return cachedLZMAAvailability;
  51.     }

  52.     /**
  53.      * Maps the given file name to the name that the file should have after compression with LZMA.
  54.      *
  55.      * @param fileName name of a file
  56.      * @return name of the corresponding compressed file
  57.      * @deprecated Use {@link #getCompressedFileName(String)}.
  58.      */
  59.     @Deprecated
  60.     public static String getCompressedFilename(final String fileName) {
  61.         return fileNameUtil.getCompressedFileName(fileName);
  62.     }

  63.     /**
  64.      * Maps the given file name to the name that the file should have after compression with LZMA.
  65.      *
  66.      * @param fileName name of a file
  67.      * @return name of the corresponding compressed file
  68.      * @since 1.25.0
  69.      */
  70.     public static String getCompressedFileName(final String fileName) {
  71.         return fileNameUtil.getCompressedFileName(fileName);
  72.     }

  73.     /**
  74.      * Maps the given name of a LZMA-compressed file to the name that the file should have after uncompression. Any file names with the generic ".lzma" suffix
  75.      * (or any other generic LZMA suffix) is mapped to a name without that suffix. If no LZMA suffix is detected, then the file name is returned unmapped.
  76.      *
  77.      * @param fileName name of a file
  78.      * @return name of the corresponding uncompressed file
  79.      * @deprecated Use {@link #getUncompressedFileName(String)}.
  80.      */
  81.     @Deprecated
  82.     public static String getUncompressedFilename(final String fileName) {
  83.         return fileNameUtil.getUncompressedFileName(fileName);
  84.     }

  85.     /**
  86.      * Maps the given name of a LZMA-compressed file to the name that the file should have after uncompression. Any file names with the generic ".lzma" suffix
  87.      * (or any other generic LZMA suffix) is mapped to a name without that suffix. If no LZMA suffix is detected, then the file name is returned unmapped.
  88.      *
  89.      * @param fileName name of a file
  90.      * @return name of the corresponding uncompressed file
  91.      * @since 1.25.0
  92.      */
  93.     public static String getUncompressedFileName(final String fileName) {
  94.         return fileNameUtil.getUncompressedFileName(fileName);
  95.     }

  96.     private static boolean internalIsLZMACompressionAvailable() {
  97.         try {
  98.             LZMACompressorInputStream.matches(null, 0);
  99.             return true;
  100.         } catch (final NoClassDefFoundError error) { // NOSONAR
  101.             return false;
  102.         }
  103.     }

  104.     /**
  105.      * Detects common LZMA suffixes in the given file name.
  106.      *
  107.      * @param fileName name of a file
  108.      * @return {@code true} if the file name has a common LZMA suffix, {@code false} otherwise
  109.      * @deprecated Use {@link #isCompressedFileName(String)}.
  110.      */
  111.     @Deprecated
  112.     public static boolean isCompressedFilename(final String fileName) {
  113.         return fileNameUtil.isCompressedFileName(fileName);
  114.     }

  115.     /**
  116.      * Detects common LZMA suffixes in the given file name.
  117.      *
  118.      * @param fileName name of a file
  119.      * @return {@code true} if the file name has a common LZMA suffix, {@code false} otherwise
  120.      * @since 1.25.0
  121.      */
  122.     public static boolean isCompressedFileName(final String fileName) {
  123.         return fileNameUtil.isCompressedFileName(fileName);
  124.     }

  125.     /**
  126.      * Are the classes required to support LZMA compression available?
  127.      *
  128.      * @return true if the classes required to support LZMA compression are available
  129.      */
  130.     public static boolean isLZMACompressionAvailable() {
  131.         final CachedAvailability cachedResult = cachedLZMAAvailability;
  132.         if (cachedResult != CachedAvailability.DONT_CACHE) {
  133.             return cachedResult == CachedAvailability.CACHED_AVAILABLE;
  134.         }
  135.         return internalIsLZMACompressionAvailable();
  136.     }

  137.     /**
  138.      * Checks if the signature matches what is expected for a .lzma file.
  139.      *
  140.      * @param signature the bytes to check
  141.      * @param length    the number of bytes to check
  142.      * @return true if signature matches the .lzma magic bytes, false otherwise
  143.      */
  144.     public static boolean matches(final byte[] signature, final int length) {
  145.         if (length < HEADER_MAGIC.length) {
  146.             return false;
  147.         }

  148.         for (int i = 0; i < HEADER_MAGIC.length; ++i) {
  149.             if (signature[i] != HEADER_MAGIC[i]) {
  150.                 return false;
  151.             }
  152.         }

  153.         return true;
  154.     }

  155.     /**
  156.      * Whether to cache the result of the LZMA check.
  157.      *
  158.      * <p>
  159.      * This defaults to {@code false} in an OSGi environment and {@code true} otherwise.
  160.      * </p>
  161.      *
  162.      * @param doCache whether to cache the result
  163.      */
  164.     public static void setCacheLZMAAvailablity(final boolean doCache) {
  165.         if (!doCache) {
  166.             cachedLZMAAvailability = CachedAvailability.DONT_CACHE;
  167.         } else if (cachedLZMAAvailability == CachedAvailability.DONT_CACHE) {
  168.             final boolean hasLzma = internalIsLZMACompressionAvailable();
  169.             cachedLZMAAvailability = hasLzma ? CachedAvailability.CACHED_AVAILABLE // NOSONAR
  170.                     : CachedAvailability.CACHED_UNAVAILABLE;
  171.         }
  172.     }

  173.     /** Private constructor to prevent instantiation of this utility class. */
  174.     private LZMAUtils() {
  175.     }
  176. }