<commit_before>// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <google/protobuf/pyext/unknown_fields.h>

#include <Python.h>
#include <set>
#include <memory>

#include <google/protobuf/message.h>
#include <google/protobuf/pyext/message.h>
#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/wire_format_lite.h>

namespace google {
namespace protobuf {
namespace python {

namespace unknown_fields {

static Py_ssize_t Len(PyObject* pself) {
  PyUnknownFields* self =
      reinterpret_cast<PyUnknownFields*>(pself);
  if (self->fields == NULL) {
    PyErr_Format(PyExc_ValueError,
                 "UnknownFields does not exist. "
                 "The parent message might be cleared.");
    return -1;
  }
  return self->fields->field_count();
}

void Clear(PyUnknownFields* self) {
  for (std::set<PyUnknownFields*>::iterator it =
           self->sub_unknown_fields.begin();
       it != self->sub_unknown_fields.end(); it++) {
    Clear(*it);
  }
  self->fields = NULL;
  self->sub_unknown_fields.clear();
}

PyObject* NewPyUnknownFieldRef(PyUnknownFields* parent,
                               Py_ssize_t index);

static PyObject* Item(PyObject* pself, Py_ssize_t index) {
  PyUnknownFields* self =
      reinterpret_cast<PyUnknownFields*>(pself);
  if (self->fields == NULL) {
    PyErr_Format(PyExc_ValueError,
                 "UnknownFields does not exist. "
                 "The parent message might be cleared.");
    return NULL;
  }
  Py_ssize_t total_size = self->fields->field_count();
  if (index < 0) {
    index = total_size + index;
  }
  if (index < 0 || index >= total_size) {
    PyErr_Format(PyExc_IndexError,
                 "index (%zd) out of range",
                 index);
    return NULL;
  }

  return unknown_fields::NewPyUnknownFieldRef(self, index);
}

PyObject* NewPyUnknownFields(CMessage* c_message) {
  PyUnknownFields* self = reinterpret_cast<PyUnknownFields*>(
      PyType_GenericAlloc(&PyUnknownFields_Type, 0));
  if (self == NULL) {
    return NULL;
  }
  // Call "placement new" to initialize PyUnknownFields.
  new (self) PyUnknownFields;

  Py_INCREF(c_message);
  self->parent = reinterpret_cast<PyObject*>(c_message);
  Message* message = c_message->message;
  const Reflection* reflection = message->GetReflection();
  self->fields = &reflection->GetUnknownFields(*message);

  return reinterpret_cast<PyObject*>(self);
}

PyObject* NewPyUnknownFieldRef(PyUnknownFields* parent,
                               Py_ssize_t index) {
  PyUnknownFieldRef* self = reinterpret_cast<PyUnknownFieldRef*>(
      PyType_GenericAlloc(&PyUnknownFieldRef_Type, 0));
  if (self == NULL) {
    return NULL;
  }

  Py_INCREF(parent);
  self->parent = parent;
  self->index = index;

  return reinterpret_cast<PyObject*>(self);
}

static void Dealloc(PyObject* pself) {
  PyUnknownFields* self =
      reinterpret_cast<PyUnknownFields*>(pself);
  if (PyObject_TypeCheck(self->parent, &PyUnknownFields_Type)) {
    reinterpret_cast<PyUnknownFields*>(
        self->parent)->sub_unknown_fields.erase(self);
  } else {
    reinterpret_cast<CMessage*>(self->parent)->unknown_field_set = nullptr;
  }
  Py_CLEAR(self->parent);
  self->~PyUnknownFields();
  Py_TYPE(pself)->tp_free(pself);
}

static PySequenceMethods SqMethods = {
  Len,        /* sq_length */
  0,          /* sq_concat */
  0,          /* sq_repeat */
  Item,       /* sq_item */
  0,          /* sq_slice */
  0,          /* sq_ass_item */
};

}  // namespace unknown_fields

PyTypeObject PyUnknownFields_Type = {
  PyVarObject_HEAD_INIT(&PyType_Type, 0)
  FULL_MODULE_NAME ".PyUnknownFields",  // tp_name
  sizeof(PyUnknownFields),             // tp_basicsize
  0,                                   //  tp_itemsize
  unknown_fields::Dealloc,             //  tp_dealloc
  0,                                   //  tp_print
  0,                                   //  tp_getattr
  0,                                   //  tp_setattr
  0,                                   //  tp_compare
  0,                                   //  tp_repr
  0,                                   //  tp_as_number
  &unknown_fields::SqMethods,          //  tp_as_sequence
  0,                                   //  tp_as_mapping
  PyObject_HashNotImplemented,         //  tp_hash
  0,                                   //  tp_call
  0,                                   //  tp_str
  0,                                   //  tp_getattro
  0,                                   //  tp_setattro
  0,                                   //  tp_as_buffer
  Py_TPFLAGS_DEFAULT,                  //  tp_flags
  "unknown field set",                 //  tp_doc
  0,                                   //  tp_traverse
  0,                                   //  tp_clear
  0,                                   //  tp_richcompare
  0,                                   //  tp_weaklistoffset
  0,                                   //  tp_iter
  0,                                   //  tp_iternext
  0,                                   //  tp_methods
  0,                                   //  tp_members
  0,                                   //  tp_getset
  0,                                   //  tp_base
  0,                                   //  tp_dict
  0,                                   //  tp_descr_get
  0,                                   //  tp_descr_set
  0,                                   //  tp_dictoffset
  0,                                   //  tp_init
};

namespace unknown_field {
static PyObject* PyUnknownFields_FromUnknownFieldSet(
    PyUnknownFields* parent, const UnknownFieldSet& fields) {
  PyUnknownFields* self = reinterpret_cast<PyUnknownFields*>(
      PyType_GenericAlloc(&PyUnknownFields_Type, 0));
  if (self == NULL) {
    return NULL;
  }
  // Call "placement new" to initialize PyUnknownFields.
  new (self) PyUnknownFields;

  Py_INCREF(parent);
  self->parent = reinterpret_cast<PyObject*>(parent);
  self->fields = &fields;
  parent->sub_unknown_fields.emplace(self);

  return reinterpret_cast<PyObject*>(self);
}

const UnknownField* GetUnknownField(PyUnknownFieldRef* self) {
  const UnknownFieldSet* fields = self->parent->fields;
  if (fields == NULL) {
    PyErr_Format(PyExc_ValueError,
                 "UnknownField does not exist. "
                 "The parent message might be cleared.");
    return NULL;
  }
  ssize_t total_size = fields->field_count();
  if (self->index >= total_size) {
    PyErr_Format(PyExc_ValueError,
                 "UnknownField does not exist. "
                 "The parent message might be cleared.");
    return NULL;
  }
  return &fields->field(self->index);
}

static PyObject* GetFieldNumber(PyUnknownFieldRef* self, void *closure) {
  const UnknownField* unknown_field = GetUnknownField(self);
  if (unknown_field == NULL) {
    return NULL;
  }
  return PyLong_FromLong(unknown_field->number());
}

using internal::WireFormatLite;
static PyObject* GetWireType(PyUnknownFieldRef* self, void *closure) {
  const UnknownField* unknown_field = GetUnknownField(self);
  if (unknown_field == NULL) {
    return NULL;
  }

  // Assign a default value to suppress may-uninitialized warnings (errors
  // when built in some places).
  WireFormatLite::WireType wire_type = WireFormatLite::WIRETYPE_VARINT;
  switch (unknown_field->type()) {
    case UnknownField::TYPE_VARINT:
      wire_type = WireFormatLite::WIRETYPE_VARINT;
      break;
    case UnknownField::TYPE_FIXED32:
      wire_type = WireFormatLite::WIRETYPE_FIXED32;
      break;
    case UnknownField::TYPE_FIXED64:
      wire_type = WireFormatLite::WIRETYPE_FIXED64;
      break;
    case UnknownField::TYPE_LENGTH_DELIMITED:
      wire_type = WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
      break;
    case UnknownField::TYPE_GROUP:
      wire_type = WireFormatLite::WIRETYPE_START_GROUP;
      break;
  }
  return PyLong_FromLong(wire_type);
}

static PyObject* GetData(PyUnknownFieldRef* self, void *closure) {
  const UnknownField* field = GetUnknownField(self);
  if (field == NULL) {
    return NULL;
  }
  PyObject* data = NULL;
  switch (field->type()) {
    case UnknownField::TYPE_VARINT:
      data = PyLong_FromLong(field->varint());
      break;
    case UnknownField::TYPE_FIXED32:
      data = PyLong_FromLong(field->fixed32());
      break;
    case UnknownField::TYPE_FIXED64:
      data = PyLong_FromLong(field->fixed64());
      break;
    case UnknownField::TYPE_LENGTH_DELIMITED:
      data = PyBytes_FromStringAndSize(field->length_delimited().data(),
                                       field->GetLengthDelimitedSize());
      break;
    case UnknownField::TYPE_GROUP:
      data = PyUnknownFields_FromUnknownFieldSet(
          self->parent, field->group());
      break;
  }
  return data;
}

static void Dealloc(PyObject* pself) {
  PyUnknownFieldRef* self =
      reinterpret_cast<PyUnknownFieldRef*>(pself);
  Py_CLEAR(self->parent);
}

static PyGetSetDef Getters[] = {
  {"field_number", (getter)GetFieldNumber, NULL},
  {"wire_type", (getter)GetWireType, NULL},
  {"data", (getter)GetData, NULL},
  {NULL}
};

}  // namespace unknown_field

PyTypeObject PyUnknownFieldRef_Type = {
  PyVarObject_HEAD_INIT(&PyType_Type, 0)
  FULL_MODULE_NAME ".PyUnknownFieldRef",  // tp_name
  sizeof(PyUnknownFieldRef),           //  tp_basicsize
  0,                                   //  tp_itemsize
  unknown_field::Dealloc,              //  tp_dealloc
  0,                                   //  tp_print
  0,                                   //  tp_getattr
  0,                                   //  tp_setattr
  0,                                   //  tp_compare
  0,                                   //  tp_repr
  0,                                   //  tp_as_number
  0,                                   //  tp_as_sequence
  0,                                   //  tp_as_mapping
  PyObject_HashNotImplemented,         //  tp_hash
  0,                                   //  tp_call
  0,                                   //  tp_str
  0,                                   //  tp_getattro
  0,                                   //  tp_setattro
  0,                                   //  tp_as_buffer
  Py_TPFLAGS_DEFAULT,                  //  tp_flags
  "unknown field",                     //  tp_doc
  0,                                   //  tp_traverse
  0,                                   //  tp_clear
  0,                                   //  tp_richcompare
  0,                                   //  tp_weaklistoffset
  0,                                   //  tp_iter
  0,                                   //  tp_iternext
  0,                                   //  tp_methods
  0,                                   //  tp_members
  unknown_field::Getters,              //  tp_getset
  0,                                   //  tp_base
  0,                                   //  tp_dict
  0,                                   //  tp_descr_get
  0,                                   //  tp_descr_set
  0,                                   //  tp_dictoffset
  0,                                   //  tp_init
};

}  // namespace python
}  // namespace protobuf
}  // namespace google
<commit_msg>Prevent integer overflow for unknown fields<commit_after>// Protocol Buffers - Google's data interchange format
// Copyright 2008 Google Inc.  All rights reserved.
// https://developers.google.com/protocol-buffers/
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//     * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following disclaimer
// in the documentation and/or other materials provided with the
// distribution.
//     * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived from
// this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

#include <google/protobuf/pyext/unknown_fields.h>

#include <Python.h>
#include <set>
#include <memory>

