text: // 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/nacl_host/nacl_validation_cache.h"
  
  #include "base/pickle.h"
  #include "base/rand_util.h"
  
  namespace {
  
  // For the moment, choose an arbitrary cache size.
  const size_t kValidationCacheCacheSize = 200;
  // Key size is equal to the block size (not the digest size) of SHA256.
  const size_t kValidationCacheKeySize = 64;
  // Entry size is equal to the digest size of SHA256.
  const size_t kValidationCacheEntrySize = 32;
  
  const char kValidationCacheBeginMagic[] = "NaCl";
  const char kValidationCacheEndMagic[] = "Done";
  
  }  // namespace
  
  NaClValidationCache::NaClValidationCache()
      : validation_cache_(kValidationCacheCacheSize) {
    // Make sure the cache key is unpredictable, even if the cache has not
    // been loaded.
    Reset();
  }
  
  NaClValidationCache::~NaClValidationCache() {
    // Make clang's style checking happy by adding a destructor.
  }
  
  bool NaClValidationCache::QueryKnownToValidate(const std::string& signature,
                                                 bool reorder) {
    if (signature.length() == kValidationCacheEntrySize) {
      ValidationCacheType::iterator iter;
      if (reorder) {
        iter = validation_cache_.Get(signature);
      } else {
        iter = validation_cache_.Peek(signature);
      }
      if (iter != validation_cache_.end()) {
        return iter->second;
      }
    }
    return false;
  }
  
  void NaClValidationCache::SetKnownToValidate(const std::string& signature) {
    if (signature.length() == kValidationCacheEntrySize) {
      validation_cache_.Put(signature, true);
    }
  }
  
  void NaClValidationCache::Serialize(Pickle* pickle) const {
    // Mark the beginning of the data stream.
    pickle->WriteString(kValidationCacheBeginMagic);
    pickle->WriteString(validation_cache_key_);
    pickle->WriteInt(validation_cache_.size());
  
    // Serialize the cache in reverse order so that deserializing it can easily
    // preserve the MRU order.  (Last item deserialized => most recently used.)
    ValidationCacheType::const_reverse_iterator iter;
    for (iter = validation_cache_.rbegin();
         iter != validation_cache_.rend();
         ++iter) {
      pickle->WriteString(iter->first);
    }
  
    // Mark the end of the data stream.
    pickle->WriteString(kValidationCacheEndMagic);
  }
  
  void NaClValidationCache::Reset() {
    validation_cache_key_ = base::RandBytesAsString(kValidationCacheKeySize);
    validation_cache_.Clear();
  }
  
  bool NaClValidationCache::Deserialize(const Pickle* pickle) {
    bool success = DeserializeImpl(pickle);
    if (!success) {
      Reset();
    }
    return success;
  }
  
  bool NaClValidationCache::DeserializeImpl(const Pickle* pickle) {
    PickleIterator iter(*pickle);
    std::string buffer;
    int count;
  
    // Magic
    if (!iter.ReadString(&buffer))
      return false;
    if (0 != buffer.compare(kValidationCacheBeginMagic))
      return false;
  
    // Key
    if (!iter.ReadString(&buffer))
      return false;
    if (buffer.size() != kValidationCacheKeySize)
      return false;
  
    validation_cache_key_ = buffer;
    validation_cache_.Clear();
  
    // Cache entries
    if (!iter.ReadInt(&count))
      return false;
    for (int i = 0; i < count; ++i) {
      if (!iter.ReadString(&buffer))
        return false;
      if (buffer.size() != kValidationCacheEntrySize)
        return false;
      validation_cache_.Put(buffer, true);
    }
  
    // Magic
    if (!iter.ReadString(&buffer))
      return false;
    if (0 != buffer.compare(kValidationCacheEndMagic))
      return false;
  
    // Success!
    return true;
  }
  
  