Translate

domingo, 8 de setembro de 2013

Converter Java para C++

Durante uma pesquisa corriqueira sobre JVMs, me deparei "acidentalmente" com um conversor de códigos em Java para código em C++ bastante interessante chamado J2C.

O J2C segundo o seu site garante a conversão na maior parte das vezes, certamente, códigos complexos como algorítimos utilizadores de ServerSocketChannel, SocketChannel e outras APIs sofisticadas do Java podem não ser de tanta confiança converter somente sem avaliar o comportamento do código em sua versão C++, mas para algorítimos corriqueiros, a conversão é certa e excelente.

Importante: O Java tem a garbage colletor (gc) e faça uma conversão consciente porque não existe coleta automática de objetos em C++.

O IDE dele é o Eclipse, portanto você deve possuir uma versão recente e compatível com JDK6.

O site do projeto J2C está em https://code.google.com/a/eclipselabs.org/p/j2c/.

A partir dele, você deve:

  1. baixar o JAR mais recente do J2C;
  2. após baixar o JAR, copie-o para a pasta $ECLISE_HOME$\dropins;
  3. abra o Eclipse (no meu caso testei no Windows 7 com o Eclipse Juno);
  4. clique sobre algum projeto Java na janela "Package Explorer";
  5. você deve ver uma opção chamada "Translate to C++".

Esta ferramenta exige como você criar um pasta vazia de mesmo nome do seu projeto precedido pela letra "c". Exemplo: Se você tem um projeto chamado "OlaMundo", então deve ter uma pasta paralela e vazia chamada "cOlaMundo".

A classe Java 6 a seguir é simplesmente feita para ser convertida.

HelloWorld em Java 6 antes da conversão

public class HelloWorld {

public static void main(String[] args) {

System.out.println("Olá mundo!");

}

}

HelloWorld em versão C++ após conversão

// Generated from /UmProjetoJava6/src/HelloWorld.java
#include <HelloWorld.hpp>

#include <java/io/PrintStream.hpp>
#include <java/lang/NullPointerException.hpp>
#include <java/lang/String.hpp>
#include <java/lang/System.hpp>

template<typename ComponentType, typename... Bases> struct SubArray;
namespace java
{
    namespace io
    {
typedef ::SubArray< ::java::io::Serializable, ::java::lang::ObjectArray > SerializableArray;
    } // io

    namespace lang
    {
typedef ::SubArray< ::java::lang::CharSequence, ObjectArray > CharSequenceArray;
typedef ::SubArray< ::java::lang::Comparable, ObjectArray > ComparableArray;
typedef ::SubArray< ::java::lang::String, ObjectArray, ::java::io::SerializableArray, ComparableArray, CharSequenceArray > StringArray;
    } // lang
} // java

template<typename T>
static T* npc(T* t)
{
    if(!t) throw new ::java::lang::NullPointerException();
    return t;
}

HelloWorld::HelloWorld(const ::default_init_tag&)
    : super(*static_cast< ::default_init_tag* >(0))
{
    clinit();
}

HelloWorld::HelloWorld()
    : HelloWorld(*static_cast< ::default_init_tag* >(0))
{
    ctor();
}

void HelloWorld::main(::java::lang::StringArray* args)
{
    clinit();
    npc(::java::lang::System::out())->println(u"Olá mundo!"_j);
}

extern java::lang::Class *class_(const char16_t *c, int n);

java::lang::Class* HelloWorld::class_()
{
    static ::java::lang::Class* c = ::class_(u"HelloWorld", 10);
    return c;
}

java::lang::Class* HelloWorld::getClass0()
{
    return class_();
}

É importante deixar claro que apenas mostrei a versão CPP da conversão, mas a ferramenta J2C gera outras classes e protótipos, subpastas para garantir a conversão. Depois basta ter um compilador de sua necessidade do código em C++ para uma plataforma de sua necessidade.

Para maiores informações, consulte a página oficial do projeto.

Espero ter algum oportunidade para utilizá-la em breve.

quinta-feira, 5 de setembro de 2013

Java - Como obter o id do computador em Windows e Linux Ubuntu

