diff --git a/gerbview/CMakeLists.txt b/gerbview/CMakeLists.txt
index 953471f3c1..5f737f85c3 100644
--- a/gerbview/CMakeLists.txt
+++ b/gerbview/CMakeLists.txt
@@ -40,6 +40,7 @@ set( GERBVIEW_SRCS
     class_gerber_draw_item.cpp
     class_gerbview_layer_widget.cpp
     class_gbr_layer_box_selector.cpp
+    class_X2_gerber_attributes.cpp
     controle.cpp
     dcode.cpp
     draw_gerber_screen.cpp
diff --git a/gerbview/class_GERBER.cpp b/gerbview/class_GERBER.cpp
index eeb10ff0e8..1c79c6f684 100644
--- a/gerbview/class_GERBER.cpp
+++ b/gerbview/class_GERBER.cpp
@@ -36,6 +36,9 @@
 #include <gerbview.h>
 #include <gerbview_frame.h>
 #include <class_GERBER.h>
+#include <class_X2_gerber_attributes.h>
+
+#include <algorithm>
 
 
 /**
@@ -88,9 +91,10 @@ void GERBER_LAYER::ResetDefaultValues()
 GERBER_IMAGE::GERBER_IMAGE( GERBVIEW_FRAME* aParent, int aLayer )
 {
     m_Parent = aParent;
-    m_GraphicLayer = aLayer;  // Graphic layer Number
+    m_GraphicLayer = aLayer;        // Graphic layer Number
 
     m_Selected_Tool = FIRST_DCODE;
+    m_FileFunction = NULL;          // file function parameters
 
     ResetDefaultValues();
 
@@ -104,9 +108,9 @@ GERBER_IMAGE::~GERBER_IMAGE()
     for( unsigned ii = 0; ii < DIM( m_Aperture_List ); ii++ )
     {
         delete m_Aperture_List[ii];
-
-        // m_Aperture_List[ii] = NULL;
     }
+
+    delete m_FileFunction;
 }
 
 /*
@@ -158,6 +162,11 @@ void GERBER_IMAGE::ResetDefaultValues()
     m_FileName.Empty();
     m_ImageName     = wxT( "no name" );             // Image name from the IN command
     m_ImageNegative = false;                        // true = Negative image
+    m_IsX2_file     = false;                        // true only if a %TF, %TA or %TD command
+    delete m_FileFunction;                          // file function parameters
+    m_FileFunction = NULL;
+    m_MD5_value.Empty();                            // MD5 value found in a %TF.MD5 command
+    m_PartString.Empty();                           // string found in a %TF.Part command
     m_hasNegativeItems    = -1;                     // set to uninitialized
     m_ImageJustifyOffset  = wxPoint(0,0);           // Image justify Offset
     m_ImageJustifyXCenter = false;                  // Image Justify Center on X axis (default = false)
@@ -361,3 +370,171 @@ void GERBER_IMAGE::DisplayImageInfo( void )
     m_Parent->AppendMsgPanel( _( "Image Justify Offset" ), msg, DARKRED );
 }
 
+// GERBER_IMAGE_LIST is a helper class to handle a list of GERBER_IMAGE files
+GERBER_IMAGE_LIST::GERBER_IMAGE_LIST()
+{
+    m_GERBER_List.reserve( GERBER_DRAWLAYERS_COUNT );
+
+    for( unsigned layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer )
+        m_GERBER_List.push_back( NULL );
+}
+
+GERBER_IMAGE_LIST::~GERBER_IMAGE_LIST()
+{
+    ClearList();
+
+    for( unsigned layer = 0; layer < m_GERBER_List.size(); ++layer )
+    {
+        delete m_GERBER_List[layer];
+        m_GERBER_List[layer] = NULL;
+    }
+}
+
+GERBER_IMAGE* GERBER_IMAGE_LIST::GetGbrImage( int aIdx )
+{
+    if( (unsigned)aIdx < m_GERBER_List.size() )
+        return m_GERBER_List[aIdx];
+
+    return NULL;
+}
+
+/**
+ * creates a new, empty GERBER_IMAGE* at index aIdx
+ * or at the first free location if aIdx < 0
+ * @param aIdx = the location to use ( 0 ... GERBER_DRAWLAYERS_COUNT-1 )
+ * @return true if the index used, or -1 if no room to add image
+ */
+int GERBER_IMAGE_LIST::AddGbrImage( GERBER_IMAGE* aGbrImage, int aIdx )
+{
+    int idx = aIdx;
+
+    if( idx < 0 )
+    {
+        for( idx = 0; idx < (int)m_GERBER_List.size(); idx++ )
+        {
+            if( !IsUsed( idx ) )
+                break;
+        }
+    }
+
+    if( idx >= (int)m_GERBER_List.size() )
+        return -1;  // No room
+
+    m_GERBER_List[idx] = aGbrImage;
+
+    return idx;
+}
+
+
+// remove all loaded data in list, but do not delete empty images
+// (can be reused)
+void GERBER_IMAGE_LIST::ClearList()
+{
+    for( unsigned layer = 0; layer < m_GERBER_List.size(); ++layer )
+        ClearImage( layer );
+}
+
+// remove the loaded data of image aIdx, but do not delete it
+void GERBER_IMAGE_LIST::ClearImage( int aIdx )
+{
+    if( aIdx >= 0 && aIdx < (int)m_GERBER_List.size() && m_GERBER_List[aIdx] )
+    {
+        m_GERBER_List[aIdx]->InitToolTable();
+        m_GERBER_List[aIdx]->ResetDefaultValues();
+        m_GERBER_List[aIdx]->m_InUse = false;
+    }
+}
+
+// Build a name for image aIdx which can be used in layers manager
+const wxString GERBER_IMAGE_LIST::GetDisplayName( int aIdx )
+{
+    wxString name;
+
+    GERBER_IMAGE* gerber = NULL;
+
+    if( aIdx >= 0 && aIdx < (int)m_GERBER_List.size() )
+        gerber = m_GERBER_List[aIdx];
+
+    if( gerber && gerber->m_InUse)
+    {
+        if( gerber->m_FileFunction )
+            name.Printf( _( "Layer %d (%s, %s)" ), aIdx + 1,
+                         GetChars( gerber->m_FileFunction->GetFileType() ),
+                         GetChars( gerber->m_FileFunction->GetBrdLayerId() ) );
+        else
+            name.Printf( _( "Layer %d *" ), aIdx + 1 );
+    }
+    else
+        name.Printf( _( "Layer %d" ), aIdx + 1 );
+
+    return name;
+}
+
+// return true if image is used (loaded and not cleared)
+bool GERBER_IMAGE_LIST::IsUsed( int aIdx )
+{
+    if( aIdx >= 0 && aIdx < (int)m_GERBER_List.size() )
+        return m_GERBER_List[aIdx] != NULL && m_GERBER_List[aIdx]->m_InUse;
+
+    return false;
+}
+
+// Helper function, for std::sort.
+// Sort loaded images by Z order priority, if they have the X2 FileFormat info
+// returns true if the first argument (ref) is ordered before the second (test).
+static bool sortZorder( const GERBER_IMAGE* const& ref, const GERBER_IMAGE* const& test )
+{
+    if( !ref && !test )
+        return false;        // do not change order: no criteria to sort items
+
+    if( !ref || !ref->m_InUse )
+        return false;       // Not used: ref ordered after
+
+    if( !test || !test->m_InUse )
+        return true;        // Not used: ref ordered before
+
+    if( !ref->m_FileFunction && !test->m_FileFunction )
+        return false;        // do not change order: no criteria to sort items
+
+    if( !ref->m_FileFunction )
+        return false;
+
+    if( !test->m_FileFunction )
+        return true;
+
+    if( ref->m_FileFunction->GetZOrder() != test->m_FileFunction->GetZOrder() )
+        return ref->m_FileFunction->GetZOrder() > test->m_FileFunction->GetZOrder();
+
+    return ref->m_FileFunction->GetZSubOrder() > test->m_FileFunction->GetZSubOrder();
+}
+
+void GERBER_IMAGE_LIST::SortImagesByZOrder( GERBER_DRAW_ITEM* aDrawList )
+{
+    std::sort( m_GERBER_List.begin(), m_GERBER_List.end(), sortZorder );
+
+    // The image order has changed.
+    // Graphic layer numbering must be updated to match the widgets layer order
+
+    // Store the old/new graphic layer info:
+    std::map <int, int> tab_lyr;
+
+    for( unsigned layer = 0; layer < m_GERBER_List.size(); ++layer )
+    {
+        if( m_GERBER_List[layer] )
+        {
+            tab_lyr[m_GERBER_List[layer]->m_GraphicLayer] = layer;
+            m_GERBER_List[layer]->m_GraphicLayer = layer ;
+        }
+    }
+
+    // update the graphic layer in items to draw
+    for( GERBER_DRAW_ITEM* item = aDrawList; item; item = item->Next() )
+    {
+        int layer = item->GetLayer();
+        item->SetLayer( tab_lyr[layer] );
+    }
+}
+
+
+// The global image list:
+GERBER_IMAGE_LIST g_GERBER_List;
diff --git a/gerbview/class_GERBER.h b/gerbview/class_GERBER.h
index 1bec046cdb..1f72c1c488 100644
--- a/gerbview/class_GERBER.h
+++ b/gerbview/class_GERBER.h
@@ -61,6 +61,7 @@ class D_CODE;
  */
 
 class GERBER_IMAGE;
+class X2_ATTRIBUTE_FILEFUNCTION;
 
 class GERBER_LAYER
 {
@@ -104,6 +105,11 @@ public:
                                                                 // (a file is loaded in it)
     wxString           m_FileName;                              // Full File Name for this layer
     wxString           m_ImageName;                             // Image name, from IN <name>* command
+    bool               m_IsX2_file;                             // true if a X2 gerber attribute was found in file
+    X2_ATTRIBUTE_FILEFUNCTION* m_FileFunction;                  // file function parameters, found in a %TF command
+                                                                // or a G04
+    wxString           m_MD5_value;                             // MD5 value found in a %TF.MD5 command
+    wxString           m_PartString;                            // string found in a %TF.Part command
     int                m_GraphicLayer;                          // Graphic layer Number
     bool               m_ImageNegative;                         // true = Negative image
     bool               m_ImageJustifyXCenter;                   // Image Justify Center on X axis (default = false)
@@ -306,5 +312,67 @@ public:
     void DisplayImageInfo( void );
 };
 
+/**
+ * @brief GERBER_IMAGE_LIST is a helper class to handle a list of GERBER_IMAGE files
+ * which are loaded and can be displayed
+ * there are 32 images max which can be loaded
+ */
+class GERBER_IMAGE_LIST
+{
+    // the list of loaded images (1 image = 1 gerber file)
+    std::vector<GERBER_IMAGE*> m_GERBER_List;
+
+public:
+    GERBER_IMAGE_LIST();
+    ~GERBER_IMAGE_LIST();
+
+    //Accessor
+    GERBER_IMAGE* GetGbrImage( int aIdx );
+
+    /**
+     * Add a GERBER_IMAGE* at index aIdx
+     * or at the first free location if aIdx < 0
+     * @param aGbrImage = the image to add
+     * @param aIdx = the location to use ( 0 ... GERBER_DRAWLAYERS_COUNT-1 )
+     * @return true if the index used, or -1 if no room to add image
+     */
+    int AddGbrImage( GERBER_IMAGE* aGbrImage, int aIdx );
+
+
+    /**
+     * remove all loaded data in list
+     */
+    void ClearList();
+
+    /**
+     * remove the loaded data of image aIdx
+     * @param aIdx = the index ( 0 ... GERBER_DRAWLAYERS_COUNT-1 )
+     */
+    void ClearImage( int aIdx );
+
+    /**
+     * @return a name for image aIdx which can be used in layers manager
+     * and layer selector
+     * is is "Layer n" (n = aIdx+1), followed by file attribute info (if X2 format)
+     * @param aIdx = the index ( 0 ... GERBER_DRAWLAYERS_COUNT-1 )
+     */
+    const wxString GetDisplayName( int aIdx );
+
+    /**
+     * @return true if image is used (loaded and with items)
+     * @param aIdx = the index ( 0 ... GERBER_DRAWLAYERS_COUNT-1 )
+     */
+    bool IsUsed( int aIdx );
+
+    /**
+     * Sort loaded images by Z order priority, if they have the X2 FileFormat info
+     * @param aDrawList: the draw list associated to the gerber images
+     * (SortImagesByZOrder updates the graphic layer of these items)
+     */
+    void SortImagesByZOrder( GERBER_DRAW_ITEM* aDrawList );
+};
+
+
+extern GERBER_IMAGE_LIST g_GERBER_List;
 
 #endif  // ifndef _CLASS_GERBER_H_
diff --git a/gerbview/class_X2_gerber_attributes.cpp b/gerbview/class_X2_gerber_attributes.cpp
new file mode 100644
index 0000000000..beca5cdf23
--- /dev/null
+++ b/gerbview/class_X2_gerber_attributes.cpp
@@ -0,0 +1,253 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2010-2014 Jean-Pierre Charras  jp.charras at wanadoo.fr
+ * Copyright (C) 1992-2014 KiCad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+/**
+ * @file class_X2_gerber_attributes.cpp
+ */
+
+/*
+ * Manage the gerber extensions (attributes) in the new X2 version
+ * only few extensions are handled
+ * See http://www.ucamco.com/files/downloads/file/81/the_gerber_file_format_specification.pdf
+ *
+ * gerber attributes in the new X2 version look like:
+ * %TF.FileFunction,Copper,L1,Top*%
+ *
+ * Currently:
+ *  .FileFunction .FileFunction Identifies the file�s function in the PCB.
+ * Other Standard Attributes, not yet used in Gerbview:
+ *  .Part Identifies the part the file represents, e.g. a single PCB
+ *  .MD5 Sets the MD5 file signature or checksum.
+ */
+
+#include <wx/log.h>
+#include <class_X2_gerber_attributes.h>
+
+/*
+ * class X2_ATTRIBUTE
+ * The attribute value consists of a number of substrings separated by a �,�
+*/
+
+X2_ATTRIBUTE::X2_ATTRIBUTE()
+{
+}
+
+X2_ATTRIBUTE::~X2_ATTRIBUTE()
+{
+}
+
+/* return the attribute name (for instance .FileFunction)
+ * which is given by TF command.
+ */
+const wxString& X2_ATTRIBUTE::GetAttribute()
+{
+    return m_Prms.Item( 0 );
+}
+
+/* return a parameter
+ * aIdx = the index of the parameter
+ * aIdx = 0 is the parameter read after the TF function
+ * (the same as GetAttribute())
+ */
+const wxString& X2_ATTRIBUTE::GetPrm( int aIdx)
+{
+    static const wxString dummy;
+
+    if( GetPrmCount() < aIdx && aIdx >= 0 )
+        return m_Prms.Item( aIdx );
+
+    return dummy;
+}
+
+// Debug function: pring using wxLogMessage le list of parameters
+void X2_ATTRIBUTE::DbgListPrms()
+{
+    wxLogMessage( wxT("prms count %d"), GetPrmCount() );
+
+    for( int ii = 0; ii < GetPrmCount(); ii++ )
+        wxLogMessage( m_Prms.Item( ii ) );
+}
+
+/*
+ * parse a TF command and fill m_Prms by the parameters found.
+ * aFile = a FILE* ptr to the current Gerber file.
+ * buff = the buffer containing current Gerber data (GERBER_BUFZ size)
+ * text = a pointer to the first char to read in Gerber data
+ */
+bool X2_ATTRIBUTE::ParseAttribCmd( FILE* aFile, char *aBuffer, int aBuffSize, char*& aText )
+{
+    bool ok = true;
+    wxString data;
+
+    for( ; ; )
+    {
+        while( *aText )
+        {
+            switch( *aText )
+            {
+            case '%':       // end of command
+                return ok;  // success completion
+
+            case ' ':
+            case '\r':
+            case '\n':
+                aText++;
+                break;
+
+            case '*':       // End of block
+                m_Prms.Add( data );
+                data.Empty();
+                aText++;
+                break;
+
+            case ',':       // End of parameter
+                aText++;
+                m_Prms.Add( data );
+                data.Empty();
+                break;
+
+            default:
+                data.Append( *aText );
+                aText++;
+                break;
+            }
+        }
+
+        // end of current line, read another one.
+        if( aBuffer )
+        {
+            if( fgets( aBuffer, aBuffSize, aFile ) == NULL )
+            {
+                // end of file
+                ok = false;
+                break;
+            }
+
+            aText = aBuffer;
+        }
+        else
+            return ok;
+    }
+
+    return ok;
+}
+
+/*
+ * class X2_ATTRIBUTE_FILEFUNCTION ( from %TF.FileFunction in Gerber file)
+ *  Example file function:
+ *  %TF.FileFunction,Copper,L1,Top*%
+ * - Type. Such as copper, solder mask etc.
+ * - Position. Specifies where the file appears in the PCB layer structure.
+ *      Corresponding position substring:
+ *      Copper layer:   L1, L2, L3...to indicate the layer position followed by Top, Inr or
+ *                      Bot. L1 is always the top copper layer. E.g. L2,Inr.
+ *      Extra layer, e.g. solder mask: Top or Bot � defines the attachment of the layer.
+ *      Drill/rout layer: E.g. 1,4 � where 1 is the start and 4 is the end copper layer. The
+ *                        pair 1,4 defines the span of the drill/rout file
+ * Optional index. This can be used in instances where for example there are two solder
+ *                 masks on the same side. The index counts from the PCB surface outwards.
+ */
+X2_ATTRIBUTE_FILEFUNCTION::X2_ATTRIBUTE_FILEFUNCTION( X2_ATTRIBUTE& aAttributeBase )
+    : X2_ATTRIBUTE()
+{
+    m_Prms = aAttributeBase.GetPrms();
+    m_z_order = 0;
+
+    //ensure at least 5 parameters
+    while( GetPrmCount() < 5 )
+        m_Prms.Add( wxEmptyString );
+
+    set_Z_Order();
+}
+
+const wxString& X2_ATTRIBUTE_FILEFUNCTION::GetFileType()
+{
+    // the type of layer (Copper ,  Soldermask ... )
+    return m_Prms.Item( 1 );
+}
+
+const wxString& X2_ATTRIBUTE_FILEFUNCTION::GetBrdLayerId()
+{
+    // the brd layer identifier: Top, Bot, Ln
+    return m_Prms.Item( 2 );
+}
+
+
+const wxString& X2_ATTRIBUTE_FILEFUNCTION::GetLabel()
+{
+    // the filefunction label, if any
+    return m_Prms.Item( 3 );
+}
+
+
+// Initialize the z order priority of the current file, from its attributes
+// this priority is the order of layers from top to bottom to draw/display gerber images
+// Stack up is(  from external copper layer to external)
+// copper, then solder paste, then solder mask, then silk screen.
+// and global stackup is Front (top) layers then internal copper layers then Back (bottom) layers
+void X2_ATTRIBUTE_FILEFUNCTION::set_Z_Order()
+{
+    m_z_order = -100;     // low level
+    m_z_sub_order = 0;
+
+    if( GetFileType().IsSameAs( wxT( "Copper" ), false ) )
+    {
+        // Copper layer: the priority is the layer Id
+        m_z_order = 0;
+        wxString num = GetBrdLayerId().Mid( 1 );
+        long lnum;
+        if( num.ToLong( &lnum ) )
+            m_z_sub_order = -lnum;
+    }
+
+    if( GetFileType().IsSameAs( wxT( "Paste" ), false ) )
+    {
+        // solder paste layer: the priority is top then bottom
+        m_z_order = 1;       // for top
+
+        if( GetBrdLayerId().IsSameAs( wxT( "Bot" ), false ) )
+            m_z_order = -m_z_order;
+    }
+
+    if( GetFileType().IsSameAs( wxT( "Soldermask" ), false ) )
+    {
+        // solder mask layer: the priority is top then bottom
+        m_z_order = 2;       // for top
+
+        if( GetBrdLayerId().IsSameAs( wxT( "Bot" ), false ) )
+            m_z_order = -m_z_order;
+    }
+
+    if( GetFileType().IsSameAs( wxT( "Legend" ), false ) )
+    {
+        // Silk screen layer: the priority is top then bottom
+        m_z_order = 3;       // for top
+
+        if( GetFileType().IsSameAs( wxT( "Legend" ), false ) )
+
+        if( GetBrdLayerId().IsSameAs( wxT( "Bot" ), false ) )
+            m_z_order = -m_z_order;
+    }
+}
+
diff --git a/gerbview/class_X2_gerber_attributes.h b/gerbview/class_X2_gerber_attributes.h
new file mode 100644
index 0000000000..7b3250f971
--- /dev/null
+++ b/gerbview/class_X2_gerber_attributes.h
@@ -0,0 +1,171 @@
+/*
+ * This program source code file is part of KiCad, a free EDA CAD application.
+ *
+ * Copyright (C) 2010-2014 Jean-Pierre Charras  jp.charras at wanadoo.fr
+ * Copyright (C) 1992-2014 KiCad Developers, see change_log.txt for contributors.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, you may find one here:
+ * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
+ * or you may search the http://www.gnu.org website for the version 2 license,
+ * or you may write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA
+ */
+
+/**
+ * @file class_X2_gerber_attributes.h
+ */
+
+#ifndef _CLASS_X2_GERBER_ATTRIBUTE_H_
+#define _CLASS_X2_GERBER_ATTRIBUTE_H_
+
+/*
+ * Manage the gerber extensions (attributes) in the new X2 version
+ * only few extensions are handled
+ * See http://www.ucamco.com/files/downloads/file/81/the_gerber_file_format_specification.pdf
+ *
+ * gerber attributes in the new X2 version look like:
+ * %TF.FileFunction,Copper,L1,Top*%
+ *
+ * Currently:
+ *  .FileFunction .FileFunction Identifies the file�s function in the PCB.
+ * Other Standard Attributes, not yet used in Gerbview:
+ *  .Part Identifies the part the file represents, e.g. a single PCB
+ *  .MD5 Sets the MD5 file signature or checksum.
+ */
+
+#include <wx/arrstr.h>
+
+/**
+ * class X2_ATTRIBUTE
+ * The attribute value consists of a number of substrings separated by a �,�
+*/
+
+class X2_ATTRIBUTE
+{
+protected:
+    wxArrayString m_Prms;   ///< the list of parameters (after TF) in gbr file
+                            ///< the first one is the attribute name,
+                            ///< if starting by '.'
+
+public:
+    X2_ATTRIBUTE();
+    ~X2_ATTRIBUTE();
+
+    /**
+     * @return the parameters list read in TF command.
+     */
+    wxArrayString& GetPrms() { return m_Prms; }
+
+    /**
+     * @return a parameter read in TF command.
+     * @param aIdx = the index of the parameter
+     * aIdx = 0 is the parameter read after the TF function
+     * (the same as GetAttribute())
+     */
+    const wxString& GetPrm( int aIdx );
+
+    /**
+     * @return the attribute name (for instance .FileFunction)
+     * which is given by TF command (i.e. the first parameter read).
+     */
+    const wxString& GetAttribute();
+
+    /**
+     * @return the number of parameters read in TF command.
+     */
+    int GetPrmCount() { return int( m_Prms.GetCount() ); }
+
+    /**
+     * parse a TF command terminated with a % and fill m_Prms
+     * by the parameters found.
+     * @param aFile = a FILE* ptr to the current Gerber file.
+     * @param aBuffer = the buffer containing current Gerber data (can be null)
+     * @param aBuffSize = the size of the buffer
+     * @param aText = a pointer to the first char to read from Gerber data stored in aBuffer
+     *  After parsing, text points the last char of the command line ('%') (X2 mode)
+     *  or the end of line if the line does not contain '%' or aBuffer == NULL (X1 mode)
+     * @return true if no error.
+     */
+    bool ParseAttribCmd( FILE* aFile, char *aBuffer, int aBuffSize, char*& aText );
+
+    /**
+     * Debug function: pring using wxLogMessage le list of parameters
+     */
+    void DbgListPrms();
+
+    /**
+     * return true if the attribute is .FileFunction
+     */
+    bool IsFileFunction()
+    {
+        return GetAttribute().IsSameAs( wxT(".FileFunction"), false );
+    }
+
+    /**
+     * return true if the attribute is .MD5
+     */
+    bool IsFileMD5()
+    {
+        return GetAttribute().IsSameAs( wxT(".MD5"), false );
+    }
+
+    /**
+     * return true if the attribute is .Part
+     */
+    bool IsFilePart()
+    {
+        return GetAttribute().IsSameAs( wxT(".Part"), false );
+    }
+};
+
+/**
+ * class X2_ATTRIBUTE_FILEFUNCTION ( from %TF.FileFunction in Gerber file)
+ *  Example file function:
+ *  %TF.FileFunction,Copper,L1,Top*%
+ * - Type. Such as copper, solder mask etc.
+ * - Position. Specifies where the file appears in the PCB layer structure.
+ *      Corresponding position substring:
+ *      Copper layer:   L1, L2, L3...to indicate the layer position followed by Top, Inr or
+ *                      Bot. L1 is always the top copper layer. E.g. L2,Inr.
+ *      Extra layer, e.g. solder mask: Top or Bot � defines the attachment of the layer.
+ *      Drill/rout layer: E.g. 1,4 � where 1 is the start and 4 is the end copper layer. The
+ *                        pair 1,4 defines the span of the drill/rout file
+ * Optional index. This can be used in instances where for example there are two solder
+ *                 masks on the same side. The index counts from the PCB surface outwards.
+ */
+
+class X2_ATTRIBUTE_FILEFUNCTION : public X2_ATTRIBUTE
+{
+    int m_z_order;              // the z order of the layer for a board
+    int m_z_sub_order;          // the z sub_order of the copper layer for a board
+
+public:
+    X2_ATTRIBUTE_FILEFUNCTION( X2_ATTRIBUTE& aAttributeBase );
+
+    const wxString& GetFileType();    ///< the type of layer (Copper ,  Soldermask ... )
+    const wxString& GetBrdLayerId();  ///< the brd layer identifier: Top, Bot, Ln
+    const wxString& GetLabel();       ///< the filefunction label, if any
+
+    int GetZOrder() { return m_z_order; }   ///< the Order of the bdr layer, from front (Top side) to back side
+    int GetZSubOrder() { return m_z_sub_order; }   ///< the Order of the bdr copper layer, from front (Top side) to back side
+
+private:
+
+    /**
+     * Initialize the z order priority of the current file, from its attributes
+     */
+    void set_Z_Order();
+};
+
+#endif      // _CLASS_X2_GERBER_ATTRIBUTE_H_
diff --git a/gerbview/class_gbr_layer_box_selector.cpp b/gerbview/class_gbr_layer_box_selector.cpp
index 2410bf078c..f148306c77 100644
--- a/gerbview/class_gbr_layer_box_selector.cpp
+++ b/gerbview/class_gbr_layer_box_selector.cpp
@@ -33,11 +33,14 @@
 #include <colors_selection.h>
 #include <layers_id_colors_and_visibility.h>
 #include <gerbview_frame.h>
+#include <class_GERBER.h>
+#include <class_X2_gerber_attributes.h>
 
 #include <class_gbr_layer_box_selector.h>
 
 void GBR_LAYER_BOX_SELECTOR::Resync()
 {
+    Freeze();
     Clear();
 
     for( int layerid = 0; layerid < GERBER_DRAWLAYERS_COUNT; ++layerid )
@@ -55,6 +58,8 @@ void GBR_LAYER_BOX_SELECTOR::Resync()
 
         Append( layername, layerbmp, (void*)(intptr_t) layerid );
     }
+
+    Thaw();
 }
 
 