#include <google/protobuf/message.h>
#include <google/protobuf/pyext/message.h>
#include <google/protobuf/pyext/scoped_pyobject_ptr.h>
#include <google/protobuf/unknown_field_set.h>
#include <google/protobuf/wire_format_lite.h>

namespace google {
namespace protobuf {
namespace python {

namespace unknown_fields {

static Py_ssize_t Len(PyObject* pself) {
  PyUnknownFields* self =
      reinterpret_cast<PyUnknownFields*>(pself);
  if (self->fields == NULL) {
    PyErr_Format(PyExc_ValueError,
                 "UnknownFields does not exist. "
                 "The parent message might be cleared.");
    return -1;
  }
  return self->fields->field_count();
}

void Clear(PyUnknownFields* self) {
  for (std::set<PyUnknownFields*>::iterator it =
           self->sub_unknown_fields.begin();
       it != self->sub_unknown_fields.end(); it++) {
    Clear(*it);
  }
  self->fields = NULL;
  self->sub_unknown_fields.clear();
}

PyObject* NewPyUnknownFieldRef(PyUnknownFields* parent,
                               Py_ssize_t index);

static PyObject* Item(PyObject* pself, Py_ssize_t index) {
  PyUnknownFields* self =
      reinterpret_cast<PyUnknownFields*>(pself);
  if (self->fields == NULL) {
    PyErr_Format(PyExc_ValueError,
                 "UnknownFields does not exist. "
                 "The parent message might be cleared.");
    return NULL;
  }
  Py_ssize_t total_size = self->fields->field_count();
  if (index < 0) {
    index = total_size + index;
  }
  if (index < 0 || index >= total_size) {
    PyErr_Format(PyExc_IndexError,
                 "index (%zd) out of range",
                 index);
    return NULL;
  }

  return unknown_fields::NewPyUnknownFieldRef(self, index);
}

PyObject* NewPyUnknownFields(CMessage* c_message) {
  PyUnknownFields* self = reinterpret_cast<PyUnknownFields*>(
      PyType_GenericAlloc(&PyUnknownFields_Type, 0));
  if (self == NULL) {
    return NULL;
  }
  // Call "placement new" to initialize PyUnknownFields.
  new (self) PyUnknownFields;

  Py_INCREF(c_message);
  self->parent = reinterpret_cast<PyObject*>(c_message);
  Message* message = c_message->message;
  const Reflection* reflection = message->GetReflection();
  self->fields = &reflection->GetUnknownFields(*message);

  return reinterpret_cast<PyObject*>(self);
}

PyObject* NewPyUnknownFieldRef(PyUnknownFields* parent,
                               Py_ssize_t index) {
  PyUnknownFieldRef* self = reinterpret_cast<PyUnknownFieldRef*>(
      PyType_GenericAlloc(&PyUnknownFieldRef_Type, 0));
  if (self == NULL) {
    return NULL;
  }

  Py_INCREF(parent);
  self->parent = parent;
  self->index = index;

  return reinterpret_cast<PyObject*>(self);
}

static void Dealloc(PyObject* pself) {
  PyUnknownFields* self =
      reinterpret_cast<PyUnknownFields*>(pself);
  if (PyObject_TypeCheck(self->parent, &PyUnknownFields_Type)) {
    reinterpret_cast<PyUnknownFields*>(
        self->parent)->sub_unknown_fields.erase(self);
  } else {
    reinterpret_cast<CMessage*>(self->parent)->unknown_field_set = nullptr;
  }
  Py_CLEAR(self->parent);
  self->~PyUnknownFields();
  Py_TYPE(pself)->tp_free(pself);
}

static PySequenceMethods SqMethods = {
  Len,        /* sq_length */
  0,          /* sq_concat */
  0,          /* sq_repeat */
  Item,       /* sq_item */
  0,          /* sq_slice */
  0,          /* sq_ass_item */
};

}  // namespace unknown_fields

PyTypeObject PyUnknownFields_Type = {
  PyVarObject_HEAD_INIT(&PyType_Type, 0)
  FULL_MODULE_NAME ".PyUnknownFields",  // tp_name
  sizeof(PyUnknownFields),             // tp_basicsize
  0,                                   //  tp_itemsize
  unknown_fields::Dealloc,             //  tp_dealloc
  0,                                   //  tp_print
  0,                                   //  tp_getattr
  0,                                   //  tp_setattr
  0,                                   //  tp_compare
  0,                                   //  tp_repr
  0,                                   //  tp_as_number
  &unknown_fields::SqMethods,          //  tp_as_sequence
  0,                                   //  tp_as_mapping
  PyObject_HashNotImplemented,         //  tp_hash
  0,                                   //  tp_call
  0,                                   //  tp_str
  0,                                   //  tp_getattro
  0,                                   //  tp_setattro
  0,                                   //  tp_as_buffer
  Py_TPFLAGS_DEFAULT,                  //  tp_flags
  "unknown field set",                 //  tp_doc
  0,                                   //  tp_traverse
  0,                                   //  tp_clear
  0,                                   //  tp_richcompare
  0,                                   //  tp_weaklistoffset
  0,                                   //  tp_iter
  0,                                   //  tp_iternext
  0,                                   //  tp_methods
  0,                                   //  tp_members
  0,                                   //  tp_getset
  0,                                   //  tp_base
  0,                                   //  tp_dict
  0,                                   //  tp_descr_get
  0,                                   //  tp_descr_set
  0,                                   //  tp_dictoffset
  0,                                   //  tp_init
};

namespace unknown_field {
static PyObject* PyUnknownFields_FromUnknownFieldSet(
    PyUnknownFields* parent, const UnknownFieldSet& fields) {
  PyUnknownFields* self = reinterpret_cast<PyUnknownFields*>(
      PyType_GenericAlloc(&PyUnknownFields_Type, 0));
  if (self == NULL) {
    return NULL;
  }
  // Call "placement new" to initialize PyUnknownFields.
  new (self) PyUnknownFields;

  Py_INCREF(parent);
  self->parent = reinterpret_cast<PyObject*>(parent);
  self->fields = &fields;
  parent->sub_unknown_fields.emplace(self);

  return reinterpret_cast<PyObject*>(self);
}

const UnknownField* GetUnknownField(PyUnknownFieldRef* self) {
  const UnknownFieldSet* fields = self->parent->fields;
  if (fields == NULL) {
    PyErr_Format(PyExc_ValueError,
                 "UnknownField does not exist. "
                 "The parent message might be cleared.");
    return NULL;
  }
  ssize_t total_size = fields->field_count();
  if (self->index >= total_size) {
    PyErr_Format(PyExc_ValueError,
                 "UnknownField does not exist. "
                 "The parent message might be cleared.");
    return NULL;
  }
  return &fields->field(self->index);
}

static PyObject* GetFieldNumber(PyUnknownFieldRef* self, void *closure) {
  const UnknownField* unknown_field = GetUnknownField(self);
  if (unknown_field == NULL) {
    return NULL;
  }
  return PyLong_FromLong(unknown_field->number());
}

using internal::WireFormatLite;
static PyObject* GetWireType(PyUnknownFieldRef* self, void *closure) {
  const UnknownField* unknown_field = GetUnknownField(self);
  if (unknown_field == NULL) {
    return NULL;
  }

  // Assign a default value to suppress may-uninitialized warnings (errors
  // when built in some places).
  WireFormatLite::WireType wire_type = WireFormatLite::WIRETYPE_VARINT;
  switch (unknown_field->type()) {
    case UnknownField::TYPE_VARINT:
      wire_type = WireFormatLite::WIRETYPE_VARINT;
      break;
    case UnknownField::TYPE_FIXED32:
      wire_type = WireFormatLite::WIRETYPE_FIXED32;
      break;
    case UnknownField::TYPE_FIXED64:
      wire_type = WireFormatLite::WIRETYPE_FIXED64;
      break;
    case UnknownField::TYPE_LENGTH_DELIMITED:
      wire_type = WireFormatLite::WIRETYPE_LENGTH_DELIMITED;
      break;
    case UnknownField::TYPE_GROUP:
      wire_type = WireFormatLite::WIRETYPE_START_GROUP;
      break;
  }
  return PyLong_FromLong(wire_type);
}

static PyObject* GetData(PyUnknownFieldRef* self, void *closure) {
  const UnknownField* field = GetUnknownField(self);
  if (field == NULL) {
    return NULL;
  }
  PyObject* data = NULL;
  switch (field->type()) {
    case UnknownField::TYPE_VARINT:
      data = PyLong_FromUnsignedLongLong(field->varint());
      break;
    case UnknownField::TYPE_FIXED32:
      data = PyLong_FromUnsignedLong(field->fixed32());
      break;
    case UnknownField::TYPE_FIXED64:
      data = PyLong_FromUnsignedLongLong(field->fixed64());
      break;
    case UnknownField::TYPE_LENGTH_DELIMITED:
      data = PyBytes_FromStringAndSize(field->length_delimited().data(),
                                       field->GetLengthDelimitedSize());
      break;
    case UnknownField::TYPE_GROUP:
      data = PyUnknownFields_FromUnknownFieldSet(
          self->parent, field->group());
      break;
  }
  return data;
}

static void Dealloc(PyObject* pself) {
  PyUnknownFieldRef* self =
      reinterpret_cast<PyUnknownFieldRef*>(pself);
  Py_CLEAR(self->parent);
}

static PyGetSetDef Getters[] = {
  {"field_number", (getter)GetFieldNumber, NULL},
  {"wire_type", (getter)GetWireType, NULL},
  {"data", (getter)GetData, NULL},
  {NULL}
};

}  // namespace unknown_field

PyTypeObject PyUnknownFieldRef_Type = {
  PyVarObject_HEAD_INIT(&PyType_Type, 0)
  FULL_MODULE_NAME ".PyUnknownFieldRef",  // tp_name
  sizeof(PyUnknownFieldRef),           //  tp_basicsize
  0,                                   //  tp_itemsize
  unknown_field::Dealloc,              //  tp_dealloc
  0,                                   //  tp_print
  0,                                   //  tp_getattr
  0,                                   //  tp_setattr
  0,                                   //  tp_compare
  0,                                   //  tp_repr
  0,                                   //  tp_as_number
  0,                                   //  tp_as_sequence
  0,                                   //  tp_as_mapping
  PyObject_HashNotImplemented,         //  tp_hash
  0,                                   //  tp_call
  0,                                   //  tp_str
  0,                                   //  tp_getattro
  0,                                   //  tp_setattro
  0,                                   //  tp_as_buffer
  Py_TPFLAGS_DEFAULT,                  //  tp_flags
  "unknown field",                     //  tp_doc
  0,                                   //  tp_traverse
  0,                                   //  tp_clear
  0,                                   //  tp_richcompare
  0,                                   //  tp_weaklistoffset
  0,                                   //  tp_iter
  0,                                   //  tp_iternext
  0,                                   //  tp_methods
  0,                                   //  tp_members
  unknown_field::Getters,              //  tp_getset
  0,                                   //  tp_base
  0,                                   //  tp_dict
  0,                                   //  tp_descr_get
  0,                                   //  tp_descr_set
  0,                                   //  tp_dictoffset
  0,                                   //  tp_init
};

}  // namespace python
}  // namespace protobuf
}  // namespace google
<|endoftext|>


<commit_before>/* ========================================================================= *
 * File: memory_notification.cpp
 *
 * This file is part of Memory Notification Library (libmemnotifyqt)
 *
 * Copyright (C) 2010 Nokia Corporation. All rights reserved.
 *
 * Contacts: Leonid Moiseichuk <leonid.moiseichuk@nokia.com>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * ========================================================================= */

