@@ -52,8 +52,10 @@ public class LibraryDownloadTask extends Task<Void> {
5252 protected final File jar ;
5353 protected final DefaultCacheRepository cacheRepository ;
5454 protected final AbstractDependencyManager dependencyManager ;
55+ private final File xzFile ;
5556 protected final Library library ;
5657 protected final String url ;
58+ protected boolean xz ;
5759 private final Library originalLibrary ;
5860 private boolean cached = false ;
5961
@@ -71,6 +73,8 @@ public LibraryDownloadTask(AbstractDependencyManager dependencyManager, File fil
7173
7274 url = library .getDownload ().getUrl ();
7375 jar = file ;
76+
77+ xzFile = new File (file .getAbsoluteFile ().getParentFile (), file .getName () + ".pack.xz" );
7478 }
7579
7680 @ Override
@@ -98,6 +102,8 @@ else if (t instanceof CancellationException)
98102 throw new CancellationException ();
99103 else
100104 throw new LibraryDownloadException (library , t );
105+ } else {
106+ if (xz ) unpackLibrary (jar , Files .readAllBytes (xzFile .toPath ()));
101107 }
102108 }
103109
@@ -121,12 +127,39 @@ public void preExecute() {
121127 }
122128 }
123129
124- List <URL > urls = dependencyManager .getDownloadProvider ().injectURLWithCandidates (url );
125- task = new FileDownloadTask (urls , jar ,
126- library .getDownload ().getSha1 () != null ? new FileDownloadTask .IntegrityCheck ("SHA-1" , library .getDownload ().getSha1 ()) : null );
127- task .setCacheRepository (cacheRepository );
128- task .setCaching (true );
129- task .addIntegrityCheckHandler (FileDownloadTask .ZIP_INTEGRITY_CHECK_HANDLER );
130+ if (testURLExistence (url )) {
131+ List <URL > urls = dependencyManager .getDownloadProvider ().injectURLWithCandidates (url + ".pack.xz" );
132+ task = new FileDownloadTask (urls , xzFile , null );
133+ task .setCacheRepository (cacheRepository );
134+ task .setCaching (true );
135+ xz = true ;
136+ } else {
137+ List <URL > urls = dependencyManager .getDownloadProvider ().injectURLWithCandidates (url );
138+ task = new FileDownloadTask (urls , jar ,
139+ library .getDownload ().getSha1 () != null ? new FileDownloadTask .IntegrityCheck ("SHA-1" , library .getDownload ().getSha1 ()) : null );
140+ task .setCacheRepository (cacheRepository );
141+ task .setCaching (true );
142+ task .addIntegrityCheckHandler (FileDownloadTask .ZIP_INTEGRITY_CHECK_HANDLER );
143+ xz = false ;
144+ }
145+ }
146+
147+ private boolean testURLExistence (String rawUrl ) {
148+ List <URL > urls = dependencyManager .getDownloadProvider ().injectURLWithCandidates (rawUrl );
149+ for (URL url : urls ) {
150+ URL rawURL = NetworkUtils .toURL (url .toString ());
151+ URL xzURL = NetworkUtils .toURL (url + ".pack.xz" );
152+ for (int retry = 0 ; retry < 3 ; retry ++) {
153+ try {
154+ if (NetworkUtils .urlExists (rawURL ))
155+ return false ;
156+ return NetworkUtils .urlExists (xzURL );
157+ } catch (IOException e ) {
158+ LOG .log (Level .WARNING , "Failed to test for url existence: " + url + ".pack.xz" , e );
159+ }
160+ }
161+ }
162+ return false ; // maybe some ugly implementation will give timeout for not existent url.
130163 }
131164
132165 @ Override
@@ -138,7 +171,7 @@ public boolean doPostExecute() {
138171 public void postExecute () throws Exception {
139172 if (!cached ) {
140173 try {
141- cacheRepository .cacheLibrary (library , jar .toPath (), false );
174+ cacheRepository .cacheLibrary (library , jar .toPath (), xz );
142175 } catch (IOException e ) {
143176 LOG .log (Level .WARNING , "Failed to cache downloaded library " + library , e );
144177 }
@@ -203,4 +236,42 @@ private static boolean validateJar(byte[] data, List<String> checksums) throws I
203236 }
204237 return false ;
205238 }
239+
240+ private static void unpackLibrary (File dest , byte [] src ) throws IOException {
241+ if (dest .exists ())
242+ if (!dest .delete ())
243+ throw new IOException ("Unable to delete file " + dest );
244+
245+ byte [] decompressed ;
246+ try {
247+ decompressed = IOUtils .readFullyAsByteArray (new XZInputStream (new ByteArrayInputStream (src )));
248+ } catch (IOException e ) {
249+ throw new ArtifactMalformedException ("Library " + dest + " is malformed" );
250+ }
251+
252+ String end = new String (decompressed , decompressed .length - 4 , 4 );
253+ if (!end .equals ("SIGN" ))
254+ throw new IOException ("Unpacking failed, signature missing " + end );
255+
256+ int x = decompressed .length ;
257+ int len = decompressed [(x - 8 )] & 0xFF | (decompressed [(x - 7 )] & 0xFF ) << 8 | (decompressed [(x - 6 )] & 0xFF ) << 16 | (decompressed [(x - 5 )] & 0xFF ) << 24 ;
258+
259+ Path temp = Files .createTempFile ("minecraft" , ".pack" );
260+
261+ byte [] checksums = Arrays .copyOfRange (decompressed , decompressed .length - len - 8 , decompressed .length - 8 );
262+
263+ try (OutputStream out = Files .newOutputStream (temp )) {
264+ out .write (decompressed , 0 , decompressed .length - len - 8 );
265+ }
266+
267+ try (FileOutputStream jarBytes = new FileOutputStream (dest ); JarOutputStream jos = new JarOutputStream (jarBytes )) {
268+ Pack200Utils .unpack (FCLPath .NATIVE_LIB_DIR , temp .toAbsolutePath ().toString (), dest .getAbsolutePath ());
269+
270+ JarEntry checksumsFile = new JarEntry ("checksums.sha1" );
271+ checksumsFile .setTime (0L );
272+ jos .putNextEntry (checksumsFile );
273+ jos .write (checksums );
274+ jos .closeEntry ();
275+ }
276+ }
206277}
0 commit comments