@@ -70,7 +75,7 @@ EDA_COLOR_T GBR_LAYER_BOX_SELECTOR::GetLayerColor( int aLayer ) const
 // Returns the name of the layer id
 wxString GBR_LAYER_BOX_SELECTOR::GetLayerName( int aLayer ) const
 {
-    wxString name;
-    name.Printf( _( "Layer %d" ), aLayer + 1 );
+    wxString name = g_GERBER_List.GetDisplayName( aLayer );
+
     return name;
 }
diff --git a/gerbview/class_gbr_layout.cpp b/gerbview/class_gbr_layout.cpp
index d369b50665..19849cd6ac 100644
--- a/gerbview/class_gbr_layout.cpp
+++ b/gerbview/class_gbr_layout.cpp
@@ -39,7 +39,6 @@ GBR_LAYOUT::GBR_LAYOUT()
     PAGE_INFO pageInfo( wxT( "GERBER" ) );
     SetPageSettings( pageInfo );
 
-// no    m_printLayersMask = -1;
     m_printLayersMask.set();
 }
 
diff --git a/gerbview/class_gbr_layout.h b/gerbview/class_gbr_layout.h
index e457c80ad4..94c9b1e2f1 100644
--- a/gerbview/class_gbr_layout.h
+++ b/gerbview/class_gbr_layout.h
@@ -24,7 +24,8 @@
 
 /**
  * @file class_gbr_layout.h
- * @brief Class CLASS_GBR_LAYOUT to handle a board.
+ * @brief Class CLASS_GBR_LAYOUT to handle info to draw/print loaded Gerber images
+ * and page frame reference
  */
 
 #ifndef CLASS_GBR_LAYOUT_H
