// JLH = James Hammons <jlhamm@acm.org>
//
// Who When What
-// --- ---------- -------------------------------------------------------------
+// --- ---------- ------------------------------------------------------------
// JLH 02/20/2013 Created this file
//
#include "fileio.h"
//#include <stdio.h>
+#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <vector>
-#include "arc.h"
-#include "circle.h"
-#include "container.h"
-#include "dimension.h"
-#include "line.h"
+#include "applicationwindow.h"
+#include "drawingview.h"
+#include "global.h"
+#include "structs.h"
/*
How to handle connected objects
intrinsic to either the Line or the Circle, but is a function of the
relationship between them by virtue of their connection.
+
+OTHER CONSIDERATIONS:
+---------------------
+
+ - Need to figure out how to store the Layer list (should layer list be optional?)
+ - Need to figure out how to store the Block list and blocks
+
+
*/
-enum ObjectType { OTContainer, OTContainerEnd, OTLine, OTCircle, OTArc, OTDimension,
- OTPolygon, OTText, OTImage, OTBlock, OTEndOfFile };
+//enum ObjectTypeFile { OTFContainer, OTFContainerEnd, OTFLine, OTFCircle, OTFArc,
+// OTFDimension, OTFPolygon, OTFText, OTFImage, OTFBlock, OTFEndOfFile };
+enum ObjectTypeFile { OTFContainer, OTFContainerEnd, OTFObject, OTFEndOfFile };
-/*static*/ bool FileIO::SaveAtnsFile(FILE * file, Container * object)
+// Instantiate class variables
+/*static*/ int FileIO::objectFileType = OTFObject;
+
+
+/*static*/ bool FileIO::SaveAtnsFile(FILE * file, Container * c)
{
- /* Approach: loop through the container, doing a depth-first traversal. Any extra
- containers found are looped through until there aren't any more down, then
- ordinary objects are described. This can be handled by a virtual Object function
- that reports the object by itself if it's a non-Container, otherwise it
- enumerates all objects within itself. */
-
- fprintf(file, "ARCHITEKTONAS DRAWING V1.0\n");
-#if 1
- object->Enumerate(file);
+ /* Approach: loop through the container, doing a depth-first traversal. Any
+ extra containers found are looped through until there aren't any more
+ down, then ordinary objects are described. This can be handled by a
+ virtual Object function that reports the object by itself if it's a non-
+ Container, otherwise it enumerates all objects within itself. */
+
+ fprintf(file, "ARCHITEKTONAS DRAWING V1.2\n");
+ fprintf(file, "LAYERS %i\n", Global::numLayers);
+
+ for(int i=0; i<Global::numLayers; i++)
+ fprintf(file, "%i %i \"%s\"\n", (Global::layerHidden[i] ? 1 : 0), (Global::layerLocked[i] ? 1 : 0), Global::layerName[i].c_str());
+
+ fprintf(file, "ACTIVE %i\n", Global::activeLayer);
+ WriteObjectToFile(file, (Object *)c);
fprintf(file, "END\n");
return true;
-#else
- return false;
-#endif
}
/*static*/ bool FileIO::LoadAtnsFile(FILE * file, Container * drawing)
{
-// char buffer[256];
float version;
- fscanf(file, "ARCHITEKTONAS DRAWING V%f", &version);
+ fscanf(file, "ARCHITEKTONAS DRAWING V%f\n", &version);
+
+ // Clear out layer vectors
+ Global::layerHidden.clear();
+ Global::layerLocked.clear();
+ Global::layerName.clear();
+
+ if (version == 1.0f)
+ return LoadVersion1_0(file, drawing);
+ else if (version == 1.1f)
+ return LoadVersion1_1(file, drawing);
+ else if (version == 1.2f)
+ return LoadVersion1_2(file, drawing);
+
+//printf("LoadAtnsFile: Could not locate version! (version=%f)\n", version);
+ return false;
+}
+
+
+/*static*/ void FileIO::ResetLayerVectors(void)
+{
+ // Set up layer vectors
+ Global::layerHidden.insert(Global::layerHidden.begin(), false);
+ Global::layerLocked.insert(Global::layerLocked.begin(), false);
+ Global::layerName.insert(Global::layerName.begin(), "Background");
+ Global::numLayers = 1;
+ Global::activeLayer = 0;
+}
-//printf("Load: version = %f\n", version);
- if (version != 1.0)
- return false;
- /* Approach: read each object in the file, one by one. If the object is a Container,
- add objects to it until an "endContainer" marker is found. This will require a
- stack to maintain the current Container. */
-#if 1
+/*static*/ bool FileIO::LoadVersion1_0(FILE * file, Container * drawing)
+{
+ // Approach: read each object in the file, one by one. If the object is a
+ // Container, add objects to it until an "endContainer" marker is found.
+ // This will require a stack to maintain the current Container.
std::vector<Container *> containerStack;
- Container * currentTopContainer = drawing;//new Container(Vector(0, 0));
- Object * object;
-// ObjectType objectType;
- int objectType;
+ Container * currentTopContainer = drawing;
+ ResetLayerVectors();
while (!feof(file))
{
- if (FileIO::GetObjectFromFile(file, currentTopContainer, &object, &objectType) == false)
- return false;
-
- // object->type down below can be replaced with objType.
- // Above could be: bool FileIO::GetObjectFromFile(FILE *, Object *, ObjectType *);
- // where the return value tells if it's a valid object, Object * returns the
- // reconstructed object and ObjectType * returns the object type.
+ // Reconstruct the object
+ Object * obj = GetObjectFromFile(file);
- if (objectType == OTEndOfFile)
+ // objectFileType is set in GetObjectFromFile()...
+ if (objectFileType == OTFObject)
+ {
+ if (obj == NULL)
+ return false;
+
+ currentTopContainer->objects.push_back(obj);
+//printf("Load: Adding object. Container size = %li (%li)\n", drawing->objects.size(), currentTopContainer->objects.size());
+
+ // If the object is a container, push current TLC on the stack and
+ // set it as the new TLC
+ if (obj->type == OTContainer)
+ {
+ containerStack.push_back(currentTopContainer);
+ currentTopContainer = (Container *)obj;
+ }
+ }
+ else if (objectFileType == OTFContainerEnd)
{
-printf("Load: container size = %li\n", drawing->objects.size());
+ // Container is done, so pop the stack to get back the previous TLC
+ currentTopContainer = containerStack.back();
+ containerStack.pop_back();
+ }
+ else if (objectFileType == OTFEndOfFile)
+ {
+//printf("Load: container size = %li\n", drawing->objects.size());
return true;
}
- else if (objectType == OTContainer)
+ }
+
+ return false;
+}
+
+
+/*static*/ bool FileIO::LoadVersion1_1(FILE * file, Container * drawing)
+{
+ // Approach: read each object in the file, one by one. If the object is a
+ // Container, add objects to it until an "endContainer" marker is found.
+ // This will require a stack to maintain the current Container.
+ std::vector<Container *> containerStack;
+ Container * currentTopContainer = drawing;
+ ResetLayerVectors();
+
+ while (!feof(file))
+ {
+ // Reconstruct the object (extended format!)
+ Object * obj = GetObjectFromFile(file, true);
+
+ // objectFileType is set in GetObjectFromFile()...
+ if (objectFileType == OTFObject)
{
- containerStack.push_back(currentTopContainer);
- currentTopContainer = new Container(Vector(0, 0), currentTopContainer);
+ if (obj == NULL)
+ return false;
+
+ currentTopContainer->objects.push_back(obj);
+//printf("Load: Adding object. Container size = %li (%li)\n", drawing->objects.size(), currentTopContainer->objects.size());
+
+ // If the object is a container, push current TLC on the stack and
+ // set it as the new TLC
+ if (obj->type == OTContainer)
+ {
+ containerStack.push_back(currentTopContainer);
+ currentTopContainer = (Container *)obj;
+ }
}
- else if (objectType == OTContainerEnd)
+ else if (objectFileType == OTFContainerEnd)
{
- Container * containerToAdd = currentTopContainer;
+ // Add the extents of the current container
+ Rect r = ApplicationWindow::drawing->GetObjectExtents((Object *)currentTopContainer);
+ currentTopContainer->p[0] = r.TopLeft();
+ currentTopContainer->p[1] = r.BottomRight();
+//printf("Container extents: <%lf, %lf>, <%lf, %lf>\n", r.l, r.t, r.r, r.b);
+
+ // Container is done, so pop the stack to get back the previous TLC
currentTopContainer = containerStack.back();
containerStack.pop_back();
- currentTopContainer->Add(containerToAdd);
}
- else
+ else if (objectFileType == OTFEndOfFile)
{
- currentTopContainer->Add(object);
-printf("Load: Adding object. Container size = %li (%li)\n", drawing->objects.size(), currentTopContainer->objects.size());
+//printf("Load: container size = %li\n", drawing->objects.size());
+ return true;
}
}
return false;
-#else
+}
+
+
+/*static*/ bool FileIO::LoadVersion1_2(FILE * file, Container * drawing)
+{
+ int hidden, locked;
+ char textBuffer[65536];
+
+ // Load layer information first
+ fscanf(file, "LAYERS %i\n", &Global::numLayers);
+
+ for(int i=0; i<Global::numLayers; i++)
+ {
+ fscanf(file, "%i %i \"%[^\"]\"\n", &hidden, &locked, textBuffer);
+ Global::layerHidden.push_back(hidden ? true : false);
+ Global::layerLocked.push_back(locked ? true : false);
+ Global::layerName.push_back(textBuffer);
+ }
+
+ fscanf(file, "ACTIVE %i\n", &Global::activeLayer);
+
+ // Approach: read each object in the file, one by one. If the object is a
+ // Container, add objects to it until an "endContainer" marker is found.
+ // This will require a stack to maintain the current Container.
+ std::vector<Container *> containerStack;
+ Container * currentTopContainer = drawing;
+
+ while (!feof(file))
+ {
+ // Reconstruct the object (extended format!)
+ Object * obj = GetObjectFromFile(file, true, true);
+
+ // objectFileType is set in GetObjectFromFile()...
+ if (objectFileType == OTFObject)
+ {
+ if (obj == NULL)
+ return false;
+
+ currentTopContainer->objects.push_back(obj);
+//printf("Load: Adding object. Container size = %li (%li)\n", drawing->objects.size(), currentTopContainer->objects.size());
+
+ // If the object is a container, push current TLC on the stack and
+ // set it as the new TLC
+ if (obj->type == OTContainer)
+ {
+ containerStack.push_back(currentTopContainer);
+ currentTopContainer = (Container *)obj;
+ }
+ }
+ else if (objectFileType == OTFContainerEnd)
+ {
+ // Add the extents of the current container
+ Rect r = ApplicationWindow::drawing->GetObjectExtents((Object *)currentTopContainer);
+ currentTopContainer->p[0] = r.TopLeft();
+ currentTopContainer->p[1] = r.BottomRight();
+//printf("Container extents: <%lf, %lf>, <%lf, %lf>\n", r.l, r.t, r.r, r.b);
+
+ // Container is done, so pop the stack to get back the previous TLC
+ currentTopContainer = containerStack.back();
+ containerStack.pop_back();
+ }
+ else if (objectFileType == OTFEndOfFile)
+ {
+//printf("Load: container size = %li\n", drawing->objects.size());
+ return true;
+ }
+ }
+
return false;
-#endif
}
-/*static*/ bool FileIO::GetObjectFromFile(FILE * file, Object * parent, Object ** object, int * objectType)
+/*static*/ Object * FileIO::GetObjectFromFile(FILE * file, bool extended/*= false*/, bool ext2/*= false*/)
{
char buffer[256];
- fscanf(file, "%s ", buffer);
- bool recognized = false;
-//printf("Load: buffer = \"%s\"\n", buffer);
+ char textBuffer[65536];
+ int foundLayer = 0;
+ /*int num =*/ fscanf(file, "%s", buffer);
+ Object * obj = NULL;
+ objectFileType = OTFObject;
+//printf("FileIO: fscanf returned %i, buffer = \"%s\"\n", num, buffer);
+
+// The following fugliness is for troubleshooting. Can remove later.
+ if ((strcmp(buffer, "END") != 0) && (strcmp(buffer, "ENDCONTAINER") != 0))
+{
+errno = 0;
+ /*num =*/ fscanf(file, " %i ", &foundLayer);
+//printf("FileIO: fscanf returned %i, foundLayer = %i\n", num, foundLayer);
+if (errno)
+{
+ if (errno == EAGAIN)
+ printf("EAGAIN\n");
+ else if (errno == EBADF)
+ printf("EBADF\n");
+ else if (errno == EILSEQ)
+ printf("EILSEQ\n");
+ else if (errno == EINTR)
+ printf("EINTR\n");
+ else if (errno == EINVAL)
+ printf("EINVAL\n");
+ else if (errno == ENOMEM)
+ printf("ENOMEM\n");
+ else if (errno == ERANGE)
+ printf("ERANGE\n");
+ else
+ printf("errno = %i\n", errno);
+}
+}
+ // Need to add pen attributes as well... do that for v1.1 :-P
+ // And fill attributes... do that for v1.3 (1.2 added layers)
if (strcmp(buffer, "LINE") == 0)
{
-//printf(" Found LINE.\n");
- recognized = true;
- Vector v1, v2;
- fscanf(file, "(%lf,%lf) (%lf,%lf)", &v1.x, &v1.y, &v2.x, &v2.y);
-//printf(" Number of params recognized: %i\n", n);
- *object = new Line(v1, v2, parent);
- *objectType = OTLine;
+ Point p1, p2;
+ fscanf(file, "(%lf,%lf) (%lf,%lf)", &p1.x, &p1.y, &p2.x, &p2.y);
+ obj = (Object *)new Line(p1, p2);
}
else if (strcmp(buffer, "CIRCLE") == 0)
{
- recognized = true;
- Vector v;
+ Point p;
double r;
- fscanf(file, "(%lf,%lf) %lf", &v.x, &v.y, &r);
- *object = new Circle(v, r, parent);
- *objectType = OTCircle;
+ fscanf(file, "(%lf,%lf) %lf", &p.x, &p.y, &r);
+ obj = (Object *)new Circle(p, r);
}
else if (strcmp(buffer, "ARC") == 0)
{
- recognized = true;
- Vector v;
+ Point p;
double r, a1, a2;
- fscanf(file, "(%lf,%lf) %lf, %lf, %lf", &v.x, &v.y, &r, &a1, &a2);
- *object = new Arc(v, r, a1, a2, parent);
- *objectType = OTArc;
+ fscanf(file, "(%lf,%lf) %lf, %lf, %lf", &p.x, &p.y, &r, &a1, &a2);
+ obj = (Object *)new Arc(p, r, a1, a2);
+ }
+ else if (strcmp(buffer, "TEXT") == 0)
+ {
+ Point p;
+ fscanf(file, "(%lf,%lf) \"%[^\"]\"", &p.x, &p.y, textBuffer);
+ obj = (Object *)new Text(p, textBuffer);
}
else if (strcmp(buffer, "DIMENSION") == 0)
{
- recognized = true;
- Vector v1, v2;
+ Point p1, p2;
DimensionType type;
- fscanf(file, "(%lf,%lf) (%lf,%lf) %i", &v1.x, &v1.y, &v2.x, &v2.y, &type);
- *object = new Dimension(v1, v2, type, parent);
- *objectType = OTDimension;
+ double offset = 0;
+ fscanf(file, "(%lf,%lf) (%lf,%lf) %i", &p1.x, &p1.y, &p2.x, &p2.y, (int *)&type);
+
+ if (ext2)
+ fscanf(file, " %lf", &offset);
+
+ obj = (Object *)new Dimension(p1, p2, type, offset);
}
else if (strcmp(buffer, "CONTAINER") == 0)
{
- recognized = true;
- *objectType = OTContainer;
+ obj = (Object *)new Container();
+// objectFileType = OTFContainer;
}
else if (strcmp(buffer, "ENDCONTAINER") == 0)
{
- recognized = true;
- *objectType = OTContainerEnd;
+ objectFileType = OTFContainerEnd;
}
else if (strcmp(buffer, "END") == 0)
{
- recognized = true;
- *objectType = OTEndOfFile;
+ objectFileType = OTFEndOfFile;
+ }
+ else
+ printf("Unknown object type '%s'...\n", buffer);
+
+ if (obj != NULL)
+ {
+ obj->layer = foundLayer;
+
+ if (extended && (obj->type != OTContainer))
+ {
+ fscanf(file, " (%i, %f, %i)\n", &obj->color, &obj->thickness, &obj->style);
+ }
}
- return recognized;
+ return obj;
+}
+
+
+/*static*/ bool FileIO::WriteObjectToFile(FILE * file, Object * obj)
+{
+ // Sanity check
+ if (obj == NULL)
+ return false;
+
+ switch (obj->type)
+ {
+ case OTLine:
+ fprintf(file, "LINE %i (%lf,%lf) (%lf,%lf)", obj->layer, obj->p[0].x, obj->p[0].y, obj->p[1].x, obj->p[1].y);
+ break;
+ case OTCircle:
+ fprintf(file, "CIRCLE %i (%lf,%lf) %lf", obj->layer, obj->p[0].x, obj->p[0].y, obj->radius[0]);
+ break;
+ case OTEllipse:
+ break;
+ case OTArc:
+ fprintf(file, "ARC %i (%lf,%lf) %lf, %lf, %lf", obj->layer, obj->p[0].x, obj->p[0].y, obj->radius[0], obj->angle[0], obj->angle[1]);
+ break;
+ case OTPolygon:
+ break;
+ case OTDimension:
+// fprintf(file, "DIMENSION %i (%lf,%lf) (%lf,%lf) %i\n", layer, position.x, position.y, endpoint.x, endpoint.y, dimensionType);
+ fprintf(file, "DIMENSION %i (%lf,%lf) (%lf,%lf) %i %lf", obj->layer, obj->p[0].x, obj->p[0].y, obj->p[1].x, obj->p[1].y, ((Dimension *)obj)->subtype, ((Dimension *)obj)->offset);
+ break;
+ case OTSpline:
+ break;
+ case OTText:
+ fprintf(file, "TEXT %i (%lf,%lf) \"%s\"", obj->layer, obj->p[0].x, obj->p[0].y, ((Text *)obj)->s.c_str());
+ break;
+ case OTContainer:
+ {
+ Container * c = (Container *)obj;
+
+ if (c->topLevel == false)
+ fprintf(file, "CONTAINER %i\n", obj->layer);
+
+ std::vector<void *>::iterator i;
+
+ for(i=c->objects.begin(); i!=c->objects.end(); i++)
+ WriteObjectToFile(file, (Object *)*i);
+
+ if (c->topLevel == false)
+ fprintf(file, "ENDCONTAINER\n");
+
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (obj->type != OTContainer)
+ fprintf(file, " (%i, %f, %i)\n", obj->color, obj->thickness, obj->style);
+
+ return true;
}