Base64 decode and uncompress a string - java

I have a String which is first zipped (not gzip) and then base64 encoded.
I want to have the plain text again. Following code
private void decode_decompress(String string) {
byte[] decodedBytes = Base64.decodeBase64(string.getBytes());
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Inflater decompresser = new Inflater(true);
InflaterOutputStream inflaterOutputStream = new InflaterOutputStream(stream, decompresser);
try {
inflaterOutputStream.write(decodedBytes);
inflaterOutputStream.close();
byte[] output2 = stream.toByteArray();
logger.info("Data: {}", output2.toString());
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
throws an exception:
java.util.zip.ZipException: invalid stored block lengths
at java.util.zip.InflaterOutputStream.write(InflaterOutputStream.java:273)
at java.io.FilterOutputStream.write(FilterOutputStream.java:97)
at de.martinm.tools.EBICS.DSTools.decode_decompress(DSTools.java:87)
at de.martinm.tools.EBICS.DSTools.process(DSTools.java:77)
at de.martinm.tools.EBICS.DSTools.main(DSTools.java:100)
I guess, I'm mixing up again input/output inflate/deflate
Here is the data which is compressed and base64 encoded:
eJx1U2tzqjAQ/SsO96NTw1PBQTr4qlgtyqvVL3cihEehiSYg1l9/rd46dZx+y549Ocme3dUfDx9FY48oywjucUKL5xoIhyTKcNLjfG/8oHINVkIcwYJg1OMw4R4N3c0SDMuKokW1eUafNo0QHcISNk5qmPW4tCy3XQDqum6hTRayFqEJcHle4C6MbnRLqqUzQ+R5HvAaOHEiliV/vtlnjR5XUdw90S5hd8Lz8jfhwLJf9ATwNp+5YYo+4EOGvyoJ0ekWy7rsDM5ICMtz7b/+uXH/Ljgf/7JvG1oHFnF3tlg4JoZ+OQewqJChR6zruOZNPCdRVVTMMOebJcxHZRJ1kqeDJJqfR6IQJDdngt1cBt5ncYKnO8d99Tp9gYoweT2O40BUatURhWKZvVHV7E8102XHXTDN5ZI1vZyX6KKeSm+SmK9VlQZ5nZeKvd8X7aPUmRztxdp8rtaZom1kJlsRqsK95RSS7RJ7AYOQbg6S2vZXrjWA6S5vqzlWYCG/z947YgXjcOasFuF8/JKs34nngCGYIVBukJd9jLHftuQSmfV6LJFg2CQrU5Ze4qJYpR1/b5qD2MaOvSv27Z1PV4GA+p1U1IDFWLJaifGEKmGKxZ3lq5Ox0EHb1G++JvGIpaSayxYd9J2kfO7nhXiw4XYYD3fyJsbC8kmDVv2iJZqqaAtnn/d08MPkL8NHh+1plHFpmEtzcM5ekXN00yBw075rg4PLxhgmz7d1cAf/gG5GAdISI2oNjVHfGried5K/QrrPfqYUHfwH7sSu62b8A39iR+Y=

This solved the issue:
private void decode_decompress(String string) {
byte[] decodedBytes = Base64.decodeBase64(string);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
Inflater decompresser = new Inflater(false);
InflaterOutputStream inflaterOutputStream = new InflaterOutputStream(stream, decompresser);
try {
inflaterOutputStream.write(decodedBytes);
inflaterOutputStream.close();
String data = stream.toString();
logger.info("Data: {}", data);
} catch (IOException e) {
logger.error(string, e);
}
}

Related

CipherOutputStream causes IllegalBlockSizeException on receiving message

I'm writing server/client system that uses AES.
The following method (server side) works fine:
public static byte[] encode(byte type, byte subType, String string, Cipher cipher)
throws NullPointerException, IOException {
Objects.requireNonNull(string);
Objects.requireNonNull(cipher);
byte[] data = null;
try {
data = string.getBytes(StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e1) {};
ByteArrayOutputStream bytesOutput = new ByteArrayOutputStream();
bytesOutput.write(type);
bytesOutput.write(subType);
bytesOutput.write(data);
byte[] plainBytes = bytesOutput.toByteArray();
byte[] bytes = null;
try {
bytes = cipher.doFinal(plainBytes);
} catch (Exception e) {
e.printStackTrace();
}
byte[] base64Bytes = Base64.getEncoder().encode(bytes);
return base64Bytes;
}
But when I replaced it with the following code I got IllegalBlockSizeException on client side.
public static byte[] encode(byte type, byte subType, String string, Cipher cipher)
throws NullPointerException, EncodingException {
Objects.requireNonNull(string);
Objects.requireNonNull(cipher);
byte[] data = null;
try {
data = string.getBytes(StandardCharsets.UTF_8.name());
} catch (UnsupportedEncodingException e1) {};
CipherOutputStream cipherOutput = null;
try {
ByteArrayOutputStream bytesOutput = new ByteArrayOutputStream();
OutputStream base64Output = Base64.getEncoder().wrap(bytesOutput);
cipherOutput = new CipherOutputStream(base64Output, cipher);
cipherOutput.write(type);
cipherOutput.write(subType);
cipherOutput.write(data);
cipherOutput.flush();
byte[] bytes = bytesOutput.toByteArray();
return bytes;
} catch (IllegalStateException | IOException e) {
throw new EncodingException(e);
} finally {
if (cipherOutput != null)
try {
cipherOutput.close();
} catch (IOException e) {};
}
}
}
What is wrong with second method? Both methods use the same cipher. Nothing changed on server excluding the encode method.

Base 64 Encoded QRGen QR code can't be decoded

Im trying to generate a QR code using QRGen, encode it in Base64 and insert it as an image in an HTML string. Later, the HTML string is decoded to be displayed in a JEditorPane (and then sent to a printer). To this end, the ImageView class is extended and a custom View factory is used. This all works fine... sometimes. It completely depends on the input string. Some strings work without issue, others fail cause the decode process to fail with the error java.lang.IllegalArgumentException: Input byte array has wrong 4-byte ending unit.
Here is the encode process:
public BufferedImage generateQRCodeImage(String barcodeText) throws Exception {
ByteArrayOutputStream stream = QRCode.from(barcodeText).to(ImageType.PNG).stream();
ByteArrayInputStream bis = new ByteArrayInputStream(stream.toByteArray());
return ImageIO.read(bis);
}
public static String encodeToString(BufferedImage image, String type) {
String imageString = null;
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try {
ImageIO.write(image, type, bos);
byte[] imageBytes = bos.toByteArray();
Base64.Encoder encoder = Base64.getEncoder();
imageString = encoder.encodeToString(imageBytes);
bos.close();
} catch (IOException e) {
e.printStackTrace();
}
return imageString;
}
and the decode process:
private Image loadImage() {
String b64 = getBASE64Image();
BufferedImage newImage = null;
ByteArrayInputStream bais = null;
try {
bais = new ByteArrayInputStream(Base64.getDecoder().decode(b64.getBytes())); //fails here
newImage = ImageIO.read(bais);
} catch (Throwable ex) {
ex.printStackTrace();
}
return newImage;
}
#Override
public URL getImageURL() {
String src = (String) getElement().getAttributes().getAttribute(HTML.Attribute.SRC);
if (isBase64Encoded(src)) {
this.url = BASE64ImageView.class.getProtectionDomain()
.getCodeSource().getLocation();
return this.url;
}
return super.getImageURL();
}
private boolean isBase64Encoded(String src) {
return src != null && src.contains("base64,");
}
private String getBASE64Image() {
String src = (String) getElement().getAttributes().getAttribute(HTML.Attribute.SRC);
if (!isBase64Encoded(src)) {
return null;
}
return src.substring(src.indexOf("base64,") + 7, src.length() - 1);
}
And here is the QR code in question that fails to decode.
<img width='30' height='30' src='data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAH0AAAB9AQAAAACn+1GIAAAApklEQVR4Xu2UMQ4EMQgD/QP+/0vK6zjsvayUMmavWxQpMAUBkwS12wcveAAkgNSCD3rR5Lkgoai3GUCMgWqbAEYR3HxAkZlzU/0MyBisYRsgI1ERFfcpBpA+ze6k56Cj7KTdXNigFWZvSOpsgqLfd18i2aAukXh9TXBNmdWt5gzA/oqzWkkN8HtA7G8CNOwYAiZt3wZixUfkA32OHNQq7Bxs9oI/gC/9fV8AVCkPjQAAAABJRU5ErkJggg=='/>
I did open the above QR in a browser (Chrome) and it does work, which definitely points to something being wrong in the decode process and not the encode process.
Found the issue. In getBASE64Image(), I have
private String getBASE64Image() {
String src = (String) getElement().getAttributes().getAttribute(HTML.Attribute.SRC);
if (!isBase64Encoded(src)) {
return null;
}
return src.substring(src.indexOf("base64,") + 7, src.length() - 1);
}
The "-1" in the substring call was the cause of my problems. Not sure why this would work only sometimes, but removing seems to have fixed the problem.

Binary data in String representation to PDF file

So I'm receiving a response from a service which is a byte array representation of pdf file in String like below:
response.pdfStream = "JVBERi0xLjQKJcfsj6IKNSAwIG9iago8PC9MZW5ndGggNiAwIFIvRmlsdGVyIC9GbGF0ZURlY29kZT4+CnN0cmVhbQp4nK1aS3MbxxG+45Qql+9zcQlIEat57wxzAgJIcviQTYCqKGIOKwEWN3hJIKgU+Wt88U9I/kKuOflk6OqrTz4RrHyzu7MASCzHUkypCtBOT3dPT39fdy/1ntBIGkLdH//lzaT2+CQmby9q7wnjUmUPxXrJkM6s9u3mIuOZRLZqd68ylS8zunudx8U6q9Bui3W+e12xYl3sXtcPuxerB5dN/OCytQ+fnbGH13kgduJh75h82D2mfPBkhUDso6cqBIwICFj1sACncUCA2YCACDjJZcBJrkJO6pCTcchJG3BS0ICTggWcFDzgpBABJ4UKOalDTsYhJ03ISRtwUrKAk5IHnJQi4KSUASelCjkZAo4MAUeGgKNCwFEh4KgQcFQIOCoEHBUCjgoBR4WAo0PA0SHg6BBwdAg4OgQcHQKODgFHh4CjQ8CJQ8CJQ8CJQ8CJQ8CJQ8CJQ8CJQ8CJQ8AxIeCYEHBMCDgmBBwTAo4JAceEgGNCwLEh4NgQcGwIODYEHBsCjg0Bx4aAY0PAsSHgMBpCDqMh6DAawg6jIfAwGkIPo8GGj..."
I need to convert this to absolute byte array and then create pdf file with it to open.
Tried this:
byte[] pdfStream = response.pdfStream.getBytes(Charsets.UTF_8);
InputStream inputStream = new ByteArrayInputStream(pdfStream);
File file = null;
try {
file = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), filename);
Logger.debug("createFile: "+file.getAbsolutePath());
OutputStream outputStream = new FileOutputStream(file);
IOUtils.copy(inputStream, outputStream);
outputStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return file;
try {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/pdf");
getMainActivity().startActivity(intent);
} catch (Exception e) {
Logger.printStackTrace(e);
}
With this code snippet it was very easy to convert a Base64 encoded String to a pdf-File.
The String is read from the input.txt file.
public void convertInputFile() {
try {
convertToPDF("/home/input.txt");
} catch (IOException e) {
}
}
private void convertToPDF(String inputFilePath) throws IOException {
byte[] byteArray = Files.toByteArray(new File(inputFilePath));
byte[] bytes = Base64.decodeBase64(byteArray);
DataOutputStream os = new DataOutputStream(new FileOutputStream("/home/output.pdf"));
os.write(bytes);
os.close();
}

Merging PDF in Java is not working

I am writing a function that takes as inputs a list of PDFs that are already converted into ByteArrayOutputStream and the destination filepath\name.pdf.
But I am getting errors and the document is not saved.
Public Void mergePDF(<ByteArrayOutputStream> src3,String DestinationFileName ){
PDFMergerUtility PDFmerger3 = new PDFMergerUtility();
PDFmerger3.setDestinationFileName(DestinationFileName);
for(ByteArrayOutputStream bos:src3){
byte[] bytes = bos.toByteArray();
InputStream is = new ByteArrayInputStream(bytes);
PDFmerger.addSource(is);
}
try {
PDFmerger.mergeDocuments(null);
} catch (IOException e1) {
e1.printStackTrace();
}// end of the Function
}

reading deflated data from the stream using inflater and InflaterInputStream

I'm trying to send a deflated string over http, when I use compression and decompression on the server side, without using streams, it's ok but when I write it to stream like this:
byte[] deflatedData = mtext.getByte();
try {
t.sendResponseHeaders(200,deflatedData.length);
} catch (IOException e1) {
display(e1);
e1.printStackTrace();
if(closeafter){
t.close();
}
return;
}
DeflaterOutputStream os = new DeflaterOutputStream(t.getResponseBody());
try {
os.write(deflatedData ,0,deflatedData .length);
} catch (IOException e1) {
mByte = null;
display(e1);
if(closeafter){
t.close();
}
return;
}
os.flush();
os.close();
and read from client side like this:
InflaterInputStream ini = new
InflaterInputStream(response.body().byteStream());
ByteArrayOutputStream bout =new ByteArrayOutputStream(512);
int b;
while ((b = ini.read()) != -1) {
bout.write(b);
}
ini.close();
bout.close();
String s=new String(bout.toByteArray());
android decompresses like this:
public static byte[] decompress(byte[] data) throws IOException, DataFormatException{
Inflater inflater = new Inflater();
inflater.setInput(data);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(data.length);
byte[] buffer = new byte[1024];
while (!inflater.finished()) {
int count = inflater.inflate(buffer);
outputStream.write(buffer, 0, count);
}
byte[] output = outputStream.toByteArray();
outputStream.close();
inflater.end();
return output;
}
so I get the following exception:
java.util.zip.DataFormatException: data error
Where am I going wrong?
The sending part was totally ok , The answer was to Use InflaterInputStream Directly from the input stream , like this:
public static String ReadDeflatedData(InputStream input){
InflaterInputStream in = new InflaterInputStream(input, new Inflater());
int bytesRead=0;
StringBuilder sb = new StringBuilder();
byte[] contents = null;
try {
contents = new byte[in.available()];
} catch (IOException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
}
try {
while( (bytesRead = in.read(contents)) != -1){
sb.append(new String(contents, 0, bytesRead));
}
} catch (IOException e) {
System.out.println(e.toString());
e.printStackTrace();
}
try {
return new String(sb.toString().getBytes(),"UTF-8");
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return null;
}

Categories