@@ -55,7 +56,7 @@ private:
     std::bitset <GERBER_DRAWLAYERS_COUNT> m_printLayersMask; // When printing: the list of layers to print
 public:
 
-    DLIST<GERBER_DRAW_ITEM> m_Drawings;     // linked list of Gerber Items
+    DLIST<GERBER_DRAW_ITEM> m_Drawings;     // linked list of Gerber Items to draw
 
     GBR_LAYOUT();
     ~GBR_LAYOUT();
diff --git a/gerbview/class_gerber_draw_item.cpp b/gerbview/class_gerber_draw_item.cpp
index 33318b6d43..02bf826dbb 100644
--- a/gerbview/class_gerber_draw_item.cpp
+++ b/gerbview/class_gerber_draw_item.cpp
@@ -225,7 +225,9 @@ D_CODE* GERBER_DRAW_ITEM::GetDcodeDescr()
 {
     if( (m_DCode < FIRST_DCODE) || (m_DCode > LAST_DCODE) )
         return NULL;
-    GERBER_IMAGE* gerber = g_GERBER_List[m_Layer];
+
+    GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( m_Layer );
+
     if( gerber == NULL )
         return NULL;
 
diff --git a/gerbview/class_gerbview_layer_widget.cpp b/gerbview/class_gerbview_layer_widget.cpp
index 3cccd72f37..94a2b1fb7a 100644
--- a/gerbview/class_gerbview_layer_widget.cpp
+++ b/gerbview/class_gerbview_layer_widget.cpp
@@ -41,6 +41,7 @@
 #include <class_GERBER.h>
 #include <layer_widget.h>
 #include <class_gerbview_layer_widget.h>
+#include <class_X2_gerber_attributes.h>
 
 
 /*
@@ -70,7 +71,7 @@ GERBER_LAYER_WIDGET::GERBER_LAYER_WIDGET( GERBVIEW_FRAME* aParent, wxWindow* aFo
 
     // since Popupmenu() calls this->ProcessEvent() we must call this->Connect()
     // and not m_LayerScrolledWindow->Connect()
-    Connect( ID_SHOW_ALL_LAYERS, ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE,
+    Connect( ID_LAYER_MANAGER_START, ID_LAYER_MANAGER_END,
         wxEVT_COMMAND_MENU_SELECTED,
         wxCommandEventHandler( GERBER_LAYER_WIDGET::onPopupSelection ), NULL, this );
 
@@ -146,8 +147,7 @@ void GERBER_LAYER_WIDGET::onRightDownLayers( wxMouseEvent& event )
 {
     wxMenu          menu;
 
-    // menu text is capitalized:
-    // http://library.gnome.org/devel/hig-book/2.20/design-text-labels.html.en#layout-capitalization
+    // Remember: menu text is capitalized (see our rules_for_capitalization_in_Kicad_UI.txt)
     menu.Append( new wxMenuItem( &menu, ID_SHOW_ALL_LAYERS,
                                  _("Show All Layers") ) );
 
@@ -160,6 +160,9 @@ void GERBER_LAYER_WIDGET::onRightDownLayers( wxMouseEvent& event )
     menu.Append( new wxMenuItem( &menu, ID_SHOW_NO_LAYERS,
                                  _( "Hide All Layers" ) ) );
 
+    menu.AppendSeparator();
+    menu.Append( new wxMenuItem( &menu, ID_SORT_GBR_LAYERS,
+                                 _( "Sort Layers if X2 Mode" ) ) );
     PopupMenu( &menu );
 
     passOnFocus();
@@ -204,6 +207,13 @@ void GERBER_LAYER_WIDGET::onPopupSelection( wxCommandEvent& event )
         myframe->SetVisibleLayers( visibleLayers );
         myframe->GetCanvas()->Refresh();
         break;
+
+    case ID_SORT_GBR_LAYERS:
+        g_GERBER_List.SortImagesByZOrder( myframe->GetItemsList() );
+        myframe->ReFillLayerWidget();
+        myframe->syncLayerBox();
+        myframe->GetCanvas()->Refresh();
+        break;
     }
 }
 
@@ -212,7 +222,7 @@ bool  GERBER_LAYER_WIDGET::OnLayerSelected()
     if( !m_alwaysShowActiveLayer )
         return false;
 
-    // postprocess after an active layer selection
+    // postprocess after active layer selection
     // ensure active layer visible
     wxCommandEvent event;
     event.SetId( ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE );
@@ -223,16 +233,20 @@ bool  GERBER_LAYER_WIDGET::OnLayerSelected()
 
 void GERBER_LAYER_WIDGET::ReFill()
 {
+    Freeze();
+
     ClearLayerRows();
 
     for( int layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer )
     {
-        wxString msg;
-        msg.Printf( _("Layer %d"), layer+1 );
+        wxString msg = g_GERBER_List.GetDisplayName( layer );
+
         AppendLayerRow( LAYER_WIDGET::ROW( msg, layer,
                         myframe->GetLayerColor( layer ), wxEmptyString, true ) );
     }
 
+    Thaw();
+
     installRightLayerClickHandler();
 }
 
@@ -298,17 +312,10 @@ void GERBER_LAYER_WIDGET::OnRenderEnable( int aId, bool isEnabled )
  */
 bool GERBER_LAYER_WIDGET::useAlternateBitmap(int aRow)
 {
-    bool inUse = false;
-    GERBER_IMAGE* gerber = g_GERBER_List[aRow];
-
-    if( gerber != NULL && gerber->m_InUse )
-        inUse = true;
-
-    return inUse;
+    return g_GERBER_List.IsUsed( aRow );
 }
 
-/**
- * Function UpdateLayerIcons
+/*
  * Update the layer manager icons (layers only)
  * Useful when loading a file or clearing a layer because they change
  */
@@ -322,7 +329,8 @@ void GERBER_LAYER_WIDGET::UpdateLayerIcons()
             continue;
 
         if( row == m_CurrentRow )
-            bm->SetBitmap( useAlternateBitmap(row) ? *m_RightArrowAlternateBitmap : *m_RightArrowBitmap );
+            bm->SetBitmap( useAlternateBitmap(row) ? *m_RightArrowAlternateBitmap :
+                           *m_RightArrowBitmap );
         else
             bm->SetBitmap( useAlternateBitmap(row) ? *m_BlankAlternateBitmap : *m_BlankBitmap );
     }
