I was wondering which is the best way to get the title from a disk image in .iso or .cue+.bin format,
Is there any java library that can do this or should I read from the file header?
UPDATE:
I managed to do it, i was particularly interested in PSX ISOs title. It's 10 bytes long and this is a sample code to read it:
File f = new File("cdimage2.bin");
FileInputStream fin = new FileInputStream(f);
fin.skip(37696);
int i = 0;
while (i < 10) {
System.out.print((char) fin.read());
i++;
}
System.out.println();
UPDATE2: This method is better:
private String getPSXId(File f) {
FileInputStream fin;
try {
fin = new FileInputStream(f);
fin.skip(32768);
byte[] buffer = new byte[4096];
long start = System.currentTimeMillis();
while (fin.read(buffer) != -1) {
String buffered = new String(buffer);
if (buffered.contains("BOOT = cdrom:\\")) {
String tmp = "";
int lidx = buffered.lastIndexOf("BOOT = cdrom:\\") + 14;
for (int i = 0; i < 11; i++) {
tmp += buffered.charAt(lidx + i);
}
long elapsed = System.currentTimeMillis() - start;
// System.out.println("BOOT = cdrom:\\" + tmp);
tmp = tmp.toUpperCase().replace(".", "").replace("_", "-");
fin.close();
return tmp;
}
}
fin.close();
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}
Just start reading after 32768 bytes (unused by ISO9660) in 2048 byte chunks (Volume Descriptor). The first byte determines the type of the descriptor, and 1 means Primary Volume Descriptor, which contain the title after the first 7 bytes (which are always \x01CD001\x01). The next byte is a NUL (\x00) and it is followed by 32 bytes of system and 32 bytes of volume identifier, the latter usually known and displayed as title. See http://alumnus.caltech.edu/~pje/iso9660.html for a more detailed description.
Related
Alright, so I am writing a small program that should have taken 10 minutes to complete however I am running into unforeseen problems.
The program should take in some old files I had in a vault program on my old phone, they are basically Jpg files but with an added "obscured" text to the front of the file.
So below is my code logic
get a folder input for the files,
create an arraylist containing each actual file.
call ConvertFiles to convert the file to a string,
delete the first 8 characters using substring and save that temp file to another arraylist containing the strings.
decode that string as base64 and input that into a bytearrayinputstream and save that to a bufferedimage.
This is where the problem occurs. I have content all the way up to the ImageIO.read(bis), so when it tries to write to a new file it throws the image == null
from the ImageTypeSpecifier. I have tried multiple ways of decoding and encoding the string, but any help is wanted and if any more information is needed I will provide it!
public class ImageConvert {
private File folder;
private ArrayList<File> files;
private ArrayList<String> stringFiles = new ArrayList<>();
private ArrayList<BufferedImage> bfImages = new ArrayList<>();
boolean isRunning = true;
Scanner scanner = new Scanner(System.in);
String folderPath;
public static void main(String[] args) {
ImageConvert mc = new ImageConvert();
mc.mainCode();
}
public void mainCode(){
System.out.println("Please enter the folder path: ");
folderPath = scanner.nextLine();
folder = new File(folderPath);
//System.out.println("folderpath: " + folder);
files = new ArrayList<File>(Arrays.asList(folder.listFiles()));
convertFiles();
}
public void convertFiles(){
for(int i = 0; i < files.size(); i++){
try {
String temp = FileUtils.readFileToString(files.get(i));
//System.out.println("String " + i + " : " + temp);
stringFiles.add(temp.substring(8));
} catch (IOException ex) {
Logger.getLogger(ImageConvert.class.getName()).log(Level.SEVERE,
null, ex);
}
}
//System.out.println("Converted string 1: " + stringFiles.get(0));
for(int j = 0; j < stringFiles.size(); j++){
BufferedImage image = null;
byte[] imageByte;
try {
BASE64Decoder decoder = new BASE64Decoder();
imageByte = decoder.decodeBuffer(stringFiles.get(j));
System.out.println(imageByte.toString());
ByteArrayInputStream bis = new ByteArrayInputStream(imageByte);
image = ImageIO.read(bis);
bis.close();
bfImages.add(image);
} catch (IOException ex) {
Logger.getLogger(ImageConvert.class.getName()).log(Level.SEVERE,
null, ex);
}
}
System.out.println("Image 1: " + bfImages.get(0));
for(int k = 0; k < bfImages.size(); k++){
try {
ImageIO.write(bfImages.get(k), "jpg",
new File(folderPath + "/" + k + ".jpg"));
} catch (IOException ex) {
Logger.getLogger(ImageConvert.class.getName()).log(Level.SEVERE,
null, ex);
}
}
}
}
This is an example of my files:
The following example uses the file you included with your question. You don't need to do any decoding, just read the file into memory, store the 8 byte String and then write the remaining bytes to a jpg from an 8 byte offset.
Just adapt the method below to work with your: "folder input for files". You don't need an ArrayList containing each actual jpg file.
public void convertFiles() {
File imgFile;
byte[] bytes;
FileOutputStream fos;
String temp;
for (int i = 0; i < files.size(); i++) {
temp = "";
try {
// 'read' method can be found below
bytes = read(files.get(i));
// read the 8 byte string from the beginning of the file
for(int j = 0; j < 8; j++) {
temp += (char) bytes[j];
}
imgFile = new File("img.jpg");
// points to './img.jpg'
fos = new FileOutputStream(imgFile);
// write from offset 8 to end of 'bytes'
fos.write(bytes, 8, bytes.length - 8);
fos.close();
} catch (FileNotFoundException e) {
// Logger stuff
} catch (IOException ex) {
// Logger stuff
}
System.out.println("[temp]:> " + temp);
}
}
read(File file) method adapted from a community wiki answer to File to byte[] in Java
public byte[] read(File file) throws IOException {
ByteArrayOutputStream ous = null;
InputStream ios = null;
try {
byte[] buffer = new byte[4096];
ous = new ByteArrayOutputStream();
ios = new FileInputStream(file);
int read = 0;
while ((read = ios.read(buffer)) != -1) {
ous.write(buffer, 0, read);
}
} finally {
try {
if (ous != null)
ous.close();
} catch (IOException e) {
}
try {
if (ios != null)
ios.close();
} catch (IOException e) {
}
}
return ous.toByteArray();
}
Output:
[temp]:> obscured
Image File:
I wrote this piece of code to chunk the files into multiple chunks. The program works fine for a file of size 12KB with chunk size of 8KB. However, when I give a input file size of 2980144 bytes, it goes into spin - never comes out.
Is there something to do with the size of input file and the FileChannel issue to access? I want to use this program to chunk the larger files (binary form) into multiple chunks for easy transport over network. I have kept the chunk size as parameter, so that I can configure as per requirement.
public static void main(String[] args) {
int chunkSize = 8000;
long offset = 0;
while (offset >= 0) {
offset = splitter.GetNextChunk(offset);
}
}
public long GetNextChunk(long offset) {
long bytesRead = 0;
ByteBuffer tmpBuf = ByteBuffer.allocate(chunkSize);
RandomAccessFile outFile = null;
RandomAccessFile inFile = null;
FileChannel inFC = null;
FileChannel outFC = null;
try {
inFile = new RandomAccessFile(inFileName, "r");
inFC = inFile.getChannel();
tmpBuf.clear();
// Seek to the offset in the file
inFC.position(offset);
// Read the specified number of bytes into the buffer.
do {
bytesRead = inFC.read(tmpBuf);
} while (bytesRead != -1 && tmpBuf.hasRemaining());
// Write the copied bytes into a new file (chunk).
String outFileName = outFolder + File.separator + "Chunk" + String.valueOf(chunkCounter++) + ".dat";
outFile = new RandomAccessFile(outFileName, "rw");
outFC = outFile.getChannel();
outFC.position(0);
tmpBuf.flip();
while(tmpBuf.hasRemaining()) {
outFC.write(tmpBuf);
}
// Reposition the buffer to 0.
tmpBuf.rewind();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
if (inFC != null)
inFile.close();
if (outFC != null)
outFile.close();
if (inFC != null)
inFC.close();
if (outFC != null)
outFC.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return bytesRead;
}
Found the issue. The loop was faulty. Below is the correct loop.
while (bytesRead >= 0) {
bytesRead = splitter.GetNextChunk(offset);
if (bytesRead == -1)
break;
offset += bytesRead;
System.out.println("Byte offset is: " + offset);
}
It's not nearly as hard as you're making it. Your code is about ten times as long as it needs to be. Try this:
while (in.read(buffer) > 0 || buffer.position() > 0)
{
buffer.flip();
out.write(buffer);
buffer.compact();
}
If 'out' is a SocketChannel this will send the file over the network at maximum speed.
You don't need a monstro buffer, but you should always use powers of 2. I generally use 8192.
I'm trying to decrypt the content of a file bigger than 1k for a "RETR" action of an FTP Client and I'm encountering this kind of exception.
javax.crypto.BadPaddingException: Given final block not properly padded
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:811)
at com.sun.crypto.provider.CipherCore.doFinal(CipherCore.java:676)
at com.sun.crypto.provider.DESCipher.engineDoFinal(DESCipher.java:314)
at javax.crypto.Cipher.doFinal(Cipher.java:2145)
This is the code that is giving me problem:
byte[] encontent = new byte[0];
byte[] buff = new byte[1024];
int k = -1;
while((k = bis.read(buff, 0, buff.length)) > -1) {
byte[] tbuff = new byte[encontent.length + k]; // temp buffer size = bytes already read + bytes last read
System.arraycopy(encontent, 0, tbuff, 0, encontent.length); // copy previous bytes
System.arraycopy(buff, 0, tbuff, encontent.length, k); // copy current lot
encontent = tbuff; // call the temp buffer as your result buff
}
System.out.println(encontent.length + " bytes read.");
byte [] plain = dcipher.doFinal(encontent, 0,encontent.length);
The length of the byte array encontent is always an 8-bit multple, because it is the result of a previous encryption.
Here it's the code that starts the operation from server side:
public void download (String pathfile)
{
Socket DataSock = null;
try {
DataSock = new Socket (clientAddr, TRANSMISSION_PORT);
if (DataSock.isConnected())
{
BufferedOutputStream bos = new BufferedOutputStream (DataSock.getOutputStream());
int size=0;
int blocks=0;
int resto=0;
if (pathfile.endsWith(".txt"))
{
String text = readTxtFile (pathfile);
byte [] encontent = ecipher.doFinal(text.getBytes("UTF8"));
sendFile (bos,encontent);
} else {
byte [] content = readFile (pathfile);
byte [] encontent = ecipher.doFinal(content);
sendFile (bos, content);
}
}
} catch (Exception e)
{
e.printStackTrace();
} finally {
try {
DataSock.close();
} catch (Exception e)
{
e.printStackTrace();
}
}
}
The final block must contain 8 bytes. If it does not, one has to pad until its 8 bytes wide. Your assumption is wrong.
Have a look at https://stackoverflow.com/a/10427679/867816
public static void main(String[] args) {
File inFile = null;
if (0 < args.length) {
inFile = new File(args[0]);
}
BufferedInputStream bStream = null;
try {
int read;
bStream = new BufferedInputStream(new FileInputStream(inFile));
while ((read = bStream.read()) > 0) {
getMarker(read, bStream);
System.out.println(read);
}
}
catch (IOException e) {
e.printStackTrace();
}
finally {
try {
if (bStream != null)bStream.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
private static void getMarker(int read, BufferedInputStream bStream) {
}
I want to find the long 1234567890 in the bufferedInputStream. Am I able to search the bufferedInputStream for a long type? (I'm not sure whether I need 'read' as a parameter. I doubt it, I may remove that). How do I search a bufferedInputStream? Big endian, 8 byte aligned.
The initial marker that I'm searching for contains the value 1234567890. Once I have found that value I want to put the value of 2 bytes into a variable. These 2 bytes are located 11 bytes after marker.
With the method java.io.DataInputStream.readLong() it's possible to read data 8 bytes per 8 bytes. But the question is: the file contains only long or other data?
If the data may be anywhere, we have to read 8 times the file beginning at the offset 0, 1, 2 and so on.
class FuzzyReaderHelper {
public static final long MAGIC_NUMBER = 1234567890L;
public static DataInputStream getStream( File source ) {
boolean magicNumberFound = false;
for( int offset = 0; !magicNumberFound && offset < 8; ++offset ) {
dis = new DataInputStream( new FileInputStream( source ));
for( int i = 0; i < offset; ++i ) {
dis.read();
}
try {
long l;
while(( l = dis.readLong()) != MAGIC_NUMBER ) {
/* Nothing to do... */
}
magicNumberFound = true;
for( int i = 0; i < 11; ++i ) {
dis.read();
}
return dis;
}
catch( EOFException eof ){}
dis.close();
}
// choose:
throw new IllegalStateException( "Incompatible file: " + source );
// or
return null;
}
}
The next steps are up to you:
DataInputStream dis = FuzzyReaderHelper.getStream( new File( root, "toto.dat" ));
if( dis != null ) {
byte[] bytes = new byte[2];
bytes[0] = dis.read();
bytes[1] = dis.read();
...
}
I have troubles with my program when i need to send Strings from my server bluetooth-socket to my client bluetooth-socket.
Everything works fine as long as I am only sending one String at a time (for example chatting) but if I need to write more Strings at a short period of time (to interchange informations), the Strings will not get seperated from the client code. For example if I'm sending "FirstUser" and right after that "SecondUser" the client does not read "FirstUser" and then "SecondUser". It will read "FirstUserSecondUser". How can I avoid this behaviour?
Edit: If I let the Thread sleep before it is able to send a new message, it reads the right strings but this solution is not working fine for my need.
Server-Code: sending to all clients(edited)
public synchronized void sendToAll(String message)
{
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
publishProgress(message);
for(OutputStream writer:outputList) {
try {
writer.write(message.getBytes());
writer.flush();
} catch (IOException e) {
System.out.println("Some-Error-Code");
}
}
}
Server-Code: reading from a client:
public void run() {
String nachricht;
int numRead;
byte[] buffer = new byte[1024];
while (runningFlag)
{
try {
if((numRead = inputStream.read(buffer)) >= 0) {
nachricht = new String(buffer, 0, numRead);
serverThread.handleMessage(nachricht);
}
}
catch (IOException e) {
this.cancel();
e.printStackTrace();
}
}
}
Client-Code: reading from server(edited)
#Override
protected Void doInBackground(Integer... ints) {
String nachricht = new String();
byte[] buffer = new byte[1024];
int numRead;
while (runningFlag)
{
try {
if(((numRead = inputStream.read(buffer)) >= 0)) {
nachricht = new String(buffer, 0, numRead);
publishProgress(nachricht);
}
}
catch (IOException e) {
clientGame.finish();
e.printStackTrace();
}
}
return null;
}
Client-Code: writing to server
public synchronized void write(String nachricht)
{
try {
Thread.sleep(100);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
try {
outputStream.write(nachricht.getBytes());
outputStream.flush();
} catch (IOException e) {
this.cancel();
e.printStackTrace();
}
}
I appreciate every little help :) .
You need to encapsulate your data item to avoid concatenation.
It means that you have to write and read a whole data item before continuing.
You should have some utility methods to do that instead of directly using methods of OutputStream and InputStream :
public static void writeItem(OutputStream out, String s) throws IOException
{
// Get the array of bytes for the string item:
byte[] bs = s.getBytes(); // as bytes
// Encapsulate by sending first the total length on 4 bytes :
// - bits 7..0 of length
out.write(bs.length); // modulo 256 done by write method
// - bits 15..8 of length
out.write(bs.length>>>8); // modulo 256 done by write method
// - bits 23..16 of length
out.write(bs.length>>>16); // modulo 256 done by write method
// - bits 31..24 of length
out.write(bs.length>>>24); // modulo 256 done by write method
// Write the array content now:
out.write(bs); // Send the bytes
out.flush();
}
public static String readItem(InputStream in) throws IOException
{
// first, read the total length on 4 bytes
// - if first byte is missing, end of stream reached
int len = in.read(); // 1 byte
if (len<0) throw new IOException("end of stream");
// - the other 3 bytes of length are mandatory
for(int i=1;i<4;i++) // need 3 more bytes:
{
int n = in.read();
if (n<0) throw new IOException("partial data");
len |= n << (i<<3); // shift by 8,16,24
}
// Create the array to receive len bytes:
byte[] bs = new byte[len];
// Read the len bytes into the created array
int ofs = 0;
while (len>0) // while there is some byte to read
{
int n = in.read(bs, ofs, len); // number of bytes actually read
if (n<0) throw new IOException("partial data");
ofs += n; // update offset
len -= n; // update remaining number of bytes to read
}
// Transform bytes into String item:
return new String(bs);
}
Then you use these methods both for server & client to read and write your String items.