org.apache.pdfbox.util.Hex Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of pdfbox Show documentation
Show all versions of pdfbox Show documentation
The Apache PDFBox library is an open source Java tool for working with PDF documents.
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.pdfbox.util;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* Utility functions for hex encoding.
*
* @author John Hewson
*/
public final class Hex
{
private static final Log LOG = LogFactory.getLog(Hex.class);
/**
* for hex conversion.
*
* https://stackoverflow.com/questions/2817752/java-code-to-convert-byte-to-hexadecimal
*
*/
private static final byte[] HEX_BYTES = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
private static final char[] HEX_CHARS = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
private Hex() {}
/**
* Returns a hex string of the given byte.
*/
public static String getString(byte b)
{
char[] chars = new char[]{HEX_CHARS[getHighNibble(b)], HEX_CHARS[getLowNibble(b)]};
return new String(chars);
}
/**
* Returns a hex string of the given byte array.
*/
public static String getString(byte[] bytes)
{
StringBuilder string = new StringBuilder(bytes.length * 2);
for (byte b : bytes)
{
string.append(HEX_CHARS[getHighNibble(b)]).append(HEX_CHARS[getLowNibble(b)]);
}
return string.toString();
}
/**
* Returns the bytes corresponding to the ASCII hex encoding of the given byte.
*/
public static byte[] getBytes(byte b)
{
return new byte[]{HEX_BYTES[getHighNibble(b)], HEX_BYTES[getLowNibble(b)]};
}
/**
* Returns the bytes corresponding to the ASCII hex encoding of the given bytes.
*/
public static byte[] getBytes(byte[] bytes)
{
byte[] asciiBytes = new byte[bytes.length*2];
for(int i=0; i< bytes.length; i++)
{
asciiBytes[i*2] = HEX_BYTES[getHighNibble(bytes[i])];
asciiBytes[i*2+1] = HEX_BYTES[getLowNibble(bytes[i])];
}
return asciiBytes;
}
/**
* Returns the characters corresponding to the ASCII hex encoding of the given short.
*/
public static char[] getChars(short num)
{
char[] hex = new char[4];
hex[0] = HEX_CHARS[(num >> 12) & 0x0F];
hex[1] = HEX_CHARS[(num >> 8) & 0x0F];
hex[2] = HEX_CHARS[(num >> 4) & 0x0F];
hex[3] = HEX_CHARS[num & 0x0F];
return hex;
}
/**
* Takes the characters in the given string, convert it to bytes in UTF16-BE format
* and build a char array that corresponds to the ASCII hex encoding of the resulting
* bytes.
*
* Example:
*
* getCharsUTF16BE("ab") == new char[]{'0','0','6','1','0','0','6','2'}
*
*
* @param text The string to convert
* @return The string converted to hex
*/
public static char[] getCharsUTF16BE(String text)
{
// Note that the internal representation of string in Java is already UTF-16. Therefore
// we do not need to use an encoder to convert the string to its byte representation.
char[] hex = new char[text.length()*4];
for (int stringIdx = 0, charIdx = 0; stringIdx < text.length(); stringIdx++)
{
char c = text.charAt(stringIdx);
hex[charIdx++] = HEX_CHARS[(c >> 12) & 0x0F];
hex[charIdx++] = HEX_CHARS[(c >> 8) & 0x0F];
hex[charIdx++] = HEX_CHARS[(c >> 4) & 0x0F];
hex[charIdx++] = HEX_CHARS[c & 0x0F];
}
return hex;
}
/**
* Writes the given byte as hex value to the given output stream.
* @param b the byte to be written
* @param output the output stream to be written to
* @throws IOException exception if anything went wrong
*/
public static void writeHexByte(byte b, OutputStream output) throws IOException
{
output.write(HEX_BYTES[getHighNibble(b)]);
output.write(HEX_BYTES[getLowNibble(b)]);
}
/**
* Writes the given byte array as hex value to the given output stream.
* @param bytes the byte array to be written
* @param output the output stream to be written to
* @throws IOException exception if anything went wrong
*/
public static void writeHexBytes(byte[] bytes, OutputStream output) throws IOException
{
for (byte b : bytes)
{
writeHexByte(b, output);
}
}
/**
* Get the high nibble of the given byte.
*
* @param b the given byte
* @return the high nibble
*/
private static int getHighNibble(byte b)
{
return (b & 0xF0) >> 4;
}
/**
* Get the low nibble of the given byte.
*
* @param b the given byte
* @return the low nibble
*/
private static int getLowNibble(byte b)
{
return b & 0x0F;
}
/**
* Decode a base64 String.
*
* @param base64Value a base64 encoded String.
*
* @return the decoded String as a byte array.
*
* @throws IllegalArgumentException if this isn't a base64 encoded string.
*/
public static byte[] decodeBase64(String base64Value)
{
// https://stackoverflow.com/questions/469695/decode-base64-data-in-java
try
{
// jdk8 and higher? java.util.Base64.getDecoder().decode()
Class b64Class = Class.forName("java.util.Base64");
Method getDecoderMethod = b64Class.getMethod("getDecoder");
Object base64Decoder = getDecoderMethod.invoke(b64Class);
Method decodeMethod = base64Decoder.getClass().getMethod("decode", String.class);
return (byte[]) decodeMethod.invoke(base64Decoder, base64Value.replaceAll("\\s", ""));
}
catch (ClassNotFoundException ex)
{
LOG.debug(ex);
}
catch (IllegalAccessException ex)
{
LOG.debug(ex);
}
catch (IllegalArgumentException ex)
{
LOG.debug(ex);
}
catch (NoSuchMethodException ex)
{
LOG.debug(ex);
}
catch (SecurityException ex)
{
LOG.debug(ex);
}
catch (InvocationTargetException ex)
{
LOG.debug(ex);
}
try
{
// up to java7? javax.xml.bind.DatatypeConverter.parseBase64Binary()
Class datatypeConverterClass = Class.forName("javax.xml.bind.DatatypeConverter");
Method parseBase64BinaryMethod = datatypeConverterClass.getMethod("parseBase64Binary", String.class);
return (byte[]) parseBase64BinaryMethod.invoke(null, base64Value);
}
catch (ClassNotFoundException ex)
{
LOG.debug(ex);
}
catch (IllegalAccessException ex)
{
LOG.debug(ex);
}
catch (IllegalArgumentException ex)
{
LOG.debug(ex);
}
catch (NoSuchMethodException ex)
{
LOG.debug(ex);
}
catch (SecurityException ex)
{
LOG.debug(ex);
}
catch (InvocationTargetException ex)
{
LOG.debug(ex);
}
LOG.error("Can't decode base64 value, try adding javax.xml.bind:jaxb-api to your build");
return new byte[0];
}
/**
* Decodes a hex String into a byte array.
*
* @param s A String with ASCII hex.
* @return decoded byte array.
* @throws IOException
*/
public static byte[] decodeHex(String s) throws IOException
{
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int i = 0;
while (i < s.length() - 1)
{
if (s.charAt(i) == '\n' || s.charAt(i) == '\r')
{
++i;
}
else
{
String hexByte = s.substring(i, i + 2);
try
{
baos.write(Integer.parseInt(hexByte, 16)); // Byte.parseByte won't work with "9C"
}
catch (NumberFormatException ex)
{
LOG.error("Can't parse " + hexByte + ", aborting decode", ex);
break;
}
i += 2;
}
}
return baos.toByteArray();
}
}