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

#include "ppapi/cpp/var.h"

#include <string.h>

#include <algorithm>

#include "ppapi/c/pp_var.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/cpp/logging.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/module_impl.h"
#include "ppapi/cpp/scriptable_object.h"

// Defining sprintf
#include <stdio.h>
#if defined(_MSC_VER)
#  define snprintf _snprintf_s
#endif

// Defining PRId32
#if defined(_WIN64)
#  define PRId32 "I64d"
#elif defined(_WIN32)
#  define PRId32 "ld"
#else
#  include <inttypes.h>
#endif

namespace {

DeviceFuncs<PPB_Var> ppb_var_f(PPB_VAR_INTERFACE);

// Technically you can call AddRef and Release on any Var, but it may involve
// cross-process calls depending on the plugin. This is an optimization so we
// only do refcounting on the necessary objects.
inline bool NeedsRefcounting(const PP_Var& var) {
  return var.type == PP_VARTYPE_STRING || var.type == PP_VARTYPE_OBJECT;
}

}  // namespace

namespace pp {

Var::Var() {
  var_.type = PP_VARTYPE_VOID;
  needs_release_ = false;
}

Var::Var(Null) {
  var_.type = PP_VARTYPE_NULL;
  needs_release_ = false;
}

Var::Var(bool b) {
  var_.type = PP_VARTYPE_BOOL;
  var_.value.as_bool = b;
  needs_release_ = false;
}

Var::Var(int32_t i) {
  var_.type = PP_VARTYPE_INT32;
  var_.value.as_int = i;
  needs_release_ = false;
}

Var::Var(double d) {
  var_.type = PP_VARTYPE_DOUBLE;
  var_.value.as_double = d;
  needs_release_ = false;
}

Var::Var(const char* str) {
  if (ppb_var_f) {
    var_ = ppb_var_f->VarFromUtf8(str, static_cast<uint32_t>(strlen(str)));
    needs_release_ = true;
  } else {
    var_.type = PP_VARTYPE_VOID;
    needs_release_ = false;
  }
}

Var::Var(const std::string& str) {
  if (ppb_var_f) {
    var_ = ppb_var_f->VarFromUtf8(str.c_str(),
                                  static_cast<uint32_t>(str.size()));
    needs_release_ = true;
  } else {
    var_.type = PP_VARTYPE_VOID;
    needs_release_ = false;
  }
}

Var::Var(ScriptableObject* object) {
  if (ppb_var_f) {
    var_ = ppb_var_f->CreateObject(object->GetClass(), object);
    needs_release_ = true;
  } else {
    var_.type = PP_VARTYPE_VOID;
    needs_release_ = false;
  }
}

Var::Var(const Var& other) {
  var_ = other.var_;
  if (NeedsRefcounting(var_) && other.needs_release_) {
    if (ppb_var_f) {
      needs_release_ = true;
      ppb_var_f->AddRef(var_);
    } else {
      var_.type = PP_VARTYPE_VOID;
      needs_release_ = false;
    }
  } else {
    needs_release_ = false;
  }
}

Var::~Var() {
  if (needs_release_ && ppb_var_f)
    ppb_var_f->Release(var_);
}

Var& Var::operator=(const Var& other) {
  // Use the copy constructor to make a copy, then swap into that. This makes
  // sure we call the correct init and destruct for everything, without actually
  // needing to write the refcounting code here.
  Var copy(other);
  swap(copy);
  return *this;
}

void Var::swap(Var& other) {
  std::swap(var_, other.var_);
  std::swap(needs_release_, other.needs_release_);
}

bool Var::AsBool() const {
  if (!is_bool()) {
    PP_NOTREACHED();
    return false;
  }
  return var_.value.as_bool;
}

int32_t Var::AsInt() const {
  if (is_int())
    return var_.value.as_int;
  if (is_double())
    return static_cast<int>(var_.value.as_double);
  PP_NOTREACHED();
  return 0;
}

double Var::AsDouble() const {
  if (is_double())
    return var_.value.as_double;
  if (is_int())
    return static_cast<double>(var_.value.as_int);
  PP_NOTREACHED();
  return 0.0;
}

std::string Var::AsString() const {
  if (!is_string()) {
    PP_NOTREACHED();
    return std::string();
  }

  if (!ppb_var_f)
    return std::string();
  uint32_t len;
  const char* str = ppb_var_f->VarToUtf8(var_, &len);
  return std::string(str, len);
}

bool Var::HasProperty(const Var& name, Var* exception) const {
  if (!ppb_var_f)
    return false;
  return ppb_var_f->HasProperty(var_, name.var_, OutException(exception));
}

Var Var::GetProperty(const Var& name, Var* exception) const {
  if (!ppb_var_f)
    return Var();
  return Var(PassRef(), ppb_var_f->GetProperty(var_, name.var_,
                                               OutException(exception)));
}

void Var::GetAllPropertyNames(std::vector<Var>* properties,
                              Var* exception) const {
  if (!ppb_var_f)
    return;
  PP_Var* props = NULL;
  uint32_t prop_count = 0;
  ppb_var_f->GetAllPropertyNames(var_, &prop_count, &props,
                                 OutException(exception));
  if (!prop_count)
    return;
  properties->resize(prop_count);
  for (uint32_t i = 0; i < prop_count; ++i) {
    Var temp(PassRef(), props[i]);
    (*properties)[i].swap(temp);
  }
  Module::Get()->core()->MemFree(props);
}

void Var::SetProperty(const Var& name, const Var& value, Var* exception) {
  if (!ppb_var_f)
    return;
  ppb_var_f->SetProperty(var_, name.var_, value.var_, OutException(exception));
}

void Var::RemoveProperty(const Var& name, Var* exception) {
  if (!ppb_var_f)
    return;
  ppb_var_f->RemoveProperty(var_, name.var_, OutException(exception));
}

Var Var::Call(const Var& method_name, uint32_t argc, Var* argv,
              Var* exception) {
  if (!ppb_var_f)
    return Var();
  if (argc > 0) {
    std::vector<PP_Var> args;
    args.reserve(argc);
    for (size_t i = 0; i < argc; i++)
      args.push_back(argv[i].var_);
    return Var(PassRef(), ppb_var_f->Call(var_, method_name.var_,
                                          argc, &args[0],
                                          OutException(exception)));
  } else {
    // Don't try to get the address of a vector if it's empty.
    return Var(PassRef(), ppb_var_f->Call(var_, method_name.var_, 0, NULL,
                                          OutException(exception)));
  }
}

Var Var::Construct(uint32_t argc, Var* argv, Var* exception) const {
  if (!ppb_var_f)
    return Var();
  if (argc > 0) {
    std::vector<PP_Var> args;
    args.reserve(argc);
    for (size_t i = 0; i < argc; i++)
      args.push_back(argv[i].var_);
    return Var(PassRef(), ppb_var_f->Construct(var_, argc, &args[0],
                                               OutException(exception)));
  } else {
    // Don't try to get the address of a vector if it's empty.
    return Var(PassRef(), ppb_var_f->Construct(var_, 0, NULL,
                                               OutException(exception)));
  }
}

Var Var::Call(const Var& method_name, const Var& arg1, Var* exception) {
  if (!ppb_var_f)
    return Var();
  PP_Var args[1] = {arg1.var_};
  return Var(PassRef(), ppb_var_f->Call(var_, method_name.var_, 1, args,
                                        OutException(exception)));
}

Var Var::Call(const Var& method_name, const Var& arg1, const Var& arg2,
              Var* exception) {
  if (!ppb_var_f)
    return Var();
  PP_Var args[2] = {arg1.var_, arg2.var_};
  return Var(PassRef(), ppb_var_f->Call(var_, method_name.var_, 2, args,
                                        OutException(exception)));
}

Var Var::Call(const Var& method_name, const Var& arg1, const Var& arg2,
              const Var& arg3, Var* exception) {
  if (!ppb_var_f)
    return Var();
  PP_Var args[3] = {arg1.var_, arg2.var_, arg3.var_};
  return Var(PassRef(), ppb_var_f->Call(var_, method_name.var_, 3, args,
                                        OutException(exception)));
}

Var Var::Call(const Var& method_name, const Var& arg1, const Var& arg2,
              const Var& arg3, const Var& arg4, Var* exception) {
  if (!ppb_var_f)
    return Var();
  PP_Var args[4] = {arg1.var_, arg2.var_, arg3.var_, arg4.var_};
  return Var(PassRef(), ppb_var_f->Call(var_, method_name.var_, 4, args,
                                        OutException(exception)));
}

std::string Var::DebugString() const {
  char buf[256];
  if (is_void())
    snprintf(buf, sizeof(buf), "Var<VOID>");
  else if (is_null())
    snprintf(buf, sizeof(buf), "Var<NULL>");
  else if (is_bool())
    snprintf(buf, sizeof(buf), AsBool() ? "Var<true>" : "Var<false>");
  else if (is_int())
    snprintf(buf, sizeof(buf), "Var<%"PRId32">", AsInt());
  else if (is_double())
    snprintf(buf, sizeof(buf), "Var<%f>", AsDouble());
  else if (is_string())
    snprintf(buf, sizeof(buf), "Var<'%s'>", AsString().c_str());
  else if (is_object())
    snprintf(buf, sizeof(buf), "Var<OBJECT>");
  return buf;
}

}  // namespace pp
<commit_msg>Fix snprintf comment.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ppapi/cpp/var.h"

#include <string.h>

#include <algorithm>

#include "ppapi/c/pp_var.h"
#include "ppapi/c/ppb_var.h"
#include "ppapi/cpp/logging.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/module_impl.h"
#include "ppapi/cpp/scriptable_object.h"

// Defining snprintf
#include <stdio.h>
#if defined(_MSC_VER)
#  define snprintf _snprintf_s
#endif

// Defining PRId32
#if defined(_WIN64)
#  define PRId32 "I64d"
#elif defined(_WIN32)
#  define PRId32 "ld"
#else
#  include <inttypes.h>
#endif

namespace {

DeviceFuncs<PPB_Var> ppb_var_f(PPB_VAR_INTERFACE);

// Technically you can call AddRef and Release on any Var, but it may involve
// cross-process calls depending on the plugin. This is an optimization so we
// only do refcounting on the necessary objects.
inline bool NeedsRefcounting(const PP_Var& var) {
  return var.type == PP_VARTYPE_STRING || var.type == PP_VARTYPE_OBJECT;
}

}  // namespace

