Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFile.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFile.java	(revision 33652)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFile.java	(revision 33653)
@@ -9,4 +9,6 @@
 import java.time.LocalDate;
 import java.time.format.DateTimeFormatter;
+import java.util.Arrays;
+import java.util.Collection;
 import java.util.List;
 import java.util.Objects;
@@ -56,4 +58,20 @@
         }
 
+        static boolean areNotNull(Object... objects) {
+            return Arrays.stream(objects).noneMatch(o -> o == null);
+        }
+
+        static boolean areNotEmpty(String... strings) {
+            return areNotNull((Object[]) strings) && Arrays.stream(strings).noneMatch(String::isEmpty);
+        }
+
+        static boolean areSameSize(int size, Collection<?>... collections) {
+            return areNotNull((Object[]) collections) && Arrays.stream(collections).allMatch(c -> c.size() == size);
+        }
+
+        boolean isValid() {
+            return type.length() == 3 && areNotEmpty(identifier);
+        }
+
         protected final void safeGet(EdigeoRecord r, List<String> list) {
             list.add("");
@@ -66,4 +84,8 @@
         protected final void safeGet(EdigeoRecord r, Consumer<String> callback) {
             (lastReadString = callback).accept(r.length > 0 ? r.values.get(0) : null);
+        }
+
+        protected final char safeGetChar(EdigeoRecord r) {
+            return r.length > 0 ? r.values.get(0).charAt(0) : 0;
         }
 
@@ -175,3 +197,5 @@
         currentBlock.processRecord(r);
     }
+
+    abstract boolean isValid();
 }
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileDIC.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileDIC.java	(revision 33652)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileDIC.java	(revision 33653)
@@ -12,4 +12,5 @@
 import org.openstreetmap.josm.plugins.fr.cadastre.edigeo.EdigeoFileTHF.ChildBlock;
 import org.openstreetmap.josm.plugins.fr.cadastre.edigeo.EdigeoFileTHF.Lot;
+import org.openstreetmap.josm.plugins.fr.cadastre.edigeo.EdigeoRecord.Format;
 
 /**
@@ -27,5 +28,4 @@
         /** DEF */ String definition = "";
         /** ORI */ String origin = "";
-        /** CAT */ String category = "";
 
         DicBlock(Lot lot, String type) {
@@ -40,5 +40,4 @@
             case "DEF": safeGet(r, s -> definition += s); break;
             case "ORI": safeGet(r, s -> origin += s); break;
-            case "CAT": safeGet(r, s -> category += s); break;
             default:
                 super.processRecord(r);
@@ -46,4 +45,9 @@
         }
 
