<commit_before>/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   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 */

#include "mysql_priv.h"
#include <stdarg.h>

	/* Send a error string to client */

void send_error(NET *net, uint sql_errno, const char *err)
{
  uint length;
  char buff[MYSQL_ERRMSG_SIZE+2];
  THD *thd=current_thd;
  DBUG_ENTER("send_error");
  DBUG_PRINT("enter",("sql_errno: %d  err: %s", sql_errno,
		      err ? err : net->last_error[0] ?
		      net->last_error : "NULL"));

  if (thd)
    thd->query_error = 1; // needed to catch query errors during replication
  if (!err)
  {
    if (sql_errno)
      err=ER(sql_errno);
    else if (!err)
    {
      if ((err=net->last_error)[0])
	sql_errno=net->last_errno;
      else
      {
	sql_errno=ER_UNKNOWN_ERROR;
	err=ER(sql_errno);	 /* purecov: inspected */
      }
    }
  }
  if (net->vio == 0)
  {
    if (thd && thd->bootstrap)
    {
      fprintf(stderr,"ERROR: %d  %s\n",sql_errno,err);
    }
    DBUG_VOID_RETURN;
  }

  if (net->return_errno)
  {				// new client code; Add errno before message
    int2store(buff,sql_errno);
    length= (uint) (strmake(buff+2,err,MYSQL_ERRMSG_SIZE-1) - buff);
    err=buff;
  }
  else
  {
    length=(uint) strlen(err);
    set_if_smaller(length,MYSQL_ERRMSG_SIZE);
  }
  VOID(net_write_command(net,(uchar) 255,(char*) err,length));
  if (thd)
    thd->fatal_error=0;			// Error message is given
  DBUG_VOID_RETURN;
}

/*
  At some point we need to be able to distinguish between warnings and
  errors; The following function will help make this easier.
*/

void send_warning(NET *net, uint sql_errno, const char *err)
{
  DBUG_ENTER("send_warning");
  send_error(net,sql_errno,err);
  DBUG_VOID_RETURN;
}

/**
** write error package and flush to client
** It's a little too low level, but I don't want to allow another buffer
*/
/* VARARGS3 */

void
net_printf(NET *net, uint errcode, ...)
{
  va_list args;
  uint length,offset;
  const char *format,*text_pos;
  int head_length= NET_HEADER_SIZE;
  THD *thd=current_thd;
  DBUG_ENTER("net_printf");
  DBUG_PRINT("enter",("message: %u",errcode));

  if(thd) thd->query_error = 1;
  // if we are here, something is wrong :-)

  va_start(args,errcode);
  format=ER(errcode);
  offset= net->return_errno ? 2 : 0;
  text_pos=(char*) net->buff+head_length+offset+1;
  (void) vsprintf(my_const_cast(char*) (text_pos),format,args);
  length=(uint) strlen((char*) text_pos);
  if (length >= sizeof(net->last_error))
    length=sizeof(net->last_error)-1;		/* purecov: inspected */
  va_end(args);

  if (net->vio == 0)
  {
    if (thd && thd->bootstrap)
    {
      fprintf(stderr,"ERROR: %d  %s\n",errcode,text_pos);
      thd->fatal_error=1;
    }
    DBUG_VOID_RETURN;
  }

  int3store(net->buff,length+1+offset);
  net->buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
  net->buff[head_length]=(uchar) 255;		// Error package
  if (offset)
    int2store(text_pos-2, errcode);
  VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset));
  if (thd)
    thd->fatal_error=0;			// Error message is given
  DBUG_VOID_RETURN;
}

void
send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message)
{
  if (net->no_send_ok)				// hack for re-parsing queries
    return;

  char buff[MYSQL_ERRMSG_SIZE+10],*pos;
  DBUG_ENTER("send_ok");
  buff[0]=0;					// No fields
  pos=net_store_length(buff+1,(ulonglong) affected_rows);
  pos=net_store_length(pos, (ulonglong) id);
  if (net->return_status)
  {
    int2store(pos,*net->return_status);
    pos+=2;
  }
  if (message)
    pos=net_store_data((char*) pos,message);
  if (net->vio != 0)
  {
    VOID(my_net_write(net,buff,(uint) (pos-buff)));
    VOID(net_flush(net));
  }
  DBUG_VOID_RETURN;
}

void
send_eof(NET *net,bool no_flush)
{
  static char eof_buff[1]= { (char) 254 };	/* Marker for end of fields */
  DBUG_ENTER("send_eof");
  if (net->vio != 0)
  {
    VOID(my_net_write(net,eof_buff,1));
    if (!no_flush)
      VOID(net_flush(net));
  }
  DBUG_VOID_RETURN;
}

/****************************************************************************
** Store a field length in logical packet
****************************************************************************/

char *
net_store_length(char *pkg, ulonglong length)
{
  uchar *packet=(uchar*) pkg;
  if (length < LL(251))
  {
    *packet=(uchar) length;
    return (char*) packet+1;
  }
  /* 251 is reserved for NULL */
  if (length < LL(65536))
  {
    *packet++=252;
    int2store(packet,(uint) length);
    return (char*) packet+2;
  }
  if (length < LL(16777216))
  {
    *packet++=253;
    int3store(packet,(ulong) length);
    return (char*) packet+3;
  }
  *packet++=254;
  int8store(packet,length);
  return (char*) packet+9;
}

char *
net_store_length(char *pkg, uint length)
{
  uchar *packet=(uchar*) pkg;
  if (length < 251)
  {
    *packet=(uchar) length;
    return (char*) packet+1;
  }
  *packet++=252;
  int2store(packet,(uint) length);
  return (char*) packet+2;
}

/* The following will only be used for short strings < 65K */
char *
net_store_data(char *to,const char *from)
{
  uint length=(uint) strlen(from);
  to=net_store_length(to,length);
  memcpy(to,from,length);
  return to+length;
}

char *
net_store_data(char *to,int32 from)
{
  char buff[20];
  uint length=(uint) (int10_to_str(from,buff,10)-buff);
  to=net_store_length(to,length);
  memcpy(to,buff,length);
  return to+length;
}

char *
net_store_data(char *to,longlong from)
{
  char buff[22];
  uint length=(uint) (longlong10_to_str(from,buff,10)-buff);
  to=net_store_length(to,length);
  memcpy(to,buff,length);
  return to+length;
}

bool net_store_null(String *packet)
{
  return packet->append((char) 251);
}

bool
net_store_data(String *packet,const char *from,uint length)
{
  ulong packet_length=packet->length();
  if (packet_length+5+length > packet->alloced_length() &&
      packet->realloc(packet_length+5+length))
    return 1;
  char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
				    (ulonglong) length);
  memcpy(to,from,length);
  packet->length((uint) (to+length-packet->ptr()));
  return 0;
}

/* The following is only used at short, null terminated data */

bool
net_store_data(String *packet,const char *from)
{
  uint length=(uint) strlen(from);
  uint packet_length=packet->length();
  if (packet_length+5+length > packet->alloced_length() &&
      packet->realloc(packet_length+5+length))
    return 1;
  char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
				    length);
  memcpy(to,from,length);
  packet->length((uint) (to+length-packet->ptr()));
  return 0;
}

bool
net_store_data(String *packet,uint32 from)
{
  char buff[20];
  return net_store_data(packet,(char*) buff,
			(uint) (int10_to_str(from,buff,10)-buff));
}

bool
net_store_data(String *packet, longlong from)
{
  char buff[22];
  return net_store_data(packet,(char*) buff,
			(uint) (longlong10_to_str(from,buff,10)-buff));
}

bool
net_store_data(String *packet,struct tm *tmp)
{
  char buff[20];
  sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d",
	  ((int) (tmp->tm_year+1900)) % 10000,
	  (int) tmp->tm_mon+1,
	  (int) tmp->tm_mday,
	  (int) tmp->tm_hour,
	  (int) tmp->tm_min,
	  (int) tmp->tm_sec);
  return net_store_data(packet,(char*) buff,19);
}

bool net_store_data(String* packet, I_List<i_string>* str_list)
{
  char buf[256];
  String tmp(buf, sizeof(buf));
  tmp.length(0);
  I_List_iterator<i_string> it(*str_list);
  i_string* s;

  while((s=it++))
  {
    if(tmp.length())
      tmp.append(',');
    tmp.append(s->ptr);
  }

  return net_store_data(packet, (char*)tmp.ptr(), tmp.length());
}

/*
** translate and store data; These are mainly used by the SHOW functions
*/

bool
net_store_data(String *packet,CONVERT *convert, const char *from,uint length)
{
  if (convert)
    return convert->store(packet, from, length);
  return net_store_data(packet,from,length);
}

bool
net_store_data(String *packet, CONVERT *convert, const char *from)
{
  uint length=(uint) strlen(from);
  if (convert)
    return convert->store(packet, from, length);
  return net_store_data(packet,from,length);
}
<commit_msg>Fixed wrong packed length for packet > 16M.<commit_after>/* Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult AB

   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 */

#include "mysql_priv.h"
#include <stdarg.h>

	/* Send a error string to client */

void send_error(NET *net, uint sql_errno, const char *err)
{
  uint length;
  char buff[MYSQL_ERRMSG_SIZE+2];
  THD *thd=current_thd;
  DBUG_ENTER("send_error");
  DBUG_PRINT("enter",("sql_errno: %d  err: %s", sql_errno,
		      err ? err : net->last_error[0] ?
		      net->last_error : "NULL"));

  if (thd)
    thd->query_error = 1; // needed to catch query errors during replication
  if (!err)
  {
    if (sql_errno)
      err=ER(sql_errno);
    else if (!err)
    {
      if ((err=net->last_error)[0])
	sql_errno=net->last_errno;
      else
      {
	sql_errno=ER_UNKNOWN_ERROR;
	err=ER(sql_errno);	 /* purecov: inspected */
      }
    }
  }
  if (net->vio == 0)
  {
    if (thd && thd->bootstrap)
    {
      fprintf(stderr,"ERROR: %d  %s\n",sql_errno,err);
    }
    DBUG_VOID_RETURN;
  }

  if (net->return_errno)
  {				// new client code; Add errno before message
    int2store(buff,sql_errno);
    length= (uint) (strmake(buff+2,err,MYSQL_ERRMSG_SIZE-1) - buff);
    err=buff;
  }
  else
  {
    length=(uint) strlen(err);
    set_if_smaller(length,MYSQL_ERRMSG_SIZE);
  }
  VOID(net_write_command(net,(uchar) 255,(char*) err,length));
  if (thd)
    thd->fatal_error=0;			// Error message is given
  DBUG_VOID_RETURN;
}

/*
  At some point we need to be able to distinguish between warnings and
  errors; The following function will help make this easier.
*/

void send_warning(NET *net, uint sql_errno, const char *err)
{
  DBUG_ENTER("send_warning");
  send_error(net,sql_errno,err);
  DBUG_VOID_RETURN;
}

/**
** write error package and flush to client
** It's a little too low level, but I don't want to allow another buffer
*/
/* VARARGS3 */

void
net_printf(NET *net, uint errcode, ...)
{
  va_list args;
  uint length,offset;
  const char *format,*text_pos;
  int head_length= NET_HEADER_SIZE;
  THD *thd=current_thd;
  DBUG_ENTER("net_printf");
  DBUG_PRINT("enter",("message: %u",errcode));

  if(thd) thd->query_error = 1;
  // if we are here, something is wrong :-)

  va_start(args,errcode);
  format=ER(errcode);
  offset= net->return_errno ? 2 : 0;
  text_pos=(char*) net->buff+head_length+offset+1;
  (void) vsprintf(my_const_cast(char*) (text_pos),format,args);
  length=(uint) strlen((char*) text_pos);
  if (length >= sizeof(net->last_error))
    length=sizeof(net->last_error)-1;		/* purecov: inspected */
  va_end(args);

  if (net->vio == 0)
  {
    if (thd && thd->bootstrap)
    {
      fprintf(stderr,"ERROR: %d  %s\n",errcode,text_pos);
      thd->fatal_error=1;
    }
    DBUG_VOID_RETURN;
  }

  int3store(net->buff,length+1+offset);
  net->buff[3]= (net->compress) ? 0 : (uchar) (net->pkt_nr++);
  net->buff[head_length]=(uchar) 255;		// Error package
  if (offset)
    int2store(text_pos-2, errcode);
  VOID(net_real_write(net,(char*) net->buff,length+head_length+1+offset));
  if (thd)
    thd->fatal_error=0;			// Error message is given
  DBUG_VOID_RETURN;
}

void
send_ok(NET *net,ha_rows affected_rows,ulonglong id,const char *message)
{
  if (net->no_send_ok)				// hack for re-parsing queries
    return;

  char buff[MYSQL_ERRMSG_SIZE+10],*pos;
  DBUG_ENTER("send_ok");
  buff[0]=0;					// No fields
  pos=net_store_length(buff+1,(ulonglong) affected_rows);
  pos=net_store_length(pos, (ulonglong) id);
  if (net->return_status)
  {
    int2store(pos,*net->return_status);
    pos+=2;
  }
  if (message)
    pos=net_store_data((char*) pos,message);
  if (net->vio != 0)
  {
    VOID(my_net_write(net,buff,(uint) (pos-buff)));
    VOID(net_flush(net));
  }
  DBUG_VOID_RETURN;
}

void
send_eof(NET *net,bool no_flush)
{
  static char eof_buff[1]= { (char) 254 };	/* Marker for end of fields */
  DBUG_ENTER("send_eof");
  if (net->vio != 0)
  {
    VOID(my_net_write(net,eof_buff,1));
    if (!no_flush)
      VOID(net_flush(net));
  }
  DBUG_VOID_RETURN;
}

/****************************************************************************
** Store a field length in logical packet
****************************************************************************/

char *
net_store_length(char *pkg, ulonglong length)
{
  uchar *packet=(uchar*) pkg;
  if (length < LL(251))
  {
    *packet=(uchar) length;
    return (char*) packet+1;
  }
  /* 251 is reserved for NULL */
  if (length < LL(65536))
  {
    *packet++=252;
    int2store(packet,(uint) length);
    return (char*) packet+2;
  }
  if (length < LL(16777216))
  {
    *packet++=253;
    int3store(packet,(ulong) length);
    return (char*) packet+3;
  }
  *packet++=254;
  int8store(packet,length);
  return (char*) packet+8;
}

char *
net_store_length(char *pkg, uint length)
{
  uchar *packet=(uchar*) pkg;
  if (length < 251)
  {
    *packet=(uchar) length;
    return (char*) packet+1;
  }
  *packet++=252;
  int2store(packet,(uint) length);
  return (char*) packet+2;
}

/* The following will only be used for short strings < 65K */
char *
net_store_data(char *to,const char *from)
{
  uint length=(uint) strlen(from);
  to=net_store_length(to,length);
  memcpy(to,from,length);
  return to+length;
}

char *
net_store_data(char *to,int32 from)
{
  char buff[20];
  uint length=(uint) (int10_to_str(from,buff,10)-buff);
  to=net_store_length(to,length);
  memcpy(to,buff,length);
  return to+length;
}

char *
net_store_data(char *to,longlong from)
{
  char buff[22];
  uint length=(uint) (longlong10_to_str(from,buff,10)-buff);
  to=net_store_length(to,length);
  memcpy(to,buff,length);
  return to+length;
}

bool net_store_null(String *packet)
{
  return packet->append((char) 251);
}

bool
net_store_data(String *packet,const char *from,uint length)
{
  ulong packet_length=packet->length();
  if (packet_length+5+length > packet->alloced_length() &&
      packet->realloc(packet_length+5+length))
    return 1;
  char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
				    (ulonglong) length);
  memcpy(to,from,length);
  packet->length((uint) (to+length-packet->ptr()));
  return 0;
}

/* The following is only used at short, null terminated data */

bool
net_store_data(String *packet,const char *from)
{
  uint length=(uint) strlen(from);
  uint packet_length=packet->length();
  if (packet_length+5+length > packet->alloced_length() &&
      packet->realloc(packet_length+5+length))
    return 1;
  char *to=(char*) net_store_length((char*) packet->ptr()+packet_length,
				    length);
  memcpy(to,from,length);
  packet->length((uint) (to+length-packet->ptr()));
  return 0;
}

bool
net_store_data(String *packet,uint32 from)
{
  char buff[20];
  return net_store_data(packet,(char*) buff,
			(uint) (int10_to_str(from,buff,10)-buff));
}

bool
net_store_data(String *packet, longlong from)
{
  char buff[22];
  return net_store_data(packet,(char*) buff,
			(uint) (longlong10_to_str(from,buff,10)-buff));
}

bool
net_store_data(String *packet,struct tm *tmp)
{
  char buff[20];
  sprintf(buff,"%04d-%02d-%02d %02d:%02d:%02d",
	  ((int) (tmp->tm_year+1900)) % 10000,
	  (int) tmp->tm_mon+1,
	  (int) tmp->tm_mday,
	  (int) tmp->tm_hour,
	  (int) tmp->tm_min,
	  (int) tmp->tm_sec);
  return net_store_data(packet,(char*) buff,19);
}

bool net_store_data(String* packet, I_List<i_string>* str_list)
{
  char buf[256];
  String tmp(buf, sizeof(buf));
  tmp.length(0);
  I_List_iterator<i_string> it(*str_list);
  i_string* s;

  while((s=it++))
  {
    if(tmp.length())
      tmp.append(',');
    tmp.append(s->ptr);
  }

  return net_store_data(packet, (char*)tmp.ptr(), tmp.length());
}

/*
** translate and store data; These are mainly used by the SHOW functions
*/

bool
net_store_data(String *packet,CONVERT *convert, const char *from,uint length)
{
  if (convert)
    return convert->store(packet, from, length);
  return net_store_data(packet,from,length);
}

bool
net_store_data(String *packet, CONVERT *convert, const char *from)
{
  uint length=(uint) strlen(from);
  if (convert)
    return convert->store(packet, from, length);
  return net_store_data(packet,from,length);
}
<|endoftext|>


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

#include "loader-png.h"

#include <cstring>
#include <cstdlib>

#include <zlib.h>
#include <png.h>

#include <dali/integration-api/bitmap.h>
#include <dali/integration-api/debug.h>
#include <dali/public-api/images/image.h>
#include "dali/public-api/math/math-utils.h"
#include "dali/public-api/math/vector2.h"
#include "platform-capabilities.h"

namespace Dali
{

using Integration::Bitmap;
using Dali::Integration::PixelBuffer;

namespace TizenPlatform
{

namespace
{

// simple class to enforce clean-up of PNG structures
struct auto_png
{
  auto_png(png_structp& _png, png_infop& _info)
  : png(_png),
    info(_info)
  {
  }

  ~auto_png()
  {
    if(NULL != png)
    {
      png_destroy_read_struct(&png, &info, NULL);
    }
  }

  png_structp& png;
  png_infop& info;
}; // struct auto_png;

bool LoadPngHeader(FILE *fp, unsigned int &width, unsigned int &height, png_structp &png, png_infop &info)
{
  png_byte header[8] = { 0 };

  // Check header to see if it is a PNG file
  size_t size = fread(header, 1, 8, fp);
  if(size != 8)
  {
    return false;
  }

  if(png_sig_cmp(header, 0, 8))
  {
    return false;
  }

  png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if(!png)
  {
    DALI_LOG_WARNING("Can't create PNG read structure\n");
    return false;
  }

  info = png_create_info_struct(png);
  if(!info)
  {
    DALI_LOG_WARNING("png_create_info_struct failed\n");
    return false;
  }

  png_set_expand(png);

  if(setjmp(png_jmpbuf(png)))
  {
    DALI_LOG_WARNING("error during png_init_io\n");
    return false;
  }

  png_init_io(png, fp);
  png_set_sig_bytes(png, 8);

  // read image info
  png_read_info(png, info);

  // dimensions
  width = png_get_image_width(png, info);
  height = png_get_image_height(png, info);

  return true;
}

} // namespace - anonymous

bool LoadPngHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
{
  png_structp png = NULL;
  png_infop info = NULL;
  auto_png autoPng(png, info);

  bool success = LoadPngHeader( input.file, width, height, png, info );

  return success;
}

bool LoadBitmapFromPng( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap )
{
  png_structp png = NULL;
  png_infop info = NULL;
  auto_png autoPng(png, info);

  /// @todo: consider parameters
  unsigned int y;
  unsigned int width, height;
  unsigned char *pixels;
  png_bytep *rows;
  unsigned int bpp = 0; // bytes per pixel
  bool valid = false;

  // Load info from the header
  if( !LoadPngHeader( input.file, width, height, png, info ) )
  {
    return false;
  }

  Pixel::Format pixelFormat = Pixel::RGBA8888;

  // decide pixel format
  unsigned int colordepth = png_get_bit_depth(png, info);

  // Ask PNGLib to convert high precision images into something we can use:
  if (colordepth == 16)
  {
    png_set_strip_16(png);
    colordepth = 8;
  }

  png_byte colortype = png_get_color_type(png, info);

  if(colortype == PNG_COLOR_TYPE_GRAY)
  {
    switch( colordepth )
    {
      case 8:
      {
        pixelFormat = Pixel::L8;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_GRAY_ALPHA)
  {
    switch(colordepth)
    {
      case 8:
      {
        pixelFormat = Pixel::LA88;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_RGB )
  {
    switch(colordepth)
    {
      case 8:
      {
        pixelFormat = Pixel::RGB888;
        valid = true;
        break;
      }
      case 5:      /// @todo is this correct for RGB16 5-6-5 ?
      {
        pixelFormat = Pixel::RGB565;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_RGBA)
  {
    switch(colordepth)
    {
      case 8:
      {
        pixelFormat = Pixel::RGBA8888;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_PALETTE)
  {
    switch(colordepth)
    {
      case 1:
      {
        pixelFormat = Pixel::LA88;
        valid = true;
        break;
      }

      case 2:
      case 4:
      case 8:
      {
        /* Expand paletted or RGB images with transparency to full alpha channels
         * so the data will be available as RGBA quartets. PNG_INFO_tRNS = 0x10
         */
        if(png_get_valid(png, info, PNG_INFO_tRNS) == 0x10)
        {
          pixelFormat = Pixel::RGBA8888;
          valid = true;
        }
        else
        {
          pixelFormat = Pixel::RGB888;
          png_set_packing(png);
          png_set_packswap(png);
          png_set_palette_to_rgb(png);
          valid = true;
        }
        break;
      }
      default:
      {
        break;
      }
    }
  }

  if( !valid )
  {
    DALI_LOG_WARNING( "Unsupported png format\n" );
    return false;
  }

  // bytes per pixel
  bpp = Pixel::GetBytesPerPixel(pixelFormat);

  png_read_update_info(png, info);

  if(setjmp(png_jmpbuf(png)))
  {
    DALI_LOG_WARNING("error during png_read_image\n");
    return false;
  }

  unsigned int rowBytes = png_get_rowbytes(png, info);

  unsigned int bufferWidth   = GetTextureDimension(width);
  unsigned int bufferHeight  = GetTextureDimension(height);
  unsigned int stride        = bufferWidth*bpp;

  // not sure if this ever happens
  if( rowBytes > stride )
  {
    stride = GetTextureDimension(rowBytes);
    bufferWidth = stride / bpp;
  }

  // decode the whole image into bitmap buffer
  pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(pixelFormat, width, height, bufferWidth, bufferHeight);

  DALI_ASSERT_DEBUG(pixels);
  rows = (png_bytep*) malloc(sizeof(png_bytep) * height);
  for(y=0; y<height; y++)
  {
    rows[y] = (png_byte*) (pixels + y * stride);
  }

  // decode image
  png_read_image(png, rows);

  free(rows);

  return true;
}

// simple class to enforce clean-up of PNG structures
struct AutoPngWrite
{
  AutoPngWrite(png_structp& _png, png_infop& _info)
  : png(_png),
    info(_info)
  {
    DALI_ASSERT_DEBUG(&_png != 0 && &_info != 0);
  }

  ~AutoPngWrite()
  {
    if(NULL != png)
    {
      png_destroy_write_struct(&png, &info);
    }
  }

  png_structp& png;
  png_infop& info;
}; // struct AutoPngWrite;

namespace
{
  // Custom libpng write callbacks that buffer to a vector instead of a file:

  /**
   * extern "C" linkage is used because this is a callback that we pass to a C
   * library which is part of the underlying platform and so potentially compiled
   * as C rather than C++.
   * @see http://stackoverflow.com/a/2594222
   * */
  extern "C" void WriteData(png_structp png_ptr, png_bytep data, png_size_t length)
  {
    DALI_ASSERT_DEBUG(png_ptr && data);
    if(!png_ptr || !data)
    {
      return;
    }
    // Make sure we don't try to propagate a C++ exception up the call stack of a pure C library:
    try
    {
      // Recover our buffer for writing into:
      Vector<unsigned char>* const encoded_img = static_cast< Vector<unsigned char>* >( png_get_io_ptr(png_ptr) );
      if(encoded_img)
      {
        const Vector<unsigned char>::SizeType bufferSize = encoded_img->Count();
        encoded_img->Reserve( bufferSize + length ); //< Can throw OOM.
        unsigned char* const bufferBack = encoded_img->Begin() + bufferSize;
        memcpy(bufferBack, data, length);
      }
      else
      {
        DALI_LOG_ERROR("PNG buffer for write to memory was passed from libpng as null.\n");
      }
    }
    catch(...)
    {
      DALI_LOG_ERROR("C++ Exception caught\n");
    }
  }

  /** Override the flush with a NOP to prevent libpng trying cstdlib file io. */
  extern "C" void FlushData(png_structp png_ptr)
  {
#ifdef DEBUG_ENABLED
    Debug::LogMessage(Debug::DebugInfo, "PNG Flush");
#endif // DEBUG_ENABLED
  }
}

/**
 * Potential improvements:
 * 1. Detect <= 256 colours and write in palette mode.
 * 2. Detect grayscale (will early-out quickly for colour images).
 * 3. Store colour space / gamma correction info related to the device screen?
 *    http://www.libpng.org/pub/png/book/chapter10.html
 * 4. Refactor with callers to write straight through to disk and save keeping a big buffer around.
 * 5. Prealloc buffer (reserve) to input size / <A number greater than 2 (expexcted few realloc but without using lots of memory) | 1 (expected zero reallocs but using a lot of memory)>.
 * 6. Set the modification time with png_set_tIME(png_ptr, info_ptr, mod_time);
 * 7. If caller asks for no compression, bypass libpng and blat raw data to
 *    disk, topped and tailed with header/tail blocks.
 */
bool EncodeToPng( const unsigned char* const pixelBuffer, Vector<unsigned char>& encodedPixels, std::size_t width, std::size_t height, Pixel::Format pixelFormat )
{
  // Translate pixel format enum:
  int pngPixelFormat = -1;
  unsigned pixelBytes = 0;
  bool rgbaOrder = true;

  // Account for RGB versus BGR and presence of alpha in input pixels:
  switch( pixelFormat )
  {
    case Pixel::RGB888:
    {
      pngPixelFormat = PNG_COLOR_TYPE_RGB;
      pixelBytes = 3;
      break;
    }
    case Pixel::BGRA8888:
    {
      rgbaOrder = false;
      ///! No break: fall through:
    }
    case Pixel::RGBA8888:
    {
      pngPixelFormat = PNG_COLOR_TYPE_RGB_ALPHA;
      pixelBytes = 4;
      break;
    }
    default:
    {
      DALI_LOG_ERROR( "Unsupported pixel format for encoding to PNG.\n" );
      return false;
    }
  }

  const int interlace = PNG_INTERLACE_NONE;

  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if(!png_ptr)
  {
    return false;
  }
  /* Allocate/initialize the image information data.  REQUIRED */
  png_infop info_ptr = png_create_info_struct( png_ptr );
  if(!info_ptr)
  {
    png_destroy_write_struct(&png_ptr, NULL);
    return false;
  }

  /* Set error handling.  REQUIRED if you aren't supplying your own
   * error handling functions in the png_create_write_struct() call.
   */
  if(setjmp(png_jmpbuf(png_ptr)))
  {
    png_destroy_write_struct(&png_ptr, &info_ptr);
    return false;
  }

  // Since we are going to write to memory instead of a file, lets provide
  // libpng with a custom write function and ask it to pass back our
  // Vector buffer each time it calls back to flush data to "file":
  png_set_write_fn(png_ptr, &encodedPixels, WriteData, FlushData);

  // png_set_compression_level( png_ptr, Z_BEST_COMPRESSION);
  png_set_compression_level(png_ptr, Z_BEST_SPEED);
  // png_set_compression_level( png_ptr, Z_NO_COMPRESSION); //! We could just generate png directly without libpng in this case.

  // Explicitly limit the number of filters used per scanline to speed us up:
  // png_set_filter(png_ptr, 0, PNG_FILTER_NONE); ///!ToDo: Try this once baseline profile is in place.
       // PNG_FILTER_SUB   |
       // PNG_FILTER_UP    |
       // PNG_FILTER_AVE   |
       // PNG_FILTER_PAETH |
       // PNG_ALL_FILTERS);
  // Play with Zlib parameters in optimisation phase:
    // png_set_compression_mem_level(png_ptr, 8);
    // png_set_compression_strategy(png_ptr,
        // Z_DEFAULT_STRATEGY);
    // png_set_compression_window_bits(png_ptr, 15);
    // png_set_compression_method(png_ptr, 8);
    // png_set_compression_buffer_size(png_ptr, 8192)

  // Let lib_png know if the pixel bytes are in BGR(A) order:
  if(!rgbaOrder)
  {
    png_set_bgr( png_ptr );
  }

  // Set the image information:
  png_set_IHDR(png_ptr, info_ptr, width, height, 8,
     pngPixelFormat, interlace,
     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  // Start to output the PNG data to our buffer:
  png_write_info(png_ptr, info_ptr);

  // Walk the rows:
  const unsigned row_step = width * pixelBytes;
  png_bytep row_ptr = const_cast<png_bytep>(pixelBuffer);
  const png_bytep row_end = row_ptr + height * row_step;
  for(; row_ptr < row_end; row_ptr += row_step)
  {
    png_write_row(png_ptr, row_ptr);
  }

  /* It is REQUIRED to call this to finish writing the rest of the file */
  png_write_end(png_ptr, info_ptr);
  /* Clean up after the write, and free any memory allocated */
  png_destroy_write_struct(&png_ptr, &info_ptr);
  return true;
}

} // namespace TizenPlatform

} // namespace Dali
<commit_msg>Address of member variables can never be null.<commit_after>/*
 * Copyright (c) 2015 Samsung Electronics Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

#include "loader-png.h"

#include <cstring>
#include <cstdlib>

#include <zlib.h>
#include <png.h>

#include <dali/integration-api/bitmap.h>
#include <dali/integration-api/debug.h>
#include <dali/public-api/images/image.h>
#include "dali/public-api/math/math-utils.h"
#include "dali/public-api/math/vector2.h"
#include "platform-capabilities.h"

namespace Dali
{

using Integration::Bitmap;
using Dali::Integration::PixelBuffer;

namespace TizenPlatform
{

namespace
{

// simple class to enforce clean-up of PNG structures
struct auto_png
{
  auto_png(png_structp& _png, png_infop& _info)
  : png(_png),
    info(_info)
  {
  }

  ~auto_png()
  {
    if(NULL != png)
    {
      png_destroy_read_struct(&png, &info, NULL);
    }
  }

  png_structp& png;
  png_infop& info;
}; // struct auto_png;

bool LoadPngHeader(FILE *fp, unsigned int &width, unsigned int &height, png_structp &png, png_infop &info)
{
  png_byte header[8] = { 0 };

  // Check header to see if it is a PNG file
  size_t size = fread(header, 1, 8, fp);
  if(size != 8)
  {
    return false;
  }

  if(png_sig_cmp(header, 0, 8))
  {
    return false;
  }

  png = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);

  if(!png)
  {
    DALI_LOG_WARNING("Can't create PNG read structure\n");
    return false;
  }

  info = png_create_info_struct(png);
  if(!info)
  {
    DALI_LOG_WARNING("png_create_info_struct failed\n");
    return false;
  }

  png_set_expand(png);

  if(setjmp(png_jmpbuf(png)))
  {
    DALI_LOG_WARNING("error during png_init_io\n");
    return false;
  }

  png_init_io(png, fp);
  png_set_sig_bytes(png, 8);

  // read image info
  png_read_info(png, info);

  // dimensions
  width = png_get_image_width(png, info);
  height = png_get_image_height(png, info);

  return true;
}

} // namespace - anonymous

bool LoadPngHeader( const ImageLoader::Input& input, unsigned int& width, unsigned int& height )
{
  png_structp png = NULL;
  png_infop info = NULL;
  auto_png autoPng(png, info);

  bool success = LoadPngHeader( input.file, width, height, png, info );

  return success;
}

bool LoadBitmapFromPng( const ResourceLoadingClient& client, const ImageLoader::Input& input, Integration::Bitmap& bitmap )
{
  png_structp png = NULL;
  png_infop info = NULL;
  auto_png autoPng(png, info);

  /// @todo: consider parameters
  unsigned int y;
  unsigned int width, height;
  unsigned char *pixels;
  png_bytep *rows;
  unsigned int bpp = 0; // bytes per pixel
  bool valid = false;

  // Load info from the header
  if( !LoadPngHeader( input.file, width, height, png, info ) )
  {
    return false;
  }

  Pixel::Format pixelFormat = Pixel::RGBA8888;

  // decide pixel format
  unsigned int colordepth = png_get_bit_depth(png, info);

  // Ask PNGLib to convert high precision images into something we can use:
  if (colordepth == 16)
  {
    png_set_strip_16(png);
    colordepth = 8;
  }

  png_byte colortype = png_get_color_type(png, info);

  if(colortype == PNG_COLOR_TYPE_GRAY)
  {
    switch( colordepth )
    {
      case 8:
      {
        pixelFormat = Pixel::L8;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_GRAY_ALPHA)
  {
    switch(colordepth)
    {
      case 8:
      {
        pixelFormat = Pixel::LA88;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_RGB )
  {
    switch(colordepth)
    {
      case 8:
      {
        pixelFormat = Pixel::RGB888;
        valid = true;
        break;
      }
      case 5:      /// @todo is this correct for RGB16 5-6-5 ?
      {
        pixelFormat = Pixel::RGB565;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_RGBA)
  {
    switch(colordepth)
    {
      case 8:
      {
        pixelFormat = Pixel::RGBA8888;
        valid = true;
        break;
      }
      default:
      {
        break;
      }
    }
  }
  else if(colortype == PNG_COLOR_TYPE_PALETTE)
  {
    switch(colordepth)
    {
      case 1:
      {
        pixelFormat = Pixel::LA88;
        valid = true;
        break;
      }

      case 2:
      case 4:
      case 8:
      {
        /* Expand paletted or RGB images with transparency to full alpha channels
         * so the data will be available as RGBA quartets. PNG_INFO_tRNS = 0x10
         */
        if(png_get_valid(png, info, PNG_INFO_tRNS) == 0x10)
        {
          pixelFormat = Pixel::RGBA8888;
          valid = true;
        }
        else
        {
          pixelFormat = Pixel::RGB888;
          png_set_packing(png);
          png_set_packswap(png);
          png_set_palette_to_rgb(png);
          valid = true;
        }
        break;
      }
      default:
      {
        break;
      }
    }
  }

  if( !valid )
  {
    DALI_LOG_WARNING( "Unsupported png format\n" );
    return false;
  }

  // bytes per pixel
  bpp = Pixel::GetBytesPerPixel(pixelFormat);

  png_read_update_info(png, info);

  if(setjmp(png_jmpbuf(png)))
  {
    DALI_LOG_WARNING("error during png_read_image\n");
    return false;
  }

  unsigned int rowBytes = png_get_rowbytes(png, info);

  unsigned int bufferWidth   = GetTextureDimension(width);
  unsigned int bufferHeight  = GetTextureDimension(height);
  unsigned int stride        = bufferWidth*bpp;

  // not sure if this ever happens
  if( rowBytes > stride )
  {
    stride = GetTextureDimension(rowBytes);
    bufferWidth = stride / bpp;
  }

  // decode the whole image into bitmap buffer
  pixels = bitmap.GetPackedPixelsProfile()->ReserveBuffer(pixelFormat, width, height, bufferWidth, bufferHeight);

  DALI_ASSERT_DEBUG(pixels);
  rows = (png_bytep*) malloc(sizeof(png_bytep) * height);
  for(y=0; y<height; y++)
  {
    rows[y] = (png_byte*) (pixels + y * stride);
  }

  // decode image
  png_read_image(png, rows);

  free(rows);

  return true;
}

// simple class to enforce clean-up of PNG structures
struct AutoPngWrite
{
  AutoPngWrite(png_structp& _png, png_infop& _info)
  : png(_png),
    info(_info)
  {
  }

  ~AutoPngWrite()
  {
    if(NULL != png)
    {
      png_destroy_write_struct(&png, &info);
    }
  }

  png_structp& png;
  png_infop& info;
}; // struct AutoPngWrite;

namespace
{
  // Custom libpng write callbacks that buffer to a vector instead of a file:

  /**
   * extern "C" linkage is used because this is a callback that we pass to a C
   * library which is part of the underlying platform and so potentially compiled
   * as C rather than C++.
   * @see http://stackoverflow.com/a/2594222
   * */
  extern "C" void WriteData(png_structp png_ptr, png_bytep data, png_size_t length)
  {
    DALI_ASSERT_DEBUG(png_ptr && data);
    if(!png_ptr || !data)
    {
      return;
    }
    // Make sure we don't try to propagate a C++ exception up the call stack of a pure C library:
    try
    {
      // Recover our buffer for writing into:
      Vector<unsigned char>* const encoded_img = static_cast< Vector<unsigned char>* >( png_get_io_ptr(png_ptr) );
      if(encoded_img)
      {
        const Vector<unsigned char>::SizeType bufferSize = encoded_img->Count();
        encoded_img->Reserve( bufferSize + length ); //< Can throw OOM.
        unsigned char* const bufferBack = encoded_img->Begin() + bufferSize;
        memcpy(bufferBack, data, length);
      }
      else
      {
        DALI_LOG_ERROR("PNG buffer for write to memory was passed from libpng as null.\n");
      }
    }
    catch(...)
    {
      DALI_LOG_ERROR("C++ Exception caught\n");
    }
  }

  /** Override the flush with a NOP to prevent libpng trying cstdlib file io. */
  extern "C" void FlushData(png_structp png_ptr)
  {
#ifdef DEBUG_ENABLED
    Debug::LogMessage(Debug::DebugInfo, "PNG Flush");
#endif // DEBUG_ENABLED
  }
}

/**
 * Potential improvements:
 * 1. Detect <= 256 colours and write in palette mode.
 * 2. Detect grayscale (will early-out quickly for colour images).
 * 3. Store colour space / gamma correction info related to the device screen?
 *    http://www.libpng.org/pub/png/book/chapter10.html
 * 4. Refactor with callers to write straight through to disk and save keeping a big buffer around.
 * 5. Prealloc buffer (reserve) to input size / <A number greater than 2 (expexcted few realloc but without using lots of memory) | 1 (expected zero reallocs but using a lot of memory)>.
 * 6. Set the modification time with png_set_tIME(png_ptr, info_ptr, mod_time);
 * 7. If caller asks for no compression, bypass libpng and blat raw data to
 *    disk, topped and tailed with header/tail blocks.
 */
bool EncodeToPng( const unsigned char* const pixelBuffer, Vector<unsigned char>& encodedPixels, std::size_t width, std::size_t height, Pixel::Format pixelFormat )
{
  // Translate pixel format enum:
  int pngPixelFormat = -1;
  unsigned pixelBytes = 0;
  bool rgbaOrder = true;

  // Account for RGB versus BGR and presence of alpha in input pixels:
  switch( pixelFormat )
  {
    case Pixel::RGB888:
    {
      pngPixelFormat = PNG_COLOR_TYPE_RGB;
      pixelBytes = 3;
      break;
    }
    case Pixel::BGRA8888:
    {
      rgbaOrder = false;
      ///! No break: fall through:
    }
    case Pixel::RGBA8888:
    {
      pngPixelFormat = PNG_COLOR_TYPE_RGB_ALPHA;
      pixelBytes = 4;
      break;
    }
    default:
    {
      DALI_LOG_ERROR( "Unsupported pixel format for encoding to PNG.\n" );
      return false;
    }
  }

  const int interlace = PNG_INTERLACE_NONE;

  png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
  if(!png_ptr)
  {
    return false;
  }
  /* Allocate/initialize the image information data.  REQUIRED */
  png_infop info_ptr = png_create_info_struct( png_ptr );
  if(!info_ptr)
  {
    png_destroy_write_struct(&png_ptr, NULL);
    return false;
  }

  /* Set error handling.  REQUIRED if you aren't supplying your own
   * error handling functions in the png_create_write_struct() call.
   */
  if(setjmp(png_jmpbuf(png_ptr)))
  {
    png_destroy_write_struct(&png_ptr, &info_ptr);
    return false;
  }

  // Since we are going to write to memory instead of a file, lets provide
  // libpng with a custom write function and ask it to pass back our
  // Vector buffer each time it calls back to flush data to "file":
  png_set_write_fn(png_ptr, &encodedPixels, WriteData, FlushData);

  // png_set_compression_level( png_ptr, Z_BEST_COMPRESSION);
  png_set_compression_level(png_ptr, Z_BEST_SPEED);
  // png_set_compression_level( png_ptr, Z_NO_COMPRESSION); //! We could just generate png directly without libpng in this case.

  // Explicitly limit the number of filters used per scanline to speed us up:
  // png_set_filter(png_ptr, 0, PNG_FILTER_NONE); ///!ToDo: Try this once baseline profile is in place.
       // PNG_FILTER_SUB   |
       // PNG_FILTER_UP    |
       // PNG_FILTER_AVE   |
       // PNG_FILTER_PAETH |
       // PNG_ALL_FILTERS);
  // Play with Zlib parameters in optimisation phase:
    // png_set_compression_mem_level(png_ptr, 8);
    // png_set_compression_strategy(png_ptr,
        // Z_DEFAULT_STRATEGY);
    // png_set_compression_window_bits(png_ptr, 15);
    // png_set_compression_method(png_ptr, 8);
    // png_set_compression_buffer_size(png_ptr, 8192)

  // Let lib_png know if the pixel bytes are in BGR(A) order:
  if(!rgbaOrder)
  {
    png_set_bgr( png_ptr );
  }

  // Set the image information:
  png_set_IHDR(png_ptr, info_ptr, width, height, 8,
     pngPixelFormat, interlace,
     PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);

  // Start to output the PNG data to our buffer:
  png_write_info(png_ptr, info_ptr);

  // Walk the rows:
  const unsigned row_step = width * pixelBytes;
  png_bytep row_ptr = const_cast<png_bytep>(pixelBuffer);
  const png_bytep row_end = row_ptr + height * row_step;
  for(; row_ptr < row_end; row_ptr += row_step)
  {
    png_write_row(png_ptr, row_ptr);
  }

  /* It is REQUIRED to call this to finish writing the rest of the file */
  png_write_end(png_ptr, info_ptr);
  /* Clean up after the write, and free any memory allocated */
  png_destroy_write_struct(&png_ptr, &info_ptr);
  return true;
}

} // namespace TizenPlatform

} // namespace Dali
<|endoftext|>


<commit_before>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2017 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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.

#pragma once
#ifndef NET_TLS_SERVER_STREAM_HPP
#define NET_TLS_SERVER_STREAM_HPP

#include <botan/credentials_manager.h>
#include <botan/rng.h>
#include <botan/tls_server.h>
#include <botan/tls_callbacks.h>
#include <net/tcp/connection.hpp>
#include <net/botan/credman.hpp>

namespace net
{
namespace botan
{
class Server : public Botan::TLS::Callbacks, public net::Stream
{
public:
  Server(net::Stream_ptr remote,
         Botan::RandomNumberGenerator& rng,
         Botan::Credentials_Manager& credman)
  : m_creds{credman},
    m_session_manager{},
    m_tls{*this, m_session_manager, m_creds, m_policy, rng},
    m_transport{std::move(remote)}
  {
    assert(m_transport->is_connected());
    // default read callback
    m_transport->on_read(4096, {this, &Server::tls_read});
  }
  ~Server() {
    assert(m_busy == false && "Cannot delete stream while in its call stack");
  }

  void on_read(size_t bs, ReadCallback cb) override
  {
    m_transport->on_read(bs, {this, &Server::tls_read});
    this->m_on_read = cb;
  }
  void on_write(WriteCallback cb) override {
    this->m_on_write = cb;
  }
  void on_connect(ConnectCallback cb) override {
    this->m_on_connect = cb;
  }
  void on_close(CloseCallback cb) override {
    this->m_on_close = cb;
  }

  void write(const void* buf, size_t n) override
  {
    m_tls.send((uint8_t*) buf, n);
  }
  void write(const std::string& str) override
  {
    this->write(str.data(), str.size());
  }
  void write(buffer_t buf) override
  {
    m_tls.send(buf->data(), buf->size());
  }

  void close() override
  {
    if (this->m_busy) {
      this->m_deferred_close = true; return;
    }
    m_transport->close();
    CloseCallback cb = std::move(m_on_close);
    this->reset_callbacks();
    if (cb) cb();
  }
  void abort() override {
    m_transport->abort();
    this->close();
  }
  void reset_callbacks() override
  {
    m_on_read  = nullptr;
    m_on_write = nullptr;
    m_on_connect = nullptr;
    m_on_close = nullptr;
    m_transport->reset_callbacks();
  }

  net::Socket local() const override {
    return m_transport->local();
  }
  net::Socket remote() const override {
    return m_transport->remote();
  }
  std::string to_string() const override {
    return m_transport->to_string();
  }

  bool is_connected() const noexcept override {
    return m_transport->is_connected();
  }
  bool is_writable() const noexcept override {
    return m_tls.is_active();
  }
  bool is_readable() const noexcept override {
    return m_transport->is_readable();
  }
  bool is_closing() const noexcept override {
    return m_transport->is_closing();
  }
  bool is_closed() const noexcept override {
    return m_tls.is_closed() || m_transport->is_closed();
  }

  int get_cpuid() const noexcept override {
    return m_transport->get_cpuid();
  }

  Stream* transport() noexcept override {
    return m_transport.get();
  }

  /** Not implemented **/
  size_t serialize_to(void* /*ptr*/) const override {
    throw std::runtime_error("Not implemented");
  }

protected:
  void tls_read(buffer_t buf)
  {
    try
    {
      int rem = m_tls.received_data(buf->data(), buf->size());
      (void) rem;
      //printf("Finished processing (rem: %u)\n", rem);
    }
    catch(Botan::Exception& e)
    {
      printf("Fatal TLS error %s\n", e.what());
      this->close();
    }
  }

  void tls_alert(Botan::TLS::Alert alert) override
  {
    // ignore close notifications
    if (alert.type() != Botan::TLS::Alert::CLOSE_NOTIFY)
    {
      printf("Got a %s alert: %s\n",
            (alert.is_fatal() ? "fatal" : "warning"),
            alert.type_string().c_str());
    }
  }

  bool tls_session_established(const Botan::TLS::Session&) override
  {
    // return true to store session
    return true;
  }

  void tls_emit_data(const uint8_t buf[], size_t len) override
  {
    m_transport->write(buf, len);
    if (m_on_write) {
      this->m_busy = true;
      m_on_write(len);
      this->m_busy = false;
      if (this->m_deferred_close) this->close();
    }
  }

  void tls_record_received(uint64_t, const uint8_t buf[], size_t buf_len) override
  {
    if (m_on_read) {
      this->m_busy = true;
      m_on_read(Stream::construct_buffer(buf, buf + buf_len));
      this->m_busy = false;
      if (this->m_deferred_close) this->close();
    }
  }

  void tls_session_activated() override
  {
    if (m_on_connect) m_on_connect(*this);
  }

private:
  Stream::ReadCallback    m_on_read = nullptr;
  Stream::WriteCallback   m_on_write = nullptr;
  Stream::ConnectCallback m_on_connect = nullptr;
  Stream::CloseCallback   m_on_close = nullptr;
  bool m_busy = false;
  bool m_deferred_close = false;

  Botan::Credentials_Manager&   m_creds;
  Botan::TLS::Strict_Policy     m_policy;
  Botan::TLS::Session_Manager_Noop m_session_manager;

  Botan::TLS::Server m_tls;
  net::Stream_ptr    m_transport = nullptr;
};

} // tls
} // net

#endif
<commit_msg>net: Fix close issue with Botan TLS stream<commit_after>// This file is a part of the IncludeOS unikernel - www.includeos.org
//
// Copyright 2015-2017 Oslo and Akershus University College of Applied Sciences
// and Alfred Bratterud
//
// 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.

#pragma once
#ifndef NET_TLS_SERVER_STREAM_HPP
#define NET_TLS_SERVER_STREAM_HPP

#include <botan/credentials_manager.h>
#include <botan/rng.h>
#include <botan/tls_server.h>
#include <botan/tls_callbacks.h>
#include <net/tcp/connection.hpp>
#include <net/botan/credman.hpp>

namespace net
{
namespace botan
{
class Server : public Botan::TLS::Callbacks, public net::Stream
{
public:
  Server(net::Stream_ptr remote,
         Botan::RandomNumberGenerator& rng,
         Botan::Credentials_Manager& credman)
  : m_creds{credman},
    m_session_manager{},
    m_tls{*this, m_session_manager, m_creds, m_policy, rng},
    m_transport{std::move(remote)}
  {
    assert(m_transport->is_connected());
    // default read callback
    m_transport->on_read(4096, {this, &Server::tls_read});
    m_transport->on_close({this, &Server::close_callback_once});
  }
  ~Server() {
    assert(m_busy == false && "Cannot delete stream while in its call stack");
  }

  void on_read(size_t bs, ReadCallback cb) override
  {
    m_transport->on_read(bs, {this, &Server::tls_read});
    this->m_on_read = cb;
  }
  void on_write(WriteCallback cb) override {
    this->m_on_write = cb;
  }
  void on_connect(ConnectCallback cb) override {
    this->m_on_connect = cb;
  }
  void on_close(CloseCallback cb) override {
    this->m_on_close = cb;
  }

  void write(const void* buf, size_t n) override
  {
    m_tls.send((uint8_t*) buf, n);
  }
  void write(const std::string& str) override
  {
    this->write(str.data(), str.size());
  }
  void write(buffer_t buf) override
  {
    m_tls.send(buf->data(), buf->size());
  }

  void close() override
  {
    if (this->m_busy) {
      this->m_deferred_close = true; return;
    }
    CloseCallback cb = std::move(m_on_close);
    this->reset_callbacks();
    m_transport->close();
    if (cb) cb();
  }
  void close_callback_once()
  {
    CloseCallback cb = std::move(m_on_close);
    this->reset_callbacks();
    if (cb) cb();
  }
  void abort() override {
    m_transport->abort();
    this->close();
  }
  void reset_callbacks() override
  {
    m_on_read  = nullptr;
    m_on_write = nullptr;
    m_on_connect = nullptr;
    m_on_close = nullptr;
  }

  net::Socket local() const override {
    return m_transport->local();
  }
  net::Socket remote() const override {
    return m_transport->remote();
  }
  std::string to_string() const override {
    return m_transport->to_string();
  }

  bool is_connected() const noexcept override {
    return m_transport->is_connected();
  }
  bool is_writable() const noexcept override {
    return m_tls.is_active();
  }
  bool is_readable() const noexcept override {
    return m_transport->is_readable();
  }
  bool is_closing() const noexcept override {
    return m_transport->is_closing();
  }
  bool is_closed() const noexcept override {
    return m_tls.is_closed() || m_transport->is_closed();
  }

  int get_cpuid() const noexcept override {
    return m_transport->get_cpuid();
  }

  Stream* transport() noexcept override {
    return m_transport.get();
  }

  /** Not implemented **/
  size_t serialize_to(void* /*ptr*/) const override {
    throw std::runtime_error("Not implemented");
  }

protected:
  void tls_read(buffer_t buf)
  {
    this->m_busy = true;
    try
    {
      int rem = m_tls.received_data(buf->data(), buf->size());
      (void) rem;
      //printf("Finished processing (rem: %u)\n", rem);
    }
    catch(Botan::Exception& e)
    {
      printf("Fatal TLS error %s\n", e.what());
      this->close();
    }
    this->m_busy = false;
    if (this->m_deferred_close) this->close();
  }

  void tls_alert(Botan::TLS::Alert alert) override
  {
    // ignore close notifications
    if (alert.type() != Botan::TLS::Alert::CLOSE_NOTIFY)
    {
      printf("Got a %s alert: %s\n",
            (alert.is_fatal() ? "fatal" : "warning"),
            alert.type_string().c_str());
    }
  }

  bool tls_session_established(const Botan::TLS::Session&) override
  {
    // return true to store session
    return true;
  }

  void tls_emit_data(const uint8_t buf[], size_t len) override
  {
    m_transport->write(buf, len);
    if (m_on_write) {
      this->m_busy = true;
      m_on_write(len);
      this->m_busy = false;
      if (this->m_deferred_close) this->close();
    }
  }

  void tls_record_received(uint64_t, const uint8_t buf[], size_t buf_len) override
  {
    if (m_on_read) {
      m_on_read(Stream::construct_buffer(buf, buf + buf_len));
    }
  }

  void tls_session_activated() override
  {
    if (m_on_connect) m_on_connect(*this);
  }

private:
  Stream::ReadCallback    m_on_read = nullptr;
  Stream::WriteCallback   m_on_write = nullptr;
  Stream::ConnectCallback m_on_connect = nullptr;
  Stream::CloseCallback   m_on_close = nullptr;
  bool m_busy = false;
  bool m_deferred_close = false;

  Botan::Credentials_Manager&   m_creds;
  Botan::TLS::Strict_Policy     m_policy;
  Botan::TLS::Session_Manager_Noop m_session_manager;

  Botan::TLS::Server m_tls;
  net::Stream_ptr    m_transport = nullptr;
};

} // tls
} // net

#endif
<|endoftext|>


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

Library:   TubeTK

Copyright 2010 Kitware Inc. 28 Corporate Drive,
Clifton Park, NY, 12065, USA.

All rights reserved.

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.

=========================================================================*/

// ITK includes
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>
#include <itkTimeProbesCollectorBase.h>

// TubeTKITK includes
#include "tubeMergeAdjacentImages.h"

// TubeTK includes
#include "tubeCLIProgressReporter.h"
#include "tubeMessage.h"

#include "MergeAdjacentImagesCLP.h"

template< class TPixel, unsigned int VDimension >
int DoIt( int argc, char * argv[] );

#define PARSE_ARGS_FLOAT_ONLY 1

// Must follow include of "...CLP.h" and forward declaration of int DoIt( ... ).
#include "tubeCLIHelperFunctions.h"

// Your code should be within the DoIt function...
template< class TPixel, unsigned int VDimension >
int DoIt( int argc, char * argv[] )
{
  PARSE_ARGS;

  // setup progress reporting
  double progress = 0.0;

  tube::CLIProgressReporter progressReporter(
    "MergeAdjacentImages", CLPProcessInformation );
  progressReporter.Start();
  progressReporter.Report( progress );

  // The timeCollector to perform basic profiling of algorithmic components
  itk::TimeProbesCollectorBase timeCollector;

  // define types
  typedef TPixel                                        PixelType;
  typedef itk::Image< PixelType, VDimension >           ImageType;
  typedef itk::ImageFileReader< ImageType >             ReaderType;
  typedef itk::ImageFileWriter< ImageType  >            WriterType;

  // Load input image 1
  timeCollector.Start( "Loading input image 1" );

  typename ReaderType::Pointer reader1 = ReaderType::New();

  try
    {
    reader1->SetFileName( inputVolume1.c_str() );
    reader1->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Error loading input image 1: "
      + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }

  timeCollector.Stop( "Loading input image 1" );
  progress = 0.05;
  progressReporter.Report( progress );

  // Load input image 2
  timeCollector.Start( "Loading input image 2" );

  typename ReaderType::Pointer reader2 = ReaderType::New();

  try
    {
    reader2->SetFileName( inputVolume2.c_str() );
    reader2->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Error loading input image 2: "
      + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }

  timeCollector.Stop( "Loading input image 2" );
  progress = 0.1;
  progressReporter.Report( progress );

  // Perform merging
  timeCollector.Start( "Merging images" );

  typedef tube::MergeAdjacentImages< TPixel, VDimension >
    MergeAdjacentImagesFilterType;

  typename MergeAdjacentImagesFilterType::Pointer filter =
    MergeAdjacentImagesFilterType::New();

  filter->SetInput1( reader1->GetOutput() );
  filter->SetInput2( reader2->GetOutput() );

  filter->SetBackground( background );
  filter->SetMaskZero( mask );
  filter->SetMaxIterations( iterations );
  filter->SetExpectedOffset( expectedOffset );
  filter->SetExpectedRotation( expectedRotation );
  filter->SetSamplingRatio( samplingRatio );
  filter->LoadTransform( loadTransform );
  filter->SaveTransform( saveTransform );
  filter->SetBlendUsingAverage( averagePixels );
  filter->SetUseFastBlending( useFastBlending );

  if( boundary.size() == VDimension )
    {
    filter->SetPadding( boundary );
    }

  filter->Update();

  timeCollector.Stop( "Merging images" );
  progress = 0.9;
  progressReporter.Report( progress );

  // Write output image
  timeCollector.Start( "Writing output image" );

  typename WriterType::Pointer writer = WriterType::New();

  try
    {
    writer->SetFileName( outputVolume.c_str() );
    writer->SetInput( outImage );
    writer->SetUseCompression( true );
    writer->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Error writing output image: "
                        + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }

  timeCollector.Stop( "Writing output image" );
  progress = 1.0;
  progressReporter.Report( progress );
  progressReporter.End();

  timeCollector.Report();
  return EXIT_SUCCESS;
}

// Main
int main( int argc, char * argv[] )
{
  PARSE_ARGS;

  // You may need to update this line if, in the project's .xml CLI file,
  //   you change the variable name for the inputVolume.
  return tube::ParseArgsAndCallDoIt( inputVolume1, argc, argv );
}
<commit_msg>Fix bugs in MergeAdjacentImages.cxx<commit_after>/*=========================================================================

Library:   TubeTK

Copyright 2010 Kitware Inc. 28 Corporate Drive,
Clifton Park, NY, 12065, USA.

All rights reserved.

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.

=========================================================================*/

// ITK includes
#include <itkImageFileReader.h>
#include <itkImageFileWriter.h>
#include <itkTimeProbesCollectorBase.h>

// TubeTKITK includes
#include "tubeMergeAdjacentImages.h"

// TubeTK includes
#include "tubeCLIProgressReporter.h"
#include "tubeMessage.h"

#include "MergeAdjacentImagesCLP.h"

template< class TPixel, unsigned int VDimension >
int DoIt( int argc, char * argv[] );

#define PARSE_ARGS_FLOAT_ONLY 1

// Must follow include of "...CLP.h" and forward declaration of int DoIt( ... ).
#include "tubeCLIHelperFunctions.h"

// Your code should be within the DoIt function...
template< class TPixel, unsigned int VDimension >
int DoIt( int argc, char * argv[] )
{
  PARSE_ARGS;

  // setup progress reporting
  double progress = 0.0;

  tube::CLIProgressReporter progressReporter(
    "MergeAdjacentImages", CLPProcessInformation );
  progressReporter.Start();
  progressReporter.Report( progress );

  // The timeCollector to perform basic profiling of algorithmic components
  itk::TimeProbesCollectorBase timeCollector;

  // define types
  typedef TPixel                                        PixelType;
  typedef itk::Image< PixelType, VDimension >           ImageType;
  typedef itk::ImageFileReader< ImageType >             ReaderType;
  typedef itk::ImageFileWriter< ImageType  >            WriterType;

  // Load input image 1
  timeCollector.Start( "Loading input image 1" );

  typename ReaderType::Pointer reader1 = ReaderType::New();

  try
    {
    reader1->SetFileName( inputVolume1.c_str() );
    reader1->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Error loading input image 1: "
      + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }

  timeCollector.Stop( "Loading input image 1" );
  progress = 0.05;
  progressReporter.Report( progress );

  // Load input image 2
  timeCollector.Start( "Loading input image 2" );

  typename ReaderType::Pointer reader2 = ReaderType::New();

  try
    {
    reader2->SetFileName( inputVolume2.c_str() );
    reader2->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Error loading input image 2: "
      + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }

  timeCollector.Stop( "Loading input image 2" );
  progress = 0.1;
  progressReporter.Report( progress );

  // Perform merging
  timeCollector.Start( "Merging images" );

  typedef tube::MergeAdjacentImages< ImageType >
    MergeAdjacentImagesFilterType;

  typename MergeAdjacentImagesFilterType::Pointer filter =
    MergeAdjacentImagesFilterType::New();

  filter->SetInput1( reader1->GetOutput() );
  filter->SetInput2( reader2->GetOutput() );

  filter->SetBackground( background );
  filter->SetMaskZero( mask );
  filter->SetMaxIterations( iterations );
  filter->SetExpectedOffset( expectedOffset );
  filter->SetExpectedRotation( expectedRotation );
  filter->SetSamplingRatio( samplingRatio );
  filter->LoadTransform( loadTransform );
  filter->SaveTransform( saveTransform );
  filter->SetBlendUsingAverage( averagePixels );
  filter->SetUseFastBlending( useFastBlending );

  if( boundary.size() == VDimension )
    {
    filter->SetPadding( boundary );
    }

  filter->Update();

  timeCollector.Stop( "Merging images" );
  progress = 0.9;
  progressReporter.Report( progress );

  // Write output image
  timeCollector.Start( "Writing output image" );

  typename WriterType::Pointer writer = WriterType::New();

  try
    {
    writer->SetFileName( outputVolume.c_str() );
    writer->SetInput( filter->GetOutput() );
    writer->SetUseCompression( true );
    writer->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    tube::ErrorMessage( "Error writing output image: "
                        + std::string(err.GetDescription()) );
    timeCollector.Report();
    return EXIT_FAILURE;
    }

  timeCollector.Stop( "Writing output image" );
  progress = 1.0;
  progressReporter.Report( progress );
  progressReporter.End();

  timeCollector.Report();
  return EXIT_SUCCESS;
}

// Main
int main( int argc, char * argv[] )
{
  PARSE_ARGS;

  // You may need to update this line if, in the project's .xml CLI file,
  //   you change the variable name for the inputVolume.
  return tube::ParseArgsAndCallDoIt( inputVolume1, argc, argv );
}
<|endoftext|>


<commit_before>/*******************************************************************************
* ALMA - Atacama Large Millimiter Array
* Copyright (c) European Southern Observatory, 2016
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
*
* who       when      what
* --------  --------  ----------------------------------------------
* almadev  2016-02-18  created
*/
#include "BDNTSenderSimulatorFlow.h"

ACE_Thread_Manager BDNTSenderSimulatorFlow::threadManager;

BDNTSenderSimulatorFlow::BDNTSenderSimulatorFlow(
		const char* streamName,
		const char* flowName,
		unsigned int sizeOfDataToSend,
		ACE_Barrier& theStartBarrier,
		ACE_Barrier& theDoneBarrier,
		LoggingProxy& logger,
		AcsBulkdata::BulkDataNTSenderFlow* theFlow):
	size(sizeOfDataToSend),
	numOfIterations(0),
	startSendBarrier(theStartBarrier),
	doneSendBarrier(theDoneBarrier),
	m_logger(logger),
	flow(theFlow)
{
	// Build the name of the flow
	name.append(flowName);
	name.append("@");
	name.append(streamName);

	// Allocate and initialize the bytes to send
	charsToSend = new unsigned char[size];
	for (unsigned int i=0; i<size; i++)	{
		charsToSend[i]=i%256;
	}

	// Start the thread
	if (threadManager.spawn((ACE_THR_FUNC)BDNTSenderSimulatorFlow::threadFunc, this, 0, &threadId) == -1) {
		cerr << "Error spawning thread" << name << endl;
	} else {
		cout << "Thread for "<< name << " name started with Id=" << threadId << endl;
	}
}

BDNTSenderSimulatorFlow::~BDNTSenderSimulatorFlow() {
	delete charsToSend;
	charsToSend = NULL;
}

void* BDNTSenderSimulatorFlow::threadFunc(void *arg) {
	BDNTSenderSimulatorFlow* simSenderFlow = (BDNTSenderSimulatorFlow*)arg;
	simSenderFlow->sendDataThread();
	return NULL;
}

void BDNTSenderSimulatorFlow::sendDataThread() {
	cout << "Sender thread " << name << " started. Now entering the loop." << endl;
	while (startSendBarrier.wait()!=-1) {
		cout << "Sender thread " << name << " iteration #" << (++numOfIterations) << endl;

		// startSend
		//
		// the param is the name of this object (i.e flow@stream)
		cout << name << " is going to call startSend with parameter [" << name << "] to " << flow->getNumberOfReceivers() << " receiver(s)" << endl;
		startSendExecTime = ACE_OS::gettimeofday();
		flow->startSend((const unsigned char*)name.c_str(), name.size());
		startSendExecTime = ACE_OS::gettimeofday() - startSendExecTime;

		// sendData
		cout << name << " is going to send " << size << " bytes to " << flow->getNumberOfReceivers() << " receiver(s)" << endl;
		sendDataExecTime = ACE_OS::gettimeofday();
		flow->sendData(charsToSend, size);
		sendDataExecTime = ACE_OS::gettimeofday() - sendDataExecTime;
		double send_time = (sendDataExecTime.sec()+( sendDataExecTime.usec() / 1000000. ));
		throuhgput = (size/(1024.0*1024.0))/send_time;

		// stopSend
		cout << name << " is going to call stopSend to " << flow->getNumberOfReceivers() << " receiver(s)" << endl;
		stopSendExecTime = ACE_OS::gettimeofday();
		flow->stopSend();
		stopSendExecTime = ACE_OS::gettimeofday() - stopSendExecTime;

		// Signal that the iteration terminated
		doneSendBarrier.wait();
	}
	cout << "Sender thread " << name << " now exiting." << endl;
}

/*___oOo___*/
<commit_msg>The constructor prints also the number of bytes to send together with the thread ID<commit_after>/*******************************************************************************
* ALMA - Atacama Large Millimiter Array
* Copyright (c) European Southern Observatory, 2016
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
*
*
* who       when      what
* --------  --------  ----------------------------------------------
* almadev  2016-02-18  created
*/
#include "BDNTSenderSimulatorFlow.h"

ACE_Thread_Manager BDNTSenderSimulatorFlow::threadManager;

BDNTSenderSimulatorFlow::BDNTSenderSimulatorFlow(
		const char* streamName,
		const char* flowName,
		unsigned int sizeOfDataToSend,
		ACE_Barrier& theStartBarrier,
		ACE_Barrier& theDoneBarrier,
		LoggingProxy& logger,
		AcsBulkdata::BulkDataNTSenderFlow* theFlow):
	size(sizeOfDataToSend),
	numOfIterations(0),
	startSendBarrier(theStartBarrier),
	doneSendBarrier(theDoneBarrier),
	m_logger(logger),
	flow(theFlow)
{
	// Build the name of the flow
	name.append(flowName);
	name.append("@");
	name.append(streamName);

	// Allocate and initialize the bytes to send
	charsToSend = new unsigned char[size];
	for (unsigned int i=0; i<size; i++)	{
		charsToSend[i]=i%256;
	}

	// Start the thread
	if (threadManager.spawn((ACE_THR_FUNC)BDNTSenderSimulatorFlow::threadFunc, this, 0, &threadId) == -1) {
		cerr << "Error spawning thread" << name << endl;
	} else {
		cout << "Thread for "<< name << " name started with Id=" << threadId << ": will send "<< size << " bytes" << endl;
	}
}

BDNTSenderSimulatorFlow::~BDNTSenderSimulatorFlow() {
	delete charsToSend;
	charsToSend = NULL;
}

void* BDNTSenderSimulatorFlow::threadFunc(void *arg) {
	BDNTSenderSimulatorFlow* simSenderFlow = (BDNTSenderSimulatorFlow*)arg;
	simSenderFlow->sendDataThread();
	return NULL;
}

void BDNTSenderSimulatorFlow::sendDataThread() {
	cout << "Sender thread " << name << " started. Now entering the loop." << endl;
	while (startSendBarrier.wait()!=-1) {
		cout << "Sender thread " << name << " iteration #" << (++numOfIterations) << endl;

		// startSend
		//
		// the param is the name of this object (i.e flow@stream)
		cout << name << " is going to call startSend with parameter [" << name << "] to " << flow->getNumberOfReceivers() << " receiver(s)" << endl;
		startSendExecTime = ACE_OS::gettimeofday();
		flow->startSend((const unsigned char*)name.c_str(), name.size());
		startSendExecTime = ACE_OS::gettimeofday() - startSendExecTime;

		// sendData
		cout << name << " is going to send " << size << " bytes to " << flow->getNumberOfReceivers() << " receiver(s)" << endl;
		sendDataExecTime = ACE_OS::gettimeofday();
		flow->sendData(charsToSend, size);
		sendDataExecTime = ACE_OS::gettimeofday() - sendDataExecTime;
		double send_time = (sendDataExecTime.sec()+( sendDataExecTime.usec() / 1000000. ));
		throuhgput = (size/(1024.0*1024.0))/send_time;

		// stopSend
		cout << name << " is going to call stopSend to " << flow->getNumberOfReceivers() << " receiver(s)" << endl;
		stopSendExecTime = ACE_OS::gettimeofday();
		flow->stopSend();
		stopSendExecTime = ACE_OS::gettimeofday() - stopSendExecTime;

		// Signal that the iteration terminated
		doneSendBarrier.wait();
	}
	cout << "Sender thread " << name << " now exiting." << endl;
}

/*___oOo___*/
<|endoftext|>


<commit_before>#include "LogobotText.h"

// local copy of critical command defines - for space optimisation
#define LOGO_CMD_TO			4
#define LOGO_CMD_BZ			8
#define LOGO_CMD_PU			9
#define LOGO_CMD_PD			10

namespace LogobotText
{
	// Namespace containing private functions
	namespace
	{
		float fontSize;  // =em, equal to line spacing (between baselines), text sizes derived from this
		float capHeight;
		float letterSpacing;
		float w;

		CommandQueue * _cmdQ;

		void pushPU() {
			_cmdQ->enqueue("", LOGO_CMD_PU);
		}

		void pushPD() {
			_cmdQ->enqueue("", LOGO_CMD_PD);
		}

		void pushTo(float x, float y)
		{
			String s = String(x);
			s += " ";
			s += y;
			_cmdQ->enqueue(s, LOGO_CMD_TO);
		}

		// Alphabet
		void writeA(float x, float y)
		{
			pushPD();
			pushTo(x + w/2, y + capHeight);
			pushTo(x + w, y);
			pushPU();
			pushTo(x + w / 4, y + capHeight / 2);
			pushPD();
			pushTo(x + 3 * w / 4, y + capHeight / 2 );
		}

		void writeB(float x, float y)
		{
			pushPD();
			pushTo(x + 2 * w / 3, y);
			pushTo(x + w, y + capHeight / 4);
			pushTo(x + 2 * w / 3, y + capHeight / 2);
			pushTo(x + w, y + 3 * capHeight / 4);
			pushTo(x + 2 * w / 3, y + capHeight);
			pushTo(x, y + capHeight);
			pushTo(x, y);
		}

		void writeC(float x, float y)
		{
			pushTo(x + w, y + capHeight);
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x, y);
			pushTo(x + w, y);
		}

		void writeD(float x, float y)
		{
			pushPD();
			pushTo(x + 3 * w / 4, y);
			pushTo(x + w, y + capHeight / 4);
			pushTo(x + w, y + 3 * capHeight / 4);
			pushTo(x + 3 * w / 4, y + capHeight);
			pushTo(x, y + capHeight);
			pushTo(x, y);
		}

		void writeE(float x, float y)
		{
			writeC(x, y);
			pushPU();
			pushTo(x, y + capHeight / 2);
			pushPD();
			pushTo(x + w, y + capHeight /2);
		}

		void writeF(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x + w, y + capHeight);
			pushPU();
			pushTo(x + w, y + capHeight / 2);
			pushPD();
			pushTo(x, y + capHeight / 2);
		}

		void writeG(float x, float y)
		{
			pushTo(x + w, y + capHeight);
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x, y);
			pushTo(x + w, y);
			pushTo(x + w, y + capHeight/3);
			pushTo(x + w/3, y + capHeight/3);
		}

		void writeH(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x, y + capHeight / 2);
			pushTo(x + w, y + capHeight / 2);
			pushTo(x + w, y + capHeight);
			pushTo(x + w, y);
		}

		void writeI(float x, float y)
		{
			pushTo(x + w / 2, y);
			pushPD();
			pushTo(x + w / 2, y + capHeight);
		}

		void writeJ(float x, float y)
		{
			pushTo(x, y + capHeight / 4);
			pushPD();
			pushTo(x, y);
			pushTo(x + w, y);
			pushTo(x + w, y + capHeight);
		}

		void writeK(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushPU();
			pushTo(x + w, y + capHeight);
			pushPD();
			pushTo(x, y + capHeight / 2);
			pushTo(x + w, y);
		}

		void writeL(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x,y);
			pushTo(x + w, y);
		}

		void writeM(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x + w / 2, y + capHeight / 2);
			pushTo(x + w, y + capHeight);
			pushTo(x + w, y);
		}

		void writeN(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x + w, y);
			pushTo(x + w, y + capHeight);

		}

		void writeO(float x, float y)
		{
			pushPD();
			pushTo(x + w, y);
			pushTo(x + w, y + capHeight);
			pushTo(x, y + capHeight);
			pushTo(x, y);
		}

		void writeP(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x + w, y + capHeight);
			pushTo(x + w, y + capHeight / 2);
			pushTo(x, y + capHeight / 2);
		}

		void writeQ(float x, float y)
		{
			pushPD();
			pushTo(x + w / 2, y);
			pushTo(x + w, y + capHeight / 2);
			pushTo(x + w, y + capHeight);
			pushTo(x, y + capHeight);
			pushTo(x, y);
			pushPU();
			pushTo(x + w / 2, y + capHeight / 2);
			pushPD();
			pushTo(x + w, y);
		}

		void writeR(float x, float y)
		{
			writeP(x, y);
			pushTo(x + w, y);
		}

		void writeS(float x, float y)
		{
			pushPD();
			pushTo(x + w, y);
			pushTo(x + w, y + capHeight / 2);
			pushTo(x, y + capHeight / 2);
			pushTo(x, y + capHeight);
			pushTo(x + w, y + capHeight);
		}

		void writeT(float x, float y)
		{
			pushTo(x + w/2, y);
			pushPD();
			pushTo(x + w/2, y + capHeight);
			pushTo(x, y + capHeight);
			pushTo(x + w, y + capHeight);
		}

		void writeU(float x, float y)
		{
			pushTo(x, y + capHeight);
			pushPD();
			pushTo(x, y);
			pushTo(x + w, y);
			pushTo(x + w, y + capHeight);
		}

		void writeV(float x, float y)
		{
			pushTo(x, y + capHeight);
			pushPD();
			pushTo(x + w / 2, y);
			pushTo(x + w, y + capHeight);
		}

		void writeW(float x, float y)
		{
			pushTo(x, y + capHeight);
			pushPD();
			pushTo(x + w / 4, y);
			pushTo(x + w / 2, y + capHeight / 2);
			pushTo(x + 3 * w / 4, y);
			pushTo(x + w, y + capHeight);
		}

		void writeX(float x, float y)
		{
			pushPD();
			pushTo(x + w, y + capHeight);
			pushPU();
			pushTo(x, y + capHeight);
			pushPD();
			pushTo(x + w, y);
		}

		void writeY(float x, float y)
		{
			pushPD();
			pushTo(x + w, y + capHeight);
			pushPU();
			pushTo(x, y + capHeight);
			pushPD();
			pushTo(x + w / 2, y + capHeight / 2);
		}

		void writeZ(float x, float y)
		{
			pushTo(x, y + capHeight);
			pushPD();
			pushTo(x + w, y + capHeight);
			pushTo(x, y);
			pushTo(x + w, y);
		}

		void writeColon(float x, float y)
		{
			pushTo(x + w/3, y + capHeight/3);
			pushPD();
			pushTo(x + 2*w/3, y + capHeight/3);
			pushPU();
			pushTo(x + 2*w/3, y + 2*capHeight/3);
			pushPD();
			pushTo(x + w/3, y + 2*capHeight/3);
		}

		void writeCloseBracket(float x, float y)
		{
			pushTo(x + w/3, y);
			pushPD();
			pushTo(x + 2*w/3, y + capHeight/4);
			pushTo(x + 2*w/3, y + 3*capHeight/4);
			pushTo(x + w/3, y + capHeight);
		}

		void writeHash(float x, float y)
		{
			pushTo(x, y + capHeight/3);
			pushPD();
			pushTo(x + w, y + capHeight/3);
			pushPU();
			pushTo(x + w, y + 2*capHeight/3);
			pushPD();
			pushTo(x, y + 2*capHeight/3);
			pushPU();

			pushTo(x + w/3, y + capHeight);
			pushPD();
			pushTo(x + w/3, y);
			pushPU();
			pushTo(x + 2*w/3, y);
			pushPD();
			pushTo(x + 2*w/3, y + capHeight);
		}
	}
	// End private namespace functions

	// Logobot text public functions
	void begin(CommandQueue& cmdQ)
	{
		_cmdQ = &cmdQ;
		setFontSize(20);
	}

	void setFontSize(float size)
	{
		fontSize = size;
		capHeight = fontSize * 0.7;
		letterSpacing = fontSize * 0.1;
		w = fontSize * 0.5;
	}

	void writeChar(char c, float x, float y)
	{
		switch (c) {
			case 'A':
				writeA(x, y);
				break;
			case 'B':
				writeB(x, y);
				break;
			case 'C':
				writeC(x, y);
				break;
			case 'D':
				writeD(x, y);
				break;
			case 'E':
				writeE(x, y);
				break;
			case 'F':
				writeF(x, y);
				break;
			case 'G':
				writeG(x, y);
				break;
			case 'H':
				writeH(x, y);
				break;
			case 'I':
				writeI(x, y);
				break;
			case 'J':
				writeJ(x, y);
				break;
			case 'K':
				writeK(x, y);
				break;
			case 'L':
				writeL(x, y);
				break;
			case 'M':
				writeM(x, y);
				break;
			case 'N':
				writeN(x, y);
				break;
			case 'O':
				writeO(x, y);
				break;
			case 'P':
				writeP(x, y);
				break;
			case 'Q':
				writeQ(x, y);
				break;
			case 'R':
				writeR(x, y);
				break;
			case 'S':
				writeS(x, y);
				break;
			case 'T':
				writeT(x, y);
				break;
			case 'U':
				writeU(x, y);
				break;
			case 'V':
				writeV(x, y);
				break;
			case 'W':
				writeW(x, y);
				break;
			case 'X':
				writeX(x, y);
				break;
			case 'Y':
				writeY(x, y);
				break;
			case 'Z':
				writeZ(x, y);
				break;
			case ' ':
				// nothing to do, just move to next letter
				break;
			case ':':
				writeColon(x,y);
				break;
			case ')':
				writeCloseBracket(x,y);
				break;
			case '#':
				writeHash(x,y);
				break;

			default:
				_cmdQ->enqueue("500",LOGO_CMD_BZ);
				//pushCmd("BZ 500");
				return;
		}

		pushPU();
		pushTo(x + w + letterSpacing, y);
	}
}
<commit_msg>@.  Probably.<commit_after>#include "LogobotText.h"

