<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gfx/image/image_skia.h"

#include <algorithm>
#include <cmath>
#include <limits>

#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/gfx/skia_util.h"

namespace gfx {
namespace {

// static
gfx::ImageSkiaRep& NullImageRep() {
  CR_DEFINE_STATIC_LOCAL(ImageSkiaRep, null_image_rep, ());
  return null_image_rep;
}

}  // namespace

namespace internal {
namespace {

class Matcher {
 public:
  explicit Matcher(ui::ScaleFactor scale_factor) : scale_factor_(scale_factor) {
  }

  bool operator()(const ImageSkiaRep& rep) const {
    return rep.scale_factor() == scale_factor_;
  }

 private:
  ui::ScaleFactor scale_factor_;
};

}  // namespace

// A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a
// refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's
// information. Having both |base::RefCountedThreadSafe| and
// |base::NonThreadSafe| may sounds strange but necessary to turn
// the 'thread-non-safe modifiable ImageSkiaStorage' into
// the 'thread-safe read-only ImageSkiaStorage'.
class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>,
                         public base::NonThreadSafe {
 public:
  ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size)
      : source_(source),
        size_(size),
        read_only_(false) {
  }

  ImageSkiaStorage(ImageSkiaSource* source, ui::ScaleFactor scale_factor)
      : source_(source),
        read_only_(false) {
    ImageSkia::ImageSkiaReps::iterator it =
        FindRepresentation(scale_factor, true);
    if (it == image_reps_.end() || it->is_null())
      source_.reset();
    else
      size_.SetSize(it->GetWidth(), it->GetHeight());
  }

  bool has_source() const { return source_.get() != NULL; }

  std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; }

  const gfx::Size& size() const { return size_; }

  bool read_only() const { return read_only_; }

  void DeleteSource() {
    source_.reset();
  }

  void SetReadOnly() {
    read_only_ = true;
  }

  void DetachFromThread() {
    base::NonThreadSafe::DetachFromThread();
  }

  // Checks if the current thread can safely modify the storage.
  bool CanModify() const {
    return !read_only_ && CalledOnValidThread();
  }

  // Checks if the current thread can safely read the storage.
  bool CanRead() const {
    return (read_only_ && !source_.get()) || CalledOnValidThread();
  }

  // Returns the iterator of the image rep whose density best matches
  // |scale_factor|. If the image for the |scale_factor| doesn't exist
  // in the storage and |storage| is set, it fetches new image by calling
  // |ImageSkiaSource::GetImageForScale|. If the source returns the
  // image with different scale factor (if the image doesn't exist in
  // resource, for example), it will fallback to closest image rep.
  std::vector<ImageSkiaRep>::iterator FindRepresentation(
      ui::ScaleFactor scale_factor, bool fetch_new_image) const {
    ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this);

    float scale = ui::GetScaleFactorScale(scale_factor);
    ImageSkia::ImageSkiaReps::iterator closest_iter =
        non_const->image_reps().end();
    ImageSkia::ImageSkiaReps::iterator exact_iter =
        non_const->image_reps().end();
    float smallest_diff = std::numeric_limits<float>::max();
    for (ImageSkia::ImageSkiaReps::iterator it =
             non_const->image_reps().begin();
         it < image_reps_.end(); ++it) {
      if (it->GetScale() == scale) {
        // found exact match
        fetch_new_image = false;
        if (it->is_null())
          continue;
        exact_iter = it;
        break;
      }
      float diff = std::abs(it->GetScale() - scale);
      if (diff < smallest_diff && !it->is_null()) {
        closest_iter = it;
        smallest_diff = diff;
      }
    }

    if (fetch_new_image && source_.get()) {
      DCHECK(CalledOnValidThread()) <<
          "An ImageSkia with the source must be accessed by the same thread.";

      ImageSkiaRep image = source_->GetImageForScale(scale_factor);

      // If the source returned the new image, store it.
      if (!image.is_null() &&
          std::find_if(image_reps_.begin(), image_reps_.end(),
                       Matcher(image.scale_factor())) == image_reps_.end()) {
        non_const->image_reps().push_back(image);
      }

      // If the result image's scale factor isn't same as the expected
      // scale factor, create null ImageSkiaRep with the |scale_factor|
      // so that the next lookup will fallback to the closest scale.
      if (image.is_null() || image.scale_factor() != scale_factor) {
        non_const->image_reps().push_back(
            ImageSkiaRep(SkBitmap(), scale_factor));
      }

      // image_reps_ must have the exact much now, so find again.
      return FindRepresentation(scale_factor, false);
    }
    return exact_iter != image_reps_.end() ? exact_iter : closest_iter;
  }

 private:
  virtual ~ImageSkiaStorage() {
    // We only care if the storage is modified by the same thread.
    // Don't blow up even if someone else deleted the ImageSkia.
    DetachFromThread();
  }

  // Vector of bitmaps and their associated scale factor.
  std::vector<gfx::ImageSkiaRep> image_reps_;

  scoped_ptr<ImageSkiaSource> source_;

  // Size of the image in DIP.
  gfx::Size size_;

  bool read_only_;

  friend class base::RefCountedThreadSafe<ImageSkiaStorage>;
};

}  // internal

ImageSkia::ImageSkia() : storage_(NULL) {
}

ImageSkia::ImageSkia(ImageSkiaSource* source, const gfx::Size& size)
    : storage_(new internal::ImageSkiaStorage(source, size)) {
  DCHECK(source);
  // No other thread has reference to this, so it's safe to detach the thread.
  DetachStorageFromThread();
}

ImageSkia::ImageSkia(ImageSkiaSource* source, ui::ScaleFactor scale_factor)
    : storage_(new internal::ImageSkiaStorage(source, scale_factor)) {
  DCHECK(source);
  if (!storage_->has_source())
    storage_ = NULL;
  // No other thread has reference to this, so it's safe to detach the thread.
  DetachStorageFromThread();
}

ImageSkia::ImageSkia(const SkBitmap& bitmap) {
  Init(ImageSkiaRep(bitmap, ui::SCALE_FACTOR_100P));
  // No other thread has reference to this, so it's safe to detach the thread.
  DetachStorageFromThread();
}

ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) {
  Init(image_rep);
  // No other thread has reference to this, so it's safe to detach the thread.
  DetachStorageFromThread();
}

ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) {
}

ImageSkia& ImageSkia::operator=(const ImageSkia& other) {
  storage_ = other.storage_;
  return *this;
}

ImageSkia::~ImageSkia() {
}

scoped_ptr<ImageSkia> ImageSkia::DeepCopy() const {
  ImageSkia* copy = new ImageSkia;
  if (isNull())
    return scoped_ptr<ImageSkia>(copy);

  CHECK(CanRead());

  std::vector<gfx::ImageSkiaRep>& reps = storage_->image_reps();
  for (std::vector<gfx::ImageSkiaRep>::iterator iter = reps.begin();
       iter != reps.end(); ++iter) {
    copy->AddRepresentation(*iter);
  }
  // The copy has its own storage. Detach the copy from the current
  // thread so that other thread can use this.
  if (!copy->isNull())
    copy->storage_->DetachFromThread();
  return scoped_ptr<ImageSkia>(copy);
}

bool ImageSkia::BackedBySameObjectAs(const gfx::ImageSkia& other) const {
  return storage_.get() == other.storage_.get();
}

void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) {
  DCHECK(!image_rep.is_null());

  // TODO(oshima): This method should be called |SetRepresentation|
  // and replace the existing rep if there is already one with the
  // same scale factor so that we can guarantee that a ImageSkia
  // instance contians only one image rep per scale factor. This is
  // not possible now as ImageLoadingTracker currently stores need
  // this feature, but this needs to be fixed.
  if (isNull()) {
    Init(image_rep);
  } else {
    CHECK(CanModify());
    storage_->image_reps().push_back(image_rep);
  }
}

void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) {
  if (isNull())
    return;
  CHECK(CanModify());

  ImageSkiaReps& image_reps = storage_->image_reps();
  ImageSkiaReps::iterator it =
      storage_->FindRepresentation(scale_factor, false);
  if (it != image_reps.end() && it->scale_factor() == scale_factor)
    image_reps.erase(it);
}

bool ImageSkia::HasRepresentation(ui::ScaleFactor scale_factor) const {
  if (isNull())
    return false;
  CHECK(CanRead());

  ImageSkiaReps::iterator it =
      storage_->FindRepresentation(scale_factor, false);
  return (it != storage_->image_reps().end() &&
          it->scale_factor() == scale_factor);
}

const ImageSkiaRep& ImageSkia::GetRepresentation(
    ui::ScaleFactor scale_factor) const {
  if (isNull())
    return NullImageRep();

  CHECK(CanRead());

  ImageSkiaReps::iterator it = storage_->FindRepresentation(scale_factor, true);
  if (it == storage_->image_reps().end())
    return NullImageRep();

  return *it;
}

void ImageSkia::SetReadOnly() {
  CHECK(storage_);
  storage_->SetReadOnly();
  DetachStorageFromThread();
}

void ImageSkia::MakeThreadSafe() {
  CHECK(storage_);
  EnsureRepsForSupportedScaleFactors();
  // Delete source as we no longer needs it.
  if (storage_)
    storage_->DeleteSource();
  storage_->SetReadOnly();
  CHECK(IsThreadSafe());
}

bool ImageSkia::IsThreadSafe() const {
  return !storage_ || (storage_->read_only() && !storage_->has_source());
}

int ImageSkia::width() const {
  return isNull() ? 0 : storage_->size().width();
}

gfx::Size ImageSkia::size() const {
  return gfx::Size(width(), height());
}

int ImageSkia::height() const {
  return isNull() ? 0 : storage_->size().height();
}

std::vector<ImageSkiaRep> ImageSkia::image_reps() const {
  if (isNull())
    return std::vector<ImageSkiaRep>();

  CHECK(CanRead());

  ImageSkiaReps internal_image_reps = storage_->image_reps();
  // Create list of image reps to return, skipping null image reps which were
  // added for caching purposes only.
  ImageSkiaReps image_reps;
  for (ImageSkiaReps::iterator it = internal_image_reps.begin();
       it != internal_image_reps.end(); ++it) {
    if (!it->is_null())
      image_reps.push_back(*it);
  }

  return image_reps;
}

void ImageSkia::EnsureRepsForSupportedScaleFactors() const {
  // Don't check ReadOnly because the source may generate images
  // even for read only ImageSkia. Concurrent access will be protected
  // by |DCHECK(CalledOnValidThread())| in FindRepresentation.
  if (storage_ && storage_->has_source()) {
    std::vector<ui::ScaleFactor> supported_scale_factors =
        ui::GetSupportedScaleFactors();
    for (size_t i = 0; i < supported_scale_factors.size(); ++i)
      storage_->FindRepresentation(supported_scale_factors[i], true);
  }
}