namespace pp {

Var::Var() {
  var_.type = PP_VARTYPE_VOID;
  needs_release_ = false;
}

Var::Var(Null) {
  var_.type = PP_VARTYPE_NULL;
  needs_release_ = false;
}

Var::Var(bool b) {
  var_.type = PP_VARTYPE_BOOL;
  var_.value.as_bool = b;
  needs_release_ = false;
}

Var::Var(int32_t i) {
  var_.type = PP_VARTYPE_INT32;
  var_.value.as_int = i;
  needs_release_ = false;
}

Var::Var(double d) {
  var_.type = PP_VARTYPE_DOUBLE;
  var_.value.as_double = d;
  needs_release_ = false;
}

Var::Var(const char* str) {
  if (ppb_var_f) {
    var_ = ppb_var_f->VarFromUtf8(str, static_cast<uint32_t>(strlen(str)));
    needs_release_ = true;
  } else {
    var_.type = PP_VARTYPE_VOID;
    needs_release_ = false;
  }
}

Var::Var(const std::string& str) {
  if (ppb_var_f) {
    var_ = ppb_var_f->VarFromUtf8(str.c_str(),
                                  static_cast<uint32_t>(str.size()));
    needs_release_ = true;
  } else {
    var_.type = PP_VARTYPE_VOID;
    needs_release_ = false;
  }
}

Var::Var(ScriptableObject* object) {
  if (ppb_var_f) {
    var_ = ppb_var_f->CreateObject(object->GetClass(), object);
    needs_release_ = true;
  } else {
    var_.type = PP_VARTYPE_VOID;
    needs_release_ = false;
  }
}

Var::Var(const Var& other) {
  var_ = other.var_;
  if (NeedsRefcounting(var_) && other.needs_release_) {
    if (ppb_var_f) {
      needs_release_ = true;
      ppb_var_f->AddRef(var_);
    } else {
      var_.type = PP_VARTYPE_VOID;
      needs_release_ = false;
    }
  } else {
    needs_release_ = false;
  }
}

Var::~Var() {
  if (needs_release_ && ppb_var_f)
    ppb_var_f->Release(var_);
}

Var& Var::operator=(const Var& other) {
  // Use the copy constructor to make a copy, then swap into that. This makes
  // sure we call the correct init and destruct for everything, without actually
  // needing to write the refcounting code here.
  Var copy(other);
  swap(copy);
  return *this;
}

void Var::swap(Var& other) {
  std::swap(var_, other.var_);
  std::swap(needs_release_, other.needs_release_);
}

bool Var::AsBool() const {
  if (!is_bool()) {
    PP_NOTREACHED();
    return false;
  }
  return var_.value.as_bool;
}

int32_t Var::AsInt() const {
  if (is_int())
    return var_.value.as_int;
  if (is_double())
    return static_cast<int>(var_.value.as_double);
  PP_NOTREACHED();
  return 0;
}

double Var::AsDouble() const {
  if (is_double())
    return var_.value.as_double;
  if (is_int())
    return static_cast<double>(var_.value.as_int);
  PP_NOTREACHED();
  return 0.0;
}

std::string Var::AsString() const {
  if (!is_string()) {
    PP_NOTREACHED();
    return std::string();
  }

  if (!ppb_var_f)
    return std::string();
  uint32_t len;
  const char* str = ppb_var_f->VarToUtf8(var_, &len);
  return std::string(str, len);
}

bool Var::HasProperty(const Var& name, Var* exception) const {
  if (!ppb_var_f)
    return false;
  return ppb_var_f->HasProperty(var_, name.var_, OutException(exception));
}

Var Var::GetProperty(const Var& name, Var* exception) const {
  if (!ppb_var_f)
    return Var();
  return Var(PassRef(), ppb_var_f->GetProperty(var_, name.var_,
                                               OutException(exception)));
}

void Var::GetAllPropertyNames(std::vector<Var>* properties,
                              Var* exception) const {
  if (!ppb_var_f)
    return;
  PP_Var* props = NULL;
  uint32_t prop_count = 0;
  ppb_var_f->GetAllPropertyNames(var_, &prop_count, &props,
                                 OutException(exception));
  if (!prop_count)
    return;
  properties->resize(prop_count);
  for (uint32_t i = 0; i < prop_count; ++i) {
    Var temp(PassRef(), props[i]);
    (*properties)[i].swap(temp);
  }
  Module::Get()->core()->MemFree(props);
}

void Var::SetProperty(const Var& name, const Var& value, Var* exception) {
  if (!ppb_var_f)
    return;
  ppb_var_f->SetProperty(var_, name.var_, value.var_, OutException(exception));
}

void Var::RemoveProperty(const Var& name, Var* exception) {
  if (!ppb_var_f)
    return;
  ppb_var_f->RemoveProperty(var_, name.var_, OutException(exception));
}

Var Var::Call(const Var& method_name, uint32_t argc, Var* argv,
              Var* exception) {
  if (!ppb_var_f)
    return Var();
  if (argc > 0) {
    std::vector<PP_Var> args;
    args.reserve(argc);
    for (size_t i = 0; i < argc; i++)
      args.push_back(argv[i].var_);
    return Var(PassRef(), ppb_var_f->Call(var_, method_name.var_,
                                          argc, &args[0],
                                          OutException(exception)));
  } else {
    // Don't try to get the address of a vector if it's empty.
    return Var(PassRef(), ppb_var_f->Call(var_, method_name.var_, 0, NULL,
                                          OutException(exception)));
  }
}

Var Var::Construct(uint32_t argc, Var* argv, Var* exception) const {
  if (!ppb_var_f)
    return Var();
  if (argc > 0) {
    std::vector<PP_Var> args;
    args.reserve(argc);
    for (size_t i = 0; i < argc; i++)
      args.push_back(argv[i].var_);
    return Var(PassRef(), ppb_var_f->Construct(var_, argc, &args[0],
                                               OutException(exception)));
  } else {
    // Don't try to get the address of a vector if it's empty.
    return Var(PassRef(), ppb_var_f->Construct(var_, 0, NULL,
                                               OutException(exception)));
  }
}

Var Var::Call(const Var& method_name, const Var& arg1, Var* exception) {
  if (!ppb_var_f)
    return Var();
  PP_Var args[1] = {arg1.var_};
  return Var(PassRef(), ppb_var_f->Call(var_, method_name.var_, 1, args,
                                        OutException(exception)));
}

Var Var::Call(const Var& method_name, const Var& arg1, const Var& arg2,
              Var* exception) {
  if (!ppb_var_f)
    return Var();
  PP_Var args[2] = {arg1.var_, arg2.var_};
  return Var(PassRef(), ppb_var_f->Call(var_, method_name.var_, 2, args,
                                        OutException(exception)));
}

Var Var::Call(const Var& method_name, const Var& arg1, const Var& arg2,
              const Var& arg3, Var* exception) {
  if (!ppb_var_f)
    return Var();
  PP_Var args[3] = {arg1.var_, arg2.var_, arg3.var_};
  return Var(PassRef(), ppb_var_f->Call(var_, method_name.var_, 3, args,
                                        OutException(exception)));
}

Var Var::Call(const Var& method_name, const Var& arg1, const Var& arg2,
              const Var& arg3, const Var& arg4, Var* exception) {
  if (!ppb_var_f)
    return Var();
  PP_Var args[4] = {arg1.var_, arg2.var_, arg3.var_, arg4.var_};
  return Var(PassRef(), ppb_var_f->Call(var_, method_name.var_, 4, args,
                                        OutException(exception)));
}

std::string Var::DebugString() const {
  char buf[256];
  if (is_void())
    snprintf(buf, sizeof(buf), "Var<VOID>");
  else if (is_null())
    snprintf(buf, sizeof(buf), "Var<NULL>");
  else if (is_bool())
    snprintf(buf, sizeof(buf), AsBool() ? "Var<true>" : "Var<false>");
  else if (is_int())
    snprintf(buf, sizeof(buf), "Var<%"PRId32">", AsInt());
  else if (is_double())
    snprintf(buf, sizeof(buf), "Var<%f>", AsDouble());
  else if (is_string())
    snprintf(buf, sizeof(buf), "Var<'%s'>", AsString().c_str());
  else if (is_object())
    snprintf(buf, sizeof(buf), "Var<OBJECT>");
  return buf;
}

}  // namespace pp
<|endoftext|>


<commit_before><commit_msg>plugins: jsAPI: comment out debug messages in eventCallback<commit_after><|endoftext|>


<commit_before>/*
    This file is part of kdepim.

    Copyright (c) 2004 Till Adam <adam@kde.org>

    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <interfaces/bodypartformatter.h>
#include <interfaces/bodypart.h>
#include <interfaces/bodyparturlhandler.h>
#include <khtmlparthtmlwriter.h>

#include <kmail/callback.h>
#include <kmail/kmmessage.h>

#include <kglobal.h>
#include <klocale.h>
#include <kstringhandler.h>
#include <kglobalsettings.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kapplication.h>

#include <qurl.h>
#include <qfile.h>
#include <qdir.h>

namespace {
  class Formatter : public KMail::Interface::BodyPartFormatter {
  public:
    Result format( KMail::Interface::BodyPart *bodyPart, KMail::HtmlWriter *writer ) const {

      if ( !writer ) return Ok;

      const QString diff = bodyPart->asText();
      if ( diff.isEmpty() ) return AsIcon;

      QString addedLineStyle = QString::fromLatin1(
        "style=\""
        "padding-left: 4px; "
        "font-family: monospace; "
        //"border-right: #000 dashed 1px; "
        "color: green;\"");
      QString fileAddStyle( "style=\"font-weight: bold; font-family: monospace; color: green; \"" );

      QString removedLineStyle = QString::fromLatin1(
        "style=\""
        "padding-left: 4px; "
        "font-family: monospace; "
        "color: red;\"");
      QString fileRemoveStyle( "style=\"font-weight: bold; font-family: monospace; color: red ;\"" );

      QString tableStyle = QString::fromLatin1(
        "style=\""
        "border: dashed 1px; "
        "margin: 0em;\"");

      QString sepStyle( "style=\"color: black; font-weight: bold; font-family: monospace; \"" );
      QString chunkStyle( "style=\"color: blue; font-family: monospace;  \"" );

      QString regularStyle( "style=\"font-family: monospace;\"" );

      QString html = "

";
      html += "
";

      QStringList lines = QStringList::split( '\n', diff, true );
      for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) {
        QString line( *it );
        QString style;
        if ( line.length() > 0 ) {
          if ( line.startsWith( "+++" ) ) {
            style = fileAddStyle;
          } else if ( line.startsWith( "---" ) ) {
            style = fileRemoveStyle;
          } else if ( line.startsWith( "+" ) || line.startsWith( ">" ) ) {
            style = addedLineStyle;
          } else if ( line.startsWith( "-" ) || line.startsWith( "<" ) ) {
            style = removedLineStyle;
          } else if ( line.startsWith( "==") ) {
            style = sepStyle;
          } else if ( line.startsWith( "@@" ) ) {
            style = chunkStyle;
          } else {
            style = regularStyle;
          }
        }
        html += "
" + line + "
";
      }

      html += "

";
      writer->queue( html );

      return Ok;
    }
  };

  class Plugin : public KMail::Interface::BodyPartFormatterPlugin {
  public:
    const KMail::Interface::BodyPartFormatter * bodyPartFormatter( int idx ) const {
      return idx == 0 ? new Formatter() : 0 ;
    }
    const char * type( int idx ) const {
      return idx == 0 ? "text" : 0 ;
    }
    const char * subtype( int idx ) const {
      return idx == 0 ? "x-diff" : 0 ;
    }

    const KMail::Interface::BodyPartURLHandler * urlHandler( int ) const { return 0; }
  };

}

extern "C"
KMail::Interface::BodyPartFormatterPlugin *
libkmail_bodypartformatter_text_xdiff_create_bodypart_formatter_plugin() {
  return new Plugin();
}
<commit_msg>Quote strings that are used in html.<commit_after>/*
    This file is part of kdepim.

    Copyright (c) 2004 Till Adam <adam@kde.org>

    This program is free software; you can redistribute it and/or modify it
    under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program 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
    General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

    In addition, as a special exception, the copyright holders give
    permission to link the code of this program with any edition of
    the Qt library by Trolltech AS, Norway (or with modified versions
    of Qt that use the same license as Qt), and distribute linked
    combinations including the two.  You must obey the GNU General
    Public License in all respects for all of the code used other than
    Qt.  If you modify this file, you may extend this exception to
    your version of the file, but you are not obligated to do so.  If
    you do not wish to do so, delete this exception statement from
    your version.
*/

