1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6 #include <stdint.h>
7 #include <string.h>
8
9 // clang-format off
10 #include <hb.h>
11 #include <hb-subset.h>
12 // clang-format on
13
14 #include "base/check.h"
15 #include "base/stl_util.h"
16 #include "third_party/harfbuzz-ng/utils/hb_scoped.h"
17
18 namespace {
19
TrySubset(hb_face_t * face,const hb_codepoint_t text[],const int text_length,const uint8_t flags)20 void TrySubset(hb_face_t* face,
21 const hb_codepoint_t text[],
22 const int text_length,
23 const uint8_t flags) {
24 bool drop_hints = flags & (1 << 0);
25 bool drop_layout = flags & (1 << 1);
26 bool retain_gids = flags & (1 << 2);
27
28 HbScoped<hb_subset_input_t> input(hb_subset_input_create_or_fail());
29 hb_subset_input_set_drop_hints(input.get(), drop_hints);
30 hb_subset_input_set_retain_gids(input.get(), retain_gids);
31 hb_set_t* codepoints = hb_subset_input_unicode_set(input.get());
32
33 if (!drop_layout) {
34 hb_set_del(hb_subset_input_drop_tables_set(input.get()),
35 HB_TAG('G', 'S', 'U', 'B'));
36 hb_set_del(hb_subset_input_drop_tables_set(input.get()),
37 HB_TAG('G', 'P', 'O', 'S'));
38 hb_set_del(hb_subset_input_drop_tables_set(input.get()),
39 HB_TAG('G', 'D', 'E', 'F'));
40 }
41
42 for (int i = 0; i < text_length; i++) {
43 hb_set_add(codepoints, text[i]);
44 }
45
46 HbScoped<hb_face_t> result(hb_subset(face, input.get()));
47 HbScoped<hb_blob_t> blob(hb_face_reference_blob(result.get()));
48 uint32_t length;
49 const char* data = hb_blob_get_data(blob.get(), &length);
50
51 // Access all the blob data
52 uint32_t bytes_count = 0;
53 if (data) {
54 for (uint32_t i = 0; i < length; ++i) {
55 if (data[i])
56 ++bytes_count;
57 }
58 }
59 CHECK(bytes_count || !length);
60 }
61
62 } // namespace
63
64 constexpr size_t kMaxInputLength = 16800;
65
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)66 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
67 if (size > kMaxInputLength)
68 return 0;
69
70 const char* data_ptr = reinterpret_cast<const char*>(data);
71 HbScoped<hb_blob_t> blob(hb_blob_create(
72 data_ptr, size, HB_MEMORY_MODE_READONLY, nullptr, nullptr));
73 HbScoped<hb_face_t> face(hb_face_create(blob.get(), 0));
74
75 // Test hb_set API
76 {
77 HbScoped<hb_set_t> output(hb_set_create());
78 hb_face_collect_unicodes(face.get(), output.get());
79 }
80
81 uint8_t subset_flags = 0;
82 const hb_codepoint_t text[] = {'A', 'B', 'C', 'D', 'E', 'X', 'Y',
83 'Z', '1', '2', '3', '@', '_', '%',
84 '&', ')', '*', '$', '!'};
85
86 TrySubset(face.get(), text, base::size(text), subset_flags);
87
88 hb_codepoint_t text_from_data[16];
89 if (size > sizeof(text_from_data) + 1) {
90 memcpy(text_from_data, data + size - sizeof(text_from_data),
91 sizeof(text_from_data));
92 subset_flags = data[size - sizeof(text_from_data) - 1];
93 size_t text_size = base::size(text_from_data);
94 TrySubset(face.get(), text_from_data, text_size, subset_flags);
95 }
96
97 return 0;
98 }
99