klayout/src/db/dbGDS2Reader.cc

278 lines
6.3 KiB
C++

/*
KLayout Layout Viewer
Copyright (C) 2006-2017 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<db::GDS2ReaderOptions> ();
m_common_options = options.get_options<db::CommonReaderOptions> ();
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 ()
<< ")";
}
}