/*
* This file is a part of Alchemy OS project.
* Copyright (C) 2011-2013, Sergey Basalaev <sbasalaev@gmail.com>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package alchemy.io;
import alchemy.fs.Filesystem;
import alchemy.util.Strings;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import javax.microedition.io.Connector;
/**
* Miscellaneous I/O utilities used in Alchemy OS.
* @author Sergey Basalaev
*/
public final class IO {
private IO() { }
/**
* Reads until the end of the stream and returns result as a byte array.
* @param s input stream
* @return byte array containing all bytes read
* @throws IOException if an I/O error occurs
*/
public static byte[] readFully(InputStream s) throws IOException {
int count = 0;
byte[] buf = new byte[32];
while (true) {
if (count == buf.length) {
byte[] newbuf = new byte[count << 1];
System.arraycopy(buf, 0, newbuf, 0, count);
buf = newbuf;
}
int len = s.read(buf, count, buf.length-count);
if (len <= 0) break;
count += len;
}
byte[] ret = new byte[count];
System.arraycopy(buf, 0, ret, 0, count);
return ret;
}
/** Converts object to a string and writes it as UTF-8. */
public static void print(OutputStream s, Object obj) {
try {
s.write(Strings.utfEncode(Strings.toString(obj)));
} catch (IOException ioe) { }
}
/** Converts object to a string, writes it as UTF-8 and terminates a line. */
public static void println(OutputStream s, Object obj) {
try {
s.write(Strings.utfEncode(Strings.toString(obj)));
s.write('\n');
s.flush();
} catch (IOException ioe) { }
}
/** Channels all data from the input to the output. */
public static void writeAll(InputStream from, OutputStream to) throws IOException {
byte[] buf = new byte[1024];
int len = from.read(buf);
while (len > 0) {
to.write(buf, 0, len);
len = from.read(buf);
}
}
/**
* Checks if given filename matches glob pattern.
* Supported wildcards are <code>*</code> and <code>?</code>.
* These characters can be escaped using backslash.
*/
public static boolean matchesPattern(String name, String pattern) {
int nameofs = 0;
int pofs = 0;
int namelen = name.length();
int plen = pattern.length();
while (pofs < plen) {
char ch = pattern.charAt(pofs);
pofs++;
switch (ch) {
case '*': { // any sequence of characters
/* skip subsequent stars */
while (pofs < plen && pattern.charAt(pofs) == '*')
pofs++;
/* ending star matches everything */
if (pofs == plen) return true;
/* match tails */
String tailpattern = pattern.substring(pofs, plen);
ch = tailpattern.charAt(0);
if (ch == '?') { //unoptimized cycle
for (int i = nameofs; i < namelen; i++) {
if (matchesPattern(name.substring(i,namelen), tailpattern))
return true;
}
} else {
if (ch == '\\' && tailpattern.length() > 1) ch = tailpattern.charAt(1);
for (int i = name.indexOf(ch, nameofs); i >= 0; i = name.indexOf(ch, i+1)) {
if (matchesPattern(name.substring(i,namelen), tailpattern))
return true;
}
}
return false;
}
case '\\': { // escaped character, exact match
if (pofs < plen) ch = pattern.charAt(pofs);
if (nameofs == namelen) return false;
if (name.charAt(nameofs) != ch) return false;
nameofs++;
pofs++;
break;
}
case '?': { // any character
if (nameofs == namelen) return false;
nameofs++;
break;
}
default: { // exact character match
if (nameofs == namelen) return false;
if (name.charAt(nameofs) != ch) return false;
nameofs++;
}
}
}
/* empty pattern matches empty string */
return nameofs == namelen;
}
/**
* Returns input stream to read from the specified URL.
* Supported protocols are "file", "res", "http" and "https".
*/
public static ConnectionInputStream readUrl(String url) throws IOException {
int cl = url.indexOf(':');
if (cl <= 0)
throw new IOException("No protocol in URL");
ConnectionInputStream input;
String protocol = url.substring(0,cl);
String path = url.substring(cl+1);
InputStream in;
if ("file".equals(protocol)) {
in = Filesystem.read(path);
} else if ("res".equals(protocol)) {
in = String.class.getResourceAsStream(path);
if (in == null)
throw new IOException("Resource not found: " + path);
} else if ("http".equals(protocol) || "https".equals(protocol)) {
in = Connector.openInputStream(url);
} else {
throw new IOException("Unknown protocol: " + protocol);
}
if (in instanceof ConnectionInputStream) {
return (ConnectionInputStream)in;
} else {
return new ConnectionInputStream(in);
}
}
}