[SCM] morituri/master: * morituri/image/table.py: Add logging. Add methods to clear a table of files, and to absolutize indexes as long as the source is the same file, and to set a File on a given index, adjusting all following indexes that match the duration, and check if the IndexTable has all information for a TOC. * morituri/image/toc.py: Add logging. Use a counter for the source. Fix up index offset calculation. * morituri/program/cdrdao.py: Use a real IndexTable as the result, instead of a TocFile. * morituri/image/cue.py: Use a real IndexTable to store tracks. * morituri/test/test_image_toc.py: The toc file now has a table which has the tracks. Fix the tests to adjust for wrong index calculations. * morituri/test/test_image_cue.py: * morituri/test/test_image_image.py: * morituri/image/image.py: The cue file now has a table which has the tracks. * morituri/test/test_image_table.py: Add assertions to make sure when the table can serve as a TOC. * examples/readdisc.py: Adjust for changes. Fix up to include AccurateRip results. First time we can do a complete normal rip including verifying against AccurateRip results!

js at users.alioth.debian.org js at users.alioth.debian.org
Sun Oct 19 20:08:57 UTC 2014


The following commit has been merged in the master branch:
commit 2f464207dbe50f3179f207ae318e4147e950f327
Author: Thomas Vander Stichele <thomas (at) apestaart (dot) org>
Date:   Tue May 5 10:01:41 2009 +0000

    	* morituri/image/table.py:
    	  Add logging.
    	  Add methods to clear a table of files, and to absolutize indexes
    	  as long as the source is the same file, and to set a File on a
    	  given index, adjusting all following indexes that match the
    	  duration, and check if the IndexTable has all information for a TOC.
    	* morituri/image/toc.py:
    	  Add logging.
    	  Use a counter for the source.
    	  Fix up index offset calculation.
    	* morituri/program/cdrdao.py:
    	  Use a real IndexTable as the result, instead of a TocFile.
    	* morituri/image/cue.py:
    	  Use a real IndexTable to store tracks.
    	* morituri/test/test_image_toc.py:
    	  The toc file now has a table which has the tracks.
    	  Fix the tests to adjust for wrong index calculations.
    	* morituri/test/test_image_cue.py:
    	* morituri/test/test_image_image.py:
    	* morituri/image/image.py:
    	  The cue file now has a table which has the tracks.
    	* morituri/test/test_image_table.py:
    	  Add assertions to make sure when the table can serve as a TOC.
    	* examples/readdisc.py:
    	  Adjust for changes.  Fix up to include AccurateRip results.
    	  First time we can do a complete normal rip including verifying
    	  against AccurateRip results!

diff --git a/ChangeLog b/ChangeLog
index 2b20081..f3ef80b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,35 @@
 2009-05-05  Thomas Vander Stichele  <thomas at apestaart dot org>
 
+	* morituri/image/table.py:
+	  Add logging.
+	  Add methods to clear a table of files, and to absolutize indexes
+	  as long as the source is the same file, and to set a File on a
+	  given index, adjusting all following indexes that match the
+	  duration, and check if the IndexTable has all information for a TOC.
+	* morituri/image/toc.py:
+	  Add logging.
+	  Use a counter for the source.
+	  Fix up index offset calculation.
+	* morituri/program/cdrdao.py:
+	  Use a real IndexTable as the result, instead of a TocFile.
+	* morituri/image/cue.py:
+	  Use a real IndexTable to store tracks.
+	* morituri/test/test_image_toc.py:
+	  The toc file now has a table which has the tracks.
+	  Fix the tests to adjust for wrong index calculations.
+	* morituri/test/test_image_cue.py:
+	* morituri/test/test_image_image.py:
+	* morituri/image/image.py:
+	  The cue file now has a table which has the tracks.
+	* morituri/test/test_image_table.py:
+	  Add assertions to make sure when the table can serve as a TOC.
+	* examples/readdisc.py:
+	  Adjust for changes.  Fix up to include AccurateRip results.
+	  First time we can do a complete normal rip including verifying
+	  against AccurateRip results!
+
+2009-05-05  Thomas Vander Stichele  <thomas at apestaart dot org>
+
 	* examples/readdisc.py:
 	* morituri/image/table.py:
 	* morituri/test/test_image_table.py:
diff --git a/examples/readdisc.py b/examples/readdisc.py
index 8a7c679..40b52da 100644
--- a/examples/readdisc.py
+++ b/examples/readdisc.py
@@ -121,9 +121,11 @@ def main(argv):
     if not ptable.object:
         t = cdrdao.ReadIndexTableTask()
         function(runner, t)
