Logo Search packages:      
Sourcecode: papaya version File versions  Download package

BSX.cpp

#include <gtk/gtk.h>

#include "BSX.h"
#include "BSXSceneGTK.h"

#include "Win32PluginAPI.cpp"

static BSX * bsx = NULL;

#define MAJOR "0"
#define MINOR "1"

extern "C" G_MODULE_EXPORT char * plugin_query_name() {
  return "BSX";
}

extern "C" G_MODULE_EXPORT char * plugin_query_description() {
  return _("Implementation of the BSX protocol.");
}

extern "C" G_MODULE_EXPORT char * plugin_query_major() {
  return "MAJOR";
}

extern "C" G_MODULE_EXPORT char * plugin_query_minor() {
  return "MINOR";
}

extern "C" G_MODULE_EXPORT void plugin_init(plugin_address_table_t * pat) {
      plugin_address_table_init(pat);

      bsx = new BSX();
}

extern "C" G_MODULE_EXPORT void plugin_cleanup(void) {
  delete bsx;
}

BSX::BSX() {
  register_plugin(this, VERSION);
}

BSX::~BSX() {
  unregister_plugin(this);

}

char * findNextCommand(char * pc) {

  if (!strncmp(pc, "@RFS", 4))
    return pc + 4;

  if (!strncmp(pc, "@RQV", 4))
    return pc + 4;

  if (!strncmp(pc, "@TMS", 4))
    return pc + 4;

  char * end = strchr(pc + 1, '@');
  if (end) {
    return end;
  }
 
  return pc + strlen(pc);
}

void BSX::output(Connection * conn, char * string) {

  char * ptr = string;
  char * pc;

  BSXData * data = find_data(conn);
  if (data) {
    if (data->prev_cmd > 0) {

      char * next = findNextCommand(ptr);

      // Append the stuff from str to next to end of data string.
      strncat(data->incoming, ptr, next - ptr);

      // Is this complete yet?
      if (*next != '\0') {
      
      switch (data->prev_cmd) {
      case 2: // DFS
        parseDFS(conn, data->incoming);
        break;
        
      case 1: // DFO
        parseDFO(conn, data->incoming);
        break;
      }

      data->prev_cmd = 0;
      }

      memcpy(ptr, next, strlen(next) + 1);
    }
  }

  while (true) {
    pc = strchr(ptr, '@');
    if (!pc)
      break;

    char * next = findNextCommand(pc);

    if (!strncmp(pc + 1, "RFS", 3)) {
      parseRFS(conn, pc);
      memcpy(pc, next, strlen(next) + 1);
      ptr = pc;
      continue;
    }

    if (!strncmp(pc + 1, "SCE", 3)) {
      parseSCE(conn, pc);
      memcpy(pc, next, strlen(next) + 1);
      ptr = pc;
      continue;
    }

    if (!strncmp(pc + 1, "VIO", 3)) {
      parseVIO(conn, pc);
      memcpy(pc, next, strlen(next) + 1);
      ptr = pc;
      continue;
    }

    if (!strncmp(pc + 1, "DFS", 3)) {

      // This command might be split over multiple callbacks
      if (*next == '\0') {

      // Stick the data so far received into a storage object.
      BSXData * data = find_data(conn);
      if (!data) {
        memcpy(pc, next, strlen(next) + 1);
        ptr = pc;
        continue;
      }

      sprintf(data->incoming, "%s", pc);
      data->prev_cmd = 2; // DFS
      memcpy(pc, next, strlen(next) + 1);
      ptr = next;
      continue;
      }

      // Completely contained in this callback
      parseDFS(conn, pc);
      memcpy(pc, next, strlen(next) + 1);
      ptr = pc;
      continue;
    }

    if (!strncmp(pc + 1, "DFO", 3)) {

      // This command might be split over multiple callbacks
      if (*next == '\0') {

      // Stick the data so far received into a storage object.
      BSXData * data = find_data(conn);
      if (!data) {
        memcpy(pc, next, strlen(next) + 1);
        ptr = pc;
        continue;
      }

      sprintf(data->incoming, "%s", pc);
      data->prev_cmd = 1; // DFO
      memcpy(pc, next, strlen(next) + 1);
      ptr = next;
      continue;
      }

      // Completely contained in this callback
      parseDFO(conn, pc);
      memcpy(pc, next, strlen(next) + 1);
      ptr = pc;
      continue;
    }

    if (!strncmp(pc + 1, "RMO", 3)) {
      parseRMO(conn, pc);
      memcpy(pc, next, strlen(next) + 1);
      ptr = pc;
      continue;
    }

    if (!strncmp(pc + 1, "TMS", 3)) {
      parseTMS(conn, pc);
      memcpy(pc, next, strlen(next) + 1);
      ptr = pc;
      continue;
    }
     
    if (!strncmp(pc + 1, "RQV", 3)) {
      parseRQV(conn, pc);
      memcpy(pc, next, strlen(next) + 1);
      ptr = pc;
      continue;
    }
    
    // Unrecognised command
    ptr = pc + 1;
    continue;
  }

  return;
}

void BSX::parseRQV(Connection * conn, char * pc) {
  char buf[16384];

  snprintf(buf, 16384, "#VER Papaya %s (BSX Plugin %s.%s)\n", VERSION, MAJOR, MINOR);


  socket_write(connection_get_socket(conn), buf, strlen(buf));


  // Delete any existing entries for this connection.
  BSXData * data = find_data(conn);
  if (data) {
    delete data->scenes;
    delete data->objects;
    delete data->scene;
    remove_data(data);
  }

  // Create a BSXData element and add into the list of connections.
  data = (BSXData *)calloc(1, sizeof(BSXData));
  data->connection = conn;
  add_data(data);

  // Initialise the cache to default sizes.
  data->scenes = new BSXCache(1024000);
  data->objects = new BSXCache(1024000);

  //  data->scene = new BSXScene();
  data->scene = new BSXSceneGTK();
}

void BSX::parseSCE(Connection * conn, char * pc) {

  char * scene = NULL;
  // Locate the next '@' character, or EOS.

  char * end = findNextCommand(pc);

  BSXData * data = find_data(conn);
  if (!data || !data->scenes || !data->scene)
    return;

  char * stop = strchr(pc, '.');
  if (!stop || stop > end) {
    // Malformed SCE command.
    return;
  }

  *stop = '\0';
  scene = pc + 4;

  data->scene->reset();

  BSXCacheEntry * scene_data = data->scenes->retrieve(scene);
  if (!scene_data) {
    char buf[16384];
    snprintf(buf, 16384, "#RQS %s\n", scene);
      socket_write(connection_get_socket(conn), buf, strlen(buf));

    data->scenes->insert(scene, "");
    scene_data = data->scenes->retrieve(scene);
  }

  if (scene_data)
    data->scene->setScene(scene_data);
  
  return;
}

void BSX::parseVIO(Connection * conn, char * pc) {

  char * id = NULL;
  // Locate the next '@' character, or EOS.

  char * end = findNextCommand(pc);

  BSXData * data = find_data(conn);
  if (!data || !data->objects || !data->scene)
    return;

  char * stop = strchr(pc, '.');
  if (!stop || stop > end) {
    return;
  }

  *stop = '\0';
  id = pc + 4;

  // Retrieve the object with this ID.
  BSXCacheEntry * object = data->objects->retrieve(id);
  if (!object) {
    char buf[16384];
    snprintf(buf, 16384, "#RQO %s\n", id);
      socket_write(connection_get_socket(conn), buf, strlen(buf));

    data->objects->insert(id, "");
    object = data->objects->retrieve(id);
  }

  // Add the object to the scene at (stop + 1)
  if (object)
    data->scene->addObject(object, stop + 1);

  return;
}



void BSX::parseRFS(Connection * conn, char * pc) {

  BSXData * data = find_data(conn);
  if (data && data->scene)
    data->scene->redraw();

  return;
}

void BSX::parseDFO(Connection * conn, char * pc) {

  char * id = NULL;
  // Locate the next '@' character, or EOS.

  char * end = findNextCommand(pc);

  BSXData * data = find_data(conn);
  if (!data || !data->objects)
    return;

  char * stop = strchr(pc, '.');
  if (!stop || stop > end) {
    return;
  }

  *stop = '\0';
  id = pc + 4;

  char object_data[16384];

  strncpy(object_data, stop + 1, end - stop + 1);
  object_data[end - stop + 2] = '\0';

  BSXCacheEntry * entry = data->objects->retrieve(id);
  if (entry)
    data->objects->replace(id, object_data);
  else
    data->objects->insert(id, object_data);

  memmove(pc, end, strlen(end) + 1);
  return;
}

void BSX::parseRMO(Connection * conn, char * pc) {
  char * id = NULL;
  // Locate the next '@' character, or EOS.

  char * end = findNextCommand(pc);

  BSXData * data = find_data(conn);
  if (!data || !data->objects || !data->scene)
    return;

  char * stop = strchr(pc, '.');
  if (!stop || stop > end) {
    return;
  }

  *stop = '\0';
  id = pc + 4;

  BSXCacheEntry * entry = data->objects->retrieve(id);
  if (entry) {
    data->scene->removeObject(entry);
    //    data->objects->remove(id);
  }

  return;
}

void BSX::parseDFS(Connection * conn, char * pc) {

  char * id = NULL;
  // Locate the next '@' character, or EOS.

  char * end = findNextCommand(pc);

  BSXData * data = find_data(conn);
  if (!data || !data->scenes)
    return;

  char * stop = strchr(pc, '.');
  if (!stop || stop > end) {
    // Malformed SCE command.
    return;
  }

  *stop = '\0';
  id = pc + 4;

  char object_data[16384];
  strncpy(object_data, stop + 1, end - stop + 1);
  object_data[end - stop + 2] = '\0';

  BSXCacheEntry * entry = data->scenes->retrieve(id);
  if (entry)
    data->scenes->replace(id, object_data);
  else
    data->scenes->insert(id, object_data);

  return;
}

void BSX::parseTMS(Connection * conn, char * pc) {
  // Terminate the session and free any resources related to this session.

  BSXData * data = find_data(conn);
  if (data) {
    delete data->scenes;
    delete data->objects;
    delete data->scene;
    remove_data(data);
  }

  return;
}

static int BSXCmp(BSXData * l1, BSXData *l2) {
  return (l1 < l2);
}

void BSX::remove_data(BSXData * data) {
  BSXDataList::iterator i = std::lower_bound(BSXList.begin(),
                                               BSXList.end(),
                                               data,
                                               BSXCmp);
  if (i == BSXList.end() || (*i) != data)
    return;

  BSXList.erase(i);
}

BSXData * BSX::find_data(Connection * connection) {
  for (BSXDataList::iterator i = BSXList.begin(); i != BSXList.end(); i++
)
    if ((*i)->connection == connection)
      return (*i);

  return NULL;
}

void BSX::add_data(BSXData * data) {
    BSXDataList::iterator i = std::lower_bound(BSXList.begin(),
                                                 BSXList.end(),
                                                 data,
                                                 BSXCmp);
    
    BSXList.insert(i, data);
}

Generated by  Doxygen 1.6.0   Back to index