KiCad PCB EDA Suite
gbr_metadata.cpp File Reference

helper functions to handle the gerber metadata in files, related to the netlist info and aperture attribute. More...

#include <wx/string.h>
#include <wx/datetime.h>
#include <gbr_metadata.h>
#include <utf8.h>

Go to the source code of this file.

Macros

#define NO_NET_NAME   wxT( "N/C" )
 
#define NO_PAD_NAME   wxT( "" )
 

Functions

wxString GbrMakeCreationDateAttributeString (GBR_NC_STRING_FORMAT aFormat)
 
wxString GbrMakeProjectGUIDfromString (const wxString &aText)
 Build a project GUID using format RFC4122 Version 1 or 4 from the project name, because a KiCad project has no specific GUID. More...
 
int char2Hex (unsigned aCode)
 
wxString FormatStringFromGerber (const wxString &aString)
 Convert a gerber string into a 16 bit Unicode string. More...
 
wxString ConvertNotAllowedCharsInGerber (const wxString &aString, bool aAllowUtf8Chars, bool aQuoteString)
 Normalize aString and convert it to a Gerber compatible wxString. More...
 
std::string FormatStringToGerber (const wxString &aString)
 Normalize aString and convert it to a Gerber std::string. More...
 
bool FormatNetAttribute (std::string &aPrintedText, std::string &aLastNetAttributes, const GBR_NETLIST_METADATA *aData, bool &aClearPreviousAttributes, bool aUseX1StructuredComment)
 Generate the string to set a net attribute for a graphic object to print to a gerber file. More...
 

Detailed Description

helper functions to handle the gerber metadata in files, related to the netlist info and aperture attribute.

Definition in file gbr_metadata.cpp.

Macro Definition Documentation

◆ NO_NET_NAME

#define NO_NET_NAME   wxT( "N/C" )

Definition at line 524 of file gbr_metadata.cpp.

◆ NO_PAD_NAME

#define NO_PAD_NAME   wxT( "" )

Definition at line 525 of file gbr_metadata.cpp.

Function Documentation

◆ char2Hex()

int char2Hex ( unsigned  aCode)

Definition at line 347 of file gbr_metadata.cpp.

348 {
349  if( aCode >= '0' && aCode <= '9' )
350  return aCode - '0';
351 
352  if( aCode >= 'A' && aCode <= 'F' )
353  return aCode - 'A' + 10;
354 
355  if( aCode >= 'a' && aCode <= 'f' )
356  return aCode - 'a' + 10;
357 
358  return -1;
359 }

Referenced by FormatStringFromGerber().

◆ ConvertNotAllowedCharsInGerber()

wxString ConvertNotAllowedCharsInGerber ( const wxString &  aString,
bool  aAllowUtf8Chars,
bool  aQuoteString 
)

Normalize aString and convert it to a Gerber compatible wxString.

Normalization means convert to a hexadecimal 16 bit sequence Unicode and on request convert any code > 0x7F. Illegal characters are ',' '*' '' '\'.

Parameters
aStringthe string to convert.
aAllowUtf8Charsfalse to convert non ASCII7 values to Unicode sequence.
aQuoteStringtrue to double quote the returned string.
Returns
a without illegal chars (and converted non ASCII7 chars on request)

Definition at line 426 of file gbr_metadata.cpp.