-        ptable.persist(t.toc)
+        ptable.persist(t.table)
     itable = ptable.object
 
+    assert itable.hasTOC()
+
     lastTrackStart = 0
 
     for i, track in enumerate(itable.tracks):
@@ -139,36 +141,16 @@ def main(argv):
             if t.checksum:
                 print 'Checksums match for track %d' % (i + 1)
 
-        ittrack = table.ITTrack(i + 1)
-        # we know the .toc file represents a single wav rip, so all offsets
-        # are absolute since beginning of disc
-
-        # copy over indexes, adjusting the offset
-        tocTrack = itable.tracks[i]
-
-        # first copy over index 0 if there is any
-        try:
-            sector, _ = tocTrack.getIndex(0)
-            ittrack.index(0, path=path, relative=sector - lastTrackStart)
-        except KeyError:
-            pass
-        lastTrackStart, _ = tocTrack.getIndex(1)
-
-        indexes = itable.tracks[i]._indexes
-        numbers = indexes.keys()
-        numbers.sort()
-        if 0 in numbers: 
-            del numbers[0]
-        for number in numbers:
-            sector, _ = tocTrack.getIndex(number)
-            ittrack.index(number, path=path, relative=sector - lastTrackStart)
-        #itable.tracks.append(ittrack)
-
-            
-
-    # FIXME: this is the part where our IndexTable reader should convert
-    # a .toc file to a IndexTable we can dump .cue from
-    print ittoc.cue()
+        # overlay this rip onto the IndexTable
+        itable.setFile(i + 1, 1, path, ittoc.getTrackLength(i + 1))
+
+    print itable.tracks
+    for t in itable.tracks:
+        print t, t.indexes.values()
+
+    handle = open('morituri.cue', 'w')
+    handle.write(itable.cue())
+    handle.close()
 
     # verify using accuraterip
     print "CDDB disc id", itable.getCDDBDiscId()
@@ -196,7 +178,55 @@ def main(argv):
                 responses[0].cddbDiscId
 
        
-                
+    # FIXME: put accuraterip verification into a separate task/function
+    # and apply here
+    cueImage = image.Image('morituri.cue')
+    verifytask = image.ImageVerifyTask(cueImage)
+    cuetask = image.AccurateRipChecksumTask(cueImage)
+    function(runner, verifytask)
+    function(runner, cuetask)
+
+    response = None # track which response matches, for all tracks
+
+    # loop over tracks
+    for i, checksum in enumerate(cuetask.checksums):
+        status = 'rip NOT accurate'
+
+        confidence = None
+        archecksum = None
+
+        # match against each response's checksum
+        for j, r in enumerate(responses):
+            if "%08x" % checksum == r.checksums[i]:
+                if not response:
+                    response = r
+                else:
+                    assert r == response, \
+                        "checksum %s for %d matches wrong response %d, "\
+                        "checksum %s" % (
+                            checksum, i + 1, j + 1, response.checksums[i])
+                status = 'rip accurate    '
+                archecksum = checksum
+                confidence = response.confidences[i]
+
+        c = "(not found)"
+        ar = "(not in database)"
+        if responses:
+            if not response:
+                print 'ERROR: none of the responses matched.'
+            else:
+                maxConfidence = max(r.confidences[i] for r in responses)
+                     
+                c = "(confidence %3d)" % maxConfidence
+                if confidence is not None:
+                    if confidence < maxConfidence:
+                        c = "(confidence %3d of %3d)" % (confidence, maxConfidence)
+
+                ar = ", AR [%s]" % response.checksums[i]
+        print "Track %2d: %s %s [%08x]%s" % (
+            i + 1, status, c, checksum, ar)
+
+
 
 
 main(sys.argv)