#include <interfaces/bodypartformatter.h>
#include <interfaces/bodypart.h>
#include <interfaces/bodyparturlhandler.h>
#include <khtmlparthtmlwriter.h>

#include <kmail/callback.h>
#include <kmail/kmmessage.h>

#include <kglobal.h>
#include <klocale.h>
#include <kstringhandler.h>
#include <kglobalsettings.h>
#include <kiconloader.h>
#include <kdebug.h>
#include <kmessagebox.h>
#include <kstandarddirs.h>
#include <kapplication.h>

#include <qurl.h>
#include <qfile.h>
#include <qdir.h>
#include <qstylesheet.h>

namespace {
  class Formatter : public KMail::Interface::BodyPartFormatter {
  public:
    Result format( KMail::Interface::BodyPart *bodyPart, KMail::HtmlWriter *writer ) const {

      if ( !writer ) return Ok;

      const QString diff = bodyPart->asText();
      if ( diff.isEmpty() ) return AsIcon;

      QString addedLineStyle = QString::fromLatin1(
        "style=\""
        "padding-left: 4px; "
        "font-family: monospace; "
        //"border-right: #000 dashed 1px; "
        "color: green;\"");
      QString fileAddStyle( "style=\"font-weight: bold; font-family: monospace; color: green; \"" );

      QString removedLineStyle = QString::fromLatin1(
        "style=\""
        "padding-left: 4px; "
        "font-family: monospace; "
        "color: red;\"");
      QString fileRemoveStyle( "style=\"font-weight: bold; font-family: monospace; color: red ;\"" );

      QString tableStyle = QString::fromLatin1(
        "style=\""
        "border: dashed 1px; "
        "margin: 0em;\"");

      QString sepStyle( "style=\"color: black; font-weight: bold; font-family: monospace; \"" );
      QString chunkStyle( "style=\"color: blue; font-family: monospace;  \"" );

      QString regularStyle( "style=\"font-family: monospace;\"" );

      QString html = "

";
      html += "
";

      QStringList lines = QStringList::split( '\n', diff, true );
      for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it ) {
        QString line( QStyleSheet::escape( *it ) );
        QString style;
        if ( line.length() > 0 ) {
          if ( line.startsWith( "+++" ) ) {
            style = fileAddStyle;
          } else if ( line.startsWith( "---" ) ) {
            style = fileRemoveStyle;
          } else if ( line.startsWith( "+" ) || line.startsWith( ">" ) ) {
            style = addedLineStyle;
          } else if ( line.startsWith( "-" ) || line.startsWith( "<" ) ) {
            style = removedLineStyle;
          } else if ( line.startsWith( "==") ) {
            style = sepStyle;
          } else if ( line.startsWith( "@@" ) ) {
            style = chunkStyle;
          } else {
            style = regularStyle;
          }
        }
        html += "
" + line + "
";
      }

      html += "

";
      writer->queue( html );

      return Ok;
    }
  };

  class Plugin : public KMail::Interface::BodyPartFormatterPlugin {
  public:
    const KMail::Interface::BodyPartFormatter * bodyPartFormatter( int idx ) const {
      return idx == 0 ? new Formatter() : 0 ;
    }
    const char * type( int idx ) const {
      return idx == 0 ? "text" : 0 ;
    }
    const char * subtype( int idx ) const {
      return idx == 0 ? "x-diff" : 0 ;
    }

    const KMail::Interface::BodyPartURLHandler * urlHandler( int ) const { return 0; }
  };

}

extern "C"
KMail::Interface::BodyPartFormatterPlugin *
libkmail_bodypartformatter_text_xdiff_create_bodypart_formatter_plugin() {
  return new Plugin();
}
<|endoftext|>


<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.2  1999/11/17 22:36:41  rahulj
 * Code works with ICU transcoding service
 *
 * Revision 1.1.1.1  1999/11/09 01:06:07  twl
 * Initial checkin
 *
 * Revision 1.3  1999/11/08 20:45:33  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <util/TranscodingException.hpp>
#include "ICUTransService.hpp"
#include <string.h>
#include <uloc.h>
#include <unicode.h>
#include <ucnv.h>
#include <ustring.h>

// ---------------------------------------------------------------------------
//  ICUTransService: Public, static methods
// ---------------------------------------------------------------------------
void ICUTransService::setICUPath(const char* const pathToSet)
{
    uloc_setDataDirectory(pathToSet);
}

// ---------------------------------------------------------------------------
//  ICUTransService: Constructors and Destructor
// ---------------------------------------------------------------------------
ICUTransService::ICUTransService()
{
}

ICUTransService::~ICUTransService()
{
}

// ---------------------------------------------------------------------------
//  ICUTransService: The virtual transcoding service API
// ---------------------------------------------------------------------------
int ICUTransService::compareIString(const   XMLCh* const    comp1
                                    , const XMLCh* const    comp2)
{
    const XMLCh* psz1 = comp1;
    const XMLCh* psz2 = comp2;

    unsigned int curCount = 0;
    while (true)
    {
        // If an inequality, then return the difference
        if (Unicode::toUpperCase(*psz1) != Unicode::toUpperCase(*psz2))
            return int(*psz1) - int(*psz2);

        // If either has ended, then they both ended, so equal
        if (!*psz1 || !*psz2)
            break;

        // Move upwards for the next round
        psz1++;
        psz2++;
    }
    return 0;
}

int ICUTransService::compareNIString(const  XMLCh* const    comp1
                                    , const XMLCh* const    comp2
                                    , const unsigned int    maxChars)
{
    const XMLCh* psz1 = comp1;
    const XMLCh* psz2 = comp2;

    unsigned int curCount = 0;
    while (true)
    {
        // If an inequality, then return difference
        if (Unicode::toUpperCase(*psz1) != Unicode::toUpperCase(*psz2))
            return int(*psz1) - int(*psz2);

        // If either ended, then both ended, so equal
        if (!*psz1 || !*psz2)
            break;

        // Move upwards to next chars
        psz1++;
        psz2++;

        //
        //  Bump the count of chars done. If it equals the count then we
        //  are equal for the requested count, so break out and return
        //  equal.
        //
        curCount++;
        if (maxChars == curCount)
            break;
    }
    return 0;
}

bool ICUTransService::isSpace(const XMLCh toCheck) const
{
    return (Unicode::isSpaceChar(toCheck) != 0);
}

XMLTranscoder* ICUTransService::makeNewDefTranscoder()
{
    //
    //  Try to create a default converter. If it fails, return a null pointer
    //  which will basically cause the system to give up because we really can't
    //  do anything without one.
    //
    UErrorCode uerr = U_ZERO_ERROR;
    UConverter* converter = ucnv_open(NULL, &uerr);
    if (!converter)
        return 0;

    // That went ok, so create an ICU transcoder wrapper and return it
    return new ICUTranscoder(converter, 0);
}

XMLTranscoder*
ICUTransService::makeNewTranscoderFor(  const   XMLCh* const            encodingName
                                        ,       XMLTransService::Codes& resValue
                                        , const unsigned int            blockSize)
{
    UErrorCode uerr = U_ZERO_ERROR;
    UConverter* converter = ucnv_openU(encodingName, &uerr);
    if (!converter)
    {
        resValue = XMLTransService::UnsupportedEncoding;
        return 0;
    }
    return new ICUTranscoder(converter, blockSize);
}

// ---------------------------------------------------------------------------
//  ICUTranscoder: Constructors and Destructor
// ---------------------------------------------------------------------------
ICUTranscoder::ICUTranscoder(       UConverter* const   toAdopt
                            , const unsigned int        blockSize) :
    fCharOfsBuf(0)
    , fConverter(toAdopt)
{
    // There won't be a block size if this is for a default transcoder
    if (blockSize)
        fCharOfsBuf = new long[blockSize];
}

ICUTranscoder::~ICUTranscoder()
{
    delete [] fCharOfsBuf;

    // If there is a converter, ask ICU to clean it up
    if (fConverter)
    {
        // <TBD> Does this actually delete the structure???
        ucnv_close(fConverter);
        fConverter = 0;
    }
}

// ---------------------------------------------------------------------------
//  ICUTranscoder: The virtual transcoder API
// ---------------------------------------------------------------------------
unsigned int ICUTranscoder::calcRequiredSize(const XMLCh* const srcText)
{
    if (!srcText)
        return 0;

    XMLMutexLock lockConverter(&fMutex);

    UErrorCode err = U_ZERO_ERROR;
    const int32_t targetCap = ucnv_fromUChars
    (
        fConverter
        , 0
        , 0
        , srcText
        , &err
    );

    if (err != U_BUFFER_OVERFLOW_ERROR)
        return 0;

    return (unsigned int)targetCap;
}

