1 | /* |
2 | * Copyright © 2011,2012 Google, Inc. |
3 | * |
4 | * This is part of HarfBuzz, a text shaping library. |
5 | * |
6 | * Permission is hereby granted, without written agreement and without |
7 | * license or royalty fees, to use, copy, modify, and distribute this |
8 | * software and its documentation for any purpose, provided that the |
9 | * above copyright notice and the following two paragraphs appear in |
10 | * all copies of this software. |
11 | * |
12 | * IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR |
13 | * DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES |
14 | * ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN |
15 | * IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH |
16 | * DAMAGE. |
17 | * |
18 | * THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, |
19 | * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND |
20 | * FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS |
21 | * ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO |
22 | * PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. |
23 | * |
24 | * Google Author(s): Behdad Esfahbod |
25 | */ |
26 | |
27 | #ifndef HB_OT_NAME_TABLE_HH |
28 | #define HB_OT_NAME_TABLE_HH |
29 | |
30 | #include "hb-open-type.hh" |
31 | |
32 | |
33 | namespace OT { |
34 | |
35 | |
36 | /* |
37 | * name -- Naming |
38 | * https://docs.microsoft.com/en-us/typography/opentype/spec/name |
39 | */ |
40 | #define HB_OT_TAG_name HB_TAG('n','a','m','e') |
41 | |
42 | |
43 | struct NameRecord |
44 | { |
45 | static int cmp (const void *pa, const void *pb) |
46 | { |
47 | const NameRecord *a = (const NameRecord *) pa; |
48 | const NameRecord *b = (const NameRecord *) pb; |
49 | int ret; |
50 | ret = b->platformID.cmp (a->platformID); |
51 | if (ret) return ret; |
52 | ret = b->encodingID.cmp (a->encodingID); |
53 | if (ret) return ret; |
54 | ret = b->languageID.cmp (a->languageID); |
55 | if (ret) return ret; |
56 | ret = b->nameID.cmp (a->nameID); |
57 | if (ret) return ret; |
58 | return 0; |
59 | } |
60 | |
61 | inline bool sanitize (hb_sanitize_context_t *c, const void *base) const |
62 | { |
63 | TRACE_SANITIZE (this); |
64 | /* We can check from base all the way up to the end of string... */ |
65 | return_trace (c->check_struct (this) && c->check_range ((char *) base, (unsigned int) length + offset)); |
66 | } |
67 | |
68 | HBUINT16 platformID; /* Platform ID. */ |
69 | HBUINT16 encodingID; /* Platform-specific encoding ID. */ |
70 | HBUINT16 languageID; /* Language ID. */ |
71 | HBUINT16 nameID; /* Name ID. */ |
72 | HBUINT16 length; /* String length (in bytes). */ |
73 | HBUINT16 offset; /* String offset from start of storage area (in bytes). */ |
74 | public: |
75 | DEFINE_SIZE_STATIC (12); |
76 | }; |
77 | |
78 | struct name |
79 | { |
80 | static const hb_tag_t tableTag = HB_OT_TAG_name; |
81 | |
82 | inline unsigned int get_name (unsigned int platform_id, |
83 | unsigned int encoding_id, |
84 | unsigned int language_id, |
85 | unsigned int name_id, |
86 | void *buffer, |
87 | unsigned int buffer_length) const |
88 | { |
89 | NameRecord key; |
90 | key.platformID.set (platform_id); |
91 | key.encodingID.set (encoding_id); |
92 | key.languageID.set (language_id); |
93 | key.nameID.set (name_id); |
94 | NameRecord *match = (NameRecord *) bsearch (&key, nameRecord, count, sizeof (nameRecord[0]), NameRecord::cmp); |
95 | |
96 | if (!match) |
97 | return 0; |
98 | |
99 | unsigned int length = MIN (buffer_length, (unsigned int) match->length); |
100 | memcpy (buffer, (char *) this + stringOffset + match->offset, length); |
101 | return length; |
102 | } |
103 | |
104 | inline unsigned int get_size (void) const |
105 | { return min_size + count * nameRecord[0].min_size; } |
106 | |
107 | inline bool sanitize_records (hb_sanitize_context_t *c) const { |
108 | TRACE_SANITIZE (this); |
109 | char *string_pool = (char *) this + stringOffset; |
110 | unsigned int _count = count; |
111 | for (unsigned int i = 0; i < _count; i++) |
112 | if (!nameRecord[i].sanitize (c, string_pool)) return_trace (false); |
113 | return_trace (true); |
114 | } |
115 | |
116 | inline bool sanitize (hb_sanitize_context_t *c) const |
117 | { |
118 | TRACE_SANITIZE (this); |
119 | return_trace (c->check_struct (this) && |
120 | likely (format == 0 || format == 1) && |
121 | c->check_array (nameRecord, nameRecord[0].static_size, count) && |
122 | sanitize_records (c)); |
123 | } |
124 | |
125 | /* We only implement format 0 for now. */ |
126 | HBUINT16 format; /* Format selector (=0/1). */ |
127 | HBUINT16 count; /* Number of name records. */ |
128 | Offset16 stringOffset; /* Offset to start of string storage (from start of table). */ |
129 | NameRecord nameRecord[VAR]; /* The name records where count is the number of records. */ |
130 | public: |
131 | DEFINE_SIZE_ARRAY (6, nameRecord); |
132 | }; |
133 | |
134 | |
135 | } /* namespace OT */ |
136 | |
137 | |
138 | #endif /* HB_OT_NAME_TABLE_HH */ |
139 | |