<commit_before>//
// file : function.hpp
// in : file:///home/tim/projects/nsched/nsched/tools/function.hpp
//
// created by : Timothée Feuillet on linux.site
// date: 17/07/2014 11:59:09
//
//
// Copyright (C) 2014 Timothée Feuillet
//
// 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.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//

// ATTENTION NOT FINISHED YET !!!

#ifndef __N_2111737739159269973_1204098121__FUNCTION_HPP__
# define __N_2111737739159269973_1204098121__FUNCTION_HPP__

#include "ct_list.hpp"
#include "execute_pack.hpp" // some magic
#include "constructor_call.hpp"
#include "param.hpp"

namespace neam
{
  namespace ct
  {
    template<typename Ptr>
    struct is_function_pointer
    {
      static constexpr bool value = false;
    };
    template<typename Ret, typename... Params>
    struct is_function_pointer<Ret(*)(Params...)>
    {
      static constexpr bool value = true;
    };
    template<typename Ret, typename Class, typename... Params>
    struct is_function_pointer<Ret(Class::*)(Params...)>
    {
      static constexpr bool value = true;
    };
    template<typename Ret, typename... Params>
    struct is_function_pointer<Ret(&)(Params...)>
    {
      static constexpr bool value = true;
    };

    // /// ///
    // for a ct function wrapper
    // /// ///

    // the wrappers
    template<typename PtrType, PtrType Ptr, typename... Args> struct function_wrapper {};      // the one that wrap
    template<typename PtrType, PtrType Ptr, typename... Args> struct _sub_function_wrapper {}; // the result one

    // for C functions
    template<typename PtrType, PtrType Ptr, typename Return, typename... FuncArgList>
    struct function_wrapper<PtrType, Ptr, Return, type_list<FuncArgList...>>
    {
      template<typename... Types>
      static constexpr _sub_function_wrapper<PtrType, Ptr, Return, type_list<FuncArgList...>, type_list<Types...>> wrap(Types... values)
      {
        return _sub_function_wrapper<PtrType, Ptr, Return, type_list<FuncArgList...>, type_list<Types...>>(values...);
      }
    };

    template<typename PtrType, PtrType Ptr, typename Return, typename... FuncArgList, typename... ArgList>
    struct _sub_function_wrapper<PtrType, Ptr, Return, type_list<FuncArgList...>, type_list<ArgList...>>
    {
      static_assert(sizeof...(FuncArgList) == sizeof...(ArgList), "the number of supplied argument does not match the function's arity");

//       constexpr _sub_function_wrapper(ArgList... values)
//
//       {
//       }
    };

    // /// ///
    // function traits
    // /// ///

    template<typename FunctionType>
    struct function_traits
    {
      static constexpr bool is_function = false;
    };
    template<typename FunctionType>
    constexpr bool function_traits<FunctionType>::is_function;

    // standard function
    template<typename Return, typename... Parameters>
    struct function_traits<Return (Parameters...)>
    {
      static constexpr bool is_function = true;
      static constexpr bool is_member = false;
      using return_type = Return;
      using ptr_type = Return (*)(Parameters...);
      using arg_list = type_list<Parameters...>;

      template<ptr_type ptr>
      using create_wrapper = function_wrapper<ptr_type, ptr, Return, /*Class,*/ arg_list>;
    };
    template<typename Return, typename... Parameters>
    constexpr bool function_traits<Return (Parameters...)>::is_function;
    template<typename Return, typename... Parameters>
    constexpr bool function_traits<Return (Parameters...)>::is_member;

    // class member function
    template<typename Return, typename Class,typename... Parameters>
    struct function_traits<Return (Class::*)(Parameters...)>
    {
      static constexpr bool is_function = true;
      static constexpr bool is_member = true;
      static constexpr bool is_const = false;
      static constexpr bool is_volatile = false;
      using return_type = Return;
      using class_type = Class;
      using ptr_type = Return (Class::*)(Parameters...);
      using arg_list = type_list<Parameters...>;
    };
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...)>::is_function;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...)>::is_member;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...)>::is_const;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...)>::is_volatile;

    template<typename Return, typename Class, typename... Parameters>
    struct function_traits<Return (Class::*)(Parameters...) const>
    {
      static constexpr bool is_function = true;
      static constexpr bool is_member = true;
      static constexpr bool is_const = true;
      static constexpr bool is_volatile = false;
      using return_type = Return;
      using class_type = Class;
      using ptr_type = Return (Class::*)(Parameters...) const;
      using arg_list = type_list<Parameters...>;
    };
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const>::is_function;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const>::is_member;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const>::is_const;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const>::is_volatile;

    template<typename Return, typename Class, typename... Parameters>
    struct function_traits<Return (Class::*)(Parameters...) volatile>
    {
      static constexpr bool is_function = true;
      static constexpr bool is_member = true;
      static constexpr bool is_const = false;
      static constexpr bool is_volatile = true;
      using return_type = Return;
      using class_type = Class;
      using ptr_type = Return (Class::*)(Parameters...) volatile;
      using arg_list = type_list<Parameters...>;
    };
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) volatile>::is_function;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) volatile>::is_member;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) volatile>::is_const;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) volatile>::is_volatile;

    template<typename Return, typename Class, typename... Parameters>
    struct function_traits<Return (Class::*)(Parameters...) const volatile>
    {
      static constexpr bool is_function = true;
      static constexpr bool is_member = true;
      static constexpr bool is_const = false;
      static constexpr bool is_volatile = true;
      using return_type = Return;
      using class_type = Class;
      using ptr_type = Return (Class::*)(Parameters...) const volatile;
      using arg_list = type_list<Parameters...>;
    };
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const volatile>::is_function;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const volatile>::is_member;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const volatile>::is_const;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const volatile>::is_volatile;

  } // namespace ct
} // namespace neam

#endif /*__N_2111737739159269973_1204098121__FUNCTION_HPP__*/

// kate: indent-mode cstyle; indent-width 2; replace-tabs on;

<commit_msg>[TOOLS/TRAITS/FUNCTION]: fix some issues with function pointers. (it was using signatures instead of pointers)<commit_after>//
// file : function.hpp
// in : file:///home/tim/projects/nsched/nsched/tools/function.hpp
//
// created by : Timothée Feuillet on linux.site
// date: 17/07/2014 11:59:09
//
//
// Copyright (C) 2014 Timothée Feuillet
//
// 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.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//

// ATTENTION NOT FINISHED YET !!!

#ifndef __N_2111737739159269973_1204098121__FUNCTION_HPP__
# define __N_2111737739159269973_1204098121__FUNCTION_HPP__

#include "ct_list.hpp"
#include "execute_pack.hpp" // some magic
#include "constructor_call.hpp"
#include "param.hpp"

namespace neam
{
  namespace ct
  {
    template<typename Ptr>
    struct is_function_pointer
    {
      static constexpr bool value = false;
    };
    template<typename Ret, typename... Params>
    struct is_function_pointer<Ret(*)(Params...)>
    {
      static constexpr bool value = true;
    };
    template<typename Ret, typename Class, typename... Params>
    struct is_function_pointer<Ret(Class::*)(Params...)>
    {
      static constexpr bool value = true;
    };
    template<typename Ret, typename... Params>
    struct is_function_pointer<Ret(&)(Params...)>
    {
      static constexpr bool value = true;
    };

    // /// ///
    // for a ct function wrapper
    // /// ///

    // the wrappers
    template<typename PtrType, PtrType Ptr, typename... Args> struct function_wrapper {};      // the one that wrap
    template<typename PtrType, PtrType Ptr, typename... Args> struct _sub_function_wrapper {}; // the result one

    // for C functions
    template<typename PtrType, PtrType Ptr, typename Return, typename... FuncArgList>
    struct function_wrapper<PtrType, Ptr, Return, type_list<FuncArgList...>>
    {
      template<typename... Types>
      static constexpr _sub_function_wrapper<PtrType, Ptr, Return, type_list<FuncArgList...>, type_list<Types...>> wrap(Types... values)
      {
        return _sub_function_wrapper<PtrType, Ptr, Return, type_list<FuncArgList...>, type_list<Types...>>(values...);
      }
    };

    template<typename PtrType, PtrType Ptr, typename Return, typename... FuncArgList, typename... ArgList>
    struct _sub_function_wrapper<PtrType, Ptr, Return, type_list<FuncArgList...>, type_list<ArgList...>>
    {
      static_assert(sizeof...(FuncArgList) == sizeof...(ArgList), "the number of supplied argument does not match the function's arity");

//       constexpr _sub_function_wrapper(ArgList... values)
//
//       {
//       }
    };

    // /// ///
    // function traits
    // /// ///

    template<typename FunctionType>
    struct function_traits
    {
      static constexpr bool is_function = false;
#ifdef IN_IDE_PARSER
      static constexpr bool is_member = false;
      using return_type = void;
      using ptr_type = void; // not a pointer
      using arg_list = type_list<>;
#endif
    };

    template<typename FunctionType>
    constexpr bool function_traits<FunctionType>::is_function;

    // standard function
    template<typename Return, typename... Parameters>
    struct function_traits<Return(*)(Parameters...)>
    {
      static constexpr bool is_function = true;
      static constexpr bool is_member = false;
      using return_type = Return;
      using ptr_type = Return (*)(Parameters...);
      using arg_list = type_list<Parameters...>;

      template<ptr_type ptr>
      using create_wrapper = function_wrapper<ptr_type, ptr, Return, /*Class,*/ arg_list>;
    };
    template<typename Return, typename... Parameters>
    constexpr bool function_traits<Return(*)(Parameters...)>::is_function;
    template<typename Return, typename... Parameters>
    constexpr bool function_traits<Return(*)(Parameters...)>::is_member;