diff --git a/morituri/image/cue.py b/morituri/image/cue.py
index 53fea20..11307d3 100644
--- a/morituri/image/cue.py
+++ b/morituri/image/cue.py
@@ -58,12 +58,18 @@ _INDEX_RE = re.compile(r"""
 
 
 class CueFile(object, log.Loggable):
+    """
+    I represent a .cue file as an object.
+    
+    @type table: L{table.IndexTable}
+    @ivar table: the index table.
+    """
     def __init__(self, path):
         self._path = path
         self._rems = {}
         self._messages = []
-        self.tracks = []
         self.leadout = None
+        self.table = table.IndexTable()
 
     def parse(self):
         state = 'HEADER'
@@ -109,7 +115,7 @@ class CueFile(object, log.Loggable):
 
                 self.debug('found track %d', trackNumber)
                 currentTrack = table.ITTrack(trackNumber)
-                self.tracks.append(currentTrack)
+                self.table.tracks.append(currentTrack)
                 continue
 
             # look for INDEX lines
@@ -145,13 +151,13 @@ class CueFile(object, log.Loggable):
         # returns track length in frames, or -1 if can't be determined and
         # complete file should be assumed
         # FIXME: this assumes a track can only be in one file; is this true ?
-        i = self.tracks.index(track)
-        if i == len(self.tracks) - 1:
+        i = self.table.tracks.index(track)
+        if i == len(self.table.tracks) - 1:
             # last track, so no length known
             return -1
 
         thisIndex = track.indexes[1] # FIXME: could be more
-        nextIndex = self.tracks[i + 1].indexes[1] # FIXME: could be 0
+        nextIndex = self.table.tracks[i + 1].indexes[1] # FIXME: could be 0
 
         c = thisIndex.counter
         if c is not None and c == nextIndex.counter:
diff --git a/morituri/image/image.py b/morituri/image/image.py
index 50f0080..34afc0a 100644
--- a/morituri/image/image.py
+++ b/morituri/image/image.py
@@ -73,19 +73,19 @@ class Image(object, log.Loggable):
 
         # CD's have a standard lead-in time of 2 seconds;
         # checksums that use it should add it there
-        offset = self.cue.tracks[0].getIndex(1).relative
+        offset = self.cue.table.tracks[0].getIndex(1).relative
 
         tracks = []
 
-        for i in range(len(self.cue.tracks)):
-            length = self.cue.getTrackLength(self.cue.tracks[i])
+        for i in range(len(self.cue.table.tracks)):
+            length = self.cue.getTrackLength(self.cue.table.tracks[i])
             if length == -1:
                 length = verify.lengths[i + 1]
             t = table.ITTrack(i + 1, audio=True)
             tracks.append(t)
             # FIXME: this probably only works for non-compliant .CUE files
             # where pregap is put at end of previous file
-            t.index(1, absolute=offset, path=self.cue.tracks[i].getIndex(1).path,
+            t.index(1, absolute=offset, path=self.cue.table.tracks[i].getIndex(1).path,
                 relative=0)
 
             offset += length
@@ -107,15 +107,15 @@ class AccurateRipChecksumTask(task.MultiSeparateTask):
         cue = image.cue
         self.checksums = []
 
-        self.debug('Checksumming %d tracks' % len(cue.tracks))
-        for trackIndex, track in enumerate(cue.tracks):
+        self.debug('Checksumming %d tracks' % len(cue.table.tracks))
+        for trackIndex, track in enumerate(cue.table.tracks):
             index = track.indexes[1]
             length = cue.getTrackLength(track)
             self.debug('track %d has length %d' % (trackIndex + 1, length))
 
             path = image.getRealPath(index.path)
             checksumTask = checksum.AccurateRipChecksumTask(path,
-                trackNumber=trackIndex + 1, trackCount=len(cue.tracks),
+                trackNumber=trackIndex + 1, trackCount=len(cue.table.tracks),
                 frameStart=index.relative * checksum.SAMPLES_PER_FRAME,
                 frameLength=length * checksum.SAMPLES_PER_FRAME)
             self.addTask(checksumTask)
@@ -176,7 +176,7 @@ class ImageVerifyTask(task.MultiSeparateTask):
         self._tasks = []
         self.lengths = {}
 
-        for trackIndex, track in enumerate(cue.tracks):
+        for trackIndex, track in enumerate(cue.table.tracks):
             self.debug('verifying track %d', trackIndex + 1)
             index = track.indexes[1]
             length = cue.getTrackLength(track)
diff --git a/morituri/image/table.py b/morituri/image/table.py
index 7775d0e..924fb08 100644
--- a/morituri/image/table.py
+++ b/morituri/image/table.py
@@ -29,7 +29,9 @@ import struct
 
 import gst
 
-from morituri.common import task, checksum, common
+from morituri.common import task, checksum, common, log
+
+from morituri.test import common as tcommon
 
 class DeleteMeTrack:
     """
@@ -249,12 +251,12 @@ class Index:
         self.counter = counter
 
     def __repr__(self):
-        return '<Index %02d, absolute %r, path %r, relative %r>' % (
-            self.number, self.absolute, self.path, self.relative)
+        return '<Index %02d, absolute %r, path %r, relative %r, counter %r>' % (
+            self.number, self.absolute, self.path, self.relative, self.counter)
 
-class IndexTable:
+class IndexTable(object, log.Loggable):
     """
-    I represent the Table of Contents of a CD.
+    I represent a table of indexes on a CD.
 
     @ivar tracks: tracks on this CD
     @type tracks: list of L{ITTrack}
@@ -417,6 +419,140 @@ class IndexTable:
                     common.framesToMSF(index.relative)))
 
         lines.append("")
+
         return "\n".join(lines) 
 
+    ### methods that modify the table
+    def clearFiles(self):
+        """
+        Clear all file backings.
+        Resets indexes paths and relative offsets.
+        """
+        # FIXME: do a loop over track indexes better, with a pythonic
+        # construct that allows you to do for t, i in ...
+        t = self.tracks[0].number
+        index = self.tracks[0].getFirstIndex()
+        i = index.number
+        # the first cut is the deepest
+        counter = index.counter
+
+        self.debug('clearing path')
+        while True:
+            track = self.tracks[t - 1]
+            index = track.getIndex(i)
+            self.debug('Clearing path on track %d, index %d', t, i)
+            index.path = None
+            index.relative = None
+            try:
+                t, i = self.getNextTrackIndex(t, i)
+            except IndexError:
+                break
+
+
+    def setFile(self, track, index, path, length):
+        """
+        Sets the given file as the source from the given index on.
+        Will loop over all indexes that fall within the given length,
+        to adjust the path.
+
+        Assumes all indexes have an absolute offset and will raise if not.
+        """
+        t = self.tracks[track - 1]
+        i = t.indexes[index]
+        start = i.absolute
+        assert start is not None, "index %r is missing absolute offset" % i
+        end = start + length
+
+        # FIXME: check border conditions here, esp. wrt. toc's off-by-one bug
+        while i.absolute <= end:
+            self.debug('Setting path and relative on track %d, index %d',
+                track, index)
+            i.path = path
+            i.relative = i.absolute - start
+            try:
+                track, index = self.getNextTrackIndex(track, index)
+                t = self.tracks[track - 1]
+                i = t.indexes[index]
+            except IndexError:
+                break
+
+    def absolutize(self):
+        """
+        Calculate absolute offsets on indexes as much as possible.
+        Only possible for as long as tracks draw from the same file.
+        """ 
+        t = self.tracks[0].number
+        index = self.tracks[0].getFirstIndex()
+        i = index.number
+        # the first cut is the deepest
+        counter = index.counter
+
+        self.debug('absolutizing')
+        while True:
+            if index.counter is None:
+                self.debug('Track %d, index %d has no counter', t, i)
+                break
+            if  index.counter != counter:
+                self.debug('Track %d, index %d has a different counter', t, i)
+                break
+            track = self.tracks[t - 1]
+            index = track.getIndex(i)
+            assert track.number == t
+            assert index.number == i
+            self.debug('Setting absolute offset %d on track %d, index %d',
+                index.relative, t, i)
+            index.absolute = index.relative
+            try:
+                t, i = self.getNextTrackIndex(t, i)
+            except IndexError:
+                break
+
+    ### lookups
+    def getNextTrackIndex(self, track, index):
+        """
+        Return the next track and index.
+
+        @param track: track number, 1-based
 
+        @raises IndexError: on last index
+
+        @rtype: tuple of (int, int)
+        """
+        t = self.tracks[track - 1]
+        indexes = t.indexes.keys()
+        position = indexes.index(index)
+
+        if position + 1 < len(indexes):
+            return track, indexes[position + 1]
+
+        track += 1
+        if track > len(self.tracks):
+            raise IndexError, "No index beyond track %d, index %d" % (
+                track - 1, index)
+
+        t = self.tracks[track - 1]
+        indexes = t.indexes.keys()
+
+        return track, indexes[0]
+
+
+    # various tests for types of IndexTable
+    def hasTOC(self):
+        """
+        Check if the Index Table has a complete TOC.
+        a TOC is a list of all tracks and their Index 01, with absolute
+        offsets, as well as the leadout.
+        """
+        if not self.leadout:
+            self.debug('no leadout, no TOC')
+            return False
+
+        for t in self.tracks:
+            if 1 not in t.indexes.keys():
+                self.debug('no index 1, no TOC')
+                return False
+            if t.indexes[1].absolute is None:
+                self.debug('no absolute index 1, no TOC')
+                return False
+
+        return True
diff --git a/morituri/image/toc.py b/morituri/image/toc.py
index 754e13e..879e5d3 100644
--- a/morituri/image/toc.py
+++ b/morituri/image/toc.py
@@ -27,7 +27,8 @@ Reading .toc files
 import os
 import re
 
-from morituri.common import common
+from morituri.common import common, log
+from morituri.image import table
 
 # header
 _CATALOG_RE = re.compile(r'^CATALOG "(?P<catalog>\d+)"$')
@@ -64,16 +65,17 @@ _INDEX_RE = re.compile(r"""
     \s(?P<offset>.+)$ # start offset
 """, re.VERBOSE)
 
-class TocFile(object):
+class TocFile(object, log.Loggable):
     def __init__(self, path):
         self._path = path
         self._messages = []
-        self.tracks = []
+        self.table = table.IndexTable()
 
     def parse(self):
         state = 'HEADER'
         currentFile = None
         currentTrack = None
+        counter = 0
         trackNumber = 0
         indexNumber = 0
         currentOffset = 0 # running absolute offset of where each track starts
@@ -100,8 +102,8 @@ class TocFile(object):
 
                 # handle index 1 of previous track, if any
                 if currentTrack:
-                    currentTrack.index(1, currentOffset + pregapLength,
-                        currentFile)
+                    currentTrack.index(1, path=currentFile.path,
+                        relative=currentOffset + pregapLength, counter=counter)
 
                 trackNumber += 1
                 currentOffset += currentLength
@@ -109,13 +111,18 @@ class TocFile(object):
                 indexNumber = 1
                 trackMode = m.group('mode')
 
-                currentTrack = Track(trackNumber)
-                self.tracks.append(currentTrack)
+                # FIXME: track mode
+                currentTrack = table.ITTrack(trackNumber)
+                self.table.tracks.append(currentTrack)
                 continue
 
             # look for SILENCE lines
             m = _SILENCE_RE.search(line)
             if m:
+                if currentFile is not None:
+                    self.debug('SILENCE after FILE, increasing counter')
+                    counter += 1
+                    currentFile = None
                 length = m.group('length')
                 currentLength += common.msfToFrames(length)
 
@@ -125,6 +132,13 @@ class TocFile(object):
                 filePath = m.group('name')
                 start = m.group('start')
                 length = m.group('length')
+                self.debug('FILE %s, start %r, length %r',
+                    filePath, common.msfToFrames(start),
+                    common.msfToFrames(length))
+                if not currentFile or filePath != currentFile.path:
+                    counter += 1
+                    self.debug('track %d, switched to new FILE, increased counter to %d',
+                        trackNumber, counter)
                 currentFile = File(filePath, start, length)
                 #currentOffset += common.msfToFrames(start)
                 currentLength += common.msfToFrames(length)
@@ -138,8 +152,9 @@ class TocFile(object):
                     continue
 
                 length = common.msfToFrames(m.group('length'))
-                currentTrack.index(0, currentOffset, currentFile)
-                currentLength += length
+                currentTrack.index(0, path=currentFile.path,
+                    relative=currentOffset - length, counter=counter)
+                #currentLength += length
                 pregapLength = length
                 
              # look for INDEX lines
@@ -149,11 +164,13 @@ class TocFile(object):
                     self.message(number, 'INDEX without preceding TRACK')
                     indexNumber += 1
                     offset = common.msfToFrames(m.group('offset'))
-                    currentTrack.index(indexNumber, offset, currentFile)
+                    currentTrack.index(indexNumber, path=currentFile.path,
+                        relative=offset, counter=counter)
 
         # handle index 1 of final track, if any
         if currentTrack:
-            currentTrack.index(1, currentOffset + pregapLength, currentFile)
+            currentTrack.index(1, path=currentFile.path,
+                relative=currentOffset + pregapLength, counter=counter)
 
     def message(self, number, message):
         """
@@ -167,16 +184,18 @@ class TocFile(object):
         # returns track length in frames, or -1 if can't be determined and
         # complete file should be assumed
         # FIXME: this assumes a track can only be in one file; is this true ?
-        i = self.tracks.index(track)
-        if i == len(self.tracks) - 1:
+        i = self.table.tracks.index(track)
+        if i == len(self.table.tracks) - 1:
             # last track, so no length known
             return -1
 
-        thisIndex = track._indexes[1] # FIXME: could be more
-        nextIndex = self.tracks[i + 1]._indexes[1] # FIXME: could be 0
+        thisIndex = track.indexes[1] # FIXME: could be more
+        nextIndex = self.table.tracks[i + 1].indexes[1] # FIXME: could be 0
 
-        if thisIndex[1] == nextIndex[1]: # same file
-            return nextIndex[0] - thisIndex[0]
+        c = thisIndex.counter
+        if c is not None and c == nextIndex.counter:
+            # they belong to the same source, so their relative delta is length
+            return nextIndex.relative - thisIndex.relative
 
         # FIXME: more logic
         return -1
@@ -218,15 +237,15 @@ class File:
     """
     def __init__(self, path, start, length):
         self.path = path
-        self.start = start
-        self.length = length
+        #self.start = start
+        #self.length = length
 
     def __repr__(self):
         return '<File "%s">' % (self.path, )
 
 
 # FIXME: add type ? separate AUDIO from others
-class Track:
+class DeleteMeTrack:
     """
     I represent a track in a cue file.
     I have index points.
diff --git a/morituri/program/cdrdao.py b/morituri/program/cdrdao.py
index f940040..ac33d39 100644
--- a/morituri/program/cdrdao.py
+++ b/morituri/program/cdrdao.py
@@ -69,7 +69,7 @@ class OutputParser(object, log.Loggable):
         self._track = None    # which track are we analyzing?
         self._task = taskk
 
-        self.toc = table.IndexTable() # the index table for the TOC
+        self.table = table.IndexTable() # the index table for the TOC
 
     def read(self, bytes):
         self.log('received %d bytes in state %s', len(bytes), self._state)
@@ -95,7 +95,7 @@ class OutputParser(object, log.Loggable):
             # we need both a position reported and an Analyzing line
             # to have been parsed to report progress
             if m and self._track is not None:
-                track = self.toc.tracks[self._track - 1]
+                track = self.table.tracks[self._track - 1]
                 frame = (track.getIndex(1).absolute or 0) \
                     + int(m.group('hh')) * 60 * 75 \
                     + int(m.group('mm')) * 75 \
@@ -146,7 +146,7 @@ class OutputParser(object, log.Loggable):
             self._tracks = int(m.group('track'))
             track = table.ITTrack(self._tracks)
             track.index(1, absolute=int(m.group('start')))
-            self.toc.tracks.append(track)
+            self.table.tracks.append(track)
             self.debug('Found track %d', self._tracks)
 
         m = _LEADOUT_RE.search(line)
@@ -155,7 +155,7 @@ class OutputParser(object, log.Loggable):
             self._state = 'LEADOUT'
             self._frames = int(m.group('start'))
             self.debug('Found leadout at offset %r', self._frames)
-            self.toc.leadout = self._frames
+            self.table.leadout = self._frames
             self.info('%d tracks found', self._tracks)
             return
 
@@ -238,21 +238,21 @@ class ReadIndexTableTask(CDRDAOTask):
     """
     I am a task that reads all indexes of a CD.
 
-    @ivar toc: the .toc file object
-    @type toc: L{toc.TOC}
+    @ivar table: the index table
+    @type table: L{table.IndexTable}
     """
 
     description = "Scanning indexes..."
+    table = None
 
     def __init__(self):
         CDRDAOTask.__init__(self)
         self.parser = OutputParser(self)
-        self.toc = None # result
-        (fd, self._toc) = tempfile.mkstemp(suffix='.morituri')
+        (fd, self._tocfilepath) = tempfile.mkstemp(suffix='.morituri')
         os.close(fd)
-        os.unlink(self._toc)
+        os.unlink(self._tocfilepath)
 
-        self.options = ['read-toc', self._toc]
+        self.options = ['read-toc', self._tocfilepath]
 
     def readbytes(self, bytes):
         self.parser.read(bytes)
@@ -260,13 +260,34 @@ class ReadIndexTableTask(CDRDAOTask):
     def done(self):
         # FIXME: instead of reading only a TOC, output a complete IndexTable
         # by merging the TOC info.
-        self.toc = toc.TocFile(self._toc)
-        self.toc.parse()
-        os.unlink(self._toc)
+        self._tocfile = toc.TocFile(self._tocfilepath)
+        self._tocfile.parse()
+        os.unlink(self._tocfilepath)
+        self.table = self._tocfile.table
+
+        # we know the .toc file represents a single wav rip, so all offsets
+        # are absolute since beginning of disc
+        self.table.absolutize()
+        # we unset relative since there is no real file backing this toc
+        for t in self.table.tracks:
+            for i in t.indexes.values():
+                #i.absolute = i.relative
+                i.relative = None
+
+        # copy the leadout from the parser's table
+        # FIXME: how do we get the length of the last audio track in the case
+        # of a data track ?
+        self.table.leadout = self.parser.table.leadout
+
+        # we should have parsed it from the initial output
+        assert self.table.leadout is not None
 
 class ReadTOCTask(CDRDAOTask):
     """
     I am a task that reads the TOC of a CD, without pregaps.
+
+    @ivar table: the index table that matches the TOC.
+    @type table: L{table.IndexTable}
     """
 
     description = "Reading TOC..."
@@ -287,4 +308,6 @@ class ReadTOCTask(CDRDAOTask):
 
     def done(self):
         os.unlink(self._toc)
-        self.table = self.parser.toc
+        self.table = self.parser.table
+
+        assert self.table.hasTOC(), "This Table Index should be a TOC"
diff --git a/morituri/test/test_image_cue.py b/morituri/test/test_image_cue.py
index bcd4ae5..3a8c06c 100644
--- a/morituri/test/test_image_cue.py
+++ b/morituri/test/test_image_cue.py
@@ -14,13 +14,13 @@ class KingsSingleTestCase(unittest.TestCase):
         self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__),
             'kings-single.cue'))
         self.cue.parse()