/* ========================================================================= *
* Includes.
* ========================================================================= */

#include <sys/types.h>
#include <aio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <QSettings>
#include <memnotify/watcher_builder.hpp>
#include <memnotify/memory_notification.hpp>

BEGIN_MEMNOTIFY_NAMESPACE

/* ========================================================================= *
* Class MemoryNotification.
* ========================================================================= */

static MemoryNotification*  MemoryNotification :: ourMemoryNotification = NULL;

bool MemoryNotification :: setup(const char* pathSpecification)
{
  const bool wasEnabled = myEnabled;

  /* We should disable functionality if it is enabled */
  if (myEnabled && !disable())
    return false;

  /* If no files pointed the default file should be loaded */
  if ( !(pathSpecification && *pathSpecification) )
    pathSpecification = "default";

  /* if we have some watchers in list - they must be removed */
  clearWatchers();

  const QStringList files = QString(pathSpecification).split(":", QString::SkipEmptyParts);

  foreach(QString file, files)
  {
    const QSettings   config(file, QSettings::IniFormat);
    /* array with names of thresholds */
    const QStringList tholds(config.childGroups());
    /* array with data to create watchers */
    const QStringList data(config.allKeys());

    /* Now trying to build the watchers, one by one */
    foreach(QString thold, tholds)
    {
      Watcher* newcomer = WatcherBuilder::build(data, thold);
      Q_ASSERT(NULL != newcomer);
#if MEMNOTIFY_DUMP
      Q_ASSERT(true == newcomer->valid());
#endif
      if ( newcomer )
        myWatchers.append(newcomer);
    } /* for each thold */
  } /* for each file */

  /* As a result we must have at least one watcher created */
  if ( myWatchers.isEmpty() )
    return false;

  /* We should enable functionality back if it was enabled */
  return (!wasEnabled || enable());
} /* setup */

bool MemoryNotification :: poll()
{
  /* FIXME: QThread-based solution for epoll expected. AIO doesn't work as necessary */
  return false;
} /* poll */

uint MemoryNotification :: query(int* fds, uint size)
{
  uint index = 0;
  if (myEnabled && fd && myWatchers->count() <= (int)size)
  {
    foreach(const Watcher* watcher, myWatchers)
    {
      const int handler = (watcher ? watcher->handler() : -1);
      if ( handler < 0 )
        return 0;
      fds[index++] = handler;
    }
  }

  return index;
} /* query */

bool MemoryNotification :: process(const int* fds, uint counter)
{
  /* we should be enabled */
  if ( !myEnable )
    return false;

  /* Check the parameters */
  if ( !fd )
    return false;

  if ( !counter )
    return true;

  /* result of processing, should be true if all watchers handled OK */
  bool result = true;
  QList<Watcher*> updated;

  /* And now handling the all incoming events */
  for (uint ifd = 0; ifd < counter; ifd++)
  {
    const int fd = fds[ifd];

    /* First - we should find the watcher */
    foreach(Watcher* cursor, myWatchers)
    {
      Q_ASSERT(NULL != watcher);
      if (watcher && fd == watcher->handler())
      {
        const bool oldState = watcher->state();
        if ( watcher->process() )
        {
          if (oldState != watcher->state())
            updated.append(watcher);
        }
        else
        {
          /* we are failed with processing but we must continue until the end */
          result = false;
        }
      }
    } /* scan for watcher */
  } /* for each file descriptor */

  /* Now we have list of updated watchers -> sending the notifications */
  foreach(const Watcher* watcher, updated)
  {
    Q_ASSERT(NULL != watcher);
    const QString& name  = watcher->name();
    const bool     state = watcher->state();

    /* if necessary - notify callbacks */
    if (myObservers.count() > 0)
    {
      foreach(OBSERVER observer, myObservers)
      {
        Q_ASSERT(NULL != observer);
        if ( observer )
          observer(name, state);
      }
    }

    /* if necessary - notify subscribers */
    if (mySignalCounter > 0)
      emit notified(name, state);
  } /* for each updated */

  return result;
} /* process */

bool MemoryNotification :: enable()
{
  if ( myEnabled )
    return false;

  if (0 == mySignalCounter && myObservers.isEmpty())
    return false;

  if ( myWatchers.isEmpty() )
    return false;

  /* disable watchers one by one */
  int enabled_counter = 0;
  foreach(Watcher* watcher, myWatchers)
  {
    if (watcher && watcher->enable())
    {
      /* item successfully enabled */
      enabled_counter++;
    }
  }

  /* set common enabled flag on only if we have all items enabled */
  myEnabled = (myWatchers->count() == enabled_counter);

  /* function done if no items enabled */
  return (myEnabled);
} /* enable */

bool MemoryNotification :: disable()
{
  if ( !myEnabled )
    return false;

  /* disable watchers one by one */
  int disabled_counter = 0;
  foreach(Watcher* watcher, myWatchers)
  {
    if (watcher && watcher->disable())
    {
      /* item successfully disabled */
      disabled_counter++;
    }
  }

  /* set common enabled flag off only if we have all items disabled */
  myEnabled = (myWatchers->count() != disabled_counter);

  /* function done if no items enabled */
  return (! myEnabled);
} /* disable */

bool MemoryNotification :: valid() const
{
  /* first, we must have subscribed items */
  if (0 == mySignalCounter && myObservers.isEmpty())
    return false;

  /* we must have sources for signal generation */
  if ( myWatchers.isEmpty() )
    return false;

  /* All observers must be non-null */
  if ( myObservers.indexOf(NULL) >= 0 )
    return false;

  /* All watchers must be non-null, valid and maybe enabled */
  foreach(const Watcher* watcher, myWatchers)
  {
    if (watcher && watcher->valid() && watcher->enabled() == myEnabled)
    {
      /* check the next item */
      continue;
    }
    return false;
  }

  return true;
} /* valid */

void MemoryNotification :: clearWatchers()
{
  if (myWatchers.count() > 0)
  {
    foreach (Watcher* watcher, myWatchers)
    {
      if (watcher)
        delete watcher;
    }
    myWatchers.clear();
  }
} /* clearWatchers */

void MemoryNotification :: dump()
{
#if MEMNOTIFY_DUMP
  printf ("MemoryNotification %08x {\n", (uint)this);

ZZZ
  printf ("}\n");
#endif /* if MEMNOTIFY_DUMP */
}

END_MEMOTIFY_NAMESPACE

/* =================[ end of file memnotify/memory_notification.cpp ]========================= */
<commit_msg>added MemoryNotification::dump<commit_after>/* ========================================================================= *
 * File: memory_notification.cpp
 *
 * This file is part of Memory Notification Library (libmemnotifyqt)
 *
 * Copyright (C) 2010 Nokia Corporation. All rights reserved.
 *
 * Contacts: Leonid Moiseichuk <leonid.moiseichuk@nokia.com>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 * ========================================================================= */

/* ========================================================================= *
* Includes.
* ========================================================================= */

#include <sys/types.h>
#include <aio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <QSettings>
#include <memnotify/watcher_builder.hpp>
#include <memnotify/memory_notification.hpp>

BEGIN_MEMNOTIFY_NAMESPACE

/* ========================================================================= *
* Class MemoryNotification.
* ========================================================================= */

static MemoryNotification*  MemoryNotification :: ourMemoryNotification = NULL;

bool MemoryNotification :: setup(const char* pathSpecification)
{
  const bool wasEnabled = myEnabled;

  /* We should disable functionality if it is enabled */
  if (myEnabled && !disable())
    return false;

  /* If no files pointed the default file should be loaded */
  if ( !(pathSpecification && *pathSpecification) )
    pathSpecification = "default";

  /* if we have some watchers in list - they must be removed */
  clearWatchers();

  const QStringList files = QString(pathSpecification).split(":", QString::SkipEmptyParts);

  foreach(QString file, files)
  {
    const QSettings   config(file, QSettings::IniFormat);
    /* array with names of thresholds */
    const QStringList tholds(config.childGroups());
    /* array with data to create watchers */
    const QStringList data(config.allKeys());

    /* Now trying to build the watchers, one by one */
    foreach(QString thold, tholds)
    {
      Watcher* newcomer = WatcherBuilder::build(data, thold);
      Q_ASSERT(NULL != newcomer);
#if MEMNOTIFY_DUMP
      Q_ASSERT(true == newcomer->valid());
#endif
      if ( newcomer )
        myWatchers.append(newcomer);
    } /* for each thold */
  } /* for each file */

  /* As a result we must have at least one watcher created */
  if ( myWatchers.isEmpty() )
    return false;

  /* We should enable functionality back if it was enabled */
  return (!wasEnabled || enable());
} /* setup */

bool MemoryNotification :: poll()
{
  /* FIXME: QThread-based solution for epoll expected. AIO doesn't work as necessary */
  return false;
} /* poll */

uint MemoryNotification :: query(int* fds, uint size)
{
  uint index = 0;
  if (myEnabled && fd && myWatchers->count() <= (int)size)
  {
    foreach(const Watcher* watcher, myWatchers)
    {
      const int handler = (watcher ? watcher->handler() : -1);
      if ( handler < 0 )
        return 0;
      fds[index++] = handler;
    }
  }

  return index;
} /* query */

bool MemoryNotification :: process(const int* fds, uint counter)
{
  /* we should be enabled */
  if ( !myEnable )
    return false;

  /* Check the parameters */
  if ( !fd )
    return false;

  if ( !counter )
    return true;

  /* result of processing, should be true if all watchers handled OK */
  bool result = true;
  QList<Watcher*> updated;

  /* And now handling the all incoming events */
  for (uint ifd = 0; ifd < counter; ifd++)
  {
    const int fd = fds[ifd];

    /* First - we should find the watcher */
    foreach(Watcher* cursor, myWatchers)
    {
      Q_ASSERT(NULL != watcher);
      if (watcher && fd == watcher->handler())
      {
        const bool oldState = watcher->state();
        if ( watcher->process() )
        {
          if (oldState != watcher->state())
            updated.append(watcher);
        }
        else
        {
          /* we are failed with processing but we must continue until the end */
          result = false;
        }
      }
    } /* scan for watcher */
  } /* for each file descriptor */

  /* Now we have list of updated watchers -> sending the notifications */
  foreach(const Watcher* watcher, updated)
  {
    Q_ASSERT(NULL != watcher);
    const QString& name  = watcher->name();
    const bool     state = watcher->state();

    /* if necessary - notify callbacks */
    if (myObservers.count() > 0)
    {
      foreach(OBSERVER observer, myObservers)
      {
        Q_ASSERT(NULL != observer);
        if ( observer )
          observer(name, state);
      }
    }

    /* if necessary - notify subscribers */
    if (mySignalCounter > 0)
      emit notified(name, state);
  } /* for each updated */

  return result;
} /* process */

bool MemoryNotification :: enable()
{
  if ( myEnabled )
    return false;

  if (0 == mySignalCounter && myObservers.isEmpty())
    return false;

  if ( myWatchers.isEmpty() )
    return false;

  /* disable watchers one by one */
  int enabled_counter = 0;
  foreach(Watcher* watcher, myWatchers)
  {
    if (watcher && watcher->enable())
    {
      /* item successfully enabled */
      enabled_counter++;
    }
  }

  /* set common enabled flag on only if we have all items enabled */
  myEnabled = (myWatchers->count() == enabled_counter);

  /* function done if no items enabled */
  return (myEnabled);
} /* enable */