    // class member function
    template<typename Return, typename Class,typename... Parameters>
    struct function_traits<Return (Class::*)(Parameters...)>
    {
      static constexpr bool is_function = true;
      static constexpr bool is_member = true;
      static constexpr bool is_const = false;
      static constexpr bool is_volatile = false;
      using return_type = Return;
      using class_type = Class;
      using ptr_type = Return (Class::*)(Parameters...);
      using arg_list = type_list<Parameters...>;
    };
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...)>::is_function;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...)>::is_member;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...)>::is_const;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...)>::is_volatile;

    template<typename Return, typename Class, typename... Parameters>
    struct function_traits<Return (Class::*)(Parameters...) const>
    {
      static constexpr bool is_function = true;
      static constexpr bool is_member = true;
      static constexpr bool is_const = true;
      static constexpr bool is_volatile = false;
      using return_type = Return;
      using class_type = Class;
      using ptr_type = Return (Class::*)(Parameters...) const;
      using arg_list = type_list<Parameters...>;
    };
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const>::is_function;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const>::is_member;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const>::is_const;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const>::is_volatile;

    template<typename Return, typename Class, typename... Parameters>
    struct function_traits<Return (Class::*)(Parameters...) volatile>
    {
      static constexpr bool is_function = true;
      static constexpr bool is_member = true;
      static constexpr bool is_const = false;
      static constexpr bool is_volatile = true;
      using return_type = Return;
      using class_type = Class;
      using ptr_type = Return (Class::*)(Parameters...) volatile;
      using arg_list = type_list<Parameters...>;
    };
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) volatile>::is_function;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) volatile>::is_member;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) volatile>::is_const;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) volatile>::is_volatile;

    template<typename Return, typename Class, typename... Parameters>
    struct function_traits<Return (Class::*)(Parameters...) const volatile>
    {
      static constexpr bool is_function = true;
      static constexpr bool is_member = true;
      static constexpr bool is_const = false;
      static constexpr bool is_volatile = true;
      using return_type = Return;
      using class_type = Class;
      using ptr_type = Return (Class::*)(Parameters...) const volatile;
      using arg_list = type_list<Parameters...>;
    };
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const volatile>::is_function;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const volatile>::is_member;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const volatile>::is_const;
    template<typename Return, typename Class, typename... Parameters>
    constexpr bool function_traits<Return (Class::*)(Parameters...) const volatile>::is_volatile;

  } // namespace ct
} // namespace neam

#endif /*__N_2111737739159269973_1204098121__FUNCTION_HPP__*/

// kate: indent-mode cstyle; indent-width 2; replace-tabs on;

<|endoftext|>


<commit_before>#include "StdAfx.h"
#include "FileReader.h"
#ifdef __unix__
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
//#include <sys/mman.h>
#endif // __unix__
/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/

namespace RawSpeed {

FileReader::FileReader(LPCWSTR _filename) : mFilename(_filename) {
}

FileMap* FileReader::readFile() {
#ifdef __unix__
  struct stat st;
  int bytes_read = 0;
  int fd;
  char *dest;

  fd = open(mFilename, O_RDONLY);
  if (fd < 0)
    throw FileIOException("Could not open file.");
  if (fstat(fd, &st) < 0)
	throw FileIOException("Could not read size of file (check permissions)");
  if (st.st_size == 0)
	throw FileIOException("File is 0 bytes.");

#if 0
  // Not used, as it is slower than sync read

  uchar8* pa = (uchar8*)mmap(0, st.st_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
  FileMap *fileData = new FileMap(pa, st.st_size);

#else
  FileMap *fileData = new FileMap(st.st_size);

  while ((st.st_size > 0) && (bytes_read < st.st_size)) {
    dest = (char *) fileData->getDataWrt(bytes_read);
    bytes_read += read(fd, dest, st.st_size - bytes_read);
  }
  close(fd);
#endif

#else // __unix__
  HANDLE file_h;  // File handle
  file_h = CreateFile(mFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  if (file_h == INVALID_HANDLE_VALUE) {
    throw FileIOException("Could not open file.");
  }

  LARGE_INTEGER f_size;
  GetFileSizeEx(file_h , &f_size);

  FileMap *fileData = new FileMap(f_size.LowPart);

  DWORD bytes_read;
  if (! ReadFile(file_h, fileData->getDataWrt(0), fileData->getSize(), &bytes_read, NULL)) {
    CloseHandle(file_h);
    delete fileData;
    throw FileIOException("Could not read file.");
  }
  CloseHandle(file_h);

#endif // __unix__
  return fileData;
}

FileReader::~FileReader(void) {

}

} // namespace RawSpeed
<commit_msg>Use another way of determining file size on unix.<commit_after>#include "StdAfx.h"
#include "FileReader.h"
#ifdef __unix__
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
//#include <sys/mman.h>
#endif // __unix__
/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/

namespace RawSpeed {

FileReader::FileReader(LPCWSTR _filename) : mFilename(_filename) {
}

FileMap* FileReader::readFile() {
#ifdef __unix__
  int bytes_read = 0;
  FILE *file;
  char *dest;
  long size;

  file = fopen(mFilename, "rb");
  if (file == NULL)
    throw FileIOException("Could not open file.");
  fseek(file, 0, SEEK_END);
  size = ftell(file);
  if (size <= 0) {
    fclose(file);
    throw FileIOException("File is 0 bytes.");
  }
  fseek(file, 0, SEEK_SET);

#if 0
  // Not used, as it is slower than sync read

  uchar8* pa = (uchar8*)mmap(0, size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
  FileMap *fileData = new FileMap(pa, size);

#else
  FileMap *fileData = new FileMap(size);

  dest = (char *)fileData->getDataWrt(0);
  bytes_read = fread(dest, 1, size, file);
  fclose(file);
  if (size != bytes_read) {
    delete fileData;
    throw FileIOException("Could not read file.");
  }
#endif

#else // __unix__
  HANDLE file_h;  // File handle
  file_h = CreateFile(mFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  if (file_h == INVALID_HANDLE_VALUE) {
    throw FileIOException("Could not open file.");
  }

  LARGE_INTEGER f_size;
  GetFileSizeEx(file_h , &f_size);

  FileMap *fileData = new FileMap(f_size.LowPart);

  DWORD bytes_read;
  if (! ReadFile(file_h, fileData->getDataWrt(0), fileData->getSize(), &bytes_read, NULL)) {
    CloseHandle(file_h);
    delete fileData;
    throw FileIOException("Could not read file.");
  }
  CloseHandle(file_h);

#endif // __unix__
  return fileData;
}

FileReader::~FileReader(void) {

}

} // namespace RawSpeed
<|endoftext|>


<commit_before>#include "StdAfx.h"
#include "PefDecoder.h"
/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/

namespace RawSpeed {

PefDecoder::PefDecoder(TiffIFD *rootIFD, FileMap* file) :
    RawDecoder(file), mRootIFD(rootIFD) {
      decoderVersion = 2;
}

PefDecoder::~PefDecoder(void) {
  if (mRootIFD)
    delete mRootIFD;
  mRootIFD = NULL;
}

RawImage PefDecoder::decodeRawInternal() {
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(STRIPOFFSETS);

  if (data.empty())
    ThrowRDE("PEF Decoder: No image data found");

  TiffIFD* raw = data[0];

  int compression = raw->getEntry(COMPRESSION)->getInt();

  if (1 == compression) {
    decodeUncompressed(raw, true);
    return mRaw;
  }

  if (65535 != compression)
    ThrowRDE("PEF Decoder: Unsupported compression");

  TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
  TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);

  if (offsets->count != 1) {
    ThrowRDE("PEF Decoder: Multiple Strips found: %u", offsets->count);
  }
  if (counts->count != offsets->count) {
    ThrowRDE("PEF Decoder: Byte count number does not match strip size: count:%u, strips:%u ", counts->count, offsets->count);
  }
  if (!mFile->isValid(offsets->getInt() + counts->getInt()))
    ThrowRDE("PEF Decoder: Truncated file.");

  uint32 width = raw->getEntry(IMAGEWIDTH)->getInt();
  uint32 height = raw->getEntry(IMAGELENGTH)->getInt();

  mRaw->dim = iPoint2D(width, height);
  mRaw->createData();
  try {
    PentaxDecompressor l(mFile, mRaw);
    l.decodePentax(mRootIFD, offsets->getInt(), counts->getInt());
  } catch (IOException &e) {
    mRaw->setError(e.what());
    // Let's ignore it, it may have delivered somewhat useful data.
  }

  return mRaw;
}

void PefDecoder::checkSupportInternal(CameraMetaData *meta) {
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);
  if (data.empty())
    ThrowRDE("PEF Support check: Model name found");
  if (!data[0]->hasEntry(MAKE))
    ThrowRDE("PEF Support: Make name not found");

  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();
  this->checkCameraSupported(meta, make, model, "");
}

void PefDecoder::decodeMetaDataInternal(CameraMetaData *meta) {
  int iso = 0;
  mRaw->cfa.setCFA(CFA_RED, CFA_GREEN, CFA_GREEN2, CFA_BLUE);
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);

  if (data.empty())
    ThrowRDE("PEF Meta Decoder: Model name found");

  TiffIFD* raw = data[0];

  string make = raw->getEntry(MAKE)->getString();
  string model = raw->getEntry(MODEL)->getString();

  if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
    iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getInt();

  setMetaData(meta, make, model, "", iso);
}

} // namespace RawSpeed
<commit_msg>Read black level from PEF files. Should affect most Pentax cameras.<commit_after>#include "StdAfx.h"
#include "PefDecoder.h"
/*
    RawSpeed - RAW file decoder.

    Copyright (C) 2009 Klaus Post

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

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

    http://www.klauspost.com
*/

namespace RawSpeed {

PefDecoder::PefDecoder(TiffIFD *rootIFD, FileMap* file) :
    RawDecoder(file), mRootIFD(rootIFD) {
      decoderVersion = 2;
}

PefDecoder::~PefDecoder(void) {
  if (mRootIFD)
    delete mRootIFD;
  mRootIFD = NULL;
}

RawImage PefDecoder::decodeRawInternal() {
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(STRIPOFFSETS);

  if (data.empty())
    ThrowRDE("PEF Decoder: No image data found");

  TiffIFD* raw = data[0];

  int compression = raw->getEntry(COMPRESSION)->getInt();

  if (1 == compression) {
    decodeUncompressed(raw, true);
    return mRaw;
  }

  if (65535 != compression)
    ThrowRDE("PEF Decoder: Unsupported compression");

  TiffEntry *offsets = raw->getEntry(STRIPOFFSETS);
  TiffEntry *counts = raw->getEntry(STRIPBYTECOUNTS);

  if (offsets->count != 1) {
    ThrowRDE("PEF Decoder: Multiple Strips found: %u", offsets->count);
  }
  if (counts->count != offsets->count) {
    ThrowRDE("PEF Decoder: Byte count number does not match strip size: count:%u, strips:%u ", counts->count, offsets->count);
  }
  if (!mFile->isValid(offsets->getInt() + counts->getInt()))
    ThrowRDE("PEF Decoder: Truncated file.");

  uint32 width = raw->getEntry(IMAGEWIDTH)->getInt();
  uint32 height = raw->getEntry(IMAGELENGTH)->getInt();

  mRaw->dim = iPoint2D(width, height);
  mRaw->createData();
  try {
    PentaxDecompressor l(mFile, mRaw);
    l.decodePentax(mRootIFD, offsets->getInt(), counts->getInt());
  } catch (IOException &e) {
    mRaw->setError(e.what());
    // Let's ignore it, it may have delivered somewhat useful data.
  }

  return mRaw;
}

void PefDecoder::checkSupportInternal(CameraMetaData *meta) {
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);
  if (data.empty())
    ThrowRDE("PEF Support check: Model name found");
  if (!data[0]->hasEntry(MAKE))
    ThrowRDE("PEF Support: Make name not found");