-        self.assertEquals(len(self.cue.tracks), 11)
+        self.assertEquals(len(self.cue.table.tracks), 11)
 
     def testGetTrackLength(self):
-        t = self.cue.tracks[0]
+        t = self.cue.table.tracks[0]
         self.assertEquals(self.cue.getTrackLength(t), 17811)
         # last track has unknown length
-        t = self.cue.tracks[-1]
+        t = self.cue.table.tracks[-1]
         self.assertEquals(self.cue.getTrackLength(t), -1)
 
 class KingsSeparateTestCase(unittest.TestCase):
@@ -28,13 +28,13 @@ class KingsSeparateTestCase(unittest.TestCase):
         self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__),
             'kings-separate.cue'))
         self.cue.parse()
-        self.assertEquals(len(self.cue.tracks), 11)
+        self.assertEquals(len(self.cue.table.tracks), 11)
 
     def testGetTrackLength(self):
         # all tracks have unknown length
-        t = self.cue.tracks[0]
+        t = self.cue.table.tracks[0]
         self.assertEquals(self.cue.getTrackLength(t), -1)
-        t = self.cue.tracks[-1]
+        t = self.cue.table.tracks[-1]
         self.assertEquals(self.cue.getTrackLength(t), -1)
 
 class KanyeMixedTestCase(unittest.TestCase):
