HiveBrain v1.2.0
Get Started
← Back to all entries
patternjavaMinor

Deserializing a byte array from Java in C++

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
fromarraybytejavadeserializing

Problem

I am writing a byte array value into a file, consisting of up to three of these arrays, using Java with big Endian byte order format. Now I need to read that file from a C++ program.

short employeeId = 32767;
long lastModifiedDate = "1379811105109L";
byte[] attributeValue = os.toByteArray();


I am writing employeeId, lastModifiedDate and attributeValue together into a single byte array. I am writing that resulting byte array into a file and then I will have my C++ program retrieve that byte array data from the file and then deserialize it to extract employeeId, lastModifiedDate and attributeValue from it.

This writes the byte array value into a file with big Endian format:

public class ByteBufferTest {

    public static void main(String[] args) {

        String text = "Byte Array Test For Big Endian";
        byte[] attributeValue = text.getBytes();

        long lastModifiedDate = 1289811105109L;
        short employeeId = 32767;

        int size = 2 + 8 + 4 + attributeValue.length; // short is 2 bytes, long 8 and int 4

        ByteBuffer bbuf = ByteBuffer.allocate(size); 
        bbuf.order(ByteOrder.BIG_ENDIAN);

        bbuf.putShort(employeeId);
        bbuf.putLong(lastModifiedDate);
        bbuf.putInt(attributeValue.length);
        bbuf.put(attributeValue);

        bbuf.rewind();

        // best approach is copy the internal buffer
        byte[] bytesToStore = new byte[size];
        bbuf.get(bytesToStore);

        writeFile(bytesToStore);

    }

    /**
     * Write the file in Java
     * @param byteArray
     */
    public static void writeFile(byte[] byteArray) {

        try{
            File file = new File("bytebuffertest");

            FileOutputStream output = new FileOutputStream(file);
            IOUtils.write(byteArray, output);           

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}


Now I need to retrieve the byte array from that same file using this C++ program

Solution

Obviously the code isn't portable to big-endian machines. I'll use C syntax, since I'm more familiar with that than C++.

If you have endian.h, you can use the functions in there; if not, you should have arpa/inet.h which defines functions for swapping network byte order (big-endian) to host byte order, but lacks a function for 64-bit values. Look for either be16toh (from endian.h) or ntohs (from arpa/inet.h) and friends.

Why not read directly into the values:

fread((void *)&employeeId, sizeof(employeeId), 1, file);
employeeId = be16toh(employeeId);


Since you can manipulate pointers in C, you just need to provide a universal pointer (void *) to the read function where it should place the results. The & operator takes the address of a value. Once that is done, you can manipulate the value directly, as above.

Using this Java test code:

import java.io.*;

public class write {
  public static void main(String... args) throws Exception {
    final FileOutputStream file = new FileOutputStream("java.dat");
    final DataOutputStream data = new DataOutputStream(file);

    final long time = System.currentTimeMillis();
    final short value = 32219;

    //  fill a table with a..z0..9
    final byte[] table = new byte[36];
    int index = 0;
    for (int i = 0; i < 26; i++) {
      table[index++] = (byte)(i + 'a');
    }
    for (int i = 0 ; i < 10; i++) {
      table[index++] = (byte)(i + '0');
    }

    data.writeLong(time);
    data.writeShort(value);
    data.writeInt(table.length);
    data.write(table);
    data.close();

    System.out.format("wrote time: %d%n  value: %d%n  length: %d%n  table:%n", time, value, table.length);
    for (int i = 0; i < table.length; i++) {
      System.out.format("%c ", (char)table[i]);
    }
    System.out.println();
  }
}


The output from this code is:

wrote time: 1380743479723
  value: 32219
  length: 36
  table:
a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9


You can read the values in with this C code:

#include 
#include 
#include 
#include 

int main(int argc, char **argv) {
  int64_t time;
  int16_t value;
  int32_t length;
  u_int8_t *array;

  FILE *in = fopen("java.dat", "rb");

  fread(&time, sizeof(time), 1, in);
  time = (int64_t)be64toh( (u_int64_t)time);

  fread(&value, sizeof(value), 1, in);
  value = (int16_t)be16toh( (u_int16_t)value );

  fread(&length, sizeof(length), 1, in);
  length = (int32_t)be32toh( (u_int32_t)length );

  array = (u_int8_t *)malloc(length);
  fread(array, sizeof(array[0]), length, in);

  fclose(in);

  printf("time: %ld\nvalue: %d\narray length: %d\narray:\n", time, value, length);
  for (int i = 0; i < length; i++) {
    printf("%c ", array[i]);
  }
  printf("\n");

  free(array);
  return 0;
}


I compiled this on Ubuntu x64 with clang. Its output was:

./a.out
time: 1380743479723
value: 32219
array length: 36
array:
a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9


Keep in mind that the only unsigned types in Java are byte (8 bits) and char (16-32 bits).

Code Snippets

fread((void *)&employeeId, sizeof(employeeId), 1, file);
employeeId = be16toh(employeeId);
import java.io.*;

public class write {
  public static void main(String... args) throws Exception {
    final FileOutputStream file = new FileOutputStream("java.dat");
    final DataOutputStream data = new DataOutputStream(file);

    final long time = System.currentTimeMillis();
    final short value = 32219;

    //  fill a table with a..z0..9
    final byte[] table = new byte[36];
    int index = 0;
    for (int i = 0; i < 26; i++) {
      table[index++] = (byte)(i + 'a');
    }
    for (int i = 0 ; i < 10; i++) {
      table[index++] = (byte)(i + '0');
    }

    data.writeLong(time);
    data.writeShort(value);
    data.writeInt(table.length);
    data.write(table);
    data.close();

    System.out.format("wrote time: %d%n  value: %d%n  length: %d%n  table:%n", time, value, table.length);
    for (int i = 0; i < table.length; i++) {
      System.out.format("%c ", (char)table[i]);
    }
    System.out.println();
  }
}
wrote time: 1380743479723
  value: 32219
  length: 36
  table:
a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9
#include <stdio.h>
#include <stdlib.h>
#include <endian.h>
#include <sys/types.h>

int main(int argc, char **argv) {
  int64_t time;
  int16_t value;
  int32_t length;
  u_int8_t *array;

  FILE *in = fopen("java.dat", "rb");

  fread(&time, sizeof(time), 1, in);
  time = (int64_t)be64toh( (u_int64_t)time);

  fread(&value, sizeof(value), 1, in);
  value = (int16_t)be16toh( (u_int16_t)value );

  fread(&length, sizeof(length), 1, in);
  length = (int32_t)be32toh( (u_int32_t)length );

  array = (u_int8_t *)malloc(length);
  fread(array, sizeof(array[0]), length, in);

  fclose(in);

  printf("time: %ld\nvalue: %d\narray length: %d\narray:\n", time, value, length);
  for (int i = 0; i < length; i++) {
    printf("%c ", array[i]);
  }
  printf("\n");

  free(array);
  return 0;
}
./a.out
time: 1380743479723
value: 32219
array length: 36
array:
a b c d e f g h i j k l m n o p q r s t u v w x y z 0 1 2 3 4 5 6 7 8 9

Context

StackExchange Code Review Q#32106, answer score: 4

Revisions (0)

No revisions yet.