void ImageSkia::Init(const ImageSkiaRep& image_rep) {
  // TODO(pkotwicz): The image should be null whenever image rep is null.
  if (image_rep.sk_bitmap().empty()) {
    storage_ = NULL;
    return;
  }
  storage_ = new internal::ImageSkiaStorage(
      NULL, gfx::Size(image_rep.GetWidth(), image_rep.GetHeight()));
  storage_->image_reps().push_back(image_rep);
}

SkBitmap& ImageSkia::GetBitmap() const {
  if (isNull()) {
    // Callers expect a ImageSkiaRep even if it is |isNull()|.
    // TODO(pkotwicz): Fix this.
    return NullImageRep().mutable_sk_bitmap();
  }

  // TODO(oshima): This made a few tests flaky on Windows.
  // Fix the root cause and re-enable this. crbug.com/145623.
#if !defined(OS_WIN)
  CHECK(CanRead());
#endif

  ImageSkiaReps::iterator it =
      storage_->FindRepresentation(ui::SCALE_FACTOR_100P, true);
  if (it != storage_->image_reps().end())
    return it->mutable_sk_bitmap();
  return NullImageRep().mutable_sk_bitmap();
}

bool ImageSkia::CanRead() const {
  return !storage_ || storage_->CanRead();
}

bool ImageSkia::CanModify() const {
  return !storage_ || storage_->CanModify();
}

void ImageSkia::DetachStorageFromThread() {
  if (storage_)
    storage_->DetachFromThread();
}

}  // namespace gfx
<commit_msg>Enable DCHECK in GetBitmap on WIN<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/gfx/image/image_skia.h"

#include <algorithm>
#include <cmath>
#include <limits>

#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
#include "base/threading/non_thread_safe.h"
#include "ui/gfx/image/image_skia_operations.h"
#include "ui/gfx/image/image_skia_source.h"
#include "ui/gfx/rect.h"
#include "ui/gfx/size.h"
#include "ui/gfx/skia_util.h"

namespace gfx {
namespace {

// static
gfx::ImageSkiaRep& NullImageRep() {
  CR_DEFINE_STATIC_LOCAL(ImageSkiaRep, null_image_rep, ());
  return null_image_rep;
}

}  // namespace

namespace internal {
namespace {

class Matcher {
 public:
  explicit Matcher(ui::ScaleFactor scale_factor) : scale_factor_(scale_factor) {
  }

  bool operator()(const ImageSkiaRep& rep) const {
    return rep.scale_factor() == scale_factor_;
  }

 private:
  ui::ScaleFactor scale_factor_;
};

}  // namespace

// A helper class such that ImageSkia can be cheaply copied. ImageSkia holds a
// refptr instance of ImageSkiaStorage, which in turn holds all of ImageSkia's
// information. Having both |base::RefCountedThreadSafe| and
// |base::NonThreadSafe| may sounds strange but necessary to turn
// the 'thread-non-safe modifiable ImageSkiaStorage' into
// the 'thread-safe read-only ImageSkiaStorage'.
class ImageSkiaStorage : public base::RefCountedThreadSafe<ImageSkiaStorage>,
                         public base::NonThreadSafe {
 public:
  ImageSkiaStorage(ImageSkiaSource* source, const gfx::Size& size)
      : source_(source),
        size_(size),
        read_only_(false) {
  }

  ImageSkiaStorage(ImageSkiaSource* source, ui::ScaleFactor scale_factor)
      : source_(source),
        read_only_(false) {
    ImageSkia::ImageSkiaReps::iterator it =
        FindRepresentation(scale_factor, true);
    if (it == image_reps_.end() || it->is_null())
      source_.reset();
    else
      size_.SetSize(it->GetWidth(), it->GetHeight());
  }

  bool has_source() const { return source_.get() != NULL; }

  std::vector<gfx::ImageSkiaRep>& image_reps() { return image_reps_; }

  const gfx::Size& size() const { return size_; }

  bool read_only() const { return read_only_; }

  void DeleteSource() {
    source_.reset();
  }

  void SetReadOnly() {
    read_only_ = true;
  }

  void DetachFromThread() {
    base::NonThreadSafe::DetachFromThread();
  }

  // Checks if the current thread can safely modify the storage.
  bool CanModify() const {
    return !read_only_ && CalledOnValidThread();
  }

  // Checks if the current thread can safely read the storage.
  bool CanRead() const {
    return (read_only_ && !source_.get()) || CalledOnValidThread();
  }

  // Returns the iterator of the image rep whose density best matches
  // |scale_factor|. If the image for the |scale_factor| doesn't exist
  // in the storage and |storage| is set, it fetches new image by calling
  // |ImageSkiaSource::GetImageForScale|. If the source returns the
  // image with different scale factor (if the image doesn't exist in
  // resource, for example), it will fallback to closest image rep.
  std::vector<ImageSkiaRep>::iterator FindRepresentation(
      ui::ScaleFactor scale_factor, bool fetch_new_image) const {
    ImageSkiaStorage* non_const = const_cast<ImageSkiaStorage*>(this);

    float scale = ui::GetScaleFactorScale(scale_factor);
    ImageSkia::ImageSkiaReps::iterator closest_iter =
        non_const->image_reps().end();
    ImageSkia::ImageSkiaReps::iterator exact_iter =
        non_const->image_reps().end();
    float smallest_diff = std::numeric_limits<float>::max();
    for (ImageSkia::ImageSkiaReps::iterator it =
             non_const->image_reps().begin();
         it < image_reps_.end(); ++it) {
      if (it->GetScale() == scale) {
        // found exact match
        fetch_new_image = false;
        if (it->is_null())
          continue;
        exact_iter = it;
        break;
      }
      float diff = std::abs(it->GetScale() - scale);
      if (diff < smallest_diff && !it->is_null()) {
        closest_iter = it;
        smallest_diff = diff;
      }
    }

    if (fetch_new_image && source_.get()) {
      DCHECK(CalledOnValidThread()) <<
          "An ImageSkia with the source must be accessed by the same thread.";

      ImageSkiaRep image = source_->GetImageForScale(scale_factor);

      // If the source returned the new image, store it.
      if (!image.is_null() &&
          std::find_if(image_reps_.begin(), image_reps_.end(),
                       Matcher(image.scale_factor())) == image_reps_.end()) {
        non_const->image_reps().push_back(image);
      }

      // If the result image's scale factor isn't same as the expected
      // scale factor, create null ImageSkiaRep with the |scale_factor|
      // so that the next lookup will fallback to the closest scale.
      if (image.is_null() || image.scale_factor() != scale_factor) {
        non_const->image_reps().push_back(
            ImageSkiaRep(SkBitmap(), scale_factor));
      }

      // image_reps_ must have the exact much now, so find again.
      return FindRepresentation(scale_factor, false);
    }
    return exact_iter != image_reps_.end() ? exact_iter : closest_iter;
  }

 private:
  virtual ~ImageSkiaStorage() {
    // We only care if the storage is modified by the same thread.
    // Don't blow up even if someone else deleted the ImageSkia.
    DetachFromThread();
  }

  // Vector of bitmaps and their associated scale factor.
  std::vector<gfx::ImageSkiaRep> image_reps_;

  scoped_ptr<ImageSkiaSource> source_;

  // Size of the image in DIP.
  gfx::Size size_;

  bool read_only_;

  friend class base::RefCountedThreadSafe<ImageSkiaStorage>;
};

}  // internal

ImageSkia::ImageSkia() : storage_(NULL) {
}

ImageSkia::ImageSkia(ImageSkiaSource* source, const gfx::Size& size)
    : storage_(new internal::ImageSkiaStorage(source, size)) {
  DCHECK(source);
  // No other thread has reference to this, so it's safe to detach the thread.
  DetachStorageFromThread();
}

ImageSkia::ImageSkia(ImageSkiaSource* source, ui::ScaleFactor scale_factor)
    : storage_(new internal::ImageSkiaStorage(source, scale_factor)) {
  DCHECK(source);
  if (!storage_->has_source())
    storage_ = NULL;
  // No other thread has reference to this, so it's safe to detach the thread.
  DetachStorageFromThread();
}

ImageSkia::ImageSkia(const SkBitmap& bitmap) {
  Init(ImageSkiaRep(bitmap, ui::SCALE_FACTOR_100P));
  // No other thread has reference to this, so it's safe to detach the thread.
  DetachStorageFromThread();
}

ImageSkia::ImageSkia(const ImageSkiaRep& image_rep) {
  Init(image_rep);
  // No other thread has reference to this, so it's safe to detach the thread.
  DetachStorageFromThread();
}

ImageSkia::ImageSkia(const ImageSkia& other) : storage_(other.storage_) {
}

ImageSkia& ImageSkia::operator=(const ImageSkia& other) {
  storage_ = other.storage_;
  return *this;
}

ImageSkia::~ImageSkia() {
}

scoped_ptr<ImageSkia> ImageSkia::DeepCopy() const {
  ImageSkia* copy = new ImageSkia;
  if (isNull())
    return scoped_ptr<ImageSkia>(copy);

  CHECK(CanRead());

  std::vector<gfx::ImageSkiaRep>& reps = storage_->image_reps();
  for (std::vector<gfx::ImageSkiaRep>::iterator iter = reps.begin();
       iter != reps.end(); ++iter) {
    copy->AddRepresentation(*iter);
  }
  // The copy has its own storage. Detach the copy from the current
  // thread so that other thread can use this.
  if (!copy->isNull())
    copy->storage_->DetachFromThread();
  return scoped_ptr<ImageSkia>(copy);
}

bool ImageSkia::BackedBySameObjectAs(const gfx::ImageSkia& other) const {
  return storage_.get() == other.storage_.get();
}

void ImageSkia::AddRepresentation(const ImageSkiaRep& image_rep) {
  DCHECK(!image_rep.is_null());

  // TODO(oshima): This method should be called |SetRepresentation|
  // and replace the existing rep if there is already one with the
  // same scale factor so that we can guarantee that a ImageSkia
  // instance contians only one image rep per scale factor. This is
  // not possible now as ImageLoadingTracker currently stores need
  // this feature, but this needs to be fixed.
  if (isNull()) {
    Init(image_rep);
  } else {
    CHECK(CanModify());
    storage_->image_reps().push_back(image_rep);
  }
}

void ImageSkia::RemoveRepresentation(ui::ScaleFactor scale_factor) {
  if (isNull())
    return;
  CHECK(CanModify());

  ImageSkiaReps& image_reps = storage_->image_reps();
  ImageSkiaReps::iterator it =
      storage_->FindRepresentation(scale_factor, false);
  if (it != image_reps.end() && it->scale_factor() == scale_factor)
    image_reps.erase(it);
}

bool ImageSkia::HasRepresentation(ui::ScaleFactor scale_factor) const {
  if (isNull())
    return false;
  CHECK(CanRead());

  ImageSkiaReps::iterator it =
      storage_->FindRepresentation(scale_factor, false);
  return (it != storage_->image_reps().end() &&
          it->scale_factor() == scale_factor);
}

const ImageSkiaRep& ImageSkia::GetRepresentation(
    ui::ScaleFactor scale_factor) const {
  if (isNull())
    return NullImageRep();

  CHECK(CanRead());

  ImageSkiaReps::iterator it = storage_->FindRepresentation(scale_factor, true);
  if (it == storage_->image_reps().end())
    return NullImageRep();

  return *it;
}

void ImageSkia::SetReadOnly() {
  CHECK(storage_);
  storage_->SetReadOnly();
  DetachStorageFromThread();
}

void ImageSkia::MakeThreadSafe() {
  CHECK(storage_);
  EnsureRepsForSupportedScaleFactors();
  // Delete source as we no longer needs it.
  if (storage_)
    storage_->DeleteSource();
  storage_->SetReadOnly();
  CHECK(IsThreadSafe());
}

bool ImageSkia::IsThreadSafe() const {
  return !storage_ || (storage_->read_only() && !storage_->has_source());
}

int ImageSkia::width() const {
  return isNull() ? 0 : storage_->size().width();
}

gfx::Size ImageSkia::size() const {
  return gfx::Size(width(), height());
}

int ImageSkia::height() const {
  return isNull() ? 0 : storage_->size().height();
}

std::vector<ImageSkiaRep> ImageSkia::image_reps() const {
  if (isNull())
    return std::vector<ImageSkiaRep>();

  CHECK(CanRead());

  ImageSkiaReps internal_image_reps = storage_->image_reps();
  // Create list of image reps to return, skipping null image reps which were
  // added for caching purposes only.
  ImageSkiaReps image_reps;
  for (ImageSkiaReps::iterator it = internal_image_reps.begin();
       it != internal_image_reps.end(); ++it) {
    if (!it->is_null())
      image_reps.push_back(*it);
  }

  return image_reps;
}

void ImageSkia::EnsureRepsForSupportedScaleFactors() const {
  // Don't check ReadOnly because the source may generate images
  // even for read only ImageSkia. Concurrent access will be protected
  // by |DCHECK(CalledOnValidThread())| in FindRepresentation.
  if (storage_ && storage_->has_source()) {
    std::vector<ui::ScaleFactor> supported_scale_factors =
        ui::GetSupportedScaleFactors();
    for (size_t i = 0; i < supported_scale_factors.size(); ++i)
      storage_->FindRepresentation(supported_scale_factors[i], true);
  }
}

void ImageSkia::Init(const ImageSkiaRep& image_rep) {
  // TODO(pkotwicz): The image should be null whenever image rep is null.
  if (image_rep.sk_bitmap().empty()) {
    storage_ = NULL;
    return;
  }
  storage_ = new internal::ImageSkiaStorage(
      NULL, gfx::Size(image_rep.GetWidth(), image_rep.GetHeight()));
  storage_->image_reps().push_back(image_rep);
}

SkBitmap& ImageSkia::GetBitmap() const {
  if (isNull()) {
    // Callers expect a ImageSkiaRep even if it is |isNull()|.
    // TODO(pkotwicz): Fix this.
    return NullImageRep().mutable_sk_bitmap();
  }

  CHECK(CanRead());

  ImageSkiaReps::iterator it =
      storage_->FindRepresentation(ui::SCALE_FACTOR_100P, true);
  if (it != storage_->image_reps().end())
    return it->mutable_sk_bitmap();
  return NullImageRep().mutable_sk_bitmap();
}

bool ImageSkia::CanRead() const {
  return !storage_ || storage_->CanRead();
}

bool ImageSkia::CanModify() const {
  return !storage_ || storage_->CanModify();
}

void ImageSkia::DetachStorageFromThread() {
  if (storage_)
    storage_->DetachFromThread();
}

}  // namespace gfx
<|endoftext|>