@@ -42,10 +42,10 @@ class KanyeMixedTestCase(unittest.TestCase):
         self.cue = cue.CueFile(os.path.join(os.path.dirname(__file__),
             'kanye.cue'))
         self.cue.parse()
-        self.assertEquals(len(self.cue.tracks), 13)
+        self.assertEquals(len(self.cue.table.tracks), 13)
 
     def testGetTrackLength(self):
-        t = self.cue.tracks[0]
+        t = self.cue.table.tracks[0]
         self.assertEquals(self.cue.getTrackLength(t), -1)
 
 
diff --git a/morituri/test/test_image_image.py b/morituri/test/test_image_image.py
index 01695c5..86db997 100644
--- a/morituri/test/test_image_image.py
+++ b/morituri/test/test_image_image.py
@@ -61,7 +61,7 @@ class TrackSeparateTestCase(unittest.TestCase):
         self.assertEquals(h(checksumtask.checksums[3]), '0x7271db39')
 
     def testLength(self):
-        tracks = self.image.cue.tracks
+        tracks = self.image.cue.table.tracks
         self.assertEquals(self.image.table.getTrackLength(1), 10)
         self.assertEquals(self.image.table.getTrackLength(2), 10)
         self.assertEquals(self.image.table.getTrackLength(3), 10)