diff --git a/gerbview/class_gerbview_layer_widget.h b/gerbview/class_gerbview_layer_widget.h
index ebb4eb16b5..d7dfc78dc4 100644
--- a/gerbview/class_gerbview_layer_widget.h
+++ b/gerbview/class_gerbview_layer_widget.h
@@ -33,6 +33,18 @@
 
 #include <layer_widget.h>
 
+// popup menu ids. in layer manager
+enum LAYER_MANAGER
+{
+    ID_LAYER_MANAGER_START = wxID_HIGHEST+1,
+    ID_SHOW_ALL_LAYERS = ID_LAYER_MANAGER_START,
+    ID_SHOW_NO_LAYERS,
+    ID_SHOW_NO_LAYERS_BUT_ACTIVE,
+    ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE,
+    ID_SORT_GBR_LAYERS,
+    ID_LAYER_MANAGER_END = ID_SORT_GBR_LAYERS,
+};
+
 /**
  * Class GERBER_LAYER_WIDGET
  * is here to implement the abtract functions of LAYER_WIDGET so they
@@ -45,11 +57,6 @@ class GERBER_LAYER_WIDGET : public LAYER_WIDGET
     bool m_alwaysShowActiveLayer;   // If true: Only shows the current active layer
                                     // even if it is changed
 
-    // popup menu ids.
-#define ID_SHOW_ALL_LAYERS                      wxID_HIGHEST
-#define ID_SHOW_NO_LAYERS                       (wxID_HIGHEST+1)
-#define ID_SHOW_NO_LAYERS_BUT_ACTIVE            (wxID_HIGHEST+2)
-#define ID_ALWAYS_SHOW_NO_LAYERS_BUT_ACTIVE     (wxID_HIGHEST+3)
 
     /**
      * Function OnRightDownLayers
diff --git a/gerbview/dialogs/dialog_print_using_printer.cpp b/gerbview/dialogs/dialog_print_using_printer.cpp
index 2baa22cc3a..645bb51332 100644
--- a/gerbview/dialogs/dialog_print_using_printer.cpp
+++ b/gerbview/dialogs/dialog_print_using_printer.cpp
@@ -37,6 +37,7 @@
 
 #include <gerbview.h>
 #include <gerbview_frame.h>
+#include <class_GERBER.h>
 #include <pcbplot.h>
 
 static double s_ScaleList[] =
@@ -163,7 +164,7 @@ void DIALOG_PRINT_USING_PRINTER::InitValues( )
         msg << wxT( " " ) << ii + 1;
         m_BoxSelectLayer[ii] = new wxCheckBox( this, -1, msg );
 
-        if( g_GERBER_List[ii] == NULL )     // Nothing loaded on this draw layer
+        if( g_GERBER_List.GetGbrImage( ii ) == NULL )     // Nothing loaded on this draw layer
             m_BoxSelectLayer[ii]->Enable( false );
 
         if( ii < 16 )
diff --git a/gerbview/draw_gerber_screen.cpp b/gerbview/draw_gerber_screen.cpp
index 21aaba20f1..2fdc48d058 100644
--- a/gerbview/draw_gerber_screen.cpp
+++ b/gerbview/draw_gerber_screen.cpp
@@ -214,14 +214,16 @@ void GBR_LAYOUT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode,
 
     bool end = false;
 
-    for( int layer = 0; !end; ++layer )
+    // Draw layers from bottom to top, and active layer last
+    // in non transparent modes, the last layer drawn mask mask previously drawn layer
+    for( int layer = GERBER_DRAWLAYERS_COUNT-1; !end; --layer )
     {
         int active_layer = gerbFrame->getActiveLayer();
 
         if( layer == active_layer ) // active layer will be drawn after other layers
             continue;
 
-        if( layer == GERBER_DRAWLAYERS_COUNT )   // last loop: draw active layer
+        if( layer < 0 )   // last loop: draw active layer
         {
             end   = true;
             layer = active_layer;
@@ -230,7 +232,7 @@ void GBR_LAYOUT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode,
         if( !gerbFrame->IsLayerVisible( layer ) )
             continue;
 
-        GERBER_IMAGE* gerber = g_GERBER_List[layer];
+        GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer );
 
         if( gerber == NULL )    // Graphic layer not yet used
             continue;
diff --git a/gerbview/events_called_functions.cpp b/gerbview/events_called_functions.cpp
index c1d4db3fd8..96b5d3d577 100644
--- a/gerbview/events_called_functions.cpp
+++ b/gerbview/events_called_functions.cpp
@@ -234,7 +234,7 @@ void GERBVIEW_FRAME::Process_Special_Functions( wxCommandEvent& event )
 
 void GERBVIEW_FRAME::OnSelectActiveDCode( wxCommandEvent& event )
 {
-    GERBER_IMAGE* gerber_image = g_GERBER_List[getActiveLayer()];
+    GERBER_IMAGE* gerber_image = g_GERBER_List.GetGbrImage( getActiveLayer() );
 
     if( gerber_image )
     {
@@ -266,7 +266,7 @@ void GERBVIEW_FRAME::OnSelectActiveLayer( wxCommandEvent& event )
 void GERBVIEW_FRAME::OnShowGerberSourceFile( wxCommandEvent& event )
 {
     int     layer = getActiveLayer();
-    GERBER_IMAGE* gerber_layer = g_GERBER_List[layer];
+    GERBER_IMAGE* gerber_layer = g_GERBER_List.GetGbrImage( layer );
 
     if( gerber_layer )
     {
diff --git a/gerbview/excellon_read_drill_file.cpp b/gerbview/excellon_read_drill_file.cpp
index 540be36983..2114eca452 100644
--- a/gerbview/excellon_read_drill_file.cpp
+++ b/gerbview/excellon_read_drill_file.cpp
@@ -169,13 +169,20 @@ bool GERBVIEW_FRAME::Read_EXCELLON_File( const wxString& aFullFileName )
 {
     wxString msg;
     int layer = getActiveLayer();      // current layer used in GerbView
+    EXCELLON_IMAGE* drill_Layer = (EXCELLON_IMAGE*) g_GERBER_List.GetGbrImage( layer );
 
-    if( g_GERBER_List[layer] == NULL )
+    if( drill_Layer == NULL )
     {
-        g_GERBER_List[layer] = new EXCELLON_IMAGE( this, layer );
+        drill_Layer = new EXCELLON_IMAGE( this, layer );
+        layer = g_GERBER_List.AddGbrImage( drill_Layer, layer );
+    }
+
+    if( layer < 0 )
+    {
+        DisplayError( this, _( "No room to load file" ) );
+        return false;
     }
 
-    EXCELLON_IMAGE* drill_Layer = (EXCELLON_IMAGE*) g_GERBER_List[layer];
     ClearMessageList();
 
     /* Read the gerber file */
