text:
using media::Decryptor;
using media::MediaKeys;
using media::NewSessionCdmPromise;
using media::SimpleCdmPromise;
using ppapi::ArrayBufferVar;
using ppapi::ArrayVar;
using ppapi::PpapiGlobals;
using ppapi::ScopedPPResource;
using ppapi::StringVar;
using ppapi::thunk::EnterResourceNoLock;
using ppapi::thunk::PPB_Buffer_API;

namespace content {

namespace {

// Fills |resource| with a PPB_Buffer_Impl and copies |data| into the buffer
// resource. The |*resource|, if valid, will be in the ResourceTracker with a
// reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns
// true upon success and false if any error happened.
bool MakeBufferResource(PP_Instance instance,
                        const std::vector<uint8_t>& data,
                        scoped_refptr<PPB_Buffer_Impl>* resource) {
  TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource");
  DCHECK(resource);

  if (data.empty()) {
    resource = NULL;
    return true;
  }

  scoped_refptr<PPB_Buffer_Impl> buffer(
      PPB_Buffer_Impl::CreateResource(instance, data.size()));
  if (!buffer.get())
    return false;

  BufferAutoMapper mapper(buffer.get());
  if (!mapper.data() || mapper.size() < data.size())
    return false;
  memcpy(mapper.data(), &data[0], data.size());

  *resource = buffer;
  return true;
}

// Copies the content of |str| into |array|.
// Returns true if copy succeeded. Returns false if copy failed, e.g. if the
// |array_size| is smaller than the |str| length.
template <uint32_t array_size>
bool CopyStringToArray(const std::string& str, uint8_t(&array)[array_size]) {
  if (array_size < str.size())
    return false;

  memcpy(array, str.data(), str.size());
  return true;
}

// Fills the |block_info| with information from |encrypted_buffer|.
//
// Returns true if |block_info| is successfully filled. Returns false
// otherwise.
bool MakeEncryptedBlockInfo(
    const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
    uint32_t request_id,
    PP_EncryptedBlockInfo* block_info) {
  // TODO(xhwang): Fix initialization of PP_EncryptedBlockInfo here and
  // anywhere else.
  memset(block_info, 0, sizeof(*block_info));
  block_info->tracking_info.request_id = request_id;

  // EOS buffers need a request ID and nothing more.
  if (encrypted_buffer->end_of_stream())
    return true;

  DCHECK(encrypted_buffer->data_size())
      << "DecryptConfig is set on an empty buffer";

  block_info->tracking_info.timestamp =
      encrypted_buffer->timestamp().InMicroseconds();
  block_info->data_size = encrypted_buffer->data_size();

  const media::DecryptConfig* decrypt_config =
      encrypted_buffer->decrypt_config();

  if (!CopyStringToArray(decrypt_config->key_id(), block_info->key_id) ||
      !CopyStringToArray(decrypt_config->iv(), block_info->iv))
    return false;

  block_info->key_id_size = decrypt_config->key_id().size();
  block_info->iv_size = decrypt_config->iv().size();

  if (decrypt_config->subsamples().size() > arraysize(block_info->subsamples))
    return false;

  block_info->num_subsamples = decrypt_config->subsamples().size();
  for (uint32_t i = 0; i < block_info->num_subsamples; ++i) {
    block_info->subsamples[i].clear_bytes =
        decrypt_config->subsamples()[i].clear_bytes;
    block_info->subsamples[i].cipher_bytes =
        decrypt_config->subsamples()[i].cypher_bytes;
  }

  return true;
}

PP_AudioCodec MediaAudioCodecToPpAudioCodec(media::AudioCodec codec) {
  switch (codec) {
    case media::kCodecVorbis:
      return PP_AUDIOCODEC_VORBIS;
    case media::kCodecAAC:
      return PP_AUDIOCODEC_AAC;
    default:
      return PP_AUDIOCODEC_UNKNOWN;
  }
}

PP_VideoCodec MediaVideoCodecToPpVideoCodec(media::VideoCodec codec) {
  switch (codec) {
    case media::kCodecVP8:
      return PP_VIDEOCODEC_VP8;
    case media::kCodecH264:
      return PP_VIDEOCODEC_H264;
    case media::kCodecVP9:
      return PP_VIDEOCODEC_VP9;
    default:
      return PP_VIDEOCODEC_UNKNOWN;
  }
}

PP_VideoCodecProfile MediaVideoCodecProfileToPpVideoCodecProfile(
    media::VideoCodecProfile profile) {
  switch (profile) {
    case media::VP8PROFILE_ANY:
    case media::VP9PROFILE_ANY:
      return PP_VIDEOCODECPROFILE_NOT_NEEDED;
    case media::H264PROFILE_BASELINE:
      return PP_VIDEOCODECPROFILE_H264_BASELINE;
    case media::H264PROFILE_MAIN:
      return PP_VIDEOCODECPROFILE_H264_MAIN;
    case media::H264PROFILE_EXTENDED:
      return PP_VIDEOCODECPROFILE_H264_EXTENDED;
    case media::H264PROFILE_HIGH:
      return PP_VIDEOCODECPROFILE_H264_HIGH;
    case media::H264PROFILE_HIGH10PROFILE:
      return PP_VIDEOCODECPROFILE_H264_HIGH_10;
    case media::H264PROFILE_HIGH422PROFILE:
      return PP_VIDEOCODECPROFILE_H264_HIGH_422;
    case media::H264PROFILE_HIGH444PREDICTIVEPROFILE:
      return PP_VIDEOCODECPROFILE_H264_HIGH_444_PREDICTIVE;
    default:
      return PP_VIDEOCODECPROFILE_UNKNOWN;
  }
}

PP_DecryptedFrameFormat MediaVideoFormatToPpDecryptedFrameFormat(
    media::VideoPixelFormat format) {
  switch (format) {
    case media::PIXEL_FORMAT_YV12:
      return PP_DECRYPTEDFRAMEFORMAT_YV12;
    case media::PIXEL_FORMAT_I420:
      return PP_DECRYPTEDFRAMEFORMAT_I420;
    default:
      return PP_DECRYPTEDFRAMEFORMAT_UNKNOWN;
  }
}

Decryptor::Status PpDecryptResultToMediaDecryptorStatus(
    PP_DecryptResult result) {
  switch (result) {
    case PP_DECRYPTRESULT_SUCCESS:
      return Decryptor::kSuccess;
    case PP_DECRYPTRESULT_DECRYPT_NOKEY:
      return Decryptor::kNoKey;
    case PP_DECRYPTRESULT_NEEDMOREDATA:
      return Decryptor::kNeedMoreData;
    case PP_DECRYPTRESULT_DECRYPT_ERROR:
      return Decryptor::kError;
    case PP_DECRYPTRESULT_DECODE_ERROR:
      return Decryptor::kError;
    default:
      NOTREACHED();
      return Decryptor::kError;
  }
}

PP_DecryptorStreamType MediaDecryptorStreamTypeToPpStreamType(
    Decryptor::StreamType stream_type) {
  switch (stream_type) {
    case Decryptor::kAudio:
      return PP_DECRYPTORSTREAMTYPE_AUDIO;
    case Decryptor::kVideo:
      return PP_DECRYPTORSTREAMTYPE_VIDEO;
    default:
      NOTREACHED();
      return PP_DECRYPTORSTREAMTYPE_VIDEO;
  }
}

media::SampleFormat PpDecryptedSampleFormatToMediaSampleFormat(
    PP_DecryptedSampleFormat result) {
  switch (result) {
    case PP_DECRYPTEDSAMPLEFORMAT_U8:
      return media::kSampleFormatU8;
    case PP_DECRYPTEDSAMPLEFORMAT_S16:
      return media::kSampleFormatS16;
    case PP_DECRYPTEDSAMPLEFORMAT_S32:
      return media::kSampleFormatS32;
    case PP_DECRYPTEDSAMPLEFORMAT_F32:
      return media::kSampleFormatF32;
    case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_S16:
      return media::kSampleFormatPlanarS16;
    case PP_DECRYPTEDSAMPLEFORMAT_PLANAR_F32:
      return media::kSampleFormatPlanarF32;
    default:
      NOTREACHED();
      return media::kUnknownSampleFormat;
  }
}

PP_SessionType MediaSessionTypeToPpSessionType(
    MediaKeys::SessionType session_type) {
  switch (session_type) {
    case MediaKeys::TEMPORARY_SESSION:
      return PP_SESSIONTYPE_TEMPORARY;
    case MediaKeys::PERSISTENT_LICENSE_SESSION:
      return PP_SESSIONTYPE_PERSISTENT_LICENSE;
    case MediaKeys::PERSISTENT_RELEASE_MESSAGE_SESSION:
      return PP_SESSIONTYPE_PERSISTENT_RELEASE;
    default:
      NOTREACHED();
      return PP_SESSIONTYPE_TEMPORARY;
  }
}

PP_InitDataType MediaInitDataTypeToPpInitDataType(
    media::EmeInitDataType init_data_type) {
  switch (init_data_type) {
    case media::EmeInitDataType::CENC:
      return PP_INITDATATYPE_CENC;
    case media::EmeInitDataType::KEYIDS:
      return PP_INITDATATYPE_KEYIDS;
    case media::EmeInitDataType::WEBM:
      return PP_INITDATATYPE_WEBM;
    case media::EmeInitDataType::UNKNOWN:
      break;
  }
  NOTREACHED();
  return PP_INITDATATYPE_KEYIDS;
}

MediaKeys::Exception PpExceptionTypeToMediaException(
    PP_CdmExceptionCode exception_code) {
  switch (exception_code) {
    case PP_CDMEXCEPTIONCODE_NOTSUPPORTEDERROR:
      return MediaKeys::NOT_SUPPORTED_ERROR;
    case PP_CDMEXCEPTIONCODE_INVALIDSTATEERROR:
      return MediaKeys::INVALID_STATE_ERROR;
    case PP_CDMEXCEPTIONCODE_INVALIDACCESSERROR:
      return MediaKeys::INVALID_ACCESS_ERROR;
    case PP_CDMEXCEPTIONCODE_QUOTAEXCEEDEDERROR:
      return MediaKeys::QUOTA_EXCEEDED_ERROR;
    case PP_CDMEXCEPTIONCODE_UNKNOWNERROR:
      return MediaKeys::UNKNOWN_ERROR;
    case PP_CDMEXCEPTIONCODE_CLIENTERROR:
      return MediaKeys::CLIENT_ERROR;
    case PP_CDMEXCEPTIONCODE_OUTPUTERROR:
      return MediaKeys::OUTPUT_ERROR;
    default:
      NOTREACHED();
      return MediaKeys::UNKNOWN_ERROR;
  }
}

media::CdmKeyInformation::KeyStatus PpCdmKeyStatusToCdmKeyInformationKeyStatus(
    PP_CdmKeyStatus status) {
  switch (status) {
    case PP_CDMKEYSTATUS_USABLE:
      return media::CdmKeyInformation::USABLE;
    case PP_CDMKEYSTATUS_INVALID:
      return media::CdmKeyInformation::INTERNAL_ERROR;
    case PP_CDMKEYSTATUS_EXPIRED:
      return media::CdmKeyInformation::EXPIRED;
    case PP_CDMKEYSTATUS_OUTPUTRESTRICTED:
      return media::CdmKeyInformation::OUTPUT_RESTRICTED;
    case PP_CDMKEYSTATUS_OUTPUTDOWNSCALED:
      return media::CdmKeyInformation::OUTPUT_DOWNSCALED;
    case PP_CDMKEYSTATUS_STATUSPENDING:
      return media::CdmKeyInformation::KEY_STATUS_PENDING;
    case PP_CDMKEYSTATUS_RELEASED:
      return media::CdmKeyInformation::RELEASED;
    default:
      NOTREACHED();
      return media::CdmKeyInformation::INTERNAL_ERROR;
  }
}

MediaKeys::MessageType PpCdmMessageTypeToMediaMessageType(
    PP_CdmMessageType message_type) {
  switch (message_type) {
    case PP_CDMMESSAGETYPE_LICENSE_REQUEST:
      return MediaKeys::LICENSE_REQUEST;
    case PP_CDMMESSAGETYPE_LICENSE_RENEWAL:
      return MediaKeys::LICENSE_RENEWAL;
    case PP_CDMMESSAGETYPE_LICENSE_RELEASE:
      return MediaKeys::LICENSE_RELEASE;
    default:
      NOTREACHED();
      return MediaKeys::LICENSE_REQUEST;
  }
}

// TODO(xhwang): Unify EME UMA reporting code when prefixed EME is deprecated.
// See http://crbug.com/412987 for details.
void ReportSystemCodeUMA(const std::string& key_system, uint32_t system_code) {
  // Sparse histogram macro does not cache the histogram, so it's safe to use
  // macro with non-static histogram name here.
  UMA_HISTOGRAM_SPARSE_SLOWLY(
      "Media.EME." + media::GetKeySystemNameForUMA(key_system) + ".SystemCode",
      system_code);
}

}  // namespace

ContentDecryptorDelegate::ContentDecryptorDelegate(
    PP_Instance pp_instance,
    const PPP_ContentDecryptor_Private* plugin_decryption_interface)
    : pp_instance_(pp_instance),
      plugin_decryption_interface_(plugin_decryption_interface),
      next_decryption_request_id_(1),
      audio_samples_per_second_(0),
      audio_channel_count_(0),
      audio_channel_layout_(media::CHANNEL_LAYOUT_NONE),
      weak_ptr_factory_(this) {
  weak_this_ = weak_ptr_factory_.GetWeakPtr();
}

ContentDecryptorDelegate::~ContentDecryptorDelegate() {
  SatisfyAllPendingCallbacksOnError();
}

void ContentDecryptorDelegate::Initialize(
    const std::string& key_system,
    bool allow_distinctive_identifier,
    bool allow_persistent_state,
    const media::SessionMessageCB& session_message_cb,
    const media::SessionClosedCB& session_closed_cb,
    const media::LegacySessionErrorCB& legacy_session_error_cb,
    const media::SessionKeysChangeCB& session_keys_change_cb,
    const media::SessionExpirationUpdateCB& session_expiration_update_cb,
    const base::Closure& fatal_plugin_error_cb,
    scoped_ptr<media::SimpleCdmPromise> promise) {
  DCHECK(!key_system.empty());
  DCHECK(key_system_.empty());
  key_system_ = key_system;

  session_message_cb_ = session_message_cb;
  session_closed_cb_ = session_closed_cb;
  legacy_session_error_cb_ = legacy_session_error_cb;
  session_keys_change_cb_ = session_keys_change_cb;
  session_expiration_update_cb_ = session_expiration_update_cb;
  fatal_plugin_error_cb_ = fatal_plugin_error_cb;

  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
  plugin_decryption_interface_->Initialize(
      pp_instance_, promise_id, StringVar::StringToPPVar(key_system_),
      PP_FromBool(allow_distinctive_identifier),
      PP_FromBool(allow_persistent_state));
}

void ContentDecryptorDelegate::InstanceCrashed() {
  fatal_plugin_error_cb_.Run();
  SatisfyAllPendingCallbacksOnError();
}

void ContentDecryptorDelegate::SetServerCertificate(
    const std::vector<uint8_t>& certificate,
    scoped_ptr<media::SimpleCdmPromise> promise) {
  if (certificate.size() < media::limits::kMinCertificateLength ||
      certificate.size() > media::limits::kMaxCertificateLength) {
    promise->reject(
        media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect certificate.");
    return;
  }

  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
  PP_Var certificate_array =
      PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
          base::checked_cast<uint32>(certificate.size()), certificate.data());
  plugin_decryption_interface_->SetServerCertificate(
      pp_instance_, promise_id, certificate_array);
}

void ContentDecryptorDelegate::CreateSessionAndGenerateRequest(
    MediaKeys::SessionType session_type,
    media::EmeInitDataType init_data_type,
    const std::vector<uint8_t>& init_data,
    scoped_ptr<NewSessionCdmPromise> promise) {
  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
  PP_Var init_data_array =
      PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
          base::checked_cast<uint32>(init_data.size()), init_data.data());
  plugin_decryption_interface_->CreateSessionAndGenerateRequest(
      pp_instance_, promise_id, MediaSessionTypeToPpSessionType(session_type),
      MediaInitDataTypeToPpInitDataType(init_data_type), init_data_array);
}

