We have a requirement to send a saml request to IDP.The request should be deflated ,base64 & URL encoded.Below is the code for deflate the request.
byte[] encodedArray=IDPUtil.compress(samlRequest.getBytes());
public static byte[] compress(byte[] data){
byte[] output = null;
try {
Deflater deflater = new Deflater();
deflater.setInput(data);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
deflater.finish();
byte[] buffer = new byte[1024];
while (!deflater.finished()) {
int count = deflater.deflate(buffer);
outputStream.write(buffer, 0, count);
output = outputStream.toByteArray();
System.out.println("Original: " + data.length / 1024 + " Kb");
System.out.println("Compressed: " + output.length / 1024 + " Kb");
}
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
return output;
}
In the IDP end while inflating we are getting the below exception
java.util.zip.DataFormatException: invalid bit length repeat
at java.util.zip.Inflater.inflateBytes(Native Method)
at java.util.zip.Inflater.inflate(Inflater.java:238)
Below is the decompression logic
String urlDecodedString=URLDecoder.decode(urlEncodedString,"UTF-8");
byte[] base64DecodedArray=base64.decode(urlDecodedString);
System.out.println(new String(decompress(base64DecodedArray)));
public static byte[] decompress(byte[] data){
System.out.println("Length : "+data.length/1024 + "KB");
byte[] output = null ;
Inflater inflater = new Inflater();
inflater.setInput(data);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
byte[] buffer = new byte[1024];
try {
while (!inflater.finished()) {
int count;
count = inflater.inflate(buffer);
outputStream.write(buffer, 0, count);
}
outputStream.close();
output = outputStream.toByteArray();
} catch (DataFormatException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return output;
}
Please suggest what went here ?
Related
I am deflating a string with java with this function:
protected static byte[] Compress(String source) {
try {
// deficne start time
long startTime = System.currentTimeMillis();
//get bytes
byte[] bytes = source.getBytes("UTF-8");
Deflater deflater = new Deflater();
deflater.setInput(bytes);
deflater.finish();
ByteArrayOutputStream bos = new ByteArrayOutputStream(bytes.length);
byte[] buffer = new byte[1024];
while (!deflater.finished()) {
int bytesCompressed = deflater.deflate(buffer);
bos.write(buffer, 0, bytesCompressed);
}
try {
//close the output stream
bos.close();
} catch (IOException ioe) {
System.out.println("Error while closing the stream : " + ioe);
}
//get the compressed byte array from output stream
byte[] compressedArray = bos.toByteArray();
return compressedArray;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
now, I want to inflate that string with PHP with this function:
$uncompressed = gzinflate($filepath);
echo $uncompressed;
die();
but I got data error in php file, how can I solve this problem?
the error message is :
Warning: gzinflate(): data error
regards
I am getting error when i am trying to decompressing the files coming from server,but i am getting error of invalid bit length in while loop.Is there any problem with code or encoding.
byte[] buffer = new byte[1024];
FileInputStream fileInput = null;
FileOutputStream fileOutputStream = null;
GZIPInputStream gzipInputStream = null;
System.out.println(source_compressed_filepath);
System.out.println(destinaton_decompressed_filepath);
try {
fileInput = new FileInputStream(source_compressed_filepath);
gzipInputStream = new GZIPInputStream(fileInput);
fileOutputStream = new FileOutputStream(destinaton_decompressed_filepath);
int len;
while ((len = gzipInputStream.read(buffer)) >=0) {
fileOutputStream.write(buffer, 0, len);
}
System.out.println("The file" + source_compressed_filepath + " was DeCompressed successfully!"
+ destinaton_decompressed_filepath);
}catch (IOException ex) {
System.out.println(" error in file decompression " + source_compressed_filepath);
} finally {
// close resources
try {
fileOutputStream.close();
gzipInputStream.close();
} catch (IOException e) {
}
}
In my application I get a profile picture for user then I save it to a serialized class as string.
I do the GZIP compress and Base64 using the code below, but I can not do the reverse thing as you see in the getProfilePicture() method further down:
private void saveBitmap(){
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
mBitmap.compress(Bitmap.CompressFormat.PNG, 100, byteArrayOutputStream);
byte[] byteArray = byteArrayOutputStream.toByteArray();
String bitmapContent = "";
try {
bitmapContent = FileHelpers.compressAndBase64(byteArray);
//later save it...
} catch (IOException e) {
e.printStackTrace();
Log.e(TAG, "Error converting bitmap to gzip and base64");
}
}
public static String compressAndBase64(byte[] byteArray)
throws IOException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
GZIPOutputStream zos = new GZIPOutputStream(baos);
zos.write(byteArray);
zos.close();
byte[] bytes = baos.toByteArray();
return Base64.encodeToString(bytes, Base64.DEFAULT);
}
Now I want to convert it back to Bitmap...but so far I didn't succeed to.
The steps are decoding back the string from Base64 to byte array then decompress the byte array and convert to Bitmap.
public Bitmap getProfilePicture(){
if(getProfilePhotoBase64() != null) {
byte[] decoded = Base64.decode(mProfilePhotoBase64.getBytes(), Base64.DEFAULT);
final int BUFFER_SIZE = 32;
ByteArrayInputStream is = new ByteArrayInputStream(decoded);
GZIPInputStream gis = null;
try {
gis = new GZIPInputStream(is, BUFFER_SIZE);
} catch (IOException e) {
e.printStackTrace();
}
StringBuilder string = new StringBuilder();
byte[] data = new byte[BUFFER_SIZE];
int bytesRead;
try {
while ((bytesRead = gis.read(data)) != -1) {
string.append(new String(data, 0, bytesRead));
}
} catch (IOException e) {
e.printStackTrace();
}
try {
gis.close();
is.close();
} catch (IOException e) {
e.printStackTrace();
}
byte[] byteArray = string.toString().getBytes();
Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0,byteArray.length);
if(bitmap != null) {
return bitmap;
} else {
return null;
}
}
return null;
}
This is the error message I get using the code above:
--- SkImageDecoder::Factory returned null
I can do this quite easy in PHP, but its darn hard to make it work in Java!
if(isset($_POST["photo"])) {
$photoContent = $_POST["photo"];
$photo = imap_base64 ($photoContent);
$photo = gzdecode($photo);
$filename = $_POST["username"].".png";
$dir = SITE_ROOT_PATH."/images/".$user."/".$filename;
file_force_contents($dir, $photo);
} else {
$filename = "NO_PROFILE_PHOTO";
}
Ok I managed to fix the problem in this way:
/**
* IMPORTANT NOTE!!!!!!!!!!!!!!
* String is first converted to byte array, then compressed using GZIP and then
* the resulting byte array is encoded to Base64.DEFAULT
* #return
*/
public String getProfilePhotoBase64() {
return mProfilePhotoBase64;
}
public Bitmap getProfilePicture(){
if(getProfilePhotoBase64() != null) {
byte[] decoded = Base64.decode(mProfilePhotoBase64.getBytes(), Base64.DEFAULT);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteArrayInputStream bis = new ByteArrayInputStream(decoded);
GZIPInputStream zis = null;
try {
zis = new GZIPInputStream(bis);
byte[] tmpBuffer = new byte[256];
int n;
while ((n = zis.read(tmpBuffer)) >= 0) {
bos.write(tmpBuffer, 0, n);
}
zis.close();
} catch (IOException e) {
e.printStackTrace();
}
Bitmap bitmap = BitmapFactory.decodeByteArray(bos.toByteArray(), 0
, bos.toByteArray().length);
if(bitmap != null) {
return bitmap;
} else {
return null;
}
}
return null;
}
And what is the problem exactly? compressAndBase64() will return an empty string as boas.toByteArray() will return 0 bytes as boas is just created and hence empty. You don't need to create a boas. Just change
return Base64.encodeToString(bytes, Base64.DEFAULT);
to
return Base64.encodeToString(byteArray, Base64.DEFAULT);
I know that there's a way of converting a file to byte array in chunks, here's a sample code:
InputStream inputStream = new FileInputStream(videoFile);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
byte[] b = new byte[1024];
int bytesRead =0;
while ((bytesRead = inputStream.read(b)) != -1)
{
bos.write(b, 0, bytesRead);
}
I'm looking for the opposite: a way of converting a byte array into a file in chunks. I didn't find any example of doing it in chunks.
You just have to use either the write(byte[]) or write(byte[],int,int) methods from the FileOutputStream class.
byte[] to file:
FileOutputStream fop = null; File file;
try {
file = new File(filePath);
fop = new FileOutputStream(file, true);
fop.write(chunk);
fop.flush();
fop.close();
System.out.println("Done");
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if (fop != null) {
fop.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
Try this for file to byte[]:
InputStream is = new FileInputStream(file);
int length = (int) file.length();
int take = 262144;//size of your chunk
byte[] bytes = new byte[take];
int offset=0;
int a = 0;
do {
a = is.read(bytes, 0, take);
offset += a;
//And you can add here each chunk created in to a list, etc, etc.
//encode to base 64 this is extra :)
String str = Base64.encodeToString(bytes, Base64.DEFAULT);
} while (offset < length);=
is.close();
is=null;
Consider generalizing the problem.
This method copies data in chunks:
public static <T extends OutputStream> T copy(InputStream in, T out)
throws IOException {
byte[] buffer = new byte[1024];
for (int r = in.read(buffer); r != -1; r = in.read(buffer)) {
out.write(buffer, 0, r);
}
return out;
}
This can then be used in both reading to and from byte arrays:
try (InputStream in = new FileInputStream("original.txt");
OutputStream out = new FileOutputStream("copy.txt")) {
byte[] contents = copy(in, new ByteArrayOutputStream()).toByteArray();
copy(new ByteArrayInputStream(contents), out);
}
I am developing an Android App to send a file via bluetooth to a java server using the BlueCove library version 2.1.0 based on this snippet. At the beginning everything looks fine, but the file will not transfered completly. Only about 7KB of 35KB.
Android
private void sendFileViaBluetooth(byte[] data){
OutputStream outStream = null;
BluetoothDevice device = btAdapter.getRemoteDevice(address);
btSocket = device.createRfcommSocketToServiceRecord(MY_UUID);
btSocket.connect();
try {
outStream = btSocket.getOutputStream();
outStream.write( data );
outStream.write("end of file".getBytes());
outStream.flush();
} catch (IOException e) {
} finally{
try {
outStream.close();
btSocket.close();
device = null;
} catch (IOException e) {
}
}
}
PC Server
InputStream inStream = connection.openInputStream();
byte[] buffer = new byte[1024];
File f = new File("d:\\temp.jpg");
FileOutputStream fos = new FileOutputStream (f);
InputStream bis = new BufferedInputStream(inStream);
int bytes = 0;
boolean eof = false;
while (!eof) {
bytes = bis.read(buffer);
if (bytes > 0){
int offset = bytes - 11;
byte[] eofByte = new byte[11];
eofByte = Arrays.copyOfRange(buffer, offset, bytes);
String message = new String(eofByte, 0, 11);
if(message.equals("end of file")) {
eof = true;
} else {
fos.write (buffer, 0, bytes);
}
}
}
fos.close();
connection.close();
I tried already to split the byte array before writing:
public static byte[][] divideArray(byte[] source, int chunksize) {
byte[][] ret = new byte[(int)Math.ceil(source.length / (double)chunksize)][chunksize];
int start = 0;
for(int i = 0; i < ret.length; i++) {
ret[i] = Arrays.copyOfRange(source,start, start + chunksize);
start += chunksize ;
}
return ret;
}
private void sendFileViaBluetooth(byte[] data){
[...]
byte[][] chunks = divideArray(data, 1024);
for (int i = 0; i < (int)Math.ceil(data.length / 1024.0); i += 1) {
outStream.write( chunks[i][1024] );
}
outStream.write("end of file".getBytes());
outStream.flush();
[...]
}
Every help or ideas are appreciated.
You don't need any of this. The canonical way to copy a stream in Java is this:
while ((count = in.read(buffer)) > 0)
{
out.write(buffer, 0, count);
}
out.close();
Same at both ends. TCP/IP will do all the chunking for you. All you need to do is cope correctly with varying size reads, which this code does.