Reading .OV2 TomTom POI Files using Java or C#
I’m posting today some source code about the famous TomTom One .OV2 file formats. These files are the one used by TomTom to store Point of Interest information within their navigation systems. However such format is proprietary, the data specs can be found in the TomTom website (see this PDF at section 2.4). I wrote down a simple procedure that gathers record by record only the simple POI records. Actually the OV2 format is a little bit more complicated than a simple list of POIs and it can be subjected to changes and version incompatibilities. I tested it with POIs taken from my TomTom ONE XL and ti worked great, however if the OV2 files contains proprietary or special record types (not specified in TomTom data sheets) these procedures will simply stop since it is not possible for this format to distinguish between a corrupted file or non standard encoding.
I hope you’ll find it interesting.
Java version:
package readers;
import java.io.FileInputStream;
import java.io.IOException;
public class OV2RecordReader {
public static String[] readOV2Record(FileInputStream inputStream){
String[] record = null;
int b = -1;
try{
if ((b = inputStream.read())> -1) {
// if it is a simple POI record
if (b == 2) {
record = new String[3];
long total = readLong(inputStream);
double longitude = (double) readLong(inputStream) / 100000.0;
double latitude = (double) readLong(inputStream) / 100000.0;
byte[] r = new byte[(int) total - 13];
inputStream.read(r);
record[0] = new String(r);
record[0] = record[0].substring(0,record[0].length()-1);
record[1] = Double.toString(latitude);
record[2] = Double.toString(longitude);
}
//if it is a deleted record
else if(b == 0){
byte[] r = new byte[9];
inputStream.read(r);
}
//if it is a skipper record
else if(b == 1){
byte[] r = new byte[20];
inputStream.read(r);
}
else{
throw new IOException("wrong record type");
}
}
else{
return null;
}
}
catch(IOException e){
e.printStackTrace();
}
return record;
}
private static long readLong(FileInputStream is){
long res = 0;
try{
res = is.read();
res += is.read() <<8;
res += is.read() <<16;
res += is.read() <<24;
}
catch(IOException e){
e.printStackTrace();
}
return res;
}
}
C# Version
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
namespace OV2Reader
{
class Program
{
static void Main(string[] args)
{
string filename = @"C:\test.ov2";
FileStream infile = new FileStream(filename, FileMode.Open, FileAccess.Read);
while (infile.Length != infile.Position)
{
string[] data = readOV2Record(infile);
if (data != null)
{
for (int i = 0; i < data.Length; i++)
{
Console.WriteLine(data[i]);
}
}
}
Console.WriteLine("exiting....");
Console.ReadKey();
}
static string[] readOV2Record(FileStream inputStream)
{
String[] record = null;
int b = -1;
if ((b = inputStream.ReadByte()) > -1)
{
// if it is a simple POI record
if (b == 2)
{
long total = readLong(inputStream);
double longitude = (double)readLong(inputStream) / 100000.0;
double latitude = (double)readLong(inputStream) / 100000.0;
byte[] r = new byte[(int)total - 13];
inputStream.Read(r, 0, (int)total - 13);
record = new String[3];
string s = System.Text.ASCIIEncoding.ASCII.GetString(r);
record[0] = s;
record[0] = record[0].Substring(0, record[0].Length - 1);
record[1] = latitude.ToString();
record[2] = longitude.ToString();
}
//if it is a deleted record
else if (b == 0)
{
byte[] r = new byte[9];
inputStream.Read(r, 0, 9);
}
//if it is a skipper record
else if (b == 1)
{
byte[] r = new byte[20];
inputStream.Read(r, 0, 20);
}
else
{
//
return null;
}
}
else
{
return null;
}
return record;
}
private static long readLong(FileStream fis)
{
long res = 0;
res = fis.ReadByte();
res += fis.ReadByte() << 8;
res += fis.ReadByte() << 16;
res += fis.ReadByte() << 24;
return res;
}
}
}




