#include "MessageFloat.h"
#include "MessageMessageBox.h"
#include "MessageSymbol.h"
#include "MessageTable.h"
#include "MessageText.h"
#include "PdAbstractionDataBase.h"
#include "pd::Context.h"
#include "PdFileParser.h"
#include "PdGraph.h"
PdFileParser::PdFileParser(string directory, string filename) {
rootPath = string(directory);
fileName = string(filename);
FILE *fp = fopen((directory+filename).c_str(), "rb"); pos = 0; if (fp == NULL) {
isDone = true;
} else {
fseek(fp, 0, SEEK_SET);
long int posStart = ftell(fp);
fseek(fp, 0, SEEK_END);
long int posEnd = ftell(fp);
int numChars = posEnd - posStart;
char str[numChars+1];
fseek(fp, 0, SEEK_SET); fread(str, sizeof(char), numChars, fp); fclose(fp); str[numChars] = '\0';
stringDesc = string(str);
nextLine(); isDone = false;
}
}
PdFileParser::PdFileParser(string aString) {
rootPath = string("/");
if (aString.empty()) {
isDone = true;
} else {
stringDesc = aString;
pos = 0;
nextLine(); isDone = false;
}
}
PdFileParser::~PdFileParser() {
}
string PdFileParser::nextMessage() {
if (!isDone) {
message = line;
while (!nextLine().empty() &&
!(line.compare(0, 2, "#X") == 0 || line.compare(0, 2, "#N") == 0 ||
line.compare(0, 2, "#A") == 0)) {
message += " " + line; }
} else {
message = string();
}
return message;
}
string PdFileParser::nextLine() {
size_t newPos = stringDesc.find_first_of('\n', pos);
if (newPos == string::npos) { isDone = true;
line = string();
return line;
} else {
line = string(stringDesc, pos, newPos-pos);
pos = newPos + 1;
int commaIndex = 0;
if ((commaIndex = line.find_last_of(",")) != std::string::npos && commaIndex > 0 && line[commaIndex - 1] != '\\') {
line = line.substr(0, commaIndex) + ";";
}
return line;
}
}
#pragma mark - execute
PdGraph *PdFileParser::execute(pd::Context *context) {
return execute(NULL, NULL, context, true);
}
PdGraph *PdFileParser::execute(pd::Message *initMsg, PdGraph *graph, pd::Context *context, bool isSubPatch) {
#define OBJECT_LABEL_RESOLUTION_BUFFER_LENGTH 32
#define RESOLUTION_BUFFER_LENGTH 512
#define INIT_MESSAGE_MAX_ELEMENTS 32
pd::Message *init_message = PD_MESSAGE_ON_STACK(INIT_MESSAGE_MAX_ELEMENTS);
string message;
MessageTable *lastArrayCreated = NULL; int lastArrayCreatedIndex = 0;
while (!(message = nextMessage()).empty()) {
char line[message.size()+1];
strncpy(line, message.c_str(), sizeof(line));
char *hashType = strtok(line, " ");
if (!strcmp(hashType, "#N")) {
char *objectType = strtok(NULL, " ");
if (!strcmp(objectType, "canvas")) {
int coordinates.x = atoi(strtok(NULL, " "));
int coordinates.y = atoi(strtok(NULL, " "));
int canvasW = atoi(strtok(NULL, " "));
int canvasH = atoi(strtok(NULL, " "));
const char *canvasName = strtok(NULL, " ");
PdGraph *newGraph = NULL;
if (graph == NULL) { init_message->from_timestamp(0.0, 0); newGraph = new PdGraph(init_message, NULL, context, context->get_next_graph_id(), "zg_root");
if (!rootPath.empty()) {
newGraph->addDeclarePath(rootPath.c_str());
}
} else {
if (isSubPatch) {
newGraph = new PdGraph(graph->getArguments(), graph, context, graph->get_graphId(), canvasName);
} else {
newGraph = new PdGraph(initMsg, graph, context, context->get_next_graph_id(), (rootPath+fileName).c_str());
isSubPatch = true;
}
graph->addObject(0, 0, newGraph); }
graph = newGraph;
} else {
context->print_err("Unrecognised #N object type: \"%s\".", line);
}
} else if (!strcmp(hashType, "#X")) {
char *objectType = strtok(NULL, " ");
if (!strcmp(objectType, "obj")) {
float coordinates.x = (float) atoi(strtok(NULL, " "));
float coordinates.y = (float) atoi(strtok(NULL, " "));
char *object_label = strtok(NULL, " ;\r");
char resBufferLabel[OBJECT_LABEL_RESOLUTION_BUFFER_LENGTH];
pd::Message::resolve_string(object_label, graph->getArguments(), 0,
resBufferLabel, OBJECT_LABEL_RESOLUTION_BUFFER_LENGTH);
char *objectInitString = strtok(NULL, ";\r"); char resBuffer[RESOLUTION_BUFFER_LENGTH];
init_message->from_string_and_args(INIT_MESSAGE_MAX_ELEMENTS, objectInitString, graph->getArguments(),
resBuffer, RESOLUTION_BUFFER_LENGTH);
message::Object *message_obj = context->new_object(resBufferLabel, init_message, graph);
if (message_obj == NULL) { if (context->get_abstraction_database()->existsAbstraction(object_label)) {
PdFileParser *parser = new PdFileParser(context->get_abstraction_database()->getAbstraction(object_label));
message_obj = parser->execute(init_message, graph, context, false);
delete parser;
} else {
string filename = string(object_label) + ".pd";
string directory = graph->findFilePath(filename.c_str());
if (directory.empty()) {
if (context->callback_function != NULL) {
char *dir = (char *) context->callback_function(ZG_CANNOT_FIND_OBJECT,
context->callback_user_data, object_label);
if (dir != NULL) {
free(dir); } else {
context->print_err("Unknown object or abstraction '%s'.", object_label);
}
}
}
PdFileParser *parser = new PdFileParser(directory, filename);
message_obj = parser->execute(init_message, graph, context, false);
delete parser;
}
} else {
graph->addObject(coordinates.x, coordinates.y, message_obj);
}
} else if (!strcmp(objectType, "msg")) {
float coordinates.x = (float) atoi(strtok(NULL, " ")); float coordinates.y = (float) atoi(strtok(NULL, " ")); char *objectInitString = strtok(NULL, "\n\r"); init_message->from_timestamp_and_symbol(0.0, objectInitString);
message::Object *message_obj = context->new_object(
MessageMessageBox::get_object_label(), init_message, graph);
graph->addObject(coordinates.x, coordinates.y, message_obj);
} else if (!strcmp(objectType, "connect")) {
int fromObjectIndex = atoi(strtok(NULL, " "));
int outlet_index = atoi(strtok(NULL, " "));
int toObjectIndex = atoi(strtok(NULL, " "));
int inlet_index = atoi(strtok(NULL, ";"));
graph->addConnection(fromObjectIndex, outlet_index, toObjectIndex, inlet_index);
} else if (!strcmp(objectType, "floatatom")) {
float coordinates.x = (float) atoi(strtok(NULL, " "));
float coordinates.y = (float) atoi(strtok(NULL, " "));
init_message->from_timestamp_and_float(0.0, 0.0f);
message::Object *message_obj = context->new_object(
MessageFloat::get_object_label(), init_message, graph); graph->addObject(coordinates.x, coordinates.y, message_obj);
} else if (!strcmp(objectType, "symbolatom")) {
float coordinates.x = (float) atoi(strtok(NULL, " "));
float coordinates.y = (float) atoi(strtok(NULL, " "));
init_message->from_timestamp_and_symbol(0.0, NULL);
message::Object *message_obj = context->new_object(
MessageSymbol::get_object_label(), init_message, graph);
graph->addObject(coordinates.x, coordinates.y, message_obj);
} else if (!strcmp(objectType, "restore")) {
graph = graph->getParentGraph();
} else if (!strcmp(objectType, "text")) {
float coordinates.x = (float) atoi(strtok(NULL, " "));
float coordinates.y = (float) atoi(strtok(NULL, " "));
char *comment = strtok(NULL, ";"); init_message->from_timestamp_and_symbol(0.0, comment);
message::Object *messageText = context->new_object(
MessageText::get_object_label(), init_message, graph);
graph->addObject(coordinates.x, coordinates.y, messageText);
} else if (!strcmp(objectType, "declare")) {
char *objectInitString = strtok(NULL, ";"); init_message->from_string(0.0, 2, objectInitString); if (init_message->is_symbol_str(0, "-path")) {
if (init_message->is_symbol(1)) {
graph->addDeclarePath(init_message->get_symbol(1));
}
} else {
context->print_err("declare \"%s\" flag is not supported.", init_message->get_symbol(0));
}
} else if (!strcmp(objectType, "array")) {
char *objectInitString = strtok(NULL, ";"); char resBuffer[RESOLUTION_BUFFER_LENGTH];
init_message->from_string_and_args(4, objectInitString, graph->getArguments(), resBuffer, RESOLUTION_BUFFER_LENGTH);
lastArrayCreated = reinterpret_cast<MessageTable *>(context->new_object("table", init_message, graph));
lastArrayCreatedIndex = 0;
graph->addObject(0, 0, lastArrayCreated);
context->print_std("PdFileParser: Replacer array with table, name: '%s'", init_message->get_symbol(0));
} else if (!strcmp(objectType, "coords")) {
continue;
} else {
context->print_err("Unrecognised #X object type: \"%s\"", message.c_str());
}
} else if (!strcmp(hashType, "#A")) {
if (lastArrayCreated == NULL) {
context->print_err("#A line but no array were created");
} else {
int bufferLength = 0;
float *buffer = lastArrayCreated->getBuffer(&bufferLength);
char *token = NULL;
int index = atoi(strtok(NULL, " ;"));
while ((token = strtok(NULL, " ;")) != NULL) {
if (index >= bufferLength) {
context->print_err("#A trying to add value at index %d while buffer length is %d", index, bufferLength);
break;
}
buffer[index] = atof(token);
++index;
++lastArrayCreatedIndex;
}
if (lastArrayCreatedIndex == bufferLength) {
lastArrayCreated = NULL;
lastArrayCreatedIndex = 0;
}
}
} else {
context->print_err("Unrecognised hash type: \"%s\"", message.c_str());
}
}
return graph;
}