@@ -183,7 +190,7 @@ bool GERBVIEW_FRAME::Read_EXCELLON_File( const wxString& aFullFileName )
     if( file == NULL )
     {
         msg.Printf( _( "File %s not found" ), GetChars( aFullFileName ) );
-        DisplayError( this, msg, 10 );
+        DisplayError( this, msg );
         return false;
     }
 
diff --git a/gerbview/export_to_pcbnew.cpp b/gerbview/export_to_pcbnew.cpp
index 086aff955a..a2694b366e 100644
--- a/gerbview/export_to_pcbnew.cpp
+++ b/gerbview/export_to_pcbnew.cpp
@@ -39,6 +39,7 @@
 #include <gerbview.h>
 #include <gerbview_frame.h>
 #include <class_gerber_draw_item.h>
+#include <class_GERBER.h>
 #include <select_layers_to_pcb.h>
 #include <build_version.h>
 #include <wildcards_and_files_ext.h>
@@ -159,7 +160,7 @@ void GERBVIEW_FRAME::ExportDataInPcbnewFormat( wxCommandEvent& event )
     // Count the Gerber layers which are actually currently used
     for( LAYER_NUM ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii )
     {
-        if( g_GERBER_List[ii] != NULL )
+        if( g_GERBER_List.GetGbrImage( ii ) )
             layercount++;
     }
 
