1 // Copyright (C) 2023 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "icing/store/namespace-id-fingerprint.h"
16
17 #include <cstdint>
18 #include <string>
19 #include <string_view>
20
21 #include "icing/text_classifier/lib3/utils/base/statusor.h"
22 #include "icing/text_classifier/lib3/utils/hash/farmhash.h"
23 #include "icing/absl_ports/canonical_errors.h"
24 #include "icing/absl_ports/str_cat.h"
25 #include "icing/store/namespace-id.h"
26 #include "icing/util/encode-util.h"
27
28 namespace icing {
29 namespace lib {
30
31 /* static */ libtextclassifier3::StatusOr<NamespaceIdFingerprint>
DecodeFromCString(std::string_view encoded_cstr)32 NamespaceIdFingerprint::DecodeFromCString(std::string_view encoded_cstr) {
33 if (encoded_cstr.size() < kMinEncodedLength) {
34 return absl_ports::InvalidArgumentError("Invalid length");
35 }
36
37 NamespaceId namespace_id = encode_util::DecodeIntFromCString(
38 encoded_cstr.substr(0, kEncodedNamespaceIdLength));
39 uint64_t fingerprint = encode_util::DecodeIntFromCString(
40 encoded_cstr.substr(kEncodedNamespaceIdLength));
41 return NamespaceIdFingerprint(namespace_id, fingerprint);
42 }
43
NamespaceIdFingerprint(NamespaceId namespace_id,std::string_view target_str)44 NamespaceIdFingerprint::NamespaceIdFingerprint(NamespaceId namespace_id,
45 std::string_view target_str)
46 : namespace_id_(namespace_id),
47 fingerprint_(tc3farmhash::Fingerprint64(target_str)) {}
48
EncodeToCString() const49 std::string NamespaceIdFingerprint::EncodeToCString() const {
50 // encoded_namespace_id_str should be 1 to 3 bytes based on the value of
51 // namespace_id.
52 std::string encoded_namespace_id_str =
53 encode_util::EncodeIntToCString(namespace_id_);
54 // Make encoded_namespace_id_str to fixed kEncodedNamespaceIdLength bytes.
55 while (encoded_namespace_id_str.size() < kEncodedNamespaceIdLength) {
56 // C string cannot contain 0 bytes, so we append it using 1, just like what
57 // we do in encode_util::EncodeIntToCString.
58 //
59 // The reason that this works is because DecodeIntToString decodes a byte
60 // value of 0x01 as 0x00. When EncodeIntToCString returns an encoded
61 // namespace id that is less than 3 bytes, it means that the id contains
62 // unencoded leading 0x00. So here we're explicitly encoding those bytes as
63 // 0x01.
64 encoded_namespace_id_str.push_back(1);
65 }
66
67 return absl_ports::StrCat(encoded_namespace_id_str,
68 encode_util::EncodeIntToCString(fingerprint_));
69 }
70
71 } // namespace lib
72 } // namespace icing
73