bool MemoryNotification :: disable()
{
  if ( !myEnabled )
    return false;

  /* disable watchers one by one */
  int disabled_counter = 0;
  foreach(Watcher* watcher, myWatchers)
  {
    if (watcher && watcher->disable())
    {
      /* item successfully disabled */
      disabled_counter++;
    }
  }

  /* set common enabled flag off only if we have all items disabled */
  myEnabled = (myWatchers->count() != disabled_counter);

  /* function done if no items enabled */
  return (! myEnabled);
} /* disable */

bool MemoryNotification :: valid() const
{
  /* first, we must have subscribed items */
  if (0 == mySignalCounter && myObservers.isEmpty())
    return false;

  /* we must have sources for signal generation */
  if ( myWatchers.isEmpty() )
    return false;

  /* All observers must be non-null */
  if ( myObservers.indexOf(NULL) >= 0 )
    return false;

  /* All watchers must be non-null, valid and maybe enabled */
  foreach(const Watcher* watcher, myWatchers)
  {
    if (watcher && watcher->valid() && watcher->enabled() == myEnabled)
    {
      /* check the next item */
      continue;
    }
    return false;
  }

  return true;
} /* valid */

void MemoryNotification :: clearWatchers()
{
  if (myWatchers.count() > 0)
  {
    foreach (Watcher* watcher, myWatchers)
    {
      if (watcher)
        delete watcher;
    }
    myWatchers.clear();
  }
} /* clearWatchers */

void MemoryNotification :: dump()
{
#if MEMNOTIFY_DUMP
  printf ("MemoryNotification %08x {\n", (uint)this);
  printf ("  outMemoryNotification %08x signal counter %u enabled %d poll thread %08x\n",
          (uint)ourMemoryNotification, mySignalCounter, myEnabled, (uint)myThread
      );

  printf ("  observers %d {\n", myObservers.count());
  for (const OBSERVER observer, myObservers)
  {
    printf ("\t%08x\n", (uint)observer);
  }
  printf ("  }\n");

  printf ("  watchers %d {\n", myWatchers.count());
  for (const Watchers watcher, myWatchers)
  {
    printf ("\t%08x ", (uint)watcher);
    if (watcher)
      watcher->dump();
    else
      printf ("\n");
  }
  printf ("  }\n");

  if ( myThread )
    ((const PollThread*)myThread)->dump();

  printf ("}\n");
#endif /* if MEMNOTIFY_DUMP */
}

END_MEMOTIFY_NAMESPACE

/* =================[ end of file memnotify/memory_notification.cpp ]========================= */
<|endoftext|>


<commit_before>#include "gtest/gtest.h"

#ifdef EXECUTOR
#define AUTOMATIC_CONVERSIONS
#include <QuickDraw.h>
#include <CQuickDraw.h>
#include <MemoryMgr.h>

using namespace Executor;
extern QDGlobals qd;

#define PTR(x) (&guestref(x))

    // FIXME: Executor still defines Pattern as an array, rather than an array wrapped in a struct
#define PATREF(pat) (pat)
#else
#include <Quickdraw.h>
#include <QDOffscreen.h>

#define PTR(x) (&x)
#define PATREF(pat) (&(pat))
#endif

struct OffscreenPort
{
    GrafPort port;
    Rect r;

    OffscreenPort(int height = 2, int width = 2)
    {
        OpenPort(&port);

        short rowBytes = (width + 31) / 31 * 4;
        port.portBits.rowBytes = rowBytes;
        port.portBits.baseAddr = NewPtrClear(rowBytes * height);
        SetRect(&r, 0,0,width,height);
        port.portBits.bounds = r;

        set();
    }

    ~OffscreenPort()
    {
        ClosePort(&port);
    }

    void set()
    {
        SetPort(&port);
    }

    uint8_t data(int row, int offset)
    {
        return port.portBits.baseAddr[row * port.portBits.rowBytes + offset];
    }
};

struct OffscreenWorld
{
    GWorldPtr world = nullptr;
    Rect r;

    OffscreenWorld(int depth, int height = 2, int width = 2)
    {
        SetRect(&r,0,0,2,2);
        NewGWorld(PTR(world), depth, &r, nullptr, nullptr, 0);
        LockPixels(world->portPixMap);
        set();
    }

    ~OffscreenWorld()
    {
        if((GrafPtr)world == qd.thePort)
            SetGDevice(GetMainDevice());
        DisposeGWorld(world);
    }

    void set()
    {
        SetGWorld(world, nullptr);
    }

    uint8_t data(int row, int offset)
    {
        Ptr baseAddr = (*world->portPixMap)->baseAddr;
        uint8_t *data = (uint8_t*)baseAddr;
        short rowBytes = (*world->portPixMap)->rowBytes;
        rowBytes &= 0x3FFF;

        return data[row * rowBytes + offset];
    }

    uint16_t data16(int row, int offset)
    {
        return data(row, offset*2) * 256 + data(row, offset*2+1);
    }
    uint32_t data32(int row, int offset)
    {
        return data16(row, offset*2) * 65536 + data16(row, offset*2+1);
    }
};

TEST(QuickDraw, BWLine1)
{
    OffscreenPort port;

    EraseRect(&port.r);
    MoveTo(0,0);
    LineTo(2,2);

    EXPECT_EQ(0x80, port.data(0,0));
    EXPECT_EQ(0x40, port.data(1,0));
}

TEST(QuickDraw, GWorld8)
{
    OffscreenWorld world(8);

    EraseRect(&world.r);
    MoveTo(0,0);
    LineTo(2,2);

    EXPECT_EQ(255, world.data(0,0));
    EXPECT_EQ(0, world.data(0,1));
    EXPECT_EQ(0, world.data(1,0));
    EXPECT_EQ(255, world.data(1,1));
}

TEST(QuickDraw, GWorld16)
{
    OffscreenWorld world(16);

    EraseRect(&world.r);
    MoveTo(0,0);
    LineTo(2,2);

    EXPECT_EQ(0, world.data16(0,0));
    EXPECT_EQ(0x7FFF, world.data16(0,1));
}

TEST(QuickDraw, GWorld32)
{
    OffscreenWorld world(32);

    EraseRect(&world.r);
    MoveTo(0,0);
    LineTo(2,2);

    EXPECT_EQ(0, world.data32(0,0));
    EXPECT_EQ(0x00FFFFFF, world.data32(0,1));
}

TEST(QuickDraw, BasicQDColorBW)
{
    OffscreenPort port;

    FillRect(&port.r, PATREF(qd.gray));
    EXPECT_EQ(0x80, port.data(0,0));
    EXPECT_EQ(0x40, port.data(1,0));

    ForeColor(whiteColor);
    BackColor(redColor);
    FillRect(&port.r, PATREF(qd.gray));

    EXPECT_EQ(0x40, port.data(0,0));
    EXPECT_EQ(0x80, port.data(1,0));

    EXPECT_EQ(whiteColor, port.port.fgColor);
    EXPECT_EQ(redColor, port.port.bkColor);
}

TEST(QuickDraw, BasicQDColor32)
{
    OffscreenWorld world(32);

    FillRect(&world.r, PATREF(qd.gray));
    EXPECT_EQ(0x00000000, world.data32(0,0));
    EXPECT_EQ(0x00FFFFFF, world.data32(0,1));
    EXPECT_EQ(0x00FFFFFF, world.data32(1,0));
    EXPECT_EQ(0x00000000, world.data32(1,1));

    ForeColor(whiteColor);
    BackColor(redColor);

    const uint32_t rgbRed = 0xDD0806;

    EXPECT_EQ(0x00FFFFFF, world.world->fgColor);
    EXPECT_EQ(rgbRed, world.world->bkColor);

    FillRect(&world.r, PATREF(qd.gray));

    EXPECT_EQ(0x00FFFFFF, world.data32(0,0));
    EXPECT_EQ(rgbRed, world.data32(0,1));
    EXPECT_EQ(rgbRed, world.data32(1,0));
    EXPECT_EQ(0x00FFFFFF, world.data32(1,1));
}

TEST(QuickDraw, GrayPattern32)
{
    OffscreenWorld world(32);

    FillRect(&world.r, PATREF(qd.gray));
    EXPECT_EQ(0x00000000, world.data32(0,0));
    EXPECT_EQ(0x00FFFFFF, world.data32(0,1));
    EXPECT_EQ(0x00FFFFFF, world.data32(1,0));
    EXPECT_EQ(0x00000000, world.data32(1,1));
}

TEST(QuickDraw, GrayPattern8)
{
    OffscreenWorld world(8);

    FillRect(&world.r, PATREF(qd.gray));
    EXPECT_EQ(0xFF, world.data(0,0));
    EXPECT_EQ(0x00, world.data(0,1));
    EXPECT_EQ(0x00, world.data(1,0));
    EXPECT_EQ(0xFF, world.data(1,1));
}

TEST(QuickDraw, GrayPattern1)
{
    OffscreenPort port;

    FillRect(&port.r, PATREF(qd.gray));
    EXPECT_EQ(0x80, port.data(0,0));
    EXPECT_EQ(0x40, port.data(1,0));
}

TEST(QuickDraw, BlackPattern32)
{
    OffscreenWorld world(32);

    FillRect(&world.r, PATREF(qd.black));
    EXPECT_EQ(0x00000000, world.data32(0,0));
    EXPECT_EQ(0x00000000, world.data32(0,1));
    EXPECT_EQ(0x00000000, world.data32(1,0));
    EXPECT_EQ(0x00000000, world.data32(1,1));
}
<commit_msg>more quickdraw tests<commit_after>#include "gtest/gtest.h"

#ifdef EXECUTOR
#define AUTOMATIC_CONVERSIONS
#include <QuickDraw.h>
#include <CQuickDraw.h>
#include <MemoryMgr.h>

using namespace Executor;
extern QDGlobals qd;

#define PTR(x) (&guestref(x))

    // FIXME: Executor still defines Pattern as an array, rather than an array wrapped in a struct
#define PATREF(pat) (pat)
#else
#include <Quickdraw.h>
#include <QDOffscreen.h>

#define PTR(x) (&x)
#define PATREF(pat) (&(pat))
#endif

struct OffscreenPort
{
    GrafPort port;
    Rect r;

    OffscreenPort(int height = 2, int width = 2)
    {
        OpenPort(&port);

        short rowBytes = (width + 31) / 31 * 4;
        port.portBits.rowBytes = rowBytes;
        port.portBits.baseAddr = NewPtrClear(rowBytes * height);
        SetRect(&r, 0,0,width,height);
        port.portBits.bounds = r;

        set();
    }

    ~OffscreenPort()
    {
        ClosePort(&port);
    }

    void set()
    {
        SetPort(&port);
    }

    uint8_t& data(int row, int offset)
    {
        return reinterpret_cast<uint8_t&>(
            port.portBits.baseAddr[row * port.portBits.rowBytes + offset]);
    }
};

struct OffscreenWorld
{
    GWorldPtr world = nullptr;
    Rect r;

    OffscreenWorld(int depth, int height = 2, int width = 2)
    {
        SetRect(&r,0,0,2,2);
        NewGWorld(PTR(world), depth, &r, nullptr, nullptr, 0);
        LockPixels(world->portPixMap);
        set();
    }

    ~OffscreenWorld()
    {
        if((GrafPtr)world == qd.thePort)
            SetGDevice(GetMainDevice());
        DisposeGWorld(world);
    }

    void set()
    {
        SetGWorld(world, nullptr);
    }

    uint8_t& data(int row, int offset)
    {
        Ptr baseAddr = (*world->portPixMap)->baseAddr;
        uint8_t *data = (uint8_t*)baseAddr;
        short rowBytes = (*world->portPixMap)->rowBytes;
        rowBytes &= 0x3FFF;

        return data[row * rowBytes + offset];
    }