<commit_before>/*
 *
 *    Copyright (c) 2021 Project CHIP Authors
 *
 *    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.
 */
#include "DeviceAttestationConstructor.h"
#include "DeviceAttestationVendorReserved.h"

#include <lib/core/CHIPTLV.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>

#include <cstdint>

namespace chip {
namespace Credentials {

// context tag positions
enum AttestationInfoId : uint32_t
{
    kCertificationDeclarationTagId = 1,
    kAttestationNonceTagId         = 2,
    kTimestampTagId                = 3,
    kFirmwareInfoTagId             = 4,
};

enum OperationalCSRInfoId : uint32_t
{
    kCsr             = 1,
    kCsrNonce        = 2,
    kVendorReserved1 = 3,
    kVendorReserved2 = 4,
    kVendorReserved3 = 5,
};

// utility to determine number of Vendor Reserved elements in a bytespan
CHIP_ERROR CountVendorReservedElementsInDA(const ByteSpan & attestationElements, size_t & numOfElements)
{
    TLV::ContiguousBufferTLVReader tlvReader;
    TLV::TLVType containerType = TLV::kTLVType_Structure;

    tlvReader.Init(attestationElements);
    ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag()));
    ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));

    size_t count = 0;
    CHIP_ERROR error;
    while ((error = tlvReader.Next()) == CHIP_NO_ERROR)
    {
        TLV::Tag tag = tlvReader.GetTag();
        if (TLV::IsProfileTag(tag))
        {
            count++;
        }
    }
    VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error);

    numOfElements = count;
    return CHIP_NO_ERROR;
}

CHIP_ERROR DeconstructAttestationElements(const ByteSpan & attestationElements, ByteSpan & certificationDeclaration,
                                          ByteSpan & attestationNonce, uint32_t & timestamp, ByteSpan & firmwareInfo,
                                          DeviceAttestationVendorReservedDeconstructor & vendorReserved)
{
    bool certificationDeclarationExists = false;
    bool attestationNonceExists         = false;
    bool timestampExists                = false;
    bool gotFirstContextTag             = false;
    uint32_t lastContextTagId           = 0;

    TLV::ContiguousBufferTLVReader tlvReader;
    TLV::TLVType containerType = TLV::kTLVType_Structure;

    firmwareInfo = ByteSpan();

    tlvReader.Init(attestationElements);
    ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag()));
    ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));

    CHIP_ERROR error;

    // process context tags first (should be in sorted order)
    while ((error = tlvReader.Next()) == CHIP_NO_ERROR)
    {
        TLV::Tag tag = tlvReader.GetTag();
        if (!TLV::IsContextTag(tag))
        {
            break;
        }

        // Ensure tag-order and correct first expected tag
        uint32_t contextTagId = TLV::TagNumFromTag(tag);
        if (!gotFirstContextTag)
        {
            // First tag must always be Certification Declaration
            VerifyOrReturnError(contextTagId == kCertificationDeclarationTagId, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
            gotFirstContextTag = true;
        }
        else
        {
            // Subsequent tags must always be in order
            VerifyOrReturnError(contextTagId > lastContextTagId, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
        }
        lastContextTagId = contextTagId;

        switch (contextTagId)
        {
        case kCertificationDeclarationTagId:
            ReturnErrorOnFailure(tlvReader.GetByteView(certificationDeclaration));
            certificationDeclarationExists = true;
            break;
        case kAttestationNonceTagId:
            ReturnErrorOnFailure(tlvReader.GetByteView(attestationNonce));
            attestationNonceExists = true;
            break;
        case kTimestampTagId:
            ReturnErrorOnFailure(tlvReader.Get(timestamp));
            timestampExists = true;
            break;
        case kFirmwareInfoTagId:
            ReturnErrorOnFailure(tlvReader.GetByteView(firmwareInfo));
            break;
        default:
            // It's OK to have future context tags before vendor specific tags.
            // We already checked that the tags are in order.
            break;
        }
    }

    VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error);

    const bool allTagsNeededPresent = certificationDeclarationExists && attestationNonceExists && timestampExists;
    VerifyOrReturnError(allTagsNeededPresent, CHIP_ERROR_MISSING_TLV_ELEMENT);

    size_t count = 0;
    ReturnErrorOnFailure(CountVendorReservedElementsInDA(attestationElements, count));
    ReturnErrorOnFailure(vendorReserved.PrepareToReadVendorReservedElements(attestationElements, count));
    return CHIP_NO_ERROR;
}

CHIP_ERROR ConstructAttestationElements(const ByteSpan & certificationDeclaration, const ByteSpan & attestationNonce,
                                        uint32_t timestamp, const ByteSpan & firmwareInfo,
                                        DeviceAttestationVendorReservedConstructor & vendorReserved,
                                        MutableByteSpan & attestationElements)
{
    TLV::TLVWriter tlvWriter;
    TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;

    VerifyOrReturnError(!certificationDeclaration.empty() && !attestationNonce.empty(), CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrReturnError(attestationNonce.size() == kExpectedAttestationNonceSize, CHIP_ERROR_INVALID_ARGUMENT);

    tlvWriter.Init(attestationElements.data(), static_cast<uint32_t>(attestationElements.size()));
    outerContainerType = TLV::kTLVType_NotSpecified;
    ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
    ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), certificationDeclaration));
    ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), attestationNonce));
    ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), timestamp));
    if (!firmwareInfo.empty())
    {
        ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(4), firmwareInfo));
    }

    const VendorReservedElement * element = vendorReserved.cbegin();
    while ((element = vendorReserved.Next()) != nullptr)
    {
        ReturnErrorOnFailure(
            tlvWriter.Put(TLV::ProfileTag(element->vendorId, element->profileNum, element->tagNum), element->vendorReservedData));
    }

    ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
    ReturnErrorOnFailure(tlvWriter.Finalize());
    attestationElements = attestationElements.SubSpan(0, tlvWriter.GetLengthWritten());

    return CHIP_NO_ERROR;
}

CHIP_ERROR ConstructNOCSRElements(const ByteSpan & csr, const ByteSpan & csrNonce, const ByteSpan & vendor_reserved1,
                                  const ByteSpan & vendor_reserved2, const ByteSpan & vendor_reserved3,
                                  MutableByteSpan & nocsrElements)
{
    TLV::TLVWriter tlvWriter;
    TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;

    VerifyOrReturnError(!csr.empty() && !csrNonce.empty(), CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrReturnError(csrNonce.size() == kExpectedAttestationNonceSize, CHIP_ERROR_INVALID_ARGUMENT);

    tlvWriter.Init(nocsrElements.data(), static_cast<uint32_t>(nocsrElements.size()));
    outerContainerType = TLV::kTLVType_NotSpecified;
    ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
    ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), csr));
    ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), csrNonce));
    if (!vendor_reserved1.empty())
    {
        ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), vendor_reserved1));
    }
    if (!vendor_reserved2.empty())
    {
        ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(4), vendor_reserved2));
    }
    if (!vendor_reserved3.empty())
    {
        ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(5), vendor_reserved3));
    }

    ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
    ReturnErrorOnFailure(tlvWriter.Finalize());
    nocsrElements = nocsrElements.SubSpan(0, tlvWriter.GetLengthWritten());

    return CHIP_NO_ERROR;
}

