mirror of https://github.com/KLayout/klayout.git
Merge pull request #1810 from KLayout/gds2-writer-overflow-checks
Gds2 writer overflow checks
This commit is contained in:
commit
a126c8f8c4
|
|
@ -44,40 +44,128 @@ namespace db
|
|||
{
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// GDS2WriterBase implementation
|
||||
// Limit checking conversion functions
|
||||
|
||||
GDS2WriterBase::GDS2WriterBase ()
|
||||
static int32_t safe_convert_to_int32 (int32_t value)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
return value;
|
||||
}
|
||||
|
||||
static int safe_scale (double sf, int value)
|
||||
static int32_t safe_convert_to_int32 (uint32_t value)
|
||||
{
|
||||
if (value > std::numeric_limits<int32_t>::max ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Coordinate overflow")));
|
||||
}
|
||||
return int32_t (value);
|
||||
}
|
||||
|
||||
static int32_t safe_convert_to_int32 (int64_t value)
|
||||
{
|
||||
if (value < std::numeric_limits<int32_t>::min ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Coordinate underflow")));
|
||||
}
|
||||
if (value > std::numeric_limits<int32_t>::max ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Coordinate overflow")));
|
||||
}
|
||||
return int32_t (value);
|
||||
}
|
||||
|
||||
static int32_t safe_convert_to_int32 (uint64_t value)
|
||||
{
|
||||
if (value > std::numeric_limits<int32_t>::max ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Coordinate overflow")));
|
||||
}
|
||||
return int32_t (value);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static int32_t safe_scale (double sf, T value)
|
||||
{
|
||||
double i = floor (sf * value + 0.5);
|
||||
if (i < double (std::numeric_limits<int>::min ())) {
|
||||
throw tl::Exception ("Scaling failed: coordinate underflow");
|
||||
if (i < double (std::numeric_limits<int32_t>::min ())) {
|
||||
throw tl::Exception (tl::to_string (tr ("Scaling failed: coordinate underflow")));
|
||||
}
|
||||
if (i > double (std::numeric_limits<int>::max ())) {
|
||||
throw tl::Exception ("Scaling failed: coordinate overflow");
|
||||
if (i > double (std::numeric_limits<int32_t>::max ())) {
|
||||
throw tl::Exception (tl::to_string (tr ("Scaling failed: coordinate overflow")));
|
||||
}
|
||||
return int (i);
|
||||
return int32_t (i);
|
||||
}
|
||||
|
||||
inline int scale (double sf, int value)
|
||||
template <class T>
|
||||
inline int32_t scale (double sf, T value)
|
||||
{
|
||||
if (sf == 1.0) {
|
||||
return value;
|
||||
return safe_convert_to_int32 (value);
|
||||
} else {
|
||||
return safe_scale (sf, value);
|
||||
}
|
||||
}
|
||||
|
||||
static uint16_t safe_convert_to_uint16 (int16_t value)
|
||||
{
|
||||
// we accept this as GDS is not well defined here ...
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint16_t safe_convert_to_uint16 (uint16_t value)
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
static uint16_t safe_convert_to_uint16 (int32_t value)
|
||||
{
|
||||
if (value < 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Short unsigned integer underflow")));
|
||||
}
|
||||
if (value > std::numeric_limits<uint16_t>::max ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Short unsigned integer overflow")));
|
||||
}
|
||||
return uint16_t (value);
|
||||
}
|
||||
|
||||
static uint16_t safe_convert_to_uint16 (uint32_t value)
|
||||
{
|
||||
if (value > std::numeric_limits<uint16_t>::max ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Short unsigned integer overflow")));
|
||||
}
|
||||
return uint16_t (value);
|
||||
}
|
||||
|
||||
static uint16_t safe_convert_to_uint16 (int64_t value)
|
||||
{
|
||||
if (value < 0) {
|
||||
throw tl::Exception (tl::to_string (tr ("Short unsigned integer underflow")));
|
||||
}
|
||||
if (value > std::numeric_limits<uint16_t>::max ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Short unsigned integer overflow")));
|
||||
}
|
||||
return uint16_t (value);
|
||||
}
|
||||
|
||||
static uint16_t safe_convert_to_uint16 (uint64_t value)
|
||||
{
|
||||
if (value > std::numeric_limits<uint16_t>::max ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("Short unsigned integer overflow")));
|
||||
}
|
||||
return uint16_t (value);
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------
|
||||
// GDS2WriterBase implementation
|
||||
|
||||
GDS2WriterBase::GDS2WriterBase ()
|
||||
: m_dbu (0.0), m_resolve_skew_arrays (false), m_multi_xy (false), m_no_zero_length_paths (false),
|
||||
m_max_vertex_count (0), m_write_cell_properties (false), m_keep_instances (false)
|
||||
{
|
||||
// .. nothing yet ..
|
||||
}
|
||||
|
||||
void
|
||||
GDS2WriterBase::write_context_string (size_t n, const std::string &s)
|
||||
{
|
||||
// max. size for GDS strings used as payload carrier
|
||||
size_t chunk_size = 32000;
|
||||
short max_short = std::numeric_limits<short>::max ();
|
||||
short max_short = std::numeric_limits<int16_t>::max ();
|
||||
|
||||
if (n > size_t (max_short) || s.size () > chunk_size) {
|
||||
|
||||
|
|
@ -113,7 +201,7 @@ GDS2WriterBase::write_context_string (size_t n, const std::string &s)
|
|||
|
||||
write_record_size (6);
|
||||
write_record (sPROPATTR);
|
||||
write_short (short (n));
|
||||
write_short (int16_t (n));
|
||||
|
||||
write_string_record (sPROPVALUE, s);
|
||||
|
||||
|
|
@ -211,13 +299,135 @@ GDS2WriterBase::write_context_cell (db::Layout &layout, const short *time_data,
|
|||
write_record (sENDSTR);
|
||||
}
|
||||
|
||||
void
|
||||
GDS2WriterBase::write_shape (const db::Layout &layout, int layer, int datatype, const db::Shape &shape, double sf)
|
||||
{
|
||||
if (shape.is_text ()) {
|
||||
|
||||
write_text (layer, datatype, sf, m_dbu, shape, layout, shape.prop_id ());
|
||||
|
||||
} else if (shape.is_polygon ()) {
|
||||
|
||||
write_polygon (layer, datatype, sf, shape, m_multi_xy, m_max_vertex_count, layout, shape.prop_id ());
|
||||
|
||||
} else if (shape.is_edge ()) {
|
||||
|
||||
write_edge (layer, datatype, sf, shape, layout, shape.prop_id ());
|
||||
|
||||
} else if (shape.is_edge_pair ()) {
|
||||
|
||||
write_edge (layer, datatype, sf, shape.edge_pair ().first (), layout, shape.prop_id ());
|
||||
write_edge (layer, datatype, sf, shape.edge_pair ().second (), layout, shape.prop_id ());
|
||||
|
||||
} else if (shape.is_path ()) {
|
||||
|
||||
if (m_no_zero_length_paths && (shape.path_length () - shape.path_extensions ().first - shape.path_extensions ().second) == 0) {
|
||||
// eliminate the zero-width path
|
||||
db::Polygon poly;
|
||||
shape.polygon (poly);
|
||||
write_polygon (layer, datatype, sf, poly, m_multi_xy, m_max_vertex_count, layout, shape.prop_id (), false);
|
||||
} else {
|
||||
write_path (layer, datatype, sf, shape, m_multi_xy, layout, shape.prop_id ());
|
||||
}
|
||||
|
||||
} else if (shape.is_box ()) {
|
||||
|
||||
write_box (layer, datatype, sf, shape, layout, shape.prop_id ());
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
GDS2WriterBase::write_cell (db::Layout &layout, const db::Cell &cref, const std::vector <std::pair <unsigned int, db::LayerProperties> > &layers, const std::set<db::cell_index_type> &cell_set, double sf, short *time_data)
|
||||
{
|
||||
// cell header
|
||||
|
||||
write_record_size (4 + 12 * 2);
|
||||
write_record (sBGNSTR);
|
||||
write_time (time_data);
|
||||
write_time (time_data);
|
||||
|
||||
try {
|
||||
write_string_record (sSTRNAME, m_cell_name_map.cell_name (cref.cell_index ()));
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (ex.msg () + tl::to_string (tr (", writing cell name")));
|
||||
}
|
||||
|
||||
// cell body
|
||||
|
||||
if (m_write_cell_properties && cref.prop_id () != 0) {
|
||||
try {
|
||||
write_properties (layout, cref.prop_id ());
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (ex.msg () + tl::to_string (tr (", writing layout properties")));
|
||||
}
|
||||
}
|
||||
|
||||
// instances
|
||||
|
||||
for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) {
|
||||
|
||||
// write only instances to selected cells
|
||||
if (m_keep_instances || cell_set.find (inst->cell_index ()) != cell_set.end ()) {
|
||||
|
||||
progress_checkpoint ();
|
||||
try {
|
||||
write_inst (sf, *inst, true /*normalize*/, m_resolve_skew_arrays, layout, inst->prop_id ());
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (ex.msg () + tl::to_string (tr (", writing instances")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// shapes
|
||||
|
||||
for (std::vector <std::pair <unsigned int, db::LayerProperties> >::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
|
||||
if (layout.is_valid_layer (l->first) && l->second.layer >= 0 && l->second.datatype >= 0) {
|
||||
|
||||
int layer = l->second.layer;
|
||||
if (layer > std::numeric_limits<uint16_t>::max ()) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot write layer numbers larger than %d to GDS2 streams")), int (std::numeric_limits<uint16_t>::max ())));
|
||||
}
|
||||
int datatype = l->second.datatype;
|
||||
if (datatype > std::numeric_limits<uint16_t>::max ()) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot write datatype numbers larger than %d to GDS2 streams")), int (std::numeric_limits<uint16_t>::max ())));
|
||||
}
|
||||
|
||||
db::ShapeIterator shape (cref.shapes (l->first).begin (db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Edges | db::ShapeIterator::EdgePairs | db::ShapeIterator::Paths | db::ShapeIterator::Texts));
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
progress_checkpoint ();
|
||||
|
||||
try {
|
||||
write_shape (layout, layer, datatype, *shape, sf);
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (ex.msg () + tl::sprintf (tl::to_string (tr (", writing layer %d/%d")), layer, datatype));
|
||||
}
|
||||
|
||||
++shape;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// end of cell
|
||||
|
||||
write_record_size (4);
|
||||
write_record (sENDSTR);
|
||||
}
|
||||
|
||||
void
|
||||
GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::SaveLayoutOptions &options)
|
||||
{
|
||||
set_stream (stream);
|
||||
|
||||
double dbu = (options.dbu () == 0.0) ? layout.dbu () : options.dbu ();
|
||||
double sf = options.scale_factor () * (layout.dbu () / dbu);
|
||||
m_dbu = (options.dbu () == 0.0) ? layout.dbu () : options.dbu ();
|
||||
double sf = options.scale_factor () * (layout.dbu () / m_dbu);
|
||||
if (fabs (sf - 1.0) < 1e-9) {
|
||||
// to avoid rounding problems, set to 1.0 exactly if possible.
|
||||
sf = 1.0;
|
||||
|
|
@ -225,8 +435,8 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S
|
|||
|
||||
db::GDS2WriterOptions gds2_options = options.get_options<db::GDS2WriterOptions> ();
|
||||
|
||||
layout.add_meta_info ("dbuu", MetaInfo (tl::to_string (tr ("Database unit in user units")), tl::to_string (dbu / std::max (1e-9, gds2_options.user_units))));
|
||||
layout.add_meta_info ("dbum", MetaInfo (tl::to_string (tr ("Database unit in meter")), tl::to_string (dbu * 1e-6)));
|
||||
layout.add_meta_info ("dbuu", MetaInfo (tl::to_string (tr ("Database unit in user units")), tl::to_string (m_dbu / std::max (1e-9, gds2_options.user_units))));
|
||||
layout.add_meta_info ("dbum", MetaInfo (tl::to_string (tr ("Database unit in meter")), tl::to_string (m_dbu * 1e-6)));
|
||||
layout.add_meta_info ("libname", MetaInfo (tl::to_string (tr ("Library name")), gds2_options.libname));
|
||||
|
||||
std::vector <std::pair <unsigned int, db::LayerProperties> > layers;
|
||||
|
|
@ -265,11 +475,14 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S
|
|||
layout.add_meta_info ("mod_time", MetaInfo (tl::to_string (tr ("Modification Time")), str_time));
|
||||
layout.add_meta_info ("access_time", MetaInfo (tl::to_string (tr ("Access Time")), str_time));
|
||||
|
||||
bool multi_xy = gds2_options.multi_xy_records;
|
||||
m_keep_instances = options.keep_instances ();
|
||||
m_multi_xy = gds2_options.multi_xy_records;
|
||||
m_max_vertex_count = std::max (gds2_options.max_vertex_count, (unsigned int)4);
|
||||
m_no_zero_length_paths = gds2_options.no_zero_length_paths;
|
||||
m_resolve_skew_arrays = gds2_options.resolve_skew_arrays;
|
||||
m_write_cell_properties = gds2_options.write_cell_properties;
|
||||
|
||||
size_t max_cellname_length = std::max (gds2_options.max_cellname_length, (unsigned int)8);
|
||||
size_t max_vertex_count = std::max (gds2_options.max_vertex_count, (unsigned int)4);
|
||||
bool no_zero_length_paths = gds2_options.no_zero_length_paths;
|
||||
bool resolve_skew_arrays = gds2_options.resolve_skew_arrays;
|
||||
|
||||
m_cell_name_map = db::WriterCellNameMap (max_cellname_length);
|
||||
m_cell_name_map.replacement ('$');
|
||||
|
|
@ -302,17 +515,25 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S
|
|||
write_time (time_data);
|
||||
write_time (time_data);
|
||||
|
||||
write_string_record (sLIBNAME, gds2_options.libname);
|
||||
try {
|
||||
write_string_record (sLIBNAME, gds2_options.libname);
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (ex.msg () + tl::to_string (tr (", writing LIBNAME")));
|
||||
}
|
||||
|
||||
write_record_size (4 + 8 * 2);
|
||||
write_record (sUNITS);
|
||||
write_double (dbu / std::max (1e-9, gds2_options.user_units));
|
||||
write_double (dbu * 1e-6);
|
||||
write_double (m_dbu / std::max (1e-9, gds2_options.user_units));
|
||||
write_double (m_dbu * 1e-6);
|
||||
|
||||
// layout properties
|
||||
|
||||
if (gds2_options.write_file_properties && layout.prop_id () != 0) {
|
||||
write_properties (layout, layout.prop_id ());
|
||||
try {
|
||||
write_properties (layout, layout.prop_id ());
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (ex.msg () + tl::to_string (tr (", writing layout properties")));
|
||||
}
|
||||
}
|
||||
|
||||
// write context info
|
||||
|
|
@ -327,7 +548,11 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S
|
|||
}
|
||||
|
||||
if (has_context) {
|
||||
write_context_cell (layout, time_data, cells);
|
||||
try {
|
||||
write_context_cell (layout, time_data, cells);
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (ex.msg () + tl::to_string (tr (", writing context cell")));
|
||||
}
|
||||
}
|
||||
|
||||
// body
|
||||
|
|
@ -342,84 +567,12 @@ GDS2WriterBase::write (db::Layout &layout, tl::OutputStream &stream, const db::S
|
|||
// also don't write proxy cells which are not employed
|
||||
if ((! cref.is_ghost_cell () || ! cref.empty ()) && (! cref.is_proxy () || ! cref.is_top ())) {
|
||||
|
||||
// cell header
|
||||
|
||||
write_record_size (4 + 12 * 2);
|
||||
write_record (sBGNSTR);
|
||||
write_time (time_data);
|
||||
write_time (time_data);
|
||||
|
||||
write_string_record (sSTRNAME, m_cell_name_map.cell_name (*cell));
|
||||
|
||||
// cell body
|
||||
|
||||
if (gds2_options.write_cell_properties && cref.prop_id () != 0) {
|
||||
write_properties (layout, cref.prop_id ());
|
||||
try {
|
||||
write_cell (layout, cref, layers, cell_set, sf, time_data);
|
||||
} catch (tl::Exception &ex) {
|
||||
throw tl::Exception (ex.msg () + tl::sprintf (tl::to_string (tr (", writing cell '%s'")), layout.cell_name (*cell)));
|
||||
}
|
||||
|
||||
// instances
|
||||
|
||||
for (db::Cell::const_iterator inst = cref.begin (); ! inst.at_end (); ++inst) {
|
||||
|
||||
// write only instances to selected cells
|
||||
if (options.keep_instances () || cell_set.find (inst->cell_index ()) != cell_set.end ()) {
|
||||
|
||||
progress_checkpoint ();
|
||||
write_inst (sf, *inst, true /*normalize*/, resolve_skew_arrays, layout, inst->prop_id ());
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// shapes
|
||||
|
||||
for (std::vector <std::pair <unsigned int, db::LayerProperties> >::const_iterator l = layers.begin (); l != layers.end (); ++l) {
|
||||
|
||||
if (layout.is_valid_layer (l->first)) {
|
||||
|
||||
int layer = l->second.layer;
|
||||
int datatype = l->second.datatype;
|
||||
|
||||
db::ShapeIterator shape (cref.shapes (l->first).begin (db::ShapeIterator::Boxes | db::ShapeIterator::Polygons | db::ShapeIterator::Edges | db::ShapeIterator::EdgePairs | db::ShapeIterator::Paths | db::ShapeIterator::Texts));
|
||||
while (! shape.at_end ()) {
|
||||
|
||||
progress_checkpoint ();
|
||||
|
||||
if (shape->is_text ()) {
|
||||
write_text (layer, datatype, sf, dbu, *shape, layout, shape->prop_id ());
|
||||
} else if (shape->is_polygon ()) {
|
||||
write_polygon (layer, datatype, sf, *shape, multi_xy, max_vertex_count, layout, shape->prop_id ());
|
||||
} else if (shape->is_edge ()) {
|
||||
write_edge (layer, datatype, sf, *shape, layout, shape->prop_id ());
|
||||
} else if (shape->is_edge_pair ()) {
|
||||
write_edge (layer, datatype, sf, shape->edge_pair ().first (), layout, shape->prop_id ());
|
||||
write_edge (layer, datatype, sf, shape->edge_pair ().second (), layout, shape->prop_id ());
|
||||
} else if (shape->is_path ()) {
|
||||
if (no_zero_length_paths && (shape->path_length () - shape->path_extensions ().first - shape->path_extensions ().second) == 0) {
|
||||
// eliminate the zero-width path
|
||||
db::Polygon poly;
|
||||
shape->polygon (poly);
|
||||
write_polygon (layer, datatype, sf, poly, multi_xy, max_vertex_count, layout, shape->prop_id (), false);
|
||||
} else {
|
||||
write_path (layer, datatype, sf, *shape, multi_xy, layout, shape->prop_id ());
|
||||
}
|
||||
} else if (shape->is_box ()) {
|
||||
write_box (layer, datatype, sf, *shape, layout, shape->prop_id ());
|
||||
}
|
||||
|
||||
++shape;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// end of cell
|
||||
|
||||
write_record_size (4);
|
||||
write_record (sENDSTR);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -545,8 +698,8 @@ GDS2WriterBase::write_inst (double sf, const db::Instance &instance, bool normal
|
|||
if (is_reg) {
|
||||
write_record_size (4 + 2 * 2);
|
||||
write_record (sCOLROW);
|
||||
if (amax > 32767 || bmax > 32767) {
|
||||
throw tl::Exception (tl::to_string (tr ("Cannot write array references with more than 32767 columns or rows to GDS2 streams")));
|
||||
if (amax > std::numeric_limits<int16_t>::max () || bmax > std::numeric_limits<int16_t>::max ()) {
|
||||
throw tl::Exception (tl::sprintf (tl::to_string (tr ("Cannot write array references with more than %d columns or rows to GDS2 streams")), int (std::numeric_limits<int16_t>::max ())));
|
||||
}
|
||||
write_short (std::max ((unsigned long) 1, bmax));
|
||||
write_short (std::max ((unsigned long) 1, amax));
|
||||
|
|
@ -558,10 +711,10 @@ GDS2WriterBase::write_inst (double sf, const db::Instance &instance, bool normal
|
|||
write_int (scale (sf, t.disp ().y ()));
|
||||
|
||||
if (is_reg) {
|
||||
write_int (scale (sf, t.disp ().x () + b.x () * bmax));
|
||||
write_int (scale (sf, t.disp ().y () + b.y () * bmax));
|
||||
write_int (scale (sf, t.disp ().x () + a.x () * amax));
|
||||
write_int (scale (sf, t.disp ().y () + a.y () * amax));
|
||||
write_int (scale (sf, t.disp ().x () + b.x () * (int64_t) bmax));
|
||||
write_int (scale (sf, t.disp ().y () + b.y () * (int64_t) bmax));
|
||||
write_int (scale (sf, t.disp ().x () + a.x () * (int64_t) amax));
|
||||
write_int (scale (sf, t.disp ().y () + a.y () * (int64_t) amax));
|
||||
}
|
||||
|
||||
finish (layout, prop_id);
|
||||
|
|
@ -584,11 +737,11 @@ GDS2WriterBase::write_box (int layer, int datatype, double sf, const db::Shape &
|
|||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sLAYER);
|
||||
write_short (layer);
|
||||
write_short (safe_convert_to_uint16 (layer));
|
||||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sDATATYPE);
|
||||
write_short (datatype);
|
||||
write_short (safe_convert_to_uint16 (datatype));
|
||||
|
||||
write_record_size (4 + 5 * 2 * 4);
|
||||
write_record (sXY);
|
||||
|
|
@ -618,11 +771,11 @@ GDS2WriterBase::write_path (int layer, int datatype, double sf, const db::Shape
|
|||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sLAYER);
|
||||
write_short (layer);
|
||||
write_short (safe_convert_to_uint16 (layer));
|
||||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sDATATYPE);
|
||||
write_short (datatype);
|
||||
write_short (safe_convert_to_uint16 (datatype));
|
||||
|
||||
short type = 0;
|
||||
db::Coord w = path.width ();
|
||||
|
|
@ -698,11 +851,11 @@ GDS2WriterBase::write_edge (int layer, int datatype, double sf, const db::Edge &
|
|||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sLAYER);
|
||||
write_short (layer);
|
||||
write_short (safe_convert_to_uint16 (layer));
|
||||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sDATATYPE);
|
||||
write_short (datatype);
|
||||
write_short (safe_convert_to_uint16 (datatype));
|
||||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sPATHTYPE);
|
||||
|
|
@ -732,11 +885,11 @@ GDS2WriterBase::write_text (int layer, int datatype, double sf, double dbu, cons
|
|||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sLAYER);
|
||||
write_short (layer);
|
||||
write_short (safe_convert_to_uint16 (layer));
|
||||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sTEXTTYPE);
|
||||
write_short (datatype);
|
||||
write_short (safe_convert_to_uint16 (datatype));
|
||||
|
||||
if (shape.text_halign () != db::NoHAlign || shape.text_valign () != db::NoVAlign || shape.text_font () != db::NoFont) {
|
||||
short ha = short (shape.text_halign () == db::NoHAlign ? db::HAlignLeft : shape.text_halign ());
|
||||
|
|
@ -817,11 +970,11 @@ GDS2WriterBase::write_polygon (int layer, int datatype, double sf, const db::Pol
|
|||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sLAYER);
|
||||
write_short (layer);
|
||||
write_short (safe_convert_to_uint16 (layer));
|
||||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sDATATYPE);
|
||||
write_short (datatype);
|
||||
write_short (safe_convert_to_uint16 (datatype));
|
||||
|
||||
size_t n = polygon.vertices ();
|
||||
|
||||
|
|
@ -892,11 +1045,11 @@ GDS2WriterBase::write_polygon (int layer, int datatype, double sf, const db::Sha
|
|||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sLAYER);
|
||||
write_short (layer);
|
||||
write_short (safe_convert_to_uint16 (layer));
|
||||
|
||||
write_record_size (4 + 2);
|
||||
write_record (sDATATYPE);
|
||||
write_short (datatype);
|
||||
write_short (safe_convert_to_uint16 (datatype));
|
||||
|
||||
db::Shape::point_iterator e (shape.begin_hull ());
|
||||
while (n > 0) {
|
||||
|
|
@ -947,11 +1100,11 @@ GDS2WriterBase::write_properties (const db::Layout &layout, db::properties_id_ty
|
|||
attr = name.to_long ();
|
||||
}
|
||||
|
||||
if (attr >= 0 && attr < 65535) {
|
||||
if (attr >= 0 && attr <= std::numeric_limits<uint16_t>::max ()) {
|
||||
|
||||
write_record_size (6);
|
||||
write_record (sPROPATTR);
|
||||
write_short (attr);
|
||||
write_short ((int16_t) attr);
|
||||
|
||||
write_string_record (sPROPVALUE, p->second.to_string ());
|
||||
|
||||
|
|
@ -974,7 +1127,11 @@ GDS2WriterBase::finish (const db::Layout &layout, db::properties_id_type prop_id
|
|||
void
|
||||
GDS2WriterBase::write_string_record (short record, const std::string &t)
|
||||
{
|
||||
write_record_size (4 + (int16_t (t.size () + 1) / 2) * 2);
|
||||
size_t rs = 4 + ((t.size () + 1) / 2) * 2;
|
||||
if (rs > std::numeric_limits<uint16_t>::max ()) {
|
||||
throw tl::Exception (tl::to_string (tr ("String max. length overflow")));
|
||||
}
|
||||
write_record_size (uint16_t (rs));
|
||||
write_record (record);
|
||||
write_string (t);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ namespace db
|
|||
|
||||
class Layout;
|
||||
class SaveLayoutOptions;
|
||||
class GDS2WriterOptions;
|
||||
|
||||
/**
|
||||
* @brief A GDS2 writer abstraction
|
||||
|
|
@ -166,10 +167,20 @@ protected:
|
|||
|
||||
private:
|
||||
db::WriterCellNameMap m_cell_name_map;
|
||||
double m_dbu;
|
||||
bool m_resolve_skew_arrays;
|
||||
bool m_multi_xy;
|
||||
bool m_no_zero_length_paths;
|
||||
size_t m_max_vertex_count;
|
||||
bool m_write_cell_properties;
|
||||
bool m_keep_instances;
|
||||
|
||||
void write_properties (const db::Layout &layout, db::properties_id_type prop_id);
|
||||
void write_context_cell (db::Layout &layout, const short *time_data, const std::vector<cell_index_type> &cells);
|
||||
void write_context_string (size_t n, const std::string &s);
|
||||
void write_cell (db::Layout &layout, const db::Cell &cref, const std::vector <std::pair <unsigned int, db::LayerProperties> > &layers,
|
||||
const std::set <db::cell_index_type> &cell_set, double sf, short *time_data);
|
||||
void write_shape (const db::Layout &layout, int layer, int datatype, const db::Shape &shape, double sf);
|
||||
};
|
||||
|
||||
} // namespace db
|
||||
|
|
|
|||
|
|
@ -1419,6 +1419,96 @@ TEST(132)
|
|||
EXPECT_EQ (layout_read.meta_info (ci2, "c").value.to_string (), "-1");
|
||||
}
|
||||
|
||||
// Limits
|
||||
static std::string run_test_with_error (double sf, db::Layout &layout)
|
||||
{
|
||||
try {
|
||||
|
||||
tl::OutputMemoryStream buffer;
|
||||
tl::OutputStream stream (buffer);
|
||||
|
||||
db::SaveLayoutOptions options;
|
||||
options.set_format ("GDS2");
|
||||
options.set_scale_factor (sf);
|
||||
|
||||
db::Writer writer (options);
|
||||
writer.write (layout, stream);
|
||||
|
||||
return std::string ();
|
||||
|
||||
} catch (tl::Exception &ex) {
|
||||
return ex.msg ();
|
||||
}
|
||||
}
|
||||
|
||||
static std::string huge_string ()
|
||||
{
|
||||
std::string n;
|
||||
for (unsigned int i = 0; i < 100000; ++i) {
|
||||
n += "A";
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// Exceeding limits
|
||||
TEST(140)
|
||||
{
|
||||
db::Layout layout;
|
||||
db::cell_index_type top_index = layout.add_cell ("TOP");
|
||||
db::Cell &top = layout.cell (top_index);
|
||||
unsigned int l1 = layout.insert_layer (db::LayerProperties (1, 0));
|
||||
top.shapes (l1).insert (db::Text (huge_string (), db::Trans ()));
|
||||
|
||||
EXPECT_EQ (run_test_with_error (1.0, layout), "String max. length overflow, writing layer 1/0, writing cell 'TOP'");
|
||||
}
|
||||
|
||||
TEST(141)
|
||||
{
|
||||
db::Layout layout;
|
||||
db::cell_index_type top_index = layout.add_cell ("TOP");
|
||||
db::Cell &top = layout.cell (top_index);
|
||||
unsigned int l1 = layout.insert_layer (db::LayerProperties (100000, 0));
|
||||
top.shapes (l1).insert (db::Box (0, 0, 100, 200));
|
||||
|
||||
EXPECT_EQ (run_test_with_error (1.0, layout), "Cannot write layer numbers larger than 65535 to GDS2 streams, writing cell 'TOP'");
|
||||
}
|
||||
|
||||
TEST(142)
|
||||
{
|
||||
db::Layout layout;
|
||||
db::cell_index_type top_index = layout.add_cell ("TOP");
|
||||
db::Cell &top = layout.cell (top_index);
|
||||
db::cell_index_type child_index = layout.add_cell ("CHILD");
|
||||
db::Cell &child = layout.cell (child_index);
|
||||
unsigned int l1 = layout.insert_layer (db::LayerProperties (1, 0));
|
||||
child.shapes (l1).insert (db::Box (0, 0, 100, 200));
|
||||
|
||||
top.insert (db::CellInstArray (child_index, db::Trans (), db::Vector (100000000, 0), db::Vector (0, 100000000), 10, 10));
|
||||
EXPECT_EQ (run_test_with_error (1.0, layout), ""); // no error
|
||||
|
||||
top.clear_insts ();
|
||||
|
||||
top.insert (db::CellInstArray (child_index, db::Trans (), db::Vector (100000000, 0), db::Vector (0, 100000000), 100, 100));
|
||||
EXPECT_EQ (run_test_with_error (1.0, layout), "Coordinate overflow, writing instances, writing cell 'TOP'");
|
||||
|
||||
top.clear_insts ();
|
||||
|
||||
top.insert (db::CellInstArray (child_index, db::Trans (), db::Vector (100, 0), db::Vector (0, 100), 100000, 100));
|
||||
EXPECT_EQ (run_test_with_error (1.0, layout), "Cannot write array references with more than 32767 columns or rows to GDS2 streams, writing instances, writing cell 'TOP'");
|
||||
}
|
||||
|
||||
TEST(143)
|
||||
{
|
||||
db::Layout layout;
|
||||
db::cell_index_type top_index = layout.add_cell ("TOP");
|
||||
db::Cell &top = layout.cell (top_index);
|
||||
unsigned int l1 = layout.insert_layer (db::LayerProperties (1, 0));
|
||||
top.shapes (l1).insert (db::Box (-2000000000, 0, 0, 200000000));
|
||||
|
||||
EXPECT_EQ (run_test_with_error (1.0, layout), "");
|
||||
EXPECT_EQ (run_test_with_error (23.0, layout), "Scaling failed: coordinate underflow, writing layer 1/0, writing cell 'TOP'");
|
||||
}
|
||||
|
||||
// Extreme fracturing by max. points
|
||||
TEST(166)
|
||||
{
|
||||
|
|
@ -1427,3 +1517,5 @@ TEST(166)
|
|||
run_test (_this, "t166.oas.gz", "t166_au.gds.gz", false, opt);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue