<commit_before>
/*
 *  CS Object output
 *  Author: Luca Pancallo 2000.09.28
 */

#include "3dsout.h"
#include "3ds2lev.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>

// includes for lib3ds
#include <lib3ds/camera.h>
#include <lib3ds/file.h>
#include <lib3ds/io.h>
#include <lib3ds/light.h>
#include <lib3ds/material.h>
#include <lib3ds/matrix.h>
#include <lib3ds/mesh.h>
#include <lib3ds/node.h>
#include <lib3ds/vector.h>

extern int flags;

/**
 * Outputs the header with TEXTURES, MATERIALS, PLUGINS.
 */
void OutpHeadCS (FILE *o, Lib3dsFile *p3dsFile)
{
  if (flags & FLAG_SPRITE)
  {
    fprintf (o, "MESHFACT 'sprite' (\n");
    fprintf (o, "  PLUGIN ('crystalspace.mesh.loader.factory.sprite.3d')\n");
    fprintf (o, "  PARAMS (\n");
  }
  else
  {

    // extracts all unique textures
    char *textures[100];
    int numTextures = 0;
    int j;

    // set the current mesh to the first in the file
    Lib3dsMesh *p3dsMesh = p3dsFile->meshes;
    // as long as we have a valid mesh...
    while( p3dsMesh )
    {
      // search if already present
      bool found = false;

      for (j=0; j<numTextures; j++) {
        if (strcmp(p3dsMesh->faceL->material, textures[j])==0) {
          found = true;
          break;
        }
      }
      // if not present add it!
      if (!found) {
        textures[numTextures] = p3dsMesh->faceL->material;
        numTextures++;
      }

      // go to next mesh
      p3dsMesh = p3dsMesh->next;
    }

    fprintf (o, "WORLD (\n");

    fprintf (o, "  TEXTURES (\n");

    // set the current mesh to the first in the file
    for (j=0; j<numTextures; j++)
        fprintf (o, "    TEXTURE '%s' (FILE (%s)) \n",textures[j], textures[j]);

    fprintf (o, "  )\n\n");

    fprintf (o, "  MATERIALS (\n");

    for (j=0; j<numTextures; j++)
        fprintf (o, "    MATERIAL '%s' (TEXTURE ('%s')) \n",textures[j], textures[j]);

    fprintf (o, "  )\n\n");

    fprintf (o, "  PLUGINS (\n");
    fprintf (o, "    PLUGIN 'thing' ('crystalspace.mesh.loader.thing')\n");
    fprintf (o, "    )\n");
    fprintf (o, "  SECTOR 'room' (\n");
  }
}

/**
 * Outputs all the objects present in the 3ds file.
 * Based on the object name we create MESHOBJ or PART.
 *
 */
void OutpObjectsCS (FILE * o, Lib3dsFile *p3dsFile, bool lighting)
{

  Lib3dsMesh *p3dsMesh = p3dsFile->meshes;

  if (flags & FLAG_SPRITE)
  {
    fprintf (o, "  ; '%s'\n", p3dsMesh->name);
  } else {

    // count meshes
    int numMeshes = 0;
    int n;
    while (p3dsMesh) {
         numMeshes++;
         p3dsMesh = p3dsMesh->next;
    }
    // build an array with all meshes
    Lib3dsMesh* p3dsMeshArray = new Lib3dsMesh[numMeshes];
    p3dsMesh = p3dsFile->meshes;
    for (n=0; n<numMeshes; n++) {
         p3dsMeshArray[n] = *p3dsMesh;
         p3dsMesh = p3dsMesh->next;
    }

    // Reorder the objects to have all "_s_" first.
    // set the current mesh to the first in the file
    for (n=0; n<numMeshes; n++)
    {
        // if not static...
        if (!strstr( ((Lib3dsMesh *)&p3dsMeshArray[n])->name, "_s_")) {
          // search a static and swap
          for (int j=n+1; j<numMeshes; j++) {
             if (strstr( ((Lib3dsMesh *)&p3dsMeshArray[j])->name, "_s_")) {
                Lib3dsMesh tmp = p3dsMeshArray[j];
                p3dsMeshArray[j] = p3dsMeshArray[n];
                p3dsMeshArray[n] = tmp;
                break;
             }
          }
        }
    }

    // assign reordered vector to main Lib3ds struct
    p3dsMesh = p3dsFile->meshes;
    for (n=0; n<numMeshes-1; n++) {
      ((Lib3dsMesh *)&p3dsMeshArray[n])->next=&p3dsMeshArray[n+1];
    }
    ((Lib3dsMesh *)&p3dsMeshArray[n])->next=0;

    p3dsFile->meshes = p3dsMeshArray;
  }

  // iterate on all meshes
  p3dsMesh = p3dsFile->meshes;

  bool staticObj = false;
  bool part = false;
  int numMesh = 0;
  while (p3dsMesh)
  {

    if (flags & FLAG_SPRITE) {
    }
    else {
        // on "_s_" decide if MESHOBJ or PART
        if (strstr(p3dsMesh->name, "_s_")) {
            if (!staticObj) {
                fprintf (o, "    MESHOBJ 'static' (\n");
                fprintf (o, "      PLUGIN ('thing')\n");
                fprintf (o, "      ZFILL ()\n");
                fprintf (o, "      PRIORITY('wall')\n");
                fprintf (o, "      PARAMS (\n");
                fprintf (o, "      VISTREE()\n");
                fprintf (o, "; Object Name : %s ", p3dsMesh->name);
                fprintf (o, " Faces: %6d faces \n", (int)p3dsMesh->faces);
                fprintf (o, "      PART '%s' (\n", p3dsMesh->name);
                staticObj = true;
            }
            else  {
                fprintf (o, "      PART '%s' (\n", p3dsMesh->name);
            }
            part = true;
        // else always MESHOBJ
        } else {
            // close previous PART and MESHOBJ if present
            if (part) {
                fprintf (o, "      )\n\n");
                fprintf (o, "    )\n\n");
                part = false;
            }
            fprintf (o, "; Object Name : %s ", p3dsMesh->name);
            fprintf (o, " Faces: %6d faces \n", (int)p3dsMesh->faces);

            fprintf (o, "    MESHOBJ '%s' (\n", p3dsMesh->name);
            fprintf (o, "      PLUGIN ('thing')\n");
            fprintf (o, "      ZUSE ()\n");
            // handles transparent objects
            if (strstr(p3dsMesh->name, "_t_")) {
                fprintf (o, "      PRIORITY('alpha')\n");
            } else {
                fprintf (o, "      PRIORITY('object')\n");
            }
            fprintf (o, "      PARAMS (\n");
        }
    }
    fprintf (o, "        MATERIAL ('%s')\n", p3dsMesh->faceL->material);

    // <--output vertexes-->

    // get the number of vertices in the current mesh
    int numVertices = p3dsMesh->points;
    int i;

    // vertexes pointer
    Lib3dsPoint *pCurPoint = p3dsMesh->pointL;
    Lib3dsTexel *pCurTexel = p3dsMesh->texelL;

    for (i = 0 ; i < numVertices ; i++ )
    {
      // index to the position on the list using index
      float *xyz = pCurPoint->pos;
      if (flags & FLAG_SPRITE)
      {
        float u = 0;
        float v = 0;
        if (pCurTexel != NULL)
        {
          u = pCurTexel[0][0];
          v = pCurTexel[0][1];
	  pCurTexel++;
        }

        fprintf (o, "        V(%g,%g,%g:", xyz[0], xyz[1], xyz[2]);
        fprintf (o, "%g,%g)\n",u, (flags & FLAG_SWAP_V ? 1.-v : v));
      }
      else
      {
        fprintf (o, "        VERTEX (%g,%g,%g)    ; %d\n",
        	  xyz[0], xyz[1], xyz[2], i);
      }

      // go to next vertex and texel
      pCurPoint++;
    }

    // <--output faces-->

    // get the number of faces in the current mesh
    int numFaces = p3dsMesh->faces;
    Lib3dsFace *pCurFace = p3dsMesh->faceL;

    // output faces
    for (i=0; i<numFaces; i++)
    {
      Lib3dsTexel *mapV0 = (Lib3dsTexel*)p3dsMesh->texelL[pCurFace->points[0]];
      Lib3dsTexel *mapV1 = (Lib3dsTexel*)p3dsMesh->texelL[pCurFace->points[1]];
      Lib3dsTexel *mapV2 = (Lib3dsTexel*)p3dsMesh->texelL[pCurFace->points[2]];

      if (flags & FLAG_SPRITE)
      {
        fprintf (o, "        TRIANGLE (%d,%d,%d)\n", pCurFace->points[0], pCurFace->points[1], pCurFace->points[2]);
      }
      else
      {
        // if a light is present in the 3ds file force LIGHTNING (yes)
        if (p3dsFile->lights)
            lighting = true;

        fprintf (o, "        POLYGON 'x%d_%d'  (VERTICES (%d,%d,%d)%s\n",
	             numMesh, i, pCurFace->points[0], pCurFace->points[1], pCurFace->points[2],
	             lighting ? "" : " LIGHTING (no)");
        fprintf (o, "          TEXTURE (UV (0,%g,%g,1,%g,%g,2,%g,%g))\n",
                 mapV0[0][0], (flags & FLAG_SWAP_V ? 1.-mapV0[0][1] : mapV0[0][1]),
                 mapV1[0][0], (flags & FLAG_SWAP_V ? 1.-mapV1[0][1] : mapV1[0][1]),
                 mapV2[0][0], (flags & FLAG_SWAP_V ? 1.-mapV2[0][1] : mapV2[0][1]));

/*                 mapV0[0][0], mapV0[0][1],
                 mapV1[0][0], mapV1[0][1],
                 mapV2[0][0], mapV2[0][1]);
                 */
        fprintf (o, "        )\n"); // close polygon
      }

      // go to next face
      pCurFace++;
    }
    // close PARAMS tag
    fprintf (o, "      )\n\n");

    // close MESHOBJ tag
    if (!part)
        fprintf (o, "    )\n\n");

    // increment mesh count
    numMesh++;
    p3dsMesh = p3dsMesh->next;

  } // ~end while (p3dsMesh)

  if (flags & FLAG_SPRITE)
  {
    fprintf (o, "ACTION 'default' (F (f1,1000))\n");
    fprintf (o, "  )\n");
  }
  else
  {
    fprintf (o, "    CULLER ('static')\n");

    Lib3dsLight *pCurLight = p3dsFile->lights;
    // output lights
    while (pCurLight) {

      // discart spot-lights
      if (pCurLight->spot_light) {
        fprintf (stderr, "Spotlight are not supported. Light '%s' will not be imported in CS\n", pCurLight->name);
      // convert omni-lights
      } else {
        fprintf (o, "    LIGHT (\n");
        fprintf (o, "      CENTER (%g,%g,%g) \n",pCurLight->position[0], pCurLight->position[1], pCurLight->position[2]);
        fprintf (o, "      RADIUS (%g) \n",pCurLight->outer_range);
        fprintf (o, "      COLOR (%g,%g,%g)\n",pCurLight->color[0], pCurLight->color[1], pCurLight->color[2]);
        fprintf (o, "    )\n");
      }

      pCurLight = pCurLight->next;
    }

    fprintf (o, "  )\n");
    fprintf (o, ")\n");
  }

}

<commit_msg>Another similar fix.<commit_after>
/*
 *  CS Object output
 *  Author: Luca Pancallo 2000.09.28
 */

#include "3dsout.h"
#include "3ds2lev.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>

// includes for lib3ds
#include <lib3ds/camera.h>
#include <lib3ds/file.h>
#include <lib3ds/io.h>
#include <lib3ds/light.h>
#include <lib3ds/material.h>
#include <lib3ds/matrix.h>
#include <lib3ds/mesh.h>
#include <lib3ds/node.h>
#include <lib3ds/vector.h>

extern int flags;

/**
 * Outputs the header with TEXTURES, MATERIALS, PLUGINS.
 */
void OutpHeadCS (FILE *o, Lib3dsFile *p3dsFile)
{
  if (flags & FLAG_SPRITE)
  {
    fprintf (o, "MESHFACT 'sprite' (\n");
    fprintf (o, "  PLUGIN ('crystalspace.mesh.loader.factory.sprite.3d')\n");
    fprintf (o, "  PARAMS (\n");
  }
  else
  {

    // extracts all unique textures
    char *textures[100];
    int numTextures = 0;
    int j;

    // set the current mesh to the first in the file
    Lib3dsMesh *p3dsMesh = p3dsFile->meshes;
    // as long as we have a valid mesh...
    while( p3dsMesh )
    {
      // search if already present
      bool found = false;

      for (j=0; j<numTextures; j++) {
        if (strcmp(p3dsMesh->faceL->material, textures[j])==0) {
          found = true;
          break;
        }
      }
      // if not present add it!
      if (!found) {
        textures[numTextures] = p3dsMesh->faceL->material;
        numTextures++;
      }

      // go to next mesh
      p3dsMesh = p3dsMesh->next;
    }

    fprintf (o, "WORLD (\n");

    fprintf (o, "  TEXTURES (\n");

    // set the current mesh to the first in the file
    for (j=0; j<numTextures; j++)
        fprintf (o, "    TEXTURE '%s' (FILE (%s)) \n",textures[j], textures[j]);

    fprintf (o, "  )\n\n");

    fprintf (o, "  MATERIALS (\n");

    for (j=0; j<numTextures; j++)
        fprintf (o, "    MATERIAL '%s' (TEXTURE ('%s')) \n",textures[j], textures[j]);

    fprintf (o, "  )\n\n");

    fprintf (o, "  PLUGINS (\n");
    fprintf (o, "    PLUGIN 'thing' ('crystalspace.mesh.loader.thing')\n");
    fprintf (o, "    )\n");
    fprintf (o, "  SECTOR 'room' (\n");
  }
}

/**
 * Outputs all the objects present in the 3ds file.
 * Based on the object name we create MESHOBJ or PART.
 *
 */
void OutpObjectsCS (FILE * o, Lib3dsFile *p3dsFile, bool lighting)
{

  Lib3dsMesh *p3dsMesh = p3dsFile->meshes;

  if (flags & FLAG_SPRITE)
  {
    fprintf (o, "  ; '%s'\n", p3dsMesh->name);
  } else {

    // count meshes
    int numMeshes = 0;
    int n;
    while (p3dsMesh) {
         numMeshes++;
         p3dsMesh = p3dsMesh->next;
    }
    // build an array with all meshes
    Lib3dsMesh* p3dsMeshArray = new Lib3dsMesh[numMeshes];
    p3dsMesh = p3dsFile->meshes;
    for (n=0; n<numMeshes; n++) {
         p3dsMeshArray[n] = *p3dsMesh;
         p3dsMesh = p3dsMesh->next;
    }

    // Reorder the objects to have all "_s_" first.
    // set the current mesh to the first in the file
    for (n=0; n<numMeshes; n++)
    {
        // if not static...
        if (!strstr( ((Lib3dsMesh *)&p3dsMeshArray[n])->name, "_s_")) {
          // search a static and swap
          for (int j=n+1; j<numMeshes; j++) {
             if (strstr( ((Lib3dsMesh *)&p3dsMeshArray[j])->name, "_s_")) {
                Lib3dsMesh tmp = p3dsMeshArray[j];
                p3dsMeshArray[j] = p3dsMeshArray[n];
                p3dsMeshArray[n] = tmp;
                break;
             }
          }
        }
    }

    // assign reordered vector to main Lib3ds struct
    p3dsMesh = p3dsFile->meshes;
    for (n=0; n<numMeshes-1; n++) {
      ((Lib3dsMesh *)&p3dsMeshArray[n])->next=&p3dsMeshArray[n+1];
    }
    ((Lib3dsMesh *)&p3dsMeshArray[n])->next=0;

    p3dsFile->meshes = p3dsMeshArray;
  }

  // iterate on all meshes
  p3dsMesh = p3dsFile->meshes;

  bool staticObj = false;
  bool part = false;
  int numMesh = 0;
  while (p3dsMesh)
  {

    if (flags & FLAG_SPRITE) {
    }
    else {
        // on "_s_" decide if MESHOBJ or PART
        if (strstr(p3dsMesh->name, "_s_")) {
            if (!staticObj) {
                fprintf (o, "    MESHOBJ 'static' (\n");
                fprintf (o, "      PLUGIN ('thing')\n");
                fprintf (o, "      ZFILL ()\n");
                fprintf (o, "      PRIORITY('wall')\n");
                fprintf (o, "      PARAMS (\n");
                fprintf (o, "      VISTREE()\n");
                fprintf (o, "; Object Name : %s ", p3dsMesh->name);
                fprintf (o, " Faces: %6d faces \n", (int)p3dsMesh->faces);
                fprintf (o, "      PART '%s' (\n", p3dsMesh->name);
                staticObj = true;
            }
            else  {
                fprintf (o, "      PART '%s' (\n", p3dsMesh->name);
            }
            part = true;
        // else always MESHOBJ
        } else {
            // close previous PART and MESHOBJ if present
            if (part) {
                fprintf (o, "      )\n\n");
                fprintf (o, "    )\n\n");
                part = false;
            }
            fprintf (o, "; Object Name : %s ", p3dsMesh->name);
            fprintf (o, " Faces: %6d faces \n", (int)p3dsMesh->faces);

            fprintf (o, "    MESHOBJ '%s' (\n", p3dsMesh->name);
            fprintf (o, "      PLUGIN ('thing')\n");
            fprintf (o, "      ZUSE ()\n");
            // handles transparent objects
            if (strstr(p3dsMesh->name, "_t_")) {
                fprintf (o, "      PRIORITY('alpha')\n");
            } else {
                fprintf (o, "      PRIORITY('object')\n");
            }
            fprintf (o, "      PARAMS (\n");
        }
    }
    fprintf (o, "        MATERIAL ('%s')\n", p3dsMesh->faceL->material);

    // <--output vertexes-->

    // get the number of vertices in the current mesh
    int numVertices = p3dsMesh->points;
    int i;

    // vertexes pointer
    Lib3dsPoint *pCurPoint = p3dsMesh->pointL;
    Lib3dsTexel *pCurTexel = p3dsMesh->texelL;

    for (i = 0 ; i < numVertices ; i++ )
    {
      // index to the position on the list using index
      float *xyz = pCurPoint->pos;
      if (flags & FLAG_SPRITE)
      {
        float u = 0;
        float v = 0;
        if (pCurTexel != NULL)
        {
          u = pCurTexel[0][0];
          v = pCurTexel[0][1];
	  pCurTexel++;
        }

        fprintf (o, "        V(%g,%g,%g:", xyz[0], xyz[1], xyz[2]);
        fprintf (o, "%g,%g)\n",u, (flags & FLAG_SWAP_V ? 1.-v : v));
      }
      else
      {
        fprintf (o, "        VERTEX (%g,%g,%g)    ; %d\n",
        	  xyz[0], xyz[1], xyz[2], i);
      }

      // go to next vertex and texel
      pCurPoint++;
    }

    // <--output faces-->

    // get the number of faces in the current mesh
    int numFaces = p3dsMesh->faces;
    Lib3dsFace *pCurFace = p3dsMesh->faceL;

    // output faces
    for (i=0; i<numFaces; i++)
    {
      if (flags & FLAG_SPRITE)
      {
        fprintf (o, "        TRIANGLE (%d,%d,%d)\n",
		pCurFace->points[0], pCurFace->points[1], pCurFace->points[2]);
      }
      else
      {
        // if a light is present in the 3ds file force LIGHTNING (yes)
        if (p3dsFile->lights)
            lighting = true;

        fprintf (o, "        POLYGON 'x%d_%d'  (VERTICES (%d,%d,%d)%s\n",
	             numMesh, i, pCurFace->points[0],
		     pCurFace->points[1], pCurFace->points[2],
	             lighting ? "" : " LIGHTING (no)");
        Lib3dsTexel *pCurTexel = p3dsMesh->texelL;
	if (pCurTexel)
	{
          Lib3dsTexel *mapV0 = (Lib3dsTexel*)pCurTexel[pCurFace->points[0]];
	  float u0 = mapV0[0][0];
	  float v0 = mapV0[0][1];
          Lib3dsTexel *mapV1 = (Lib3dsTexel*)pCurTexel[pCurFace->points[1]];
	  float u1 = mapV1[0][0];
	  float v1 = mapV1[0][1];
          Lib3dsTexel *mapV2 = (Lib3dsTexel*)pCurTexel[pCurFace->points[2]];
	  float u2 = mapV2[0][0];
	  float v2 = mapV2[0][1];
          fprintf (o, "          TEXTURE (UV (0,%g,%g,1,%g,%g,2,%g,%g))\n",
                 u0, (flags & FLAG_SWAP_V ? 1.-v0 : v0),
                 u1, (flags & FLAG_SWAP_V ? 1.-v1 : v1),
                 u2, (flags & FLAG_SWAP_V ? 1.-v2 : v2));
	}

        fprintf (o, "        )\n"); // close polygon
      }

      // go to next face
      pCurFace++;
    }
    // close PARAMS tag
    fprintf (o, "      )\n\n");

    // close MESHOBJ tag
    if (!part)
        fprintf (o, "    )\n\n");

    // increment mesh count
    numMesh++;
    p3dsMesh = p3dsMesh->next;

  } // ~end while (p3dsMesh)

  if (flags & FLAG_SPRITE)
  {
    fprintf (o, "ACTION 'default' (F (f1,1000))\n");
    fprintf (o, "  )\n");
  }
  else
  {
    fprintf (o, "    CULLER ('static')\n");

    Lib3dsLight *pCurLight = p3dsFile->lights;
    // output lights
    while (pCurLight) {

      // discart spot-lights
      if (pCurLight->spot_light) {
        fprintf (stderr, "Spotlight are not supported. Light '%s' will not be imported in CS\n", pCurLight->name);
      // convert omni-lights
      } else {
        fprintf (o, "    LIGHT (\n");
        fprintf (o, "      CENTER (%g,%g,%g) \n",pCurLight->position[0], pCurLight->position[1], pCurLight->position[2]);
        fprintf (o, "      RADIUS (%g) \n",pCurLight->outer_range);
        fprintf (o, "      COLOR (%g,%g,%g)\n",pCurLight->color[0], pCurLight->color[1], pCurLight->color[2]);
        fprintf (o, "    )\n");
      }

      pCurLight = pCurLight->next;
    }

    fprintf (o, "  )\n");
    fprintf (o, ")\n");
  }

}

<|endoftext|>


<commit_before>/*
 * Copyright (c) 2015 Samsung Electronics Co., Ltd 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.
 */
/**
 * @file        src/common/error/api.cpp
 * @author      Aleksander Zdyb <a.zdyb@samsung.com>
 * @version     1.0
 * @brief       Implementation of cynara_strerror
 */

#include <cstring>

#include <cynara-error.h>

int cynara_strerror(int errnum, char *buf, size_t buflen) {
    if (buf == nullptr)
        return CYNARA_API_INVALID_PARAM;

    const char *message = nullptr;

    switch (errnum) {
        case CYNARA_API_ACCESS_NOT_RESOLVED:
            message = "Access not resolved";
            break;
        case CYNARA_API_ACCESS_ALLOWED:
            message = "Access granted";
            break;
        case CYNARA_API_ACCESS_DENIED:
            message = "Access denied";
            break;
        case CYNARA_API_SUCCESS:
            message = "Operation successful";
            break;
        case CYNARA_API_CACHE_MISS:
            message = "Value not in cache";
            break;
        case CYNARA_API_MAX_PENDING_REQUESTS:
            message = "Pending requests exceeded maximum";
            break;
        case CYNARA_API_OUT_OF_MEMORY:
            message = "Out of memory";
            break;
        case CYNARA_API_INVALID_PARAM:
            message = "Invalid param";
            break;
        case CYNARA_API_SERVICE_NOT_AVAILABLE:
            message = "Service not available";
            break;
        case CYNARA_API_METHOD_NOT_SUPPORTED:
            message = "Method not supported";
            break;
        case CYNARA_API_OPERATION_NOT_ALLOWED:
            message = "Operation not allowed";
            break;
        case CYNARA_API_OPERATION_FAILED:
            message = "Operation failed";
            break;
        case CYNARA_API_BUCKET_NOT_FOUND:
            message = "Bucket not found";
            break;
        case CYNARA_API_UNKNOWN_ERROR:
            message = "Unknown error";
            break;
        case CYNARA_API_CONFIGURATION_ERROR:
            message = "Configuration error";
            break;
        case CYNARA_API_INVALID_COMMANDLINE_PARAM:
            message = "Invalid parameter in command-line";
            break;
        case CYNARA_API_BUFFER_TOO_SHORT:
            message = "Buffer too short";
            break;
        case CYNARA_API_DATABASE_CORRUPTED:
            message = "Database corrupted";
            break;
    }

    if (message == nullptr)
        return CYNARA_API_INVALID_PARAM;

    if (buflen < strlen(message) + 1)
        return CYNARA_API_BUFFER_TOO_SHORT;

    strcpy(buf, message);

    return CYNARA_API_SUCCESS;
}
<commit_msg>Add description of CYNARA_API_PERMISSION_DENIED<commit_after>/*
 * Copyright (c) 2015-2016 Samsung Electronics Co., Ltd 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.
 */
