Skip to content

Commit 38f491c

Browse files
committed
squash: Moves the logic into tracks and tag and fix it by seeking the correct src position when coping the end of the file.
1 parent 083f49c commit 38f491c

File tree

5 files changed

+119
-104
lines changed

5 files changed

+119
-104
lines changed

src/main/java/org/ebml/io/FileDataWriter.java

+32-6
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,39 @@ public void copyFromPosition(FileDataWriter src) throws IOException
158158
src.fc.transferTo(src.fc.position(), src.fc.size() - src.fc.position(), fc);
159159
}
160160

161-
public void replaceWithFile(FileDataWriter dw)
162-
throws IOException
161+
/**
162+
* Copies the beginning of the file to a temporary file.
163+
* @return the FileDataWriter for the temporary file.
164+
* @throws IOException
165+
*/
166+
public FileDataWriter copyBeginningOfFile()
167+
throws IOException
163168
{
164-
Files.move(Path.of(dw.filename), Path.of(this.filename), StandardCopyOption.REPLACE_EXISTING);
169+
Path f = Files.createTempFile("mka", ".tmp");
170+
171+
FileDataWriter dw = new FileDataWriter(f.toFile().getPath());
172+
dw.copyToPosition(this);
173+
174+
return dw;
175+
}
176+
177+
/**
178+
* Copies the end of the current file(from current position) into the supplied FileDataWriter and replaces
179+
* the current file with the temp one.
180+
* @param dw The FileDataWriter to use as a new file.
181+
* @throws IOException
182+
*/
183+
public void copyEndOfFile(FileDataWriter dw)
184+
throws IOException
185+
{
186+
dw.copyFromPosition(this);
187+
188+
this.close();
189+
190+
Files.move(Path.of(dw.filename), Path.of(this.filename), StandardCopyOption.REPLACE_EXISTING);
165191

166-
// recreate after we move the new file
167-
file = new RandomAccessFile(filename, "rw");
168-
fc = file.getChannel();
192+
// recreate after we move the new file
193+
file = new RandomAccessFile(filename, "rw");
194+
fc = file.getChannel();
169195
}
170196
}

src/main/java/org/ebml/matroska/MatroskaFileTags.java

+38-8
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,18 @@
11
package org.ebml.matroska;
22

3+
import java.beans.PropertyChangeEvent;
4+
import java.beans.PropertyChangeListener;
5+
import java.io.IOException;
36
import java.util.ArrayList;
47

58
import org.ebml.MasterElement;
69
import org.ebml.io.DataWriter;
10+
import org.ebml.io.FileDataWriter;
711
import org.slf4j.Logger;
812
import org.slf4j.LoggerFactory;
913

1014
public class MatroskaFileTags
15+
implements PropertyChangeListener
1116
{
1217
private static final int BLOCK_SIZE = 4096;
1318
private static final Logger LOG = LoggerFactory.getLogger(MatroskaFileTags.class);
@@ -21,8 +26,7 @@ public void addTag(final MatroskaFileTagEntry tag)
2126
tags.add(tag);
2227
}
2328

24-
public long writeTags(final DataWriter ioDW, boolean checkBlockSize)
25-
throws VoidOutOfBoundException
29+
public long writeTags(final DataWriter ioDW)
2630
{
2731
myPosition = ioDW.getFilePointer();
2832
final MasterElement tagsElem = MatroskaDocTypes.Tags.getInstance();
@@ -32,11 +36,29 @@ public long writeTags(final DataWriter ioDW, boolean checkBlockSize)
3236
tagsElem.addChildElement(tag.toElement());
3337
}
3438

35-
if (checkBlockSize && BLOCK_SIZE < tagsElem.getTotalSize())
39+
if (BLOCK_SIZE < tagsElem.getTotalSize() && ioDW.isSeekable())
3640
{
37-
LOG.warn("Tags element size exceeds block size!");
41+
long len;
3842

39-
throw new VoidOutOfBoundException();
43+
// we need to write beyond the void space we have reserved
44+
// copy beginning of file into a temporary file
45+
try (FileDataWriter dw = ((FileDataWriter)ioDW).copyBeginningOfFile())
46+
{
47+
// write the tags
48+
len = tagsElem.writeElement(dw);
49+
50+
// now let's copy the rest of the original file by first setting the position after the tags
51+
ioDW.seek(myPosition + BLOCK_SIZE);
52+
53+
// copy the rest of the original file
54+
((FileDataWriter)ioDW).copyEndOfFile(dw);
55+
}
56+
catch (IOException ex)
57+
{
58+
throw new RuntimeException(ex);
59+
}
60+
61+
return len;
4062
}
4163

4264
long len = tagsElem.writeElement(ioDW);
@@ -50,14 +72,22 @@ public long writeTags(final DataWriter ioDW, boolean checkBlockSize)
5072
return len;
5173
}
5274

53-
public long update(final DataWriter ioDW, boolean checkBlockSize)
54-
throws VoidOutOfBoundException
75+
public long update(final DataWriter ioDW)
5576
{
5677
LOG.info("Updating tags list!");
5778
final long start = ioDW.getFilePointer();
5879
ioDW.seek(myPosition);
59-
long len = writeTags(ioDW, checkBlockSize);
80+
long len = writeTags(ioDW);
6081
ioDW.seek(start);
6182
return len;
6283
}
84+
85+
@Override
86+
public void propertyChange(PropertyChangeEvent evt)
87+
{
88+
if (evt.getPropertyName().equals(MatroskaFileTracks.RESIZED))
89+
{
90+
myPosition = myPosition + ((long) evt.getNewValue() - (long) evt.getOldValue());
91+
}
92+
}
6393
}

src/main/java/org/ebml/matroska/MatroskaFileTracks.java

+42-9
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,23 @@
11
package org.ebml.matroska;
22

3+
import java.beans.PropertyChangeSupport;
4+
import java.beans.PropertyChangeListener;
5+
import java.io.IOException;
36
import java.util.ArrayList;
47

58
import org.ebml.MasterElement;
69
import org.ebml.io.DataWriter;
10+
import org.ebml.io.FileDataWriter;
711
import org.slf4j.Logger;
812
import org.slf4j.LoggerFactory;
913

1014
public class MatroskaFileTracks
1115
{
12-
private static final int BLOCK_SIZE = 4096;
16+
final public static String RESIZED = "resized";
17+
18+
private final PropertyChangeSupport listeners = new PropertyChangeSupport(this);
19+
20+
private static final long BLOCK_SIZE = 4096;
1321
private static final Logger LOG = LoggerFactory.getLogger(MatroskaFileTracks.class);
1422

1523
private final ArrayList<MatroskaFileTrack> tracks = new ArrayList<>();
@@ -21,8 +29,7 @@ public void addTrack(final MatroskaFileTrack track)
2129
tracks.add(track);
2230
}
2331

24-
public long writeTracks(final DataWriter ioDW, boolean checkBlockSize)
25-
throws VoidOutOfBoundException
32+
public long writeTracks(final DataWriter ioDW)
2633
{
2734
myPosition = ioDW.getFilePointer();
2835
final MasterElement tracksElem = MatroskaDocTypes.Tracks.getInstance();
@@ -32,11 +39,33 @@ public long writeTracks(final DataWriter ioDW, boolean checkBlockSize)
3239
tracksElem.addChildElement(track.toElement());
3340
}
3441

35-
if (checkBlockSize && BLOCK_SIZE < tracksElem.getTotalSize())
42+
if (BLOCK_SIZE < tracksElem.getTotalSize() && ioDW.isSeekable())
3643
{
37-
LOG.warn("Tracks element size exceeds block size!");
44+
long len;
45+
46+
// we need to write beyond the void space we have reserved
47+
// copy beginning of file into a temporary file
48+
try (FileDataWriter dw = ((FileDataWriter)ioDW).copyBeginningOfFile())
49+
{
50+
// write the tracks
51+
len = tracksElem.writeElement(dw);
52+
53+
// now let's copy the rest of the original file by first setting the position after the tracks
54+
ioDW.seek(myPosition + BLOCK_SIZE);
55+
56+
// copy the rest of the original file
57+
((FileDataWriter)ioDW).copyEndOfFile(dw);
58+
}
59+
catch (IOException ex)
60+
{
61+
throw new RuntimeException(ex);
62+
}
3863

39-
throw new VoidOutOfBoundException();
64+
// we need to update tags element that its current position changed as we moved the data and inserted
65+
// some data before tags
66+
this.listeners.firePropertyChange(RESIZED, BLOCK_SIZE, len);
67+
68+
return len;
4069
}
4170

4271
long size = tracksElem.writeElement(ioDW);
@@ -50,14 +79,18 @@ public long writeTracks(final DataWriter ioDW, boolean checkBlockSize)
5079
return size;
5180
}
5281

53-
public long update(final DataWriter ioDW, boolean checkBlockSize)
54-
throws VoidOutOfBoundException
82+
public long update(final DataWriter ioDW)
5583
{
5684
LOG.info("Updating tracks list!");
5785
final long start = ioDW.getFilePointer();
5886
ioDW.seek(myPosition);
59-
long len = writeTracks(ioDW, checkBlockSize);
87+
long len = writeTracks(ioDW);
6088
ioDW.seek(start);
6189
return len;
6290
}
91+
92+
public void addPropertyChangeListener(PropertyChangeListener listener)
93+
{
94+
this.listeners.addPropertyChangeListener(listener);
95+
}
6396
}

