From 170f0a5021b603a4433e30e3a5ec727a4c2b01b9 Mon Sep 17 00:00:00 2001 From: unknown Date: Sun, 1 Jun 2014 18:55:53 +0200 Subject: [PATCH] idf tools: code cleanup and debugging --- utils/idftools/dxf2idfmain.cpp | 2 +- utils/idftools/idf2vrml.cpp | 173 +- utils/idftools/idf_common.cpp | 390 ++-- utils/idftools/idf_common.h | 85 +- utils/idftools/idf_helpers.cpp | 32 +- utils/idftools/idf_helpers.h | 8 +- utils/idftools/idf_outlines.cpp | 2162 +++++++++++++++------- utils/idftools/idf_outlines.h | 400 +++-- utils/idftools/idf_parser.cpp | 2983 +++++++++++++++++-------------- utils/idftools/idf_parser.h | 246 ++- 10 files changed, 4006 insertions(+), 2475 deletions(-) diff --git a/utils/idftools/dxf2idfmain.cpp b/utils/idftools/dxf2idfmain.cpp index 30ad09a527..df804c15be 100644 --- a/utils/idftools/dxf2idfmain.cpp +++ b/utils/idftools/dxf2idfmain.cpp @@ -187,4 +187,4 @@ int main( int argc, char **argv ) fprintf( fp, ".END_ELECTRICAL\n" ); return 0; -} +} \ No newline at end of file diff --git a/utils/idftools/idf2vrml.cpp b/utils/idftools/idf2vrml.cpp index 0032e39b61..dce24f41db 100644 --- a/utils/idftools/idf2vrml.cpp +++ b/utils/idftools/idf2vrml.cpp @@ -31,6 +31,7 @@ * would be more likely if we used a 1:1 scale. */ + #include #include #include @@ -45,6 +46,7 @@ #include #include #include +#include #include #include @@ -111,6 +113,7 @@ VRML_COLOR colors[NCOLORS] = { \ bool WriteHeader( IDF3_BOARD& board, std::ofstream& file ); bool MakeBoard( IDF3_BOARD& board, std::ofstream& file ); bool MakeComponents( IDF3_BOARD& board, std::ofstream& file, bool compact ); +bool MakeOtherOutlines( IDF3_BOARD& board, std::ofstream& file ); bool PopulateVRML( VRML_LAYER& model, const std::list< IDF_OUTLINE* >* items, bool bottom, double scale, double dX = 0.0, double dY = 0.0, double angle = 0.0 ); bool AddSegment( VRML_LAYER& model, IDF_SEGMENT* seg, int icont, int iseg ); @@ -124,12 +127,19 @@ VRML_IDS* GetColor( std::map& cmap, void PrintUsage( void ) { - cout << "-\nUsage: idf2vrml -f input_file.emn -s scale_factor -k\n"; - cout << "flags: -k: produce KiCad-firendly VRML output; default is compact VRML\n-\n"; + cout << "-\nUsage: idf2vrml -f input_file.emn -s scale_factor {-k} {-d} {-z} {-m}\n"; + cout << "flags:\n"; + cout << " -k: produce KiCad-friendly VRML output; default is compact VRML\n"; + cout << " -d: suppress substitution of default outlines\n"; + cout << " -z: suppress rendering of zero-height outlines\n"; + cout << " -m: print object mapping to stdout for debugging purposes\n"; cout << "example to produce a model for use by KiCad: idf2vrml -f input.emn -s 0.3937008 -k\n\n"; return; } +bool nozeroheights; +bool showObjectMapping; + int main( int argc, char **argv ) { // IDF implicitly requires the C locale @@ -148,9 +158,13 @@ int main( int argc, char **argv ) std::string inputFilename; double scaleFactor = 1.0; bool compact = true; + bool nooutlinesubs = false; int ichar; - while( ( ichar = getopt( argc, argv, ":f:s:k" ) ) != -1 ) + nozeroheights = false; + showObjectMapping = false; + + while( ( ichar = getopt( argc, argv, ":f:s:kdzm" ) ) != -1 ) { switch( ichar ) { @@ -184,6 +198,18 @@ int main( int argc, char **argv ) compact = false; break; + case 'd': + nooutlinesubs = true; + break; + + case 'z': + nozeroheights = true; + break; + + case 'm': + showObjectMapping = true; + break; + case ':': cerr << "* Missing parameter to option '-" << ((char) optopt) << "'\n"; PrintUsage(); @@ -215,10 +241,11 @@ int main( int argc, char **argv ) cout << "** Reading file: " << inputFilename << "\n"; - if( !pcb.ReadFile( FROM_UTF8( inputFilename.c_str() ) ) ) + if( !pcb.ReadFile( FROM_UTF8( inputFilename.c_str() ), nooutlinesubs ) ) { - CLEANUP; - cerr << "* Could not read file: " << inputFilename << "\n"; + cerr << "** Failed to read IDF data:\n"; + cerr << pcb.GetError() << "\n\n"; + return -1; } @@ -261,6 +288,9 @@ int main( int argc, char **argv ) // STEP 2: Render the components MakeComponents( pcb, ofile, compact ); + // STEP 3: Render the OTHER outlines + MakeOtherOutlines( pcb, ofile ); + ofile << "]\n}\n"; ofile.close(); @@ -328,7 +358,7 @@ bool MakeBoard( IDF3_BOARD& board, std::ofstream& file ) vpcb.EnsureWinding( 0, false ); - int nvcont = vpcb.GetNContours(); + int nvcont = vpcb.GetNContours() - 1; while( nvcont > 0 ) vpcb.EnsureWinding( nvcont--, true ); @@ -553,13 +583,10 @@ bool WriteTriangles( std::ofstream& file, VRML_IDS* vID, VRML_LAYER* layer, bool file << "coord Coordinate {\n"; file << "point [\n"; - // XXX: TODO: check return values of Write() routines; they may fail - // even though the stream is good (bad internal data) - // Coordinates (vertices) if( plane ) { - if( ! layer->WriteVertices( top_z, file, precision ) ) + if( !layer->WriteVertices( top_z, file, precision ) ) { cerr << "* errors writing planar vertices to " << vID->objectName << "\n"; cerr << "** " << layer->GetError() << "\n"; @@ -567,7 +594,7 @@ bool WriteTriangles( std::ofstream& file, VRML_IDS* vID, VRML_LAYER* layer, bool } else { - if( ! layer->Write3DVertices( top_z, bottom_z, file, precision ) ) + if( !layer->Write3DVertices( top_z, bottom_z, file, precision ) ) { cerr << "* errors writing 3D vertices to " << vID->objectName << "\n"; cerr << "** " << layer->GetError() << "\n"; @@ -717,6 +744,7 @@ bool MakeComponents( IDF3_BOARD& board, std::ofstream& file, bool compact ) std::map< std::string, VRML_IDS*> cmap; // map colors by outline UID VRML_IDS* vcp; + IDF3_COMP_OUTLINE* pout; while( sc != ec ) { @@ -732,12 +760,28 @@ bool MakeComponents( IDF3_BOARD& board, std::ofstream& file, bool compact ) while( so != eo ) { + if( (*so)->GetOutline()->GetThickness() < 0.00000001 && nozeroheights ) + { + vpcb.Clear(); + ++so; + continue; + } + (*so)->GetOffsets( tX, tY, tZ, tA ); tX += vX; tY += vY; tA += vA; - vcp = GetColor( cmap, cidx, ((IDF3_COMP_OUTLINE*)((*so)->GetOutline()))->GetUID() ); + if( ( pout = (IDF3_COMP_OUTLINE*)((*so)->GetOutline()) ) ) + { + vcp = GetColor( cmap, cidx, pout->GetUID() ); + } + else + { + vpcb.Clear(); + ++so; + continue; + } if( !compact ) { @@ -764,6 +808,12 @@ bool MakeComponents( IDF3_BOARD& board, std::ofstream& file, bool compact ) if( !compact || !vcp->used ) { vpcb.EnsureWinding( 0, false ); + + int nvcont = vpcb.GetNContours() - 1; + + while( nvcont > 0 ) + vpcb.EnsureWinding( nvcont--, true ); + vpcb.Tesselate( NULL ); } @@ -792,6 +842,10 @@ bool MakeComponents( IDF3_BOARD& board, std::ofstream& file, bool compact ) vcp = GetColor( cmap, cidx, ((IDF3_COMP_OUTLINE*)((*so)->GetOutline()))->GetUID() ); vcp->bottom = bottom; + // note: this can happen because IDF allows some negative heights/thicknesses + if( bot > top ) + std::swap( bot, top ); + WriteTriangles( file, vcp, &vpcb, false, false, top, bot, board.GetUserPrecision(), compact ); @@ -828,7 +882,8 @@ VRML_IDS* GetColor( std::map& cmap, int& index, const st ostr << "OBJECTn" << refnum++; id->objectName = ostr.str(); - cout << "* " << ostr.str() << " = '" << uid << "'\n"; + if( showObjectMapping ) + cout << "* " << ostr.str() << " = '" << uid << "'\n"; cmap.insert( std::pair(uid, id) ); @@ -840,3 +895,93 @@ VRML_IDS* GetColor( std::map& cmap, int& index, const st return cit->second; } + + +bool MakeOtherOutlines( IDF3_BOARD& board, std::ofstream& file ) +{ + int cidx = 2; // color index; start at 2 since 0,1 are special (board, NOGEOM_NOPART) + + VRML_LAYER vpcb; + + double scale = board.GetUserScale(); + double thick = board.GetBoardThickness() / 2.0; + + // set the arc parameters according to output scale + int tI; + double tMin, tMax; + vpcb.GetArcParams( tI, tMin, tMax ); + vpcb.SetArcParams( tI, tMin * scale, tMax * scale ); + + // Add the component outlines + const std::map< std::string, OTHER_OUTLINE* >*const comp = board.GetOtherOutlines(); + std::map< std::string, OTHER_OUTLINE* >::const_iterator sc = comp->begin(); + std::map< std::string, OTHER_OUTLINE* >::const_iterator ec = comp->end(); + + double top, bot; + bool bottom; + int nvcont; + + std::map< std::string, VRML_IDS*> cmap; // map colors by outline UID + VRML_IDS* vcp; + OTHER_OUTLINE* pout; + + while( sc != ec ) + { + pout = sc->second; + + if( pout->GetSide() == IDF3::LYR_BOTTOM ) + bottom = true; + else + bottom = false; + + if( pout->GetThickness() < 0.00000001 && nozeroheights ) + { + vpcb.Clear(); + ++sc; + continue; + } + + vcp = GetColor( cmap, cidx, pout->GetOutlineIdentifier() ); + + if( !PopulateVRML( vpcb, pout->GetOutlines(), bottom, + board.GetUserScale(), 0, 0, 0 ) ) + { + return false; + } + + vpcb.EnsureWinding( 0, false ); + + nvcont = vpcb.GetNContours() - 1; + + while( nvcont > 0 ) + vpcb.EnsureWinding( nvcont--, true ); + + vpcb.Tesselate( NULL ); + + if( bottom ) + { + top = -thick; + bot = ( top - pout->GetThickness() ) * scale; + top *= scale; + } + else + { + bot = thick; + top = (bot + pout->GetThickness() ) * scale; + bot *= scale; + } + + // note: this can happen because IDF allows some negative heights/thicknesses + if( bot > top ) + std::swap( bot, top ); + + vcp->bottom = bottom; + WriteTriangles( file, vcp, &vpcb, false, + false, top, bot, board.GetUserPrecision(), false ); + + vpcb.Clear(); + ++sc; + } + + return true; +} diff --git a/utils/idftools/idf_common.cpp b/utils/idftools/idf_common.cpp index 492ca928ce..948bf23c66 100644 --- a/utils/idftools/idf_common.cpp +++ b/utils/idftools/idf_common.cpp @@ -23,6 +23,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + #include #include #include @@ -89,7 +90,7 @@ IDF_NOTE::IDF_NOTE() } -bool IDF_NOTE::ReadNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState, +bool IDF_NOTE::readNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState, IDF3::IDF_UNIT aBoardUnit ) { std::string iline; // the input line @@ -104,19 +105,16 @@ bool IDF_NOTE::ReadNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardStat if( ( !aBoardFile.good() && !aBoardFile.eof() ) || iline.empty() ) { - ERROR_IDF; - cerr << "problems reading board notes\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "problems reading board notes" ) ); } if( isComment ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: comment within a section (NOTES)\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: comment within a section (NOTES)" ) ); } idx = 0; @@ -124,21 +122,14 @@ bool IDF_NOTE::ReadNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardStat if( quoted ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: X position in NOTES section must not be in quotes\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: X position in NOTES section must not be in quotes" ) ); } if( CompareToken( ".END_NOTES", token ) ) - { - // the end of the note section is a special case; although we return 'false' - // we do not change the board's state variable and we ensure that errno is 0; - // all other false returns set the state to FILE_INVALID - errno = 0; return false; - } istringstream istr; istr.str( token ); @@ -146,29 +137,26 @@ bool IDF_NOTE::ReadNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardStat istr >> xpos; if( istr.fail() ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: X position in NOTES section is not numeric\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: X position in NOTES section is not numeric" ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: Y position in NOTES section is missing\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: Y position in NOTES section is missing" ) ); } if( quoted ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: Y position in NOTES section must not be in quotes\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: Y position in NOTES section must not be in quotes" ) ); } istr.clear(); @@ -177,29 +165,26 @@ bool IDF_NOTE::ReadNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardStat istr >> ypos; if( istr.fail() ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: Y position in NOTES section is not numeric\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: Y position in NOTES section is not numeric" ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: text height in NOTES section is missing\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: text height in NOTES section is missing" ) ); } if( quoted ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: text height in NOTES section must not be in quotes\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: text height in NOTES section must not be in quotes" ) ); } istr.clear(); @@ -208,29 +193,26 @@ bool IDF_NOTE::ReadNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardStat istr >> height; if( istr.fail() ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: text height in NOTES section is not numeric\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: text height in NOTES section is not numeric" ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: text length in NOTES section is missing\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: text length in NOTES section is missing" ) ); } if( quoted ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: text length in NOTES section must not be in quotes\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: text length in NOTES section must not be in quotes" ) ); } istr.clear(); @@ -239,45 +221,43 @@ bool IDF_NOTE::ReadNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardStat istr >> length; if( istr.fail() ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: text length in NOTES section is not numeric\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: text length in NOTES section is not numeric" ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: text value in NOTES section is missing\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: text value in NOTES section is missing" ) ); } text = token; if( aBoardUnit == UNIT_THOU ) { - xpos *= IDF_MM_TO_THOU; - ypos *= IDF_MM_TO_THOU; - height *= IDF_MM_TO_THOU; - length *= IDF_MM_TO_THOU; + xpos *= IDF_THOU_TO_MM; + ypos *= IDF_THOU_TO_MM; + height *= IDF_THOU_TO_MM; + length *= IDF_THOU_TO_MM; } return true; } -bool IDF_NOTE::WriteNote( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit ) +bool IDF_NOTE::writeNote( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit ) { if( aBoardUnit == UNIT_THOU ) { aBoardFile << setiosflags(ios::fixed) << setprecision(1) - << (xpos / IDF_MM_TO_THOU) << " " - << (ypos / IDF_MM_TO_THOU) << " " - << (height / IDF_MM_TO_THOU) << " " - << (length / IDF_MM_TO_THOU) << " "; + << (xpos / IDF_THOU_TO_MM) << " " + << (ypos / IDF_THOU_TO_MM) << " " + << (height / IDF_THOU_TO_MM) << " " + << (length / IDF_THOU_TO_MM) << " "; } else { @@ -422,8 +402,8 @@ bool IDF_DRILL_DATA::Matches( double aDrillDia, double aPosX, double aPosY ) return false; } -bool IDF_DRILL_DATA::Read( std::ifstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit, - IDF3::FILE_STATE aBoardState ) +bool IDF_DRILL_DATA::read( std::ifstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit, + IDF3::FILE_STATE aBoardState, IDF3::IDF_VERSION aIdfVersion ) { std::string iline; // the input line bool isComment; // true if a line just read in is a comment line @@ -436,161 +416,151 @@ bool IDF_DRILL_DATA::Read( std::ifstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit, while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() ); if( ( !aBoardFile.good() && !aBoardFile.eof() ) || iline.empty() ) - { - ERROR_IDF; - cerr << "problems reading board drilled holes\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "problems reading board drilled holes" ) ); if( isComment ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: comment within a section (DRILLED HOLES)\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: comment within a section (DRILLED HOLES)" ) ); idx = 0; GetIDFString( iline, token, quoted, idx ); if( quoted ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: drill diameter must not be in quotes\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: drill diameter must not be in quotes" ) ); if( CompareToken( ".END_DRILLED_HOLES", token ) ) - { - // the end of the section is a special case; although we return 'false' - // we do not change the board's state variable and we ensure that errno is 0; - // all other false returns set the state to FILE_INVALID - errno = 0; return false; - } istringstream istr; istr.str( token ); istr >> dia; if( istr.fail() ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: drill diameter is not numeric\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: drill diameter is not numeric" ) ); if( ( aBoardUnit == UNIT_MM && dia < IDF_MIN_DIA_MM ) - || ( aBoardUnit != UNIT_MM && dia < IDF_MIN_DIA_THOU ) ) + || ( aBoardUnit == UNIT_THOU && dia < IDF_MIN_DIA_THOU ) + || ( aBoardUnit == UNIT_TNM && dia < IDF_MIN_DIA_TNM ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Invalid drill diameter (too small): " << token << "\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + ostr << "invalid IDF file\n"; + ostr << "* Invalid drill diameter (too small): '" << token << "'"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: missing X position for drilled hole\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: missing X position for drilled hole" ) ); if( quoted ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: X position in DRILLED HOLES section must not be in quotes\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: X position in DRILLED HOLES section must not be in quotes" ) ); istr.clear(); istr.str( token ); istr >> x; if( istr.fail() ) - { - ERROR_IDF; - cerr << "* Violation of specification: X position in DRILLED HOLES section is not numeric\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: X position in DRILLED HOLES section is not numeric" ) ); if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: missing Y position for drilled hole\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: missing Y position for drilled hole" ) ); if( quoted ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: Y position in DRILLED HOLES section must not be in quotes\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: Y position in DRILLED HOLES section must not be in quotes" ) ); istr.clear(); istr.str( token ); istr >> y; if( istr.fail() ) - { - ERROR_IDF; - cerr << "* Violation of specification: Y position in DRILLED HOLES section is not numeric\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: Y position in DRILLED HOLES section is not numeric" ) ); - if( !GetIDFString( iline, token, quoted, idx ) ) + if( aIdfVersion > IDF_V2 ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: missing PLATING for drilled hole\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + if( !GetIDFString( iline, token, quoted, idx ) ) + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: missing PLATING for drilled hole" ) ); - if( CompareToken( "PTH", token ) ) - { - plating = IDF3::PTH; - } - else if( CompareToken( "NPTH", token ) ) - { - plating = IDF3::NPTH; + if( CompareToken( "PTH", token ) ) + { + plating = IDF3::PTH; + } + else if( CompareToken( "NPTH", token ) ) + { + plating = IDF3::NPTH; + } + else + { + ostringstream ostr; + ostr << "invalid IDFv3 file\n"; + ostr << "* Violation of specification: invalid PLATING type ('" << token << "')"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } } else { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: invalid PLATING type ('" << token << "')\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + plating = IDF3::PTH; } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: missing REFDES for drilled hole\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + if( aIdfVersion > IDF_V2 ) + { + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: missing REFDES for drilled hole" ) ); + } + else + { + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv2 file\n" + "* Violation of specification: missing HOLE TYPE for drilled hole" ) ); + } } + std::string tok1 = token; + + if( !GetIDFString( iline, token, quoted, idx ) ) + { + if( aIdfVersion > IDF_V2 ) + { + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: missing HOLE TYPE for drilled hole" ) ); + } + else + { + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv2 file\n" + "* Violation of specification: missing REFDES for drilled hole" ) ); + } + } + + std::string tok2 = token; + + if( aIdfVersion > IDF_V2 ) + token = tok1; + if( CompareToken( "BOARD", token ) ) { kref = IDF3::BOARD; @@ -609,14 +579,10 @@ bool IDF_DRILL_DATA::Read( std::ifstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit, refdes = token; } - if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: missing HOLE TYPE for drilled hole\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + if( aIdfVersion > IDF_V2 ) + token = tok2; + else + token = tok1; if( CompareToken( "PIN", token ) ) { @@ -640,35 +606,51 @@ bool IDF_DRILL_DATA::Read( std::ifstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit, holetype = token; } - if( !GetIDFString( iline, token, quoted, idx ) ) + if( aIdfVersion > IDF_V2 ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: missing OWNER for drilled hole\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + if( !GetIDFString( iline, token, quoted, idx ) ) + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv3 file\n" + "* Violation of specification: missing OWNER for drilled hole" ) ); - if( !ParseOwner( token, owner ) ) + if( !ParseOwner( token, owner ) ) + { + ostringstream ostr; + ostr << "invalid IDFv3 file\n"; + ostr << "* Violation of specification: invalid OWNER for drilled hole ('" << token << "')"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + } + else { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: invalid OWNER for drilled hole ('" << token << "')\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + owner = IDF3::UNOWNED; } if( aBoardUnit == UNIT_THOU ) { - dia *= IDF_MM_TO_THOU; - x *= IDF_MM_TO_THOU; - y *= IDF_MM_TO_THOU; + dia *= IDF_THOU_TO_MM; + x *= IDF_THOU_TO_MM; + y *= IDF_THOU_TO_MM; + } + else if( ( aIdfVersion == IDF_V2 ) && ( aBoardUnit == UNIT_TNM ) ) + { + dia *= IDF_TNM_TO_MM; + x *= IDF_TNM_TO_MM; + y *= IDF_TNM_TO_MM; + } + else if( aBoardUnit != UNIT_MM ) + { + ostringstream ostr; + ostr << "\n* BUG: invalid UNIT type: " << aBoardUnit; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } return true; } -bool IDF_DRILL_DATA::Write( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit ) +void IDF_DRILL_DATA::write( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit ) { std::string holestr; std::string refstr; @@ -746,13 +728,13 @@ bool IDF_DRILL_DATA::Write( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit } else { - aBoardFile << std::setiosflags( std::ios::fixed ) << std::setprecision( 1 ) << (dia / IDF_MM_TO_THOU) << " " - << std::setprecision( 1 ) << (x / IDF_MM_TO_THOU) << " " << (y / IDF_MM_TO_THOU) << " " + aBoardFile << std::setiosflags( std::ios::fixed ) << std::setprecision( 1 ) << (dia / IDF_THOU_TO_MM) << " " + << std::setprecision( 1 ) << (x / IDF_THOU_TO_MM) << " " << (y / IDF_THOU_TO_MM) << " " << pltstr.c_str() << " " << refstr.c_str() << " " << holestr.c_str() << " " << ownstr.c_str() << "\n"; } - return ! aBoardFile.fail(); + return; } // IDF_DRILL_DATA::Write( aBoardFile, unitMM ) diff --git a/utils/idftools/idf_common.h b/utils/idftools/idf_common.h index ffa9faf7f2..ac8a4db382 100644 --- a/utils/idftools/idf_common.h +++ b/utils/idftools/idf_common.h @@ -86,6 +86,16 @@ namespace IDF3 { FILE_ERROR // other errors while processing the file }; + /** + * ENUM IDF_VERSION + * represents the supported IDF versions (3.0 and 2.0 ONLY) + */ + enum IDF_VERSION + { + IDF_V2 = 0, // version 2 has read support only; files written as IDFv3 + IDF_V3 // version 3 has full read/write support + }; + /** * ENUM KEY_OWNER * represents the type of CAD which has ownership an object @@ -194,6 +204,7 @@ namespace IDF3 { { UNIT_MM = 0, //< Units in the file are in millimeters UNIT_THOU, //< Units in the file are in mils (aka thou) + UNIT_TNM, //< Deprecated Ten Nanometer Units from IDFv2 UNIT_INVALID }; @@ -261,6 +272,7 @@ namespace IDF3 { */ class IDF_NOTE { +friend class IDF3_BOARD; private: std::string text; // note text as per IDFv3 double xpos; // text X position as per IDFv3 @@ -268,11 +280,8 @@ private: double height; // text height as per IDFv3 double length; // text length as per IDFv3 -public: - IDF_NOTE(); - /** - * Function ReadNote + * Function readNote * reads a note entry from an IDFv3 file * * @param aBoardFile is an open BOARD file; the file position must be set to the start of a NOTE entry @@ -282,10 +291,10 @@ public: * @return bool: true if a note item was read, false otherwise. In case of unrecoverable errors * an exception is thrown */ - bool ReadNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState, IDF3::IDF_UNIT aBoardUnit ); + bool readNote( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState, IDF3::IDF_UNIT aBoardUnit ); /** - * Function WriteNote + * Function writeNote * writes a note entry to an IDFv3 file * * @param aBoardFile is an open BOARD file; the file position must be within a NOTE section @@ -294,7 +303,10 @@ public: * @return bool: true if the item was successfully written, false otherwise. In case of * unrecoverable errors an exception is thrown */ - bool WriteNote( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit ); + bool writeNote( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit ); + +public: + IDF_NOTE(); /** * Function SetText @@ -341,6 +353,8 @@ public: */ class IDF_DRILL_DATA { +friend class IDF3_BOARD; +friend class IDF3_COMPONENT; private: double dia; double x; @@ -352,11 +366,35 @@ private: std::string holetype; IDF3::KEY_OWNER owner; + /** + * Function read + * read a drill entry from an IDFv3 file + * + * @param aBoardFile is an open IDFv3 file; the file position must be within the DRILLED_HOLES section + * @param aBoardUnit is the board file's native unit (MM or THOU) + * @param aBoardState is the state value of the parser + * + * @return bool: true if data was successfully read, otherwise false. In case of an + * unrecoverable error an exception is thrown + */ + bool read( std::ifstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit, IDF3::FILE_STATE aBoardState, + IDF3::IDF_VERSION aIdfVersion ); + + /** + * Function write + * writes a single line representing a hole within a .DRILLED_HOLES section + * In case of an unrecoverable error an exception is thrown. + * + * @param aBoardFile is an open BOARD file + * @param aBoardUnit is the native unit of the output file + */ + void write( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit ); + public: /** * Constructor IDF_DRILL_DATA * creates an empty drill entry which can be populated by the - * Read() function + * read() function */ IDF_DRILL_DATA(); @@ -391,38 +429,12 @@ public: */ bool Matches( double aDrillDia, double aPosX, double aPosY ); - /** - * Function Read - * read a drill entry from an IDFv3 file - * - * @param aBoardFile is an open IDFv3 file; the file position must be within the DRILLED_HOLES section - * @param aBoardUnit is the board file's native unit (MM or THOU) - * @param aBoardState is the state value of the parser - * - * @return bool: true if data was successfully read, otherwise false. In case of an - * unrecoverable error an exception is thrown - */ - bool Read( std::ifstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit, IDF3::FILE_STATE aBoardState ); - - /** - * Function Write - * writes a single line representing a hole within a .DRILLED_HOLES section - * - * @param aBoardFile is an open BOARD file - * @param aBoardUnit is the native unit of the output file - * - * @return bool: true if the data was successfully written, otherwise false. In case of - * an unrecoverable error an exception is thrown - */ - bool Write( std::ofstream& aBoardFile, IDF3::IDF_UNIT aBoardUnit ); - /** * Function GettDrillDia * returns the drill diameter in mm */ double GetDrillDia(); - /** * Function GettDrillXPos * returns the drill's X position in mm @@ -455,6 +467,11 @@ public: * PIN, VIA, MTG, TOOL, or a user-specified string */ const std::string& GetDrillHoleType(); + + IDF3::KEY_OWNER GetDrillOwner( void ) + { + return owner; + } }; diff --git a/utils/idftools/idf_helpers.cpp b/utils/idftools/idf_helpers.cpp index a1c7141acb..cad1852732 100644 --- a/utils/idftools/idf_helpers.cpp +++ b/utils/idftools/idf_helpers.cpp @@ -229,8 +229,13 @@ bool IDF3::WriteLayersText( std::ofstream& aBoardFile, IDF3::IDF_LAYER aLayer ) break; default: - ERROR_IDF << "Invalid IDF layer" << aLayer << "\n"; - return false; + do{ + std::ostringstream ostr; + ostr << "invalid IDF layer: " << aLayer; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } while( 0 ); + break; } @@ -293,3 +298,26 @@ std::string IDF3::GetLayerString( IDF3::IDF_LAYER aLayer ) return ostr.str(); } + +std::string IDF3::GetOwnerString( IDF3::KEY_OWNER aOwner ) +{ + switch( aOwner ) + { + case IDF3::UNOWNED: + return "UNOWNED"; + + case IDF3::MCAD: + return "MCAD"; + + case IDF3::ECAD: + return "ECAD"; + + default: + break; + } + + ostringstream ostr; + ostr << "UNKNOWN: " << aOwner; + + return ostr.str(); +} diff --git a/utils/idftools/idf_helpers.h b/utils/idftools/idf_helpers.h index da392f0774..9b0c33fc6e 100644 --- a/utils/idftools/idf_helpers.h +++ b/utils/idftools/idf_helpers.h @@ -59,9 +59,12 @@ static inline wxString FROM_UTF8( const char* cstring ) // minimum drill diameters / slot widths to be represented in the IDF output #define IDF_MIN_DIA_MM ( 0.001 ) #define IDF_MIN_DIA_THOU ( 0.00039 ) +#define IDF_MIN_DIA_TNM ( 100 ) -// conversion between mm and thou -#define IDF_MM_TO_THOU 0.0254 +// conversion from thou to mm +#define IDF_THOU_TO_MM 0.0254 +// conversion from TNM to mm +#define IDF_TNM_TO_MM 0.00001 namespace IDF3 { @@ -166,6 +169,7 @@ std::string GetPlacementString( IDF3::IDF_PLACEMENT aPlacement ); */ std::string GetLayerString( IDF3::IDF_LAYER aLayer ); +std::string GetOwnerString( IDF3::KEY_OWNER aOwner ); } #endif // IDF_HELPERS_H diff --git a/utils/idftools/idf_outlines.cpp b/utils/idftools/idf_outlines.cpp index 67779a407b..9558d7dab2 100644 --- a/utils/idftools/idf_outlines.cpp +++ b/utils/idftools/idf_outlines.cpp @@ -34,6 +34,98 @@ using namespace IDF3; using namespace std; +static std::string GetOutlineTypeString( IDF3::OUTLINE_TYPE aOutlineType ) +{ + switch( aOutlineType ) + { + case OTLN_BOARD: + return ".BOARD_OUTLINE"; + + case OTLN_OTHER: + return ".OTHER_OUTLINE"; + + case OTLN_PLACE: + return ".PLACEMENT_OUTLINE"; + + case OTLN_ROUTE: + return ".ROUTE_OUTLINE"; + + case OTLN_PLACE_KEEPOUT: + return ".PLACE_KEEPOUT"; + + case OTLN_ROUTE_KEEPOUT: + return ".ROUTE_KEEPOUT"; + + case OTLN_VIA_KEEPOUT: + return ".VIA_KEEPOUT"; + + case OTLN_GROUP_PLACE: + return ".PLACE_REGION"; + + case OTLN_COMPONENT: + return "COMPONENT OUTLINE"; + + default: + break; + } + + std::ostringstream ostr; + ostr << "[INVALID OUTLINE TYPE VALUE]:" << aOutlineType; + + return ostr.str(); +} + +#ifndef DISABLE_IDF_OWNERSHIP +static bool CheckOwnership( int aSourceLine, const char* aSourceFunc, + IDF3_BOARD* aParent, IDF3::KEY_OWNER aOwnerCAD, + IDF3::OUTLINE_TYPE aOutlineType, std::string& aErrorString ) +{ + if( aParent == NULL ) + { + ostringstream ostr; + ostr << "* " << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n"; + ostr << "* BUG: outline's parent not set; cannot enforce ownership rules\n"; + ostr << "* outline type: " << GetOutlineTypeString( aOutlineType ); + aErrorString = ostr.str(); + + return false; + } + + // note: component outlines have no owner so we don't care about + // who modifies them + if( aOwnerCAD == UNOWNED || aOutlineType == IDF3::OTLN_COMPONENT ) + return true; + + IDF3::CAD_TYPE parentCAD = aParent->GetCadType(); + + if( aOwnerCAD == MCAD && parentCAD == CAD_MECH ) + return true; + + if( aOwnerCAD == ECAD && parentCAD == CAD_ELEC ) + return true; + + do + { + ostringstream ostr; + ostr << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n"; + ostr << "* ownership violation; CAD type is "; + + if( parentCAD == CAD_MECH ) + ostr << "MCAD "; + else + ostr << "ECAD "; + + ostr << "while outline owner is " << GetOwnerString( aOwnerCAD ) << "\n"; + ostr << "* outline type: " << GetOutlineTypeString( aOutlineType ); + aErrorString = ostr.str(); + + } while( 0 ); + + return false; +} +#endif + + /* * CLASS: BOARD OUTLINE */ @@ -50,7 +142,7 @@ BOARD_OUTLINE::BOARD_OUTLINE() BOARD_OUTLINE::~BOARD_OUTLINE() { - Clear(); + clear(); return; } @@ -59,7 +151,7 @@ IDF3::OUTLINE_TYPE BOARD_OUTLINE::GetOutlineType( void ) return outlineType; } -bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) +void BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile, IDF3::IDF_VERSION aIdfVersion ) { // reads the outline data from a file double x, y, ang; @@ -81,7 +173,7 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) std::streampos pos; // destroy any existing outline data - ClearOutlines(); + clearOutlines(); while( aBoardFile.good() ) { @@ -93,9 +185,13 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) if( quoted ) { - ERROR_IDF << "invalid outline; FIELD 1 is quoted\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " << GetOutlineTypeString( outlineType ); + ostr << " is quoted\n"; + ostr << "* line: '" << iline << "'"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } // check for the end of the section @@ -110,8 +206,11 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) { if( npts > 0 && !closed ) { - ERROR_IDF << "invalid outline (not closed)\n"; - return false; + ostringstream ostr; + ostr << "invalid outline (not closed)\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } // verify winding @@ -120,24 +219,21 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) if( !outlines.front()->IsCCW() ) { ERROR_IDF << "invalid IDF3 file (BOARD_OUTLINE)\n"; - cerr << "* first outline is not in CCW order\n"; -//#warning TO BE IMPLEMENTED - // outlines.front()->EnsureWinding( false ); - return true; + cerr << "* WARNING: first outline is not in CCW order\n"; + return; } if( outlines.size() > 1 && outlines.back()->IsCCW() && !outlines.back()->IsCircle() ) { ERROR_IDF << "invalid IDF3 file (BOARD_OUTLINE)\n"; - cerr << "* cutout points are not in CW order\n"; -//#warning TO BE IMPLEMENTED - // outlines.front()->EnsureWinding( true ); - return true; + cerr << "* WARNING: final cutout does not have points in CW order\n"; + cerr << "* file position: " << pos << "\n"; + return; } } } - return true; + return; } tstr.clear(); @@ -149,23 +245,44 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) if( outlineType == OTLN_COMPONENT && CompareToken( "PROP", entry ) ) { aBoardFile.seekg( pos ); - return true; + return; } - ERROR_IDF << "invalid outline; FIELD 1 is not numeric\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + do{ + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " << GetOutlineTypeString( outlineType ); + ostr << " is not numeric\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + + } while( 0 ); } if( tmp != loopidx ) { // index change + if( npts > 0 && !closed ) + { + ostringstream ostr; + ostr << "invalid outline ( outline # " << loopidx << " not closed)\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } if( tmp < 0 ) { - ERROR_IDF << "invalid outline; FIELD 1 is invalid\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " << GetOutlineTypeString( outlineType ); + ostr << " is invalid\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( loopidx == -1 ) @@ -177,19 +294,27 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) if( tmp == 0 || tmp == 1 ) { op = new IDF_OUTLINE; + if( op == NULL ) { - ERROR_IDF << "memory allocation failed\n"; - return false; + clearOutlines(); + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "memory allocation failed" ) ); } + outlines.push_back( op ); loopidx = tmp; } else { - ERROR_IDF << "invalid outline; FIELD 1 is invalid (must be 0 or 1)\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " << GetOutlineTypeString( outlineType ); + ostr << " is invalid (must be 0 or 1)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } } else @@ -197,17 +322,23 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) // outline *MUST* have a Loop Index of 0 if( tmp != 0 ) { - ERROR_IDF << "invalid outline; first outline of a BOARD or PANEL must have a Loop Index of 0\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " << GetOutlineTypeString( outlineType ); + ostr << " is invalid (must be 0)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } op = new IDF_OUTLINE; if( op == NULL ) { - ERROR_IDF << "memory allocation failed\n"; - return false; + clearOutlines(); + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "memory allocation failed" ) ); } outlines.push_back( op ); @@ -220,33 +351,49 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) // outline for cutout if( single ) { - ERROR_IDF << "invalid outline; a simple outline type may only have one outline\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ); + ostr << " section may only have one outline\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( tmp - loopidx != 1 ) { - ERROR_IDF << "invalid outline; cutouts must be numbered in order from 1 onwards\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ); + ostr << " section must have cutouts in numeric order from 1 onwards\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } // verify winding of previous outline if( ( loopidx = 0 && !op->IsCCW() ) || ( loopidx > 0 && op->IsCCW() ) ) { - ERROR_IDF << "invalid outline (violation of loop point order rules by Loop Index " - << loopidx << ")\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation of loop point order rules by Loop Index " << loopidx << "\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } op = new IDF_OUTLINE; if( op == NULL ) { - ERROR_IDF << "memory allocation failed\n"; - return false; + clearOutlines(); + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "memory allocation failed" ) ); } outlines.push_back( op ); @@ -259,23 +406,38 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) if( op == NULL ) { - ERROR_IDF << "invalid outline; FIELD 1 is invalid\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 1 of " << GetOutlineTypeString( outlineType ); + ostr << " is invalid\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, entry, quoted, idx ) ) { - ERROR_IDF << "invalid RECORD 3, FIELD 2 does not exist\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 2 of "; + ostr << GetOutlineTypeString( outlineType ) << " does not exist\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( quoted ) { - ERROR_IDF << "invalid RECORD 3, FIELD 2 is quoted\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 2 of "; + ostr << GetOutlineTypeString( outlineType ) << " must not be in quotes\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } tstr.clear(); @@ -284,23 +446,38 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) tstr >> x; if( tstr.fail() ) { - ERROR_IDF << "invalid RECORD 3, invalid X value in FIELD 2\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 2 of "; + ostr << GetOutlineTypeString( outlineType ) << " is an invalid X value\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, entry, quoted, idx ) ) { - ERROR_IDF << "invalid RECORD 3, FIELD 3 does not exist\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 3 of "; + ostr << GetOutlineTypeString( outlineType ) << " does not exist\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( quoted ) { - ERROR_IDF << "invalid RECORD 3, FIELD 3 is quoted\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 3 of "; + ostr << GetOutlineTypeString( outlineType ) << " must not be in quotes\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } tstr.clear(); @@ -309,23 +486,38 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) tstr >> y; if( tstr.fail() ) { - ERROR_IDF << "invalid RECORD 3, invalid Y value in FIELD 3\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 3 of "; + ostr << GetOutlineTypeString( outlineType ) << " is an invalid Y value\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, entry, quoted, idx ) ) { - ERROR_IDF << "invalid RECORD 3, FIELD 4 does not exist\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 4 of "; + ostr << GetOutlineTypeString( outlineType ) << " does not exist\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( quoted ) { - ERROR_IDF << "invalid RECORD 3, FIELD 4 is quoted\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 4 of "; + ostr << GetOutlineTypeString( outlineType ) << " must not be in quotes\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } tstr.clear(); @@ -334,16 +526,33 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) tstr >> ang; if( tstr.fail() ) { - ERROR_IDF << "invalid ANGLE value in FIELD 3\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3, FIELD 4 of "; + ostr << GetOutlineTypeString( outlineType ) << " is not a valid angle\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } // the line was successfully read; convert to mm if necessary if( unit == UNIT_THOU ) { - x *= IDF_MM_TO_THOU; - y *= IDF_MM_TO_THOU; + x *= IDF_THOU_TO_MM; + y *= IDF_THOU_TO_MM; + } + else if( ( aIdfVersion == IDF_V2 ) && ( unit == UNIT_TNM ) ) + { + x *= IDF_TNM_TO_MM; + y *= IDF_TNM_TO_MM; + } + else if( unit != UNIT_MM ) + { + ostringstream ostr; + ostr << "\n* BUG: invalid UNIT type: " << unit; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( npts++ == 0 ) @@ -355,9 +564,15 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) // ensure that the first point is not an arc specification if( ang < -MIN_ANG || ang > MIN_ANG ) { - ERROR_IDF << "invalid RECORD 3, first point has non-zero angle\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3 of "; + ostr << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: first point of an outline has a non-zero angle\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } } else @@ -365,9 +580,15 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) // Nth point if( closed ) { - ERROR_IDF << "invalid RECORD 3; adding a segment to a closed outline\n"; - std::cerr << " LINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3 of "; + ostr << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: adding a segment to a closed outline\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } curPt.x = x; @@ -384,8 +605,9 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) if( sp == NULL ) { - ERROR_IDF << "memory allocation failure\n"; - return false; + clearOutlines(); + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "memory allocation failed" ) ); } if( sp->IsCircle() ) @@ -393,10 +615,17 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) // this is a circle; the loop is closed if( op->size() != 0 ) { - ERROR_IDF << "invalid RECORD 3; adding a circle to a non-empty outline\n"; - std::cerr << " LINE: " << iline << "\n"; delete sp; - return false; + + ostringstream ostr; + + ostr << "\n* invalid outline: RECORD 3 of "; + ostr << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: adding a circle to a non-empty outline\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } closed = true; @@ -414,10 +643,12 @@ bool BOARD_OUTLINE::readOutlines( std::ifstream& aBoardFile ) } // while( aBoardFile.good() ) // NOTE: - // 1. ideally we would ensure that there are no arcs with a radius of 0; this entails - // actively calculating the last point as the previous entry could have been an instruction + // 1. ideally we would ensure that there are no arcs with a radius of 0 - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "problems reading file (premature end of outline)" ) ); + + return; } bool BOARD_OUTLINE::writeComments( std::ofstream& aBoardFile ) @@ -457,28 +688,23 @@ bool BOARD_OUTLINE::writeOwner( std::ofstream& aBoardFile ) return !aBoardFile.fail(); } -bool BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutline, size_t aIndex ) +void BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutline, size_t aIndex ) { - // TODO: check the stream integrity - std::list::iterator bo; std::list::iterator eo; if( aOutline->size() == 1 ) { if( !aOutline->front()->IsCircle() ) - { - // this is a bad outline - ERROR_IDF << "bad outline (single segment item, not circle)\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "bad outline (single segment item, not circle)" ) ); if( single ) aIndex = 0; // NOTE: a circle always has an angle of 360, never -360, // otherwise SolidWorks chokes on the file. - if( unit == UNIT_MM ) + if( unit != UNIT_THOU ) { aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(5) << aOutline->front()->startPoint.x << " " @@ -491,15 +717,15 @@ bool BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli else { aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << (aOutline->front()->startPoint.x / IDF_MM_TO_THOU) << " " - << (aOutline->front()->startPoint.y / IDF_MM_TO_THOU) << " 0\n"; + << (aOutline->front()->startPoint.x / IDF_THOU_TO_MM) << " " + << (aOutline->front()->startPoint.y / IDF_THOU_TO_MM) << " 0\n"; aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << (aOutline->front()->endPoint.x / IDF_MM_TO_THOU) << " " - << (aOutline->front()->endPoint.y / IDF_MM_TO_THOU) << " 360\n"; + << (aOutline->front()->endPoint.x / IDF_THOU_TO_MM) << " " + << (aOutline->front()->endPoint.y / IDF_THOU_TO_MM) << " 360\n"; } - return !aBoardFile.fail(); + return; } // ensure that the very last point is the same as the very first point @@ -524,7 +750,7 @@ bool BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli --bo; // for the first item we write out both points - if( unit == UNIT_MM ) + if( unit != UNIT_THOU ) { if( aOutline->front()->angle < MIN_ANG && aOutline->front()->angle > -MIN_ANG ) { @@ -553,22 +779,22 @@ bool BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli if( aOutline->front()->angle < MIN_ANG && aOutline->front()->angle > -MIN_ANG ) { aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << (aOutline->front()->endPoint.x / IDF_MM_TO_THOU) << " " - << (aOutline->front()->endPoint.y / IDF_MM_TO_THOU) << " 0\n"; + << (aOutline->front()->endPoint.x / IDF_THOU_TO_MM) << " " + << (aOutline->front()->endPoint.y / IDF_THOU_TO_MM) << " 0\n"; aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << (aOutline->front()->startPoint.x / IDF_MM_TO_THOU) << " " - << (aOutline->front()->startPoint.y / IDF_MM_TO_THOU) << " 0\n"; + << (aOutline->front()->startPoint.x / IDF_THOU_TO_MM) << " " + << (aOutline->front()->startPoint.y / IDF_THOU_TO_MM) << " 0\n"; } else { aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << (aOutline->front()->endPoint.x / IDF_MM_TO_THOU) << " " - << (aOutline->front()->endPoint.y / IDF_MM_TO_THOU) << " 0\n"; + << (aOutline->front()->endPoint.x / IDF_THOU_TO_MM) << " " + << (aOutline->front()->endPoint.y / IDF_THOU_TO_MM) << " 0\n"; aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << (aOutline->front()->startPoint.x / IDF_MM_TO_THOU) << " " - << (aOutline->front()->startPoint.y / IDF_MM_TO_THOU) << " " + << (aOutline->front()->startPoint.x / IDF_THOU_TO_MM) << " " + << (aOutline->front()->startPoint.y / IDF_THOU_TO_MM) << " " << setprecision(5) << -aOutline->front()->angle << "\n"; } } @@ -576,7 +802,7 @@ bool BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli // for all other segments we only write out the start point while( bo != eo ) { - if( unit == UNIT_MM ) + if( unit != UNIT_THOU ) { if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG ) { @@ -597,14 +823,14 @@ bool BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG ) { aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << ((*bo)->startPoint.x / IDF_MM_TO_THOU) << " " - << ((*bo)->startPoint.y / IDF_MM_TO_THOU) << " 0\n"; + << ((*bo)->startPoint.x / IDF_THOU_TO_MM) << " " + << ((*bo)->startPoint.y / IDF_THOU_TO_MM) << " 0\n"; } else { aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << ((*bo)->startPoint.x / IDF_MM_TO_THOU) << " " - << ((*bo)->startPoint.y / IDF_MM_TO_THOU) << " " + << ((*bo)->startPoint.x / IDF_THOU_TO_MM) << " " + << ((*bo)->startPoint.y / IDF_THOU_TO_MM) << " " << setprecision(5) << -(*bo)->angle << "\n"; } } @@ -618,7 +844,7 @@ bool BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli eo = aOutline->end(); // for the first item we write out both points - if( unit == UNIT_MM ) + if( unit != UNIT_THOU ) { if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG ) { @@ -647,22 +873,22 @@ bool BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG ) { aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << ((*bo)->startPoint.x / IDF_MM_TO_THOU) << " " - << ((*bo)->startPoint.y / IDF_MM_TO_THOU) << " 0\n"; + << ((*bo)->startPoint.x / IDF_THOU_TO_MM) << " " + << ((*bo)->startPoint.y / IDF_THOU_TO_MM) << " 0\n"; aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << ((*bo)->endPoint.x / IDF_MM_TO_THOU) << " " - << ((*bo)->endPoint.y / IDF_MM_TO_THOU) << " 0\n"; + << ((*bo)->endPoint.x / IDF_THOU_TO_MM) << " " + << ((*bo)->endPoint.y / IDF_THOU_TO_MM) << " 0\n"; } else { aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << ((*bo)->startPoint.x / IDF_MM_TO_THOU) << " " - << ((*bo)->startPoint.y / IDF_MM_TO_THOU) << " 0\n"; + << ((*bo)->startPoint.x / IDF_THOU_TO_MM) << " " + << ((*bo)->startPoint.y / IDF_THOU_TO_MM) << " 0\n"; aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << ((*bo)->endPoint.x / IDF_MM_TO_THOU) << " " - << ((*bo)->endPoint.y / IDF_MM_TO_THOU) << " " + << ((*bo)->endPoint.x / IDF_THOU_TO_MM) << " " + << ((*bo)->endPoint.y / IDF_THOU_TO_MM) << " " << setprecision(5) << (*bo)->angle << "\n"; } } @@ -672,7 +898,7 @@ bool BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli // for all other segments we only write out the last point while( bo != eo ) { - if( unit == UNIT_MM ) + if( unit != UNIT_THOU ) { if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG ) { @@ -693,14 +919,14 @@ bool BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli if( (*bo)->angle < MIN_ANG && (*bo)->angle > -MIN_ANG ) { aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << ((*bo)->endPoint.x / IDF_MM_TO_THOU) << " " - << ((*bo)->endPoint.y / IDF_MM_TO_THOU) << " 0\n"; + << ((*bo)->endPoint.x / IDF_THOU_TO_MM) << " " + << ((*bo)->endPoint.y / IDF_THOU_TO_MM) << " 0\n"; } else { aBoardFile << aIndex << " " << setiosflags(ios::fixed) << setprecision(1) - << ((*bo)->endPoint.x / IDF_MM_TO_THOU) << " " - << ((*bo)->endPoint.y / IDF_MM_TO_THOU) << " " + << ((*bo)->endPoint.x / IDF_THOU_TO_MM) << " " + << ((*bo)->endPoint.y / IDF_THOU_TO_MM) << " " << setprecision(5) << (*bo)->angle << "\n"; } } @@ -709,13 +935,13 @@ bool BOARD_OUTLINE::writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutli } } - return !aBoardFile.fail(); + return; } -bool BOARD_OUTLINE::writeOutlines( std::ofstream& aBoardFile ) +void BOARD_OUTLINE::writeOutlines( std::ofstream& aBoardFile ) { if( outlines.empty() ) - return true; + return; int idx = 0; std::list< IDF_OUTLINE* >::iterator itS = outlines.begin(); @@ -723,19 +949,30 @@ bool BOARD_OUTLINE::writeOutlines( std::ofstream& aBoardFile ) while( itS != itE ) { - if( !writeOutline( aBoardFile, *itS, idx++ ) ) - return false; - + writeOutline( aBoardFile, *itS, idx++ ); ++itS; } - return true; + return; } -void BOARD_OUTLINE::SetUnit( IDF3::IDF_UNIT aUnit ) +bool BOARD_OUTLINE::SetUnit( IDF3::IDF_UNIT aUnit ) { + // note: although UNIT_TNM is accepted here without reservation, + // this can only affect data being read from a file. + if( aUnit != UNIT_MM && aUnit != UNIT_THOU && aUnit != UNIT_TNM ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: invalid IDF UNIT (must be one of UNIT_MM or UNIT_THOU): " << aUnit << "\n"; + ostr << "* outline type: " << GetOutlineTypeString( outlineType ); + errormsg = ostr.str(); + + return false; + } + unit = aUnit; - return; + return true; } IDF3::IDF_UNIT BOARD_OUTLINE::GetUnit( void ) @@ -743,21 +980,40 @@ IDF3::IDF_UNIT BOARD_OUTLINE::GetUnit( void ) return unit; } -bool BOARD_OUTLINE::SetThickness( double aThickness ) +bool BOARD_OUTLINE::setThickness( double aThickness ) { if( aThickness < 0.0 ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: aThickness < 0.0\n"; + ostr << "* outline type: " << GetOutlineTypeString( outlineType ); + errormsg = ostr.str(); + return false; + } thickness = aThickness; return true; } +bool BOARD_OUTLINE::SetThickness( double aThickness ) +{ +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + + return setThickness( aThickness ); +} + double BOARD_OUTLINE::GetThickness( void ) { return thickness; } -bool BOARD_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHeader ) +void BOARD_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHeader, + IDF3::IDF_VERSION aIdfVersion ) { // BOARD_OUTLINE (PANEL_OUTLINE) // .BOARD_OUTLINE [OWNER] @@ -768,30 +1024,42 @@ bool BOARD_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea std::string token; bool quoted = false; int idx = 0; + std::streampos pos; + + pos = aBoardFile.tellg(); if( !GetIDFString( aHeader, token, quoted, idx ) ) - { - ERROR_IDF << "invalid invocation; blank header line\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, "invalid invocation: blank header line" ) ); if( quoted ) { - ERROR_IDF << "section names may not be quoted:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: section names may not be in quotes\n"; + ostr << "* line: '" << aHeader << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !CompareToken( ".BOARD_OUTLINE", token ) ) { - ERROR_IDF << "not a board outline:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: not a board outline\n"; + ostr << "* line: '" << aHeader << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( aHeader, token, quoted, idx ) ) { - ERROR_IDF << "no OWNER; setting to UNOWNED\n"; + if( aIdfVersion > IDF_V2 ) + ERROR_IDF << "no OWNER; setting to UNOWNED\n"; + owner = UNOWNED; } else @@ -806,27 +1074,41 @@ bool BOARD_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea // check RECORD 2 std::string iline; bool comment = false; - std::streampos pos; - while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) ); if( ( !aBoardFile.good() && !aBoardFile.eof() ) || iline.empty() ) { - ERROR_IDF << "bad .BOARD_OUTLINE section (premature end)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: premature end\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } idx = 0; if( comment ) { - ERROR_IDF << "comment within .BOARD_OUTLINE section\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within .BOARD_OUTLINE section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad .BOARD_OUTLINE section (no thickness)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no thickness specified\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } std::stringstream teststr; @@ -835,44 +1117,96 @@ bool BOARD_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea teststr >> thickness; if( teststr.fail() ) { - ERROR_IDF << "bad .BOARD_OUTLINE section (invalid RECORD 2)\n"; - std::cerr << "\tLINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: invalid RECORD 2 (thickness)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( unit == UNIT_THOU ) - thickness *= IDF_MM_TO_THOU; + { + thickness *= IDF_THOU_TO_MM; + } + else if( ( aIdfVersion == IDF_V2 ) && ( unit == UNIT_TNM ) ) + { + thickness *= IDF_TNM_TO_MM; + } + else if( unit != UNIT_MM ) + { + ostringstream ostr; + ostr << "\n* BUG: invalid UNIT type: " << unit; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + // for some unknown reason IDF allows 0 or negative thickness, but this + // is a problem so we fix it here + if( thickness <= 0.0 ) + { + if( thickness == 0.0 ) + { + ERROR_IDF << "\n* WARNING: setting board thickness to default 1.6mm ("; + cerr << thickness << ")\n"; + thickness = 1.6; + } + else + { + thickness = -thickness; + ERROR_IDF << "\n* WARNING: setting board thickness to positive number ("; + cerr << thickness << ")\n"; + } + } // read RECORD 3 values - // XXX - check the return value - we may have empty lines and what-not - readOutlines( aBoardFile ); + readOutlines( aBoardFile, aIdfVersion ); // check RECORD 4 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) ); if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() ) { - ERROR_IDF << "bad .BOARD_OUTLINE section (premature end)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: premature end\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } idx = 0; if( comment ) { - ERROR_IDF << "comment within .BOARD_OUTLINE section\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !CompareToken( ".END_BOARD_OUTLINE", iline ) ) { - ERROR_IDF << "bad .BOARD_OUTLINE section (no .END_BOARD_OUTLINE)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no .END_BOARD_OUTLINE found\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } - return true; + return; } -bool BOARD_OUTLINE::WriteData( std::ofstream& aBoardFile ) + +void BOARD_OUTLINE::writeData( std::ofstream& aBoardFile ) { writeComments( aBoardFile ); @@ -881,29 +1215,40 @@ bool BOARD_OUTLINE::WriteData( std::ofstream& aBoardFile ) writeOwner( aBoardFile ); - if( unit == UNIT_MM ) + if( unit != UNIT_THOU ) aBoardFile << setiosflags(ios::fixed) << setprecision(5) << thickness << "\n"; else - aBoardFile << setiosflags(ios::fixed) << setprecision(1) << (thickness / IDF_MM_TO_THOU) << "\n"; + aBoardFile << setiosflags(ios::fixed) << setprecision(1) << (thickness / IDF_THOU_TO_MM) << "\n"; - if( !writeOutlines( aBoardFile ) ) - return false; + writeOutlines( aBoardFile ); aBoardFile << ".END_BOARD_OUTLINE\n\n"; - return !aBoardFile.fail(); + return; } -void BOARD_OUTLINE::Clear( void ) +void BOARD_OUTLINE::clear( void ) { comments.clear(); - ClearOutlines(); + clearOutlines(); owner = UNOWNED; return; } -void BOARD_OUTLINE::SetParent( IDF3_BOARD* aParent ) +bool BOARD_OUTLINE::Clear( void ) +{ +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + + clear(); + + return true; +} + +void BOARD_OUTLINE::setParent( IDF3_BOARD* aParent ) { parent = aParent; } @@ -913,30 +1258,66 @@ IDF3_BOARD* BOARD_OUTLINE::GetParent( void ) return parent; } -bool BOARD_OUTLINE::AddOutline( IDF_OUTLINE* aOutline ) +bool BOARD_OUTLINE::addOutline( IDF_OUTLINE* aOutline ) { std::list< IDF_OUTLINE* >::iterator itS = outlines.begin(); std::list< IDF_OUTLINE* >::iterator itE = outlines.end(); - while( itS != itE ) + try { - if( *itS == aOutline ) - return false; + while( itS != itE ) + { + if( *itS == aOutline ) + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "duplicate outline pointer" ) ); - ++itS; + ++itS; + } + + outlines.push_back( aOutline ); + + } + catch( std::exception& e ) + { + errormsg = e.what(); + + return false; } - outlines.push_back( aOutline ); return true; } +bool BOARD_OUTLINE::AddOutline( IDF_OUTLINE* aOutline ) +{ +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + + return addOutline( aOutline ); +} + bool BOARD_OUTLINE::DelOutline( IDF_OUTLINE* aOutline ) { std::list< IDF_OUTLINE* >::iterator itS = outlines.begin(); std::list< IDF_OUTLINE* >::iterator itE = outlines.end(); - if( outlines.empty() ) + if( !aOutline ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: NULL aOutline pointer\n"; + ostr << "* outline type: " << GetOutlineTypeString( outlineType ); + errormsg = ostr.str(); + return false; + } + + if( outlines.empty() ) + { + errormsg.clear(); + return false; + } // if there are more than 1 outlines it makes no sense to delete // the first outline (board outline) since that would have the @@ -944,7 +1325,15 @@ bool BOARD_OUTLINE::DelOutline( IDF_OUTLINE* aOutline ) if( aOutline == outlines.front() ) { if( outlines.size() > 1 ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: attempting to delete first outline in list\n"; + ostr << "* outline type: " << GetOutlineTypeString( outlineType ); + errormsg = ostr.str(); + return false; + } outlines.clear(); return true; @@ -961,19 +1350,32 @@ bool BOARD_OUTLINE::DelOutline( IDF_OUTLINE* aOutline ) ++itS; } + errormsg.clear(); return false; } + bool BOARD_OUTLINE::DelOutline( size_t aIndex ) { std::list< IDF_OUTLINE* >::iterator itS = outlines.begin(); std::list< IDF_OUTLINE* >::iterator itE = outlines.end(); if( outlines.empty() ) + { + errormsg.clear(); return false; + } if( aIndex >= outlines.size() ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: index out of bounds (" << aIndex << " / " << outlines.size() << ")\n"; + ostr << "* outline type: " << GetOutlineTypeString( outlineType ); + errormsg = ostr.str(); + return false; + } if( aIndex == 0 ) { @@ -981,7 +1383,15 @@ bool BOARD_OUTLINE::DelOutline( size_t aIndex ) // the first outline (board outline) since that would have the // undesirable effect of substituting a cutout outline as the board outline if( outlines.size() > 1 ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: attempting to delete first outline in list\n"; + ostr << "* outline type: " << GetOutlineTypeString( outlineType ); + errormsg = ostr.str(); + return false; + } delete *itS; outlines.clear(); @@ -1011,7 +1421,14 @@ size_t BOARD_OUTLINE::OutlinesSize( void ) IDF_OUTLINE* BOARD_OUTLINE::GetOutline( size_t aIndex ) { if( aIndex >= outlines.size() ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* aIndex (" << aIndex << ") is out of range (" << outlines.size() << ")"; + errormsg = ostr.str(); + return NULL; + } std::list< IDF_OUTLINE* >::iterator itS = outlines.begin(); @@ -1028,36 +1445,13 @@ IDF3::KEY_OWNER BOARD_OUTLINE::GetOwner( void ) bool BOARD_OUTLINE::SetOwner( IDF3::KEY_OWNER aOwner ) { - // if this is a COMPONENT OUTLINE there can be no owner - if( outlineType == IDF3::OTLN_COMPONENT ) - return true; - - // if no one owns the outline, any system may - // set the owner - if( owner == UNOWNED ) - { - owner = aOwner; - return true; - } - - // if the outline is owned, only the owning - // CAD system can make alterations - if( parent == NULL ) +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) return false; +#endif - if( owner == MCAD && parent->GetCadType() == CAD_MECH ) - { - owner = aOwner; - return true; - } - - if( owner == ECAD && parent->GetCadType() == CAD_ELEC ) - { - owner = aOwner; - return true; - } - - return false; + owner = aOwner; + return true; } bool BOARD_OUTLINE::IsSingle( void ) @@ -1065,7 +1459,7 @@ bool BOARD_OUTLINE::IsSingle( void ) return single; } -void BOARD_OUTLINE::ClearOutlines( void ) +void BOARD_OUTLINE::clearOutlines( void ) { std::list< IDF_OUTLINE* >::iterator itS = outlines.begin(); std::list< IDF_OUTLINE* >::iterator itE = outlines.end(); @@ -1136,19 +1530,26 @@ void BOARD_OUTLINE::ClearComments( void ) /* * CLASS: OTHER_OUTLINE */ -OTHER_OUTLINE::OTHER_OUTLINE() +OTHER_OUTLINE::OTHER_OUTLINE( IDF3_BOARD* aParent ) { + setParent( aParent ); outlineType = OTLN_OTHER; side = LYR_INVALID; - single = true; + single = false; return; } -void OTHER_OUTLINE::SetOutlineIdentifier( const std::string aUniqueID ) +bool OTHER_OUTLINE::SetOutlineIdentifier( const std::string aUniqueID ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + uniqueID = aUniqueID; - return; + + return true; } const std::string& OTHER_OUTLINE::GetOutlineIdentifier( void ) @@ -1158,6 +1559,11 @@ const std::string& OTHER_OUTLINE::GetOutlineIdentifier( void ) bool OTHER_OUTLINE::SetSide( IDF3::IDF_LAYER aSide ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + switch( aSide ) { case LYR_TOP: @@ -1166,9 +1572,17 @@ bool OTHER_OUTLINE::SetSide( IDF3::IDF_LAYER aSide ) break; default: - ERROR_IDF << "invalid side (" << aSide << "); must be one of TOP/BOTTOM\n"; + do{ + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: invalid side (" << aSide << "); must be one of TOP/BOTTOM\n"; + ostr << "* outline type: " << GetOutlineTypeString( outlineType ); + errormsg = ostr.str(); + } while( 0 ); + side = LYR_INVALID; return false; + break; } @@ -1180,7 +1594,8 @@ IDF3::IDF_LAYER OTHER_OUTLINE::GetSide( void ) return side; } -bool OTHER_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHeader ) +void OTHER_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHeader, + IDF3::IDF_VERSION aIdfVersion ) { // OTHER_OUTLINE/VIA_KEEPOUT // .OTHER_OUTLINE [OWNER] @@ -1191,42 +1606,58 @@ bool OTHER_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea std::string token; bool quoted = false; int idx = 0; + std::streampos pos = aBoardFile.tellg(); if( !GetIDFString( aHeader, token, quoted, idx ) ) { - ERROR_IDF << "invalid invocation; blank header line\n"; - return false; + ostringstream ostr; + ostr << "\n* BUG: invalid invocation: blank header line\n"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( quoted ) { - ERROR_IDF << "section names may not be quoted:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: section names must not be in quotes\n"; + ostr << "* line: '" << aHeader << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( outlineType == OTLN_OTHER ) { if( !CompareToken( ".OTHER_OUTLINE", token ) ) { - ERROR_IDF << "not an OTHER outline:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* BUG: not an .OTHER outline\n"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } } else { if( !CompareToken( ".VIA_KEEPOUT", token ) ) { - ERROR_IDF << "not a VIA_KEEPOUT outline:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* BUG: not a .VIA_KEEPOUT outline\n"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } } if( !GetIDFString( aHeader, token, quoted, idx ) ) { - ERROR_IDF << "no OWNER; setting to UNOWNED\n"; + if( aIdfVersion > IDF_V2 ) + ERROR_IDF << "no OWNER; setting to UNOWNED\n"; + owner = UNOWNED; } else @@ -1240,7 +1671,6 @@ bool OTHER_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea std::string iline; bool comment = false; - std::streampos pos; if( outlineType == OTLN_OTHER ) { @@ -1250,29 +1680,52 @@ bool OTHER_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() ) { - ERROR_IDF << "bad .OTHER_OUTLINE section (premature end)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: premature end\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } idx = 0; if( comment ) { - ERROR_IDF << "comment within .OTHER_OUTLINE section\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within .OTHER_OUTLINE section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad .OTHER_OUTLINE section (no outline identifier)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no outline identifier\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } uniqueID = token; if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad .OTHER_OUTLINE section (no thickness)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no thickness\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } std::stringstream teststr; @@ -1281,72 +1734,130 @@ bool OTHER_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea teststr >> thickness; if( teststr.fail() ) { - ERROR_IDF << "bad .OTHER_OUTLINE section (invalid RECORD 2 reading thickness)\n"; - std::cerr << "\tLINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: invalid thickness\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( unit == UNIT_THOU ) - thickness *= IDF_MM_TO_THOU; - - if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad .OTHER_OUTLINE section (no board side)\n"; - return false; + thickness *= IDF_THOU_TO_MM; + } + else if( ( aIdfVersion == IDF_V2 ) && ( unit == UNIT_TNM ) ) + { + thickness *= IDF_TNM_TO_MM; + } + else if( unit != UNIT_MM ) + { + ostringstream ostr; + ostr << "\n* BUG: invalid UNIT type: " << unit; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } - if( !ParseIDFLayer( token, side ) || ( side != LYR_TOP && side != LYR_BOTTOM ) ) + if( aIdfVersion == IDF_V2 ) { - ERROR_IDF << "bad .OTHER_OUTLINE section (invalid side, must be TOP/BOTTOM only)\n"; - std::cerr << "\tLINE: " << iline << "\n"; - return false; + side = LYR_TOP; } + else + { + if( !GetIDFString( iline, token, quoted, idx ) ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no board side\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( !ParseIDFLayer( token, side ) || ( side != LYR_TOP && side != LYR_BOTTOM ) ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: invalid side (must be TOP or BOTTOM only)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + } + } // read RECORD 3 values - readOutlines( aBoardFile ); + readOutlines( aBoardFile, aIdfVersion ); // check RECORD 4 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) ); if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() ) { - ERROR_IDF << "bad .OTHER_OUTLINE/.VIA_KEEPOUT section (premature end)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: premature end\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } idx = 0; if( comment ) { - ERROR_IDF << "comment within .OTHER_OUTLINE/.VIA_KEEPOUT section\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( outlineType == OTLN_OTHER ) { if( !CompareToken( ".END_OTHER_OUTLINE", iline ) ) { - ERROR_IDF << "bad .OTHER_OUTLINE section (no .END_OTHER_OUTLINE)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no .END_OTHER_OUTLINE found\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } } else { if( !CompareToken( ".END_VIA_KEEPOUT", iline ) ) { - ERROR_IDF << "bad .VIA_KEEPOUT section (no .END_VIA_KEEPOUT)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no .END_VIA_KEEPOUT found\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } } - return true; + return; } -bool OTHER_OUTLINE::WriteData( std::ofstream& aBoardFile ) +void OTHER_OUTLINE::writeData( std::ofstream& aBoardFile ) { // this section is optional; do not write if not required if( outlines.empty() ) - return true; + return; writeComments( aBoardFile ); @@ -1363,10 +1874,10 @@ bool OTHER_OUTLINE::WriteData( std::ofstream& aBoardFile ) { aBoardFile << "\"" << uniqueID << "\" "; - if( unit == UNIT_MM ) + if( unit != UNIT_THOU ) aBoardFile << setiosflags(ios::fixed) << setprecision(5) << thickness << " "; else - aBoardFile << setiosflags(ios::fixed) << setprecision(1) << (thickness / IDF_MM_TO_THOU) << " "; + aBoardFile << setiosflags(ios::fixed) << setprecision(1) << (thickness / IDF_THOU_TO_MM) << " "; switch( side ) { @@ -1376,15 +1887,19 @@ bool OTHER_OUTLINE::WriteData( std::ofstream& aBoardFile ) break; default: - ERROR_IDF << "Invalid OTHER_OUTLINE side (neither top nor bottom): " << side << "\n"; - return false; + do{ + ostringstream ostr; + ostr << "\n* invalid OTHER_OUTLINE side (neither top nor bottom): "; + ostr << side; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } while( 0 ); + break; } } // write RECORD 3 - if( !writeOutlines( aBoardFile ) ) - return false; + writeOutlines( aBoardFile ); // write RECORD 4 if( outlineType == OTLN_OTHER ) @@ -1392,33 +1907,46 @@ bool OTHER_OUTLINE::WriteData( std::ofstream& aBoardFile ) else aBoardFile << ".END_VIA_KEEPOUT\n\n"; - return !aBoardFile.fail(); + return; } -void OTHER_OUTLINE::Clear( void ) + +bool OTHER_OUTLINE::Clear( void ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + + clear(); side = LYR_INVALID; uniqueID.clear(); - BOARD_OUTLINE::Clear(); - - return; + return true; } /* * CLASS: ROUTE_OUTLINE */ -ROUTE_OUTLINE::ROUTE_OUTLINE() +ROUTE_OUTLINE::ROUTE_OUTLINE( IDF3_BOARD* aParent ) { + setParent( aParent ); outlineType = OTLN_ROUTE; single = true; layers = LYR_INVALID; } -void ROUTE_OUTLINE::SetLayers( IDF3::IDF_LAYER aLayer ) +bool ROUTE_OUTLINE::SetLayers( IDF3::IDF_LAYER aLayer ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + layers = aLayer; + + return true; } IDF3::IDF_LAYER ROUTE_OUTLINE::GetLayers( void ) @@ -1426,7 +1954,8 @@ IDF3::IDF_LAYER ROUTE_OUTLINE::GetLayers( void ) return layers; } -bool ROUTE_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHeader ) +void ROUTE_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHeader, + IDF3::IDF_VERSION aIdfVersion ) { // ROUTE_OUTLINE (or ROUTE_KEEPOUT) // .ROUTE_OUTLINE [OWNER] @@ -1437,42 +1966,44 @@ bool ROUTE_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea std::string token; bool quoted = false; int idx = 0; + std::streampos pos = aBoardFile.tellg(); if( !GetIDFString( aHeader, token, quoted, idx ) ) { - ERROR_IDF << "invalid invocation; blank header line\n"; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* BUG: invalid invocation; blank header line" ) ); } if( quoted ) { - ERROR_IDF << "section names may not be quoted:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: section names must not be in quotes\n"; + ostr << "* line: '" << aHeader << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( outlineType == OTLN_ROUTE ) { if( !CompareToken( ".ROUTE_OUTLINE", token ) ) - { - ERROR_IDF << "not a ROUTE outline:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* BUG: not a ROUTE outline" ) ); } else { if( !CompareToken( ".ROUTE_KEEPOUT", token ) ) - { - ERROR_IDF << "not a ROUTE KEEPOUT outline:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* BUG: not a ROUTE KEEPOUT outline" ) ); } if( !GetIDFString( aHeader, token, quoted, idx ) ) { - ERROR_IDF << "no OWNER; setting to UNOWNED\n"; + if( aIdfVersion > IDF_V2 ) + ERROR_IDF << "no OWNER; setting to UNOWNED\n"; + owner = UNOWNED; } else @@ -1488,94 +2019,163 @@ bool ROUTE_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea // [layers: TOP, BOTTOM, BOTH, INNER, ALL] std::string iline; bool comment = false; - std::streampos pos; - while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) ); - - if( !aBoardFile.good() ) + if( aIdfVersion > IDF_V2 || outlineType == OTLN_ROUTE_KEEPOUT ) { - ERROR_IDF << "bad .ROUTE_OUTLINE/KEEPOUT section (premature end)\n"; - return false; - } + while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) ); - idx = 0; - if( comment ) - { - ERROR_IDF << "comment within .ROUTE_OUTLINE/KEEPOUT section\n"; - return false; - } + if( !aBoardFile.good() ) + { + ostringstream ostr; - if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF << "bad .ROUTE_OUTLINE/KEEPOUT section (no layers specification)\n"; - return false; - } + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: premature end\n"; + ostr << "* file position: " << pos; - if( quoted ) - { - ERROR_IDF << "bad .ROUTE_OUTLINE/KEEPOUT section (layers may not be quoted)\n"; - std::cerr << "\tLINE: " << iline << "\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } - if( !ParseIDFLayer( token, layers ) ) + idx = 0; + if( comment ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within a section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( !GetIDFString( iline, token, quoted, idx ) ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no layers specification\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( quoted ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: layers specification must not be in quotes\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( !ParseIDFLayer( token, layers ) ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: invalid layers specification\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( aIdfVersion == IDF_V2 ) + { + if( layers == LYR_INNER || layers == LYR_ALL ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: IDFv2 allows only TOP/BOTTOM/BOTH; layer was '"; + ostr << token << "'\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + } + + } // RECORD 2, conditional > IDFv2 or ROUTE_KO_OUTLINE + else { - ERROR_IDF << "bad .ROUTE_OUTLINE/KEEPOUT section (invalid layer)\n"; - std::cerr << "\tLINE: " << iline << "\n"; - return false; + layers = LYR_ALL; } // read RECORD 3 values - readOutlines( aBoardFile ); + readOutlines( aBoardFile, aIdfVersion ); // check RECORD 4 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) ); if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() ) { - ERROR_IDF << "bad .ROUTE_OUTLINE/KEEPOUT section (premature end)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: premature end\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } idx = 0; if( comment ) { - ERROR_IDF << "comment within .ROUTE_OUTLINE/KEEPOUT section\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( outlineType == OTLN_ROUTE ) { if( !CompareToken( ".END_ROUTE_OUTLINE", iline ) ) { - ERROR_IDF << "bad .ROUTE_OUTLINE section (no .END_ROUTE_OUTLINE)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no .END_ROUTE_OUTLINE found\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } } else { if( !CompareToken( ".END_ROUTE_KEEPOUT", iline ) ) { - ERROR_IDF << "bad .ROUTE_KEEPOUT section (no .END_ROUTE_KEEPOUT)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no .END_ROUTE_KEEPOUT found\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } } - return true; + return; } -bool ROUTE_OUTLINE::WriteData( std::ofstream& aBoardFile ) +void ROUTE_OUTLINE::writeData( std::ofstream& aBoardFile ) { // this section is optional; do not write if not required if( outlines.empty() ) - return true; + return; if( layers == LYR_INVALID ) - { - ERROR_IDF << "layer not specified\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "layer not specified" ) ); writeComments( aBoardFile ); @@ -1592,8 +2192,7 @@ bool ROUTE_OUTLINE::WriteData( std::ofstream& aBoardFile ) aBoardFile << "\n"; // write RECORD 3 - if( !writeOutlines( aBoardFile ) ) - return false; + writeOutlines( aBoardFile ); // write RECORD 4 if( outlineType == OTLN_ROUTE ) @@ -1601,31 +2200,43 @@ bool ROUTE_OUTLINE::WriteData( std::ofstream& aBoardFile ) else aBoardFile << ".END_ROUTE_KEEPOUT\n\n"; - return !aBoardFile.fail(); + return; } -void ROUTE_OUTLINE::Clear( void ) +bool ROUTE_OUTLINE::Clear( void ) { - BOARD_OUTLINE::Clear(); +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + + clear(); layers = LYR_INVALID; - return; + + return true; } /* * CLASS: PLACE_OUTLINE */ -PLACE_OUTLINE::PLACE_OUTLINE() +PLACE_OUTLINE::PLACE_OUTLINE( IDF3_BOARD* aParent ) { + setParent( aParent ); outlineType = OTLN_PLACE; single = true; thickness = 0.0; side = LYR_INVALID; } -void PLACE_OUTLINE::SetSide( IDF3::IDF_LAYER aSide ) +bool PLACE_OUTLINE::SetSide( IDF3::IDF_LAYER aSide ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + switch( aSide ) { case LYR_TOP: @@ -1635,32 +2246,54 @@ void PLACE_OUTLINE::SetSide( IDF3::IDF_LAYER aSide ) break; default: - // XXX - throw - ERROR_IDF << "invalid layer (" << aSide << "): must be one of TOP/BOTTOM/BOTH\n"; - side = LYR_INVALID; - return; + do{ + side = LYR_INVALID; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: invalid layer (" << aSide << "): must be one of TOP/BOTTOM/BOTH\n"; + ostr << "* outline type: " << GetOutlineTypeString( outlineType ); + errormsg = ostr.str(); + + return false; + } while( 0 ); + break; } - return; + return true; } + IDF3::IDF_LAYER PLACE_OUTLINE::GetSide( void ) { return side; } -void PLACE_OUTLINE::SetMaxHeight( double aHeight ) + +bool PLACE_OUTLINE::SetMaxHeight( double aHeight ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + if( aHeight < 0.0 ) { - ERROR_IDF << "invalid height (must be >= 0.0); default to 0\n"; thickness = 0.0; - return; + + do{ + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: invalid height (" << aHeight << "): must be >= 0.0"; + ostr << "* outline type: " << GetOutlineTypeString( outlineType ); + errormsg = ostr.str(); + + return false; + } while( 0 ); } thickness = aHeight; - return; + return true; } double PLACE_OUTLINE::GetMaxHeight( void ) @@ -1668,7 +2301,8 @@ double PLACE_OUTLINE::GetMaxHeight( void ) return thickness; } -bool PLACE_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHeader ) +void PLACE_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHeader, + IDF3::IDF_VERSION aIdfVersion ) { // PLACE_OUTLINE/KEEPOUT // .PLACE_OUTLINE [OWNER] @@ -1679,42 +2313,42 @@ bool PLACE_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea std::string token; bool quoted = false; int idx = 0; + std::streampos pos = aBoardFile.tellg(); if( !GetIDFString( aHeader, token, quoted, idx ) ) - { - ERROR_IDF << "invalid invocation; blank header line\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* BUG: invalid invocation: blank header line\n" ) ); if( quoted ) { - ERROR_IDF << "section names may not be quoted:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: section name must not be in quotes\n"; + ostr << "* line: '" << aHeader << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( outlineType == OTLN_PLACE ) { if( !CompareToken( ".PLACE_OUTLINE", token ) ) - { - ERROR_IDF << "not a PLACE outline:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* BUG: not a .PLACE_OUTLINE" ) ); } else { if( !CompareToken( ".PLACE_KEEPOUT", token ) ) - { - ERROR_IDF << "not a PLACE_KEEPOUT outline:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* BUG: not a .PLACE_KEEPOUT" ) ); } if( !GetIDFString( aHeader, token, quoted, idx ) ) { - ERROR_IDF << "no OWNER; setting to UNOWNED\n"; + if( aIdfVersion > IDF_V2 ) + ERROR_IDF << "no OWNER; setting to UNOWNED\n"; + owner = UNOWNED; } else @@ -1730,103 +2364,178 @@ bool PLACE_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea // [board side: Top/Bot/Both] [height] std::string iline; bool comment = false; - std::streampos pos; - while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) ); - - if( !aBoardFile.good() ) + if( aIdfVersion > IDF_V2 || outlineType == OTLN_PLACE_KEEPOUT ) { - ERROR_IDF << "bad .PLACE_OUTLINE/KEEPOUT section (premature end)\n"; - return false; - } + while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) ); - idx = 0; - if( comment ) + if( !aBoardFile.good() ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: premature end\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + idx = 0; + if( comment ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within the section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( !GetIDFString( iline, token, quoted, idx ) ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no board side information\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( !ParseIDFLayer( token, side ) || + ( side != LYR_TOP && side != LYR_BOTTOM && side != LYR_BOTH ) ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: invalid board side: must be one of TOP/BOTTOM/BOTH\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( !GetIDFString( iline, token, quoted, idx ) ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no height specified\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + std::stringstream teststr; + teststr << token; + + teststr >> thickness; + if( teststr.fail() ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: invalid height\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( thickness < 0.0 ) + { + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: thickness < 0\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( unit == UNIT_THOU ) + { + thickness *= IDF_THOU_TO_MM; + } + else if( ( aIdfVersion == IDF_V2 ) && ( unit == UNIT_TNM ) ) + { + thickness *= IDF_TNM_TO_MM; + } + else if( unit != UNIT_MM ) + { + ostringstream ostr; + ostr << "\n* BUG: invalid UNIT type: " << unit; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( thickness < 0.0 ) + thickness = 0.0; + } + else { - ERROR_IDF << "comment within .PLACE_OUTLINE/KEEPOUT section\n"; - return false; + side = LYR_TOP; + thickness = 0.0; } - if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF << "bad .PLACE_OUTLINE/KEEPOUT section (no board side information)\n"; - return false; - } - - if( !ParseIDFLayer( token, side ) || - ( side != LYR_TOP && side != LYR_BOTTOM && side != LYR_BOTH ) ) - { - ERROR_IDF << "bad .PLACE_OUTLINE/KEEPOUT section (invalid side, must be one of TOP/BOTTOM/BOTH)\n"; - std::cerr << "\tLINE: " << iline << "\n"; - return false; - } - - if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF << "bad .PLACE_OUTLINE/KEEPOUT section (no height)\n"; - return false; - } - - std::stringstream teststr; - teststr << token; - - teststr >> thickness; - if( teststr.fail() ) - { - ERROR_IDF << "bad .PLACE_OUTLINE/KEEPOUT section (invalid RECORD 2 reading height)\n"; - std::cerr << "\tLINE: " << iline << "\n"; - return false; - } - - if( unit == UNIT_THOU ) - thickness *= IDF_MM_TO_THOU; - // read RECORD 3 values - readOutlines( aBoardFile ); + readOutlines( aBoardFile, aIdfVersion ); // check RECORD 4 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) ); if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() ) { - ERROR_IDF << "bad .PLACE_OUTLINE/KEEPOUT section (premature end)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: premature end\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } idx = 0; if( comment ) { - ERROR_IDF << "comment within .PLACE_OUTLINE/KEEPOUT section\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( outlineType == OTLN_PLACE ) { if( !GetIDFString( iline, token, quoted, idx ) || !CompareToken( ".END_PLACE_OUTLINE", token ) ) - { - ERROR_IDF << "bad .PLACE_OUTLINE section (no .END_PLACE_OUTLINE)\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid .PLACE_OUTLINE section: no .END_PLACE_OUTLINE found" ) ); } else { if( !GetIDFString( iline, token, quoted, idx ) || !CompareToken( ".END_PLACE_KEEPOUT", token ) ) - { - ERROR_IDF << "bad .PLACE_KEEPOUT section (no .END_PLACE_KEEPOUT)\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid .PLACE_KEEPOUT section: no .END_PLACE_KEEPOUT found" ) ); } - return true; + return; } -bool PLACE_OUTLINE::WriteData( std::ofstream& aBoardFile ) +void PLACE_OUTLINE::writeData( std::ofstream& aBoardFile ) { // this section is optional; do not write if not required if( outlines.empty() ) - return true; + return; writeComments( aBoardFile ); @@ -1848,21 +2557,26 @@ bool PLACE_OUTLINE::WriteData( std::ofstream& aBoardFile ) break; default: - ERROR_IDF << "Invalid PLACE_OUTLINE/KEEPOUT side (" << side << "); must be one of TOP/BOTTOM/BOTH\n"; - return false; + do + { + ostringstream ostr; + ostr << "\n* invalid PLACE_OUTLINE/KEEPOUT side ("; + ostr << side << "); must be one of TOP/BOTTOM/BOTH"; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } while( 0 ); + break; } aBoardFile << " "; - if( unit == UNIT_MM ) + if( unit != UNIT_THOU ) aBoardFile << setiosflags(ios::fixed) << setprecision(5) << thickness << "\n"; else - aBoardFile << setiosflags(ios::fixed) << setprecision(1) << (thickness / IDF_MM_TO_THOU) << "\n"; + aBoardFile << setiosflags(ios::fixed) << setprecision(1) << (thickness / IDF_THOU_TO_MM) << "\n"; // write RECORD 3 - if( !writeOutlines( aBoardFile ) ) - return false; + writeOutlines( aBoardFile ); // write RECORD 4 if( outlineType == OTLN_PLACE ) @@ -1870,22 +2584,30 @@ bool PLACE_OUTLINE::WriteData( std::ofstream& aBoardFile ) else aBoardFile << ".END_PLACE_KEEPOUT\n\n"; - return !aBoardFile.fail(); + return; } -void PLACE_OUTLINE::Clear( void ) + +bool PLACE_OUTLINE::Clear( void ) { - BOARD_OUTLINE::Clear(); +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + + clear(); thickness = 0.0; side = LYR_INVALID; - return; + + return true; } /* * CLASS: ROUTE_KEEPOUT */ -ROUTE_KO_OUTLINE::ROUTE_KO_OUTLINE() +ROUTE_KO_OUTLINE::ROUTE_KO_OUTLINE( IDF3_BOARD* aParent ) + : ROUTE_OUTLINE( aParent ) { outlineType = OTLN_ROUTE_KEEPOUT; return; @@ -1895,7 +2617,8 @@ ROUTE_KO_OUTLINE::ROUTE_KO_OUTLINE() /* * CLASS: PLACE_KEEPOUT */ -PLACE_KO_OUTLINE::PLACE_KO_OUTLINE() +PLACE_KO_OUTLINE::PLACE_KO_OUTLINE( IDF3_BOARD* aParent ) + : PLACE_OUTLINE( aParent ) { outlineType = OTLN_PLACE_KEEPOUT; return; @@ -1905,8 +2628,10 @@ PLACE_KO_OUTLINE::PLACE_KO_OUTLINE() /* * CLASS: VIA_KEEPOUT */ -VIA_KO_OUTLINE::VIA_KO_OUTLINE() +VIA_KO_OUTLINE::VIA_KO_OUTLINE( IDF3_BOARD* aParent ) + : OTHER_OUTLINE( aParent ) { + single = true; outlineType = OTLN_VIA_KEEPOUT; } @@ -1914,8 +2639,9 @@ VIA_KO_OUTLINE::VIA_KO_OUTLINE() /* * CLASS: PLACEMENT GROUP (PLACE_REGION) */ -GROUP_OUTLINE::GROUP_OUTLINE() +GROUP_OUTLINE::GROUP_OUTLINE( IDF3_BOARD* aParent ) { + setParent( aParent ); outlineType = OTLN_GROUP_PLACE; thickness = 0.0; side = LYR_INVALID; @@ -1923,8 +2649,14 @@ GROUP_OUTLINE::GROUP_OUTLINE() return; } -void GROUP_OUTLINE::SetSide( IDF3::IDF_LAYER aSide ) + +bool GROUP_OUTLINE::SetSide( IDF3::IDF_LAYER aSide ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + switch( aSide ) { case LYR_TOP: @@ -1934,32 +2666,49 @@ void GROUP_OUTLINE::SetSide( IDF3::IDF_LAYER aSide ) break; default: - // XXX throw - ERROR_IDF << "invalid side (" << aSide << "); must be one of TOP/BOTTOM/BOTH\n"; - return; + do{ + ostringstream ostr; + ostr << "invalid side (" << aSide << "); must be one of TOP/BOTTOM/BOTH\n"; + ostr << "* outline type: " << GetOutlineTypeString( outlineType ); + errormsg = ostr.str(); + + return false; + } while( 0 ); + break; } - return; + return true; } + IDF3::IDF_LAYER GROUP_OUTLINE::GetSide( void ) { return side; } -void GROUP_OUTLINE::SetGroupName( std::string aGroupName ) + +bool GROUP_OUTLINE::SetGroupName( std::string aGroupName ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + groupName = aGroupName; - return; + + return true; } + const std::string& GROUP_OUTLINE::GetGroupName( void ) { return groupName; } -bool GROUP_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHeader ) + +void GROUP_OUTLINE::readData( std::ifstream& aBoardFile, const std::string& aHeader, + IDF3::IDF_VERSION aIdfVersion ) { // Placement Group // .PLACE_REGION [OWNER] @@ -1970,30 +2719,33 @@ bool GROUP_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea std::string token; bool quoted = false; int idx = 0; + std::streampos pos = aBoardFile.tellg(); if( !GetIDFString( aHeader, token, quoted, idx ) ) - { - ERROR_IDF << "invalid invocation; blank header line\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* BUG: invalid invocation: blank header line" ) ); if( quoted ) { - ERROR_IDF << "section names may not be quoted:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: section name must not be in quotes\n"; + ostr << "* line: '" << aHeader << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !CompareToken( ".PLACE_REGION", token ) ) - { - ERROR_IDF << "not a PLACE_REGION outline:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* BUG: not a .PLACE_REGION" ) ); if( !GetIDFString( aHeader, token, quoted, idx ) ) { - ERROR_IDF << "no OWNER; setting to UNOWNED\n"; + if( aIdfVersion > IDF_V2 ) + ERROR_IDF << "no OWNER; setting to UNOWNED\n"; + owner = UNOWNED; } else @@ -2007,7 +2759,6 @@ bool GROUP_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea std::string iline; bool comment = false; - std::streampos pos; // check RECORD 2 // [side: Top/Bot/Both ] [component group name] @@ -2015,73 +2766,111 @@ bool GROUP_OUTLINE::ReadData( std::ifstream& aBoardFile, const std::string& aHea if( !aBoardFile.good() ) { - ERROR_IDF << "bad .PLACE_REGION section (premature end)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: premature end\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } idx = 0; if( comment ) { - ERROR_IDF << "comment within .PLACE_REGION section\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad .PLACE_REGION section (no board side)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no board side specified\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !ParseIDFLayer( token, side ) || ( side != LYR_TOP && side != LYR_BOTTOM && side != LYR_BOTH ) ) { - ERROR_IDF << "bad .PLACE_REGION section (invalid side, must be TOP/BOTTOM/BOTH)\n"; - std::cerr << "\tLINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: invalid board side, must be one of TOP/BOTTOM/BOTH\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad .PLACE_REGION section (no outline identifier)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no outline identifier\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } groupName = token; // read RECORD 3 values - readOutlines( aBoardFile ); + readOutlines( aBoardFile, aIdfVersion ); // check RECORD 4 while( aBoardFile.good() && !FetchIDFLine( aBoardFile, iline, comment, pos ) ); if( ( !aBoardFile.good() && aBoardFile.eof() ) || iline.empty() ) { - ERROR_IDF << "bad .PLACE_REGION section (premature end)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: premature end\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } idx = 0; if( comment ) { - ERROR_IDF << "comment within .PLACE_REGION section\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) || !CompareToken( ".END_PLACE_REGION", token ) ) - { - ERROR_IDF << "bad .PLACE_REGION section (no .END_PLACE_REGION)\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* invalid .PLACE_REGION section: no .END_PLACE_REGION found" ) ); - return true; + return; } -bool GROUP_OUTLINE::WriteData( std::ofstream& aBoardFile ) + +void GROUP_OUTLINE::writeData( std::ofstream& aBoardFile ) { // this section is optional; do not write if not required if( outlines.empty() ) - return true; + return; writeComments( aBoardFile ); @@ -2100,37 +2889,49 @@ bool GROUP_OUTLINE::WriteData( std::ofstream& aBoardFile ) break; default: - ERROR_IDF << "Invalid PLACE_REGION side (must be TOP/BOTTOM/BOTH): " << side << "\n"; - return false; + do{ + ostringstream ostr; + ostr << "\n* invalid PLACE_REGION side (must be TOP/BOTTOM/BOTH): "; + ostr << side; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } while( 0 ); + break; } aBoardFile << " \"" << groupName << "\"\n"; // write RECORD 3 - if( !writeOutlines( aBoardFile ) ) - return false; + writeOutlines( aBoardFile ); // write RECORD 4 aBoardFile << ".END_PLACE_REGION\n\n"; - return !aBoardFile.fail(); + return; } -void GROUP_OUTLINE::Clear( void ) +bool GROUP_OUTLINE::Clear( void ) { - BOARD_OUTLINE::Clear(); +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + + clear(); thickness = 0.0; side = LYR_INVALID; groupName.clear(); - return; + + return true; } /* * CLASS: COMPONENT OUTLINE */ -IDF3_COMP_OUTLINE::IDF3_COMP_OUTLINE() +IDF3_COMP_OUTLINE::IDF3_COMP_OUTLINE( IDF3_BOARD* aParent ) { + setParent( aParent ); single = true; outlineType = OTLN_COMPONENT; compType = COMP_INVALID; @@ -2138,7 +2939,7 @@ IDF3_COMP_OUTLINE::IDF3_COMP_OUTLINE() return; } -bool IDF3_COMP_OUTLINE::readProperties( std::ifstream& aLibFile ) +void IDF3_COMP_OUTLINE::readProperties( std::ifstream& aLibFile ) { bool quoted = false; bool comment = false; @@ -2155,63 +2956,106 @@ bool IDF3_COMP_OUTLINE::readProperties( std::ifstream& aLibFile ) continue; idx = 0; + if( comment ) { - ERROR_IDF << "comment within component outline section\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad component outline section (no PROP)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: bad property section (no PROP)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( quoted ) { - ERROR_IDF << "bad component outline section (PROP or .END may not be quoted)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: PROP or .END must not be quoted\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( token.size() >= 5 && CompareToken( ".END_", token.substr( 0, 5 ) ) ) { aLibFile.seekg( pos ); - return true; + return; } if( !CompareToken( "PROP", token ) ) { - ERROR_IDF << "invalid electrical outline; expecting PROP or .END_ELECTRICAL\n"; - std::cerr << "\tLINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: expecting PROP or .END_ELECTRICAL\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad component outline section (no prop name)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no PROP name\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } pname = token; if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad component outline section (no prop value)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no PROP value\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } pval = token; if( props.insert( pair< string, string >(pname, pval) ).second == false ) { - ERROR_IDF << "bad component outline: duplicate property name '" << pname << "'\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: duplicate property name \"" << pname << "\"\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } } - return !aLibFile.fail(); + return; } + bool IDF3_COMP_OUTLINE::writeProperties( std::ofstream& aLibFile ) { if( props.empty() ) @@ -2229,7 +3073,8 @@ bool IDF3_COMP_OUTLINE::writeProperties( std::ofstream& aLibFile ) return !aLibFile.fail(); } -bool IDF3_COMP_OUTLINE::ReadData( std::ifstream& aLibFile, const std::string& aHeader ) +void IDF3_COMP_OUTLINE::readData( std::ifstream& aLibFile, const std::string& aHeader, + IDF3::IDF_VERSION aIdfVersion ) { // .ELECTRICAL/.MECHANICAL // [GEOM] [PART] [UNIT] [HEIGHT] @@ -2239,18 +3084,22 @@ bool IDF3_COMP_OUTLINE::ReadData( std::ifstream& aLibFile, const std::string& aH std::string token; bool quoted = false; int idx = 0; + std::streampos pos = aLibFile.tellg(); if( !GetIDFString( aHeader, token, quoted, idx ) ) - { - ERROR_IDF << "invalid invocation; blank header line\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* BUG: invalid invocation: blank header line" ) ); if( quoted ) { - ERROR_IDF << "section names may not be quoted:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: section name must not be in quotes\n"; + ostr << "* line: '" << aHeader << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( CompareToken( ".ELECTRICAL", token ) ) @@ -2263,58 +3112,97 @@ bool IDF3_COMP_OUTLINE::ReadData( std::ifstream& aLibFile, const std::string& aH } else { - ERROR_IDF << "not a component outline:\n"; - std::cerr << "\tLINE: " << aHeader << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: expecting .ELECTRICAL or .MECHANICAL header\n"; + ostr << "* line: '" << aHeader << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } // check RECORD 2 // [GEOM] [PART] [UNIT] [HEIGHT] std::string iline; bool comment = false; - std::streampos pos; while( aLibFile.good() && !FetchIDFLine( aLibFile, iline, comment, pos ) ); if( !aLibFile.good() ) { - ERROR_IDF << "bad component outline data (premature end)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: premature end\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } idx = 0; if( comment ) { - ERROR_IDF << "comment within a component outline section\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad component outline (no GEOMETRY NAME)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no GEOMETRY NAME\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } geometry = token; if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad component outline (no PART NAME)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no PART NAME\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } part = token; if( part.empty() && geometry.empty() ) { - ERROR_IDF << "bad component outline (both GEOMETRY and PART names are empty)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: both GEOMETRY and PART names are empty\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad component outline (no unit type)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no UNIT type\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( CompareToken( "MM", token ) ) @@ -2325,17 +3213,32 @@ bool IDF3_COMP_OUTLINE::ReadData( std::ifstream& aLibFile, const std::string& aH { unit = UNIT_THOU; } + else if( aIdfVersion == IDF_V2 && !CompareToken( "TNM", token ) ) + { + unit = UNIT_TNM; + } else { - ERROR_IDF << "bad component outline (invalid unit type)\n"; - std::cerr << "\tLINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: invalid UNIT '" << token << "': must be one of MM or THOU\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF << "bad component outline (no height)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no height specified\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } std::istringstream teststr; @@ -2344,69 +3247,110 @@ bool IDF3_COMP_OUTLINE::ReadData( std::ifstream& aLibFile, const std::string& aH teststr >> thickness; if( teststr.fail() ) { - ERROR_IDF << "bad component outline (invalid height)\n"; - std::cerr << "\tLINE: " << iline << "\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: invalid height '" << token << "'\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( unit == UNIT_THOU ) - thickness *= IDF_MM_TO_THOU; + { + thickness *= IDF_THOU_TO_MM; + } + else if( ( aIdfVersion == IDF_V2 ) && ( unit == UNIT_TNM ) ) + { + thickness *= IDF_TNM_TO_MM; + } + else if( unit != UNIT_MM ) + { + ostringstream ostr; + ostr << "\n* BUG: invalid UNIT type: " << unit; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } // read RECORD 3 values - readOutlines( aLibFile ); + readOutlines( aLibFile, aIdfVersion ); - if( compType == COMP_ELEC ) - { - if( !readProperties( aLibFile ) ) - return false; - } + if( compType == COMP_ELEC && aIdfVersion > IDF_V2 ) + readProperties( aLibFile ); // check RECORD 4 while( aLibFile.good() && !FetchIDFLine( aLibFile, iline, comment, pos ) ); if( ( !aLibFile.good() && aLibFile.eof() ) || iline.empty() ) { - ERROR_IDF << "bad component outline data (premature end)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: premature end\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } idx = 0; if( comment ) { - ERROR_IDF << "comment within component outline section\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: comment within section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( compType == COMP_ELEC ) { if( !CompareToken( ".END_ELECTRICAL", iline ) ) { - ERROR_IDF << "bad component outline (no .END_ELECTRICAL)\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no .END_ELECTRICAL found\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } } else { if( !CompareToken( ".END_MECHANICAL", iline ) ) { - ERROR_IDF << "corrupt .MECHANICAL outline\n"; - return false; + ostringstream ostr; + + ostr << "\n* invalid outline: " << GetOutlineTypeString( outlineType ) << "\n"; + ostr << "* violation: no .END_MECHANICAL found\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } } - return true; + return; } -bool IDF3_COMP_OUTLINE::WriteData( std::ofstream& aLibFile ) + +void IDF3_COMP_OUTLINE::writeData( std::ofstream& aLibFile ) { + if( refNum == 0 ) + return; // nothing to do + if( compType != COMP_ELEC && compType != COMP_MECH ) { - ERROR_IDF << "component type not set or invalid\n"; - return false; - } + ostringstream ostr; + ostr << "\n* component type not set or invalid: " << compType; - if( refNum == 0 ) - return true; // nothing to do + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } writeComments( aLibFile ); @@ -2420,13 +3364,12 @@ bool IDF3_COMP_OUTLINE::WriteData( std::ofstream& aLibFile ) // [GEOM] [PART] [UNIT] [HEIGHT] aLibFile << "\"" << geometry << "\" \"" << part << "\" "; - if( unit == UNIT_MM ) + if( unit != UNIT_THOU ) aLibFile << "MM " << setiosflags(ios::fixed) << setprecision(5) << thickness << "\n"; else - aLibFile << "THOU " << setiosflags(ios::fixed) << setprecision(1) << (thickness / IDF_MM_TO_THOU) << "\n"; + aLibFile << "THOU " << setiosflags(ios::fixed) << setprecision(1) << (thickness / IDF_THOU_TO_MM) << "\n"; - if( !writeOutlines( aLibFile ) ) - return false; + writeOutlines( aLibFile ); if( compType == COMP_ELEC ) { @@ -2438,22 +3381,29 @@ bool IDF3_COMP_OUTLINE::WriteData( std::ofstream& aLibFile ) aLibFile << ".END_MECHANICAL\n\n"; } - return !aLibFile.fail(); + return; } -void IDF3_COMP_OUTLINE::Clear( void ) + +bool IDF3_COMP_OUTLINE::Clear( void ) { - BOARD_OUTLINE::Clear(); +#ifndef DISABLE_IDF_OWNERSHIP + if( !CheckOwnership( __LINE__, __FUNCTION__, parent, owner, outlineType, errormsg ) ) + return false; +#endif + + clear(); uid.clear(); geometry.clear(); part.clear(); compType = COMP_INVALID; refNum = 0; props.clear(); - return; + + return true; } -void IDF3_COMP_OUTLINE::SetComponentClass( IDF3::COMP_TYPE aCompClass ) +bool IDF3_COMP_OUTLINE::SetComponentClass( IDF3::COMP_TYPE aCompClass ) { switch( aCompClass ) { @@ -2463,15 +3413,23 @@ void IDF3_COMP_OUTLINE::SetComponentClass( IDF3::COMP_TYPE aCompClass ) break; default: - // XXX - throw - ERROR_IDF << "invalid component class (must be ELECTRICAL or MECHANICAL)\n"; - return; + do{ + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: invalid component class (must be ELECTRICAL or MECHANICAL): "; + ostr << aCompClass << "\n"; + errormsg = ostr.str(); + + return false; + } while( 0 ); + break; } - return; + return true; } + IDF3::COMP_TYPE IDF3_COMP_OUTLINE::GetComponentClass( void ) { return compType; @@ -2516,17 +3474,21 @@ const std::string& IDF3_COMP_OUTLINE::GetUID( void ) } -int IDF3_COMP_OUTLINE::IncrementRef( void ) +int IDF3_COMP_OUTLINE::incrementRef( void ) { return ++refNum; } -int IDF3_COMP_OUTLINE::DecrementRef( void ) +int IDF3_COMP_OUTLINE::decrementRef( void ) { if( refNum == 0 ) { - ERROR_IDF << "BUG: decrementing refNum beyond 0\n"; - return 0; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: decrementing refNum beyond 0"; + errormsg = ostr.str(); + + return -1; } --refNum; diff --git a/utils/idftools/idf_outlines.h b/utils/idftools/idf_outlines.h index 4ca55ca329..d52c9ff052 100644 --- a/utils/idftools/idf_outlines.h +++ b/utils/idftools/idf_outlines.h @@ -91,7 +91,9 @@ class IDF3_BOARD; */ class BOARD_OUTLINE { +friend class IDF3_BOARD; protected: + std::string errormsg; std::list< IDF_OUTLINE* > outlines; IDF3::KEY_OWNER owner; // indicates the owner of this outline (MCAD, ECAD, UNOWNED) IDF3::OUTLINE_TYPE outlineType;// type of IDF outline @@ -102,15 +104,48 @@ protected: double thickness; // Board/Extrude Thickness or Height (IDF spec) // Read outline data from a BOARD or LIBRARY file's outline section - bool readOutlines( std::ifstream& aBoardFile ); + void readOutlines( std::ifstream& aBoardFile, IDF3::IDF_VERSION aIdfVersion ); // Write comments to a BOARD or LIBRARY file (must not be within a SECTION as per IDFv3 spec) bool writeComments( std::ofstream& aBoardFile ); // Write the outline owner to a BOARD file bool writeOwner( std::ofstream& aBoardFile ); // Write the data of a single outline object - bool writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutline, size_t aIndex ); + void writeOutline( std::ofstream& aBoardFile, IDF_OUTLINE* aOutline, size_t aIndex ); // Iterate through the outlines and write out all data - bool writeOutlines( std::ofstream& aBoardFile ); // write outline data (no headers) + void writeOutlines( std::ofstream& aBoardFile ); // write outline data (no headers) + // Clear internal list of outlines + void clearOutlines( void ); + /** + * Function SetParent + * sets the parent IDF_BOARD object + */ + void setParent( IDF3_BOARD* aParent ); + + // Shadow routines used by friends to bypass ownership checks + bool addOutline( IDF_OUTLINE* aOutline ); + virtual bool setThickness( double aThickness ); + virtual void clear( void ); + + /** + * Function readData + * reads data from a .BOARD_OUTLINE section + * In case of an unrecoverable error an exception is thrown. On a successful + * return the file pointer will be at the line following .END_BOARD_OUTLINE + * + * @param aBoardFile is an IDFv3 file opened for reading + * @param aHeader is the ".BOARD_OUTLINE" header line as read by FetchIDFLine + */ + virtual void readData( std::ifstream& aBoardFile, const std::string& aHeader, + IDF3::IDF_VERSION aIdfVersion ); + + /** + * Function writeData + * writes the comments and .BOARD_OUTLINE section to an IDFv3 file. + * Throws exceptions. + * + * @param aBoardFile is an IDFv3 file opened for writing + */ + virtual void writeData( std::ofstream& aBoardFile ); public: BOARD_OUTLINE(); @@ -123,7 +158,7 @@ public: * * @param aUnit is the native unit (UNIT_MM or UNIT_THOU) */ - virtual void SetUnit( IDF3::IDF_UNIT aUnit ); + virtual bool SetUnit( IDF3::IDF_UNIT aUnit ); /** * Function GetUnit @@ -147,34 +182,13 @@ public: */ virtual double GetThickness( void ); - /** - * Function ReadData - * reads data from a .BOARD_OUTLINE section - * - * @param aBoardFile is an IDFv3 file opened for reading - * @param aHeader is the ".BOARD_OUTLINE" header line as read by FetchIDFLine - * - * @return bool: true if the BOARD_OUTLINE section was successfully read, otherwise - * false. In case of an unrecoverable error an exception is thrown. On a successful - * return the file pointer will be at the line following .END_BOARD_OUTLINE - */ - virtual bool ReadData( std::ifstream& aBoardFile, const std::string& aHeader ); - - /** - * Function WriteData - * writes the comments and .BOARD_OUTLINE section to an IDFv3 file - * - * @param aBoardFile is an IDFv3 file opened for writing - * - * @return bool: true if the data had been successfully written, otherwise false. - */ - virtual bool WriteData( std::ofstream& aBoardFile ); - /** * Function Clear - * frees memory and reinitializes all internal data except for the parent pointer + * frees memory and reinitializes all internal data except for the parent pointer. + * + * @return bool: true if OK, false on ownership violations */ - virtual void Clear( void ); + virtual bool Clear( void ); /** * Function GetOutlineType @@ -182,12 +196,6 @@ public: */ IDF3::OUTLINE_TYPE GetOutlineType( void ); - /** - * Function SetParent - * sets the parent IDF_BOARD object - */ - void SetParent( IDF3_BOARD* aParent ); - /** * Function GetParent * returns the parent IDF_BOARD object @@ -202,10 +210,7 @@ public: * @param aOutline is a valid IDF outline * * @return bool: true if the outline was added; false if the outline - * already existed. If the outline cannot be added due to a violation - * of the IDF specification (multiple outlines for anything other than - * a BOARD_OUTLINE, or the ownership rules are violated) an exception is - * thrown. + * already existed or an ownership violation occurs. */ bool AddOutline( IDF_OUTLINE* aOutline ); @@ -221,8 +226,7 @@ public: * @param aOutline is a pointer to the outline to remove from the list * * @return bool: true if the outline was found and removed; false if - * the outline was not found. If an ownership violation occurs an - * exception is thrown. + * the outline was not found or an ownership violation occurs. */ bool DelOutline( IDF_OUTLINE* aOutline ); @@ -237,8 +241,8 @@ public: * @param aIndex is an index to the outline to delete * * @return bool: true if the outline was found and deleted; false if - * the outline was not found. If an ownership violation or indexation - * error occurs an exception is thrown. + * the outline was not found or an ownership violation or indexation + * error occurs. */ bool DelOutline( size_t aIndex ); @@ -259,8 +263,9 @@ public: /** * Function GetOutline * returns a pointer to the outline as specified by aIndex. - * If the index is out of bounds an error is thrown. It is the - * responsibility of the user to observe IDF ownership rules. + * If the index is out of bounds NULL is returned and the + * error message is set. It is the responsibility of the + * user to observe IDF ownership rules. */ IDF_OUTLINE* GetOutline( size_t aIndex ); @@ -331,6 +336,11 @@ public: * deletes all comments */ void ClearComments( void ); + + const std::string& GetError( void ) + { + return errormsg; + } }; @@ -340,19 +350,41 @@ public: */ class OTHER_OUTLINE : public BOARD_OUTLINE { +friend class IDF3_BOARD; private: std::string uniqueID; // Outline Identifier (IDF spec) IDF3::IDF_LAYER side; // Board Side [TOP/BOTTOM ONLY] (IDF spec) + /** + * Function readData + * reads an OTHER_OUTLINE data from an IDFv3 file. + * If an unrecoverable error occurs an exception is thrown. + * + * @param aBoardFile is an IDFv3 file open for reading + * @param aHeader is the .OTHER_OUTLINE header as read via FetchIDFLine + */ + virtual void readData( std::ifstream& aBoardFile, const std::string& aHeader, + IDF3::IDF_VERSION aIdfVersion ); + + /** + * Function writeData + * writes the OTHER_OUTLINE data to an open IDFv3 file + * + * @param aBoardFile is an IDFv3 file open for writing + * + * @return bool: true if the data was successfully written, otherwise false. + */ + virtual void writeData( std::ofstream& aBoardFile ); + public: - OTHER_OUTLINE(); + OTHER_OUTLINE( IDF3_BOARD* aParent ); /** * Function SetOutlineIdentifier * sets the Outline Identifier string of this OTHER_OUTLINE object * as per IDFv3 spec. */ - virtual void SetOutlineIdentifier( const std::string aUniqueID ); + virtual bool SetOutlineIdentifier( const std::string aUniqueID ); /** * Function GetOutlineIdentifier @@ -364,8 +396,8 @@ public: * Function SetSide * sets the side which this outline is applicable to (TOP, BOTTOM). * - * @return bool: true if the side was set, false if the side is invalid. - * An exception is thrown if there is a violation of IDF ownership rules. + * @return bool: true if the side was set, false if the side is invalid + * or there is a violation of IDF ownership rules. */ virtual bool SetSide( IDF3::IDF_LAYER aSide ); @@ -375,33 +407,11 @@ public: */ virtual IDF3::IDF_LAYER GetSide( void ); - /** - * Function ReadData - * reads an OTHER_OUTLINE data from an IDFv3 file. - * - * @param aBoardFile is an IDFv3 file open for reading - * @param aHeader is the .OTHER_OUTLINE header as read via FetchIDFLine - * - * @return bool: true if data was read, otherwise false. If an unrecoverable - * error occurs an exception is thrown. - */ - virtual bool ReadData( std::ifstream& aBoardFile, const std::string& aHeader ); - - /** - * Function WriteData - * writes the OTHER_OUTLINE data to an open IDFv3 file - * - * @param aBoardFile is an IDFv3 file open for writing - * - * @return bool: true if the data was successfully written, otherwise false. - */ - virtual bool WriteData( std::ofstream& aBoardFile ); - /** * Function Clear * deletes internal data except for the parent object */ - virtual void Clear( void ); + virtual bool Clear( void ); }; @@ -411,20 +421,38 @@ public: */ class ROUTE_OUTLINE : public BOARD_OUTLINE { +friend class IDF3_BOARD; +private: + /** + * Function readData + * reads ROUTE_OUTLINE data from an IDFv3 file + * If an unrecoverable error occurs an exception is thrown. + * + * @param aBoardFile is an open IDFv3 board file + * @param aHeader is the .ROUTE_OUTLINE header as returned by FetchIDFLine + */ + virtual void readData( std::ifstream& aBoardFile, const std::string& aHeader, + IDF3::IDF_VERSION aIdfVersion ); + + /** + * Function writeData + * writes the ROUTE_OUTLINE data to an open IDFv3 file + */ + virtual void writeData( std::ofstream& aBoardFile ); + protected: IDF3::IDF_LAYER layers; // Routing layers (IDF spec) public: - ROUTE_OUTLINE(); + ROUTE_OUTLINE( IDF3_BOARD* aParent ); /** * Function SetLayers * sets the layer or group of layers this outline is applicable to. - * This function is subject to IDF ownership rules. An exception is - * thrown if an invalid layer is provided or an IDF ownership violation - * occurs. + * This function is subject to IDF ownership rules; true is returned + * on success, otherwise false is returned and the error message is set. */ - virtual void SetLayers( IDF3::IDF_LAYER aLayer ); + virtual bool SetLayers( IDF3::IDF_LAYER aLayer ); /** * Function GetLayers @@ -432,29 +460,11 @@ public: */ virtual IDF3::IDF_LAYER GetLayers( void ); - /** - * Function ReadData - * reads ROUTE_OUTLINE data from an IDFv3 file - * - * @param aBoardFile is an open IDFv3 board file - * @param aHeader is the .ROUTE_OUTLINE header as returned by FetchIDFLine - * - * @return bool: true if data was read, otherwise false. If unrecoverable - * errors occur an exception is thrown. - */ - virtual bool ReadData( std::ifstream& aBoardFile, const std::string& aHeader ); - - /** - * Function WriteData - * writes the ROUTE_OUTLINE data to an open IDFv3 file - */ - virtual bool WriteData( std::ofstream& aBoardFile ); - /** * Function Clear * deletes internal data except for the parent object */ - virtual void Clear( void ); + virtual bool Clear( void ); }; /** @@ -463,20 +473,43 @@ public: */ class PLACE_OUTLINE : public BOARD_OUTLINE { +friend class IDF3_BOARD; +private: + /** + * Function readData + * reads PLACE_OUTLINE data from an open IDFv3 file. + * If an unrecoverable error occurs an exception is thrown. + * + * @param aBoardFile is an IDFv3 file opened for reading + * @param aHeader is the .PLACE_OUTLINE header as returned by FetchIDFLine + */ + virtual void readData( std::ifstream& aBoardFile, const std::string& aHeader, + IDF3::IDF_VERSION aIdfVersion ); + + /** + * Function writeData + * writes the PLACE_OUTLINE data to an open IDFv3 file + * + * @param aBoardFile is an IDFv3 file opened for writing + * + * @return bool: true if the data was successfully written, otherwise false + */ + virtual void writeData( std::ofstream& aBoardFile ); + protected: IDF3::IDF_LAYER side; // Board Side [TOP/BOTTOM/BOTH ONLY] (IDF spec) double height; // Max Height (IDF spec) public: - PLACE_OUTLINE(); + PLACE_OUTLINE( IDF3_BOARD* aParent ); /** * Function SetSide - * sets the side (TOP, BOTTOM, BOTH) which this outline applies to, - * subject to IDF ownership rules. An exception is thrown if there is - * an ownership violation or an invalid layer is passed. + * sets the side (TOP, BOTTOM, BOTH) which this outline applies to. + * This function is subject to IDF ownership rules; true is returned + * on success, otherwise false is returned and the error message is set. */ - virtual void SetSide( IDF3::IDF_LAYER aSide ); + virtual bool SetSide( IDF3::IDF_LAYER aSide ); /** * Function GetSide @@ -486,11 +519,11 @@ public: /** * Function SetMaxHeight - * sets the maximum height of a component within this outline, - * subject to IDF ownership rules. An exception is thrown if - * there is an ownership violation or aHeight is negative. + * sets the maximum height of a component within this outline. + * This function is subject to IDF ownership rules; true is returned + * on success, otherwise false is returned and the error message is set. */ - virtual void SetMaxHeight( double aHeight ); + virtual bool SetMaxHeight( double aHeight ); /** * Function GetMaxHeight @@ -498,33 +531,11 @@ public: */ virtual double GetMaxHeight( void ); - /** - * Function ReadData - * reads PLACE_OUTLINE data from an open IDFv3 file. - * - * @param aBoardFile is an IDFv3 file opened for reading - * @param aHeader is the .PLACE_OUTLINE header as returned by FetchIDFLine - * - * @return bool: true if data was read, otherwise false. If there are - * unrecoverable errors an exception is thrown. - */ - virtual bool ReadData( std::ifstream& aBoardFile, const std::string& aHeader ); - - /** - * Function WriteData - * writes the PLACE_OUTLINE data to an open IDFv3 file - * - * @param aBoardFile is an IDFv3 file opened for writing - * - * @return bool: true if the data was successfully written, otherwise false - */ - virtual bool WriteData( std::ofstream& aBoardFile ); - /** * Function Clear * deletes all internal data */ - virtual void Clear( void ); + virtual bool Clear( void ); }; @@ -535,7 +546,7 @@ public: class ROUTE_KO_OUTLINE : public ROUTE_OUTLINE { public: - ROUTE_KO_OUTLINE(); + ROUTE_KO_OUTLINE( IDF3_BOARD* aParent ); }; /** @@ -547,7 +558,7 @@ public: class VIA_KO_OUTLINE : public OTHER_OUTLINE { public: - VIA_KO_OUTLINE(); + VIA_KO_OUTLINE( IDF3_BOARD* aParent ); }; @@ -559,7 +570,7 @@ public: class PLACE_KO_OUTLINE : public PLACE_OUTLINE { public: - PLACE_KO_OUTLINE(); + PLACE_KO_OUTLINE( IDF3_BOARD* aParent ); }; /** @@ -569,20 +580,42 @@ public: */ class GROUP_OUTLINE : public BOARD_OUTLINE { +friend class IDF3_BOARD; private: IDF3::IDF_LAYER side; // Board Side [TOP/BOTTOM/BOTH ONLY] (IDF spec) std::string groupName; // non-unique string + /** + * Function readData + * reads GROUP_OUTLINE data from an open IDFv3 file + * If an unrecoverable error occurs an exception is thrown. + * + * @param aBoardFile is an open IDFv3 file + * @param aHeader is the .PLACE_REGION header as returned by FetchIDFLine + */ + virtual void readData( std::ifstream& aBoardFile, const std::string& aHeader, + IDF3::IDF_VERSION aIdfVersion ); + + /** + * Function writeData + * writes the data to a .PLACE_REGION section of an IDFv3 file + * + * @param aBoardFile is an IDFv3 file open for writing + * + * @return bool: true if the data is successfully written, otherwise false + */ + virtual void writeData( std::ofstream& aBoardFile ); + public: - GROUP_OUTLINE(); + GROUP_OUTLINE( IDF3_BOARD* aParent ); /** * Function SetSide - * sets the side which this outline applies to (TOP, BOTTOM, BOTH), - * subject to IDF ownership rules. If an ownership violation occurs - * or an invalid side is specified, an exception is thrown. + * sets the side which this outline applies to (TOP, BOTTOM, BOTH). + * This function is subject to IDF ownership rules; true is returned + * on success, otherwise false is returned and the error message is set. */ - virtual void SetSide( IDF3::IDF_LAYER aSide ); + virtual bool SetSide( IDF3::IDF_LAYER aSide ); /** * Function GetSide @@ -593,10 +626,10 @@ public: /** * Function SetGroupName * sets the name of the group, subject to IDF ownership rules. - * An empty name or an ownership violation results in a thrown - * exception. + * This function is subject to IDF ownership rules; true is returned + * on success, otherwise false is returned and the error message is set. */ - virtual void SetGroupName( std::string aGroupName ); + virtual bool SetGroupName( std::string aGroupName ); /** * Function GetGroupName @@ -604,33 +637,11 @@ public: */ virtual const std::string& GetGroupName( void ); - /** - * Function ReadData - * reads GROUP_OUTLINE data from an open IDFv3 file - * - * @param aBoardFile is an open IDFv3 file - * @param aHeader is the .PLACE_REGION header as returned by FetchIDFLine - * - * @return bool: true if data was read, otherwise false. If an unrecoverable - * error occurs an exception is thrown. - */ - virtual bool ReadData( std::ifstream& aBoardFile, const std::string& aHeader ); - - /** - * Function WriteData - * writes the data to a .PLACE_REGION section of an IDFv3 file - * - * @param aBoardFile is an IDFv3 file open for writing - * - * @return bool: true if the data is successfully written, otherwise false - */ - virtual bool WriteData( std::ofstream& aBoardFile ); - /** * Function Clear * deletes internal data, subject to IDF ownership rules */ - virtual void Clear( void ); + virtual bool Clear( void ); }; @@ -640,6 +651,8 @@ public: */ class IDF3_COMP_OUTLINE : public BOARD_OUTLINE { +friend class IDF3_BOARD; +friend class IDF3_COMP_OUTLINE_DATA; private: std::string uid; // unique ID std::string geometry; // geometry name (IDF) @@ -649,46 +662,65 @@ private: std::map< std::string, std::string > props; // properties list - bool readProperties( std::ifstream& aLibFile ); + void readProperties( std::ifstream& aLibFile ); bool writeProperties( std::ofstream& aLibFile ); -public: - IDF3_COMP_OUTLINE(); - /** - * Function ReadData + * Function readData * reads a component outline from an open IDFv3 file + * If an unrecoverable error occurs, an exception is thrown. * * @param aLibFile is an open IDFv3 Library file * @param aHeader is the .ELECTRICAL or .MECHANICAL header as returned by FetchIDFLine - * - * @return bool: true if data was read, otherwise false. If unrecoverable errors - * occur, an exception is thrown. */ - virtual bool ReadData( std::ifstream& aLibFile, const std::string& aHeader ); + virtual void readData( std::ifstream& aLibFile, const std::string& aHeader, + IDF3::IDF_VERSION aIdfVersion ); /** - * Function WriteData + * Function writeData * writes comments and component outline data to an IDFv3 Library file * * @param aLibFile is an IDFv3 library file open for writing * * @return bool: true if the data was successfully written, otherwise false */ - virtual bool WriteData( std::ofstream& aLibFile ); + virtual void writeData( std::ofstream& aLibFile ); + + /** + * Function incrementRef + * increments the internal reference counter to keep track of the number of + * components referring to this outline. + * + * @return int: the number of current references to this component outline + */ + int incrementRef( void ); + + /** + * Function decrementRef + * decrements the internal reference counter to keep track of the number of + * components referring to this outline. + * + * @return int: the number of remaining references or -1 if there were no + * references when the function was invoked, in which case the error message + * is also set. + */ + int decrementRef( void ); + +public: + IDF3_COMP_OUTLINE( IDF3_BOARD* aParent ); /** * Function Clear * deletes internal outline data */ - virtual void Clear( void ); + virtual bool Clear( void ); /** * Function SetComponentClass - * sets the type of component outline (.ELECTRICAL or .MECHANICAL) - * If the specified class is invalid an exception is thrown. + * sets the type of component outline (.ELECTRICAL or .MECHANICAL). + * Returns true on success, otherwise false and the error message is set */ - void SetComponentClass( IDF3::COMP_TYPE aCompClass ); + bool SetComponentClass( IDF3::COMP_TYPE aCompClass ); /** * Function GetComponentClass @@ -727,20 +759,6 @@ public: */ const std::string& GetUID( void ); - /** - * Function IncrementRef - * increments the internal reference counter to keep track of the number of - * components referring to this outline. - */ - int IncrementRef( void ); - - /** - * Function DecrementRef - * decrements the internal reference counter to keep track of the number of - * components referring to this outline. - */ - int DecrementRef( void ); - /** * Function CreateDefaultOutline * creates a default outline with the given Geometry and Part names. diff --git a/utils/idftools/idf_parser.cpp b/utils/idftools/idf_parser.cpp index 8582cc0321..37d4b0a24a 100644 --- a/utils/idftools/idf_parser.cpp +++ b/utils/idftools/idf_parser.cpp @@ -21,6 +21,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ + #include #include #include @@ -64,7 +65,7 @@ IDF3_COMP_OUTLINE_DATA::IDF3_COMP_OUTLINE_DATA( IDF3_COMPONENT* aParent, aoff = 0.0; if( aOutline ) - aOutline->IncrementRef(); + aOutline->incrementRef(); return; } @@ -86,19 +87,69 @@ IDF3_COMP_OUTLINE_DATA::IDF3_COMP_OUTLINE_DATA( IDF3_COMPONENT* aParent, IDF3_COMP_OUTLINE_DATA::~IDF3_COMP_OUTLINE_DATA() { if( outline ) - outline->DecrementRef(); + outline->decrementRef(); return; } -void IDF3_COMP_OUTLINE_DATA::SetOffsets( double aXoff, double aYoff, +#ifndef DISABLE_IDF_OWNERSHIP +bool IDF3_COMP_OUTLINE_DATA::checkOwnership( int aSourceLine, const char* aSourceFunc ) +{ + if( !parent ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n"; + ostr << "* BUG: IDF3_COMP_OUTLINE_DATA::parent not set; cannot enforce ownership rules\n"; + errormsg = ostr.str(); + + return false; + } + + IDF3::IDF_PLACEMENT placement = parent->GetPlacement(); + IDF3::CAD_TYPE parentCAD = parent->GetCadType(); + + if( placement == PS_PLACED || placement == PS_UNPLACED ) + return true; + + if( placement == PS_MCAD && parentCAD == CAD_MECH ) + return true; + + if( placement == PS_ECAD && parentCAD == CAD_ELEC ) + return true; + + do + { + ostringstream ostr; + ostr << "* " << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n"; + ostr << "* ownership violation; CAD type is "; + + if( parentCAD == CAD_MECH ) + ostr << "MCAD "; + else + ostr << "ECAD "; + + ostr << "while outline owner is " << GetPlacementString( placement ) << "\n"; + errormsg = ostr.str(); + + } while( 0 ); + + return false; +} +#endif + +bool IDF3_COMP_OUTLINE_DATA::SetOffsets( double aXoff, double aYoff, double aZoff, double aAngleOff ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !checkOwnership( __LINE__, __FUNCTION__ ) ) + return false; +#endif + xoff = aXoff; yoff = aYoff; zoff = aZoff; aoff = aAngleOff; - return; + return true; } void IDF3_COMP_OUTLINE_DATA::GetOffsets( double& aXoff, double& aYoff, @@ -117,29 +168,34 @@ void IDF3_COMP_OUTLINE_DATA::SetParent( IDF3_COMPONENT* aParent ) parent = aParent; } -void IDF3_COMP_OUTLINE_DATA::SetOutline( IDF3_COMP_OUTLINE* aOutline ) +bool IDF3_COMP_OUTLINE_DATA::SetOutline( IDF3_COMP_OUTLINE* aOutline ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !checkOwnership( __LINE__, __FUNCTION__ ) ) + return false; +#endif + if( outline ) - outline->DecrementRef(); + outline->decrementRef(); outline = aOutline; if( outline ) - outline->IncrementRef(); + outline->incrementRef(); - return; + return true; } -bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, - IDF3::FILE_STATE& aBoardState, IDF3_BOARD *aBoard ) + +bool IDF3_COMP_OUTLINE_DATA::readPlaceData( std::ifstream &aBoardFile, + IDF3::FILE_STATE& aBoardState, + IDF3_BOARD *aBoard, + IDF3::IDF_VERSION aIdfVersion, + bool aNoSubstituteOutlines ) { if( !aBoard ) - { - ERROR_IDF; - cerr << "BUG: invoked with no reference to the parent IDF_BOARD\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* BUG: invoked with no reference to the parent IDF_BOARD" ) ); // clear out data possibly left over from previous use of the object outline = NULL; @@ -161,19 +217,25 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, if( ( !aBoardFile.good() && !aBoardFile.eof() ) || iline.empty() ) { - ERROR_IDF; - cerr << "problems reading PLACEMENT SECTION\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: could not read PLACEMENT section\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( isComment ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: comment within a section (PLACEMENT)\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: comment within PLACEMENT section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } idx = 0; @@ -181,7 +243,6 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, if( !quoted && CompareToken( ".END_PLACEMENT", token ) ) { - errno = 0; aBoardState = IDF3::FILE_PLACEMENT; return false; } @@ -190,11 +251,14 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: no PART NAME in PLACEMENT RECORD2\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: no PART NAME in PLACEMENT RECORD2\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } std::string npart = token; @@ -202,12 +266,14 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: no REFDES in PLACEMENT RECORD2\n"; - cerr << "* Line: '" << iline << "'\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: no REFDES in PLACEMENT RECORD2\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( CompareToken( "NOREFDES", token ) ) @@ -223,27 +289,36 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, } else if( CompareToken( "BOARD", token ) ) { - ERROR_IDF; - cerr << "unsupported feature\n"; - cerr << "* RefDes is 'BOARD', indicating this is a PANEL FILE (not supported)\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "UNSUPPORTED FEATURE\n"; + ostr << "* RefDes is 'BOARD', indicating this is a PANEL FILE (not supported)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } else if( CompareToken( "PANEL", token ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: RefDes in PLACEMENT RECORD2 is 'PANEL'\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: RefDes in PLACEMENT RECORD2 is 'PANEL'\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } else if( token.empty() ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: empty RefDes string in PLACEMENT RECORD2\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: empty RefDes string in PLACEMENT RECORD2\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } else { @@ -251,24 +326,31 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, refdes = token; } - // RECORD 3: X, Y, Z, ROT, SIDE (top/bot), PLACEMENT (placed, unplaced, mcad, ecad) + // V2: RECORD 3: X, Y, ROT, SIDE (top/bot), PLACEMENT (fixed, placed, unplaced) + // V3: RECORD 3: X, Y, Z, ROT, SIDE (top/bot), PLACEMENT (placed, unplaced, mcad, ecad) while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() ); if( !aBoardFile.good() ) { - ERROR_IDF; - cerr << "problems reading PLACEMENT SECTION, RECORD 3\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* problems reading PLACEMENT SECTION, RECORD 3\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( isComment ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: comment within a section (PLACEMENT)\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: comment within PLACEMENT section\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } idx = 0; @@ -276,11 +358,14 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, if( quoted ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: X value must not be in quotes (PLACEMENT RECORD 3)\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: X value must not be in quotes (PLACEMENT RECORD 3)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } istringstream istr; @@ -289,20 +374,26 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, istr >> xoff; if( istr.fail() ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: X value is not numeric (PLACEMENT RECORD 3)\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: X value is not numeric (PLACEMENT RECORD 3)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: no Y value in PLACEMENT RECORD 3\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: no Y value (PLACEMENT RECORD 3)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } istr.clear(); @@ -311,42 +402,57 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, istr >> yoff; if( istr.fail() ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: Y value is not numeric (PLACEMENT RECORD 3)\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: Y value is not numeric (PLACEMENT RECORD 3)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( aIdfVersion > IDF_V2 ) + { + if( !GetIDFString( iline, token, quoted, idx ) ) + { + ostringstream ostr; + + ostr << "invalid IDFv3 file\n"; + ostr << "* violation: no Z value (PLACEMENT RECORD 3)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + istr.clear(); + istr.str( token ); + + istr >> zoff; + if( istr.fail() ) + { + ostringstream ostr; + + ostr << "invalid IDFv3 file\n"; + ostr << "* violation: Z value is not numeric (PLACEMENT RECORD 3)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: no Z value in PLACEMENT RECORD 3\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + ostringstream ostr; - istr.clear(); - istr.str( token ); + ostr << "invalid IDF file\n"; + ostr << "* violation: no rotation value (PLACEMENT RECORD 3)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; - istr >> zoff; - if( istr.fail() ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: Z value is not numeric (PLACEMENT RECORD 3)\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } - - if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: no rotation value in PLACEMENT RECORD 3\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } istr.clear(); @@ -355,20 +461,26 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, istr >> aoff; if( istr.fail() ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: rotation value is not numeric (PLACEMENT RECORD 3)\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: rotation value is not numeric (PLACEMENT RECORD 3)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: no SIDE value in PLACEMENT RECORD 3\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: no SIDE value (PLACEMENT RECORD 3)\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( CompareToken( "TOP", token ) ) @@ -381,21 +493,27 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, } else { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: SIDE value in PLACEMENT RECORD 3 is invalid ('"; - cerr << token << "')\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: invalid SIDE value in PLACEMENT RECORD 3 ('"; + ostr << token << "'); must be one of TOP/BOTTOM\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: no PLACEMENT value in PLACEMENT RECORD 3\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: no PLACEMENT value in PLACEMENT RECORD 3\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( CompareToken( "PLACED", token ) ) @@ -406,27 +524,37 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, { placement = IDF3::PS_UNPLACED; } - else if( CompareToken( "MCAD", token ) ) + else if( aIdfVersion > IDF_V2 && CompareToken( "MCAD", token ) ) { placement = IDF3::PS_MCAD; } - else if( CompareToken( "ECAD", token ) ) + else if( aIdfVersion > IDF_V2 && CompareToken( "ECAD", token ) ) { placement = IDF3::PS_ECAD; } + else if( aIdfVersion < IDF_V3 && CompareToken( "FIXED", token ) ) + { + if( aBoard->GetCadType() == CAD_ELEC ) + placement = IDF3::PS_MCAD; + else + placement = IDF3::PS_ECAD; + } else { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: PLACEMENT value in PLACEMENT RECORD 3 is invalid ('"; - cerr << token << "')\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: invalid PLACEMENT value ('"; + ostr << token << "') in PLACEMENT RECORD 3\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } outline = aBoard->GetComponentOutline( uid ); - if( outline == NULL ) + if( outline == NULL && !aNoSubstituteOutlines ) { ERROR_IDF << "MISSING OUTLINE\n"; cerr << "* GeomName( " << ngeom << " ), PartName( " << npart << " )\n"; @@ -434,18 +562,15 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, outline = aBoard->GetInvalidOutline( ngeom, npart ); if( outline == NULL ) - { - ERROR_IDF << "cannot create outline object\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* missing outline: cannot create default" ) ); } if( aBoard->GetUnit() == IDF3::UNIT_THOU ) { - xoff *= IDF_MM_TO_THOU; - yoff *= IDF_MM_TO_THOU; - zoff *= IDF_MM_TO_THOU; + xoff *= IDF_THOU_TO_MM; + yoff *= IDF_THOU_TO_MM; + zoff *= IDF_THOU_TO_MM; } parent = aBoard->FindComponent( refdes ); @@ -456,10 +581,10 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, if( cp == NULL ) { - ERROR_IDF << "cannot create component object\n"; - aBoardState = IDF3::FILE_INVALID; outline = NULL; - return false; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "cannot create component object" ) ); } cp->SetRefDes( refdes ); @@ -483,12 +608,17 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, { if( side != tL ) { - ERROR_IDF << "inconsistent PLACEMENT data\n"; - cerr << "* SIDE value has changed from " << GetLayerString( tL ); - cerr << " to " << GetLayerString( side ) << "\n"; - aBoardState = IDF3::FILE_INVALID; outline = NULL; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: inconsistent PLACEMENT data; "; + ostr << "* SIDE value has changed from " << GetLayerString( tL ); + ostr << " to " << GetLayerString( side ) << "\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } xoff -= tX; @@ -507,13 +637,18 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, if( placement != parent->GetPlacement() ) { - ERROR_IDF << "inconsistent PLACEMENT data\n"; - cerr << "* placement value has changed from " << GetPlacementString( parent->GetPlacement() ); - cerr << " to " << GetPlacementString( placement ) << "\n"; - cerr << "* line: '" << iline << "'\n"; - aBoardState = IDF3::FILE_INVALID; outline = NULL; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* violation: inconsistent PLACEMENT data; "; + ostr << "* PLACEMENT value has changed from "; + ostr << GetPlacementString( parent->GetPlacement() ); + ostr << " to " << GetPlacementString( placement ) << "\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* file position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } } @@ -521,34 +656,33 @@ bool IDF3_COMP_OUTLINE_DATA::ReadPlaceData( std::ifstream &aBoardFile, // copy internal data to a new object and push it into the component's outline list IDF3_COMP_OUTLINE_DATA* cdp = new IDF3_COMP_OUTLINE_DATA; *cdp = *this; - outline->IncrementRef(); + if( outline ) outline->incrementRef(); outline = NULL; if( !parent->AddOutlineData( cdp ) ) { - ERROR_IDF << "could not add outline data object\n"; - aBoardState = IDF3::FILE_INVALID; delete cdp; - return false; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "could not add outline data object" ) ); } return true; -} +} // IDF3_COMP_OUTLINE_DATA::readPlaceData -bool IDF3_COMP_OUTLINE_DATA::WritePlaceData( std::ofstream& aBoardFile, + +void IDF3_COMP_OUTLINE_DATA::writePlaceData( std::ofstream& aBoardFile, double aXpos, double aYpos, double aAngle, const std::string aRefDes, IDF3::IDF_PLACEMENT aPlacement, IDF3::IDF_LAYER aSide ) { if( outline == NULL ) - return true; + return; if( outline->GetUID().empty() ) - { - ERROR_IDF << "invalid GEOM/PART names\n"; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "empty GEOM and PART names" ) ); if( aPlacement == PS_INVALID ) { @@ -558,8 +692,11 @@ bool IDF3_COMP_OUTLINE_DATA::WritePlaceData( std::ofstream& aBoardFile, if( aSide != LYR_TOP && aSide != LYR_BOTTOM ) { - ERROR_IDF << "invalid side (" << aSide << "); must be TOP or BOTTOM\n"; - return false; + ostringstream ostr; + ostr << "\n* invalid side (" << GetLayerString( aSide ) << "); "; + ostr << "must be TOP or BOTTOM\n"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } // calculate the final position based on layer @@ -602,8 +739,8 @@ bool IDF3_COMP_OUTLINE_DATA::WritePlaceData( std::ofstream& aBoardFile, } else { - aBoardFile << setiosflags(ios::fixed) << setprecision(1) << (xpos / IDF_MM_TO_THOU) << " " - << (ypos / IDF_MM_TO_THOU) << " " << (zoff / IDF_MM_TO_THOU) << " " + aBoardFile << setiosflags(ios::fixed) << setprecision(1) << (xpos / IDF_THOU_TO_MM) << " " + << (ypos / IDF_THOU_TO_MM) << " " << (zoff / IDF_THOU_TO_MM) << " " << setprecision(3) << ang << " "; } @@ -628,7 +765,7 @@ bool IDF3_COMP_OUTLINE_DATA::WritePlaceData( std::ofstream& aBoardFile, break; } - return !aBoardFile.fail(); + return; } @@ -638,19 +775,6 @@ bool IDF3_COMP_OUTLINE_DATA::WritePlaceData( std::ofstream& aBoardFile, * This represents a component and its associated * IDF outlines and ancillary data (position, etc) */ -IDF3_COMPONENT::IDF3_COMPONENT() -{ - xpos = 0.0; - ypos = 0.0; - angle = 0.0; - parent = NULL; - - hasPosition = false; - placement = PS_INVALID; - layer = LYR_INVALID; - return; -} - IDF3_COMPONENT::IDF3_COMPONENT( IDF3_BOARD* aParent ) { xpos = 0.0; @@ -692,6 +816,73 @@ IDF3_COMPONENT::~IDF3_COMPONENT() return; } +#ifndef DISABLE_IDF_OWNERSHIP +bool IDF3_COMPONENT::checkOwnership( int aSourceLine, const char* aSourceFunc ) +{ + if( !parent ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n"; + ostr << "\n* BUG: parent not set"; + errormsg = ostr.str(); + + return false; + } + + IDF3::CAD_TYPE pcad = parent->GetCadType(); + + switch( placement ) + { + case PS_UNPLACED: + case PS_PLACED: + case PS_INVALID: + break; + + case PS_MCAD: + + if( pcad != CAD_MECH ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "\n* ownership violation; internal CAD type (MCAD) conflicts with PLACEMENT ("; + ostr << GetPlacementString( placement ) << ")"; + errormsg = ostr.str(); + + return false; + } + break; + + case PS_ECAD: + + if( pcad != CAD_ELEC ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "\n* ownership violation; internal CAD type (MCAD) conflicts with PLACEMENT ("; + ostr << GetPlacementString( placement ) << ")"; + errormsg = ostr.str(); + + return false; + } + break; + + default: + do{ + ostringstream ostr; + ostr << "\n* BUG: unhandled internal placement value (" << placement << ")"; + errormsg = ostr.str(); + + return false; + } while( 0 ); + + break; + } + + return true; +} +#endif + + void IDF3_COMPONENT::SetParent( IDF3_BOARD* aParent ) { parent = aParent; @@ -714,19 +905,29 @@ IDF3::IDF_UNIT IDF3_COMPONENT::GetUnit( void ) return UNIT_INVALID; } - bool IDF3_COMPONENT::SetRefDes( const std::string& aRefDes ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !checkOwnership( __LINE__, __FUNCTION__ ) ) + return false; +#endif + if( aRefDes.empty() ) { - ERROR_IDF << "invalid RefDes (empty)\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): invalid RefDes (empty)"; + errormsg = ostr.str(); + return false; } if( CompareToken( "PANEL", aRefDes ) ) { - ERROR_IDF; - cerr << "\n*BUG: PANEL is a reserved designator and may not be used by components\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: PANEL is a reserved designator and may not be used by components"; + errormsg = ostr.str(); + return false; } @@ -734,6 +935,7 @@ bool IDF3_COMPONENT::SetRefDes( const std::string& aRefDes ) return true; } + const std::string& IDF3_COMPONENT::GetRefDes( void ) { return refdes; @@ -755,6 +957,7 @@ IDF_DRILL_DATA* IDF3_COMPONENT::AddDrill( double aDia, double aXpos, double aYpo return dp; } + IDF_DRILL_DATA* IDF3_COMPONENT::AddDrill( IDF_DRILL_DATA* aDrilledHole ) { if( !aDrilledHole ) @@ -763,14 +966,14 @@ IDF_DRILL_DATA* IDF3_COMPONENT::AddDrill( IDF_DRILL_DATA* aDrilledHole ) if( CompareToken( "PANEL", refdes ) ) { ERROR_IDF; - cerr << "\n*BUG: PANEL drills not supported\n"; + cerr << "\n* BUG: PANEL drills not supported at component level\n"; return NULL; } if( refdes.compare( aDrilledHole->GetDrillRefDes() ) ) { ERROR_IDF; - cerr << "\n*BUG: pushing an incorrect REFDES ('" << aDrilledHole->GetDrillRefDes(); + cerr << "\n* BUG: pushing an incorrect REFDES ('" << aDrilledHole->GetDrillRefDes(); cerr << "') to component ('" << refdes << "')\n"; return NULL; } @@ -783,11 +986,16 @@ IDF_DRILL_DATA* IDF3_COMPONENT::AddDrill( IDF_DRILL_DATA* aDrilledHole ) bool IDF3_COMPONENT::DelDrill( double aDia, double aXpos, double aYpos ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !checkOwnership( __LINE__, __FUNCTION__ ) ) + return false; +#endif + + errormsg.clear(); + if( drills.empty() ) return false; - // XXX - throw on ownership violation - bool val = false; list< IDF_DRILL_DATA* >::iterator itS = drills.begin(); @@ -810,13 +1018,19 @@ bool IDF3_COMPONENT::DelDrill( double aDia, double aXpos, double aYpos ) return val; } + bool IDF3_COMPONENT::DelDrill( IDF_DRILL_DATA* aDrill ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !checkOwnership( __LINE__, __FUNCTION__ ) ) + return false; +#endif + + errormsg.clear(); + if( drills.empty() ) return false; - // XXX - throw on ownership violation - list< IDF_DRILL_DATA* >::iterator itS = drills.begin(); list< IDF_DRILL_DATA* >::iterator itE = drills.end(); @@ -842,7 +1056,14 @@ const std::list< IDF_DRILL_DATA* >*const IDF3_COMPONENT::GetDrills( void ) bool IDF3_COMPONENT::AddOutlineData( IDF3_COMP_OUTLINE_DATA* aComponentOutline ) { if( aComponentOutline == NULL ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): invalid aComponentOutline (NULL)"; + errormsg = ostr.str(); + return false; + } + components.push_back( aComponentOutline ); @@ -851,8 +1072,30 @@ bool IDF3_COMPONENT::AddOutlineData( IDF3_COMP_OUTLINE_DATA* aComponentOutline ) bool IDF3_COMPONENT::DeleteOutlineData( IDF3_COMP_OUTLINE_DATA* aComponentOutline ) { - if( components.empty() || aComponentOutline == NULL ) +#ifndef DISABLE_IDF_OWNERSHIP + if( !checkOwnership( __LINE__, __FUNCTION__ ) ) return false; +#endif + + if( components.empty() ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): component list is empty"; + errormsg = ostr.str(); + + return false; + } + + if( aComponentOutline == NULL ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): invalid aComponentOutline (NULL)"; + errormsg = ostr.str(); + + return false; + } + + errormsg.clear(); std::list< IDF3_COMP_OUTLINE_DATA* >::iterator itS = components.begin(); std::list< IDF3_COMP_OUTLINE_DATA* >::iterator itE = components.end(); @@ -874,8 +1117,20 @@ bool IDF3_COMPONENT::DeleteOutlineData( IDF3_COMP_OUTLINE_DATA* aComponentOutlin bool IDF3_COMPONENT::DeleteOutlineData( size_t aIndex ) { - if( aIndex >= components.size() ) +#ifndef DISABLE_IDF_OWNERSHIP + if( !checkOwnership( __LINE__, __FUNCTION__ ) ) return false; +#endif + + if( aIndex >= components.size() ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* aIndex (" << aIndex << ") out of range; list size is " << components.size(); + errormsg = ostr.str(); + + return false; + } std::list< IDF3_COMP_OUTLINE_DATA* >::iterator itS = components.begin(); std::list< IDF3_COMP_OUTLINE_DATA* >::iterator itE = components.end(); @@ -910,6 +1165,8 @@ const std::list< IDF3_COMP_OUTLINE_DATA* >*const IDF3_COMPONENT::GetOutlinesData bool IDF3_COMPONENT::GetPosition( double& aXpos, double& aYpos, double& aAngle, IDF3::IDF_LAYER& aLayer ) { + errormsg.clear(); + if( !hasPosition ) { aXpos = 0.0; @@ -928,6 +1185,13 @@ bool IDF3_COMPONENT::GetPosition( double& aXpos, double& aYpos, double& aAngle, bool IDF3_COMPONENT::SetPosition( double aXpos, double aYpos, double aAngle, IDF3::IDF_LAYER aLayer ) { +#ifndef DISABLE_IDF_OWNERSHIP + if( !checkOwnership( __LINE__, __FUNCTION__ ) ) + return false; +#endif + + errormsg.clear(); + switch( aLayer ) { case LYR_TOP: @@ -935,8 +1199,14 @@ bool IDF3_COMPONENT::SetPosition( double aXpos, double aYpos, double aAngle, IDF break; default: - ERROR_IDF << "invalid side (must be TOP or BOTTOM only): " << aLayer << "\n"; - return false; + do{ + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "\n* invalid side (must be TOP or BOTTOM only): " << GetLayerString( aLayer ); + errormsg = ostr.str(); + + return false; + } while( 0 ); break; } @@ -958,17 +1228,29 @@ IDF3::IDF_PLACEMENT IDF3_COMPONENT::GetPlacement( void ) } -void IDF3_COMPONENT::SetPlacement( IDF3::IDF_PLACEMENT aPlacementValue ) +bool IDF3_COMPONENT::SetPlacement( IDF3::IDF_PLACEMENT aPlacementValue ) { - // XXX - throw on ownership violation or invalid placement value if( aPlacementValue < PS_UNPLACED || aPlacementValue >= PS_INVALID ) - return; + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "\n* invalid PLACEMENT value (" << aPlacementValue << ")"; + errormsg = ostr.str(); + + return false; + } + +#ifndef DISABLE_IDF_OWNERSHIP + if( !checkOwnership( __LINE__, __FUNCTION__ ) ) + return false; +#endif placement = aPlacementValue; - return; + + return true; } -bool IDF3_COMPONENT::WriteDrillData( std::ofstream& aBoardFile ) +bool IDF3_COMPONENT::writeDrillData( std::ofstream& aBoardFile ) { if( drills.empty() ) return true; @@ -978,16 +1260,15 @@ bool IDF3_COMPONENT::WriteDrillData( std::ofstream& aBoardFile ) while( itS != itE ) { - if( !(*itS)->Write( aBoardFile, GetUnit() ) ) - return false; - + (*itS)->write( aBoardFile, GetUnit() ); ++itS; } return true; } -bool IDF3_COMPONENT::WritePlaceData( std::ofstream& aBoardFile ) + +bool IDF3_COMPONENT::writePlaceData( std::ofstream& aBoardFile ) { if( components.empty() ) return true; @@ -997,9 +1278,7 @@ bool IDF3_COMPONENT::WritePlaceData( std::ofstream& aBoardFile ) while( itS != itE ) { - if( !(*itS)->WritePlaceData( aBoardFile, xpos, ypos, angle, refdes, placement, layer ) ) - return false; - + (*itS)->writePlaceData( aBoardFile, xpos, ypos, angle, refdes, placement, layer ); ++itS; } @@ -1009,6 +1288,7 @@ bool IDF3_COMPONENT::WritePlaceData( std::ofstream& aBoardFile ) IDF3_BOARD::IDF3_BOARD( IDF3::CAD_TYPE aCadType ) { + idfVer = IDF_V3; state = FILE_START; cadType = aCadType; userPrec = 5; @@ -1021,8 +1301,8 @@ IDF3_BOARD::IDF3_BOARD( IDF3::CAD_TYPE aCadType ) // unlike other outlines which are created as necessary, // the board outline always exists and its parent must // be set here - olnBoard.SetParent( this ); - olnBoard.SetThickness( 1.6 ); + olnBoard.setParent( this ); + olnBoard.setThickness( 1.6 ); return; } @@ -1034,6 +1314,51 @@ IDF3_BOARD::~IDF3_BOARD() return; } +#ifndef DISABLE_IDF_OWNERSHIP +bool IDF3_BOARD::checkComponentOwnership( int aSourceLine, const char* aSourceFunc, + IDF3_COMPONENT* aComponent ) +{ + if( !aComponent ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc; + ostr << "(): Invalid component pointer (NULL)"; + errormsg = ostr.str(); + + return false; + } + + IDF3::IDF_PLACEMENT place = aComponent->GetPlacement(); + + if( place == PS_PLACED || place == PS_UNPLACED ) + return true; + + if( place == PS_MCAD && cadType == CAD_MECH ) + return true; + + if( place == PS_ECAD && cadType == CAD_ELEC ) + return true; + + do + { + ostringstream ostr; + ostr << "* " << __FILE__ << ":" << aSourceLine << ":" << aSourceFunc << "():\n"; + ostr << "* ownership violation; CAD type is "; + + if( cadType == CAD_MECH ) + ostr << "MCAD "; + else + ostr << "ECAD "; + + ostr << "while outline owner is " << GetPlacementString( place ) << "\n"; + errormsg = ostr.str(); + + } while( 0 ); + + return false; +} +#endif + IDF3::CAD_TYPE IDF3_BOARD::GetCadType( void ) { return cadType; @@ -1059,9 +1384,22 @@ bool IDF3_BOARD::setUnit( IDF3::IDF_UNIT aUnit, bool convert ) unit = aUnit; break; + case UNIT_TNM: + ERROR_IDF << "\n* TNM unit is not supported; defaulting to mm\n"; + unit = UNIT_MM; + break; + default: - ERROR_IDF << "invalid board unit\n"; - return false; + do + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* invalid board unit (" << aUnit << ")"; + errormsg = ostr.str(); + + return false; + } while( 0 ); + break; } @@ -1190,11 +1528,21 @@ bool IDF3_BOARD::SetBoardThickness( double aBoardThickness ) { if( aBoardThickness <= 0.0 ) { - ERROR_IDF << "board thickness must be > 0\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): "; + ostr << "board thickness (" << aBoardThickness << ") must be > 0"; + errormsg = ostr.str(); + return false; } - return olnBoard.SetThickness( aBoardThickness ); + if(! olnBoard.SetThickness( aBoardThickness ) ) + { + errormsg = olnBoard.GetError(); + return false; + } + + return true; } @@ -1205,77 +1553,57 @@ double IDF3_BOARD::GetBoardThickness( void ) // read the DRILLED HOLES section -bool IDF3_BOARD::readBrdDrills( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ) +void IDF3_BOARD::readBrdDrills( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ) { IDF_DRILL_DATA drill; - while( drill.Read( aBoardFile, unit, aBoardState ) ) + while( drill.read( aBoardFile, unit, aBoardState, idfVer ) ) { - if( CompareToken( "PANEL", drill.GetDrillRefDes() ) ) - { - ERROR_IDF; - cerr << "\n[INFO]: Dropping unsupported drill refdes: 'PANEL' (not supported)\n"; - continue; - } - IDF_DRILL_DATA *dp = new IDF_DRILL_DATA; *dp = drill; + if( AddDrill( dp ) == NULL ) { delete dp; - ERROR_IDF; - cerr << "\n* BUG: could not add drill data; cannot continue reading the file\n"; - aBoardState = FILE_INVALID; - return false; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* BUG: could not add drill data; cannot continue reading the file" ) ); } } - if( errno == 0 && aBoardState != IDF3::FILE_INVALID ) - return true; - - return false; - + return; } // read the NOTES section -bool IDF3_BOARD::readBrdNotes( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ) +void IDF3_BOARD::readBrdNotes( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ) { IDF_NOTE note; - while( note.ReadNote( aBoardFile, aBoardState, unit ) ) + while( note.readNote( aBoardFile, aBoardState, unit ) ) { IDF_NOTE *np = new IDF_NOTE; *np = note; notes.push_back( np ); } - if( errno == 0 && aBoardState != IDF3::FILE_INVALID ) - return true; - - return false; + return; } // read the component placement section -bool IDF3_BOARD::readBrdPlacement( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ) +void IDF3_BOARD::readBrdPlacement( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState, bool aNoSubstituteOutlines ) { IDF3_COMP_OUTLINE_DATA oldata; - while( oldata.ReadPlaceData( aBoardFile, aBoardState, this ) ); - - if( errno == 0 && aBoardState != IDF3::FILE_INVALID ) - return true; - - ERROR_IDF << "problems reading board PLACEMENT section\n"; - - return false; + while( oldata.readPlaceData( aBoardFile, aBoardState, this, idfVer, aNoSubstituteOutlines ) ); + return; } // read the board HEADER -bool IDF3_BOARD::readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ) +void IDF3_BOARD::readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ) { std::string iline; // the input line bool isComment; // true if a line just read in is a comment line @@ -1288,30 +1616,19 @@ bool IDF3_BOARD::readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBo while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() ); if( !aBoardFile.good() ) - { - ERROR_IDF; - cerr << "problems reading board header\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "problems reading board header" ) ); if( isComment ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: first line must be .HEADER\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: first line must be .HEADER\n" ) ); if( !CompareToken( ".HEADER", iline ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: first line must be .HEADER and have no quotes or trailing text\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification:\n" + "* first line must be .HEADER and have no quotes or trailing text" ) ); // RECORD 2: // File Type [str]: BOARD_FILE (PANEL_FILE not supported) @@ -1322,109 +1639,83 @@ bool IDF3_BOARD::readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBo while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() ); if( !aBoardFile.good() ) - { - ERROR_IDF; - cerr << "problems reading board header, RECORD 2\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "problems reading board header, RECORD 2" ) ); if( isComment ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: comment within .HEADER section\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: comment within .HEADER section" ) ); idx = 0; GetIDFString( iline, token, quoted, idx ); if( quoted ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: File Type in HEADER section must not be in quotes\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification:\n" + "* File Type in HEADER section must not be in quotes" ) ); if( !CompareToken( "BOARD_FILE", token ) ) { ERROR_IDF; if( CompareToken( "PANEL_FILE", token ) ) - { - cerr << "not a board file\n"; - cerr << "* PANEL_FILE is not supported (expecting BOARD_FILE)\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "not a board file\n" + "* PANEL_FILE is not supported (expecting BOARD_FILE)" ) ); else - { - cerr << "invalid IDFv3 file\n"; - cerr << "* Expecting string: BOARD_FILE\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Expecting string: BOARD_FILE" ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification for HEADER section, RECORD 2: no FIELD 2\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: HEADER section, RECORD 2: no FIELD 2" ) ); if( quoted ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: IDF Version must not be in quotes\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: IDF Version must not be in quotes" ) ); - if( token.compare( "3.0" ) && token.compare( "3." ) && token.compare( "3" ) ) + if( !token.compare( "3.0" ) || !token.compare( "3." ) || !token.compare( "3" ) ) + idfVer = IDF_V3; + else if( !token.compare( "2.0" ) || !token.compare( "2." ) || !token.compare( "2" ) ) + idfVer = IDF_V2; + else { - ERROR_IDF; - cerr << "unsupported IDF version\n"; - cerr << "* Expecting version to be one of '3.0', '3.', or '3' (value: '" << token << "')\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "unsupported IDF version\n"; + ostr << "* Expecting version to be a variant of '3.0', '2.0' (value: '" << token << "')\n"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification for HEADER section, RECORD 2, FIELD 3: no Source System string\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification:\n" + "* HEADER section, RECORD 2, FIELD 3: no Source System string" ) ); + brdSource = token; if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification for HEADER section, RECORD 2, FIELD 4: no Date string\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification:\n" + "* HEADER section, RECORD 2, FIELD 4: no Date string" ) ); + brdDate = token; if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification for HEADER section, RECORD 2, FIELD 5: no Board File Version number\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification:\n" + "* HEADER section, RECORD 2, FIELD 5: no Board File Version number" ) ); + std::istringstream istr; istr.str( token ); @@ -1438,13 +1729,10 @@ bool IDF3_BOARD::readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBo } if( quoted ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: HEADER section, RECORD 2, FIELD 5: Board File Version must not be in quotes\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification:\n" + "* HEADER section, RECORD 2, FIELD 5: Board File Version must not be in quotes" ) ); // RECORD 3: // Board Name [str]: stored @@ -1452,21 +1740,13 @@ bool IDF3_BOARD::readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBo while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() ); if( !aBoardFile.good() ) - { - ERROR_IDF; - cerr << "problems reading board header, RECORD 2\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* problems reading board header, RECORD 2" ) ); if( isComment ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: comment within .HEADER section\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: comment within .HEADER section" ) ); idx = 0; GetIDFString( iline, token, quoted, idx ); @@ -1474,22 +1754,16 @@ bool IDF3_BOARD::readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBo boardName = token; if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification for HEADER section, RECORD 3, FIELD 1: no Board Name\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification:\n" + "* HEADER section, RECORD 3, FIELD 1: no Board Name" ) ); if( quoted ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: HEADER section, RECORD 3, FIELD 2: UNIT may not be in quotes\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification:\n" + "* HEADER section, RECORD 3, FIELD 2: UNIT may not be in quotes" ) ); if( CompareToken( "MM", token ) ) { @@ -1499,13 +1773,18 @@ bool IDF3_BOARD::readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBo { unit = IDF3::UNIT_THOU; } + else if( ( idfVer == IDF_V2 ) && CompareToken( "TNM", token ) ) + { + unit = IDF3::UNIT_TNM; + } else { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* HEADER section, RECORD 3, FIELD 2: expecting MM or THOU (got '" << token << "')\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* HEADER section, RECORD 3, FIELD 2: expecting MM or THOU (got '" << token << "')\n"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } olnBoard.SetUnit( unit ); @@ -1515,38 +1794,33 @@ bool IDF3_BOARD::readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBo while( !FetchIDFLine( aBoardFile, iline, isComment, pos ) && aBoardFile.good() ); if( ( !aBoardFile.good() && !aBoardFile.eof() ) || iline.empty() ) - { - ERROR_IDF; - cerr << "problems reading board header, RECORD 4\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "problems reading board header, RECORD 4" ) ); if( isComment ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: comment within .HEADER section\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: comment within .HEADER section\n" ) ); if( !CompareToken( ".END_HEADER", iline ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: expected .END_HEADER (got '" << iline << "')\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* Violation of specification: expected .END_HEADER\n"; + ostr << "* line: '" << iline << "'"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } aBoardState = IDF3::FILE_HEADER; - return true; + return; } // read individual board sections; pay attention to IDFv3 section specifications -bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ) +void IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState, + bool aNoSubstituteOutlines ) { std::list< std::string > comments; // comments associated with a section @@ -1562,7 +1836,7 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB // .PLACE_KEEPOUT // .PLACE_REGION // .DRILLED_HOLES - // .NOTES (NOT YET SUPPORTED: NOTES SECTION WILL BE SKIPPED FOR NOW) + // .NOTES // .PLACEMENT std::string iline; // the input line bool isComment; // true if a line just read in is a comment line @@ -1578,12 +1852,15 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB if( !aBoardFile.good() ) { if( aBoardFile.eof() && aBoardState >= IDF3::FILE_HEADER && aBoardState < IDF3::FILE_INVALID ) - return true; + { + if( !comments.empty() ) + ERROR_IDF << "[warning]: trailing comments in IDF file (comments will be lost)\n"; - ERROR_IDF; - cerr << "problems reading board section\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + return; + } + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "problems reading board section" ) ); } if( isComment ) @@ -1593,41 +1870,31 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB } // This must be a header - if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "problems reading board section\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + GetIDFString( iline, token, quoted, idx ); if( quoted ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: quoted string where SECTION HEADER expected\n"; - aBoardState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "invalid IDF file\n"; + ostr << "* Violation of specification: quoted string where SECTION HEADER expected\n"; + ostr << "* line: '" << iline << "'"; + ostr << "* position: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( CompareToken( ".BOARD_OUTLINE", token ) ) { if( aBoardState != IDF3::FILE_HEADER ) { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: no HEADER section\n"; aBoardState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: no HEADER section" ) ); } - if( !olnBoard.ReadData( aBoardFile, iline ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + olnBoard.readData( aBoardFile, iline, idfVer ); if( !comments.empty() ) { @@ -1642,47 +1909,28 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB } aBoardState = IDF3::FILE_OUTLINE; - return true; + return; } if( CompareToken( ".PANEL_OUTLINE", token ) ) - { - ERROR_IDF; - cerr << "PANEL_OUTLINE not supported\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "PANEL_OUTLINE not supported" ) ); if( CompareToken( ".OTHER_OUTLINE", token ) ) { if( aBoardState != IDF3::FILE_OUTLINE ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: expecting .BOARD_OUTLINE, have .OTHER_OUTLINE\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: expecting .BOARD_OUTLINE, have .OTHER_OUTLINE" ) ); - OTHER_OUTLINE* op = new OTHER_OUTLINE; + OTHER_OUTLINE* op = new OTHER_OUTLINE( this ); if( op == NULL ) - { - ERROR_IDF; - cerr << "could not create OTHER_OUTLINE object\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "could not create OTHER_OUTLINE object" ) ); op->SetUnit( unit ); - - if( !op->ReadData( aBoardFile, iline ) ) - { - ERROR_IDF; - cerr << "problems reading the OTHER_OUTLINE section\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + op->readData( aBoardFile, iline, idfVer ); if( !comments.empty() ) { @@ -1698,47 +1946,36 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB if( olnOther.insert( pair(op->GetOutlineIdentifier(), op) ).second == false ) { - ERROR_IDF; - cerr << "* Violation of specification. Non-unique ID in OTHER_OUTLINE '"; - cerr << op->GetOutlineIdentifier() << "'\n"; delete op; - aBoardState = IDF3::FILE_ERROR; - return false; + + ostringstream ostr; + ostr << "invalid IDF file\n"; + ostr << "* Violation of specification. Non-unique ID in OTHER_OUTLINE '"; + ostr << op->GetOutlineIdentifier() << "'\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* pos: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } - return true; + return; } if( CompareToken( ".ROUTE_OUTLINE", token ) ) { if( aBoardState != IDF3::FILE_OUTLINE ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: expecting .BOARD_OUTLINE, have .ROUTE_OUTLINE\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: expecting .BOARD_OUTLINE, have .ROUTE_OUTLINE" ) ); - ROUTE_OUTLINE* op = new ROUTE_OUTLINE; + ROUTE_OUTLINE* op = new ROUTE_OUTLINE( this ); if( op == NULL ) - { - ERROR_IDF; - cerr << "could not create ROUTE_OUTLINE object\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "could not create ROUTE_OUTLINE object" ) ); op->SetUnit( unit ); - - if( !op->ReadData( aBoardFile, iline ) ) - { - ERROR_IDF; - cerr << "problems reading the ROUTE_OUTLINE section\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + op->readData( aBoardFile, iline, idfVer ); if( !comments.empty() ) { @@ -1754,39 +1991,24 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB olnRoute.push_back( op ); - return true; + return; } if( CompareToken( ".PLACE_OUTLINE", token ) ) { if( aBoardState != IDF3::FILE_OUTLINE ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: expecting .BOARD_OUTLINE, have .PLACE_OUTLINE\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: expecting .BOARD_OUTLINE, have .PLACE_OUTLINE" ) ); - PLACE_OUTLINE* op = new PLACE_OUTLINE; + PLACE_OUTLINE* op = new PLACE_OUTLINE( this ); if( op == NULL ) - { - ERROR_IDF; - cerr << "could not create PLACE_OUTLINE object\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "could not create PLACE_OUTLINE object" ) ); op->SetUnit( unit ); - - if( !op->ReadData( aBoardFile, iline ) ) - { - ERROR_IDF; - cerr << "problems reading the PLACE_OUTLINE section\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + op->readData( aBoardFile, iline, idfVer ); if( !comments.empty() ) { @@ -1802,39 +2024,24 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB olnPlace.push_back( op ); - return true; + return; } if( CompareToken( ".ROUTE_KEEPOUT", token ) ) { if( aBoardState != IDF3::FILE_OUTLINE ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: expecting .BOARD_OUTLINE, have .ROUTE_KEEPOUT\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: expecting .BOARD_OUTLINE, have .ROUTE_KEEPOUT" ) ); - ROUTE_KO_OUTLINE* op = new ROUTE_KO_OUTLINE; + ROUTE_KO_OUTLINE* op = new ROUTE_KO_OUTLINE( this ); if( op == NULL ) - { - ERROR_IDF; - cerr << "could not create ROUTE_KEEPOUT object\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "could not create ROUTE_KEEPOUT object" ) ); op->SetUnit( unit ); - - if( !op->ReadData( aBoardFile, iline ) ) - { - ERROR_IDF; - cerr << "problems reading the ROUTE_KEEPOUT section\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + op->readData( aBoardFile, iline, idfVer ); if( !comments.empty() ) { @@ -1850,39 +2057,24 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB olnRouteKeepout.push_back( op ); - return true; + return; } if( CompareToken( ".VIA_KEEPOUT", token ) ) { if( aBoardState != IDF3::FILE_OUTLINE ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: expecting .BOARD_OUTLINE, have .VIA_KEEPOUT\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: expecting .BOARD_OUTLINE, have .VIA_KEEPOUT" ) ); - VIA_KO_OUTLINE* op = new VIA_KO_OUTLINE; + VIA_KO_OUTLINE* op = new VIA_KO_OUTLINE( this ); if( op == NULL ) - { - ERROR_IDF; - cerr << "could not create VIA_KEEPOUT object\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "could not create VIA_KEEPOUT object" ) ); op->SetUnit( unit ); - - if( !op->ReadData( aBoardFile, iline ) ) - { - ERROR_IDF; - cerr << "problems reading the VIA_KEEPOUT section\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + op->readData( aBoardFile, iline, idfVer ); if( !comments.empty() ) { @@ -1898,39 +2090,24 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB olnViaKeepout.push_back( op ); - return true; + return; } if( CompareToken( ".PLACE_KEEPOUT", token ) ) { if( aBoardState != IDF3::FILE_OUTLINE ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: expecting .BOARD_OUTLINE, have .PLACE_KEEPOUT\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: expecting .BOARD_OUTLINE, have .PLACE_KEEPOUT" ) ); - PLACE_KO_OUTLINE* op = new PLACE_KO_OUTLINE; + PLACE_KO_OUTLINE* op = new PLACE_KO_OUTLINE( this ); if( op == NULL ) - { - ERROR_IDF; - cerr << "could not create PLACE_KEEPOUT object\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "could not create PLACE_KEEPOUT object" ) ); op->SetUnit( unit ); - - if( !op->ReadData( aBoardFile, iline ) ) - { - ERROR_IDF; - cerr << "problems reading the PLACE_KEEPOUT section\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + op->readData( aBoardFile, iline, idfVer ); if( !comments.empty() ) { @@ -1946,39 +2123,24 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB olnPlaceKeepout.push_back( op ); - return true; + return; } if( CompareToken( ".PLACE_REGION", token ) ) { if( aBoardState != IDF3::FILE_OUTLINE ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: expecting .BOARD_OUTLINE, have .PLACE_REGION\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: expecting .BOARD_OUTLINE, have .PLACE_REGION" ) ); - GROUP_OUTLINE* op = new GROUP_OUTLINE; + GROUP_OUTLINE* op = new GROUP_OUTLINE( this ); if( op == NULL ) - { - ERROR_IDF; - cerr << "could not create PLACE_REGION object\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "could not create PLACE_REGION object" ) ); op->SetUnit( unit ); - - if( !op->ReadData( aBoardFile, iline ) ) - { - ERROR_IDF; - cerr << "problems reading the PLACE_REGION section\n"; - aBoardState = IDF3::FILE_ERROR; - return false; - } + op->readData( aBoardFile, iline, idfVer ); if( !comments.empty() ) { @@ -1994,28 +2156,17 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB olnGroup.insert( pair(op->GetGroupName(), op) ); - return true; + return; } if( CompareToken( ".DRILLED_HOLES", token ) ) { if( aBoardState != IDF3::FILE_OUTLINE ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: expecting .BOARD_OUTLINE, have .DRILLED_HOLES\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: expecting .BOARD_OUTLINE, have .DRILLED_HOLES" ) ); - if( !readBrdDrills( aBoardFile, aBoardState ) ) - { - if( !aBoardFile.good() || aBoardState == IDF3::FILE_INVALID ) - { - ERROR_IDF << "could not read board DRILLED HOLES section\n"; - return false; - } - } + readBrdDrills( aBoardFile, aBoardState ); if( !comments.empty() ) { @@ -2029,28 +2180,22 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB } } - return true; + return; } if( CompareToken( ".NOTES", token ) ) { if( aBoardState != IDF3::FILE_OUTLINE ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: expecting .BOARD_OUTLINE, have .NOTES\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: expecting .BOARD_OUTLINE, have .NOTES" ) ); - if( !readBrdNotes( aBoardFile, aBoardState ) ) - { - if( !aBoardFile.good() || aBoardState == IDF3::FILE_INVALID ) - { - ERROR_IDF << "could not read board NOTES section\n"; - return false; - } - } + if( idfVer < IDF_V3 ) + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDFv2 file\n" + "* Violation of specification: NOTES section not in specification" ) ); + + readBrdNotes( aBoardFile, aBoardState ); if( !comments.empty() ) { @@ -2064,28 +2209,17 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB } } - return true; + return; } if( CompareToken( ".PLACEMENT", token ) ) { if( aBoardState != IDF3::FILE_OUTLINE ) - { - ERROR_IDF; - cerr << "invalid IDFv3 file\n"; - cerr << "* Violation of specification: expecting .BOARD_OUTLINE, have .PLACEMENT\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: expecting .BOARD_OUTLINE, have .PLACEMENT" ) ); - if( !readBrdPlacement( aBoardFile, aBoardState ) ) - { - if( !aBoardFile.good() || aBoardState == IDF3::FILE_INVALID ) - { - ERROR_IDF << "could not read board PLACEMENT section\n"; - return false; - } - } + readBrdPlacement( aBoardFile, aBoardState, aNoSubstituteOutlines ); if( !comments.empty() ) { @@ -2099,129 +2233,122 @@ bool IDF3_BOARD::readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aB } } - return true; + return; } } // while( aBoardFile.good() - if( !aBoardFile.good() ) - { - if( !aBoardFile.eof() || aBoardState < IDF3::FILE_OUTLINE || aBoardState >= IDF3::FILE_INVALID ) - { - ERROR_IDF; - cerr << "problems reading board section\n"; - aBoardState = IDF3::FILE_INVALID; - return false; - } - } - - return true; + return; } // readBrdSection() // read the board file data -bool IDF3_BOARD::readBoardFile( const std::string& aFileName ) +void IDF3_BOARD::readBoardFile( const std::string& aFileName, bool aNoSubstituteOutlines ) { std::ifstream brd; - brd.open( aFileName.c_str(), std::ios_base::in ); + brd.exceptions ( std::ifstream::badbit ); - if( !brd.is_open() ) + try { - ERROR_IDF; - cerr << "could not open file: '" << aFileName << "'\n"; - return false; - } + brd.open( aFileName.c_str(), std::ios_base::in ); - std::string iline; // the input line - bool isComment; // true if a line just read in is a comment line - std::streampos pos; - IDF3::FILE_STATE state = IDF3::FILE_START; - - // note: as per IDFv3 specification: - // "The Header section must be the first section in the file, the second - // section must be the Outline section, and the last section must be the - // Placement section. All other sections may be in any order." - - // further notes: Except for the HEADER section, sections may be preceeded by - // comment lines which will be copied back out on write(). No comments may - // be associated with the board file itself since the only logical location - // for unambiguous association is at the end of the file, which is inconvenient - // for large files. - - if( !readBrdHeader( brd, state ) ) - { - ERROR_IDF; - cerr << "could not find a valid header\n"; - brd.close(); - return false; - } - - // read the various sections - while( readBrdSection( brd, state ) && state != IDF3::FILE_PLACEMENT && !brd.eof() ); - - if( state == IDF3::FILE_INVALID ) - { - brd.close(); - ERROR_IDF; - cerr << "problems reading file: '" << aFileName << "'\n"; - return false; - } - - if( !brd.good() ) - { - // check if we have valid data - if( brd.eof() && state >= IDF3::FILE_OUTLINE && state < IDF3::FILE_INVALID ) + if( !brd.is_open() ) { - brd.close(); - return true; + ostringstream ostr; + ostr << "\n* could not open file: '" << aFileName << "'"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } - brd.close(); - ERROR_IDF; - cerr << "problems reading file: '" << aFileName << "'\n"; - return false; - } + std::string iline; // the input line + bool isComment; // true if a line just read in is a comment line + std::streampos pos; + IDF3::FILE_STATE state = IDF3::FILE_START; - if( brd.good() && state == IDF3::FILE_PLACEMENT ) - { - // read in any trailing lines and report on ignored comments (minor fault) - // and any non-comment item (non-compliance with IDFv3) - while( brd.good() ) + // note: as per IDFv3 specification: + // "The Header section must be the first section in the file, the second + // section must be the Outline section, and the last section must be the + // Placement section. All other sections may be in any order." + + // further notes: Except for the HEADER section, sections may be preceeded by + // comment lines which will be copied back out on write(). No comments may + // be associated with the board file itself since the only logical location + // for unambiguous association is at the end of the file, which is inconvenient + // for large files. + + readBrdHeader( brd, state ); + + // read the various sections + while( state != IDF3::FILE_PLACEMENT && brd.good() ) + readBrdSection( brd, state, aNoSubstituteOutlines ); + + if( !brd.good() ) { - while( !FetchIDFLine( brd, iline, isComment, pos ) && brd.good() ); - - // normally this is a fault but we have all the data in accordance with specs - if( ( !brd.good() && !brd.eof() ) || iline.empty() ) - break; - - if( isComment ) + // check if we have valid data + if( brd.eof() && state >= IDF3::FILE_OUTLINE && state < IDF3::FILE_INVALID ) { - ERROR_IDF << "[warning]: trailing comments after PLACEMENT\n"; - } - else - { - ERROR_IDF << "invalid IDF3 file\n"; - cerr << "* Violation of specification: non-comment lines after PLACEMENT section\n"; - Clear(); brd.close(); - return false; + return; + } + + brd.close(); + + ostringstream ostr; + ostr << "\n* empty IDF file: '" << aFileName << "'"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( brd.good() && state == IDF3::FILE_PLACEMENT ) + { + // read in any trailing lines and report on ignored comments (minor fault) + // and any non-comment item (non-compliance with IDFv3) + while( brd.good() ) + { + while( !FetchIDFLine( brd, iline, isComment, pos ) && brd.good() ); + + // normally this is a fault but we have all the data in accordance with specs + if( ( !brd.good() && !brd.eof() ) || iline.empty() ) + break; + + if( isComment ) + { + ERROR_IDF << "[warning]: trailing comments after PLACEMENT\n"; + } + else + { + ostringstream ostr; + ostr << "\n* problems reading file: '" << aFileName << "'"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF file\n" + "* Violation of specification: non-comment lines after PLACEMENT section" ) ); + } } } } + catch( std::exception& e ) + { + brd.exceptions ( std::ios_base::goodbit ); + + if( brd.is_open() ) + brd.close(); + + throw; + } brd.close(); - return true; + return; } // readBoardFile() // read the library sections (outlines) -bool IDF3_BOARD::readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState, IDF3_BOARD* aBoard ) +void IDF3_BOARD::readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState, IDF3_BOARD* aBoard ) { if( aBoard == NULL ) { - ERROR_IDF << "BUG: invoked with NULL reference aBoard\n"; - aLibState = IDF3::FILE_INVALID; - return false; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* BUG: invoked with NULL reference aBoard" ) ); } std::list< std::string > comments; // comments associated with a section @@ -2233,23 +2360,23 @@ bool IDF3_BOARD::readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLib int idx = 0; bool quoted = false; std::string token; - IDF3_COMP_OUTLINE *pout = new IDF3_COMP_OUTLINE; + IDF3_COMP_OUTLINE *pout = new IDF3_COMP_OUTLINE( this ); + + if( !pout ) + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "\n* memory allocation failure" ) ); while( aLibFile.good() ) { while( !FetchIDFLine( aLibFile, iline, isComment, pos ) && aLibFile.good() ); if( !aLibFile.good() && !aLibFile.eof() ) - { - ERROR_IDF; - cerr << "problems reading library section\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "problems reading library section" ) ); // no data was read; this only happens at eof() if( iline.empty() ) - return true; + return; if( isComment ) { @@ -2258,32 +2385,22 @@ bool IDF3_BOARD::readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLib } // This must be a header - if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "problems reading library section\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + GetIDFString( iline, token, quoted, idx ); if( quoted ) { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Violation of specification: quoted string where .ELECTRICAL or .MECHANICAL expected\n"; - aLibState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + ostr << "invalid IDF library\n"; + ostr << "* Violation of specification: quoted string where .ELECTRICAL or .MECHANICAL expected\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* pos: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( CompareToken( ".ELECTRICAL", token ) || CompareToken( ".MECHANICAL", token ) ) { - if( !pout->ReadData( aLibFile, token ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 library [faulty section]\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + pout->readData( aLibFile, token, idfVer ); if( !comments.empty() ) { @@ -2305,33 +2422,42 @@ bool IDF3_BOARD::readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLib } else { - ERROR_IDF; - cerr << "duplicate Component Outline: '" << pout->GetUID() << "'\n"; delete pout; + + ostringstream ostr; + ostr << "invalid IDF library\n"; + ostr << "duplicate Component Outline: '" << pout->GetUID() << "'\n"; + ostr << "* Violation of specification: multiple outlines have the same GEOM and PART name\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* pos: " << pos; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } - return true; + return; } else { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Expecting .ELECTRICAL or .MECHANICAL, got '" << token << "'\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + ostringstream ostr; + ostr << "invalid IDF library\n"; + ostr << "* Expecting .ELECTRICAL or .MECHANICAL, got '" << token << "'\n"; + ostr << "* line: '" << iline << "'\n"; + ostr << "* pos: " << pos; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } } - ERROR_IDF; - cerr << "problems reading library section\n"; - aLibState = IDF3::FILE_INVALID; - return false; + if( !aLibFile.eof() ) + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "problems reading IDF library file" ) ); + + return; } // read the library HEADER -bool IDF3_BOARD::readLibHeader( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState ) +void IDF3_BOARD::readLibHeader( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState ) { std::string iline; // the input line bool isComment; // true if a line just read in is a comment line @@ -2344,30 +2470,20 @@ bool IDF3_BOARD::readLibHeader( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibS while( !FetchIDFLine( aLibFile, iline, isComment, pos ) && aLibFile.good() ); if( !aLibFile.good() ) - { - ERROR_IDF; - cerr << "problems reading library header\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* premature end of file (no HEADER)" ) ); if( isComment ) - { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Violation of specification: first line must be .HEADER\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* Violation of specification: first line must be .HEADER" ) ); if( !CompareToken( ".HEADER", iline ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Violation of specification: first line must be .HEADER and have no quotes or trailing text\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* Violation of specification:\n" + "* first line must be .HEADER and have no quotes or trailing text" ) ); // RECORD 2: // File Type [str]: LIBRARY_FILE @@ -2378,99 +2494,79 @@ bool IDF3_BOARD::readLibHeader( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibS while( !FetchIDFLine( aLibFile, iline, isComment, pos ) && aLibFile.good() ); if( !aLibFile.good() ) - { - ERROR_IDF; - cerr << "problems reading library header, RECORD 2\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* premature end of HEADER" ) ); if( isComment ) - { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Violation of specification: comment within .HEADER section\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* Violation of specification: comment within .HEADER section" ) ); idx = 0; GetIDFString( iline, token, quoted, idx ); if( quoted ) - { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Violation of specification: File Type in HEADER section must not be in quotes\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* Violation of specification:\n" + "* file Type in HEADER section must not be in quotes" ) ); if( !CompareToken( "LIBRARY_FILE", token ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Expecting string: LIBRARY_FILE (got '" << token << "')\n"; - aLibState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + ostr << "invalid IDF library\n"; + ostr << "* Expecting string: LIBRARY_FILE (got '" << token << "')\n"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Violation of specification for HEADER section, RECORD 2: no FIELD 2\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* Violation of specification: HEADER section, RECORD 2: no FIELD 2" ) ); if( quoted ) - { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Violation of specification: IDF Version must not be in quotes\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* Violation of specification: IDF Version must not be in quotes" ) ); - if( token.compare( "3.0" ) && token.compare( "3." ) && token.compare( "3" ) ) + if( !token.compare( "3.0" ) || !token.compare( "3." ) || !token.compare( "3" ) ) + idfVer = IDF_V3; + else if( !token.compare( "2.0" ) || !token.compare( "2." ) || !token.compare( "2" ) ) + idfVer = IDF_V2; + else { - ERROR_IDF; - cerr << "unsupported IDF library version\n"; - cerr << "* Expecting version to be one of '3.0', '3.', or '3' (value: '" << token << "')\n"; - aLibState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + + ostr << "unsupported IDF version\n"; + ostr << "* Expecting version to be a variant of '3.0', '2.0' (value: '" << token << "')\n"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Violation of specification for HEADER section, RECORD 2, FIELD 3: no Source System string\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* Violation of specification:\n" + "* HEADER section, RECORD 2, FIELD 3: no Source System string" ) ); + libSource = token; - if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Violation of specification for HEADER section, RECORD 2, FIELD 4: no Date string\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* Violation of specification:\n" + "* HEADER section, RECORD 2, FIELD 4: no Date string" ) ); + libDate = token; if( !GetIDFString( iline, token, quoted, idx ) ) - { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Violation of specification for HEADER section, RECORD 2, FIELD 5: no Board File Version number\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* Violation of specification:\n" + "* HEADER section, RECORD 2, FIELD 5: no Board File Version number" ) ); + std::istringstream istr; istr.str( token ); @@ -2484,90 +2580,71 @@ bool IDF3_BOARD::readLibHeader( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibS } if( quoted ) - { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Violation of specification: HEADER section, RECORD 2, FIELD 5: Library File Version must not be in quotes\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* Violation of specification:\n" + "* HEADER section, RECORD 2, FIELD 5: Library File Version must not be in quotes" ) ); // RECORD 3: // .END_HEADER while( !FetchIDFLine( aLibFile, iline, isComment, pos ) && aLibFile.good() ); if( ( !aLibFile.good() && !aLibFile.eof() ) || iline.empty() ) - { - ERROR_IDF; - cerr << "problems reading library header, RECORD 3\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "problems reading library header, RECORD 3" ) ); if( isComment ) - { - ERROR_IDF; - cerr << "invalid IDFv3 library\n"; - cerr << "* Violation of specification: comment within .HEADER section\n"; - aLibState = IDF3::FILE_INVALID; - return false; - } + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, + "invalid IDF library file\n" + "* Violation of specification: comment within .HEADER section" ) ); if( !CompareToken( ".END_HEADER", iline ) ) { - ERROR_IDF; - cerr << "invalid IDFv3 header\n"; - cerr << "* Violation of specification: expected .END_HEADER (got '" << iline << "')\n"; - aLibState = IDF3::FILE_INVALID; - return false; + ostringstream ostr; + ostr << "invalid IDF header\n"; + ostr << "* Violation of specification: expected .END_HEADER (got '" << iline << "')\n"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } aLibState = IDF3::FILE_HEADER; - return true; + return; } // read the library file data -bool IDF3_BOARD::readLibFile( const std::string& aFileName ) +void IDF3_BOARD::readLibFile( const std::string& aFileName ) { std::ifstream lib; - lib.open( aFileName.c_str(), std::ios_base::in ); + lib.exceptions ( std::ifstream::badbit ); - if( !lib.is_open() ) + try { - ERROR_IDF; - cerr << "could not open file: '" << aFileName << "'\n"; - return false; + lib.open( aFileName.c_str(), std::ios_base::in ); + + IDF3::FILE_STATE state = IDF3::FILE_START; + + readLibHeader( lib, state ); + + while( lib.good() ) readLibSection( lib, state, this ); } - - IDF3::FILE_STATE state = IDF3::FILE_START; - - if( !readLibHeader( lib, state ) ) + catch( std::exception& e ) { - ERROR_IDF; - cerr << "[IDF library] could not find a valid header\n"; - lib.close(); - return false; - } + lib.exceptions ( std::ios_base::goodbit ); - // read the library sections - while( readLibSection( lib, state, this ) && lib.good() ); + if( lib.is_open() ) + lib.close(); - if( state <= IDF3::FILE_START || state >= IDF3::FILE_INVALID ) - { - lib.close(); - ERROR_IDF; - cerr << "problems reading file: '" << aFileName << "'\n"; - return false; + throw; } lib.close(); - return true; + return; } -bool IDF3_BOARD::ReadFile( const wxString& aFullFileName ) +bool IDF3_BOARD::ReadFile( const wxString& aFullFileName, bool aNoSubstituteOutlines ) { // 1. Check that the file extension is 'emn' // 2. Check if a file with extension 'emp' exists and read it @@ -2583,334 +2660,370 @@ bool IDF3_BOARD::ReadFile( const wxString& aFullFileName ) std::string bfname = TO_UTF8( aFullFileName ); - if( !brdname.IsOk() ) + try { - ERROR_IDF; - cerr << "invalid file name: '" << bfname << "'\n"; - return false; - } - - if( !brdname.IsOk() ) - { - ERROR_IDF; - cerr << "invalid file name: '" << bfname << "'\n"; - return false; - } - - if( !brdname.FileExists() ) - { - ERROR_IDF; - cerr << "no such file: '" << bfname << "'\n"; - return false; - } - - if( !brdname.IsFileReadable() ) - { - ERROR_IDF; - cerr << "cannot read file: '" << bfname << "'\n"; - return false; - } - - bfname = TO_UTF8( brdname.GetFullPath() ); - std::string lfname = TO_UTF8( libname.GetFullPath() ); - - if( !libname.FileExists() ) - { - ERROR_IDF; - cerr << "no associated library file (*.emp)\n"; - } - else if( !libname.IsFileReadable() ) - { - ERROR_IDF; - cerr << "cannot read library file: '" << lfname << "'\n"; - } - else - { - // read the library file before proceeding - if( !readLibFile( lfname ) ) + if( !brdname.IsOk() ) { - ERROR_IDF; - cerr << "problems reading library file: '" << lfname << "'\n"; - return false; - } - } + ostringstream ostr; + ostr << "\n* invalid file name: '" << bfname << "'"; - // read the board file - if( !readBoardFile( bfname ) ) + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( !brdname.FileExists() ) + { + ostringstream ostr; + ostr << "\n* no such file: '" << bfname << "'"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( !brdname.IsFileReadable() ) + { + ostringstream ostr; + ostr << "\n* cannot read file: '" << bfname << "'"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + bfname = TO_UTF8( brdname.GetFullPath() ); + std::string lfname = TO_UTF8( libname.GetFullPath() ); + + if( !libname.FileExists() ) + { + // NOTE: Since this is a common case we simply proceed + // with the assumption that there is no library file; + // however we print a message to inform the user. + ERROR_IDF; + cerr << "no associated library file (*.emp)\n"; + } + else if( !libname.IsFileReadable() ) + { + ostringstream ostr; + ostr << "\n* cannot read library file: '" << lfname << "'"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + else + { + // read the library file before proceeding + readLibFile( lfname ); + } + + // read the board file + readBoardFile( bfname, aNoSubstituteOutlines ); + } + catch( std::exception& e ) { Clear(); - ERROR_IDF; - cerr << "problems reading board file: '" << lfname << "'\n"; + errormsg = e.what(); + return false; } return true; } + // write the library file data bool IDF3_BOARD::writeLibFile( const std::string& aFileName ) { std::ofstream lib; + lib.exceptions( std::ofstream::failbit ); - lib.open( aFileName.c_str(), std::ios_base::out ); - - if( !lib.is_open() ) + try { - ERROR_IDF; - cerr << "could not open library file: '" << aFileName << "'\n"; - return false; + lib.open( aFileName.c_str(), std::ios_base::out ); + + wxDateTime tdate( time( NULL ) ); + + if( idfSource.empty() ) + idfSource = "KiCad-IDF Framework"; + + ostringstream fileDate; + fileDate << setfill( '0' ) << setw(4) << tdate.GetYear(); + fileDate << "/" << setw(2) << tdate.GetMonth() << "/" << tdate.GetDay(); + fileDate << "." << tdate.GetHour() << ":" << tdate.GetMinute() << ":" << tdate.GetSecond(); + libDate = fileDate.str(); + + lib << ".HEADER\n"; + lib << "LIBRARY_FILE 3.0 \"Created by " << idfSource; + lib << "\" " << libDate << " " << (++libFileVersion) << "\n"; + lib << ".END_HEADER\n\n"; + + std::map< std::string, IDF3_COMP_OUTLINE*>::iterator its = compOutlines.begin(); + std::map< std::string, IDF3_COMP_OUTLINE*>::iterator ite = compOutlines.end(); + + while( its != ite ) + { + its->second->writeData( lib ); + ++its; + } + } - - wxDateTime tdate( time( NULL ) ); - - if( idfSource.empty() ) - idfSource = "KiCad-IDF Framework"; - - ostringstream fileDate; - fileDate << setfill( '0' ) << setw(4) << tdate.GetYear(); - fileDate << "/" << setw(2) << tdate.GetMonth() << "/" << tdate.GetDay(); - fileDate << "." << tdate.GetHour() << ":" << tdate.GetMinute() << ":" << tdate.GetSecond(); - libDate = fileDate.str(); - - lib << ".HEADER\n"; - lib << "LIBRARY_FILE 3.0 \"Created by " << idfSource; - lib << "\" " << libDate << " " << (++libFileVersion) << "\n"; - lib << ".END_HEADER\n\n"; - - std::map< std::string, IDF3_COMP_OUTLINE*>::iterator its = compOutlines.begin(); - std::map< std::string, IDF3_COMP_OUTLINE*>::iterator ite = compOutlines.end(); - - while( its != ite ) + catch( std::exception& e ) { - its->second->WriteData( lib ); - ++its; - } + lib.exceptions( std::ios_base::goodbit ); - bool ok = !lib.fail(); + if( lib.is_open() ) + lib.close(); + + throw; + } lib.close(); - return ok; + return true; } // write the board file data -bool IDF3_BOARD::writeBoardFile( const std::string& aFileName ) +void IDF3_BOARD::writeBoardFile( const std::string& aFileName ) { std::ofstream brd; + brd.exceptions( std::ofstream::failbit ); - brd.open( aFileName.c_str(), std::ios_base::out ); - - if( !brd.is_open() ) + try { - ERROR_IDF; - cerr << "could not open board file: '" << aFileName << "'\n"; - return false; - } + brd.open( aFileName.c_str(), std::ios_base::out ); - wxDateTime tdate( time( NULL ) ); + wxDateTime tdate( time( NULL ) ); - if( idfSource.empty() ) - idfSource = "KiCad-IDF Framework"; + if( idfSource.empty() ) + idfSource = "KiCad-IDF Framework"; - ostringstream fileDate; - fileDate << setfill( '0' ) << setw(4) << tdate.GetYear(); - fileDate << "/" << setw(2) << tdate.GetMonth() << "/" << tdate.GetDay(); - fileDate << "." << tdate.GetHour() << ":" << tdate.GetMinute() << ":" << tdate.GetSecond(); - brdDate = fileDate.str(); + ostringstream fileDate; + fileDate << setfill( '0' ) << setw(4) << tdate.GetYear(); + fileDate << "/" << setw(2) << tdate.GetMonth() << "/" << tdate.GetDay(); + fileDate << "." << tdate.GetHour() << ":" << tdate.GetMinute() << ":" << tdate.GetSecond(); + brdDate = fileDate.str(); - brd << ".HEADER\n"; - brd << "BOARD_FILE 3.0 \"Created by " << idfSource; - brd << "\" " << brdDate << " " << (++brdFileVersion) << "\n"; + brd << ".HEADER\n"; + brd << "BOARD_FILE 3.0 \"Created by " << idfSource; + brd << "\" " << brdDate << " " << (++brdFileVersion) << "\n"; - if( boardName.empty() ) - brd << "\"BOARD WITH NO NAME\" "; - else - brd << "\"" << boardName << "\" "; + if( boardName.empty() ) + brd << "\"BOARD WITH NO NAME\" "; + else + brd << "\"" << boardName << "\" "; - brd << setw(1) << setfill( ' ' ); + brd << setw(1) << setfill( ' ' ); - if( unit == IDF3::UNIT_MM ) - brd << "MM\n"; - else - brd << "THOU\n"; + if( unit == IDF3::UNIT_MM ) + brd << "MM\n"; + else + brd << "THOU\n"; - brd << ".END_HEADER\n\n"; + brd << ".END_HEADER\n\n"; - // write the BOARD_OUTLINE - if( !olnBoard.WriteData( brd ) ) - { - ERROR_IDF << "problems writing BOARD OUTLINE\n"; - brd.close(); - return false; - } + // write the BOARD_OUTLINE + olnBoard.writeData( brd ); - // OTHER outlines - do - { - std::map::iterator its = olnOther.begin(); - std::map::iterator ite = olnOther.end(); - - while( (its != ite) && its->second->WriteData( brd ) ) ++its; - - } while( 0 ); - - // ROUTE outlines - do - { - std::list::iterator its = olnRoute.begin(); - std::list::iterator ite = olnRoute.end(); - - while( (its != ite) && (*its)->WriteData( brd ) ) ++its; - - } while( 0 ); - - // PLACEMENT outlines - do - { - std::list::iterator its = olnPlace.begin(); - std::list::iterator ite = olnPlace.end(); - - while( (its != ite) && (*its)->WriteData( brd ) ) ++its; - - } while( 0 ); - - // ROUTE KEEPOUT outlines - do - { - std::list::iterator its = olnRouteKeepout.begin(); - std::list::iterator ite = olnRouteKeepout.end(); - - while( (its != ite) && (*its)->WriteData( brd ) ) ++its; - - } while( 0 ); - - // VIA KEEPOUT outlines - do - { - std::list::iterator its = olnViaKeepout.begin(); - std::list::iterator ite = olnViaKeepout.end(); - - while( (its != ite) && (*its)->WriteData( brd ) ) ++its; - - } while( 0 ); - - // PLACE KEEPOUT outlines - do - { - std::list::iterator its = olnPlaceKeepout.begin(); - std::list::iterator ite = olnPlaceKeepout.end(); - - while( (its != ite) && (*its)->WriteData( brd ) ) ++its; - - } while( 0 ); - - // PLACEMENT GROUP outlines - do - { - std::map::iterator its = olnGroup.begin(); - std::map::iterator ite = olnGroup.end(); - - while( (its != ite) && its->second->WriteData( brd ) ) ++its; - - } while( 0 ); - - // Drilled holes - do - { - std::list::iterator itds = drillComments.begin(); - std::list::iterator itde = drillComments.end(); - - while( itds != itde ) + // OTHER outlines + do { - brd << "# " << *itds << "\n"; - ++itds; + std::map::iterator its = olnOther.begin(); + std::map::iterator ite = olnOther.end(); + + while(its != ite ) + { + its->second->writeData( brd ); + ++its; + } + + } while( 0 ); + + // ROUTE outlines + do + { + std::list::iterator its = olnRoute.begin(); + std::list::iterator ite = olnRoute.end(); + + while( its != ite ) + { + (*its)->writeData( brd ); + ++its; + } + + } while( 0 ); + + // PLACEMENT outlines + do + { + std::list::iterator its = olnPlace.begin(); + std::list::iterator ite = olnPlace.end(); + + while( its != ite ) + { + (*its)->writeData( brd ); + ++its; + } + + } while( 0 ); + + // ROUTE KEEPOUT outlines + do + { + std::list::iterator its = olnRouteKeepout.begin(); + std::list::iterator ite = olnRouteKeepout.end(); + + while( its != ite ) + { + (*its)->writeData( brd ); + ++its; + } + + } while( 0 ); + + // VIA KEEPOUT outlines + do + { + std::list::iterator its = olnViaKeepout.begin(); + std::list::iterator ite = olnViaKeepout.end(); + + while( its != ite ) + { + (*its)->writeData( brd ); + ++its; + } + + } while( 0 ); + + // PLACE KEEPOUT outlines + do + { + std::list::iterator its = olnPlaceKeepout.begin(); + std::list::iterator ite = olnPlaceKeepout.end(); + + while( its != ite ) + { + (*its)->writeData( brd ); + ++its; + } + + } while( 0 ); + + // PLACEMENT GROUP outlines + do + { + std::map::iterator its = olnGroup.begin(); + std::map::iterator ite = olnGroup.end(); + + while( its != ite ) + { + its->second->writeData( brd ); + ++its; + } + + } while( 0 ); + + // Drilled holes + do + { + std::list::iterator itds = drillComments.begin(); + std::list::iterator itde = drillComments.end(); + + while( itds != itde ) + { + brd << "# " << *itds << "\n"; + ++itds; + } + + brd << ".DRILLED_HOLES\n"; + + std::list::iterator itbs = board_drills.begin(); + std::list::iterator itbe = board_drills.end(); + + while( itbs != itbe ) + { + (*itbs)->write( brd, unit ); + ++itbs; + } + + std::map< std::string, IDF3_COMPONENT*>::iterator itcs = components.begin(); + std::map< std::string, IDF3_COMPONENT*>::iterator itce = components.end(); + + while( itcs != itce ) + { + itcs->second->writeDrillData( brd ); + ++itcs; + } + + brd << ".END_DRILLED_HOLES\n\n"; + } while( 0 ); + + // Notes + if( !notes.empty() ) + { + std::list::iterator itncs = noteComments.begin(); + std::list::iterator itnce = noteComments.end(); + + while( itncs != itnce ) + { + brd << "# " << *itncs << "\n"; + ++itncs; + } + + brd << ".NOTES\n"; + + std::list::iterator itns = notes.begin(); + std::list::iterator itne = notes.end(); + + while( itns != itne ) + { + (*itns)->writeNote( brd, unit ); + ++itns; + } + + brd << ".END_NOTES\n\n"; + } - brd << ".DRILLED_HOLES\n"; - - std::list::iterator itbs = board_drills.begin(); - std::list::iterator itbe = board_drills.end(); - - while( itbs != itbe ) + // Placement + if( !components.empty() ) { - (*itbs)->Write( brd, unit ); - ++itbs; + std::list::iterator itpcs = placeComments.begin(); + std::list::iterator itpce = placeComments.end(); + + while( itpcs != itpce ) + { + brd << "# " << *itpcs << "\n"; + ++itpcs; + } + + std::map< std::string, IDF3_COMPONENT*>::iterator itcs = components.begin(); + std::map< std::string, IDF3_COMPONENT*>::iterator itce = components.end(); + + brd << ".PLACEMENT\n"; + + while( itcs != itce ) + { + itcs->second->writePlaceData( brd ); + ++itcs; + } + + brd << ".END_PLACEMENT\n"; } - std::map< std::string, IDF3_COMPONENT*>::iterator itcs = components.begin(); - std::map< std::string, IDF3_COMPONENT*>::iterator itce = components.end(); - - while( itcs != itce ) - { - itcs->second->WriteDrillData( brd ); - ++itcs; - } - - brd << ".END_DRILLED_HOLES\n\n"; - } while( 0 ); - - // Notes - if( !notes.empty() ) - { - std::list::iterator itncs = noteComments.begin(); - std::list::iterator itnce = noteComments.end(); - - while( itncs != itnce ) - { - brd << "# " << *itncs << "\n"; - ++itncs; - } - - brd << ".NOTES\n"; - - std::list::iterator itns = notes.begin(); - std::list::iterator itne = notes.end(); - - while( itns != itne ) - { - (*itns)->WriteNote( brd, unit ); - ++itns; - } - - brd << ".END_NOTES\n\n"; - } - - // Placement - if( !components.empty() ) + catch( std::exception& e ) { - std::list::iterator itpcs = placeComments.begin(); - std::list::iterator itpce = placeComments.end(); + brd.exceptions( std::ios_base::goodbit ); - while( itpcs != itpce ) - { - brd << "# " << *itpcs << "\n"; - ++itpcs; - } + if( brd.is_open() ) + brd.close(); - std::map< std::string, IDF3_COMPONENT*>::iterator itcs = components.begin(); - std::map< std::string, IDF3_COMPONENT*>::iterator itce = components.end(); - - brd << ".PLACEMENT\n"; - - while( itcs != itce ) - { - itcs->second->WritePlaceData( brd ); - ++itcs; - } - - brd << ".END_PLACEMENT\n"; + throw; } - bool ok = !brd.fail(); brd.close(); - return ok; + return; } + bool IDF3_BOARD::WriteFile( const wxString& aFullFileName, bool aUnitMM, bool aForceUnitFlag ) { - if( aUnitMM == IDF3::UNIT_MM ) + if( aUnitMM != IDF3::UNIT_THOU ) setUnit( IDF3::UNIT_MM, aForceUnitFlag ); else setUnit( IDF3::UNIT_THOU, aForceUnitFlag ); @@ -2929,46 +3042,45 @@ bool IDF3_BOARD::WriteFile( const wxString& aFullFileName, bool aUnitMM, bool aF std::string bfname = TO_UTF8( aFullFileName ); - if( !brdname.IsOk() ) + try { - ERROR_IDF; - cerr << "invalid file name: '" << bfname << "'\n"; - errno = EINVAL; - return false; + if( !brdname.IsOk() ) + { + ostringstream ostr; + ostr << "\n* invalid file name: '" << bfname << "'"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + if( brdname.FileExists() && !brdname.IsFileWritable() ) + { + ostringstream ostr; + ostr << "cannot overwrite existing board file\n"; + ostr << "* filename: '" << bfname << "'"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + bfname = TO_UTF8( brdname.GetFullPath() ); + std::string lfname = TO_UTF8( libname.GetFullPath() ); + + if( libname.FileExists() && !libname.IsFileWritable() ) + { + ostringstream ostr; + ostr << "cannot overwrite existing library file\n"; + ostr << "* filename: '" << lfname << "'"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + writeLibFile( lfname ); + writeBoardFile( bfname ); + } - - if( brdname.FileExists() && !brdname.IsFileWritable() ) + catch( std::exception& e ) { - ERROR_IDF; - cerr << "cannot overwrite existing board file\n"; - cerr << "* Filename: '" << bfname << "'\n"; - errno = EACCES; - return false; - } + errormsg = e.what(); - bfname = TO_UTF8( brdname.GetFullPath() ); - std::string lfname = TO_UTF8( libname.GetFullPath() ); - - if( libname.FileExists() && !libname.IsFileWritable() ) - { - ERROR_IDF; - cerr << "cannot overwrite existing library file\n"; - cerr << "* Filename: '" << lfname << "'\n"; - errno = EACCES; - return false; - } - - if( !writeLibFile( lfname ) ) - { - ERROR_IDF; - cerr << "problems writing library file: '" << lfname << "'\n"; - return false; - } - - if( !writeBoardFile( bfname ) ) - { - ERROR_IDF; - cerr << "problems writing board file: '" << bfname << "'\n"; return false; } @@ -3016,7 +3128,14 @@ int IDF3_BOARD::GetBoardVersion( void ) bool IDF3_BOARD::SetBoardVersion( int aVersion ) { if( aVersion < 0 ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* board version (" << aVersion << ") must be > 0"; + errormsg = ostr.str(); + return false; + } brdFileVersion = aVersion; @@ -3033,7 +3152,14 @@ int IDF3_BOARD::GetLibraryVersion( void ) bool IDF3_BOARD::SetLibraryVersion( int aVersion ) { if( aVersion < 0 ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* library version (" << aVersion << ") must be > 0"; + errormsg = ostr.str(); + return false; + } libFileVersion = aVersion; @@ -3049,9 +3175,13 @@ double IDF3_BOARD::GetUserScale( void ) bool IDF3_BOARD::SetUserScale( double aScaleFactor ) { - if( aScaleFactor <= 0.0 ) + if( aScaleFactor == 0.0 ) { - ERROR_IDF << "user scale factor must be > 0\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* BUG: user scale factor must not be 0"; + errormsg = ostr.str(); + return false; } @@ -3066,8 +3196,15 @@ int IDF3_BOARD::GetUserPrecision( void ) bool IDF3_BOARD::SetUserPrecision( int aPrecision ) { - if( aPrecision < 0 || aPrecision > 8 ) + if( aPrecision < 1 || aPrecision > 8 ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* precision value (" << aPrecision << ") must be 1..8"; + errormsg = ostr.str(); + return false; + } userPrec = aPrecision; return true; @@ -3092,19 +3229,38 @@ void IDF3_BOARD::SetUserOffset( double aXoff, double aYoff ) bool IDF3_BOARD::AddBoardOutline( IDF_OUTLINE* aOutline ) { - return olnBoard.AddOutline( aOutline ); + if( !olnBoard.AddOutline( aOutline ) ) + { + errormsg = olnBoard.GetError(); + + return false; + } + + return true; } bool IDF3_BOARD::DelBoardOutline( IDF_OUTLINE* aOutline ) { - return olnBoard.DelOutline( aOutline ); + if( !olnBoard.DelOutline( aOutline ) ) + { + errormsg = olnBoard.GetError(); + return false; + } + + return true; } bool IDF3_BOARD::DelBoardOutline( size_t aIndex ) { - return olnBoard.DelOutline( aIndex ); + if( !olnBoard.DelOutline( aIndex ) ) + { + errormsg = olnBoard.GetError(); + return false; + } + + return true; } @@ -3145,14 +3301,10 @@ IDF_DRILL_DATA* IDF3_BOARD::AddDrill( IDF_DRILL_DATA* aDrilledHole ) if( !aDrilledHole ) return NULL; - if( CompareToken( "PANEL", aDrilledHole->GetDrillRefDes() ) ) - { - ERROR_IDF; - cerr << "\n*BUG: PANEL drilled holes are not supported\n"; - return NULL; - } - - if( CompareToken( "BOARD", aDrilledHole->GetDrillRefDes() ) ) + // note: PANEL drills are essentially BOARD drills which + // the panel requires to be present + if( CompareToken( "BOARD", aDrilledHole->GetDrillRefDes() ) + || CompareToken( "PANEL", aDrilledHole->GetDrillRefDes() ) ) { board_drills.push_back( aDrilledHole ); return aDrilledHole; @@ -3164,6 +3316,8 @@ IDF_DRILL_DATA* IDF3_BOARD::AddDrill( IDF_DRILL_DATA* aDrilledHole ) bool IDF3_BOARD::DelBoardDrill( double aDia, double aXpos, double aYpos ) { + errormsg.clear(); + std::list::iterator sp = board_drills.begin(); std::list::iterator ep = board_drills.end(); bool rval = false; @@ -3172,11 +3326,62 @@ bool IDF3_BOARD::DelBoardDrill( double aDia, double aXpos, double aYpos ) { if( (*sp)->Matches( aDia, aXpos, aYpos ) ) { +#ifndef DISABLE_IDF_OWNERSHIP + IDF3::KEY_OWNER keyo = (*sp)->GetDrillOwner(); + + if( keyo == UNOWNED || ( keyo == MCAD && cadType == CAD_MECH ) + || ( keyo == ECAD && cadType == CAD_ELEC ) ) + { + rval = true; + delete *sp; + sp = board_drills.erase( sp ); + continue; + } + else + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* ownership violation; drill owner ("; + + switch( keyo ) + { + case UNOWNED: + ostr << "UNOWNED"; + break; + + case ECAD: + ostr << "ECAD"; + break; + + case MCAD: + ostr << "MCAD"; + break; + + default: + ostr << "invalid: " << keyo; + break; + } + + ostr << ") may not be modified by "; + + if( cadType == CAD_MECH ) + ostr << "MCAD"; + else + ostr << "ECAD"; + + errormsg = ostr.str(); + + ++sp; + continue; + } +#else rval = true; delete *sp; sp = board_drills.erase( sp ); continue; +#endif } + ++sp; } @@ -3186,11 +3391,29 @@ bool IDF3_BOARD::DelBoardDrill( double aDia, double aXpos, double aYpos ) // a slot is a deficient representation of a kicad slotted hole; // it is usually associated with a component but IDFv3 does not -// provide for such an association. +// provide for such an association. Note: this mechanism must bypass +// the BOARD_OUTLINE ownership rules bool IDF3_BOARD::AddSlot( double aWidth, double aLength, double aOrientation, double aX, double aY ) { if( aWidth < IDF_MIN_DIA_MM ) - return true; + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* slot width (" << aWidth << ") must be >= " << IDF_MIN_DIA_MM; + errormsg = ostr.str(); + + return false; + } + + if( aLength < IDF_MIN_DIA_MM ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* slot length (" << aLength << ") must be >= " << IDF_MIN_DIA_MM; + errormsg = ostr.str(); + + return false; + } IDF_POINT c[2]; // centers IDF_POINT pt[4]; @@ -3201,8 +3424,11 @@ bool IDF3_BOARD::AddSlot( double aWidth, double aLength, double aOrientation, do if( aLength == aWidth ) { - ERROR_IDF; - cerr << "length == width (" << aWidth << ")\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* slot length must not equal width"; + errormsg = ostr.str(); + return false; } @@ -3237,8 +3463,11 @@ bool IDF3_BOARD::AddSlot( double aWidth, double aLength, double aOrientation, do if( outline == NULL ) { - ERROR_IDF; - cerr << "could not create an outline object\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* could not create an outline object"; + errormsg = ostr.str(); + return false; } @@ -3255,7 +3484,13 @@ bool IDF3_BOARD::AddSlot( double aWidth, double aLength, double aOrientation, do seg = new IDF_SEGMENT( c[0], pt[3], -180.0, true ); outline->push( seg ); - return AddBoardOutline( outline ); + if( !olnBoard.addOutline( outline ) ) + { + errormsg = olnBoard.GetError(); + return false; + } + + return true; } @@ -3287,8 +3522,11 @@ IDF_DRILL_DATA* IDF3_BOARD::addCompDrill( double aDia, double aXpos, double aYpo if( CompareToken( "PANEL", refdes ) ) { - ERROR_IDF; - cerr << "PANEL data not supported\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* PANEL data not supported"; + errormsg = ostr.str(); + return NULL; } @@ -3301,8 +3539,11 @@ IDF_DRILL_DATA* IDF3_BOARD::addCompDrill( double aDia, double aXpos, double aYpo if( comp == NULL ) { - ERROR_IDF; - cerr << "could not create new component object\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* could not create new component object"; + errormsg = ostr.str(); + return NULL; } @@ -3312,19 +3553,36 @@ IDF_DRILL_DATA* IDF3_BOARD::addCompDrill( double aDia, double aXpos, double aYpo } // add the drill - return ref->second->AddDrill( aDia, aXpos, aYpos, aPlating, aHoleType, aOwner ); + IDF_DRILL_DATA* dp = ref->second->AddDrill( aDia, aXpos, aYpos, aPlating, aHoleType, aOwner ); + + if( !dp ) + { + errormsg = ref->second->GetError(); + return NULL; + } + + return dp; } IDF_DRILL_DATA* IDF3_BOARD::addCompDrill( IDF_DRILL_DATA* aDrilledHole ) { if( !aDrilledHole ) + { + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): NULL pointer"; + errormsg = ostr.str(); + return NULL; + } if( CompareToken( "PANEL", aDrilledHole->GetDrillRefDes() ) ) { - ERROR_IDF; - cerr << "PANEL data not supported\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* PANEL data not supported"; + errormsg = ostr.str(); + return NULL; } @@ -3337,8 +3595,11 @@ IDF_DRILL_DATA* IDF3_BOARD::addCompDrill( IDF_DRILL_DATA* aDrilledHole ) if( comp == NULL ) { - ERROR_IDF; - cerr << "could not create new component object\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "():\n"; + ostr << "* could not create new component object"; + errormsg = ostr.str(); + return NULL; } @@ -3347,19 +3608,34 @@ IDF_DRILL_DATA* IDF3_BOARD::addCompDrill( IDF_DRILL_DATA* aDrilledHole ) ref = components.insert( std::pair< std::string, IDF3_COMPONENT*> ( comp->GetRefDes(), comp ) ).first; } - // add the drill - return ref->second->AddDrill( aDrilledHole ); + IDF_DRILL_DATA* dp = ref->second->AddDrill( aDrilledHole ); + + if( !dp ) + { + errormsg = ref->second->GetError(); + return NULL; + } + + return dp; } bool IDF3_BOARD::delCompDrill( double aDia, double aXpos, double aYpos, std::string aRefDes ) { + errormsg.clear(); + std::map::iterator ref = components.find( aRefDes ); if( ref == components.end() ) return false; - return ref->second->DelDrill( aDia, aXpos, aYpos ); + if( !ref->second->DelDrill( aDia, aXpos, aYpos ) ) + { + errormsg = ref->second->GetError(); + return false; + } + + return true; } @@ -3367,14 +3643,22 @@ bool IDF3_BOARD::AddComponent( IDF3_COMPONENT* aComponent ) { if( !aComponent ) { - ERROR_IDF << "Invalid component pointer (NULL)\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__; + ostr << "(): Invalid component pointer (NULL)"; + errormsg = ostr.str(); + return false; } if( components.insert( std::pair ( aComponent->GetRefDes(), aComponent ) ).second == false ) { - ERROR_IDF << "Duplicate RefDes ('" << aComponent->GetRefDes() << "')\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n"; + ostr << "* duplicate RefDes ('" << aComponent->GetRefDes() << "')"; + errormsg = ostr.str(); + return false; } @@ -3384,11 +3668,12 @@ bool IDF3_BOARD::AddComponent( IDF3_COMPONENT* aComponent ) bool IDF3_BOARD::DelComponent( IDF3_COMPONENT* aComponent ) { - if( !aComponent ) - { - ERROR_IDF << "Invalid component pointer (NULL)\n"; + errormsg.clear(); + +#ifndef DISABLE_IDF_OWNERSHIP + if( !checkComponentOwnership( __LINE__, __FUNCTION__, aComponent ) ) return false; - } +#endif std::map::iterator it = components.find( aComponent->GetRefDes() ); @@ -3407,19 +3692,27 @@ bool IDF3_BOARD::DelComponent( size_t aIndex ) { if( aIndex >= components.size() ) { - ERROR_IDF << "index (" << aIndex << ") >= components size (" - << components.size() << ")\n"; - return false; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n"; + ostr << "* aIndex (" << aIndex << ") out of range (" << components.size() << ")"; + errormsg = ostr.str(); + + return false; } std::map::iterator it = components.begin(); while( aIndex-- > 0 ) ++it; +#ifndef DISABLE_IDF_OWNERSHIP + if( !checkComponentOwnership( __LINE__, __FUNCTION__, it->second ) ) + return false; +#endif + delete it->second; components.erase( it ); - return false; + return true; } @@ -3462,14 +3755,17 @@ IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( const std::string aGeomName, std::string fname = TO_UTF8( aFullFileName ); - cp = new IDF3_COMP_OUTLINE; + cp = new IDF3_COMP_OUTLINE( this ); if( cp == NULL ) { - ERROR_IDF; - cerr << "failed to create outline with UID '" << aGeomName << "_"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n"; + cerr << "* failed to create outline with UID '" << aGeomName << "_"; cerr << aPartName << "'\n"; - cerr << "* filename: '" << fname << "'\n"; + cerr << "* filename: '" << fname << "'"; + errormsg = ostr.str(); + return NULL; } @@ -3477,89 +3773,97 @@ IDF3_COMP_OUTLINE* IDF3_BOARD::GetComponentOutline( const std::string aGeomName, if( !idflib.IsOk() ) { - ERROR_IDF; - cerr << "invalid file name: '" << fname << "'\n"; delete cp; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n"; + cerr << "* invalid file name: '" << fname << "'"; + errormsg = ostr.str(); + return NULL; } if( !idflib.FileExists() ) { - ERROR_IDF; - cerr << "no such file: '" << fname << "'\n"; delete cp; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n"; + cerr << "* no such file: '" << fname << "'"; + errormsg = ostr.str(); + return NULL; } if( !idflib.IsFileReadable() ) { - ERROR_IDF; - cerr << "cannot read file: '" << fname << "'\n"; delete cp; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): \n"; + cerr << "* cannot read file: '" << fname << "'"; + errormsg = ostr.str(); + return NULL; } std::ifstream model; + model.exceptions ( std::ifstream::badbit ); - model.open( fname.c_str(), std::ios_base::in ); - - if( !model.is_open() ) + try { - ERROR_IDF; - cerr << "could not open file: '" << fname << "'\n"; - delete cp; - return NULL; - } + model.open( fname.c_str(), std::ios_base::in ); - std::string iline; // the input line - bool isComment; // true if a line just read in is a comment line - std::streampos pos; - while( true ) - { - while( !FetchIDFLine( model, iline, isComment, pos ) && model.good() ); + std::string iline; // the input line + bool isComment; // true if a line just read in is a comment line + std::streampos pos; - if( !model.good() ) + + while( true ) { - ERROR_IDF; - cerr << "problems reading file: '" << fname << "'\n"; - delete cp; - model.close(); - return NULL; - } + while( !FetchIDFLine( model, iline, isComment, pos ) && model.good() ); - // accept comment lines, .ELECTRICAL, or .MECHANICAL only - if( isComment ) - { - cp->AddComment( iline ); - continue; - } - - if( CompareToken( ".ELECTRICAL", iline ) || CompareToken( ".MECHANICAL", iline ) ) - { - if( !cp->ReadData( model, iline ) ) + if( !model.good() ) { - ERROR_IDF; - cerr << "problems reading file: '" << fname << "'\n"; - delete cp; - model.close(); - return NULL; + ostringstream ostr; + ostr << "\n* problems reading file: '" << fname << "'"; + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); + } + + // accept comment lines, .ELECTRICAL, or .MECHANICAL only + if( isComment ) + { + cp->AddComment( iline ); + continue; + } + + if( CompareToken( ".ELECTRICAL", iline ) || CompareToken( ".MECHANICAL", iline ) ) + { + cp->readData( model, iline, idfVer ); + break; } else { - break; + ostringstream ostr; + ostr << "faulty IDF component definition\n"; + ostr << "* Expecting .ELECTRICAL or .MECHANICAL, got '" << iline << "'\n"; + cerr << "* File: '" << fname << "'\n"; + + throw( IDF_ERROR( __FILE__, __FUNCTION__, __LINE__, ostr.str() ) ); } - } - else - { - ERROR_IDF << "faulty IDF component definition\n"; - cerr << "* Expecting .ELECTRICAL or .MECHANICAL, got '" << iline << "'\n"; - cerr << "* File: '" << fname << "'\n"; - delete cp; + } // while( true ) + } + catch( std::exception& e ) + { + delete cp; + + model.exceptions ( std::ios_base::goodbit ); + + if( model.is_open() ) model.close(); - return NULL; - } - } // while( true ) + + errormsg = e.what(); + + return NULL; + } model.close(); @@ -3602,11 +3906,15 @@ IDF3_COMP_OUTLINE* IDF3_BOARD::GetInvalidOutline( const std::string& aGeomName, if( cp != NULL ) return cp; - cp = new IDF3_COMP_OUTLINE; + cp = new IDF3_COMP_OUTLINE( this ); if( cp == NULL ) { - ERROR_IDF << "could not create new outline\n"; + ostringstream ostr; + ostr << __FILE__ << ":" << __LINE__ << ":" << __FUNCTION__ << "(): "; + cerr << "could not create new outline"; + errormsg = ostr.str(); + return NULL; } @@ -3807,7 +4115,7 @@ void IDF3_BOARD::Clear( void ) } while(0); boardName.clear(); - olnBoard.SetThickness( thickness ); + olnBoard.setThickness( thickness ); state = FILE_START; unit = UNIT_MM; @@ -3817,3 +4125,10 @@ void IDF3_BOARD::Clear( void ) return; } + + +const std::map*const +IDF3_BOARD::GetOtherOutlines( void ) +{ + return &olnOther; +} diff --git a/utils/idftools/idf_parser.h b/utils/idftools/idf_parser.h index eb812a997c..cc7909f347 100644 --- a/utils/idftools/idf_parser.h +++ b/utils/idftools/idf_parser.h @@ -21,27 +21,36 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ -// NOTE: -// 1. Due to the complexity of objects and the risk of accumulated -// position errors, CAD packages should only delete or add complete -// components. If a component being added already exists, it is -// replaced by the new component IF and only if the CAD type is -// permitted to make such changes. -// -// 2. Internally all units shall be in mm and by default we shall -// write files with mm units. The internal flags mm/thou shall only -// be used to translate data being read from or written to files. -// This avoids the painful management of a mixture of mm and thou. -// The API shall require all dimensions in mm; for people using any -// other unit, it is their responsibility to perform the conversion -// to mm. Conversion back to thou may incur small rounding errors. +/* + * NOTE: + * + * Rules to ensure friendly use within a DLL: + * + * 1. all functions which throw exceptions must not be publicly available; + * they must become FRIEND functions instead. + * + * 2. All objects with PRIVATE functions which throw exceptions when + * invoked by a PUBLIC function must indicate success or failure + * and make the exception information available via a GetError() + * routine. + * + * General notes: + * + * 1. Due to the complexity of objects and the risk of accumulated + * position errors, CAD packages should only delete or add complete + * components. If a component being added already exists, it is + * replaced by the new component IF and only if the CAD type is + * permitted to make such changes. + * + * 2. Internally all units shall be in mm and by default we shall + * write files with mm units. The internal flags mm/thou shall only + * be used to translate data being read from or written to files. + * This avoids the painful management of a mixture of mm and thou. + * The API shall require all dimensions in mm; for people using any + * other unit, it is their responsibility to perform the conversion + * to mm. Conversion back to thou may incur small rounding errors. + */ -// BUGS: -// 1. IDF compliance: On DELETE operations, ensure that the CAD -// has permission to make these deletions. This is no small task; -// however this compliance task can be deferred since it is not -// essential to the immediate needs of KiCad which are IDF -// export and IDF->VRML conversion #ifndef IDF_PARSER_H #define IDF_PARSER_H @@ -52,15 +61,58 @@ class IDF3_COMPONENT; class IDF3_COMP_OUTLINE_DATA { +friend class IDF3_BOARD; +friend class IDF3_COMPONENT; private: double xoff; // X offset from KiCad or X placement from IDF file double yoff; // Y offset from KiCad or Y placement from IDF file double zoff; // height offset (specified in IDFv3 spec, corresponds to KiCad Z offset) double aoff; // angular offset from KiCad or Rotation Angle from IDF file + std::string errormsg; IDF3_COMP_OUTLINE* outline; // component outline to use IDF3_COMPONENT* parent; // associated component +#ifndef DISABLE_IDF_OWNERSHIP + bool checkOwnership( int aSourceLine, const char* aSourceFunc ); +#endif + + /** + * Function readPlaceData + * reads placement data from an open IDFv3 file + * + * @param aBoardFile is the open IDFv3 file + * @param aBoardState is the internal status flag of the IDF parser + * @param aIdfVersion is the version of the file currently being parsed + * @param aBoard is the IDF3_BOARD object which will store the data + * + * @return bool: true if placement data was successfully read. false if + * no placement data was read; this may happen if the end of the placement + * data was encountered or an error occurred. if an error occurred then + * an exception is thrown. + */ + bool readPlaceData( std::ifstream &aBoardFile, IDF3::FILE_STATE& aBoardState, + IDF3_BOARD *aBoard, IDF3::IDF_VERSION aIdfVersion, + bool aNoSubstituteOutlines ); + + /** + * Function writePlaceData + * writes RECORD 2 and RECORD 3 of a PLACEMENT section as per IDFv3 specification + * + * @param aBoardFile is the open IDFv3 file + * @param aXpos is the X location of the parent component + * @param aYpos is the Y location of the parent component + * @param aAngle is the rotation of the parent component + * @param aRefDes is the reference designator of the parent component + * @param aPlacement is the IDF Placement Status of the parent component + * @param aSide is the IDF Layer Designator (TOP or BOTTOM) + * + * @return bool: true if data was successfully written, otherwise false + */ + void writePlaceData( std::ofstream& aBoardFile, double aXpos, double aYpos, double aAngle, + const std::string aRefDes, IDF3::IDF_PLACEMENT aPlacement, + IDF3::IDF_LAYER aSide ); + public: /** * Constructor @@ -102,8 +154,11 @@ public: * @param aYoff is the Y offset of this outline in relation to its parent * @param aZoff is the board offset of this outline as per IDFv3 specification * @param aAoff is the rotational offset of this outline in relation to its parent + * + * @return bool: true if the operation succeeded, false if an ownership + * violation occurred */ - void SetOffsets( double aXoff, double aYoff, double aZoff, double aAngleOff ); + bool SetOffsets( double aXoff, double aYoff, double aZoff, double aAngleOff ); /** * Function GetOffsets @@ -129,8 +184,11 @@ public: * sets the outline whose position is managed by this object * * @param aOutline is the outline for this component + * + * @return bool: true if the operation succeeded, false if an ownership + * violation occurred */ - void SetOutline( IDF3_COMP_OUTLINE* aOutline ); + bool SetOutline( IDF3_COMP_OUTLINE* aOutline ); /** * Function GetOutline @@ -143,44 +201,16 @@ public: return outline; } - /** - * Function ReadPlaceData - * reads placement data from an open IDFv3 file - * - * @param aBoardFile is the open IDFv3 file - * @param aBoardState is the internal status flag of the IDF parser - * @param aBoard is the IDF3_BOARD object which will store the data - * - * @return bool: true if placement data was successfully read. false if - * no placement data was read; this may happen if the end of the placement - * data was encountered or an error occurred. if an error occurred then - * aBoardState is set to IDF3::FILE_INVALID or IDF3::FILE_ERROR. - */ - bool ReadPlaceData( std::ifstream &aBoardFile, IDF3::FILE_STATE& aBoardState, - IDF3_BOARD *aBoard ); - - /** - * Function WritePlaceData - * writes RECORD 2 and RECORD 3 of a PLACEMENT section as per IDFv3 specification - * - * @param aBoardFile is the open IDFv3 file - * @param aXpos is the X location of the parent component - * @param aYpos is the Y location of the parent component - * @param aAngle is the rotation of the parent component - * @param aRefDes is the reference designator of the parent component - * @param aPlacement is the IDF Placement Status of the parent component - * @param aSide is the IDF Layer Designator (TOP or BOTTOM) - * - * @return bool: true if data was successfully written, otherwise false - */ - bool WritePlaceData( std::ofstream& aBoardFile, double aXpos, double aYpos, double aAngle, - const std::string aRefDes, IDF3::IDF_PLACEMENT aPlacement, - IDF3::IDF_LAYER aSide ); + const std::string& GetError( void ) + { + return errormsg; + } }; class IDF3_COMPONENT { +friend class IDF3_BOARD; private: std::list< IDF3_COMP_OUTLINE_DATA* > components; std::list< IDF_DRILL_DATA* > drills; @@ -193,14 +223,33 @@ private: bool hasPosition; ///< True after SetPosition is called once std::string refdes; ///< Reference Description (MUST BE UNIQUE) IDF3_BOARD* parent; + std::string errormsg; + + /** + * Function WriteDrillData + * writes the internal drill data to an IDFv3 .DRILLED_HOLES section + * + * @param aBoardFile is an IDFv3 file opened for writing + * + * @return bool: true if the operation succeeded, otherwise false + */ + bool writeDrillData( std::ofstream& aBoardFile ); + + /** + * Function WritePlaceData + * writes the component placement data to an IDFv3 .PLACEMENT section + * + * @param aBoardFile is an IDFv3 file opened for writing + * + * @return bool: true if the operation succeeded, otherwise false + */ + bool writePlaceData( std::ofstream& aBoardFile ); + +#ifndef DISABLE_IDF_OWNERSHIP + bool checkOwnership( int aSourceLine, const char* aSourceFunc ); +#endif public: - /** - * Constructor - * sets internal parameters to default values - */ - IDF3_COMPONENT(); - /** * Constructor * sets the parent object and initializes other internal parameters to default values @@ -399,33 +448,22 @@ public: * sets the placement value of the component subject to ownership rules. * An exception is thrown if aPlacementValue is invalid or an ownership * violation occurs. + * + * @return bool: true if the operation succeeded, otherwise false and the + * error message is set. */ - void SetPlacement( IDF3::IDF_PLACEMENT aPlacementValue ); + bool SetPlacement( IDF3::IDF_PLACEMENT aPlacementValue ); - /** - * Function WriteDrillData - * writes the internal drill data to an IDFv3 .DRILLED_HOLES section - * - * @param aBoardFile is an IDFv3 file opened for writing - * - * @return bool: true if the operation succeeded, otherwise false - */ - bool WriteDrillData( std::ofstream& aBoardFile ); - - /** - * Function WritePlaceData - * writes the component placement data to an IDFv3 .PLACEMENT section - * - * @param aBoardFile is an IDFv3 file opened for writing - * - * @return bool: true if the operation succeeded, otherwise false - */ - bool WritePlaceData( std::ofstream& aBoardFile ); + const std::string& GetError( void ) + { + return errormsg; + } }; class IDF3_BOARD { private: + std::string errormsg; // string for passing error messages to user std::list< IDF_NOTE* > notes; // IDF notes std::list< std::string > noteComments; // comment list for NOTES section std::list< std::string > drillComments; // comment list for DRILL section @@ -437,6 +475,7 @@ private: IDF3::FILE_STATE state; IDF3::CAD_TYPE cadType; IDF3::IDF_UNIT unit; + IDF3::IDF_VERSION idfVer; // IDF version of Board or Library std::string idfSource; // SOURCE string to use when writing BOARD and LIBRARY headers std::string brdSource; // SOURCE string as retrieved from a BOARD file @@ -483,31 +522,40 @@ private: bool delCompDrill( double aDia, double aXpos, double aYpos, std::string aRefDes ); // read the DRILLED HOLES section - bool readBrdDrills( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ); + void readBrdDrills( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ); // read the NOTES section - bool readBrdNotes( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ); + void readBrdNotes( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ); // read the component placement section - bool readBrdPlacement( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ); + void readBrdPlacement( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState, + bool aNoSubstituteOutlines ); // read the board HEADER - bool readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ); + void readBrdHeader( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ); // read individual board sections; pay attention to IDFv3 section specifications - bool readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState ); + // exception thrown on unrecoverable errors. state flag set to FILE_PLACEMENT + // upon reading the PLACEMENT file; according to IDFv3 this is the final section + void readBrdSection( std::ifstream& aBoardFile, IDF3::FILE_STATE& aBoardState, + bool aNoSubstituteOutlines ); // read the board file data - bool readBoardFile( const std::string& aFileName ); + void readBoardFile( const std::string& aFileName, bool aNoSubstituteOutlines ); // write the board file data - bool writeBoardFile( const std::string& aFileName ); + void writeBoardFile( const std::string& aFileName ); // read the library sections (outlines) - bool readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState, IDF3_BOARD* aBoard ); + void readLibSection( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState, IDF3_BOARD* aBoard ); // read the library HEADER - bool readLibHeader( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState ); + void readLibHeader( std::ifstream& aLibFile, IDF3::FILE_STATE& aLibState ); // read the library file data - bool readLibFile( const std::string& aFileName ); + void readLibFile( const std::string& aFileName ); // write the library file data bool writeLibFile( const std::string& aFileName ); +#ifndef DISABLE_IDF_OWNERSHIP + bool checkComponentOwnership( int aSourceLine, const char* aSourceFunc, + IDF3_COMPONENT* aComponent ); +#endif + public: IDF3_BOARD( IDF3::CAD_TYPE aCadType ); virtual ~IDF3_BOARD(); @@ -527,7 +575,7 @@ public: bool SetBoardThickness( double aBoardThickness ); double GetBoardThickness( void ); - bool ReadFile( const wxString& aFullFileName ); + bool ReadFile( const wxString& aFullFileName, bool aNoSubstituteOutlines = false ); bool WriteFile( const wxString& aFullFileName, bool aUnitMM = true, bool aForceUnitFlag = false ); const std::string& GetIDFSource( void ); @@ -557,7 +605,13 @@ public: BOARD_OUTLINE* GetBoardOutline( void ); const std::list< IDF_OUTLINE* >*const GetBoardOutlines( void ); + // Operations for OTHER OUTLINES + const std::map*const GetOtherOutlines( void ); + /// XXX - TO BE IMPLEMENTED + // + // SetBoardOutlineOwner() + // // AddDrillComment // AddPlacementComment // GetDrillComments() @@ -568,7 +622,7 @@ public: // GetNoteComments // AddNote // - // const std::map*const GetOtherOutlines() + // [IMPLEMENTED] const std::map*const GetOtherOutlines( void ) // size_t GetOtherOutlinesSize() // OTHER_OUTLINE* AddOtherOutline( OTHER_OUTLINE* aOtherOutline ) // bool DelOtherOutline( int aIndex ) @@ -652,6 +706,12 @@ public: // clears all data void Clear( void ); + + // return error string + const std::string& GetError( void ) + { + return errormsg; + } }; #endif // IDF_PARSER_H