void ContentDecryptorDelegate::LoadSession(
    media::MediaKeys::SessionType session_type,
    const std::string& session_id,
    scoped_ptr<NewSessionCdmPromise> promise) {
  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
  plugin_decryption_interface_->LoadSession(
      pp_instance_, promise_id, MediaSessionTypeToPpSessionType(session_type),
      StringVar::StringToPPVar(session_id));
}

void ContentDecryptorDelegate::UpdateSession(
    const std::string& session_id,
    const std::vector<uint8_t>& response,
    scoped_ptr<SimpleCdmPromise> promise) {
  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
  PP_Var response_array =
      PpapiGlobals::Get()->GetVarTracker()->MakeArrayBufferPPVar(
          base::checked_cast<uint32>(response.size()), response.data());
  plugin_decryption_interface_->UpdateSession(
      pp_instance_, promise_id, StringVar::StringToPPVar(session_id),
      response_array);
}

void ContentDecryptorDelegate::CloseSession(
    const std::string& session_id,
    scoped_ptr<SimpleCdmPromise> promise) {
  if (session_id.length() > media::limits::kMaxSessionIdLength) {
    promise->reject(
        media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
    return;
  }

  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
  plugin_decryption_interface_->CloseSession(
      pp_instance_, promise_id, StringVar::StringToPPVar(session_id));
}

void ContentDecryptorDelegate::RemoveSession(
    const std::string& session_id,
    scoped_ptr<SimpleCdmPromise> promise) {
  if (session_id.length() > media::limits::kMaxSessionIdLength) {
    promise->reject(
        media::MediaKeys::INVALID_ACCESS_ERROR, 0, "Incorrect session.");
    return;
  }

  uint32_t promise_id = cdm_promise_adapter_.SavePromise(promise.Pass());
  plugin_decryption_interface_->RemoveSession(
      pp_instance_, promise_id, StringVar::StringToPPVar(session_id));
}

// TODO(xhwang): Remove duplication of code in Decrypt(),
// DecryptAndDecodeAudio() and DecryptAndDecodeVideo().
bool ContentDecryptorDelegate::Decrypt(
    Decryptor::StreamType stream_type,
    const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
    const Decryptor::DecryptCB& decrypt_cb) {
  DVLOG(3) << "Decrypt() - stream_type: " << stream_type;

  // |{audio|video}_input_resource_| is not being used by the plugin
  // now because there is only one pending audio/video decrypt request at any
  // time. This is enforced by the media pipeline.
  scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
  if (!MakeMediaBufferResource(
          stream_type, encrypted_buffer, &encrypted_resource) ||
      !encrypted_resource.get()) {
    return false;
  }
  ScopedPPResource pp_resource(encrypted_resource.get());

  const uint32_t request_id = next_decryption_request_id_++;
  DVLOG(2) << "Decrypt() - request_id " << request_id;

  PP_EncryptedBlockInfo block_info = {};
  DCHECK(encrypted_buffer->decrypt_config());
  if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
    return false;
  }

  // There is only one pending decrypt request at any time per stream. This is
  // enforced by the media pipeline.
  switch (stream_type) {
    case Decryptor::kAudio:
      audio_decrypt_cb_.Set(request_id, decrypt_cb);
      break;
    case Decryptor::kVideo:
      video_decrypt_cb_.Set(request_id, decrypt_cb);
      break;
    default:
      NOTREACHED();
      return false;
  }

  SetBufferToFreeInTrackingInfo(&block_info.tracking_info);

  plugin_decryption_interface_->Decrypt(pp_instance_, pp_resource, &block_info);
  return true;
}

bool ContentDecryptorDelegate::CancelDecrypt(
    Decryptor::StreamType stream_type) {
  DVLOG(3) << "CancelDecrypt() - stream_type: " << stream_type;

  Decryptor::DecryptCB decrypt_cb;
  switch (stream_type) {
    case Decryptor::kAudio:
      // Release the shared memory as it can still be in use by the plugin.
      // The next Decrypt() call will need to allocate a new shared memory
      // buffer.
      audio_input_resource_ = NULL;
      decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
      break;
    case Decryptor::kVideo:
      // Release the shared memory as it can still be in use by the plugin.
      // The next Decrypt() call will need to allocate a new shared memory
      // buffer.
      video_input_resource_ = NULL;
      decrypt_cb = video_decrypt_cb_.ResetAndReturn();
      break;
    default:
      NOTREACHED();
      return false;
  }

  if (!decrypt_cb.is_null())
    decrypt_cb.Run(Decryptor::kSuccess, NULL);

  return true;
}

bool ContentDecryptorDelegate::InitializeAudioDecoder(
    const media::AudioDecoderConfig& decoder_config,
    const Decryptor::DecoderInitCB& init_cb) {
  PP_AudioDecoderConfig pp_decoder_config;
  pp_decoder_config.codec =
      MediaAudioCodecToPpAudioCodec(decoder_config.codec());
  pp_decoder_config.channel_count =
      media::ChannelLayoutToChannelCount(decoder_config.channel_layout());
  pp_decoder_config.bits_per_channel = decoder_config.bits_per_channel();
  pp_decoder_config.samples_per_second = decoder_config.samples_per_second();
  pp_decoder_config.request_id = next_decryption_request_id_++;

  audio_samples_per_second_ = pp_decoder_config.samples_per_second;
  audio_channel_count_ = pp_decoder_config.channel_count;
  audio_channel_layout_ = decoder_config.channel_layout();

  scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
  if (!MakeBufferResource(pp_instance_,
                          decoder_config.extra_data(),
                          &extra_data_resource)) {
    return false;
  }
  ScopedPPResource pp_resource(extra_data_resource.get());

  audio_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
  plugin_decryption_interface_->InitializeAudioDecoder(
      pp_instance_, &pp_decoder_config, pp_resource);
  return true;
}

bool ContentDecryptorDelegate::InitializeVideoDecoder(
    const media::VideoDecoderConfig& decoder_config,
    const Decryptor::DecoderInitCB& init_cb) {
  PP_VideoDecoderConfig pp_decoder_config;
  pp_decoder_config.codec =
      MediaVideoCodecToPpVideoCodec(decoder_config.codec());
  pp_decoder_config.profile =
      MediaVideoCodecProfileToPpVideoCodecProfile(decoder_config.profile());
  pp_decoder_config.format =
      MediaVideoFormatToPpDecryptedFrameFormat(decoder_config.format());
  pp_decoder_config.width = decoder_config.coded_size().width();
  pp_decoder_config.height = decoder_config.coded_size().height();
  pp_decoder_config.request_id = next_decryption_request_id_++;

  scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
  if (!MakeBufferResource(pp_instance_,
                          decoder_config.extra_data(),
                          &extra_data_resource)) {
    return false;
  }
  ScopedPPResource pp_resource(extra_data_resource.get());

  video_decoder_init_cb_.Set(pp_decoder_config.request_id, init_cb);
  natural_size_ = decoder_config.natural_size();

  plugin_decryption_interface_->InitializeVideoDecoder(
      pp_instance_, &pp_decoder_config, pp_resource);
  return true;
}