diff --git a/gerbview/files.cpp b/gerbview/files.cpp
index 5b5aaf7bb1..b35a61a021 100644
--- a/gerbview/files.cpp
+++ b/gerbview/files.cpp
@@ -84,6 +84,7 @@ void GERBVIEW_FRAME::Files_io( wxCommandEvent& event )
         Zoom_Automatique( false );
         m_canvas->Refresh();
         ClearMsgPanel();
+        ReFillLayerWidget();
         break;
 
     case ID_GERBVIEW_LOAD_DRILL_FILE:
@@ -200,6 +201,7 @@ bool GERBVIEW_FRAME::LoadGerberFiles( const wxString& aFullFileName )
     Zoom_Automatique( false );
 
     // Synchronize layers tools with actual active layer:
+    ReFillLayerWidget();
     setActiveLayer( getActiveLayer() );
     m_LayersManager->UpdateLayerIcons();
     syncLayerBox();
@@ -282,6 +284,7 @@ bool GERBVIEW_FRAME::LoadExcellonFiles( const wxString& aFullFileName )
     Zoom_Automatique( false );
 
     // Synchronize layers tools with actual active layer:
+    ReFillLayerWidget();
     setActiveLayer( getActiveLayer() );
     m_LayersManager->UpdateLayerIcons();
     syncLayerBox();