427 {
428  /* format string means convert any code > 0x7E and unautorized codes to a hexadecimal
429  * 16 bits sequence unicode
430  * However if aAllowUtf8Chars is true only unautorized codes will be escaped, because some
431  * Gerber files accept UTF8 chars.
432  * unautorized codes are ',' '*' '%' '\' '"' and are used as separators in Gerber files
433  */
434  wxString txt;
435 
436  if( aQuoteString )
437  txt << "\"";
438 
439  for( unsigned ii = 0; ii < aString.Length(); ++ii )
440  {
441  wxChar code = aString[ii];
442  bool convert = false;
443 
444  switch( code )
445  {
446  case '\\':
447  case '%':
448  case '*':
449  case ',':
450  convert = true;
451  break;
452 
453  case '"':
454  if( aQuoteString )
455  convert = true;
456  break;
457 
458  default:
459  break;
460  }
461 
462  if( !aAllowUtf8Chars && code > 0x7F )
463  convert = true;
464 
465  if( convert )
466  {
467  // Convert code to 4 hexadecimal digit
468  // (Gerber allows only 4 hexadecimal digit) in escape seq:
469  // "\uXXXX", XXXX is the unicode 16 bits hexa value
470  char hexa[32];
471  sprintf( hexa,"\\u%4.4X", code & 0xFFFF);
472  txt += hexa;
473  }
474  else
475  txt += code;
476  }
477 
478  if( aQuoteString )
479  txt << "\"";
480 
481  return txt;
482 }

References convert.

Referenced by PLACEFILE_GERBER_WRITER::CreatePlaceFile(), FormatStringToGerber(), and GBR_DATA_FIELD::GetGerberString().

◆ FormatNetAttribute()

bool FormatNetAttribute ( std::string &  aPrintedText,
std::string &  aLastNetAttributes,
const GBR_NETLIST_METADATA aData,
bool &  aClearPreviousAttributes,
bool  aUseX1StructuredComment 
)

Generate the string to set a net attribute for a graphic object to print to a gerber file.

