/* Chrysalide - Outil d'analyse de fichiers binaires * io.c - entrées sorties fiables et manipulation des nombres * * Copyright (C) 2014-2019 Cyrille Bagard * * This file is part of Chrysalide. * * Chrysalide is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * Chrysalide is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Chrysalide. If not, see . */ #include "io.h" #include #include #include #include #include #include #include #include #include #include "../core/logs.h" /** * Mutualisation des aiguillages... */ #if __BYTE_ORDER != __LITTLE_ENDIAN && __BYTE_ORDER != __BIG_ENDIAN /* __PDP_ENDIAN et Cie... */ # error "Congratulations! Your byte order is not supported!" #endif /* ---------------------------------------------------------------------------------- */ /* ENTREES/SORTIES BRUTES ENCADREES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : fd = flux ouvert en lecture. * * buf = données à recevoir. * * count = quantité de ces données. * * * * Description : Lit des données depuis un flux local. * * * * Retour : true si toutes les données ont été lues, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool safe_read(int fd, void *buf, size_t count) { uint8_t *iter; /* Données en attente */ size_t remaining; /* Quantité restante */ ssize_t got; /* Données envoyées */ iter = (uint8_t *)buf; remaining = count; while (remaining > 0) { got = read(fd, iter, remaining); if (got == -1) { if (errno == EINTR) continue; else { perror("read"); break; } } if (got == 0) break; iter += got; remaining -= got; } return (remaining == 0); } /****************************************************************************** * * * Paramètres : fd = flux ouvert en lecture. * * buf = données à recevoir. * * max = quantité maximale de ces données. * * * * Description : Lit des données depuis un flux local. * * * * Retour : Nombre d'octets lus, au pire 0 en cas d'erreur. * * * * Remarques : - * * * ******************************************************************************/ ssize_t safe_read_partial(int fd, void *buf, size_t max) { ssize_t result; /* Quantité lue à remonter */ uint8_t *iter; /* Données en attente */ size_t remaining; /* Quantité restante */ ssize_t got; /* Données envoyées */ result = 0; iter = (uint8_t *)buf; remaining = max; while (remaining > 0) { got = read(fd, iter, remaining); if (got == -1) { if (errno == EINTR) continue; else { perror("read"); break; } } if (got == 0) break; result += got; iter += got; remaining -= got; } return result; } /****************************************************************************** * * * Paramètres : fd = flux ouvert en écriture. * * buf = données à émettre. * * count = quantité de ces données. * * * * Description : Ecrit des données dans un flux local. * * * * Retour : true si toutes les données ont été écrites, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool safe_write(int fd, const void *buf, size_t count) { uint8_t *iter; /* Données en attente */ size_t remaining; /* Quantité restante */ ssize_t sent; /* Données envoyées */ iter = (uint8_t *)buf; remaining = count; while (remaining > 0) { sent = write(fd, iter, remaining); if (sent == -1) { if (errno == EINTR) continue; else { perror("write"); break; } } if (sent == 0) break; iter += sent; remaining -= sent; } return (remaining == 0); } /****************************************************************************** * * * Paramètres : sockfd = flux ouvert en lecture. * * buf = données à recevoir. * * len = quantité de ces données. * * flags = options de réception. * * * * Description : Réceptionne des données depuis un flux réseau. * * * * Retour : true si toutes les données ont été reçues, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool safe_recv(int sockfd, void *buf, size_t len, int flags) { uint8_t *iter; /* Données en attente */ size_t remaining; /* Quantité restante */ ssize_t got; /* Données envoyées */ iter = buf; remaining = len; while (remaining > 0) { got = recv(sockfd, iter, remaining, MSG_NOSIGNAL | flags); if (got == -1) { if (errno == EINTR) continue; else { perror("recv"); break; } } iter += got; remaining -= got; } return (remaining == 0); } /****************************************************************************** * * * Paramètres : sockfd = flux ouvert en écriture. * * buf = données à émettre. * * len = quantité de ces données. * * flags = options d'envoi. * * * * Description : Envoie des données au travers un flux réseau. * * * * Retour : true si toutes les données ont été émises, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool safe_send(int sockfd, const void *buf, size_t len, int flags) { uint8_t *iter; /* Données en attente */ size_t remaining; /* Quantité restante */ ssize_t sent; /* Données envoyées */ iter = (uint8_t *)buf; remaining = len; while (remaining > 0) { sent = send(sockfd, iter, remaining, MSG_NOSIGNAL | flags); if (sent == -1) { if (errno == EINTR) continue; else { perror("send"); break; } } iter += sent; remaining -= sent; } return (remaining == 0); } /* ---------------------------------------------------------------------------------- */ /* CONVERSION ENTRE BOUTISMES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : value = valeur d'origine à manipuler. * * endian = ordre des bits dans la source. * * * * Description : Adapte un nombre sur 16 bits à un boutisme donné. * * * * Retour : Valeur transformée au besoin. * * * * Remarques : - * * * ******************************************************************************/ uint16_t swap_u16(const uint16_t *value, SourceEndian endian) { uint16_t result; /* Valeur à retourner */ switch (endian) { case SRE_LITTLE: #if __BYTE_ORDER == __LITTLE_ENDIAN result = *value; #elif __BYTE_ORDER == __BIG_ENDIAN result = ((*value >> 0) & 0xff) << 8 | ((*value >> 8) & 0xff) << 0; #endif break; case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN result = ((*value >> 0) & 0xff) << 8 | ((*value >> 8) & 0xff) << 0; #elif __BYTE_ORDER == __BIG_ENDIAN result = *value; #endif break; default: assert(false); result = -1; break; } return result; } /****************************************************************************** * * * Paramètres : value = valeur d'origine à manipuler. * * endian = ordre des bits dans la source. * * * * Description : Adapte un nombre sur 16 bits à un boutisme donné. * * * * Retour : Valeur transformée au besoin. * * * * Remarques : - * * * ******************************************************************************/ uint32_t swap_u32(const uint32_t *value, SourceEndian endian) { uint32_t result; /* Valeur à retourner */ switch (endian) { case SRE_LITTLE: #if __BYTE_ORDER == __LITTLE_ENDIAN result = *value; #elif __BYTE_ORDER == __BIG_ENDIAN result = ((*value >> 0) & 0xff) << 24 | ((*value >> 8) & 0xff) << 16 | ((*value >> 16) & 0xff) << 8 | ((*value >> 24) & 0xff) << 0; #endif break; case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN result = ((*value >> 0) & 0xff) << 24 | ((*value >> 8) & 0xff) << 16 | ((*value >> 16) & 0xff) << 8 | ((*value >> 24) & 0xff) << 0; #elif __BYTE_ORDER == __BIG_ENDIAN result = *value; #endif break; default: assert(false); result = -1; break; } return result; } /****************************************************************************** * * * Paramètres : value = valeur d'origine à manipuler. * * endian = ordre des bits dans la source. * * * * Description : Adapte un nombre sur 16 bits à un boutisme donné. * * * * Retour : Valeur transformée au besoin. * * * * Remarques : - * * * ******************************************************************************/ uint64_t swap_u64(const uint64_t *value, SourceEndian endian) { uint64_t result; /* Valeur à retourner */ switch (endian) { case SRE_LITTLE: #if __BYTE_ORDER == __LITTLE_ENDIAN result = *value; #elif __BYTE_ORDER == __BIG_ENDIAN result = ((*value >> 0) & 0xff) << 56 | ((*value >> 8) & 0xff) << 48 | ((*value >> 16) & 0xff) << 40 | ((*value >> 24) & 0xff) << 32 | ((*value >> 32) & 0xff) << 24 | ((*value >> 40) & 0xff) << 16 | ((*value >> 48) & 0xff) << 8 | ((*value >> 56) & 0xff) << 0; #endif break; case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN result = ((*value >> 0) & 0xff) << 56 | ((*value >> 8) & 0xff) << 48 | ((*value >> 16) & 0xff) << 40 | ((*value >> 24) & 0xff) << 32 | ((*value >> 32) & 0xff) << 24 | ((*value >> 40) & 0xff) << 16 | ((*value >> 48) & 0xff) << 8 | ((*value >> 56) & 0xff) << 0; #elif __BYTE_ORDER == __BIG_ENDIAN result = *value; #endif break; default: assert(false); result = -1; break; } return result; } /* ---------------------------------------------------------------------------------- */ /* BOUTISME DES ENTREES / SORTIES */ /* ---------------------------------------------------------------------------------- */ /****************************************************************************** * * * Paramètres : target = lieu d'enregistrement de la lecture. [OUT] * * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * end = limite des données à analyser. * * low = position éventuelle des 4 bits visés. [OUT] * * * * Description : Lit un nombre non signé sur 4 bits. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool read_u4(uint8_t *target, const bin_t *data, phys_t *pos, phys_t end, bool *low) { if (end < 1) return false; if (*pos > (end - 1)) return false; if (*low) { *target = data[*pos] & 0x0f; *low = false; } else { *target = (data[*pos] & 0xf0) >> 4; *low = true; *pos += 1; } return true; } /****************************************************************************** * * * Paramètres : target = lieu d'enregistrement de la lecture. [OUT] * * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * end = limite des données à analyser. * * * * Description : Lit un nombre non signé sur un octet. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool read_u8(uint8_t *target, const bin_t *data, phys_t *pos, phys_t end) { if (end < 1) return false; if (*pos > (end - 1)) return false; *target = data[*pos]; *pos += 1; return true; } /****************************************************************************** * * * Paramètres : target = lieu d'enregistrement de la lecture. [OUT] * * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * end = limite des données à analyser. * * endian = ordre des bits dans la source. * * * * Description : Lit un nombre non signé sur deux octets. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool read_u16(uint16_t *target, const bin_t *data, phys_t *pos, phys_t end, SourceEndian endian) { if (end < 2) return false; if (*pos > (end - 2)) return false; switch (endian) { case SRE_LITTLE: #if __BYTE_ORDER == __LITTLE_ENDIAN *target = data[*pos] | (uint16_t)data[*pos + 1] << 8; #elif __BYTE_ORDER == __BIG_ENDIAN *target = data[*pos + 1] | (uint16_t)data[*pos] << 8; #endif break; case SRE_LITTLE_WORD: #if __BYTE_ORDER == __LITTLE_ENDIAN *target = data[*pos] << 8 | (uint16_t)data[*pos + 1]; #elif __BYTE_ORDER == __BIG_ENDIAN *target = data[*pos + 1] << 8 | (uint16_t)data[*pos]; #endif break; case SRE_BIG_WORD: #if __BYTE_ORDER == __LITTLE_ENDIAN *target = data[*pos + 1] << 8 | (uint16_t)data[*pos]; #elif __BYTE_ORDER == __BIG_ENDIAN *target = data[*pos] << 8 | (uint16_t)data[*pos + 1]; #endif break; case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN *target = data[*pos + 1] | (uint16_t)data[*pos] << 8; #elif __BYTE_ORDER == __BIG_ENDIAN *target = data[*pos] | (uint16_t)data[*pos + 1] << 8; #endif break; default: return false; break; } *pos += 2; return true; } /****************************************************************************** * * * Paramètres : target = lieu d'enregistrement de la lecture. [OUT] * * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * end = limite des données à analyser. * * endian = ordre des bits dans la source. * * * * Description : Lit un nombre non signé sur quatre octets. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool read_u32(uint32_t *target, const bin_t *data, phys_t *pos, phys_t end, SourceEndian endian) { if (end < 4) return false; if (*pos > (end - 4)) return false; switch (endian) { case SRE_LITTLE: #if __BYTE_ORDER == __LITTLE_ENDIAN *target = data[*pos] | (uint32_t)data[*pos + 1] << 8; *target |= data[*pos + 2] << 16 | (uint32_t)data[*pos + 3] << 24; #elif __BYTE_ORDER == __BIG_ENDIAN *target = data[*pos + 3] | (uint32_t)data[*pos + 2] << 8; *target |= data[*pos + 1] << 16 | (uint32_t)data[*pos] << 24; #endif break; case SRE_LITTLE_WORD: #if __BYTE_ORDER == __LITTLE_ENDIAN *target = data[*pos] << 8 | (uint32_t)data[*pos + 1]; *target |= data[*pos + 2] << 24 | (uint32_t)data[*pos + 3] << 16; #elif __BYTE_ORDER == __BIG_ENDIAN *target = data[*pos + 3] << 8 | (uint32_t)data[*pos + 2]; *target |= data[*pos + 1] << 24 | (uint32_t)data[*pos] << 16; #endif break; case SRE_BIG_WORD: #if __BYTE_ORDER == __LITTLE_ENDIAN *target = data[*pos + 3] << 8 | (uint32_t)data[*pos + 2]; *target |= data[*pos + 1] << 24 | (uint32_t)data[*pos] << 16; #elif __BYTE_ORDER == __BIG_ENDIAN *target = data[*pos] << 8 | (uint32_t)data[*pos + 1]; *target |= data[*pos + 2] << 24 | (uint32_t)data[*pos + 3] << 16; #endif break; case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN *target = data[*pos + 3] | (uint32_t)data[*pos + 2] << 8; *target |= data[*pos + 1] << 16 | (uint32_t)data[*pos] << 24; #elif __BYTE_ORDER == __BIG_ENDIAN *target = data[*pos] | (uint32_t)data[*pos + 1] << 8; *target |= data[*pos + 2] << 16 | (uint32_t)data[*pos + 3] << 24; #endif break; default: return false; break; } *pos += 4; return true; } /****************************************************************************** * * * Paramètres : target = lieu d'enregistrement de la lecture. [OUT] * * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * end = limite des données à analyser. * * endian = ordre des bits dans la source. * * * * Description : Lit un nombre non signé sur huit octets. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool read_u64(uint64_t *target, const bin_t *data, phys_t *pos, phys_t end, SourceEndian endian) { if (end < 8) return false; if (*pos > (end - 8)) return false; switch (endian) { case SRE_LITTLE: #if __BYTE_ORDER == __LITTLE_ENDIAN *target = (uint64_t)data[*pos] | (uint64_t)data[*pos + 1] << 8; *target |= (uint64_t)data[*pos + 2] << 16 | (uint64_t)data[*pos + 3] << 24; *target |= (uint64_t)data[*pos + 4] << 32 | (uint64_t)data[*pos + 5] << 40; *target |= (uint64_t)data[*pos + 6] << 48 | (uint64_t)data[*pos + 7] << 56; #elif __BYTE_ORDER == __BIG_ENDIAN *target = (uint64_t)data[*pos + 7] | (uint64_t)data[*pos + 6] << 8; *target |= (uint64_t)data[*pos + 5] << 16 | (uint64_t)data[*pos + 4] << 24; *target |= (uint64_t)data[*pos + 3] << 32 | (uint64_t)data[*pos + 2] << 40; *target |= (uint64_t)data[*pos + 1] << 48 | (uint64_t)data[*pos] << 56; #endif break; case SRE_LITTLE_WORD: #if __BYTE_ORDER == __LITTLE_ENDIAN *target = (uint64_t)data[*pos] << 8 | (uint64_t)data[*pos + 1]; *target |= (uint64_t)data[*pos + 2] << 24 | (uint64_t)data[*pos + 3] << 16; *target |= (uint64_t)data[*pos + 4] << 40 | (uint64_t)data[*pos + 5] << 32; *target |= (uint64_t)data[*pos + 6] << 56 | (uint64_t)data[*pos + 7] << 48; #elif __BYTE_ORDER == __BIG_ENDIAN *target = (uint64_t)data[*pos + 7] << 8 | (uint64_t)data[*pos + 6]; *target |= (uint64_t)data[*pos + 5] << 24 | (uint64_t)data[*pos + 4] << 16; *target |= (uint64_t)data[*pos + 3] << 40 | (uint64_t)data[*pos + 2] << 32; *target |= (uint64_t)data[*pos + 1] << 56 | (uint64_t)data[*pos] << 48; #endif break; case SRE_BIG_WORD: #if __BYTE_ORDER == __LITTLE_ENDIAN *target = (uint64_t)data[*pos + 7] << 8 | (uint64_t)data[*pos + 6]; *target |= (uint64_t)data[*pos + 5] << 24 | (uint64_t)data[*pos + 4] << 16; *target |= (uint64_t)data[*pos + 3] << 40 | (uint64_t)data[*pos + 2] << 32; *target |= (uint64_t)data[*pos + 1] << 56 | (uint64_t)data[*pos] << 48; #elif __BYTE_ORDER == __BIG_ENDIAN *target = (uint64_t)data[*pos] << 8| (uint64_t)data[*pos + 1]; *target |= (uint64_t)data[*pos + 2] << 24 | (uint64_t)data[*pos + 3] << 16; *target |= (uint64_t)data[*pos + 4] << 40 | (uint64_t)data[*pos + 5] << 32; *target |= (uint64_t)data[*pos + 6] << 56 | (uint64_t)data[*pos + 7] << 48; #endif break; case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN *target = (uint64_t)data[*pos + 7] | (uint64_t)data[*pos + 6] << 8; *target |= (uint64_t)data[*pos + 5] << 16 | (uint64_t)data[*pos + 4] << 24; *target |= (uint64_t)data[*pos + 3] << 32 | (uint64_t)data[*pos + 2] << 40; *target |= (uint64_t)data[*pos + 1] << 48 | (uint64_t)data[*pos] << 56; #elif __BYTE_ORDER == __BIG_ENDIAN *target = (uint64_t)data[*pos] | (uint64_t)data[*pos + 1] << 8; *target |= (uint64_t)data[*pos + 2] << 16 | (uint64_t)data[*pos + 3] << 24; *target |= (uint64_t)data[*pos + 4] << 32 | (uint64_t)data[*pos + 5] << 40; *target |= (uint64_t)data[*pos + 6] << 48 | (uint64_t)data[*pos + 7] << 56; #endif break; default: return false; break; } *pos += 8; return true; } /****************************************************************************** * * * Paramètres : value = source de la valeur à transcrire. * * size = taille de cette source de données. * * data = flux de données à modifier. [OUT] * * pos = position courante dans ce flux. [OUT] * * end = limite des données à analyser. * * endian = ordre des bits dans la source. * * * * Description : Ecrit un nombre non signé sur n octets. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool _write_un(const bin_t *value, size_t size, bin_t *data, off_t *pos, off_t end, SourceEndian endian) { size_t i; /* Boucle de parcours */ if (end < size) return false; if (*pos > (end - size)) return false; switch (endian) { case SRE_LITTLE: #if __BYTE_ORDER == __LITTLE_ENDIAN memcpy(&data[*pos], value, size); (*pos) += size; #elif __BYTE_ORDER == __BIG_ENDIAN for (i = 0; i < size; i++, (*pos)++) *(data + *pos) = *(value + size - i - 1); #endif break; case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN for (i = 0; i < size; i++, (*pos)++) *(data + *pos) = *(value + size - i - 1); #elif __BYTE_ORDER == __BIG_ENDIAN memcpy(&data[*pos], value, size); (*pos) += size; #endif break; default: return false; break; } return true; } /****************************************************************************** * * * Paramètres : target = lieu d'enregistrement de la lecture. [OUT] * * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * end = limite des données à analyser. * * endian = ordre des bits dans la source. * * * * Description : Lit un nombre hexadécimal non signé sur deux octets. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool strtou8(uint8_t *target, const char *data, size_t *pos, size_t end, SourceEndian endian) { size_t i; /* Boucle de parcours */ if (end < 2) return false; if (*pos > (end - 2)) return false; *target = 0; for (i = 0; i < 2; i++) switch (data[*pos + i]) { case '0' ... '9': *target |= ((data[*pos + i] - '0') << (4 * (1 - i))); break; case 'A' ... 'F': *target |= ((data[*pos + i] + 10 - 'A') << (4 * (1 - i))); break; case 'a' ... 'f': *target |= ((data[*pos + i] + 10 - 'a') << (4 * (1 - i))); break; } *pos += 2; return true; } /****************************************************************************** * * * Paramètres : n = nombre d'octets constituant le nombre à lire. * * data = flux de données à analyser. * * pos = position courante dans ce flux. [OUT] * * end = limite des données à analyser. * * endian = ordre des bits dans la source. * * ... = lieu d'enregistrement de la lecture. [OUT] * * * * Description : Lit un nombre hexadécimal non signé sur n octets. * * * * Retour : Bilan de l'opération : true en cas de succès, false sinon. * * * * Remarques : - * * * ******************************************************************************/ bool _strtoun(uint8_t n, const char *data, size_t *pos, size_t end, SourceEndian endian, ...) { bool result; /* Bilan à renvoyer */ va_list ap; /* Arguments variables */ uint8_t *target8; /* Enregistrement sur 8 bits */ uint16_t *target16; /* Enregistrement sur 16 bits */ uint32_t *target32; /* Enregistrement sur 32 bits */ uint64_t *target64; /* Enregistrement sur 64 bits */ uint8_t i; /* Boucle de parcours #1 */ size_t j; /* Boucle de parcours #2 */ uint8_t tmp; /* Valeur temporaire de 8 bits */ if (end < (n * 2)) return false; if (*pos > (end - (n * 2))) return false; /* Récupération de la destination */ va_start(ap, endian); switch (n) { case 1: target8 = va_arg(ap, uint8_t *); *target8 = 0; target64 = (uint64_t *)target8; break; case 2: target16 = va_arg(ap, uint16_t *); *target16 = 0; target64 = (uint64_t *)target16; break; case 4: target32 = va_arg(ap, uint32_t *); *target32 = 0; target64 = (uint64_t *)target32; break; case 8: target64 = va_arg(ap, uint64_t *); *target64 = 0ull; break; default: va_end(ap); return false; break; } va_end(ap); /* Lecture des données */ result = true; for (i = 0; i < n && result; i++) { tmp = 0; for (j = 0; j < 2 && result; j++) switch (data[*pos + j]) { case '0' ... '9': tmp |= ((data[*pos + j] - '0') << (4 * (1 - j))); break; case 'A' ... 'F': tmp |= ((data[*pos + j] + 10 - 'A') << (4 * (1 - j))); break; case 'a' ... 'f': tmp |= ((data[*pos + j] + 10 - 'a') << (4 * (1 - j))); break; default: result = false; break; } *pos += 2; switch (endian) { case SRE_LITTLE: #if __BYTE_ORDER == __LITTLE_ENDIAN *target64 |= ((uint64_t)tmp) << (8 * i); #elif __BYTE_ORDER == __BIG_ENDIAN *target64 |= ((uint64_t)tmp) << (8 * (n - 1 - i)); #endif break; case SRE_BIG: #if __BYTE_ORDER == __LITTLE_ENDIAN *target64 |= ((uint64_t)tmp) << (8 * (n - 1 - i)); #elif __BYTE_ORDER == __BIG_ENDIAN *target64 |= ((uint64_t)tmp) << (8 * i); #endif break; default: return false; break; } } return result; }