/**
 * @file        src/common/error/api.cpp
 * @author      Aleksander Zdyb <a.zdyb@samsung.com>
 * @version     1.0
 * @brief       Implementation of cynara_strerror
 */

#include <cstring>

#include <cynara-error.h>

int cynara_strerror(int errnum, char *buf, size_t buflen) {
    if (buf == nullptr)
        return CYNARA_API_INVALID_PARAM;

    const char *message = nullptr;

    switch (errnum) {
        case CYNARA_API_ACCESS_NOT_RESOLVED:
            message = "Access not resolved";
            break;
        case CYNARA_API_ACCESS_ALLOWED:
            message = "Access granted";
            break;
        case CYNARA_API_ACCESS_DENIED:
            message = "Access denied";
            break;
        case CYNARA_API_SUCCESS:
            message = "Operation successful";
            break;
        case CYNARA_API_CACHE_MISS:
            message = "Value not in cache";
            break;
        case CYNARA_API_MAX_PENDING_REQUESTS:
            message = "Pending requests exceeded maximum";
            break;
        case CYNARA_API_OUT_OF_MEMORY:
            message = "Out of memory";
            break;
        case CYNARA_API_INVALID_PARAM:
            message = "Invalid param";
            break;
        case CYNARA_API_SERVICE_NOT_AVAILABLE:
            message = "Service not available";
            break;
        case CYNARA_API_METHOD_NOT_SUPPORTED:
            message = "Method not supported";
            break;
        case CYNARA_API_OPERATION_NOT_ALLOWED:
            message = "Operation not allowed";
            break;
        case CYNARA_API_OPERATION_FAILED:
            message = "Operation failed";
            break;
        case CYNARA_API_BUCKET_NOT_FOUND:
            message = "Bucket not found";
            break;
        case CYNARA_API_UNKNOWN_ERROR:
            message = "Unknown error";
            break;
        case CYNARA_API_CONFIGURATION_ERROR:
            message = "Configuration error";
            break;
        case CYNARA_API_INVALID_COMMANDLINE_PARAM:
            message = "Invalid parameter in command-line";
            break;
        case CYNARA_API_BUFFER_TOO_SHORT:
            message = "Buffer too short";
            break;
        case CYNARA_API_DATABASE_CORRUPTED:
            message = "Database corrupted";
            break;
        case CYNARA_API_PERMISSION_DENIED:
            message = "Not enough permission to perform action";
            break;
    }

    if (message == nullptr)
        return CYNARA_API_INVALID_PARAM;

    if (buflen < strlen(message) + 1)
        return CYNARA_API_BUFFER_TOO_SHORT;

    strcpy(buf, message);

    return CYNARA_API_SUCCESS;
}
<|endoftext|>


<commit_before>/* Copyright (C) 2016 Matthew Giordano
 * You may use, distribute, and modify this code under the
 * terms of the GPL license.
 *
 * You should have recieved a copy of the GPL license with
 * this file. If not, please visit https://github.com/matthewpipie/Comets
 */
#include <string>
#include <utility>
#include "stdafx.h"
#include "Comet.h"
#include "CollisionCalculator.h"
#include "Constants.h"
#include "Errors.h"

SDL_Texture *Comet::cometTexture = nullptr;

Comet::Comet() :
	Sprite(Constants::STAR_TEXTURE),
	_initPos(0),
	_initDegree(0),
	_speedMultiplier(1),
	_initSide(Side::TOP),
	isAlive(true) {}

Comet::~Comet() {}

void Comet::initCometTexture(SDL_Renderer *rend) {
	cometTexture = IMG_LoadTexture(rend, Constants::COMET_TEXTURE);
	std::cout << "Comet image has been loaded: " << std::endl;
	if (cometTexture == nullptr) {
		// SDL_DestroyTexture(texture);
		fatalError("Failed to load image (comet)!  SDL_Error: " + std::string(SDL_GetError()));
	}
}

void Comet::initPos() {
	setSize(Constants::COMET_SIZE, Constants::COMET_SIZE);
	isAlive = true;
	_initPos = static_cast<double>(rand() % 101);
	_initDegree = (rand() % 179) + 1;
	_initSide = (Side)(rand() % 4);
	_speedMultiplier = (Constants::COMET_SPEED_MULTIPLIER_MAX
		- Constants::COMET_SPEED_MULTIPLIER_MIN)
		* (static_cast<double>(rand()) / static_cast<double>(RAND_MAX))
		+ Constants::COMET_SPEED_MULTIPLIER_MIN;

	// switch
	/* if side is 0, setPos(_initPos, 0)
	if 1, setPos(100, _initPos)
	if 2, setPos(_initPos, 100)
	if 3, setPos(0, _initPos)*/

	switch (static_cast<int>(_initSide)) {
		case 0:
			setPos(_initPos, 0.0);
			break;
		case 1:
			setPos(100.0, _initPos);
			break;
		case 2:
			setPos(_initPos, 100.0);
			break;
		case 3:
			setPos(0, _initPos);
			break;
		default:
			fatalError("Failed to set position!");
	}
}

void Comet::moveComet(bool isBack) {
	double xMovement;
	double yMovement;

	if (!isBack) {
		/*if (_isOut && (_x < 0 || _x > Constants::SCREEN_WIDTH || _y < 0 || _y > Constants::SCREEN_HEIGHT)) { // IS TRIGGERING AND IT SHUDNT BE
			isAlive = false;
			return;
		}
		if (!_isOut && (_x > 0 && _x < Constants::SCREEN_WIDTH && _y > 0 && _y < Constants::SCREEN_HEIGHT)) {
			_isOut = true;
		}*/
		if (getX() < -getW() || getX() > Constants::SCREEN_WIDTH + getW() || getY() < -getH() || getY() > Constants::SCREEN_HEIGHT + getH()) {
			isAlive = false;
			return;
		}
		xMovement = static_cast<double>(Constants::COMET_SPEED) * getXSpeed() * getSpeedMP();
		yMovement = static_cast<double>(Constants::COMET_SPEED) * getYSpeed() * getSpeedMP();
	} else {
		// std::cout << "initial thigo!" << std::endl;
		switch (_initSide) {
		case Side::TOP:
			xMovement = 0;
			yMovement = (-0.6 * getW())
				/ (.01 * static_cast<double>(Constants::SCREEN_HEIGHT_CALC));
			break;
		case Side::RIGHT:
			xMovement = (0.6 * getH())
				/ (.01 * static_cast<double>(Constants::SCREEN_WIDTH_CALC));
			yMovement = 0;
			break;
		case Side::BOTTOM:
			xMovement = 0;
			yMovement = (0.6 * getW())
				/ (.01 * static_cast<double>(Constants::SCREEN_HEIGHT_CALC));
			break;
		case Side::LEFT:
			xMovement = (-0.6 * getH())
				/ (.01 * static_cast<double>(Constants::SCREEN_WIDTH_CALC));
			yMovement = 0;
			break;
		default:
			fatalError("Failed to read position!");
		}
	}

	move(xMovement, yMovement);

	/*if (isBack) {
		std::cout << "init: moving comet x:" << _x << " y: " << _y << std::endl;

	}*/
}

bool Comet::isColliding(Comet *testComet) {
	double distanceBetweenCometsSquared = pow(getX() - testComet->getX(), 2.0) + pow(getY() - testComet->getY(), 2.0);
	double maxCollisionDistanceSquared = pow(getR() + testComet->getR(), 2.0);

	// std::cout << maxCollisionDistanceSquared << " " << distanceBetweenCometsSquared << std::endl;

	if (distanceBetweenCometsSquared <= maxCollisionDistanceSquared) {
		return true;
	}
	return false;
}

void Comet::resolveCollision(Comet *resolveComet) {
	CollisionCalculator collision(this, resolveComet);
	double finalX1 = collision.getFinalX();
	double finalY1 = collision.getFinalY();
	double finalX2 = collision.getSwappedX();
	double finalY2 = collision.getSwappedY();
	double speedMP1 = getSpeedMP();
	double speedMP2 = resolveComet->getSpeedMP();
	double angle = collision.getCollisionAngle();

	modifyTrueAngle(finalX1, finalY1, angle, speedMP1, speedMP2);
	resolveComet->modifyTrueAngle(finalX2, finalY2, angle, speedMP2, speedMP1);

	/*double tempMP = resolveComet->getSpeedMP();
	resolveComet->setSpeedMP(getSpeedMP());
	setSpeedMP(tempMP);*/
}

void Comet::setSpeedMP(double newMP) {
	_speedMultiplier = newMP;
	std::cout << "setting speed to " << newMP << std::endl;
}

double Comet::getSpeedMP() {
	return _speedMultiplier;
}

void Comet::modifyTrueAngle(double xSpeed, double ySpeed, double collisionAngle, double initSpeed, double altSpeed) {
	double angle = atan(ySpeed / xSpeed) * 180.0 / M_PI;
	if (angle < 180) {
		_initSide = Side::BOTTOM;
	} else {
		_initSide = Side::TOP;
	}

	std::cout << altSpeed << " " << collisionAngle * 180.0 / M_PI << " " << initSpeed << std::endl;

	_initDegree = 180.0 - angle;
	setSpeedMP(abs(std::sin(collisionAngle) * initSpeed) + abs(std::cos(collisionAngle) * altSpeed));
}

double Comet::getR() {
	return (getW() + getH()) / 4.0;
}

