ssize_t MyVorbisExtractor::readPage(off64_t offset, Page *page) {
    uint8_t header[27];
    ssize_t n;
    if ((n = mSource->readAt(offset, header, sizeof(header)))
            < (ssize_t)sizeof(header)) {

        if (n < 0) {
            return n;
        } else if (n == 0) {
            return ERROR_END_OF_STREAM;
        } else {
            return ERROR_IO;
        }
    }

    if (memcmp(header, "OggS", 4)) {
        return ERROR_MALFORMED;
    }

    if (header[4] != 0) {
        // Wrong version.

        return ERROR_UNSUPPORTED;
    }

    page->mFlags = header[5];

    if (page->mFlags & ~7) {
        // Only bits 0-2 are defined in version 0.
        return ERROR_MALFORMED;
    }

    page->mGranulePosition = U64LE_AT(&header[6]);

    page->mSerialNo = U32LE_AT(&header[14]);
    page->mPageNo = U32LE_AT(&header[18]);

    page->mNumSegments = header[26];
    if (mSource->readAt(
                offset + sizeof(header), page->mLace, page->mNumSegments)
            < (ssize_t)page->mNumSegments) {
        return ERROR_IO;
    }

    size_t totalSize = 0;;
    for (size_t i = 0; i < page->mNumSegments; ++i) {
        totalSize += page->mLace[i];
    }

    return sizeof(header) + page->mNumSegments + totalSize;
}
Пример #2
0
ssize_t MyVorbisExtractor::readPage(off64_t offset, Page *page) {
    uint8_t header[27];
    ssize_t n;
    if ((n = mSource->readAt(offset, header, sizeof(header)))
            < (ssize_t)sizeof(header)) {
        LOGV("failed to read %d bytes at offset 0x%016llx, got %ld bytes",
             sizeof(header), offset, n);

        if (n < 0) {
            return n;
        } else if (n == 0) {
            return ERROR_END_OF_STREAM;
        } else {
            return ERROR_IO;
        }
    }

    if (memcmp(header, "OggS", 4)) {
        return ERROR_MALFORMED;
    }

    if (header[4] != 0) {
        // Wrong version.

        return ERROR_UNSUPPORTED;
    }

    page->mFlags = header[5];

    if (page->mFlags & ~7) {
        // Only bits 0-2 are defined in version 0.
        return ERROR_MALFORMED;
    }

    page->mGranulePosition = U64LE_AT(&header[6]);

#if 0
    printf("granulePosition = %llu (0x%llx)\n",
           page->mGranulePosition, page->mGranulePosition);
#endif

    page->mSerialNo = U32LE_AT(&header[14]);
    page->mPageNo = U32LE_AT(&header[18]);

    page->mNumSegments = header[26];
    if (mSource->readAt(
                offset + sizeof(header), page->mLace, page->mNumSegments)
            < (ssize_t)page->mNumSegments) {
        return ERROR_IO;
    }

    size_t totalSize = 0;;
    for (size_t i = 0; i < page->mNumSegments; ++i) {
        totalSize += page->mLace[i];
    }

#if 0
    String8 tmp;
    for (size_t i = 0; i < page->mNumSegments; ++i) {
        char x[32];
        sprintf(x, "%s%u", i > 0 ? ", " : "", (unsigned)page->mLace[i]);

        tmp.append(x);
    }

    LOGV("%c %s", page->mFlags & 1 ? '+' : ' ', tmp.string());
#endif

    return sizeof(header) + page->mNumSegments + totalSize;
}
Пример #3
0
int main(int argc, char* argv[])
{
    int retval = 1;
    int fdout = -1;
    uint8_t* pIn  = NULL;
    uint8_t* pOut = NULL;

    if (argc < 3 || argc > 3)
    {
        fprintf(stderr, "Usage: mfrafix infile outfile\n");
        return 1;
    }

    int fdin = open(argv[1], O_RDONLY);
    if (fdin < 0)
    {
        fprintf(stderr, "Error: failed to open '%s' for reading\n", argv[1]);
        goto cleanup;
    }

    off_t length = lseek(fdin, 0, SEEK_END);

    lseek(fdin, 0, SEEK_SET);
    debug("Length of in file: %d\n", (int)length);

    pIn = mmap(NULL, length, PROT_READ, MAP_SHARED, fdin, 0);
    if (pIn == NULL)
    {
        fprintf(stderr, "Error: mmap failed with error %d - '%s'\n", errno, strerror(errno));
        goto cleanup;
    }

    // Look for the mfra by checking the last four bytes in the mfro
    // For now we assume that the mfra is at the end of the file...
    uint32_t mfro = U32_AT(pIn + length - sizeof(uint32_t));
    uint8_t* pMFRA = pIn + length - mfro;
    uint32_t mfraSize = U32_AT(pMFRA);
    uint8_t* pMFRAEnd = pMFRA + mfraSize;
    SKIP(pMFRA, 4); // Size processed

    debug("mfro offset %x\n", mfro);
    debug("MFRA size %x\n", mfraSize);
    debug("MFRA box '%08x'\n", U32_AT(pMFRA));

    if (FOURCC('m', 'f', 'r', 'a') != U32_AT(pMFRA))
    {
        fprintf(stderr, "Error: The mfra box was not found\n");
        goto cleanup;
    }
    SKIP(pMFRA, 4); // Type processed

    debug("Found mfra\n");

    TFRAEntry* tfraEntries = NULL;
    int numTFRAEntries = 0;

    while (pMFRA < pMFRAEnd)
    {
        uint32_t boxSize = U32_AT(pMFRA);
        SKIP(pMFRA, 4); // Size read

        debug("Box size %x\n", boxSize);
        debug("Box type '%08x'\n", U32_AT(pMFRA));
        switch (U32_AT(pMFRA))
        {
            case FOURCC('t', 'f', 'r', 'a'):
                debug("Found tfra\n");
                SKIP(pMFRA, 4); // Type processed
                SKIP(pMFRA, 4); // Ignore version and flags

                uint32_t trackId = U32_AT(pMFRA);
                SKIP(pMFRA, 4); // trackId processed

                uint32_t tmp = U32LE_AT(pMFRA);
                int trafNum   = (tmp >> 4) & 0x3;
                int trunNum   = (tmp >> 2) & 0x3;
                int sampleNum = (tmp >> 0) & 0x3;
                SKIP(pMFRA, 4); // Traf, trun and samples processed
                debug("trackId %d\ntraf %d trun %d sample %d\n", trackId, trafNum, trunNum, sampleNum);

                uint32_t numEntry = U32_AT(pMFRA);
                SKIP(pMFRA, 4); // numEntry processed
                debug("numEntry: %d\n", numEntry);

                tfraEntries = realloc(tfraEntries, sizeof(TFRAEntry) * (numEntry + numTFRAEntries));
                if (tfraEntries == NULL)
                {
                    fprintf(stderr, "Error: Failed to allocate memory for tfra entries\n");
                    goto cleanup;
                }

                for (int i = numTFRAEntries; i < (numEntry + numTFRAEntries); ++i)
                {
                    tfraEntries[i].trackId = trackId;

                    debug("time: %lx\n", U64_AT(pMFRA));
                    tfraEntries[i].time = U64_AT(pMFRA);
                    SKIP(pMFRA, 8); // Skip uint64, time

                    debug("moof: %lx\n", U64_AT(pMFRA));
                    tfraEntries[i].moof = U64_AT(pMFRA);
                    tfraEntries[i].moofOffset = (pMFRA - pIn);
                    SKIP(pMFRA, 8); // Skip uint64, moof offset

                    int skip = trafNum + 1 + trunNum + 1 + sampleNum + 1;
                    pMFRA = pMFRA + skip;
                }

                // Update here as we use numTFRAEntries as offset when indexing the array
                numTFRAEntries += numEntry; 

                break;
            case FOURCC('m', 'f', 'r', 'o'):
                debug("found mfro box\n");
                pMFRA = pMFRA + boxSize - sizeof(uint32_t);
                break;

            default:
                fprintf(stderr, "Error: Unknown box found '%08x'\n", U32_AT(pMFRA));
                goto cleanup;
        }

    }

    if (numTFRAEntries == 0)
    {
        fprintf(stderr, "Error: No TFRA entries found.\n");
        goto cleanup;
    }

    // Start by checking if the first entry points to a moof
    uint8_t* p1 = pIn + tfraEntries[0].moof;
    if (FOURCC('m', 'o', 'o', 'f') != U32_AT(p1 + 4))
    {
        uint32_t offset = U32_AT(p1);
        fprintf(stdout, "We found '%08x' instead of moof, try to correct with offset %x\n", U32_AT(p1 + 4), offset);

        for (int i = 0; i < numTFRAEntries; ++i)
        {
            debug("p = %x\n", tfraEntries[i].moof);
            uint8_t *p = pIn + tfraEntries[i].moof + offset;

            if (U32_AT(p + 4) == FOURCC('m', 'o', 'o', 'f'))
                debug("Found moof\n");
            else
            {
                debug("Found '%08x'\n", U32_AT(p + 4));
                goto cleanup;
            }
        }

        debug("Open output file\n");

        fdout = open(argv[2], O_RDWR | O_CREAT | O_TRUNC);
        if (fdout < 0)
        {
            fprintf(stderr, "Error: failed to open '%s' for writing\n", argv[2]);
            goto cleanup;
        }

        debug("Set size of out file\n");

        lseek(fdout, length - 1, SEEK_SET);
        write(fdout, "", 1);

        debug("Call mmap for output file\n");

        pOut = mmap(NULL, length, PROT_WRITE | PROT_READ, MAP_SHARED, fdout, 0);
        if (pOut == NULL)
        {
            fprintf(stderr, "Error: mmap failed with error %d - '%s'\n", errno, strerror(errno));
            goto cleanup;
        }

        debug("Do memcpy\n");
        memcpy(pOut, pIn, length);

        debug("Update moof references\n");
        for (int i = 0; i < numTFRAEntries; ++i)
        {
            debug("p = %x\n", tfraEntries[i].moof);
            debug("offset = %x\n", offset);
            debug("out = %x\n", tfraEntries[i].moof + offset);
            uint64_t *p = (uint64_t*)(pOut + tfraEntries[i].moofOffset);
            (*p) = TO_U64(tfraEntries[i].moof + offset);
        }

        debug("Do msync\n");
        msync(pOut, length, MS_SYNC);
        fprintf(stdout, "Fixed all entries...\n");
    }
    else
    {
        fprintf(stdout, "The first moof reference is correct, assume the rest are as well and exit\n");
    }

    retval = 0;

cleanup:
    if (tfraEntries != NULL)
        free(tfraEntries);

    if (fdout >= 0)
        close(fdout);

    if (pOut != NULL)
        munmap(pOut, length);

    if (pIn != NULL)
        munmap(pIn, length);

    if (fdin >= 0)
        close(fdin);

    return retval;
}