bool ContentDecryptorDelegate::DeinitializeDecoder(
    Decryptor::StreamType stream_type) {
  CancelDecode(stream_type);

  if (stream_type == Decryptor::kVideo)
    natural_size_ = gfx::Size();

  // TODO(tomfinegan): Add decoder deinitialize request tracking, and get
  // stream type from media stack.
  plugin_decryption_interface_->DeinitializeDecoder(
      pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
  return true;
}

bool ContentDecryptorDelegate::ResetDecoder(Decryptor::StreamType stream_type) {
  CancelDecode(stream_type);

  // TODO(tomfinegan): Add decoder reset request tracking.
  plugin_decryption_interface_->ResetDecoder(
      pp_instance_, MediaDecryptorStreamTypeToPpStreamType(stream_type), 0);
  return true;
}

bool ContentDecryptorDelegate::DecryptAndDecodeAudio(
    const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
    const Decryptor::AudioDecodeCB& audio_decode_cb) {
  // |audio_input_resource_| is not being used by the plugin now
  // because there is only one pending audio decode request at any time.
  // This is enforced by the media pipeline.
  scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
  if (!MakeMediaBufferResource(
          Decryptor::kAudio, encrypted_buffer, &encrypted_resource)) {
    return false;
  }

  // The resource should not be NULL for non-EOS buffer.
  if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
    return false;

  const uint32_t request_id = next_decryption_request_id_++;
  DVLOG(2) << "DecryptAndDecodeAudio() - request_id " << request_id;

  PP_EncryptedBlockInfo block_info = {};
  if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
    return false;
  }

  SetBufferToFreeInTrackingInfo(&block_info.tracking_info);

  // There is only one pending audio decode request at any time. This is
  // enforced by the media pipeline. If this DCHECK is violated, our buffer
  // reuse policy is not valid, and we may have race problems for the shared
  // buffer.
  audio_decode_cb_.Set(request_id, audio_decode_cb);

  ScopedPPResource pp_resource(encrypted_resource.get());
  plugin_decryption_interface_->DecryptAndDecode(
      pp_instance_, PP_DECRYPTORSTREAMTYPE_AUDIO, pp_resource, &block_info);
  return true;
}

bool ContentDecryptorDelegate::DecryptAndDecodeVideo(
    const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
    const Decryptor::VideoDecodeCB& video_decode_cb) {
  // |video_input_resource_| is not being used by the plugin now
  // because there is only one pending video decode request at any time.
  // This is enforced by the media pipeline.
  scoped_refptr<PPB_Buffer_Impl> encrypted_resource;
  if (!MakeMediaBufferResource(
          Decryptor::kVideo, encrypted_buffer, &encrypted_resource)) {
    return false;
  }

  // The resource should not be 0 for non-EOS buffer.
  if (!encrypted_buffer->end_of_stream() && !encrypted_resource.get())
    return false;

  const uint32_t request_id = next_decryption_request_id_++;
  DVLOG(2) << "DecryptAndDecodeVideo() - request_id " << request_id;
  TRACE_EVENT_ASYNC_BEGIN0(
      "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);

  PP_EncryptedBlockInfo block_info = {};
  if (!MakeEncryptedBlockInfo(encrypted_buffer, request_id, &block_info)) {
    return false;
  }

  SetBufferToFreeInTrackingInfo(&block_info.tracking_info);

  // Only one pending video decode request at any time. This is enforced by the
  // media pipeline. If this DCHECK is violated, our buffer
  // reuse policy is not valid, and we may have race problems for the shared
  // buffer.
  video_decode_cb_.Set(request_id, video_decode_cb);

  // TODO(tomfinegan): Need to get stream type from media stack.
  ScopedPPResource pp_resource(encrypted_resource.get());
  plugin_decryption_interface_->DecryptAndDecode(
      pp_instance_, PP_DECRYPTORSTREAMTYPE_VIDEO, pp_resource, &block_info);
  return true;
}

void ContentDecryptorDelegate::OnPromiseResolved(uint32_t promise_id) {
  cdm_promise_adapter_.ResolvePromise(promise_id);
}

void ContentDecryptorDelegate::OnPromiseResolvedWithSession(uint32_t promise_id,
                                                            PP_Var session_id) {
  StringVar* session_id_string = StringVar::FromPPVar(session_id);
  DCHECK(session_id_string);
  cdm_promise_adapter_.ResolvePromise(promise_id, session_id_string->value());
}

void ContentDecryptorDelegate::OnPromiseRejected(
    uint32_t promise_id,
    PP_CdmExceptionCode exception_code,
    uint32_t system_code,
    PP_Var error_description) {
  ReportSystemCodeUMA(key_system_, system_code);

  StringVar* error_description_string = StringVar::FromPPVar(error_description);
  DCHECK(error_description_string);
  cdm_promise_adapter_.RejectPromise(
      promise_id, PpExceptionTypeToMediaException(exception_code), system_code,
      error_description_string->value());
}

void ContentDecryptorDelegate::OnSessionMessage(PP_Var session_id,
                                                PP_CdmMessageType message_type,
                                                PP_Var message,
                                                PP_Var legacy_destination_url) {
  if (session_message_cb_.is_null())
    return;

  StringVar* session_id_string = StringVar::FromPPVar(session_id);
  DCHECK(session_id_string);

  ArrayBufferVar* message_array_buffer = ArrayBufferVar::FromPPVar(message);
  std::vector<uint8_t> message_vector;
  if (message_array_buffer) {
    const uint8_t* data =
        static_cast<const uint8_t*>(message_array_buffer->Map());
    message_vector.assign(data, data + message_array_buffer->ByteLength());
  }

  StringVar* destination_url_string =
      StringVar::FromPPVar(legacy_destination_url);
  if (!destination_url_string) {
    NOTREACHED();
    return;
  }

  GURL verified_gurl = GURL(destination_url_string->value());
  if (!verified_gurl.is_valid()) {
    DLOG(WARNING) << "SessionMessage legacy_destination_url is invalid : "
                  << verified_gurl.possibly_invalid_spec();
    verified_gurl = GURL::EmptyGURL();  // Replace invalid destination_url.
  }

  session_message_cb_.Run(session_id_string->value(),
                          PpCdmMessageTypeToMediaMessageType(message_type),
                          message_vector, verified_gurl);
}

void ContentDecryptorDelegate::OnSessionKeysChange(
    PP_Var session_id,
    PP_Bool has_additional_usable_key,
    uint32_t key_count,
    const struct PP_KeyInformation key_information[]) {
  if (session_keys_change_cb_.is_null())
    return;

  StringVar* session_id_string = StringVar::FromPPVar(session_id);
  DCHECK(session_id_string);

  media::CdmKeysInfo keys_info;
  keys_info.reserve(key_count);
  for (uint32_t i = 0; i < key_count; ++i) {
    const auto& info = key_information[i];
    keys_info.push_back(new media::CdmKeyInformation(
        info.key_id, info.key_id_size,
        PpCdmKeyStatusToCdmKeyInformationKeyStatus(info.key_status),
        info.system_code));
  }

  session_keys_change_cb_.Run(session_id_string->value(),
                              PP_ToBool(has_additional_usable_key),
                              keys_info.Pass());
}

void ContentDecryptorDelegate::OnSessionExpirationChange(
    PP_Var session_id,
    PP_Time new_expiry_time) {
  if (session_expiration_update_cb_.is_null())
    return;

  StringVar* session_id_string = StringVar::FromPPVar(session_id);
  DCHECK(session_id_string);

  session_expiration_update_cb_.Run(session_id_string->value(),
                                    ppapi::PPTimeToTime(new_expiry_time));
}

void ContentDecryptorDelegate::OnSessionClosed(PP_Var session_id) {
  if (session_closed_cb_.is_null())
    return;

  StringVar* session_id_string = StringVar::FromPPVar(session_id);
  DCHECK(session_id_string);

  session_closed_cb_.Run(session_id_string->value());
}

void ContentDecryptorDelegate::OnLegacySessionError(
    PP_Var session_id,
    PP_CdmExceptionCode exception_code,
    uint32_t system_code,
    PP_Var error_description) {
  ReportSystemCodeUMA(key_system_, system_code);

  if (legacy_session_error_cb_.is_null())
    return;

  StringVar* session_id_string = StringVar::FromPPVar(session_id);
  DCHECK(session_id_string);

  StringVar* error_description_string = StringVar::FromPPVar(error_description);
  DCHECK(error_description_string);

  legacy_session_error_cb_.Run(session_id_string->value(),
                               PpExceptionTypeToMediaException(exception_code),
                               system_code, error_description_string->value());
}

void ContentDecryptorDelegate::DecoderInitializeDone(
    PP_DecryptorStreamType decoder_type,
    uint32_t request_id,
    PP_Bool success) {
  if (decoder_type == PP_DECRYPTORSTREAMTYPE_AUDIO) {
    // If the request ID is not valid or does not match what's saved, do
    // nothing.
    if (request_id == 0 || !audio_decoder_init_cb_.Matches(request_id))
      return;

    audio_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
  } else {
    if (request_id == 0 || !video_decoder_init_cb_.Matches(request_id))
      return;

    if (!success)
      natural_size_ = gfx::Size();

    video_decoder_init_cb_.ResetAndReturn().Run(PP_ToBool(success));
  }
}

void ContentDecryptorDelegate::DecoderDeinitializeDone(
    PP_DecryptorStreamType decoder_type,
    uint32_t request_id) {
  // TODO(tomfinegan): Add decoder stop completion handling.
}

void ContentDecryptorDelegate::DecoderResetDone(
    PP_DecryptorStreamType decoder_type,
    uint32_t request_id) {
  // TODO(tomfinegan): Add decoder reset completion handling.
}

void ContentDecryptorDelegate::DeliverBlock(
    PP_Resource decrypted_block,
    const PP_DecryptedBlockInfo* block_info) {
  DCHECK(block_info);

  FreeBuffer(block_info->tracking_info.buffer_id);

  const uint32_t request_id = block_info->tracking_info.request_id;
  DVLOG(2) << "DeliverBlock() - request_id: " << request_id;

  // If the request ID is not valid or does not match what's saved, do nothing.
  if (request_id == 0) {
    DVLOG(1) << "DeliverBlock() - invalid request_id " << request_id;
    return;
  }

  Decryptor::DecryptCB decrypt_cb;
  if (audio_decrypt_cb_.Matches(request_id)) {
    decrypt_cb = audio_decrypt_cb_.ResetAndReturn();
  } else if (video_decrypt_cb_.Matches(request_id)) {
    decrypt_cb = video_decrypt_cb_.ResetAndReturn();
  } else {
    DVLOG(1) << "DeliverBlock() - request_id " << request_id << " not found";
    return;
  }

  Decryptor::Status status =
      PpDecryptResultToMediaDecryptorStatus(block_info->result);
  if (status != Decryptor::kSuccess) {
    decrypt_cb.Run(status, NULL);
    return;
  }

  EnterResourceNoLock<PPB_Buffer_API> enter(decrypted_block, true);
  if (!enter.succeeded()) {
    decrypt_cb.Run(Decryptor::kError, NULL);
    return;
  }
  BufferAutoMapper mapper(enter.object());
  if (!mapper.data() || !mapper.size() ||
      mapper.size() < block_info->data_size) {
    decrypt_cb.Run(Decryptor::kError, NULL);
    return;
  }

  // TODO(tomfinegan): Find a way to take ownership of the shared memory
  // managed by the PPB_Buffer_Dev, and avoid the extra copy.
  scoped_refptr<media::DecoderBuffer> decrypted_buffer(
      media::DecoderBuffer::CopyFrom(static_cast<uint8_t*>(mapper.data()),
                                     block_info->data_size));
  decrypted_buffer->set_timestamp(
      base::TimeDelta::FromMicroseconds(block_info->tracking_info.timestamp));
  decrypt_cb.Run(Decryptor::kSuccess, decrypted_buffer);
}

// Use a non-class-member function here so that if for some reason
// ContentDecryptorDelegate is destroyed before VideoFrame calls this callback,
// we can still get the shared memory unmapped.
static void BufferNoLongerNeeded(
    const scoped_refptr<PPB_Buffer_Impl>& ppb_buffer,
    base::Closure buffer_no_longer_needed_cb) {
  ppb_buffer->Unmap();
  buffer_no_longer_needed_cb.Run();
}

// Enters |resource|, maps shared memory and returns pointer of mapped data.
// Returns NULL if any error occurs.
static uint8_t* GetMappedBuffer(PP_Resource resource,
                                scoped_refptr<PPB_Buffer_Impl>* ppb_buffer) {
  EnterResourceNoLock<PPB_Buffer_API> enter(resource, true);
  if (!enter.succeeded())
    return NULL;

  uint8_t* mapped_data = static_cast<uint8_t*>(enter.object()->Map());
  if (!enter.object()->IsMapped() || !mapped_data)
    return NULL;

  uint32_t mapped_size = 0;
  if (!enter.object()->Describe(&mapped_size) || !mapped_size) {
    enter.object()->Unmap();
    return NULL;
  }

  *ppb_buffer = static_cast<PPB_Buffer_Impl*>(enter.object());

  return mapped_data;
}

void ContentDecryptorDelegate::DeliverFrame(
    PP_Resource decrypted_frame,
    const PP_DecryptedFrameInfo* frame_info) {
  DCHECK(frame_info);

  const uint32_t request_id = frame_info->tracking_info.request_id;
  DVLOG(2) << "DeliverFrame() - request_id: " << request_id;

  // If the request ID is not valid or does not match what's saved, do nothing.
  if (request_id == 0 || !video_decode_cb_.Matches(request_id)) {
    DVLOG(1) << "DeliverFrame() - request_id " << request_id << " not found";
    FreeBuffer(frame_info->tracking_info.buffer_id);
    return;
  }

  TRACE_EVENT_ASYNC_END0(
      "media", "ContentDecryptorDelegate::DecryptAndDecodeVideo", request_id);

  Decryptor::VideoDecodeCB video_decode_cb = video_decode_cb_.ResetAndReturn();

  Decryptor::Status status =
      PpDecryptResultToMediaDecryptorStatus(frame_info->result);
  if (status != Decryptor::kSuccess) {
    DCHECK(!frame_info->tracking_info.buffer_id);
    video_decode_cb.Run(status, NULL);
    return;
  }

  scoped_refptr<PPB_Buffer_Impl> ppb_buffer;
  uint8_t* frame_data = GetMappedBuffer(decrypted_frame, &ppb_buffer);
  if (!frame_data) {
    FreeBuffer(frame_info->tracking_info.buffer_id);
    video_decode_cb.Run(Decryptor::kError, NULL);
    return;
  }

  gfx::Size frame_size(frame_info->width, frame_info->height);
  DCHECK_EQ(frame_info->format, PP_DECRYPTEDFRAMEFORMAT_YV12);

  scoped_refptr<media::VideoFrame> decoded_frame =
      media::VideoFrame::WrapExternalYuvData(
          media::PIXEL_FORMAT_YV12, frame_size, gfx::Rect(frame_size),
          natural_size_, frame_info->strides[PP_DECRYPTEDFRAMEPLANES_Y],
          frame_info->strides[PP_DECRYPTEDFRAMEPLANES_U],
          frame_info->strides[PP_DECRYPTEDFRAMEPLANES_V],
          frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_Y],
          frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_U],
          frame_data + frame_info->plane_offsets[PP_DECRYPTEDFRAMEPLANES_V],
          base::TimeDelta::FromMicroseconds(
              frame_info->tracking_info.timestamp));
  decoded_frame->AddDestructionObserver(
      media::BindToCurrentLoop(
          base::Bind(&BufferNoLongerNeeded,
                     ppb_buffer,
                     base::Bind(&ContentDecryptorDelegate::FreeBuffer,
                                weak_this_,
                                frame_info->tracking_info.buffer_id))));

  video_decode_cb.Run(Decryptor::kSuccess, decoded_frame);
}

