1f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project/* Copyright (C) 2003 Vladimir Roubtsov. All rights reserved.
2f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *
3f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * This program and the accompanying materials are made available under
4f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * the terms of the Common Public License v1.0 which accompanies this distribution,
5f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * and is available at http://www.eclipse.org/legal/cpl-v10.html
6f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project *
7f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * $Id: DataFactory.java,v 1.1.1.1.2.3 2004/07/16 23:32:29 vlad_r Exp $
8f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project */
9f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectpackage com.vladium.emma.data;
10f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
11f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.BufferedInputStream;
12f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.BufferedOutputStream;
13f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.DataInput;
14f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.DataInputStream;
15f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.DataOutput;
16f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.DataOutputStream;
17f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.File;
18f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.FileDescriptor;
19f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.FileInputStream;
20f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.FileOutputStream;
21f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.IOException;
22f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.ObjectInputStream;
23f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.ObjectOutputStream;
24f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.OutputStream;
25f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.io.RandomAccessFile;
26f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.net.URL;
27f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport java.net.URLConnection;
28f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
29f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.logging.Logger;
30f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.util.asserts.$assert;
31f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectimport com.vladium.emma.IAppConstants;
32f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
33f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project// ----------------------------------------------------------------------------
34f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project/**
35f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project * @author Vlad Roubtsov, (C) 2003
36f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project */
37f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectpublic
38f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Projectabstract class DataFactory
39f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project{
40f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // public: ................................................................
41f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
42f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // TODO: file compaction
43f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // TODO: file locking
44f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
45f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // TODO: what's the best place for these?
46f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
47f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static final byte TYPE_METADATA          = 0x0; // must start with 0
48f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static final byte TYPE_COVERAGEDATA      = 0x1; // must be consistent with mergeload()
49f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
50f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
51f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static IMergeable [] load (final File file)
52f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
53f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
54f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (file == null) throw new IllegalArgumentException ("null input: file");
55f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
56f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return mergeload (file);
57f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
58f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
59f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static void persist (final IMetaData data, final File file, final boolean merge)
60f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
61f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
62f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (data == null) throw new IllegalArgumentException ("null input: data");
63f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (file == null) throw new IllegalArgumentException ("null input: file");
64f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
65f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (! merge && file.exists ())
66f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
67f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (! file.delete ())
68f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                throw new IOException ("could not delete file [" + file.getAbsolutePath () + "]");
69f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
70f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
71f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        persist (data, TYPE_METADATA, file);
72f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
73f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
74f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static void persist (final ICoverageData data, final File file, final boolean merge)
75f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
76f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
77f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (data == null) throw new IllegalArgumentException ("null input: data");
78f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (file == null) throw new IllegalArgumentException ("null input: file");
79f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
80f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (! merge && file.exists ())
81f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
82f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (! file.delete ())
83f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                throw new IOException ("could not delete file [" + file.getAbsolutePath () + "]");
84f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
85f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
86f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        persist (data, TYPE_COVERAGEDATA, file);
87f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
88f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
89f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static void persist (final ISessionData data, final File file, final boolean merge)
90f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
91f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
92f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (data == null) throw new IllegalArgumentException ("null input: data");
93f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (file == null) throw new IllegalArgumentException ("null input: file");
94f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
95f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (! merge && file.exists ())
96f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
97f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (! file.delete ())
98f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                throw new IOException ("could not delete file [" + file.getAbsolutePath () + "]");
99f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
100f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
101f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        persist (data.getMetaData (), TYPE_METADATA, file);
102f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        persist (data.getCoverageData (), TYPE_COVERAGEDATA, file);
103f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
104f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
105f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
106f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static IMetaData newMetaData (final CoverageOptions options)
107f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
108f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return new MetaData (options);
109f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
110f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
111f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static ICoverageData newCoverageData ()
112f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
113f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return new CoverageData ();
114f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
115f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
116f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static IMetaData readMetaData (final URL url)
117f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException, ClassNotFoundException
118f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
119f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        ObjectInputStream oin = null;
120f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
121f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        try
122f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
123f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            oin = new ObjectInputStream (new BufferedInputStream (url.openStream (), 32 * 1024));
124f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
125f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return (IMetaData) oin.readObject ();
126f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
127f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        finally
128f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
129f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (oin != null) try { oin.close (); } catch (Exception ignore) {}
130f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
131f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
132f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
133f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static void writeMetaData (final IMetaData data, final OutputStream out)
134f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
135f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
136f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        ObjectOutputStream oout = new ObjectOutputStream (out);
137f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        oout.writeObject (data);
138f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
139f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
140f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static void writeMetaData (final IMetaData data, final URL url)
141f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
142f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
143f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final URLConnection connection = url.openConnection ();
144f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        connection.setDoOutput (true);
145f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
146f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        OutputStream out = null;
147f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        try
148f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
149f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            out = connection.getOutputStream ();
150f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
151f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            writeMetaData (data, out);
152f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            out.flush ();
153f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
154f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        finally
155f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
156f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (out != null) try { out.close (); } catch (Exception ignore) {}
157f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
158f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
159f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
160f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static ICoverageData readCoverageData (final URL url)
161f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException, ClassNotFoundException
162f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
163f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        ObjectInputStream oin = null;
164f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
165f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        try
166f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
167f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            oin = new ObjectInputStream (new BufferedInputStream (url.openStream (), 32 * 1024));
168f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
169f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return (ICoverageData) oin.readObject ();
170f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
171f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        finally
172f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
173f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (oin != null) try { oin.close (); } catch (Exception ignore) {}
174f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
175f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
176f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
177f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static void writeCoverageData (final ICoverageData data, final OutputStream out)
178f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
179f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
180f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // TODO: prevent concurrent modification problems here
181f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
182f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        ObjectOutputStream oout = new ObjectOutputStream (out);
183f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        oout.writeObject (data);
184f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
185f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
186f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static int [] readIntArray (final DataInput in)
187f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
188f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
189f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final int length = in.readInt ();
190f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (length == NULL_ARRAY_LENGTH)
191f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return null;
192f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
193f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
194f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final int [] result = new int [length];
195f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
196f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // read array in reverse order:
197f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            for (int i = length; -- i >= 0; )
198f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
199f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                result [i] = in.readInt ();
200f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
201f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
202f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return result;
203f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
204f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
205f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
206f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static boolean [] readBooleanArray (final DataInput in)
207f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
208f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
209f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final int length = in.readInt ();
210f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (length == NULL_ARRAY_LENGTH)
211f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return null;
212f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
213f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
214f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final boolean [] result = new boolean [length];
215f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
216f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // read array in reverse order:
217f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            for (int i = length; -- i >= 0; )
218f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
219f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                result [i] = in.readBoolean ();
220f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
221f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
222f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return result;
223f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
224f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
225f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
226f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static void writeIntArray (final int [] array, final DataOutput out)
227f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
228f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
229f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (array == null)
230f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            out.writeInt (NULL_ARRAY_LENGTH);
231f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
232f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
233f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final int length = array.length;
234f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            out.writeInt (length);
235f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
236f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // write array in reverse order:
237f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            for (int i = length; -- i >= 0; )
238f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
239f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                out.writeInt (array [i]);
240f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
241f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
242f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
243f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
244f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    public static void writeBooleanArray (final boolean [] array, final DataOutput out)
245f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
246f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
247f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (array == null)
248f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            out.writeInt (NULL_ARRAY_LENGTH);
249f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
250f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
251f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final int length = array.length;
252f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            out.writeInt (length);
253f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
254f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // write array in reverse order:
255f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            for (int i = length; -- i >= 0; )
256f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
257f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                out.writeBoolean (array [i]);
258f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
259f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
260f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
261f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
262f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // protected: .............................................................
263f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
264f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // package: ...............................................................
265f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
266f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    // private: ...............................................................
267f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
268f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
269f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final class UCFileInputStream extends FileInputStream
270f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
271f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        public void close ()
272f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
273f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
274f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
275f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        UCFileInputStream (final FileDescriptor fd)
276f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
277f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            super (fd);
278f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
279f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if ($assert.ENABLED) $assert.ASSERT (fd.valid (), "UCFileInputStream.<init>: FD invalid");
280f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
281f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
282f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    } // end of nested class
283f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
284f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final class UCFileOutputStream extends FileOutputStream
285f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
286f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        public void close ()
287f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
288f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
289f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
290f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        UCFileOutputStream (final FileDescriptor fd)
291f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
292f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            super (fd);
293f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
294f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if ($assert.ENABLED) $assert.ASSERT (fd.valid (), "UCFileOutputStream.<init>: FD invalid");
295f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
296f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
297f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    } // end of nested class
298f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
299f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
300f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final class RandomAccessFileInputStream extends BufferedInputStream
301f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
302f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        public final int read () throws IOException
303f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
304f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final int rc = super.read ();
305f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (rc >= 0) ++ m_count;
306f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
307f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return rc;
308f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
309f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
310f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        public final int read (final byte [] b, final int off, final int len)
311f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throws IOException
312f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
313f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final int rc = super.read (b, off, len);
314f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (rc >= 0) m_count += rc;
315f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
316f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return rc;
317f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
318f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
319f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        public final int read (final byte [] b) throws IOException
320f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
321f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            final int rc = super.read (b);
322f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (rc >= 0) m_count += rc;
323f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
324f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return rc;
325f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
326f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
327f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        public void close ()
328f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
329f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
330f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
331f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
332f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        RandomAccessFileInputStream (final RandomAccessFile raf, final int bufSize)
333f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throws IOException
334f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
335f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            super (new UCFileInputStream (raf.getFD ()), bufSize);
336f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
337f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
338f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final long getCount ()
339f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
340f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return m_count;
341f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
342f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
343f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private long m_count;
344f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
345f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    } // end of nested class
346f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
347f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final class RandomAccessFileOutputStream extends BufferedOutputStream
348f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
349f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        public final void write (final byte [] b, final int off, final int len) throws IOException
350f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
351f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            super.write (b, off, len);
352f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_count += len;
353f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
354f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
355f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        public final void write (final byte [] b) throws IOException
356f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
357f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            super.write (b);
358f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            m_count += b.length;
359f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
360f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
361f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        public final void write (final int b) throws IOException
362f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
363f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            super.write (b);
364f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            ++ m_count;
365f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
366f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
367f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        public void close ()
368f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
369f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
370f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
371f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
372f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        RandomAccessFileOutputStream (final RandomAccessFile raf, final int bufSize)
373f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throws IOException
374f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
375f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            super (new UCFileOutputStream (raf.getFD ()), bufSize);
376f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
377f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
378f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final long getCount ()
379f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
380f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            return m_count;
381f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
382f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
383f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        private long m_count;
384f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
385f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    } // end of nested class
386f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
387f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
388f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private DataFactory () {} // prevent subclassing
389f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
390f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /*
391f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * input checked by the caller
392f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
393f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static IMergeable [] mergeload (final File file)
394f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
395f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
396f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final Logger log = Logger.getLogger ();
397f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final boolean trace1 = log.atTRACE1 ();
398f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final boolean trace2 = log.atTRACE2 ();
399f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final String method = "mergeload";
400f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
401f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        long start = 0, end;
402f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
403f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (trace1) start = System.currentTimeMillis ();
404f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
405f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final IMergeable [] result = new IMergeable [2];
406f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
407f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (! file.exists ())
408f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
409f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            throw new IOException ("input file does not exist: [" + file.getAbsolutePath () +  "]");
410f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
411f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        else
412f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
413f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            RandomAccessFile raf = null;
414f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            try
415f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
416f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                raf = new RandomAccessFile (file, "r");
417f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
418f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // 'file' is a valid existing file, but it could still be of 0 length or otherwise corrupt:
419f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final long length = raf.length ();
420f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (trace1) log.trace1 (method, "[" + file + "]: file length = " + length);
421f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
422f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (length < FILE_HEADER_LENGTH)
423f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
424f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    throw new IOException ("file [" + file.getAbsolutePath () + "] is corrupt or was not created by " + IAppConstants.APP_NAME);
425f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
426f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                else
427f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
428f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // TODO: data version checks parallel to persist()
429f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
430f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (length > FILE_HEADER_LENGTH) // return {null, null} in case of equality
431f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
432f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        raf.seek (FILE_HEADER_LENGTH);
433f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
434f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        // [assertion: file length > FILE_HEADER_LENGTH]
435f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
436f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        // read entries until the first corrupt entry or the end of the file:
437f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
438f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        long position = FILE_HEADER_LENGTH;
439f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        long entryLength;
440f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
441f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        long entrystart = 0;
442f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
443f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        while (true)
444f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        {
445f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            if (trace2) log.trace2 (method, "[" + file + "]: position " + raf.getFilePointer ());
446f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            if (position >= length) break;
447f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
448f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            entryLength = raf.readLong ();
449f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
450f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            if ((entryLength <= 0) || (position + entryLength + ENTRY_HEADER_LENGTH > length))
451f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                break;
452f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            else
453f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            {
454f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                final byte type = raf.readByte ();
455f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                if ((type < 0) || (type >= result.length))
456f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    break;
457f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
458f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                if (trace2) log.trace2 (method, "[" + file + "]: found valid entry of size " + entryLength + " and type " + type);
459f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                {
460f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    if (trace2) entrystart = System.currentTimeMillis ();
461f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    final IMergeable data = readEntry (raf, type, entryLength);
462f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    if (trace2) log.trace2 (method, "entry read in " + (System.currentTimeMillis () - entrystart) + " ms");
463f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
464f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    final IMergeable current = result [type];
465f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
466f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    if (current == null)
467f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                        result [type] = data;
468f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    else
469f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                        result [type] = current.merge (data); // note: later entries overrides earlier entries
470f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                }
471f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
472f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                position += entryLength + ENTRY_HEADER_LENGTH;
473f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
474f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                if ($assert.ENABLED) $assert.ASSERT (raf.getFD ().valid (), "FD invalid");
475f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                raf.seek (position);
476f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            }
477f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        }
478f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
479f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
480f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
481f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            finally
482f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
483f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (raf != null) try { raf.close (); } catch (Throwable ignore) {}
484f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                raf = null;
485f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
486f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
487f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
488f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (trace1)
489f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
490f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            end = System.currentTimeMillis ();
491f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
492f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.trace1 (method, "[" + file + "]: file processed in " + (end - start) + " ms");
493f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
494f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
495f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return result;
496f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
497f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
498f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
499f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /*
500f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * input checked by the caller
501f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
502f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static void persist (final IMergeable data, final byte type, final File file)
503f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
504f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
505f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final Logger log = Logger.getLogger ();
506f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final boolean trace1 = log.atTRACE1 ();
507f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final boolean trace2 = log.atTRACE2 ();
508f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final String method = "persist";
509f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
510f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        long start = 0, end;
511f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
512f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (trace1) start = System.currentTimeMillis ();
513f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
514f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // TODO: 1.4 adds some interesting RAF open mode options as well
515f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // TODO: will this benefit from extra buffering?
516f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
517f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // TODO: data version checks
518f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
519f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        RandomAccessFile raf = null;
520f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        try
521f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
522f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            boolean overwrite = false;
523f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            boolean truncate = false;
524f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
525f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (file.exists ())
526f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
527f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // 'file' exists:
528f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
529f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (! file.isFile ()) throw new IOException ("can persist in normal files only: " + file.getAbsolutePath ());
530f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
531f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                raf = new RandomAccessFile (file, "rw");
532f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
533f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // 'file' is a valid existing file, but it could still be of 0 length or otherwise corrupt:
534f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final long length = raf.length ();
535f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (trace1) log.trace1 (method, "[" + file + "]: existing file length = " + length);
536f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
537f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
538f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (length < 4)
539f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
540f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    overwrite = true;
541f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    truncate = (length > 0);
542f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
543f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                else
544f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                {
545f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // [assertion: file length >= 4]
546f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
547f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    // check header info before reading further:
548f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    final int magic = raf.readInt ();
549f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (magic != MAGIC)
550f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        throw new IOException ("cannot overwrite [" + file.getAbsolutePath () + "]: not created by " + IAppConstants.APP_NAME);
551f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
552f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    if (length < FILE_HEADER_LENGTH)
553f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
554f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        // it's our file, but the header is corrupt: overwrite
555f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        overwrite = true;
556f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        truncate = true;
557f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
558f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    else
559f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    {
560f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        // [assertion: file length >= FILE_HEADER_LENGTH]
561f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
562f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//                        if (! append)
563f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//                        {
564f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//                            // overwrite any existing data:
565f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//
566f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//                            raf.seek (FILE_HEADER_LENGTH);
567f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//                            writeEntry (raf, FILE_HEADER_LENGTH, data, type);
568f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//                        }
569f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//                        else
570f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        {
571f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            // check data format version info:
572f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            final long dataVersion = raf.readLong ();
573f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
574f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            if (dataVersion != IAppConstants.DATA_FORMAT_VERSION)
575f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            {
576f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                // read app version info for the error message:
577f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
578f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                int major = 0, minor = 0, build = 0;
579f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                boolean gotAppVersion = false;
580f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                try
581f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                {
582f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    major = raf.readInt ();
583f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    minor = raf.readInt ();
584f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    build = raf.readInt ();
585f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
586f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    gotAppVersion = true;
587f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                }
588f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                catch (Throwable ignore) {}
589f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
590f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                // TODO: error code here?
591f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                if (gotAppVersion)
592f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                {
593f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    throw new IOException ("cannot merge new data into [" + file.getAbsolutePath () + "]: created by another " + IAppConstants.APP_NAME + " version [" + makeAppVersion (major, minor, build) + "]");
594f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                }
595f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                else
596f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                {
597f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    throw new IOException ("cannot merge new data into [" + file.getAbsolutePath () + "]: created by another " + IAppConstants.APP_NAME + " version");
598f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                }
599f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            }
600f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            else
601f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            {
602f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                // [assertion: file header is valid and data format version is consistent]
603f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
604f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                raf.seek (FILE_HEADER_LENGTH);
605f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
606f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                if (length == FILE_HEADER_LENGTH)
607f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                {
608f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    // no previous data entries: append 'data'
609f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
610f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    writeEntry (log, raf, FILE_HEADER_LENGTH, data, type);
611f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                }
612f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                else
613f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                {
614f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    // [assertion: file length > FILE_HEADER_LENGTH]
615f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
616f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    // write 'data' starting with the first corrupt entry or the end of the file:
617f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
618f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    long position = FILE_HEADER_LENGTH;
619f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    long entryLength;
620f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
621f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    while (true)
622f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    {
623f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                        if (trace2) log.trace2 (method, "[" + file + "]: position " + raf.getFilePointer ());
624f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                        if (position >= length) break;
625f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
626f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                        entryLength = raf.readLong ();
627f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
628f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                        if ((entryLength <= 0) || (position + entryLength + ENTRY_HEADER_LENGTH > length))
629f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                            break;
630f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                        else
631f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                        {
632f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                            if (trace2) log.trace2 (method, "[" + file + "]: found valid entry of size " + entryLength);
633f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
634f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                            position += entryLength + ENTRY_HEADER_LENGTH;
635f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                            raf.seek (position);
636f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                        }
637f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    }
638f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
639f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    if (trace2) log.trace2 (method, "[" + file + "]: adding entry at position " + position);
640f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                    writeEntry (log, raf, position, data, type);
641f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                                }
642f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                            }
643f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                        }
644f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    }
645f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                }
646f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
647f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            else
648f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
649f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // 'file' does not exist:
650f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
651f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (trace1) log.trace1 (method, "[" + file + "]: creating a new file");
652f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
653f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                final File parent = file.getParentFile ();
654f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (parent != null) parent.mkdirs ();
655f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
656f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                raf = new RandomAccessFile (file, "rw");
657f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
658f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                overwrite = true;
659f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
660f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
661f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
662f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (overwrite)
663f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
664f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                // persist starting from 0 offset:
665f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
666f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if ($assert.ENABLED) $assert.ASSERT (raf != null, "raf = null");
667f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
668f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if (truncate) raf.seek (0);
669f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                writeFileHeader (raf);
670f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                if ($assert.ENABLED) $assert.ASSERT (raf.getFilePointer () == FILE_HEADER_LENGTH, "invalid header length: " + raf.getFilePointer ());
671f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
672f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                writeEntry (log, raf, FILE_HEADER_LENGTH, data, type);
673f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            }
674f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
675f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        finally
676f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
677f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            if (raf != null) try { raf.close (); } catch (Throwable ignore) {}
678f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            raf = null;
679f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
680f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
681f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (trace1)
682f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
683f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            end = System.currentTimeMillis ();
684f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
685f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            log.trace1 (method, "[" + file + "]: file processed in " + (end - start) + " ms");
686f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
687f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
688f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
689f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static void writeFileHeader (final DataOutput out)
690f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
691f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
692f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        out.writeInt (MAGIC);
693f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
694f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        out.writeLong (IAppConstants.DATA_FORMAT_VERSION);
695f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
696f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        out.writeInt (IAppConstants.APP_MAJOR_VERSION);
697f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        out.writeInt (IAppConstants.APP_MINOR_VERSION);
698f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        out.writeInt (IAppConstants.APP_BUILD_ID);
699f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
700f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
701f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static void writeEntryHeader (final DataOutput out, final byte type)
702f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
703f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
704f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        out.writeLong (UNKNOWN); // length placeholder
705f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        out.writeByte (type);
706f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
707f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
708f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static void writeEntry (final Logger log, final RandomAccessFile raf, final long marker, final IMergeable data, final byte type)
709f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
710f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
711f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // [unfinished] entry header:
712f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        writeEntryHeader (raf, type);
713f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
714f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // serialize 'data' starting with the current raf position:
715f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        RandomAccessFileOutputStream rafout = new RandomAccessFileOutputStream (raf, IO_BUF_SIZE); // note: no new file descriptors created here
716f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
717f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//            ObjectOutputStream oout = new ObjectOutputStream (rafout);
718f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//
719f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//            oout.writeObject (data);
720f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//            oout.flush ();
721f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//            oout = null;
722f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
723f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            DataOutputStream dout = new DataOutputStream (rafout);
724f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            switch (type)
725f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
726f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                case TYPE_METADATA: MetaData.writeExternal ((MetaData) data, dout);
727f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    break;
728f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
729f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                default /* TYPE_COVERAGEDATA */: CoverageData.writeExternal ((CoverageData) data, dout);
730f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    break;
731f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
732f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            } // end of switch
733f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            dout.flush ();
734f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            dout = null;
735f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
736f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            // truncate:
737f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            raf.setLength (raf.getFilePointer ());
738f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
739f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
740f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        // transact this entry [finish the header]:
741f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        raf.seek (marker);
742f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        raf.writeLong (rafout.getCount ());
743f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (DO_FSYNC) raf.getFD ().sync ();
744f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
745f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if (log.atTRACE2 ()) log.trace2 ("writeEntry", "entry [" + data.getClass ().getName () + "] length: " + rafout.getCount ());
746f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
747f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
748f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static IMergeable readEntry (final RandomAccessFile raf, final byte type, final long entryLength)
749f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        throws IOException
750f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
751f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final Object data;
752f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
753f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        RandomAccessFileInputStream rafin = new RandomAccessFileInputStream (raf, IO_BUF_SIZE); // note: no new file descriptors created here
754f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        {
755f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//           ObjectInputStream oin = new ObjectInputStream (rafin);
756f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//
757f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//            try
758f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//            {
759f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//                data = oin.readObject ();
760f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//            }
761f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//            catch (ClassNotFoundException cnfe)
762f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//            {
763f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//                // TODO: EMMA exception here
764f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//                throw new IOException ("could not read data entry: " + cnfe.toString ());
765f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project//            }
766f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
767f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            DataInputStream din = new DataInputStream (rafin);
768f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            switch (type)
769f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            {
770f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                case TYPE_METADATA: data = MetaData.readExternal (din);
771f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    break;
772f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
773f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                default /* TYPE_COVERAGEDATA */: data = CoverageData.readExternal (din);
774f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project                    break;
775f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
776f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project            } // end of switch
777f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        }
778f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
779f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        if ($assert.ENABLED) $assert.ASSERT (rafin.getCount () == entryLength, "entry length mismatch: " + rafin.getCount () + " != " + entryLength);
780f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
781f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return (IMergeable) data;
782f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
783f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
784f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
785f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    /*
786f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * This is cloned from EMMAProperties by design, to eliminate a CONSTANT_Class_info
787f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     * dependency between this and EMMAProperties classes.
788f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project     */
789f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static String makeAppVersion (final int major, final int minor, final int build)
790f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    {
791f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        final StringBuffer buf = new StringBuffer ();
792f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
793f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        buf.append (major);
794f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        buf.append ('.');
795f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        buf.append (minor);
796f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        buf.append ('.');
797f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        buf.append (build);
798f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
799f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project        return buf.toString ();
800f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    }
801f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
802f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
803f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final int NULL_ARRAY_LENGTH = -1;
804f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
805f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final int MAGIC = 0x454D4D41; // "EMMA"
806f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final long UNKNOWN = 0L;
807f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final int FILE_HEADER_LENGTH = 4 + 8 + 3 * 4; // IMPORTANT: update on writeFileHeader() changes
808f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final int ENTRY_HEADER_LENGTH = 8 + 1; // IMPORTANT: update on writeEntryHeader() changes
809f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final boolean DO_FSYNC = true;
810f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project    private static final int IO_BUF_SIZE = 32 * 1024;
811f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project
812f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project} // end of class
813f6fe897e173f4e4bda72a7dddb091b667066764aThe Android Open Source Project// ----------------------------------------------------------------------------
814