unsigned int ICUTranscoder::calcRequiredSize(const char* const srcText)
{
    if (!srcText)
        return 0;

    XMLMutexLock lockConverter(&fMutex);

    UErrorCode err = U_ZERO_ERROR;
    const int32_t targetCap = ucnv_toUChars
    (
        fConverter
        , 0
        , 0
        , srcText
        , strlen(srcText)
        , &err
    );

    if (err != U_BUFFER_OVERFLOW_ERROR)
        return 0;

    // Subtract one since it includes the terminator space
    return (unsigned int)(targetCap - 1);
}

XMLCh ICUTranscoder::transcodeOne(  const   char* const     srcData
                                    , const unsigned int    srcBytes
                                    ,       unsigned int&   bytesEaten)
{
    // Check for stupid stuff
    if (!srcBytes)
        return 0;

    XMLMutexLock lockConverter(&fMutex);

    UErrorCode err = U_ZERO_ERROR;
    const char* startSrc = srcData;
    const XMLCh chRet = ucnv_getNextUChar
    (
        fConverter
        , &startSrc
        , (srcData + srcBytes) - 1
        , &err
    );

    // Bail out if an error
    if (U_FAILURE(err))
        return 0;

    // Calculate the bytes eaten and return the char
    bytesEaten = startSrc - srcData;
    return chRet;
}

char* ICUTranscoder::transcode(const XMLCh* const toTranscode)
{
    char* retBuf = 0;

    // Check for a couple of special cases
    if (!toTranscode)
        return 0;

    if (!*toTranscode)
    {
        retBuf = new char[1];
        retBuf[0] = 0;
        return retBuf;
    }

    XMLMutexLock lockConverter(&fMutex);

    // Caculate a return buffer size not too big, but less likely to overflow
    int32_t targetLen = (int32_t)(u_strlen(toTranscode) * 1.25);

    // Allocate the return buffer
    retBuf = new char[targetLen + 1];

    //Convert the Unicode string to char* using Intl stuff
    UErrorCode err = U_ZERO_ERROR;
    int32_t targetCap = ucnv_fromUChars
    (
        fConverter
        , retBuf
        , targetLen + 1
        , toTranscode
        , &err
    );

    // If targetLen is not enough then buffer overflow might occur
    if (err == U_BUFFER_OVERFLOW_ERROR)
    {
        // Reset the error, delete the old buffer, allocate a new one, and try again
        err = U_ZERO_ERROR;
        delete [] retBuf;
        retBuf = new char[targetCap];
        targetCap = ucnv_fromUChars(fConverter, retBuf, targetCap, toTranscode, &err);
    }

    if (U_FAILURE(err))
    {
        delete [] retBuf;
        return 0;
    }

    // Cap it off and return
    retBuf[targetCap] = 0;
    return retBuf;
}

bool ICUTranscoder::transcode(  const   XMLCh* const    toTranscode
                                ,       char* const     toFill
                                , const unsigned int    maxChars)
{
    // Watch for a few psycho corner cases
    if (!toTranscode || !maxChars)
    {
        toFill[0] = 0;
        return true;
    }

    if (!*toTranscode)
    {
        toFill[0] = 0;
        return true;
    }

    XMLMutexLock lockConverter(&fMutex);

    UErrorCode err = U_ZERO_ERROR;
    int32_t targetCap;
    targetCap = ucnv_fromUChars(fConverter, toFill, maxChars + 1, toTranscode, &err);

    if (U_FAILURE(err))
        return false;

    return true;
}

XMLCh* ICUTranscoder::transcode(const char* const toTranscode)
{
    // Watch for a few pyscho corner cases
    if (!toTranscode)
        return 0;

    XMLCh* retVal = 0;
    if (!*toTranscode)
    {
        retVal = new XMLCh[1];
        retVal[0] = 0;
        return retVal;
    }

    XMLMutexLock lockConverter(&fMutex);

    //
    //  Get the length of the string to transcode. The Unicode string will
    //  almost always be no more chars than were in the source, so this is
    //  the best guess as to the storage needed.
    //
    const int32_t srcLen = (int32_t)strlen(toTranscode);

    //
    //  Here we don't know what the target length will be so use 0 and expect
    //  an BUFFER_OVERFLOW_ERROR in which case it'd get resolved by the
    //  correct capacity value.
    //
    UErrorCode err = U_ZERO_ERROR;
    int32_t targetCap;
    targetCap = ucnv_toUChars
    (
        fConverter
        , 0
        , 0
        , toTranscode
        , srcLen
        , &err
    );

    if (err != U_BUFFER_OVERFLOW_ERROR)
        return 0;

    err = U_ZERO_ERROR;
    retVal = new XMLCh[targetCap];
    ucnv_toUChars
    (
        fConverter
        , retVal
        , targetCap
        , toTranscode
        , srcLen
        , &err
    );

    if (U_FAILURE(err))
        return 0;

    return retVal;
}

bool ICUTranscoder::transcode(  const   char* const     toTranscode
                                ,       XMLCh* const    toFill
                                , const unsigned int    maxChars)
{
    // Check for a couple of psycho corner cases
    if (!toTranscode || !maxChars)
    {
        toFill[0] = 0;
        return true;
    }

    if (!*toTranscode)
    {
        toFill[0] = 0;
        return true;
    }

    XMLMutexLock lockConverter(&fMutex);

    UErrorCode err = U_ZERO_ERROR;
    const int32_t srcLen = (int32_t)strlen(toTranscode);

    ucnv_toUChars
    (
        fConverter
        , toFill
        , maxChars + 1
        , toTranscode
        , srcLen
        , &err
    );

    if (U_FAILURE(err))
        return false;
    return true;
}

unsigned int
ICUTranscoder::transcodeXML(const   char* const             srcData
                            , const unsigned int            srcCount
                            ,       XMLCh* const            toFill
                            , const unsigned int            maxChars
                            ,       unsigned int&           bytesEaten)
{
    //
    //  If the input encoding uses fixed size characters, we can use a
    //  simpler, faster approach to computing the character sizes to be
    //  returned in the charSizes array.
    //
    const int   maxCharSize = ucnv_getMaxCharSize(fConverter);
    const int   minCharSize = ucnv_getMinCharSize(fConverter);

    //
    //  Set up pointers to the source and destination buffers.
    //
    UChar*          startTarget = toFill;
    const char*     startSrc = srcData;
    const char*     endSrc = srcData + srcCount;

    //
    //  Transoode the buffer.  Buffer overflow errors are normal, occuring
    //  when the raw input buffer holds more characters than will fit
    //  in the Unicode output buffer.
    //
    UErrorCode  err = U_ZERO_ERROR;
    ucnv_toUnicode
    (
        fConverter
        , &startTarget
        , toFill + maxChars
        , &startSrc
        , endSrc
        , 0
        , false
        , &err
    );

    if ((err != U_ZERO_ERROR) && (err != U_INDEX_OUTOFBOUNDS_ERROR))
        ThrowXML(TranscodingException, XML4CExcepts::Trans_CouldNotXCodeXMLData);

    // Calculate the bytes eaten and store in caller's param
    bytesEaten = startSrc - srcData;

    // Return the chars we put into the target buffer
    return  startTarget - toFill;
}
<commit_msg>Now works with ICU 1.3.1<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 1999 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xerces" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache\@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED 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 APACHE SOFTWARE FOUNDATION OR
 * ITS 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.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation, and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com .  For more information
 * on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

/**
 * $Log$
 * Revision 1.3  1999/11/18 20:16:52  abagchi
 * Now works with ICU 1.3.1
 *
 * Revision 1.2  1999/11/17 22:36:41  rahulj
 * Code works with ICU transcoding service
 *
 * Revision 1.1.1.1  1999/11/09 01:06:07  twl
 * Initial checkin
 *
 * Revision 1.3  1999/11/08 20:45:33  rahul
 * Swat for adding in Product name and CVS comment log variable.
 *
 */

// ---------------------------------------------------------------------------
//  Includes
// ---------------------------------------------------------------------------
#include <util/TranscodingException.hpp>
#include "ICUTransService.hpp"
#include <string.h>
#include <uloc.h>
#include <unicode.h>
#include <ucnv.h>
#include <ustring.h>

// ---------------------------------------------------------------------------
//  ICUTransService: Public, static methods
// ---------------------------------------------------------------------------
void ICUTransService::setICUPath(const char* const pathToSet)
{
    uloc_setDataDirectory(pathToSet);
}

// ---------------------------------------------------------------------------
//  ICUTransService: Constructors and Destructor
// ---------------------------------------------------------------------------
ICUTransService::ICUTransService()
{
}

ICUTransService::~ICUTransService()
{
}

// ---------------------------------------------------------------------------
//  ICUTransService: The virtual transcoding service API
// ---------------------------------------------------------------------------
int ICUTransService::compareIString(const   XMLCh* const    comp1
                                    , const XMLCh* const    comp2)
{
    const XMLCh* psz1 = comp1;
    const XMLCh* psz2 = comp2;

    unsigned int curCount = 0;
    while (true)
    {
        // If an inequality, then return the difference
        if (Unicode::toUpperCase(*psz1) != Unicode::toUpperCase(*psz2))
            return int(*psz1) - int(*psz2);

        // If either has ended, then they both ended, so equal
        if (!*psz1 || !*psz2)
            break;

        // Move upwards for the next round
        psz1++;
        psz2++;
    }
    return 0;
}

int ICUTransService::compareNIString(const  XMLCh* const    comp1
                                    , const XMLCh* const    comp2
                                    , const unsigned int    maxChars)
{
    const XMLCh* psz1 = comp1;
    const XMLCh* psz2 = comp2;

    unsigned int curCount = 0;
    while (true)
    {
        // If an inequality, then return difference
        if (Unicode::toUpperCase(*psz1) != Unicode::toUpperCase(*psz2))
            return int(*psz1) - int(*psz2);

        // If either ended, then both ended, so equal
        if (!*psz1 || !*psz2)
            break;

        // Move upwards to next chars
        psz1++;
        psz2++;

        //
        //  Bump the count of chars done. If it equals the count then we
        //  are equal for the requested count, so break out and return
        //  equal.
        //
        curCount++;
        if (maxChars == curCount)
            break;
    }
    return 0;
}

bool ICUTransService::isSpace(const XMLCh toCheck) const
{
    return (Unicode::isSpaceChar(toCheck) != 0);
}

XMLTranscoder* ICUTransService::makeNewDefTranscoder()
{
    //
    //  Try to create a default converter. If it fails, return a null pointer
    //  which will basically cause the system to give up because we really can't
    //  do anything without one.
    //
    UErrorCode uerr = U_ZERO_ERROR;
    UConverter* converter = ucnv_open(NULL, &uerr);
    if (!converter)
        return 0;

    // That went ok, so create an ICU transcoder wrapper and return it
    return new ICUTranscoder(converter, 0);
}