    uint16_t data16(int row, int offset)
    {
        return data(row, offset*2) * 256 + data(row, offset*2+1);
    }
    uint32_t data32(int row, int offset)
    {
        return data16(row, offset*2) * 65536 + data16(row, offset*2+1);
    }
};

TEST(QuickDraw, BWLine1)
{
    OffscreenPort port;

    EraseRect(&port.r);
    MoveTo(0,0);
    LineTo(2,2);

    EXPECT_EQ(0x80, port.data(0,0));
    EXPECT_EQ(0x40, port.data(1,0));
}

TEST(QuickDraw, GWorld8)
{
    OffscreenWorld world(8);

    EraseRect(&world.r);
    MoveTo(0,0);
    LineTo(2,2);

    EXPECT_EQ(255, world.data(0,0));
    EXPECT_EQ(0, world.data(0,1));
    EXPECT_EQ(0, world.data(1,0));
    EXPECT_EQ(255, world.data(1,1));
}

TEST(QuickDraw, GWorld16)
{
    OffscreenWorld world(16);

    EraseRect(&world.r);
    MoveTo(0,0);
    LineTo(2,2);

    EXPECT_EQ(0, world.data16(0,0));
    EXPECT_EQ(0x7FFF, world.data16(0,1));
}

TEST(QuickDraw, GWorld32)
{
    OffscreenWorld world(32);

    EraseRect(&world.r);
    MoveTo(0,0);
    LineTo(2,2);

    EXPECT_EQ(0, world.data32(0,0));
    EXPECT_EQ(0x00FFFFFF, world.data32(0,1));
}

TEST(QuickDraw, BasicQDColorBW)
{
    OffscreenPort port;

    FillRect(&port.r, PATREF(qd.gray));
    EXPECT_EQ(0x80, port.data(0,0));
    EXPECT_EQ(0x40, port.data(1,0));

    ForeColor(whiteColor);
    BackColor(redColor);
    FillRect(&port.r, PATREF(qd.gray));

    EXPECT_EQ(0x40, port.data(0,0));
    EXPECT_EQ(0x80, port.data(1,0));

    EXPECT_EQ(whiteColor, port.port.fgColor);
    EXPECT_EQ(redColor, port.port.bkColor);
}

TEST(QuickDraw, BasicQDColor32)
{
    OffscreenWorld world(32);

    FillRect(&world.r, PATREF(qd.gray));
    EXPECT_EQ(0x00000000, world.data32(0,0));
    EXPECT_EQ(0x00FFFFFF, world.data32(0,1));
    EXPECT_EQ(0x00FFFFFF, world.data32(1,0));
    EXPECT_EQ(0x00000000, world.data32(1,1));

    ForeColor(whiteColor);
    BackColor(redColor);

    const uint32_t rgbRed = 0xDD0806;

    EXPECT_EQ(0x00FFFFFF, world.world->fgColor);
    EXPECT_EQ(rgbRed, world.world->bkColor);

    FillRect(&world.r, PATREF(qd.gray));

    EXPECT_EQ(0x00FFFFFF, world.data32(0,0));
    EXPECT_EQ(rgbRed, world.data32(0,1));
    EXPECT_EQ(rgbRed, world.data32(1,0));
    EXPECT_EQ(0x00FFFFFF, world.data32(1,1));
}

TEST(QuickDraw, GrayPattern32)
{
    OffscreenWorld world(32);

    FillRect(&world.r, PATREF(qd.gray));
    EXPECT_EQ(0x00000000, world.data32(0,0));
    EXPECT_EQ(0x00FFFFFF, world.data32(0,1));
    EXPECT_EQ(0x00FFFFFF, world.data32(1,0));
    EXPECT_EQ(0x00000000, world.data32(1,1));
}

TEST(QuickDraw, GrayPattern8)
{
    OffscreenWorld world(8);

    FillRect(&world.r, PATREF(qd.gray));
    EXPECT_EQ(0xFF, world.data(0,0));
    EXPECT_EQ(0x00, world.data(0,1));
    EXPECT_EQ(0x00, world.data(1,0));
    EXPECT_EQ(0xFF, world.data(1,1));
}

TEST(QuickDraw, GrayPattern1)
{
    OffscreenPort port;

    FillRect(&port.r, PATREF(qd.gray));
    EXPECT_EQ(0x80, port.data(0,0));
    EXPECT_EQ(0x40, port.data(1,0));
}

TEST(QuickDraw, BlackPattern32)
{
    OffscreenWorld world(32);

    FillRect(&world.r, PATREF(qd.black));
    EXPECT_EQ(0x00000000, world.data32(0,0));
    EXPECT_EQ(0x00000000, world.data32(0,1));
    EXPECT_EQ(0x00000000, world.data32(1,0));
    EXPECT_EQ(0x00000000, world.data32(1,1));
}

TEST(QuickDraw, CopyBit8)
{
    OffscreenWorld world1(8);

    world1.data(0,0) = 1;
    world1.data(0,1) = 2;
    world1.data(1,0) = 3;
    world1.data(1,1) = 4;
    OffscreenWorld world2(8);
    EraseRect(&world2.r);

    RgnHandle rgn1 = NewRgn();
    SetRectRgn(rgn1, 0,0,2,1);
    RgnHandle rgn2 = NewRgn();
    SetRectRgn(rgn2, 0,0,1,2);
    UnionRgn(rgn1, rgn2, rgn1);
    DisposeRgn(rgn2);

    CopyBits(
        &GrafPtr(world1.world)->portBits,
        &GrafPtr(world2.world)->portBits,
        &world1.r, &world2.r, srcCopy, rgn1);

    DisposeRgn(rgn1);

    EXPECT_EQ(1, world2.data(0,0));
    EXPECT_EQ(2, world2.data(0,1));
    EXPECT_EQ(3, world2.data(1,0));
    EXPECT_EQ(0, world2.data(1,1));
}

TEST(QuickDraw, CopyBit32)
{
    OffscreenWorld world1(32);

    world1.data(0,3) = 1;
    world1.data(0,7) = 2;
    world1.data(1,3) = 3;
    world1.data(1,7) = 4;
    OffscreenWorld world2(32);
    EraseRect(&world2.r);

    RgnHandle rgn1 = NewRgn();
    SetRectRgn(rgn1, 0,0,2,1);
    RgnHandle rgn2 = NewRgn();
    SetRectRgn(rgn2, 0,0,1,2);
    UnionRgn(rgn1, rgn2, rgn1);
    DisposeRgn(rgn2);

    CopyBits(
        &GrafPtr(world1.world)->portBits,
        &GrafPtr(world2.world)->portBits,
        &world1.r, &world2.r, srcCopy, rgn1);

    DisposeRgn(rgn1);

    EXPECT_EQ(1, world2.data(0,3));
    EXPECT_EQ(2, world2.data(0,7));
    EXPECT_EQ(3, world2.data(1,3));
    EXPECT_EQ(255, world2.data(1,7));
}

TEST(QuickDraw, CopyMask8)
{
    OffscreenPort mask;

    mask.data(0,0) = 0xC0;
    mask.data(1,0) = 0x80;

    OffscreenWorld world1(8);

    world1.data(0,0) = 1;
    world1.data(0,1) = 2;
    world1.data(1,0) = 3;
    world1.data(1,1) = 4;
    OffscreenWorld world2(8);
    EraseRect(&world2.r);

    CopyMask(
        &GrafPtr(world1.world)->portBits,
        &mask.port.portBits,
        &GrafPtr(world2.world)->portBits,
        &world1.r, &mask.r, &world2.r);

    EXPECT_EQ(1, world2.data(0,0));
    EXPECT_EQ(2, world2.data(0,1));
    EXPECT_EQ(3, world2.data(1,0));
    EXPECT_EQ(0, world2.data(1,1));
}

TEST(QuickDraw, CopyMask32)
{
    OffscreenPort mask;

    mask.data(0,0) = 0xC0;
    mask.data(1,0) = 0x80;

    OffscreenWorld world1(32);

    world1.data(0,3) = 1;
    world1.data(0,7) = 2;
    world1.data(1,3) = 3;
    world1.data(1,7) = 4;
    OffscreenWorld world2(32);
    EraseRect(&world2.r);

    CopyMask(
        &GrafPtr(world1.world)->portBits,
        &mask.port.portBits,
        &GrafPtr(world2.world)->portBits,
        &world1.r, &mask.r, &world2.r);

    EXPECT_EQ(1, world2.data(0,3));
    EXPECT_EQ(2, world2.data(0,7));
    EXPECT_EQ(3, world2.data(1,3));
    EXPECT_EQ(255, world2.data(1,7));
}
<|endoftext|>


<commit_before>#include <QDBusVariant>
#include <QsLog.h>
#include <QTimer>
#include <velib/qt/v_busitem.h>
#include <velib/qt/v_busitems.h>
#include "v_bus_node.h"
#include "dbus_bridge.h"

Q_DECLARE_METATYPE(QList<int>)

DBusBridge::DBusBridge(QObject *parent) :
	QObject(parent),
	mServiceRegistered(false),
	mUpdateBusy(false),
	mUpdateTimer(0)
{
}

DBusBridge::DBusBridge(const QString &serviceName, QObject *parent):
	QObject(parent),
	mServiceName(serviceName),
	mServiceRegistered(false),
	mUpdateBusy(false),
	mUpdateTimer(0)
{
}

DBusBridge::~DBusBridge()
{
	if (!mServiceRegistered)
		return;
	QLOG_INFO() << "Unregistering service" << mServiceName;
	QDBusConnection connection = VBusItems::getConnection(mServiceName);
	if (!connection.unregisterService(mServiceName)) {
		QLOG_FATAL() << "UnregisterService failed";
	}
}

void DBusBridge::setUpdateInterval(int interval)
{
	if (interval <= 0) {
		if (mUpdateTimer != 0) {
			delete mUpdateTimer;
			mUpdateTimer = 0;
		}
		return;
	}
	if (mUpdateTimer == 0) {
		mUpdateTimer = new QTimer(this);
		connect(mUpdateTimer, SIGNAL(timeout()), this, SLOT(onUpdateTimer()));
	}
	mUpdateTimer->setInterval(interval);
	mUpdateTimer->start();
}

void DBusBridge::produce(QObject *src, const char *property,
						 const QString &path, const QString &unit,
						 int precision)
{
	VBusItem *vbi = new VBusItem(this);
	QVariant value = src->property(property);
	toDBus(path, value);
	if (!value.isValid())
		value = QVariant::fromValue(QList<int>());
	connectItem(vbi, src, property, path);
	QDBusConnection connection = VBusItems::getConnection(mServiceName);
	vbi->produce(connection, path, "?", value, unit, precision);
	addVBusNodes(path, vbi);
}

void DBusBridge::produce(const QString &path, const QVariant &value,
						 const QString &unit, int precision)
{
	VBusItem *vbi = new VBusItem(this);
	connectItem(vbi, 0, 0, path);
	QDBusConnection connection = VBusItems::getConnection(mServiceName);
	vbi->produce(connection, path, "", value, unit, precision);
	addVBusNodes(path, vbi);
}

void DBusBridge::consume(const QString &service, QObject *src,
						 const char *property, const QString &path)
{
	QDBusConnection &connection = VBusItems::getConnection();
	VBusItem *vbi = new VBusItem(this);
	connectItem(vbi, src, property, path);
	vbi->consume(connection, service, path);
	vbi->getValue(); // force value retrieval
}