CHIP_ERROR DeconstructNOCSRElements(const ByteSpan & nocsrElements, ByteSpan & csr, ByteSpan & csrNonce,
                                    ByteSpan & vendor_reserved1, ByteSpan & vendor_reserved2, ByteSpan & vendor_reserved3)
{
    bool csrExists            = false;
    bool csrNonceExists       = false;
    bool gotFirstContextTag   = false;
    uint32_t lastContextTagId = 0;

    TLV::ContiguousBufferTLVReader tlvReader;
    TLV::TLVType containerType = TLV::kTLVType_Structure;

    // empty out the optional items initially
    vendor_reserved1 = vendor_reserved2 = vendor_reserved3 = ByteSpan();

    tlvReader.Init(nocsrElements);
    ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag));
    ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));

    CHIP_ERROR error;

    // process context tags first (should be in sorted order)
    while ((error = tlvReader.Next()) == CHIP_NO_ERROR)
    {
        TLV::Tag tag = tlvReader.GetTag();
        if (!TLV::IsContextTag(tag))
        {
            break;
        }

        // Ensure tag-order and correct first expected tag
        uint32_t contextTagId = TLV::TagNumFromTag(tag);
        if (!gotFirstContextTag)
        {
            // First tag must always be CSR
            VerifyOrReturnError(contextTagId == kCsr, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
            gotFirstContextTag = true;
        }
        else
        {
            // Subsequent tags must always be in order
            VerifyOrReturnError(contextTagId > lastContextTagId, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
        }
        lastContextTagId = contextTagId;

        switch (contextTagId)
        {
        case kCsr:
            ReturnErrorOnFailure(tlvReader.GetByteView(csr));
            csrExists = true;
            break;
        case kCsrNonce:
            ReturnErrorOnFailure(tlvReader.GetByteView(csrNonce));
            csrNonceExists = true;
            break;
        case kVendorReserved1:
            ReturnErrorOnFailure(tlvReader.Get(vendor_reserved1));
            break;
        case kVendorReserved2:
            ReturnErrorOnFailure(tlvReader.Get(vendor_reserved2));
            break;
        case kVendorReserved3:
            ReturnErrorOnFailure(tlvReader.Get(vendor_reserved3));
            break;
        default:
            // unrecognized TLV element
            return CHIP_ERROR_INVALID_TLV_ELEMENT;
        }
    }

    VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error);

    const bool allTagsNeededPresent = csrExists && csrNonceExists;
    VerifyOrReturnError(allTagsNeededPresent, CHIP_ERROR_MISSING_TLV_ELEMENT);

    return CHIP_NO_ERROR;
}

} // namespace Credentials

} // namespace chip
<commit_msg>Fix build failure (#13302)<commit_after>/*
 *
 *    Copyright (c) 2021 Project CHIP Authors
 *
 *    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.
 */
#include "DeviceAttestationConstructor.h"
#include "DeviceAttestationVendorReserved.h"

#include <lib/core/CHIPTLV.h>
#include <lib/support/CodeUtils.h>
#include <lib/support/logging/CHIPLogging.h>

#include <cstdint>

namespace chip {
namespace Credentials {

// context tag positions
enum AttestationInfoId : uint32_t
{
    kCertificationDeclarationTagId = 1,
    kAttestationNonceTagId         = 2,
    kTimestampTagId                = 3,
    kFirmwareInfoTagId             = 4,
};

enum OperationalCSRInfoId : uint32_t
{
    kCsr             = 1,
    kCsrNonce        = 2,
    kVendorReserved1 = 3,
    kVendorReserved2 = 4,
    kVendorReserved3 = 5,
};

// utility to determine number of Vendor Reserved elements in a bytespan
CHIP_ERROR CountVendorReservedElementsInDA(const ByteSpan & attestationElements, size_t & numOfElements)
{
    TLV::ContiguousBufferTLVReader tlvReader;
    TLV::TLVType containerType = TLV::kTLVType_Structure;

    tlvReader.Init(attestationElements);
    ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag()));
    ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));

    size_t count = 0;
    CHIP_ERROR error;
    while ((error = tlvReader.Next()) == CHIP_NO_ERROR)
    {
        TLV::Tag tag = tlvReader.GetTag();
        if (TLV::IsProfileTag(tag))
        {
            count++;
        }
    }
    VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error);

    numOfElements = count;
    return CHIP_NO_ERROR;
}

CHIP_ERROR DeconstructAttestationElements(const ByteSpan & attestationElements, ByteSpan & certificationDeclaration,
                                          ByteSpan & attestationNonce, uint32_t & timestamp, ByteSpan & firmwareInfo,
                                          DeviceAttestationVendorReservedDeconstructor & vendorReserved)
{
    bool certificationDeclarationExists = false;
    bool attestationNonceExists         = false;
    bool timestampExists                = false;
    bool gotFirstContextTag             = false;
    uint32_t lastContextTagId           = 0;

    TLV::ContiguousBufferTLVReader tlvReader;
    TLV::TLVType containerType = TLV::kTLVType_Structure;

    firmwareInfo = ByteSpan();

    tlvReader.Init(attestationElements);
    ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag()));
    ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));

    CHIP_ERROR error;

    // process context tags first (should be in sorted order)
    while ((error = tlvReader.Next()) == CHIP_NO_ERROR)
    {
        TLV::Tag tag = tlvReader.GetTag();
        if (!TLV::IsContextTag(tag))
        {
            break;
        }

        // Ensure tag-order and correct first expected tag
        uint32_t contextTagId = TLV::TagNumFromTag(tag);
        if (!gotFirstContextTag)
        {
            // First tag must always be Certification Declaration
            VerifyOrReturnError(contextTagId == kCertificationDeclarationTagId, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
            gotFirstContextTag = true;
        }
        else
        {
            // Subsequent tags must always be in order
            VerifyOrReturnError(contextTagId > lastContextTagId, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
        }
        lastContextTagId = contextTagId;

        switch (contextTagId)
        {
        case kCertificationDeclarationTagId:
            ReturnErrorOnFailure(tlvReader.GetByteView(certificationDeclaration));
            certificationDeclarationExists = true;
            break;
        case kAttestationNonceTagId:
            ReturnErrorOnFailure(tlvReader.GetByteView(attestationNonce));
            attestationNonceExists = true;
            break;
        case kTimestampTagId:
            ReturnErrorOnFailure(tlvReader.Get(timestamp));
            timestampExists = true;
            break;
        case kFirmwareInfoTagId:
            ReturnErrorOnFailure(tlvReader.GetByteView(firmwareInfo));
            break;
        default:
            // It's OK to have future context tags before vendor specific tags.
            // We already checked that the tags are in order.
            break;
        }
    }

    VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error);

    const bool allTagsNeededPresent = certificationDeclarationExists && attestationNonceExists && timestampExists;
    VerifyOrReturnError(allTagsNeededPresent, CHIP_ERROR_MISSING_TLV_ELEMENT);

    size_t count = 0;
    ReturnErrorOnFailure(CountVendorReservedElementsInDA(attestationElements, count));
    ReturnErrorOnFailure(vendorReserved.PrepareToReadVendorReservedElements(attestationElements, count));
    return CHIP_NO_ERROR;
}

CHIP_ERROR ConstructAttestationElements(const ByteSpan & certificationDeclaration, const ByteSpan & attestationNonce,
                                        uint32_t timestamp, const ByteSpan & firmwareInfo,
                                        DeviceAttestationVendorReservedConstructor & vendorReserved,
                                        MutableByteSpan & attestationElements)
{
    TLV::TLVWriter tlvWriter;
    TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;

    VerifyOrReturnError(!certificationDeclaration.empty() && !attestationNonce.empty(), CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrReturnError(attestationNonce.size() == kExpectedAttestationNonceSize, CHIP_ERROR_INVALID_ARGUMENT);

    tlvWriter.Init(attestationElements.data(), static_cast<uint32_t>(attestationElements.size()));
    outerContainerType = TLV::kTLVType_NotSpecified;
    ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
    ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), certificationDeclaration));
    ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), attestationNonce));
    ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), timestamp));
    if (!firmwareInfo.empty())
    {
        ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(4), firmwareInfo));
    }

    const VendorReservedElement * element = vendorReserved.cbegin();
    while ((element = vendorReserved.Next()) != nullptr)
    {
        ReturnErrorOnFailure(
            tlvWriter.Put(TLV::ProfileTag(element->vendorId, element->profileNum, element->tagNum), element->vendorReservedData));
    }

    ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
    ReturnErrorOnFailure(tlvWriter.Finalize());
    attestationElements = attestationElements.SubSpan(0, tlvWriter.GetLengthWritten());

    return CHIP_NO_ERROR;
}

CHIP_ERROR ConstructNOCSRElements(const ByteSpan & csr, const ByteSpan & csrNonce, const ByteSpan & vendor_reserved1,
                                  const ByteSpan & vendor_reserved2, const ByteSpan & vendor_reserved3,
                                  MutableByteSpan & nocsrElements)
{
    TLV::TLVWriter tlvWriter;
    TLV::TLVType outerContainerType = TLV::kTLVType_NotSpecified;

    VerifyOrReturnError(!csr.empty() && !csrNonce.empty(), CHIP_ERROR_INVALID_ARGUMENT);
    VerifyOrReturnError(csrNonce.size() == kExpectedAttestationNonceSize, CHIP_ERROR_INVALID_ARGUMENT);

    tlvWriter.Init(nocsrElements.data(), static_cast<uint32_t>(nocsrElements.size()));
    outerContainerType = TLV::kTLVType_NotSpecified;
    ReturnErrorOnFailure(tlvWriter.StartContainer(TLV::AnonymousTag(), TLV::kTLVType_Structure, outerContainerType));
    ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(1), csr));
    ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(2), csrNonce));
    if (!vendor_reserved1.empty())
    {
        ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(3), vendor_reserved1));
    }
    if (!vendor_reserved2.empty())
    {
        ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(4), vendor_reserved2));
    }
    if (!vendor_reserved3.empty())
    {
        ReturnErrorOnFailure(tlvWriter.Put(TLV::ContextTag(5), vendor_reserved3));
    }

    ReturnErrorOnFailure(tlvWriter.EndContainer(outerContainerType));
    ReturnErrorOnFailure(tlvWriter.Finalize());
    nocsrElements = nocsrElements.SubSpan(0, tlvWriter.GetLengthWritten());

    return CHIP_NO_ERROR;
}

