summaryrefslogtreecommitdiffstats
blob: 2ee816124bfe0c09735382973821a6365066e4cb (plain) (blame)
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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
//
// Copyright (C) 2017 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//      http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#ifndef PROPERTY_INFO_PARSER_H
#define PROPERTY_INFO_PARSER_H

#include <stdint.h>
#include <stdlib.h>

namespace android {
namespace properties {

// The below structs intentionally do not end with char name[0] or other tricks to allocate
// with a dynamic size, such that they can be added onto in the future without breaking
// backwards compatibility.
struct PropertyEntry {
  uint32_t name_offset;
  uint32_t namelen;

  // This is the context match for this node_; ~0u if it doesn't correspond to any.
  uint32_t context_index;
  // This is the schema for this node_; ~0u if it doesn't correspond to any.
  uint32_t schema_index;
};

struct TrieNodeInternal {
  // This points to a property entry struct, which includes the name for this node
  uint32_t property_entry;

  // Children are a sorted list of child nodes_; binary search them.
  uint32_t num_child_nodes;
  uint32_t child_nodes;

  // Prefixes are terminating prefix matches at this node, sorted longest to smallest
  // Take the first match sequentially found with StartsWith().
  uint32_t num_prefixes;
  uint32_t prefix_entries;

  // Exact matches are a sorted list of exact matches at this node_; binary search them.
  uint32_t num_exact_matches;
  uint32_t exact_match_entries;
};

struct PropertyInfoAreaHeader {
  // The current version of this data as created by property service.
  uint32_t current_version;
  // The lowest version of libc that can properly parse this data.
  uint32_t minimum_supported_version;
  uint32_t size;
  uint32_t contexts_offset;
  uint32_t schemas_offset;
  uint32_t root_offset;
};

class SerializedData {
 public:
  uint32_t size() const {
    return reinterpret_cast<const PropertyInfoAreaHeader*>(data_base_)->size;
  }

  const char* c_string(uint32_t offset) const {
    if (offset != 0 && offset > size()) return nullptr;
    return static_cast<const char*>(data_base_ + offset);
  }

  const uint32_t* uint32_array(uint32_t offset) const {
    if (offset != 0 && offset > size()) return nullptr;
    return reinterpret_cast<const uint32_t*>(data_base_ + offset);
  }

  uint32_t uint32(uint32_t offset) const {
    if (offset != 0 && offset > size()) return ~0u;
    return *reinterpret_cast<const uint32_t*>(data_base_ + offset);
  }

  const char* data_base() const { return data_base_; }

 private:
  const char data_base_[0];
};

class TrieNode {
 public:
  TrieNode() : serialized_data_(nullptr), trie_node_base_(nullptr) {}
  TrieNode(const SerializedData* data_base, const TrieNodeInternal* trie_node_base)
      : serialized_data_(data_base), trie_node_base_(trie_node_base) {}

  const char* name() const {
    return serialized_data_->c_string(node_property_entry()->name_offset);
  }

  uint32_t context_index() const { return node_property_entry()->context_index; }
  uint32_t schema_index() const { return node_property_entry()->schema_index; }

  uint32_t num_child_nodes() const { return trie_node_base_->num_child_nodes; }
  TrieNode child_node(int n) const {
    uint32_t child_node_offset = serialized_data_->uint32_array(trie_node_base_->child_nodes)[n];
    const TrieNodeInternal* trie_node_base =
        reinterpret_cast<const TrieNodeInternal*>(serialized_data_->data_base() + child_node_offset);
    return TrieNode(serialized_data_, trie_node_base);
  }

  bool FindChildForString(const char* input, uint32_t namelen, TrieNode* child) const;

  uint32_t num_prefixes() const { return trie_node_base_->num_prefixes; }
  const PropertyEntry* prefix(int n) const {
    uint32_t prefix_entry_offset =
        serialized_data_->uint32_array(trie_node_base_->prefix_entries)[n];
    return reinterpret_cast<const PropertyEntry*>(serialized_data_->data_base() +
                                                  prefix_entry_offset);
  }