Alguns aplicativos dos tipos desktop, serviço ou licenciadores baseados em processamento fortemente identificado sempre requerem do programador desafios novos para pegar a identidade física do computador.

Quando surge o problema de pegar uma identidade sempre vem a cabeça do programador mais experiente as seguintes perguntas seguidas por mais perguntas:

1) Se eu pegar o macaddress da placa de rede?
2) Mas se a placa de rede queimar ou for trocada de posição?
3) Posso obter o número mais seguro?
4) Será este número o código de série da CPU porque o FCC cuida para não haver repetição de serial, ok?
5) Mas a máquina pode ser virtual e copiada, o macaddress e código da CPU podem ser clonados e assim o FCC perder controle?
6) Talvez o nome da máquina possar ser menos sujeito a alteração e se tiver clone, não vai funcionar na mesma rede, mas será que numa mudança de política de infra-estrutura não vão mudar o nome da máquina legalmente?
7) Como faço para saber se a máquina é virtual?

Não existe uma fórmula mágica para impedir as alterações das identidades de uma máquina, até de seu processador porque pode ser trocado.

Em caso de máquinas virtuais o problema é agravado mais ainda porque elas podem ser clonadas e funcionarem com identidades idênticas em redes (LAN) diferentes.

Por causa disso a única forma segura de garantir uma identidade única é resolvida através de tags ou tokens em forma de hardware para imprimir uma identidade imutável, no entanto, este método pode ser bastante caro e ainda reduzir bastante a atratividade de seu aplicativo num cenário mundial onde as pessoas buscam fazer as coisas no menor tempo, da forma mais simples e mais barata.

Mas não se desespere, para a maior parte dos casos, obter a identidade na primeira execução do software e persistir em um arquivo, registro do sistema operacional ou banco de dados de maneira ofuscada já é o suficiente para congelar e tornar imutável o conjunto de identidades da máquina. Esta técnica pode ser chamada de congelar ou tirar um snapshot dos identificadores da máquina para não sofrerem uma crise caso uma identidade utilizada para validação de sua aplicação seja legalmente mudada por razões diversas.

A classe a seguir se chama ComputerInfo e possui métodos para obter o número de série da CPU, endereço IP do computador, nome do computador, macaddress do primeiro adaptador de rede e se é um adaptador virtual. Não é objetivo discutir a utilização desta classe porque isso vai variar da necessidade de solução de cada um.

A classe ComputerInfo

Crie um arquivo classe chamado ComputerInfo.java:

import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.InputStreamReader;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.net.SocketException;
import java.net.UnknownHostException;
import java.util.Collections;
import java.util.StringTokenizer;