+        @Override
+        boolean isValid() {
+            return super.isValid() && areNotEmpty(code);
+        }
+
         /**
          * Returns code.
@@ -69,4 +73,49 @@
             return origin;
         }
+    }
+
+    /**
+     * Categorized definition.
+     */
+    abstract static class CategorizedBlock extends DicBlock {
+
+        enum Category {
+            GENERAL('G'),
+            SPECIFIC('P');
+
+            final char code;
+            Category(char code) {
+                this.code = code;
+            }
+
+            public static Category of(char code) {
+                for (Category s : values()) {
+                    if (s.code == code) {
+                        return s;
+                    }
+                }
+                throw new IllegalArgumentException(Character.toString(code));
+            }
+        }
+
+        /** CAT */ Category category;
+
+        CategorizedBlock(Lot lot, String type) {
+            super(lot, type);
+        }
+
+        @Override
+        void processRecord(EdigeoRecord r) {
+            switch (r.name) {
+            case "CAT": category = Category.of(safeGetChar(r)); break;
+            default:
+                super.processRecord(r);
+            }
+        }
+
+        @Override
+        boolean isValid() {
+            return super.isValid() && areNotNull(category);
+        }
 
         /**
@@ -74,5 +123,5 @@
          * @return category
          */
-        public final String getCategory() {
+        public final Category getCategory() {
             return category;
         }
@@ -91,7 +140,7 @@
      * Attribute definition.
      */
-    public static class AttributeDef extends DicBlock {
-
-        /** TYP */ String type = "";
+    public static class AttributeDef extends CategorizedBlock {
+
+        /** TYP */ Format type;
         /** UNI */ String unit = "";
         /** AVC */ int nValues;
@@ -106,5 +155,5 @@
         void processRecord(EdigeoRecord r) {
             switch (r.name) {
-            case "TYP": safeGet(r, s -> type += s); break;
+            case "TYP": type = Format.of(safeGetChar(r)); break;
             case "UNI": safeGet(r, s -> unit += s); break;
             case "AVC": nValues = safeGetInt(r); break;
@@ -120,5 +169,5 @@
          * @return attribute type
          */
-        public final String getType() {
+        public final Format getType() {
             return type;
         }
@@ -160,5 +209,5 @@
      * Relation definition.
      */
-    public static class RelationDef extends DicBlock {
+    public static class RelationDef extends CategorizedBlock {
         RelationDef(Lot lot, String type) {
             super(lot, type);
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileGEN.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileGEN.java	(revision 33652)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileGEN.java	(revision 33653)
@@ -45,4 +45,9 @@
                 super.processRecord(r);
             }
+        }
+
+        @Override
+        boolean isValid() {
+            return super.isValid() && areNotNull(min, max);
         }
 
@@ -133,4 +138,9 @@
         }
 
+        @Override
+        boolean isValid() {
+            return super.isValid() && areNotNull(structure);
+        }
+
         /**
          * Returns general information.
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileGEO.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileGEO.java	(revision 33652)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileGEO.java	(revision 33653)
@@ -6,5 +6,8 @@
 import java.io.IOException;
 import java.nio.file.Path;
-
+import java.util.ArrayList;
+import java.util.List;
+
+import org.openstreetmap.josm.data.coor.EastNorth;
 import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.projection.Projection;
@@ -61,4 +64,23 @@
             public static AltitudeSystem of(int code) {
                 for (AltitudeSystem s : values()) {
+                    if (s.code == code) {
+                        return s;
+                    }
+                }
+                throw new IllegalArgumentException(Integer.toString(code));
+            }
+        }
+
+        enum AltitudeSystemType {
+            TERRESTRIAL(1),
+            BATHYMETRIC(2);
+
+            int code;
+            AltitudeSystemType(int code) {
+                this.code = code;
+            }
+
+            public static AltitudeSystemType of(int code) {
+                for (AltitudeSystemType s : values()) {
                     if (s.code == code) {
                         return s;
@@ -164,5 +186,9 @@
         /** DIM */ int nDim;
         /** ALS */ AltitudeSystem altitudeSystem;
-        /** UNH */ String unit = "";
+        /**     */ AltitudeSystemType altitudeSystemType; // TODO
+        /**     */ String altitudeSystemName = ""; // TODO
+        /**     */ String altitudeSystemCode = ""; // TODO
+        /** UNH */ String unitHorizontal = "";
+        /**     */ String unitVertical = ""; // TODO
 
         CoorReference(Lot lot, String type) {
@@ -178,5 +204,5 @@
             case "DIM": nDim = safeGetInt(r); break;
             case "ALS": altitudeSystem = AltitudeSystem.of(safeGetInt(r)); break;
-            case "UNH": safeGet(r, s -> unit += s); break;
+            case "UNH": safeGet(r, s -> unitHorizontal += s); break;
             default:
                 super.processRecord(r);
@@ -184,4 +210,12 @@
         }
 
+        @Override
+        boolean isValid() {
+            return super.isValid() && areNotNull(type, altitudeSystem) && areNotEmpty(code, unitHorizontal)
+                    && (nDim == 2 || (nDim == 3 && areNotEmpty(unitVertical)))
+                    && (AltitudeSystem.THREE_DIM_OR_NO_ALTITUDE == altitudeSystem
+                    || areNotNull(altitudeSystemType, altitudeSystemName, altitudeSystemCode));
+        }
+
         /**
          * Returns reference type.
@@ -225,9 +259,17 @@
 
         /**
-         * Returns unit.
-         * @return unit
-         */
-        public final String getUnit() {
-            return unit;
+         * Returns horizontal unit.
+         * @return horizontal unit
+         */
+        public final String getUnitHorizontal() {
+            return unitHorizontal;
+        }
+
+        /**
+         * Returns vertical unit.
+         * @return vertical unit
+         */
+        public final String getUnitVertical() {
+            return unitVertical;
         }
 
@@ -245,4 +287,30 @@
             }
             return Projections.getProjectionByCode(ref.getEpsgCode());
+        }
+    }
+
+    /**
+     * Offset.
+     */
+    public static class Offset extends GeoBlock {
+
+        /**     */ int nOffsetPoints; // TODO
+        /**     */ int nControlPoints; // TODO
+        /**     */ final List<String> offsetPointIds = new ArrayList<>(); // TODO
+        /**     */ final List<EastNorth> offsetInputCoor = new ArrayList<>(); // TODO
+        /**     */ final List<EastNorth> offsetReferCoor = new ArrayList<>(); // TODO
+        /**     */ final List<String> controlPointIds = new ArrayList<>(); // TODO
+        /**     */ final List<EastNorth> controlInputCoor = new ArrayList<>(); // TODO
+        /**     */ final List<EastNorth> controlReferCoor = new ArrayList<>(); // TODO
+
+        Offset(Lot lot, String type) {
+            super(lot, type);
+        }
+
+        @Override
+        boolean isValid() {
+            return super.isValid()
+                    && areSameSize(nOffsetPoints, offsetPointIds, offsetInputCoor, offsetReferCoor)
+                    && areSameSize(nControlPoints, controlPointIds, controlInputCoor, controlReferCoor);
         }
     }
@@ -258,4 +326,5 @@
         super(lot, seId, path);
         register("GEO", CoorReference.class);
+        register("RPR", Offset.class);
         lot.geo = this;
     }
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileQAL.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileQAL.java	(revision 33652)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileQAL.java	(revision 33653)
@@ -25,5 +25,14 @@
 
     /**
-     * Update descriptor.
+     * Genealogy descriptor (6.4.5.1). TODO
+     */
+    public static class Genealogy extends QalBlock {
+        Genealogy(Lot lot, String type) {
+            super(lot, type);
+        }
+    }
+
+    /**
+     * Update descriptor (6.4.5.2).
      */
     public static class Update extends QalBlock {
@@ -100,4 +109,67 @@
 
     /**
+     * Horizontal precision descriptor (6.4.5.3). TODO
+     */
+    public static class HorizontalPrecision extends QalBlock {
+        HorizontalPrecision(Lot lot, String type) {
+            super(lot, type);
+        }
+    }
+
+    /**
+     * Vertical precision descriptor (6.4.5.4). TODO
+     */
+    public static class VerticalPrecision extends QalBlock {
+        VerticalPrecision(Lot lot, String type) {
+            super(lot, type);
+        }
+    }
+
+    /**
+     * Metric precision descriptor (6.4.5.5). TODO
+     */
+    public static class MetricPrecision extends QalBlock {
+        MetricPrecision(Lot lot, String type) {
+            super(lot, type);
+        }
+    }
+
+    /**
+     * Exhaustivity descriptor (6.4.5.6). TODO
+     */
+    public static class Exhaustivity extends QalBlock {
+        Exhaustivity(Lot lot, String type) {
+            super(lot, type);
+        }
+    }
+
+    /**
+     * Semantic precision descriptor (6.4.5.7). TODO
+     */
+    public static class SemanticPrecision extends QalBlock {
+        SemanticPrecision(Lot lot, String type) {
+            super(lot, type);
+        }
+    }
+
+    /**
+     * Logical coherence descriptor (6.4.5.8). TODO
+     */
+    public static class LogicalCoherence extends QalBlock {
+        LogicalCoherence(Lot lot, String type) {
+            super(lot, type);
+        }
+    }
+
+    /**
+     * Specific quality descriptor (6.4.5.9). TODO
+     */
+    public static class SpecificQuality extends QalBlock {
+        SpecificQuality(Lot lot, String type) {
+            super(lot, type);
+        }
+    }
+
+    /**
      * Constructs a new {@code EdigeoFileQAL}.
      * @param lot parent lot
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileTHF.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileTHF.java	(revision 33652)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileTHF.java	(revision 33653)
@@ -13,4 +13,5 @@
 
 import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.tools.Logging;
 
 /**
@@ -52,4 +53,5 @@
         /** LOC */ int nLots;
         /** VOC */ int nVolumes;
+        /**     */ final List<String> volumeLabels = new ArrayList<>(); // TODO
         /** SEC */ SecurityClassification security;
         /** RDI */ String diffusionRestriction = "";
@@ -83,4 +85,10 @@
                 super.processRecord(r);
             }
+        }
+
+        @Override
+        boolean isValid() {
+            return super.isValid() && areNotEmpty(author, recipient, edigeoVersion, transmissionName)
+                    && areSameSize(nVolumes, volumeLabels) && transmissionEdition >= 1;
         }
 
@@ -239,12 +247,26 @@
         void readFiles(Path path, DataSet ds) throws IOException, ReflectiveOperationException {
             Path dir = path.getParent();
-            new EdigeoFileGEN(this, genId, dir.resolve(name + genName + ".GEN")).read(ds);
-            new EdigeoFileGEO(this, geoId, dir.resolve(name + geoName + ".GEO")).read(ds);
-            new EdigeoFileDIC(this, dicId, dir.resolve(name + dicName + ".DIC")).read(ds);
-            new EdigeoFileSCD(this, scdId, dir.resolve(name + scdName + ".SCD")).read(ds);
-            new EdigeoFileQAL(this, qalId, dir.resolve(name + qalName + ".QAL")).read(ds);
+            List<EdigeoFile> allFiles = new ArrayList<>();
+            allFiles.add(new EdigeoFileGEN(this, genId, dir.resolve(name + genName + ".GEN")).read(ds));
+            allFiles.add(new EdigeoFileGEO(this, geoId, dir.resolve(name + geoName + ".GEO")).read(ds));
+            allFiles.add(new EdigeoFileDIC(this, dicId, dir.resolve(name + dicName + ".DIC")).read(ds));
+            allFiles.add(new EdigeoFileSCD(this, scdId, dir.resolve(name + scdName + ".SCD")).read(ds));
+            allFiles.add(new EdigeoFileQAL(this, qalId, dir.resolve(name + qalName + ".QAL")).read(ds));
             for (int i = 0; i < getNumberOfGeoData(); i++) {
-                new EdigeoFileVEC(this, vecId.get(i), dir.resolve(name + vecName.get(i) + ".VEC")).read(ds);
-            }
+                allFiles.add(new EdigeoFileVEC(this, vecId.get(i), dir.resolve(name + vecName.get(i) + ".VEC")).read(ds));
+            }
+            for (EdigeoFile f : allFiles) {
+                boolean valid = f.isValid();
+                if (valid) {
+                    Logging.debug(f.path + ": valid");
+                } else {
+                    Logging.warn(f.path + ": invalid!");
+                }
+            }
+        }
+
+        @Override
+        boolean isValid() {
+            return super.isValid() && areNotEmpty(name, genName, genId, geoName, geoId);
         }
 
@@ -448,3 +470,8 @@
         return this;
     }
+
+    @Override
+    boolean isValid() {
+        return support.isValid() && lots.stream().allMatch(Block::isValid);
+    }
 }
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileVEC.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileVEC.java	(revision 33652)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoFileVEC.java	(revision 33653)
@@ -34,4 +34,10 @@
 
         /** SCP */ T scdRef;
