1 //
2 // Copyright 2011 The Android Open Source Project
3 //
4 // Abstraction of calls to system to make directories and delete files and
5 // wrapper to image processing.
6 
7 #ifndef CACHE_UPDATER_H
8 #define CACHE_UPDATER_H
9 
10 #include <androidfw/PathUtils.h>
11 #include <utils/String8.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <stdio.h>
15 #include "Images.h"
16 #ifdef _WIN32
17 #include <direct.h>
18 #endif
19 
20 #include "Utils.h"
21 
22 using namespace android;
23 
24 /** CacheUpdater
25  *  This is a pure virtual class that declares abstractions of functions useful
26  *  for managing a cache files. This manager is set up to be used in a
27  *  mirror cache where the source tree is duplicated and filled with processed
28  *  images. This class is abstracted to allow for dependency injection during
29  *  unit testing.
30  *  Usage:
31  *      To update/add a file to the cache, call processImage
32  *      To remove a file from the cache, call deleteFile
33  */
34 class CacheUpdater {
35 public:
~CacheUpdater()36     virtual ~CacheUpdater() {}
37 
38     // Make sure all the directories along this path exist
39     virtual void ensureDirectoriesExist(String8 path) = 0;
40 
41     // Delete a file
42     virtual void deleteFile(String8 path) = 0;
43 
44     // Process an image from source out to dest
45     virtual void processImage(String8 source, String8 dest) = 0;
46 private:
47 };
48 
49 /** SystemCacheUpdater
50  * This is an implementation of the above virtual cache updater specification.
51  * This implementations hits the filesystem to manage a cache and calls out to
52  * the PNG crunching in images.h to process images out to its cache components.
53  */
54 class SystemCacheUpdater : public CacheUpdater {
55 public:
56     // Constructor to set bundle to pass to preProcessImage
SystemCacheUpdater(Bundle * b)57     explicit SystemCacheUpdater (Bundle* b)
58         : bundle(b) { };
59 
60     // Make sure all the directories along this path exist
ensureDirectoriesExist(String8 path)61     virtual void ensureDirectoriesExist(String8 path)
62     {
63         // Check to see if we're dealing with a fully qualified path
64         String8 existsPath;
65         String8 toCreate;
66         String8 remains;
67         struct stat s;
68 
69         // Check optomistically to see if all directories exist.
70         // If something in the path doesn't exist, then walk the path backwards
71         // and find the place to start creating directories forward.
72         if (stat(path.c_str(),&s) == -1) {
73             // Walk backwards to find place to start creating directories
74             existsPath = path;
75             do {
76                 // As we remove the end of existsPath add it to
77                 // the string of paths to create.
78                 toCreate = appendPathCopy(getPathLeaf(existsPath), toCreate);
79                 existsPath = getPathDir(existsPath);
80             } while (stat(existsPath.c_str(),&s) == -1);
81 
82             // Walk forwards and build directories as we go
83             do {
84                 // Advance to the next segment of the path
85                 appendPath(existsPath, walkPath(toCreate, &remains));
86                 toCreate = remains;
87 #ifdef _WIN32
88                 _mkdir(existsPath.c_str());
89 #else
90                 mkdir(existsPath.c_str(), S_IRUSR|S_IWUSR|S_IXUSR|S_IRGRP|S_IXGRP);
91 #endif
92             } while (remains.length() > 0);
93         } //if
94     };
95 
96     // Delete a file
deleteFile(String8 path)97     virtual void deleteFile(String8 path)
98     {
99         if (remove(path.c_str()) != 0)
100             fprintf(stderr,"ERROR DELETING %s\n",path.c_str());
101     };
102 
103     // Process an image from source out to dest
processImage(String8 source,String8 dest)104     virtual void processImage(String8 source, String8 dest)
105     {
106         // Make sure we're trying to write to a directory that is extant
107         ensureDirectoriesExist(getPathDir(dest));
108 
109         preProcessImageToCache(bundle, source, dest);
110     };
111 private:
112     Bundle* bundle;
113 };
114 
115 #endif // CACHE_UPDATER_H
116