public class ComputerInfo {

public static final String NO_CPU_ID = "XXXXXXXXXX";

private static ComputerInfo ci = null;

private String cpuSerial;
private String hostName;
private String macAddress;
private String hostAddress;
private boolean virtualAdapter;


private ComputerInfo() {

try {

NetworkInterface netInter = null;

if (OS.OS == OS.WINDOWS) {
InetAddress localHost = InetAddress.getLocalHost();
netInter = NetworkInterface.getByInetAddress(localHost);
} else if (OS.OS == OS.LINUX) {
for (NetworkInterface n : Collections.list(NetworkInterface.getNetworkInterfaces())) {
netInter = n;
break;
}
}

byte[] macAddressBytes = netInter.getHardwareAddress();

String macAddress = "";

// Verifica se obteve macaddress
if (macAddressBytes != null && macAddressBytes.length > 5) {

macAddress = String.format(
"%1$02x%2$02x%3$02x%4$02x%5$02x%6$02x", macAddressBytes[0],
macAddressBytes[1], macAddressBytes[2], macAddressBytes[3],
macAddressBytes[4], macAddressBytes[5]).toUpperCase();
}

InetAddress addr = InetAddress.getLocalHost();

this.cpuSerial = getCPUID();
this.hostName = addr.getHostName();
this.macAddress = macAddress;
this.hostAddress = addr.getHostAddress();
this.virtualAdapter = netInter.isVirtual();

} catch (UnknownHostException e) {
System.err.println(e);
} catch (SocketException e) {
System.err.println(e);
}

}

public static synchronized ComputerInfo getIntance() {

if (ci == null) {
ci = new ComputerInfo();
}

return ci;

}

public String getCpuSerial() {
return cpuSerial;
}

public String getHostName() {
return hostName;
}

public String getMacAddress() {
return macAddress;
}

public String getHostAddress() {
return hostAddress;
}

public boolean isVirtualAdapter() {
return virtualAdapter;
}

public static String getCPUID() {

String result = null;

if (OS.OS == OS.WINDOWS) {
result = getCPUIDForWindows();
} else if (OS.OS == OS.LINUX) {
result = getCPUIDForLinux();
}

return result;

}

private static String getCPUIDForWindows() {

StringBuffer result = new StringBuffer();

try {
File file = File.createTempFile("tmp", ".vbs");
file.deleteOnExit();
FileWriter fw = new java.io.FileWriter(file);

StringBuffer vbs = new StringBuffer();
vbs.append("On Error Resume Next \r\n\r\n");
vbs.append("strComputer = \".\"  \r\n");
vbs.append("Set objWMIService = GetObject(\"winmgmts:\" _ \r\n");
vbs.append("    & \"{impersonationLevel=impersonate}!\\\\\" & strComputer & \"\\root\\cimv2\") \r\n");
vbs.append("Set colItems = objWMIService.ExecQuery(\"Select * from Win32_Processor\")  \r\n ");
vbs.append("For Each objItem in colItems\r\n ");
vbs.append("    Wscript.Echo objItem.ProcessorId  \r\n ");
vbs.append("    exit for  ' do the first cpu only! \r\n");
vbs.append("Next                    ");

fw.write(vbs.toString());
fw.close();
Process p = Runtime.getRuntime().exec(
"cscript //NoLogo " + file.getPath());
BufferedReader input = new BufferedReader(new InputStreamReader(p
.getInputStream()));
String line;
while ((line = input.readLine()) != null) {
result.append(line);
}
input.close();
} catch (Exception e) {

}

if (result == null || result.toString().trim().length() < 1 ) {
result = new StringBuffer();
return NO_CPU_ID;
}

return result.toString().trim();

}

private static String getCPUIDForLinux() {

String result = null;

try {

Process p = Runtime.getRuntime().exec("dmidecode -t 4");

BufferedReader input =
new BufferedReader
(new InputStreamReader(p.getInputStream()));

String line;

while ((line = input.readLine()) != null) {
if (line.length()>3 && line.substring(0, 3).equals(("ID:"))) {
StringTokenizer tokenizer = new StringTokenizer(line, ":");
line = tokenizer.nextToken();
result = tokenizer.nextToken();
}
}
input.close();

if(result==null || result.trim().length()==0) {
result=NO_CPU_ID;
}
}
catch(Exception e){
System.err.println(e);
}
return result.trim();
}

}

A enum OS utilizada como dependência

Crie um arquivo enum (não é classe) chamado OS.java:

public enum OS {

WINDOWS("windows"), LINUX("linux");

public static final OS OS;

private static DGLog logger = new DGLog(br.com.digicon.dnserver.util.OS.class);

private String name;

static {
String tempOS = System.getProperty("os.name"); 

if(tempOS==null) {
tempOS = "N/A";
} else {
tempOS = tempOS.trim().toLowerCase();
}

if(tempOS.indexOf(WINDOWS.name)!=-1){
OS = WINDOWS;
} else if(tempOS.indexOf(LINUX.name)!=-1){
OS = LINUX;
} else {
OS=null;
logger.error("O sistema operacional %s não é compatível a aplicação", tempOS);
}
}
OS(String os) {
name = os;
}

public String toString() {
return this.name;
}

}

Obs.: Esta classe é de autoria do Rafael Lima que contribuiu para a melhoria de ComputerInfo.

Testes da classe ComputerInfo

Agora vamos testar com um método main para isso:

public static void main(String args[]) {

ComputerInfo cii = ComputerInfo.getIntance();

System.out.println(cii.getCpuSerial());
System.out.println(cii.getHostAddress());
System.out.println(cii.getHostName());
System.out.println(cii.getMacAddress());
System.out.println(cii.isVirtualAdapter());
}

