In SQL, I have a field called "Data" that contains what was once a PDF, but has been converted to a VARBINARY(MAX) field. I am pulling that data from a java servlet, and I need to know how to format it so that it can be sent to the front end and displayed as a PDF. I've seen a number of solutions that relate to BASE 64 encoding\decoding but those have not proven useful. Here is an example of what the data looks like after it has been put into SQL:
0x255044462D312E350D0A25B5B5B5B50D0A312030206F626A0D0A3C3C2F547970652F436174616C6F672F50616765732032203020522F4C616E6728656E2D555329203E3E0D0A656E646F626A0D0A322030206F626A0D0A3C3C2F547970652F50616765732F436F756E7420312F4B6964735B2033203020525D203E3E0D0A656E646F626A0D0A332030206F626A0D0A3C3C2F547970652F506167652F506172656E742032203020522F5265736F75726365733C3C2F466F6E743C3C2F46312035203020522F46322037203020523E3E2F50726F635365745B2F5044462F546578742F496D616765422F496D616765432F496D616765495D203E3E2F4D65646961426F785B2030203020363132203739325D202F436F6E74656E74732034203020522F47726F75703C3C2F547970652F47726F75702F532F5472616E73706172656E63792F43532F4465766963655247423E3E2F546162732F533E3E0D0A656E646F626A0D0A342030206F626A0D0A3C3C2F46696C7465722F466C6174654465636F64652F4C656E67746820323737373E3E0D0A73747265616D0D0A789C955A4B6FE4C611BE0BD07F9823279068369BCFA39D788304D985836C72117CA038DCD100323922C5C5FEFCD4ABBB8BD4702CC1C07AD88FEAEA7A7E55AD5FBEDEDEFCF4C9ECD2244EB2DDD76FB7376697C07F3062ABB8B4BB3231B1AD765FFFB8BD497647FCE7EFB7370FD1E7666CBBE7DDE77D1635E3A9DF57D1B0FF7DF7F59FB737BF02C55FBE063AB6B4715A6A3A0FD14EAD3548B54CE2BCCA764551C5F92E83AF3ADF997C3776B737DFFEC2F47EFA94EE0C2C2B165C96699CA4B011B704261FA27F0D63B73769F4C7FEBE84E3EE6D1D9DF6F75974DE1B134D33FEABA60EC3DE24D1332E18461C2AA38996BFEE7359D2F0161B75AF70E73B3FDE0EFDD4B5AF305A46B3EC6D0E482E9C47BFA6D6FFEC8F38CFFB3B38358FFC61B127FCEBFE3EA5219A6B561C7FC76F90FC8CAB26184BABE81B521A81453E04571C4F4080EEF5BC2FA206D66549D48D0D721BEE40C4981175A917244D926AF0CA22A999AF566CEB30B79B3A5C6B2DCF975A23466662E43CE3A1747287D7ABE9D043CC9CC06DFF01ECF73C43DB06DA46BBCE8E61588612ECBCF0481DA4E234DF3A4D8E3045F4050547120822D47A00F29D9F45F6C45C707C216318988643F38CE427C5B3577B2377647D1751DFA2E20EC4601F2EF3327BC39A026956DF84CB68EA71F6D6BC3074B851B08C4DF5D96D175CAB2F5B39DD791EE72926DB405BF902BF40BC62806B0B9EE609475ABCEEF9844A08CE464AE39D406262B325DE0FFC9BC65BBCB19B6D07A4D61FE73DF8D446284A2B1BD7A5E2FB41F9DB7FC8DCA733CAAEEB0F7B0918D3D4F10124B5012D2E03AEE711B80FA7F7A82E0E1981E2CF48B1EB8960431BD3B7A6BAF22F71D1E17082A1E1AAA2D2F7FB59BAF2B349794437EE8D25F3484A0821B9B211654D935C0B17FD5745C6BA006207096738A962C969B9AEEF5AB5AEFBC197A38F4D5BC0C9E0139E27E5188AAFBF2A8BF73722C203B913EB539821990F2FC8D18C1AAE2B1045DF70D035A5BBFBA4591635C1763CA039F6DE4878F44056705569C9FBBDCBACBDAB1939C99C3A48B72E2AE4C4CB409F1D04051924FD35530B3C9B9C13531A720331DA86C886669C1121F45F21B1725F5C4119A6097A4037640128D3CFD9F0FDDC0B29AB41413AF797907CE4A0D504B60F9EB40E1779F0FD623BA0AB3003C91F2E5EB8F0CB7184366DA1941C62825132DFC62879FD6EBFCBEB95DF11CBC4E1343514F193E83C905AF1D32686B9FCE172330E105870B64723A8940E5548FAE008739049AF63B2438A4F38ECDC72E9957E669D88CC92559F75254C7A8F0FA47B600366C0AD5C9A99640739F5346BFDE370D3CAFE96032B47DC82D79014C8A6953F6FE8A37CB74BE5D5CAA5D89E89B5961D9E85E620406E17C10EBF97580947484833271E1CCA520E0FC8BDC76F2E5DE30676B990BD7007C0E999A68D3E416D7AEA904B72EBC308317BA9485CD18D03305EBACFDF20483C3514BF3AEFC5FE3C2147A4B237A456E9D5E48B8480BF9EEE8288BA795337858DB3322887B4704D41C53A51CD0A369F1796CA8046A017FC730CA8077D0942F8716CBE636E23E048631036070CDAB1DFFF6FF83553C6995E280F989A719ED40FCEEF0C923863525639A1D840EF97A06308691B655251C7A656125846A0654595C6D62C963EB10F1E46E2793CBDDE81F69913C152F70A4C99F292D71BA920BAF9E8F25A136E1F6E4059BA2799D1F71DA6CB4D0BB025F22A169016B129AE1A400EEB161610144C760746BE031BEF49D97D8B4989113C5E63C45C476B89C78EB29A46E872DD3BC953DFFC1DE696EEF3E86266A6A25AC56270312D0F994D73B42A21ABE0FA1AB730DB2C55C87668790558CD869EAB32AE8D96C995AC94A64ACE7F1206D32C2E8D16B2605FE413401068FFC02E41E19F32429AFAD2EF9E73814D2F25155795C0ACC475C09A35142ECD2B0E838D2D0AEB34352AD33B67C351AD557661AF53A06E956F8535A8782F6B0443A670CC342DCD847A68A2637BB95B00F7A975F0924410B371138DFF51EA239978E53E4A0D992F4B2D5C2E3439586C682D29DFAFB5A45E69ED4D0FC0948533F7E28D4A705241F5B0F43E5378EA62E2E5D50B3DC781E827D0AF84690A2385826BF8E16AA3C26D18427B842A1C45EB33264EAE13008C4F40592648256F02305E89F478C633BA9EC604B6B474BC60D66599EE648556F3C45AA223670744715F730DC767F5FBDD2DABD7EEB6464C2EB8484594B32A9CC44451740F5F9F053B476DCC63ECE33DF5455E5DE03B7623656941E1C1AD7971C8EAD3B33F2E442E09F7CB8AEBCE27B975B558A06E76041CFBAD989699D85A2D9307CE502A2D2DB1CF02F1DBE8ACD32FC1FAD65BEB7429FF62928020DB0EFD77DCD8782CE42C417D3E4230C70CBAA9F6F2FDFE9A9517FD7599734BBA938BA939445F9F4582634A6D176AD5F262F4833B76A17AFB9B772FA8BB690F07C071E29AC08567CCF5B3F35D9635162415FC2B18C2E998E655B502A2FF41FF7B0CD05081D47959F0318D5832DF6FAE1C1D4ED2C62BB81FC2C52116860D42B7695313C5071CB0583BE0C491A4EBEF7C450F676286AAAD6EA316D2AAF5C5AE879775297517972C56F721BE28B0E7FB10CD1286B03B7A74090B24C2F9E3A4EF22B3CA51FDAFBB7024A1DBC4B5027B899FAF2750AEA340FB42A0773D0D5F87438C682621332D2C55DFC077C0D57D49994FDC70D0F65B08A4D8D461F6016FCAD6DEC4717DC42EDCE5CC75BF44A59AA849CBB8D4341F04D0868B4B129F9446D05C0CC3962C5B410686CBAD4703A102B6E9C2C70919A1178A796B5A7892C8154759AED4389942020B7D5DB75BF99F9401CEA7351CE9E86EAF813C9742F2F1F671C4BAA9037170D600F9AA56ED073CD3AE3D33B41D42FC9BB87974706D08631340ACD5C566AD377259C7F79A96D84FE63C4A3A7AB53577E1884E35DBFD568AA8846CACC188C5081397935227D74B75471F1C41A82B21C4A03F52F09F8404699E02B4499345092F97ECF8B074B572D9B9280228DA504A52C4892EC36C72B510CF4C1D57562BA6EB4F7BF134573EE9D7889DA4A1A7810B3317BC72DD6B76FDC13F2B37B2CBC5538020480432110A1B57FAD59CBDB0FADA8258DBB55612A756DF7BBBD6B2B551C2BC6EE1B6B671B6B07081B8680A3D9B41B50C1015DF74AB5369306A559AF0832B3B256103059D6D0A5194AFAEAA90D0D39A9D1E1F6EF053B270785B4288D7CCED85AC846F5A74CCD137EC5F75E0736DC0B5F3C59EF69B3C09630A5F8447B242D4398EF28899E293ED338286C1215FD8EBDD25ADDDAAD011E0B0763572D9B278BF5ECB6AA5D720D34CDAEF33414FCC0EE791DE874FEA81420273269D86C12B4CBD60FAE21356AD7AEAA486664D4A5E1D1784A936D5347D02E07A56DE0D8BCD67435CDA7A1E51552A120E72614EC4C3249F0ECBBD658A401501DA112162AA430A57EA5755547CC0F58AB5EBF9F6B23C7A71D8F1ADF5D446FD8C6FB4A1D785C33657C85D1BA2A4235CE0F16CD371C7D53DCFE0E4F2AD43910D92F1CB7CE7DF2AD88D1FFC8E05B9B896CCA80951C7B2F595110F39FCFF4821199963FFBC1C56B22CC3669312DA03B9F1F2FA5CB8A88BBFAB27B2DDBCB7D9075C2E5BBBDC5690DFF15F5648C59BEBF44DEFC726043D4074143EECC517F9CC15A3571A24FE41FB59414079167E74CD98266014F52725AD13641D7DE2268EEFA2C0E6EBBD6F772071D15213400EBDFCD710E1595AB7BCB90AB9861CACFD80C7591BE7F66D507CE3EE3B0C6CDEFA7329BEAAC5728C278B22D294820E970F2B015470F4CF9C438BDD764FD46475D01C61D30E619BC2250ED050A5AC3BC6EA918DD44EE47B92D7CBDC6D61892CADC9958234DEF6F2E9AF99D24B7FCA64F189B8BCB0EDFF5747508E0D0A656E6473747265616D0D0A656E646F626A0D0A352030206F626A0D0A3C3C2F547970652F466F6E742F537562747970652F54727565547970652F4E616D652F46312F42617365466F6E742F417269616C2C426F6C642F456E636F64696E672F57696E416E7369456E636F64696E672F466F6E7444657363726970746F722036203020522F4669727374436861722033322F4C61737443686172203131342F576964746873203130203020523E3E0D0A656E646F626A0D0A362030206F626A0D0A3C3C2F547970652F466F6E7444657363726970746F722F466F6E744E616D652F417269616C2C426F6C642F466C6167732033322F4974616C6963416E676C6520302F417363656E74203930352F44657363656E74202D3231302F436170486569676874203732382F4176675769647468203437392F4D6178576964746820323632382F466F6E74576569676874203730302F58486569676874203235302F4C656164696E672033332F5374656D562034372F466F6E7442426F785B202D363238202D3231302032303030203732385D203E3E0D0A656E646F626A0D0A372030206F626A0D0A3C3C2F547970652F466F6E742F537562747970652F54727565547970652F4E616D652F46322F42617365466F6E742F417269616C2F456E636F64696E672F57696E416E7369456E636F64696E672F466F6E7444657363726970746F722038203020522F4669727374436861722033322F4C61737443686172203132302F576964746873203131203020523E3E0D0A656E646F626A0D0A382030206F626A0D0A3C3C2F547970652F466F6E7444657363726970746F722F466F6E744E616D652F417269616C2F466C6167732033322F4974616C6963416E676C6520302F417363656E74203930352F44657363656E74202D3231302F436170486569676874203732382F4176675769647468203434312F4D6178576964746820323636352F466F6E74576569676874203430302F58486569676874203235302F4C656164696E672033332F5374656D562034342F466F6E7442426F785B202D363635202D3231302032303030203732385D203E3E0D0A656E646F626A0D0A392030206F626A0D0A3C3C2F417574686F72284D617263656C204D6172696E6F29202F43726561746F7228FEFF004D006900630072006F0073006F0066007400AE00200057006F007200640020003200300031003029202F4372656174696F6E4461746528443A32303136303730373039333831322D30342730302729202F4D6F644461746528443A32303136303730373039333831322D30342730302729202F50726F647563657228FEFF004D006900630072006F0073006F0066007400AE00200057006F007200640020003200300031003029203E3E0D0A656E646F626A0D0A31302030206F626A0D0A5B2032373820302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203020302030203833332030203020302030203020302030203020302030203020302030203020302030203020302030203535362030203535362030203535362030203020302032373820302030203237382030203631312036313120302030203338395D200D0A656E646F626A0D0A31312030206F626A0D0A5B20323738203020302030203020302030203020302030203020302032373820302032373820302030203020302030203020302030203020302030203020302030203020302030203020363637203020373232203732322036363720363131203020302032373820302030203535362038333320373232203020363637203737382030203636372030203732322036363720302030203020302030203020302030203020302035353620353536203530302035353620353536203237382035353620353536203232322030203020323232203833332035353620353536203535362035353620333333203530302032373820353536203530302030203530305D200D0A656E646F626A0D0A31322030206F626A0D0A3C3C2F547970652F585265662F53697A652031322F575B2031203420325D202F526F6F742031203020522F496E666F2039203020522F49445B3C33454531373636413535414137333435413738303236393235343731373330323E3C33454531373636413535414137333435413738303236393235343731373330323E5D202F46696C7465722F466C6174654465636F64652F4C656E6774682035353E3E0D0A73747265616D0D0A789C63600082FFFF1981A420030388F283506D608A31154CF17482295E5D30C52704A1368229FE89604AA0184C09BA3030000034DB067B0D0A656E6473747265616D0D0A656E646F626A0D0A787265660D0A302031330D0A3030303030303030303020363535333520660D0A30303030303030303137203030303030206E0D0A30303030303030303738203030303030206E0D0A30303030303030313334203030303030206E0D0A30303030303030333537203030303030206E0D0A30303030303033323039203030303030206E0D0A30303030303033333733203030303030206E0D0A30303030303033363032203030303030206E0D0A30303030303033373631203030303030206E0D0A30303030303033393835203030303030206E0D0A30303030303034323131203030303030206E0D0A30303030303034343230203030303030206E0D0A30303030303034363937203030303030206E0D0A747261696C65720D0A3C3C2F53697A652031332F526F6F742031203020522F496E666F2039203020522F49445B3C33454531373636413535414137333435413738303236393235343731373330323E3C33454531373636413535414137333435413738303236393235343731373330323E5D203E3E0D0A7374617274787265660D0A343935310D0A2525454F460D0A787265660D0A3020300D0A747261696C65720D0A3C3C2F53697A652031332F526F6F742031203020522F496E666F2039203020522F49445B3C33454531373636413535414137333435413738303236393235343731373330323E3C33454531373636413535414137333435413738303236393235343731373330323E5D202F5072657620343935312F5852656653746D20343639373E3E0D0A7374617274787265660D0A353336360D0A2525454F46
I've gotten to the point where I can display a PDF with the right number of pages, but each of those pages are completely blank. Any help would be greatly appreciated. The database says that the datatype is "application/pdf;filename="DocName.pdf";frevvo-attachment=true; charset=utf-8" and the conversion can be on Java or Javascript.
Update:
So I am able to get this to work thanks to the help of Mark, but there are some exceptions. On some I get the following error:
Exception in thread "main" java.lang.StringIndexOutOfBoundsException: String index out of range: 43677
at java.lang.String.charAt(String.java:658)
at pdftestapp.PDFTestApp.hexStringToByteArray(PDFTestApp.java:40)
at pdftestapp.PDFTestApp.main(PDFTestApp.java:31)
Here is my code:
package pdftestapp;
import java.io.*;
import java.util.Base64;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
import java.nio.file.Files;
import java.nio.file.Paths;
/**
*
* #author mmarino
*/
public class PDFTestApp {
/**
* #param args the command line arguments
*/
public static void main(String args[]) throws Exception{
String str = "0x255044462D312E350..."; //data omitted
str = str.substring(2)
byte[] arr = hexStringToByteArray(str1);
Files.write(Paths.get("test.pdf"), arr);
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}
To test it:
If you got the String representation use something like this:
import java.nio.file.Files;
import java.nio.file.Paths;
public class Main {
public static void main(String args[]) throws Exception{
String str = "255[...]0A2525454F46"; //0x removed, omitted data
byte[] arr = hexStringToByteArray(str);
Files.write(Paths.get("test.pdf"), arr);
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}
Your pdf file will be able to read:
If your pdf is in a byte array you could write it directly to file.
To do it:
If the question is how to display it to an user with a browser you should do something simmilar:
#WebServlet("/foo.pdf")
public class PdfServlet extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
byte[] file = getsomehow();
response.setHeader("Content-Type", "Your staffs content type");
response.setHeader("Content-Length", file.length);
response.setHeader("Content-Disposition", "inline; filename=\"something.pdf\"");
response.getOutputStream().write(file);
response.getOutputStream().close();
}
}
Related
I have a StringBuilder (~1GB size) which converts to an almost 1GB String. Then it is sent to AWSS3Client to be put as a file on s3. Now to write the String to s3, I need to further convert the string to a ByteArrayInputStream, which takes another 1GB.
InputStream dataInputStream = new ByteArrayInputStream(data.getBytes(StandardCharsets.UTF_8));
amazonS3Client.putObject(bucket, key, dataInputStream, new ObjectMetadata());
Now I end up with a JVM heap of 3GB. Is there a way to directly send the 1GB StringBuilder directly to S3 with little over 1GB heap?
The only way I could think of is to convert StringBuilder to a File instance (using FileWriter) --> S3 API which takes File as input. But this approach requires a 2-IOPS to the SSD -- penalty that I want to avoid.
Any better way to handle the problem is welcome.
[edit 1]
(as per comments) The builder size changed from 5GB to 1GB. I wanted to convey that the builderis a huge one (and hence used 5GB previously, which was my mistake)
The string-oriented classes are frustratingly locked down with final in many cases, which means that oftentimes buffers that already exist in memory have to be duplicated. This is probably to do with security but is nevertheless wasteful and frustrating. You should be able to do something with the following if you have a StringBuilder. Obviously you'll need a much bigger buffer than in the illustrative main method.
import java.io.ByteArrayInputStream;
import java.io.FilterInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.FileOutputStream;
import java.nio.ByteBuffer;
import java.nio.CharBuffer;
import java.nio.charset.CharsetEncoder;
import java.nio.charset.Charset;
import java.util.Objects;
/**
*
* #author CEHJ
* #version 1.0
*/
public class CharSequenceInputStream extends InputStream {
private CharSequence charSequence;
private int position;
private CharsetEncoder enc;
private Charset outputEncoding;
private CharBuffer cb;
private ByteBuffer bb;
public CharSequenceInputStream(CharSequence charSequence) {
this(charSequence, Charset.forName(System.getProperty("native.encoding", Charset.defaultCharset().name())));
}
public CharSequenceInputStream(CharSequence charSequence, Charset outputEncoding) {
this.charSequence = charSequence;
this.outputEncoding = outputEncoding;
position = 0;
enc = outputEncoding.newEncoder();
cb = CharBuffer.allocate(1);
bb = ByteBuffer.allocate(8);
}
// For testing only
public static void main(String[] args) throws IOException {
if (args.length < 2) {
System.err.printf("Usage: java CharSequenceInputStream <String to be stored> <Output file> [Char encoding for output]");
System.exit(1);
}
String content = args[0];
String outputPath = args[1];
StringBuilder sb = new StringBuilder(content);
CharSequenceInputStream in = null;
if (args.length > 2) {
in = new CharSequenceInputStream(sb, Charset.forName(args[2]));
} else {
in = new CharSequenceInputStream(sb);
}
try (OutputStream out = new FileOutputStream(outputPath)) {
int bytesRead = -1;
final int BUF_SIZE = 8;
byte[] buf = new byte[BUF_SIZE];
while ((bytesRead = in.read(buf, 0, BUF_SIZE)) > -1) {
out.write(buf, 0, bytesRead);
}
}
}
#Override
public int read() throws IOException {
int result = -1;
if (position < charSequence.length()) {
if (bb.remaining() == bb.capacity() || bb.position() == bb.limit()) {
// At start - nothing yet has been decoded
// OR - we've read all bytes in the buffer and need to refill it
cb.clear();
bb.clear();
char currentChar = charSequence.charAt(position++);
cb.append(currentChar);
cb.flip();
enc.reset();
enc.encode(cb, bb, false);
enc.encode(cb, bb, true);
enc.flush(bb);
bb.flip();
}
}
if (bb.position() < bb.limit()) {
result = bb.get() & 0xFF;
}
return result;
}
#Override
public int read(byte[] b) throws IOException {
return read(b, 0, b.length);
}
#Override
public int read(byte b[], int off, int len) throws IOException {
Objects.checkFromIndexSize(off, len, b.length);
if (len == 0) {
return 0;
}
int c = read();
if (c == -1) {
return -1;
}
b[off] = (byte) c;
int i = 1;
try {
for (; i < len; i++) {
c = read();
if (c == -1) {
break;
}
b[off + i] = (byte) c;
}
} catch (IOException ee) {
}
return i;
}
#Override
public void close() {
// NO OP
}
}
I'm trying to repeat in .NET the algorithm that was originally written in Java and I'm having troubles with the GZIP decompression.
At the bottom of the post I inserted the hex string that is converted to byte array in both .NET and Java. The resulting byte array is then decompressed in Java with the following method:
public static Object readObjectFromByte(byte[] bytes)
{
ObjectInputStream oos = null;
try {
ByteArrayInputStream baos = new ByteArrayInputStream(bytes);
zis = new GZIPInputStream(baos);
oos = new ObjectInputStream(zis);
return oos.readObject();
} catch (Throwable t) { GZIPInputStream zis;
return null;
} finally {
try {
if (oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
After decompression the resulting byte array has a length of 3952 which is probably correct. At the same time I tried different .NET classes/libs to decompress, but it always gives a byte array of 3979 bytes which is probably incorrect.
I tried:
GZipStream
DotNetZip
SevenZipLib
SharpZipLib
I read a lot of articles about GZIP issues in .NET trying to fix this. I use .NET 4.5, and for example my last decompression version is this:
Ionic.Zlib.GZipStream.UncompressBuffer(compressedBytes)
It's weird but even if I try:
Ionic.Zlib.GZipStream.CompressBuffer(Ionic.Zlib.GZipStream.UncompressBuffer(compressedBytes)).SequenceEquals(compressedBytes)
It gives me FALSE.
The hex string:
EDIT:
Java Code:
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;
public class JavaFiddle
{
public static void main(String[] args)
{
String hex = "PLEASE_UPDATE"; //update this from the hex constant at the end of the post
byte[] compressedBytes = hexStringToByteArray(hex);
byte[] decompressedBytes = (byte[])readObjectFromByte(compressedBytes);
System.out.println(decompressedBytes.length); //THIS GIVES 3952
}
public static byte[] hexStringToByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
public static Object readObjectFromByte(byte[] bytes)
{
ObjectInputStream oos = null;
try {
ByteArrayInputStream baos = new ByteArrayInputStream(bytes);
GZIPInputStream zis = new GZIPInputStream(baos);
oos = new ObjectInputStream(zis);
return oos.readObject();
} catch (Throwable t) { GZIPInputStream zis;
return null;
} finally {
try {
if (oos != null) {
oos.close();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
.NET Code
private byte[] StringToByteArray(string hex)
{
int NumberChars = hex.Length;
byte[] bytes = new byte[NumberChars / 2];
for (int i = 0; i < NumberChars; i += 2)
bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16);
return bytes;
}
...
var hex = "PLEASE_UPDATE"; //update this from the hex constant at the end of the post
var compressedBytes = StringToByteArray(hex);
var decompressedBytes = Ionic.Zlib.GZipStream.UncompressBuffer(compressedBytes);
//decompressedBytes.Length is 3979, Note that this is using one of the external libraries, the same result is for built-in GZipStream in .NET
1F8B0800000000000000ADCEF923130A0000E0596C8A1CB90AA1D0E428916C4AE6889C61071E1D2A77B42C67D1731BF2DE6C662C5744C6DE7BC8DC4791DCB79E35315EC2C62437E1FDBE9FF7FD055FC53240282418007437AB5893DB060923594000201C030088639882D19C31C860FB7838A60DBBF039C3B41821FF606044C89D24EB4C1D6A627FBF8E978D3616796C2ACDD165ABB32B81A0C493A35F163889E74665A9341C7C36F06FA0F991201BEAAB6A47842C43A50DA6B8C000AD794840CF03E29A527D0C921FAE6D607C71AEF7C01DB34037A7F8CDD8CB1F61DB9C15A87DBBDD1F933FDF58312B054D7B5AF72FE75A0AA101714EEA6980BF405A15A1F13A0979FB5BBE1636A367CB4C943FB7F87A3245573BB6857DA6AA0B412CCB553B39E06973EB2A3864E98915E46C16E4EE06E9DA63DB642915AF6E86811FD2C8F3A1F325C82677EA701D1E3574885696DEB3B8A0C29AE1FDD41DA26C55C6381506A3CF77DD15BD37783F545F76E8DCF9FB6A8B0776E2427FBFF431B73748CE96786EA569E307B5DC8990A68A52838D9DC1BA19291F283BF2C7EE43D3E4516D77A07FDE04934BB7C254057BDFC3AD153A0A711E7EFDDDED31AED367FAAEA6F494A55E029BF6AECA9433CA7D45B52EC24BCF9074315BFE5F5494F4F0DDDE8D73F56397A0667992950E62AD4020A4102DBE7C4D6B85E457F184DC5AA51D2D536313E1E16636928BD6500207571B83C8830DB9E7CF2C92AE4DDB12B8DF3C6AAF83B09CAACB78AA78CDB0DB393D71A599F185B413BFDB907FC99598D2E56ADE701EE72DB71C9650E820DB452F7DD4904E4679FFD0CB6FEEDF7527AF21BE5A5404B8BAE4E9951AE5C88BF9B5D5FFC6447989445C7A2DB80B3E4A2DBCB51978BA1729F97BDCAD174D345417B96941BF2CC5C10539C952B2526770BA4637A5820DCF150E16AED3159AD9724A8DFCFEA8BADA2A08BD1A0C9B05B019CE61E01EDECF7F028B466E4B53A5F1FAE56CB137EF269E1946896D1A3DDCDB756364A96D8E47F3FB33E9B70BBED37FA8719F2D2EA89BBFB0CAFB71CC56947F7907439E9FE97C61D2A326F830592509674860BA7CC7E713EFD69D2724DED740A2959846CFE801B313BB1DAB45594D70E888F2A3063C67085BFDB345D64D116372F5BE42BB08ABBC6D65D90E1E50C849EDD9A6F977751C4DB5A454C66B997D6A0CA148827E03AEE30F1697392124A8C44C6A914C3C69C21447F9C5660665C5D0D3F758D57086D0938608E9BECE9BA95D359C41E255B0524C55EDC97816A76E32B29BF55BAE0EC1F71DBF3FF548DC2C181755D85ABCAFEDF23C248EF7D3C1580AB88D28CDCF9935F1DA797145A7F0B18603C1DA39EA8E969A2279F20F077E7F62BD5C1F7C095BF1B21D36561A254836F37EBC0AEB8C8EAE8EC725044EE47F107DE413DE804EED41473E4D3BEC93E9234255F9FDD1FD91F00B32BF13B2629C4373888813E5FD08F66AB7295D281E180ACE99A77952DE6DCD675B20E021A71E91F78B899A1FC2F8FD913C0E4D980B1D6CF13F7A76E823BDF75FDE8FC513C3C491F51305F1A483B81A11884254CB2DB396F864B08DDEDD005A90EF457E7F8EDFB64FF7C7443C6E2135183619ED69F27E1464BF862FB14A66509C379818517F6B2423D0D1BE794E4D9C7130D9F54AB19DDF9FC825CF8B3B5EBD8090811D372C0315CEFBB926701AC2B84CB4820D25DD2D71F2F6630FB3FA88A3EAAF9E44C709EFACC05FF2FBD342E844AB8A22F433B7C2161FEDE70BF07EF29A6B6355DAF2D33E7A2679C8A38511939EEE73DABDE98B021A9F0E21A5CFFEE6F7A7C44CE2358158F5B15F837CE96B75622FEFE702653D87222B9319D46D321EEDA628713D1B355A30E0D07A655F12A55B6397CFEFCFA3DB3B76DB80347FDCA613FD1F3F6022EF276A1666DDA3BE518CB634F67B185BD2016DB2DC20E56C1C9B58CD411710E802FCFED0E3E1E182C37A9684A007EF0DEBBBCB783F37A0D39E2B6FAB147A3BCD75B1C24FA5939BDD9501D5E0365A60E58BE429C821BF3F774DC4603D43CE355412CC3DBF47639DF7B33CFEF4138133255770F2659E44F2FC9EE285FCDCEC414B473CCB31BA39BA798CDF1FF28A3EBD7549341C8E809E8AABF836C7FB59DB4025ED1DC5BF1874EDF4511ECCC397050C8C3F404FB04BF52DF4F35411EBFCFEFCB70C2AF6EE8AFC32A539F624F0E30D47DE8F9138B0C9B24F03F5CD53E05CA77D63CAA8800CA567E4D60D8D4ECBA9F9FE3C75FADED32267AB07ED635AD14CB6A87B1F8D5B5BD43F7C04E14DB30935A6B6CA780F2FBD10CD2EAE8DD13D6C9FA89334A8ADEAC40D63C54B6E881F9F382D3056BF7DACFFC6914A6DF60F64E7C5FE8EB222FD71632318CDC5E3CF8EC48602D238E95FC06C9BDBBD3D85535DED236D1FFA4EB1F3939B334A222BBF7FE034EB1599A7E20DFF89F92E9B3EE0D45FA7103A9B8BE6F727EC6D338C464AAA1B6B8AF426BA2153793FF7C43EEE7A43E6038296B83E130BAA9D467DB7A9B8E29E18B8F4E4493DB3E1BE4CDC1ABA3074A8D69058420FB2F56BCCD3CAB0806FA9C1E825D6F18644CD9137AB9195DD63A8BD3BA9F5C9BF0AEC9F5B6E605B2C02CAA93FB10A5F03ADD7370A981F3A99F0F3CC2DA93C298292E9859C01BBB088FE6CD979FC5A02127305D63C72B319EDD48A0EE6BE431C17B3F8E4FFDAC1F5D9A9F4EB7443EE2D3CAD6A3508A918C48DBB7F89081B7087C94A60F9FD297839305DA999BE163F234E3ED7D8D8CDFBA16AE5327F3E9D5925DF533EF5FEA2F26D3784CFB578877E15799DB73DAEC8D767F9FD81597235251D2DC413C2E1F58887AF75783F8248EC923F57F93D81A88D9E3E1E045997FD3C40B1BF83CEFC9CC2CCC079197928232333623BE67DA6A70B4818095DEEC23ABEC73E4DC9E1A74E04AEC1D420EB533CF3C06C242E1612F85A560A2861A0E54C218AC1834FCCDBD2F61FBC3B32983F25B29F5967A7219C74A10C769002C1869E9DC926A99C9D1AC92CC8BC3A5D151D405693BA0DBE292D94F40B918AFCEE6851DFC215B3738975F1EFAA32923037D96656C2D2B94B015CD1DA5F43D0A8FFA063099BA0BFB246724C8E61150FB2126EDE245963F4454EBCFF5105BDA267D598E2D1E9985136AF4348D8FCF96F355B27AE6E6F5378415D8A8D1CAD3EC3426969BF5790DBA0C01EF9B7E86095D9313F74309E01C7BA00B9B0E85DA89900D6F89DEA5BCA9273C017B56139F9CF13E7DB74724240262CBDFCEC05FB5DDAA64CB98257C9AAF7AA48AAD36577B3D6F11CD0A074D5B15860B2791E8E8B87AB2A5B2419F61561E6ECF56746E2185EBFFF0F96F821B38B0F0000
Thanks,
Now we've got more of the Java code, we can see the problem: you've got an extra layer of serialization around your real data. That has nothing to do with compression really.
Here's an example to show what I mean:
import java.io.*;
public class Test {
public static void main(String[] args) throws Exception {
try (ByteArrayOutputStream output = new ByteArrayOutputStream()) {
try (ObjectOutputStream oos = new ObjectOutputStream(output)) {
oos.writeObject(new byte[5]);
}
byte[] data = output.toByteArray();
System.out.println(data.length);
}
}
}
That's writing a byte array that's 10 bytes long - but the result is 32 bytes long, because of the extra "wrapper" information. Note that the extra 27 bytes is the same as the discrepancy you've seen.
Fundamentally, it's odd to wrap a byte array in this way, and if you can possibly change the original code, that would be for the best. If you absolutely can't do that, it may be safe to just ignore the first 27 bytes of the resulting data.
Am passing JSON Input String which needs to convert as hashvalue by using SHA1 with Base64 Encoder Format..
Like below i have tried,
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import org.apache.commons.codec.binary.Base64;
import org.json.JSONObject;
import java.util.Base64.Encoder;;
public class HashTextTest {
public static void main(String[] args) throws NoSuchAlgorithmException {
System.out.println(sha1(""));
}
static String sha1(String input) throws NoSuchAlgorithmException {
MessageDigest mDigest = MessageDigest.getInstance("SHA1");
byte[] result = mDigest.digest(input.getBytes());
StringBuffer sb = new StringBuffer();
for (int i = 0; i < result.length; i++) {
sb.append(Integer.toString((result[i] & 0xff) + 0x100, 16).substring(1));
}
return sb.toString();
}
}
But Above code Takes only string input, here am not able to pass JSON String, and its return Hashvalue perfectly but i need that hashvalue in Base64Encoder Format..
help me
I've the following test code. I'd like to know how I can put, and get a String using a Java NIO ByteBuffer.
I've added two comments where I need help.
package testPipe;
import java.io.UnsupportedEncodingException;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;
import java.nio.charset.CharsetDecoder;
import java.nio.charset.CharsetEncoder;
public class TestMemBuff {
static final String dataFile = "invoicedata";
static final double[] prices = { 19.99, 9.99, 15.99, 3.99, 4.99 };
static final int[] units = { 12, 8, 13, 29, 50 };
static final String[] descs = { "Java T-shirt", "Java Mug",
"Duke Juggling Dolls", "Java Pin", "Java Key Chain" };
public static Charset charset = Charset.forName("UTF-8");
public static CharsetEncoder encoder = charset.newEncoder();
public static CharsetDecoder decoder = charset.newDecoder();
public static void main(String[] args) throws UnsupportedEncodingException {
double price;
int unit;
String desc;
double total = 0.0;
ByteBuffer buf = ByteBuffer.allocate(1024);
for (int i = 0; i < prices.length; i++) {
buf.putDouble(prices[i]);
buf.putInt(units[i]);
buf.asCharBuffer().put(descs[i]); // Is it correct?
}
buf.flip();
// INPUT
while (buf.hasRemaining()) {
price = buf.getDouble();
unit = buf.getInt();
desc = buf.asCharBuffer().toString(); //This must be wrong!
System.out.format("You ordered %d" + " units of %s at $%.2f%n",
unit, desc, price);
total += unit * price;
}
}
}
This is the output when I execute it:
You ordered 12 units of ????
[...]
and so on.
Thanks for your attention
Writing part:
for (int i = 0; i < prices.length; i++) {
buf.putDouble(prices[i]);
buf.putInt(units[i]);
byte[] descsBytes = descs[i].getBytes();
buf.putInt(descsBytes.length);
buf.put(descsBytes);
}
Reading part:
while (buf.hasRemaining()) {
price = buf.getDouble();
unit = buf.getInt();
int len = buf.getInt();
byte[] bytes = new byte[len];
buf.get(bytes);
desc = new String(bytes);
System.out.format("You ordered %d" + " units of %s at $%.2f%n",
unit, desc, price);
total += unit * price;
}
ByteBuffer.asCharBuffer() has a somewhat own behaviour. It creates a new buffer that shares the content with the ByteBuffer but has an own, independent position & limit.
So put() and get() on the CharBuffer do not change the position on the ByteBuffer!
So I would refrain from using ByteBuffer.asCharBuffer() at all as long as this is not exactly what you need.
So the solution would be to write and read the bytes into the original ByteBuffer:
buf.putInt(descs[i].length);
buf.put(descs[i].getBytes());`
To read the string again read the length and allocate the byte[] yourself:
int stringLength = buf.getInt();
byte[] bytes = new byte[stringLength];
buf.get(bytes);
desc = new String(bytes);
I have my own little serialiser class
package mypackage.shared;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class Serializer {
static final String HEXES = "0123456789ABCDEF";
public static String serialize(Object o) throws IOException {
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(stream);
os.writeObject(o);
os.close();
return toHex(stream.toByteArray());
}
public static Object deserialize(String hexString) throws IOException, ClassNotFoundException {
byte[] serializedBytes = toByteArray(hexString);
ByteArrayInputStream bis = new ByteArrayInputStream(serializedBytes);
ObjectInputStream ois = new ObjectInputStream(bis);
Object o = null;
o = ois.readObject();
ois.close();
return o;
}
public static String toHex( byte [] raw ) {
if ( raw == null ) {
return null;
}
final StringBuilder hex = new StringBuilder( 2 * raw.length );
for ( final byte b : raw ) {
hex.append(HEXES.charAt((b & 0xF0) >> 4))
.append(HEXES.charAt((b & 0x0F)));
}
return hex.toString();
}
private static byte[] toByteArray(String s) {
int len = s.length();
byte[] data = new byte[len / 2];
for (int i = 0; i < len; i += 2) {
data[i / 2] = (byte) ((Character.digit(s.charAt(i), 16) << 4)
+ Character.digit(s.charAt(i+1), 16));
}
return data;
}
}
It works great for some home made objects I have. However, as soon as I have an ArrayList of these objects it fails to deserialize them. ANy idea why that would be? I find it quite hard to debug since readObject() just fails
If serialization doesn't work it means that some object is not serializable.
Try to deserialize an arraylist containing only one home object and do it for all home objects