Index: trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java
===================================================================
--- trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java	(revision 9657)
+++ trunk/src/org/openstreetmap/josm/data/imagery/ImageryInfo.java	(revision 9658)
@@ -145,5 +145,4 @@
         }
     }
-
 
     /** original name of the imagery entry in case of translation call, for multiple languages English when possible */
@@ -186,4 +185,6 @@
     /** country code of the imagery (for country specific imagery) */
     private String countryCode = "";
+    /** mirrors of different type for this entry */
+    private List<ImageryInfo> mirrors = null;
     /** icon used in menu */
     private String icon;
@@ -1029,3 +1030,47 @@
     }
 
+    /**
+     * Adds a mirror entry. Mirror entries are completed with the data from the master entry
+     * and only describe another method to access identical data.
+     *
+     * @param entry the mirror to be added
+     * @since 9658
+     */
+    public void addMirror(ImageryInfo entry) {
+       if (mirrors == null) {
+           mirrors = new ArrayList<>();
+       }
+       mirrors.add(entry);
+    }
+
+    /**
+     * Returns the mirror entries. Entries are completed with master entry data.
+     *
+     * @return the list of mirrors
+     * @since 9658
+     */
+    public List<ImageryInfo> getMirrors() {
+       List<ImageryInfo> l = new ArrayList<>();
+       if (mirrors != null) {
+           for (ImageryInfo i : mirrors) {
+               ImageryInfo n = new ImageryInfo(this);
+               if (i.defaultMaxZoom != 0) {
+                   n.defaultMaxZoom = i.defaultMaxZoom;
+               }
+               if (i.defaultMinZoom != 0) {
+                   n.defaultMinZoom = i.defaultMinZoom;
+               }
+               if (i.serverProjections != null) {
+                   n.serverProjections = i.serverProjections;
+               }
+               n.url = i.url;
+               n.imageryType = i.imageryType;
+               if (i.getTileSize() != 0) {
+                   n.setTileSize(i.getTileSize());
+               }
+               l.add(n);
+           }
+       }
+       return l;
+    }
 }
Index: trunk/src/org/openstreetmap/josm/io/imagery/ImageryReader.java
===================================================================
--- trunk/src/org/openstreetmap/josm/io/imagery/ImageryReader.java	(revision 9657)
+++ trunk/src/org/openstreetmap/josm/io/imagery/ImageryReader.java	(revision 9658)
@@ -40,5 +40,8 @@
         ENTRY,              // inside an entry
         ENTRY_ATTRIBUTE,    // note we are inside an entry attribute to collect the character data
-        PROJECTIONS,
+        PROJECTIONS,        // inside projections block of an entry
+        MIRROR,             // inside an mirror entry
+        MIRROR_ATTRIBUTE,   // note we are inside an mirror attribute to collect the character data
+        MIRROR_PROJECTIONS, // inside projections block of an mirror entry
         CODE,
         BOUNDS,
@@ -89,4 +92,6 @@
 
         private ImageryInfo entry;
+        /** In case of mirror parsing this contains the mirror entry */
+        private ImageryInfo mirrorEntry;
         private ImageryBounds bounds;
         private Shape shape;
@@ -130,4 +135,19 @@
                     noTileChecksums = new HashMap<>();
                     metadataHeaders = new HashMap<>();
+                }
+                break;
+            case MIRROR:
+                if (Arrays.asList(new String[] {
+                        "type",
+                        "url",
+                        "min-zoom",
+                        "max-zoom",
+                        "tile-size",
+                }).contains(qName)) {
+                    newState = State.MIRROR_ATTRIBUTE;
+                    lang = atts.getValue("lang");
+                } else if ("projections".equals(qName)) {
+                    projections = new ArrayList<>();
+                    newState = State.MIRROR_PROJECTIONS;
                 }
                 break;
@@ -171,4 +191,8 @@
                     projections = new ArrayList<>();
                     newState = State.PROJECTIONS;
+                } else if ("mirror".equals(qName)) {
+                    projections = new ArrayList<>();
+                    newState = State.MIRROR;
+                    mirrorEntry = new ImageryInfo();
                 } else if ("no-tile-header".equals(qName)) {
                     String name = atts.getValue("name");
@@ -214,4 +238,5 @@
                 break;
             case PROJECTIONS:
+            case MIRROR_PROJECTIONS:
                 if ("code".equals(qName)) {
                     newState = State.CODE;
@@ -259,4 +284,65 @@
                 }
                 break;
+            case MIRROR:
+                if ("mirror".equals(qName)) {
+                    if (mirrorEntry != null) {
+                        entry.addMirror(mirrorEntry);
+                        mirrorEntry = null;
+                    }
+                }
+                break;
+            case MIRROR_ATTRIBUTE:
+                if (mirrorEntry != null) {
+                    switch(qName) {
+                    case "type":
+                        boolean found = false;
+                        for (ImageryType type : ImageryType.values()) {
+                            if (Objects.equals(accumulator.toString(), type.getTypeString())) {
+                                mirrorEntry.setImageryType(type);
+                                found = true;
+                                break;
+                            }
+                        }
+                        if (!found) {
+                            mirrorEntry = null;
+                        }
+                        break;
+                    case "url":
+                        mirrorEntry.setUrl(accumulator.toString());
+                        break;
+                    case "min-zoom":
+                    case "max-zoom":
+                        Integer val = null;
+                        try {
+                            val = Integer.valueOf(accumulator.toString());
+                        } catch (NumberFormatException e) {
+                            val = null;
+                        }
+                        if (val == null) {
+                            mirrorEntry = null;
+                        } else {
+                            if ("min-zoom".equals(qName)) {
+                                mirrorEntry.setDefaultMinZoom(val);
+                            } else {
+                                mirrorEntry.setDefaultMaxZoom(val);
+                            }
+                        }
+                        break;
+                    case "tile-size":
+                        Integer tileSize = null;
+                        try {
+                            tileSize = Integer.valueOf(accumulator.toString());
+                        } catch (NumberFormatException e) {
+                            tileSize = null;
+                        }
+                        if (tileSize == null) {
+                            mirrorEntry = null;
+                        } else {
+                            entry.setTileSize(tileSize.intValue());
+                        }
+                        break;
+                    }
+                }
+                break;
             case ENTRY_ATTRIBUTE:
                 switch(qName) {
@@ -379,7 +465,15 @@
                 projections = null;
                 break;
+            case MIRROR_PROJECTIONS:
+                mirrorEntry.setServerProjections(projections);
+                projections = null;
+                break;
+            /* nothing to do for these or the unknown type:
             case NO_TILE:
-                break;
-
+            case NO_TILESUM:
+            case METADATA:
+            case UNKNOWN:
+                break;
+            */
             }
         }
