New upstream version 0.0.0+svn4810
Bas Couwenberg
2 years ago
70 | 70 | into {user}\AppData\Roaming\Garmin\Maps or \ProgramData\Garmin\Maps |
71 | 71 | and the map will be available to Garmin PC programs. |
72 | 72 | The directory name is --family-name with extension .gmap. |
73 | ||
74 | ;--gmapi-minimal[=<include-pattern>] | |
75 | : Special option for map providers to reduce disk writes when updating. Works like | |
76 | --gmapi but does not write Product data for input files which are provided as | |
77 | *.img. It is assumed that the content of those files wasn't changed and thus | |
78 | doesn't need a rewrite. The optional include-pattern is a regular expression | |
79 | which can be used to specify *.img files for which a write should be forced. The | |
80 | pattern is used on the full path to the input file. The global index files and | |
81 | the *.tdb file will still contain all needed references. | |
82 | : Example usage with pattern: | |
83 | :: --gmapi-minimal=.*4711[0-9]{4}\.img | |
84 | :: This pattern matches file names between 47110000.img and 47119999.img | |
85 | :: and ignores the path. | |
73 | 86 | |
74 | 87 | ;-c filename |
75 | 88 | ;--read-config=filename |
69 | 69 | into {user}\AppData\Roaming\Garmin\Maps or \ProgramData\Garmin\Maps and the |
70 | 70 | map will be available to Garmin PC programs. The directory name is |
71 | 71 | --family-name with extension .gmap. |
72 | ||
73 | --gmapi-minimal[=<include-pattern>] | |
74 | Special option for map providers to reduce disk writes when updating. Works | |
75 | like --gmapi but does not write Product data for input files which are | |
76 | provided as *.img. It is assumed that the content of those files wasn't | |
77 | changed and thus doesn't need a rewrite. The optional include-pattern is a | |
78 | regular expression which can be used to specify *.img files for which a | |
79 | write should be forced. The pattern is used on the full path to the input | |
80 | file. The global index files and the *.tdb file will still contain all | |
81 | needed references. | |
82 | Example usage with pattern: | |
83 | --gmapi-minimal=.*4711[0-9]{4}\.img | |
84 | This pattern matches file names between 47110000.img and 47119999.img | |
85 | and ignores the path. | |
72 | 86 | |
73 | 87 | -c filename |
74 | 88 | --read-config=filename |
0 | svn.version: 4807 | |
1 | build.timestamp: 2021-09-14T09:45:24+0100 | |
0 | svn.version: 4810 | |
1 | build.timestamp: 2021-10-25T08:27:43+0100 |
26 | 26 | for (String listOpt : Arrays.asList("mdr7-excl", "mdr7-del", "poi-excl-index", "location-autofill", |
27 | 27 | "overview-levels", "levels", "name-tag-list", "polygon-size-limits", "dem", "dem-dists", "drive-on", |
28 | 28 | "dead-ends", "add-pois-to-lines", "coastlinefile", "generate-sea", "nearby-poi-rules", |
29 | "line-types-with-direction")) { | |
29 | "line-types-with-direction", "gmapi-minimal")) { | |
30 | 30 | stringToList(get(listOpt, null), listOpt); |
31 | 31 | } |
32 | 32 | } |
31 | 31 | import uk.me.parabola.imgfmt.app.Area; |
32 | 32 | import uk.me.parabola.imgfmt.app.BufferedImgFileReader; |
33 | 33 | import uk.me.parabola.imgfmt.app.lbl.LBLFileReader; |
34 | import uk.me.parabola.imgfmt.app.map.MapReader; | |
34 | 35 | import uk.me.parabola.imgfmt.app.srt.Sort; |
35 | 36 | import uk.me.parabola.imgfmt.app.trergn.TREFileReader; |
36 | 37 | import uk.me.parabola.imgfmt.app.trergn.TREHeader; |
84 | 85 | private int codePage; |
85 | 86 | private int sortOrderId; |
86 | 87 | private int demsize; |
88 | private MapReader mapReader; | |
87 | 89 | |
88 | 90 | private FileInfo(String filename, FileKind kind) { |
89 | 91 | this.filename = filename; |
474 | 476 | public void setDemsize(int demsize) { |
475 | 477 | this.demsize = demsize; |
476 | 478 | } |
479 | ||
480 | public MapReader getMapReader() throws FileNotFoundException { | |
481 | if (mapReader == null) | |
482 | mapReader = new MapReader(filename); | |
483 | return mapReader; | |
484 | } | |
485 | ||
486 | public void closeMapReader() { | |
487 | if (mapReader != null) { | |
488 | Utils.closeFile(mapReader); | |
489 | mapReader = null; | |
490 | } | |
491 | } | |
477 | 492 | } |
33 | 33 | import uk.me.parabola.imgfmt.fs.FileSystem; |
34 | 34 | import uk.me.parabola.imgfmt.fs.ImgChannel; |
35 | 35 | import uk.me.parabola.imgfmt.sys.ImgFS; |
36 | import uk.me.parabola.log.Logger; | |
36 | 37 | import uk.me.parabola.mkgmap.CommandArgs; |
37 | 38 | |
38 | 39 | import static java.nio.file.StandardOpenOption.*; |
44 | 45 | * each .img file. |
45 | 46 | */ |
46 | 47 | public class GmapiBuilder implements Combiner { |
48 | private static final Logger log = Logger.getLogger(GmapiBuilder.class); | |
47 | 49 | private static final String NS = "http://www.garmin.com/xmlschemas/MapProduct/v1"; |
48 | 50 | |
49 | 51 | private final Map<String, Combiner> combinerMap; |
52 | private final Map<String, String> sourceMap; | |
50 | 53 | |
51 | 54 | private Path gmapDir; |
52 | 55 | private final Map<Integer, ProductInfo> productMap = new HashMap<>(); |
57 | 60 | |
58 | 61 | private String typFile; |
59 | 62 | |
60 | public GmapiBuilder(Map<String, Combiner> combinerMap) { | |
63 | private boolean forceWrite; | |
64 | private String mustWritePattern; | |
65 | ||
66 | ||
67 | public GmapiBuilder(Map<String, Combiner> combinerMap, Map<String, String> sourceMap) { | |
61 | 68 | this.combinerMap = combinerMap; |
69 | this.sourceMap = sourceMap; | |
62 | 70 | } |
63 | 71 | |
64 | 72 | /** |
74 | 82 | productVersion = (short) args.get("product-version", 100); |
75 | 83 | |
76 | 84 | gmapDir = Paths.get(args.getOutputDir(), String.format("%s.gmap", familyName)); |
85 | forceWrite = args.exists("gmapi"); | |
86 | ||
87 | mustWritePattern = args.get("gmapi-minimal", null); | |
77 | 88 | } |
78 | 89 | |
79 | 90 | /** |
92 | 103 | |
93 | 104 | // Unzip the image into the product tile directory. |
94 | 105 | try { |
95 | if (info.isImg()) | |
96 | unzipImg(fn, mapname, productId); | |
106 | if (info.isImg()) { | |
107 | if (forceWrite || shouldWrite(info)) | |
108 | unzipImg(fn, mapname, productId); | |
109 | } | |
97 | 110 | else if (info.getKind() == FileKind.TYP_KIND) |
98 | 111 | typFile = info.getFilename(); |
99 | 112 | |
100 | 113 | } catch (IOException e) { |
101 | 114 | throw new ExitException("Error saving gmapi data", e); |
102 | 115 | } |
116 | } | |
117 | ||
118 | private boolean shouldWrite(FileInfo info) { | |
119 | String fn = info.getFilename(); | |
120 | String source = sourceMap.get(fn); | |
121 | if (!source.equals(fn)) { | |
122 | log.diagnostic("gmapi-minimal: Writing freshly compiled file " + fn); | |
123 | return true; | |
124 | } | |
125 | if (mustWritePattern != null) { | |
126 | if (fn.matches(mustWritePattern)) { | |
127 | log.diagnostic("gmapi-minimal: Writing old file " + fn + " because it matches pattern " + mustWritePattern); | |
128 | return true; | |
129 | } | |
130 | } | |
131 | log.diagnostic("gmapi-minimal: Skipping file " + fn); | |
132 | return false; | |
103 | 133 | } |
104 | 134 | |
105 | 135 | /** |
156 | 186 | unzipImg(srcImgName, destDir); |
157 | 187 | } |
158 | 188 | |
159 | private static void unzipImg(String srcImgName, Path destDir) throws IOException { | |
189 | private void unzipImg(String srcImgName, Path destDir) throws IOException { | |
160 | 190 | FileSystem fs = ImgFS.openFs(srcImgName); |
161 | 191 | for (DirectoryEntry ent : fs.list()) { |
162 | 192 | String fullname = ent.getFullName(); |
167 | 197 | continue; |
168 | 198 | |
169 | 199 | Files.createDirectories(destDir); |
170 | copyToFile(f, destDir.resolve(name)); | |
200 | Path out = destDir.resolve(name); | |
201 | copyToFile(f, out); | |
171 | 202 | } |
172 | 203 | } |
173 | 204 | } |
154 | 154 | mdrFile.addMap(info.getHexname(), info.getCodePage()); |
155 | 155 | |
156 | 156 | String filename = info.getFilename(); |
157 | MapReader mr = null; | |
158 | 157 | try { |
159 | mr = new MapReader(filename); | |
158 | MapReader mr = info.getMapReader(); | |
160 | 159 | |
161 | 160 | AreaMaps maps = new AreaMaps(); |
162 | 161 | |
171 | 170 | addZips(mr); |
172 | 171 | } catch (FileNotFoundException e) { |
173 | 172 | throw new ExitException("Could not open " + filename + " when creating mdr file"); |
174 | } finally { | |
175 | Utils.closeFile(mr); | |
176 | 173 | } |
177 | 174 | } |
178 | 175 |
134 | 134 | for (String m : msgs) |
135 | 135 | tdb.addCopyright(m); |
136 | 136 | |
137 | MapReader mapReader = null; | |
138 | 137 | String filename = finfo.getFilename(); |
139 | 138 | try{ |
140 | mapReader = new MapReader(filename); | |
139 | MapReader mapReader = finfo.getMapReader(); | |
141 | 140 | |
142 | 141 | msgs = mapReader.getCopyrights(); |
143 | 142 | boolean found = false; |
156 | 155 | |
157 | 156 | } catch (FileNotFoundException e) { |
158 | 157 | throw new ExitException("Could not open " + filename + " when creating tdb file"); |
159 | } finally { | |
160 | Utils.closeFile(mapReader); | |
161 | 158 | } |
162 | 159 | |
163 | 160 |
103 | 103 | private volatile int programRC = 0; |
104 | 104 | |
105 | 105 | private final Map<String, Combiner> combinerMap = new HashMap<>(); |
106 | private final Map<String, String> sourceMap = new HashMap<>(); | |
106 | 107 | private boolean informationDisplayed = false; |
107 | 108 | |
108 | 109 | /** |
296 | 297 | } |
297 | 298 | }); |
298 | 299 | task.setArgs(args); |
300 | task.setSource(filename); | |
299 | 301 | futures.add(task); |
300 | 302 | } |
301 | 303 | |
617 | 619 | final Map<String, Integer> nameToHex = new HashMap<>(); |
618 | 620 | for (FilenameTask f : filenames) { |
619 | 621 | if (f.getFilename().endsWith(".img")) { |
622 | sourceMap.put(f.getFilename(), f.getSource()); | |
620 | 623 | int hex; |
621 | 624 | try { |
622 | 625 | hex = FileInfo.getFileInfo(f.getFilename() ).getHexname(); |
674 | 677 | continue; |
675 | 678 | c.onMapEnd(fileInfo); |
676 | 679 | } |
680 | fileInfo.closeMapReader(); | |
677 | 681 | } catch (FileNotFoundException e) { |
678 | 682 | throw new MapFailedException("could not open file " + e.getMessage()); |
679 | 683 | } |
705 | 709 | boolean indexOpt = args.exists("index"); |
706 | 710 | boolean gmapsuppOpt = args.exists("gmapsupp"); |
707 | 711 | boolean tdbOpt = args.exists("tdbfile"); |
708 | boolean gmapiOpt = args.exists("gmapi"); | |
712 | boolean gmapiOpt = args.exists("gmapi") || args.exists("gmapi-minimal"); | |
709 | 713 | boolean nsisOpt = args.exists("nsis"); |
710 | 714 | |
711 | for (String opt : Arrays.asList("gmapi", "nsis")) { | |
715 | if (args.exists("gmapi") && args.exists("gmapi-minimal")) { | |
716 | throw new ExitException("Options --gmapi and --gmapi-minimal are mutually exclusive"); | |
717 | } | |
718 | for (String opt : Arrays.asList("gmapi", "nsis", "gmapi-minimal")) { | |
712 | 719 | if (!createTdbFiles && args.exists(opt)) { |
713 | 720 | throw new ExitException("Options --" + opt + " and --no-tdbfiles are mutually exclusive"); |
714 | 721 | } |
728 | 735 | addCombiner("mdx", new MdxBuilder()); |
729 | 736 | } |
730 | 737 | if (gmapiOpt) { |
731 | addCombiner("gmapi", new GmapiBuilder(combinerMap)); | |
738 | addCombiner("gmapi", new GmapiBuilder(combinerMap, sourceMap)); | |
732 | 739 | } |
733 | 740 | if (nsisOpt) { |
734 | 741 | addCombiner("nsis", new NsisBuilder(combinerMap)); |
771 | 778 | private static class FilenameTask extends FutureTask<String> { |
772 | 779 | private CommandArgs args; |
773 | 780 | private String filename; |
781 | private String source; | |
774 | 782 | |
775 | 783 | private FilenameTask(Callable<String> callable) { |
776 | 784 | super(callable); |
793 | 801 | } |
794 | 802 | |
795 | 803 | public String toString() { |
796 | return filename; | |
797 | } | |
804 | return source + " -> " + filename; | |
805 | } | |
806 | ||
807 | public void setSource(String source) { | |
808 | this.source = source; | |
809 | } | |
810 | ||
811 | public String getSource() { | |
812 | return source; | |
813 | } | |
814 | ||
798 | 815 | } |
799 | 816 | } |