void ContentDecryptorDelegate::DeliverSamples(
    PP_Resource audio_frames,
    const PP_DecryptedSampleInfo* sample_info) {
  DCHECK(sample_info);

  FreeBuffer(sample_info->tracking_info.buffer_id);

  const uint32_t request_id = sample_info->tracking_info.request_id;
  DVLOG(2) << "DeliverSamples() - request_id: " << request_id;

  // If the request ID is not valid or does not match what's saved, do nothing.
  if (request_id == 0 || !audio_decode_cb_.Matches(request_id)) {
    DVLOG(1) << "DeliverSamples() - request_id " << request_id << " not found";
    return;
  }

  Decryptor::AudioDecodeCB audio_decode_cb = audio_decode_cb_.ResetAndReturn();

  const Decryptor::AudioFrames empty_frames;

  Decryptor::Status status =
      PpDecryptResultToMediaDecryptorStatus(sample_info->result);
  if (status != Decryptor::kSuccess) {
    audio_decode_cb.Run(status, empty_frames);
    return;
  }

  media::SampleFormat sample_format =
      PpDecryptedSampleFormatToMediaSampleFormat(sample_info->format);

  Decryptor::AudioFrames audio_frame_list;
  if (!DeserializeAudioFrames(audio_frames,
                              sample_info->data_size,
                              sample_format,
                              &audio_frame_list)) {
    NOTREACHED() << "CDM did not serialize the buffer correctly.";
    audio_decode_cb.Run(Decryptor::kError, empty_frames);
    return;
  }

  audio_decode_cb.Run(Decryptor::kSuccess, audio_frame_list);
}

// TODO(xhwang): Try to remove duplicate logic here and in CancelDecrypt().
void ContentDecryptorDelegate::CancelDecode(Decryptor::StreamType stream_type) {
  switch (stream_type) {
    case Decryptor::kAudio:
      // Release the shared memory as it can still be in use by the plugin.
      // The next DecryptAndDecode() call will need to allocate a new shared
      // memory buffer.
      audio_input_resource_ = NULL;
      if (!audio_decode_cb_.is_null())
        audio_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess,
                                              Decryptor::AudioFrames());
      break;
    case Decryptor::kVideo:
      // Release the shared memory as it can still be in use by the plugin.
      // The next DecryptAndDecode() call will need to allocate a new shared
      // memory buffer.
      video_input_resource_ = NULL;
      if (!video_decode_cb_.is_null())
        video_decode_cb_.ResetAndReturn().Run(Decryptor::kSuccess, NULL);
      break;
    default:
      NOTREACHED();
  }
}

bool ContentDecryptorDelegate::MakeMediaBufferResource(
    Decryptor::StreamType stream_type,
    const scoped_refptr<media::DecoderBuffer>& encrypted_buffer,
    scoped_refptr<PPB_Buffer_Impl>* resource) {
  TRACE_EVENT0("media", "ContentDecryptorDelegate::MakeMediaBufferResource");

  // End of stream buffers are represented as null resources.
  if (encrypted_buffer->end_of_stream()) {
    *resource = NULL;
    return true;
  }

  DCHECK(stream_type == Decryptor::kAudio || stream_type == Decryptor::kVideo);
  scoped_refptr<PPB_Buffer_Impl>& media_resource =
      (stream_type == Decryptor::kAudio) ? audio_input_resource_
                                         : video_input_resource_;

  const size_t data_size = static_cast<size_t>(encrypted_buffer->data_size());
  if (!media_resource.get() || media_resource->size() < data_size) {
    // Either the buffer hasn't been created yet, or we have one that isn't big
    // enough to fit |size| bytes.

    // Media resource size starts from |kMinimumMediaBufferSize| and grows
    // exponentially to avoid frequent re-allocation of PPB_Buffer_Impl,
    // which is usually expensive. Since input media buffers are compressed,
    // they are usually small (compared to outputs). The over-allocated memory
    // should be negligible.
    const uint32_t kMinimumMediaBufferSize = 1024;
    uint32_t media_resource_size =
        media_resource.get() ? media_resource->size() : kMinimumMediaBufferSize;
    while (media_resource_size < data_size)
      media_resource_size *= 2;

    DVLOG(2) << "Size of media buffer for "
             << ((stream_type == Decryptor::kAudio) ? "audio" : "video")
             << " stream bumped to " << media_resource_size
             << " bytes to fit input.";
    media_resource =
        PPB_Buffer_Impl::CreateResource(pp_instance_, media_resource_size);
    if (!media_resource.get())
      return false;
  }

  BufferAutoMapper mapper(media_resource.get());
  if (!mapper.data() || mapper.size() < data_size) {
    media_resource = NULL;
    return false;
  }
  memcpy(mapper.data(), encrypted_buffer->data(), data_size);

  *resource = media_resource;
  return true;
}

void ContentDecryptorDelegate::FreeBuffer(uint32_t buffer_id) {
  if (buffer_id)
    free_buffers_.push(buffer_id);
}

void ContentDecryptorDelegate::SetBufferToFreeInTrackingInfo(
    PP_DecryptTrackingInfo* tracking_info) {
  DCHECK_EQ(tracking_info->buffer_id, 0u);

  if (free_buffers_.empty())
    return;

  tracking_info->buffer_id = free_buffers_.front();
  free_buffers_.pop();
}

bool ContentDecryptorDelegate::DeserializeAudioFrames(
    PP_Resource audio_frames,
    size_t data_size,
    media::SampleFormat sample_format,
    Decryptor::AudioFrames* frames) {
  DCHECK(frames);
  EnterResourceNoLock<PPB_Buffer_API> enter(audio_frames, true);
  if (!enter.succeeded())
    return false;

  BufferAutoMapper mapper(enter.object());
  if (!mapper.data() || !mapper.size() ||
      mapper.size() < static_cast<uint32_t>(data_size))
    return false;

  // TODO(jrummell): Pass ownership of data() directly to AudioBuffer to avoid
  // the copy. Since it is possible to get multiple buffers, it would need to be
  // sliced and ref counted appropriately. http://crbug.com/255576.
  const uint8_t* cur = static_cast<uint8_t*>(mapper.data());
  size_t bytes_left = data_size;

  const int audio_bytes_per_frame =
      media::SampleFormatToBytesPerChannel(sample_format) *
      audio_channel_count_;
  if (audio_bytes_per_frame <= 0)
    return false;

  // Allocate space for the channel pointers given to AudioBuffer.
  std::vector<const uint8_t*> channel_ptrs(audio_channel_count_, nullptr);
  do {
    int64 timestamp = 0;
    int64 frame_size = -1;
    const size_t kHeaderSize = sizeof(timestamp) + sizeof(frame_size);

    if (bytes_left < kHeaderSize)
      return false;

    memcpy(&timestamp, cur, sizeof(timestamp));
    cur += sizeof(timestamp);
    bytes_left -= sizeof(timestamp);

    memcpy(&frame_size, cur, sizeof(frame_size));
    cur += sizeof(frame_size);
    bytes_left -= sizeof(frame_size);

    // We should *not* have empty frames in the list.
    if (frame_size <= 0 ||
        bytes_left < base::checked_cast<size_t>(frame_size)) {
      return false;
    }

    // Setup channel pointers.  AudioBuffer::CopyFrom() will only use the first
    // one in the case of interleaved data.
    const int size_per_channel = frame_size / audio_channel_count_;
    for (int i = 0; i < audio_channel_count_; ++i)
      channel_ptrs[i] = cur + i * size_per_channel;

    const int frame_count = frame_size / audio_bytes_per_frame;
    scoped_refptr<media::AudioBuffer> frame = media::AudioBuffer::CopyFrom(
        sample_format,
        audio_channel_layout_,
        audio_channel_count_,
        audio_samples_per_second_,
        frame_count,
        &channel_ptrs[0],
        base::TimeDelta::FromMicroseconds(timestamp));
    frames->push_back(frame);

    cur += frame_size;
    bytes_left -= frame_size;
  } while (bytes_left > 0);

  return true;
}

