Question

J'essaie d'envoyer un UUID Java au C ++, où il sera utilisé en tant que GUID, puis renvoyé et vu comme un UUID. J'espère pouvoir le transmettre avec seulement 16 octets.

Des suggestions sur un moyen facile de le faire?

J'ai une façon compliquée de le faire: envoyer de Java au C ++, où je demande à l'UUID ses bits les plus significatifs, écris cela dans un ByteBuffer, puis le lit sous forme d'octets.

Voici ma façon stupide et compliquée d'extraire deux longs d'un UUID, de les envoyer en C ++:

Java

public static byte[] asByteArray(UUID uuid) 
 {
    long msb = uuid.getMostSignificantBits();
    long lsb = uuid.getLeastSignificantBits();
    byte[] buffer = new byte[16];

    for (int i = 0; i < 8; i++) {
            buffer[i] = (byte) (msb >>> 8 * (7 - i));
    }
    for (int i = 8; i < 16; i++) {
            buffer[i] = (byte) (lsb >>> 8 * (7 - i));
    }

    return buffer;

}




    byte[] bytesOriginal = asByteArray(uuid);
    byte[] bytes = new byte[16];

    // Reverse the first 4 bytes
    bytes[0] = bytesOriginal[3];
    bytes[1] = bytesOriginal[2];
    bytes[2] = bytesOriginal[1];
    bytes[3] = bytesOriginal[0];
    // Reverse 6th and 7th
    bytes[4] = bytesOriginal[5];
    bytes[5] = bytesOriginal[4];
    // Reverse 8th and 9th
    bytes[6] = bytesOriginal[7];
    bytes[7] = bytesOriginal[6];                                 
    // Copy the rest straight up        
    for ( int i = 8; i < 16; i++ )
    {
        bytes[i] = bytesOriginal[i];
    }    

    // Use a ByteBuffer to switch our ENDIAN-ness
    java.nio.ByteBuffer buffer = java.nio.ByteBuffer.allocate(16);
    buffer.order(java.nio.ByteOrder.BIG_ENDIAN);
    buffer.put(bytes);
    buffer.order(java.nio.ByteOrder.LITTLE_ENDIAN);
    buffer.position(0);

    UUIDComponents x = new UUIDComponents();

    x.id1 = buffer.getLong();
    x.id2 = buffer.getLong();

C ++

    google::protobuf::int64 id1 = id.id1();
    google::protobuf::int64 id2 = id.id2();

    char* pGuid = (char*) &guid;
    char* pGuidLast8Bytes = pGuid + 8;
    memcpy(pGuid, &id1, 8);
    memcpy(pGuidLast8Bytes, &id2, 8);

Cela fonctionne, mais semble trop complexe et je ne peux pas encore le faire fonctionner dans l'autre sens.