  string make = data[0]->getEntry(MAKE)->getString();
  string model = data[0]->getEntry(MODEL)->getString();
  this->checkCameraSupported(meta, make, model, "");
}

void PefDecoder::decodeMetaDataInternal(CameraMetaData *meta) {
  int iso = 0;
  mRaw->cfa.setCFA(CFA_RED, CFA_GREEN, CFA_GREEN2, CFA_BLUE);
  vector<TiffIFD*> data = mRootIFD->getIFDsWithTag(MODEL);

  if (data.empty())
    ThrowRDE("PEF Meta Decoder: Model name found");

  TiffIFD* raw = data[0];

  string make = raw->getEntry(MAKE)->getString();
  string model = raw->getEntry(MODEL)->getString();

  if (mRootIFD->hasEntryRecursive(ISOSPEEDRATINGS))
    iso = mRootIFD->getEntryRecursive(ISOSPEEDRATINGS)->getInt();

  setMetaData(meta, make, model, "", iso);

  // Read black level
  if (mRootIFD->hasEntryRecursive((TiffTag)0x200)) {
    TiffEntry *black = mRootIFD->getEntryRecursive((TiffTag)0x200);
    const ushort16 *levels = black->getShortArray();
    for (int i = 0; i < 4; i++)
      mRaw->blackLevelSeparate[i] = levels[i];
  }
}

} // namespace RawSpeed
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMapper.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkMapper.h"

#include "vtkDataSet.h"
#include "vtkLookupTable.h"
#include "vtkMath.h"

vtkCxxRevisionMacro(vtkMapper, "1.110");

// Initialize static member that controls global immediate mode rendering
static int vtkMapperGlobalImmediateModeRendering = 0;

// Initialize static member that controls global coincidence resolution
static int vtkMapperGlobalResolveCoincidentTopology = VTK_RESOLVE_OFF;
static double vtkMapperGlobalResolveCoincidentTopologyZShift = 0.01;
static double vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetFactor = 1.0;
static double vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetUnits = 1.0;

// Construct with initial range (0,1).
vtkMapper::vtkMapper()
{
  this->Colors = NULL;

  this->LookupTable = NULL;

  this->ScalarVisibility = 1;
  this->ScalarRange[0] = 0.0; this->ScalarRange[1] = 1.0;
  this->UseLookupTableScalarRange = 0;

  this->ImmediateModeRendering = 0;

  this->ColorMode = VTK_COLOR_MODE_DEFAULT;
  this->ScalarMode = VTK_SCALAR_MODE_DEFAULT;
  this->ScalarMaterialMode = VTK_MATERIALMODE_DEFAULT;

  vtkMath::UninitializeBounds(this->Bounds);
  this->Center[0] = this->Center[1] = this->Center[2] = 0.0;

  this->RenderTime = 0.0;

  strcpy(this->ArrayName, "");
  this->ArrayId = -1;
  this->ArrayComponent = 0;
  this->ArrayAccessMode = VTK_GET_ARRAY_BY_ID;
}

vtkMapper::~vtkMapper()
{
  if (this->LookupTable)
    {
    this->LookupTable->UnRegister(this);
    }
  if ( this->Colors != NULL )
    {
    this->Colors->UnRegister(this);
    }
}

// Get the bounds for the input of this mapper as
// (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
double *vtkMapper::GetBounds()
{
  static double bounds[] = {-1.0,1.0, -1.0,1.0, -1.0,1.0};

  if ( ! this->GetInput() )
    {
    return bounds;
    }
  else
    {
    this->Update();
    this->GetInput()->GetBounds(this->Bounds);
    return this->Bounds;
    }
}

vtkDataSet *vtkMapper::GetInput()
{
  if (this->NumberOfInputs < 1)
    {
    return NULL;
    }

  return (vtkDataSet *)(this->Inputs[0]);
}

void vtkMapper::SetGlobalImmediateModeRendering(int val)
{
  if (val == vtkMapperGlobalImmediateModeRendering)
    {
    return;
    }
  vtkMapperGlobalImmediateModeRendering = val;
}

int vtkMapper::GetGlobalImmediateModeRendering()
{
  return vtkMapperGlobalImmediateModeRendering;
}

void vtkMapper::SetResolveCoincidentTopology(int val)
{
  if (val == vtkMapperGlobalResolveCoincidentTopology)
    {
    return;
    }
  vtkMapperGlobalResolveCoincidentTopology = val;
}

int vtkMapper::GetResolveCoincidentTopology()
{
  return vtkMapperGlobalResolveCoincidentTopology;
}

void vtkMapper::SetResolveCoincidentTopologyToDefault()
{
  vtkMapperGlobalResolveCoincidentTopology = VTK_RESOLVE_OFF;
}

void vtkMapper::SetResolveCoincidentTopologyZShift(double val)
{
  if (val == vtkMapperGlobalResolveCoincidentTopologyZShift)
    {
    return;
    }
  vtkMapperGlobalResolveCoincidentTopologyZShift = val;
}

double vtkMapper::GetResolveCoincidentTopologyZShift()
{
  return vtkMapperGlobalResolveCoincidentTopologyZShift;
}

void vtkMapper::SetResolveCoincidentTopologyPolygonOffsetParameters(
                                            double factor, double units)
{
  if (factor == vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetFactor &&
      units == vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetUnits )
    {
    return;
    }
  vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetFactor = factor;
  vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetUnits = units;
}

void vtkMapper::GetResolveCoincidentTopologyPolygonOffsetParameters(
                           double& factor, double& units)
{
  factor = vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetFactor;
  units = vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetUnits;
}

// Overload standard modified time function. If lookup table is modified,
// then this object is modified as well.
unsigned long vtkMapper::GetMTime()
{
  //unsigned long mTime=this->MTime.GetMTime();
  unsigned long mTime=vtkAbstractMapper::GetMTime();
  unsigned long lutMTime;

  if ( this->LookupTable != NULL )
    {
    lutMTime = this->LookupTable->GetMTime();
    mTime = ( lutMTime > mTime ? lutMTime : mTime );
    }

  return mTime;
}

void vtkMapper::ShallowCopy(vtkAbstractMapper *mapper)
{
  vtkMapper *m = vtkMapper::SafeDownCast(mapper);
  if ( m != NULL )
    {
    this->SetLookupTable(m->GetLookupTable());
    this->SetScalarVisibility(m->GetScalarVisibility());
    this->SetScalarRange(m->GetScalarRange());
    this->SetColorMode(m->GetColorMode());
    this->SetScalarMode(m->GetScalarMode());
    this->SetScalarMaterialMode(m->GetScalarMaterialMode());
    this->SetImmediateModeRendering(m->GetImmediateModeRendering());
    this->SetUseLookupTableScalarRange(m->GetUseLookupTableScalarRange());
    if ( m->GetArrayAccessMode() == VTK_GET_ARRAY_BY_ID )
      {
      this->ColorByArrayComponent(m->GetArrayId(),m->GetArrayComponent());
      }
    else
      {
      this->ColorByArrayComponent(m->GetArrayName(),m->GetArrayComponent());
      }
    }

  // Now do superclass
  this->vtkAbstractMapper3D::ShallowCopy(mapper);

}

// a side effect of this is that this->Colors is also set
// to the return value
vtkUnsignedCharArray *vtkMapper::MapScalars(double alpha)
{
  // Lets try to resuse the old colors.
  if (this->ScalarVisibility && this->Colors)
    {
    if (this->LookupTable && this->LookupTable->GetAlpha() == alpha)
      {
      vtkDataArray *scalars = vtkAbstractMapper::
        GetScalars(this->GetInput(), this->ScalarMode, this->ArrayAccessMode,
                   this->ArrayId, this->ArrayName, this->ArrayComponent);
      if (this->GetMTime() < this->Colors->GetMTime() &&
          this->GetInput() &&
          this->GetInput()->GetMTime() < this->Colors->GetMTime())
        {
        return this->Colors;
        }
      }
    }

  // Get rid of old colors
  if ( this->Colors )
    {
    this->Colors->UnRegister(this);
    this->Colors = NULL;
    }

  // map scalars if necessary
  if ( this->ScalarVisibility )
    {
    vtkDataArray *scalars = vtkAbstractMapper::
      GetScalars(this->GetInput(), this->ScalarMode, this->ArrayAccessMode,
                 this->ArrayId, this->ArrayName, this->ArrayComponent);
    if ( scalars )
      {
      if ( scalars->GetLookupTable() )
        {
        this->SetLookupTable(scalars->GetLookupTable());
        }
      else
        {
        // make sure we have a lookup table
        if ( this->LookupTable == NULL )
          {
          this->CreateDefaultLookupTable();
          }
        this->LookupTable->Build();
        }
      if ( !this->UseLookupTableScalarRange )
        {
        this->LookupTable->SetRange(this->ScalarRange);
        }
      this->LookupTable->SetAlpha(alpha);
      this->Colors = this->LookupTable->
        MapScalars(scalars, this->ColorMode, this->ArrayComponent);
      // Consistent register and unregisters
      this->Colors->Register(this);
      this->Colors->Delete();
      }
    }

  return this->Colors;
}

void vtkMapper::SelectColorArray(int arrayNum)
{
  this->ColorByArrayComponent(arrayNum, -1);
}

void vtkMapper::SelectColorArray(const char* arrayName)
{
  this->ColorByArrayComponent(arrayName, -1);
}

void vtkMapper::ColorByArrayComponent(int arrayNum, int component)
{
  if (this->ArrayId == arrayNum && component == this->ArrayComponent &&
      this->ArrayAccessMode == VTK_GET_ARRAY_BY_ID)
    {
    return;
    }
  this->Modified();

  this->ArrayId = arrayNum;
  this->ArrayComponent = component;
  this->ArrayAccessMode = VTK_GET_ARRAY_BY_ID;
}

void vtkMapper::ColorByArrayComponent(const char* arrayName, int component)
{
  if (!arrayName ||
      ( strcmp(this->ArrayName, arrayName) == 0 &&
        component == this->ArrayComponent &&
        this->ArrayAccessMode == VTK_GET_ARRAY_BY_ID ))
    {
    return;
    }
  this->Modified();

  strcpy(this->ArrayName, arrayName);
  this->ArrayComponent = component;
  this->ArrayAccessMode = VTK_GET_ARRAY_BY_NAME;
}

// Specify a lookup table for the mapper to use.
void vtkMapper::SetLookupTable(vtkScalarsToColors *lut)
{
  if ( this->LookupTable != lut )
    {
    if ( this->LookupTable)
      {
      this->LookupTable->UnRegister(this);
      }
    this->LookupTable = lut;
    if (lut)
      {
      lut->Register(this);
      }
    this->Modified();
    }
}

vtkScalarsToColors *vtkMapper::GetLookupTable()
{
  if ( this->LookupTable == NULL )
    {
    this->CreateDefaultLookupTable();
    }
  return this->LookupTable;
}

void vtkMapper::CreateDefaultLookupTable()
{
  if ( this->LookupTable)
    {
    this->LookupTable->UnRegister(this);
    }
  this->LookupTable = vtkLookupTable::New();
  // Consistent Register/UnRegisters.
  this->LookupTable->Register(this);
  this->LookupTable->Delete();
}

// Update the network connected to this mapper.
void vtkMapper::Update()
{
  if ( this->GetInput() )
    {
    this->GetInput()->Update();
    }
}

// Return the method of coloring scalar data.
const char *vtkMapper::GetColorModeAsString(void)
{
  if ( this->ColorMode == VTK_COLOR_MODE_MAP_SCALARS )
    {
    return "MapScalars";
    }
  else
    {
    return "Default";
    }
}

// Return the method for obtaining scalar data.
const char *vtkMapper::GetScalarModeAsString(void)
{
  if ( this->ScalarMode == VTK_SCALAR_MODE_USE_CELL_DATA )
    {
    return "UseCellData";
    }
  else if ( this->ScalarMode == VTK_SCALAR_MODE_USE_POINT_DATA )
    {
    return "UsePointData";
    }
  else if ( this->ScalarMode == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA )
    {
    return "UsePointFieldData";
    }
  else if ( this->ScalarMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA )
    {
    return "UseCellFieldData";
    }
  else
    {
    return "Default";
    }
}

const char *vtkMapper::GetScalarMaterialModeAsString(void)
{
  if ( this->ColorMode == VTK_MATERIALMODE_AMBIENT )
    {
    return "Ambient";
    }
  else if ( this->ColorMode == VTK_MATERIALMODE_DIFFUSE )
    {
    return "Diffuse";
    }
  else if ( this->ColorMode == VTK_MATERIALMODE_AMBIENT_AND_DIFFUSE )
    {
    return "Ambient and Diffuse";
    }
  else
    {
    return "Default";
    }
}

void vtkMapper::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  if ( this->LookupTable )
    {
    os << indent << "Lookup Table:\n";
    this->LookupTable->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << indent << "Lookup Table: (none)\n";
    }

  os << indent << "Immediate Mode Rendering: "
    << (this->ImmediateModeRendering ? "On\n" : "Off\n");
  os << indent << "Global Immediate Mode Rendering: " <<
    (vtkMapperGlobalImmediateModeRendering ? "On\n" : "Off\n");

  os << indent << "Scalar Visibility: "
    << (this->ScalarVisibility ? "On\n" : "Off\n");

  double *range = this->GetScalarRange();
  os << indent << "Scalar Range: (" << range[0] << ", " << range[1] << ")\n";

  os << indent << "UseLookupTableScalarRange: "
     << this->UseLookupTableScalarRange << "\n";

  os << indent << "Color Mode: " << this->GetColorModeAsString() << endl;

  os << indent << "Scalar Mode: " << this->GetScalarModeAsString() << endl;

  os << indent << "LM Color Mode: "
     << this->GetScalarMaterialModeAsString() << endl;

  os << indent << "RenderTime: " << this->RenderTime << endl;

  os << indent << "Resolve Coincident Topology: ";
  if ( vtkMapperGlobalResolveCoincidentTopology == VTK_RESOLVE_OFF )
    {
    os << "Off" << endl;
    }
  else if ( vtkMapperGlobalResolveCoincidentTopology == VTK_RESOLVE_POLYGON_OFFSET )
    {
    os << "Polygon Offset" << endl;
    }
  else
    {
    os << "Shift Z-Buffer" << endl;
    }
}
<commit_msg>Fixed warning<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkMapper.cxx

  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notice for more information.

=========================================================================*/
#include "vtkMapper.h"

#include "vtkDataSet.h"
#include "vtkLookupTable.h"
#include "vtkMath.h"

vtkCxxRevisionMacro(vtkMapper, "1.111");

// Initialize static member that controls global immediate mode rendering
static int vtkMapperGlobalImmediateModeRendering = 0;

// Initialize static member that controls global coincidence resolution
static int vtkMapperGlobalResolveCoincidentTopology = VTK_RESOLVE_OFF;
static double vtkMapperGlobalResolveCoincidentTopologyZShift = 0.01;
static double vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetFactor = 1.0;
static double vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetUnits = 1.0;

// Construct with initial range (0,1).
vtkMapper::vtkMapper()
{
  this->Colors = NULL;

  this->LookupTable = NULL;

  this->ScalarVisibility = 1;
  this->ScalarRange[0] = 0.0; this->ScalarRange[1] = 1.0;
  this->UseLookupTableScalarRange = 0;

  this->ImmediateModeRendering = 0;

  this->ColorMode = VTK_COLOR_MODE_DEFAULT;
  this->ScalarMode = VTK_SCALAR_MODE_DEFAULT;
  this->ScalarMaterialMode = VTK_MATERIALMODE_DEFAULT;

  vtkMath::UninitializeBounds(this->Bounds);
  this->Center[0] = this->Center[1] = this->Center[2] = 0.0;

  this->RenderTime = 0.0;

  strcpy(this->ArrayName, "");
  this->ArrayId = -1;
  this->ArrayComponent = 0;
  this->ArrayAccessMode = VTK_GET_ARRAY_BY_ID;
}

vtkMapper::~vtkMapper()
{
  if (this->LookupTable)
    {
    this->LookupTable->UnRegister(this);
    }
  if ( this->Colors != NULL )
    {
    this->Colors->UnRegister(this);
    }
}

// Get the bounds for the input of this mapper as
// (Xmin,Xmax,Ymin,Ymax,Zmin,Zmax).
double *vtkMapper::GetBounds()
{
  static double bounds[] = {-1.0,1.0, -1.0,1.0, -1.0,1.0};

  if ( ! this->GetInput() )
    {
    return bounds;
    }
  else
    {
    this->Update();
    this->GetInput()->GetBounds(this->Bounds);
    return this->Bounds;
    }
}

vtkDataSet *vtkMapper::GetInput()
{
  if (this->NumberOfInputs < 1)
    {
    return NULL;
    }

  return (vtkDataSet *)(this->Inputs[0]);
}

void vtkMapper::SetGlobalImmediateModeRendering(int val)
{
  if (val == vtkMapperGlobalImmediateModeRendering)
    {
    return;
    }
  vtkMapperGlobalImmediateModeRendering = val;
}

int vtkMapper::GetGlobalImmediateModeRendering()
{
  return vtkMapperGlobalImmediateModeRendering;
}

void vtkMapper::SetResolveCoincidentTopology(int val)
{
  if (val == vtkMapperGlobalResolveCoincidentTopology)
    {
    return;
    }
  vtkMapperGlobalResolveCoincidentTopology = val;
}

int vtkMapper::GetResolveCoincidentTopology()
{
  return vtkMapperGlobalResolveCoincidentTopology;
}

void vtkMapper::SetResolveCoincidentTopologyToDefault()
{
  vtkMapperGlobalResolveCoincidentTopology = VTK_RESOLVE_OFF;
}

void vtkMapper::SetResolveCoincidentTopologyZShift(double val)
{
  if (val == vtkMapperGlobalResolveCoincidentTopologyZShift)
    {
    return;
    }
  vtkMapperGlobalResolveCoincidentTopologyZShift = val;
}

double vtkMapper::GetResolveCoincidentTopologyZShift()
{
  return vtkMapperGlobalResolveCoincidentTopologyZShift;
}

void vtkMapper::SetResolveCoincidentTopologyPolygonOffsetParameters(
                                            double factor, double units)
{
  if (factor == vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetFactor &&
      units == vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetUnits )
    {
    return;
    }
  vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetFactor = factor;
  vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetUnits = units;
}

void vtkMapper::GetResolveCoincidentTopologyPolygonOffsetParameters(
                           double& factor, double& units)
{
  factor = vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetFactor;
  units = vtkMapperGlobalResolveCoincidentTopologyPolygonOffsetUnits;
}

// Overload standard modified time function. If lookup table is modified,
// then this object is modified as well.
unsigned long vtkMapper::GetMTime()
{
  //unsigned long mTime=this->MTime.GetMTime();
  unsigned long mTime=vtkAbstractMapper::GetMTime();
  unsigned long lutMTime;

  if ( this->LookupTable != NULL )
    {
    lutMTime = this->LookupTable->GetMTime();
    mTime = ( lutMTime > mTime ? lutMTime : mTime );
    }

  return mTime;
}