void ContentDecryptorDelegate::SatisfyAllPendingCallbacksOnError() {
  if (!audio_decoder_init_cb_.is_null())
    audio_decoder_init_cb_.ResetAndReturn().Run(false);

  if (!video_decoder_init_cb_.is_null())
    video_decoder_init_cb_.ResetAndReturn().Run(false);

  audio_input_resource_ = NULL;
  video_input_resource_ = NULL;

  if (!audio_decrypt_cb_.is_null())
    audio_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);

  if (!video_decrypt_cb_.is_null())
    video_decrypt_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);

  if (!audio_decode_cb_.is_null()) {
    const media::Decryptor::AudioFrames empty_frames;
    audio_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError,
                                          empty_frames);
  }

  if (!video_decode_cb_.is_null())
    video_decode_cb_.ResetAndReturn().Run(media::Decryptor::kError, NULL);

  cdm_promise_adapter_.Clear();
}

}  // namespace content


text:
package com.graphs.util;

import static org.junit.Assert.*;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;

import org.junit.Test;

import com.graphs.AbstractTest;
import com.graphs.exception.EmptyFileException;

public class FileUtilsTest extends AbstractTest {

	private String[] dataLines = { "AB5", "BC4", "CD8", "DC8", "DE6", "AD5", "CE2", "EB3", "AE7" };

	@Test
	public void shouldPassWhenFileIsGivenAndDoesExistTest() throws IOException {
		final File file = FileUtils.getFile("data.txt");
		assertNotNull(file);
	}

	@Test
	public void shouldFailWhenFileIsGivenAndDoesNotExistTest() throws IOException {
		expect(FileNotFoundException.class ,"File \"not_existing_data.txt\" not found");
		FileUtils.getFile("not_existing_data.txt");
	}

	@Test
	public void shouldPassWhenReadingFileWithContentTest() throws IOException {
		final List<String> lines = FileUtils.readLines(new File("data.txt"));
		for (int i = 0; i < lines.size(); i++) {
			String line = lines.get(i);
			assertEquals(dataLines[i], line);
		}
	}

	@Test
	public void shouldFailWhenReadingFileWithoutContentTest() throws IOException {
		expect(EmptyFileException.class ,"The file empty_data.txt is empty");
		FileUtils.readLines(new File("empty_data.txt"));
	}

}

redpajama_set_name: RedPajamaGithub


text:
    #pragma hdrstop
#endif

#ifndef WX_PRECOMP
    #include "wx/wx.h"
#endif // WX_PRECOMP

#include "wx/intl.h"

#if wxUSE_INTL

// ----------------------------------------------------------------------------
// test class
// ----------------------------------------------------------------------------

class IntlTestCase : public CppUnit::TestCase
{
public:
    IntlTestCase() { m_locale=NULL; }

    virtual void setUp();
    virtual void tearDown();

private:
    CPPUNIT_TEST_SUITE( IntlTestCase );
        CPPUNIT_TEST( RestoreLocale );
        CPPUNIT_TEST( Domain );
        CPPUNIT_TEST( Headers );
        CPPUNIT_TEST( DateTimeFmtFrench );
        CPPUNIT_TEST( DateTimeFmtC );
        CPPUNIT_TEST( IsAvailable );
    CPPUNIT_TEST_SUITE_END();

    void RestoreLocale();
    void Domain();
    void Headers();
    void DateTimeFmtFrench();
    void DateTimeFmtC();
    void IsAvailable();

    static wxString GetDecimalPoint()
    {
        return wxLocale::GetInfo(wxLOCALE_DECIMAL_POINT, wxLOCALE_CAT_NUMBER);
    }

    wxLocale *m_locale;

    DECLARE_NO_COPY_CLASS(IntlTestCase)
};

// register in the unnamed registry so that these tests are run by default
CPPUNIT_TEST_SUITE_REGISTRATION( IntlTestCase );

// also include in its own registry so that these tests can be run alone
CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( IntlTestCase, "IntlTestCase" );

void IntlTestCase::setUp()
{
    // Check that French locale is supported, this test doesn't work without it
    // and all the other function need to check whether m_locale is non-NULL
    // before continuing
    if ( !wxLocale::IsAvailable(wxLANGUAGE_FRENCH) )
        return;

    wxLocale::AddCatalogLookupPathPrefix("./intl");

    m_locale = new wxLocale;
    CPPUNIT_ASSERT( m_locale );

    // don't load default catalog, it may be unavailable:
    bool loaded = m_locale->Init(wxLANGUAGE_FRENCH, wxLOCALE_DONT_LOAD_DEFAULT);
    CPPUNIT_ASSERT( loaded );

    m_locale->AddCatalog("internat");
}

void IntlTestCase::tearDown()
{
    if (m_locale)
    {
        delete m_locale;
        m_locale = NULL;
    }
}

void IntlTestCase::RestoreLocale()
{
    if ( !m_locale )
        return;

    // We must be using the French locale now, it was changed in setUp().
    CPPUNIT_ASSERT_EQUAL( ",", GetDecimalPoint() );

    // Switch to the English locale.
    {
        wxLocale locEn(wxLANGUAGE_ENGLISH);
        CPPUNIT_ASSERT_EQUAL( ".", GetDecimalPoint() );
    }

    // Verify that after destroying the English locale object, French locale is
    // restored.
    CPPUNIT_ASSERT_EQUAL( ",", GetDecimalPoint() );
}

void IntlTestCase::Domain()
{
    if (!m_locale)
        return;

    // _() searches all domains by default:
    CPPUNIT_ASSERT_EQUAL( "&Ouvrir un fichier", _("&Open bogus file") );

    // search in our domain only:
    CPPUNIT_ASSERT_EQUAL( "&Ouvrir un fichier", wxGetTranslation("&Open bogus file", "internat") );

    // search in a domain that doesn't have this string:
    CPPUNIT_ASSERT_EQUAL( "&Open bogus file", wxGetTranslation("&Open bogus file", "BogusDomain") );
}

void IntlTestCase::Headers()
{
    if ( !m_locale )
        return;

    CPPUNIT_ASSERT_EQUAL( "wxWindows 2.0 i18n sample", m_locale->GetHeaderValue("Project-Id-Version") );
    CPPUNIT_ASSERT_EQUAL( "1999-01-13 18:19+0100", m_locale->GetHeaderValue("POT-Creation-Date") );
    CPPUNIT_ASSERT_EQUAL( "YEAR-MO-DA HO:MI+ZONE", m_locale->GetHeaderValue("PO-Revision-Date") );
    CPPUNIT_ASSERT_EQUAL( "Vadim Zeitlin <zeitlin@dptmaths.ens-cachan.fr>", m_locale->GetHeaderValue("Last-Translator") );
    CPPUNIT_ASSERT_EQUAL( "1.0", m_locale->GetHeaderValue("MIME-Version") );
    CPPUNIT_ASSERT_EQUAL( "text/plain; charset=utf-8", m_locale->GetHeaderValue("Content-Type") );
    CPPUNIT_ASSERT_EQUAL( "8bit", m_locale->GetHeaderValue("Content-Transfer-Encoding") );

    // check that it fails with a bogus domain:
    CPPUNIT_ASSERT_EQUAL( "", m_locale->GetHeaderValue("POT-Creation-Date", "Bogus") );

    // and that it fails for nonexisting header:
    CPPUNIT_ASSERT_EQUAL( "", m_locale->GetHeaderValue("X-Not-Here") );
}

static wxString
NormalizeFormat(const wxString& fmtOrig)
{
    wxString fmt(fmtOrig);

#ifdef __GLIBC__
    // glibc uses some extensions in its formats which we need to convert to
    // standard form
    fmt.Replace("%T", "%H:%M:%S");
    fmt.Replace("%e", "%d");
#endif // __GLIBC__

    return fmt;
}

#define WX_ASSERT_EQUAL_FORMAT(msg, expected, actual) \
    if ( !actual.empty() ) \
        CPPUNIT_ASSERT_EQUAL_MESSAGE(msg, expected, NormalizeFormat(actual))

void IntlTestCase::DateTimeFmtFrench()
{
    if ( !m_locale )
        return;

#ifdef __GLIBC__
    // Versions of glibc up to 2.7 wrongly used periods for French locale
    // separator.
#if __GLIBC__ > 2 || __GLIBC_MINOR__ >= 8
    static const char *FRENCH_DATE_FMT = "%d/%m/%Y";
#else
    static const char *FRENCH_DATE_FMT = "%d.%m.%Y";
#endif
    static const char *FRENCH_LONG_DATE_FMT = "%a %d %b %Y";
    static const char *FRENCH_DATE_TIME_FMT = "%a %d %b %Y %H:%M:%S %Z";
#else
    static const char *FRENCH_DATE_FMT = "%d/%m/%Y";
    static const char *FRENCH_LONG_DATE_FMT = "%A %d %B %Y";
#ifdef __WXOSX__
    static const char *FRENCH_DATE_TIME_FMT = "%A %d %B %Y %H:%M:%S";
#else
    static const char *FRENCH_DATE_TIME_FMT = "%d/%m/%Y %H:%M:%S";
#endif
#endif

    WX_ASSERT_EQUAL_FORMAT( "French short date", FRENCH_DATE_FMT,
                   m_locale->GetInfo(wxLOCALE_SHORT_DATE_FMT) );
    WX_ASSERT_EQUAL_FORMAT( "French long date", FRENCH_LONG_DATE_FMT,
                    m_locale->GetInfo(wxLOCALE_LONG_DATE_FMT) );
    WX_ASSERT_EQUAL_FORMAT( "French date and time", FRENCH_DATE_TIME_FMT,
                    m_locale->GetInfo(wxLOCALE_DATE_TIME_FMT) );
    WX_ASSERT_EQUAL_FORMAT( "French time", "%H:%M:%S",
                    m_locale->GetInfo(wxLOCALE_TIME_FMT) );
}

void IntlTestCase::DateTimeFmtC()
{
    // again, glibc uses different defaults
#ifdef __GLIBC__
    static const char *C_DATE_FMT = "%m/%d/%y";
    static const char *C_LONG_DATE_FMT = "%a %b %d %Y";
    static const char *C_DATE_TIME_FMT = "%a %b %d %H:%M:%S %Y";
#else
    static const char *C_DATE_FMT = "%d/%m/%Y";
    static const char *C_LONG_DATE_FMT = "%A %d %B %Y";
#ifdef __WXOSX__
    static const char *C_DATE_TIME_FMT = "%A %d %B %Y %H:%M:%S";
#else
    static const char *C_DATE_TIME_FMT = "%d/%m/%Y %H:%M:%S";
#endif
#endif

    setlocale(LC_ALL, "C");

    WX_ASSERT_EQUAL_FORMAT( "C short date", C_DATE_FMT,
                    m_locale->GetInfo(wxLOCALE_SHORT_DATE_FMT) );
    WX_ASSERT_EQUAL_FORMAT( "C long date", C_LONG_DATE_FMT,
                    m_locale->GetInfo(wxLOCALE_LONG_DATE_FMT) );
    WX_ASSERT_EQUAL_FORMAT( "C date and time", C_DATE_TIME_FMT,
                    m_locale->GetInfo(wxLOCALE_DATE_TIME_FMT) );
    WX_ASSERT_EQUAL_FORMAT( "C time", "%H:%M:%S",
                    m_locale->GetInfo(wxLOCALE_TIME_FMT) );
}

void IntlTestCase::IsAvailable()
{
    const wxString origLocale(setlocale(LC_ALL, NULL));

    // Calling IsAvailable() shouldn't change the locale.
    wxLocale::IsAvailable(wxLANGUAGE_ENGLISH);

    CPPUNIT_ASSERT_EQUAL( origLocale, setlocale(LC_ALL, NULL) );
}

