gds-render/gdsparse.c

477 lines
11 KiB
C
Raw Normal View History

2018-05-07 13:27:50 +02:00
#include "gdsparse.h"
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
2018-05-07 17:36:14 +02:00
#define GDS_ERROR(fmt, ...) printf("[PARSE_ERROR] " fmt "\n",## __VA_ARGS__)
#define GDS_WARN(fmt, ...) printf("[PARSE_WARNING] " fmt "\n",## __VA_ARGS__)
2018-05-07 13:27:50 +02:00
enum parsing_state {PARSING_LENGTH = 0, PARSING_TYPE, PARSING_DAT};
enum record {
2018-05-07 13:42:06 +02:00
INVALID = 0x0000,
2018-05-07 13:27:50 +02:00
HEADER = 0x0002,
BGNLIB = 0x0102,
LIBNAME = 0x0206,
UNITS = 0x0305,
ENDLIB = 0x0400,
2018-05-07 13:42:06 +02:00
BGNSTR = 0x0502,
2018-05-07 13:27:50 +02:00
STRNAME = 0x0606,
ENDSTR = 0x0700,
2018-05-07 15:17:29 +02:00
BOUNDARY = 0x0800,
PATH = 0x0900,
SREF = 0x0A00,
2018-05-07 17:36:14 +02:00
ENDEL = 0x1100,
XY = 0x1003,
MAG = 0x1B05,
ANGLE = 0x1C05,
SNAME = 0x1206,
STRANS = 0x1A01,
BOX = 0x2D00,
LAYER = 0x0D02,
2018-05-07 13:27:50 +02:00
};
2018-05-07 17:36:14 +02:00
static int name_cell_ref(struct gds_cell_instance *cell_inst, unsigned int bytes, char* data) {
int len;
if (cell_inst == NULL)
{
GDS_ERROR("Naming cell ref with no opened cell ref");
return -1;
}
data[bytes] = 0; // Append '0'
len = strlen(data);
if (len > CELL_NAME_MAX-1) {
GDS_ERROR("Cell name '%s' too long: %d\n", data, len);
return -1;
} else {
strcpy(cell_inst->ref_name, data);
printf("\tCell referenced: %s\n", cell_inst->ref_name);
}
return 0;
}
static signed int gds_convert_signed_int(char *data)
{
if (!data) {
GDS_ERROR("This should not happen");
return 0;
}
return (signed int)((((int)(data[0])) << 24) |
(((int)(data[1])) << 16) |
(((int)(data[2])) << 8) |
(((int)(data[3])) << 0));
}
static int16_t gds_convert_signed_int16(char *data)
{
if (!data) {
GDS_ERROR("This should not happen");
return 0;
}
return (int16_t)((((int16_t)(data[0])) << 8) |
(((int16_t)(data[1])) << 0));
}
2018-05-07 15:57:47 +02:00
static GList * append_library(GList *curr_list)
2018-05-07 13:27:50 +02:00
{
2018-05-07 15:57:47 +02:00
struct gds_library *lib;
lib = (struct gds_library *)malloc(sizeof(struct gds_library));
if(lib) {
lib->cells = NULL;
lib->name[0] = 0;
lib->unit_to_meters = 1; // Default. Will be overwritten
} else
return NULL;
return g_list_append(curr_list, lib);
2018-05-07 15:17:29 +02:00
}
2018-05-07 15:57:47 +02:00
static GList * append_graphics(GList *curr_list, enum graphics_type type)
2018-05-07 15:17:29 +02:00
{
2018-05-07 15:57:47 +02:00
struct gds_graphics *gfx;
gfx = (struct gds_graphics *)malloc(sizeof(struct gds_graphics));
if (gfx) {
gfx->datatype = 0;
gfx->layer = 0;
gfx->vertices = NULL;
gfx->width_absolute = 0;
gfx->type = type;
} else
return NULL;
return g_list_append(curr_list, gfx);
2018-05-07 13:27:50 +02:00
}
2018-05-07 17:36:14 +02:00
static GList * append_vertex(GList *curr_list, int x, int y)
{
struct gds_point *vertex;
vertex = (struct gds_point *)malloc(sizeof(struct gds_point));
if (vertex) {
vertex->x = x;
vertex->y = y;
} else
return NULL;
return g_list_append(curr_list, vertex);
}
2018-05-07 15:57:47 +02:00
static GList * append_cell(GList *curr_list)
2018-05-07 13:27:50 +02:00
{
2018-05-07 15:57:47 +02:00
struct gds_cell *cell;
cell = (struct gds_cell *)malloc(sizeof(struct gds_cell));
if (cell) {
cell->child_cells = NULL;
cell->graphic_objs = NULL;
cell->name[0] = 0;
} else
return NULL;
2018-05-07 15:17:29 +02:00
2018-05-07 15:57:47 +02:00
return g_list_append(curr_list, cell);
2018-05-07 15:17:29 +02:00
}
2018-05-07 15:57:47 +02:00
static GList * append_cell_ref(GList *curr_list)
2018-05-07 15:17:29 +02:00
{
2018-05-07 15:57:47 +02:00
struct gds_cell_instance *inst;
inst = (struct gds_cell_instance *)malloc(sizeof(struct gds_cell_instance));
if (inst) {
inst->cell_ref = NULL;
inst->ref_name[0] = 0;
2018-05-07 17:36:14 +02:00
inst->magnification = 1;
inst->flipped = 0;
inst->angle = 0;
2018-05-07 15:57:47 +02:00
} else
return NULL;
2018-05-07 15:17:29 +02:00
2018-05-07 15:57:47 +02:00
return g_list_append(curr_list, inst);
2018-05-07 13:27:50 +02:00
}
static int name_library(struct gds_library *current_library, unsigned int bytes, char* data) {
int len;
2018-05-07 13:42:06 +02:00
if (current_library == NULL)
{
GDS_ERROR("Naming cell with no opened library");
return -1;
}
2018-05-07 13:27:50 +02:00
data[bytes] = 0; // Append '0'
len = strlen(data);
if (len > CELL_NAME_MAX-1) {
GDS_ERROR("Library name '%s' too long: %d\n", data, len);
return -1;
} else {
strcpy(current_library->name, data);
printf("Named library: %s\n", current_library->name);
}
return 0;
}
static int name_cell(struct gds_cell *cell, unsigned int bytes, char* data) {
int len;
2018-05-07 13:42:06 +02:00
if (cell == NULL)
{
GDS_ERROR("Naming library with no opened library");
return -1;
}
2018-05-07 13:27:50 +02:00
data[bytes] = 0; // Append '0'
len = strlen(data);
if (len > CELL_NAME_MAX-1) {
2018-05-07 13:42:06 +02:00
GDS_ERROR("Cell name '%s' too long: %d\n", data, len);
2018-05-07 13:27:50 +02:00
return -1;
} else {
strcpy(cell->name, data);
2018-05-07 13:42:06 +02:00
printf("Named cell: %s\n", cell->name);
2018-05-07 13:27:50 +02:00
}
return 0;
}
2018-05-07 15:57:47 +02:00
int parse_gds_from_file(const char *filename, GList **library_list)
2018-05-07 13:27:50 +02:00
{
char workbuff[1024];
int read;
2018-05-07 17:36:14 +02:00
int i;
2018-05-07 13:27:50 +02:00
int run = 1;
FILE *gds_file = NULL;
uint16_t rec_data_length;
enum record rec_type;
enum parsing_state state = PARSING_LENGTH;
struct gds_library *current_lib = NULL;
struct gds_cell *current_cell = NULL;
struct gds_graphics *current_graphics = NULL;
struct gds_cell_instance *current_s_reference = NULL;
////////////
2018-05-07 15:57:47 +02:00
GList *lib_list;
lib_list = *library_list;
2018-05-07 13:27:50 +02:00
/* open File */
gds_file = fopen(filename, "r");
if (gds_file == NULL) {
GDS_ERROR("Could not open File %s", filename);
return -1;
}
/* Record parser */
while (run == 1) {
switch (state) {
case PARSING_LENGTH:
2018-05-07 13:42:06 +02:00
rec_type = INVALID;
2018-05-07 13:27:50 +02:00
read = fread(workbuff, sizeof(char), 2, gds_file);
if (read != 2 && (current_cell != NULL ||
current_graphics != NULL ||
current_lib != NULL ||
current_s_reference != NULL)) {
GDS_ERROR("End of File. with openend structs/libs");
run = -2;
break;
} else if (read != 2) {
/* EOF */
run = 0;
break;
}
rec_data_length = (uint16_t)((((uint16_t)(workbuff[0])) << 8) |
(uint16_t)(workbuff[1]));
if (rec_data_length < 4) {
/* Possible Zero-Padding: */
run = 0;
GDS_WARN("Zero Padding detected!");
if (current_cell != NULL ||
current_graphics != NULL ||
current_lib != NULL ||
current_s_reference != NULL) {
GDS_ERROR("Not all structures closed");
run = -2;
}
break;
}
rec_data_length -= 4;
state = PARSING_TYPE;
break;
case PARSING_TYPE:
read = fread(workbuff, sizeof(char), 2, gds_file);
if (read != 2) {
run = -2;
GDS_ERROR("Unexpected end of file");
break;
}
rec_type = (uint16_t)((((uint16_t)(workbuff[0])) << 8) |
(uint16_t)(workbuff[1]));
state = PARSING_DAT;
/* if begin: Allocate structures */
switch (rec_type) {
case BGNLIB:
2018-05-07 15:57:47 +02:00
lib_list = append_library(lib_list);
if (lib_list == NULL) {
2018-05-07 13:27:50 +02:00
GDS_ERROR("Allocating memory failed");
run = -3;
break;
}
printf("Entering Lib\n");
2018-05-07 15:57:47 +02:00
current_lib = (struct gds_library *)g_list_last(lib_list)->data;
2018-05-07 13:27:50 +02:00
break;
case ENDLIB:
if (current_lib == NULL) {
run = -4;
GDS_ERROR("Closing Library with no opened library");
break;
}
2018-05-07 15:17:29 +02:00
/* Check for open Cells */
if (current_cell != NULL) {
run = -4;
GDS_ERROR("Closing Library with opened cells");
break;
}
2018-05-07 13:27:50 +02:00
current_lib = NULL;
printf("Leaving Library\n");
2018-05-07 13:42:06 +02:00
break;
2018-05-07 13:27:50 +02:00
case BGNSTR:
2018-05-07 15:57:47 +02:00
current_lib->cells = append_cell(current_lib->cells);
if (current_lib->cells == NULL) {
2018-05-07 13:27:50 +02:00
GDS_ERROR("Allocating memory failed");
run = -3;
break;
}
printf("Entering Cell\n");
2018-05-07 15:57:47 +02:00
current_cell = (struct gds_cell *)g_list_last(current_lib->cells)->data;
2018-05-07 13:27:50 +02:00
break;
case ENDSTR:
if (current_cell == NULL) {
run = -4;
GDS_ERROR("Closing cell with no opened cell");
break;
}
2018-05-07 15:17:29 +02:00
/* Check for open Elements */
if (current_graphics != NULL || current_s_reference != NULL) {
run = -4;
GDS_ERROR("Closing cell with opened Elements");
break;
}
2018-05-07 13:27:50 +02:00
current_cell = NULL;
printf("Leaving Cell\n");
break;
2018-05-07 17:36:14 +02:00
//case BOX:
2018-05-07 15:17:29 +02:00
case BOUNDARY:
if (current_cell == NULL) {
GDS_ERROR("Boundary outside of cell");
run = -3;
break;
}
2018-05-07 15:57:47 +02:00
current_cell->graphic_objs = append_graphics(current_cell->graphic_objs, GRAPHIC_POLYGON);
2018-05-07 15:17:29 +02:00
if (current_cell->graphic_objs == NULL) {
GDS_ERROR("Memory allocation failed");
run = -4;
break;
}
2018-05-07 15:57:47 +02:00
current_graphics = (struct gds_graphics *) g_list_last(current_cell->graphic_objs)->data;
2018-05-07 15:17:29 +02:00
printf("\tEntering boundary\n");
break;
case SREF:
if (current_cell == NULL) {
GDS_ERROR("Path outside of cell");
run = -3;
break;
}
2018-05-07 15:57:47 +02:00
current_cell->child_cells = append_cell_ref(current_cell->child_cells);
2018-05-07 15:17:29 +02:00
if (current_cell->child_cells == NULL) {
GDS_ERROR("Memory allocation failed");
run = -4;
break;
}
2018-05-07 17:36:14 +02:00
current_s_reference = (struct gds_cell_instance *) g_list_last(current_cell->child_cells)->data;
printf("\tEntering reference\n");
2018-05-07 15:17:29 +02:00
break;
case PATH:
if (current_cell == NULL) {
GDS_ERROR("Path outside of cell");
run = -3;
break;
}
2018-05-07 15:57:47 +02:00
current_cell->graphic_objs = append_graphics(current_cell->graphic_objs, GRAPHIC_PATH);
2018-05-07 15:17:29 +02:00
if (current_cell->graphic_objs == NULL) {
GDS_ERROR("Memory allocation failed");
run = -4;
break;
}
2018-05-07 15:57:47 +02:00
current_graphics = (struct gds_graphics *) g_list_last(current_cell->graphic_objs)->data;
2018-05-07 15:17:29 +02:00
printf("\tEntering Path\n");
break;
case ENDEL:
if (current_graphics != NULL) {
printf("\tLeaving %s\n", (current_graphics->type == GRAPHIC_POLYGON ? "boundary" : "path"));
current_graphics = NULL;
}
2018-05-07 17:36:14 +02:00
if (current_s_reference != NULL) {
printf("\tLeaving Reference\n");
current_s_reference = NULL;
}
2018-05-07 15:17:29 +02:00
break;
2018-05-07 17:36:14 +02:00
case XY:
if (current_graphics) {
2018-05-07 13:27:50 +02:00
2018-05-07 17:36:14 +02:00
} else if (current_s_reference) {
if (rec_data_length != 8) {
GDS_WARN("Instance has weird coordinates. Rendered output might be screwed!");
}
}
break;
case MAG:
GDS_WARN("Magnification not yet supported");
break;
case STRANS:
break;
default:
//GDS_WARN("Record: %04x, len: %u", (unsigned int)rec_type, (unsigned int)rec_data_length);
break;
2018-05-07 13:27:50 +02:00
}
break;
2018-05-07 17:36:14 +02:00
2018-05-07 13:27:50 +02:00
case PARSING_DAT:
read = fread(workbuff, sizeof(char), rec_data_length, gds_file);
state = PARSING_LENGTH;
if (read != rec_data_length) {
GDS_ERROR("Could not read enough data");
run = -5;
break;
}
/* No Data -> No Processing */
if (!read) break;
switch (rec_type) {
case LIBNAME:
2018-05-07 15:17:29 +02:00
name_library(current_lib, read, workbuff);
2018-05-07 13:27:50 +02:00
break;
case STRNAME:
name_cell(current_cell, read, workbuff);
break;
2018-05-07 17:36:14 +02:00
case XY:
if (current_s_reference) {
/* Get origin of reference */
current_s_reference->origin.x = gds_convert_signed_int(workbuff);
current_s_reference->origin.y = gds_convert_signed_int(&workbuff[4]);
} else if (current_graphics) {
for (i = 0; i < read/8; i++) {
// printf("coords: %d/%d", gds_convert_signed_int(&workbuff[i*8]), gds_convert_signed_int(&workbuff[i*8+4]));
current_graphics->vertices = append_vertex(current_graphics->vertices,
gds_convert_signed_int(&workbuff[i*8]),
gds_convert_signed_int(&workbuff[i*8]));
}
}
break;
case STRANS:
if (!current_s_reference) {
GDS_ERROR("Transformation defined outside of instance");
break;
}
current_s_reference->flipped = ((workbuff[0] & 0x80) ? 1 : 0);
break;
case SNAME:
name_cell_ref(current_s_reference, read, workbuff);
break;
case LAYER:
if (!current_graphics) {
GDS_WARN("Layer has to be defined inside graphics object. Probably unknown object.");
break;
}
current_graphics->layer = gds_convert_signed_int16(workbuff);
printf("\tAdded layer %d\n", (int)current_graphics->layer);
break;
2018-05-07 13:27:50 +02:00
}
break;
}
}
fclose(gds_file);
2018-05-07 15:17:29 +02:00
/* Iterate and find references to cells */
2018-05-07 17:36:14 +02:00
// TODO
2018-05-07 15:17:29 +02:00
2018-05-07 15:57:47 +02:00
*library_list = lib_list;
2018-05-07 13:27:50 +02:00
return run;
}