readWholeFiles (const std::string & fn)
{
    Array2D<unsigned int> uData;
    Array2D<float> fData;
    Array2D<half> hData;

    MultiPartInputFile file(fn.c_str());
    for (size_t i = 0; i < static_cast<size_t>(file.parts()); i++)
    {
        const Header& header = file.header(i);
        assert (header.displayWindow() == headers[i].displayWindow());
        assert (header.dataWindow() == headers[i].dataWindow());
        assert (header.pixelAspectRatio() == headers[i].pixelAspectRatio());
        assert (header.screenWindowCenter() == headers[i].screenWindowCenter());
        assert (header.screenWindowWidth() == headers[i].screenWindowWidth());
        assert (header.lineOrder() == headers[i].lineOrder());
        assert (header.compression() == headers[i].compression());

        //
        // It rarely fails here. Added code to see what's wrong when it happens.
        //
        ChannelList::ConstIterator i1 = header.channels().begin();
        ChannelList::ConstIterator i2 = headers[i].channels().begin();
        Channel c1 = i1.channel();
        Channel c2 = i2.channel();
        if (!(c1 == c2))
        {
            cout << " type is " << c1.type << ", should be " << c2.type
                 << " xSampling is " << c1.xSampling << ", should be " << c2.xSampling
                 << " ySampling is " << c1.ySampling << ", should be " << c2.ySampling
                 << " pLinear is " << c1.pLinear << ", should be " << c2.pLinear << flush;
        }

        assert (header.channels() == headers[i].channels());
        assert (header.name() == headers[i].name());
        assert (header.type() == headers[i].type());
    }

    cout << "Reading whole files " << flush;

    //
    // Shuffle part numbers.
    //
    vector<int> shuffledPartNumber;
    int nHeaders = static_cast<int>(headers.size());
    for (int i = 0; i < nHeaders; i++)
        shuffledPartNumber.push_back(i);
    for (int i = 0; i < nHeaders; i++)
    {
        int a = random_int(nHeaders);
        int b = random_int(nHeaders);
        swap (shuffledPartNumber[a], shuffledPartNumber[b]);
    }

    //
    // Start reading whole files.
    //
    int i;
    int partNumber;
    try
    {
        for (i = 0; i < nHeaders; i++)
        {
            partNumber = shuffledPartNumber[i];
            if (partTypes[partNumber] == 0)
            {
                FrameBuffer frameBuffer;
                setInputFrameBuffer(frameBuffer, pixelTypes[partNumber],
                                    uData, fData, hData, width, height);

                InputPart part(file, partNumber);
                part.setFrameBuffer(frameBuffer);
                part.readPixels(0, height - 1);
                switch (pixelTypes[partNumber])
                {
                    case 0:
                        assert(checkPixels<unsigned int>(uData, width, height));
                        break;
                    case 1:
                        assert(checkPixels<float>(fData, width, height));
                        break;
                    case 2:
                        assert(checkPixels<half>(hData, width, height));
                        break;
                }
            }
            else
            {
                FrameBuffer frameBuffer;
                TiledInputPart part(file, partNumber);
                int numXLevels = part.numXLevels();
                int numYLevels = part.numYLevels();
                for (int xLevel = 0; xLevel < numXLevels; xLevel++)
                    for (int yLevel = 0; yLevel < numYLevels; yLevel++)
                    {
                        if (!part.isValidLevel(xLevel, yLevel))
                            continue;

                        int w = part.levelWidth(xLevel);
                        int h = part.levelHeight(yLevel);

                        setInputFrameBuffer(frameBuffer, pixelTypes[partNumber],
                                            uData, fData, hData, width, height);

                        part.setFrameBuffer(frameBuffer);
                        int numXTiles = part.numXTiles(xLevel);
                        int numYTiles = part.numYTiles(yLevel);
                        part.readTiles(0, numXTiles - 1, 0, numYTiles - 1, xLevel, yLevel);
                        switch (pixelTypes[partNumber])
                        {
                            case 0:
                                assert(checkPixels<unsigned int>(uData, w, h));
                                break;
                            case 1:
                                assert(checkPixels<float>(fData, w, h));
                                break;
                            case 2:
                                assert(checkPixels<half>(hData, w, h));
                                break;
                        }
                    }
            }
        }
    }
    catch (...)
    {
        cout << "Error while reading part " << partNumber << endl << flush;
        throw;
    }
}