#endif // wxUSE_INTL


text:
module Main where

import Network.AWS.S3Bucket
import Network.AWS.AWSConnection
import Network.AWS.AWSResult
import System.Environment
import System.IO
import Data.Maybe
import Network.AWS.S3Object
import qualified Data.ByteString.Lazy.Char8 as L

withConn :: ( AWSConnection -> IO (AWSResult a)) -> IO a
withConn f = do
  mConn <- amazonS3ConnectionFromEnv
  case mConn of
    Just c -> fmap (either (error . prettyReqError) -- failure
                    id ) $ f c
    Nothing -> error "couldn't connect"

main :: IO ()
main = do
  args <- getArgs
  case args of
    -- create / empty / delete bucket
    ["cb", name, location] -> withConn $ \g -> createBucketIn g name location
    ["db", name ] ->  withConn $ \g -> deleteBucket g name
    ["eb", name ] ->  withConn $ \g -> emptyBucket g name
    -- objects
    ["go", bucket, gkey ] ->
        do c <- withConn $ \g -> getObject g $ S3Object bucket gkey "" [] L.empty
           L.putStr $ obj_data c
    ["do", bucket, key] ->
        withConn $ \g -> deleteObject g $ S3Object bucket key "" [] L.empty
    ["so", bucket, skey ] ->
        (\c ->  withConn $ \g -> sendObject g $ S3Object bucket skey "" [] c)
            =<< L.getContents
    ["los", bucket] ->
        do l <- withConn $ \g -> listObjects g bucket (ListRequest "" "" "" 1000)
           mapM_ (putStrLn . key) (snd l)
    ["lbs"] -> withConn listBuckets >>= mapM_ (putStrLn . bucket_name)
    _ -> usage

usage :: IO ()
usage = putStr $ unlines [
         "export AWS_ACCESS_KEY_ID and AWS_ACCESS_KEY_SECRET"
        , ""
        , "cb <name> [EU, US] : create bucket"
        , "db <name> : delete bucket"
        , "eb <name> : empty bucket"
        , "do <bucket> <key> : delete object"
        , ""
        , "lbs : list buckets"
        , "so : send object"
        , "go : get object"
        , "los : list objects" ]


text:
These test cases cover obfuscation (more properly, masking) of literal values
from SQL statements captured by agents. SQL statements may be captured and
attached to transaction trace nodes, or to slow SQL traces.

Input queries end with the suffix `.sql`, and the expected obfuscated results
end with the suffix `.obfuscated`. Input queries may contain comment lines
explaining notes about the test case. Comment lines will precede the actual
query, and begin with a `#` symbol.

Test cases that have a `.mysql` or `.postgres` tag in the filename preceding the
`.sql` suffix are specific to either mysql or postgres obfuscation. This is
relevant because PostgreSQL uses different identifier and string quoting rules
than MySQL (most notably, double-quoted string literals are not allowed in
PostgreSQL, where double-quotes are instead used around identifiers).

The `malformed` directory contains SQL queries that are not valid SQL in any
quoting mode. Some agents may choose to attempt to obfuscate these cases, and
others may instead just replace the query entirely with a placeholder message.