XMLTranscoder*
ICUTransService::makeNewTranscoderFor(  const   XMLCh* const            encodingName
                                        ,       XMLTransService::Codes& resValue
                                        , const unsigned int            blockSize)
{
    UErrorCode uerr = U_ZERO_ERROR;
    UConverter* converter = ucnv_openU(encodingName, &uerr);
    if (!converter)
    {
        resValue = XMLTransService::UnsupportedEncoding;
        return 0;
    }
    return new ICUTranscoder(converter, blockSize);
}

// ---------------------------------------------------------------------------
//  ICUTranscoder: Constructors and Destructor
// ---------------------------------------------------------------------------
ICUTranscoder::ICUTranscoder(       UConverter* const   toAdopt
                            , const unsigned int        blockSize) :
    fCharOfsBuf(0)
    , fConverter(toAdopt)
{
    // There won't be a block size if this is for a default transcoder
    if (blockSize)
        fCharOfsBuf = new long[blockSize];
}

ICUTranscoder::~ICUTranscoder()
{
    delete [] fCharOfsBuf;

    // If there is a converter, ask ICU to clean it up
    if (fConverter)
    {
        // <TBD> Does this actually delete the structure???
        ucnv_close(fConverter);
        fConverter = 0;
    }
}

// ---------------------------------------------------------------------------
//  ICUTranscoder: The virtual transcoder API
// ---------------------------------------------------------------------------
unsigned int ICUTranscoder::calcRequiredSize(const XMLCh* const srcText)
{
    if (!srcText)
        return 0;

    XMLMutexLock lockConverter(&fMutex);

    UErrorCode err = U_ZERO_ERROR;
    const int32_t targetCap = ucnv_fromUChars
    (
        fConverter
        , 0
        , 0
        , srcText
        , &err
    );

    if (err != U_BUFFER_OVERFLOW_ERROR)
        return 0;

    return (unsigned int)targetCap;
}

unsigned int ICUTranscoder::calcRequiredSize(const char* const srcText)
{
    if (!srcText)
        return 0;

    XMLMutexLock lockConverter(&fMutex);

    UErrorCode err = U_ZERO_ERROR;
    const int32_t targetCap = ucnv_toUChars
    (
        fConverter
        , 0
        , 0
        , srcText
        , strlen(srcText)
        , &err
    );

    if (err != U_BUFFER_OVERFLOW_ERROR)
        return 0;

    // Subtract one since it includes the terminator space
    return (unsigned int)(targetCap - 1);
}

XMLCh ICUTranscoder::transcodeOne(  const   char* const     srcData
                                    , const unsigned int    srcBytes
                                    ,       unsigned int&   bytesEaten)
{
    // Check for stupid stuff
    if (!srcBytes)
        return 0;

    XMLMutexLock lockConverter(&fMutex);

    UErrorCode err = U_ZERO_ERROR;
    const char* startSrc = srcData;
    const XMLCh chRet = ucnv_getNextUChar
    (
        fConverter
        , &startSrc
        , (srcData + srcBytes) - 1
        , &err
    );

    // Bail out if an error
    if (U_FAILURE(err))
        return 0;

    // Calculate the bytes eaten and return the char
    bytesEaten = startSrc - srcData;
    return chRet;
}

char* ICUTranscoder::transcode(const XMLCh* const toTranscode)
{
    char* retBuf = 0;

    // Check for a couple of special cases
    if (!toTranscode)
        return 0;

    if (!*toTranscode)
    {
        retBuf = new char[1];
        retBuf[0] = 0;
        return retBuf;
    }

    XMLMutexLock lockConverter(&fMutex);

    // Caculate a return buffer size not too big, but less likely to overflow
    int32_t targetLen = (int32_t)(u_strlen(toTranscode) * 1.25);

    // Allocate the return buffer
    retBuf = new char[targetLen + 1];

    //Convert the Unicode string to char* using Intl stuff
    UErrorCode err = U_ZERO_ERROR;
    int32_t targetCap = ucnv_fromUChars
    (
        fConverter
        , retBuf
        , targetLen + 1
        , toTranscode
        , &err
    );

    // If targetLen is not enough then buffer overflow might occur
    if (err == U_BUFFER_OVERFLOW_ERROR)
    {
        // Reset the error, delete the old buffer, allocate a new one, and try again
        err = U_ZERO_ERROR;
        delete [] retBuf;
        retBuf = new char[targetCap];
        targetCap = ucnv_fromUChars(fConverter, retBuf, targetCap, toTranscode, &err);
    }

    if (U_FAILURE(err))
    {
        delete [] retBuf;
        return 0;
    }

    // Cap it off and return
    retBuf[targetCap] = 0;
    return retBuf;
}

bool ICUTranscoder::transcode(  const   XMLCh* const    toTranscode
                                ,       char* const     toFill
                                , const unsigned int    maxChars)
{
    // Watch for a few psycho corner cases
    if (!toTranscode || !maxChars)
    {
        toFill[0] = 0;
        return true;
    }

    if (!*toTranscode)
    {
        toFill[0] = 0;
        return true;
    }

    XMLMutexLock lockConverter(&fMutex);

    UErrorCode err = U_ZERO_ERROR;
    int32_t targetCap;
    targetCap = ucnv_fromUChars(fConverter, toFill, maxChars + 1, toTranscode, &err);

    if (U_FAILURE(err))
        return false;

    return true;
}

XMLCh* ICUTranscoder::transcode(const char* const toTranscode)
{
    // Watch for a few pyscho corner cases
    if (!toTranscode)
        return 0;

    XMLCh* retVal = 0;
    if (!*toTranscode)
    {
        retVal = new XMLCh[1];
        retVal[0] = 0;
        return retVal;
    }

    XMLMutexLock lockConverter(&fMutex);

    //
    //  Get the length of the string to transcode. The Unicode string will
    //  almost always be no more chars than were in the source, so this is
    //  the best guess as to the storage needed.
    //
    const int32_t srcLen = (int32_t)strlen(toTranscode);

    //
    //  Here we don't know what the target length will be so use 0 and expect
    //  an U_BUFFER_OVERFLOW_ERROR in which case it'd get resolved by the
    //  correct capacity value.
    //
    UErrorCode err = U_ZERO_ERROR;
    int32_t targetCap;
    targetCap = ucnv_toUChars
    (
        fConverter
        , 0
        , 0
        , toTranscode
        , srcLen
        , &err
    );

    if (err != U_BUFFER_OVERFLOW_ERROR)
        return 0;

    err = U_ZERO_ERROR;
    retVal = new XMLCh[targetCap];
    ucnv_toUChars
    (
        fConverter
        , retVal
        , targetCap
        , toTranscode
        , srcLen
        , &err
    );

    if (U_FAILURE(err))
        return 0;

    return retVal;
}

bool ICUTranscoder::transcode(  const   char* const     toTranscode
                                ,       XMLCh* const    toFill
                                , const unsigned int    maxChars)
{
    // Check for a couple of psycho corner cases
    if (!toTranscode || !maxChars)
    {
        toFill[0] = 0;
        return true;
    }

    if (!*toTranscode)
    {
        toFill[0] = 0;
        return true;
    }

    XMLMutexLock lockConverter(&fMutex);

    UErrorCode err = U_ZERO_ERROR;
    const int32_t srcLen = (int32_t)strlen(toTranscode);

    ucnv_toUChars
    (
        fConverter
        , toFill
        , maxChars + 1
        , toTranscode
        , srcLen
        , &err
    );

    if (U_FAILURE(err))
        return false;
    return true;
}

