org.netbeans.modules.autoupdate.services.ExternalFile Maven / Gradle / Ivy
The newest version!
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.netbeans.modules.autoupdate.services;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.CRC32;
import static org.netbeans.modules.autoupdate.services.Utilities.hexDecode;
public class ExternalFile {
private static final Logger LOG = Logger.getLogger(ExternalFile.class.getName());
/**
* Parse an ".external" file from supplied input stream.
*
* The expected format is a UTF-8 encoded text file. The format is line
* oriented and contain the following items:
*
*
* - lines with the format {@code #
} are treated as a
* comments
* - lines with the format {@code CRC:
} represent a CRC32
* checksum
* - lines with the format {@code URL:
} represents one possible URL
* for download
* - lines with the format {@code SIZE:
} represent the
* size of the target file (currently unused)
* - lines with the format {@code URL:
} represents one possible URL
* for download
* - lines with the format
* {@code MessageDigest:
} represents one message
* digest for the data. {@code } is the message digest algorithm
* used and {@code } the result of the digest algorithm applied
* to the data referenced by the URL(s) and hex encoded.
*
*
* If multiple {@code CRC} lines are found, the last value will be used,
* if multiple {@code URL} lines are found, all URLs are considered as
* possible download source. Multiple {@code MessageDigest} lines with
* different {@code algorithm} values will all be considered, if the same
* {@code algorithm} is found twice, only the last entry is considered.
*
* This method will not close the inputStream.
*
* @param is
* @return
*/
public static ExternalFile fromStream(String name, InputStream is) throws IOException {
ExternalFile ext = new ExternalFile();
ext.setName(name);
BufferedReader br = new BufferedReader(new InputStreamReader(is, StandardCharsets.UTF_8));
for(String line = br.readLine(); line != null; line = br.readLine()) {
if(line.startsWith("#")) {
// Comment
} else if (line.startsWith("SIZE:")) {
ext.setSize(Integer.parseInt(line.substring(5).trim()));
} else if (line.startsWith("CRC:")) {
ext.setCrc32(Long.parseLong(line.substring(4).trim()));
} else if (line.startsWith("URL:")) {
String url = line.substring(4).trim();
for (;;) {
int index = url.indexOf("${");
if (index == -1) {
break;
}
int end = url.indexOf("}", index);
String propName = url.substring(index + 2, end);
final String propVal = System.getProperty(propName);
if (propVal == null) {
throw new IOException("Can't find property " + propName);
}
url = url.substring(0, index) + propVal + url.substring(end + 1);
}
ext.getModifiableUrls().add(url);
} else if (line.startsWith("MessageDigest:")) {
// Assume format: HexEncodedHashValue>
String[] parts = line.substring(14).trim().split("\\s+");
if(parts.length == 2) {
try {
ext.getModifiableMessageDigests().put(
parts[0],
hexDecode(parts[1]));
} catch (IllegalArgumentException ex) {
LOG.log(Level.INFO, MessageFormat.format(
"Invalidly formatted MessageDigest line found in {1}: {0}",
new Object[]{line, name}), ex);
}
} else {
LOG.log(Level.INFO,
"Invalidly formatted MessageDigest line found in {1}: {0}",
new Object[]{line, name});
}
} else if (! line.trim().isEmpty()) {
LOG.log(Level.INFO, "Invalid content found in {1}: {0}",
new Object[]{line, name});
}
}
return ext;
}
private String name;
private final List urls = new ArrayList<>();
private Long crc32 = null;
private Integer size = null;
private final Map messageDigest = new HashMap<>();
private ExternalFile() {
}
public List getUrls() {
return Collections.unmodifiableList(urls);
}
public Map getMessageDigests() {
return Collections.unmodifiableMap(this.messageDigest);
}
@SuppressWarnings("ReturnOfCollectionOrArrayField")
private List getModifiableUrls() {
return urls;
}
@SuppressWarnings("ReturnOfCollectionOrArrayField")
private Map getModifiableMessageDigests() {
return this.messageDigest;
}
public Long getCrc32() {
return crc32;
}
private void setCrc32(Long crc32) {
this.crc32 = crc32;
}
public Integer getSize() {
return size;
}
public void setSize(Integer size) {
this.size = size;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
/**
* @return validator, that checks the CRC32 value and all message digest
* values, that can be verified by the runtime JRE. Unsupported
* message digest values will be ignored
*/
public MessageMultiValidator getValidator() {
List validators = new ArrayList<>(2);
validators.add(new MessageChecksumValidator(new CRC32(), getCrc32()));
for(Entry entry: getMessageDigests().entrySet()) {
try {
validators.add(new MessageDigestValidator(
MessageDigest.getInstance(entry.getKey()), entry.getValue()));
} catch (NoSuchAlgorithmException ex) {
LOG.log(Level.INFO,
"Requested message digest {0} not found for {1}",
new Object[] {entry.getKey(), getName()});
}
}
return new MessageMultiValidator(validators);
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy