• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
21 import java.util.HashMap;
22 import java.util.Map;
23 import org.apache.commons.compress.compressors.FileNameUtil;
24 
25 /**
26  * Utility code for the lzma compression format.
27  * @ThreadSafe
28  * @since 1.10
29  */
30 public class LZMAUtils {
31 
32     private static final FileNameUtil fileNameUtil;
33 
34     /**
35      * LZMA Header Magic Bytes begin a LZMA file.
36      */
37     private static final byte[] HEADER_MAGIC = {
38         (byte) 0x5D, 0, 0
39     };
40 
41     enum CachedAvailability {
42         DONT_CACHE, CACHED_AVAILABLE, CACHED_UNAVAILABLE
43     }
44 
45     private static volatile CachedAvailability cachedLZMAAvailability;
46 
47     static {
48         final Map<String, String> uncompressSuffix = new HashMap<>();
49         uncompressSuffix.put(".lzma", "");
50         uncompressSuffix.put("-lzma", "");
51         fileNameUtil = new FileNameUtil(uncompressSuffix, ".lzma");
52         cachedLZMAAvailability = CachedAvailability.DONT_CACHE;
53         try {
54             Class.forName("org.osgi.framework.BundleEvent");
55         } catch (final Exception ex) {
56             setCacheLZMAAvailablity(true);
57         }
58     }
59 
60     /** Private constructor to prevent instantiation of this utility class. */
LZMAUtils()61     private LZMAUtils() {
62     }
63 
64     /**
65      * Checks if the signature matches what is expected for a .lzma file.
66      *
67      * @param   signature     the bytes to check
68      * @param   length        the number of bytes to check
69      * @return  true if signature matches the .lzma magic bytes, false otherwise
70      */
matches(final byte[] signature, final int length)71     public static boolean matches(final byte[] signature, final int length) {
72         if (length < HEADER_MAGIC.length) {
73             return false;
74         }
75 
76         for (int i = 0; i < HEADER_MAGIC.length; ++i) {
77             if (signature[i] != HEADER_MAGIC[i]) {
78                 return false;
79             }
80         }
81 
82         return true;
83     }
84 
85     /**
86      * Are the classes required to support LZMA compression available?
87      * @return true if the classes required to support LZMA
88      * compression are available
89      */
isLZMACompressionAvailable()90     public static boolean isLZMACompressionAvailable() {
91         final CachedAvailability cachedResult = cachedLZMAAvailability;
92         if (cachedResult != CachedAvailability.DONT_CACHE) {
93             return cachedResult == CachedAvailability.CACHED_AVAILABLE;
94         }
95         return internalIsLZMACompressionAvailable();
96     }
97 
internalIsLZMACompressionAvailable()98     private static boolean internalIsLZMACompressionAvailable() {
99         try {
100             LZMACompressorInputStream.matches(null, 0);
101             return true;
102         } catch (final NoClassDefFoundError error) {
103             return false;
104         }
105     }
106 
107     /**
108      * Detects common lzma suffixes in the given filename.
109      *
110      * @param filename name of a file
111      * @return {@code true} if the filename has a common lzma suffix,
112      *         {@code false} otherwise
113      */
isCompressedFilename(final String filename)114     public static boolean isCompressedFilename(final String filename) {
115         return fileNameUtil.isCompressedFilename(filename);
116     }
117 
118     /**
119      * Maps the given name of a lzma-compressed file to the name that
120      * the file should have after uncompression.  Any filenames with
121      * the generic ".lzma" suffix (or any other generic lzma suffix)
122      * is mapped to a name without that suffix. If no lzma suffix is
123      * detected, then the filename is returned unmapped.
124      *
125      * @param filename name of a file
126      * @return name of the corresponding uncompressed file
127      */
getUncompressedFilename(final String filename)128     public static String getUncompressedFilename(final String filename) {
129         return fileNameUtil.getUncompressedFilename(filename);
130     }
131 
132     /**
133      * Maps the given filename to the name that the file should have after
134      * compression with lzma.
135      *
136      * @param filename name of a file
137      * @return name of the corresponding compressed file
138      */
getCompressedFilename(final String filename)139     public static String getCompressedFilename(final String filename) {
140         return fileNameUtil.getCompressedFilename(filename);
141     }
142 
143     /**
144      * Whether to cache the result of the LZMA check.
145      *
146      * <p>This defaults to {@code false} in an OSGi environment and {@code true} otherwise.</p>
147      * @param doCache whether to cache the result
148      */
setCacheLZMAAvailablity(final boolean doCache)149     public static void setCacheLZMAAvailablity(final boolean doCache) {
150         if (!doCache) {
151             cachedLZMAAvailability = CachedAvailability.DONT_CACHE;
152         } else if (cachedLZMAAvailability == CachedAvailability.DONT_CACHE) {
153             final boolean hasLzma = internalIsLZMACompressionAvailable();
154             cachedLZMAAvailability = hasLzma ? CachedAvailability.CACHED_AVAILABLE // NOSONAR
155                 : CachedAvailability.CACHED_UNAVAILABLE;
156         }
157     }
158 
159     // only exists to support unit tests
getCachedLZMAAvailability()160     static CachedAvailability getCachedLZMAAvailability() {
161         return cachedLZMAAvailability;
162     }
163 }
164