I'm receiving SMS from GSM modem in PDU format; the TP-User-Data is "C8329BFD06DDDF72363904"
and what I get is: "�2����r69", while the sent sms is "Hello World!".
Here is my java code:
private String fromPDUText(String PDUSMSText) {
String endoding = PDUSMSText.substring(0, 2);
PDUSMSText = PDUSMSText.substring(18);
byte bs[] = new byte[PDUSMSText.length() / 2];
for(int i = 0; i < PDUSMSText.length(); i += 2) {
bs[i / 2] = (byte) Integer.parseInt(PDUSMSText.substring(i, i + 2), 16);
}
try {
String out = new String(bs, "ASCII");
} catch(UnsupportedEncodingException e) {
e.printStackTrace();
return "";
} finally {
return out;
}
}
The input is packed in 7-bits per character, which means that every 8 bytes encode 9 characters. Constructing a parser for this format can be a fun exercise or a frustrating experience, depending on how you take it. You are probably better off using a library, and a quick Google search reveals several code examples.
This is how 7Bit characters are packed:
Encoding-Decoding-7-bit-User-Data-for-SMS-PDU-PDU
Personally I find it easiest to attack this kind of problem by viewing it as having a pipe where you feed 8 bits in one end and retrieve 7 bits in the other. As long as there is at least 7 bits in the pipe you read from it. When there are less than 7 bits you need to add some more so you write 8 new bits to it. So what you need is:
A pipe that can hold at least 14 bits (but why be cheap? Go with a 32-bit int!).
A counter keeping track of how many bits are in the pipe at any given moment.
The algorithm in pseudo code is as follows:
pipe = 0;
bitCount = 0;
while(hasMoreData())
{
pipe |= readByte() << bitCount;
bitCount += 8;
while(bitCount >= 7)
{
writeByte(pipe & 0x7F);
pipe >>= 7;
bitCount -= 7;
}
}
Related
I have two programs that talk with serial rs232
1. written in c# with the use pf SerialPort class
2. written in java with the use of librxtx - SerialPort class
both: BaudRate - 9600, Parity-None, StopBits - 1, DataBits - 8
they communicate with the same the device that send the same data all the time
in c# i get the following 6 bytes: 255,98,144,19,1,0
in java i get the following 6 bytes: -1,98,-112,19,1,0
the c# code is the right one.
here are the code for c#:
m_serialPort = new SerialPort("COM15", 9600, Parity.None, 8, StopBits.One);
m_serialPort.DataReceived += SPDataRecieved;
m_serialPort.Open();
public override void SPDataRecieved(object sender, SerialDataReceivedEventArgs e)
{
try
{
Thread.Sleep(80);
byte[] toBytes = new byte[6];
m_serialPort.Read(toBytes, 0, 6);
}
catch (Exception ex)
{
}
}
}
here are the code for java:
m_SerialPort = (SerialPort) commPort;
m_SerialPort.setSerialPortParams
(9600,SerialPort.DATABITS_8,SerialPort.STOPBITS_1,SerialPort.PARITY_NONE);
InputStream in = m_SerialPort.getInputStream();
byte[] buffer = new byte[6];
int len = -1;
Thread.sleep(80);
len = in.read(buffer,0,6);
what i need to add to the java code that the result will be the same?
Note that byte[] in Java and C# differ for 2 main reasons:
Java byte type is signed, while the C# byte type is unsigned (if you need signed use sbyte type)
Java stores byte as Big Endian, while C# uses Little Endian by default
Since java doesn't include unsigned byte in the language, you can print a conversion to int in the following way:
byte b = 0x3a; // random value
return b & 0xFF;
The java bytes are signed, while the C# bytes are not.
Convert each java value with the following:
newValue = (value + 256) % 256
// (-1 + 256) % 256 = 255
// (98 + 256) % 256 = 98 etc
I have a program in C# .net which writes 1 integer and 3 strings to a file, using BinaryWriter.Write().
Now I am programming in Java (for Android, and I'm new in Java), and I have to access the data which were previously written to a file using C#.
I tried using DataInputStream.readInt() and DataInputStream.readUTF(), but I can't get proper results. I usually get a UTFDataFormatException:
java.io.UTFDataFormatException: malformed input around byte 21
or the String and int I get is wrong...
FileInputStream fs = new FileInputStream(strFilePath);
DataInputStream ds = new DataInputStream(fs);
int i;
String str1,str2,str3;
i=ds.readInt();
str1=ds.readUTF();
str2=ds.readUTF();
str3=ds.readUTF();
ds.close();
What is the proper way of doing this?
I wrote a quick example on how to read .net's binaryWriter format in java here
excerpt from link:
/**
* Get string from binary stream. >So, if len < 0x7F, it is encoded on one
* byte as b0 = len >if len < 0x3FFF, is is encoded on 2 bytes as b0 = (len
* & 0x7F) | 0x80, b1 = len >> 7 >if len < 0x 1FFFFF, it is encoded on 3
* bytes as b0 = (len & 0x7F) | 0x80, b1 = ((len >> 7) & 0x7F) | 0x80, b2 =
* len >> 14 etc.
*
* #param is
* #return
* #throws IOException
*/
public static String getString(final InputStream is) throws IOException {
int val = getStringLength(is);
byte[] buffer = new byte[val];
if (is.read(buffer) < 0) {
throw new IOException("EOF");
}
return new String(buffer);
}
/**
* Binary files are encoded with a variable length prefix that tells you
* the size of the string. The prefix is encoded in a 7bit format where the
* 8th bit tells you if you should continue. If the 8th bit is set it means
* you need to read the next byte.
* #param bytes
* #return
*/
public static int getStringLength(final InputStream is) throws IOException {
int count = 0;
int shift = 0;
boolean more = true;
while (more) {
byte b = (byte) is.read();
count |= (b & 0x7F) << shift;
shift += 7;
if((b & 0x80) == 0) {
more = false;
}
}
return count;
}
As its name implies, BinaryWriter writes in binary format. .Net binary format to be precise, and as java is not a .Net language, it has no way of reading it. You have to use an interoperable format.
You can choose an existing format, like xml or json or any other interop format.
Or you can create your own, providing your data is simple enough to make it this way (it seems to be the case here). Just write a string to your file (using a StreamWriter for instance), provided you know your string's format. Then read your file from java as a string and parse it.
There is a very good explanation of the format used by BinaryWriter in this question Right Here it should be possible to read the data with a ByteArrayInputStream and write a simple translator.
So I have binary FRX files, from which I need to extract strings into Java.
I wrote this into my Java program like so:
FileInputStream ReadFRX = null ;
FileOutputStream TempCapt = null ;
try{
// refNum is hex number on end of VB form property converted to decimal, ex: $"frmResidency.frx":0134
int refNum = Integer.parseInt(line.substring(line.length() - 4, line.length()), 16);
// FRXtemp.txt is created, to temporarily write FRX captions onto to be read from.
PrintWriter writer = new PrintWriter("FRXtemp.txt", "UTF-8");
writer.close();
//opens corresponding FRX file to read into
ReadFRX = new FileInputStream("FRXFiles\\"+curFrmName + ".frx");
//aLittleEndian... must be used to match readInt() little-endianness
LittleEndianDataInputStream ActReadFRX = new LittleEndianDataInputStream(ReadFRX);
TempCapt = new FileOutputStream("FRXtemp.txt");
ActReadFRX.skipBytes(refNum);
int length = ActReadFRX.readInt();
int c;
for (c = 0; c < length; c++) {
// first read byte and check for EOF
TempCapt.write(ActReadFRX.read());
}
}
//If caption is not read properly (ie. possibly wrong bytes), EOF Exception will occur and designer will break
catch (EOFException e){
System.out.println("ERROR : FRX Caption property was mishandled");
break;
}
//Read data from FRXtemp.txt into string
String actCaption = "\"" + new Scanner(new File("FRXtemp.txt")).useDelimiter("\\A").next() + " \" ";
This works perfectly, however I think writing to a temporary file so that I can read off of it must be highly unnecessary.
Why I can't think of a more efficient method:
I feel like a much more practical approach would be to use a Byte[] Array, and then convert that to a string, however I must only have the bytes in which the string are stored. Research led me to believe that RandomAccessFile was then necessary so that I could set an offset from ReadInt to begin reading bytes , however RandomAccessFile assumes big-endian format, whereas I have little-endian format. I can obviously convert, however at that point my current solution seems just as viable.
My question is, is there an efficient way to convert a specific section of bytes corresponding to a 4-byte integer (from a binary file with little-endian format) into a string in Java?
I feel as though I must be overlooking something much more simple. Thanks :)
You can do this any number ways, however the simplest might be.
try (DataInputStream dis = new DataInputStream(new FileInputStream(file))) {
dis.skip(bytesToSkip);
int length = Integer.reverseBytes(dis.readInt());
byte[] bytes = new bytes[length];
dis.readFully(bytes);
return new String(bytes, "UTF-8");
}
The method you might have been looking for is in Integer
/**
* Returns the value obtained by reversing the order of the bytes in the
* two's complement representation of the specified {#code int} value.
*
* #param i the value whose bytes are to be reversed
* #return the value obtained by reversing the bytes in the specified
* {#code int} value.
* #since 1.5
*/
public static int reverseBytes(int i) {
return ((i >>> 24) ) |
((i >> 8) & 0xFF00) |
((i << 8) & 0xFF0000) |
((i << 24));
}
Something like this maybe?
long length = 0xff && mybytes[0]; length<<8;
length |= 0xff && mybytes[1]; length<<8;
length |= 0xff && mybytes[2]; length<<8;
length |= 0xff && mybytes[3]; length<<8;
You can use the inputStream that you have as the source and use a ByteBuffer to correct the endianess when creating the Strings as needed. This would be the most efficient way.
I'm developing an app based on Samsung Chord SDK. I need to send the video's current position in the sendDataToAll(), which accepts data in byte[][]. My problem is that when I try to send the current position (which is an int) type-casted into byte, I'm getting negative value (in byte) as returned. And when I try to convert the negative value in to int in the OnDataRecived(), it's still the same negative value. How do I solve this issue?
Sending code:
//for sending the message
int currPos = mVideoView.getCurrentPosition();
logView.append("Duration sent= " + currPos);
//Integer resume = -3;
Byte msgByte = new Byte("-3");
byte [] [] pay = new byte [1] [2];
pay[0] [0] = msgByte;
Byte msgByte2 = new Byte((byte) currPos);
logView.append("Duration sent= " + msgByte2);
pay[0] [1] = msgByte2;
mChordchannel.sendDataToAll("Integer", pay);
// im sending -3 so that im checking that the user pressed the resume .
Receiving code:
//on receiving
else if(intRec == -3) {
Byte pos = rec[0] [1];
int posn;
posn = pos.intValue();
logView.append("Duration received= " + posn);
mVideoView.seekTo(posn);
mVideoView.start();
}
I don't know anything about the Samsung Chord SDK, but you can't fit (most) ints in a byte. An int is 4 bytes wide.
To create a payload compatible with your current code, that sends all 4 bytes:
byte[][] payload = { {
-3,
(byte)(currPos >> 24),
(byte)(currPos >> 16),
(byte)(currPos >> 8),
(byte)(currPos >> 0),
} };
mChordchannel.sendDataToAll("Integer", payload);
To receive:
int position = new java.math.BigInteger(
Arrays.copyOfRange(rec[0], 1, 5)).intValue();
P.S. This is not pretty code! It is tolerable for basic ints, but if you later find you need to transmit more complicated data structures you will need a better way. Some ideas, in increasing order of sophistication:
Use data streams (wrap a DataOutputStream around a ByteArrayOutputStream; write values; when done writing, close the DataOutputStream and call toByteArray() on the ByteArrayOutputStream to get the payload).
Use serialization (wrap an ObjectOutputStream around a ByteArrayOutputStream; write values and/or objects; finish as above).
Use a JSON-encoder or XML-encoder. (E.g., encode the data as a String, then call getBytes("UTF-8") on the String and send that.)
I'm trying to write my own WebSocket Server.
I know that there are some frameworks for this but i would like to learn, so I do it on my own :)
My JavaScript client reacts currently with onOpen, so I think the handshake is valid and
the connection is established.
Now the problem:
My Java server uses a selector thread for reading on an Channel.
If I do *.send("test message") on the WebSocket object at my client, my server can't decode the byte array.
I found no information about the used encode/decode technology, so I tried many versions to decode.
for example:
new String(Base64.decodeBase64(buffer.array()))
or
Charset set = Charset.forName("UTF-8");
new String(Base64.decodeBase64(set.decode(buffer).toString()))
The message is completely read from the Channel into an ByteBuffer, so I don't think this is the problem.
Can anyone help me?
okay this Post helps me to send data to the Client. This works fine :)
But I don't understand how to decode the data received from the Client :(
At the Client i send only one Letter
socket.send("x");
The Server receives 7 byte ???
ByteBuffer buffer = ByteBuffer.allocate(8192);
int read = client.getInputStream().read(buffer2.array());
System.out.println("read: " + read);
// read: 7
for (int i = 0; i < read; i++) {
int j = buffer.get(i) & 0xff;
System.out.println("i: " + i + " => " + j + "=>" + new BigInteger(j + "").toString(2));
}
//i: 0 => 129=>10000001
//i: 1 => 129=>10000001
//i: 2 => 195=>11000011
//i: 3 => 235=>11101011
//i: 4 => 4=>100
//i: 5 => 96=>1100000
//i: 6 => 187=>10111011
If i do this
secondByte AND 0111 1111
the result of (i: 1) is "1" i think this means that there are only one byte data. Then why read is 7 ???
As for your second issue - the data from client to server is always masked as I also explained at the link above. Masks take 4 bytes.
So, the length of the actual data is indeed 1. Only the last 7 bits of the second byte say something about the length - the first bit doesn't, so just discard that one to get 000 0001 which is 1.
The bytes are categorised as follows in this case:
0, 1 are meta bytes
3, 4, 5, 6 are masks
7 is the data
To get the data, calculate data XOR masks[data_index MOD 4], i.e. 187 XOR 195 in this case, which is 120 - the character code for x.
private String decodeMessage(){
try {
byte[] data = new byte[1024];
int size = in.read(data);
if (size == -1) return null;
byte[] decoded = new byte[size-6];
byte[] key = new byte[]{ data[2], data[3], data[4], data[5] };
for (int i = 0; i < size-6; i++) {
decoded[i] = (byte) (data[i+6] ^ key[i & 0x3]);
}
return new String(decoded, "UTF-8");
}catch (IOException ex){
ex.printStackTrace();
}
return "ping";
}
This code is probably bad, but it works for me