unsigned int
ICUTranscoder::transcodeXML(const   char* const             srcData
                            , const unsigned int            srcCount
                            ,       XMLCh* const            toFill
                            , const unsigned int            maxChars
                            ,       unsigned int&           bytesEaten)
{
    //
    //  If the input encoding uses fixed size characters, we can use a
    //  simpler, faster approach to computing the character sizes to be
    //  returned in the charSizes array.
    //
    const int   maxCharSize = ucnv_getMaxCharSize(fConverter);
    const int   minCharSize = ucnv_getMinCharSize(fConverter);

    //
    //  Set up pointers to the source and destination buffers.
    //
    UChar*          startTarget = toFill;
    const char*     startSrc = srcData;
    const char*     endSrc = srcData + srcCount;

    //
    //  Transoode the buffer.  Buffer overflow errors are normal, occuring
    //  when the raw input buffer holds more characters than will fit
    //  in the Unicode output buffer.
    //
    UErrorCode  err = U_ZERO_ERROR;
    ucnv_toUnicode
    (
        fConverter
        , &startTarget
        , toFill + maxChars
        , &startSrc
        , endSrc
        , 0
        , false
        , &err
    );

    if ((err != U_ZERO_ERROR) && (err != U_INDEX_OUTOFBOUNDS_ERROR))
        ThrowXML(TranscodingException, XML4CExcepts::Trans_CouldNotXCodeXMLData);

    // Calculate the bytes eaten and store in caller's param
    bytesEaten = startSrc - srcData;

    // Return the chars we put into the target buffer
    return  startTarget - toFill;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include <base/parse_object.h>
#include <ifmap/ifmap_link.h>
#include <ifmap/ifmap_table.h>
#include <vnc_cfg_types.h>

#include <cmn/agent_cmn.h>
#include <cmn/agent.h>
#include <init/agent_param.h>
#include <cmn/agent_db.h>

#include <cfg/cfg_init.h>
#include <cfg/cfg_interface_listener.h>
#include <cfg/cfg_interface.h>

#include <oper/agent_types.h>
#include <oper/interface_common.h>
#include <oper/vm.h>
#include <oper/vn.h>
#include <oper/mirror_table.h>
#include <oper/config_manager.h>

using namespace std;
using namespace boost::uuids;
using namespace autogen;

void InterfaceCfgClient::Notify(DBTablePartBase *partition, DBEntryBase *e) {
    CfgIntEntry *entry = static_cast<CfgIntEntry *>(e);
    Agent *agent = Agent::GetInstance();

    if (entry->IsDeleted()) {
        VmInterface::Delete(agent->interface_table(),
                             entry->GetUuid(), VmInterface::INSTANCE_MSG);
    } else {
        uint16_t tx_vlan_id = VmInterface::kInvalidVlanId;
        uint16_t rx_vlan_id = VmInterface::kInvalidVlanId;
        string port = Agent::NullString();
        Interface::Transport transport = Interface::TRANSPORT_ETHERNET;
        if (agent->params()->isVmwareMode()) {
            tx_vlan_id = entry->tx_vlan_id();
            rx_vlan_id = entry->rx_vlan_id();
            port = agent->params()->vmware_physical_port();
            transport = Interface::TRANSPORT_VIRTUAL;
        }
        if (agent->vrouter_on_nic_mode() == true ||
            agent->vrouter_on_host_dpdk() == true) {
            transport = Interface::TRANSPORT_PMD;
        }

        VmInterface::NovaAdd(agent->interface_table(), entry->GetUuid(),
                             entry->GetIfname(), entry->ip_addr().to_v4(),
                             entry->GetMacAddr(), entry->vm_name(),
                             entry->vm_project_uuid(), tx_vlan_id, rx_vlan_id,
                             port, entry->ip6_addr(), transport);
        FetchInterfaceData(entry->GetUuid());
    }
}

void InterfaceCfgClient::FetchInterfaceData(const uuid if_uuid) const {
    IFMapNode *node = UuidToIFNode(if_uuid);
    if (node != NULL) {

        DBRequest req;
        req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
        if (agent_cfg_->agent()->interface_table()->IFNodeToReq(node,
                    req, const_cast<uuid&>(if_uuid))) {
            agent_cfg_->agent()->interface_table()->Enqueue(&req);
        }
    }
}

void InterfaceCfgClient::RouteTableNotify(DBTablePartBase *partition,
                                          DBEntryBase *e) {
    IFMapNode *node = static_cast<IFMapNode *>(e);
    if (node->IsDeleted()) {
       return;
    }

    //Trigger change on all interface entries
    IFMapAgentTable *table = static_cast<IFMapAgentTable *>(node->table());
    for (DBGraphVertex::adjacency_iterator iter =
         node->begin(table->GetGraph());
         iter != node->end(table->GetGraph()); ++iter) {
        if (iter->IsDeleted()) {
            continue;
        }
        IFMapNode *adj_node = static_cast<IFMapNode *>(iter.operator->());
        if (Agent::GetInstance()->config_manager()->SkipNode(adj_node)) {
            continue;
        }

        if (adj_node->table() ==
            Agent::GetInstance()->cfg()->cfg_vm_interface_table()) {
            DBRequest req;
            req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
            boost::uuids::uuid id;
            agent_cfg_->agent()->interface_table()->IFNodeToUuid(adj_node, id);
            if (agent_cfg_->agent()->interface_table()->IFNodeToReq(adj_node,
                                                                     req, id)) {
                agent_cfg_->agent()->interface_table()->Enqueue(&req);
            }
        }
    }
}

void InterfaceCfgClient::CfgNotify(DBTablePartBase *partition, DBEntryBase *e) {
    IFMapNode *node = static_cast<IFMapNode *>(e);
    CfgState *state = static_cast<CfgState *>(e->GetState(partition->parent(), cfg_listener_id_));

    if (node->IsDeleted()) {
        if (state) {
            VirtualMachineInterface *cfg =
                static_cast <VirtualMachineInterface *> (node->GetObject());
            assert(cfg);
            autogen::IdPermsType id_perms = cfg->id_perms();
            boost::uuids::uuid u;
            CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u);
            uuid_ifnode_tree_.erase(u);
            node->ClearState(partition->parent(), cfg_listener_id_);
            delete state;
        }
    } else {
        VirtualMachineInterface *cfg =
            static_cast <VirtualMachineInterface *> (node->GetObject());
        if (cfg == NULL) {
            return;
        }
        autogen::IdPermsType id_perms = cfg->id_perms();
        boost::uuids::uuid u;
        CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u);
        // We have observed that control node gives a node withoug uuid first
        // followed by subsequent changes that give uuid.
        // Ignore if UUID is not yet present
        if (u == nil_uuid()) {
            return;
        }

        if (state == NULL) {
            uuid_ifnode_tree_.insert(UuidIFNodePair(u, node));
            state = new CfgState();
            state->seen_ = true;
            node->SetState(partition->parent(), cfg_listener_id_, state);
        }
    }
}

IFMapNode *InterfaceCfgClient::UuidToIFNode(const uuid &u) const {
    UuidToIFNodeTree::const_iterator it;

    it = uuid_ifnode_tree_.find(u);
    if (it == uuid_ifnode_tree_.end()) {
        return NULL;
    }

    return it->second;
}

void InterfaceCfgClient::Init() {
    DBTableBase *table = agent_cfg_->agent()->interface_config_table();
    table->Register(boost::bind(&InterfaceCfgClient::Notify, this, _1, _2));

    // Register with config DB table for vm-port UUID to IFNode mapping
    DBTableBase *cfg_db = IFMapTable::FindTable(agent_cfg_->agent()->db(),
                                                "virtual-machine-interface");
    assert(cfg_db);
    cfg_listener_id_ = cfg_db->Register
        (boost::bind(&InterfaceCfgClient::CfgNotify, this, _1, _2));

    // Register with config DB table for static route table changes
    DBTableBase *cfg_route_db = IFMapTable::FindTable(agent_cfg_->agent()->db(),
                                                      "interface-route-table");
    assert(cfg_route_db);
    cfg_route_table_listener_id_ = cfg_route_db->Register
        (boost::bind(&InterfaceCfgClient::RouteTableNotify, this, _1, _2));
}

void InterfaceCfgClient::Shutdown() {
    IFMapTable *cfg_db = IFMapTable::FindTable(agent_cfg_->agent()->db(),
                                                "virtual-machine-interface");
    DBTable::DBStateClear(cfg_db, cfg_listener_id_);
    cfg_db->Unregister(cfg_listener_id_);

    DBTableBase *cfg_route_db = IFMapTable::FindTable(agent_cfg_->agent()->db(),
                                                      "interface-route-table");
    cfg_route_db->Unregister(cfg_route_table_listener_id_);
}
<commit_msg>* Set transport type as ethernet if its a namespace interface Closes-bug:#1519731<commit_after>/*
 * Copyright (c) 2013 Juniper Networks, Inc. All rights reserved.
 */

#include <base/parse_object.h>
#include <ifmap/ifmap_link.h>
#include <ifmap/ifmap_table.h>
#include <vnc_cfg_types.h>

#include <cmn/agent_cmn.h>
#include <cmn/agent.h>
#include <init/agent_param.h>
#include <cmn/agent_db.h>

#include <cfg/cfg_init.h>
#include <cfg/cfg_interface_listener.h>
#include <cfg/cfg_interface.h>

#include <oper/agent_types.h>
#include <oper/interface_common.h>
#include <oper/vm.h>
#include <oper/vn.h>
#include <oper/mirror_table.h>
#include <oper/config_manager.h>

using namespace std;
using namespace boost::uuids;
using namespace autogen;

void InterfaceCfgClient::Notify(DBTablePartBase *partition, DBEntryBase *e) {
    CfgIntEntry *entry = static_cast<CfgIntEntry *>(e);
    Agent *agent = Agent::GetInstance();

    if (entry->IsDeleted()) {
        VmInterface::Delete(agent->interface_table(),
                             entry->GetUuid(), VmInterface::INSTANCE_MSG);
    } else {
        uint16_t tx_vlan_id = VmInterface::kInvalidVlanId;
        uint16_t rx_vlan_id = VmInterface::kInvalidVlanId;
        string port = Agent::NullString();
        Interface::Transport transport = Interface::TRANSPORT_ETHERNET;
        if (agent->params()->isVmwareMode()) {
            tx_vlan_id = entry->tx_vlan_id();
            rx_vlan_id = entry->rx_vlan_id();
            port = agent->params()->vmware_physical_port();
            transport = Interface::TRANSPORT_VIRTUAL;
        }

        if ((agent->vrouter_on_nic_mode() == true ||
             agent->vrouter_on_host_dpdk() == true) &&
             entry->port_type() == CfgIntEntry::CfgIntVMPort) {
            transport = Interface::TRANSPORT_PMD;
        }

        VmInterface::NovaAdd(agent->interface_table(), entry->GetUuid(),
                             entry->GetIfname(), entry->ip_addr().to_v4(),
                             entry->GetMacAddr(), entry->vm_name(),
                             entry->vm_project_uuid(), tx_vlan_id, rx_vlan_id,
                             port, entry->ip6_addr(), transport);
        FetchInterfaceData(entry->GetUuid());
    }
}

void InterfaceCfgClient::FetchInterfaceData(const uuid if_uuid) const {
    IFMapNode *node = UuidToIFNode(if_uuid);
    if (node != NULL) {

        DBRequest req;
        req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
        if (agent_cfg_->agent()->interface_table()->IFNodeToReq(node,
                    req, const_cast<uuid&>(if_uuid))) {
            agent_cfg_->agent()->interface_table()->Enqueue(&req);
        }
    }
}

void InterfaceCfgClient::RouteTableNotify(DBTablePartBase *partition,
                                          DBEntryBase *e) {
    IFMapNode *node = static_cast<IFMapNode *>(e);
    if (node->IsDeleted()) {
       return;
    }

    //Trigger change on all interface entries
    IFMapAgentTable *table = static_cast<IFMapAgentTable *>(node->table());
    for (DBGraphVertex::adjacency_iterator iter =
         node->begin(table->GetGraph());
         iter != node->end(table->GetGraph()); ++iter) {
        if (iter->IsDeleted()) {
            continue;
        }
        IFMapNode *adj_node = static_cast<IFMapNode *>(iter.operator->());
        if (Agent::GetInstance()->config_manager()->SkipNode(adj_node)) {
            continue;
        }

        if (adj_node->table() ==
            Agent::GetInstance()->cfg()->cfg_vm_interface_table()) {
            DBRequest req;
            req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
            boost::uuids::uuid id;
            agent_cfg_->agent()->interface_table()->IFNodeToUuid(adj_node, id);
            if (agent_cfg_->agent()->interface_table()->IFNodeToReq(adj_node,
                                                                     req, id)) {
                agent_cfg_->agent()->interface_table()->Enqueue(&req);
            }
        }
    }
}

