/* KLayout Layout Viewer Copyright (C) 2006-2016 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 "dbGDS2Reader.h" #include "dbGDS2.h" #include "dbArray.h" #include "tlException.h" #include "tlString.h" #include "tlClassRegistry.h" namespace db { // --------------------------------------------------------------- // GDS2Reader GDS2Reader::GDS2Reader (tl::InputStream &s) : m_stream (s), m_recnum (0), m_reclen (0), m_recptr (0), mp_rec_buf (0), m_stored_rec (0), m_progress (tl::to_string (QObject::tr ("Reading GDS2 file")), 10000) { m_progress.set_format (tl::to_string (QObject::tr ("%.0f MB"))); m_progress.set_unit (1024 * 1024); } GDS2Reader::~GDS2Reader () { // .. nothing yet .. } const LayerMap & GDS2Reader::read (db::Layout &layout, const db::LoadLayoutOptions &options) { m_options = options.get_options (); m_common_options = options.get_options (); m_recnum = 0; --m_recnum; m_reclen = 0; return basic_read (layout, m_common_options.layer_map, m_common_options.create_other_layers, m_common_options.enable_text_objects, m_common_options.enable_properties, m_options.allow_multi_xy_records, m_options.box_mode); } const LayerMap & GDS2Reader::read (db::Layout &layout) { return read (layout, db::LoadLayoutOptions ()); } void GDS2Reader::unget_record (short rec_id) { m_stored_rec = rec_id; m_recptr = 0; } short GDS2Reader::get_record () { if (m_stored_rec) { short ret = m_stored_rec; m_stored_rec = 0; return ret; } unsigned char *b = (unsigned char *) m_stream.get (4); if (! b) { error (tl::to_string (QObject::tr ("Unexpected end-of-file"))); return 0; } m_recnum++; uint16_t l = *((uint16_t *)b); gds2h ((int16_t &) l); m_reclen = size_t (l); uint16_t rec_id = ((uint16_t *)b) [1]; gds2h ((int16_t &) rec_id); if (m_reclen < 4) { error (tl::to_string (QObject::tr ("Invalid record length (less than 4)"))); } if (m_reclen >= 0x8000) { if (m_options.allow_big_records) { warn (tl::to_string (QObject::tr ("Record length larger than 0x8000 encountered: interpreting as unsigned"))); } else { error (tl::to_string (QObject::tr ("Record length larger than 0x8000 encountered (reader is configured not to allow such records)"))); } } if (m_reclen % 2 == 1) { warn (tl::to_string (QObject::tr ("Odd record length"))); } m_reclen -= 4; if (m_reclen > 0) { mp_rec_buf = (unsigned char *) m_stream.get (m_reclen); if (! mp_rec_buf) { error (tl::to_string (QObject::tr ("Unexpected end-of-file"))); } } else { mp_rec_buf = 0; } m_recptr = 0; return rec_id; } inline int GDS2Reader::get_int () { unsigned char *b = mp_rec_buf + m_recptr; m_recptr += 4; int32_t l = *((int32_t *)b); gds2h (l); return l; } inline short GDS2Reader::get_short () { unsigned char *b = mp_rec_buf + m_recptr; m_recptr += 2; int16_t s = *((int16_t *)b); gds2h (s); return s; } inline unsigned short GDS2Reader::get_ushort () { unsigned char *b = mp_rec_buf + m_recptr; m_recptr += 2; uint16_t s = *((uint16_t *)b); gds2h ((int16_t &) s); return s; } inline double GDS2Reader::get_double () { unsigned char *b = mp_rec_buf + m_recptr; m_recptr += 8; uint32_t l0 = ((uint32_t *)b) [0]; gds2h ((int32_t &) l0); l0 &= 0xffffff; uint32_t l1 = ((uint32_t *)b) [1]; gds2h ((int32_t &) l1); double x = 4294967296.0 * double (l0) + double (l1); if (b[0] & 0x80) { x = -x; } int e = int (b[0] & 0x7f) - (64 + 14); if (e != 0) { x *= pow (16.0, double (e)); } return x; } const char * GDS2Reader::get_string () { if (m_reclen == 0) { return ""; } if (mp_rec_buf [m_reclen - 1] == 0) { // we already have a terminating '\0': just return the string's location return (const char *) mp_rec_buf; } else { // use the temporary buffer to create a zero-terminated string m_string_buf.assign ((const char *) mp_rec_buf, 0, m_reclen); return m_string_buf.c_str (); } } void GDS2Reader::get_string (tl::string &s) const { s.assign ((const char *) mp_rec_buf, 0, m_reclen); } void GDS2Reader::get_time (unsigned int *mod_time, unsigned int *access_time) { unsigned int length = (unsigned int) (m_reclen / sizeof (uint16_t)); for (unsigned int l = 0; l < length && l < 6; ++l) { mod_time [l] = get_ushort (); } for (unsigned int l = 0; l + 6 < length && l < 6; ++l) { access_time [l] = get_ushort (); } // correct year if required if (mod_time [0] == 0 && mod_time [1] == 0 && mod_time [2] == 0) { // leave it } else if (mod_time [0] < 50) { mod_time [0] += 2000; } else if (mod_time [0] < 1900) { mod_time [0] += 1900; } if (access_time [0] == 0 && access_time [1] == 0 && access_time [2] == 0) { // leave it } else if (access_time [0] < 50) { access_time [0] += 2000; } else if (access_time [0] < 1900) { access_time [0] += 1900; } } GDS2XY * GDS2Reader::get_xy_data (unsigned int &length) { length = (unsigned int) (m_reclen / sizeof (GDS2XY)); return (GDS2XY *) mp_rec_buf; } void GDS2Reader::progress_checkpoint () { m_progress.set (m_stream.pos ()); } void GDS2Reader::error (const std::string &msg) { throw GDS2ReaderException (msg, m_stream.pos (), m_recnum, cellname ().c_str ()); } void GDS2Reader::warn (const std::string &msg) { // TODO: compress tl::warn << msg << tl::to_string (QObject::tr (" (position=")) << m_stream.pos () << tl::to_string (QObject::tr (", record number=")) << m_recnum << tl::to_string (QObject::tr (", cell=")) << cellname ().c_str () << ")"; } }