void vtkMapper::ShallowCopy(vtkAbstractMapper *mapper)
{
  vtkMapper *m = vtkMapper::SafeDownCast(mapper);
  if ( m != NULL )
    {
    this->SetLookupTable(m->GetLookupTable());
    this->SetScalarVisibility(m->GetScalarVisibility());
    this->SetScalarRange(m->GetScalarRange());
    this->SetColorMode(m->GetColorMode());
    this->SetScalarMode(m->GetScalarMode());
    this->SetScalarMaterialMode(m->GetScalarMaterialMode());
    this->SetImmediateModeRendering(m->GetImmediateModeRendering());
    this->SetUseLookupTableScalarRange(m->GetUseLookupTableScalarRange());
    if ( m->GetArrayAccessMode() == VTK_GET_ARRAY_BY_ID )
      {
      this->ColorByArrayComponent(m->GetArrayId(),m->GetArrayComponent());
      }
    else
      {
      this->ColorByArrayComponent(m->GetArrayName(),m->GetArrayComponent());
      }
    }

  // Now do superclass
  this->vtkAbstractMapper3D::ShallowCopy(mapper);

}

// a side effect of this is that this->Colors is also set
// to the return value
vtkUnsignedCharArray *vtkMapper::MapScalars(double alpha)
{
  // Lets try to resuse the old colors.
  if (this->ScalarVisibility && this->Colors)
    {
    if (this->LookupTable && this->LookupTable->GetAlpha() == alpha)
      {
        GetScalars(this->GetInput(), this->ScalarMode, this->ArrayAccessMode,
                   this->ArrayId, this->ArrayName, this->ArrayComponent);
      if (this->GetMTime() < this->Colors->GetMTime() &&
          this->GetInput() &&
          this->GetInput()->GetMTime() < this->Colors->GetMTime())
        {
        return this->Colors;
        }
      }
    }

  // Get rid of old colors
  if ( this->Colors )
    {
    this->Colors->UnRegister(this);
    this->Colors = NULL;
    }

  // map scalars if necessary
  if ( this->ScalarVisibility )
    {
    vtkDataArray *scalars = vtkAbstractMapper::
      GetScalars(this->GetInput(), this->ScalarMode, this->ArrayAccessMode,
                 this->ArrayId, this->ArrayName, this->ArrayComponent);
    if ( scalars )
      {
      if ( scalars->GetLookupTable() )
        {
        this->SetLookupTable(scalars->GetLookupTable());
        }
      else
        {
        // make sure we have a lookup table
        if ( this->LookupTable == NULL )
          {
          this->CreateDefaultLookupTable();
          }
        this->LookupTable->Build();
        }
      if ( !this->UseLookupTableScalarRange )
        {
        this->LookupTable->SetRange(this->ScalarRange);
        }
      this->LookupTable->SetAlpha(alpha);
      this->Colors = this->LookupTable->
        MapScalars(scalars, this->ColorMode, this->ArrayComponent);
      // Consistent register and unregisters
      this->Colors->Register(this);
      this->Colors->Delete();
      }
    }

  return this->Colors;
}

void vtkMapper::SelectColorArray(int arrayNum)
{
  this->ColorByArrayComponent(arrayNum, -1);
}

void vtkMapper::SelectColorArray(const char* arrayName)
{
  this->ColorByArrayComponent(arrayName, -1);
}

void vtkMapper::ColorByArrayComponent(int arrayNum, int component)
{
  if (this->ArrayId == arrayNum && component == this->ArrayComponent &&
      this->ArrayAccessMode == VTK_GET_ARRAY_BY_ID)
    {
    return;
    }
  this->Modified();

  this->ArrayId = arrayNum;
  this->ArrayComponent = component;
  this->ArrayAccessMode = VTK_GET_ARRAY_BY_ID;
}

void vtkMapper::ColorByArrayComponent(const char* arrayName, int component)
{
  if (!arrayName ||
      ( strcmp(this->ArrayName, arrayName) == 0 &&
        component == this->ArrayComponent &&
        this->ArrayAccessMode == VTK_GET_ARRAY_BY_ID ))
    {
    return;
    }
  this->Modified();

  strcpy(this->ArrayName, arrayName);
  this->ArrayComponent = component;
  this->ArrayAccessMode = VTK_GET_ARRAY_BY_NAME;
}

// Specify a lookup table for the mapper to use.
void vtkMapper::SetLookupTable(vtkScalarsToColors *lut)
{
  if ( this->LookupTable != lut )
    {
    if ( this->LookupTable)
      {
      this->LookupTable->UnRegister(this);
      }
    this->LookupTable = lut;
    if (lut)
      {
      lut->Register(this);
      }
    this->Modified();
    }
}

vtkScalarsToColors *vtkMapper::GetLookupTable()
{
  if ( this->LookupTable == NULL )
    {
    this->CreateDefaultLookupTable();
    }
  return this->LookupTable;
}

void vtkMapper::CreateDefaultLookupTable()
{
  if ( this->LookupTable)
    {
    this->LookupTable->UnRegister(this);
    }
  this->LookupTable = vtkLookupTable::New();
  // Consistent Register/UnRegisters.
  this->LookupTable->Register(this);
  this->LookupTable->Delete();
}

// Update the network connected to this mapper.
void vtkMapper::Update()
{
  if ( this->GetInput() )
    {
    this->GetInput()->Update();
    }
}

// Return the method of coloring scalar data.
const char *vtkMapper::GetColorModeAsString(void)
{
  if ( this->ColorMode == VTK_COLOR_MODE_MAP_SCALARS )
    {
    return "MapScalars";
    }
  else
    {
    return "Default";
    }
}

// Return the method for obtaining scalar data.
const char *vtkMapper::GetScalarModeAsString(void)
{
  if ( this->ScalarMode == VTK_SCALAR_MODE_USE_CELL_DATA )
    {
    return "UseCellData";
    }
  else if ( this->ScalarMode == VTK_SCALAR_MODE_USE_POINT_DATA )
    {
    return "UsePointData";
    }
  else if ( this->ScalarMode == VTK_SCALAR_MODE_USE_POINT_FIELD_DATA )
    {
    return "UsePointFieldData";
    }
  else if ( this->ScalarMode == VTK_SCALAR_MODE_USE_CELL_FIELD_DATA )
    {
    return "UseCellFieldData";
    }
  else
    {
    return "Default";
    }
}

const char *vtkMapper::GetScalarMaterialModeAsString(void)
{
  if ( this->ColorMode == VTK_MATERIALMODE_AMBIENT )
    {
    return "Ambient";
    }
  else if ( this->ColorMode == VTK_MATERIALMODE_DIFFUSE )
    {
    return "Diffuse";
    }
  else if ( this->ColorMode == VTK_MATERIALMODE_AMBIENT_AND_DIFFUSE )
    {
    return "Ambient and Diffuse";
    }
  else
    {
    return "Default";
    }
}

void vtkMapper::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);

  if ( this->LookupTable )
    {
    os << indent << "Lookup Table:\n";
    this->LookupTable->PrintSelf(os,indent.GetNextIndent());
    }
  else
    {
    os << indent << "Lookup Table: (none)\n";
    }

  os << indent << "Immediate Mode Rendering: "
    << (this->ImmediateModeRendering ? "On\n" : "Off\n");
  os << indent << "Global Immediate Mode Rendering: " <<
    (vtkMapperGlobalImmediateModeRendering ? "On\n" : "Off\n");

  os << indent << "Scalar Visibility: "
    << (this->ScalarVisibility ? "On\n" : "Off\n");

  double *range = this->GetScalarRange();
  os << indent << "Scalar Range: (" << range[0] << ", " << range[1] << ")\n";

  os << indent << "UseLookupTableScalarRange: "
     << this->UseLookupTableScalarRange << "\n";

  os << indent << "Color Mode: " << this->GetColorModeAsString() << endl;

  os << indent << "Scalar Mode: " << this->GetScalarModeAsString() << endl;

  os << indent << "LM Color Mode: "
     << this->GetScalarMaterialModeAsString() << endl;

  os << indent << "RenderTime: " << this->RenderTime << endl;

  os << indent << "Resolve Coincident Topology: ";
  if ( vtkMapperGlobalResolveCoincidentTopology == VTK_RESOLVE_OFF )
    {
    os << "Off" << endl;
    }
  else if ( vtkMapperGlobalResolveCoincidentTopology == VTK_RESOLVE_POLYGON_OFFSET )
    {
    os << "Polygon Offset" << endl;
    }
  else
    {
    os << "Shift Z-Buffer" << endl;
    }
}
<|endoftext|>


<commit_before>#include "FilesApi_p.hpp"

#include "ApiUtils.hpp"
#include "ClientBackend.hpp"
#include "ClientConnection.hpp"
#include "ClientRpcLayer.hpp"
#include "ConnectionApi_p.hpp"
#include "DataStorage_p.hpp"
#include "Debug_p.hpp"
#include "Operations/ConnectionOperation.hpp"
#include "Operations/FileOperation_p.hpp"
#include "RpcLayers/ClientRpcUploadLayer.hpp"

#include <QIODevice>
#include <QLoggingCategory>
#include <QTimer>

Q_LOGGING_CATEGORY(lcFilesApi, "telegram.client.api.files", QtWarningMsg)