+        /** ATC */ int nAttributes;
+        /** ATP */ final List<String> attributeDefs = new ArrayList<>();
+        /** TEX */ EdigeoCharset charset;
+        /** ATV */ final List<String> attributeValues = new ArrayList<>();
+        /** QAC */ int nQualities;
+        /** QAP */ final List<String> qualityIndics = new ArrayList<>();
 
         VecBlock(Lot lot, String type, Class<T> klass) {
@@ -44,4 +50,29 @@
             switch (r.name) {
             case "SCP": scdRef = lot.scd.find(r.values, klass); break;
+            case "ATC": nAttributes = safeGetInt(r); break;
+            case "ATP": safeGet(r, attributeDefs); break;
+            case "TEX": safeGet(r, s -> charset = EdigeoCharset.of(s)); break;
+            case "ATV": safeGet(r, attributeValues); break;
+            case "QAC": nQualities = safeGetInt(r); break;
+            case "QAP": safeGet(r, qualityIndics); break;
+            default:
+                super.processRecord(r);
+            }
+        }
+    }
+
+    abstract static class BoundedBlock<T extends ScdBlock> extends VecBlock<T> {
+        /** CM1 */ EastNorth minCoordinate;
+        /** CM2 */ EastNorth maxCoordinate;
+
+        BoundedBlock(Lot lot, String type, Class<T> klass) {
+            super(lot, type, klass);
+        }
+
+        @Override
+        void processRecord(EdigeoRecord r) {
+            switch (r.name) {
+            case "CM1": minCoordinate = safeGetEastNorth(r); break;
+            case "CM2": maxCoordinate = safeGetEastNorth(r); break;
             default:
                 super.processRecord(r);
@@ -76,6 +107,4 @@
         /** TYP */ NodeType nodeType;
         /** COR */ EastNorth coordinate;
-        /** ATC */ int nAttributes;
-        /** QAC */ int nQualities;
 
         NodeBlock(Lot lot, String type) {
@@ -88,6 +117,4 @@
             case "TYP": nodeType = NodeType.of(safeGetInt(r)); break;
             case "COR": coordinate = safeGetEastNorth(r); break;
-            case "ATC": nAttributes = safeGetInt(r); break;
-            case "QAC": nQualities = safeGetInt(r); break;
             default:
                 super.processRecord(r);
@@ -139,5 +166,5 @@
      * Arc descriptor block.
      */
-    public static class ArcBlock extends VecBlock<McdPrimitiveDef> {
+    public static class ArcBlock extends BoundedBlock<McdPrimitiveDef> {
         enum ArcType {
             LINE(1),
@@ -160,11 +187,7 @@
         }
 
-        /** CM1 */ EastNorth minCoordinate;
-        /** CM2 */ EastNorth maxCoordinate;
         /** TYP */ ArcType arcType;
         /** PTC */ int nPoints;
         /** COR */ final List<EastNorth> points = new ArrayList<>();
-        /** ATC */ int nAttributes;
-        /** QAC */ int nQualities;
 
         ArcBlock(Lot lot, String type) {
@@ -175,13 +198,18 @@
         void processRecord(EdigeoRecord r) {
             switch (r.name) {
-            case "CM1": minCoordinate = safeGetEastNorth(r); break;
-            case "CM2": maxCoordinate = safeGetEastNorth(r); break;
             case "TYP": arcType = ArcType.of(safeGetInt(r)); break;
-            case "PTC": nPoints = safeGetInt(r); break;
+            case "PTC": nPoints = safeGetInt(r); assert checkNumberOfPoints(); break;
             case "COR": points.add(safeGetEastNorth(r)); break;
-            case "ATC": nAttributes = safeGetInt(r); break;
-            case "QAC": nQualities = safeGetInt(r); break;
-            default:
-                super.processRecord(r);
+            default:
+                super.processRecord(r);
+            }
+        }
+
+        private boolean checkNumberOfPoints() {
+            switch (arcType) {
+            case LINE: return nPoints >= 2;
+            case CIRCLE_ARC: return nPoints == 3;
+            case CURVE: return nPoints >= 3;
+            default: throw new IllegalStateException(arcType.toString());
             }
         }
@@ -191,25 +219,9 @@
      * Face descriptor block.
      */
-    public static class FaceBlock extends VecBlock<McdPrimitiveDef> {
-        /** CM1 */ EastNorth minCoordinate;
-        /** CM2 */ EastNorth maxCoordinate;
-        /** ATC */ int nAttributes;
-        /** QAC */ int nQualities;
+    public static class FaceBlock extends BoundedBlock<McdPrimitiveDef> {
 
         FaceBlock(Lot lot, String type) {
             super(lot, type, McdPrimitiveDef.class);
         }
-
-        @Override
-        void processRecord(EdigeoRecord r) {
-            switch (r.name) {
-            case "CM1": minCoordinate = safeGetEastNorth(r); break;
-            case "CM2": maxCoordinate = safeGetEastNorth(r); break;
-            case "ATC": nAttributes = safeGetInt(r); break;
-            case "QAC": nQualities = safeGetInt(r); break;
-            default:
-                super.processRecord(r);
-            }
-        }
     }
 
@@ -217,14 +229,6 @@
      * Object descriptor block.
      */
-    public static class ObjectBlock extends VecBlock<McdObjectDef> {
-        /** CM1 */ EastNorth minCoordinate;
-        /** CM2 */ EastNorth maxCoordinate;
+    public static class ObjectBlock extends BoundedBlock<McdObjectDef> {
         /** REF */ String pointRef = "";
-        /** ATC */ int nAttributes;
-        /** ATP */ final List<String> attributeDefs = new ArrayList<>();
-        /** TEX */ EdigeoCharset charset;
-        /** ATV */ final List<String> attributeValues = new ArrayList<>();
-        /** QAC */ int nQualities;
-        /** QAP */ final List<String> qualityIndics = new ArrayList<>();
 
         ObjectBlock(Lot lot, String type) {
@@ -235,13 +239,5 @@
         void processRecord(EdigeoRecord r) {
             switch (r.name) {
-            case "CM1": minCoordinate = safeGetEastNorth(r); break;
-            case "CM2": maxCoordinate = safeGetEastNorth(r); break;
             case "REF": safeGet(r, s -> pointRef += s); break;
-            case "ATC": nAttributes = safeGetInt(r); break;
-            case "ATP": safeGet(r, attributeDefs); break;
-            case "TEX": safeGet(r, s -> charset = EdigeoCharset.of(s)); break;
-            case "ATV": safeGet(r, attributeValues); break;
-            case "QAC": nQualities = safeGetInt(r); break;
-            case "QAP": safeGet(r, qualityIndics); break;
             default:
                 super.processRecord(r);
@@ -256,19 +252,19 @@
 
         enum Composition {
-            PLUS("P"),
-            MINUS("M");
-
-            String code;
-            Composition(String code) {
+            PLUS('P'),
+            MINUS('M');
+
+            final char code;
+            Composition(char code) {
                 this.code = code;
             }
 
-            public static Composition of(String code) {
+            public static Composition of(char code) {
                 for (Composition s : values()) {
-                    if (s.code.equals(code)) {
+                    if (s.code == code) {
                         return s;
                     }
                 }
-                throw new IllegalArgumentException(code);
+                throw new IllegalArgumentException(Character.toString(code));
             }
         }
@@ -277,6 +273,4 @@
         /** FTP */ final List<String> elements = new ArrayList<>();
         /** SNS */ final Map<String, Composition> compositions = new HashMap<>();
-        /** ATC */ int nAttributes;
-        /** QAC */ int nQualities;
 
         RelationBlock(Lot lot, String type) {
@@ -289,7 +283,5 @@
             case "FTC": nElements = safeGetInt(r); break;
             case "FTP": safeGet(r, elements); break;
-            case "SNS": safeGet(r, s -> compositions.put(elements.get(elements.size()-1), Composition.of(s))); break;
-            case "ATC": nAttributes = safeGetInt(r); break;
-            case "QAC": nQualities = safeGetInt(r); break;
+            case "SNS": compositions.put(elements.get(elements.size()-1), Composition.of(safeGetChar(r))); break;
             default:
                 super.processRecord(r);
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoLotFile.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoLotFile.java	(revision 33652)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoLotFile.java	(revision 33653)
@@ -10,4 +10,5 @@
 import java.util.Objects;
 
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.plugins.fr.cadastre.edigeo.EdigeoFileTHF.ChildBlock;
 import org.openstreetmap.josm.plugins.fr.cadastre.edigeo.EdigeoFileTHF.Lot;
@@ -42,4 +43,15 @@
         Class<? extends B> klass = classes.get(type);
         return addBlock(blocks.get(klass), klass.getDeclaredConstructor(Lot.class, String.class).newInstance(lot, type));
+    }
+
+    @Override
+    public EdigeoLotFile<B> read(DataSet ds) throws IOException, ReflectiveOperationException {
+        super.read(ds);
+        return this;
+    }
+
+    @Override
+    boolean isValid() {
+        return blocks.values().stream().allMatch(l -> l.stream().allMatch(Block::isValid));
     }
 
Index: /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoRecord.java
===================================================================
--- /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoRecord.java	(revision 33652)
+++ /applications/editors/josm/plugins/cadastre-fr/src/org/openstreetmap/josm/plugins/fr/cadastre/edigeo/EdigeoRecord.java	(revision 33653)
@@ -28,5 +28,5 @@
                 }
             }
-            throw new IllegalArgumentException("Unknown code: " + c);
+            throw new IllegalArgumentException(Character.toString(c));
         }
     }
@@ -34,4 +34,5 @@
     enum Format {
         STRING('A'),
+        BINARY('B'),
         COORDINATES('C'),
         DATE('D'),
@@ -55,5 +56,5 @@
                 }
             }
-            throw new IllegalArgumentException("Unknown code: " + c);
+            throw new IllegalArgumentException(Character.toString(c));
         }
     }