Hello, how could I translate this code to C#??
Thanks a lot.
And thanks for your work.
@Specter
hi Specter, actually I’m not a C# expert but I would suggest you to try to use the same algorithm with small substitutions of InputStream against C# Stream object and its .read function like it is shown in those links
http://www.yoda.arachsys.com/csharp/readbinary.html
and using a bit converter to get the long from byte array like it is done here
http://msdn.microsoft.com/en-us/library/bb384066.aspx
I will try to double check it as well in the meanwhile but I’m pretty sure that will do the job
@admin
Thanks a lot for your help, I think I have translated the code to C#. The code in Visual Studio 2008 gives no errors but I need to test it with some ov2 file.
I have one last question, this function reads only a record or the whole file?
hi! actually this function translates one record but it can be iterated until the .OV file is completely parsed. yes you should try with a real OV2 file to be sure on the correctness and beware that on the internet there are a lot of OV2 files that are not complying with TomTom specifications, (if for example they have more record types) and therefore they will not considered by this function (and if no information is given for a specific record type it is impossible to know its byte size, causing the thread to terminate with an Exception)
Hello again. I tried to read an ov2 file with only 1 record inside, and it didn’t read it.
This is the ov2 file:
http://www.multiupload.com/VK74VHH0C7
I think it doesn’t read it because the first byte of this ov2 file is 01, and it’s skipped by the algorythm, or maybe I’m doing something wrong.
Thanks.
Could you help me, please?
hi! actually I used the same procedure and the result was:
SEM VTS Sevilla Carlos III CRUCE Fco. Montesinos DIR CÛrdoba CL 37.39609 -6.01247
are you using your own C# algorithm or the same java version? in the last case you can try the TestOV2Reader java class of this library (st-toolkit.sourceforge.net)
in order to get more insights on the OV2 data extraction (click here to see the class source)
Hello!! Yes, that’s what that file contents, but it seems mine doesn’t work.
I think the problem is here:
11 try{
12 if ((b = inputStream.read())> -1) {
13 // if it is a simple POI record
In C# I’m using a FileStream object to read the file, but this object doesn’t have any read method that accepts 0 parameters.
This object has two read methods. The first one is:
http://msdn.microsoft.com/en-gb/library/system.io.filestream.read.aspx
and the second is:
http://msdn.microsoft.com/en-gb/library/system.io.filestream.readbyte.aspx
And I suppose I have to use the second, am I right?
I think your guess is right you should follow the example shown in the second link, however I will set up a working C# Example for you so that you can have a clearer idea on your issue: give me a couple of days (nights to be more accurate
) and I will add it to the post!
bests
Simone
Hello again, any tips about the c# code? Will this code work if I use a BinaryReader instead of the FileStream object that I have been using??
hi sorry for the late reply
I’ve posted the correct C# translation of the java code in the main topic. Hope you’ll find the answers you were looking for! actually you needed to use both Read and ReadByte.
thanks for your interest in my blog
Simone
Hello, have you tried the C# code? It throws me a Null Reference Exception because the returned value from readOV2Record function is null.
yes of course I tried it but with a TomTom strictly compliant .OV2 file, and not the one your provided: is it that one that was throwing the exception?
Yes, it is. I tried to read it with this code but it throws that exception. I basically had the same code that you have posted in C#, but I always have the same problem, the ov2 file starts with 01, the readOV2Record function doesn’t read anything and it returns a null.
I’ve updated the main executing function in my C# code: basically the problem that you were encountering was due to the return values of the read function. The function I’ve provided is only returning dat structures for POI content, reading them one by one (you have to iterate on the FileStream to get all of them). It is only looping inside the OV2 records and if it does not contain a proper POI data field it returns simply a null pointer (to be handled and filtered when the function is called). If you keep looping until the end of the file, skipping the null records, you can retrieve all the POIs of your OV2 File. I’ve tested with the OV2 file you gave me and it works with it as well.
cheers
simone
Thanks a lot Simone, now it works.
Hello, it’s me again. Do you know how to read/write upi files for Sygic?
hi there! unfortunately I’ve never tried reading those files… do you need the C# procedure or just a standalone readeR? otherwise you could make use of POI Converter…
bests
Simone
Hello, I’m using now the POI Converter, but I’d like to know how to read/write this kind of files.
Greetings
Hi, i’m interested too in read/write upi files in java
. In version 7 of sygic, just renaming the ov2 to upi files works fine, but in the new version 8.06 of sygic doesn’t seems to works.
I’ve found this site on sygic http://www.sygic.com/partners/pois.html but not suficient
Hello, I have the structure of the upi format, but I’d need some help.
hi unfortunately I’ve never worked with such files, but I’m investigating on it! Can you give me the link of the file organisation? I think I can provide another reader for UPIs…. in the next days stay tuned!
Hello, this is the structure of the upi files:
Header File UPI
—————————–
1 byte – L – name length
L bytes – name with 3 00 at the end (i.e. null terminated)
1 byte – Z – licence length (02 if null)
Z bytes – licence name with 3 00 at the end (i.e. null terminated) (00 00 if null)
2 Bytes – notification (00 00 if null)
5 bytes – expiration date with 00 at the end (1 byte day, 1 byte month, 2 bytes year) (00 00 00 00 00 if null)
1 byte – B – name length of bmp file
B bytes – bmp file name with 3 00 at the end (i.e. null terminated)
Record – Area
—————————–
1 byte – type = 01
4 bytes – length (included type and POI records)
4 bytes – lon vertex upper/right area
4 bytes – lat vertex upper/right area
4 bytes – lon vertex bottom/left area
4 bytes – lat vertex bottom/left area
Records – POI
—————————–
1 byte – record type = 03
4 bytes – R – record length (included record type)
4 bytes – lon POI
4 bytes – lat POI
(R-13) bytes – poi description with 3 00 at the end (i.e. null terminated)