diff --git a/gerbview/gerbview.cpp b/gerbview/gerbview.cpp
index 34412da4b1..3a64d1ec3d 100644
--- a/gerbview/gerbview.cpp
+++ b/gerbview/gerbview.cpp
@@ -45,7 +45,6 @@
 
 // Colors for layers and items
 COLORS_DESIGN_SETTINGS g_ColorsSettings;
-int g_Default_GERBER_Format;
 
 
 const wxChar* g_GerberPageSizeList[] = {
@@ -60,9 +59,6 @@ const wxChar* g_GerberPageSizeList[] = {
 };
 
 
-GERBER_IMAGE*  g_GERBER_List[32];
-
-
 namespace GERBV {
 
 static struct IFACE : public KIFACE_I
diff --git a/gerbview/gerbview.h b/gerbview/gerbview.h
index b7a960b5e1..b4a3c0a3d7 100644
--- a/gerbview/gerbview.h
+++ b/gerbview/gerbview.h
@@ -109,6 +109,4 @@ enum Gerb_Analyse_Cmd
     ENTER_RS274X_CMD
 };
 
-extern GERBER_IMAGE* g_GERBER_List[GERBER_DRAWLAYERS_COUNT];
-
 #endif  // ifndef GERBVIEW_H
diff --git a/gerbview/gerbview_frame.cpp b/gerbview/gerbview_frame.cpp
index ad5ddaa8d0..7c83369140 100644
--- a/gerbview/gerbview_frame.cpp
+++ b/gerbview/gerbview_frame.cpp
@@ -348,7 +348,7 @@ int GERBVIEW_FRAME::getNextAvailableLayer( int aLayer ) const
 
     for( int i = 0; i < GERBER_DRAWLAYERS_COUNT; ++i )
     {
-        GERBER_IMAGE* gerber = g_GERBER_List[ layer ];
+        GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer );
 
         if( gerber == NULL || gerber->m_FileName.IsEmpty() )
             return layer;
@@ -378,9 +378,11 @@ void GERBVIEW_FRAME::syncLayerWidget()
  */
 void GERBVIEW_FRAME::syncLayerBox()
 {
+    m_SelLayerBox->Resync();
     m_SelLayerBox->SetSelection( getActiveLayer() );
+
     int             dcodeSelected = -1;
-    GERBER_IMAGE*   gerber = g_GERBER_List[getActiveLayer()];
+    GERBER_IMAGE*   gerber = g_GERBER_List.GetGbrImage( getActiveLayer() );
 
     if( gerber )
         dcodeSelected = gerber->m_Selected_Tool;
@@ -406,7 +408,7 @@ void GERBVIEW_FRAME::Liste_D_Codes()
 
     for( int layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer )
     {
-        GERBER_IMAGE* gerber = g_GERBER_List[layer];
+        GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer );
 
         if( gerber == NULL )
             continue;
@@ -474,7 +476,7 @@ void GERBVIEW_FRAME::Liste_D_Codes()
  */
 void GERBVIEW_FRAME::UpdateTitleAndInfo()
 {
-    GERBER_IMAGE*   gerber = g_GERBER_List[ getActiveLayer() ];
+    GERBER_IMAGE*   gerber = g_GERBER_List.GetGbrImage(  getActiveLayer() );
     wxString        text;
 
     // Display the gerber filename
@@ -491,6 +493,8 @@ void GERBVIEW_FRAME::UpdateTitleAndInfo()
 
     text = _( "File:" );
     text << wxT( " " ) << gerber->m_FileName;
+    if( gerber->m_IsX2_file )
+        text << wxT( " " ) << _( "(with X2 Attributes)" );
     SetTitle( text );
 
     gerber->DisplayImageInfo();
@@ -508,7 +512,13 @@ void GERBVIEW_FRAME::UpdateTitleAndInfo()
                  gerber->m_FmtLen.y - gerber->m_FmtScale.y, gerber->m_FmtScale.y,
                  gerber->m_NoTrailingZeros ? 'T' : 'L' );
 
+    if( gerber->m_IsX2_file )
+        text << wxT(" ") << _( "X2 attr" );
+
     m_TextInfo->SetValue( text );
+
+    if( EnsureTextCtrlWidth( m_TextInfo, &text ) )  // Resized
+       m_auimgr.Update();
 }
 
 /*
diff --git a/gerbview/init_gbr_drawlayers.cpp b/gerbview/init_gbr_drawlayers.cpp
index 3f7c6a8145..87773b0b1f 100644
--- a/gerbview/init_gbr_drawlayers.cpp
+++ b/gerbview/init_gbr_drawlayers.cpp
@@ -40,8 +40,6 @@
 
 bool GERBVIEW_FRAME::Clear_DrawLayers( bool query )
 {
-    int layer;
-
     if( GetGerberLayout() == NULL )
         return false;
 
@@ -53,14 +51,7 @@ bool GERBVIEW_FRAME::Clear_DrawLayers( bool query )
 
     GetGerberLayout()->m_Drawings.DeleteAll();
 
-    for( layer = 0; layer < GERBER_DRAWLAYERS_COUNT; ++layer )
-    {
-        if( g_GERBER_List[layer] )
-        {
-            g_GERBER_List[layer]->InitToolTable();
-            g_GERBER_List[layer]->ResetDefaultValues();
-        }
-    }
+    g_GERBER_List.ClearList();
 
     GetGerberLayout()->SetBoundingBox( EDA_RECT() );
 
@@ -98,11 +89,7 @@ void GERBVIEW_FRAME::Erase_Current_DrawLayer( bool query )
         item->DeleteStructure();
     }
 
-    if( g_GERBER_List[layer] )
-    {
-        g_GERBER_List[layer]->InitToolTable();
-        g_GERBER_List[layer]->ResetDefaultValues();
-    }
+    g_GERBER_List.ClearImage( layer );
 
     GetScreen()->SetModify();
     m_canvas->Refresh();
diff --git a/gerbview/onleftclick.cpp b/gerbview/onleftclick.cpp
index 9b006be5e6..5e857558e1 100644
--- a/gerbview/onleftclick.cpp
+++ b/gerbview/onleftclick.cpp
@@ -56,7 +56,7 @@ void GERBVIEW_FRAME::OnLeftClick( wxDC* DC, const wxPoint& aPosition )
             GetScreen()->SetCurItem( DrawStruct );
             if( DrawStruct == NULL )
             {
-                GERBER_IMAGE* gerber = g_GERBER_List[getActiveLayer() ];
+                GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( getActiveLayer() );
                 if( gerber )
                     gerber->DisplayImageInfo( );
             }
diff --git a/gerbview/readgerb.cpp b/gerbview/readgerb.cpp
index c9b1102435..6d49b34ef5 100644
--- a/gerbview/readgerb.cpp
+++ b/gerbview/readgerb.cpp
@@ -34,7 +34,7 @@
 #include <html_messagebox.h>
 #include <macros.h>
 
-/* Read a gerber file, RS274D or RS274X format.
+/* Read a gerber file, RS274D, RS274X or RS274X2 format.
  */
 bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName,
                                            const wxString& D_Code_FullFileName )
