boolean validate(Manifest manifest, Payload payload, TIPPErrorHandler errorHandler) {
        CollectingErrorHandler validationErrors = new CollectingErrorHandler();
        Set<String> objectPaths = payload.getPaths();
        Set<String> pathsInManifest = new HashSet<String>();
        for (TIPPSection section : manifest.getSections()) {
            for (TIPPFile obj : section.getFileResources()) {
                String expectedPath = Payload.getFilePath(section.getType(),
                                        manifest.getLocationForFile(obj));
                if (pathsInManifest.contains(expectedPath)) {
                    validationErrors.reportError(DUPLICATE_RESOURCE_LOCATION_IN_MANIFEST,
                            "Duplicate resource in manifest: " + expectedPath, null);
                }
                if (!objectPaths.contains(expectedPath)) {
                    validationErrors.reportError(MISSING_PAYLOAD_RESOURCE, 
                            "Missing resource: " + expectedPath, null);
                }
                pathsInManifest.add(expectedPath);
            }
        }
        // Now check in the other direction
        for (String objectPath : objectPaths) {
            if (!pathsInManifest.contains(objectPath)) {
                validationErrors.reportError(TIPPErrorType.UNEXPECTED_PAYLOAD_RESOURCE, 
                                "Unexpected package resource: " + objectPath, null);
            }
        }
        for (TIPPError e : validationErrors.getErrors()) {
            errorHandler.reportError(e.getErrorType(), e.getMessage(), e.getException());
        }
        // Add all errors to the regular error.
        return validationErrors.getErrors().size() == 0;
    }