Resultados

Após obter a instância por meio de uma função singleton getInstance(), a série de invocações de métodos para obtenção dos identificadores do computador gerou a seguinte sequência de resultados:

BFEBFBFF000300A9
192.168.0.8
BRE1010
005056C00001
false

Boa sorte!

quarta-feira, 21 de agosto de 2013

Como multiplicar sem perder precisão

Conforme o último artigo, na plataforma Intel ocorre problema de precisão para número ponto flutuante quando se tenta multiplicar com o operador padrão "*".

Este problema é bastante severo quando o sistema trata de transações comerciais ou financeiras, porque são dois tipos de transações que não podem ter erro de precisão, senão os números não batem na contabilidade e em casos mais graves, quando se trata de sistemas de recargas, isso é mais crítico ainda porque é a população humana quem sofre o ônus da falha. Claro, existem "n" impactos.

Para contornar o problema em qualquer linguagem, basta usar a seguinte lógica:

      double tempValue = value * 100;
      tempValue = Math.floor(tempValue + 0.5);

Pronto!

Não, vamos fazer uma classe com as funções e testes dos erros e da solução:

Classe FloatToInteger

O nome da classe não tem nada a ver com os tipos numéricos do Java, é apenas uma forma de dizer que esta classe trata de transformar número flutuantes em números inteiros.

Dentro desta classe existem as seguintes funções auxiliares:

  • doubleToLong - está função converte double para long;
  • doubleToInt - está função converte double para int;
  • floatToInt - está função converte float para int;
  • floatToShort - está função converte float para short.

Para todas as funções, os parâmetros são value e scale:

  • value - é o valor flutuante;
  • scale - é o número de casas decimais e value para a função saber como transformar o flutuante em inteiro.

Código

public class FloatToInteger {

public static long doubleToLong(double value, int scale) {  

double tempValue = value * Math.pow(10, scale);
tempValue = Math.floor(tempValue + 0.5);
return (long) tempValue;

}

public static int doubleToInt(double value, int scale) {  

double tempValue = value * Math.pow(10, scale);
tempValue = Math.floor(tempValue + 0.5);
return (int) tempValue;

}

public static int floatToInt(float value, int scale) {  

double tempValue = value * Math.pow(10, scale);
tempValue = Math.floor(tempValue + 0.5);
return (int) tempValue;

}

public static short floatToShort(float value, int scale) {  

double tempValue = value * Math.pow(10, scale);
tempValue = Math.floor(tempValue + 0.5);
return (short) tempValue;

}

public static void main(String[] args) {

troubleSimulation();
solutionSimulation();

}

public static void troubleSimulation() { 

int erros = 0;

/***********************
* Provocar até 5 erros para amostragem do problema
* ao usar a múltiplicação comum
***********************/
double decimalValue = 0.01d;
long singleNumber = 0L;

System.out.println("1) AMOSTRAGEM DO PROBLEMA - Com o problema");

while (true) {

if (decimalValue >= 100.0d) {
break;
}

decimalValue += 0.10d;

singleNumber = (long) (decimalValue * 100); 

if (singleNumber != doubleToLong(decimalValue, 2)) {
if (erros <= 5) {
System.err.println(String.format("  ERROR: Original: %.20f, After: %d", decimalValue, singleNumber));
}
erros++;
}

}

System.out.println(String.format("População: %.0f, Total de erros: %d\n", 100 / 0.10, erros));

}

public static void solutionSimulation() { 

int erros = 0;

/***********************
* Provocar até 5 erros para amostragem do problema
* ao usar a múltiplicação comum
***********************/
double decimalValue = 0.01d;
long singleNumber = 0L;

System.out.println("2) AMOSTRAGEM DE PROBLEMAS - Após com a solução");

while (true) {

if (decimalValue >= 100.0d) {
break;
}

decimalValue += 0.10d;

singleNumber = doubleToLong(decimalValue, 2); 

if (singleNumber != doubleToLong(decimalValue, 2)) {
if (erros <= 100) {
System.err.println(String.format("  ERROR: Original: %.20f, After: %d", decimalValue, singleNumber));
}
erros++;
}

}

System.out.println(String.format("População: %.0f, Total de erros: %d\n", 100 / 0.10, erros));

}

}

