001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019package org.apache.commons.compress.compressors.xz; 020 021import java.util.HashMap; 022import java.util.Map; 023import org.apache.commons.compress.compressors.FileNameUtil; 024import org.apache.commons.compress.utils.OsgiUtils; 025 026/** 027 * Utility code for the xz compression format. 028 * @ThreadSafe 029 * @since 1.4 030 */ 031public class XZUtils { 032 033 private static final FileNameUtil fileNameUtil; 034 035 /** 036 * XZ Header Magic Bytes begin a XZ file. 037 * 038 * <p>This is a copy of {@code org.tukaani.xz.XZ.HEADER_MAGIC} in 039 * XZ for Java version 1.5.</p> 040 */ 041 private static final byte[] HEADER_MAGIC = { 042 (byte) 0xFD, '7', 'z', 'X', 'Z', '\0' 043 }; 044 045 enum CachedAvailability { 046 DONT_CACHE, CACHED_AVAILABLE, CACHED_UNAVAILABLE 047 } 048 049 private static volatile CachedAvailability cachedXZAvailability; 050 051 static { 052 final Map<String, String> uncompressSuffix = new HashMap<>(); 053 uncompressSuffix.put(".txz", ".tar"); 054 uncompressSuffix.put(".xz", ""); 055 uncompressSuffix.put("-xz", ""); 056 fileNameUtil = new FileNameUtil(uncompressSuffix, ".xz"); 057 cachedXZAvailability = CachedAvailability.DONT_CACHE; 058 setCacheXZAvailablity(!OsgiUtils.isRunningInOsgiEnvironment()); 059 } 060 061 /** Private constructor to prevent instantiation of this utility class. */ 062 private XZUtils() { 063 } 064 065 /** 066 * Checks if the signature matches what is expected for a .xz file. 067 * 068 * <p>This is more or less a copy of the version found in {@link 069 * XZCompressorInputStream} but doesn't depend on the presence of 070 * XZ for Java.</p> 071 * 072 * @param signature the bytes to check 073 * @param length the number of bytes to check 074 * @return true if signature matches the .xz magic bytes, false otherwise 075 * @since 1.9 076 */ 077 public static boolean matches(final byte[] signature, final int length) { 078 if (length < HEADER_MAGIC.length) { 079 return false; 080 } 081 082 for (int i = 0; i < HEADER_MAGIC.length; ++i) { 083 if (signature[i] != HEADER_MAGIC[i]) { 084 return false; 085 } 086 } 087 088 return true; 089 } 090 091 /** 092 * Are the classes required to support XZ compression available? 093 * @since 1.5 094 * @return true if the classes required to support XZ compression are available 095 */ 096 public static boolean isXZCompressionAvailable() { 097 final CachedAvailability cachedResult = cachedXZAvailability; 098 if (cachedResult != CachedAvailability.DONT_CACHE) { 099 return cachedResult == CachedAvailability.CACHED_AVAILABLE; 100 } 101 return internalIsXZCompressionAvailable(); 102 } 103 104 private static boolean internalIsXZCompressionAvailable() { 105 try { 106 XZCompressorInputStream.matches(null, 0); 107 return true; 108 } catch (final NoClassDefFoundError error) { // NOSONAR 109 return false; 110 } 111 } 112 113 /** 114 * Detects common xz suffixes in the given file name. 115 * 116 * @param fileName name of a file 117 * @return {@code true} if the file name has a common xz suffix, 118 * {@code false} otherwise 119 */ 120 public static boolean isCompressedFilename(final String fileName) { 121 return fileNameUtil.isCompressedFilename(fileName); 122 } 123 124 /** 125 * Maps the given name of a xz-compressed file to the name that the 126 * file should have after uncompression. Commonly used file type specific 127 * suffixes like ".txz" are automatically detected and 128 * correctly mapped. For example the name "package.txz" is mapped to 129 * "package.tar". And any file names with the generic ".xz" suffix 130 * (or any other generic xz suffix) is mapped to a name without that 131 * suffix. If no xz suffix is detected, then the file name is returned 132 * unmapped. 133 * 134 * @param fileName name of a file 135 * @return name of the corresponding uncompressed file 136 */ 137 public static String getUncompressedFilename(final String fileName) { 138 return fileNameUtil.getUncompressedFilename(fileName); 139 } 140 141 /** 142 * Maps the given file name to the name that the file should have after 143 * compression with xz. Common file types with custom suffixes for 144 * compressed versions are automatically detected and correctly mapped. 145 * For example the name "package.tar" is mapped to "package.txz". If no 146 * custom mapping is applicable, then the default ".xz" suffix is appended 147 * to the file name. 148 * 149 * @param fileName name of a file 150 * @return name of the corresponding compressed file 151 */ 152 public static String getCompressedFilename(final String fileName) { 153 return fileNameUtil.getCompressedFilename(fileName); 154 } 155 156 /** 157 * Whether to cache the result of the XZ for Java check. 158 * 159 * <p>This defaults to {@code false} in an OSGi environment and {@code true} otherwise.</p> 160 * @param doCache whether to cache the result 161 * @since 1.9 162 */ 163 public static void setCacheXZAvailablity(final boolean doCache) { 164 if (!doCache) { 165 cachedXZAvailability = CachedAvailability.DONT_CACHE; 166 } else if (cachedXZAvailability == CachedAvailability.DONT_CACHE) { 167 final boolean hasXz = internalIsXZCompressionAvailable(); 168 cachedXZAvailability = hasXz ? CachedAvailability.CACHED_AVAILABLE // NOSONAR 169 : CachedAvailability.CACHED_UNAVAILABLE; 170 } 171 } 172 173 // only exists to support unit tests 174 static CachedAvailability getCachedXZAvailability() { 175 return cachedXZAvailability; 176 } 177}