diff --git a/morituri/test/test_image_table.py b/morituri/test/test_image_table.py
index 13db8ba..ea13199 100644
--- a/morituri/test/test_image_table.py
+++ b/morituri/test/test_image_table.py
@@ -30,8 +30,12 @@ class LadyhawkeTestCase(unittest.TestCase):
         for i, offset in enumerate(offsets):
             t[i].index(1, absolute=offset)
 
+        self.failIf(self.table.hasTOC())
+
         self.table.leadout = 210385
 
+        self.failUnless(self.table.hasTOC())
+
     def testCDDB(self):
         self.assertEquals(self.table.getCDDBDiscId(), "c60af50d")
 
diff --git a/morituri/test/test_image_toc.py b/morituri/test/test_image_toc.py
index 08a5b9d..1c9971a 100644
--- a/morituri/test/test_image_toc.py
+++ b/morituri/test/test_image_toc.py
@@ -11,24 +11,71 @@ class CureTestCase(unittest.TestCase):
         self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__),
             'cure.toc'))
         self.toc.parse()
-        self.assertEquals(len(self.toc.tracks), 13)
+        self.assertEquals(len(self.toc.table.tracks), 13)
 
     def testGetTrackLength(self):
-        t = self.toc.tracks[0]
-        self.assertEquals(self.toc.getTrackLength(t), -1)
+        t = self.toc.table.tracks[0]
+        # first track has known length because the .toc is a single file
+        self.assertEquals(self.toc.getTrackLength(t), 28324)
         # last track has unknown length