// local copy of critical command defines - for space optimisation
#define LOGO_CMD_TO			4
#define LOGO_CMD_BZ			8
#define LOGO_CMD_PU			9
#define LOGO_CMD_PD			10

namespace LogobotText
{
	// Namespace containing private functions
	namespace
	{
		float fontSize;  // =em, equal to line spacing (between baselines), text sizes derived from this
		float capHeight;
		float letterSpacing;
		float w;

		CommandQueue * _cmdQ;

		void pushPU() {
			_cmdQ->enqueue("", LOGO_CMD_PU);
		}

		void pushPD() {
			_cmdQ->enqueue("", LOGO_CMD_PD);
		}

		void pushTo(float x, float y)
		{
			String s = String(x);
			s += " ";
			s += y;
			_cmdQ->enqueue(s, LOGO_CMD_TO);
		}

		// Alphabet
		void writeA(float x, float y)
		{
			pushPD();
			pushTo(x + w/2, y + capHeight);
			pushTo(x + w, y);
			pushPU();
			pushTo(x + w / 4, y + capHeight / 2);
			pushPD();
			pushTo(x + 3 * w / 4, y + capHeight / 2 );
		}

		void writeB(float x, float y)
		{
			pushPD();
			pushTo(x + 2 * w / 3, y);
			pushTo(x + w, y + capHeight / 4);
			pushTo(x + 2 * w / 3, y + capHeight / 2);
			pushTo(x + w, y + 3 * capHeight / 4);
			pushTo(x + 2 * w / 3, y + capHeight);
			pushTo(x, y + capHeight);
			pushTo(x, y);
		}