void InterfaceCfgClient::CfgNotify(DBTablePartBase *partition, DBEntryBase *e) {
    IFMapNode *node = static_cast<IFMapNode *>(e);
    CfgState *state = static_cast<CfgState *>(e->GetState(partition->parent(), cfg_listener_id_));

    if (node->IsDeleted()) {
        if (state) {
            VirtualMachineInterface *cfg =
                static_cast <VirtualMachineInterface *> (node->GetObject());
            assert(cfg);
            autogen::IdPermsType id_perms = cfg->id_perms();
            boost::uuids::uuid u;
            CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u);
            uuid_ifnode_tree_.erase(u);
            node->ClearState(partition->parent(), cfg_listener_id_);
            delete state;
        }
    } else {
        VirtualMachineInterface *cfg =
            static_cast <VirtualMachineInterface *> (node->GetObject());
        if (cfg == NULL) {
            return;
        }
        autogen::IdPermsType id_perms = cfg->id_perms();
        boost::uuids::uuid u;
        CfgUuidSet(id_perms.uuid.uuid_mslong, id_perms.uuid.uuid_lslong, u);
        // We have observed that control node gives a node withoug uuid first
        // followed by subsequent changes that give uuid.
        // Ignore if UUID is not yet present
        if (u == nil_uuid()) {
            return;
        }

        if (state == NULL) {
            uuid_ifnode_tree_.insert(UuidIFNodePair(u, node));
            state = new CfgState();
            state->seen_ = true;
            node->SetState(partition->parent(), cfg_listener_id_, state);
        }
    }
}

IFMapNode *InterfaceCfgClient::UuidToIFNode(const uuid &u) const {
    UuidToIFNodeTree::const_iterator it;

    it = uuid_ifnode_tree_.find(u);
    if (it == uuid_ifnode_tree_.end()) {
        return NULL;
    }

    return it->second;
}

void InterfaceCfgClient::Init() {
    DBTableBase *table = agent_cfg_->agent()->interface_config_table();
    table->Register(boost::bind(&InterfaceCfgClient::Notify, this, _1, _2));

    // Register with config DB table for vm-port UUID to IFNode mapping
    DBTableBase *cfg_db = IFMapTable::FindTable(agent_cfg_->agent()->db(),
                                                "virtual-machine-interface");
    assert(cfg_db);
    cfg_listener_id_ = cfg_db->Register
        (boost::bind(&InterfaceCfgClient::CfgNotify, this, _1, _2));

    // Register with config DB table for static route table changes
    DBTableBase *cfg_route_db = IFMapTable::FindTable(agent_cfg_->agent()->db(),
                                                      "interface-route-table");
    assert(cfg_route_db);
    cfg_route_table_listener_id_ = cfg_route_db->Register
        (boost::bind(&InterfaceCfgClient::RouteTableNotify, this, _1, _2));
}

void InterfaceCfgClient::Shutdown() {
    IFMapTable *cfg_db = IFMapTable::FindTable(agent_cfg_->agent()->db(),
                                                "virtual-machine-interface");
    DBTable::DBStateClear(cfg_db, cfg_listener_id_);
    cfg_db->Unregister(cfg_listener_id_);

    DBTableBase *cfg_route_db = IFMapTable::FindTable(agent_cfg_->agent()->db(),
                                                      "interface-route-table");
    cfg_route_db->Unregister(cfg_route_table_listener_id_);
}
<|endoftext|>


<commit_before>/*
 * Copyright 2001-2002,2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Id$
 */

//////////////////////////////////////////////////////////////////////
// DOMNodeIteratorImpl.cpp: implementation of the DOMNodeIteratorImpl class.
//
//////////////////////////////////////////////////////////////////////

#include "DOMNodeIteratorImpl.hpp"
#include "DOMDocumentImpl.hpp"
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMException.hpp>

XERCES_CPP_NAMESPACE_BEGIN

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

DOMNodeIteratorImpl::DOMNodeIteratorImpl (DOMDocument* doc,
                                    DOMNode* root,
                                    unsigned long whatToShow,
                                    DOMNodeFilter* nodeFilter,
                                    bool expandEntityRef)
:   fRoot(root),
    fDocument(doc),
    fWhatToShow(whatToShow),
    fNodeFilter(nodeFilter),
    fExpandEntityReferences(expandEntityRef),
    fDetached(false),
    fCurrentNode(0),
    fForward(true)
{

}

DOMNodeIteratorImpl::DOMNodeIteratorImpl ( const DOMNodeIteratorImpl& toCopy)
    :   fRoot(toCopy.fRoot),
    fDocument(toCopy.fDocument),
    fWhatToShow(toCopy.fWhatToShow),
    fNodeFilter(toCopy.fNodeFilter),
    fExpandEntityReferences(toCopy.fExpandEntityReferences),
    fDetached(toCopy.fDetached),
    fCurrentNode(toCopy.fCurrentNode),
    fForward(toCopy.fForward)
{
}

DOMNodeIteratorImpl& DOMNodeIteratorImpl::operator= (const DOMNodeIteratorImpl& other) {
    fRoot                   = other.fRoot;
    fCurrentNode            = other.fRoot;
    fWhatToShow             = other.fWhatToShow;
    fNodeFilter             = other.fNodeFilter;
    fForward                = other.fForward;
    fDetached               = other.fDetached;
    fExpandEntityReferences = other.fExpandEntityReferences;
    fDocument               = other.fDocument;
    return *this;
}

DOMNodeIteratorImpl::~DOMNodeIteratorImpl ()
{
	fDetached = false;
}

void DOMNodeIteratorImpl::detach ()
{
	fDetached = true;
   ((DOMDocumentImpl *)fDocument)->removeNodeIterator(this);
}

DOMNode* DOMNodeIteratorImpl::getRoot() {
    return fRoot;
}

// Implementation Note: Note that the iterator looks at whatToShow
// and filter values at each call, and therefore one _could_ add
// setters for these values and alter them while iterating!

/** Return the whatToShow value */

unsigned long DOMNodeIteratorImpl::getWhatToShow () {
    return fWhatToShow;
}

/** Return the filter */

DOMNodeFilter* DOMNodeIteratorImpl::getFilter () {
    return fNodeFilter;
}

/** Get the expandEntity reference flag. */
bool DOMNodeIteratorImpl::getExpandEntityReferences()
{
    return fExpandEntityReferences;
}

/** Return the next DOMNode* in the Iterator. The node is the next node in
 *  depth-first order which also passes the filter, and whatToShow.
 *  A 0 return means either that
 */

DOMNode* DOMNodeIteratorImpl::nextNode () {
	if (fDetached)
		throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);

    // if root is 0 there is no next node->
    if (!fRoot)
			return 0;

    DOMNode* aNextNode = fCurrentNode;
    bool accepted = false; // the next node has not been accepted.

    while (!accepted) {

        // if last direction is not forward, repeat node->
        if (!fForward && (aNextNode != 0)) {
            //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
            aNextNode = fCurrentNode;
        } else {
        // else get the next node via depth-first
            aNextNode = nextNode(aNextNode, true);
        }

        fForward = true; //REVIST: should direction be set forward before 0 check?

        // nothing in the list. return 0.
        if (!aNextNode) return 0;

        // does node pass the filters and whatToShow?
        accepted = acceptNode(aNextNode);
        if (accepted) {
            // if so, then the node is the current node->
            fCurrentNode = aNextNode;
            return fCurrentNode;
        }
    }

    // no nodes, or no accepted nodes.
    return 0;
}

/** Return the previous Node in the Iterator. The node is the next node in
 *  _backwards_ depth-first order which also passes the filter, and whatToShow.
 */

DOMNode* DOMNodeIteratorImpl::previousNode () {
	if (fDetached)
		throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);

    // if the root is 0, or the current node is 0, return 0.
    if (!fRoot || !fCurrentNode) return 0;

    DOMNode* aPreviousNode = fCurrentNode;
    bool accepted = false;

    while (!accepted) {

        if (fForward && (aPreviousNode != 0)) {
            //repeat last node->
            aPreviousNode = fCurrentNode;
        } else {
            // get previous node in backwards depth first order.
            aPreviousNode = previousNode(aPreviousNode);
        }

        // we are going backwards
        fForward = false;

        // if the new previous node is 0, we're at head or past the root,
        // so return 0.
        if (!aPreviousNode) return 0;

        // check if node passes filters and whatToShow.
        accepted = acceptNode(aPreviousNode);
        if (accepted) {
            // if accepted, update the current node, and return it.
            fCurrentNode = aPreviousNode;
            return fCurrentNode;
        }
    }
    // there are no nodes?
    return 0;
}

/** The node is accepted if it passes the whatToShow and the filter. */
bool DOMNodeIteratorImpl::acceptNode (DOMNode* node) {
	if (fDetached)
		throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);

    if (fNodeFilter == 0) {
        return ((fWhatToShow & (1 << (node->getNodeType() - 1))) != 0);
    } else {
        return ((fWhatToShow & (1 << (node->getNodeType() - 1))) != 0)
            && fNodeFilter->acceptNode(node) == DOMNodeFilter::FILTER_ACCEPT;
    }
}

/** Return node, if matches or any parent if matches. */
DOMNode* DOMNodeIteratorImpl::matchNodeOrParent (DOMNode* node) {

    for (DOMNode* n = fCurrentNode; n != fRoot; n = n->getParentNode()) {
        if (node == n) return n;
    }

    return 0;
}

/** The method nextNode(DOMNode, bool) returns the next node
 *  from the actual DOM tree.
 *
 *  The bool visitChildren determines whether to visit the children.
 *  The result is the nextNode.
 */

DOMNode* DOMNodeIteratorImpl::nextNode (DOMNode* node, bool visitChildren) {
	if (fDetached)
		throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);

    if (!node) return fRoot;

    DOMNode* result = 0;
    // only check children if we visit children.
    if (visitChildren) {
        //if hasChildren, return 1st child.
        if (node->hasChildNodes()) {
            result = node->getFirstChild();
            return result;
        }
    }

    // if hasSibling, return sibling
    if (node != fRoot) {
        result = node->getNextSibling();
        if (result != 0) return result;

        // return parent's 1st sibling.
        DOMNode* parent = node->getParentNode();
        while ((parent != 0) && parent != fRoot) {
            result = parent->getNextSibling();
            if (result != 0) {
                return result;
            } else {
                parent = parent->getParentNode();
            }

        } // while (parent != 0 && parent != fRoot) {
    }
    // end of list, return 0
    return 0;
}

/** The method previousNode(DOMNode) returns the previous node
 *  from the actual DOM tree.
 */

DOMNode* DOMNodeIteratorImpl::previousNode (DOMNode* node) {
	if (fDetached)
		throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);

    DOMNode* result = 0;

    // if we're at the root, return 0.
    if (node == fRoot)
			return 0;

    // get sibling
    result = node->getPreviousSibling();
    if (!result) {
        //if 1st sibling, return parent
        result = node->getParentNode();
        return result;
    }

    // if sibling has children, keep getting last child of child.
    if (result->hasChildNodes()) {
        while (result->hasChildNodes()) {
            result = result->getLastChild();
        }
    }

    return result;
}