namespace Telegram {

namespace Client {

FilesApiPrivate::FilesApiPrivate(FilesApi *parent) :
    ClientApiPrivate(parent)
{
    m_uploadLayer = new UploadRpcLayer(this);

    if (lcFilesApi().isDebugEnabled()) {
        m_monitorTimer = new QTimer(this);
        m_monitorTimer->setInterval(5000);
        m_monitorTimer->setSingleShot(false);
        connect(m_monitorTimer, &QTimer::timeout, this, &FilesApiPrivate::dumpCurrentState);
        m_monitorTimer->start();
    }
}

FilesApiPrivate *FilesApiPrivate::get(FilesApi *parent)
{
    return reinterpret_cast<FilesApiPrivate*>(parent->d);
}

/* Download FileOperation does not fail on network errors.
 * FileOperation fails if:
 * - the file location is not valid. E.g.
 *   - if we has no such DC in DC Configuration or
 *   - the server returns InvalidLocation or similar error
 */
FileOperation *FilesApiPrivate::downloadFile(const QString &fileId, QIODevice *output)
{
    const FileInfo::Private info = FileInfo::Private::fromFileId(fileId);
    if (!info.isValid()) {
        return PendingOperation::failOperation<FileOperation>
                (QLatin1String("Invalid RemoteFile for getFile()"), this);
    }

    FileInfo *file = new FileInfo();
    FileInfo::Private *filePriv = FileInfo::Private::get(file);
    *filePriv = info;

    const FileRequestDescriptor descriptor = FileRequestDescriptor::downloadRequest(info.dcId(), info.getInputFileLocation(), info.size());
    FileOperation *operation = addFileRequest(descriptor, output);
    FileOperationPrivate *privOperation = FileOperationPrivate::get(operation);
    privOperation->m_fileInfo = file;
    return operation;
}

FileOperation *FilesApiPrivate::downloadFile(const FileInfo *file, QIODevice *output)
{
    if (!file->isValid()) {
        return PendingOperation::failOperation<FileOperation>
                (QLatin1String("Invalid FileInfo for getFile()"), this);
    }

    const FileInfo::Private *filePriv = FileInfo::Private::get(file);
    const FileRequestDescriptor descriptor = FileRequestDescriptor::downloadRequest(filePriv->dcId(), filePriv->getInputFileLocation(), filePriv->size());
    FileOperation *operation = addFileRequest(descriptor, output);
    FileOperationPrivate *privOperation = FileOperationPrivate::get(operation);
    privOperation->m_fileInfo = new FileInfo(*file);
    return operation;
}

FileOperation *FilesApiPrivate::uploadFile(const QByteArray &fileContent, const QString &fileName)
{
    return PendingOperation::failOperation<FileOperation>
            (QLatin1String("Not implemented"), this);
}

FileOperation *FilesApiPrivate::uploadFile(QIODevice *source, const QString &fileName)
{
    return PendingOperation::failOperation<FileOperation>
            (QLatin1String("Not implemented"), this);
}

FileOperation *FilesApiPrivate::addFileRequest(const FileRequestDescriptor &descriptor, QIODevice *device)
{
    if (descriptor.type() == FileRequestDescriptor::Download) {
        qCDebug(lcFilesApi) << __func__ << descriptor.dcId() << descriptor.inputLocation().tlType;
    } else if (descriptor.type() == FileRequestDescriptor::Upload) {
        qCDebug(lcFilesApi) << __func__ << descriptor.dcId() << descriptor.fileId();
    }

    if (!descriptor.isValid()) {
        qCDebug(lcFilesApi) << __func__ << "Invalid descriptor";
        return PendingOperation::failOperation<FileOperation>
                (QLatin1String("Unable to addFileRequest(): Invalid FileRequestDescriptor"), this);
    }

    FileOperation *operation = new FileOperation(this);
    FileOperationPrivate *privOperation = FileOperationPrivate::get(operation);
    privOperation->m_descriptor = descriptor;
    privOperation->ensureDeviceIsSet(device);
    m_fileRequests.enqueue(operation);

    if (!m_currentOperation) {
        processNextRequest();
    }

    return operation;
}

void FilesApiPrivate::dumpCurrentState() const
{
    if (m_currentOperation) {
        qCInfo(lcFilesApi) << "Current operation:" << m_currentOperation;
        const FileOperationPrivate *privOperation = FileOperationPrivate::get(m_currentOperation);
        qCInfo(lcFilesApi) << "  Child:" << privOperation->m_childOperation;
        qCInfo(lcFilesApi) << "  Status:" << privOperation->m_transferStatus;
    } else {
        qCInfo(lcFilesApi) << "No current operation";
    }
    if (m_fileRequests.isEmpty()) {
        qCInfo(lcFilesApi) << "No file requests in queue";
    } else {
        qCInfo(lcFilesApi) << m_fileRequests.count() << "requests in queue";
    }
}

void FilesApiPrivate::processNextRequest()
{
    if (m_fileRequests.isEmpty()) {
        m_currentOperation = nullptr;
        return;
    }

    m_currentOperation = m_fileRequests.dequeue();
    connect(m_currentOperation, &FileOperation::finished,
            this, &FilesApiPrivate::onFileOperationFinished);

    qCDebug(lcFilesApi) << __func__ << "Current operation:" << m_currentOperation;
    FileOperationPrivate *privOperation = FileOperationPrivate::get(m_currentOperation);
    privOperation->prepareForDownload();

    processCurrentRequest();
}

void FilesApiPrivate::processCurrentRequest()
{
    qCDebug(lcFilesApi) << __func__;
    FileOperationPrivate *privOperation = FileOperationPrivate::get(m_currentOperation);
    ConnectOperation *connectionOperation = ensureConnection(privOperation->dcId());
    privOperation->m_childOperation = connectionOperation;

    if (connectionOperation->isFinished()) {
        onConnectOperationFinished(connectionOperation);
    } else {
        connectionOperation->connectToFinished(this, &FilesApiPrivate::onConnectOperationFinished,
                                     connectionOperation);
    }
}

bool FilesApiPrivate::isConnectionNeeded(quint32 dcId) const
{
    if (m_currentOperation) {
        const FileOperationPrivate *privOperation = FileOperationPrivate::get(m_currentOperation);
        if (privOperation->dcId() == dcId) {
            return true;
        }
    }

// Wanted to parallel operations:
//    for (const FileOperation *operation : m_fileRequests) {
//        const FileOperationPrivate *privOperation = FileOperationPrivate::get(operation);
//        if (privOperation->dcId() == dcId) {
//            return true;
//        }
//    }

    return false;
}

ConnectOperation *FilesApiPrivate::ensureConnection(quint32 dcId)
{
    ConnectionApiPrivate *privConnectionApi = ConnectionApiPrivate::get(backend()->connectionApi());
    const ConnectionSpec spec(dcId, ConnectionSpec::RequestFlag::MediaOnly);
    return privConnectionApi->connectToExtraDc(spec);
}

void FilesApiPrivate::processFileRequestForConnection(FileOperation *operation, Connection *connection)
{
    FileOperationPrivate *privOperation = FileOperationPrivate::get(operation);
    privOperation->m_transferStatus = FileOperationPrivate::TransferStatus::TransferringBytes;
    const FileRequestDescriptor &descriptor = privOperation->m_descriptor;
    UploadRpcLayer::PendingUploadFile *rpcOperation = nullptr;
    rpcOperation = uploadLayer()->getFile(descriptor.inputLocation(), descriptor.offset(), descriptor.chunkSize());
    qCDebug(lcFilesApi) << __func__ << operation << connection->dcOption().id << rpcOperation;
    privOperation->m_childOperation = rpcOperation;
    connection->rpcLayer()->sendRpc(rpcOperation);
    rpcOperation->connectToFinished(this, &FilesApiPrivate::onGetFileResult, operation, rpcOperation);
}

void FilesApiPrivate::onGetFileResult(FileOperation *operation, UploadRpcLayer::PendingUploadFile *rpcOperation)
{
    qCDebug(lcFilesApi) << __func__ << operation;
    TLUploadFile result;
    if (rpcOperation->isFailed()) {
        qCDebug(lcFilesApi) << __func__ << "failed" << rpcOperation->errorDetails();
        if (rpcOperation->errorDetails().contains(Connection::c_statusKey())) {
            // The operation failed due to connection lost
            // Schedule full retry
            if (m_currentOperation == operation) {
                // We can work only with one queue ATM
                QMetaObject::invokeMethod(this, "processCurrentRequest", Qt::QueuedConnection); // Invoke after return
                return;
            } else {
                qCCritical(lcFilesApi) << __func__ << "Unprocessed failed operation" << operation << rpcOperation;
            }
        }

        operation->setFinishedWithError(rpcOperation->errorDetails());
        return;
    }
    rpcOperation->getResult(&result);

    FileOperationPrivate *privOperation = FileOperationPrivate::get(operation);
    static const QVector<TLValue> badTypes = {
        TLValue::StorageFileUnknown,
        TLValue::StorageFilePartial,
    };
    if (result.type.isValid() && !badTypes.contains(result.type.tlType)) {
        // has type!
        const QString typeStr = Utils::mimeTypeByStorageFileType(result.type.tlType);
        if (!typeStr.isEmpty()) {
            FileInfo *fileInfo = privOperation->m_fileInfo;
            FileInfo::Private::get(fileInfo)->setMimeType(typeStr);
        }
    }
    operation->device()->write(result.bytes);

    FileRequestDescriptor &descriptor = privOperation->m_descriptor;
    const quint32 totalBytesDownloaded = descriptor.offset() + result.bytes.size();
    privOperation->m_totalTransferredBytes = totalBytesDownloaded;

#ifdef DEVELOPER_BUILD
    qCDebug(lcFilesApi).nospace() << operation
                                  << " download progress: "
                                  << totalBytesDownloaded << '/' << descriptor.size();
#endif // DEVELOPER_BUILD

    bool finished = false;
    if (descriptor.size()) {
        if (result.bytes.isEmpty()) {
            static const QString text = QLatin1String("Invalid download: zero bytes received");
            operation->setFinishedWithTextError(text);
            qCWarning(lcFilesApi) << __func__ << text;
            return;
        }

        finished = totalBytesDownloaded == descriptor.size();
    } else {
        finished = result.bytes.isEmpty() || (result.bytes.size() % 1024);
    }

    if (finished) {
        descriptor.setSize(totalBytesDownloaded);
    }

    if (finished) {
        privOperation->m_transferStatus = FileOperationPrivate::TransferStatus::Finished;
        privOperation->finalizeDownload();
        operation->setFinished();
        return;
    }

    descriptor.setOffset(totalBytesDownloaded);

    Connection *connection = Connection::fromOperation(rpcOperation);
    processFileRequestForConnection(operation, connection);
}

void FilesApiPrivate::onOperationCanceled(PendingOperation *operation)
{
    // TODO
}

void FilesApiPrivate::onConnectOperationFinished(ConnectOperation *operation)
{
    Connection *connection = operation->connection();
    qCDebug(lcFilesApi) << __func__ << operation << operation->errorDetails() << connection;

    if (!m_currentOperation) {
        return;
    }

    FileOperationPrivate *privOperation = FileOperationPrivate::get(m_currentOperation);
    if (privOperation->m_childOperation != operation) {
        qCWarning(lcFilesApi) << __func__ << "Unexpected connection operation" << operation
                              << "for" << m_currentOperation;
        return;
    }

    if (connection->dcOption().id != privOperation->dcId()) {
        qCWarning(lcFilesApi) << "Invalid operation dcOption";
        return;
    }

    privOperation->m_childOperation = nullptr;
    if (operation->isFailed()) {
        qCDebug(lcFilesApi) << __func__ << m_currentOperation
                            << "failed due to connection" << operation->errorDetails();

        privOperation->m_transferStatus = FileOperationPrivate::TransferStatus::Finished;
        m_currentOperation->setFinishedWithError(operation->errorDetails());
        return;
    }

    privOperation->m_transferStatus = FileOperationPrivate::TransferStatus::WaitingForAuthorization;

    connect(connection, &Connection::statusChanged, this, &FilesApiPrivate::onConnectionStatusChanged, Qt::UniqueConnection);
    processConnectionStatus(connection);
}

void FilesApiPrivate::onFileOperationFinished(PendingOperation *operation)
{
    if (operation != m_currentOperation) {
        return;
    }
    m_currentOperation = nullptr;
    processNextRequest();
}

void FilesApiPrivate::onConnectionStatusChanged()
{
    processConnectionStatus(qobject_cast<Connection *>(sender()));
}

void FilesApiPrivate::processConnectionStatus(Connection *connection)
{
    if (!connection) {
        // Invalid call
        return;
    }

    if (!m_currentOperation) {
        return;
    }

    qCDebug(lcFilesApi) << __func__ << connection << connection->status();

    const bool mediaConnection = connection->dcOption().flags & DcOption::MediaOnly;
    if (!mediaConnection) {
        qCDebug(lcFilesApi) << __func__ << "not media";
        return;
    }
    quint32 dcId = connection->dcOption().id;
    if (!isConnectionNeeded(dcId)) {
        qCDebug(lcFilesApi) << __func__ << "dc not needed";
        return;
    }
    // DC needed.

    switch (connection->status()) {
    case Connection::Status::Signed:
        processFileRequestForConnection(m_currentOperation, connection);
        break;
    case Connection::Status::Disconnected:
        ensureConnection(dcId);
        break;
    default:
        break;
    }
}

/*!
    \class Telegram::Client::FilesApi
    \brief Provides an API to work download and upload files.

    \inmodule TelegramQt
    \ingroup Client
*/
FilesApi::FilesApi(QObject *parent) :
    ClientApi(parent)
{
    d = new FilesApiPrivate(this);
}

FileOperation *FilesApi::downloadFile(const QString &fileId, QIODevice *output)
{
    Q_D(FilesApi);
    return d->downloadFile(fileId, output);
}

FileOperation *FilesApi::downloadFile(const FileInfo *file, QIODevice *output)
{
    Q_D(FilesApi);
    return d->downloadFile(file, output);
}

FileOperation *FilesApi::uploadFile(const QByteArray &data, const QString &fileName)
{
    Q_D(FilesApi);
    return d->uploadFile(data, fileName);
}

FileOperation *FilesApi::uploadFile(QIODevice *input, const QString &fileName)
{
    Q_D(FilesApi);
    return d->uploadFile(input, fileName);
}

} // Client namespace

} // Telegram namespace
<commit_msg>FilesApi: Fix GetFile() for Qt 5.10+<commit_after>#include "FilesApi_p.hpp"

