Hello

Here is a new patch. I have reproduced the actual error you see on a gmapsupp of 1.2G. This patch fixes that and also the other cases I believe.

The patch still has the debugging in. If it still fails, could you send me the output again.

There is no need, for the purpose of testing the patch, to recompile everything. Just "mkgmap --gmapsupp 63*.img" or similar should do.

Thanks,
Best wishes

..Steve
Index: src/uk/me/parabola/imgfmt/FileSystemParam.java
===================================================================
--- src/uk/me/parabola/imgfmt/FileSystemParam.java	(revision 341)
+++ src/uk/me/parabola/imgfmt/FileSystemParam.java	(revision )
@@ -1,18 +1,14 @@
 /*
- * Copyright (C) 2006 Steve Ratcliffe
+ * Copyright (C) 2006, 2011.
- * 
+ *
- *  This program is free software; you can redistribute it and/or modify
+ * This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License version 2 as
- *  published by the Free Software Foundation.
+ * it under the terms of the GNU General Public License version 3 or
+ * version 2 as published by the Free Software Foundation.
- * 
+ *
- *  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.
- * 
- * 
- * Author: Steve Ratcliffe
- * Create date: 02-Dec-2006
+ * 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.
  */
 package uk.me.parabola.imgfmt;
 
@@ -25,7 +21,7 @@
 public class FileSystemParam {
 	private String mapDescription = "Open Street Map";
 	private int blockSize = 512;
-	private int directoryStartBlock = 2;
+	private int directoryStartEntry = 2; // Always in terms of entries of 512 bytes
 	private int reservedDirectoryBlocks = 202;
 
 	public String getMapDescription() {
@@ -44,12 +40,12 @@
 		this.blockSize = blockSize;
 	}
 
-	public int getDirectoryStartBlock() {
-		return directoryStartBlock;
+	public int getDirectoryStartEntry() {
+		return directoryStartEntry;
 	}
 
-	public void setDirectoryStartBlock(int directoryStartBlock) {
-		this.directoryStartBlock = directoryStartBlock;
+	public void setDirectoryStartEntry(int directoryStartBlock) {
+		this.directoryStartEntry = directoryStartBlock;
 	}
 
 	public int getReservedDirectoryBlocks() {
Index: src/uk/me/parabola/mkgmap/combiners/FileInfo.java
===================================================================
--- src/uk/me/parabola/mkgmap/combiners/FileInfo.java	(revision 1870)
+++ src/uk/me/parabola/mkgmap/combiners/FileInfo.java	(revision )
@@ -281,15 +281,16 @@
 	}
 
 	/**
-	 * Get the number of blocks required at a particular block size.
-	 * Each subfile will need at least one block and so we go through each
+	 * Get the number header slots (512 byte entry) required to represent this file
+	 * at the given block size.
+	 * Each sub-file will need at least one block and so we go through each
 	 * separately and round up for each and return the total.
 	 *
 	 * @param blockSize The block size.
-	 * @return The number of blocks that would be needed for all the subfiles
+	 * @return The number of 512 byte header entries that are needed for all the subfiles
 	 * in this .img file.
 	 */
-	public int getNumHeaderSlots(int blockSize) {
+	public int getNumHeaderEntries(int blockSize) {
 		int totHeaderSlots = 0;
 		for (int size : fileSizes) {
 			// You use up one header slot for every 240 blocks with a minimum
@@ -301,9 +302,14 @@
 	}
 
 	/**
-	 * Get the number of blocks at the given block size.  Note that a complete block is
-	 * always used for a file.
+	 * Get the number of blocks for all the sub-files of this file at the given block size.
+	 * Note that a complete block is always used for a file.
+	 *
+	 * For TYP files and other files that do not have sub-files, then it is just the number of blocks
+	 * for the complete file.
+	 * 
 	 * @param bs The block size at which to calculate the value.
+	 * @return The number of blocks at the given size required to save all the sub-files of this file.
 	 */
 	public int getNumBlocks(int bs) {
 		int totBlocks = 0;
Index: src/uk/me/parabola/imgfmt/sys/Directory.java
===================================================================
--- src/uk/me/parabola/imgfmt/sys/Directory.java	(revision 1911)
+++ src/uk/me/parabola/imgfmt/sys/Directory.java	(revision )
@@ -44,13 +44,15 @@
 	private ImgChannel chan;
 
 	private final BlockManager headerBlockManager;
+	private final int startEntry;
 	private long startPos;
 
 	// The list of files themselves.
 	private final Map<String, DirectoryEntry> entries = new LinkedHashMap<String, DirectoryEntry>();
 
-	Directory(BlockManager headerBlockManager) {
+	Directory(BlockManager headerBlockManager, int startEntry) {
 		this.headerBlockManager = headerBlockManager;
+		this.startEntry = startEntry;
 	}
 
 	/**
@@ -140,19 +142,27 @@
 		// The first entry can't really be written until the rest of the directory is
 		// so we have to step through once to calculate the size and then again
 		// to write it out.
-		int blocks = 0;
+		int headerEntries = 0;
 		for (DirectoryEntry dir : entries.values()) {
 			Dirent ent = (Dirent) dir;
 			log.debug("ent size", ent.getSize());
 			int n = ent.numberHeaderBlocks();
-			blocks += n;
+			headerEntries += n;
 		}
+		System.out.println("dir: header blocks(slots) " + headerEntries);
 
 		// Save the current position
 		long dirPosition = chan.position();
+
 		int blockSize = headerBlockManager.getBlockSize();
 
-		int forHeader = (blocks + Dirent.ENTRY_SIZE - 1)/Dirent.ENTRY_SIZE;
+		// Get the number of blocks required for the directory entry representing the header.
+		// First calculate the number of blocks required for the directory entries.
+		int headerBlocks = (int) Math.ceil((startEntry + 1.0 + headerEntries) * Dirent.ENTRY_SIZE / blockSize);
+		System.out.println("dir: headerBlocks " + headerBlocks);
+		int forHeader = (headerBlocks + Dirent.ENTRY_SIZE - 1)/Dirent.ENTRY_SIZE;
+
+		System.out.println("header blocks needed " + forHeader);
 		log.debug("header blocks needed", forHeader);
 
 		// There is nothing really wrong with larger values (perhaps, I don't
@@ -162,7 +172,7 @@
 		// Write the blocks that will will contain the header blocks.
 		chan.position(dirPosition + (long) forHeader * Dirent.ENTRY_SIZE);
 
-		for (DirectoryEntry dir : entries.values()) {
+		for (DirectoryEntry dir : this.entries.values()) {
 			Dirent ent = (Dirent) dir;
 
 			if (!ent.isSpecial()) {
@@ -173,6 +183,7 @@
 		}
 
 		long end = (long) blockSize * headerBlockManager.getMaxBlock();
+		System.out.println("dir: end slot " + end/512);
 		ByteBuffer buf = ByteBuffer.allocate((int) (end - chan.position()));
 		for (int i = 0; i < buf.capacity(); i++)
 			buf.put((byte) 0);
@@ -181,7 +192,7 @@
 
 		// Now go back and write in the directory entry for the header.
 		chan.position(dirPosition);
-		Dirent ent = (Dirent) entries.values().iterator().next();
+		Dirent ent = (Dirent) this.entries.values().iterator().next();
 		log.debug("ent header size", ent.getSize());
 		ent.sync(chan);
 
Index: src/uk/me/parabola/imgfmt/sys/ImgFS.java
===================================================================
--- src/uk/me/parabola/imgfmt/sys/ImgFS.java	(revision 1751)
+++ src/uk/me/parabola/imgfmt/sys/ImgFS.java	(revision )
@@ -58,7 +58,9 @@
 
 	// The filesystem is responsible for allocating blocks
 	private BlockManager fileBlockManager;
-	private static final long BASIC_BLOCK_SIZE = 512L;
+
+	// The header entries are written in 512 blocks, regardless of the block size of the file itself.
+	private static final long ENTRY_BLOCK_SIZE = 512L;
 	private BlockManager headerBlockManager;
 
 	private byte xorByte;	// if non-zero, all bytes are XORed with this
@@ -242,6 +244,8 @@
 			log.debug("could not sync filesystem");
 		} finally {
 			try {
+				if (fileBlockManager != null)
+				System.out.println("file size in blocks " + file.size()/fileBlockManager.getBlockSize());
 				file.close();
 			} catch (IOException e) {
 				log.warn("Could not close file");
@@ -268,7 +272,7 @@
 		// to the header and directory, but to create one normally would involve
 		// it already existing, so it is created by hand.
 		try {
-			directory = new Directory(headerBlockManager);
+			directory = new Directory(headerBlockManager, params.getDirectoryStartEntry());
 
 			Dirent ent = directory.create(DIRECTORY_FILE_NAME, headerBlockManager);
 			ent.setSpecial(true);
@@ -313,8 +317,8 @@
 		BlockManager headerBlockManager = new BlockManager(params.getBlockSize(), 0);
 		headerBlockManager.setMaxBlock(params.getReservedDirectoryBlocks());
 
-		directory = new Directory(headerBlockManager);
-		directory.setStartPos(params.getDirectoryStartBlock() * BASIC_BLOCK_SIZE);
+		directory = new Directory(headerBlockManager, params.getDirectoryStartEntry());
+		directory.setStartPos(params.getDirectoryStartEntry() * ENTRY_BLOCK_SIZE);
 
 		Dirent ent = directory.create(DIRECTORY_FILE_NAME, headerBlockManager);
 		FileNode f = new FileNode(chan, ent, "r");
Index: src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java
===================================================================
--- src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java	(revision 1885)
+++ src/uk/me/parabola/mkgmap/combiners/GmapsuppBuilder.java	(revision )
@@ -66,7 +66,7 @@
 	 * The number of block numbers that will fit into one entry block
 	 */
 	private static final int ENTRY_SIZE = 240;
-	private static final int DIRECTORY_OFFSET_BLOCK = 2;
+	private static final int DIRECTORY_OFFSET_ENTRY = 2;
 
 	private final Map<String, FileInfo> files = new LinkedHashMap<String, FileInfo>();
 
@@ -350,15 +350,12 @@
 		FileSystemParam params = new FileSystemParam();
 		params.setBlockSize(blockSize);
 		params.setMapDescription(overallDescription);
-		params.setDirectoryStartBlock(DIRECTORY_OFFSET_BLOCK);
+		params.setDirectoryStartEntry(DIRECTORY_OFFSET_ENTRY);
 
-		int reserved = DIRECTORY_OFFSET_BLOCK + bi.reserveBlocks + bi.headerSlots;
-		log.info("bs of", blockSize, "reserving", reserved);
+		int reserveBlocks = (int) Math.ceil(bi.reserveEntries * 512.0 / blockSize);
+		System.out.println("bs: " + blockSize + " reserve blocks " + reserveBlocks);
+		params.setReservedDirectoryBlocks(reserveBlocks);
 
-		int reserve = (int) Math.ceil(reserved * 512.0 / blockSize);
-		params.setReservedDirectoryBlocks(reserve);
-		log.info("reserved", reserve);
-
 		FileSystem outfs = ImgFS.createFs(Utils.joinPath(outputDir, GMAPSUPP), params);
 		mpsFile = createMpsFile(outfs);
 		mpsFile.setMapsetName(mapsetName);
@@ -432,25 +429,33 @@
 
 		for (int bs : ints) {
 			int totBlocks = 0;
-			int totHeaderSlots = 0;
+			int totHeaderEntries = 0;
 			for (FileInfo info : files.values()) {
 				totBlocks += info.getNumBlocks(bs);
 				// Each file will take up at least one directory block.
 				// Each directory block can hold 480 block-references
-				int slots = info.getNumHeaderSlots(bs);
+				int slots = info.getNumHeaderEntries(bs);
 				log.info("adding", slots, "slots for", info.getFilename());
-				totHeaderSlots += slots;
+				totHeaderEntries += slots;
 			}
 
-			totHeaderSlots += 2;
-			int totHeaderBlocks = totHeaderSlots * 512 / bs;
+			// Estimate the number of blocks needed for the MPS file
+			int mpsSize = files.size() * 80 + 100;
+			int mpsBlocks = (mpsSize + (bs - 1)) / bs;
+			int mpsSlots = (mpsBlocks + ENTRY_SIZE-1) / ENTRY_SIZE;
 
-			log.info("total blocks for", bs, "is", totHeaderBlocks, "based on slots=", totHeaderSlots);
+			totBlocks += mpsBlocks;
+			totHeaderEntries += mpsSlots;
 
-			if (totBlocks < 0xfffe && totHeaderBlocks <= ENTRY_SIZE) {
-				// Add one for the MPS file
-				totHeaderSlots += 1;
-				return new BlockInfo(bs, totHeaderSlots, totHeaderSlots / bs + 1);
+			totHeaderEntries += 2;
+			int totHeaderBlocks = totHeaderEntries * 512 / bs;
+
+			log.info("total blocks for", bs, "is", totHeaderBlocks, "based on slots=", totHeaderEntries);
+
+			System.out.printf("bs %d: tot blocks %d, tot header blocks %d\n", bs, totBlocks, totHeaderBlocks);
+			int reserveEntries = (int) Math.ceil(DIRECTORY_OFFSET_ENTRY + 1 + totHeaderEntries);
+			if (totBlocks + reserveEntries < 0xfffe && totHeaderBlocks <= ENTRY_SIZE) {
+				return new BlockInfo(bs, totHeaderEntries, reserveEntries);
 			}
 		}
 
@@ -463,12 +468,12 @@
 	private static class BlockInfo {
 		private final int blockSize;
 		private final int headerSlots;
-		private final int reserveBlocks;
+		private final int reserveEntries;
 
-		private BlockInfo(int blockSize, int headerSlots, int reserveBlocks) {
+		private BlockInfo(int blockSize, int headerSlots, int reserveEntries) {
 			this.blockSize = blockSize;
 			this.headerSlots = headerSlots;
-			this.reserveBlocks = reserveBlocks;
+			this.reserveEntries = reserveEntries;
 		}
 	}
 }
Index: src/uk/me/parabola/imgfmt/sys/ImgHeader.java
===================================================================
--- src/uk/me/parabola/imgfmt/sys/ImgHeader.java	(revision 1919)
+++ src/uk/me/parabola/imgfmt/sys/ImgHeader.java	(revision )
@@ -114,6 +114,7 @@
 	 * @param params File system parameters.
 	 */
 	void createHeader(FileSystemParam params) {
+		System.out.println("create header " + params.getBlockSize());
 		this.fsParams = params;
 
 		header.put(OFF_XOR, (byte) 0);
@@ -146,7 +147,7 @@
 
 		// Actually this may not be the directory start block, I am guessing -
 		// always assume it is 2 anyway.
-		header.put(OFF_DIRECTORY_START_BLOCK, (byte) fsParams.getDirectoryStartBlock());
+		header.put(OFF_DIRECTORY_START_BLOCK, (byte) fsParams.getDirectoryStartEntry());
 
 		// This sectors, head, cylinders stuff appears to be used by mapsource
 		// and they have to be larger than the actual size of the map.  It
@@ -193,7 +194,7 @@
 		header.putInt(OFF_NUMBER_OF_SECTORS, endBlock+1);
 		log.info("number of blocks " + blocks);
 
-		setDirectoryStartBlock(params.getDirectoryStartBlock());
+		setDirectoryStartEntry(params.getDirectoryStartEntry());
 
 		// Set the times.
 		Date date = new Date();
@@ -216,7 +217,7 @@
 
 		fsParams = new FileSystemParam();
 		fsParams.setBlockSize(1 << (exp1 + exp2));
-		fsParams.setDirectoryStartBlock(header.get(OFF_DIRECTORY_START_BLOCK));
+		fsParams.setDirectoryStartEntry(header.get(OFF_DIRECTORY_START_BLOCK));
 
 		StringBuffer sb = new StringBuffer();
 		sb.append(Utils.bytesToString(buf, OFF_MAP_DESCRIPTION, LEN_MAP_DESCRIPTION));
@@ -245,7 +246,7 @@
 		header.rewind();
 		file.position(0);
 		file.write(header);
-		file.position(fsParams.getDirectoryStartBlock() * 512L);
+		file.position(fsParams.getDirectoryStartEntry() * 512L);
 	}
 
 	/**
@@ -312,9 +313,9 @@
 		return (byte) (y - 1900);
 	}
 
-	protected void setDirectoryStartBlock(int directoryStartBlock) {
-		header.put(OFF_DIRECTORY_START_BLOCK, (byte) directoryStartBlock);
-		fsParams.setDirectoryStartBlock(directoryStartBlock);
+	protected void setDirectoryStartEntry(int directoryStartEntry) {
+		header.put(OFF_DIRECTORY_START_BLOCK, (byte) directoryStartEntry);
+		fsParams.setDirectoryStartEntry(directoryStartEntry);
 	}
 
 	protected void setCreationTime(Date date) {
_______________________________________________
mkgmap-dev mailing list
[email protected]
http://www.mkgmap.org.uk/mailman/listinfo/mkgmap-dev

Reply via email to