void DBusBridge::consume(const QString &service, QObject *src,
						 const char *property, const QVariant &defaultValue,
						 const QString &path)
{
	addSetting(path, defaultValue, QVariant(0), QVariant(0));
	consume(service, src, property, path);
}

void DBusBridge::consume(const QString &service, QObject *src,
						 const char *property, double defaultValue,
						 double minValue, double maxValue, const QString &path)
{
	addSetting(path, QVariant(defaultValue), QVariant(minValue), QVariant(maxValue));
	consume(service, src, property, path);
}

QString DBusBridge::serviceName() const
{
	return mServiceName;
}

void DBusBridge::setServiceName(const QString &sn)
{
	mServiceName = sn;
}

void DBusBridge::registerService()
{
	if (mServiceRegistered) {
		QLOG_ERROR() << "Service already registered";
		return;
	}
	QLOG_INFO() << "Registering service" << mServiceName;
	QDBusConnection connection = VBusItems::getConnection(mServiceName);
	if (connection.registerService(mServiceName))
		mServiceRegistered = true;
	else
		QLOG_FATAL() << "RegisterService failed";
}

bool DBusBridge::toDBus(const QString &, QVariant &)
{
	return true;
}

bool DBusBridge::fromDBus(const QString &, QVariant &)
{
	return true;
}

bool DBusBridge::addSetting(const QString &path,
							const QVariant &defaultValue,
							const QVariant &minValue,
							const QVariant &maxValue)
{
	if (!path.startsWith("/Settings"))
		return false;
	int groupStart = path.indexOf('/', 1);
	if (groupStart == -1)
		return false;
	int nameStart = path.lastIndexOf('/');
	if (nameStart <= groupStart)
		return false;
	QChar type;
	switch (defaultValue.type()) {
	case QVariant::Int:
		type = 'i';
		break;
	case QVariant::Double:
		type = 'f';
		break;
	case QVariant::String:
		type = 's';
		break;
	default:
		return false;
	}
	QString group = path.mid(groupStart + 1, nameStart - groupStart - 1);
	QString name = path.mid(nameStart + 1);
	QDBusConnection &connection = VBusItems::getConnection();
	QDBusMessage m = QDBusMessage::createMethodCall(
						 "com.victronenergy.settings",
						 "/Settings",
						 "com.victronenergy.Settings",
						 "AddSetting")
					 << group
					 << name
					 << QVariant::fromValue(QDBusVariant(defaultValue))
					 << QString(type)
					 << QVariant::fromValue(QDBusVariant(minValue))
					 << QVariant::fromValue(QDBusVariant(maxValue));
	QDBusMessage reply = connection.call(m);
	return reply.type() == QDBusMessage::ReplyMessage;
}

void DBusBridge::onPropertyChanged()
{
	QObject *src = sender();
	int signalIndex = senderSignalIndex();
	const QMetaObject *mo = src->metaObject();
	for (int i=0; i<mo->propertyCount(); ++i) {
		QMetaProperty mp = mo->property(i);
		if (mp.hasNotifySignal() && mp.notifySignalIndex() == signalIndex) {
			for (QList<BusItemBridge>::iterator it = mBusItems.begin();
				 it != mBusItems.end();
				 ++it) {
				if (it->src == src &&
					it->property.isValid() &&
					strcmp(it->property.name(), mp.name()) == 0) {
					if (mUpdateTimer == 0)
						publishValue(*it);
					else
						it->changed	= true;
					break;
				}
			}
		}
	}
}

void DBusBridge::onVBusItemChanged()
{
	if (mUpdateBusy)
		return;
	bool checkInit = false;
	for (QList<BusItemBridge>::iterator it = mBusItems.begin();
		 it != mBusItems.end();
		 ++it) {
		if (it->item == sender()) {
			if (it->src == 0) {
				QLOG_WARN() << "Value changed on D-Bus could not be stored in QT-property";
			} else if (it->property.isValid()) {
				QVariant value = it->item->getValue();
				if (value.canConvert<QList<int> >()) {
					QList<int> l = value.value<QList<int> >();
					if (l.isEmpty())
						value = QVariant();
				}
				if (fromDBus(it->path, value))
					it->src->setProperty(it->property.name(), value);
			}
			if (!it->initialized) {
				it->initialized = true;
				checkInit = true;
			}
			break;
		}
	}
	if (checkInit) {
		foreach (BusItemBridge bib, mBusItems) {
			if (!bib.initialized) {
				checkInit = false;
				break;
			}
		}
		if (checkInit)
			emit initialized();
	}
}

void DBusBridge::onUpdateTimer()
{
	for (QList<BusItemBridge>::iterator it = mBusItems.begin();
		 it != mBusItems.end();
		 ++it) {
		if (it->changed) {
			publishValue(*it);
			it->changed = false;
		}
	}
}

void DBusBridge::connectItem(VBusItem *busItem, QObject *src,
							 const char *property, const QString &path)
{
	BusItemBridge bib;
	bib.item = busItem;
	bib.src = src;
	bib.path = path;
	bib.initialized = false;
	bib.changed = false;
	if (src == 0) {
		if (property != 0) {
			QLOG_ERROR() << "Property specified (" << property
						 << "), but source omitted in DBusBridge. Path was"
						 << path;
		}
	} else {
		if (property == 0) {
			QLOG_ERROR() << "Source specified, but property omitted in"
						 << "DBusBridge. Path was"
						 << path;
		} else {
			const QMetaObject *mo = src->metaObject();
			int i = mo->indexOfProperty(property);
			if (i == -1) {
				QLOG_ERROR() << "DBusBridge could not find property" << property
							 << "Path was" << path;
			} else {
				QMetaProperty mp = mo->property(i);
				if (mp.hasNotifySignal()) {
					QMetaMethod signal = mp.notifySignal();
					int index = metaObject()->indexOfSlot("onPropertyChanged()");
					QMetaMethod slot = metaObject()->method(index);
					connect(src, signal, this, slot);
				}
				bib.property = mp;
			}
		}
	}
	mBusItems.push_back(bib);
	connect(busItem, SIGNAL(valueChanged()), this, SLOT(onVBusItemChanged()));
}

void DBusBridge::addVBusNodes(const QString &path, VBusItem *vbi)
{
	if (mServiceRoot.isNull()) {
		QDBusConnection connection = VBusItems::getConnection(serviceName());
		mServiceRoot = new VBusNode(connection, "/", this);
	}
	mServiceRoot->addChild(path, vbi);
}

void DBusBridge::publishValue(DBusBridge::BusItemBridge &item)
{
	QVariant value = item.src->property(item.property.name());
	if (!toDBus(item.path, value))
		return;
	if (!value.isValid())
		value = QVariant::fromValue(QList<int>());
	mUpdateBusy = true;
	item.item->setValue(value);
	mUpdateBusy = false;
}
<commit_msg>Improved performance of DBusBridge<commit_after>#include <QDBusVariant>
#include <QsLog.h>
#include <QTimer>
#include <velib/qt/v_busitem.h>
#include <velib/qt/v_busitems.h>
#include "v_bus_node.h"
#include "dbus_bridge.h"

Q_DECLARE_METATYPE(QList<int>)

DBusBridge::DBusBridge(QObject *parent) :
	QObject(parent),
	mServiceRegistered(false),
	mUpdateBusy(false),
	mUpdateTimer(0)
{
}

DBusBridge::DBusBridge(const QString &serviceName, QObject *parent):
	QObject(parent),
	mServiceName(serviceName),
	mServiceRegistered(false),
	mUpdateBusy(false),
	mUpdateTimer(0)
{
}

DBusBridge::~DBusBridge()
{
	if (!mServiceRegistered)
		return;
	QLOG_INFO() << "Unregistering service" << mServiceName;
	QDBusConnection connection = VBusItems::getConnection(mServiceName);
	if (!connection.unregisterService(mServiceName)) {
		QLOG_FATAL() << "UnregisterService failed";
	}
}

void DBusBridge::setUpdateInterval(int interval)
{
	if (interval <= 0) {
		if (mUpdateTimer != 0) {
			delete mUpdateTimer;
			mUpdateTimer = 0;
		}
		return;
	}
	if (mUpdateTimer == 0) {
		mUpdateTimer = new QTimer(this);
		connect(mUpdateTimer, SIGNAL(timeout()), this, SLOT(onUpdateTimer()));
	}
	mUpdateTimer->setInterval(interval);
	mUpdateTimer->start();
}

void DBusBridge::produce(QObject *src, const char *property,
						 const QString &path, const QString &unit,
						 int precision)
{
	VBusItem *vbi = new VBusItem(this);
	QVariant value = src->property(property);
	toDBus(path, value);
	if (!value.isValid())
		value = QVariant::fromValue(QList<int>());
	connectItem(vbi, src, property, path);
	QDBusConnection connection = VBusItems::getConnection(mServiceName);
	vbi->produce(connection, path, "?", value, unit, precision);
	addVBusNodes(path, vbi);
}

void DBusBridge::produce(const QString &path, const QVariant &value,
						 const QString &unit, int precision)
{
	VBusItem *vbi = new VBusItem(this);
	connectItem(vbi, 0, 0, path);
	QDBusConnection connection = VBusItems::getConnection(mServiceName);
	vbi->produce(connection, path, "", value, unit, precision);
	addVBusNodes(path, vbi);
}

void DBusBridge::consume(const QString &service, QObject *src,
						 const char *property, const QString &path)
{
	QDBusConnection &connection = VBusItems::getConnection();
	VBusItem *vbi = new VBusItem(this);
	connectItem(vbi, src, property, path);
	vbi->consume(connection, service, path);
	vbi->getValue(); // force value retrieval
}

void DBusBridge::consume(const QString &service, QObject *src,
						 const char *property, const QVariant &defaultValue,
						 const QString &path)
{
	addSetting(path, defaultValue, QVariant(0), QVariant(0));
	consume(service, src, property, path);
}

void DBusBridge::consume(const QString &service, QObject *src,
						 const char *property, double defaultValue,
						 double minValue, double maxValue, const QString &path)
{
	addSetting(path, QVariant(defaultValue), QVariant(minValue), QVariant(maxValue));
	consume(service, src, property, path);
}

QString DBusBridge::serviceName() const
{
	return mServiceName;
}

void DBusBridge::setServiceName(const QString &sn)
{
	mServiceName = sn;
}

void DBusBridge::registerService()
{
	if (mServiceRegistered) {
		QLOG_ERROR() << "Service already registered";
		return;
	}
	QLOG_INFO() << "Registering service" << mServiceName;
	QDBusConnection connection = VBusItems::getConnection(mServiceName);
	if (connection.registerService(mServiceName))
		mServiceRegistered = true;
	else
		QLOG_FATAL() << "RegisterService failed";
}

bool DBusBridge::toDBus(const QString &, QVariant &)
{
	return true;
}

bool DBusBridge::fromDBus(const QString &, QVariant &)
{
	return true;
}

bool DBusBridge::addSetting(const QString &path,
							const QVariant &defaultValue,
							const QVariant &minValue,
							const QVariant &maxValue)
{
	if (!path.startsWith("/Settings"))
		return false;
	int groupStart = path.indexOf('/', 1);
	if (groupStart == -1)
		return false;
	int nameStart = path.lastIndexOf('/');
	if (nameStart <= groupStart)
		return false;
	QChar type;
	switch (defaultValue.type()) {
	case QVariant::Int:
		type = 'i';
		break;
	case QVariant::Double:
		type = 'f';
		break;
	case QVariant::String:
		type = 's';
		break;
	default:
		return false;
	}
	QString group = path.mid(groupStart + 1, nameStart - groupStart - 1);
	QString name = path.mid(nameStart + 1);
	QDBusConnection &connection = VBusItems::getConnection();
	QDBusMessage m = QDBusMessage::createMethodCall(
						 "com.victronenergy.settings",
						 "/Settings",
						 "com.victronenergy.Settings",
						 "AddSetting")
					 << group
					 << name
					 << QVariant::fromValue(QDBusVariant(defaultValue))
					 << QString(type)
					 << QVariant::fromValue(QDBusVariant(minValue))
					 << QVariant::fromValue(QDBusVariant(maxValue));
	QDBusMessage reply = connection.call(m);
	return reply.type() == QDBusMessage::ReplyMessage;
}