(J'utilise des tampons de protocole Google pour envoyer les deux longs en avant et en arrière)

  • Alex
Était-ce utile?

La solution

J'ai quelque chose qui fonctionne.

Au lieu de l'envoyer sous forme de deux longs, je l'envoie sous forme d'octets, voici le code Java:

public static UUID fromBytes( ByteString byteString)
{
    byte[] bytesOriginal = byteString.toByteArray();
    byte[] bytes = new byte[16];

    // Reverse the first 4 bytes
    bytes[0] = bytesOriginal[3];
    bytes[1] = bytesOriginal[2];
    bytes[2] = bytesOriginal[1];
    bytes[3] = bytesOriginal[0];
    // Reverse 6th and 7th
    bytes[4] = bytesOriginal[5];
    bytes[5] = bytesOriginal[4];
    // Reverse 8th and 9th
    bytes[6] = bytesOriginal[7];
    bytes[7] = bytesOriginal[6];                                 
    // Copy the rest straight up        
    for ( int i = 8; i < 16; i++ )
    {
        bytes[i] = bytesOriginal[i];
    }    

    return toUUID(bytes);
}

public static ByteString toBytes( UUID uuid )
{
    byte[] bytesOriginal = asByteArray(uuid);
    byte[] bytes = new byte[16];

    // Reverse the first 4 bytes
    bytes[0] = bytesOriginal[3];
    bytes[1] = bytesOriginal[2];
    bytes[2] = bytesOriginal[1];
    bytes[3] = bytesOriginal[0];
    // Reverse 6th and 7th
    bytes[4] = bytesOriginal[5];
    bytes[5] = bytesOriginal[4];
    // Reverse 8th and 9th
    bytes[6] = bytesOriginal[7];
    bytes[7] = bytesOriginal[6];                                 
    // Copy the rest straight up        
    for ( int i = 8; i < 16; i++ )
    {
        bytes[i] = bytesOriginal[i];
    }    

    return ByteString.copyFrom(bytes);
}


private static byte[] asByteArray(UUID uuid) 
 {
    long msb = uuid.getMostSignificantBits();
    long lsb = uuid.getLeastSignificantBits();
    byte[] buffer = new byte[16];

    for (int i = 0; i < 8; i++) {
            buffer[i] = (byte) (msb >>> 8 * (7 - i));
    }
    for (int i = 8; i < 16; i++) {
            buffer[i] = (byte) (lsb >>> 8 * (7 - i));
    }

    return buffer;

}

private static UUID toUUID(byte[] byteArray) {

    long msb = 0;
    long lsb = 0;
    for (int i = 0; i < 8; i++)
            msb = (msb << 8) | (byteArray[i] & 0xff);
    for (int i = 8; i < 16; i++)
            lsb = (lsb << 8) | (byteArray[i] & 0xff);
    UUID result = new UUID(msb, lsb);

    return result;
}

En procédant de cette façon, les octets peuvent être utilisés directement du côté C ++. Je suppose que la commutation de l'ordre des octets pourrait se faire à soit à fin.

C ++

    memcpy(&guid, data, 16);

Autres conseils

Il est peut-être plus simple d'utiliser getMostSignificantBits et getLeastSignificant bits pour obtenir long des valeurs et les envoyer. De même, vous pouvez reconstruire l’UUID à partir de ces deux longs en utilisant le constructeur approprié.

Dommage qu'il n'y ait pas de toByteArray / fromByteArray méthodes: (

Votre méthode actuelle est satisfaisante, rien de mal à le faire de cette façon. Une autre approche consiste à simplement communiquer avec la représentation sous forme de chaîne de l’uid, envoyer la chaîne, l’analyser en c ++.

Btw, les octets n'ont pas de finalité, sauf si vous convertissez un tableau d'octets / caractères ou similaire à un type entier, vous déterminez simplement la finalité en réaffectant les octets dans l'ordre approprié.

Voici ce que je fais pour convertir un GUID C ++ en un UUID Java. Du côté C ++, la structure GUID est simplement convertie en octets. La conversion en C ++ peut alors aller dans le même sens.

public static UUID cppGuidBytesToUuid(byte[] cppGuid) {
    ByteBuffer b = ByteBuffer.wrap(cppGuid);
    b.order(ByteOrder.LITTLE_ENDIAN);
    java.nio.ByteBuffer out = java.nio.ByteBuffer.allocate(16);
    out.order(ByteOrder.BIG_ENDIAN);
    out.putInt(b.getInt());
    out.putShort(b.getShort());
    out.putShort(b.getShort());
    out.put(b);
    out.position(0);
    return new UUID(out.getLong(), out.getLong());
}


// Here is the JNI code ;-)
jbyteArray GUID2ByteArray(JNIEnv *env,GUID* guid)
{
    if (guid == NULL)
    return NULL;
    jbyteArray jGUID = env->NewByteArray(sizeof(GUID));
    if (jGUID == NULL)
    return NULL;
    env->SetByteArrayRegion(jGUID,0,sizeof(GUID),(signed char*)(guid));
    if (env->ExceptionOccurred() != NULL)
    return NULL;
    return jGUID;
}

Peut-être pourriez-vous expliquer pourquoi vous ne faites pas que faire.

UUID uuid = 
x.id1 = uuid.getMostSignificantBits();
x.id2 = uuid.getLeastSignificantBits();

P.S. En relisant le billet de @Jon Skeet, je pense que c'est à peu près le même conseil. ;)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top