summaryrefslogtreecommitdiff
path: root/AK/UUID.cpp
blob: 3c08fc7c5264800295fbdbff70d43d7e05a35ca7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/*
 * Copyright (c) 2020, Liav A. <liavalb@hotmail.co.il>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <AK/AllOf.h>
#include <AK/Hex.h>
#include <AK/StringBuilder.h>
#include <AK/UUID.h>

namespace AK {

UUID::UUID(Array<u8, 16> uuid_buffer)
{
    uuid_buffer.span().copy_to(m_uuid_buffer);
}

void UUID::convert_string_view_to_little_endian_uuid(StringView uuid_string_view)
{
    VERIFY(uuid_string_view.length() == 36);
    auto first_unit = MUST(decode_hex(uuid_string_view.substring_view(0, 8)));
    auto second_unit = MUST(decode_hex(uuid_string_view.substring_view(9, 4)));
    auto third_unit = MUST(decode_hex(uuid_string_view.substring_view(14, 4)));
    auto fourth_unit = MUST(decode_hex(uuid_string_view.substring_view(19, 4)));
    auto fifth_unit = MUST(decode_hex(uuid_string_view.substring_view(24, 12)));

    VERIFY(first_unit.size() == 4 && second_unit.size() == 2
        && third_unit.size() == 2 && fourth_unit.size() == 2
        && fifth_unit.size() == 6);

    m_uuid_buffer.span().overwrite(0, first_unit.data(), first_unit.size());
    m_uuid_buffer.span().overwrite(4, second_unit.data(), second_unit.size());
    m_uuid_buffer.span().overwrite(6, third_unit.data(), third_unit.size());
    m_uuid_buffer.span().overwrite(8, fourth_unit.data(), fourth_unit.size());
    m_uuid_buffer.span().overwrite(10, fifth_unit.data(), fifth_unit.size());
}

void UUID::convert_string_view_to_mixed_endian_uuid(StringView uuid_string_view)
{
    VERIFY(uuid_string_view.length() == 36);
    auto first_unit = MUST(decode_hex(uuid_string_view.substring_view(0, 8)));
    auto second_unit = MUST(decode_hex(uuid_string_view.substring_view(9, 4)));
    auto third_unit = MUST(decode_hex(uuid_string_view.substring_view(14, 4)));
    auto fourth_unit = MUST(decode_hex(uuid_string_view.substring_view(19, 4)));
    auto fifth_unit = MUST(decode_hex(uuid_string_view.substring_view(24, 12)));

    VERIFY(first_unit.size() == 4 && second_unit.size() == 2
        && third_unit.size() == 2 && fourth_unit.size() == 2
        && fifth_unit.size() == 6);

    // Revert endianness for first 4 bytes
    for (size_t index = 0; index < 4; index++) {
        m_uuid_buffer[3 - index] = first_unit[index];
    }

    // Revert endianness for second 2 bytes and again for 2 bytes
    for (size_t index = 0; index < 2; index++) {
        m_uuid_buffer[3 + 2 - index] = second_unit[index];
        m_uuid_buffer[5 + 2 - index] = third_unit[index];
    }

    m_uuid_buffer.span().overwrite(8, fourth_unit.data(), fourth_unit.size());
    m_uuid_buffer.span().overwrite(10, fifth_unit.data(), fifth_unit.size());
}

UUID::UUID(StringView uuid_string_view, Endianness endianness)
{
    if (endianness == Endianness::Little) {
        convert_string_view_to_little_endian_uuid(uuid_string_view);
        return;
    } else if (endianness == Endianness::Mixed) {
        convert_string_view_to_mixed_endian_uuid(uuid_string_view);
        return;
    }
    VERIFY_NOT_REACHED();
}

#ifdef KERNEL
ErrorOr<NonnullOwnPtr<Kernel::KString>> UUID::to_string() const
{
    StringBuilder builder(36);
    auto nibble0 = TRY(encode_hex(m_uuid_buffer.span().trim(4)));
    TRY(builder.try_append(nibble0->view()));
    TRY(builder.try_append('-'));
    auto nibble1 = TRY(encode_hex(m_uuid_buffer.span().slice(4).trim(2)));
    TRY(builder.try_append(nibble1->view()));
    TRY(builder.try_append('-'));
    auto nibble2 = TRY(encode_hex(m_uuid_buffer.span().slice(6).trim(2)));
    TRY(builder.try_append(nibble2->view()));
    TRY(builder.try_append('-'));
    auto nibble3 = TRY(encode_hex(m_uuid_buffer.span().slice(8).trim(2)));
    TRY(builder.try_append(nibble3->view()));
    TRY(builder.try_append('-'));
    auto nibble4 = TRY(encode_hex(m_uuid_buffer.span().slice(10).trim(6)));
    TRY(builder.try_append(nibble4->view()));
    return Kernel::KString::try_create(builder.string_view());
}
#else
String UUID::to_string() const
{
    StringBuilder builder(36);
    builder.append(encode_hex(m_uuid_buffer.span().trim(4)).view());
    builder.append('-');
    builder.append(encode_hex(m_uuid_buffer.span().slice(4).trim(2)).view());
    builder.append('-');
    builder.append(encode_hex(m_uuid_buffer.span().slice(6).trim(2)).view());
    builder.append('-');
    builder.append(encode_hex(m_uuid_buffer.span().slice(8).trim(2)).view());
    builder.append('-');
    builder.append(encode_hex(m_uuid_buffer.span().slice(10).trim(6)).view());
    return builder.to_string();
}
#endif

bool UUID::operator==(const UUID& other) const
{
    for (size_t index = 0; index < 16; index++) {
        if (m_uuid_buffer[index] != other.m_uuid_buffer[index])
            return false;
    }
    return true;
}

bool UUID::is_zero() const
{
    return all_of(m_uuid_buffer, [](auto const octet) { return octet == 0; });
}

}