/*******************************************************************************
* Copyright (c) 2015 ARM Ltd. and others
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* ARM Ltd and ARM Germany GmbH - Initial API and implementation
*
* OS type detection is based on algorithm published here:
* http://stackoverflow.com/questions/228477/how-do-i-programmatically-determine-operating-system-in-java
*
*******************************************************************************/
package com.arm.cmsis.pack.utils;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.Collection;
import java.util.LinkedList;
import java.util.Set;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import com.arm.cmsis.pack.common.CmsisConstants;
/**
* Class for different utilities
*/
public class Utils {
static public final String QUOTE = "\""; //$NON-NLS-1$
static private String host = null; // name of a running host OS : win, mac, or linux
/**
* Find all pdsc recursively from given directory
* @param dir directory to start search
* @param files list to collect items, if null the list will be allocated
* @param depth number of sub-directory levels to search for: 0 - search current directory only
* @return list of found pdsc files
*/
static public Collection<String> findPdscFiles(File dir, Collection<String> files, int depth){
if( files == null) {
files = new LinkedList<String>();
}
File[] list = dir.listFiles();
if (list == null) {
return files;
}
// search dir for pdsc files
for ( File f : list ) {
if( f.isFile() && !f.isHidden()) {
String name = f.getName();
if(!name.startsWith(".") && name.endsWith(CmsisConstants.EXT_PDSC)){ //$NON-NLS-1$
files.add(f.getAbsolutePath());
}
}
}
if(depth <= 0) {
return files;
}
// search sub-directories
// search dir for pdsc files
for ( File f : list ) {
if( f.isDirectory() && !f.isHidden() && !f.getName().startsWith(".")) { //$NON-NLS-1$
findPdscFiles(f, files, depth-1);
}
}
return files;
}
/**
* Replaces all '*' and '?' to 'x' and all non-alphanumeric chars to '_' in supplied string
* @param s source string
* @return the resulting string
*/
static public String wildCardsToX(String s) {
if(s == null || s.isEmpty()) {
return s;
}
StringBuilder res = new StringBuilder();
for(int i = 0; i < s.length(); i++){
char ch = s.charAt(i);
if(Character.isLetterOrDigit(ch) || ch== '-' || ch =='.') { // allowed characters
// do nothing
} else if(ch == '*' || ch == '?') { // wildcards
ch = 'x';
} else {// any other character
ch = '_';
}
res.append(ch);
}
return res.toString();
}
/**
* Adds trailing slash to path
* @param path path to add slash
* @return the result string
*/
static public String addTrailingSlash(String path) {
if(path == null || path.isEmpty() || path.endsWith("/")) { //$NON-NLS-1$
return path;
}
if(path.endsWith(File.separator)) {
path = removeTrailingSlash(path);
}
return path + "/"; //$NON-NLS-1$
}
/**
* Removes trailing slash from path
* @param path path to remove slash
* @return the result string
*/
static public String removeTrailingSlash(String path) {
if(path == null || path.isEmpty()) {
return path;
}
if(path.endsWith("/") || path.endsWith(File.separator)) { //$NON-NLS-1$
return path.substring(0, path.length() - 1);
}
return path;
}
/**
* Extracts filename portion out of supplied pathname (leaves last segment only)
* @param path absolute or relative path with forward slashes as delimiters
* @return the result filename
*/
static public String extractFileName(String path) {
if(path == null || path.isEmpty()) {
return path;
}
int pos = path.lastIndexOf('/');
if(pos < 0) {
pos = path.lastIndexOf('\\');
}
if(pos >= 0 ) {
return path.substring(pos + 1);
}
return path;
}
/**
* Extracts base filename portion (without extension) out of supplied pathname
* @param path absolute or relative path with forward slashes as delimiters
* @return the result filename
*/
static public String extractBaseFileName(String path) {
if(path == null || path.isEmpty()) {
return path;
}
String filename = extractFileName(path);
int pos = filename.lastIndexOf('.');
if(pos >= 0 ) {
return filename.substring(0, pos);
}
return filename;
}
/**
* Extracts file extension (leaves last segment only)
* @param filename absolute or relative filename with forward slashes as delimiters
* @return the result filename
*/
static public String extractFileExtension(String filename) {
if(filename == null || filename.isEmpty()) {
return filename;
}
int pos = filename.lastIndexOf('.');
if(pos >= 0 ) {
return filename.substring(pos+1);
}
return null;
}
/**
* Extracts path portion out of supplied pathname (removes section out last slash)
* @param path absolute or relative path with forward slashes as delimiters
* @param keepSlash flag if to keep or remove trailing slash
* @return the result path
*/
static public String extractPath(String path, boolean keepSlash) {
if(path == null || path.isEmpty()) {
return path;
}
int pos = path.lastIndexOf('/');
if(pos < 0) {
pos = path.lastIndexOf('\\');
}
if(pos >= 0 ) {
if(keepSlash) {
pos++;
}
return path.substring(0, pos);
}
return path;
}
/**
* Returns a path equivalent to this path, but relative to the given base path if possible.
* @param path path to make relative
* @param basePath absolute base directory
* @return A path relative to the base path, or this path if it could not be made relative to the given base
*/
static public String makePathRelative(String path, String basePath) {
if(path == null || basePath ==null || basePath.isEmpty()) {
return path;
}
IPath p = new Path(path);
IPath base = new Path(basePath);
p = p.makeRelativeTo(base);
return p.toString();
}
/**
* Check if a URL string is valid
* @param urlStr the URL string
* @return true if the URL is valid
*/
static public boolean isValidURL(String urlStr) {
if (urlStr == null) {
return false;
}
try {
new URL(urlStr);
return true;
} catch (MalformedURLException e) {
return false;
}
}
/**
* Surround supplied path with quotes if needed
* @param path path to surround with quotes
* @return quoted string
*/
static public String addQuotes(String path) {
if(path == null || path.isEmpty()) {
return path;
}
String quoted = CmsisConstants.EMPTY_STRING;
if(!path.startsWith(QUOTE)) {
quoted = QUOTE;
}
quoted += path;
if(!path.endsWith(QUOTE)) {
quoted += QUOTE;
}
return quoted;
}
/**
* Returns index of string in a string collection
* @param stringCollection collection of strings
* @param str string to search for
* @return index of the string if found, otherwise -1
*/
static public int indexOf(Collection<String> stringCollection, String str) {
if (str != null && stringCollection != null) {
int i = 0;
for(String s : stringCollection) {
if (s.equals(str)) {
return i;
}
i++;
}
}
return -1;
}
/**
* Returns index of string in a string array
* @param stringArray collection of strings
* @param str string to search for
* @return index of the string if found, otherwise -1
*/
static public int indexOf(String[] stringArray, String str) {
if (str != null && stringArray != null) {
int i = 0;
for(String s : stringArray) {
if (s.equals(str)) {
return i;
}
i++;
}
}
return -1;
}
/**
* Returns clock value with suffix
* @param dclock String representing decimal clock frequency
* @return scaled string
*/
static public String getScaledClockFrequency(String dclock)
{
if (dclock == null || dclock.isEmpty()) {
return CmsisConstants.EMPTY_STRING;
}
int len = dclock.length();
if (len > 6) {
return (dclock.substring(0, len - 6) + " MHz"); //$NON-NLS-1$
} else if (len > 3) {
return (dclock.substring(0, len - 3) + " kHz"); //$NON-NLS-1$
} else {
return (dclock.substring(0, len - 6) + " Hz"); //$NON-NLS-1$
}
}
/**
* Returns readable representation of memory size
* @param size memory size in bytes
* @return readable memory size string
*/
static public String getMemorySizeString(long size)
{
if (size == 0) {
return CmsisConstants.EMPTY_STRING;
}
if (size < 1024) {
return Long.toString(size) + " Byte"; //$NON-NLS-1$
}
size >>= 10; // Scale to kByte
if (size < 1024 || (size % 1024) != 0) {
// Less than a MByte or division with rest => show kByte
return Long.toString(size) + " kB"; //$NON-NLS-1$
}
size >>= 10; // Scale to MByte
return Long.toString(size) + " MB"; //$NON-NLS-1$
}
/**
* Copy from one directory to another
*
* @param sourceLocation source directory
* @param destLocation destination directory
* @throws IOException
*/
public static void copyDirectory(File sourceLocation, File destLocation) throws IOException {
if(sourceLocation == null) {
return;
}
if (sourceLocation.isDirectory()) {
String[] children = sourceLocation.list();
if(children == null) {
return;
}
for (String child : children) {
copyDirectory(new File(sourceLocation, child), new File(destLocation, child));
}
} else {
if (!destLocation.getParentFile().exists()) {
destLocation.getParentFile().mkdirs();
}
copy(sourceLocation, destLocation);
}
}
/**
* Copy from one directory to another
*
* @param srcDir source directory
* @param dstDir destination directory
* @param ignoreDir directories that should ignore during copy (directories w/ absolute path)
* @throws IOException
*/
public static void copyDirectoryWithProgress(File srcDir, File dstDir, Set<String> ignoreDir, IProgressMonitor monitor) throws IOException {
if(srcDir == null || (ignoreDir != null && ignoreDir.contains(srcDir.getAbsolutePath()))) {
return;
}
if (srcDir.isDirectory()) {
String[] children = srcDir.list();
if(children == null) {
return;
}
for (String child : children) {
copyDirectoryWithProgress(new File(srcDir, child), new File(dstDir, child), ignoreDir, monitor);
}
} else {
if (!dstDir.getParentFile().exists()) {
dstDir.getParentFile().mkdirs();
}
copy(srcDir, dstDir);
monitor.worked(1);
}
}
/**
* Get the String of current date in the format of "dd-mm-yyyy"
* @return String of current date in the format of "dd-mm-yyyy"
*/
public static String getCurrentDate() {
DateTimeFormatter dtf = DateTimeFormatter.ofPattern("dd/MM/yyyy"); //$NON-NLS-1$
LocalDate localDate = LocalDate.now();
String[] date = dtf.format(localDate).split("/"); //$NON-NLS-1$
return String.valueOf(Integer.parseInt(date[0])) + '-'
+ String.valueOf(Integer.parseInt(date[1])) + '-'
+ String.valueOf(Integer.parseInt(date[2]));
}
/**
* Copy sourceFile to destFile
*
* @param source source file
* @param dest destination file
*/
public static void copy(File source, File dest) throws IOException {
InputStream input = null;
OutputStream output = null;
if (!dest.getParentFile().exists()) {
dest.getParentFile().mkdirs();
}
try {
input = new FileInputStream(source);
if (dest.exists()) {
dest.delete();
}
output = new FileOutputStream(dest);
byte[] buf = new byte[1024];
int bytesRead;
while ((bytesRead = input.read(buf)) > 0) {
output.write(buf, 0, bytesRead);
}
dest.setWritable(true, true);
} finally {
if (input != null) {
input.close();
}
if (output != null) {
output.close();
}
}
}
/**
* Delete the folder recursively: first file, then folder
*
* @param folder the folder
*/
public static void deleteFolderRecursive(File folder) {
if (folder == null) {
return;
}
if (folder.exists()) {
File[] files = folder.listFiles();
if(files == null) {
return;
}
for (File f : files) {
if (f.isDirectory()) {
deleteFolderRecursive(f);
f.setWritable(true, false);
f.delete();
} else {
f.setWritable(true, false);
f.delete();
}
}
folder.setWritable(true, false);
folder.delete();
}
}
/**
* @param archiveFile the zip file
* @return the number of files contained in this zip file
* @throws IOException
*/
public static int getFilesCount(File archiveFile) throws IOException {
ZipInputStream zipInput;
zipInput = new ZipInputStream(new FileInputStream(archiveFile));
ZipEntry zipEntry = zipInput.getNextEntry();
int count = 0;
while (zipEntry != null) {
if (!zipEntry.isDirectory()) {
count++;
}
zipEntry = zipInput.getNextEntry();
}
zipInput.closeEntry();
zipInput.close();
return count;
}
/**
* Delete the folder recursively with progress monitor: first file, then folder
*
* @param folder the folder
*/
public static void deleteFolderRecursiveWithProgress(File folder, IProgressMonitor monitor) {
if (folder == null) {
return;
}
if (folder.isFile()) {
folder.setWritable(true, false);
folder.delete();
return;
}
if (folder.exists()) {
File[] files = folder.listFiles();
if(files == null) {
return;
}
for (File f : files) {
if (f.isDirectory()) {
deleteFolderRecursiveWithProgress(f, monitor);
f.setWritable(true, false);
f.delete();
} else {
f.setWritable(true, false);
f.delete();
monitor.worked(1);
}
}
folder.setWritable(true, false);
folder.delete();
}
}
/**
* Count the number of files in specific folder
* @param folder the root folder
* @return the number of files in folder
*/
public static int countFiles(File folder) {
if (folder == null) {
return 0;
}
if (folder.isFile()) {
return 1;
}
int count = 0;
if (folder.exists()) {
File[] files = folder.listFiles();
if(files == null) {
return 0;
}
for (File f : files) {
if (f.isDirectory()) {
count += countFiles(f);
} else {
count++;
}
}
}
return count;
}
/**
* Clear the read-only flag
*
* @param folder the root folder
* @param extension extension of the files whose read-only flag should be cleared,
* use an empty string to clear the read-only flag on all the files
*/
public static void clearReadOnly(File folder, String extension) {
if (folder == null) {
return;
}
if (folder.exists()) {
File[] files = folder.listFiles();
if(files == null) {
return;
}
for (File f : files) {
if (f.isDirectory()) {
clearReadOnly(f, extension);
f.setWritable(true, false);
} else if (extension == null || extension.isEmpty() || f.getName().endsWith(extension)) {
f.setWritable(true, false);
}
}
folder.setWritable(true, false);
}
}
/**
* Set the read-only flag
*
* @param folder the folder
*/
public static void setReadOnly(File folder) {
if (folder == null) {
return;
}
if (folder.exists()) {
File[] files = folder.listFiles();
if(files == null) {
return;
}
for (File f : files) {
if (f.isDirectory()) {
setReadOnly(f);
f.setReadOnly();
} else {
f.setReadOnly();
}
}
folder.setReadOnly();
}
}
/**
* Checks if two sets intersect
* @param set1 first set
* @param set2 second set
* @return true if both sets contain at least one common member
*/
public static <T> boolean checkIfIntersect(Set<T> set1, Set<T> set2) {
if(set1 == null || set2 == null) {
return false;
}
if (set1.size() > set2.size()) {
return checkIfIntersect(set2, set1);
}
for (T o : set1) {
if (set2.contains(o)) {
return true;
}
}
return false;
}
/**
* Returns host type: win, mac or linux
* @return host type
*/
public static String getHostType(){
if(host == null) {
String os = System.getProperty("os.name", CmsisConstants.EMPTY_STRING).toLowerCase(); //$NON-NLS-1$
if (os.contains(CmsisConstants.MAC) || os.contains("darwin")) { //$NON-NLS-1$
host = CmsisConstants.MAC;
} else if (os.contains("nux") || os.contains("nix")) { //$NON-NLS-1$ //$NON-NLS-2$
host = CmsisConstants.LINUX;
} else if (os.contains(CmsisConstants.WIN)) {
host = CmsisConstants.WIN;
} else {
host = CmsisConstants.EMPTY_STRING;
}
}
return host;
}
}