double Comet::getXSpeed() {
	double xSpeed;
	switch (_initSide) {
	case Side::TOP:
		xSpeed = std::cos(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	case Side::RIGHT:
		xSpeed = -1.0 * std::sin(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	case Side::BOTTOM:
		xSpeed = -1.0 * std::cos(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	case Side::LEFT:
		xSpeed = std::sin(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	default:
		fatalError("Failed to read position!");
	}
	return xSpeed;
}

double Comet::getYSpeed() {
	double ySpeed;
	switch(_initSide) {
	case Side::TOP:
		ySpeed = std::sin(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	case Side::RIGHT:
		ySpeed = std::cos(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	case Side::BOTTOM:
		ySpeed = -1.0 * std::sin(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	case Side::LEFT:
		ySpeed = -1.0 * std::cos(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	default:
		fatalError("Failed to read position!");
	}
	return ySpeed;
}

int Comet::getRealAngle() {
	int degree = 0;
	switch (_initSide) {
	case Side::TOP:
		degree = -_initDegree;
		break;
	case Side::RIGHT:
		degree = 270 - _initDegree;
		break;
	case Side::BOTTOM:
		degree = 180 - _initDegree;
		break;
	case Side::LEFT:
		degree = 90 - _initDegree;
		break;
	default:
		fatalError("Failed to read position!");
	}
	return degree;
}

double Comet::getSpeed() {
	return sqrt(pow(getXSpeed(), 2.0) + pow(getYSpeed(), 2.0));
}
<commit_msg>Fix super speed bug! Thanks @poi830!<commit_after>/* Copyright (C) 2016 Matthew Giordano
 * You may use, distribute, and modify this code under the
 * terms of the GPL license.
 *
 * You should have recieved a copy of the GPL license with
 * this file. If not, please visit https://github.com/matthewpipie/Comets
 */
#include <string>
#include <utility>
#include "stdafx.h"
#include "Comet.h"
#include "CollisionCalculator.h"
#include "Constants.h"
#include "Errors.h"

SDL_Texture *Comet::cometTexture = nullptr;

Comet::Comet() :
	Sprite(Constants::STAR_TEXTURE),
	_initPos(0),
	_initDegree(0),
	_speedMultiplier(1),
	_initSide(Side::TOP),
	isAlive(true) {}

Comet::~Comet() {}

void Comet::initCometTexture(SDL_Renderer *rend) {
	cometTexture = IMG_LoadTexture(rend, Constants::COMET_TEXTURE);
	std::cout << "Comet image has been loaded: " << std::endl;
	if (cometTexture == nullptr) {
		// SDL_DestroyTexture(texture);
		fatalError("Failed to load image (comet)!  SDL_Error: " + std::string(SDL_GetError()));
	}
}

void Comet::initPos() {
	setSize(Constants::COMET_SIZE, Constants::COMET_SIZE);
	isAlive = true;
	_initPos = static_cast<double>(rand() % 101);
	_initDegree = (rand() % 179) + 1;
	_initSide = (Side)(rand() % 4);
	_speedMultiplier = (Constants::COMET_SPEED_MULTIPLIER_MAX
		- Constants::COMET_SPEED_MULTIPLIER_MIN)
		* (static_cast<double>(rand()) / static_cast<double>(RAND_MAX))
		+ Constants::COMET_SPEED_MULTIPLIER_MIN;

	// switch
	/* if side is 0, setPos(_initPos, 0)
	if 1, setPos(100, _initPos)
	if 2, setPos(_initPos, 100)
	if 3, setPos(0, _initPos)*/

	switch (static_cast<int>(_initSide)) {
		case 0:
			setPos(_initPos, 0.0);
			break;
		case 1:
			setPos(100.0, _initPos);
			break;
		case 2:
			setPos(_initPos, 100.0);
			break;
		case 3:
			setPos(0, _initPos);
			break;
		default:
			fatalError("Failed to set position!");
	}
}

void Comet::moveComet(bool isBack) {
	double xMovement;
	double yMovement;

	if (!isBack) {
		/*if (_isOut && (_x < 0 || _x > Constants::SCREEN_WIDTH || _y < 0 || _y > Constants::SCREEN_HEIGHT)) { // IS TRIGGERING AND IT SHUDNT BE
			isAlive = false;
			return;
		}
		if (!_isOut && (_x > 0 && _x < Constants::SCREEN_WIDTH && _y > 0 && _y < Constants::SCREEN_HEIGHT)) {
			_isOut = true;
		}*/
		if (getX() < -getW() || getX() > Constants::SCREEN_WIDTH + getW() || getY() < -getH() || getY() > Constants::SCREEN_HEIGHT + getH()) {
			isAlive = false;
			return;
		}
		xMovement = static_cast<double>(Constants::COMET_SPEED) * getXSpeed() * getSpeedMP();
		yMovement = static_cast<double>(Constants::COMET_SPEED) * getYSpeed() * getSpeedMP();
	} else {
		// std::cout << "initial thigo!" << std::endl;
		switch (_initSide) {
		case Side::TOP:
			xMovement = 0;
			yMovement = (-0.6 * getW())
				/ (.01 * static_cast<double>(Constants::SCREEN_HEIGHT_CALC));
			break;
		case Side::RIGHT:
			xMovement = (0.6 * getH())
				/ (.01 * static_cast<double>(Constants::SCREEN_WIDTH_CALC));
			yMovement = 0;
			break;
		case Side::BOTTOM:
			xMovement = 0;
			yMovement = (0.6 * getW())
				/ (.01 * static_cast<double>(Constants::SCREEN_HEIGHT_CALC));
			break;
		case Side::LEFT:
			xMovement = (-0.6 * getH())
				/ (.01 * static_cast<double>(Constants::SCREEN_WIDTH_CALC));
			yMovement = 0;
			break;
		default:
			fatalError("Failed to read position!");
		}
	}

	move(xMovement, yMovement);

	/*if (isBack) {
		std::cout << "init: moving comet x:" << _x << " y: " << _y << std::endl;

	}*/
}

bool Comet::isColliding(Comet *testComet) {
	double distanceBetweenCometsSquared = pow(getX() - testComet->getX(), 2.0) + pow(getY() - testComet->getY(), 2.0);
	double maxCollisionDistanceSquared = pow(getR() + testComet->getR(), 2.0);

	// std::cout << maxCollisionDistanceSquared << " " << distanceBetweenCometsSquared << std::endl;

	if (distanceBetweenCometsSquared <= maxCollisionDistanceSquared) {
		return true;
	}
	return false;
}

void Comet::resolveCollision(Comet *resolveComet) {
	CollisionCalculator collision(this, resolveComet);
	double finalX1 = collision.getFinalX();
	double finalY1 = collision.getFinalY();
	double finalX2 = collision.getSwappedX();
	double finalY2 = collision.getSwappedY();
	double speedMP1 = getSpeedMP();
	double speedMP2 = resolveComet->getSpeedMP();
	double angle = collision.getCollisionAngle();

	std::cout << speedMP1 << " " << speedMP2 << std::endl;

	modifyTrueAngle(finalX1, finalY1, angle, speedMP1, speedMP2);
	resolveComet->modifyTrueAngle(finalX2, finalY2, angle, speedMP2, speedMP1);

	/*double tempMP = resolveComet->getSpeedMP();
	resolveComet->setSpeedMP(getSpeedMP());
	setSpeedMP(tempMP);*/
}

void Comet::setSpeedMP(double newMP) {
	_speedMultiplier = newMP;
	std::cout << "setting speed to " << newMP << std::endl;
}

double Comet::getSpeedMP() {
	return _speedMultiplier;
}

void Comet::modifyTrueAngle(double xSpeed, double ySpeed, double collisionAngle, double initSpeed, double altSpeed) {
	double angle = atan(ySpeed / xSpeed) * 180.0 / M_PI;
	if (angle < 180) {
		_initSide = Side::BOTTOM;
	} else {
		_initSide = Side::TOP;
	}

	std::cout << altSpeed << " " << collisionAngle << "/" << collisionAngle * 180.0 / M_PI << " " << initSpeed << std::endl;

	_initDegree = 180.0 - angle;
	setSpeedMP(std::pow(std::sin(collisionAngle), 2) * initSpeed + std::pow(std::cos(collisionAngle), 2) * altSpeed);
}

double Comet::getR() {
	return (getW() + getH()) / 4.0;
}

double Comet::getXSpeed() {
	double xSpeed;
	switch (_initSide) {
	case Side::TOP:
		xSpeed = std::cos(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	case Side::RIGHT:
		xSpeed = -1.0 * std::sin(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	case Side::BOTTOM:
		xSpeed = -1.0 * std::cos(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	case Side::LEFT:
		xSpeed = std::sin(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	default:
		fatalError("Failed to read position!");
	}
	return xSpeed;
}

double Comet::getYSpeed() {
	double ySpeed;
	switch(_initSide) {
	case Side::TOP:
		ySpeed = std::sin(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	case Side::RIGHT:
		ySpeed = std::cos(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	case Side::BOTTOM:
		ySpeed = -1.0 * std::sin(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	case Side::LEFT:
		ySpeed = -1.0 * std::cos(static_cast<double>(_initDegree) * M_PI / 180.0);
		break;
	default:
		fatalError("Failed to read position!");
	}
	return ySpeed;
}

int Comet::getRealAngle() {
	int degree = 0;
	switch (_initSide) {
	case Side::TOP:
		degree = -_initDegree;
		break;
	case Side::RIGHT:
		degree = 270 - _initDegree;
		break;
	case Side::BOTTOM:
		degree = 180 - _initDegree;
		break;
	case Side::LEFT:
		degree = 90 - _initDegree;
		break;
	default:
		fatalError("Failed to read position!");
	}
	return degree;
}

double Comet::getSpeed() {
	return sqrt(pow(getXSpeed(), 2.0) + pow(getYSpeed(), 2.0));
}
<|endoftext|>


<commit_before>#ifndef SUBEVENT_TIMER_MANAGER_INL
#define SUBEVENT_TIMER_MANAGER_INL

#include <algorithm>
#include <functional>

#include <subevent/timer_manager.hpp>
#include <subevent/common.hpp>
#include <subevent/timer.hpp>
#include <subevent/thread.hpp>

SEV_NS_BEGIN

//----------------------------------------------------------------------------//
// TimerManager
//----------------------------------------------------------------------------//

TimerManager::TimerManager()
{
}

TimerManager::~TimerManager()
{
    cancelAll();
}

void TimerManager::start(Timer* timer)
{
    timer->mRunning = true;

    Item item;
    item.end = std::chrono::system_clock::now() +
        std::chrono::milliseconds(timer->getInterval());
    item.timer = timer;

    for (auto it = mItems.begin(); it != mItems.end(); ++it)
    {
        if (it->end > item.end)
        {
            mItems.insert(it, std::move(item));
            return;
        }
    }
    mItems.push_back(std::move(item));
}

void TimerManager::cancel(Timer* timer)
{
    timer->mRunning = false;

    auto it = std::find_if(
        mItems.begin(), mItems.end(),
        [&](const Item& item) {
            return (item.timer == timer);
        });
    if (it != mItems.end())
    {
        mItems.erase(it);
        return;
    }

    mExpired.erase(timer);
}

void TimerManager::cancelAll()
{
    for (Item& item : mItems)
    {
        item.timer->mRunning = false;
    }
    mItems.clear();

    for (Timer* timer : mExpired)
    {
        timer->mRunning = false;
    }
    mExpired.clear();
}

uint32_t TimerManager::nextTimeout()
{
    if (mItems.empty())
    {
        return UINT32_MAX;
    }
    else
    {
        auto now = std::chrono::system_clock::now();
        if (mItems.front().end <= now)
        {
            return 0;
        }

        auto remain = mItems.front().end - now;
        return static_cast<uint32_t>(std::chrono::duration_cast<
            std::chrono::milliseconds>(remain).count());
    }
}

void TimerManager::expire()
{
    auto now = std::chrono::system_clock::now();

    while (!mItems.empty())
    {
        Item& item = mItems.front();

        if (item.end > now)
        {
            break;
        }

        Timer* timer = item.timer;
        mItems.pop_front();

        if (!timer->isRunning())
        {
            continue;
        }

        mExpired.insert(timer);

        Thread::getCurrent()->post([this, timer]() {

            if (mExpired.erase(timer) == 0)
            {
                return;
            }

            if (!timer->isRunning())
            {
                return;
            }
            timer->mRunning = false;

            if (timer->isRepeat())
            {
                start(timer);
            }

            timer->mHandler(timer);
        });
    }
}

SEV_NS_END

#endif // SUBEVENT_TIMER_MANAGER_INL
<commit_msg>fix timer bug<commit_after>#ifndef SUBEVENT_TIMER_MANAGER_INL
#define SUBEVENT_TIMER_MANAGER_INL

#include <algorithm>
#include <functional>

#include <subevent/timer_manager.hpp>
#include <subevent/common.hpp>
#include <subevent/timer.hpp>
#include <subevent/thread.hpp>

SEV_NS_BEGIN

//----------------------------------------------------------------------------//
// TimerManager
//----------------------------------------------------------------------------//

TimerManager::TimerManager()
{
}

TimerManager::~TimerManager()
{
    cancelAll();
}

void TimerManager::start(Timer* timer)
{
    timer->mRunning = true;

    Item item;
    item.end = std::chrono::system_clock::now() +
        std::chrono::milliseconds(timer->getInterval());
    item.timer = timer;

    for (auto it = mItems.begin(); it != mItems.end(); ++it)
    {
        if (it->end > item.end)
        {
            mItems.insert(it, std::move(item));
            return;
        }
    }
    mItems.push_back(std::move(item));
}

void TimerManager::cancel(Timer* timer)
{
    timer->mRunning = false;

    auto it = std::find_if(
        mItems.begin(), mItems.end(),
        [&](const Item& item) {
            return (item.timer == timer);
        });
    if (it != mItems.end())
    {
        mItems.erase(it);
        return;
    }

    mExpired.erase(timer);
}

void TimerManager::cancelAll()
{
    for (Item& item : mItems)
    {
        item.timer->mRunning = false;
    }
    mItems.clear();

    for (Timer* timer : mExpired)
    {
        timer->mRunning = false;
    }
    mExpired.clear();
}

uint32_t TimerManager::nextTimeout()
{
    if (mItems.empty())
    {
        return UINT32_MAX;
    }
    else
    {
        auto now = std::chrono::system_clock::now();
        if (mItems.front().end <= now)
        {
            return 0;
        }

        auto remain = mItems.front().end - now;
        return static_cast<uint32_t>(std::chrono::duration_cast<
            std::chrono::milliseconds>(remain).count());
    }
}

void TimerManager::expire()
{
    auto now = std::chrono::system_clock::now();

    while (!mItems.empty())
    {
        Item& item = mItems.front();

        if (item.end > now)
        {
            break;
        }

        Timer* timer = item.timer;
        mItems.pop_front();

        if (!timer->isRunning())
        {
            continue;
        }

        mExpired.insert(timer);

        Thread::getCurrent()->post([this, timer]() {

            if (mExpired.erase(timer) == 0)
            {
                return;
            }

            if (!timer->isRunning())
            {
                return;
            }
            timer->mRunning = false;

            if (timer->isRepeat())
            {
                start(timer);
            }

            TimerHandler handler = timer->mHandler;
            handler(timer);
        });
    }
}

SEV_NS_END

#endif // SUBEVENT_TIMER_MANAGER_INL
<|endoftext|>


<commit_before>//debugging level 0 = nothing
//debugging level 1 = critical errors
//debugging level 2 = errors
//debugging level 3 = status information
//debugging level 4 = extremely verbose status information
#define DEBUG 4

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/epoll.h>
#include <getopt.h>

enum {HANDLER_NONE, HANDLER_PROGRESSIVE, HANDLER_FLASH, HANDLER_APPLE, HANDLER_MICRO};

#define DEFAULT_PORT 8080
#include "../util/server_setup.cpp"
#include "../util/http_parser.cpp"
#include "../util/MP4/interface.cpp"

static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string base64_encode(std::string const input) {
  std::string ret;
  unsigned int in_len = input.size();
  char quad[4], triple[3];
  unsigned int i, x, n = 3;
  for (x = 0; x < in_len; x = x + 3){
    if ((in_len - x) / 3 == 0){n = (in_len - x) % 3;}
    for (i=0; i < 3; i++){triple[i] = '0';}
    for (i=0; i < n; i++){triple[i] = input[x + i];}
    quad[0] = base64_chars[(triple[0] & 0xFC) >> 2]; // FC = 11111100
    quad[1] = base64_chars[((triple[0] & 0x03) << 4) | ((triple[1] & 0xF0) >> 4)]; // 03 = 11
    quad[2] = base64_chars[((triple[1] & 0x0F) << 2) | ((triple[2] & 0xC0) >> 6)]; // 0F = 1111, C0=11110
    quad[3] = base64_chars[triple[2] & 0x3F]; // 3F = 111111
    if (n < 3){quad[3] = '=';}
    if (n < 2){quad[2] = '=';}
    for(i=0; i < 4; i++){ret += quad[i];}
  }
  return ret;
}//base64_encode

int FlvToFragNum( FLV_Pack * tag ) {
  int Timestamp = (tag->data[7] << 24 ) + (tag->data[4] << 16 ) + (tag->data[5] << 8 ) + (tag->data[6] );
  return (Timestamp / 10000) + 1;
}

int FlvGetTimestamp( Flv_Pack * tag ) {
  return ( (tag->data[7] << 24 ) + (tag->data[4] << 16 ) + (tag->data[5] << 8 ) + (tag->data[6] ) );
}

std::string BuildManifest( std::string MetaData, std::string MovieId, int CurrentMediaTime ) {
  Interface * temp = new Interface;
  std::string Result="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n";
  Result += "<id>";
  Result += MovieId;
  Result += "</id>\n<mimeType>video/mp4</mimeType>\n";
  Result += "<streamType>live</streamType>\n";
  Result += "<deliveryType>streaming</deliveryType>\n";
  Result += "<bootstrapInfo profile=\"named\" id=\"bootstrap1\">";
  Result += base64_encode(temp->GenerateLiveBootstrap(CurrentMediaTime));
  Result += "</bootstrapInfo>\n";
  Result += "<media streamId=\"1\" bootstrapInfoId=\"bootstrap1\" url=\"";
  Result += MovieId;
  Result += "/\">\n";
  Result += "<metadata>";
  Result += base64_encode(MetaData);
  Result += "</metadata>\n";
  Result += "</media>\n";
  Result += "</manifest>\n";
  delete temp;
  return Result;
}

int mainHandler(int CONN_fd){
  int handler = HANDLER_PROGRESSIVE;
  bool ready4data = false;//set to true when streaming starts
  bool inited = false;
  bool progressive_has_sent_header = false;
  int ss;
  std::string streamname;
  std::string FlashBuf;
  std::string FlashMeta;
  bool Flash_ManifestSent = false;
  FLV_Pack * tag = 0;
  HTTPReader HTTP_R, HTTP_S;//HTTP Receiver en HTTP Sender.

  int retval;
  int poller = epoll_create(1);
  int sspoller = epoll_create(1);
  struct epoll_event ev;
  ev.events = EPOLLIN;
  ev.data.fd = CONN_fd;
  epoll_ctl(poller, EPOLL_CTL_ADD, CONN_fd, &ev);
  struct epoll_event events[1];

  std::string Movie = "";
  std::string Quality = "";
  int Segment = -1;
  int ReqFragment = -1;
  int temp;
  //int CurrentFragment = -1; later herbruiken?

  while (!socketError && !All_Hell_Broke_Loose){
    //only parse input if available or not yet init'ed
    retval = epoll_wait(poller, events, 1, 1);
    if ((retval > 0) || !ready4data){
      if (HTTP_R.ReadSocket(CONN_fd)){
        handler = HANDLER_PROGRESSIVE;
        if ((HTTP_R.url.find("Seg") != std::string::npos) && (HTTP_R.url.find("Frag") != std::string::npos)){handler = HANDLER_FLASH;}
        if (HTTP_R.url.find("f4m") != std::string::npos){handler = HANDLER_FLASH;}
        if (HTTP_R.url == "/crossdomain.xml"){
          handler = HANDLER_NONE;
          HTTP_S.Clean();
          HTTP_S.SetHeader("Content-Type", "text/xml");
          HTTP_S.SetBody("<?xml version=\"1.0\"?><!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" /><site-control permitted-cross-domain-policies=\"all\"/></cross-domain-policy>");
          HTTP_S.SendResponse(CONN_fd, "200", "OK");//geen SetBody = unknown length! Dat willen we hier.
          #if DEBUG >= 3
          printf("Sending crossdomain.xml file\n");
          #endif
        }
        if(handler == HANDLER_FLASH){
          if (HTTP_R.url.find("f4m") == std::string::npos){
            Movie = HTTP_R.url.substr(1);
            Movie = Movie.substr(0,Movie.find("/"));
            Quality = HTTP_R.url.substr( HTTP_R.url.find("/",1)+1 );
            Quality = Quality.substr(0, Quality.find("Seg"));
            temp = HTTP_R.url.find("Seg") + 3;
            Segment = atoi( HTTP_R.url.substr(temp,HTTP_R.url.find("-",temp)-temp).c_str());
            temp = HTTP_R.url.find("Frag") + 4;
            ReqFragment = atoi( HTTP_R.url.substr(temp).c_str() );
            #if DEBUG >= 4
            printf( "URL: %s\n", HTTP_R.url.c_str());
            printf( "Movie Identifier: %s\n", Movie.c_str() );
            printf( "Quality Modifier: %s\n", Quality.c_str() );
            printf( "Segment: %d\n", Segment );
            printf( "Fragment: %d\n", ReqFragment );
            #endif
            HTTP_S.Clean();
            HTTP_S.SetHeader("Content-Type","video/mp4");
            HTTP_S.SetBody(Interface::mdatFold(FlashBuf));
            FlashBuf = "";
            HTTP_S.SendResponse(CONN_fd, "200", "OK");//schrijf de HTTP response header
          }else{
            Movie = HTTP_R.url.substr(1);
            Movie = Movie.substr(0,Movie.find("/"));
          }
          streamname = "/tmp/shared_socket_";
          for (std::string::iterator i=Movie.end()-1; i>=Movie.begin(); --i){
            if (!isalpha(*i) && !isdigit(*i)){
              Movie.erase(i);
            }else{
              *i=tolower(*i);
            }//strip nonalphanumeric
          }
          streamname += Movie;
          ready4data = true;
        }//FLASH handler
        if (handler == HANDLER_PROGRESSIVE){
          //in het geval progressive nemen we aan dat de URL de streamname is, met .flv erachter
          streamname = HTTP_R.url.substr(0, HTTP_R.url.size()-4);//strip de .flv
          for (std::string::iterator i=streamname.end()-1; i>=streamname.begin(); --i){
            if (!isalpha(*i) && !isdigit(*i)){streamname.erase(i);}else{*i=tolower(*i);}//strip nonalphanumeric
          }
          streamname = "/tmp/shared_socket_" + streamname;//dit is dan onze shared_socket
          //normaal zouden we ook een position uitlezen uit de URL, maar bij LIVE streams is dat zinloos
          printf("Streamname: %s\n", streamname.c_str());
          ready4data = true;
        }//PROGRESSIVE handler
        HTTP_R.Clean(); //maak schoon na verwerken voor eventuele volgende requests...
      }
    }
    if (ready4data){
      if (!inited){
        //we are ready, connect the socket!
        ss = DDV_OpenUnix(streamname);
        if (ss <= 0){
          #if DEBUG >= 1
          fprintf(stderr, "Could not connect to server!\n");
          #endif
          socketError = 1;
          break;
        }
        ev.events = EPOLLIN;
        ev.data.fd = ss;
        epoll_ctl(sspoller, EPOLL_CTL_ADD, ss, &ev);
        #if DEBUG >= 3
        fprintf(stderr, "Everything connected, starting to send video data...\n");
        #endif
        inited = true;
      }
      retval = epoll_wait(sspoller, events, 1, 1);
      switch (DDV_ready(ss)){
        case 0:
          socketError = true;
          #if DEBUG >= 1
          fprintf(stderr, "Source socket is disconnected.\n");
          #endif
          break;
        case -1: break;//not ready yet
        default:
          if (FLV_GetPacket(tag, ss)){//able to read a full packet?
            if (handler == HANDLER_FLASH){
              if(tag->data[0] != 0x12 ) {
                FlashBuf.append(tag->data,tag->len);
              } else {
                FlashMeta = "";
                FlashMeta.append(tag->data+11,tag->len-15);
                if( !Flash_ManifestSent ) {
                  HTTP_S.Clean();
                  HTTP_S.SetHeader("Content-Type","text/xml");
                  HTTP_S.SetHeader("Cache-Control","no-cache");
                  HTTP_S.SetBody(BuildManifest(FlashMeta, Movie, FlvGetTimestamp(tag)));
                  HTTP_S.SendResponse(CONN_fd, "200", "OK");
                }
              }
            }
            if (handler == HANDLER_PROGRESSIVE){
              if (!progressive_has_sent_header){
                HTTP_S.Clean();//troep opruimen die misschien aanwezig is...
                HTTP_S.SetHeader("Content-Type", "video/x-flv");//FLV files hebben altijd dit content-type.
                //HTTP_S.SetHeader("Transfer-Encoding", "chunked");
                HTTP_S.protocol = "HTTP/1.0";
                HTTP_S.SendResponse(CONN_fd, "200", "OK");//geen SetBody = unknown length! Dat willen we hier.
                //HTTP_S.SendBodyPart(CONN_fd, FLVHeader, 13);//schrijf de FLV header
                DDV_write(FLVHeader, 13, CONN_fd);
                progressive_has_sent_header = true;
              }
              //HTTP_S.SendBodyPart(CONN_fd, tag->data, tag->len);//schrijf deze FLV tag onbewerkt weg
              DDV_write(tag->data, tag->len, CONN_fd);
            }//PROGRESSIVE handler
          }
          break;
      }
    }
  }
  close(CONN_fd);
  if (inited) close(ss);
  #if DEBUG >= 1
  if (All_Hell_Broke_Loose){fprintf(stderr, "All Hell Broke Loose\n");}
  fprintf(stderr, "User %i disconnected.\n", CONN_fd);
  if (inited){
    fprintf(stderr, "Status was: inited\n");
  }else{
    if (ready4data){
      fprintf(stderr, "Status was: ready4data\n");
    }else{
      fprintf(stderr, "Status was: connected\n");
    }
  }
  #endif
  return 0;
}

<commit_msg>Bugfix abst<commit_after>//debugging level 0 = nothing
//debugging level 1 = critical errors
//debugging level 2 = errors
//debugging level 3 = status information
//debugging level 4 = extremely verbose status information
#define DEBUG 4

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/epoll.h>
#include <getopt.h>

enum {HANDLER_NONE, HANDLER_PROGRESSIVE, HANDLER_FLASH, HANDLER_APPLE, HANDLER_MICRO};

#define DEFAULT_PORT 8080
#include "../util/server_setup.cpp"
#include "../util/http_parser.cpp"
#include "../util/MP4/interface.cpp"

static const std::string base64_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
std::string base64_encode(std::string const input) {
  std::string ret;
  unsigned int in_len = input.size();
  char quad[4], triple[3];
  unsigned int i, x, n = 3;
  for (x = 0; x < in_len; x = x + 3){
    if ((in_len - x) / 3 == 0){n = (in_len - x) % 3;}
    for (i=0; i < 3; i++){triple[i] = '0';}
    for (i=0; i < n; i++){triple[i] = input[x + i];}
    quad[0] = base64_chars[(triple[0] & 0xFC) >> 2]; // FC = 11111100
    quad[1] = base64_chars[((triple[0] & 0x03) << 4) | ((triple[1] & 0xF0) >> 4)]; // 03 = 11
    quad[2] = base64_chars[((triple[1] & 0x0F) << 2) | ((triple[2] & 0xC0) >> 6)]; // 0F = 1111, C0=11110
    quad[3] = base64_chars[triple[2] & 0x3F]; // 3F = 111111
    if (n < 3){quad[3] = '=';}
    if (n < 2){quad[2] = '=';}
    for(i=0; i < 4; i++){ret += quad[i];}
  }
  return ret;
}//base64_encode

int FlvToFragNum( FLV_Pack * tag ) {
  int Timestamp = (tag->data[7] << 24 ) + (tag->data[4] << 16 ) + (tag->data[5] << 8 ) + (tag->data[6] );
  return (Timestamp / 10000) + 1;
}

int FlvGetTimestamp( FLV_Pack * tag ) {
  return ( (tag->data[7] << 24 ) + (tag->data[4] << 16 ) + (tag->data[5] << 8 ) + (tag->data[6] ) );
}

std::string BuildManifest( std::string MetaData, std::string MovieId, int CurrentMediaTime ) {
  Interface * temp = new Interface;
  std::string Result="<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns=\"http://ns.adobe.com/f4m/1.0\">\n";
  Result += "<id>";
  Result += MovieId;
  Result += "</id>\n<mimeType>video/mp4</mimeType>\n";
  Result += "<streamType>live</streamType>\n";
  Result += "<deliveryType>streaming</deliveryType>\n";
  Result += "<bootstrapInfo profile=\"named\" id=\"bootstrap1\">";
  Result += base64_encode(temp->GenerateLiveBootstrap(CurrentMediaTime));
  Result += "</bootstrapInfo>\n";
  Result += "<media streamId=\"1\" bootstrapInfoId=\"bootstrap1\" url=\"";
  Result += MovieId;
  Result += "/\">\n";
  Result += "<metadata>";
  Result += base64_encode(MetaData);
  Result += "</metadata>\n";
  Result += "</media>\n";
  Result += "</manifest>\n";
  delete temp;
  return Result;
}

int mainHandler(int CONN_fd){
  int handler = HANDLER_PROGRESSIVE;
  bool ready4data = false;//set to true when streaming starts
  bool inited = false;
  bool progressive_has_sent_header = false;
  int ss;
  std::string streamname;
  std::string FlashBuf;
  std::string FlashMeta;
  bool Flash_ManifestSent = false;
  FLV_Pack * tag = 0;
  HTTPReader HTTP_R, HTTP_S;//HTTP Receiver en HTTP Sender.

  int retval;
  int poller = epoll_create(1);
  int sspoller = epoll_create(1);
  struct epoll_event ev;
  ev.events = EPOLLIN;
  ev.data.fd = CONN_fd;
  epoll_ctl(poller, EPOLL_CTL_ADD, CONN_fd, &ev);
  struct epoll_event events[1];

  std::string Movie = "";
  std::string Quality = "";
  int Segment = -1;
  int ReqFragment = -1;
  int temp;
  //int CurrentFragment = -1; later herbruiken?

  while (!socketError && !All_Hell_Broke_Loose){
    //only parse input if available or not yet init'ed
    retval = epoll_wait(poller, events, 1, 1);
    if ((retval > 0) || !ready4data){
      if (HTTP_R.ReadSocket(CONN_fd)){
        handler = HANDLER_PROGRESSIVE;
        if ((HTTP_R.url.find("Seg") != std::string::npos) && (HTTP_R.url.find("Frag") != std::string::npos)){handler = HANDLER_FLASH;}
        if (HTTP_R.url.find("f4m") != std::string::npos){handler = HANDLER_FLASH;}
        if (HTTP_R.url == "/crossdomain.xml"){
          handler = HANDLER_NONE;
          HTTP_S.Clean();
          HTTP_S.SetHeader("Content-Type", "text/xml");
          HTTP_S.SetBody("<?xml version=\"1.0\"?><!DOCTYPE cross-domain-policy SYSTEM \"http://www.adobe.com/xml/dtds/cross-domain-policy.dtd\"><cross-domain-policy><allow-access-from domain=\"*\" /><site-control permitted-cross-domain-policies=\"all\"/></cross-domain-policy>");
          HTTP_S.SendResponse(CONN_fd, "200", "OK");//geen SetBody = unknown length! Dat willen we hier.
          #if DEBUG >= 3
          printf("Sending crossdomain.xml file\n");
          #endif
        }
        if(handler == HANDLER_FLASH){
          if (HTTP_R.url.find("f4m") == std::string::npos){
            Movie = HTTP_R.url.substr(1);
            Movie = Movie.substr(0,Movie.find("/"));
            Quality = HTTP_R.url.substr( HTTP_R.url.find("/",1)+1 );
            Quality = Quality.substr(0, Quality.find("Seg"));
            temp = HTTP_R.url.find("Seg") + 3;
            Segment = atoi( HTTP_R.url.substr(temp,HTTP_R.url.find("-",temp)-temp).c_str());
            temp = HTTP_R.url.find("Frag") + 4;
            ReqFragment = atoi( HTTP_R.url.substr(temp).c_str() );
            #if DEBUG >= 4
            printf( "URL: %s\n", HTTP_R.url.c_str());
            printf( "Movie Identifier: %s\n", Movie.c_str() );
            printf( "Quality Modifier: %s\n", Quality.c_str() );
            printf( "Segment: %d\n", Segment );
            printf( "Fragment: %d\n", ReqFragment );
            #endif
            HTTP_S.Clean();
            HTTP_S.SetHeader("Content-Type","video/mp4");
            HTTP_S.SetBody(Interface::mdatFold(FlashBuf));
            FlashBuf = "";
            HTTP_S.SendResponse(CONN_fd, "200", "OK");//schrijf de HTTP response header
          }else{
            Movie = HTTP_R.url.substr(1);
            Movie = Movie.substr(0,Movie.find("/"));
          }
          streamname = "/tmp/shared_socket_";
          for (std::string::iterator i=Movie.end()-1; i>=Movie.begin(); --i){
            if (!isalpha(*i) && !isdigit(*i)){
              Movie.erase(i);
            }else{
              *i=tolower(*i);
            }//strip nonalphanumeric
          }
          streamname += Movie;
          ready4data = true;
        }//FLASH handler
        if (handler == HANDLER_PROGRESSIVE){
          //in het geval progressive nemen we aan dat de URL de streamname is, met .flv erachter
          streamname = HTTP_R.url.substr(0, HTTP_R.url.size()-4);//strip de .flv
          for (std::string::iterator i=streamname.end()-1; i>=streamname.begin(); --i){
            if (!isalpha(*i) && !isdigit(*i)){streamname.erase(i);}else{*i=tolower(*i);}//strip nonalphanumeric
          }
          streamname = "/tmp/shared_socket_" + streamname;//dit is dan onze shared_socket
          //normaal zouden we ook een position uitlezen uit de URL, maar bij LIVE streams is dat zinloos
          printf("Streamname: %s\n", streamname.c_str());
          ready4data = true;
        }//PROGRESSIVE handler
        HTTP_R.Clean(); //maak schoon na verwerken voor eventuele volgende requests...
      }
    }
    if (ready4data){
      if (!inited){
        //we are ready, connect the socket!
        ss = DDV_OpenUnix(streamname);
        if (ss <= 0){
          #if DEBUG >= 1
          fprintf(stderr, "Could not connect to server!\n");
          #endif
          socketError = 1;
          break;
        }
        ev.events = EPOLLIN;
        ev.data.fd = ss;
        epoll_ctl(sspoller, EPOLL_CTL_ADD, ss, &ev);
        #if DEBUG >= 3
        fprintf(stderr, "Everything connected, starting to send video data...\n");
        #endif
        inited = true;
      }
      retval = epoll_wait(sspoller, events, 1, 1);
      switch (DDV_ready(ss)){
        case 0:
          socketError = true;
          #if DEBUG >= 1
          fprintf(stderr, "Source socket is disconnected.\n");
          #endif
          break;
        case -1: break;//not ready yet
        default:
          if (FLV_GetPacket(tag, ss)){//able to read a full packet?
            if (handler == HANDLER_FLASH){
              if(tag->data[0] != 0x12 ) {
                FlashBuf.append(tag->data,tag->len);
              } else {
                FlashMeta = "";
                FlashMeta.append(tag->data+11,tag->len-15);
                if( !Flash_ManifestSent ) {
                  HTTP_S.Clean();
                  HTTP_S.SetHeader("Content-Type","text/xml");
                  HTTP_S.SetHeader("Cache-Control","no-cache");
                  HTTP_S.SetBody(BuildManifest(FlashMeta, Movie, FlvGetTimestamp(tag)));
                  HTTP_S.SendResponse(CONN_fd, "200", "OK");
                }
              }
            }
            if (handler == HANDLER_PROGRESSIVE){
              if (!progressive_has_sent_header){
                HTTP_S.Clean();//troep opruimen die misschien aanwezig is...
                HTTP_S.SetHeader("Content-Type", "video/x-flv");//FLV files hebben altijd dit content-type.
                //HTTP_S.SetHeader("Transfer-Encoding", "chunked");
                HTTP_S.protocol = "HTTP/1.0";
                HTTP_S.SendResponse(CONN_fd, "200", "OK");//geen SetBody = unknown length! Dat willen we hier.
                //HTTP_S.SendBodyPart(CONN_fd, FLVHeader, 13);//schrijf de FLV header
                DDV_write(FLVHeader, 13, CONN_fd);
                progressive_has_sent_header = true;
              }
              //HTTP_S.SendBodyPart(CONN_fd, tag->data, tag->len);//schrijf deze FLV tag onbewerkt weg
              DDV_write(tag->data, tag->len, CONN_fd);
            }//PROGRESSIVE handler
          }
          break;
      }
    }
  }
  close(CONN_fd);
  if (inited) close(ss);
  #if DEBUG >= 1
  if (All_Hell_Broke_Loose){fprintf(stderr, "All Hell Broke Loose\n");}
  fprintf(stderr, "User %i disconnected.\n", CONN_fd);
  if (inited){
    fprintf(stderr, "Status was: inited\n");
  }else{
    if (ready4data){
      fprintf(stderr, "Status was: ready4data\n");
    }else{
      fprintf(stderr, "Status was: connected\n");
    }
  }
  #endif
  return 0;
}

<|endoftext|>


<commit_before>/**
 * @file
 *  Zenderer/Objects/Entity.hpp - A generic entity class wrapping drawable
 *  primitives, materials, and easy sprite-like functionality together.
 *
 * @author      George Kudrayvtsev (halcyon)
 * @version     2.0
 * @copyright   Apache License v2.0
 *  Licensed under the Apache License, Version 2.0 (the "License").         \n
 *  You may not use this file except in compliance with the License.        \n
 *  You may obtain a copy of the License at:
 *  http://www.apache.org/licenses/LICENSE-2.0                              \n
 *  Unless required by applicable law or agreed to in writing, software     \n
 *  distributed under the License is distributed on an "AS IS" BASIS,       \n
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n
 *  See the License for the specific language governing permissions and     \n
 *  limitations under the License.
 *
 * @addtogroup Objects
 *  A group containing renderable objects with a variety of controllable
 *  options and features like animation and collision detection.
 *  These classes are a step above the simple primitive rendering scheme
 *  set up by the architecture in zen::gfxcore::CDrawable, and are the most
 *  likely to face direct user interaction through the application.
 *
 * @{
 **/

#ifndef ZENDERER__OBJECTS__ENTITY_HPP
#define ZENDERER__OBJECTS__ENTITY_HPP

#include <regex>

#include "Zenderer/Math/Math.hpp"
#include "Zenderer/CoreGraphics/Drawable.hpp"
#include "Zenderer/Graphics/Material.hpp"
#include "Zenderer/Graphics/Quad.hpp"
#include "Zenderer/Utilities/INIParser.hpp"

namespace zen
{
namespace gfx { class ZEN_API CScene; }
namespace gui { class ZEN_API CFont;  }

/// A group of sprite-like objects that operate at a high level of abstraction.
namespace obj
{
    /// A base class for all "in-game" objects.
    class ZEN_API CEntity
    {
    protected:
        // Internal error types.
        enum class ZEN_API ErrorType : uint16_t
        {
            BAD_PAIR,
            BAD_POSITION,
            BAD_MATERIAL,
            NO_TEXTURE
        };

    public:
        explicit CEntity(asset::CAssetManager& Assets);
        virtual ~CEntity();

        /**
         * Creates an entity mesh from a file.
         *  There is a detailed specification for well-formed loading of
         *  single and multi-primitive entity loading with unique material
         *  attachments for each. This will implicitly call `Optimize()`
         *  when loading is complete.
         *
         * @param   filename    The path to the entity file.
         *
         * @return  `true`  if loaded successfully, and
         *          `false` otherwise. There is no retrievable error, but
         *                  something appropriate will be logged.
         *
         * @see     The entity file specification page [here](index.html)
         **/
        bool LoadFromFile(const string_t& filename);

        /**
         * Creates an entity from a texture file.
         *  This will simply make a quad entity the exact width and height
         *  as the provided texture returns.
         *
         * @param   filename    Path to texture
         *
         * @return  `true`  if the image and entity loaded successfully,
         *          `false` otherwise. There is no retrievable error, but
         *                  something appropriate will be logged.
         **/
        bool LoadFromTexture(const string_t& filename);

        /**
         * Creates an entity from an existing primitive, or adds it.
         *  This will store a copy of the primitive locally, to prevent bad
         *  references occuring later. Thus it's advisable to `delete` heap
         *  memory when done here, or ensure that the given primitive will go
         *  off the stack soon, to prevent uneccessary memory duplication.
         *
         * @param   Prim    A primitive with a non-default material attached
         *
         * @return  `true`  if the primitive loaded with a valid textre, and
         *          `false` otherwise.
         *
         * @note    Currently, multiple calls to this method will stack
         *          primitive on top of one another, since there is no position
         *          specification on them.
         **/
        bool AddPrimitive(const gfx::CQuad& Prim);

        /**
         * Merges primitive data with shared materials.
         *  If multiple internal quads share the same material data, this will
         *  merge their vertex buffer data together in order to minimize draw
         *  calls and state changes later when rendering.
         *
         * @return  `true`  if any optimization was done, `false` otherwise.
         *
         * @warning Not implemented.
         **/
        bool Optimize();

        /**
         * Draws the entity on-screen.
         *  Since entities are just collections of one or more primitives, this
         *  will simply call `gfx::CQuad::Draw` on each individual internal
         *  primitive.
         *
         *  If `is_bound` is `true`, the draw call will only do drawing (go
         *  figure). Otherwise, it will create an internal vertex array (on
         *  first draw), bind its local material, set up the model-view matrix,
         *  etc, and then do drawing. This allows for various scenarios and
         *  prevents the user from having to set up this data on their own if
         *  they just want to get something on-screen.
         *
         * @param   is_bound    Is there already buffer / material data bound?
         *
         *
         **/
        bool Draw(bool is_bound = false);

        /**
         * Moves the entity to the specified position.
         *  In future revisions, this will adjust all internal primitives
         *  accordingly, once the default primitive stacking behavior is
         *  removed.
         *
         * @param   Pos     The coordinate to place the entity at
         *
         * @todo    Support a variety of primitive depths.
         **/
        void Move(const math::vector_t& Pos);

        /// @overload
        void Move(const real_t x, const real_t y, const real_t z = 1.0);

        /// Transforms the entity with a shear.
        inline void Shear(const math::vector_t& Angles) { m_MV.Shear(Angles); }

        /// Transforms the entity with scaling factors.
        inline void Scale(const math::vector_t& Factors){ m_MV.Scale(Factors);}

        /// Rotate the entity in 2-dimensions (on the Z-axis).
        inline void Rotate(const real_t degrees) { m_MV.RotationZ(degrees); }

        /**
         * Inverts the vertex and texture coordinates of internal primitives.
         *  This will do nothing for existing primitives and data, and only
         *  applies to things that will be loaded after this call.
         *
         * @pre     Nothing has been loaded into the entity.
         *
         * @see     zen::gfx::CQuad::SetInverted()
         **/
        inline void Invert() { m_inv = true; }

        /**
         * Offloads the internal primitives to the given GPU buffer.
         *  If `keep` is specified (the default), the primitives will maintain
         *  their data and just offload a copy of it. Otherwise, local data
         *  will be permanently deleted until more data is added.
         *
         * @param   VAO     The vertex array to offload data to
         * @param   keep    Keep the vertex data locally? (optional=`true`)
         *
         * @note    When permanently offloaded with `keep=false`, later adding
         *          more primitives or reloading more data is untested and
         *          may cause problems.
         *
         * @warning The data will stay on the GPU, occupying precious video
         *          memory, until the `gfxcore::CVertexArray` is cleared.
         *
         * @see     zen::gfxcore::CVertexArray::Clear()
         **/
        void Offload(gfxcore::CVertexArray& VAO, const bool keep = true);

        /// Checks if the entity has offloaded any vertex data to a GPU buffer.
        bool Offloaded() const;

        /// Sets the depth of the entity, for shadows or masking later on.
        void SetDepth(uint16_t depth);

        /// Retrieves an immutable reference to the transformation matrix.
        const math::matrix4x4_t& GetTransformation() const;
        const math::aabb_t& GetBox() const;
        math::vector_t GetPosition() const;

        uint32_t GetSortFlag() const;

        /// Returns an iterator to the start of the internal primitive list.
        std::vector<gfx::CQuad*>::const_iterator cbegin() const;

        /// Returns an iterator to the end of the internal primitive list.
        std::vector<gfx::CQuad*>::const_iterator cend() const;

        inline void Enable()  { m_enabled = true; }
        inline void Disable() { m_enabled = false; }

        friend class ZEN_API gui::CFont;
        friend class ZEN_API gfx::CScene;

    protected:
        void Destroy();
        bool FileError(const string_t& filename,
                       const string_t& line, const uint32_t line_no,
                       const ErrorType& Err = ErrorType::BAD_PAIR);

        asset::CAssetManager&       m_Assets;
        util::CLog&                 m_Log;

        math::matrix4x4_t           m_MV;
        math::aabb_t                m_Box;
        std::vector<gfx::CQuad*>    mp_allPrims;
        string_t                    m_filename;
        uint16_t                    m_depth;
        uint32_t                    m_sort;
        bool                        m_inv, m_enabled;
    };
}   // namespace gfxcore
}   // namespace zen

#endif // ZENDERER__OBJECTS__ENTITY_HPP

/**
 * @class zen::obj::CEntity
 * @details
 *  These differ from generic primitives in the sense that they have a lot more
 *  functionality abstracted away, as well as additional functions like
 *  animation and physics reactions (in inheriting classes). They do use the
 *  zen::gfx::CQuad class at their core, but function at a much higher level.
 *
 *  They can also be loaded from files (see the spec) and can
 *  contain multiple primitive instances.
 *
 *  When creating an entity from multiple primitives, a copy of the primitive
 *  data will be stored internally in order to prevent a bad reference later. Thus
 *  it's recommended that if you will be creating via `AddPrimitive()` that you
 *  either dynamically allocate the primitives and then `delete` later, or you
 *  ensure that they go out of scope soon to prevent useless data duplication.
 *
 *  The call to `Optimize()` is not necessary, but is recommended to merge
 *  identical primitives together if they use the same material, especially
 *  if you've got some CPU cycles to spare, because it will save render state
 *  switches down the road.
 *
 * @see specs.html
 *
 * @todo    Allow for additional primitives not to stack up.
 **/

/** @} **/
<commit_msg>Cleaned up code documentation.<commit_after>/**
 * @file
 *  Zenderer/Objects/Entity.hpp - A generic entity class wrapping drawable
 *  primitives, materials, and easy sprite-like functionality together.
 *
 * @author      George Kudrayvtsev (halcyon)
 * @version     2.0
 * @copyright   Apache License v2.0
 *  Licensed under the Apache License, Version 2.0 (the "License").         \n
 *  You may not use this file except in compliance with the License.        \n
 *  You may obtain a copy of the License at:
 *  http://www.apache.org/licenses/LICENSE-2.0                              \n
 *  Unless required by applicable law or agreed to in writing, software     \n
 *  distributed under the License is distributed on an "AS IS" BASIS,       \n
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n
 *  See the License for the specific language governing permissions and     \n
 *  limitations under the License.
 *
 * @addtogroup Objects
 *  A group containing renderable objects with a variety of controllable
 *  options and features like animation and collision detection.
 *  These classes are a step above the simple primitive rendering scheme
 *  set up by the architecture in zen::gfxcore::CDrawable, and are the most
 *  likely to face direct user interaction through the application.
 *
 * @{
 **/

#ifndef ZENDERER__OBJECTS__ENTITY_HPP
#define ZENDERER__OBJECTS__ENTITY_HPP

#include <regex>

#include "Zenderer/Math/Math.hpp"
#include "Zenderer/CoreGraphics/Drawable.hpp"
#include "Zenderer/Graphics/Material.hpp"
#include "Zenderer/Graphics/Quad.hpp"
#include "Zenderer/Utilities/INIParser.hpp"

namespace zen
{
namespace gfx { class ZEN_API CScene; }
namespace gui { class ZEN_API CFont;  }

/// A group of sprite-like objects that operate at a high level of abstraction.
namespace obj
{
    /// A base class for all "in-game" objects.
    class ZEN_API CEntity
    {
    protected:
        // Internal error types.
        enum class ZEN_API ErrorType : uint16_t
        {
            BAD_PAIR,
            BAD_POSITION,
            BAD_MATERIAL,
            NO_TEXTURE
        };

    public:
        explicit CEntity(asset::CAssetManager& Assets);
        virtual ~CEntity();

        /**
         * Creates an entity mesh from a file.
         *  There is a detailed specification for well-formed loading of
         *  single and multi-primitive entity loading with unique material
         *  attachments for each. This will implicitly call Optimize()
         *  when loading is complete.
         *
         * @param   filename    The path to the entity file.
         *
         * @return  `true`  if loaded successfully, and
         *          `false` otherwise. There is no retrievable error, but
         *                  something appropriate will be logged.
         *
         * @see     The entity file specification page [here](index.html)
         **/
        bool LoadFromFile(const string_t& filename);

        /**
         * Creates an entity from a texture file.
         *  This will simply make a quad entity the exact width and height
         *  as the provided texture returns.
         *
         * @param   filename    Path to texture
         *
         * @return  `true`  if the image and entity loaded successfully,
         *          `false` otherwise. There is no retrievable error, but
         *                  something appropriate will be logged.
         **/
        bool LoadFromTexture(const string_t& filename);

        /**
         * Creates an entity from an existing primitive, or adds it.
         *  This will store a copy of the primitive locally, to prevent bad
         *  references occuring later. Thus it's advisable to `delete` heap
         *  memory when done here, or ensure that the given primitive will go
         *  off the stack soon, to prevent uneccessary memory duplication.
         *
         * @param   Prim    A primitive with a non-default material attached
         *
         * @return  `true`  if the primitive loaded with a valid textre, and
         *          `false` otherwise.
         *
         * @note    Currently, multiple calls to this method will stack
         *          primitive on top of one another, since there is no position
         *          specification on them.
         **/
        bool AddPrimitive(const gfx::CQuad& Prim);

        /**
         * Merges primitive data with shared materials.
         *  If multiple internal quads share the same material data, this will
         *  merge their vertex buffer data together in order to minimize draw
         *  calls and state changes later when rendering.
         *
         * @return  `true`  if any optimization was done, `false` otherwise.
         *
         * @warning Not implemented.
         **/
        bool Optimize();

        /**
         * Draws the entity on-screen.
         *  Since entities are just collections of one or more primitives, this
         *  will simply call gfx::CQuad::Draw on each individual internal
         *  primitive.
         *
         *  If `is_bound` is `true`, the draw call will only do drawing (go
         *  figure). Otherwise, it will create an internal vertex array (on
         *  first draw), bind its local material, set up the model-view matrix,
         *  etc, and then do drawing. This allows for various scenarios and
         *  prevents the user from having to set up this data on their own if
         *  they just want to get something on-screen.
         *
         * @param   is_bound    Is there already buffer / material data bound?
         *
         *
         **/
        bool Draw(bool is_bound = false);

        /**
         * Moves the entity to the specified position.
         *  In future revisions, this will adjust all internal primitives
         *  accordingly, once the default primitive stacking behavior is
         *  removed.
         *
         * @param   Pos     The coordinate to place the entity at
         *
         * @todo    Support a variety of primitive depths.
         **/
        void Move(const math::vector_t& Pos);

        /// @overload
        void Move(const real_t x, const real_t y, const real_t z = 1.0);

        /// Transforms the entity with a shear.
        inline void Shear(const math::vector_t& Angles) { m_MV.Shear(Angles); }

        /// Transforms the entity with scaling factors.
        inline void Scale(const math::vector_t& Factors){ m_MV.Scale(Factors);}

        /// Rotate the entity in 2-dimensions (on the Z-axis).
        inline void Rotate(const real_t degrees) { m_MV.RotationZ(degrees); }

        /**
         * Inverts the vertex and texture coordinates of internal primitives.
         *  This will do nothing for existing primitives and data, and only
         *  applies to things that will be loaded after this call.
         *
         * @pre     Nothing has been loaded into the entity.
         *
         * @see     zen::gfx::CQuad::SetInverted()
         **/
        inline void Invert() { m_inv = true; }

        /**
         * Offloads the internal primitives to the given GPU buffer.
         *  If `keep` is specified (the default), the primitives will maintain
         *  their data and just offload a copy of it. Otherwise, local data
         *  will be permanently deleted until more data is added.
         *
         * @param   VAO     The vertex array to offload data to
         * @param   keep    Keep the vertex data locally? (optional=`true`)
         *
         * @note    When permanently offloaded with `keep=false`, later adding
         *          more primitives or reloading more data is untested and
         *          may cause problems.
         *
         * @warning The data will stay on the GPU, occupying precious video
         *          memory, until the gfxcore::CVertexArray is cleared.
         *
         * @see     zen::gfxcore::CVertexArray::Clear()
         **/
        void Offload(gfxcore::CVertexArray& VAO, const bool keep = true);

        /// Checks if the entity has offloaded any vertex data to a GPU buffer.
        bool Offloaded() const;

        /// Sets the depth of the entity, for shadows or masking later on.
        void SetDepth(uint16_t depth);

        /// Retrieves an immutable reference to the transformation matrix.
        const math::matrix4x4_t& GetTransformation() const;
        const math::aabb_t& GetBox() const;
        math::vector_t GetPosition() const;

        uint32_t GetSortFlag() const;

        /// Returns an iterator to the start of the internal primitive list.
        std::vector<gfx::CQuad*>::const_iterator cbegin() const;

        /// Returns an iterator to the end of the internal primitive list.
        std::vector<gfx::CQuad*>::const_iterator cend() const;

        inline void Enable()  { m_enabled = true; }
        inline void Disable() { m_enabled = false; }

        friend class ZEN_API gui::CFont;
        friend class ZEN_API gfx::CScene;

    protected:
        void Destroy();
        bool FileError(const string_t& filename,
                       const string_t& line, const uint32_t line_no,
                       const ErrorType& Err = ErrorType::BAD_PAIR);

        asset::CAssetManager&       m_Assets;
        util::CLog&                 m_Log;

        math::matrix4x4_t           m_MV;
        math::aabb_t                m_Box;
        std::vector<gfx::CQuad*>    mp_allPrims;
        string_t                    m_filename;
        uint16_t                    m_depth;
        uint32_t                    m_sort;
        bool                        m_inv, m_enabled;
    };
}   // namespace gfxcore
}   // namespace zen

#endif // ZENDERER__OBJECTS__ENTITY_HPP

/**
 * @class zen::obj::CEntity
 * @details
 *  These differ from generic primitives in the sense that they have a lot more
 *  functionality abstracted away, as well as additional functions like
 *  animation and physics reactions (in inheriting classes). They do use the
 *  zen::gfx::CQuad class at their core, but function at a much higher level.
 *
 *  They can also be loaded from files (see the spec) and can
 *  contain multiple primitive instances.
 *
 *  When creating an entity from multiple primitives, a copy of the primitive
 *  data will be stored internally in order to prevent a bad reference later. Thus
 *  it's recommended that if you will be creating via AddPrimitive() that you
 *  either dynamically allocate the primitives and then `delete` later, or you
 *  ensure that they go out of scope soon to prevent useless data duplication.
 *
 *  The call to Optimize() is not necessary, but is recommended to merge
 *  identical primitives together if they use the same material, especially
 *  if you've got some CPU cycles to spare, because it will save render state
 *  switches down the road.
 *
 * @see     <a href="specs.html#ZEnt">Entity Specification</a>
 *
 * @todo    Allow for additional primitives not to stack up.
 **/

/** @} **/
<|endoftext|>


<commit_before>#define DEBUG
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/epoll.h>

//for connection to server
#include "../sockets/SocketW.h"
bool ready4data = false;//set to true when streaming starts
bool inited = false;
bool stopparsing = false;
timeval lastrec;

int CONN_fd = 0;
FILE * CONN = 0;
#include "parsechunks.cpp" //chunkstream parsing
#include "handshake.cpp" //handshaking
#include "../util/flv_sock.cpp" //FLV parsing with SocketW
#include "../util/ddv_socket.cpp" //DDVTech Socket wrapper

int main(){

  int server_socket = DDV_Listen(1935);
  int status;
  while (server_socket > 0){
    waitpid((pid_t)-1, &status, WNOHANG);
    CONN_fd = DDV_Accept(server_socket);
    pid_t myid = fork();
    if (myid == 0){
      break;
    }else{
      printf("Spawned new process %i for incoming client\n", (int)myid);
    }
  }
  if (server_socket <= 0){
    return 0;
  }

  CONN = fdopen(CONN_fd, "r+");

  unsigned int ts;
  unsigned int fts = 0;
  unsigned int ftst;
  SWUnixSocket ss;

  //first timestamp set
  firsttime = getNowMS();

  #ifdef DEBUG
  fprintf(stderr, "Doing handshake...\n");
  #endif
  if (doHandshake()){
    #ifdef DEBUG
    fprintf(stderr, "Handshake succcess!\n");
    #endif
  }else{
    #ifdef DEBUG
    fprintf(stderr, "Handshake fail!\n");
    #endif
    return 0;
  }
  #ifdef DEBUG
  fprintf(stderr, "Starting processing...\n");
  #endif

  int retval;
  int poller = epoll_create(1);
  struct epoll_event ev;
  ev.events = EPOLLIN;
  ev.data.fd = CONN_fd;
  epoll_ctl(poller, EPOLL_CTL_ADD, CONN_fd, &ev);
  struct epoll_event events[1];

  while (!ferror(CONN) && !feof(CONN)){
    //only parse input if available or not yet init'ed
    //rightnow = getNowMS();
    retval = epoll_wait(poller, events, 1, 0);
    if ((retval > 0) || (!ready4data || (snd_cnt - snd_window_at >= snd_window_size))){
      parseChunk();
    }
    if (ready4data){
      if (!inited){
        //we are ready, connect the socket!
        if (!ss.connect(streamname.c_str())){
          #ifdef DEBUG
          fprintf(stderr, "Could not connect to server!\n");
          #endif
          return 0;
        }
        FLV_Readheader(ss);//read the header, we don't want it
        #ifdef DEBUG
        fprintf(stderr, "Header read, starting to send video data...\n");
        #endif
        inited = true;
      }
      //only send data if previous data has been ACK'ed...
      if (snd_cnt - snd_window_at < snd_window_size){
        if (FLV_GetPacket(ss)){//able to read a full packet?
          ts = FLVbuffer[7] * 256*256*256;
          ts += FLVbuffer[4] * 256*256;
          ts += FLVbuffer[5] * 256;
          ts += FLVbuffer[6];
          if (ts != 0){
            if (fts == 0){fts = ts;ftst = getNowMS();}
            ts -= fts;
            FLVbuffer[7] = ts / (256*256*256);
            FLVbuffer[4] = ts / (256*256);
            FLVbuffer[5] = ts / 256;
            FLVbuffer[6] = ts % 256;
            ts += ftst;
          }else{
            ftst = getNowMS();
            FLVbuffer[7] = ftst / (256*256*256);
            FLVbuffer[4] = ftst / (256*256);
            FLVbuffer[5] = ftst / 256;
            FLVbuffer[6] = ftst % 256;
          }
          SendMedia((unsigned char)FLVbuffer[0], (unsigned char *)FLVbuffer+11, FLV_len-15, ts);
          #ifdef DEBUG
          fprintf(stderr, "Sent a tag.\n");
          #endif
          FLV_Dump();//dump packet and get ready for next
        }
        if ((SWBerr != SWBaseSocket::ok) && (SWBerr != SWBaseSocket::notReady)){
          #ifdef DEBUG
          fprintf(stderr, "No more data! :-(  (%s)\n", SWBerr.get_error().c_str());
          #endif
          return 0;//no more input possible! Fail immediately.
        }
      }
    }
    //send ACK if we received a whole window
    if (rec_cnt - rec_window_at > rec_window_size){
      rec_window_at = rec_cnt;
      SendCTL(3, rec_cnt);//send ack (msg 3)
    }
  }
  #ifdef DEBUG
  fprintf(stderr, "User disconnected.\n");
  #endif
  return 0;
}//main
<commit_msg>Nog een poging...<commit_after>#define DEBUG
#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/epoll.h>

//for connection to server
#include "../sockets/SocketW.h"
bool ready4data = false;//set to true when streaming starts
bool inited = false;
bool stopparsing = false;
timeval lastrec;

int CONN_fd = 0;
FILE * CONN = 0;
#include "parsechunks.cpp" //chunkstream parsing
#include "handshake.cpp" //handshaking
#include "../util/flv_sock.cpp" //FLV parsing with SocketW
#include "../util/ddv_socket.cpp" //DDVTech Socket wrapper

int main(){

  int server_socket = DDV_Listen(1935);
  int status;
  while (server_socket > 0){
    waitpid((pid_t)-1, &status, WNOHANG);
    CONN_fd = DDV_Accept(server_socket);
    pid_t myid = fork();
    if (myid == 0){
      break;
    }else{
      printf("Spawned new process %i for handling socket %i\n", (int)myid, CONN_fd);
    }
  }
  if (server_socket <= 0){
    return 0;
  }

  CONN = fdopen(CONN_fd, "r+");

  unsigned int ts;
  unsigned int fts = 0;
  unsigned int ftst;
  SWUnixSocket ss;

  //first timestamp set
  firsttime = getNowMS();

  #ifdef DEBUG
  fprintf(stderr, "Doing handshake...\n");
  #endif
  if (doHandshake()){
    #ifdef DEBUG
    fprintf(stderr, "Handshake succcess!\n");
    #endif
  }else{
    #ifdef DEBUG
    fprintf(stderr, "Handshake fail!\n");
    #endif
    return 0;
  }
  #ifdef DEBUG
  fprintf(stderr, "Starting processing...\n");
  #endif

  int retval;
  int poller = epoll_create(1);
  struct epoll_event ev;
  ev.events = EPOLLIN;
  ev.data.fd = CONN_fd;
  epoll_ctl(poller, EPOLL_CTL_ADD, CONN_fd, &ev);
  struct epoll_event events[1];

  while (!ferror(CONN) && !feof(CONN)){
    //only parse input if available or not yet init'ed
    //rightnow = getNowMS();
    retval = epoll_wait(poller, events, 1, 0);
    if ((retval > 0) || (!ready4data || (snd_cnt - snd_window_at >= snd_window_size))){
      parseChunk();
    }
    if (ready4data){
      if (!inited){
        //we are ready, connect the socket!
        if (!ss.connect(streamname.c_str())){
          #ifdef DEBUG
          fprintf(stderr, "Could not connect to server!\n");
          #endif
          return 0;
        }
        FLV_Readheader(ss);//read the header, we don't want it
        #ifdef DEBUG
        fprintf(stderr, "Header read, starting to send video data...\n");
        #endif
        inited = true;
      }
      //only send data if previous data has been ACK'ed...
      if (snd_cnt - snd_window_at < snd_window_size){
        if (FLV_GetPacket(ss)){//able to read a full packet?
          ts = FLVbuffer[7] * 256*256*256;
          ts += FLVbuffer[4] * 256*256;
          ts += FLVbuffer[5] * 256;
          ts += FLVbuffer[6];
          if (ts != 0){
            if (fts == 0){fts = ts;ftst = getNowMS();}
            ts -= fts;
            FLVbuffer[7] = ts / (256*256*256);
            FLVbuffer[4] = ts / (256*256);
            FLVbuffer[5] = ts / 256;
            FLVbuffer[6] = ts % 256;
            ts += ftst;
          }else{
            ftst = getNowMS();
            FLVbuffer[7] = ftst / (256*256*256);
            FLVbuffer[4] = ftst / (256*256);
            FLVbuffer[5] = ftst / 256;
            FLVbuffer[6] = ftst % 256;
          }
          SendMedia((unsigned char)FLVbuffer[0], (unsigned char *)FLVbuffer+11, FLV_len-15, ts);
          #ifdef DEBUG
          fprintf(stderr, "Sent a tag to %i\n", CONN_fd);
          #endif
          FLV_Dump();//dump packet and get ready for next
        }
        if ((SWBerr != SWBaseSocket::ok) && (SWBerr != SWBaseSocket::notReady)){
          #ifdef DEBUG
          fprintf(stderr, "No more data! :-(  (%s)\n", SWBerr.get_error().c_str());
          #endif
          return 0;//no more input possible! Fail immediately.
        }
      }
    }
    //send ACK if we received a whole window
    if (rec_cnt - rec_window_at > rec_window_size){
      rec_window_at = rec_cnt;
      SendCTL(3, rec_cnt);//send ack (msg 3)
    }
  }
  #ifdef DEBUG
  fprintf(stderr, "User disconnected.\n");
  #endif
  return 0;
}//main
<|endoftext|>