1//
2// Copyright 2011 The Android Open Source Project
3//
4// Implementation file for CrunchCache
5// This file defines functions laid out and documented in
6// CrunchCache.h
7
8#include <utils/Compat.h>
9#include <utils/Vector.h>
10#include <utils/String8.h>
11
12#include "DirectoryWalker.h"
13#include "FileFinder.h"
14#include "CacheUpdater.h"
15#include "CrunchCache.h"
16
17using namespace android;
18
19CrunchCache::CrunchCache(String8 sourcePath, String8 destPath, FileFinder* ff)
20    : mSourcePath(sourcePath), mDestPath(destPath), mSourceFiles(0), mDestFiles(0), mFileFinder(ff)
21{
22    // We initialize the default value to return to 0 so if a file doesn't exist
23    // then all files are automatically "newer" than it.
24
25    // Set file extensions to look for. Right now just pngs.
26    mExtensions.push(String8(".png"));
27
28    // Load files into our data members
29    loadFiles();
30}
31
32size_t CrunchCache::crunch(CacheUpdater* cu, bool forceOverwrite)
33{
34    size_t numFilesUpdated = 0;
35
36    // Iterate through the source files and compare to cache.
37    // After processing a file, remove it from the source files and
38    // from the dest files.
39    // We're done when we're out of files in source.
40    String8 relativePath;
41    while (mSourceFiles.size() > 0) {
42        // Get the full path to the source file, then convert to a c-string
43        // and offset our beginning pointer to the length of the sourcePath
44        // This efficiently strips the source directory prefix from our path.
45        // Also, String8 doesn't have a substring method so this is what we've
46        // got to work with.
47        const char* rPathPtr = mSourceFiles.keyAt(0).string()+mSourcePath.length();
48        // Strip leading slash if present
49        int offset = 0;
50        if (rPathPtr[0] == OS_PATH_SEPARATOR)
51            offset = 1;
52        relativePath = String8(rPathPtr + offset);
53
54        if (forceOverwrite || needsUpdating(relativePath)) {
55            cu->processImage(mSourcePath.appendPathCopy(relativePath),
56                             mDestPath.appendPathCopy(relativePath));
57            numFilesUpdated++;
58            // crunchFile(relativePath);
59        }
60        // Delete this file from the source files and (if it exists) from the
61        // dest files.
62        mSourceFiles.removeItemsAt(0);
63        mDestFiles.removeItem(mDestPath.appendPathCopy(relativePath));
64    }
65
66    // Iterate through what's left of destFiles and delete leftovers
67    while (mDestFiles.size() > 0) {
68        cu->deleteFile(mDestFiles.keyAt(0));
69        mDestFiles.removeItemsAt(0);
70    }
71
72    // Update our knowledge of the files cache
73    // both source and dest should be empty by now.
74    loadFiles();
75
76    return numFilesUpdated;
77}
78
79void CrunchCache::loadFiles()
80{
81    // Clear out our data structures to avoid putting in duplicates
82    mSourceFiles.clear();
83    mDestFiles.clear();
84
85    // Make a directory walker that points to the system.
86    DirectoryWalker* dw = new SystemDirectoryWalker();
87
88    // Load files in the source directory
89    mFileFinder->findFiles(mSourcePath, mExtensions, mSourceFiles,dw);
90
91    // Load files in the destination directory
92    mFileFinder->findFiles(mDestPath,mExtensions,mDestFiles,dw);
93
94    delete dw;
95}
96
97bool CrunchCache::needsUpdating(String8 relativePath) const
98{
99    // Retrieve modification dates for this file entry under the source and
100    // cache directory trees. The vectors will return a modification date of 0
101    // if the file doesn't exist.
102    time_t sourceDate = mSourceFiles.valueFor(mSourcePath.appendPathCopy(relativePath));
103    time_t destDate = mDestFiles.valueFor(mDestPath.appendPathCopy(relativePath));
104    return sourceDate > destDate;
105}
106