The following database documentation may be helpful in understanding these test
cases:
* [MySQL String Literals](http://dev.mysql.com/doc/refman/5.5/en/string-literals.html)
* [PostgreSQL String Constants](http://www.postgresql.org/docs/8.2/static/sql-syntax-lexical.html#SQL-SYNTAX-CONSTANTS)


text:
{-# OPTIONS -fglasgow-exts #-}

module API where

data Null = Null { a, b :: Int }
   deriving Show

plugin :: Null
plugin = Null { a = 42 , b = 1 }


text:
module.exports = function template (body, params) {
    return `
      <!DOCTYPE html>
      <html>
        <head>
          <title>${params.title}</title>
          <link rel='stylesheet' href='/stylesheets/style.css' />
        </head>
        <body>
          ${body}
        </body>
      </html>
    `;
};


text:
package org.snf4j.example.echo;

import java.nio.ByteBuffer;

import org.snf4j.core.EndingAction;
import org.snf4j.core.allocator.IByteBufferAllocator;
import org.snf4j.core.allocator.ThreadLocalCachingAllocator;
import org.snf4j.core.factory.DefaultSessionStructureFactory;
import org.snf4j.core.factory.ISessionStructureFactory;
import org.snf4j.core.handler.AbstractStreamHandler;
import org.snf4j.core.handler.SessionEvent;
import org.snf4j.core.handler.SessionIncident;
import org.snf4j.core.session.DefaultSessionConfig;
import org.snf4j.core.session.ISessionConfig;
import org.snf4j.core.session.ssl.SSLEngineBuilder;

public class EchoClientHandler extends AbstractStreamHandler {

	private static final IByteBufferAllocator ALLOCATOR = new ThreadLocalCachingAllocator(true);

	private final DefaultSessionConfig config;

	private long startTime;

	private long totalBytes;

	EchoClientHandler() {
		this(null);
	}

	EchoClientHandler(SSLEngineBuilder builder) {
		config =  new SessionConfig(EchoClient.PIPELINE_SIZE)
				.setEndingAction(EndingAction.STOP)
				.setOptimizeDataCopying(true)
				.setMinOutBufferCapacity(EchoClient.SIZE << 1);
		if (builder != null) {
			config.addSSLEngineBuilder(builder);
		}
	}

	boolean read(int size) {
		totalBytes += size;
		if (totalBytes >= EchoClient.TOTAL_SIZE) {
			getSession().close();
			return false;
		}
		return true;
	}

	@Override
	public void read(ByteBuffer data) {
		if (read(data.remaining())) {
			super.read(data);
		}
	}

	@Override
	public void read(Object msg) {
		getSession().writenf(msg);
	}

	@SuppressWarnings("incomplete-switch")
	@Override
	public void event(SessionEvent event) {
		switch (event) {
		case READY:
			ByteBuffer msg = getSession().allocate(EchoClient.SIZE);

			Logger.inf("starting...");
			startTime = System.currentTimeMillis();
			for (int i=0; i<msg.capacity(); ++i) {
				msg.put((byte)i);
			}
			msg.flip();
			getSession().writenf(msg);
			break;

		case CLOSED:
			stats();
			break;
		}
	}

	@Override
	public void exception(Throwable e) {
		Logger.err(e.toString());
	}

	@Override
	public boolean incident(SessionIncident incident, Throwable t) {
		Logger.err(incident + ": " + t.toString());
		return true;
	}

	private void stats() {
		long bytesPerSecond = 1000*totalBytes/(System.currentTimeMillis() - startTime);

		Logger.inf("avg bytes/sec: " + bytesPerSecond);
	}

	@Override
	public ISessionConfig getConfig() {
		return config;
	}

	@Override
	public ISessionStructureFactory getFactory() {
		return new DefaultSessionStructureFactory() {

			@Override
			public IByteBufferAllocator getAllocator() {
				return ALLOCATOR;
			}
		};
	}
}


text:
hqDefine('app_manager/js/summary/form_summary',[
    'jquery',
    'underscore',
    'knockout',
    'hqwebapp/js/initial_page_data',
    'hqwebapp/js/assert_properties',
    'app_manager/js/summary/models',
    'app_manager/js/summary/form_models',
    'app_manager/js/summary/utils',
    'app_manager/js/menu',  // enable lang switcher and "Updates to publish" banner
    'hqwebapp/js/knockout_bindings.ko', // popover
    'hqwebapp/js/components.ko',    // search box
], function ($, _, ko, initialPageData, assertProperties, models, formModels, utils) {
    $(function () {
        var lang = initialPageData.get('lang'),
            langs = initialPageData.get('langs');

        var formSummaryMenu = models.menuModel({
            items: _.map(initialPageData.get("modules"), function (module) {
                return models.menuItemModel({
                    unique_id: module.unique_id,
                    name: utils.translateName(module.name, lang, langs),
                    icon: utils.moduleIcon(module),
                    has_errors: false,
                    subitems: _.map(module.forms, function (form) {
                        return models.menuItemModel({
                            unique_id: form.unique_id,
                            name: utils.translateName(form.name, lang, langs),
                            icon: utils.formIcon(form),
                        });
                    }),
                });
            }),
            viewAllItems: gettext("View All Forms"),
        });

        var formSummaryContent = formModels.formSummaryModel({
            errors: initialPageData.get("errors"),
            form_name_map: initialPageData.get("form_name_map"),
            lang: lang,
            langs: langs,
            modules: initialPageData.get("modules"),
            read_only: initialPageData.get("read_only"),
            appId: initialPageData.get("app_id"),
        });

        var formSummaryController = formModels.formSummaryControlModel([formSummaryContent]);
        models.initVersionsBox(
            $("#version-selector"),
            {id: initialPageData.get("app_id"), text: initialPageData.get("app_version")}
        );
        $("#form-summary-header").koApplyBindings(formSummaryController);
        models.initMenu([formSummaryContent], formSummaryMenu);
        models.initSummary(formSummaryContent, formSummaryController, "#form-summary");
    });
});


text:
using System;
using System.Collections.Generic;

using Internal.IL;
using Internal.TypeSystem;

using Debug = System.Diagnostics.Debug;

namespace Internal.IL.Stubs
{
    public class ILCodeStream
    {
        private const int StartOffsetNotSet = -1;

        private struct LabelAndOffset
        {
            public readonly ILCodeLabel Label;
            public readonly int Offset;
            public LabelAndOffset(ILCodeLabel label, int offset)
            {
                Label = label;
                Offset = offset;
            }
        }

        internal byte[] _instructions;
        internal int _length;
        internal int _startOffsetForLinking;
        internal ArrayBuilder<ILSequencePoint> _sequencePoints;

        private ArrayBuilder<LabelAndOffset> _offsetsNeedingPatching;

        private ILEmitter _emitter;

        internal ILCodeStream(ILEmitter emitter)
        {
            _instructions = Array.Empty<byte>();
            _startOffsetForLinking = StartOffsetNotSet;
            _emitter = emitter;
        }

        internal int RelativeToAbsoluteOffset(int relativeOffset)
        {
            Debug.Assert(_startOffsetForLinking != StartOffsetNotSet);
            return _startOffsetForLinking + relativeOffset;
        }

        private void EmitByte(byte b)
        {
            if (_instructions.Length == _length)
                Array.Resize<byte>(ref _instructions, 2 * _instructions.Length + 10);
            _instructions[_length++] = b;
        }

        private void EmitUInt16(ushort value)
        {
            EmitByte((byte)value);
            EmitByte((byte)(value >> 8));
        }

        private void EmitUInt32(int value)
        {
            EmitByte((byte)value);
            EmitByte((byte)(value >> 8));
            EmitByte((byte)(value >> 16));
            EmitByte((byte)(value >> 24));
        }

        public void Emit(ILOpcode opcode)
        {
            if ((int)opcode > 0x100)
                EmitByte((byte)ILOpcode.prefix1);
            EmitByte((byte)opcode);
        }

        public void Emit(ILOpcode opcode, ILToken token)
        {
            Emit(opcode);
            EmitUInt32((int)token);
        }

        public void EmitLdc(int value)
        {
            if (-1 <= value && value <= 8)
            {
                Emit((ILOpcode)(ILOpcode.ldc_i4_0 + value));
            }
            else if (value == (sbyte)value)
            {
                Emit(ILOpcode.ldc_i4_s);
                EmitByte((byte)value);
            }
            else
            {
                Emit(ILOpcode.ldc_i4);
                EmitUInt32(value);
            }
        }

        public void EmitLdArg(int index)
        {
            if (index < 4)
            {
                Emit((ILOpcode)(ILOpcode.ldarg_0 + index));
            }
            else
            {
                Emit(ILOpcode.ldarg);
                EmitUInt16((ushort)index);
            }
        }

        public void EmitLdArga(int index)
        {
            if (index < 0x100)
            {
                Emit(ILOpcode.ldarga_s);
                EmitByte((byte)index);
            }
            else
            {
                Emit(ILOpcode.ldarga);
                EmitUInt16((ushort)index);
            }
        }

        public void EmitLdLoc(ILLocalVariable variable)
        {
            int index = (int)variable;

            if (index < 4)
            {
                Emit((ILOpcode)(ILOpcode.ldloc_0 + index));
            }
            else if (index < 0x100)
            {
                Emit(ILOpcode.ldloc_s);
                EmitByte((byte)index);
            }
            else
            {
                Emit(ILOpcode.ldloc);
                EmitUInt16((ushort)index);
            }
        }

        public void EmitLdLoca(ILLocalVariable variable)
        {
            int index = (int)variable;

            if (index < 0x100)
            {
                Emit(ILOpcode.ldloca_s);
                EmitByte((byte)index);
            }
            else
            {
                Emit(ILOpcode.ldloca);
                EmitUInt16((ushort)index);
            }
        }

        public void EmitStLoc(ILLocalVariable variable)
        {
            int index = (int)variable;

            if (index < 4)
            {
                Emit((ILOpcode)(ILOpcode.stloc_0 + index));
            }
            else if (index < 0x100)
            {
                Emit(ILOpcode.stloc_s);
                EmitByte((byte)index);
            }
            else
            {
                Emit(ILOpcode.stloc);
                EmitUInt16((ushort)index);
            }
        }

        public void Emit(ILOpcode opcode, ILCodeLabel label)
        {
            Debug.Assert(opcode == ILOpcode.br || opcode == ILOpcode.brfalse ||
                opcode == ILOpcode.brtrue || opcode == ILOpcode.beq ||
                opcode == ILOpcode.bge || opcode == ILOpcode.bgt ||
                opcode == ILOpcode.ble || opcode == ILOpcode.blt ||
                opcode == ILOpcode.bne_un || opcode == ILOpcode.bge_un ||
                opcode == ILOpcode.bgt_un || opcode == ILOpcode.ble_un ||
                opcode == ILOpcode.blt_un || opcode == ILOpcode.leave);

            Emit(opcode);
            _offsetsNeedingPatching.Add(new LabelAndOffset(label, _length));
            EmitUInt32(4);
        }

        public void EmitSwitch(ILCodeLabel[] labels)
        {
            Emit(ILOpcode.switch_);
            EmitUInt32(labels.Length);

            int remainingBytes = labels.Length * 4;
            foreach (var label in labels)
            {
                _offsetsNeedingPatching.Add(new LabelAndOffset(label, _length));
                EmitUInt32(remainingBytes);
                remainingBytes -= 4;
            }
        }

        public void EmitUnaligned()
        {
            Emit(ILOpcode.unaligned);
            EmitByte(1);
        }

        public void EmitLdInd(TypeDesc type)
        {
            switch (type.UnderlyingType.Category)
            {
                case TypeFlags.Byte:
                case TypeFlags.SByte:
                case TypeFlags.Boolean:
                    Emit(ILOpcode.ldind_i1);
                    break;
                case TypeFlags.Char:
                case TypeFlags.UInt16:
                case TypeFlags.Int16:
                    Emit(ILOpcode.ldind_i2);
                    break;
                case TypeFlags.UInt32:
                case TypeFlags.Int32:
                    Emit(ILOpcode.ldind_i4);
                    break;
                case TypeFlags.UInt64:
                case TypeFlags.Int64:
                    Emit(ILOpcode.ldind_i8);
                    break;
                case TypeFlags.Single:
                    Emit(ILOpcode.ldind_r4);
                    break;
                case TypeFlags.Double:
                    Emit(ILOpcode.ldind_r8);
                    break;
                case TypeFlags.IntPtr:
                case TypeFlags.UIntPtr:
                case TypeFlags.Pointer:
                case TypeFlags.FunctionPointer:
                    Emit(ILOpcode.ldind_i);
                    break;
                case TypeFlags.Array:
                case TypeFlags.SzArray:
                case TypeFlags.Class:
                case TypeFlags.Interface:
                    Emit(ILOpcode.ldind_ref);
                    break;
                case TypeFlags.ValueType:
                case TypeFlags.Nullable:
                case TypeFlags.SignatureMethodVariable:
                case TypeFlags.SignatureTypeVariable:
                    Emit(ILOpcode.ldobj, _emitter.NewToken(type));
                    break;
                default:
                    Debug.Fail("Unexpected TypeDesc category");
                    break;
            }
        }
        public void EmitStInd(TypeDesc type)
        {
            switch (type.UnderlyingType.Category)
            {
                case TypeFlags.Byte:
                case TypeFlags.SByte:
                case TypeFlags.Boolean:
                    Emit(ILOpcode.stind_i1);
                    break;
                case TypeFlags.Char:
                case TypeFlags.UInt16:
                case TypeFlags.Int16:
                    Emit(ILOpcode.stind_i2);
                    break;
                case TypeFlags.UInt32:
                case TypeFlags.Int32:
                    Emit(ILOpcode.stind_i4);
                    break;
                case TypeFlags.UInt64:
                case TypeFlags.Int64:
                    Emit(ILOpcode.stind_i8);
                    break;
                case TypeFlags.Single:
                    Emit(ILOpcode.stind_r4);
                    break;
                case TypeFlags.Double:
                    Emit(ILOpcode.stind_r8);
                    break;
                case TypeFlags.IntPtr:
                case TypeFlags.UIntPtr:
                case TypeFlags.Pointer:
                case TypeFlags.FunctionPointer:
                    Emit(ILOpcode.stind_i);
                    break;
                case TypeFlags.Array:
                case TypeFlags.SzArray:
                case TypeFlags.Class:
                case TypeFlags.Interface:
                    Emit(ILOpcode.stind_ref);
                    break;
                case TypeFlags.ValueType:
                case TypeFlags.Nullable:
                    Emit(ILOpcode.stobj, _emitter.NewToken(type));
                    break;
                default:
                    Debug.Fail("Unexpected TypeDesc category");
                    break;
            }
        }

        public void EmitStElem(TypeDesc type)
        {
            switch (type.UnderlyingType.Category)
            {
                case TypeFlags.Byte:
                case TypeFlags.SByte:
                case TypeFlags.Boolean:
                    Emit(ILOpcode.stelem_i1);
                    break;
                case TypeFlags.Char:
                case TypeFlags.UInt16:
                case TypeFlags.Int16:
                    Emit(ILOpcode.stelem_i2);
                    break;
                case TypeFlags.UInt32:
                case TypeFlags.Int32:
                    Emit(ILOpcode.stelem_i4);
                    break;
                case TypeFlags.UInt64:
                case TypeFlags.Int64:
                    Emit(ILOpcode.stelem_i8);
                    break;
                case TypeFlags.Single:
                    Emit(ILOpcode.stelem_r4);
                    break;
                case TypeFlags.Double:
                    Emit(ILOpcode.stelem_r8);
                    break;
                case TypeFlags.IntPtr:
                case TypeFlags.UIntPtr:
                case TypeFlags.Pointer:
                case TypeFlags.FunctionPointer:
                    Emit(ILOpcode.stelem_i);
                    break;
                case TypeFlags.Array:
                case TypeFlags.SzArray:
                case TypeFlags.Class:
                case TypeFlags.Interface:
                    Emit(ILOpcode.stelem_ref);
                    break;
                case TypeFlags.ValueType:
                case TypeFlags.Nullable:
                    Emit(ILOpcode.stelem, _emitter.NewToken(type));
                    break;
                default:
                    Debug.Fail("Unexpected TypeDesc category");
                    break;
            }
        }

        public void EmitLdElem(TypeDesc type)
        {
            switch (type.UnderlyingType.Category)
            {
                case TypeFlags.Byte:
                case TypeFlags.SByte:
                case TypeFlags.Boolean:
                    Emit(ILOpcode.ldelem_i1);
                    break;
                case TypeFlags.Char:
                case TypeFlags.UInt16:
                case TypeFlags.Int16:
                    Emit(ILOpcode.ldelem_i2);
                    break;
                case TypeFlags.UInt32:
                case TypeFlags.Int32:
                    Emit(ILOpcode.ldelem_i4);
                    break;
                case TypeFlags.UInt64:
                case TypeFlags.Int64:
                    Emit(ILOpcode.ldelem_i8);
                    break;
                case TypeFlags.Single:
                    Emit(ILOpcode.ldelem_r4);
                    break;
                case TypeFlags.Double:
                    Emit(ILOpcode.ldelem_r8);
                    break;
                case TypeFlags.IntPtr:
                case TypeFlags.UIntPtr:
                case TypeFlags.Pointer:
                case TypeFlags.FunctionPointer:
                    Emit(ILOpcode.ldelem_i);
                    break;
                case TypeFlags.Array:
                case TypeFlags.SzArray:
                case TypeFlags.Class:
                case TypeFlags.Interface:
                    Emit(ILOpcode.ldelem_ref);
                    break;
                case TypeFlags.ValueType:
                case TypeFlags.Nullable:
                    Emit(ILOpcode.ldelem, _emitter.NewToken(type));
                    break;
                default:
                    Debug.Fail("Unexpected TypeDesc category");
                    break;
            }
        }

        public void EmitLabel(ILCodeLabel label)
        {
            label.Place(this, _length);
        }

        public void BeginTry(ILExceptionRegionBuilder builder)
        {
            Debug.Assert(builder._beginTryStream == null);
            builder._beginTryStream = this;
            builder._beginTryOffset = _length;
        }

        public void EndTry(ILExceptionRegionBuilder builder)
        {
            Debug.Assert(builder._endTryStream == null);
            builder._endTryStream = this;
            builder._endTryOffset = _length;
        }

        public void BeginHandler(ILExceptionRegionBuilder builder)
        {
            Debug.Assert(builder._beginHandlerStream == null);
            builder._beginHandlerStream = this;
            builder._beginHandlerOffset = _length;
        }

        public void EndHandler(ILExceptionRegionBuilder builder)
        {
            Debug.Assert(builder._endHandlerStream == null);
            builder._endHandlerStream = this;
            builder._endHandlerOffset = _length;
        }

        internal void PatchLabels()
        {
            for (int i = 0; i < _offsetsNeedingPatching.Count; i++)
            {
                LabelAndOffset patch = _offsetsNeedingPatching[i];

                Debug.Assert(patch.Label.IsPlaced);
                Debug.Assert(_startOffsetForLinking != StartOffsetNotSet);

                int offset = patch.Offset;

                int delta = _instructions[offset + 3] << 24 |
                    _instructions[offset + 2] << 16 |
                    _instructions[offset + 1] << 8 |
                    _instructions[offset];

                int value = patch.Label.AbsoluteOffset - _startOffsetForLinking - patch.Offset - delta;

                _instructions[offset] = (byte)value;
                _instructions[offset + 1] = (byte)(value >> 8);
                _instructions[offset + 2] = (byte)(value >> 16);
                _instructions[offset + 3] = (byte)(value >> 24);
            }
        }

        public void DefineSequencePoint(string document, int lineNumber)
        {
            // Last sequence point defined for this offset wins.
            if (_sequencePoints.Count > 0 && _sequencePoints[_sequencePoints.Count - 1].Offset == _length)
            {
                _sequencePoints[_sequencePoints.Count - 1] = new ILSequencePoint(_length, document, lineNumber);
            }
            else
            {
                _sequencePoints.Add(new ILSequencePoint(_length, document, lineNumber));
            }
        }
    }

    public class ILExceptionRegionBuilder
    {
        internal ILCodeStream _beginTryStream;
        internal int _beginTryOffset;

        internal ILCodeStream _endTryStream;
        internal int _endTryOffset;

        internal ILCodeStream _beginHandlerStream;
        internal int _beginHandlerOffset;

        internal ILCodeStream _endHandlerStream;
        internal int _endHandlerOffset;

        internal ILExceptionRegionBuilder()
        {
        }

        internal int TryOffset => _beginTryStream.RelativeToAbsoluteOffset(_beginTryOffset);
        internal int TryLength => _endTryStream.RelativeToAbsoluteOffset(_endTryOffset) - TryOffset;
        internal int HandlerOffset => _beginHandlerStream.RelativeToAbsoluteOffset(_beginHandlerOffset);
        internal int HandlerLength => _endHandlerStream.RelativeToAbsoluteOffset(_endHandlerOffset) - HandlerOffset;

        internal bool IsDefined =>
            _beginTryStream != null && _endTryStream != null
            && _beginHandlerStream != null && _endHandlerStream != null;
    }

    /// <summary>
    /// Represent a token. Use one of the overloads of <see cref="ILEmitter.NewToken"/>
    /// to create a new token.
    /// </summary>
    public enum ILToken { }

    /// <summary>
    /// Represents a local variable. Use <see cref="ILEmitter.NewLocal"/> to create a new local variable.
    /// </summary>
    public enum ILLocalVariable { }

    public class ILStubMethodIL : MethodIL
    {
        private readonly byte[] _ilBytes;
        private readonly LocalVariableDefinition[] _locals;
        private readonly Object[] _tokens;
        private readonly MethodDesc _method;
        private readonly ILExceptionRegion[] _exceptionRegions;
        private readonly MethodDebugInformation _debugInformation;

        private const int MaxStackNotSet = -1;
        private int _maxStack;

        public ILStubMethodIL(MethodDesc owningMethod, byte[] ilBytes, LocalVariableDefinition[] locals, Object[] tokens, ILExceptionRegion[] exceptionRegions = null, MethodDebugInformation debugInfo = null)
        {
            _ilBytes = ilBytes;
            _locals = locals;
            _tokens = tokens;
            _method = owningMethod;
            _maxStack = MaxStackNotSet;

            if (exceptionRegions == null)
                exceptionRegions = Array.Empty<ILExceptionRegion>();
            _exceptionRegions = exceptionRegions;

            if (debugInfo == null)
                debugInfo = MethodDebugInformation.None;
            _debugInformation = debugInfo;
        }

        public ILStubMethodIL(ILStubMethodIL methodIL)
        {
            _ilBytes = methodIL._ilBytes;
            _locals = methodIL._locals;
            _tokens = methodIL._tokens;
            _method = methodIL._method;
            _debugInformation = methodIL._debugInformation;
            _maxStack = methodIL._maxStack;
        }

        public override MethodDesc OwningMethod
        {
            get
            {
                return _method;
            }
        }

        public override byte[] GetILBytes()
        {
            return _ilBytes;
        }

        public override MethodDebugInformation GetDebugInfo()
        {
            return _debugInformation;
        }

        public override int MaxStack
        {
            get
            {
                if (_maxStack == MaxStackNotSet)
                    _maxStack = this.ComputeMaxStack();
                return _maxStack;
            }
        }

        public override ILExceptionRegion[] GetExceptionRegions()
        {
            return _exceptionRegions;
        }
        public override bool IsInitLocals
        {
            get
            {
                return true;
            }
        }

        public override LocalVariableDefinition[] GetLocals()
        {
            return _locals;
        }
        public override Object GetObject(int token)
        {
            return _tokens[(token & 0xFFFFFF) - 1];
        }
    }

    public class ILCodeLabel
    {
        private ILCodeStream _codeStream;
        private int _offsetWithinCodeStream;

        internal bool IsPlaced
        {
            get
            {
                return _codeStream != null;
            }
        }

        internal int AbsoluteOffset
        {
            get
            {
                Debug.Assert(IsPlaced);
                return _codeStream.RelativeToAbsoluteOffset(_offsetWithinCodeStream);
            }
        }

        internal ILCodeLabel()
        {
        }

        internal void Place(ILCodeStream codeStream, int offsetWithinCodeStream)
        {
            Debug.Assert(!IsPlaced);
            _codeStream = codeStream;
            _offsetWithinCodeStream = offsetWithinCodeStream;
        }
    }

    public class ILEmitter
    {
        private ArrayBuilder<ILCodeStream> _codeStreams;
        private ArrayBuilder<LocalVariableDefinition> _locals;
        private ArrayBuilder<Object> _tokens;
        private ArrayBuilder<ILExceptionRegionBuilder> _finallyRegions;

        public ILEmitter()
        {
        }

        public ILCodeStream NewCodeStream()
        {
            ILCodeStream stream = new ILCodeStream(this);
            _codeStreams.Add(stream);
            return stream;
        }

        private ILToken NewToken(Object value, int tokenType)
        {
            Debug.Assert(value != null);
            _tokens.Add(value);
            return (ILToken)(_tokens.Count | tokenType);
        }

        public ILToken NewToken(TypeDesc value)
        {
            return NewToken(value, 0x01000000);
        }

        public ILToken NewToken(MethodDesc value)
        {
            return NewToken(value, 0x0a000000);
        }

        public ILToken NewToken(FieldDesc value)
        {
            return NewToken(value, 0x0a000000);
        }

        public ILToken NewToken(string value)
        {
            return NewToken(value, 0x70000000);
        }

        public ILToken NewToken(MethodSignature value)
        {
            return NewToken(value, 0x11000000);
        }

        public ILLocalVariable NewLocal(TypeDesc localType, bool isPinned = false)
        {
            int index = _locals.Count;
            _locals.Add(new LocalVariableDefinition(localType, isPinned));
            return (ILLocalVariable)index;
        }

        public ILCodeLabel NewCodeLabel()
        {
            var newLabel = new ILCodeLabel();
            return newLabel;
        }

        public ILExceptionRegionBuilder NewFinallyRegion()
        {
            var region = new ILExceptionRegionBuilder();
            _finallyRegions.Add(region);
            return region;
        }

        public MethodIL Link(MethodDesc owningMethod)
        {
            int totalLength = 0;
            int numSequencePoints = 0;

            for (int i = 0; i < _codeStreams.Count; i++)
            {
                ILCodeStream ilCodeStream = _codeStreams[i];
                ilCodeStream._startOffsetForLinking = totalLength;
                totalLength += ilCodeStream._length;
                numSequencePoints += ilCodeStream._sequencePoints.Count;
            }

            byte[] ilInstructions = new byte[totalLength];
            int copiedLength = 0;
            for (int i = 0; i < _codeStreams.Count; i++)
            {
                ILCodeStream ilCodeStream = _codeStreams[i];
                ilCodeStream.PatchLabels();
                Array.Copy(ilCodeStream._instructions, 0, ilInstructions, copiedLength, ilCodeStream._length);
                copiedLength += ilCodeStream._length;
            }

            MethodDebugInformation debugInfo = null;
            if (numSequencePoints > 0)
            {
                ILSequencePoint[] sequencePoints = new ILSequencePoint[numSequencePoints];
                int copiedSequencePointLength = 0;
                for (int codeStreamIndex = 0; codeStreamIndex < _codeStreams.Count; codeStreamIndex++)
                {
                    ILCodeStream ilCodeStream = _codeStreams[codeStreamIndex];

                    for (int sequencePointIndex = 0; sequencePointIndex < ilCodeStream._sequencePoints.Count; sequencePointIndex++)
                    {
                        ILSequencePoint sequencePoint = ilCodeStream._sequencePoints[sequencePointIndex];
                        sequencePoints[copiedSequencePointLength] = new ILSequencePoint(
                            ilCodeStream._startOffsetForLinking + sequencePoint.Offset,
                            sequencePoint.Document,
                            sequencePoint.LineNumber);
                        copiedSequencePointLength++;
                    }
                }

                debugInfo = new EmittedMethodDebugInformation(sequencePoints);
            }

            ILExceptionRegion[] exceptionRegions = null;

            int numberOfExceptionRegions = _finallyRegions.Count;
            if (numberOfExceptionRegions > 0)
            {
                exceptionRegions = new ILExceptionRegion[numberOfExceptionRegions];

                for (int i = 0; i < _finallyRegions.Count; i++)
                {
                    ILExceptionRegionBuilder region = _finallyRegions[i];

                    Debug.Assert(region.IsDefined);

                    exceptionRegions[i] = new ILExceptionRegion(ILExceptionRegionKind.Finally,
                        region.TryOffset, region.TryLength, region.HandlerOffset, region.HandlerLength,
                        classToken: 0, filterOffset: 0);
                }
            }

            var result = new ILStubMethodIL(owningMethod, ilInstructions, _locals.ToArray(), _tokens.ToArray(), exceptionRegions, debugInfo);
            result.CheckStackBalance();
            return result;
        }

        private class EmittedMethodDebugInformation : MethodDebugInformation
        {
            private readonly ILSequencePoint[] _sequencePoints;

            public EmittedMethodDebugInformation(ILSequencePoint[] sequencePoints)
            {
                _sequencePoints = sequencePoints;
            }

            public override IEnumerable<ILSequencePoint> GetSequencePoints()
            {
                return _sequencePoints;
            }
        }
    }

    public abstract partial class ILStubMethod : MethodDesc
    {
        public abstract MethodIL EmitIL();

        public override bool HasCustomAttribute(string attributeNamespace, string attributeName)
        {
            return false;
        }
    }
}


text:
<?php

namespace ITDoors\FileAccessBundle\Services;

use Symfony\Component\Filesystem\Exception\FileNotFoundException;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\Security\Core\SecurityContext;
use Symfony\Component\HttpFoundation\File\File;
use ITDoors\FileAccessBundle\Entity\FileAccessRecord;
use Doctrine\ORM\EntityManager;

/**
 * FileAccessService
 */
class FileAccessService
{
    protected $container;
    protected $projectWebDir;
    protected $em;
    protected $securityContext;

    /**
     * __construct
     *
     * @param Container         $container
     * @param string            $projectWebDir
     * @param EntityManager     $em
     * @param SecurityContext   $securityContext
     */
    public function __construct ($container, $projectWebDir, $em, $securityContext)
    {
        $this->em = $em;
        $this->container = $container;
        $this->projectWebDir = $projectWebDir;
        $this->securityContext = $securityContext;
    }

    /**
     * Returns file at given path if authenticated
     *
     * @param string  $path
     * @param integer $timestamp
     *
     * @throws FileNotFoundException If the given path is not a file
     *
     * @return File
     */
    public function getFileIfAuthenticated($path, $timestamp)
    {
        // authenticated REMEMBERED, FULLY will imply REMEMBERED (NON anonymous)
        if ($this->securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
            return $this->getFile($path, $timestamp);
        } else {
            return  null;
        }
    }

    /**
     * Returns file at given path if hasRole()
     *
     * @param string  $path
     * @param integer $timestamp
     * @param string  $role
     *
     * @throws FileNotFoundException If the given path is not a file
     *
     * @return File
     */
    public function getFileIfHasRole($path, $timestamp, $role)
    {
        if ($this->securityContext->isGranted($role)) {
            return $this->getFile($path, $timestamp);
        } else {
            return  null;
        }
    }

    private function getFile($path, $timestamp)
    {
        $fullPath = $this->projectWebDir . $path;
        $file = new File($fullPath);

        if ($file) {
            $date = new \DateTime();
            $date->setTimestamp($timestamp);
            $user = $this->securityContext->getToken()->getUser();

            $accessRecord = $this->em->getRepository('ITDoorsFileAccessBundle:FileAccessRecord')
                ->findOneBy(array(
                                'path' => $path,
                                'action' => 'get',
                                'date' => $date,
                                'user' => $user
                ));

            if (!$accessRecord) {
                $accessRecord = new FileAccessRecord(
                    $path,
                    'get',
                    $date,
                    $user
                );
                $this->em->persist($accessRecord);
                $this->em->flush();
            }
        }

        return $file;
    }
}