CHIP_ERROR DeconstructNOCSRElements(const ByteSpan & nocsrElements, ByteSpan & csr, ByteSpan & csrNonce,
                                    ByteSpan & vendor_reserved1, ByteSpan & vendor_reserved2, ByteSpan & vendor_reserved3)
{
    bool csrExists            = false;
    bool csrNonceExists       = false;
    bool gotFirstContextTag   = false;
    uint32_t lastContextTagId = 0;

    TLV::ContiguousBufferTLVReader tlvReader;
    TLV::TLVType containerType = TLV::kTLVType_Structure;

    // empty out the optional items initially
    vendor_reserved1 = vendor_reserved2 = vendor_reserved3 = ByteSpan();

    tlvReader.Init(nocsrElements);
    ReturnErrorOnFailure(tlvReader.Next(containerType, TLV::AnonymousTag()));
    ReturnErrorOnFailure(tlvReader.EnterContainer(containerType));

    CHIP_ERROR error;

    // process context tags first (should be in sorted order)
    while ((error = tlvReader.Next()) == CHIP_NO_ERROR)
    {
        TLV::Tag tag = tlvReader.GetTag();
        if (!TLV::IsContextTag(tag))
        {
            break;
        }

        // Ensure tag-order and correct first expected tag
        uint32_t contextTagId = TLV::TagNumFromTag(tag);
        if (!gotFirstContextTag)
        {
            // First tag must always be CSR
            VerifyOrReturnError(contextTagId == kCsr, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
            gotFirstContextTag = true;
        }
        else
        {
            // Subsequent tags must always be in order
            VerifyOrReturnError(contextTagId > lastContextTagId, CHIP_ERROR_UNEXPECTED_TLV_ELEMENT);
        }
        lastContextTagId = contextTagId;

        switch (contextTagId)
        {
        case kCsr:
            ReturnErrorOnFailure(tlvReader.GetByteView(csr));
            csrExists = true;
            break;
        case kCsrNonce:
            ReturnErrorOnFailure(tlvReader.GetByteView(csrNonce));
            csrNonceExists = true;
            break;
        case kVendorReserved1:
            ReturnErrorOnFailure(tlvReader.Get(vendor_reserved1));
            break;
        case kVendorReserved2:
            ReturnErrorOnFailure(tlvReader.Get(vendor_reserved2));
            break;
        case kVendorReserved3:
            ReturnErrorOnFailure(tlvReader.Get(vendor_reserved3));
            break;
        default:
            // unrecognized TLV element
            return CHIP_ERROR_INVALID_TLV_ELEMENT;
        }
    }

    VerifyOrReturnError(error == CHIP_NO_ERROR || error == CHIP_END_OF_TLV, error);

    const bool allTagsNeededPresent = csrExists && csrNonceExists;
    VerifyOrReturnError(allTagsNeededPresent, CHIP_ERROR_MISSING_TLV_ELEMENT);

    return CHIP_NO_ERROR;
}

} // namespace Credentials

} // namespace chip
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: app.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: mba $ $Date: 2000-12-15 15:38:54 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "app.hxx"
#include "wrapper.hxx"

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif

#include <offmgr/app.hxx>
#include <comphelper/processfactory.hxx>
#ifndef _UTL_CONFIGMGR_HXX_
#include <unotools/configmgr.hxx>
#endif

#include <setup2/installer.hxx>
#include <svtools/pathoptions.hxx>
#include <unotools/configmgr.hxx>
#include <vcl/msgbox.hxx>

#define DEFINE_CONST_UNICODE(CONSTASCII)        UniString(RTL_CONSTASCII_USTRINGPARAM(CONSTASCII##))

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;

void ReplaceStringHookProc( UniString& rStr )
{
    static String aBrandName;
    static String aVersion;
    if ( !aBrandName.Len() )
    {
        Any aRet = ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTNAME );
        rtl::OUString aTmp;
        aRet >>= aTmp;
        aBrandName = aTmp;

        aRet = ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTVERSION );
        aRet >>= aTmp;
        aVersion = aTmp;
    }

    rStr.SearchAndReplaceAllAscii( "%PRODUCTNAME", aBrandName );
    rStr.SearchAndReplaceAllAscii( "%PRODUCTVERSION", aVersion );
}

Desktop aDesktop;

Desktop::Desktop()
{
}

void Desktop::Main()
{
    ResMgr::SetReadStringHook( ReplaceStringHookProc );
    SetAppName( DEFINE_CONST_UNICODE("soffice") );

    Installer* pInstaller = new Installer;
    pInstaller->InitializeInstallation( Application::GetAppFileName() );
    delete pInstaller;

    SvtPathOptions* pPathOptions = new SvtPathOptions;
    RegisterServices();
    OfficeWrapper* pWrapper = new OfficeWrapper( ::comphelper::getProcessServiceFactory() );
//    Reference < XComponent > xWrapper( ::utl::getProcessServiceFactory()->createInstance( DEFINE_CONST_UNICODE("com.sun.star.office.OfficeWrapper" ) ), UNO_QUERY );
    SfxApplicationClass::Main();
//    xWrapper->dispose();

    if( pWrapper!=NULL)
    {
        delete pWrapper;
        pWrapper=NULL;
    }

    delete pPathOptions;
    utl::ConfigManager::RemoveConfigManager();
}

void Desktop::SystemSettingsChanging( AllSettings& rSettings, Window* pFrame )
{
    OFF_APP()->SystemSettingsChanging( rSettings, pFrame );
}

<commit_msg>fix: #82184# added<commit_after>/*************************************************************************
 *
 *  $RCSfile: app.cxx,v $
 *
 *  $Revision: 1.10 $
 *
 *  last change: $Author: pb $ $Date: 2001-01-23 11:56:12 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#include "app.hxx"
#include "wrapper.hxx"

#ifndef _COM_SUN_STAR_UNO_REFERENCE_H_
#include <com/sun/star/uno/Reference.h>
#endif
#ifndef _COM_SUN_STAR_LANG_XCOMPONENT_HPP_
#include <com/sun/star/lang/XComponent.hpp>
#endif

#include <offmgr/app.hxx>
#include <comphelper/processfactory.hxx>
#ifndef _UTL_CONFIGMGR_HXX_
#include <unotools/configmgr.hxx>
#endif

#include <setup2/installer.hxx>
#include <svtools/pathoptions.hxx>
#include <unotools/configmgr.hxx>
#include <vcl/msgbox.hxx>

#define DEFINE_CONST_UNICODE(CONSTASCII)        UniString(RTL_CONSTASCII_USTRINGPARAM(CONSTASCII##))

using namespace ::com::sun::star::uno;
using namespace ::com::sun::star::lang;

void ReplaceStringHookProc( UniString& rStr )
{
    static String aBrandName;
    static String aVersion;
    static String aExtension;

    static int nAll = 0, nPro = 0;

    if ( !aBrandName.Len() )
    {
        Any aRet = ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTNAME );
        rtl::OUString aTmp;
        aRet >>= aTmp;
        aBrandName = aTmp;

        aRet = ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTVERSION );
        aRet >>= aTmp;
        aVersion = aTmp;

        aRet = ::utl::ConfigManager::GetDirectConfigProperty( ::utl::ConfigManager::PRODUCTEXTENSION );
        aRet >>= aTmp;
        aExtension = aTmp;
    }

    nAll++;
    if ( rStr.SearchAscii( "%PRODUCT" ) != STRING_NOTFOUND )
    {
        nPro++;
        rStr.SearchAndReplaceAllAscii( "%PRODUCTNAME", aBrandName );
        rStr.SearchAndReplaceAllAscii( "%PRODUCTVERSION", aVersion );
        rStr.SearchAndReplaceAllAscii( "%PRODUCTEXTENSION", aExtension );
    }
}

Desktop aDesktop;

Desktop::Desktop()
{
}

void Desktop::Main()
{
    ResMgr::SetReadStringHook( ReplaceStringHookProc );
    SetAppName( DEFINE_CONST_UNICODE("soffice") );

    Installer* pInstaller = new Installer;
    pInstaller->InitializeInstallation( Application::GetAppFileName() );
    delete pInstaller;

    SvtPathOptions* pPathOptions = new SvtPathOptions;
    RegisterServices();
    OfficeWrapper* pWrapper = new OfficeWrapper( ::comphelper::getProcessServiceFactory() );
//    Reference < XComponent > xWrapper( ::utl::getProcessServiceFactory()->createInstance( DEFINE_CONST_UNICODE("com.sun.star.office.OfficeWrapper" ) ), UNO_QUERY );
    SfxApplicationClass::Main();
//    xWrapper->dispose();

    if( pWrapper!=NULL)
    {
        delete pWrapper;
        pWrapper=NULL;
    }

    delete pPathOptions;
    utl::ConfigManager::RemoveConfigManager();
}

void Desktop::SystemSettingsChanging( AllSettings& rSettings, Window* pFrame )
{
    OFF_APP()->SystemSettingsChanging( rSettings, pFrame );
}

<|endoftext|>