#include "ApiUtils.hpp"
#include "ClientBackend.hpp"
#include "ClientConnection.hpp"
#include "ClientRpcLayer.hpp"
#include "ConnectionApi_p.hpp"
#include "DataStorage_p.hpp"
#include "Debug_p.hpp"
#include "Operations/ConnectionOperation.hpp"
#include "Operations/FileOperation_p.hpp"
#include "RpcLayers/ClientRpcUploadLayer.hpp"

#include <QIODevice>
#include <QLoggingCategory>
#include <QTimer>

Q_LOGGING_CATEGORY(lcFilesApi, "telegram.client.api.files", QtWarningMsg)

namespace Telegram {

namespace Client {

FilesApiPrivate::FilesApiPrivate(FilesApi *parent) :
    ClientApiPrivate(parent)
{
    m_uploadLayer = new UploadRpcLayer(this);

    if (lcFilesApi().isDebugEnabled()) {
        m_monitorTimer = new QTimer(this);
        m_monitorTimer->setInterval(5000);
        m_monitorTimer->setSingleShot(false);
        connect(m_monitorTimer, &QTimer::timeout, this, &FilesApiPrivate::dumpCurrentState);
        m_monitorTimer->start();
    }
}

FilesApiPrivate *FilesApiPrivate::get(FilesApi *parent)
{
    return reinterpret_cast<FilesApiPrivate*>(parent->d);
}

/* Download FileOperation does not fail on network errors.
 * FileOperation fails if:
 * - the file location is not valid. E.g.
 *   - if we has no such DC in DC Configuration or
 *   - the server returns InvalidLocation or similar error
 */
FileOperation *FilesApiPrivate::downloadFile(const QString &fileId, QIODevice *output)
{
    const FileInfo::Private info = FileInfo::Private::fromFileId(fileId);
    if (!info.isValid()) {
        return PendingOperation::failOperation<FileOperation>
                (QLatin1String("Invalid RemoteFile for getFile()"), this);
    }

    FileInfo *file = new FileInfo();
    FileInfo::Private *filePriv = FileInfo::Private::get(file);
    *filePriv = info;

    const FileRequestDescriptor descriptor = FileRequestDescriptor::downloadRequest(info.dcId(), info.getInputFileLocation(), info.size());
    FileOperation *operation = addFileRequest(descriptor, output);
    FileOperationPrivate *privOperation = FileOperationPrivate::get(operation);
    privOperation->m_fileInfo = file;
    return operation;
}

FileOperation *FilesApiPrivate::downloadFile(const FileInfo *file, QIODevice *output)
{
    if (!file->isValid()) {
        return PendingOperation::failOperation<FileOperation>
                (QLatin1String("Invalid FileInfo for getFile()"), this);
    }

    const FileInfo::Private *filePriv = FileInfo::Private::get(file);
    const FileRequestDescriptor descriptor = FileRequestDescriptor::downloadRequest(filePriv->dcId(), filePriv->getInputFileLocation(), filePriv->size());
    FileOperation *operation = addFileRequest(descriptor, output);
    FileOperationPrivate *privOperation = FileOperationPrivate::get(operation);
    privOperation->m_fileInfo = new FileInfo(*file);
    return operation;
}

FileOperation *FilesApiPrivate::uploadFile(const QByteArray &fileContent, const QString &fileName)
{
    return PendingOperation::failOperation<FileOperation>
            (QLatin1String("Not implemented"), this);
}

FileOperation *FilesApiPrivate::uploadFile(QIODevice *source, const QString &fileName)
{
    return PendingOperation::failOperation<FileOperation>
            (QLatin1String("Not implemented"), this);
}

FileOperation *FilesApiPrivate::addFileRequest(const FileRequestDescriptor &descriptor, QIODevice *device)
{
    if (descriptor.type() == FileRequestDescriptor::Download) {
        qCDebug(lcFilesApi) << __func__ << descriptor.dcId() << descriptor.inputLocation().tlType;
    } else if (descriptor.type() == FileRequestDescriptor::Upload) {
        qCDebug(lcFilesApi) << __func__ << descriptor.dcId() << descriptor.fileId();
    }

    if (!descriptor.isValid()) {
        qCDebug(lcFilesApi) << __func__ << "Invalid descriptor";
        return PendingOperation::failOperation<FileOperation>
                (QLatin1String("Unable to addFileRequest(): Invalid FileRequestDescriptor"), this);
    }

    FileOperation *operation = new FileOperation(this);
    FileOperationPrivate *privOperation = FileOperationPrivate::get(operation);
    privOperation->m_descriptor = descriptor;
    privOperation->ensureDeviceIsSet(device);
    m_fileRequests.enqueue(operation);

    if (!m_currentOperation) {
        processNextRequest();
    }

    return operation;
}

void FilesApiPrivate::dumpCurrentState() const
{
    if (m_currentOperation) {
        qCInfo(lcFilesApi) << "Current operation:" << m_currentOperation;
        const FileOperationPrivate *privOperation = FileOperationPrivate::get(m_currentOperation);
        qCInfo(lcFilesApi) << "  Child:" << privOperation->m_childOperation;
        qCInfo(lcFilesApi) << "  Status:" << privOperation->m_transferStatus;
    } else {
        qCInfo(lcFilesApi) << "No current operation";
    }
    if (m_fileRequests.isEmpty()) {
        qCInfo(lcFilesApi) << "No file requests in queue";
    } else {
        qCInfo(lcFilesApi) << m_fileRequests.count() << "requests in queue";
    }
}

void FilesApiPrivate::processNextRequest()
{
    if (m_fileRequests.isEmpty()) {
        m_currentOperation = nullptr;
        return;
    }

    m_currentOperation = m_fileRequests.dequeue();
    connect(m_currentOperation, &FileOperation::finished,
            this, &FilesApiPrivate::onFileOperationFinished);

    qCDebug(lcFilesApi) << __func__ << "Current operation:" << m_currentOperation;
    FileOperationPrivate *privOperation = FileOperationPrivate::get(m_currentOperation);
    privOperation->prepareForDownload();

    processCurrentRequest();
}

void FilesApiPrivate::processCurrentRequest()
{
    qCDebug(lcFilesApi) << __func__;
    FileOperationPrivate *privOperation = FileOperationPrivate::get(m_currentOperation);
    ConnectOperation *connectionOperation = ensureConnection(privOperation->dcId());
    privOperation->m_childOperation = connectionOperation;

    if (connectionOperation->isFinished()) {
        onConnectOperationFinished(connectionOperation);
    } else {
        connectionOperation->connectToFinished(this, &FilesApiPrivate::onConnectOperationFinished,
                                     connectionOperation);
    }
}

bool FilesApiPrivate::isConnectionNeeded(quint32 dcId) const
{
    if (m_currentOperation) {
        const FileOperationPrivate *privOperation = FileOperationPrivate::get(m_currentOperation);
        if (privOperation->dcId() == dcId) {
            return true;
        }
    }

// Wanted to parallel operations:
//    for (const FileOperation *operation : m_fileRequests) {
//        const FileOperationPrivate *privOperation = FileOperationPrivate::get(operation);
//        if (privOperation->dcId() == dcId) {
//            return true;
//        }
//    }

    return false;
}

ConnectOperation *FilesApiPrivate::ensureConnection(quint32 dcId)
{
    ConnectionApiPrivate *privConnectionApi = ConnectionApiPrivate::get(backend()->connectionApi());
    const ConnectionSpec spec(dcId, ConnectionSpec::RequestFlag::MediaOnly);
    return privConnectionApi->connectToExtraDc(spec);
}

void FilesApiPrivate::processFileRequestForConnection(FileOperation *operation, Connection *connection)
{
    FileOperationPrivate *privOperation = FileOperationPrivate::get(operation);
    privOperation->m_transferStatus = FileOperationPrivate::TransferStatus::TransferringBytes;
    const FileRequestDescriptor &descriptor = privOperation->m_descriptor;
    UploadRpcLayer::PendingUploadFile *rpcOperation = nullptr;
    rpcOperation = uploadLayer()->getFile(descriptor.inputLocation(), descriptor.offset(), descriptor.chunkSize());
    qCDebug(lcFilesApi) << __func__ << operation << connection->dcOption().id << rpcOperation;
    privOperation->m_childOperation = rpcOperation;
    connection->rpcLayer()->sendRpc(rpcOperation);
    rpcOperation->connectToFinished(this, &FilesApiPrivate::onGetFileResult, operation, rpcOperation);
}

void FilesApiPrivate::onGetFileResult(FileOperation *operation, UploadRpcLayer::PendingUploadFile *rpcOperation)
{
    qCDebug(lcFilesApi) << __func__ << operation;
    TLUploadFile result;
    if (rpcOperation->isFailed()) {
        qCDebug(lcFilesApi) << __func__ << "failed" << rpcOperation->errorDetails();
        if (rpcOperation->errorDetails().contains(Connection::c_statusKey())) {
            // The operation failed due to connection lost
            // Schedule full retry
            if (m_currentOperation == operation) {
                // We can work only with one queue ATM
                // Invoke after return
#if QT_VERSION < QT_VERSION_CHECK(5, 10, 0)
                QMetaObject::invokeMethod(this, "processCurrentRequest", Qt::QueuedConnection);
#else
                QMetaObject::invokeMethod(this, &FilesApiPrivate::processCurrentRequest, Qt::QueuedConnection);
#endif
                return;
            } else {
                qCCritical(lcFilesApi) << __func__ << "Unprocessed failed operation" << operation << rpcOperation;
            }
        }

        operation->setFinishedWithError(rpcOperation->errorDetails());
        return;
    }
    rpcOperation->getResult(&result);

    FileOperationPrivate *privOperation = FileOperationPrivate::get(operation);
    static const QVector<TLValue> badTypes = {
        TLValue::StorageFileUnknown,
        TLValue::StorageFilePartial,
    };
    if (result.type.isValid() && !badTypes.contains(result.type.tlType)) {
        // has type!
        const QString typeStr = Utils::mimeTypeByStorageFileType(result.type.tlType);
        if (!typeStr.isEmpty()) {
            FileInfo *fileInfo = privOperation->m_fileInfo;
            FileInfo::Private::get(fileInfo)->setMimeType(typeStr);
        }
    }
    operation->device()->write(result.bytes);

    FileRequestDescriptor &descriptor = privOperation->m_descriptor;
    const quint32 totalBytesDownloaded = descriptor.offset() + result.bytes.size();
    privOperation->m_totalTransferredBytes = totalBytesDownloaded;

#ifdef DEVELOPER_BUILD
    qCDebug(lcFilesApi).nospace() << operation
                                  << " download progress: "
                                  << totalBytesDownloaded << '/' << descriptor.size();
#endif // DEVELOPER_BUILD

    bool finished = false;
    if (descriptor.size()) {
        if (result.bytes.isEmpty()) {
            static const QString text = QLatin1String("Invalid download: zero bytes received");
            operation->setFinishedWithTextError(text);
            qCWarning(lcFilesApi) << __func__ << text;
            return;
        }

        finished = totalBytesDownloaded == descriptor.size();
    } else {
        finished = result.bytes.isEmpty() || (result.bytes.size() % 1024);
    }

    if (finished) {
        descriptor.setSize(totalBytesDownloaded);
    }

    if (finished) {
        privOperation->m_transferStatus = FileOperationPrivate::TransferStatus::Finished;
        privOperation->finalizeDownload();
        operation->setFinished();
        return;
    }

    descriptor.setOffset(totalBytesDownloaded);

    Connection *connection = Connection::fromOperation(rpcOperation);
    processFileRequestForConnection(operation, connection);
}

void FilesApiPrivate::onOperationCanceled(PendingOperation *operation)
{
    // TODO
}

void FilesApiPrivate::onConnectOperationFinished(ConnectOperation *operation)
{
    Connection *connection = operation->connection();
    qCDebug(lcFilesApi) << __func__ << operation << operation->errorDetails() << connection;

    if (!m_currentOperation) {
        return;
    }

    FileOperationPrivate *privOperation = FileOperationPrivate::get(m_currentOperation);
    if (privOperation->m_childOperation != operation) {
        qCWarning(lcFilesApi) << __func__ << "Unexpected connection operation" << operation
                              << "for" << m_currentOperation;
        return;
    }

    if (connection->dcOption().id != privOperation->dcId()) {
        qCWarning(lcFilesApi) << "Invalid operation dcOption";
        return;
    }

    privOperation->m_childOperation = nullptr;
    if (operation->isFailed()) {
        qCDebug(lcFilesApi) << __func__ << m_currentOperation
                            << "failed due to connection" << operation->errorDetails();

        privOperation->m_transferStatus = FileOperationPrivate::TransferStatus::Finished;
        m_currentOperation->setFinishedWithError(operation->errorDetails());
        return;
    }

    privOperation->m_transferStatus = FileOperationPrivate::TransferStatus::WaitingForAuthorization;

    connect(connection, &Connection::statusChanged, this, &FilesApiPrivate::onConnectionStatusChanged, Qt::UniqueConnection);
    processConnectionStatus(connection);
}

void FilesApiPrivate::onFileOperationFinished(PendingOperation *operation)
{
    if (operation != m_currentOperation) {
        return;
    }
    m_currentOperation = nullptr;
    processNextRequest();
}

void FilesApiPrivate::onConnectionStatusChanged()
{
    processConnectionStatus(qobject_cast<Connection *>(sender()));
}

void FilesApiPrivate::processConnectionStatus(Connection *connection)
{
    if (!connection) {
        // Invalid call
        return;
    }

    if (!m_currentOperation) {
        return;
    }

    qCDebug(lcFilesApi) << __func__ << connection << connection->status();

    const bool mediaConnection = connection->dcOption().flags & DcOption::MediaOnly;
    if (!mediaConnection) {
        qCDebug(lcFilesApi) << __func__ << "not media";
        return;
    }
    quint32 dcId = connection->dcOption().id;
    if (!isConnectionNeeded(dcId)) {
        qCDebug(lcFilesApi) << __func__ << "dc not needed";
        return;
    }
    // DC needed.

    switch (connection->status()) {
    case Connection::Status::Signed:
        processFileRequestForConnection(m_currentOperation, connection);
        break;
    case Connection::Status::Disconnected:
        ensureConnection(dcId);
        break;
    default:
        break;
    }
}

/*!
    \class Telegram::Client::FilesApi
    \brief Provides an API to work download and upload files.

    \inmodule TelegramQt
    \ingroup Client
*/
FilesApi::FilesApi(QObject *parent) :
    ClientApi(parent)
{
    d = new FilesApiPrivate(this);
}

FileOperation *FilesApi::downloadFile(const QString &fileId, QIODevice *output)
{
    Q_D(FilesApi);
    return d->downloadFile(fileId, output);
}

FileOperation *FilesApi::downloadFile(const FileInfo *file, QIODevice *output)
{
    Q_D(FilesApi);
    return d->downloadFile(file, output);
}

FileOperation *FilesApi::uploadFile(const QByteArray &data, const QString &fileName)
{
    Q_D(FilesApi);
    return d->uploadFile(data, fileName);
}

FileOperation *FilesApi::uploadFile(QIODevice *input, const QString &fileName)
{
    Q_D(FilesApi);
    return d->uploadFile(input, fileName);
}

} // Client namespace

} // Telegram namespace
<|endoftext|>


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