void DBusBridge::onPropertyChanged()
{
	QObject *src = sender();
	int signalIndex = senderSignalIndex();
	for (QList<BusItemBridge>::iterator it = mBusItems.begin(); it != mBusItems.end(); ++it) {
		if (it->src == src && it->property.isValid() &&
				it->property.notifySignalIndex() == signalIndex) {
			if (mUpdateTimer == 0)
				publishValue(*it);
			else
				it->changed = true;
			break;
		}
	}
}

void DBusBridge::onVBusItemChanged()
{
	if (mUpdateBusy)
		return;
	bool checkInit = false;
	for (QList<BusItemBridge>::iterator it = mBusItems.begin();
		 it != mBusItems.end();
		 ++it) {
		if (it->item == sender()) {
			if (it->src == 0) {
				QLOG_WARN() << "Value changed on D-Bus could not be stored in QT-property";
			} else if (it->property.isValid()) {
				QVariant value = it->item->getValue();
				if (value.canConvert<QList<int> >()) {
					QList<int> l = value.value<QList<int> >();
					if (l.isEmpty())
						value = QVariant();
				}
				if (fromDBus(it->path, value))
					it->src->setProperty(it->property.name(), value);
			}
			if (!it->initialized) {
				it->initialized = true;
				checkInit = true;
			}
			break;
		}
	}
	if (checkInit) {
		foreach (BusItemBridge bib, mBusItems) {
			if (!bib.initialized) {
				checkInit = false;
				break;
			}
		}
		if (checkInit)
			emit initialized();
	}
}

void DBusBridge::onUpdateTimer()
{
	for (QList<BusItemBridge>::iterator it = mBusItems.begin(); it != mBusItems.end(); ++it) {
		if (it->changed) {
			publishValue(*it);
			it->changed = false;
		}
	}
}

void DBusBridge::connectItem(VBusItem *busItem, QObject *src,
							 const char *property, const QString &path)
{
	BusItemBridge bib;
	bib.item = busItem;
	bib.src = src;
	bib.path = path;
	bib.initialized = false;
	bib.changed = false;
	if (src == 0) {
		if (property != 0) {
			QLOG_ERROR() << "Property specified (" << property
						 << "), but source omitted in DBusBridge. Path was"
						 << path;
		}
	} else {
		if (property == 0) {
			QLOG_ERROR() << "Source specified, but property omitted in"
						 << "DBusBridge. Path was"
						 << path;
		} else {
			const QMetaObject *mo = src->metaObject();
			int i = mo->indexOfProperty(property);
			if (i == -1) {
				QLOG_ERROR() << "DBusBridge could not find property" << property
							 << "Path was" << path;
			} else {
				QMetaProperty mp = mo->property(i);
				if (mp.hasNotifySignal()) {
					QMetaMethod signal = mp.notifySignal();
					int index = metaObject()->indexOfSlot("onPropertyChanged()");
					QMetaMethod slot = metaObject()->method(index);
					connect(src, signal, this, slot);
				}
				bib.property = mp;
			}
		}
	}
	mBusItems.push_back(bib);
	connect(busItem, SIGNAL(valueChanged()), this, SLOT(onVBusItemChanged()));
}

void DBusBridge::addVBusNodes(const QString &path, VBusItem *vbi)
{
	if (mServiceRoot.isNull()) {
		QDBusConnection connection = VBusItems::getConnection(serviceName());
		mServiceRoot = new VBusNode(connection, "/", this);
	}
	mServiceRoot->addChild(path, vbi);
}

void DBusBridge::publishValue(DBusBridge::BusItemBridge &item)
{
	QVariant value = item.src->property(item.property.name());
	if (!toDBus(item.path, value))
		return;
	if (!value.isValid())
		value = QVariant::fromValue(QList<int>());
	mUpdateBusy = true;
	item.item->setValue(value);
	mUpdateBusy = false;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: hfi_siservice.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2004-07-12 15:29:23 $
 *
 *  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): _______________________________________
 *
 *
 ************************************************************************/

#ifndef ADC_DISPLAY_HFI_SISERVICE_HXX
#define ADC_DISPLAY_HFI_SISERVICE_HXX

// USED SERVICES
    // BASE CLASSES
#include "hi_factory.hxx"
    // COMPONENTS
    // PARAMETERS
#include <ary/idl/i_comrela.hxx>

class HF_NaviSubRow;
class HF_SubTitleTable;

class HF_IdlSglIfcService : public HtmlFactory_Idl
{
  public:
                        HF_IdlSglIfcService(
                            Environment &       io_rEnv,
                            Xml::Element &      o_rOut );
    virtual             ~HF_IdlSglIfcService();

    void                Produce_byData(
                           const client &       i_ce ) const;
   private:
    DYN HF_NaviSubRow & make_Navibar(
                            const client &      i_ce ) const;

    void                produce_MemberDetails(
                            HF_SubTitleTable &  o_table,
                            const client &      i_ce ) const;
};

// IMPLEMENTATION

extern const String
    C_sCePrefix_Service;

#endif

<commit_msg>INTEGRATION: CWS ooo19126 (1.2.24); FILE MERGED 2005/09/05 13:11:06 rt 1.2.24.1: #i54170# Change license header: remove SISSL<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: hfi_siservice.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-07 17:46:58 $
 *
 *  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
 *
 ************************************************************************/

#ifndef ADC_DISPLAY_HFI_SISERVICE_HXX
#define ADC_DISPLAY_HFI_SISERVICE_HXX

// USED SERVICES
    // BASE CLASSES
#include "hi_factory.hxx"
    // COMPONENTS
    // PARAMETERS
#include <ary/idl/i_comrela.hxx>

class HF_NaviSubRow;
class HF_SubTitleTable;

class HF_IdlSglIfcService : public HtmlFactory_Idl
{
  public:
                        HF_IdlSglIfcService(
                            Environment &       io_rEnv,
                            Xml::Element &      o_rOut );
    virtual             ~HF_IdlSglIfcService();

    void                Produce_byData(
                           const client &       i_ce ) const;
   private:
    DYN HF_NaviSubRow & make_Navibar(
                            const client &      i_ce ) const;

    void                produce_MemberDetails(
                            HF_SubTitleTable &  o_table,
                            const client &      i_ce ) const;
};

// IMPLEMENTATION

extern const String
    C_sCePrefix_Service;

#endif

<|endoftext|>


<commit_before>#include <iostream>
#include <map>
#include <algebra/matrix.h>
#include <algebra/vector.h>
#include <algebra/qs_matrix.h>
#include <algebra/sparse_matrix.h>

using namespace std;
using namespace MathTL;

int main()
{
  cout << "Constructing a quasi-stationary matrix..." << endl;

  Matrix<double> one(3, 2, "1 2 3 4 5 6");
  Matrix<double> two(4, 1, "-4 -3 -2 -1");
  Vector<double> b1(3, "3 4 5");
  Vector<double> b2(3, "5 6 -7");

  QuasiStationaryMatrix<double> Q(3, 17, 9, one, two, b1, b2, 2, 1);
  cout << "Q=" << endl << Q;

//   Q.set_level(4);
//   cout << "Q on next higher level:" << endl << Q;

  SparseMatrix<double> S;
  Q.to_sparse(S);
  cout << "Q as a sparse matrix:" << endl << S;

  Vector<double> x(Q.column_dimension());
  x[4] = x[5] = 1;
  Vector<double> Qx(Q.row_dimension());
  Q.apply(x, Qx);
  cout << "Q applied to x=" << x << " yields Qx=" << Qx << endl;

  Vector<double> y(Q.row_dimension());
  y[11] = y[12] = 1;
  Vector<double> Qty(Q.column_dimension());
  Q.apply_transposed(y, Qty);
  cout << "Q^T applied to y=" << y << " yields Q^Ty=" << Qty << endl;

  x.resize(Q.column_dimension()+2);
  x[5] = x[6] = 1;
  Qx.resize(Q.row_dimension()+2);
  Q.apply(x, Qx, 1, 2);
  cout << "Q applied to the part of x=" << x << " from index 1," << endl
       << "written into Qx from index 2 on yields Qx=" << Qx << endl;

  y.resize(Q.row_dimension()+3);
  y[14] = y[15] = 1;
  Qty.resize(Q.column_dimension()+1);
  Q.apply_transposed(y, Qty, 3, 1);
  cout << "Q^T applied to the part of y=" << y << " from index 3," << endl
       << "written into Qty from index 1 on yields Qty=" << Qty << endl;

  std::map<unsigned int, double> xsparse, Qxsparse;
  xsparse[6] = 1;
//   xsparse[Q.column_dimension()-1] = 1;
  unsigned int xoffset = 1;
  unsigned int Qxoffset = 0;
  Q.apply(xsparse, Qxsparse, xoffset, Qxoffset);
  cout << "entries of a sparse vector x:" << endl;
  for (std::map<unsigned int, double>::const_iterator it(xsparse.begin());
       it != xsparse.end(); ++it)
    cout << "x[" << it->first << "]=" << it->second << endl;
  cout << "Q applied to the part of x from index " << xoffset
       << ", written into Qx from index " << Qxoffset << " yields Qx=" << endl;
  for (std::map<unsigned int, double>::const_iterator it(Qxsparse.begin());
       it != Qxsparse.end(); ++it)
    cout << "Qx[" << it->first << "]=" << it->second << endl;

  std::map<unsigned int, double> ysparse, Qtysparse;
//   ysparse[9] = 1;
  ysparse[Q.row_dimension()-2] = 1;
  unsigned int yoffset = 0;
  unsigned int Qtyoffset = 0;
  Q.apply_transposed(ysparse, Qtysparse, yoffset, Qtyoffset);
  cout << "entries of a sparse vector y:" << endl;
  for (std::map<unsigned int, double>::const_iterator it(ysparse.begin());
       it != ysparse.end(); ++it)
    cout << "y[" << it->first << "]=" << it->second << endl;
  cout << "Q^T applied to the part of y from index " << yoffset
       << ", written into Qty from index " << Qtyoffset << " yields Qty=" << endl;
  for (std::map<unsigned int, double>::const_iterator it(Qtysparse.begin());
       it != Qtysparse.end(); ++it)
    cout << "Qty[" << it->first << "]=" << it->second << endl;

  return 0;
}
<commit_msg>minor change<commit_after>#include <iostream>
#include <map>
#include <algebra/matrix.h>
#include <algebra/vector.h>
#include <algebra/qs_matrix.h>
#include <algebra/sparse_matrix.h>

using namespace std;
using namespace MathTL;