<commit_before>/*
 * This file is part of telepathy-nepomuk-service
 *
 * Copyright (C) 2009-2011 Collabora Ltd. <info@collabora.co.uk>
 *   @author George Goldberg <george.goldberg@collabora.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "account.h"

#include "contact.h"

#include <KDebug>

#include <TelepathyQt/ContactManager>
#include <TelepathyQt/PendingContacts>
#include <TelepathyQt/PendingOperation>
#include <TelepathyQt/PendingReady>

Account::Account(const Tp::AccountPtr &account, QObject *parent)
 : QObject(parent),
   m_account(account)
{
    // Do nothing here. Wait for init() to be called to allow
    // signal/slot connections to be set up first.
    kDebug() << "Account Constructed.";
}

void Account::init()
{
    // Connect to all the signals that indicate changes in properties we care about.
    connect(m_account.data(),
            SIGNAL(nicknameChanged(QString)),
            SLOT(onNicknameChanged(QString)));
    connect(m_account.data(),
            SIGNAL(currentPresenceChanged(Tp::Presence)),
            SLOT(onCurrentPresenceChanged(Tp::Presence)));
    //    connect(m_account.data(),
    //            SIGNAL(avatarChanged(Tp::Avatar)),
    //            SLOT(onAvatarChanged(Tp::Avatar)));
    // ...... and any other properties we want to sync...
    connect(m_account.data(),
            SIGNAL(connectionChanged(Tp::ConnectionPtr)),
            SLOT(onConnectionChanged(Tp::ConnectionPtr)));

    // Emit a signal to notify the storage that a new account has been constructed
    // FIXME: Some IM Accounts don't have an ID as such, e.g. Link-Local-XMPP.
    emit created(m_account->objectPath(),
                 m_account->parameters().value(QLatin1String("account")).toString(),
                 m_account->protocolName());

    // Simulate all the accounts properties being changed.
    onCurrentPresenceChanged(m_account->currentPresence());
    onNicknameChanged(m_account->nickname());

    // Now that the storage stuff is done, simulate emission of all the account signals.
    onConnectionChanged(m_account->connection());
}

Account::~Account()
{
    kDebug();
}

void Account::shutdown()
{
    // Loop over all our children, and if they're Accounts, shut them down.
    foreach (Contact *contact, m_contacts.values()) {
        contact->shutdown();
    }

    kDebug();

    // Emit a signal to say we were destroyed.
    emit accountDestroyed(m_account->objectPath());
}

void Account::onConnectionChanged(const Tp::ConnectionPtr &connection)
{
    if (! connection.isNull()) {
        m_connection = connection;

        if (!m_connection->contactManager()) {
            kWarning() << "ContactManager is Null. Abort getting contacts.";
            return;
        }

        //add contacts as soon as the contact manager is ready.
        connect(m_connection->contactManager().data(),
                SIGNAL(stateChanged(Tp::ContactListState)),
                SLOT(onContactManagerStateChanged(Tp::ContactListState)));
        // Simulate a state change signal in case it is already ready.
        onContactManagerStateChanged(m_connection->contactManager()->state());

    } else {
        // Connection has gone down. Delete our pointer to it.
        m_connection.reset();
        kDebug() << "Connection closed:" << this;
    }
}

void Account::onContactManagerStateChanged(Tp::ContactListState state)
{
//    kDebug() << "contact manager state changed to " << state;

    if (state == Tp::ContactListStateSuccess)  {
        Tp::Contacts contacts = m_connection->contactManager()->allKnownContacts();

        // Create the hash containing all the contacts to notify the storage of the
        // full set of contacts that still exist when the account is connected.
        // This *must* be done before creating the contact wrapper objects.
        QList<QString> initialContacts;
        foreach (const Tp::ContactPtr &contact, contacts) {
            initialContacts.append(contact->id());
        }
        emit initialContactsLoaded(m_account->objectPath(), initialContacts);

        // Create wrapper objects for all the Contacts.
        foreach (const Tp::ContactPtr &contact, contacts) {
            onNewContact(contact);
        }
//        kDebug() << "Loop over.";
    }
}

void Account::onNicknameChanged(const QString& nickname)
{
    emit nicknameChanged(m_account->objectPath(), nickname);
}

void Account::onCurrentPresenceChanged(const Tp::Presence &presence)
{
    emit currentPresenceChanged(m_account->objectPath(), presence.barePresence());
}

void Account::onAllKnownContactsChanged(const Tp::Contacts& added, const Tp::Contacts& removed)
{
    // For each added contact, let's check if we already have a Contact wrapper for it
    foreach (const Tp::ContactPtr &contact, added) {
        if (!m_contacts.contains(contact)) {
            // It's a brand new one
            onNewContact(contact);
        }
    }

    // If contacts are removed, we don't actually need to do anything!
    Q_UNUSED(removed);
}

void Account::onNewContact(const Tp::ContactPtr &contact)
{
    // Only create a new contact if one doesn't already exist.
    if (!m_contacts.contains(contact)) {
        // Create a new Contact wrapper objectPath
        Contact *c = new Contact(contact, this);

        // Insert it into the Hash.
        m_contacts.insert(contact, c);

        // Connect to all its signals
        connect(c,
                SIGNAL(created(QString)),
                SLOT(onContactCreated(QString)));
        connect(c,
                SIGNAL(contactDestroyed(QString,Tp::ContactPtr)),
                SLOT(onContactDestroyed(QString,Tp::ContactPtr)));
        connect(c,
                SIGNAL(aliasChanged(QString,QString)),
                SLOT(onContactAliasChanged(QString,QString)));
        connect(c,
                SIGNAL(presenceChanged(QString,Tp::SimplePresence)),
                SLOT(onContactPresenceChanged(QString,Tp::SimplePresence)));
        connect(c,
                SIGNAL(groupsChanged(QString,QStringList)),
                SLOT(onContactGroupsChanged(QString,QStringList)));
        connect(c,
                SIGNAL(blockStatusChanged(QString,bool)),
                SLOT(onContactBlockStatusChanged(QString,bool)));
        connect(c,
                SIGNAL(publishStateChanged(QString,Tp::Contact::PresenceState)),
                SLOT(onContactPublishStateChanged(QString,Tp::Contact::PresenceState)));
        connect(c,
                SIGNAL(subscriptionStateChanged(QString,Tp::Contact::PresenceState)),
                SLOT(onContactSubscriptionStateChanged(QString,Tp::Contact::PresenceState)));
        connect(c,
                SIGNAL(capabilitiesChanged(QString,Tp::ConnectionPtr,Tp::ContactCapabilities)),
                SLOT(onContactCapabilitiesChanged(QString,Tp::ConnectionPtr,Tp::ContactCapabilities)));
        connect(c,
                SIGNAL(avatarChanged(QString,Tp::AvatarData)),
                SLOT(onContactAvatarChanged(QString,Tp::AvatarData)));

        c->init();
    }
}

void Account::onContactCreated(const QString &id)
{
    emit contactCreated(m_account->objectPath(), id);
}

void Account::onContactDestroyed(const QString &id, const Tp::ContactPtr &contact)
{
    m_contacts.remove(contact);

    // Relay this signal to the controller
    emit contactDestroyed(m_account->objectPath(), id);
}

void Account::onContactAliasChanged(const QString &id, const QString &alias)
{
    emit contactAliasChanged(m_account->objectPath(), id, alias);
}

void Account::onContactPresenceChanged(const QString &id, const Tp::SimplePresence &presence)
{
    emit contactPresenceChanged(m_account->objectPath(), id, presence);
}

void Account::onContactGroupsChanged(const QString &id, const QStringList &groups)
{
    emit contactGroupsChanged(m_account->objectPath(), id, groups);
}

void Account::onContactBlockStatusChanged(const QString &id, bool blocked)
{
    emit contactBlockStatusChanged(m_account->objectPath(), id, blocked);
}

void Account::onContactPublishStateChanged(const QString &id, const Tp::Contact::PresenceState &state)
{
    emit contactPublishStateChanged(m_account->objectPath(), id, state);
}

void Account::onContactSubscriptionStateChanged(const QString &id, const Tp::Contact::PresenceState &state)
{
    emit contactSubscriptionStateChanged(m_account->objectPath(), id, state);
}

void Account::onContactCapabilitiesChanged(const QString &id, const Tp::ConnectionPtr &connection, const Tp::ContactCapabilities &capabilities)
{
    emit contactCapabilitiesChanged(m_account->objectPath(), id, connection, capabilities);
}

void Account::onContactAvatarChanged(const QString &id, const Tp::AvatarData &avatar)
{
    emit contactAvatarChanged(m_account->objectPath(), id, avatar);
}

#include "account.moc"

<commit_msg>Use account service name if available<commit_after>/*
 * This file is part of telepathy-nepomuk-service
 *
 * Copyright (C) 2009-2011 Collabora Ltd. <info@collabora.co.uk>
 *   @author George Goldberg <george.goldberg@collabora.co.uk>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "account.h"

#include "contact.h"

#include <KDebug>

#include <TelepathyQt/ContactManager>
#include <TelepathyQt/PendingContacts>
#include <TelepathyQt/PendingOperation>
#include <TelepathyQt/PendingReady>

Account::Account(const Tp::AccountPtr &account, QObject *parent)
 : QObject(parent),
   m_account(account)
{
    // Do nothing here. Wait for init() to be called to allow
    // signal/slot connections to be set up first.
    kDebug() << "Account Constructed.";
}

void Account::init()
{
    // Connect to all the signals that indicate changes in properties we care about.
    connect(m_account.data(),
            SIGNAL(nicknameChanged(QString)),
            SLOT(onNicknameChanged(QString)));
    connect(m_account.data(),
            SIGNAL(currentPresenceChanged(Tp::Presence)),
            SLOT(onCurrentPresenceChanged(Tp::Presence)));
    //    connect(m_account.data(),
    //            SIGNAL(avatarChanged(Tp::Avatar)),
    //            SLOT(onAvatarChanged(Tp::Avatar)));
    // ...... and any other properties we want to sync...
    connect(m_account.data(),
            SIGNAL(connectionChanged(Tp::ConnectionPtr)),
            SLOT(onConnectionChanged(Tp::ConnectionPtr)));

    QString protocolName = m_account->serviceName().isEmpty() ? m_account->protocolName() : m_account->serviceName();
    // Emit a signal to notify the storage that a new account has been constructed
    // FIXME: Some IM Accounts don't have an ID as such, e.g. Link-Local-XMPP.
    emit created(m_account->objectPath(),
                 m_account->parameters().value(QLatin1String("account")).toString(),
                 protocolName);

    // Simulate all the accounts properties being changed.
    onCurrentPresenceChanged(m_account->currentPresence());
    onNicknameChanged(m_account->nickname());

    // Now that the storage stuff is done, simulate emission of all the account signals.
    onConnectionChanged(m_account->connection());
}

Account::~Account()
{
    kDebug();
}

void Account::shutdown()
{
    // Loop over all our children, and if they're Accounts, shut them down.
    foreach (Contact *contact, m_contacts.values()) {
        contact->shutdown();
    }

    kDebug();

    // Emit a signal to say we were destroyed.
    emit accountDestroyed(m_account->objectPath());
}

void Account::onConnectionChanged(const Tp::ConnectionPtr &connection)
{
    if (! connection.isNull()) {
        m_connection = connection;

        if (!m_connection->contactManager()) {
            kWarning() << "ContactManager is Null. Abort getting contacts.";
            return;
        }

        //add contacts as soon as the contact manager is ready.
        connect(m_connection->contactManager().data(),
                SIGNAL(stateChanged(Tp::ContactListState)),
                SLOT(onContactManagerStateChanged(Tp::ContactListState)));
        // Simulate a state change signal in case it is already ready.
        onContactManagerStateChanged(m_connection->contactManager()->state());

    } else {
        // Connection has gone down. Delete our pointer to it.
        m_connection.reset();
        kDebug() << "Connection closed:" << this;
    }
}

void Account::onContactManagerStateChanged(Tp::ContactListState state)
{
//    kDebug() << "contact manager state changed to " << state;

    if (state == Tp::ContactListStateSuccess)  {
        Tp::Contacts contacts = m_connection->contactManager()->allKnownContacts();

        // Create the hash containing all the contacts to notify the storage of the
        // full set of contacts that still exist when the account is connected.
        // This *must* be done before creating the contact wrapper objects.
        QList<QString> initialContacts;
        foreach (const Tp::ContactPtr &contact, contacts) {
            initialContacts.append(contact->id());
        }
        emit initialContactsLoaded(m_account->objectPath(), initialContacts);

        // Create wrapper objects for all the Contacts.
        foreach (const Tp::ContactPtr &contact, contacts) {
            onNewContact(contact);
        }
//        kDebug() << "Loop over.";
    }
}

void Account::onNicknameChanged(const QString& nickname)
{
    emit nicknameChanged(m_account->objectPath(), nickname);
}

void Account::onCurrentPresenceChanged(const Tp::Presence &presence)
{
    emit currentPresenceChanged(m_account->objectPath(), presence.barePresence());
}

void Account::onAllKnownContactsChanged(const Tp::Contacts& added, const Tp::Contacts& removed)
{
    // For each added contact, let's check if we already have a Contact wrapper for it
    foreach (const Tp::ContactPtr &contact, added) {
        if (!m_contacts.contains(contact)) {
            // It's a brand new one
            onNewContact(contact);
        }
    }

    // If contacts are removed, we don't actually need to do anything!
    Q_UNUSED(removed);
}

void Account::onNewContact(const Tp::ContactPtr &contact)
{
    // Only create a new contact if one doesn't already exist.
    if (!m_contacts.contains(contact)) {
        // Create a new Contact wrapper objectPath
        Contact *c = new Contact(contact, this);

        // Insert it into the Hash.
        m_contacts.insert(contact, c);

        // Connect to all its signals
        connect(c,
                SIGNAL(created(QString)),
                SLOT(onContactCreated(QString)));
        connect(c,
                SIGNAL(contactDestroyed(QString,Tp::ContactPtr)),
                SLOT(onContactDestroyed(QString,Tp::ContactPtr)));
        connect(c,
                SIGNAL(aliasChanged(QString,QString)),
                SLOT(onContactAliasChanged(QString,QString)));
        connect(c,
                SIGNAL(presenceChanged(QString,Tp::SimplePresence)),
                SLOT(onContactPresenceChanged(QString,Tp::SimplePresence)));
        connect(c,
                SIGNAL(groupsChanged(QString,QStringList)),
                SLOT(onContactGroupsChanged(QString,QStringList)));
        connect(c,
                SIGNAL(blockStatusChanged(QString,bool)),
                SLOT(onContactBlockStatusChanged(QString,bool)));
        connect(c,
                SIGNAL(publishStateChanged(QString,Tp::Contact::PresenceState)),
                SLOT(onContactPublishStateChanged(QString,Tp::Contact::PresenceState)));
        connect(c,
                SIGNAL(subscriptionStateChanged(QString,Tp::Contact::PresenceState)),
                SLOT(onContactSubscriptionStateChanged(QString,Tp::Contact::PresenceState)));
        connect(c,
                SIGNAL(capabilitiesChanged(QString,Tp::ConnectionPtr,Tp::ContactCapabilities)),
                SLOT(onContactCapabilitiesChanged(QString,Tp::ConnectionPtr,Tp::ContactCapabilities)));
        connect(c,
                SIGNAL(avatarChanged(QString,Tp::AvatarData)),
                SLOT(onContactAvatarChanged(QString,Tp::AvatarData)));

        c->init();
    }
}

void Account::onContactCreated(const QString &id)
{
    emit contactCreated(m_account->objectPath(), id);
}

void Account::onContactDestroyed(const QString &id, const Tp::ContactPtr &contact)
{
    m_contacts.remove(contact);

    // Relay this signal to the controller
    emit contactDestroyed(m_account->objectPath(), id);
}

void Account::onContactAliasChanged(const QString &id, const QString &alias)
{
    emit contactAliasChanged(m_account->objectPath(), id, alias);
}

void Account::onContactPresenceChanged(const QString &id, const Tp::SimplePresence &presence)
{
    emit contactPresenceChanged(m_account->objectPath(), id, presence);
}

void Account::onContactGroupsChanged(const QString &id, const QStringList &groups)
{
    emit contactGroupsChanged(m_account->objectPath(), id, groups);
}

void Account::onContactBlockStatusChanged(const QString &id, bool blocked)
{
    emit contactBlockStatusChanged(m_account->objectPath(), id, blocked);
}

void Account::onContactPublishStateChanged(const QString &id, const Tp::Contact::PresenceState &state)
{
    emit contactPublishStateChanged(m_account->objectPath(), id, state);
}

void Account::onContactSubscriptionStateChanged(const QString &id, const Tp::Contact::PresenceState &state)
{
    emit contactSubscriptionStateChanged(m_account->objectPath(), id, state);
}

void Account::onContactCapabilitiesChanged(const QString &id, const Tp::ConnectionPtr &connection, const Tp::ContactCapabilities &capabilities)
{
    emit contactCapabilitiesChanged(m_account->objectPath(), id, connection, capabilities);
}

void Account::onContactAvatarChanged(const QString &id, const Tp::AvatarData &avatar)
{
    emit contactAvatarChanged(m_account->objectPath(), id, avatar);
}

#include "account.moc"

<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: autonamecache.cxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: kz $ $Date: 2006-01-31 18:35:00 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifdef PCH
#include "core_pch.hxx"
#endif

#pragma hdrstop

// INCLUDE ---------------------------------------------------------------

#include <unotools/transliterationwrapper.hxx>

#include "autonamecache.hxx"
#include "dociter.hxx"
#include "cell.hxx"

// -----------------------------------------------------------------------

ScAutoNameCache::ScAutoNameCache( ScDocument* pD ) :
    pDoc( pD ),
    nCurrentTab( 0 )    // doesn't matter - aNames is empty
{
}

ScAutoNameCache::~ScAutoNameCache()
{
}

const ScAutoNameAddresses& ScAutoNameCache::GetNameOccurences( const String& rName, SCTAB nTab )
{
    if ( nTab != nCurrentTab )
    {
        // the lists are valid only for one sheet, so they are cleared when another sheet is used
        aNames.clear();
        nCurrentTab = nTab;
    }

    ScAutoNameHashMap::const_iterator aFound = aNames.find( rName );
    if ( aFound != aNames.end() )
        return aFound->second;          // already initialized

    ScAutoNameAddresses& rAddresses = aNames[rName];

    ScCellIterator aIter( pDoc, ScRange( 0, 0, nCurrentTab, MAXCOL, MAXROW, nCurrentTab ) );
    for ( ScBaseCell* pCell = aIter.GetFirst(); pCell; pCell = aIter.GetNext() )
    {
        // don't check code length here, always use the stored result
        // (AutoCalc is disabled during CompileXML)

        if ( pCell->HasStringData() )
        {
            String aStr;
            CellType eType = pCell->GetCellType();
            switch ( eType )
            {
                case CELLTYPE_STRING:
                    ((ScStringCell*)pCell)->GetString( aStr );
                break;
                case CELLTYPE_FORMULA:
                    ((ScFormulaCell*)pCell)->GetString( aStr );
                break;
                case CELLTYPE_EDIT:
                    ((ScEditCell*)pCell)->GetString( aStr );
                break;
                case CELLTYPE_NONE:
                case CELLTYPE_VALUE:
                case CELLTYPE_NOTE:
                case CELLTYPE_SYMBOLS:
                case CELLTYPE_DESTROYED:
                    ;   // nothing, prevent compiler warning
                break;
            }
            if ( ScGlobal::pTransliteration->isEqual( aStr, rName ) )
            {
                rAddresses.push_back( ScAddress( aIter.GetCol(), aIter.GetRow(), aIter.GetTab() ) );
            }
        }
    }

    return rAddresses;
}

<commit_msg>INTEGRATION: CWS pchfix01 (1.2.138); FILE MERGED 2006/07/12 10:01:28 kaib 1.2.138.1: #i67080# Converted cxx files in sc, added initial project level pch and stripped old PCH definitions.<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: autonamecache.cxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: kz $ $Date: 2006-07-21 10:47:14 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"

// INCLUDE ---------------------------------------------------------------

#include <unotools/transliterationwrapper.hxx>

#include "autonamecache.hxx"
#include "dociter.hxx"
#include "cell.hxx"

// -----------------------------------------------------------------------

ScAutoNameCache::ScAutoNameCache( ScDocument* pD ) :
    pDoc( pD ),
    nCurrentTab( 0 )    // doesn't matter - aNames is empty
{
}

ScAutoNameCache::~ScAutoNameCache()
{
}

const ScAutoNameAddresses& ScAutoNameCache::GetNameOccurences( const String& rName, SCTAB nTab )
{
    if ( nTab != nCurrentTab )
    {
        // the lists are valid only for one sheet, so they are cleared when another sheet is used
        aNames.clear();
        nCurrentTab = nTab;
    }

    ScAutoNameHashMap::const_iterator aFound = aNames.find( rName );
    if ( aFound != aNames.end() )
        return aFound->second;          // already initialized

    ScAutoNameAddresses& rAddresses = aNames[rName];

    ScCellIterator aIter( pDoc, ScRange( 0, 0, nCurrentTab, MAXCOL, MAXROW, nCurrentTab ) );
    for ( ScBaseCell* pCell = aIter.GetFirst(); pCell; pCell = aIter.GetNext() )
    {
        // don't check code length here, always use the stored result
        // (AutoCalc is disabled during CompileXML)

        if ( pCell->HasStringData() )
        {
            String aStr;
            CellType eType = pCell->GetCellType();
            switch ( eType )
            {
                case CELLTYPE_STRING:
                    ((ScStringCell*)pCell)->GetString( aStr );
                break;
                case CELLTYPE_FORMULA:
                    ((ScFormulaCell*)pCell)->GetString( aStr );
                break;
                case CELLTYPE_EDIT:
                    ((ScEditCell*)pCell)->GetString( aStr );
                break;
                case CELLTYPE_NONE:
                case CELLTYPE_VALUE:
                case CELLTYPE_NOTE:
                case CELLTYPE_SYMBOLS:
                case CELLTYPE_DESTROYED:
                    ;   // nothing, prevent compiler warning
                break;
            }
            if ( ScGlobal::pTransliteration->isEqual( aStr, rName ) )
            {
                rAddresses.push_back( ScAddress( aIter.GetCol(), aIter.GetRow(), aIter.GetTab() ) );
            }
        }
    }

    return rAddresses;
}

<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "feedconfigstore.h"
#include "feedstates.h"
#include "ifeedview.h"
#include "ireplayconfig.h"
#include "replaypacketdispatcher.h"
#include <vespa/searchcore/proton/bucketdb/ibucketdbhandler.h>
#include <vespa/searchcore/proton/feedoperation/operations.h>
#include <vespa/searchcore/proton/common/eventlogger.h>
#include <vespa/searchlib/common/idestructorcallback.h>
#include <vespa/vespalib/util/closuretask.h>
#include <vespa/vespalib/util/lambdatask.h>

#include <vespa/log/log.h>
LOG_SETUP(".proton.server.feedstates");

using search::transactionlog::Packet;
using search::transactionlog::client::RPC;
using search::SerialNum;
using vespalib::Executor;
using vespalib::makeClosure;
using vespalib::makeLambdaTask;
using vespalib::makeTask;
using vespalib::make_string;
using proton::bucketdb::IBucketDBHandler;

namespace proton {

namespace {
typedef vespalib::Closure1<const Packet::Entry &>::UP EntryHandler;

const search::SerialNum REPLAY_PROGRESS_INTERVAL = 50000;

void
handleProgress(TlsReplayProgress &progress, SerialNum currentSerial)
{
    progress.updateCurrent(currentSerial);
    if (LOG_WOULD_LOG(event) && (LOG_WOULD_LOG(debug) ||
            (progress.getCurrent() % REPLAY_PROGRESS_INTERVAL == 0)))
    {
        EventLogger::transactionLogReplayProgress(progress.getDomainName(),
                                                  progress.getProgress(),
                                                  progress.getFirst(),
                                                  progress.getLast(),
                                                  progress.getCurrent());
    }
}

void
handlePacket(PacketWrapper & wrap, EntryHandler entryHandler)
{
    vespalib::nbostream_longlivedbuf handle(wrap.packet.getHandle().data(), wrap.packet.getHandle().size());
    while ( !handle.empty() ) {
        Packet::Entry entry;
        entry.deserialize(handle);
        entryHandler->call(entry);
        if (wrap.progress != nullptr) {
            handleProgress(*wrap.progress, entry.serial());
        }
    }
    wrap.result = RPC::OK;
    wrap.gate.countDown();
}

class TransactionLogReplayPacketHandler : public IReplayPacketHandler {
    IFeedView *& _feed_view_ptr;  // Pointer can be changed in executor thread.
    IBucketDBHandler &_bucketDBHandler;
    IReplayConfig &_replay_config;
    FeedConfigStore &_config_store;
    CommitTimeTracker _commitTimeTracker;

public:
    TransactionLogReplayPacketHandler(IFeedView *& feed_view_ptr,
                                      IBucketDBHandler &bucketDBHandler,
                                      IReplayConfig &replay_config,
                                      FeedConfigStore &config_store)
        : _feed_view_ptr(feed_view_ptr),
          _bucketDBHandler(bucketDBHandler),
          _replay_config(replay_config),
          _config_store(config_store),
          _commitTimeTracker(100ms)
    { }

    ~TransactionLogReplayPacketHandler() override = default;

    void replay(const PutOperation &op) override {
        _feed_view_ptr->handlePut(FeedToken(), op);
    }
    void replay(const RemoveOperation &op) override {
        _feed_view_ptr->handleRemove(FeedToken(), op);
    }
    void replay(const UpdateOperation &op) override {
        _feed_view_ptr->handleUpdate(FeedToken(), op);
    }
    void replay(const NoopOperation &) override {} // ignored
    void replay(const NewConfigOperation &op) override {
        _replay_config.replayConfig(op.getSerialNum());
    }

    void replay(const DeleteBucketOperation &op) override {
        _feed_view_ptr->handleDeleteBucket(op);
    }
    void replay(const SplitBucketOperation &op) override {
        _bucketDBHandler.handleSplit(op.getSerialNum(), op.getSource(),
                                     op.getTarget1(), op.getTarget2());
    }
    void replay(const JoinBucketsOperation &op) override {
        _bucketDBHandler.handleJoin(op.getSerialNum(), op.getSource1(),
                                    op.getSource2(), op.getTarget());
    }
    void replay(const PruneRemovedDocumentsOperation &op) override {
        _feed_view_ptr->handlePruneRemovedDocuments(op);
    }
    void replay(const MoveOperation &op) override {
        _feed_view_ptr->handleMove(op, search::IDestructorCallback::SP());
    }
    void replay(const CreateBucketOperation &) override {
    }
    void replay(const CompactLidSpaceOperation &op) override {
        _feed_view_ptr->handleCompactLidSpace(op);
    }
    NewConfigOperation::IStreamHandler &getNewConfigStreamHandler() override {
        return _config_store;
    }
    const document::DocumentTypeRepo &getDeserializeRepo() override {
        return *_feed_view_ptr->getDocumentTypeRepo();
    }
    void optionalCommit(search::SerialNum serialNum) override {
        if (_commitTimeTracker.needCommit()) {
            _feed_view_ptr->forceCommit(serialNum);
        }
    }
};

void startDispatch(IReplayPacketHandler *packet_handler, const Packet::Entry &entry) {
    // Called by handlePacket() in executor thread.
    LOG(spam, "replay packet entry: entrySerial(%" PRIu64 "), entryType(%u)", entry.serial(), entry.type());

    ReplayPacketDispatcher dispatcher(*packet_handler);
    dispatcher.replayEntry(entry);
    packet_handler->optionalCommit(entry.serial());
}

}  // namespace

ReplayTransactionLogState::ReplayTransactionLogState(
        const vespalib::string &name,
        IFeedView *& feed_view_ptr,
        IBucketDBHandler &bucketDBHandler,
        IReplayConfig &replay_config,
        FeedConfigStore &config_store)
    : FeedState(REPLAY_TRANSACTION_LOG),
      _doc_type_name(name),
      _packet_handler(std::make_unique<TransactionLogReplayPacketHandler>(feed_view_ptr, bucketDBHandler, replay_config, config_store))
{ }

ReplayTransactionLogState::~ReplayTransactionLogState() = default;

void
ReplayTransactionLogState::receive(const PacketWrapper::SP &wrap, Executor &executor) {
    EntryHandler closure = makeClosure(&startDispatch, _packet_handler.get());
    executor.execute(makeLambdaTask([wrap = wrap, dispatch = std::move(closure)] () mutable { handlePacket(*wrap, std::move(dispatch)); }));
}

}  // namespace proton
<commit_msg>Commit every 5ms during TLS replay<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "feedconfigstore.h"
#include "feedstates.h"
#include "ifeedview.h"
#include "ireplayconfig.h"
#include "replaypacketdispatcher.h"
#include <vespa/searchcore/proton/bucketdb/ibucketdbhandler.h>
#include <vespa/searchcore/proton/feedoperation/operations.h>
#include <vespa/searchcore/proton/common/eventlogger.h>
#include <vespa/searchlib/common/idestructorcallback.h>
#include <vespa/vespalib/util/closuretask.h>
#include <vespa/vespalib/util/lambdatask.h>

#include <vespa/log/log.h>
LOG_SETUP(".proton.server.feedstates");

using search::transactionlog::Packet;
using search::transactionlog::client::RPC;
using search::SerialNum;
using vespalib::Executor;
using vespalib::makeClosure;
using vespalib::makeLambdaTask;
using vespalib::makeTask;
using vespalib::make_string;
using proton::bucketdb::IBucketDBHandler;

namespace proton {

namespace {
typedef vespalib::Closure1<const Packet::Entry &>::UP EntryHandler;

const search::SerialNum REPLAY_PROGRESS_INTERVAL = 50000;

void
handleProgress(TlsReplayProgress &progress, SerialNum currentSerial)
{
    progress.updateCurrent(currentSerial);
    if (LOG_WOULD_LOG(event) && (LOG_WOULD_LOG(debug) ||
            (progress.getCurrent() % REPLAY_PROGRESS_INTERVAL == 0)))
    {
        EventLogger::transactionLogReplayProgress(progress.getDomainName(),
                                                  progress.getProgress(),
                                                  progress.getFirst(),
                                                  progress.getLast(),
                                                  progress.getCurrent());
    }
}

void
handlePacket(PacketWrapper & wrap, EntryHandler entryHandler)
{
    vespalib::nbostream_longlivedbuf handle(wrap.packet.getHandle().data(), wrap.packet.getHandle().size());
    while ( !handle.empty() ) {
        Packet::Entry entry;
        entry.deserialize(handle);
        entryHandler->call(entry);
        if (wrap.progress != nullptr) {
            handleProgress(*wrap.progress, entry.serial());
        }
    }
    wrap.result = RPC::OK;
    wrap.gate.countDown();
}

class TransactionLogReplayPacketHandler : public IReplayPacketHandler {
    IFeedView *& _feed_view_ptr;  // Pointer can be changed in executor thread.
    IBucketDBHandler &_bucketDBHandler;
    IReplayConfig &_replay_config;
    FeedConfigStore &_config_store;
    CommitTimeTracker _commitTimeTracker;

public:
    TransactionLogReplayPacketHandler(IFeedView *& feed_view_ptr,
                                      IBucketDBHandler &bucketDBHandler,
                                      IReplayConfig &replay_config,
                                      FeedConfigStore &config_store)
        : _feed_view_ptr(feed_view_ptr),
          _bucketDBHandler(bucketDBHandler),
          _replay_config(replay_config),
          _config_store(config_store),
          _commitTimeTracker(5ms)
    { }

    ~TransactionLogReplayPacketHandler() override = default;

    void replay(const PutOperation &op) override {
        _feed_view_ptr->handlePut(FeedToken(), op);
    }
    void replay(const RemoveOperation &op) override {
        _feed_view_ptr->handleRemove(FeedToken(), op);
    }
    void replay(const UpdateOperation &op) override {
        _feed_view_ptr->handleUpdate(FeedToken(), op);
    }
    void replay(const NoopOperation &) override {} // ignored
    void replay(const NewConfigOperation &op) override {
        _replay_config.replayConfig(op.getSerialNum());
    }

    void replay(const DeleteBucketOperation &op) override {
        _feed_view_ptr->handleDeleteBucket(op);
    }
    void replay(const SplitBucketOperation &op) override {
        _bucketDBHandler.handleSplit(op.getSerialNum(), op.getSource(),
                                     op.getTarget1(), op.getTarget2());
    }
    void replay(const JoinBucketsOperation &op) override {
        _bucketDBHandler.handleJoin(op.getSerialNum(), op.getSource1(),
                                    op.getSource2(), op.getTarget());
    }
    void replay(const PruneRemovedDocumentsOperation &op) override {
        _feed_view_ptr->handlePruneRemovedDocuments(op);
    }
    void replay(const MoveOperation &op) override {
        _feed_view_ptr->handleMove(op, search::IDestructorCallback::SP());
    }
    void replay(const CreateBucketOperation &) override {
    }
    void replay(const CompactLidSpaceOperation &op) override {
        _feed_view_ptr->handleCompactLidSpace(op);
    }
    NewConfigOperation::IStreamHandler &getNewConfigStreamHandler() override {
        return _config_store;
    }
    const document::DocumentTypeRepo &getDeserializeRepo() override {
        return *_feed_view_ptr->getDocumentTypeRepo();
    }
    void optionalCommit(search::SerialNum serialNum) override {
        if (_commitTimeTracker.needCommit()) {
            _feed_view_ptr->forceCommit(serialNum);
        }
    }
};

void startDispatch(IReplayPacketHandler *packet_handler, const Packet::Entry &entry) {
    // Called by handlePacket() in executor thread.
    LOG(spam, "replay packet entry: entrySerial(%" PRIu64 "), entryType(%u)", entry.serial(), entry.type());

    ReplayPacketDispatcher dispatcher(*packet_handler);
    dispatcher.replayEntry(entry);
    packet_handler->optionalCommit(entry.serial());
}

}  // namespace

ReplayTransactionLogState::ReplayTransactionLogState(
        const vespalib::string &name,
        IFeedView *& feed_view_ptr,
        IBucketDBHandler &bucketDBHandler,
        IReplayConfig &replay_config,
        FeedConfigStore &config_store)
    : FeedState(REPLAY_TRANSACTION_LOG),
      _doc_type_name(name),
      _packet_handler(std::make_unique<TransactionLogReplayPacketHandler>(feed_view_ptr, bucketDBHandler, replay_config, config_store))
{ }

ReplayTransactionLogState::~ReplayTransactionLogState() = default;

void
ReplayTransactionLogState::receive(const PacketWrapper::SP &wrap, Executor &executor) {
    EntryHandler closure = makeClosure(&startDispatch, _packet_handler.get());
    executor.execute(makeLambdaTask([wrap = wrap, dispatch = std::move(closure)] () mutable { handlePacket(*wrap, std::move(dispatch)); }));
}

}  // namespace proton
<|endoftext|>