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 <fctsys.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 (wxString &aText)
 A helper function to 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). More...
 
int char2Hex (unsigned aCode)
 
wxString FormatStringFromGerber (const wxString &aString)
 This helper function make the inverse conversion of FormatStringToGerber() It converts a "normalized" gerber string and convert it to a 16 bits sequence unicode. More...
 
wxString ConvertNotAllowedCharsInGerber (const wxString &aString, bool aAllowUtf8Chars, bool aQuoteString)
 Similar to FormatStringToGerber. More...
 
std::string FormatStringToGerber (const wxString &aString)
 This helper function "normalize" aString and convert it to a Gerber std::string Normalisation means convert any code > 0x7F and unautorized code to a hexadecimal 16 bits sequence unicode unautorized codes are ',' '*' '' '\'. More...
 
bool FormatNetAttribute (std::string &aPrintedText, std::string &aLastNetAttributes, GBR_NETLIST_METADATA *aData, bool &aClearPreviousAttributes, bool aUseX1StructuredComment)
 Generates the string to print to a gerber file, to set a net attribute for a graphic object. 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 523 of file gbr_metadata.cpp.

◆ NO_PAD_NAME

#define NO_PAD_NAME   wxT( "" )

Definition at line 524 of file gbr_metadata.cpp.

Function Documentation

◆ char2Hex()

int char2Hex ( unsigned  aCode)

Definition at line 346 of file gbr_metadata.cpp.

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

Referenced by FormatStringFromGerber().

◆ ConvertNotAllowedCharsInGerber()

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

Similar to FormatStringToGerber.

"normalize" aString and convert it to a Gerber compatible wxString Normalisation means unautorized code to a hexadecimal 16 bits sequence unicode and, on request convert any code > 0x7F. unautorized codes are ',' '*' '' '\'

Parameters
aString= the wxString to convert
aAllowUtf8Chars= false to convert non ASCII7 values to unicode sequence
aQuoteString= true to double quote the returned string
Returns
a wxString without unautorized chars (and converted non ASCII7 chars on request)

Definition at line 425 of file gbr_metadata.cpp.

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

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

◆ FormatNetAttribute()

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

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

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 does not exist no more).
aUseX1StructuredComment= false in X2 mode, and true in X1 mode to add the net attribut 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 526 of file gbr_metadata.cpp.

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

This helper function make the inverse conversion of FormatStringToGerber() It converts a "normalized" gerber string and convert it to a 16 bits sequence unicode.

Parameters
aString= the wxString compliant with a gerber string format
Returns
a wxString (unicode 16) from the gerber string

Definition at line 361 of file gbr_metadata.cpp.

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

References char2Hex().

Referenced by GERBER_FILE_IMAGE::ExecuteRS274XCommand().

◆ FormatStringToGerber()

std::string FormatStringToGerber ( const wxString &  aString)

This helper function "normalize" aString and convert it to a Gerber std::string Normalisation means convert any code > 0x7F and unautorized code to a hexadecimal 16 bits sequence unicode unautorized codes are ',' '*' '' '\'.

Parameters
aString= the wxString to convert
Returns
a std::string (ASCII7 coded) compliant with a gerber string

Definition at line 499 of file gbr_metadata.cpp.

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

References ConvertNotAllowedCharsInGerber().

Referenced by FormatNetAttribute().

◆ GbrMakeCreationDateAttributeString()

wxString GbrMakeCreationDateAttributeString ( GBR_NC_STRING_FORMAT  aFormat)

Definition at line 35 of file gbr_metadata.cpp.

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

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 ( wxString &  aText)

A helper function to 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 77 of file gbr_metadata.cpp.

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

References Format().

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