int main()
{
  cout << "Constructing a quasi-stationary matrix..." << endl;

  Matrix<double> one(3, 2, "1 2 3 4 5 6");
  Matrix<double> two(4, 1, "-4 -3 -2 -1");
  Vector<double> b1(3, "3 4 5");
  Vector<double> b2(3, "5 6 -7");

  QuasiStationaryMatrix<double> Q(3, 17, 9, one, two, b1, b2, 2, 1);
  cout << "Q=" << endl << Q;

//   Q.set_level(4);
//   cout << "Q on next higher level:" << endl << Q;

  SparseMatrix<double> S;
  Q.to_sparse(S);
  cout << "Q as a sparse matrix:" << endl << S;

  Vector<double> x(Q.column_dimension());
  x[4] = x[5] = 1;
  Vector<double> Qx(Q.row_dimension());
  Q.apply(x, Qx);
  cout << "Q applied to x=" << x << " yields Qx=" << Qx << endl;

  Vector<double> y(Q.row_dimension());
  y[11] = y[12] = 1;
  Vector<double> Qty(Q.column_dimension());
  Q.apply_transposed(y, Qty);
  cout << "Q^T applied to y=" << y << " yields Q^Ty=" << Qty << endl;

  x.resize(Q.column_dimension()+2);
  x[5] = x[6] = 1;
  Qx.resize(Q.row_dimension()+2);
  Q.apply(x, Qx, 1, 2);
  cout << "Q applied to the part of x=" << x << " from index 1," << endl
       << "written into Qx from index 2 on yields Qx=" << Qx << endl;

  y.resize(Q.row_dimension()+3);
  y[14] = y[15] = 1;
  Qty.resize(Q.column_dimension()+1);
  Q.apply_transposed(y, Qty, 3, 1);
  cout << "Q^T applied to the part of y=" << y << " from index 3," << endl
       << "written into Qty from index 1 on yields Qty=" << Qty << endl;

  std::map<unsigned int, double> xsparse, Qxsparse;
  xsparse[6] = 1;
//   xsparse[Q.column_dimension()-1] = 1;
  unsigned int xoffset = 1;
  unsigned int Qxoffset = 0;
  Q.apply(xsparse, Qxsparse, xoffset, Qxoffset);
  cout << "entries of a sparse vector x:" << endl;
  for (std::map<unsigned int, double>::const_iterator it(xsparse.begin());
       it != xsparse.end(); ++it)
    cout << "x[" << it->first << "]=" << it->second << endl;
  cout << "Q applied to the part of x from index " << xoffset
       << ", written into Qx from index " << Qxoffset << " yields Qx=" << endl;
  for (std::map<unsigned int, double>::const_iterator it(Qxsparse.begin());
       it != Qxsparse.end(); ++it)
    cout << "Qx[" << it->first << "]=" << it->second << endl;

  std::map<size_t, double> ysparse, Qtysparse;
//   ysparse[9] = 1;
  ysparse[Q.row_dimension()-2] = 1;
  unsigned int yoffset = 0;
  unsigned int Qtyoffset = 0;
  Q.apply_transposed(ysparse, Qtysparse, yoffset, Qtyoffset);
  cout << "entries of a sparse vector y:" << endl;
  for (std::map<unsigned int, double>::const_iterator it(ysparse.begin());
       it != ysparse.end(); ++it)
    cout << "y[" << it->first << "]=" << it->second << endl;
  cout << "Q^T applied to the part of y from index " << yoffset
       << ", written into Qty from index " << Qtyoffset << " yields Qty=" << endl;
  for (std::map<unsigned int, double>::const_iterator it(Qtysparse.begin());
       it != Qtysparse.end(); ++it)
    cout << "Qty[" << it->first << "]=" << it->second << endl;

  return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: filelist.cxx,v $
 *
 *  $Revision: 1.7 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 07:38:28 $
 *
 *  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
 *
 ************************************************************************/

#include<tools/list.hxx>
#include<tools/stream.hxx>
#include<tools/string.hxx>
#include<tools/rtti.hxx>
#include<exchange.hxx>
#include<filelist.hxx>
#pragma hdrstop

#ifndef _OSL_THREAD_H_
#include <osl/thread.h>
#endif

TYPEINIT1_AUTOFACTORY( FileList, SvDataCopyStream );

// String-Liste zum Speichern der Namen deklarieren
DECLARE_LIST( FileStringList, String* );

/*************************************************************************
|*
|*    FileList - Ctor/Dtor
|*
\*************************************************************************/

FileList::FileList()
{
    pStrList = new FileStringList();
}

FileList::~FileList()
{
    ClearAll();
}

void FileList::ClearAll( void )
{
    // Strings in der Liste loeschen
    ULONG nCount = pStrList->Count();
    for( ULONG i = 0 ; i < nCount ; i++ )
        delete pStrList->GetObject( i );

    // Liste loeschen
    delete pStrList;
}

/*************************************************************************
|*
|*    FileList - Zuweisungsoperator
|*
\*************************************************************************/

FileList& FileList::operator=( const FileList& rFileList )
{
    // Liste duplizieren
    *pStrList = *rFileList.pStrList;

    // Strings in der Liste kopieren
    ULONG nCount = pStrList->Count();
    for( ULONG i = 0 ; i < nCount ; i++ )
        pStrList->Replace( new String( *rFileList.pStrList->GetObject( i ) ), i );

    return *this;
}

/*************************************************************************
|*
|*    FileList::GetFormatName()
|*
\*************************************************************************/

ULONG FileList::GetFormat()
{
    return FORMAT_FILE_LIST;
}

/******************************************************************************
|*
|*  virtuelle SvData-Methoden
|*
\******************************************************************************/

void FileList::Load( SvStream& rIStm )
{
    rIStm >> *this;
}

void FileList::Save( SvStream& rOStm )
{
    rOStm << *this;
}

void FileList::Assign( const SvDataCopyStream& rCopyStream )
{
    *this = (const FileList&)rCopyStream;
}

/******************************************************************************
|*
|*  Stream-Operatoren
|*
\******************************************************************************/

/*
 * NOTE: to correctly handle this Protocol with Unicode, native Win32 must be called:
 * e.g. DropQueryFile
 */

SvStream& operator<<( SvStream& rOStm, const FileList& rFileList )
{
    OSL_ENSURE(false, "Not implemented!");
    return rOStm;
}

/* #i28176#
   The Windows clipboard bridge now provides a double '\0'
   terminated list of file names for format SOT_FORMAT_FILE_LIST
   instead of the original Windows Sv_DROPFILES structure. All strings
   in this list are UTF16 strings. Shell link files will be already
   resolved by the Windows clipboard bridge.*/
SvStream& operator>>( SvStream& rIStm, FileList& rFileList )
{
    rFileList.ClearAll();
    rFileList.pStrList = new FileStringList();

    String aStr;
    sal_uInt16 c;

    while (!rIStm.IsEof())
    {
        aStr.Erase();

        // read first character of filepath; c==0 > reach end of stream
        rIStm >> c;
        if (!c)
            break;

        // read string till c==0
        while (c && !rIStm.IsEof())
        {
            aStr += (sal_Unicode)c;
            rIStm >> c;
        }

        // append the filepath
        rFileList.AppendFile(aStr);
    }
    return rIStm;
}

/******************************************************************************
|*
|*  Liste fuellen/abfragen
|*
\******************************************************************************/

void FileList::AppendFile( const String& rStr )
{
    pStrList->Insert( new String( rStr ) , pStrList->Count() );
}

String FileList::GetFile( ULONG i ) const
{
    String aStr;
    if( i < pStrList->Count() )
        aStr = *pStrList->GetObject( i );
    return aStr;
}

ULONG FileList::Count( void ) const
{
    return pStrList->Count();
}

<commit_msg>INTEGRATION: CWS warnings01 (1.7.8); FILE MERGED 2005/10/28 16:15:26 pl 1.7.8.2: #i55991# removed warnings for solaris platform 2005/10/21 16:25:06 pl 1.7.8.1: #i55991# removed warnings for linux platform<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: filelist.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: hr $ $Date: 2006-06-20 05:52:50 $
 *
 *  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
 *
 ************************************************************************/

#include<tools/list.hxx>
#include<tools/stream.hxx>
#include<tools/string.hxx>
#include<tools/rtti.hxx>
#include<exchange.hxx>
#include<filelist.hxx>

#ifndef _OSL_THREAD_H_
#include <osl/thread.h>
#endif

TYPEINIT1_AUTOFACTORY( FileList, SvDataCopyStream );

// String-Liste zum Speichern der Namen deklarieren
DECLARE_LIST( FileStringList, String* )

/*************************************************************************
|*
|*    FileList - Ctor/Dtor
|*
\*************************************************************************/

FileList::FileList()
{
    pStrList = new FileStringList();
}

FileList::~FileList()
{
    ClearAll();
}

void FileList::ClearAll( void )
{
    // Strings in der Liste loeschen
    ULONG nCount = pStrList->Count();
    for( ULONG i = 0 ; i < nCount ; i++ )
        delete pStrList->GetObject( i );

    // Liste loeschen
    delete pStrList;
}

/*************************************************************************
|*
|*    FileList - Zuweisungsoperator
|*
\*************************************************************************/

FileList& FileList::operator=( const FileList& rFileList )
{
    // Liste duplizieren
    *pStrList = *rFileList.pStrList;

    // Strings in der Liste kopieren
    ULONG nCount = pStrList->Count();
    for( ULONG i = 0 ; i < nCount ; i++ )
        pStrList->Replace( new String( *rFileList.pStrList->GetObject( i ) ), i );

    return *this;
}

/*************************************************************************
|*
|*    FileList::GetFormatName()
|*
\*************************************************************************/

ULONG FileList::GetFormat()
{
    return FORMAT_FILE_LIST;
}

/******************************************************************************
|*
|*  virtuelle SvData-Methoden
|*
\******************************************************************************/

void FileList::Load( SvStream& rIStm )
{
    rIStm >> *this;
}

void FileList::Save( SvStream& rOStm )
{
    rOStm << *this;
}

void FileList::Assign( const SvDataCopyStream& rCopyStream )
{
    *this = (const FileList&)rCopyStream;
}

/******************************************************************************
|*
|*  Stream-Operatoren
|*
\******************************************************************************/

/*
 * NOTE: to correctly handle this Protocol with Unicode, native Win32 must be called:
 * e.g. DropQueryFile
 */

SvStream& operator<<( SvStream& rOStm, const FileList& /*rFileList*/ )
{
    OSL_ENSURE(false, "Not implemented!");
    return rOStm;
}

/* #i28176#
   The Windows clipboard bridge now provides a double '\0'
   terminated list of file names for format SOT_FORMAT_FILE_LIST
   instead of the original Windows Sv_DROPFILES structure. All strings
   in this list are UTF16 strings. Shell link files will be already
   resolved by the Windows clipboard bridge.*/
SvStream& operator>>( SvStream& rIStm, FileList& rFileList )
{
    rFileList.ClearAll();
    rFileList.pStrList = new FileStringList();

    String aStr;
    sal_uInt16 c;

    while (!rIStm.IsEof())
    {
        aStr.Erase();

        // read first character of filepath; c==0 > reach end of stream
        rIStm >> c;
        if (!c)
            break;

        // read string till c==0
        while (c && !rIStm.IsEof())
        {
            aStr += (sal_Unicode)c;
            rIStm >> c;
        }

        // append the filepath
        rFileList.AppendFile(aStr);
    }
    return rIStm;
}

/******************************************************************************
|*
|*  Liste fuellen/abfragen
|*
\******************************************************************************/

void FileList::AppendFile( const String& rStr )
{
    pStrList->Insert( new String( rStr ) , pStrList->Count() );
}

String FileList::GetFile( ULONG i ) const
{
    String aStr;
    if( i < pStrList->Count() )
        aStr = *pStrList->GetObject( i );
    return aStr;
}

ULONG FileList::Count( void ) const
{
    return pStrList->Count();
}

<|endoftext|>