mirror of https://github.com/KLayout/klayout.git
3349 lines
95 KiB
C++
3349 lines
95 KiB
C++
|
|
/*
|
|
|
|
KLayout Layout Viewer
|
|
Copyright (C) 2006-2021 Matthias Koefferlein
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program; if not, write to the Free Software
|
|
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "dbOASISReader.h"
|
|
#include "dbCommonReader.h"
|
|
#include "dbStream.h"
|
|
#include "dbObjectWithProperties.h"
|
|
#include "dbArray.h"
|
|
#include "dbStatic.h"
|
|
|
|
#include "tlException.h"
|
|
#include "tlString.h"
|
|
#include "tlClassRegistry.h"
|
|
|
|
namespace db
|
|
{
|
|
|
|
// ---------------------------------------------------------------
|
|
|
|
// ---------------------------------------------------------------
|
|
// OASISReader
|
|
|
|
OASISReader::OASISReader (tl::InputStream &s)
|
|
: m_stream (s),
|
|
m_progress (tl::to_string (tr ("Reading OASIS file")), 10000),
|
|
m_dbu (0.001),
|
|
m_expect_strict_mode (-1),
|
|
mm_repetition (this, "repetition"),
|
|
mm_placement_cell (this, "placement-cell"),
|
|
mm_placement_x (this, "playcement-x"),
|
|
mm_placement_y (this, "playcement-y"),
|
|
mm_layer (this, "layer"),
|
|
mm_datatype (this, "datatype"),
|
|
mm_textlayer (this, "textlayer"),
|
|
mm_texttype (this, "texttype"),
|
|
mm_text_x (this, "text-x"),
|
|
mm_text_y (this, "text-y"),
|
|
mm_text_string (this, "text-string"),
|
|
mm_text_string_id (this, "text-string-id"),
|
|
mm_geometry_x (this, "geometry-x"),
|
|
mm_geometry_y (this, "geometry-y"),
|
|
mm_geometry_w (this, "geometry-w"),
|
|
mm_geometry_h (this, "geometry-h"),
|
|
mm_polygon_point_list (this, "polygon-point-list"),
|
|
mm_path_halfwidth (this, "path-halfwidth"),
|
|
mm_path_start_extension (this, "path-start-extension"),
|
|
mm_path_end_extension (this, "path-end-extension"),
|
|
mm_path_point_list (this, "path-point-list"),
|
|
mm_ctrapezoid_type (this, "ctrapezoid-type"),
|
|
mm_circle_radius (this, "circle-radius"),
|
|
mm_last_property_name (this, "last-property-name"),
|
|
mm_last_property_is_sprop (this, "last-property-is-stdprop"),
|
|
mm_last_value_list(this, "last-value-list"),
|
|
m_read_texts (true),
|
|
m_read_properties (true),
|
|
m_read_all_properties (false),
|
|
m_s_gds_property_name_id (0),
|
|
m_klayout_context_property_name_id (0)
|
|
{
|
|
m_progress.set_format (tl::to_string (tr ("%.0f MB")));
|
|
m_progress.set_unit (1024 * 1024);
|
|
m_first_cellname = 0;
|
|
m_first_propname = 0;
|
|
m_first_propstring = 0;
|
|
m_first_textstring = 0;
|
|
m_first_layername = 0;
|
|
m_in_table = NotInTable;
|
|
m_table_cellname = 0;
|
|
m_table_propname = 0;
|
|
m_table_propstring = 0;
|
|
m_table_textstring = 0;
|
|
m_table_layername = 0;
|
|
m_table_start = 0;
|
|
}
|
|
|
|
OASISReader::~OASISReader ()
|
|
{
|
|
// .. nothing yet ..
|
|
}
|
|
|
|
void
|
|
OASISReader::init (const db::LoadLayoutOptions &options)
|
|
{
|
|
CommonReader::init (options);
|
|
|
|
m_read_texts = common_options ().enable_text_objects;
|
|
m_read_properties = common_options ().enable_properties;
|
|
|
|
db::OASISReaderOptions oasis_options = options.get_options<db::OASISReaderOptions> ();
|
|
m_read_all_properties = oasis_options.read_all_properties;
|
|
m_expect_strict_mode = oasis_options.expect_strict_mode;
|
|
}
|
|
|
|
inline long long
|
|
OASISReader::get_long_long ()
|
|
{
|
|
unsigned long long u = get_ulong_long ();
|
|
if ((u & 1) != 0) {
|
|
return -(long long) (u >> 1);
|
|
} else {
|
|
return (long long) (u >> 1);
|
|
}
|
|
}
|
|
|
|
inline unsigned long long
|
|
OASISReader::get_ulong_long ()
|
|
{
|
|
unsigned long long v = 0;
|
|
unsigned long long vm = 1;
|
|
char c;
|
|
|
|
do {
|
|
unsigned char *b = (unsigned char *) m_stream.get (1);
|
|
if (! b) {
|
|
error (tl::to_string (tr ("Unexpected end-of-file")));
|
|
return 0;
|
|
}
|
|
c = *b;
|
|
if (vm > std::numeric_limits <unsigned long long>::max () / 128 &&
|
|
(unsigned long long) (c & 0x7f) > (std::numeric_limits <unsigned long long>::max () / vm)) {
|
|
error (tl::to_string (tr ("Unsigned long value overflow")));
|
|
}
|
|
v += (unsigned long long) (c & 0x7f) * vm;
|
|
vm <<= 7;
|
|
} while ((c & 0x80) != 0);
|
|
|
|
return v;
|
|
}
|
|
|
|
inline long
|
|
OASISReader::get_long ()
|
|
{
|
|
unsigned long u = get_ulong ();
|
|
if ((u & 1) != 0) {
|
|
return -long (u >> 1);
|
|
} else {
|
|
return long (u >> 1);
|
|
}
|
|
}
|
|
|
|
inline unsigned long
|
|
OASISReader::get_ulong_for_divider ()
|
|
{
|
|
unsigned long l = get_ulong ();
|
|
if (l == 0) {
|
|
error (tl::to_string (tr ("Divider must not be zero")));
|
|
}
|
|
return l;
|
|
}
|
|
|
|
inline unsigned long
|
|
OASISReader::get_ulong ()
|
|
{
|
|
unsigned long v = 0;
|
|
unsigned long vm = 1;
|
|
char c;
|
|
|
|
do {
|
|
unsigned char *b = (unsigned char *) m_stream.get (1);
|
|
if (! b) {
|
|
error (tl::to_string (tr ("Unexpected end-of-file")));
|
|
return 0;
|
|
}
|
|
c = *b;
|
|
if (vm > std::numeric_limits <unsigned long>::max () / 128 &&
|
|
(unsigned long) (c & 0x7f) > (std::numeric_limits <unsigned long>::max () / vm)) {
|
|
error (tl::to_string (tr ("Unsigned long value overflow")));
|
|
}
|
|
v += (unsigned long) (c & 0x7f) * vm;
|
|
vm <<= 7;
|
|
} while ((c & 0x80) != 0);
|
|
|
|
return v;
|
|
}
|
|
|
|
inline int
|
|
OASISReader::get_int ()
|
|
{
|
|
unsigned int u = get_uint ();
|
|
if ((u & 1) != 0) {
|
|
return -int (u >> 1);
|
|
} else {
|
|
return int (u >> 1);
|
|
}
|
|
}
|
|
|
|
inline unsigned int
|
|
OASISReader::get_uint ()
|
|
{
|
|
unsigned int v = 0;
|
|
unsigned int vm = 1;
|
|
char c;
|
|
|
|
do {
|
|
unsigned char *b = (unsigned char *) m_stream.get (1);
|
|
if (! b) {
|
|
error (tl::to_string (tr ("Unexpected end-of-file")));
|
|
return 0;
|
|
}
|
|
c = *b;
|
|
if (vm > std::numeric_limits <unsigned int>::max () / 128 &&
|
|
(unsigned int) (c & 0x7f) > (std::numeric_limits <unsigned int>::max () / vm)) {
|
|
error (tl::to_string (tr ("Unsigned integer value overflow")));
|
|
}
|
|
v += (unsigned int) (c & 0x7f) * vm;
|
|
vm <<= 7;
|
|
} while ((c & 0x80) != 0);
|
|
|
|
return v;
|
|
}
|
|
|
|
std::string
|
|
OASISReader::get_str ()
|
|
{
|
|
std::string s;
|
|
get_str (s);
|
|
return s;
|
|
}
|
|
|
|
void
|
|
OASISReader::get_str (std::string &s)
|
|
{
|
|
size_t l = 0;
|
|
get (l);
|
|
|
|
char *b = (char *) m_stream.get (l);
|
|
if (b) {
|
|
s.assign (b, l);
|
|
} else {
|
|
s = std::string ();
|
|
}
|
|
}
|
|
|
|
double
|
|
OASISReader::get_real ()
|
|
{
|
|
unsigned int t = get_uint ();
|
|
|
|
if (t == 0) {
|
|
|
|
return double (get_ulong ());
|
|
|
|
} else if (t == 1) {
|
|
|
|
return -double (get_ulong ());
|
|
|
|
} else if (t == 2) {
|
|
|
|
return 1.0 / double (get_ulong_for_divider ());
|
|
|
|
} else if (t == 3) {
|
|
|
|
return -1.0 / double (get_ulong_for_divider ());
|
|
|
|
} else if (t == 4) {
|
|
|
|
double d = double (get_ulong ());
|
|
return d / double (get_ulong_for_divider ());
|
|
|
|
} else if (t == 5) {
|
|
|
|
double d = double (get_ulong ());
|
|
return -d / double (get_ulong_for_divider ());
|
|
|
|
} else if (t == 6) {
|
|
|
|
union {
|
|
float f;
|
|
uint32_t i;
|
|
} i2f;
|
|
|
|
unsigned char *b = (unsigned char *) m_stream.get (sizeof (i2f.i));
|
|
if (! b) {
|
|
error (tl::to_string (tr ("Unexpected end-of-file")));
|
|
}
|
|
i2f.i = 0;
|
|
b += sizeof (i2f.i);
|
|
for (unsigned int i = 0; i < sizeof (i2f.i); ++i) {
|
|
i2f.i = (i2f.i << 8) + uint32_t (*--b);
|
|
}
|
|
|
|
return double (i2f.f);
|
|
|
|
} else if (t == 7) {
|
|
|
|
union {
|
|
double d;
|
|
uint64_t i;
|
|
} i2f;
|
|
|
|
unsigned char *b = (unsigned char *) m_stream.get (sizeof (i2f.i));
|
|
if (! b) {
|
|
error (tl::to_string (tr ("Unexpected end-of-file")));
|
|
}
|
|
i2f.i = 0;
|
|
b += sizeof (i2f.i);
|
|
for (unsigned int i = 0; i < sizeof (i2f.i); ++i) {
|
|
i2f.i = (i2f.i << 8) + uint64_t (*--b);
|
|
}
|
|
|
|
return double (i2f.d);
|
|
|
|
} else {
|
|
error (tl::sprintf (tl::to_string (tr ("Invalid real type %d")), t));
|
|
return 0.0;
|
|
}
|
|
}
|
|
|
|
db::Coord
|
|
OASISReader::get_ucoord (unsigned long grid)
|
|
{
|
|
unsigned long long lx = 0;
|
|
get (lx);
|
|
lx *= grid;
|
|
if (lx > (unsigned long long) (std::numeric_limits <db::Coord>::max ())) {
|
|
error (tl::to_string (tr ("Coordinate value overflow")));
|
|
}
|
|
return db::Coord (lx);
|
|
}
|
|
|
|
OASISReader::distance_type
|
|
OASISReader::get_ucoord_as_distance (unsigned long grid)
|
|
{
|
|
unsigned long long lx = 0;
|
|
get (lx);
|
|
lx *= grid;
|
|
if (lx > (unsigned long long) (std::numeric_limits <distance_type>::max ())) {
|
|
error (tl::to_string (tr ("Coordinate value overflow")));
|
|
}
|
|
return distance_type (lx);
|
|
}
|
|
|
|
db::Coord
|
|
OASISReader::get_coord (long grid)
|
|
{
|
|
long long lx = 0;
|
|
get (lx);
|
|
lx *= grid;
|
|
if (lx < (long long) (std::numeric_limits <db::Coord>::min ()) ||
|
|
lx > (long long) (std::numeric_limits <db::Coord>::max ())) {
|
|
error (tl::to_string (tr ("Coordinate value overflow")));
|
|
}
|
|
return db::Coord (lx);
|
|
}
|
|
|
|
db::Vector
|
|
OASISReader::get_2delta (long grid)
|
|
{
|
|
unsigned long long l1 = 0;
|
|
get (l1);
|
|
|
|
long long lx = l1 >> 2;
|
|
lx *= grid;
|
|
if (lx > (long long) (std::numeric_limits <db::Coord>::max ())) {
|
|
error (tl::to_string (tr ("Coordinate value overflow")));
|
|
}
|
|
db::Coord x = lx;
|
|
|
|
switch (l1 & 3) {
|
|
case 0:
|
|
return db::Vector (x, 0);
|
|
case 1:
|
|
return db::Vector (0, x);
|
|
case 2:
|
|
return db::Vector (-x, 0);
|
|
case 3:
|
|
default:
|
|
return db::Vector (0, -x);
|
|
}
|
|
}
|
|
|
|
db::Vector
|
|
OASISReader::get_3delta (long grid)
|
|
{
|
|
unsigned long long l1 = 0;
|
|
get (l1);
|
|
|
|
long long lx = l1 >> 3;
|
|
lx *= grid;
|
|
if (lx > (long long) (std::numeric_limits <db::Coord>::max ())) {
|
|
error (tl::to_string (tr ("Coordinate value overflow")));
|
|
}
|
|
db::Coord x = lx;
|
|
|
|
switch (l1 & 7) {
|
|
case 0:
|
|
return db::Vector (x, 0);
|
|
case 1:
|
|
return db::Vector (0, x);
|
|
case 2:
|
|
return db::Vector (-x, 0);
|
|
case 3:
|
|
return db::Vector (0, -x);
|
|
case 4:
|
|
return db::Vector (x, x);
|
|
case 5:
|
|
return db::Vector (-x, x);
|
|
case 6:
|
|
return db::Vector (-x, -x);
|
|
case 7:
|
|
default:
|
|
return db::Vector (x, -x);
|
|
}
|
|
}
|
|
|
|
db::Vector
|
|
OASISReader::get_gdelta (long grid)
|
|
{
|
|
unsigned long long l1 = 0;
|
|
get (l1);
|
|
|
|
if ((l1 & 1) != 0) {
|
|
|
|
long long lx = ((l1 & 2) == 0 ? (long long) (l1 >> 2) : -(long long) (l1 >> 2));
|
|
lx *= grid;
|
|
if (lx < (long long) (std::numeric_limits <db::Coord>::min ()) ||
|
|
lx > (long long) (std::numeric_limits <db::Coord>::max ())) {
|
|
error (tl::to_string (tr ("Coordinate value overflow")));
|
|
}
|
|
|
|
long long ly;
|
|
get (ly);
|
|
ly *= grid;
|
|
if (ly < (long long) (std::numeric_limits <db::Coord>::min ()) ||
|
|
ly > (long long) (std::numeric_limits <db::Coord>::max ())) {
|
|
error (tl::to_string (tr ("Coordinate value overflow")));
|
|
}
|
|
|
|
return db::Vector (db::Coord (lx), db::Coord (ly));
|
|
|
|
} else {
|
|
|
|
long long lx = l1 >> 4;
|
|
lx *= grid;
|
|
if (lx > (long long) (std::numeric_limits <db::Coord>::max ())) {
|
|
error (tl::to_string (tr ("Coordinate value overflow")));
|
|
}
|
|
db::Coord x = lx;
|
|
|
|
switch ((l1 >> 1) & 7) {
|
|
case 0:
|
|
return db::Vector (x, 0);
|
|
case 1:
|
|
return db::Vector (0, x);
|
|
case 2:
|
|
return db::Vector (-x, 0);
|
|
case 3:
|
|
return db::Vector (0, -x);
|
|
case 4:
|
|
return db::Vector (x, x);
|
|
case 5:
|
|
return db::Vector (-x, x);
|
|
case 6:
|
|
return db::Vector (-x, -x);
|
|
case 7:
|
|
default:
|
|
return db::Vector (x, -x);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
OASISReader::error (const std::string &msg)
|
|
{
|
|
throw OASISReaderException (msg, m_stream.pos (), m_cellname.c_str ());
|
|
}
|
|
|
|
void
|
|
OASISReader::warn (const std::string &msg)
|
|
{
|
|
if (warnings_as_errors ()) {
|
|
error (msg);
|
|
} else {
|
|
// TODO: compress
|
|
tl::warn << msg
|
|
<< tl::to_string (tr (" (position=")) << m_stream.pos ()
|
|
<< tl::to_string (tr (", cell=")) << m_cellname
|
|
<< ")";
|
|
}
|
|
}
|
|
|
|
/**
|
|
* @brief A helper class to join two datatype layer name map members
|
|
*/
|
|
struct LNameJoinOp1
|
|
{
|
|
void operator() (std::string &a, const std::string &b)
|
|
{
|
|
join_layer_names (a, b);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief A helper class to join two layer map members
|
|
* This implementation basically merged the datatype maps.
|
|
*/
|
|
struct LNameJoinOp2
|
|
{
|
|
void operator() (tl::interval_map<db::ld_type, std::string> &a, const tl::interval_map<db::ld_type, std::string> &b)
|
|
{
|
|
LNameJoinOp1 op1;
|
|
a.add (b.begin (), b.end (), op1);
|
|
}
|
|
};
|
|
|
|
/**
|
|
* @brief Marks the beginning of a new table
|
|
*
|
|
* This method will update m_table_start which is the location used as
|
|
* the start position of a strict mode table. Every record except CBLOCK
|
|
* will update this position to point after the record. Hence m_table_start
|
|
* points to the beginning of a table when PROPNAME, CELLNAME or any
|
|
* other table-contained record is encountered.
|
|
* Since CBLOCK does not update this record, the position of the table will
|
|
* be the location of CBLOCK rather than that of the name record itself.
|
|
* PAD records will also call this method, so the beginning of a table
|
|
* is right after any preceding PAD records and exactly at the location
|
|
* of the first name record after PADs.
|
|
*/
|
|
void
|
|
OASISReader::mark_start_table ()
|
|
{
|
|
// we need to this this to really finish a CBLOCK - this is a flaw
|
|
// in the inflating reader, but it's hard to fix.
|
|
get_byte ();
|
|
m_stream.unget (1);
|
|
|
|
// now we can fetch the position
|
|
m_table_start = m_stream.pos ();
|
|
}
|
|
|
|
void
|
|
OASISReader::read_offset_table ()
|
|
{
|
|
unsigned long of = 0;
|
|
|
|
of = get_uint ();
|
|
m_table_cellname = get_ulong ();
|
|
if (m_table_cellname != 0 && m_expect_strict_mode >= 0 && ((of == 0) != (m_expect_strict_mode == 0))) {
|
|
warn (tl::to_string (tr ("CELLNAME offset table has unexpected strict mode")));
|
|
}
|
|
|
|
of = get_uint ();
|
|
m_table_textstring = get_ulong ();
|
|
if (m_table_textstring != 0 && m_expect_strict_mode >= 0 && ((of == 0) != (m_expect_strict_mode == 0))) {
|
|
warn (tl::to_string (tr ("TEXTSTRING offset table has unexpected strict mode")));
|
|
}
|
|
|
|
of = get_uint ();
|
|
m_table_propname = get_ulong ();
|
|
if (m_table_propname != 0 && m_expect_strict_mode >= 0 && ((of == 0) != (m_expect_strict_mode == 0))) {
|
|
warn (tl::to_string (tr ("PROPNAME offset table has unexpected strict mode")));
|
|
}
|
|
|
|
of = get_uint ();
|
|
m_table_propstring = get_ulong ();
|
|
if (m_table_propstring != 0 && m_expect_strict_mode >= 0 && ((of == 0) != (m_expect_strict_mode == 0))) {
|
|
warn (tl::to_string (tr ("PROPSTRING offset table has unexpected strict mode")));
|
|
}
|
|
|
|
of = get_uint ();
|
|
m_table_layername = get_ulong ();
|
|
if (m_table_layername != 0 && m_expect_strict_mode >= 0 && ((of == 0) != (m_expect_strict_mode == 0))) {
|
|
warn (tl::to_string (tr ("LAYERNAME offset table has unexpected strict mode")));
|
|
}
|
|
|
|
// XNAME table ignored currently
|
|
get_uint ();
|
|
get_ulong ();
|
|
}
|
|
|
|
static const char magic_bytes[] = { "%SEMI-OASIS\015\012" };
|
|
|
|
void
|
|
OASISReader::do_read (db::Layout &layout)
|
|
{
|
|
unsigned char r;
|
|
char *mb;
|
|
|
|
// prepare
|
|
m_s_gds_property_name_id = layout.properties_repository ().prop_name_id ("S_GDS_PROPERTY");
|
|
m_klayout_context_property_name_id = layout.properties_repository ().prop_name_id ("KLAYOUT_CONTEXT");
|
|
|
|
// read magic bytes
|
|
mb = (char *) m_stream.get (sizeof (magic_bytes) - 1);
|
|
if (! mb) {
|
|
error (tl::to_string (tr ("File too short")));
|
|
return;
|
|
}
|
|
if (strncmp (mb, magic_bytes, sizeof (magic_bytes) - 1) != 0) {
|
|
error (tl::to_string (tr ("Format error (missing magic bytes)")));
|
|
}
|
|
|
|
// read first record
|
|
r = get_byte ();
|
|
if (r != 1 /*START*/) {
|
|
error (tl::to_string (tr ("Format error (START record expected)")));
|
|
}
|
|
|
|
std::string v = get_str ();
|
|
if (v != "1.0") {
|
|
error (tl::sprintf (tl::to_string (tr ("Format error (only version 1.0 is supported, file has version %s)")), v));
|
|
}
|
|
|
|
double res = get_real ();
|
|
if (res < 1e-6) {
|
|
error (tl::sprintf (tl::to_string (tr ("Invalid resolution of %g")), res));
|
|
}
|
|
|
|
// compute database unit in pixel per meter
|
|
m_dbu = 1.0e-6 / res;
|
|
layout.dbu (m_dbu * 1e6);
|
|
|
|
// read over table offsets if required
|
|
bool table_offsets_at_end = get_uint ();
|
|
if (! table_offsets_at_end) {
|
|
read_offset_table ();
|
|
}
|
|
|
|
// reset the strict mode checking locations
|
|
m_first_cellname = 0;
|
|
m_first_propname = 0;
|
|
m_first_propstring = 0;
|
|
m_first_textstring = 0;
|
|
m_first_layername = 0;
|
|
m_in_table = NotInTable;
|
|
m_table_cellname = 0;
|
|
m_table_propname = 0;
|
|
m_table_propstring = 0;
|
|
m_table_textstring = 0;
|
|
m_table_layername = 0;
|
|
|
|
// define the name id counters
|
|
unsigned long cellname_id = 0;
|
|
unsigned long textstring_id = 0;
|
|
unsigned long propstring_id = 0;
|
|
unsigned long propname_id = 0;
|
|
|
|
// id mode (explicit or implicit)
|
|
enum id_mode { any, expl, impl };
|
|
id_mode cellname_id_mode = any;
|
|
id_mode textstring_id_mode = any;
|
|
id_mode propstring_id_mode = any;
|
|
id_mode propname_id_mode = any;
|
|
|
|
m_cellname_properties.clear ();
|
|
m_textstrings.clear ();
|
|
m_propstrings.clear ();
|
|
m_propnames.clear ();
|
|
|
|
m_instances.clear ();
|
|
m_instances_with_props.clear ();
|
|
|
|
db::PropertiesRepository::properties_set layout_properties;
|
|
|
|
mark_start_table ();
|
|
|
|
// read next record
|
|
while (true) {
|
|
|
|
r = get_byte ();
|
|
|
|
if (r == 0 /*PAD*/) {
|
|
|
|
// simply skip.
|
|
mark_start_table ();
|
|
|
|
} else if (r == 2 /*END*/) {
|
|
|
|
// done
|
|
break;
|
|
|
|
} else if (r == 3 || r == 4 /*CELLNAME*/) {
|
|
|
|
if (m_first_cellname == 0) {
|
|
m_first_cellname = m_table_start;
|
|
} else if (m_expect_strict_mode == 1 && m_in_table != InCELLNAME && m_first_cellname != 0) {
|
|
warn (tl::to_string (tr ("CELLNAME outside table in strict mode")));
|
|
}
|
|
m_in_table = InCELLNAME;
|
|
|
|
// there cannot be more file level properties .. store what we have
|
|
if (! layout_properties.empty ()) {
|
|
layout.prop_id (layout.properties_repository ().properties_id (layout_properties));
|
|
layout_properties.clear ();
|
|
}
|
|
|
|
// read a cell name
|
|
std::string name = get_str ();
|
|
|
|
// and the associated id
|
|
unsigned long id = cellname_id;
|
|
if (r == 3) {
|
|
if (cellname_id_mode == expl) {
|
|
error (tl::to_string (tr ("Explicit and implicit CELLNAME modes cannot be mixed")));
|
|
}
|
|
cellname_id_mode = impl;
|
|
++cellname_id;
|
|
} else {
|
|
if (cellname_id_mode == impl) {
|
|
error (tl::to_string (tr ("Explicit and implicit CELLNAME modes cannot be mixed")));
|
|
}
|
|
cellname_id_mode = expl;
|
|
get (id);
|
|
}
|
|
|
|
rename_cell (layout, id, name);
|
|
|
|
reset_modal_variables ();
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), true);
|
|
if (pp.first) {
|
|
m_cellname_properties.insert (std::make_pair (id, pp.second));
|
|
}
|
|
|
|
} else if (r == 5 || r == 6 /*TEXTSTRING*/) {
|
|
|
|
if (m_first_textstring == 0) {
|
|
m_first_textstring = m_table_start;
|
|
} else if (m_expect_strict_mode == 1 && m_in_table != InTEXTSTRING && m_first_textstring != 0) {
|
|
warn (tl::to_string (tr ("TEXTSTRING outside table in strict mode")));
|
|
}
|
|
m_in_table = InTEXTSTRING;
|
|
|
|
|
|
// there cannot be more file level properties .. store what we have
|
|
if (! layout_properties.empty ()) {
|
|
layout.prop_id (layout.properties_repository ().properties_id (layout_properties));
|
|
layout_properties.clear ();
|
|
}
|
|
|
|
// read a text string
|
|
std::string name = get_str ();
|
|
|
|
// and the associated id
|
|
unsigned long id = textstring_id;
|
|
if (r == 5) {
|
|
if (textstring_id_mode == expl) {
|
|
error (tl::to_string (tr ("Explicit and implicit TEXTSTRING modes cannot be mixed")));
|
|
}
|
|
textstring_id_mode = impl;
|
|
++textstring_id;
|
|
} else {
|
|
if (textstring_id_mode == impl) {
|
|
error (tl::to_string (tr ("Explicit and implicit TEXTSTRING modes cannot be mixed")));
|
|
}
|
|
textstring_id_mode = expl;
|
|
get (id);
|
|
}
|
|
|
|
if (! m_textstrings.insert (std::make_pair (id, name)).second) {
|
|
error (tl::sprintf (tl::to_string (tr ("A TEXTSTRING with id %ld is present already")), id));
|
|
}
|
|
|
|
reset_modal_variables ();
|
|
|
|
// ignore properties attached to this name item
|
|
read_element_properties (layout.properties_repository (), true);
|
|
|
|
} else if (r == 7 || r == 8 /*PROPNAME*/) {
|
|
|
|
if (m_first_propname == 0) {
|
|
m_first_propname = m_table_start;
|
|
} else if (m_expect_strict_mode == 1 && m_in_table != InPROPNAME && m_first_propname != 0) {
|
|
warn (tl::to_string (tr ("PROPNAME outside table in strict mode")));
|
|
}
|
|
m_in_table = InPROPNAME;
|
|
|
|
// there cannot be more file level properties .. store what we have
|
|
if (! layout_properties.empty ()) {
|
|
layout.prop_id (layout.properties_repository ().properties_id (layout_properties));
|
|
layout_properties.clear ();
|
|
}
|
|
|
|
// read a property name
|
|
std::string name = get_str ();
|
|
|
|
// and the associated id
|
|
unsigned long id = propname_id;
|
|
if (r == 7) {
|
|
if (propname_id_mode == expl) {
|
|
error (tl::to_string (tr ("Explicit and implicit PROPNAME modes cannot be mixed")));
|
|
}
|
|
propname_id_mode = impl;
|
|
++propname_id;
|
|
} else {
|
|
if (propname_id_mode == impl) {
|
|
error (tl::to_string (tr ("Explicit and implicit PROPNAME modes cannot be mixed")));
|
|
}
|
|
propname_id_mode = expl;
|
|
get (id);
|
|
}
|
|
|
|
if (! m_propnames.insert (std::make_pair (id, name)).second) {
|
|
error (tl::sprintf (tl::to_string (tr ("A PROPNAME with id %ld is present already")), id));
|
|
}
|
|
|
|
// resolve forward references to property names
|
|
std::map <unsigned long, db::property_names_id_type>::iterator pf = m_propname_forward_references.find (id);
|
|
if (pf != m_propname_forward_references.end ()) {
|
|
|
|
if (name == "S_GDS_PROPERTY") {
|
|
|
|
db::PropertiesRepository &rep = layout.properties_repository ();
|
|
db::property_names_id_type s_gds_name_id = pf->second;
|
|
|
|
// exchange the properties in the repository: first locate all
|
|
// property sets that are affected
|
|
std::vector <db::properties_id_type> pids;
|
|
for (db::PropertiesRepository::iterator p = rep.begin (); p != rep.end (); ++p) {
|
|
if (p->second.find (s_gds_name_id) != p->second.end ()) {
|
|
pids.push_back (p->first);
|
|
}
|
|
}
|
|
|
|
// create new property sets for the ones we found
|
|
for (std::vector <db::properties_id_type>::const_iterator pid = pids.begin (); pid != pids.end (); ++pid) {
|
|
|
|
const db::PropertiesRepository::properties_set &old_set = rep.properties (*pid);
|
|
db::PropertiesRepository::properties_set new_set;
|
|
|
|
for (db::PropertiesRepository::properties_set::const_iterator s = old_set.begin (); s != old_set.end (); ++s) {
|
|
if (s->first == s_gds_name_id) {
|
|
|
|
if (!s->second.is_list () || s->second.get_list ().size () != 2) {
|
|
error (tl::to_string (tr ("S_GDS_PROPERTY must have a value list with exactly two elements")));
|
|
}
|
|
|
|
new_set.insert (std::make_pair (rep.prop_name_id (s->second.get_list () [0]), s->second.get_list () [1]));
|
|
|
|
} else {
|
|
new_set.insert (*s);
|
|
}
|
|
}
|
|
|
|
rep.change_properties (*pid, new_set);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
layout.properties_repository ().change_name (pf->second, tl::Variant (name));
|
|
m_propname_forward_references.erase (pf);
|
|
|
|
}
|
|
|
|
reset_modal_variables ();
|
|
|
|
// ignore properties attached to this name item
|
|
read_element_properties (layout.properties_repository (), true);
|
|
|
|
} else if (r == 9 || r == 10 /*PROPSTRING*/) {
|
|
|
|
if (m_first_propstring == 0) {
|
|
m_first_propstring = m_table_start;
|
|
} else if (m_expect_strict_mode == 1 && m_in_table != InPROPSTRING && m_first_propstring != 0) {
|
|
warn (tl::to_string (tr ("PROPSTRING outside table in strict mode")));
|
|
}
|
|
m_in_table = InPROPSTRING;
|
|
|
|
// there cannot be more file level properties .. store what we have
|
|
if (! layout_properties.empty ()) {
|
|
layout.prop_id (layout.properties_repository ().properties_id (layout_properties));
|
|
layout_properties.clear ();
|
|
}
|
|
|
|
// read a property string
|
|
std::string name = get_str ();
|
|
|
|
// and the associated id
|
|
unsigned long id = propstring_id;
|
|
if (r == 9) {
|
|
if (propstring_id_mode == expl) {
|
|
error (tl::to_string (tr ("Explicit and implicit PROPSTRING modes cannot be mixed")));
|
|
}
|
|
propstring_id_mode = impl;
|
|
++propstring_id;
|
|
} else {
|
|
if (propstring_id_mode == impl) {
|
|
error (tl::to_string (tr ("Explicit and implicit PROPSTRING modes cannot be mixed")));
|
|
}
|
|
propstring_id_mode = expl;
|
|
get (id);
|
|
}
|
|
|
|
if (! m_propstrings.insert (std::make_pair (id, name)).second) {
|
|
error (tl::sprintf (tl::to_string (tr ("A PROPSTRING with id %ld is present already")), id));
|
|
}
|
|
|
|
std::map<unsigned long, std::string>::iterator fw = m_propvalue_forward_references.find (id);
|
|
if (fw != m_propvalue_forward_references.end ()) {
|
|
fw->second = name;
|
|
}
|
|
|
|
reset_modal_variables ();
|
|
|
|
// ignore properties attached to this name item
|
|
read_element_properties (layout.properties_repository (), true);
|
|
|
|
} else if (r == 11 || r == 12 /*LAYERNAME*/) {
|
|
|
|
if (m_first_layername == 0) {
|
|
m_first_layername = m_table_start;
|
|
} else if (m_expect_strict_mode == 1 && m_in_table != InLAYERNAME && m_first_layername != 0) {
|
|
warn (tl::to_string (tr ("LAYERNAME outside table in strict mode")));
|
|
}
|
|
m_in_table = InLAYERNAME;
|
|
|
|
// there cannot be more file level properties .. store what we have
|
|
if (! layout_properties.empty ()) {
|
|
layout.prop_id (layout.properties_repository ().properties_id (layout_properties));
|
|
layout_properties.clear ();
|
|
}
|
|
|
|
// read a layer name
|
|
std::string name = get_str ();
|
|
|
|
db::ld_type dt1 = 0, dt2 = std::numeric_limits<db::ld_type>::max () - 1;
|
|
db::ld_type l1 = 0, l2 = std::numeric_limits<db::ld_type>::max () - 1;
|
|
unsigned int it;
|
|
|
|
it = get_uint ();
|
|
if (it == 0) {
|
|
// keep limits
|
|
} else if (it == 1) {
|
|
l2 = get_uint ();
|
|
} else if (it == 2) {
|
|
l1 = get_uint ();
|
|
} else if (it == 3) {
|
|
l1 = get_uint ();
|
|
l2 = l1;
|
|
} else if (it == 4) {
|
|
l1 = get_uint ();
|
|
l2 = get_uint ();
|
|
} else {
|
|
error (tl::to_string (tr ("Invalid LAYERNAME interval mode (layer)")));
|
|
}
|
|
|
|
it = get_uint ();
|
|
if (it == 0) {
|
|
// keep limits
|
|
} else if (it == 1) {
|
|
dt2 = get_uint ();
|
|
} else if (it == 2) {
|
|
dt1 = get_uint ();
|
|
} else if (it == 3) {
|
|
dt1 = get_uint ();
|
|
dt2 = dt1;
|
|
} else if (it == 4) {
|
|
dt1 = get_uint ();
|
|
dt2 = get_uint ();
|
|
} else {
|
|
error (tl::to_string (tr ("Invalid LAYERNAME interval mode (datatype)")));
|
|
}
|
|
|
|
// add to the layer name map
|
|
tl::interval_map <db::ld_type, std::string> dt_map;
|
|
LNameJoinOp1 op1;
|
|
dt_map.add (dt1, dt2 + 1, name, op1);
|
|
LNameJoinOp2 op2;
|
|
layer_names ().add (l1, l2 + 1, dt_map, op2);
|
|
|
|
reset_modal_variables ();
|
|
|
|
// ignore properties attached to this name item
|
|
read_element_properties (layout.properties_repository (), true);
|
|
|
|
} else if (r == 28 || r == 29 /*PROPERTY*/) {
|
|
|
|
// unrecognized property: store in layout properties
|
|
if (r == 28) {
|
|
read_properties (layout.properties_repository ());
|
|
}
|
|
|
|
store_last_properties (layout.properties_repository (), layout_properties, true);
|
|
|
|
mark_start_table ();
|
|
|
|
} else if (r == 30 || r == 31 /*XNAME*/) {
|
|
|
|
// there cannot be more file level properties .. store what we have
|
|
if (! layout_properties.empty ()) {
|
|
layout.prop_id (layout.properties_repository ().properties_id (layout_properties));
|
|
layout_properties.clear ();
|
|
}
|
|
|
|
// read a XNAME: it is simply ignored
|
|
get_ulong ();
|
|
get_str ();
|
|
if (r == 31) {
|
|
get_ulong ();
|
|
}
|
|
|
|
reset_modal_variables ();
|
|
|
|
// ignore properties attached to this name item
|
|
read_element_properties (layout.properties_repository (), true);
|
|
|
|
} else if (r == 13 || r == 14 /*CELL*/) {
|
|
|
|
m_in_table = NotInTable;
|
|
|
|
// there cannot be more file level properties .. store what we have
|
|
if (! layout_properties.empty ()) {
|
|
layout.prop_id (layout.properties_repository ().properties_id (layout_properties));
|
|
layout_properties.clear ();
|
|
}
|
|
|
|
db::cell_index_type cell_index = 0;
|
|
|
|
// read a cell
|
|
if (r == 13) {
|
|
|
|
unsigned long id = 0;
|
|
get (id);
|
|
|
|
std::pair<bool, db::cell_index_type> cc = cell_by_id (id);
|
|
if (cc.first && ! layout.cell (cc.second).is_ghost_cell ()) {
|
|
error (tl::sprintf (tl::to_string (tr ("A cell with id %ld is defined already")), id));
|
|
}
|
|
|
|
cell_index = make_cell (layout, id);
|
|
|
|
m_cellname = name_for_id (id);
|
|
if (m_cellname.empty ()) {
|
|
m_cellname = std::string ("#") + tl::to_string (id);
|
|
}
|
|
|
|
} else {
|
|
|
|
if (m_expect_strict_mode == 1) {
|
|
warn (tl::to_string (tr ("CELL names must be references to CELLNAME ids in strict mode")));
|
|
}
|
|
|
|
std::string name = get_str ();
|
|
|
|
std::pair<bool, db::cell_index_type> cc = cell_by_name (name);
|
|
if (cc.first && ! layout.cell (cc.second).is_ghost_cell ()) {
|
|
error (tl::sprintf (tl::to_string (tr ("A cell with name %s is defined already")), name.c_str ()));
|
|
}
|
|
|
|
cell_index = make_cell (layout, name);
|
|
|
|
m_cellname = name;
|
|
|
|
}
|
|
|
|
reset_modal_variables ();
|
|
mark_start_table ();
|
|
|
|
do_read_cell (cell_index, layout);
|
|
|
|
} else if (r == 34 /*CBLOCK*/) {
|
|
|
|
unsigned int type = get_uint ();
|
|
if (type != 0) {
|
|
error (tl::sprintf (tl::to_string (tr ("Invalid CBLOCK compression type %d")), type));
|
|
}
|
|
|
|
get_uint (); // uncomp-byte-count - not needed
|
|
get_uint (); // comp-byte-count - not needed
|
|
|
|
// put the stream into deflating mode
|
|
m_stream.inflate ();
|
|
|
|
} else {
|
|
error (tl::sprintf (tl::to_string (tr ("Invalid record type on global level %d")), int (r)));
|
|
}
|
|
|
|
}
|
|
|
|
if (! layout_properties.empty ()) {
|
|
layout.prop_id (layout.properties_repository ().properties_id (layout_properties));
|
|
layout_properties.clear ();
|
|
}
|
|
|
|
size_t pt = m_stream.pos ();
|
|
|
|
if (table_offsets_at_end) {
|
|
read_offset_table ();
|
|
}
|
|
|
|
// read over tail and discard
|
|
mb = (char *) m_stream.get (pt + 254 - m_stream.pos ());
|
|
if (! mb) {
|
|
error (tl::to_string (tr ("Format error (too few bytes after END record)")));
|
|
}
|
|
|
|
// check if there are no more bytes
|
|
mb = (char *) m_stream.get (254);
|
|
if (mb) {
|
|
error (tl::to_string (tr ("Format error (too many bytes after END record)")));
|
|
}
|
|
|
|
for (std::map <unsigned long, const db::StringRef *>::const_iterator fw = m_text_forward_references.begin (); fw != m_text_forward_references.end (); ++fw) {
|
|
std::map <unsigned long, std::string>::const_iterator ts = m_textstrings.find (fw->first);
|
|
if (ts == m_textstrings.end ()) {
|
|
error (tl::sprintf (tl::to_string (tr ("No text string defined for text string id %ld")), fw->first));
|
|
} else {
|
|
layout.string_repository ().change_string_ref (fw->second, ts->second);
|
|
}
|
|
}
|
|
|
|
// all forward references to property names must be resolved
|
|
for (std::map <unsigned long, db::property_names_id_type>::const_iterator fw = m_propname_forward_references.begin (); fw != m_propname_forward_references.end (); ++fw) {
|
|
error (tl::sprintf (tl::to_string (tr ("No property name defined for property name id %ld")), fw->first));
|
|
}
|
|
|
|
// resolve all propvalue forward referenced
|
|
if (! m_propvalue_forward_references.empty ()) {
|
|
|
|
for (db::PropertiesRepository::non_const_iterator pi = layout.properties_repository ().begin_non_const (); pi != layout.properties_repository ().end_non_const (); ++pi) {
|
|
|
|
for (db::PropertiesRepository::properties_set::iterator ps = pi->second.begin (); ps != pi->second.end (); ++ps) {
|
|
|
|
if (ps->second.is_id ()) {
|
|
|
|
unsigned long id = (unsigned long) ps->second.to_id ();
|
|
std::map <unsigned long, std::string>::const_iterator fw = m_propvalue_forward_references.find (id);
|
|
if (fw != m_propvalue_forward_references.end ()) {
|
|
ps->second = tl::Variant (fw->second);
|
|
} else {
|
|
error (tl::sprintf (tl::to_string (tr ("No property value defined for property value id %ld")), id));
|
|
}
|
|
|
|
} else if (ps->second.is_list ()) {
|
|
|
|
// Replace list elements as well
|
|
// TODO: Q: can there be a list of lists? would need recursive replacement -> make that a method of tl::Variant
|
|
|
|
const std::vector<tl::Variant> &l = ps->second.get_list ();
|
|
bool needs_replacement = false;
|
|
for (std::vector<tl::Variant>::const_iterator ll = l.begin (); ll != l.end () && ! needs_replacement; ++ll) {
|
|
needs_replacement = ll->is_id ();
|
|
}
|
|
|
|
if (needs_replacement) {
|
|
|
|
std::vector<tl::Variant> new_list (l);
|
|
for (std::vector<tl::Variant>::iterator ll = new_list.begin (); ll != new_list.end (); ++ll) {
|
|
if (ll->is_id ()) {
|
|
unsigned long id = (unsigned long) ll->to_id ();
|
|
std::map <unsigned long, std::string>::const_iterator fw = m_propvalue_forward_references.find (id);
|
|
if (fw != m_propvalue_forward_references.end ()) {
|
|
*ll = tl::Variant (fw->second);
|
|
} else {
|
|
error (tl::sprintf (tl::to_string (tr ("No property value defined for property value id %ld")), id));
|
|
}
|
|
}
|
|
}
|
|
|
|
ps->second = tl::Variant (new_list.begin (), new_list.end ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
m_propvalue_forward_references.clear ();
|
|
|
|
}
|
|
|
|
// attach the properties found in CELLNAME to the cells (which may have other properties)
|
|
for (std::map<unsigned long, db::properties_id_type>::const_iterator p = m_cellname_properties.begin (); p != m_cellname_properties.end (); ++p) {
|
|
|
|
std::pair<bool, db::cell_index_type> c = cell_by_id (p->first);
|
|
if (c.first) {
|
|
|
|
db::PropertiesRepository::properties_set cnp = layout.properties_repository ().properties (p->second);
|
|
|
|
// Merge existing properties with the ones from CELLNAME
|
|
db::Cell &cell = layout.cell (c.second);
|
|
if (cell.prop_id () != 0) {
|
|
db::PropertiesRepository::properties_set cp = layout.properties_repository ().properties (cell.prop_id ());
|
|
cnp.insert (cp.begin (), cp.end ());
|
|
}
|
|
|
|
cell.prop_id (layout.properties_repository ().properties_id (cnp));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Check the table offsets vs. real occurrence
|
|
if (m_first_cellname != 0 && m_first_cellname != m_table_cellname && m_expect_strict_mode == 1) {
|
|
warn (tl::sprintf (tl::to_string (tr ("CELLNAME table offset does not match first occurrence of CELLNAME in strict mode - %s vs. %s")), m_table_cellname, m_first_cellname));
|
|
}
|
|
if (m_first_propname != 0 && m_first_propname != m_table_propname && m_expect_strict_mode == 1) {
|
|
warn (tl::sprintf (tl::to_string (tr ("PROPNAME table offset does not match first occurrence of PROPNAME in strict mode - %s vs. %s")), m_table_propname, m_first_propname));
|
|
}
|
|
if (m_first_propstring != 0 && m_first_propstring != m_table_propstring && m_expect_strict_mode == 1) {
|
|
warn (tl::sprintf (tl::to_string (tr ("PROPSTRING table offset does not match first occurrence of PROPSTRING in strict mode - %s vs. %s")), m_table_propstring, m_first_propstring));
|
|
}
|
|
if (m_first_layername != 0 && m_first_layername != m_table_layername && m_expect_strict_mode == 1) {
|
|
warn (tl::sprintf (tl::to_string (tr ("LAYERNAME table offset does not match first occurrence of LAYERNAME in strict mode - %s vs. %s")), m_table_layername, m_first_layername));
|
|
}
|
|
if (m_first_textstring != 0 && m_first_textstring != m_table_textstring && m_expect_strict_mode == 1) {
|
|
warn (tl::sprintf (tl::to_string (tr ("TEXTSTRING table offset does not match first occurrence of TEXTSTRING in strict mode - %s vs. %s")), m_table_textstring, m_first_textstring));
|
|
}
|
|
}
|
|
|
|
void
|
|
OASISReader::store_last_properties (db::PropertiesRepository &rep, db::PropertiesRepository::properties_set &properties, bool ignore_special)
|
|
{
|
|
if (! m_read_properties) {
|
|
|
|
// All properties are ignored
|
|
|
|
} else if (mm_last_property_is_sprop.get () && mm_last_property_name.get () == m_s_gds_property_name_id) {
|
|
|
|
if (mm_last_value_list.get ().size () != 2) {
|
|
error (tl::to_string (tr ("S_GDS_PROPERTY must have a value list with exactly two elements")));
|
|
}
|
|
|
|
properties.insert (std::make_pair (rep.prop_name_id (mm_last_value_list.get () [0]), mm_last_value_list.get () [1]));
|
|
|
|
} else if (ignore_special && ! m_read_all_properties && mm_last_property_is_sprop.get ()) {
|
|
|
|
// Special properties are not turned into user properties except S_GDS_PROPERTY.
|
|
// This is mode is used for cells and layouts so the standard properties do not appear as user properties.
|
|
// For shapes we need to keep the special ones since they may be forward-references S_GDS_PROPERTY names.
|
|
|
|
} else if (mm_last_value_list.get ().size () == 0) {
|
|
properties.insert (std::make_pair (mm_last_property_name.get (), tl::Variant ()));
|
|
} else if (mm_last_value_list.get ().size () == 1) {
|
|
properties.insert (std::make_pair (mm_last_property_name.get (), tl::Variant (mm_last_value_list.get () [0])));
|
|
} else if (mm_last_value_list.get ().size () > 1) {
|
|
properties.insert (std::make_pair (mm_last_property_name.get (), tl::Variant (mm_last_value_list.get ().begin (), mm_last_value_list.get ().end ())));
|
|
}
|
|
}
|
|
|
|
std::pair <bool, db::properties_id_type>
|
|
OASISReader::read_element_properties (db::PropertiesRepository &rep, bool ignore_special)
|
|
{
|
|
db::PropertiesRepository::properties_set properties;
|
|
|
|
mark_start_table ();
|
|
|
|
while (true) {
|
|
|
|
unsigned char m = get_byte ();
|
|
|
|
if (m == 0 /*PAD*/) {
|
|
|
|
// skip PAD.
|
|
mark_start_table ();
|
|
|
|
} else if (m == 34 /*CBLOCK*/) {
|
|
|
|
unsigned int type = get_uint ();
|
|
if (type != 0) {
|
|
error (tl::sprintf (tl::to_string (tr ("Invalid CBLOCK compression type %d")), type));
|
|
}
|
|
|
|
get_uint (); // uncomp-byte-count - not needed
|
|
get_uint (); // comp-byte-count - not needed
|
|
|
|
// put the stream into deflating mode
|
|
m_stream.inflate ();
|
|
|
|
} else if (m == 28 /*PROPERTY*/) {
|
|
|
|
read_properties (rep);
|
|
store_last_properties (rep, properties, ignore_special);
|
|
|
|
mark_start_table ();
|
|
|
|
} else if (m == 29 /*PROPERTY*/) {
|
|
|
|
store_last_properties (rep, properties, ignore_special);
|
|
|
|
mark_start_table ();
|
|
|
|
} else {
|
|
|
|
m_stream.unget (1);
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (! properties.empty ()) {
|
|
return std::make_pair (true, rep.properties_id (properties));
|
|
} else {
|
|
return std::make_pair (false, 0);
|
|
}
|
|
}
|
|
|
|
void
|
|
OASISReader::read_properties (db::PropertiesRepository &rep)
|
|
{
|
|
unsigned char m = get_byte ();
|
|
|
|
if (m & 0x04) {
|
|
if (m & 0x02) {
|
|
|
|
unsigned long id;
|
|
get (id);
|
|
|
|
std::map <unsigned long, std::string>::const_iterator cid = m_propnames.find (id);
|
|
if (cid == m_propnames.end ()) {
|
|
mm_last_property_name = rep.prop_name_id (tl::Variant (id, true /*dummy for id type*/));
|
|
m_propname_forward_references.insert (std::make_pair (id, mm_last_property_name.get ()));
|
|
} else {
|
|
mm_last_property_name = rep.prop_name_id (tl::Variant (cid->second));
|
|
}
|
|
|
|
} else {
|
|
|
|
if (m_expect_strict_mode == 1) {
|
|
warn (tl::to_string (tr ("PROPERTY names must be references to PROPNAME ids in strict mode")));
|
|
}
|
|
|
|
mm_last_property_name = rep.prop_name_id (tl::Variant (get_str ()));
|
|
|
|
}
|
|
}
|
|
|
|
mm_last_property_is_sprop = ((m & 0x01) != 0);
|
|
|
|
if (! (m & 0x08)) {
|
|
|
|
unsigned long n = ((unsigned long) (m >> 4)) & 0x0f;
|
|
if (n == 15) {
|
|
get (n);
|
|
}
|
|
|
|
mm_last_value_list.get_non_const ().clear ();
|
|
mm_last_value_list.get_non_const ().reserve (n);
|
|
|
|
while (n > 0) {
|
|
|
|
unsigned char t = get_byte ();
|
|
if (t < 8) {
|
|
|
|
m_stream.unget (1);
|
|
double v = get_real ();
|
|
if (m_read_properties) {
|
|
mm_last_value_list.get_non_const ().push_back (tl::Variant (v));
|
|
}
|
|
|
|
} else if (t == 8) {
|
|
|
|
unsigned long l;
|
|
get (l);
|
|
if (m_read_properties) {
|
|
mm_last_value_list.get_non_const ().push_back (tl::Variant (long (l)));
|
|
}
|
|
|
|
} else if (t == 9) {
|
|
|
|
long l;
|
|
get (l);
|
|
if (m_read_properties) {
|
|
mm_last_value_list.get_non_const ().push_back (tl::Variant (l));
|
|
}
|
|
|
|
} else if (t == 10 || t == 11 || t == 12) {
|
|
|
|
if (m_expect_strict_mode == 1) {
|
|
warn (tl::to_string (tr ("PROPERTY strings must be references to PROPSTRING ids in strict mode")));
|
|
}
|
|
|
|
if (m_read_properties) {
|
|
mm_last_value_list.get_non_const ().push_back (tl::Variant (get_str ()));
|
|
} else {
|
|
get_str ();
|
|
}
|
|
|
|
} else if (t == 13 || t == 14 || t == 15) {
|
|
|
|
unsigned long id;
|
|
get (id);
|
|
if (m_read_properties) {
|
|
std::map <unsigned long, std::string>::const_iterator sid = m_propstrings.find (id);
|
|
if (sid == m_propstrings.end ()) {
|
|
m_propvalue_forward_references.insert (std::make_pair (id, std::string ()));
|
|
mm_last_value_list.get_non_const ().push_back (tl::Variant (id, true /*dummy for id type*/));
|
|
} else {
|
|
mm_last_value_list.get_non_const ().push_back (tl::Variant (sid->second));
|
|
}
|
|
}
|
|
|
|
} else {
|
|
error (tl::sprintf (tl::to_string (tr ("Invalid property value type %d")), int (t)));
|
|
}
|
|
|
|
--n;
|
|
|
|
}
|
|
|
|
mm_last_value_list.set_initialized ();
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void
|
|
OASISReader::read_pointlist (modal_variable <std::vector <db::Point> > &pointlist, bool for_polygon)
|
|
{
|
|
unsigned int type = get_uint ();
|
|
|
|
unsigned long n = 0;
|
|
get (n);
|
|
if (n == 0) {
|
|
error (tl::to_string (tr ("Invalid point list: length is zero")).c_str ());
|
|
}
|
|
|
|
pointlist.get_non_const ().clear ();
|
|
if ((type == 0 || type == 1) && for_polygon) {
|
|
// because for polygons, the pointlist will be closed implicitly
|
|
pointlist.get_non_const ().reserve (n + 2);
|
|
} else {
|
|
pointlist.get_non_const ().reserve (n + 1);
|
|
}
|
|
|
|
pointlist.get_non_const ().push_back (db::Point ());
|
|
|
|
if (type == 0 || type == 1) {
|
|
|
|
bool h = (type == 0);
|
|
|
|
db::Point pos;
|
|
for (unsigned long i = 0; i < n; ++i) {
|
|
db::Coord d = get_coord ();
|
|
if (h) {
|
|
pos += db::Vector (d, 0);
|
|
} else {
|
|
pos += db::Vector (0, d);
|
|
}
|
|
h = ! h;
|
|
pointlist.get_non_const ().push_back (pos);
|
|
}
|
|
|
|
// synthesize the last point for polygons
|
|
if (for_polygon) {
|
|
if ((n % 2) != 0) {
|
|
warn (tl::to_string (tr ("Type 0 or 1 point list with odd number of points is illegal")));
|
|
}
|
|
if (h) {
|
|
pointlist.get_non_const ().push_back (db::Point (0, pos.y ()));
|
|
} else {
|
|
pointlist.get_non_const ().push_back (db::Point (pos.x (), 0));
|
|
}
|
|
}
|
|
|
|
} else if (type == 2) {
|
|
|
|
db::Point pos;
|
|
for (unsigned long i = 0; i < n; ++i) {
|
|
pos += get_2delta ();
|
|
pointlist.get_non_const ().push_back (pos);
|
|
}
|
|
|
|
} else if (type == 3) {
|
|
|
|
db::Point pos;
|
|
for (unsigned long i = 0; i < n; ++i) {
|
|
pos += get_3delta ();
|
|
pointlist.get_non_const ().push_back (pos);
|
|
}
|
|
|
|
} else if (type == 4) {
|
|
|
|
db::Point pos;
|
|
for (unsigned long i = 0; i < n; ++i) {
|
|
pos += get_gdelta ();
|
|
pointlist.get_non_const ().push_back (pos);
|
|
}
|
|
|
|
} else if (type == 5) {
|
|
|
|
db::Point pos;
|
|
db::Vector delta;
|
|
for (unsigned long i = 0; i < n; ++i) {
|
|
delta += get_gdelta ();
|
|
pos += delta;
|
|
pointlist.get_non_const ().push_back (pos);
|
|
}
|
|
|
|
} else {
|
|
error (tl::sprintf (tl::to_string (tr ("Invalid point list type %d")), type));
|
|
}
|
|
|
|
pointlist.set_initialized ();
|
|
}
|
|
|
|
bool
|
|
OASISReader::read_repetition ()
|
|
{
|
|
unsigned char type = get_uint ();
|
|
if (type == 0) {
|
|
|
|
// reuse modal variable
|
|
|
|
} else if (type == 1) {
|
|
|
|
unsigned long nx = 0, ny = 0;
|
|
get (nx);
|
|
get (ny);
|
|
|
|
db::Coord dx = get_ucoord ();
|
|
db::Coord dy = get_ucoord ();
|
|
|
|
mm_repetition = new RegularRepetition (db::Vector (dx, 0), db::Vector (0, dy), dx == 0 ? 1 : nx + 2, dy == 0 ? 1 : ny + 2);
|
|
|
|
} else if (type == 2) {
|
|
|
|
unsigned long nx = 0;
|
|
get (nx);
|
|
|
|
db::Coord dx = get_ucoord ();
|
|
|
|
mm_repetition = new RegularRepetition (db::Vector (dx, 0), db::Vector (0, 0), dx == 0 ? 1 : nx + 2, 1);
|
|
|
|
} else if (type == 3) {
|
|
|
|
unsigned long ny = 0;
|
|
get (ny);
|
|
|
|
db::Coord dy = get_ucoord ();
|
|
|
|
mm_repetition = new RegularRepetition (db::Vector (0, 0), db::Vector (0, dy), 1, dy == 0 ? 1 : ny + 2);
|
|
|
|
} else if (type == 4 || type == 5) {
|
|
|
|
IrregularRepetition *rep = new IrregularRepetition ();
|
|
mm_repetition = rep;
|
|
|
|
unsigned long n = 0;
|
|
get (n);
|
|
|
|
unsigned long lgrid = 1;
|
|
if (type == 5) {
|
|
get (lgrid);
|
|
}
|
|
|
|
rep->reserve (n + 1);
|
|
|
|
db::Coord x = 0;
|
|
for (unsigned long i = 0; i <= n; ++i) {
|
|
m_progress.set (m_stream.pos ());
|
|
db::Coord d = get_ucoord (lgrid);
|
|
if (d != 0) {
|
|
x += d;
|
|
rep->push_back (db::Vector (x, 0));
|
|
}
|
|
}
|
|
|
|
} else if (type == 6 || type == 7) {
|
|
|
|
IrregularRepetition *rep = new IrregularRepetition ();
|
|
mm_repetition = rep;
|
|
|
|
unsigned long n = 0;
|
|
get (n);
|
|
|
|
unsigned long lgrid = 1;
|
|
if (type == 7) {
|
|
get (lgrid);
|
|
}
|
|
|
|
rep->reserve (n + 1);
|
|
|
|
db::Coord y = 0;
|
|
for (unsigned long i = 0; i <= n; ++i) {
|
|
m_progress.set (m_stream.pos ());
|
|
db::Coord d = get_ucoord (lgrid);
|
|
if (d != 0) {
|
|
y += d;
|
|
rep->push_back (db::Vector (0, y));
|
|
}
|
|
}
|
|
|
|
} else if (type == 8) {
|
|
|
|
unsigned long n = 0, m = 0;
|
|
|
|
get (n);
|
|
get (m);
|
|
db::Vector dn = get_gdelta ();
|
|
db::Vector dm = get_gdelta ();
|
|
|
|
mm_repetition = new RegularRepetition (dn, dm, dn == db::Vector () ? 1 : n + 2, dm == db::Vector () ? 1 : m + 2);
|
|
|
|
} else if (type == 9) {
|
|
|
|
unsigned long n = 0;
|
|
get (n);
|
|
db::Vector dn = get_gdelta ();
|
|
|
|
mm_repetition = new RegularRepetition (dn, db::Vector (0, 0), dn == db::Vector () ? 1 : n + 2, 1);
|
|
|
|
} else if (type == 10 || type == 11) {
|
|
|
|
IrregularRepetition *rep = new IrregularRepetition ();
|
|
mm_repetition = rep;
|
|
|
|
unsigned long n = 0;
|
|
get (n);
|
|
|
|
unsigned long grid = 1;
|
|
if (type == 11) {
|
|
get (grid);
|
|
}
|
|
|
|
rep->reserve (n + 1);
|
|
|
|
db::Vector p;
|
|
for (unsigned long i = 0; i <= n; ++i) {
|
|
m_progress.set (m_stream.pos ());
|
|
db::Vector d = get_gdelta (grid);
|
|
if (d != db::Vector ()) {
|
|
p += d;
|
|
rep->push_back (p);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
error (tl::sprintf (tl::to_string (tr ("Invalid repetition type %d")), type));
|
|
}
|
|
|
|
return mm_repetition.get ().size () > 1;
|
|
}
|
|
|
|
void
|
|
OASISReader::do_read_placement (unsigned char r,
|
|
bool xy_absolute,
|
|
db::Layout &layout,
|
|
tl::vector<db::CellInstArray> &instances,
|
|
tl::vector<db::CellInstArrayWithProperties> &instances_with_props)
|
|
{
|
|
unsigned char m = get_byte ();
|
|
|
|
// locate cell
|
|
if (m & 0x80) {
|
|
|
|
if (m & 0x40) {
|
|
|
|
// cell by id
|
|
unsigned long id;
|
|
get (id);
|
|
|
|
mm_placement_cell = cell_for_instance (layout, id);
|
|
|
|
} else {
|
|
|
|
// cell by name
|
|
std::string name;
|
|
get_str (name);
|
|
|
|
mm_placement_cell = cell_for_instance (layout, name);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
double mag = 1.0;
|
|
bool mag_set = false;
|
|
|
|
double angle_deg = 0.0; // only meaningful if angle < 0
|
|
int angle = 0;
|
|
bool mirror = false;
|
|
|
|
if (r == 18) {
|
|
|
|
if (m & 0x04) {
|
|
mag = get_real ();
|
|
if (fabs (mag - 1.0) > 1e-6) {
|
|
mag_set = true;
|
|
}
|
|
}
|
|
|
|
if (m & 0x02) {
|
|
angle_deg = get_real ();
|
|
double a = angle_deg / 90.0;
|
|
if (a < -4 || a > 4) {
|
|
warn (tl::sprintf (tl::to_string (tr ("Invalid rotation angle (%g is less than -360 or larger than 360)")), angle_deg));
|
|
}
|
|
angle = int (a < 0 ? (a - 0.5) : (a + 0.5));
|
|
if (fabs (double (angle) - a) > 1e-6) {
|
|
angle = -1; // indicates arbitrary orientation. Take angle_deg instead
|
|
} else {
|
|
if (angle < 0) {
|
|
angle += ((4 - 1) - angle) & ~(4 - 1);
|
|
}
|
|
angle = angle % 4;
|
|
}
|
|
}
|
|
|
|
} else {
|
|
angle = ((m & 0x06) >> 1);
|
|
}
|
|
|
|
mirror = (m & 0x01) != 0;
|
|
|
|
if (m & 0x20) {
|
|
db::Coord x;
|
|
get (x);
|
|
if (xy_absolute) {
|
|
mm_placement_x = x;
|
|
} else {
|
|
mm_placement_x = x + mm_placement_x.get ();
|
|
}
|
|
}
|
|
|
|
if (m & 0x10) {
|
|
db::Coord y;
|
|
get (y);
|
|
if (xy_absolute) {
|
|
mm_placement_y = y;
|
|
} else {
|
|
mm_placement_y = y + mm_placement_y.get ();
|
|
}
|
|
}
|
|
|
|
db::Vector pos (mm_placement_x.get (), mm_placement_y.get ());
|
|
|
|
const std::vector<db::Vector> *points = 0;
|
|
|
|
if ((m & 0x8) && read_repetition ()) {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
db::Vector a, b;
|
|
size_t na, nb;
|
|
if (mm_repetition.get ().is_regular (a, b, na, nb)) {
|
|
|
|
db::CellInstArray inst;
|
|
|
|
if (mag_set || angle < 0) {
|
|
inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()),
|
|
db::ICplxTrans (mag, angle_deg, mirror, pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb);
|
|
} else {
|
|
inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()),
|
|
db::Trans (angle, mirror, pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb);
|
|
}
|
|
|
|
if (pp.first) {
|
|
instances_with_props.push_back (db::CellInstArrayWithProperties (inst, pp.second));
|
|
} else {
|
|
instances.push_back (inst);
|
|
}
|
|
|
|
} else if (! layout.is_editable () && (points = mm_repetition.get ().is_iterated ()) != 0) {
|
|
|
|
db::CellInstArray inst;
|
|
|
|
if (mag_set || angle < 0) {
|
|
|
|
db::ICplxTrans ct (mag, angle_deg, mirror, pos);
|
|
|
|
db::CellInstArray::iterated_complex_array_type array (ct.rcos (), ct.mag ());
|
|
array.reserve (points->size () + 1);
|
|
array.insert (db::Vector ());
|
|
array.insert (points->begin (), points->end ());
|
|
array.sort ();
|
|
|
|
inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()),
|
|
db::Trans (ct), layout.array_repository ().insert (array));
|
|
|
|
} else {
|
|
|
|
db::CellInstArray::iterated_array_type array;
|
|
array.reserve (points->size () + 1);
|
|
array.insert (db::Vector ());
|
|
array.insert (points->begin (), points->end ());
|
|
array.sort ();
|
|
|
|
inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()),
|
|
db::Trans (angle, mirror, pos), layout.array_repository ().insert (array));
|
|
|
|
}
|
|
|
|
if (pp.first) {
|
|
instances_with_props.push_back (db::CellInstArrayWithProperties (inst, pp.second));
|
|
} else {
|
|
instances.push_back (inst);
|
|
}
|
|
|
|
} else {
|
|
|
|
RepetitionIterator p = mm_repetition.get ().begin ();
|
|
while (! p.at_end ()) {
|
|
|
|
db::CellInstArray inst;
|
|
|
|
if (mag_set || angle < 0) {
|
|
inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()), db::ICplxTrans (mag, angle_deg, mirror, pos + *p));
|
|
} else {
|
|
inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()), db::Trans (angle, mirror, pos + *p));
|
|
}
|
|
|
|
if (pp.first) {
|
|
instances_with_props.push_back (db::CellInstArrayWithProperties (inst, pp.second));
|
|
} else {
|
|
instances.push_back (inst);
|
|
}
|
|
|
|
++p;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
db::CellInstArray inst;
|
|
|
|
if (mag_set || angle < 0) {
|
|
inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()), db::ICplxTrans (mag, angle_deg, mirror, pos));
|
|
} else {
|
|
inst = db::CellInstArray (db::CellInst (mm_placement_cell.get ()), db::Trans (angle, mirror, pos));
|
|
}
|
|
|
|
if (pp.first) {
|
|
instances_with_props.push_back (db::CellInstArrayWithProperties (inst, pp.second));
|
|
} else {
|
|
instances.push_back (inst);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
OASISReader::do_read_text (bool xy_absolute,
|
|
db::cell_index_type cell_index,
|
|
db::Layout &layout)
|
|
{
|
|
unsigned char m = get_byte ();
|
|
|
|
if (m & 0x40) {
|
|
if (m & 0x20) {
|
|
|
|
unsigned long id;
|
|
get (id);
|
|
|
|
if (m_text_forward_references.find (id) != m_text_forward_references.end ()) {
|
|
|
|
mm_text_string.reset ();
|
|
mm_text_string_id = id;
|
|
|
|
} else {
|
|
|
|
std::map <unsigned long, std::string>::const_iterator tid = m_textstrings.find (id);
|
|
if (tid == m_textstrings.end ()) {
|
|
|
|
mm_text_string.reset ();
|
|
mm_text_string_id = id;
|
|
|
|
const db::StringRef *string_ref = layout.string_repository ().create_string_ref ();
|
|
m_text_forward_references.insert (std::make_pair (id, string_ref));
|
|
|
|
} else {
|
|
|
|
mm_text_string = tid->second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (m_expect_strict_mode == 1) {
|
|
warn (tl::to_string (tr ("TEXT strings must be references to TEXTSTRING ids in strict mode")));
|
|
}
|
|
|
|
mm_text_string = get_str ();
|
|
|
|
}
|
|
}
|
|
|
|
if (m & 0x1) {
|
|
mm_textlayer = get_uint ();
|
|
}
|
|
|
|
if (m & 0x2) {
|
|
mm_texttype = get_uint ();
|
|
}
|
|
|
|
if (m & 0x10) {
|
|
db::Coord x;
|
|
get (x);
|
|
if (xy_absolute) {
|
|
mm_text_x = x;
|
|
} else {
|
|
mm_text_x = x + mm_text_x.get ();
|
|
}
|
|
}
|
|
|
|
if (m & 0x8) {
|
|
db::Coord y;
|
|
get (y);
|
|
if (xy_absolute) {
|
|
mm_text_y = y;
|
|
} else {
|
|
mm_text_y = y + mm_text_y.get ();
|
|
}
|
|
}
|
|
|
|
db::Vector pos (mm_text_x.get (), mm_text_y.get ());
|
|
|
|
std::pair<bool, unsigned int> ll (false, 0);
|
|
if (m_read_texts) {
|
|
ll = open_dl (layout, LDPair (mm_textlayer.get (), mm_texttype.get ()));
|
|
}
|
|
|
|
if ((m & 0x4) && read_repetition ()) {
|
|
|
|
// TODO: should not read properties if layer is not enabled!
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
db::Text text;
|
|
if (mm_text_string_id.is_set ()) {
|
|
text = db::Text (m_text_forward_references.find (mm_text_string_id.get ())->second, db::Trans ());
|
|
} else {
|
|
text = db::Text (mm_text_string.get (), db::Trans ());
|
|
}
|
|
|
|
db::Cell &cell = layout.cell (cell_index);
|
|
|
|
const std::vector<db::Vector> *points = 0;
|
|
|
|
// If the repetition is a regular one, convert the repetition into
|
|
// a shape array
|
|
db::Vector a, b;
|
|
size_t na, nb;
|
|
if (! layout.is_editable () && mm_repetition.get ().is_regular (a, b, na, nb)) {
|
|
|
|
db::TextPtr text_ptr (text, layout.shape_repository ());
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::Shape::text_ptr_array_type> (db::Shape::text_ptr_array_type (text_ptr, db::Disp (pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::Shape::text_ptr_array_type (text_ptr, db::Disp (pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb));
|
|
}
|
|
|
|
} else if (! layout.is_editable () && (points = mm_repetition.get ().is_iterated ()) != 0) {
|
|
|
|
db::TextPtr text_ptr (text, layout.shape_repository ());
|
|
|
|
// Create an iterated text array
|
|
db::Shape::text_ptr_array_type::iterated_array_type array;
|
|
array.reserve (points->size () + 1);
|
|
array.insert (db::Vector ());
|
|
array.insert (points->begin (), points->end ());
|
|
array.sort ();
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::Shape::text_ptr_array_type> (db::Shape::text_ptr_array_type (text_ptr, db::Disp (pos), layout.array_repository ().insert (array)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::Shape::text_ptr_array_type (text_ptr, db::Disp (pos), layout.array_repository ().insert (array)));
|
|
}
|
|
|
|
} else {
|
|
|
|
RepetitionIterator p = mm_repetition.get ().begin ();
|
|
db::TextRef text_ref (text, layout.shape_repository ());
|
|
while (! p.at_end ()) {
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::TextRefWithProperties (text_ref.transformed (db::Disp (pos + *p)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (text_ref.transformed (db::Disp (pos + *p)));
|
|
}
|
|
++p;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
db::Text text;
|
|
if (mm_text_string_id.is_set ()) {
|
|
text = db::Text (m_text_forward_references.find (mm_text_string_id.get ())->second, db::Trans (pos));
|
|
} else {
|
|
text = db::Text (mm_text_string.get (), db::Trans (pos));
|
|
}
|
|
|
|
if (pp.first) {
|
|
layout.cell (cell_index).shapes (ll.second).insert (db::TextRefWithProperties (db::TextRef (text, layout.shape_repository ()), pp.second));
|
|
} else {
|
|
layout.cell (cell_index).shapes (ll.second).insert (db::TextRef (text, layout.shape_repository ()));
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
OASISReader::do_read_rectangle (bool xy_absolute,
|
|
db::cell_index_type cell_index,
|
|
db::Layout &layout)
|
|
{
|
|
unsigned char m = get_byte ();
|
|
|
|
if (m & 0x1) {
|
|
mm_layer = get_uint ();
|
|
}
|
|
|
|
if (m & 0x2) {
|
|
mm_datatype = get_uint ();
|
|
}
|
|
|
|
if (m & 0x40) {
|
|
mm_geometry_w = get_ucoord_as_distance ();
|
|
}
|
|
if (m & 0x80) {
|
|
mm_geometry_h = mm_geometry_w; // TODO: really?
|
|
} else {
|
|
if (m & 0x20) {
|
|
mm_geometry_h = get_ucoord_as_distance ();
|
|
}
|
|
}
|
|
|
|
if (m & 0x10) {
|
|
db::Coord x;
|
|
get (x);
|
|
if (xy_absolute) {
|
|
mm_geometry_x = x;
|
|
} else {
|
|
mm_geometry_x = x + mm_geometry_x.get ();
|
|
}
|
|
}
|
|
|
|
if (m & 0x8) {
|
|
db::Coord y;
|
|
get (y);
|
|
if (xy_absolute) {
|
|
mm_geometry_y = y;
|
|
} else {
|
|
mm_geometry_y = y + mm_geometry_y.get ();
|
|
}
|
|
}
|
|
|
|
db::Box box (db::Point (mm_geometry_x.get (), mm_geometry_y.get ()),
|
|
db::Point (mm_geometry_x.get () + mm_geometry_w.get (), mm_geometry_y.get () + mm_geometry_h.get ()));
|
|
|
|
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()));
|
|
|
|
if ((m & 0x4) && read_repetition ()) {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
db::Cell &cell = layout.cell (cell_index);
|
|
|
|
const std::vector<db::Vector> *points = 0;
|
|
|
|
// If the repetition is a regular one, convert the repetition into
|
|
// a box array
|
|
db::Vector a, b;
|
|
size_t na, nb;
|
|
if (! layout.is_editable () && mm_repetition.get ().is_regular (a, b, na, nb)) {
|
|
|
|
// Create a box array
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::Shape::box_array_type> (db::Shape::box_array_type (box, db::UnitTrans (), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::Shape::box_array_type (box, db::UnitTrans (), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb));
|
|
}
|
|
|
|
} else if (! layout.is_editable () && (points = mm_repetition.get ().is_iterated ()) != 0) {
|
|
|
|
// Create an iterated box array
|
|
db::Shape::box_array_type::iterated_array_type array;
|
|
array.reserve (points->size () + 1);
|
|
array.insert (db::Vector ());
|
|
array.insert (points->begin (), points->end ());
|
|
array.sort ();
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::Shape::box_array_type> (db::Shape::box_array_type (box, db::UnitTrans (), layout.array_repository ().insert (array)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::Shape::box_array_type (box, db::UnitTrans (), layout.array_repository ().insert (array)));
|
|
}
|
|
|
|
} else {
|
|
|
|
// convert the OASIS record into the rectangle one by one.
|
|
RepetitionIterator p = mm_repetition.get ().begin ();
|
|
while (! p.at_end ()) {
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::BoxWithProperties (box.moved (*p), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (box.moved (*p));
|
|
}
|
|
++p;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
db::Cell &cell = layout.cell (cell_index);
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::BoxWithProperties (box, pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (box);
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
OASISReader::do_read_polygon (bool xy_absolute, db::cell_index_type cell_index, db::Layout &layout)
|
|
{
|
|
unsigned char m = get_byte ();
|
|
|
|
if (m & 0x1) {
|
|
mm_layer = get_uint ();
|
|
}
|
|
|
|
if (m & 0x2) {
|
|
mm_datatype = get_uint ();
|
|
}
|
|
|
|
if (m & 0x20) {
|
|
read_pointlist (mm_polygon_point_list, true);
|
|
}
|
|
|
|
if (m & 0x10) {
|
|
db::Coord x;
|
|
get (x);
|
|
if (xy_absolute) {
|
|
mm_geometry_x = x;
|
|
} else {
|
|
mm_geometry_x = x + mm_geometry_x.get ();
|
|
}
|
|
}
|
|
|
|
if (m & 0x8) {
|
|
db::Coord y;
|
|
get (y);
|
|
if (xy_absolute) {
|
|
mm_geometry_y = y;
|
|
} else {
|
|
mm_geometry_y = y + mm_geometry_y.get ();
|
|
}
|
|
}
|
|
|
|
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
|
|
|
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()));
|
|
|
|
if ((m & 0x4) && read_repetition ()) {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
db::Cell &cell = layout.cell (cell_index);
|
|
|
|
if (mm_polygon_point_list.get ().size () < 3) {
|
|
warn (tl::to_string (tr ("POLYGON with less than 3 points ignored")));
|
|
} else {
|
|
|
|
// convert the OASIS record into the polygon.
|
|
db::SimplePolygon poly;
|
|
poly.assign_hull (mm_polygon_point_list.get ().begin (), mm_polygon_point_list.get ().end (), false /*no compression*/);
|
|
|
|
const std::vector<db::Vector> *points = 0;
|
|
|
|
// If the repetition is a regular one, convert the repetition into
|
|
// a shape array
|
|
db::Vector a, b;
|
|
size_t na, nb;
|
|
if (! layout.is_editable () && mm_repetition.get ().is_regular (a, b, na, nb)) {
|
|
|
|
// creating a SimplePolygonPtr is most efficient with a normalized polygon because no displacement is provided
|
|
db::Vector d (poly.box ().lower_left () - db::Point ());
|
|
poly.move (-d);
|
|
db::SimplePolygonPtr poly_ptr (poly, layout.shape_repository ());
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::array<db::SimplePolygonPtr, db::Disp> > (db::array<db::SimplePolygonPtr, db::Disp> (poly_ptr, db::Disp (d + pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::array<db::SimplePolygonPtr, db::Disp> (poly_ptr, db::Disp (d + pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb));
|
|
}
|
|
|
|
} else if (! layout.is_editable () && (points = mm_repetition.get ().is_iterated ()) != 0) {
|
|
|
|
db::Vector d (poly.box ().lower_left () - db::Point ());
|
|
poly.move (-d);
|
|
db::SimplePolygonPtr poly_ptr (poly, layout.shape_repository ());
|
|
|
|
// Create an iterated simple polygon array
|
|
db::Shape::simple_polygon_ptr_array_type::iterated_array_type array;
|
|
array.reserve (points->size () + 1);
|
|
array.insert (db::Vector ());
|
|
array.insert (points->begin (), points->end ());
|
|
array.sort ();
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::Shape::simple_polygon_ptr_array_type> (db::Shape::simple_polygon_ptr_array_type (poly_ptr, db::Disp (d + pos), layout.array_repository ().insert (array)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::Shape::simple_polygon_ptr_array_type (poly_ptr, db::Disp (d + pos), layout.array_repository ().insert (array)));
|
|
}
|
|
|
|
} else {
|
|
|
|
db::SimplePolygonRef poly_ref (poly, layout.shape_repository ());
|
|
|
|
RepetitionIterator p = mm_repetition.get ().begin ();
|
|
while (! p.at_end ()) {
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::SimplePolygonRefWithProperties (poly_ref.transformed (db::Disp (pos + *p)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (poly_ref.transformed (db::Disp (pos + *p)));
|
|
}
|
|
++p;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
if (mm_polygon_point_list.get ().size () < 3) {
|
|
warn (tl::to_string (tr ("POLYGON with less than 3 points ignored")));
|
|
} else {
|
|
|
|
// convert the OASIS record into the polygon.
|
|
db::SimplePolygon poly;
|
|
poly.assign_hull (mm_polygon_point_list.get ().begin (), mm_polygon_point_list.get ().end (), false /*no compression*/);
|
|
db::SimplePolygonRef poly_ref (poly, layout.shape_repository ());
|
|
|
|
if (pp.first) {
|
|
layout.cell (cell_index).shapes (ll.second).insert (db::SimplePolygonRefWithProperties (poly_ref.transformed (db::Disp (pos)), pp.second));
|
|
} else {
|
|
layout.cell (cell_index).shapes (ll.second).insert (poly_ref.transformed (db::Disp (pos)));
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
OASISReader::do_read_path (bool xy_absolute, db::cell_index_type cell_index, db::Layout &layout)
|
|
{
|
|
unsigned char m = get_byte ();
|
|
|
|
if (m & 0x1) {
|
|
mm_layer = get_uint ();
|
|
}
|
|
|
|
if (m & 0x2) {
|
|
mm_datatype = get_uint ();
|
|
}
|
|
|
|
if (m & 0x40) {
|
|
mm_path_halfwidth = get_ucoord_as_distance ();
|
|
}
|
|
|
|
if (m & 0x80) {
|
|
|
|
unsigned int e = get_uint ();
|
|
if ((e & 0x0c) == 0x0c) {
|
|
mm_path_start_extension = get_coord ();
|
|
} else if ((e & 0x0c) == 0x04) {
|
|
mm_path_start_extension = 0; // TODO: is setting the start extension modal variable correct here?
|
|
} else if ((e & 0x0c) == 0x08) {
|
|
mm_path_start_extension = mm_path_halfwidth.get (); // TODO: is setting the start extension modal variable correct here?
|
|
}
|
|
if ((e & 0x03) == 0x03) {
|
|
mm_path_end_extension = get_coord ();
|
|
} else if ((e & 0x03) == 0x01) {
|
|
mm_path_end_extension = 0; // TODO: is setting the start extension modal variable correct here?
|
|
} else if ((e & 0x03) == 0x02) {
|
|
mm_path_end_extension = mm_path_halfwidth.get (); // TODO: is setting the start extension modal variable correct here?
|
|
}
|
|
|
|
}
|
|
|
|
if (m & 0x20) {
|
|
read_pointlist (mm_path_point_list, false);
|
|
}
|
|
|
|
if (m & 0x10) {
|
|
db::Coord x;
|
|
get (x);
|
|
if (xy_absolute) {
|
|
mm_geometry_x = x;
|
|
} else {
|
|
mm_geometry_x = x + mm_geometry_x.get ();
|
|
}
|
|
}
|
|
|
|
if (m & 0x8) {
|
|
db::Coord y;
|
|
get (y);
|
|
if (xy_absolute) {
|
|
mm_geometry_y = y;
|
|
} else {
|
|
mm_geometry_y = y + mm_geometry_y.get ();
|
|
}
|
|
}
|
|
|
|
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
|
|
|
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()));
|
|
|
|
if ((m & 0x4) && read_repetition ()) {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
if (mm_path_point_list.get ().size () < 2) {
|
|
warn (tl::to_string (tr ("POLYGON with less than 2 points ignored")));
|
|
} else {
|
|
|
|
// convert the OASIS record into the path.
|
|
db::Path path;
|
|
path.width (2 * mm_path_halfwidth.get ());
|
|
path.extensions (mm_path_start_extension.get (), mm_path_end_extension.get ());
|
|
path.assign (mm_path_point_list.get ().begin (), mm_path_point_list.get ().end ());
|
|
|
|
db::Cell &cell = layout.cell (cell_index);
|
|
|
|
const std::vector<db::Vector> *points = 0;
|
|
|
|
// If the repetition is a regular one, convert the repetition into
|
|
// a shape array
|
|
db::Vector a, b;
|
|
size_t na, nb;
|
|
if (! layout.is_editable () && mm_repetition.get ().is_regular (a, b, na, nb)) {
|
|
|
|
// creating a PathPtr is most efficient with a normalized path because no displacement is provided
|
|
db::Vector d (*path.begin ());
|
|
path.move (-d);
|
|
db::PathPtr path_ptr (path, layout.shape_repository ());
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::array<db::PathPtr, db::Disp> > (db::array<db::PathPtr, db::Disp> (path_ptr, db::Disp (d + pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::array<db::PathPtr, db::Disp> (path_ptr, db::Disp (d + pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb));
|
|
}
|
|
|
|
} else if (! layout.is_editable () && (points = mm_repetition.get ().is_iterated ()) != 0) {
|
|
|
|
db::Vector d (*path.begin () - db::Point ());
|
|
path.move (-d);
|
|
db::PathPtr path_ptr (path, layout.shape_repository ());
|
|
|
|
// Create an iterated simple polygon array
|
|
db::Shape::path_ptr_array_type::iterated_array_type array;
|
|
array.reserve (points->size () + 1);
|
|
array.insert (db::Vector ());
|
|
array.insert (points->begin (), points->end ());
|
|
array.sort ();
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::Shape::path_ptr_array_type> (db::Shape::path_ptr_array_type (path_ptr, db::Disp (d + pos), layout.array_repository ().insert (array)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::Shape::path_ptr_array_type (path_ptr, db::Disp (d + pos), layout.array_repository ().insert (array)));
|
|
}
|
|
|
|
} else {
|
|
|
|
db::PathRef path_ref (path, layout.shape_repository ());
|
|
|
|
RepetitionIterator p = mm_repetition.get ().begin ();
|
|
while (! p.at_end ()) {
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::PathRefWithProperties (path_ref.transformed (db::Disp (pos + *p)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (path_ref.transformed (db::Disp (pos + *p)));
|
|
}
|
|
++p;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
if (mm_path_point_list.get ().size () < 2) {
|
|
warn (tl::to_string (tr ("PATH with less than 2 points ignored")));
|
|
} else {
|
|
|
|
// convert the OASIS record into the path.
|
|
db::Path path;
|
|
path.width (2 * mm_path_halfwidth.get ());
|
|
path.extensions (mm_path_start_extension.get (), mm_path_end_extension.get ());
|
|
path.assign (mm_path_point_list.get ().begin (), mm_path_point_list.get ().end ());
|
|
db::PathRef path_ref (path, layout.shape_repository ());
|
|
|
|
if (pp.first) {
|
|
layout.cell (cell_index).shapes (ll.second).insert (db::PathRefWithProperties (path_ref.transformed (db::Disp (pos)), pp.second));
|
|
} else {
|
|
layout.cell (cell_index).shapes (ll.second).insert (path_ref.transformed (db::Disp (pos)));
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
OASISReader::do_read_trapezoid (unsigned char r, bool xy_absolute,db::cell_index_type cell_index, db::Layout &layout)
|
|
{
|
|
unsigned char m = get_byte ();
|
|
|
|
if (m & 0x1) {
|
|
mm_layer = get_uint ();
|
|
}
|
|
|
|
if (m & 0x2) {
|
|
mm_datatype = get_uint ();
|
|
}
|
|
|
|
if (m & 0x40) {
|
|
mm_geometry_w = get_ucoord_as_distance ();
|
|
}
|
|
|
|
if (m & 0x20) {
|
|
mm_geometry_h = get_ucoord_as_distance ();
|
|
}
|
|
|
|
db::Coord delta_a = 0, delta_b = 0;
|
|
if (r == 23 || r == 24) {
|
|
delta_a = get_coord ();
|
|
}
|
|
if (r == 23 || r == 25) {
|
|
delta_b = get_coord ();
|
|
}
|
|
|
|
if (m & 0x10) {
|
|
db::Coord x;
|
|
get (x);
|
|
if (xy_absolute) {
|
|
mm_geometry_x = x;
|
|
} else {
|
|
mm_geometry_x = x + mm_geometry_x.get ();
|
|
}
|
|
}
|
|
|
|
if (m & 0x8) {
|
|
db::Coord y;
|
|
get (y);
|
|
if (xy_absolute) {
|
|
mm_geometry_y = y;
|
|
} else {
|
|
mm_geometry_y = y + mm_geometry_y.get ();
|
|
}
|
|
}
|
|
|
|
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
|
|
|
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()));
|
|
|
|
db::Point pts [4];
|
|
|
|
if (m & 0x80) {
|
|
// vertically
|
|
pts [0] = db::Point (0, std::max (delta_a, db::Coord (0)));
|
|
pts [1] = db::Point (0, mm_geometry_h.get () + std::min (delta_b, db::Coord (0)));
|
|
pts [2] = db::Point (mm_geometry_w.get (), mm_geometry_h.get () - std::max (delta_b, db::Coord (0)));
|
|
pts [3] = db::Point (mm_geometry_w.get (), -std::min (delta_a, db::Coord (0)));
|
|
} else {
|
|
// horizontally
|
|
pts [0] = db::Point (std::max (delta_a, db::Coord (0)), mm_geometry_h.get ());
|
|
pts [1] = db::Point (mm_geometry_w.get () + std::min (delta_b, db::Coord (0)), mm_geometry_h.get ());
|
|
pts [2] = db::Point (mm_geometry_w.get () - std::max (delta_b, db::Coord (0)), db::Coord (0));
|
|
pts [3] = db::Point (-std::min (delta_a, db::Coord (0)), db::Coord (0));
|
|
}
|
|
|
|
if ((m & 0x4) && read_repetition ()) {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
// convert the OASIS record into the polygon.
|
|
db::SimplePolygon poly;
|
|
poly.assign_hull (pts, pts + 4, false /*no compression*/);
|
|
|
|
db::Cell &cell = layout.cell (cell_index);
|
|
|
|
const std::vector<db::Vector> *points = 0;
|
|
|
|
// If the repetition is a regular one, convert the repetition into
|
|
// a shape array
|
|
db::Vector a, b;
|
|
size_t na, nb;
|
|
if (! layout.is_editable () && mm_repetition.get ().is_regular (a, b, na, nb)) {
|
|
|
|
// creating a SimplePolygonPtr is most efficient with a normalized polygon because no displacement is provided
|
|
db::Vector d (poly.box ().lower_left ());
|
|
poly.move (-d);
|
|
db::SimplePolygonPtr poly_ptr (poly, layout.shape_repository ());
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::array<db::SimplePolygonPtr, db::Disp> > (db::array<db::SimplePolygonPtr, db::Disp> (poly_ptr, db::Disp (d + pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::array<db::SimplePolygonPtr, db::Disp> (poly_ptr, db::Disp (d + pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb));
|
|
}
|
|
|
|
} else if (! layout.is_editable () && (points = mm_repetition.get ().is_iterated ()) != 0) {
|
|
|
|
db::Vector d (poly.box ().lower_left () - db::Point ());
|
|
poly.move (-d);
|
|
db::SimplePolygonPtr poly_ptr (poly, layout.shape_repository ());
|
|
|
|
// Create an iterated simple polygon array
|
|
db::Shape::simple_polygon_ptr_array_type::iterated_array_type array;
|
|
array.reserve (points->size () + 1);
|
|
array.insert (db::Vector ());
|
|
array.insert (points->begin (), points->end ());
|
|
array.sort ();
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::Shape::simple_polygon_ptr_array_type> (db::Shape::simple_polygon_ptr_array_type (poly_ptr, db::Disp (d + pos), layout.array_repository ().insert (array)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::Shape::simple_polygon_ptr_array_type (poly_ptr, db::Disp (d + pos), layout.array_repository ().insert (array)));
|
|
}
|
|
|
|
} else {
|
|
|
|
db::SimplePolygonRef poly_ref (poly, layout.shape_repository ());
|
|
|
|
RepetitionIterator p = mm_repetition.get ().begin ();
|
|
while (! p.at_end ()) {
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::SimplePolygonRefWithProperties (poly_ref.transformed (db::Disp (pos + *p)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (poly_ref.transformed (db::Disp (pos + *p)));
|
|
}
|
|
++p;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
// convert the OASIS record into the polygon.
|
|
db::SimplePolygon poly;
|
|
poly.assign_hull (pts, pts + 4, false /*no compression*/);
|
|
db::SimplePolygonRef poly_ref (poly, layout.shape_repository ());
|
|
|
|
if (pp.first) {
|
|
layout.cell (cell_index).shapes (ll.second).insert (SimplePolygonRefWithProperties (poly_ref.transformed (db::Disp (pos)), pp.second));
|
|
} else {
|
|
layout.cell (cell_index).shapes (ll.second).insert (poly_ref.transformed (db::Disp (pos)));
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
OASISReader::do_read_ctrapezoid (bool xy_absolute,db::cell_index_type cell_index, db::Layout &layout)
|
|
{
|
|
unsigned char m = get_byte ();
|
|
|
|
if (m & 0x1) {
|
|
mm_layer = get_uint ();
|
|
}
|
|
|
|
if (m & 0x2) {
|
|
mm_datatype = get_uint ();
|
|
}
|
|
|
|
if (m & 0x80) {
|
|
mm_ctrapezoid_type = get_uint ();
|
|
}
|
|
|
|
if (m & 0x40) {
|
|
mm_geometry_w = get_ucoord_as_distance ();
|
|
}
|
|
|
|
if (m & 0x20) {
|
|
mm_geometry_h = get_ucoord_as_distance ();
|
|
}
|
|
|
|
if (m & 0x10) {
|
|
db::Coord x;
|
|
get (x);
|
|
if (xy_absolute) {
|
|
mm_geometry_x = x;
|
|
} else {
|
|
mm_geometry_x = x + mm_geometry_x.get ();
|
|
}
|
|
}
|
|
|
|
if (m & 0x8) {
|
|
db::Coord y;
|
|
get (y);
|
|
if (xy_absolute) {
|
|
mm_geometry_y = y;
|
|
} else {
|
|
mm_geometry_y = y + mm_geometry_y.get ();
|
|
}
|
|
}
|
|
|
|
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
|
|
|
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()));
|
|
|
|
db::Point pts [4];
|
|
|
|
static db::Coord ctraps_table[][4][4] = {
|
|
// type 0
|
|
{
|
|
{ 0, 0, 0, 0 }, // x=0*w+0*h, y=0*w+0*h ...
|
|
{ 0, 0, 0, 1 },
|
|
{ 1, -1, 0, 1 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
// type 1
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 1 },
|
|
{ 1, 0, 0, 1 },
|
|
{ 1, -1, 0, 0 }
|
|
},
|
|
// type 2
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 1, 0, 1 },
|
|
{ 1, 0, 0, 1 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
// type 3
|
|
{
|
|
{ 0, 1, 0, 0 },
|
|
{ 0, 0, 0, 1 },
|
|
{ 1, 0, 0, 1 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
// type 4
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 1, 0, 1 },
|
|
{ 1, -1, 0, 1 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
// type 5
|
|
{
|
|
{ 0, 1, 0, 0 },
|
|
{ 0, 0, 0, 1 },
|
|
{ 1, 0, 0, 1 },
|
|
{ 1, -1, 0, 0 }
|
|
},
|
|
// type 6
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 1, 0, 1 },
|
|
{ 1, 0, 0, 1 },
|
|
{ 1, -1, 0, 0 }
|
|
},
|
|
// type 7
|
|
{
|
|
{ 0, 1, 0, 0 },
|
|
{ 0, 0, 0, 1 },
|
|
{ 1, -1, 0, 1 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
// type 8
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 1 },
|
|
{ 1, 0, -1, 1 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
// type 9
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, -1, 1 },
|
|
{ 1, 0, 0, 1 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
// type 10
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 1 },
|
|
{ 1, 0, 0, 1 },
|
|
{ 1, 0, 1, 0 }
|
|
},
|
|
// type 11
|
|
{
|
|
{ 0, 0, 1, 0 },
|
|
{ 0, 0, 0, 1 },
|
|
{ 1, 0, 0, 1 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
// type 12
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 1 },
|
|
{ 1, 0, -1, 1 },
|
|
{ 1, 0, 1, 0 }
|
|
},
|
|
// type 13
|
|
{
|
|
{ 0, 0, 1, 0 },
|
|
{ 0, 0, -1, 1 },
|
|
{ 1, 0, 0, 1 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
// type 14
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, -1, 1 },
|
|
{ 1, 0, 0, 1 },
|
|
{ 1, 0, 1, 0 }
|
|
},
|
|
// type 15
|
|
{
|
|
{ 0, 0, 1, 0 },
|
|
{ 0, 0, 0, 1 },
|
|
{ 1, 0, -1, 1 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
// type 16
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 1, 0 },
|
|
{ 1, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 }
|
|
},
|
|
// type 17
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 1, 0 },
|
|
{ 1, 0, 1, 0 },
|
|
{ 0, 0, 0, 0 }
|
|
},
|
|
// type 18
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 1, 0, 1, 0 },
|
|
{ 1, 0, 0, 0 },
|
|
{ 0, 0, 0, 0 }
|
|
},
|
|
// type 19
|
|
{
|
|
{ 0, 0, 1, 0 },
|
|
{ 1, 0, 1, 0 },
|
|
{ 1, 0, 0, 0 },
|
|
{ 0, 0, 1, 0 }
|
|
},
|
|
// type 20
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 1, 0, 1 },
|
|
{ 0, 2, 0, 0 },
|
|
{ 0, 0, 0, 0 }
|
|
},
|
|
// type 21
|
|
{
|
|
{ 0, 0, 0, 1 },
|
|
{ 0, 2, 0, 1 },
|
|
{ 0, 1, 0, 0 },
|
|
{ 0, 0, 0, 1 }
|
|
},
|
|
// type 22
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 2, 0 },
|
|
{ 1, 0, 1, 0 },
|
|
{ 0, 0, 0, 0 }
|
|
},
|
|
// type 23
|
|
{
|
|
{ 1, 0, 0, 0 },
|
|
{ 0, 0, 1, 0 },
|
|
{ 1, 0, 2, 0 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
// type 24
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 0, 1 },
|
|
{ 1, 0, 0, 1 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
// type 25
|
|
{
|
|
{ 0, 0, 0, 0 },
|
|
{ 0, 0, 1, 0 },
|
|
{ 1, 0, 1, 0 },
|
|
{ 1, 0, 0, 0 }
|
|
},
|
|
};
|
|
|
|
if (mm_ctrapezoid_type.get () >= sizeof (ctraps_table) / sizeof (ctraps_table [0])) {
|
|
error (tl::sprintf (tl::to_string (tr ("Invalid CTRAPEZOID type %d")), int (mm_ctrapezoid_type.get ())));
|
|
}
|
|
|
|
db::Coord w = 0, h = 0;
|
|
|
|
for (unsigned i = 0; i < 4; ++i) {
|
|
|
|
db::Coord *m = ctraps_table [mm_ctrapezoid_type.get ()][i];
|
|
|
|
db::Coord x = 0;
|
|
if (m[0] != 0) x += m[0] * mm_geometry_w.get ();
|
|
if (m[1] != 0) x += m[1] * mm_geometry_h.get ();
|
|
|
|
db::Coord y = 0;
|
|
if (m[2] != 0) y += m[2] * mm_geometry_w.get ();
|
|
if (m[3] != 0) y += m[3] * mm_geometry_h.get ();
|
|
|
|
pts [i] = db::Point (x, y);
|
|
|
|
if (x > w) w = x;
|
|
if (y > h) h = y;
|
|
|
|
}
|
|
|
|
// set modal variables to the bbox of the shape
|
|
mm_geometry_w = w;
|
|
mm_geometry_h = h;
|
|
|
|
unsigned int npts = 4;
|
|
if (pts [npts - 1] == pts [0]) {
|
|
--npts;
|
|
}
|
|
|
|
if ((m & 0x4) && read_repetition ()) {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
// convert the OASIS record into the polygon.
|
|
db::SimplePolygon poly;
|
|
poly.assign_hull (pts, pts + npts, false /*no compression*/);
|
|
|
|
db::Cell &cell = layout.cell (cell_index);
|
|
|
|
const std::vector<db::Vector> *points = 0;
|
|
|
|
// If the repetition is a regular one, convert the repetition into
|
|
// a shape array
|
|
db::Vector a, b;
|
|
size_t na, nb;
|
|
if (! layout.is_editable () && mm_repetition.get ().is_regular (a, b, na, nb)) {
|
|
|
|
db::Vector d (poly.box ().lower_left () - db::Point ());
|
|
poly.move (-d);
|
|
db::SimplePolygonPtr poly_ptr (poly, layout.shape_repository ());
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::array<db::SimplePolygonPtr, db::Disp> > (db::array<db::SimplePolygonPtr, db::Disp> (poly_ptr, db::Disp (d + pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::array<db::SimplePolygonPtr, db::Disp> (poly_ptr, db::Disp (d + pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb));
|
|
}
|
|
|
|
} else if (! layout.is_editable () && (points = mm_repetition.get ().is_iterated ()) != 0) {
|
|
|
|
db::Vector d (poly.box ().lower_left () - db::Point ());
|
|
poly.move (-d);
|
|
db::SimplePolygonPtr poly_ptr (poly, layout.shape_repository ());
|
|
|
|
// Create an iterated simple polygon array
|
|
db::Shape::simple_polygon_ptr_array_type::iterated_array_type array;
|
|
array.reserve (points->size () + 1);
|
|
array.insert (db::Vector ());
|
|
array.insert (points->begin (), points->end ());
|
|
array.sort ();
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::Shape::simple_polygon_ptr_array_type> (db::Shape::simple_polygon_ptr_array_type (poly_ptr, db::Disp (d + pos), layout.array_repository ().insert (array)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::Shape::simple_polygon_ptr_array_type (poly_ptr, db::Disp (d + pos), layout.array_repository ().insert (array)));
|
|
}
|
|
|
|
} else {
|
|
|
|
db::SimplePolygonRef poly_ref (poly, layout.shape_repository ());
|
|
|
|
RepetitionIterator p = mm_repetition.get ().begin ();
|
|
while (! p.at_end ()) {
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::SimplePolygonRefWithProperties (poly_ref.transformed (db::Disp (pos + *p)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (poly_ref.transformed (db::Disp (pos + *p)));
|
|
}
|
|
++p;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
// convert the OASIS record into the polygon.
|
|
db::SimplePolygon poly;
|
|
poly.assign_hull (pts, pts + npts, false /*no compression*/);
|
|
db::SimplePolygonRef poly_ref (poly, layout.shape_repository ());
|
|
|
|
if (pp.first) {
|
|
layout.cell (cell_index).shapes (ll.second).insert (db::SimplePolygonRefWithProperties (poly_ref.transformed (db::Disp (pos)), pp.second));
|
|
} else {
|
|
layout.cell (cell_index).shapes (ll.second).insert (poly_ref.transformed (db::Disp (pos)));
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
OASISReader::do_read_circle (bool xy_absolute, db::cell_index_type cell_index, db::Layout &layout)
|
|
{
|
|
unsigned char m = get_byte ();
|
|
|
|
if (m & 0x1) {
|
|
mm_layer = get_uint ();
|
|
}
|
|
|
|
if (m & 0x2) {
|
|
mm_datatype = get_uint ();
|
|
}
|
|
|
|
if (m & 0x20) {
|
|
mm_circle_radius = get_ucoord_as_distance ();
|
|
}
|
|
|
|
if (m & 0x10) {
|
|
db::Coord x;
|
|
get (x);
|
|
if (xy_absolute) {
|
|
mm_geometry_x = x;
|
|
} else {
|
|
mm_geometry_x = x + mm_geometry_x.get ();
|
|
}
|
|
}
|
|
|
|
if (m & 0x8) {
|
|
db::Coord y;
|
|
get (y);
|
|
if (xy_absolute) {
|
|
mm_geometry_y = y;
|
|
} else {
|
|
mm_geometry_y = y + mm_geometry_y.get ();
|
|
}
|
|
}
|
|
|
|
db::Vector pos (mm_geometry_x.get (), mm_geometry_y.get ());
|
|
|
|
std::pair<bool, unsigned int> ll = open_dl (layout, LDPair (mm_layer.get (), mm_datatype.get ()));
|
|
|
|
// ignore this circle if the radius is zero
|
|
if (mm_circle_radius.get () <= 0) {
|
|
ll.first = false;
|
|
}
|
|
|
|
if ((m & 0x4) && read_repetition ()) {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
// convert the OASIS circle into a single-point path.
|
|
db::Path path;
|
|
path.width (2 * mm_circle_radius.get ());
|
|
path.extensions (mm_circle_radius.get (), mm_circle_radius.get ());
|
|
path.round (true);
|
|
db::Point p0 (0, 0);
|
|
path.assign (&p0, &p0 + 1);
|
|
|
|
db::Cell &cell = layout.cell (cell_index);
|
|
|
|
const std::vector<db::Vector> *points = 0;
|
|
|
|
// If the repetition is a regular one, convert the repetition into
|
|
// a shape array
|
|
db::Vector a, b;
|
|
size_t na, nb;
|
|
if (! layout.is_editable () && mm_repetition.get ().is_regular (a, b, na, nb)) {
|
|
|
|
// creating a PathPtr is most efficient with a normalized path because no displacement is provided
|
|
db::PathPtr path_ptr (path, layout.shape_repository ());
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::array<db::PathPtr, db::Disp> > (db::array<db::PathPtr, db::Disp> (path_ptr, db::Disp (pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::array<db::PathPtr, db::Disp> (path_ptr, db::Disp (pos), layout.array_repository (), a, b, (unsigned long) na, (unsigned long) nb));
|
|
}
|
|
|
|
} else if (! layout.is_editable () && (points = mm_repetition.get ().is_iterated ()) != 0) {
|
|
|
|
db::PathPtr path_ptr (path, layout.shape_repository ());
|
|
|
|
// Create an iterated simple polygon array
|
|
db::Shape::path_ptr_array_type::iterated_array_type array;
|
|
array.reserve (points->size () + 1);
|
|
array.insert (db::Vector ());
|
|
array.insert (points->begin (), points->end ());
|
|
array.sort ();
|
|
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::object_with_properties<db::Shape::path_ptr_array_type> (db::Shape::path_ptr_array_type (path_ptr, db::Disp (pos), layout.array_repository ().insert (array)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (db::Shape::path_ptr_array_type (path_ptr, db::Disp (pos), layout.array_repository ().insert (array)));
|
|
}
|
|
|
|
} else {
|
|
|
|
db::PathRef path_ref (path, layout.shape_repository ());
|
|
|
|
RepetitionIterator p = mm_repetition.get ().begin ();
|
|
while (! p.at_end ()) {
|
|
if (pp.first) {
|
|
cell.shapes (ll.second).insert (db::PathRefWithProperties (path_ref.transformed (db::Disp (pos + *p)), pp.second));
|
|
} else {
|
|
cell.shapes (ll.second).insert (path_ref.transformed (db::Disp (pos + *p)));
|
|
}
|
|
++p;
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
std::pair<bool, db::properties_id_type> pp = read_element_properties (layout.properties_repository (), false);
|
|
|
|
if (ll.first) {
|
|
|
|
// convert the OASIS circle into a single-point path.
|
|
db::Path path;
|
|
path.width (2 * mm_circle_radius.get ());
|
|
path.extensions (mm_circle_radius.get (), mm_circle_radius.get ());
|
|
path.round (true);
|
|
db::Point p0 (0, 0);
|
|
path.assign (&p0, &p0 + 1);
|
|
db::PathRef path_ref (path, layout.shape_repository ());
|
|
|
|
if (pp.first) {
|
|
layout.cell (cell_index).shapes (ll.second).insert (db::PathRefWithProperties (path_ref.transformed (db::Disp (pos)), pp.second));
|
|
} else {
|
|
layout.cell (cell_index).shapes (ll.second).insert (path_ref.transformed (db::Disp (pos)));
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
void
|
|
OASISReader::reset_modal_variables ()
|
|
{
|
|
// reset modal variables
|
|
mm_repetition.reset ();
|
|
mm_placement_cell.reset ();
|
|
mm_placement_x = 0;
|
|
mm_placement_y = 0;
|
|
mm_layer.reset ();
|
|
mm_datatype.reset ();
|
|
mm_textlayer.reset ();
|
|
mm_texttype.reset ();
|
|
mm_text_x = 0;
|
|
mm_text_y = 0;
|
|
mm_text_string.reset ();
|
|
mm_text_string_id.reset ();
|
|
mm_geometry_x = 0;
|
|
mm_geometry_y = 0;
|
|
mm_geometry_w.reset ();
|
|
mm_geometry_h.reset ();
|
|
mm_polygon_point_list.reset ();
|
|
mm_path_halfwidth.reset ();
|
|
mm_path_start_extension.reset ();
|
|
mm_path_end_extension.reset ();
|
|
mm_path_point_list.reset ();
|
|
mm_ctrapezoid_type.reset ();
|
|
mm_circle_radius.reset ();
|
|
mm_last_property_name.reset ();
|
|
mm_last_property_is_sprop.reset ();
|
|
mm_last_value_list.reset ();
|
|
}
|
|
|
|
void
|
|
OASISReader::do_read_cell (db::cell_index_type cell_index, db::Layout &layout)
|
|
{
|
|
// clears current instance list
|
|
m_instances.clear ();
|
|
m_instances_with_props.clear ();
|
|
|
|
m_progress.set (m_stream.pos ());
|
|
|
|
bool xy_absolute = true;
|
|
|
|
bool has_context = false;
|
|
std::vector <std::string> context_strings;
|
|
db::PropertiesRepository::properties_set cell_properties;
|
|
|
|
// read next record
|
|
while (true) {
|
|
|
|
m_progress.set (m_stream.pos ());
|
|
|
|
unsigned char r = get_byte ();
|
|
|
|
if (r == 0 /*PAD*/) {
|
|
|
|
// simply skip.
|
|
mark_start_table ();
|
|
|
|
} else if (r == 15 /*XYABSOLUTE*/) {
|
|
|
|
// switch to absolute mode
|
|
xy_absolute = true;
|
|
|
|
mark_start_table ();
|
|
|
|
} else if (r == 16 /*XYRELATIVE*/) {
|
|
|
|
// switch to relative mode
|
|
xy_absolute = false;
|
|
|
|
mark_start_table ();
|
|
|
|
} else if (r == 17 || r == 18 /*PLACEMENT*/) {
|
|
|
|
do_read_placement (r, xy_absolute, layout, m_instances, m_instances_with_props);
|
|
|
|
} else if (r == 19 /*TEXT*/) {
|
|
|
|
do_read_text (xy_absolute, cell_index, layout);
|
|
|
|
} else if (r == 20 /*RECTANGLE*/) {
|
|
|
|
do_read_rectangle (xy_absolute, cell_index, layout);
|
|
|
|
} else if (r == 21 /*POLYGON*/) {
|
|
|
|
do_read_polygon (xy_absolute, cell_index, layout);
|
|
|
|
} else if (r == 22 /*PATH*/) {
|
|
|
|
do_read_path (xy_absolute, cell_index, layout);
|
|
|
|
} else if (r == 23 || r == 24 || r == 25 /*TRAPEZOID*/) {
|
|
|
|
do_read_trapezoid (r, xy_absolute, cell_index, layout);
|
|
|
|
} else if (r == 26 /*CTRAPEZOID*/) {
|
|
|
|
do_read_ctrapezoid (xy_absolute, cell_index, layout);
|
|
|
|
} else if (r == 27 /*CIRCLE*/) {
|
|
|
|
do_read_circle (xy_absolute, cell_index, layout);
|
|
|
|
} else if (r == 28 || r == 29 /*PROPERTY*/) {
|
|
|
|
if (r == 28 /*PROPERTY*/) {
|
|
read_properties (layout.properties_repository ());
|
|
}
|
|
|
|
if (! mm_last_property_is_sprop.get () && mm_last_property_name.get () == m_klayout_context_property_name_id) {
|
|
has_context = true;
|
|
context_strings.reserve (mm_last_value_list.get ().size ());
|
|
for (std::vector<tl::Variant>::const_iterator v = mm_last_value_list.get ().begin (); v != mm_last_value_list.get ().end (); ++v) {
|
|
context_strings.push_back (v->to_string ());
|
|
}
|
|
} else {
|
|
// store cell properties
|
|
store_last_properties (layout.properties_repository (), cell_properties, true);
|
|
}
|
|
|
|
mark_start_table ();
|
|
|
|
} else if (r == 32 /*XELEMENT*/) {
|
|
|
|
// read over
|
|
get_ulong ();
|
|
get_str ();
|
|
|
|
read_element_properties (layout.properties_repository (), true);
|
|
|
|
} else if (r == 33 /*XGEOMETRY*/) {
|
|
|
|
// read over.
|
|
|
|
unsigned char m = get_byte ();
|
|
get_ulong ();
|
|
|
|
if (m & 0x1) {
|
|
mm_layer = get_uint ();
|
|
}
|
|
|
|
if (m & 0x2) {
|
|
mm_datatype = get_uint ();
|
|
}
|
|
|
|
// data payload:
|
|
get_str ();
|
|
|
|
if (m & 0x10) {
|
|
db::Coord x;
|
|
get (x);
|
|
if (xy_absolute) {
|
|
mm_geometry_x = x;
|
|
} else {
|
|
mm_geometry_x = x + mm_geometry_x.get ();
|
|
}
|
|
}
|
|
|
|
if (m & 0x8) {
|
|
db::Coord y;
|
|
get (y);
|
|
if (xy_absolute) {
|
|
mm_geometry_y = y;
|
|
} else {
|
|
mm_geometry_y = y + mm_geometry_y.get ();
|
|
}
|
|
}
|
|
|
|
if ((m & 0x4) && read_repetition ()) {
|
|
// later: handle XGEOMETRY with repetition
|
|
}
|
|
|
|
read_element_properties (layout.properties_repository (), true);
|
|
|
|
} else if (r == 34 /*CBLOCK*/) {
|
|
|
|
unsigned int type = get_uint ();
|
|
if (type != 0) {
|
|
error (tl::sprintf (tl::to_string (tr ("Invalid CBLOCK compression type %d")), type));
|
|
}
|
|
|
|
get_uint (); // uncomp-byte-count - not needed
|
|
get_uint (); // comp-byte-count - not needed
|
|
|
|
// put the stream into deflating mode
|
|
m_stream.inflate ();
|
|
|
|
} else {
|
|
// put the byte back into the stream
|
|
m_stream.unget (1);
|
|
break;
|
|
}
|
|
|
|
}
|
|
|
|
if (! cell_properties.empty ()) {
|
|
layout.cell (cell_index).prop_id (layout.properties_repository ().properties_id (cell_properties));
|
|
}
|
|
|
|
// insert all instances collected (inserting them once is
|
|
// more effective than doing this every time)
|
|
if (! m_instances.empty ()) {
|
|
layout.cell (cell_index).insert (m_instances.begin (), m_instances.end ());
|
|
// clear immediately, because if the cell is cleared before the instances are deleted, the
|
|
// array pointers (living in the repository) may no longer be valid
|
|
m_instances.clear ();
|
|
}
|
|
if (! m_instances_with_props.empty ()) {
|
|
layout.cell (cell_index).insert (m_instances_with_props.begin (), m_instances_with_props.end ());
|
|
// see above.
|
|
m_instances_with_props.clear ();
|
|
}
|
|
|
|
// Restore proxy cell (link to PCell or Library)
|
|
if (has_context) {
|
|
CommonReaderLayerMapping layer_mapping (this, &layout);
|
|
layout.recover_proxy_as (cell_index, context_strings.begin (), context_strings.end (), &layer_mapping);
|
|
}
|
|
|
|
m_cellname = "";
|
|
}
|
|
|
|
}
|
|
|