Wednesday, January 5, 2011

Dealing with Unsigned Types in Java

Suppose we need to create a binary file with structure like this
1 unsigned byte
1 unsigned short
1 unsigned int

In C, we can do it easily like below.
writec.c
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE* myfile;

    myfile = fopen("/tmp/writec.bin", "wb");
    if (!myfile)
    {
        printf("Unable to open the file!");
        return EXIT_FAILURE;
    }

    unsigned char x = 12;
    unsigned short y = 123;
    unsigned int z = 1234;
    fwrite(&x, sizeof(unsigned char), 1, myfile);
    fwrite(&y, sizeof(unsigned short), 1, myfile);
    fwrite(&z, sizeof(unsigned int), 1, myfile);

    fclose(myfile);

    return EXIT_SUCCESS;
}

To read such a file in Java can be quite tricky since the file has unsigned types. All data types in Java are signed, except for char. Here I'm gonna show you how to read such a file in Java.
ReadJava.java
package myproject;
 
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.nio.ByteOrder;
 
public class ReadJava {
 
    public static void main(String[] args) throws Exception {
        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;
        try {
            fis = new FileInputStream("/tmp/writec.bin");
            bos = new ByteArrayOutputStream();
            byte[] bytes = new byte[128];
            int bytesRead;
            while ((bytesRead = fis.read(bytes, 0, bytes.length)) != -1) {
                bos.write(bytes, 0, bytesRead);
            }
            byte[] rawBytes = bos.toByteArray();
           
            int index = -1;
            int firstByte = 0;
            int secondByte = 0;
            int thirdByte = 0;
            int fourthByte = 0;
            short unsignedByte = 0;
            int unsignedShort = 0;
            long unsignedInt = 0;
           
            firstByte = (0x000000FF & ((int) rawBytes[++index]));
            unsignedByte = (short) ((firstByte) & 0xFF);
            System.out.println("unsigned byte=" + unsignedByte);
           
            firstByte = (0x000000FF & ((int) rawBytes[++index]));
            secondByte = (0x000000FF & ((int) rawBytes[++index]));
            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                unsignedShort = (int) ((firstByte | secondByte << 8) & 0xFFFF);
            } else {
                unsignedShort = (int) ((firstByte << 8 | secondByte) & 0xFFFF);
            }
            System.out.println("unsigned short=" + unsignedShort);
           
            firstByte = (0x000000FF & ((int) rawBytes[++index]));
            secondByte = (0x000000FF & ((int) rawBytes[++index]));
            thirdByte = (0x000000FF & ((int) rawBytes[++index]));
            fourthByte = (0x000000FF & ((int) rawBytes[++index]));
            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                unsignedInt = (long) (((firstByte | secondByte << 8 |
                    thirdByte << 16 | fourthByte << 24)) & 0xFFFFFFFFL);
            } else {
                unsignedInt = (long) (((firstByte << 24 | secondByte << 16 |
                    thirdByte << 8 | fourthByte)) & 0xFFFFFFFFL);
            }
            System.out.println("unsigned int=" + unsignedInt);
        } finally {
            if (bos != null) {
                bos.close();
            }
            if (fis != null) {
                fis.close();
            }
        }
    }
}


Similarly, if we need to create such a file in Java, we can do the following.
WriteJava.java
package myproject;

import java.io.FileOutputStream;
import java.nio.ByteOrder;
 
public class WriteJava {
 
    public static void main(String[] args) throws Exception {
        FileOutputStream fos = new FileOutputStream("/tmp/writejava.bin");
       
        try {
            short unsignedByte = 0;
            int unsignedShort = 0;
            long unsignedInt = 0;
            int index = -1;
           
            byte[] rawBytes = new byte[7];
           
            unsignedByte = (short) (12 & 0XFF);
            rawBytes[++index] = (byte) ((unsignedByte & 0x00FF));
           
            unsignedShort = (int) (123 & 0XFFFF);
            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                rawBytes[++index] = (byte) ((unsignedShort & 0x000000FF));
                rawBytes[++index] = (byte) ((unsignedShort & 0x0000FF00) >> 8);
            } else {
                rawBytes[++index] = (byte) ((unsignedShort & 0x0000FF00) >> 8);
                rawBytes[++index] = (byte) ((unsignedShort & 0x000000FF));
            }
           
            unsignedInt = (long) (1234 & 0xFFFFFFFFL);
            if (ByteOrder.nativeOrder() == ByteOrder.LITTLE_ENDIAN) {
                rawBytes[++index] = (byte) ((unsignedInt & 0x000000FFL));
                rawBytes[++index] = (byte) ((unsignedInt & 0x0000FF00L) >> 8);
                rawBytes[++index] = (byte) ((unsignedInt & 0x00FF0000L) >> 16);
                rawBytes[++index] = (byte) ((unsignedInt & 0xFF000000L) >> 24);
            } else {
                rawBytes[++index] = (byte) ((unsignedInt & 0xFF000000L) >> 24);
                rawBytes[++index] = (byte) ((unsignedInt & 0x00FF0000L) >> 16);
                rawBytes[++index] = (byte) ((unsignedInt & 0x0000FF00L) >> 8);
                rawBytes[++index] = (byte) ((unsignedInt & 0x000000FFL));
            }
           
            fos.write(rawBytes);
        } finally {
            fos.close();
        }
    }
}

To read it in C, it's as easy as below.
readc.c
#include <stdio.h>
#include <stdlib.h>

int main(void)
{
    FILE* myfile;

    myfile = fopen("/tmp/writejava.bin", "rb");
    if (!myfile)
    {
        printf("Unable to open the file!");
        return EXIT_FAILURE;
    }

    unsigned char x;
    unsigned short y;
    unsigned int z;
    fread(&x, sizeof(unsigned char), 1, myfile);
    fread(&y, sizeof(unsigned short), 1, myfile);
    fread(&z, sizeof(unsigned int), 1, myfile);

    printf("unsigned byte=%d\n", x);
    printf("unsigned short=%d\n", y);
    printf("unsigned int=%d\n", z);

    fclose(myfile);

    return EXIT_SUCCESS;
}

No comments:

Post a Comment