/** Fix-up the iterator on a remove. Called by DOM or otherwise,
 *  before an actual DOM remove.
 */

void DOMNodeIteratorImpl::removeNode (DOMNode* node) {
	if (fDetached)
		throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);

    // Implementation note: Fix-up means setting the current node properly
    // after a remove.

    if (!node) return;

    DOMNode* deleted = matchNodeOrParent(node);

    if (!deleted) return;

    if (fForward) {
        fCurrentNode = previousNode(deleted);
    } else
    // if (!fForward)
    {
        DOMNode* next = nextNode(deleted, false);
        if (next != 0) {
            // normal case: there _are_ nodes following this in the iterator.
            fCurrentNode = next;
        } else {
            // the last node in the iterator is to be removed,
            // so we set the current node to be the previous one.
            fCurrentNode = previousNode(deleted);
            fForward = true;
        }

    }

}

void DOMNodeIteratorImpl::release()
{
    detach();

    // for performance reason, do not recycle pointer
    // chance that this is allocated again and again is not usual
}

XERCES_CPP_NAMESPACE_END

<commit_msg>Take into account the fExpandEntityReferences setting [jira# 1303]<commit_after>/*
 * Copyright 2001-2002,2004 The Apache Software Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * $Id$
 */

//////////////////////////////////////////////////////////////////////
// DOMNodeIteratorImpl.cpp: implementation of the DOMNodeIteratorImpl class.
//
//////////////////////////////////////////////////////////////////////

#include "DOMNodeIteratorImpl.hpp"
#include "DOMDocumentImpl.hpp"
#include <xercesc/dom/DOMDocument.hpp>
#include <xercesc/dom/DOMException.hpp>

XERCES_CPP_NAMESPACE_BEGIN

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

DOMNodeIteratorImpl::DOMNodeIteratorImpl (DOMDocument* doc,
                                    DOMNode* root,
                                    unsigned long whatToShow,
                                    DOMNodeFilter* nodeFilter,
                                    bool expandEntityRef)
:   fRoot(root),
    fDocument(doc),
    fWhatToShow(whatToShow),
    fNodeFilter(nodeFilter),
    fExpandEntityReferences(expandEntityRef),
    fDetached(false),
    fCurrentNode(0),
    fForward(true)
{

}

DOMNodeIteratorImpl::DOMNodeIteratorImpl ( const DOMNodeIteratorImpl& toCopy)
    :   fRoot(toCopy.fRoot),
    fDocument(toCopy.fDocument),
    fWhatToShow(toCopy.fWhatToShow),
    fNodeFilter(toCopy.fNodeFilter),
    fExpandEntityReferences(toCopy.fExpandEntityReferences),
    fDetached(toCopy.fDetached),
    fCurrentNode(toCopy.fCurrentNode),
    fForward(toCopy.fForward)
{
}

DOMNodeIteratorImpl& DOMNodeIteratorImpl::operator= (const DOMNodeIteratorImpl& other) {
    fRoot                   = other.fRoot;
    fCurrentNode            = other.fRoot;
    fWhatToShow             = other.fWhatToShow;
    fNodeFilter             = other.fNodeFilter;
    fForward                = other.fForward;
    fDetached               = other.fDetached;
    fExpandEntityReferences = other.fExpandEntityReferences;
    fDocument               = other.fDocument;
    return *this;
}

DOMNodeIteratorImpl::~DOMNodeIteratorImpl ()
{
	fDetached = false;
}

void DOMNodeIteratorImpl::detach ()
{
	fDetached = true;
   ((DOMDocumentImpl *)fDocument)->removeNodeIterator(this);
}

DOMNode* DOMNodeIteratorImpl::getRoot() {
    return fRoot;
}

// Implementation Note: Note that the iterator looks at whatToShow
// and filter values at each call, and therefore one _could_ add
// setters for these values and alter them while iterating!

/** Return the whatToShow value */

unsigned long DOMNodeIteratorImpl::getWhatToShow () {
    return fWhatToShow;
}

/** Return the filter */

DOMNodeFilter* DOMNodeIteratorImpl::getFilter () {
    return fNodeFilter;
}

/** Get the expandEntity reference flag. */
bool DOMNodeIteratorImpl::getExpandEntityReferences()
{
    return fExpandEntityReferences;
}

/** Return the next DOMNode* in the Iterator. The node is the next node in
 *  depth-first order which also passes the filter, and whatToShow.
 *  A 0 return means either that
 */

DOMNode* DOMNodeIteratorImpl::nextNode () {
	if (fDetached)
		throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);

    // if root is 0 there is no next node->
    if (!fRoot)
			return 0;

    DOMNode* aNextNode = fCurrentNode;
    bool accepted = false; // the next node has not been accepted.

    while (!accepted) {

        // if last direction is not forward, repeat node->
        if (!fForward && (aNextNode != 0)) {
            //System.out.println("nextNode():!fForward:"+fCurrentNode.getNodeName());
            aNextNode = fCurrentNode;
        } else {
        // else get the next node via depth-first
            aNextNode = nextNode(aNextNode, true);
        }

        fForward = true; //REVIST: should direction be set forward before 0 check?

        // nothing in the list. return 0.
        if (!aNextNode) return 0;

        // does node pass the filters and whatToShow?
        accepted = acceptNode(aNextNode);
        if (accepted) {
            // if so, then the node is the current node->
            fCurrentNode = aNextNode;
            return fCurrentNode;
        }
    }

    // no nodes, or no accepted nodes.
    return 0;
}

/** Return the previous Node in the Iterator. The node is the next node in
 *  _backwards_ depth-first order which also passes the filter, and whatToShow.
 */

DOMNode* DOMNodeIteratorImpl::previousNode () {
	if (fDetached)
		throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);

    // if the root is 0, or the current node is 0, return 0.
    if (!fRoot || !fCurrentNode) return 0;

    DOMNode* aPreviousNode = fCurrentNode;
    bool accepted = false;

    while (!accepted) {

        if (fForward && (aPreviousNode != 0)) {
            //repeat last node->
            aPreviousNode = fCurrentNode;
        } else {
            // get previous node in backwards depth first order.
            aPreviousNode = previousNode(aPreviousNode);
        }

        // we are going backwards
        fForward = false;

        // if the new previous node is 0, we're at head or past the root,
        // so return 0.
        if (!aPreviousNode) return 0;

        // check if node passes filters and whatToShow.
        accepted = acceptNode(aPreviousNode);
        if (accepted) {
            // if accepted, update the current node, and return it.
            fCurrentNode = aPreviousNode;
            return fCurrentNode;
        }
    }
    // there are no nodes?
    return 0;
}

/** The node is accepted if it passes the whatToShow and the filter. */
bool DOMNodeIteratorImpl::acceptNode (DOMNode* node) {
	if (fDetached)
		throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);

    if (fNodeFilter == 0) {
        return ((fWhatToShow & (1 << (node->getNodeType() - 1))) != 0);
    } else {
        return ((fWhatToShow & (1 << (node->getNodeType() - 1))) != 0)
            && fNodeFilter->acceptNode(node) == DOMNodeFilter::FILTER_ACCEPT;
    }
}

/** Return node, if matches or any parent if matches. */
DOMNode* DOMNodeIteratorImpl::matchNodeOrParent (DOMNode* node) {

    for (DOMNode* n = fCurrentNode; n != fRoot; n = n->getParentNode()) {
        if (node == n) return n;
    }

    return 0;
}

/** The method nextNode(DOMNode, bool) returns the next node
 *  from the actual DOM tree.
 *
 *  The bool visitChildren determines whether to visit the children.
 *  The result is the nextNode.
 */

DOMNode* DOMNodeIteratorImpl::nextNode (DOMNode* node, bool visitChildren) {
	if (fDetached)
		throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);

    if (!node) return fRoot;

    DOMNode* result = 0;
    // only check children if we visit children.
    if (visitChildren) {
        //if hasChildren, return 1st child.
        if ((fExpandEntityReferences || node->getNodeType()!=DOMNode::ENTITY_REFERENCE_NODE) &&
            node->hasChildNodes()) {
            result = node->getFirstChild();
            return result;
        }
    }

    // if hasSibling, return sibling
    if (node != fRoot) {
        result = node->getNextSibling();
        if (result != 0) return result;

        // return parent's 1st sibling.
        DOMNode* parent = node->getParentNode();
        while ((parent != 0) && parent != fRoot) {
            result = parent->getNextSibling();
            if (result != 0) {
                return result;
            } else {
                parent = parent->getParentNode();
            }

        } // while (parent != 0 && parent != fRoot) {
    }
    // end of list, return 0
    return 0;
}

/** The method previousNode(DOMNode) returns the previous node
 *  from the actual DOM tree.
 */

DOMNode* DOMNodeIteratorImpl::previousNode (DOMNode* node) {
	if (fDetached)
		throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);

    DOMNode* result = 0;

    // if we're at the root, return 0.
    if (node == fRoot)
			return 0;

    // get sibling
    result = node->getPreviousSibling();
    if (!result) {
        //if 1st sibling, return parent
        result = node->getParentNode();
        return result;
    }

    // if sibling has children, keep getting last child of child.
    if (result->hasChildNodes()) {
        while ((fExpandEntityReferences || result->getNodeType()!=DOMNode::ENTITY_REFERENCE_NODE) &&
               result->hasChildNodes()) {
            result = result->getLastChild();
        }
    }

    return result;
}

/** Fix-up the iterator on a remove. Called by DOM or otherwise,
 *  before an actual DOM remove.
 */

void DOMNodeIteratorImpl::removeNode (DOMNode* node) {
	if (fDetached)
		throw DOMException(DOMException::INVALID_STATE_ERR, 0, GetDOMNodeIteratorMemoryManager);

    // Implementation note: Fix-up means setting the current node properly
    // after a remove.

    if (!node) return;

    DOMNode* deleted = matchNodeOrParent(node);

    if (!deleted) return;

    if (fForward) {
        fCurrentNode = previousNode(deleted);
    } else
    // if (!fForward)
    {
        DOMNode* next = nextNode(deleted, false);
        if (next != 0) {
            // normal case: there _are_ nodes following this in the iterator.
            fCurrentNode = next;
        } else {
            // the last node in the iterator is to be removed,
            // so we set the current node to be the previous one.
            fCurrentNode = previousNode(deleted);
            fForward = true;
        }

    }

}

void DOMNodeIteratorImpl::release()
{
    detach();

    // for performance reason, do not recycle pointer
    // chance that this is allocated again and again is not usual
}

XERCES_CPP_NAMESPACE_END

<|endoftext|>