  uint32_t num_exact_matches() const { return trie_node_base_->num_exact_matches; }
  const PropertyEntry* exact_match(int n) const {
    uint32_t exact_match_entry_offset =
        serialized_data_->uint32_array(trie_node_base_->exact_match_entries)[n];
    return reinterpret_cast<const PropertyEntry*>(serialized_data_->data_base() +
                                                  exact_match_entry_offset);
  }

 private:
  const PropertyEntry* node_property_entry() const {
    return reinterpret_cast<const PropertyEntry*>(serialized_data_->data_base() +
                                                  trie_node_base_->property_entry);
  }

  const SerializedData* serialized_data_;
  const TrieNodeInternal* trie_node_base_;
};

class PropertyInfoArea : private SerializedData {
 public:
  void GetPropertyInfoIndexes(const char* name, uint32_t* context_index,
                              uint32_t* schema_index) const;
  void GetPropertyInfo(const char* property, const char** context, const char** schema) const;

  int FindContextIndex(const char* context) const;
  int FindSchemaIndex(const char* schema) const;

  const char* context(uint32_t index) const {
    uint32_t context_array_size_offset = contexts_offset();
    const uint32_t* context_array = uint32_array(context_array_size_offset + sizeof(uint32_t));
    return data_base() + context_array[index];
  }

  const char* schema(uint32_t index) const {
    uint32_t schema_array_size_offset = schemas_offset();
    const uint32_t* schema_array = uint32_array(schema_array_size_offset + sizeof(uint32_t));
    return data_base() + schema_array[index];
  }

  uint32_t current_version() const { return header()->current_version; }
  uint32_t minimum_supported_version() const { return header()->minimum_supported_version; }

  uint32_t size() const { return SerializedData::size(); }

  uint32_t num_contexts() const { return uint32_array(contexts_offset())[0]; }
  uint32_t num_schemas() const { return uint32_array(schemas_offset())[0]; }

  TrieNode root_node() const { return trie(header()->root_offset); }

 private:
  void CheckPrefixMatch(const char* remaining_name, const TrieNode& trie_node,
                        uint32_t* context_index, uint32_t* schema_index) const;

  const PropertyInfoAreaHeader* header() const {
    return reinterpret_cast<const PropertyInfoAreaHeader*>(data_base());
  }
  uint32_t contexts_offset() const { return header()->contexts_offset; }
  uint32_t contexts_array_offset() const { return contexts_offset() + sizeof(uint32_t); }
  uint32_t schemas_offset() const { return header()->schemas_offset; }
  uint32_t schemas_array_offset() const { return schemas_offset() + sizeof(uint32_t); }

  TrieNode trie(uint32_t offset) const {
    if (offset != 0 && offset > size()) return TrieNode();
    const TrieNodeInternal* trie_node_base =
        reinterpret_cast<const TrieNodeInternal*>(data_base() + offset);
    return TrieNode(this, trie_node_base);
  }
};

// This is essentially a smart pointer for read only mmap region for property contexts.
class PropertyInfoAreaFile {
 public:
  PropertyInfoAreaFile() : mmap_base_(nullptr), mmap_size_(0) {}
  ~PropertyInfoAreaFile() { Reset(); }

  PropertyInfoAreaFile(const PropertyInfoAreaFile&) = delete;
  void operator=(const PropertyInfoAreaFile&) = delete;
  PropertyInfoAreaFile(PropertyInfoAreaFile&&) = default;
  PropertyInfoAreaFile& operator=(PropertyInfoAreaFile&&) = default;

  bool LoadDefaultPath();
  bool LoadPath(const char* filename);

  const PropertyInfoArea* operator->() const {
    return reinterpret_cast<const PropertyInfoArea*>(mmap_base_);
  }

  explicit operator bool() const { return mmap_base_ != nullptr; }

  void Reset();

 private:
  void* mmap_base_;
  size_t mmap_size_;
};

}  // namespace properties
}  // namespace android

#endif