-        t = self.toc.tracks[-1]
+        t = self.toc.table.tracks[-1]
         self.assertEquals(self.toc.getTrackLength(t), -1)
 
     def testIndexes(self):
         # track 2, index 0 is at 06:16:45
         # FIXME: cdrdao seems to get length of FILE 1 frame too many,
         # and START value one frame less
-        t = self.toc.tracks[1]
-        (offset, file) = t.getIndex(0)
-        self.assertEquals(offset, 28245)
-        (offset, file) = t.getIndex(1)
-        self.assertEquals(offset, 28324)
+        t = self.toc.table.tracks[1]
+        self.assertEquals(t.getIndex(0).relative, 28245)
+        self.assertEquals(t.getIndex(1).relative, 28324)
+
+    def _getIndex(self, t, i):
+        track = self.toc.table.tracks[t - 1]
+        return track.getIndex(i)
+
+    def _assertAbsolute(self, t, i, value):
+        index = self._getIndex(t, i)
+        self.assertEquals(index.absolute, value)
+
+    def _assertPath(self, t, i, value):
+        index = self._getIndex(t, i)
+        self.assertEquals(index.path, value)
+
+    def _assertRelative(self, t, i, value):
+        index = self._getIndex(t, i)
+        self.assertEquals(index.relative, value)
+
+    def testSetFile(self):
+        self._assertAbsolute(1, 1, None)
+        self._assertAbsolute(2, 0, None)
+        self._assertAbsolute(2, 1, None)
+        self._assertPath(1, 1, "data.wav")
+
+        def dump():
+            for t in self.toc.table.tracks:
+                print t
+                print t.indexes.values()
+
+        self.toc.table.absolutize()
+        self.toc.table.clearFiles()
+
+        self._assertAbsolute(1, 1, 0)
+        self._assertAbsolute(2, 0, 28166)
+        self._assertAbsolute(2, 1, 28324)
+        self._assertAbsolute(3, 1, 46110)
+        self._assertAbsolute(4, 1, 66767)
+        self._assertPath(1, 1, None)
+        self._assertRelative(1, 1, None)
+
+        # adding a file to the table should fix up to including 2, 0
+        self.toc.table.setFile(1, 1, 'track01.wav', 28245)
+        self._assertPath(1, 1, 'track01.wav')
+        self._assertRelative(1, 1, 0)
+        self._assertPath(2, 0, 'track01.wav')
+        self._assertAbsolute(2, 0, 28166)
+
+        self._assertPath(2, 1, None)
+        self._assertRelative(2, 1, None)
 
 # Bloc Party - Silent Alarm has a Hidden Track One Audio
 class BlocTestCase(unittest.TestCase):
