blob: 11e58689341114b0f874355ea29de38f6ca8d82b [file] [log] [blame]
// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/safe_browsing/safe_browsing_util.h"
#include <utility>
#include "base/strings/string_util.h"
#include "chrome/browser/safe_browsing/chunk.pb.h"
#include "components/google/core/browser/google_util.h"
namespace safe_browsing {
// SBChunkData -----------------------------------------------------------------
// TODO(shess): Right now this contains a std::unique_ptr<ChunkData> so that the
// proto buffer isn't copied all over the place, then these are contained in a
// ScopedVector for purposes of passing things around between tasks. This seems
// convoluted. Maybe it would make sense to have an overall container class
// returning references to a nested per-chunk class?
SBChunkData::SBChunkData() {
}
SBChunkData::SBChunkData(std::unique_ptr<ChunkData> data)
: chunk_data_(std::move(data)) {
DCHECK(chunk_data_.get());
}
SBChunkData::~SBChunkData() {
}
bool SBChunkData::ParseFrom(const unsigned char* data, size_t length) {
std::unique_ptr<ChunkData> chunk(new ChunkData());
if (!chunk->ParseFromArray(data, length))
return false;
if (chunk->chunk_type() != ChunkData::ADD &&
chunk->chunk_type() != ChunkData::SUB) {
return false;
}
size_t hash_size = 0;
if (chunk->prefix_type() == ChunkData::PREFIX_4B) {
hash_size = sizeof(SBPrefix);
} else if (chunk->prefix_type() == ChunkData::FULL_32B) {
hash_size = sizeof(SBFullHash);
} else {
return false;
}
const size_t hash_count = chunk->hashes().size() / hash_size;
if (hash_count * hash_size != chunk->hashes().size())
return false;
if (chunk->chunk_type() == ChunkData::SUB &&
static_cast<size_t>(chunk->add_numbers_size()) != hash_count) {
return false;
}
chunk_data_.swap(chunk);
return true;
}
int SBChunkData::ChunkNumber() const {
return chunk_data_->chunk_number();
}
bool SBChunkData::IsAdd() const {
return chunk_data_->chunk_type() == ChunkData::ADD;
}
bool SBChunkData::IsSub() const {
return chunk_data_->chunk_type() == ChunkData::SUB;
}
int SBChunkData::AddChunkNumberAt(size_t i) const {
DCHECK(IsSub());
DCHECK((IsPrefix() && i < PrefixCount()) ||
(IsFullHash() && i < FullHashCount()));
return chunk_data_->add_numbers(i);
}
bool SBChunkData::IsPrefix() const {
return chunk_data_->prefix_type() == ChunkData::PREFIX_4B;
}
size_t SBChunkData::PrefixCount() const {
DCHECK(IsPrefix());
return chunk_data_->hashes().size() / sizeof(SBPrefix);
}
SBPrefix SBChunkData::PrefixAt(size_t i) const {
DCHECK(IsPrefix());
DCHECK_LT(i, PrefixCount());
SBPrefix prefix;
memcpy(&prefix, chunk_data_->hashes().data() + i * sizeof(SBPrefix),
sizeof(SBPrefix));
return prefix;
}
bool SBChunkData::IsFullHash() const {
return chunk_data_->prefix_type() == ChunkData::FULL_32B;
}
size_t SBChunkData::FullHashCount() const {
DCHECK(IsFullHash());
return chunk_data_->hashes().size() / sizeof(SBFullHash);
}
SBFullHash SBChunkData::FullHashAt(size_t i) const {
DCHECK(IsFullHash());
DCHECK_LT(i, FullHashCount());
SBFullHash full_hash;
memcpy(&full_hash, chunk_data_->hashes().data() + i * sizeof(SBFullHash),
sizeof(SBFullHash));
return full_hash;
}
// SBListChunkRanges -----------------------------------------------------------
SBListChunkRanges::SBListChunkRanges(const std::string& n)
: name(n) {
}
// SBChunkDelete ---------------------------------------------------------------
SBChunkDelete::SBChunkDelete() : is_sub_del(false) {}
SBChunkDelete::SBChunkDelete(const SBChunkDelete& other) = default;
SBChunkDelete::~SBChunkDelete() {}
} // namespace safe_browsing