@@ -49,13 +49,14 @@ bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName,
     int layer;         // current layer used in GerbView
 
     layer = getActiveLayer();
+    GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer );
 
-    if( g_GERBER_List[layer] == NULL )
+    if( gerber == NULL )
     {
-        g_GERBER_List[layer] = new GERBER_IMAGE( this, layer );
+        gerber = new GERBER_IMAGE( this, layer );
+        g_GERBER_List.AddGbrImage( gerber, layer );
     }
 
-    GERBER_IMAGE* gerber = g_GERBER_List[layer];
     ClearMessageList( );
 
     /* Set the gerber scale: */
diff --git a/gerbview/rs274d.cpp b/gerbview/rs274d.cpp
index cb9475d6a1..1207616489 100644
--- a/gerbview/rs274d.cpp
+++ b/gerbview/rs274d.cpp
@@ -35,6 +35,7 @@
 #include <macros.h>
 #include <class_gerber_draw_item.h>
 #include <class_GERBER.h>
+#include <class_X2_gerber_attributes.h>
 
 #include <cmath>
 
@@ -43,7 +44,8 @@
  * G01 linear interpolation (right trace)
  * G02, G20, G21 Circular interpolation, meaning trig <0 (clockwise)
  * G03, G30, G31 Circular interpolation, meaning trigo> 0 (counterclockwise)
- * G04 = comment
+ * G04 = comment. Since Sept 2014, file attributes can be found here
+ *       if the line starts by G04 #@!
  * G06 parabolic interpolation
  * G07 Cubic Interpolation
  * G10 linear interpolation (scale x10)
@@ -473,9 +475,22 @@ bool GERBER_IMAGE::Execute_G_Command( char*& text, int G_command )
         break;
 
     case GC_COMMENT:
-        // Skip comment
+        // Skip comment, but only if the line does not start by "G04 #@! TF"
+        // which is a metadata
+        if( strncmp( text, " #@! TF", 7 ) == 0 )
+        {
+            text += 7;
+            X2_ATTRIBUTE dummy;
+            dummy.ParseAttribCmd( m_Current_File, NULL, 0, text );
+            if( dummy.IsFileFunction() )
+            {
+                delete m_FileFunction;
+                m_FileFunction = new X2_ATTRIBUTE_FILEFUNCTION( dummy );
+            }
+        }
+
         while ( *text && (*text != '*') )
-            text++;
+                    text++;
         break;
 
     case GC_LINEAR_INTERPOL_10X:
diff --git a/gerbview/rs274x.cpp b/gerbview/rs274x.cpp
index eb491f4b81..d30ee3acdd 100644
--- a/gerbview/rs274x.cpp
+++ b/gerbview/rs274x.cpp
@@ -33,6 +33,7 @@
 
 #include <gerbview.h>
 #include <class_GERBER.h>
+#include <class_X2_gerber_attributes.h>
 
 extern int ReadInt( char*& text, bool aSkipSeparator = true );
 extern double ReadDouble( char*& text, bool aSkipSeparator = true );
@@ -78,6 +79,13 @@ enum RS274X_PARAMETERS {
     AP_DEFINITION   = CODE( 'A', 'D' ),
     AP_MACRO = CODE( 'A', 'M' ),
 
+    // X2 extention attribute commands
+    // Mainly are found standard attributes and user attributes
+    // standard attributes commands are:
+    // TF (file attribute)
+    // TA (aperture attribute) and TD (delete aperture attribute)
+    FILE_ATTRIBUTE   = CODE( 'T', 'F' ),
+
     // Layer specific parameters
     // May be used singly or may be layer specfic
     // theses parameters are at the beginning of the file or layer
@@ -307,7 +315,7 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int       command,
             m_SwapAxis = true;
         break;
 
-    case MIRROR_IMAGE:      // commanf %MIA0B0*%, %MIA0B1*%, %MIA1B0*%, %MIA1B1*%
+    case MIRROR_IMAGE:      // command %MIA0B0*%, %MIA0B1*%, %MIA1B0*%, %MIA1B1*%
         m_MirrorA = m_MirrorB = 0;
         while( *text && *text != '*' )
         {
@@ -341,6 +349,27 @@ bool GERBER_IMAGE::ExecuteRS274XCommand( int       command,
         conv_scale = m_GerbMetric ? IU_PER_MILS / 25.4 : IU_PER_MILS;
         break;
 
+    case FILE_ATTRIBUTE:    // Command %TF ...
+        m_IsX2_file = true;
+    {
+        X2_ATTRIBUTE dummy;
+        dummy.ParseAttribCmd( m_Current_File, buff, GERBER_BUFZ, text );
+        if( dummy.IsFileFunction() )
+        {
+            delete m_FileFunction;
+            m_FileFunction = new X2_ATTRIBUTE_FILEFUNCTION( dummy );
+        }
+        else if( dummy.IsFileMD5() )
+        {
+            m_MD5_value = dummy.GetPrm( 1 );
+        }
+        else if( dummy.IsFilePart() )
+        {
+            m_PartString = dummy.GetPrm( 1 );
+        }
+     }
+        break;
+
     case OFFSET:        // command: OFAnnBnn (nn = float number) = layer Offset
         m_Offset.x = m_Offset.y = 0;
         while( *text != '*' )
diff --git a/gerbview/select_layers_to_pcb.cpp b/gerbview/select_layers_to_pcb.cpp
index 40c9f4e018..4fa893815f 100644
--- a/gerbview/select_layers_to_pcb.cpp
+++ b/gerbview/select_layers_to_pcb.cpp
@@ -121,7 +121,7 @@ void LAYERS_MAP_DIALOG::initDialog()
     m_gerberActiveLayersCount = 0;
     for( int ii = 0; ii < GERBER_DRAWLAYERS_COUNT; ++ii )
     {
-        if( g_GERBER_List[ii] == NULL )
+        if( g_GERBER_List.GetGbrImage( ii ) == NULL )
             break;
 
         if( (pcb_layer_num == m_exportBoardCopperLayersCount - 1)
@@ -189,7 +189,7 @@ void LAYERS_MAP_DIALOG::initDialog()
                                  wxRIGHT | wxLEFT, 5 );
 
         /* Add file name and extension without path. */
-        wxFileName fn( g_GERBER_List[ii]->m_FileName );
+        wxFileName fn( g_GERBER_List.GetGbrImage( ii )->m_FileName );
         label = new wxStaticText( this, wxID_STATIC, fn.GetFullName(),
                                   wxDefaultPosition, wxDefaultSize );
         flexColumnBoxSizer->Add( label, 0,
diff --git a/gerbview/toolbars_gerber.cpp b/gerbview/toolbars_gerber.cpp
index 7ad3b5e7b2..7541a0c07b 100644
--- a/gerbview/toolbars_gerber.cpp
+++ b/gerbview/toolbars_gerber.cpp
@@ -294,7 +294,7 @@ void GERBVIEW_FRAME::OnUpdateShowLayerManager( wxUpdateUIEvent& aEvent )
 void GERBVIEW_FRAME::OnUpdateSelectDCode( wxUpdateUIEvent& aEvent )
 {
     int layer = getActiveLayer();
-    GERBER_IMAGE* gerber = g_GERBER_List[layer];
+    GERBER_IMAGE* gerber = g_GERBER_List.GetGbrImage( layer );
     int selected = ( gerber ) ? gerber->m_Selected_Tool : 0;
 
     if( m_DCodeSelector && m_DCodeSelector->GetSelectedDCodeId() != selected )