Resultado dos testes

Observe o método main, ele invoca duas funções, uma para simular o problema e outro para comprovar a solução.

Resultado

1) AMOSTRAGEM DO PROBLEMA - Com o problema
  ERROR: Original: 0,90999999999999990000, After: 90
  ERROR: Original: 4,81000000000000000000, After: 480
  ERROR: Original: 4,90999999999999900000, After: 490
  ERROR: Original: 5,00999999999999900000, After: 500
  ERROR: Original: 5,10999999999999850000, After: 510
  ERROR: Original: 5,20999999999999800000, After: 520
População: 1000, Total de erros: 385

2) AMOSTRAGEM DE PROBLEMAS - Após com a solução
População: 1000, Total de erros: 0

Boa sorte!

Até mais.

terça-feira, 20 de agosto de 2013

MemCopy - Copiando bytes de forma fácil

Não é muito incomum para o programador Java fazer cópias de trechos de números para um vetor de bytes de tamanhos: 8 bits, 16 bits, 24 bits, 32 bits ou 64 bits para gerar e: guardar o resultado em arquivo binário, enviar mensagem binária para um socket, porta serial ou porta paralela.

Nota: Em C isso é relativamente fácil de fazer por causa de sua vocação original baseada na manipulação de memória, por isso em C tem a função memcpy designada para isso é extremamente versátil.

Normalmente para se fazer isso o programador já converteu números decimais para inteiros: short, int, long ou BigDecimal com uma operação de multiplicação.

Alerta: A multiplicação convencional com operador "*" utilizado para ponto flutuante pode resultar em perda de precisão não só em Java, mas em qualquer linguagem sobre a plataforma Intel por constatação ao deparar com este mesmo problema em C ANSI, C++ e depois em Java sempre na plataforma Intel. Logo mais falarei de como resolver o problema num outro artigo. É importante deixar claro que a divisão com o operador "/" funciona perfeitamente.

A classe a seguir é uma síntese prática do memcpy do C, porém com algumas melhorias porque ela oferece:
  1. tamanhos de cópias pré-estabelecidas conforme as práticas mais comuns no dia-a-dia do programador;
  2. ainda para cada função já possui assinaturas capazes de lidar com os tipos inteiros mais comuns e;
  3. permite a reversão de bytes para casos específicos onde o destino I/O possui um ordem binária reversa a sua.
Vamos para a prática.

A classe MemCopy

import java.math.BigInteger;
import java.util.Arrays;