		void writeC(float x, float y)
		{
			pushTo(x + w, y + capHeight);
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x, y);
			pushTo(x + w, y);
		}

		void writeD(float x, float y)
		{
			pushPD();
			pushTo(x + 3 * w / 4, y);
			pushTo(x + w, y + capHeight / 4);
			pushTo(x + w, y + 3 * capHeight / 4);
			pushTo(x + 3 * w / 4, y + capHeight);
			pushTo(x, y + capHeight);
			pushTo(x, y);
		}

		void writeE(float x, float y)
		{
			writeC(x, y);
			pushPU();
			pushTo(x, y + capHeight / 2);
			pushPD();
			pushTo(x + w, y + capHeight /2);
		}

		void writeF(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x + w, y + capHeight);
			pushPU();
			pushTo(x + w, y + capHeight / 2);
			pushPD();
			pushTo(x, y + capHeight / 2);
		}

		void writeG(float x, float y)
		{
			pushTo(x + w, y + capHeight);
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x, y);
			pushTo(x + w, y);
			pushTo(x + w, y + capHeight/3);
			pushTo(x + w/3, y + capHeight/3);
		}

		void writeH(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x, y + capHeight / 2);
			pushTo(x + w, y + capHeight / 2);
			pushTo(x + w, y + capHeight);
			pushTo(x + w, y);
		}

		void writeI(float x, float y)
		{
			pushTo(x + w / 2, y);
			pushPD();
			pushTo(x + w / 2, y + capHeight);
		}

		void writeJ(float x, float y)
		{
			pushTo(x, y + capHeight / 4);
			pushPD();
			pushTo(x, y);
			pushTo(x + w, y);
			pushTo(x + w, y + capHeight);
		}

		void writeK(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushPU();
			pushTo(x + w, y + capHeight);
			pushPD();
			pushTo(x, y + capHeight / 2);
			pushTo(x + w, y);
		}

		void writeL(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x,y);
			pushTo(x + w, y);
		}

		void writeM(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x + w / 2, y + capHeight / 2);
			pushTo(x + w, y + capHeight);
			pushTo(x + w, y);
		}

		void writeN(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x + w, y);
			pushTo(x + w, y + capHeight);

		}

		void writeO(float x, float y)
		{
			pushPD();
			pushTo(x + w, y);
			pushTo(x + w, y + capHeight);
			pushTo(x, y + capHeight);
			pushTo(x, y);
		}

		void writeP(float x, float y)
		{
			pushPD();
			pushTo(x, y + capHeight);
			pushTo(x + w, y + capHeight);
			pushTo(x + w, y + capHeight / 2);
			pushTo(x, y + capHeight / 2);
		}

		void writeQ(float x, float y)
		{
			pushPD();
			pushTo(x + w / 2, y);
			pushTo(x + w, y + capHeight / 2);
			pushTo(x + w, y + capHeight);
			pushTo(x, y + capHeight);
			pushTo(x, y);
			pushPU();
			pushTo(x + w / 2, y + capHeight / 2);
			pushPD();
			pushTo(x + w, y);
		}

		void writeR(float x, float y)
		{
			writeP(x, y);
			pushTo(x + w, y);
		}

		void writeS(float x, float y)
		{
			pushPD();
			pushTo(x + w, y);
			pushTo(x + w, y + capHeight / 2);
			pushTo(x, y + capHeight / 2);
			pushTo(x, y + capHeight);
			pushTo(x + w, y + capHeight);
		}

		void writeT(float x, float y)
		{
			pushTo(x + w/2, y);
			pushPD();
			pushTo(x + w/2, y + capHeight);
			pushTo(x, y + capHeight);
			pushTo(x + w, y + capHeight);
		}

		void writeU(float x, float y)
		{
			pushTo(x, y + capHeight);
			pushPD();
			pushTo(x, y);
			pushTo(x + w, y);
			pushTo(x + w, y + capHeight);
		}

		void writeV(float x, float y)
		{
			pushTo(x, y + capHeight);
			pushPD();
			pushTo(x + w / 2, y);
			pushTo(x + w, y + capHeight);
		}

		void writeW(float x, float y)
		{
			pushTo(x, y + capHeight);
			pushPD();
			pushTo(x + w / 4, y);
			pushTo(x + w / 2, y + capHeight / 2);
			pushTo(x + 3 * w / 4, y);
			pushTo(x + w, y + capHeight);
		}

		void writeX(float x, float y)
		{
			pushPD();
			pushTo(x + w, y + capHeight);
			pushPU();
			pushTo(x, y + capHeight);
			pushPD();
			pushTo(x + w, y);
		}

		void writeY(float x, float y)
		{
			pushPD();
			pushTo(x + w, y + capHeight);
			pushPU();
			pushTo(x, y + capHeight);
			pushPD();
			pushTo(x + w / 2, y + capHeight / 2);
		}

		void writeZ(float x, float y)
		{
			pushTo(x, y + capHeight);
			pushPD();
			pushTo(x + w, y + capHeight);
			pushTo(x, y);
			pushTo(x + w, y);
		}

		void writeColon(float x, float y)
		{
			pushTo(x + w / 3, y + capHeight / 3);
			pushPD();
			pushTo(x + 2 * w / 3, y + capHeight / 3);
			pushPU();
			pushTo(x + 2 * w / 3, y + 2 * capHeight / 3);
			pushPD();
			pushTo(x + w / 3, y + 2 * capHeight / 3);
		}

		void writeCloseBracket(float x, float y)
		{
			pushTo(x + w / 3, y);
			pushPD();
			pushTo(x + 2 * w / 3, y + capHeight / 4);
			pushTo(x + 2 * w / 3, y + 3 * capHeight / 4);
			pushTo(x + w / 3, y + capHeight);
		}

		void writeHash(float x, float y)
		{
			pushTo(x, y + capHeight / 3);
			pushPD();
			pushTo(x + w, y + capHeight / 3);
			pushPU();
			pushTo(x + w, y + 2 * capHeight / 3);
			pushPD();
			pushTo(x, y + 2 * capHeight / 3);
			pushPU();

			pushTo(x + w / 3, y + capHeight);
			pushPD();
			pushTo(x + w / 3, y);
			pushPU();
			pushTo(x + 2 * w / 3, y);
			pushPD();
			pushTo(x + 2 * w / 3, y + capHeight);
		}

		void writeAt(float x, float y)
		{
			pushTo(x + 2 * w / 3, y + capHeight / 3);
			pushPD();
			pushTo(x + 2 * w / 3, y + 2 * capHeight / 3);
			pushTo(x + w / 3, y + capHeight / 2);
			pushTo(x + 2 * w / 3, y + capHeight / 3);
			pushTo(x + w, y + capHeight / 2);
			pushTo(x + 2 * w / 3, y + capHeight);
			pushTo(x, y + capHeight / 2);
			pushTo(x + w / 2, y);
			pushTo(x + w, y + capHeight / 3);
		}
	}
	// End private namespace functions

	// Logobot text public functions
	void begin(CommandQueue& cmdQ)
	{
		_cmdQ = &cmdQ;
		setFontSize(20);
	}

	void setFontSize(float size)
	{
		fontSize = size;
		capHeight = fontSize * 0.7;
		letterSpacing = fontSize * 0.1;
		w = fontSize * 0.5;
	}

	void writeChar(char c, float x, float y)
	{
		switch (c) {
			case 'A':
				writeA(x, y);
				break;
			case 'B':
				writeB(x, y);
				break;
			case 'C':
				writeC(x, y);
				break;
			case 'D':
				writeD(x, y);
				break;
			case 'E':
				writeE(x, y);
				break;
			case 'F':
				writeF(x, y);
				break;
			case 'G':
				writeG(x, y);
				break;
			case 'H':
				writeH(x, y);
				break;
			case 'I':
				writeI(x, y);
				break;
			case 'J':
				writeJ(x, y);
				break;
			case 'K':
				writeK(x, y);
				break;
			case 'L':
				writeL(x, y);
				break;
			case 'M':
				writeM(x, y);
				break;
			case 'N':
				writeN(x, y);
				break;
			case 'O':
				writeO(x, y);
				break;
			case 'P':
				writeP(x, y);
				break;
			case 'Q':
				writeQ(x, y);
				break;
			case 'R':
				writeR(x, y);
				break;
			case 'S':
				writeS(x, y);
				break;
			case 'T':
				writeT(x, y);
				break;
			case 'U':
				writeU(x, y);
				break;
			case 'V':
				writeV(x, y);
				break;
			case 'W':
				writeW(x, y);
				break;
			case 'X':
				writeX(x, y);
				break;
			case 'Y':
				writeY(x, y);
				break;
			case 'Z':
				writeZ(x, y);
				break;
			case ' ':
				// nothing to do, just move to next letter
				break;
			case ':':
				writeColon(x, y);
				break;
			case ')':
				writeCloseBracket(x, y);
				break;
			case '#':
				writeHash(x, y);
				break;
			case '@':
				writeAt(x, y);

			default:
				_cmdQ->enqueue("500", LOGO_CMD_BZ);
				return;
		}

		pushPU();
		pushTo(x + w + letterSpacing, y);
	}
}
<|endoftext|>