src/main/java/org/ebml/matroska/MatroskaFileWriter.java

+7-76
Original file line numberDiff line numberDiff line change
@@ -20,17 +20,13 @@
2020
package org.ebml.matroska;
2121

2222
import java.io.Closeable;
23-
import java.io.IOException;
24-
import java.nio.file.Files;
25-
import java.nio.file.Path;
2623
import java.util.HashSet;
2724
import java.util.Set;
2825

2926
import org.ebml.MasterElement;
3027
import org.ebml.StringElement;
3128
import org.ebml.UnsignedIntegerElement;
3229
import org.ebml.io.DataWriter;
33-
import org.ebml.io.FileDataWriter;
3430
import org.slf4j.Logger;
3531
import org.slf4j.LoggerFactory;
3632

@@ -91,26 +87,13 @@ void initialize()
9187
segmentInfoElem.writeElement(ioDW);
9288

9389
metaSeek.addIndexedElement(MatroskaDocTypes.Tracks.getType(), ioDW.getFilePointer());
94-
try
95-
{
96-
tracks.writeTracks(ioDW, false);
97-
}
98-
catch (VoidOutOfBoundException e)
99-
{
100-
// when initializing tracks are empty so this should never happen
101-
LOG.error("Tracks element size exceeds block size?", e);
102-
}
90+
tracks.writeTracks(ioDW);
10391

10492
metaSeek.addIndexedElement(MatroskaDocTypes.Tags.getType(), ioDW.getFilePointer());
105-
try
106-
{
107-
tags.writeTags(ioDW, false);
108-
}
109-
catch (VoidOutOfBoundException e)
110-
{
111-
// when initializing tags are empty so this should never happen
112-
LOG.error("Tags element size exceeds block size?", e);
113-
}
93+
tags.writeTags(ioDW);
94+
95+
// If tracks got expanded beyond the void element, tags needs to adjust its pointer
96+
tracks.addPropertyChangeListener(tags);
11497

11598
cluster = new MatroskaCluster();
11699
metaSeek.addIndexedElement(MatroskaDocTypes.Cluster.getType(), ioDW.getFilePointer());
@@ -302,65 +285,13 @@ public void close()
302285
segmentInfoElem.setDuration(maxSegmentTimecode - minSegmentTimecode);
303286
segmentLen += segmentInfoElem.update(ioDW);
304287

305-
try
306-
{
307-
segmentLen += tracks.update(ioDW, true);
308-
}
309-
catch (VoidOutOfBoundException e)
310-
{
311-
LOG.info("Tracks element size exceeds block size. Will expand file.");
312-
313-
try (FileDataWriter dw = copyBeginningOfFile())
314-
{
315-
segmentLen += tracks.update(dw, false);
316-
copyEndOfFileAndClose(dw);
317-
}
318-
catch (VoidOutOfBoundException | IOException ex)
319-
{
320-
throw new RuntimeException(ex);
321-
}
322-
}
323-
try
324-
{
325-
segmentLen += tags.update(ioDW, true);
326-
}
327-
catch (VoidOutOfBoundException e)
328-
{
329-
LOG.info("Tags element size exceeds block size. Will expand file.");
330-
try (FileDataWriter dw = copyBeginningOfFile())
331-
{
332-
segmentLen += tags.update(dw, false);
333-
copyEndOfFileAndClose(dw);
334-
}
335-
catch (VoidOutOfBoundException | IOException ex)
336-
{
337-
throw new RuntimeException(ex);
338-
}
339-
}
288+
segmentLen += tracks.update(ioDW);
289+
segmentLen += tags.update(ioDW);
340290
segmentLen += clusterLen;
341291

342292
segmentElem.setUnknownSize(false);
343293
segmentElem.setSize(segmentLen);
344294
segmentElem.update(ioDW);
345295
}
346296
}
347-
348-
private FileDataWriter copyBeginningOfFile()
349-
throws IOException
350-
{
351-
FileDataWriter dw = new FileDataWriter(Files.createTempFile("mka", ".tmp").toFile().getPath());
352-
dw.copyToPosition((FileDataWriter)ioDW);
353-
354-
return dw;
355-
}
356-
357-
private void copyEndOfFileAndClose(FileDataWriter dw)
358-
throws IOException
359-
{
360-
dw.copyFromPosition((FileDataWriter)ioDW);
361-
362-
((FileDataWriter) ioDW).close();
363-
((FileDataWriter) ioDW).replaceWithFile(dw);
364-
365-
}
366297
}

src/main/java/org/ebml/matroska/VoidOutOfBoundException.java

-5
This file was deleted.

0 commit comments

Comments
 (0)