#include <TelepathyQt4/Object>

#include "TelepathyQt4/_gen/object.moc.hpp"

namespace Tp
{

/**
 * \class Object
 * \ingroup clientobject
 * \headerfile TelepathyQt4/object.h <TelepathyQt4/Object>
 *
 * \brief The Object class provides an object with property notification.
 */

/**
 * Construct a new Object object.
 */
Object::Object()
    : QObject()
{
}

/**
 * Class destructor.
 */
Object::~Object()
{
}

/**
 * Notify that a property named \a propertyName changed.
 *
 * This method will emit propertyChanged() for \a propertyName.
 */
void Object::notify(const char *propertyName)
{
    emit propertyChanged(QLatin1String(propertyName));
}

} // Tp
<commit_msg>Tp::Object: Add \todo to use for more classes<commit_after>/**
 * This file is part of TelepathyQt4
 *
 * @copyright Copyright (C) 2010 Collabora Ltd. <http://www.collabora.co.uk/>
 * @copyright Copyright (C) 2010 Nokia Corporation
 * @license LGPL 2.1
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include <TelepathyQt4/Object>

#include "TelepathyQt4/_gen/object.moc.hpp"

namespace Tp
{

/**
 * \class Object
 * \ingroup clientobject
 * \headerfile TelepathyQt4/object.h <TelepathyQt4/Object>
 *
 * \brief The Object class provides an object with property notification.
 *
 * \todo Use for more classes beyond Account. Most importantly Contact.
 */

/**
 * Construct a new Object object.
 */
Object::Object()
    : QObject()
{
}

/**
 * Class destructor.
 */
Object::~Object()
{
}

/**
 * Notify that a property named \a propertyName changed.
 *
 * This method will emit propertyChanged() for \a propertyName.
 */
void Object::notify(const char *propertyName)
{
    emit propertyChanged(QLatin1String(propertyName));
}

} // Tp
<|endoftext|>