public class MemCopy {

public static byte copy8(byte[] value) {

byte result = 0;

if (value != null && value.length > 0) {
result = value[0];
}
return result;
}

public static byte copy8(long value) {

return (byte) (value & 0x00000000000000FF);

}

public static byte copy8(int value) {

return (byte) (value & 0x000000FF);

}

public static byte copy8(short value) {

return (byte) (value & 0x00FF);

}

public static byte[] copy16(byte[] value, boolean reverseBytes) {

byte [] result = new byte[2];

if (value == null || value.length < 2) {
return null;
}

if (reverseBytes) {
result[0] = value[0];
result[1] = value[1];
} else {
result[0] = value[1];
result[1] = value[0];
}
return result;
}
public static byte[] copy16(long value, boolean reverseBytes) {
return copy16((short) (value & 0x000000000000FFFFL), reverseBytes);
}

public static byte[] copy16(int value, boolean reverseBytes) {
return copy16((short) (value & 0x0000FFFF), reverseBytes);
}
public static byte[] copy16(short value, boolean reverseBytes) {

byte [] result = new byte[2];
byte [] aux = new byte[2];

aux[0] = (byte) (value & 0x00FF);
aux[1] = (byte) ((value >> 8) & 0x00FF) ;

if (reverseBytes) {
result[1] = aux[0]; 
result[0] = aux[1]; 
} else {
result = aux;
}

return result;

}

public static byte[] copy24(byte[] value, boolean reverseBytes) {

byte [] result = new byte[3];

if (value == null || value.length < 3) {
return null;
}

if (reverseBytes) {
result[0] = value[2];
result[1] = value[1];
result[2] = value[0];
} else {
result[0] = value[0];
result[1] = value[1];
result[2] = value[2];
}
return result;
}
public static byte[] copy24(long value, boolean reverseBytes) {

byte [] result = new byte[3];
byte [] aux = new byte[3];

aux[0] = (byte) (value & 0x000000FF);
aux[1] = (byte) ((value >> 8) & 0x000000FF) ;
aux[2] = (byte) ((value >> 16) & 0x000000FF) ;

if (reverseBytes) {
result[1] = aux[0]; 
result[0] = aux[1]; 
} else {
result = aux;
}

return result;

}

public static byte[] copy32(byte[] value, boolean reverseBytes) {

byte [] result = new byte[4];
if (value == null || value.length < 4) {
return null;
}

if (reverseBytes) {
result[0] = value[3];
result[1] = value[2];
result[2] = value[1];
result[3] = value[0];
} else {
result[0] = value[0];
result[1] = value[1];
result[2] = value[2];
result[3] = value[3];
}
return result;
}
public static byte[] copy32(long value, boolean reverseBytes) {
return copy32((int) (value & 0xFFFFFFFF), reverseBytes);
}

public static byte[] copy32(int value, boolean reverseBytes) {

byte [] result = new byte[4];
byte [] aux = new byte[4];

aux[0] = (byte) (value & 0x000000FF);
aux[1] = (byte) ((value >> 8) & 0x000000FF) ;
aux[2] = (byte) ((value >> 16) & 0x000000FF);
aux[3] = (byte) ((value >> 24) & 0x000000FF);

if (reverseBytes) {
result[3] = aux[0]; 
result[2] = aux[1]; 
result[1] = aux[2]; 
result[0] = aux[3]; 
} else {
result = aux;
}

return result;
}

public static byte[] copy64(byte[] value, boolean reverseBytes) {

byte [] result = new byte[8];

if (value == null || value.length < 8) {
return null;
}

if (reverseBytes) {
result[0] = value[7];
result[1] = value[6];
result[2] = value[5];
result[3] = value[4];
result[4] = value[3];
result[5] = value[2];
result[6] = value[1];
result[7] = value[0];
} else {
result[0] = value[0];
result[1] = value[1];
result[2] = value[2];
result[3] = value[3];
result[4] = value[4];
result[5] = value[5];
result[6] = value[6];
result[7] = value[7];
}
return result;
}
public static byte[] copy64(long value, boolean reverseBytes) {

byte [] result = new byte[8];
byte [] aux = new byte[8];

aux[0] = (byte) (value & 0x00000000000000FFL);
aux[1] = (byte) ((value >> 8) & 0x00000000000000FFL);
aux[2] = (byte) ((value >> 16) & 0x00000000000000FFL);
aux[3] = (byte) ((value >> 24) & 0x00000000000000FFL);
aux[4] = (byte) ((value >> 32) & 0x00000000000000FFL);
aux[5] = (byte) ((value >> 40) & 0x00000000000000FFL);
aux[6] = (byte) ((value >> 48) & 0x00000000000000FFL);
aux[7] = (byte) ((value >> 56) & 0x00000000000000FFL);

if (reverseBytes) {
result[7] = aux[0]; 
result[6] = aux[1]; 
result[5] = aux[2]; 
result[4] = aux[3]; 
result[3] = aux[4]; 
result[2] = aux[5]; 
result[1] = aux[6]; 
result[0] = aux[7]; 
} else {
result = aux;
}

return result;

}

public static byte[] copy64(BigInteger value, boolean reverseBytes) {

if (value == null)
return null;

byte [] aux = value.toByteArray();
if (aux == null || aux.length == 0)
return null;

byte [] result = new byte[8];

Arrays.fill(result, (byte) 0);

if (aux.length < 8) {
System.arraycopy(aux, 0, result, result.length-aux.length, aux.length);
} else {
System.arraycopy(aux, 0, result, 0, result.length);
}

aux = new byte[8];
System.arraycopy(result, 0, aux, 0, aux.length);
if (!reverseBytes) {
result[7] = aux[0]; 
result[6] = aux[1]; 
result[5] = aux[2]; 
result[4] = aux[3]; 
result[3] = aux[4]; 
result[2] = aux[5]; 
result[1] = aux[6]; 
result[0] = aux[7]; 
} else {
result = aux;
}

return result;

}
}

