summaryrefslogtreecommitdiff
path: root/cmds/idmap2/libidmap2/BinaryStreamVisitor.cpp
blob: b029aea1a1bff9f49bfa150de58756926ff45fdd (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
131
132
133
134
135
136
137
138
139
140
141
142
143
/*
 * Copyright (C) 2018 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.
 */

#include "idmap2/BinaryStreamVisitor.h"

#include <algorithm>
#include <cstring>
#include <string>

#include "android-base/macros.h"

namespace android::idmap2 {

void BinaryStreamVisitor::Write8(uint8_t value) {
  stream_.write(reinterpret_cast<char*>(&value), sizeof(uint8_t));
}

void BinaryStreamVisitor::Write16(uint16_t value) {
  uint16_t x = htodl(value);
  stream_.write(reinterpret_cast<char*>(&x), sizeof(uint16_t));
}

void BinaryStreamVisitor::Write32(uint32_t value) {
  uint32_t x = htodl(value);
  stream_.write(reinterpret_cast<char*>(&x), sizeof(uint32_t));
}

void BinaryStreamVisitor::WriteString(StringPiece value) {
  // pad with null to nearest word boundary;
  size_t padding_size = CalculatePadding(value.size());
  Write32(value.size());
  stream_.write(value.data(), value.size());
  stream_.write("\0\0\0\0", padding_size);
}

void BinaryStreamVisitor::visit(const Idmap& idmap ATTRIBUTE_UNUSED) {
  // nothing to do
}

void BinaryStreamVisitor::visit(const IdmapHeader& header) {
  Write32(header.GetMagic());
  Write32(header.GetVersion());
  Write32(header.GetTargetCrc());
  Write32(header.GetOverlayCrc());
  Write32(header.GetFulfilledPolicies());
  Write32(static_cast<uint8_t>(header.GetEnforceOverlayable()));
  WriteString(header.GetTargetPath());
  WriteString(header.GetOverlayPath());
  WriteString(header.GetOverlayName());
  WriteString(header.GetDebugInfo());
}

void BinaryStreamVisitor::visit(const IdmapConstraints& constraints) {
  Write32(static_cast<uint32_t>(constraints.constraints.size()));
  for (const auto& constraint : constraints.constraints) {
    Write32(constraint.constraint_type);
    Write32(constraint.constraint_value);
  }
}

void BinaryStreamVisitor::visit(const IdmapData& data) {
  for (const auto& target_entry : data.GetTargetEntries()) {
    Write32(target_entry.target_id);
  }
  for (const auto& target_entry : data.GetTargetEntries()) {
    Write32(target_entry.overlay_id);
  }

  uint32_t current_inline_entry_values_count = 0;
  for (const auto& target_inline_entry : data.GetTargetInlineEntries()) {
    Write32(target_inline_entry.target_id);
  }
  for (const auto& target_inline_entry : data.GetTargetInlineEntries()) {
    Write32(current_inline_entry_values_count);
    Write32(target_inline_entry.values.size());
    current_inline_entry_values_count += target_inline_entry.values.size();
  }

  std::vector<ConfigDescription> configs;
  configs.reserve(data.GetHeader()->GetConfigCount());
  for (const auto& target_entry : data.GetTargetInlineEntries()) {
    for (const auto& target_entry_value : target_entry.values) {
      auto config_it = std::find(configs.begin(), configs.end(), target_entry_value.first);
      if (config_it != configs.end()) {
        Write32(config_it - configs.begin());
      } else {
        Write32(configs.size());
        configs.push_back(target_entry_value.first);
      }
      // We're writing a Res_value entry here, and the first 3 bytes of that are
      // sizeof() + a padding 0 byte
      static constexpr decltype(android::Res_value::size) kSize = sizeof(android::Res_value);
      Write16(kSize);
      Write8(0U);
      Write8(target_entry_value.second.data_type);
      Write32(target_entry_value.second.data_value);
    }
  }

  if (!configs.empty()) {
    stream_.write(reinterpret_cast<const char*>(&configs.front()),
                  sizeof(configs.front()) * configs.size());
    if (configs.size() >= 100) {
      // Let's write a message to future us so that they know when to replace the linear search
      // in `configs` vector with something more efficient.
      LOG(WARNING) << "Idmap got " << configs.size()
                   << " configurations, time to fix the bruteforce search";
    }
  }

  for (const auto& overlay_entry : data.GetOverlayEntries()) {
    Write32(overlay_entry.overlay_id);
  }
  for (const auto& overlay_entry : data.GetOverlayEntries()) {
    Write32(overlay_entry.target_id);
  }

  WriteString(data.GetStringPoolData());
}

void BinaryStreamVisitor::visit(const IdmapData::Header& header) {
  Write32(header.GetTargetEntryCount());
  Write32(header.GetTargetInlineEntryCount());
  Write32(header.GetTargetInlineEntryValueCount());
  Write32(header.GetConfigCount());
  Write32(header.GetOverlayEntryCount());
  Write32(header.GetStringPoolIndexOffset());
}

}  // namespace android::idmap2