Parameters
aPrintedTextis the string to print.
aLastNetAttributesis the current full set of attributes.
aDatais the GBR_NETLIST_METADATA associated to the graphic object (can be NULL if no associated metadata, and aClearPreviousAttributes will be set to false)
aClearPreviousAttributesreturns true if the full set of attributes must be deleted from file before adding new attribute (happens when a previous attribute no longer exists).
aUseX1StructuredCommentfalse in X2 mode and true in X1 mode to add the net attribute in compatible X1 structured comment (i.e. prefixed by "G04 #@! ")
Returns
false if nothing can be done (GBR_NETLIST_METADATA has GBR_APERTURE_ATTRIB_NONE, and true if OK. If the new attribute(s) is the same as current attribute(s), aPrintedText will be empty.

Definition at line 527 of file gbr_metadata.cpp.

530 {
531  aClearPreviousAttributes = false;
532  wxString prepend_string;
533  wxString eol_string;
534 
535  if( aUseX1StructuredComment )
536  {
537  prepend_string = "G04 #@! ";
538  eol_string = "*\n";
539  }
540  else
541  {
542  prepend_string = "%";
543  eol_string = "*%\n";
544  }
545 
546  // print a Gerber net attribute record.
547  // it is added to the object attributes dictionary
548  // On file, only modified or new attributes are printed.
549  if( aData == NULL )
550  return false;
551 
552  std::string pad_attribute_string;
553  std::string net_attribute_string;
554  std::string cmp_attribute_string;
555 
557  return false; // idle command: do nothing
558 
560  {
561  // print info associated to a flashed pad (cmpref, pad name, and optionally pin function)
562  // example1: %TO.P,R5,3*%
563  // example2: %TO.P,R5,3,reset*%
564  pad_attribute_string = prepend_string + "TO.P,";
565  pad_attribute_string += FormatStringToGerber( aData->m_Cmpref ) + ",";
566 
567  if( aData->m_Padname.IsEmpty() )
568  // Happens for "mechanical" or never connected pads
569  pad_attribute_string += FormatStringToGerber( NO_PAD_NAME );
570  else
571  {
572  pad_attribute_string += aData->m_Padname.GetGerberString();
573 
574  // In Pcbnew, the pin function comes from the schematic.
575  // so it exists only for named pads
576  if( !aData->m_PadPinFunction.IsEmpty() )
577  {
578  pad_attribute_string += ',';
579  pad_attribute_string += aData->m_PadPinFunction.GetGerberString();
580  }
581  }
582 
583  pad_attribute_string += eol_string;
584  }
585 
587  {
588  // print info associated to a net
589  // example: %TO.N,Clk3*%
590  net_attribute_string = prepend_string + "TO.N,";
591 
592  if( aData->m_Netname.IsEmpty() )
593  {
594  if( aData->m_NotInNet )
595  {
596  // Happens for not connectable pads: mechanical pads
597  // and pads with no padname/num
598  // In this case the net name must be left empty
599  }
600  else
601  {
602  // Happens for not connected pads: use a normalized
603  // dummy name
604  net_attribute_string += FormatStringToGerber( NO_NET_NAME );
605  }
606  }
607  else
608  net_attribute_string += FormatStringToGerber( aData->m_Netname );
609 
610  net_attribute_string += eol_string;
611  }
612 
615  {
616  // print info associated to a footprint
617  // example: %TO.C,R2*%
618  // Because GBR_NETINFO_PAD option already contains this info, it is not
619  // created here for a GBR_NETINFO_PAD attribute
620  cmp_attribute_string = prepend_string + "TO.C,";
621  cmp_attribute_string += FormatStringToGerber( aData->m_Cmpref ) + eol_string;
622  }
623 
624  // the full list of requested attributes:
625  std::string full_attribute_string = pad_attribute_string + net_attribute_string
626  + cmp_attribute_string;
627  // the short list of requested attributes
628  // (only modified or new attributes are stored here):
629  std::string short_attribute_string;
630 
631  // Attributes have changed: update attribute string, and see if the previous attribute
632  // list (dictionary in Gerber language) must be cleared
633  if( aLastNetAttributes != full_attribute_string )
634  {
635  // first, remove no longer existing attributes.
636  // Because in Kicad the full attribute list is evaluated for each object,
637  // the entire dictionary is cleared
638  // If m_TryKeepPreviousAttributes is true, only the no longer existing attribute
639  // is cleared.
640  // Note: to avoid interaction beteween clear attributes and set attributes
641  // the clear attribute is inserted first.
642  bool clearDict = false;
643 
644  if( aLastNetAttributes.find( "TO.P," ) != std::string::npos )
645  {
646  if( pad_attribute_string.empty() ) // No more this attribute
647  {
648  if( aData->m_TryKeepPreviousAttributes ) // Clear only this attribute
649  short_attribute_string.insert( 0, prepend_string + "TO.P" + eol_string );
650  else
651  clearDict = true;
652  }
653  else if( aLastNetAttributes.find( pad_attribute_string )
654  == std::string::npos ) // This attribute has changed
655  short_attribute_string += pad_attribute_string;
656  }
657  else // New attribute
658  short_attribute_string += pad_attribute_string;
659 
660  if( aLastNetAttributes.find( "TO.N," ) != std::string::npos )
661  {
662  if( net_attribute_string.empty() ) // No more this attribute
663  {
664  if( aData->m_TryKeepPreviousAttributes ) // Clear only this attribute
665  short_attribute_string.insert( 0, prepend_string + "TO.N" + eol_string );
666  else
667  clearDict = true;
668  }
669  else if( aLastNetAttributes.find( net_attribute_string )
670  == std::string::npos ) // This attribute has changed
671  short_attribute_string += net_attribute_string;
672  }
673  else // New attribute
674  short_attribute_string += net_attribute_string;
675 
676  if( aLastNetAttributes.find( "TO.C," ) != std::string::npos )
677  {
678  if( cmp_attribute_string.empty() ) // No more this attribute
679  {
680  if( aData->m_TryKeepPreviousAttributes ) // Clear only this attribute
681  {
682  // Refinement:
683  // the attribute will be cleared only if there is no pad attribute.
684  // If a pad attribute exists, the component name exists so the old
685  // TO.C value will be updated, therefore no need to clear it before updating
686  if( pad_attribute_string.empty() )
687  short_attribute_string.insert( 0, prepend_string + "TO.C" + eol_string );
688  }
689  else
690  clearDict = true;
691  }
692  else if( aLastNetAttributes.find( cmp_attribute_string )
693  == std::string::npos ) // This attribute has changed
694  short_attribute_string += cmp_attribute_string;
695  }
696  else // New attribute
697  short_attribute_string += cmp_attribute_string;
698 
699  aClearPreviousAttributes = clearDict;
700 
701  aLastNetAttributes = full_attribute_string;
702 
703  if( clearDict )
704  aPrintedText = full_attribute_string;
705  else
706  aPrintedText = short_attribute_string;
707  }
708 
709  return true;
710 }
std::string FormatStringToGerber(const wxString &aString)
Normalize aString and convert it to a Gerber std::string.
#define NO_NET_NAME
print info associated to a component (TO.C attribute)
wxString m_Cmpref
the component reference parent of the data
GBR_DATA_FIELD m_PadPinFunction
for a pad: the pin function (defined in schematic)
#define NULL
#define NO_PAD_NAME
GBR_DATA_FIELD m_Padname
for a flashed pad: the pad name ((TO.P attribute)
wxString m_Netname
for items associated to a net: the netname
bool m_TryKeepPreviousAttributes
If true, do not clear all attributes when a attribute has changed.
print info associated to a flashed pad (TO.P attribute)
bool m_NotInNet
true if a pad of a footprint cannot be connected (for instance a mechanical NPTH, ot a not named pad)...
std::string GetGerberString() const
print info associated to a net (TO.N attribute)
int m_NetAttribType
the type of net info (used to define the gerber string to create)

References FormatStringToGerber(), GBR_NETLIST_METADATA::GBR_NETINFO_CMP, GBR_NETLIST_METADATA::GBR_NETINFO_NET, GBR_NETLIST_METADATA::GBR_NETINFO_PAD, GBR_NETLIST_METADATA::GBR_NETINFO_UNSPECIFIED, GBR_DATA_FIELD::GetGerberString(), GBR_DATA_FIELD::IsEmpty(), GBR_NETLIST_METADATA::m_Cmpref, GBR_NETLIST_METADATA::m_NetAttribType, GBR_NETLIST_METADATA::m_Netname, GBR_NETLIST_METADATA::m_NotInNet, GBR_NETLIST_METADATA::m_Padname, GBR_NETLIST_METADATA::m_PadPinFunction, GBR_NETLIST_METADATA::m_TryKeepPreviousAttributes, NO_NET_NAME, NO_PAD_NAME, and NULL.

Referenced by GERBER_PLOTTER::formatNetAttribute().

◆ FormatStringFromGerber()

wxString FormatStringFromGerber ( const wxString &  aString)

Convert a gerber string into a 16 bit Unicode string.

Parameters
aStringthe gerber string to format.
Returns
a 16 bit Unicode string.

Definition at line 362 of file gbr_metadata.cpp.

363 {
364  // make the inverse conversion of FormatStringToGerber()
365  // It converts a "normalized" gerber string containing escape sequences
366  // and convert it to a 16 bits unicode char
367  // and return a wxString (unicode 16) from the gerber string
368  // Note the initial gerber string can already contain unicode chars.
369  wxString txt; // The string converted from Gerber string
370 
371  unsigned count = aString.Length();
372 
373  for( unsigned ii = 0; ii < count; ++ii )
374  {
375  unsigned code = aString[ii];
376 
377  if( code == '\\' && ii < count-5 && aString[ii+1] == 'u' )
378  {
379  // Note the latest Gerber X2 spec (2019 06) uses \uXXXX to encode
380  // the unicode XXXX hexadecimal value
381  // If 4 chars next to 'u' are hexadecimal chars,
382  // Convert these 4 hexadecimal digits to a 16 bit unicode
383  // (Gerber allows only 4 hexadecimal digits)
384  // If an error occurs, the escape sequence is not translated,
385  // and used "as this"
386  long value = 0;
387  bool error = false;
388 
389  for( int jj = 0; jj < 4; jj++ )
390  {
391  value <<= 4;
392  code = aString[ii+jj+2];
393 
394  int hexa = char2Hex( code );
395 
396  if( hexa >= 0 )
397  value += hexa;
398  else
399  {
400  error = true;
401  break;
402  }
403  }
404 
405  if( !error )
406  {
407  if( value >= ' ' ) // Is a valid wxChar ?
408  txt.Append( wxChar( value ) );
409 
410  ii += 5;
411  }
412  else
413  {
414  txt.Append( aString[ii] );
415  continue;
416  }
417  }
418  else
419  txt.Append( aString[ii] );
420  }
421 
422  return txt;
423 }
int char2Hex(unsigned aCode)

References char2Hex().

Referenced by GERBER_FILE_IMAGE::ExecuteRS274XCommand().

◆ FormatStringToGerber()

std::string FormatStringToGerber ( const wxString &  aString)

Normalize aString and convert it to a Gerber std::string.

Normalization means convert any code > 0x7F and unauthorized code to a hexadecimal 16 bit sequence Unicode. Illegal characters are ',' '*' '' '\'.

Parameters
aStringthe string to convert.
Returns
an ASCII7 coded compliant gerber string.

Definition at line 500 of file gbr_metadata.cpp.

501 {
502  wxString converted;
503  /* format string means convert any code > 0x7E and unautorized codes to a hexadecimal
504  * 16 bits sequence unicode
505  * unautorized codes are ',' '*' '%' '\'
506  * This conversion is not made for quoted strings, because if the string is
507  * quoted, the conversion is expected to be already made, and the returned string must use
508  * UTF8 encoding
509  */
510  if( !aString.IsEmpty() && ( aString[0] != '\"' || aString[aString.Len()-1] != '\"' ) )
511  converted = ConvertNotAllowedCharsInGerber( aString, false, false );
512  else
513  converted = aString;
514 
515  // Convert the char string to std::string. Be careful when converting awxString to
516  // a std::string: using static_cast<const char*> is mandatory
517  std::string txt = static_cast<const char*>( converted.utf8_str() );
518 
519  return txt;
520 }
wxString ConvertNotAllowedCharsInGerber(const wxString &aString, bool aAllowUtf8Chars, bool aQuoteString)
Normalize aString and convert it to a Gerber compatible wxString.

References ConvertNotAllowedCharsInGerber().

Referenced by FormatNetAttribute().

◆ GbrMakeCreationDateAttributeString()

wxString GbrMakeCreationDateAttributeString ( GBR_NC_STRING_FORMAT  aFormat)

Definition at line 36 of file gbr_metadata.cpp.

37 {
38  // creates the CreationDate attribute:
39  // The attribute value must conform to the full version of the ISO 8601
40  // date and time format, including time and time zone. Note that this is
41  // the date the Gerber file was effectively created,
42  // not the time the project of PCB was started
43  wxDateTime date( wxDateTime::GetTimeNow() );
44  // Date format: see http://www.cplusplus.com/reference/ctime/strftime
45  wxString timezone_offset; // ISO 8601 offset from UTC in timezone
46  timezone_offset = date.Format( "%z" ); // Extract the time zone offset
47  // The time zone offset format is +mm or +hhmm (or -mm or -hhmm)
48  // (mm = number of minutes, hh = number of hours. 1h00mn is returned as +0100)
49  // we want +(or -) hh:mm
50  if( timezone_offset.Len() > 3 ) // format +hhmm or -hhmm found
51  // Add separator between hours and minutes
52  timezone_offset.insert( 3, ":", 1 );
53 
54  wxString msg;
55 
56  switch( aFormat )
57  {
59  msg.Printf( "%%TF.CreationDate,%s%s*%%", date.FormatISOCombined(), timezone_offset );
60  break;
61 
63  msg.Printf( "G04 #@! TF.CreationDate,%s%s*", date.FormatISOCombined(), timezone_offset );
64  break;
65 
67  msg.Printf( "%s%s", date.FormatISOCombined(), timezone_offset );
68  break;
69 
71  msg.Printf( "; #@! TF.CreationDate,%s%s", date.FormatISOCombined(), timezone_offset );
72  break;
73  }
74  return msg;
75 }

References GBR_NC_STRING_FORMAT_GBRJOB, GBR_NC_STRING_FORMAT_NCDRILL, GBR_NC_STRING_FORMAT_X1, and GBR_NC_STRING_FORMAT_X2.

Referenced by AddGerberX2Header(), GERBER_JOBFILE_WRITER::addJSONHeader(), and EXCELLON_WRITER::writeEXCELLONHeader().

◆ GbrMakeProjectGUIDfromString()

wxString GbrMakeProjectGUIDfromString ( const wxString &  aText)

Build a project GUID using format RFC4122 Version 1 or 4 from the project name, because a KiCad project has no specific GUID.

RFC4122 is used mainly for its syntax, because fields have no meaning for Gerber files and therefore the GUID generated has no meaning because it do not use any time and time stamp specific to the project, just a random pattern (random is here a pattern specific to a project).

See en.wikipedia.org/wiki/Universally_unique_identifier

Definition at line 78 of file gbr_metadata.cpp.

79 {
80  /* Gerber GUID format should be RFC4122 Version 1 or 4.
81  * See en.wikipedia.org/wiki/Universally_unique_identifier
82  * The format is:
83  * xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
84  * with
85  * x = hexDigit lower/upper case
86  * and
87  * M = '1' or '4' (UUID version: 1 (basic) or 4 (random)) (we use 4: UUID random)
88  * and
89  * N = '8' or '9' or 'A|a' or 'B|b' : UUID variant 1: 2 MSB bits have meaning) (we use N = 9)
90  * N = 1000 or 1001 or 1010 or 1011 : 10xx means Variant 1 (Variant2: 110x and 111x are reserved)
91  */
92 
93  wxString guid;
94 
95  // Build a 32 digits GUID from the board name:
96  // guid has 32 digits, so add chars in name to be sure we can build a 32 digits guid
97  // (i.e. from a 16 char string name)
98  // In fact only 30 digits are used, and 2 UID id
99  wxString bname = aText;
100  int cnt = 16 - bname.Len();
101 
102  if( cnt > 0 )
103  bname.Append( 'X', cnt );
104 
105  int chr_idx = 0;
106 
107  // Output the 8 first hex digits:
108  for( unsigned ii = 0; ii < 4; ii++ )
109  {
110  int cc = int( bname[chr_idx++] ) & 0xFF;
111  guid << wxString::Format( "%2.2x", cc );
112  }
113 
114  // Output the 4 next hex digits:
115  guid << '-';
116 
117  for( unsigned ii = 0; ii < 2; ii++ )
118  {
119  int cc = int( bname[chr_idx++] ) & 0xFF;
120  guid << wxString::Format( "%2.2x", cc );
121  }
122 
123  // Output the 4 next hex digits (UUID version and 3 digits):
124  guid << "-4"; // first digit: UUID version 4 (M = 4)
125  {
126  int cc = int( bname[chr_idx++] ) << 4 & 0xFF0;
127  cc += int( bname[chr_idx] ) >> 4 & 0x0F;
128  guid << wxString::Format( "%3.3x", cc );
129  }
130 
131  // Output the 4 next hex digits (UUID variant and 3 digits):
132  guid << "-9"; // first digit: UUID variant 1 (N = 9)
133  {
134  int cc = (int( bname[chr_idx++] ) & 0x0F) << 8;
135  cc += int( bname[chr_idx++] ) & 0xFF;
136  guid << wxString::Format( "%3.3x", cc );
137  }
138 
139  // Output the 12 last hex digits:
140  guid << '-';
141 
142  for( unsigned ii = 0; ii < 6; ii++ )
143  {
144  int cc = int( bname[chr_idx++] ) & 0xFF;
145  guid << wxString::Format( "%2.2x", cc );
146  }
147 
148  return guid;
149 }
void Format(OUTPUTFORMATTER *out, int aNestLevel, int aCtl, const CPTREE &aTree)
Output a PTREE into s-expression format via an OUTPUTFORMATTER derivative.
Definition: ptree.cpp:200

References Format().

Referenced by AddGerberX2Header(), and GERBER_JOBFILE_WRITER::addJSONGeneralSpecs().