/*
* Copyright 2012, 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 LLVM_WRAP_BCHEADER_FIELD_H__
#define LLVM_WRAP_BCHEADER_FIELD_H__
#include <stdint.h>
#include <stdio.h>
#include <string.h>
// Class representing a variable-size metadata field in the bitcode header.
// Also contains the list of known Tag IDs.
// Contains a pointer to the data but does not own the data, so it can be
// copied with the trivial copy constructor/assignment operator.
// The serialized format has 2 fixed subfields (ID and length) and the
// variable-length data subfield
class BCHeaderField {
public:
typedef enum {
kInvalid = 0,
kBitcodeHash = 1,
kAndroidCompilerVersion = 0x4001,
kAndroidOptimizationLevel = 0x4002
} Tag;
typedef uint16_t FixedSubfield;
BCHeaderField(Tag ID, size_t len, uint8_t* data) :
ID_(ID), len_(len), data_(data) {}
size_t GetTotalSize() {
// Round up to 4 byte alignment
return (kTagLenSize + len_ + 3) & ~3;
}
bool Write(uint8_t* buf, size_t buf_len) {
size_t fields_len = kTagLenSize + len_;
size_t pad_len = (4 - (fields_len & 3)) & 3;
// Ensure buffer is large enough and that length can be represented
// in 16 bits
const size_t max_uint16_t = 65535;
if (buf_len < fields_len + pad_len ||
len_ > max_uint16_t) return false;
WriteFixedSubfield(static_cast<FixedSubfield>(ID_), buf);
WriteFixedSubfield(static_cast<FixedSubfield>(len_),
buf + sizeof(FixedSubfield));
memcpy(buf + kTagLenSize, data_, len_);
// Pad out to 4 byte alignment
if (pad_len) {
memset(buf + fields_len, 0, pad_len);
}
return true;
}
bool Read(const uint8_t* buf, size_t buf_len) {
if (buf_len < kTagLenSize) return false;
FixedSubfield field;
ReadFixedSubfield(&field, buf);
ID_ = static_cast<Tag>(field);
ReadFixedSubfield(&field, buf + sizeof(FixedSubfield));
len_ = static_cast<size_t>(field);
if (buf_len < kTagLenSize + len_) return false;
memcpy(data_, buf + kTagLenSize, len_);
return true;
}
void Print() {
fprintf(stderr, "Field ID: %d, data length %d, total length %d\n",
ID_, static_cast<int>(len_), static_cast<int>(GetTotalSize()));
fprintf(stderr, "Data:");
for (size_t i = 0; i < len_; i++) fprintf(stderr, "0x%x ", data_[i]);
fprintf(stderr, "\n");
}
// Get the data size from a serialized field to allow allocation
static size_t GetDataSizeFromSerialized(const uint8_t* buf) {
FixedSubfield len;
ReadFixedSubfield(&len, buf + sizeof(FixedSubfield));
return len;
}
Tag getID() const {
return ID_;
}
size_t getLen() const {
return len_;
}
private:
// Combined size of the fixed subfields
const static size_t kTagLenSize = 2 * sizeof(FixedSubfield);
static void WriteFixedSubfield(FixedSubfield value, uint8_t* buf) {
buf[0] = value & 0xFF;
buf[1] = (value >> 8) & 0xFF;
}
static void ReadFixedSubfield(FixedSubfield* value, const uint8_t* buf) {
*value = buf[0] | buf[1] << 8;
}
Tag ID_;
size_t len_;
uint8_t *data_;
};
#endif // LLVM_WRAP_BCHEADER_FIELD_H__