4

So I have some FRX binary files from which I am attempting to get string captions using Java's binary reading methods.

I was capable of doing so, and specifying the region in which to read bytes in C# using the following program :

using System;
using System.Collections.Generic;
using System.Text;
using System.IO;

    public class GetFromFRX
    {
        public static void Main()
        {
            StringBuilder buffer = new StringBuilder();
            using (BinaryReader b = new BinaryReader(File.Open("frmResidency.frx", FileMode.Open)))
            {
                try
                {
                    b.BaseStream.Seek(641, SeekOrigin.Begin);
                    int length = b.ReadInt32();

                    for (int i = 0; i < length; i++)
                    {
                        buffer.Append(b.ReadChar());
                    }
                }
                catch (Exception e)
                {
                    Console.WriteLine( "Error obtaining resource\n" + e.Message);
                }

            }
            Console.WriteLine(buffer);
        }
    }

Question Update : Attempting to do the same in Java, I have built the following program. Now I have implemented Guava in order to use LittleEndian equivalents, however now my length prints 24, and as a result I only get the first 24 bytes in my output file. Is ReadInt not appropriate for this situation, and function in a different manner than ReadInt32?

import java.io.*;
import com.google.common.io.*;

public class RealJavaByteReader {

    public static void main(String[] args) throws IOException {

        FileInputStream in = null;
        FileOutputStream out = null;

        try {
            in = new FileInputStream("frmResidency.frx");
            LittleEndianDataInputStream din = new LittleEndianDataInputStream(in);
            out = new FileOutputStream("output.txt");

            int length = din.readInt();
            System.out.println(length);
            int c;

            for (c = 0; c < length; c++) {
                // TODO: first read byte and check for EOF
                out.write(din.read());
            }
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
        }
    }
}
HavelTheGreat
  • 3,299
  • 2
  • 15
  • 34
  • What's the `Seek` for? – Sotirios Delimanolis Jan 26 '15 at 16:16
  • Try instantiating a buffer like byte[] buffer = new byte[4]; then use out.read(buffer); to read bytes into the buffer. You can then print the contents of the buffer with System.out.println(DatatypeConverter.printHexBinary(buffer)); to inspect the contents of the buffer to see if you advanced to the correct location. Opening it in a Hex editor might help as well. It sounds like the leading bit of the first byte of the int you are reading is set. If you expect larger data then fits in a signed int, you might need to read the 4 bytes and manually convert to long... – Aaryn Tonita Jan 26 '15 at 16:17
  • In C#, `Seek` is setting the starting position for my index, which is the decimal value corresponding to a hex value which indicates the beginning byte of the string caption I require. – HavelTheGreat Jan 26 '15 at 16:17
  • 1
    `DataInput.readInt` assumes big-endian format; `BinaryReader.ReadInt32` assumes little-endian format... so that's a problem to *start* with. I wouldn't go any further until you've at least got the right lengths. – Jon Skeet Jan 26 '15 at 16:18
  • Also, in your C# you're writing character values to a `StringBuilder`, while in Java, you are writing byte values to a file. You also don't seem to do anything with the `dout`. – Sotirios Delimanolis Jan 26 '15 at 16:18
  • I will start with attempting to get little-endian format in Java, thank you. – HavelTheGreat Jan 26 '15 at 16:23
  • See question update. Sotinos, I don't see why it would work differently, but you are correct that `dout` isn't actually doing anything, I will promptly remove that. – HavelTheGreat Jan 26 '15 at 17:56

2 Answers2

1

Elizion,

This might be because you might be reading an int stored using little endian. As such, Java uses Big endian and .NET little endian.

Use a function as below to convert a little endian int to a big endian int in java.

/**
   * Byte swap a single int value.
   * 
   * @param value  Value to byte swap.
   * @return       Byte swapped representation.
   */
  public static int swap (int value)
  {
    int b1 = (value >>  0) & 0xff;
    int b2 = (value >>  8) & 0xff;
    int b3 = (value >> 16) & 0xff;
    int b4 = (value >> 24) & 0xff;

    return b1 << 24 | b2 << 16 | b3 << 8 | b4 << 0;
  }

Please try to see the below post.

Converting Little Endian to Big Endian

Community
  • 1
  • 1
Bejoy
  • 11
  • 3
  • Welcome to SO :) While this technically is a valid answer it would do well to be expanded somewhat. Copying and pasting relevant portions from your link would make this a much higher-quality answer. – StormeHawke Jan 26 '15 at 17:06
  • I opted to use the Guava library to implement `LittleEndianDataInputStream`, but I imagine this works as well! – HavelTheGreat Jan 26 '15 at 17:58
1

I realized what my mistake was at this point. Now that LittleEndianDataInputStream has been implemented, I can correctly use SkipBytes to set my initial byte position, and will return the string caption as required. Of course I will initially only produce the first 24 bytes, as whatever is in the first 4 bytes of the binary file must hold a length of 24 for some given property in the FRX file. I must set the offset with skipBytes in order to produce anything meaningful, because the lengths of properties in FRX files are stored in groups of 4 bytes and are followed by those bytes containing that property .

For instance, if I set din.skipBytes(308);, then the 308th to 312th bytes in the FRX file hold the byte-length of the string in the Caption property I require (for instance 140), which is output by readInt. Thus the next 140 bytes will contain my string required, and my for loop will iterate properly.

HavelTheGreat
  • 3,299
  • 2
  • 15
  • 34