/*
 * Copyright 2012 Google Inc.
 *
 * 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.
 */

// Author: jmarantz@google.com (Joshua Marantz)

#include "pagespeed/kernel/cache/key_value_codec.h"

#include <limits.h>                     // for CHAR_BIT
#include <cstddef>

#include "pagespeed/kernel/base/basictypes.h"
#include "pagespeed/kernel/base/shared_string.h"
#include "pagespeed/kernel/base/string.h"
#include "pagespeed/kernel/base/string_util.h"

namespace {

// We can't store arbitrary keys in some caches (e.g. memcached), so
// encode the actual key in the value.  Thus in the unlikely event of
// a hash collision, we can reject the mismatched full key when
// reading.
//
// We encode the length as the last two bytes.  Keys of length greater than
// 65535 bytes result in an encode failure, and false returned.
const int kKeySizeOverheadBytes = 2;
const size_t kKeyMaxLength = (1 << (kKeySizeOverheadBytes * CHAR_BIT)) - 1;

}  // namespace

namespace net_instaweb {

namespace key_value_codec {

// Takes a key and a value, and encodes the pair of them into key_value,
// sharing storage with value.
//
// The encoding format is [value, key, 2 bytes of key size].
bool Encode(StringPiece key, SharedString* value, SharedString* key_value) {
  if (key.size() > kKeyMaxLength) {
    return false;
  }
  uint32 key_size = key.size();
  *key_value = *value;
  key_value->Append(key);
  uint8 ch = key_size & 0xff;
  key_value->Append(reinterpret_cast<char*>(&ch), 1);
  ch = (key_size >> 8) & 0xff;
  key_value->Append(reinterpret_cast<char*>(&ch), 1);
  return true;
}

// Takes a combined key and a value, and decodes them into key and value,
// sharing the storage with key_value.
bool Decode(SharedString* key_value, GoogleString* key, SharedString* value) {
  int key_value_size = key_value->size();
  if (key_value_size < kKeySizeOverheadBytes) {
    return false;
  }
  const uint8* data = reinterpret_cast<const uint8*>(key_value->data());
  int key_size = data[key_value_size - 1];
  key_size <<= 8;
  key_size |= data[key_value_size - 2];
  key_value_size -= kKeySizeOverheadBytes;  // ignore overhead now.
  if (key_value_size < key_size) {
    return false;
  }
  uint32 value_size = key_value_size - key_size;
  key->assign(reinterpret_cast<const char*>(data) + value_size, key_size);
  *value = *key_value;  // Shares string storage, but with different prefixes.
  value->RemoveSuffix(key_size + kKeySizeOverheadBytes);
  return true;
}

int GetValueSizeFromKeyAndKeyValue(StringPiece key,
                                   const SharedString& key_and_value) {
  return key_and_value.size() - key.size() - kKeySizeOverheadBytes;
}

}  // namespace key_value_codec

}  // namespace net_instaweb