@@ -36,18 +83,17 @@ class BlocTestCase(unittest.TestCase):
         self.toc = toc.TocFile(os.path.join(os.path.dirname(__file__),
             'bloc.toc'))
         self.toc.parse()
-        self.assertEquals(len(self.toc.tracks), 13)
+        self.assertEquals(len(self.toc.table.tracks), 13)
 
     def testGetTrackLength(self):
-        t = self.toc.tracks[0]
-        self.assertEquals(self.toc.getTrackLength(t), -1)
+        t = self.toc.table.tracks[0]
+        # first track has known length because the .toc is a single file
+        self.assertEquals(self.toc.getTrackLength(t), 50089)
         # last track has unknown length
-        t = self.toc.tracks[-1]
+        t = self.toc.table.tracks[-1]
         self.assertEquals(self.toc.getTrackLength(t), -1)
 
     def testIndexes(self):
-        t = self.toc.tracks[0]
-        (offset, file) = t.getIndex(0)
-        self.assertEquals(offset, 0)
-        (offset, file) = t.getIndex(1)
-        self.assertEquals(offset, 15220)
+        t = self.toc.table.tracks[0]
+        self.assertEquals(t.getIndex(0).relative, 0)
+        self.assertEquals(t.getIndex(1).relative, 15220)

-- 
morituri packaging



More information about the pkg-multimedia-commits mailing list