Teste da classe

O teste da classe requer as funções de conversão de array de bytes para BigInteger, porque é o maior tipo entre os testes e isso confere a capacidade de realizar os testes rápidos com todos os tamanhos de cópias, e ainda requer a função para converter array de bytes para hexadecimal para comprovar os testes.

import java.math.BigInteger;

public class TestMemCopy {

public static BigInteger byteArrayToBigInteger(byte[] b, boolean reverseBytes) {

if (b == null || b.length == 0) {
return null;
}

byte aux[] = new byte[b.length];

if (!reverseBytes) {
for (int i = 0; i < b.length; i++) {
aux[aux.length-1-i] = b[i];
}
} else {
System.arraycopy(b, 0, aux, 0, b.length);
}

return new BigInteger(aux);

}

public static String byteArrayToHex(byte[] bytes, boolean useSpace) {

StringBuffer retorno = new StringBuffer();;

if (bytes==null || bytes.length==0) {
return retorno.toString();
}

// Com espaço
if (useSpace) {

for (int i=0; i<bytes.length; i++) {
byte valor = bytes[i];
int d1 = valor & 0xF;
d1 += (d1 < 10) ? 48 : 55;
int d2 = (valor & 0xF0) >> 4;
d2 += (d2 < 10) ? 48 : 55;
retorno.append((char) d2);
retorno.append((char) d1);
retorno.append(" ");
}

// Sem espaço
} else {

for (int i=0; i<bytes.length; i++) {
byte valor = bytes[i];
int d1 = valor & 0xF;
d1 += (d1 < 10) ? 48 : 55;
int d2 = (valor & 0xF0) >> 4;
d2 += (d2 < 10) ? 48 : 55;
retorno.append((char) d2);
retorno.append((char) d1);
}

}

return retorno.toString();

}
public static void main(String[] args) {

/*******************************
 * Copiando 1 byte de short
 ******************************/
{
// Variáveis para realizar os testes
byte encoded[] = {0};
short decoded = 0;

// Teste short
short input = (short) 102;
encoded[0] = MemCopy.copy8(input);
decoded = (short) (encoded[0] & 0xFF);

System.out.println("Copiando 1 byte de short");
System.out.println(String.format("Original (short): %d, Encoding (Hex): %s, Decoding (short): %d\n", input, byteArrayToHex(encoded, true) ,decoded));
}

/*******************************
 * Copiando 2 bytes de short - Sem reversão de bytes
 ******************************/
{
// Variáveis para realizar os testes
byte encoded[] = null;
BigInteger decoded = null;

// Teste short
short input = (short) 32767;
encoded = MemCopy.copy16(input, false);
decoded = byteArrayToBigInteger(encoded, false);

System.out.println("Copiando 2 bytes de short - Sem reversão de bytes");
System.out.println(String.format("Original (short): %d, Encoding (Hex): %s, Decoding (BigInteger): %d\n", input, byteArrayToHex(encoded, true) ,decoded));
}

/*******************************
 * Copiando 2 bytes de short - Com reversão de bytes
 ******************************/
{
// Variáveis para realizar os testes
byte encoded[] = null;
BigInteger decoded = null;

// Teste short
short input = (short) 23761;
encoded = MemCopy.copy16(input, true);
decoded = byteArrayToBigInteger(encoded, true);

System.out.println("Copiando 2 bytes de short - Com reversão de bytes");
System.out.println(String.format("Original (short): %d, Encoding (Hex): %s, Decoding (BigInteger): %d\n", input, byteArrayToHex(encoded, true) ,decoded));
}

/*******************************
 * Copiando 4 bytes de int - Sem reversão de bytes
 ******************************/
{
// Variáveis para realizar os testes
byte encoded[] = {0, 0};
BigInteger decoded = null;

// Teste short
int input = 2147483647;
encoded = MemCopy.copy32(input, false);
decoded = byteArrayToBigInteger(encoded, false);

System.out.println("Copiando 4 bytes de int - Sem reversão de bytes");
System.out.println(String.format("Original (int): %d, Encoding (Hex): %s, Decoding (BigInteger): %d\n", input, byteArrayToHex(encoded, true) ,decoded));
}

/*******************************
 * Copiando 4 bytes de int - Com reversão de bytes
 ******************************/
{
// Variáveis para realizar os testes
byte encoded[] = null;
BigInteger decoded = null;

// Teste short
int input = 1157483800;
encoded = MemCopy.copy32(input, true);
decoded = byteArrayToBigInteger(encoded, true);

System.out.println("Copiando 4 bytes de int - Com reversão de bytes");
System.out.println(String.format("Original (int): %d, Encoding (Hex): %s, Decoding (BigInteger): %d\n", input, byteArrayToHex(encoded, true) ,decoded));

}

/*******************************
 * Copiando 8 bytes de long - Sem reversão de bytes
 ******************************/
{
// Variáveis para realizar os testes
byte encoded[] = {0, 0};
BigInteger decoded = null;

// Teste short
long input =  922337203685478L; 
encoded = MemCopy.copy64(input, false);
decoded = byteArrayToBigInteger(encoded, false);

System.out.println("Copiando 8 bytes de long - Sem reversão de bytes");
System.out.println(String.format("Original (long): %d, Encoding (Hex): %s, Decoding (BigInteger): %d\n", input, byteArrayToHex(encoded, true) ,decoded));
}

/*******************************
 * Copiando 8 bytes de long - Com reversão de bytes
 ******************************/
{
// Variáveis para realizar os testes
byte encoded[] = null;
BigInteger decoded = null;

// Teste short
long input =  722337203685478L; 
encoded = MemCopy.copy64(input, true);
decoded = byteArrayToBigInteger(encoded, true);

System.out.println("Copiando 8 bytes de long - Com reversão de bytes");
System.out.println(String.format("Original (long): %d, Encoding (Hex): %s, Decoding (BigInteger): %d\n", input, byteArrayToHex(encoded, true) ,decoded));

}

/*******************************
 * Copiando 8 bytes de long - Com reversão de bytes
 ******************************/
{
// Variáveis para realizar os testes
byte encoded[] = null;
BigInteger decoded = null;

// Teste short
long input =  722337203685478L; 
encoded = MemCopy.copy64(input, true);
decoded = byteArrayToBigInteger(encoded, true);

System.out.println("Copiando 8 bytes de long - Com reversão de bytes");
System.out.println(String.format("Original (long): %d, Encoding (Hex): %s, Decoding (BigInteger): %d\n", input, byteArrayToHex(encoded, true) ,decoded));

}

}

}

