I'm trying to make a Java program which calls some other software as a command from cmd, receives the output, and prints it in a Jframe. The problem is that when it prints there are some characters (Which seem to be just spaces) which become squares. I think these characters are not recognized correctly. The homsimpl command is just from CHOMP (Computational Homology Project).
I tried to remove all the HTML code from the Strings, the squared characters were still there. When I put System.out.println(s) or System.out.println(Outp) it prints correctly in the output, without the squared characters. I also tried to change the font, but with any font I tried to use, the squared characters were still squared in the JFrame. If I copy the output text and paste it to be in the JFrame the squared characters disappear, but I can't solve the problem like that.
The JFrame appears like this:
and the Output shows:
HOMSIMPL, ver. 0.01, 11/09/04. Copyright (C) 1997-2013 by Pawel Pilarczyk.
This is free software. No warranty. Consult 'license.txt' for details.
[Tech info: simpl 4, chain 12, addr 4, intgr 2.]
Reading simplices to X from 'Simplicial.sim'... 4 simplices read.
Collapsing faces in X... .. 0 removed, 14 left.
Creating the chain complex of X... .. Done.
Time used so far: 0.00 sec (0.000 min).
Computing the homology of X over the ring of integers...
Reducing D_2: 0 + 3 reductions made.
Reducing D_1: 3 + 0 reductions made.
H_0 = Z
H_1 = 0
H_2 = Z
Saving generators of X to 'Simplicial.txt'... Done.
Total time used: 0.02 sec (0.000 min).
[Press Ctrl-C to exit.]
Thank you for using this software. We appreciate your business.
A simplified version of my program follows:
import java.io.*;
import javax.swing.*;
public class Test {
public static void main(String[] args)
throws IOException {
PrintWriter Cod = new PrintWriter("Simplicial.sim");
Cod.println("{1,2,3}");
Cod.println("{1,2,4}");
Cod.println("{1,3,4}");
Cod.println("{2,3,4}");
Cod.close();
Process p = Runtime.getRuntime().exec("cmd /c \"homsimpl Simplicial.sim -g Simplicial.txt\"");
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
String s = null;
JFrame f = new JFrame();
JPanel pa = new JPanel();
JLabel la = new JLabel();
f.setSize(500, 500);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.add(pa);
String Outp="";
JScrollPane pane = new JScrollPane(pa);
pa.add(la);
f.setContentPane(pane);
f.setVisible(true);
while ((s = stdInput.readLine()) != null) {
Outp=Outp+"<br/>"+s;
la.setText("<html>"+Outp+"</html>");
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
}
Actually, this is a problem that has nothing to do with Swing. As far as i can see from the name of the file you are writing to ("Simplicial.sim), your OS language is not English. This is a usual problem when executing a command to a windows console. In order to make myself clear, i will use an example of a command that will cause a problem like this. Lets take the command that (indirectly) gives you the installed version of Microsoft Office in a windows PC. This command is reg query \"HKEY_CLASSES_ROOT\\Word.Application\\CurVer\".
Now, let's execute it to CMD:
You can easily see that there are Greek words in the answer we get. (So in your case, something similar but not English).
This is the problem. When you new BufferedReader(new InputStreamReader(p.getInputStream())); you take the exact same input with console. Since the InputStream does not use UTF-8 encoding, it cannot read Greek. So, the problem becomes now Reading InputStream as UTF-8.
Without loosing any time, let's change new BufferedReader(new InputStreamReader(p.getInputStream())); to new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF-8));
Guess what? Its a loss. We are still getting the same characters (a bit different actually but still not readable). I wish i could explain why...
The solution you have to follow here is writing a batch that will change the code page of the console to UTF-8 and then execute the command you want. After that, the input is being read flawlessly.
You can run this example (do not ignore comments) in order to see it better:
public class CmdUnicode {
private final static String COMMAND = "reg query \"HKEY_CLASSES_ROOT\\Word.Application\\CurVer\"";
public static void main(String[] args) throws IOException {
System.out.println(executeCmd());
System.out.println();
System.out.println("-------------");
System.out.println();
System.out.println(executeCmdBat());
}
private static String executeCmdBat() throws IOException {
File batFile = writeBatchFile();
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec("cmd /c " + batFile.getAbsolutePath());
return streamToString(proc.getInputStream());
}
private static File writeBatchFile() throws IOException {
File file = File.createTempFile("test", ".bat");
StringBuilder sb = new StringBuilder();
sb.append("#echo off"); // Do not show cmd window
sb.append(System.lineSeparator());
sb.append("chcp 65001"); // Enable unicode to cmd
sb.append(System.lineSeparator());
sb.append(COMMAND);
try (PrintWriter out = new PrintWriter(file)) {
out.write(sb.toString());
out.flush(); // Is this required? :P
}
return file;
}
private static String executeCmd() throws IOException {
Runtime rt = Runtime.getRuntime();
Process proc = rt.exec(COMMAND);
return streamToString(proc.getInputStream());
}
private static String streamToString(InputStream stream) throws IOException {
StringBuilder sb = new StringBuilder();
String line = null;
try (BufferedReader stdInput = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
while ((line = stdInput.readLine()) != null) {
sb.append(line);
sb.append(System.lineSeparator());
}
}
return sb.toString();
}
}
The console prints to me:
HKEY_CLASSES_ROOT\Word.Application\CurVer
(??????????) REG_SZ Word.Application.16
-------------
Active code page: 65001
HKEY_CLASSES_ROOT\Word.Application\CurVer
(Default) REG_SZ Word.Application.16
If you insist of getting the input after executing the command in your language you will have to search somewhere else (or probably make another topic here) and if you find anything that works, let me know....
And just for the record Προεπιλογή translates to Default :)
Related
I'm trying to do a proof of concept exploit to show how changing the path variable can replace standard programs for malicious ends. I put a dummy program called "cmd.exe" in a directory "C:\path\to\fake_exe\" and changed the path to have that at the front.
Below is the function I'm using to demonstrate, but it runs normally (i.e., it passes the arguments to the correct cmd.exe instead of my fake one). I even passed "cmd" to the function, and it opened my dummy program! So the path variable is definitely set to find my fake cmd.exe correctly, but the exec(..) function is finding the proper cmd.exe regardless.
How does the exec(...) function find executables? Where is this documented?
static void unsafeExec(String cmd) throws IOException, InterruptedException {
String[] run = new String[3];
run[0] = "cmd.exe";
run[1] = "/C";
run[2] = cmd;
Process p = Runtime.getRuntime().exec(run);
BufferedReader stdIN = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdER = new BufferedReader(new InputStreamReader(p.getErrorStream()));
p.waitFor();
String s;
while ((s = stdIN.readLine()) != null) {
System.out.println(s);
}
while ((s = stdER.readLine()) != null) {
System.out.print(s);
}
}
I've come across a strange issue. I've used process builder several times to call an executable from a program but have never encountered this before. For debug purposes I made a method which prints the output of the executable to System.out. Everything worked fine and my program nicely exported all of the test gifs I ran.
When it came time to run this program properly for 1000+ gifs I commented out the printout method to improve performance. Once the whole program had run I come back to find that the exportGif did not work. The program ran with no errors but the calling of the process simply did not export the gifs as expected.
After isolating lines in the printout method it seems that the deciding bit of code is the reader.readLine(). Why would this be the case? The executable should have already run, the debug method should only read the output stream after the fact, correct? I'd rather not loop through it's output stream every time as it causes the program to slow considerably.
private void printProcessOutput(Process process){
BufferedReader reader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
StringBuilder builder = new StringBuilder();
String line = null;
try{
while ( (line = reader.readLine()) != null) {
builder.append(line);
builder.append(System.getProperty("line.separator"));
}
}catch(IOException e){
e.printStackTrace();
}
System.out.println(builder.toString());
}
private void exportGIF(String dirPath) throws IOException {
List<String> lines = Arrays.asList("/Users/IdeaProjects/MasterFormat/MasterFormat-Java/MasterFormat/timMaster_4.1.png \"{200.0,467.0}\"");
Path headImageFile = Paths.get(System.getProperty("user.dir") + File.separator + "headImageInfo.txt");
Files.write(headImageFile, lines, Charset.forName("UTF-8"));
String templatePath = dirPath + File.separator + "template.mp4";
String outputPath = dirPath + File.separator;
String headImagePath = headImageFile.toString();
String gifExportExecPath = "/Users/IdeaProjects/MasterFormat/MasterFormat-Java/MasterFormat/GIFExport";
Process process = new ProcessBuilder(gifExportExecPath, "-s", templatePath, "-o", outputPath, "-h", headImagePath).start();
printProcessOutput(process);
Files.delete(headImageFile);
}
EDIT
One thing I should add. I noticed that when I comment out the debug method it clocks through all 1000+ iterations in less than ten minutes, But, of course the gifs do not export (the executable doesn't run...? Not sure).
When I include the printout method it is a lot slower. I tried running it overnight but it got stuck after 183 iterations. I've tried profiling to see if it was causing some thrashing but the GC seems to run fine.
You need to consume the output of the Process or it may hang. So you can't comment out printProcessOutput(process);. Instead, comment out the lines that actually do the printing:
try{
while ( (line = reader.readLine()) != null) {
//builder.append(line);
//builder.append(System.getProperty("line.separator"));
}
} catch(IOException e){
e.printStackTrace();
}
//System.out.println(builder.toString());
I generally use this method, which also redirects the error stream:
public static void runProcess(ProcessBuilder pb) throws IOException {
pb.redirectErrorStream(true);
Process p = pb.start();
BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
//System.out.println(line);
}
}
hope someone can help me here. Googled til my eyes bled and no luck, and tried everything I can think of.
I'm trying to execute a shell script which plays a song. When I type the following into the command line, everything's fine:
/home/pi/startsong.sh /path/to/track
However, I'm trying to execute the script via a Java app, but get no response at all. Here's what I'm doing:
public void begin(String song) throws IOException, InterruptedException {
//Split song title
String[] cmd = song.split("");
StringBuilder sb = new StringBuilder();
//Ignore for now, this is just about sorting out titles with spaces, but irrelevant
for (int i = 0; i < cmd.length; i++) {
if (cmd[i].equals(" ")) {
cmd[i] = " ";
}
sb.append(cmd[i]);
}
//Initiate bash script whilst passing song title as argument
String command = "/home/pi/startsong.sh " + sb.toString();
System.out.println(command);
Runtime rt = Runtime.getRuntime();
Process p = rt.exec(command);
p.waitFor();
System.out.println("Playing song...");
}
When I run the program, the command it prints (as I ask it to) comes out exactly the same as what I would enter into the command line.
Why doesn't the script execute?
I have tried using ProcessBuilder and calling the program that plays the track directly but neither work. For simplicity I'm testing this with a track whose path has no spaces or strange characters.
I have tried adding /bin/bash -c to the beginning of the command string
FYI I'm running Java 8 on a Raspberry Pi running Raspbian. The program that plays the track is omxplayer.
Any help most gratefully received as I've been doing my nut in all day with this!
Thanks!
OK, thanks to #Etan I have managed to solve this. Modified the code thusly, using an InputStream reader to identify problems with filenames:
public void begin(String song) throws IOException, InterruptedException {
//Split song title
String[] cmd = song.split("");
StringBuilder sb = new StringBuilder();
//Ignore for now
for (int i = 0; i < cmd.length; i++) {
if (cmd[i].equals(" ")) {
cmd[i] = " ";
}
sb.append(cmd[i]);
}
//Initiate bash script whilst passing song title as argument
System.out.println("Playing song...");
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "/home/pi/startsong.sh", "/home"+sb.toString());
final Process process = pb.start();
InputStream is = process.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
System.out.println("Program terminated!");
}
I have a python script and it takes a long time to finish. I would like to run it from Java, but also output the script's output while it is executing, so that I can tell if it is properly running.
I've searched and only found examples where we output the output after the system command has finished, rather than during its execution.
Any way to do it while the script is running?
Here's what I have
public void doSomething() throws IOException {
String[] callAndArgs = {"python", "/hi.py"};
Process p = Runtime.getRuntime().exec(callAndArgs);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String s;
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
}
i managed to get it working like this (Note it requires java7):
package test;
import java.lang.ProcessBuilder.Redirect;
public class Test {
public static void main(String... args) throws Exception {
ProcessBuilder pb = new ProcessBuilder("python","/home/foobar/Programming/test/src/test/test.py");
pb.redirectOutput(Redirect.INHERIT);
Process p = pb.start();
p.waitFor();
}
}
python (note i flush on python to make it work using sys.stdout.flush())
import time,sys
c =0
while c<=50:
time.sleep(1)
print("----")
c = c +1
sys.stdout.flush()
Note if you don't want to flush in a loop you can use this:
ProcessBuilder pb = new ProcessBuilder("python","-u","/home/foobar/Programming/NetBeansProjects/test/src/test/test.py");
Redirect.INHERIT
Indicates that subprocess I/O source or destination will be the same as those of the current process. This is the normal behavior of most operating system command interpreters (shells).
I've searched and only found examples where we output the output after
the system command has finished, rather than during its execution.
That's weird, because your example should be dumping the output as the command is executing.
Instead of using BufferedReader, you could try reading directly from the InputStream instead as the required conditions for readLine might not be being met until after the process exits.
I'd also recommend that you use a ProcessBuilder over Process directly, as, apart from anything else, it allows you to redirect the output from the error stream into the input stream, allowing you to read just one stream instead of two...
This might also be an issue with Python and how it flushes it output buffers...
For example, rather then waiting for the BufferedReader to decide when to return, try printing each character from the stream as it occurs/is reported
ProcessBuilder pb = new ProcessBuilder("test.py");
pb.redirectError();
Process p = pb.start();
InputStream is = null;
try {
is = p.getInputStream();
int in = -1;
while ((in = is.read()) != -1) {
System.out.print((char)in);
}
} finally {
try {
is.close();
} catch (Exception e) {
}
}
Update
Doing a little reading, Python seems to be buffering its out out before sending it to the stdout. I don't think you can fix this on the a Java side, but need to alter either the way Python is run or the script works.
See How to flush output of Python print? for more details
I'm suspecting that you are writing to stderr, which you can't see because you are blocking on stdin. Use a ProcessBuilder instead of doing exec. This way, you can redirect stderr and stdin into a single stream.
Here is an example:
import java.io.*;
public class Test {
public static void main(String... args) throws IOException {
ProcessBuilder pb =
new ProcessBuilder("test.py");
pb.redirectErrorStream(true);
Process proc = pb.start();
Reader reader = new InputStreamReader(proc.getInputStream());
BufferedReader bf = new BufferedReader(reader);
String s;
while ((s = bf.readLine()) != null) {
System.out.println(s);
}
}
}
Alternatively you can spawn threads to read from stdin/stderr respectively.
Another thing to look for is output buffering by python. You can see if this is the cause by doing:
import sys
sys.stdout.flush()
after you write to stdout
Don't use #readLine as the conditional in your while loop. Instead wrap your inputStream in a scanner and use #hasNextLine()
Scanner in = new Scanner(p.getInputStream());
while (in.hasNextLine()) {
System.out.println(in.nextLine());
}
I need to interact with a command line process, e.g. diskpart on windows. The problem: input.readLine() in the following sample leads to a blocking while.
public static void main(String[] args) throws IOException
{
ProcessBuilder processBuilder = new ProcessBuilder("C:\\Windows\\system32\\diskpart.exe");
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();
input = new BufferedReader(new InputStreamReader(process.getInputStream()));
output = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
// read #1 code position
String line = null;
while((line = input.readLine())!= null)
System.out.println(line);
// code position #2
System.out.println("This line is never executed");
output.write("list disk" + System.lineSeparator());
output.flush(); // important
}
The output (from read #1 code position) is
Microsoft DiskPart-Version 6.1.7601
Copyright (C) 1999-2008 Microsoft Corporation.
Auf Computer: MYPC
This is correct, however after that nothing happens, e.g. code position #2
System.out.println("This line is never executed");
is never reached. Can anyone tell me, why and how to fix this? Thanks!
Update:
Trying to read byte by byte also seems not to work? ):
InputStreamReader input = new InputStreamReader(process.getInputStream());
int mychar = -1;
while((mychar = input.read()) != -1)
System.out.println(mychar);
System.out.println("This line is never executed");
Because the next thing Diskpart does is show the prompt, which doesn't include a newline:
Microsoft DiskPart version 6.1.7601
Copyright (C) 1999-2008 Microsoft Corporation.
On computer: PCNAME
DISKPART> _
So your code sits there waiting for the newline, which never appears.
You need to change your code to send the "list disk" command at the right time.
Diskpart has an interactive console that requires input from the user. Attempting to read its output like this:
while((line = input.readLine())!= null)
System.out.println(line);
will cause you to wait indefinitely as the application itself requires input.
You need to wait for input first from the windows command so you need to add CMD /C to your command.
As diskpart is interactive, you could try running your list command as a script, so you would have instead:
String[] command = {"CMD", "/C", "C:\\Windows\\system32\\diskpart.exe", "/s", "diskpart.txt"};
ProcessBuilder processBuilder = new ProcessBuilder(command);
with diskpart.txt containing:
list disk
I recommend you getting this working in a standard batch file first though to check that the output is correct.