Inserting a string into a bytebuffer - java

I am trying to write a bunch of integers and a string into the byte buffer. Later this byte array will be written to the hard drive. Everything seems to be fine except when I am writing the string in the loop only the last character is written. The parsing of the string appears correct as I have checked that.
It appears to be the way I use the bbuf.put statement. Do I need to flush it after, and why does the .putInt statement work fine and not .put
//write the PCB from memory to file system
private static void _tfs_write_pcb()
{
int c;
byte[] bytes = new byte[11];
//to get the bytes from volume name
try {
bytes = constants.filename.getBytes("UTF-8"); //convert to bytes format to pass to function
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
ByteBuffer bbuf = ByteBuffer.allocate(bl_size);
bbuf = bbuf.putInt(rt_dir_start);
bbuf = bbuf.putInt(first_free_data_bl);
bbuf = bbuf.putInt(num_bl_fat);
bbuf = bbuf.putInt(bl_size);
bbuf = bbuf.putInt(max_rt_entries);
bbuf = bbuf.putInt(ft_copies);
for (c=0; c < vl_name.length(); c++) {
System.out.println((char)bytes[c]);
bbuf = bbuf.put(bytes[c]);
}
_tfs_write_block(1, bbuf.array());
}

ByteBuffer has a method for put'ting an array of byte. Is there a reason to put them one at a time? I note that put(byte) is abstract as well.
So the for loop is simplified to:
bbuf = bbuf.put(bytes, 6, bytes.length);
http://docs.oracle.com/javase/8/docs/api/java/nio/ByteBuffer.html#put-byte:A-
EDIT: The Javadoc specifies that put(byte[]) begins at index 0, so use the form put(byte[], index, length) instead.
public final ByteBuffer put(byte[] src)
Relative bulk put method (optional operation).
This method transfers the entire content of the given source byte array
into this buffer. An invocation of this method of the form dst.put(a)
behaves in exactly the same way as the invocation
dst.put(a, 0, a.length)
Of course, it really should not matter HOW you insert the String bytes. I am just suggesting discovery experimentation.

Related

Byte array lengths with Deflater and Inflater

How do we understand the defined length of the byte array?
For instance in this example we are defining here that the length of the byte array is 100.
What if the data that would have to be written to the byte array would be longer than 100 bytes?
The same for the result variable here. I don't understand how these lengths work and how to choose a proper length of a byte array for the needs if you don't know how big your data will be?
try {
// Encode a String into bytes
String inputString = "blahblahblah";
byte[] input = inputString.getBytes("UTF-8");
// Compress the bytes
**byte[] output = new byte[100];**
Deflater compresser = new Deflater();
compresser.setInput(input);
compresser.finish();
int compressedDataLength = compresser.deflate(output);
compresser.end();
// Decompress the bytes
Inflater decompresser = new Inflater();
decompresser.setInput(output, 0, compressedDataLength);
**byte[] result = new byte[100];**
int resultLength = decompresser.inflate(result);
decompresser.end();
// Decode the bytes into a String
String outputString = new String(result, 0, resultLength, "UTF-8");
} catch(java.io.UnsupportedEncodingException ex) {
// handle
} catch (java.util.zip.DataFormatException ex) {
// handle
}
And for this example, the byte array that is used here as input, is actually called a buffer, how do we understand it?
Here, when you call compresser.deflate(output) you cannot know the size needed for output unless you know how this method works. But this is not a problem since output is meant as a buffer.
So you should call deflate multiple times and insert output in another object like an OutputStream, like this:
byte[] buffer = new byte[1024];
while (!deflater.finished()) {
int count = deflater.deflate(buffer);
outputStream.write(buffer, 0, count);
}
Same goes for inflating.
By allocating 100 bytes to the byte array, JVM guarantees that a buffer large enough to hold 100 JVM defined bytes (i.e. 8 bits) is available to the caller. Any attempt to access the array with more than 100 bytes would result in exception e.g. ArrayIndexOutOfBoundException in case you directly try to access the array by array[101].
In case the code is written as your demo, the caller assumes the data length never exceeds 100.

How to read/write extended ASCII characters as a string into ANSI coded text file in java

This is my encryption program. Primarily used to encrypt Files(text)
This part of the program converts List<Integer> elements intobyte [] and writes it into a text file. Unfortunately i cannot provide the algorithm.
void printit(List<Integer> prnt, File outputFile) throws IOException
{
StringBuilder building = new StringBuilder(prnt.size());
for (Integer element : prnt)
{
int elmnt = element;
//building.append(getascii(elmnt));
building.append((char)elmnt);
}
String encryptdtxt=building.toString();
//System.out.println(encryptdtxt);
byte [] outputBytes = offo.getBytes();
FileOutputStream outputStream =new FileOutputStream(outputFile);
outputStream.write(outputBytes);
outputStream.close();
}
This is the decryption program where the decryption program get input from a .enc file
void getfyle(File inputFile) throws IOException
{
FileInputStream inputStream = new FileInputStream(inputFile);
byte[] inputBytes = new byte[(int)inputFile.length()];
inputStream.read(inputBytes);
inputStream.close();
String fylenters = new String(inputBytes);
for (char a:fylenters.toCharArray())
{
usertext.add((int)a);
}
for (Integer bk : usertext)
{
System.out.println(bk);
}
}
Since the methods used here, in my algorithm require List<Integer> byte[] gets converted to String first and then to List<Integer>and vice versa.
The elements while writing into a file during encryption do not match the elements read from the .enc file.
Is my method of converting List<Integer> to byte[] correct??
or is something else wrong? . I do know that java can't print extended ASCII characters so i used this .But, even this failed.It gives a lot of ?s
Is there a solution??
please help me .. and also how to do it for other formats(.png.mp3....etc)
The format of the encrypted file can be anything (it needn't be .enc)
thanxx
There are thousands of different 'extended ASCII' codes and Java supports about a hundred of them,
but you have to tell it which 'Charset' to use or the default often causes data corruption.
While representing arbitrary "binary" bytes in hex or base64 is common and often necessary,
IF the bytes will be stored and/or transmitted in ways that preserve all 256 values, often called "8-bit clean",
and File{Input,Output}Stream does, you can use "ISO-8859-1" which maps Java char codes 0-255 to and from bytes 0-255 without loss, because Unicode is based partly on 8859-1.
on input, read (into) a byte[] and then new String (bytes, charset) where charset is either the name "ISO-8859-1"
or the java.nio.charset.Charset object for that name, available as java.nio.charset.StandardCharSets.ISO_8859_1;
or create an InputStreamReader on a stream reading the bytes from a buffer or directly from the file, using that charset name or object, and read chars and/or a String from the Reader
on output, use String.getBytes(charset) where charset is that charset name or object and write the byte[];
or create an OutputStreamWriter on a stream writing the bytes to a buffer or the file, using that charset name or object, and write chars and/or String to the Writer
But you don't actually need char and String and Charset at all. You actually want to write a series of Integers as bytes, and read a series of bytes as Integers. So just do that:
void printit(List<Integer> prnt, File outputFile) throws IOException
{
byte[] outputBytes = new byte[prnt.size()]; int i = 0;
for (Integer element : prnt) outputBytes[i++] = (byte)element;
FileOutputStream outputStream =new FileOutputStream(outputFile);
outputStream.write(b);
outputStream.close();
// or replace the previous three lines by one
java.nio.file.Files.write (outputFile.toPath(), outputBytes);
}
void getfyle(File inputFile) throws IOException
{
FileInputStream inputStream = new FileInputStream(inputFile);
byte[] inputBytes = new byte[(int)inputFile.length()];
inputStream.read(inputBytes);
inputStream.close();
// or replace those four lines with
byte[] inputBytes = java.nio.file.Files.readAllBytes (inputFile.toPath());
for (byte b: inputBytes) System.out.println (b&0xFF);
// or if you really wanted a list not just a printout
ArrayList<Integer> list = new ArrayList<Integer>(inputBytes.length);
for (byte b: inputBytes) list.add (b&0xFF);
// return list or store it or whatever
}
Arbitrary data bytes are not all convertible to any character encoding and encryption creates data bytes including all values 0 - 255.
If you must convert the encrypted data to a string format the standard methods are to convert to Base64 or hexadecimal.
In encryption part:
`for (Integer element : prnt)
{
int elmnt = element;
//building.append(getascii(elmnt));
char b = Integer.toString(elmnt).charAt(0);
building.append(b);
}`
-->this will convert int to char like 1 to '1' and 5 to '5'

Using the String(bytes[]) constructor for an InputStream

I'm wondering what the objections are to using what I'll call the 'String constructor method' to convert an InputStream into a String.
Edit: added emphasis. In particular, I'm wondering why we have to mess with Streams and Buffers and Scanners and whatnot when this method seems to work fine.
private String readStream(InputStream in) {
byte[] buffer = new byte[1024];
try {
return new String(buffer, 0, in.read(buffer));
} catch (IOException e) {
Log.d(DEBUG_TAG, "Error reading input stream!");
return "";
}
}
I've seen this other helpful post and tried the methods I could:
Method 1, Apache commons, is a no-go, since I can't use and don't want libraries right now.
Method 2, The Scanner one, looks promising, but then you'd have to be able to set delimiters in the stream, which isn't always possible, right? E.g. right now I'm using an InputStream from a web API.
Method 3, the InputStreamReader in the slurp function, didn't work either - it gives me a bunch of numbers, where I'm sending a string with all types of characters, so I may be messing something up in my encoding.
But after many Google searches, I finally found the String constructor method, which is the only one that works for me.
From comments on the thread I linked, I know there are issues with encoding in the method I'm using. I've been coding for a while now and know what encodings are and why they're around. But I still lack any knowledge about what kinds of encodings are used where, and how to detect and handle them. Any resources/help on that topic would also be very appreciated!
Here is one method using only standard libraries:
use a ByteArrayOutputStream and copy all the bytes you receive in it;
wrap this ByteArrayOutputStream's bytes into a ByteBuffer;
use a CharsetDecoder to decode the ByteBuffer into a CharBuffer;
.toString() the CharBuffer after rewinding it.
Code (note: doesn't handle closing the input):
// Step 1: read all the bytes
final ByteArrayOutputStream out = new ByteArrayOutputStream();
final byte[] buffer = new byte[8196];
int count;
while ((count = in.read(buffer)) != -1)
out.write(buf, 0, count);
// Step 2: wrap the array
final ByteBuffer byteBuffer = ByteBuffer.wrap(out.toByteArray());
// Step 3: decode
final CharsetDecoder decoder = StandardCharsets.UTF_8.newDecoder()
.onUnmappableCharacter(CodingErrorAction.REPORT)
.onMalformedInput(CodingErrorAction.REPORT);
final CharBuffer charBuffer = decoder.decode(byteBuffer);
charBuffer.flip();
return charBuffer.toString();

Java: Read Binary File From JAR into Scalar, Not Primitive byte[]

I have a binary file, in my jar, and I want to slurp its contents in binary mode, not into a string of characters. Following this example
private byte[] readBinaryFile(String fileName) throws IOException {
InputStream input = getClass().getResourceAsStream(fileName);
ByteArrayOutputStream output = new ByteArrayOutputStream();
for (int read = input.read(); read >= 0; read = input.read())
output.write(read);
byte[] buffer = output.toByteArray();
input.close ();
output.close();
return buffer;
}
It's pretty trivial, but the calling context is expecting and Object. How do I pass this binary contents back to the caller, but not as a primitive array? I am trying to deliver this binary data as a response to a web service using jaxrs.
As #Jon notes, the caller should be just fine:
byte[] b = new byte[10];
Object o = b;
That works because as he points out a byte[] is an instance of Object.
Don't confuse bytes themselves, which are indeed primitives, with the array. All arrays are objects no matter what they contain.
So the caller should receive his Object and then send it back to his caller as application/octet-stream.

Equivalent for DataOutputStream of Java in Objective C

I am currently working on a Project which is in Objective C.
I need to use Functions of Java class DataOutputStream like writeChars, writeLong, flush and some functions of ByteArrayOutputStream Class.
Specifically, what can I use in Objective C which has the same functionality as the DataOutputStream and ByteArrayOutputStream class?
This is the code i need to convert into Objective C.
public static byte[] getByteArray(String key, long counter) throws IOException
{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
if (key != null)
{
dos.writeChars(key);
}
dos.writeLong(counter);
dos.flush();
byte[] data = bos.toByteArray();
return data;
}
NSLog();
the above method takes string and objects as arguments.
As,
NSLog(#"Hi this is demo of string printing.");
NSLog(#"Hi this is integer %d",intValue);//this is like printf isnt it?
EDIT:
Either %b, or convert it into NSData object and then print using %#. Obj-c uses %# for all kind of object.
unsigned int a = 0x000000FF;
NSLog(#"%x", a);//prints the most significant digits first
What you want is convert primitive data types into raw bytes.
NSMutableData* dataBuffer = [NSMutableData data]; //obj-c byte array
long long number = 123456LL; //note that long long is needed in obj-c to represent 64bit numbers
NSData* numberData = [NSData dataWithBytes:&number length:sizeof(number)];
[dataBuffer appendData:numberData];
NSString* text = #"abcdefg";
const char* rawText = [text cStringUsingEncoding:NSUTF8StringEncoding]; //java uses utf8 encoding
NSData* textData = [NSData dataWithBytes:rawText length:strlen(rawText)];
[dataBuffer appendData:textData];
return dataBuffer;
No flush() is necessary (I believe in Java is not neccessary with ByteArrayOutputStream either)
This is a bit simplified, note that when Java writes a string, the first two bytes are always the string length. Java also writes numbers in Big Endian. We are writing them in system byte-order. That shouldn't be a problem if you don't want to send the binary data to other devices.
You can switch byte order using utilities in CFByteOrderUtils.h or you can get the number in Big Endian directly by the following:
- (NSData*)bytesFromLongLong:(long long)number {
char buffer[8];
for (int i = sizeof(buffer) - 1; i >= 0; i--) {
buffer[i] = (number & 0xFF);
number >> 8;
}
return [NSData dataWithBytes:buffer length:sizeof(buffer)]
}

Categories