1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.mms.util;
18
19import java.io.IOException;
20import java.nio.ByteBuffer;
21
22import android.content.Context;
23
24public class ImageCacheService {
25    public static final String IMAGE_CACHE_FILE = "imgcache";
26    private static final int IMAGE_CACHE_MAX_ENTRIES = 500;
27    private static final int IMAGE_CACHE_MAX_BYTES = 20 * 1024 * 1024;
28    private static final int IMAGE_CACHE_VERSION = 3;
29
30    private BlobCache mCache;
31
32    private static long[] sCrcTable = new long[256];
33    private static final long POLY64REV = 0x95AC9329AC4BC9B5L;
34    private static final long INITIALCRC = 0xFFFFFFFFFFFFFFFFL;
35
36    private Context mContext;
37
38    public ImageCacheService(Context context) {
39        mCache = CacheManager.getCache(context, IMAGE_CACHE_FILE,
40                IMAGE_CACHE_MAX_ENTRIES, IMAGE_CACHE_MAX_BYTES,
41                IMAGE_CACHE_VERSION);
42        mContext = context;
43    }
44
45    public static class ImageData {
46        public ImageData(byte[] data, int offset) {
47            mData = data;
48            mOffset = offset;
49        }
50        public byte[] mData;
51        public int mOffset;
52    }
53
54    public ImageData getImageData(String path, int type) {
55        byte[] key = makeKey(path, type);
56        long cacheKey = crc64Long(key);
57        try {
58            byte[] value = null;
59            synchronized (mCache) {
60                value = mCache.lookup(cacheKey);
61            }
62            if (value == null) return null;
63            if (isSameKey(key, value)) {
64                int offset = key.length;
65                return new ImageData(value, offset);
66            }
67        } catch (IOException ex) {
68            // ignore.
69        }
70        return null;
71    }
72
73    public void putImageData(String path, int type, byte[] value) {
74        byte[] key = makeKey(path, type);
75        long cacheKey = crc64Long(key);
76        ByteBuffer buffer = ByteBuffer.allocate(key.length + value.length);
77        buffer.put(key);
78        buffer.put(value);
79        synchronized (mCache) {
80            try {
81                mCache.insert(cacheKey, buffer.array());
82            } catch (IOException ex) {
83                // ignore.
84            }
85        }
86    }
87
88    public void clear() {
89        CacheManager.clear(mContext);
90    }
91
92    private static byte[] makeKey(String path, int type) {
93        return getBytes(path + "+" + type);
94    }
95
96    private static boolean isSameKey(byte[] key, byte[] buffer) {
97        int n = key.length;
98        if (buffer.length < n) {
99            return false;
100        }
101        for (int i = 0; i < n; ++i) {
102            if (key[i] != buffer[i]) {
103                return false;
104            }
105        }
106        return true;
107    }
108
109    /**
110     * A function thats returns a 64-bit crc for string
111     *
112     * @param in input string
113     * @return a 64-bit crc value
114     */
115    public static final long crc64Long(String in) {
116        if (in == null || in.length() == 0) {
117            return 0;
118        }
119        return crc64Long(getBytes(in));
120    }
121
122    static {
123        // http://bioinf.cs.ucl.ac.uk/downloads/crc64/crc64.c
124        long part;
125        for (int i = 0; i < 256; i++) {
126            part = i;
127            for (int j = 0; j < 8; j++) {
128                long x = ((int) part & 1) != 0 ? POLY64REV : 0;
129                part = (part >> 1) ^ x;
130            }
131            sCrcTable[i] = part;
132        }
133    }
134
135    public static final long crc64Long(byte[] buffer) {
136        long crc = INITIALCRC;
137        for (int k = 0, n = buffer.length; k < n; ++k) {
138            crc = sCrcTable[(((int) crc) ^ buffer[k]) & 0xff] ^ (crc >> 8);
139        }
140        return crc;
141    }
142
143    public static byte[] getBytes(String in) {
144        byte[] result = new byte[in.length() * 2];
145        int output = 0;
146        for (char ch : in.toCharArray()) {
147            result[output++] = (byte) (ch & 0xFF);
148            result[output++] = (byte) (ch >> 8);
149        }
150        return result;
151    }
152
153}
154