Resultado

Copiando 1 byte de short
Original (short): 102, Encoding (Hex): 66 , Decoding (short): 102

Copiando 2 bytes de short - Sem reversão de bytes
Original (short): 32767, Encoding (Hex): FF 7F , Decoding (BigInteger): 32767

Copiando 2 bytes de short - Com reversão de bytes
Original (short): 23761, Encoding (Hex): 5C D1 , Decoding (BigInteger): 23761

Copiando 4 bytes de int - Sem reversão de bytes
Original (int): 2147483647, Encoding (Hex): FF FF FF 7F , Decoding (BigInteger): 2147483647

Copiando 4 bytes de int - Com reversão de bytes
Original (int): 1157483800, Encoding (Hex): 44 FD CD 18 , Decoding (BigInteger): 1157483800

Copiando 8 bytes de long - Sem reversão de bytes
Original (long): 922337203685478, Encoding (Hex): 66 88 63 5D DC 46 03 00 , Decoding (BigInteger): 922337203685478

Copiando 8 bytes de long - Com reversão de bytes
Original (long): 722337203685478, Encoding (Hex): 00 02 90 F6 3C 6F 08 66 , Decoding (BigInteger): 722337203685478


Conforme descrito no alerta, no próximo artigo vamos discutir a respeito da multiplicação de flutuantes e como evitar de vez a perda de precisão nesta operação.

Até mais.