1 /* ScummVM - Graphic Adventure Engine
2  *
3  * ScummVM is the legal property of its developers, whose names
4  * are too numerous to list here. Please refer to the COPYRIGHT
5  * file distributed with this source distribution.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20  *
21  */
22 
23 #if defined(__ANDROID__)
24 
25 #include <sys/types.h>
26 #include <unistd.h>
27 
28 #include "common/str.h"
29 #include "common/stream.h"
30 #include "common/util.h"
31 #include "common/archive.h"
32 #include "common/debug.h"
33 #include "common/textconsole.h"
34 
35 #include "backends/platform/android/jni.h"
36 #include "backends/platform/android/asset-archive.h"
37 
38 #include <android/asset_manager.h>
39 #include <android/asset_manager_jni.h>
40 
41 class AssetInputStream : public Common::SeekableReadStream {
42 public:
43 	AssetInputStream(AAssetManager *as, const Common::String &path);
44 	virtual ~AssetInputStream();
45 
eos() const46 	virtual bool eos() const { return _eos; }
47 
clearErr()48 	virtual void clearErr() {_eos = false; }
49 
50 	virtual uint32 read(void *dataPtr, uint32 dataSize);
51 
pos() const52 	virtual int32 pos() const { return _pos; }
53 
size() const54 	virtual int32 size() const { return _len; }
55 
56 	virtual bool seek(int32 offset, int whence = SEEK_SET);
57 
58 private:
59 	void close();
60 	AAsset *_asset;
61 
62 	uint32 _pos;
63 	uint32 _len;
64 	bool _eos;
65 };
66 
AssetInputStream(AAssetManager * as,const Common::String & path)67 AssetInputStream::AssetInputStream(AAssetManager *as, const Common::String &path) :
68 	_eos(false), _pos(0) {
69 	_asset = AAssetManager_open(as, path.c_str(), AASSET_MODE_RANDOM);
70 	_len = AAsset_getLength(_asset);
71 }
72 
~AssetInputStream()73 AssetInputStream::~AssetInputStream() {
74 }
75 
close()76 void AssetInputStream::close() {
77 	AAsset_close(_asset);
78 }
79 
read(void * dataPtr,uint32 dataSize)80 uint32 AssetInputStream::read(void *dataPtr, uint32 dataSize) {
81 	uint32 readlen = AAsset_read(_asset, dataPtr, dataSize);
82 	_pos += readlen;
83 	if (readlen != dataSize) {
84 		_eos = true;
85 	}
86 	return readlen;
87 }
88 
seek(int32 offset,int whence)89 bool AssetInputStream::seek(int32 offset, int whence) {
90 	int res = AAsset_seek(_asset, offset, whence);
91 	if (res == -1) {
92 		return false;
93 	}
94 	if (whence == SEEK_CUR) {
95 		_pos += offset;
96 	} else if (whence == SEEK_SET) {
97 		_pos = offset;
98 	} else if (whence == SEEK_END) {
99 		_pos = _len + offset;
100 	}
101 	assert(_pos < _len);
102 	_eos = false;
103 	return true;
104 }
105 
106 
AndroidAssetArchive(jobject am)107 AndroidAssetArchive::AndroidAssetArchive(jobject am) {
108 	JNIEnv *env = JNI::getEnv();
109 
110 	_am = AAssetManager_fromJava(env, am);
111 	_cachedMembers = NULL;
112 }
113 
~AndroidAssetArchive()114 AndroidAssetArchive::~AndroidAssetArchive() {
115 	delete _cachedMembers;
116 	_cachedMembers = NULL;
117 }
118 
hasFile(const Common::String & name) const119 bool AndroidAssetArchive::hasFile(const Common::String &name) const {
120 	AAsset *asset = AAssetManager_open(_am, name.c_str(), AASSET_MODE_RANDOM);
121 	bool exists = false;
122 	if (asset != NULL) {
123 		exists = true;
124 		AAsset_close(asset);
125 	}
126 	return exists;
127 }
128 
listMembers(Common::ArchiveMemberList & member_list) const129 int AndroidAssetArchive::listMembers(Common::ArchiveMemberList &member_list) const {
130 	if (_cachedMembers) {
131 		member_list.insert(member_list.end(), _cachedMembers->begin(), _cachedMembers->end());
132 		return _cachedMembers->size();
133 	}
134 
135 	Common::List<Common::String> dirs;
136 	dirs.push_back("");
137 	dirs.push_back("shaders");
138 	int count = 0;
139 	while (!dirs.empty()) {
140 		Common::String currentDir = dirs.front();
141 		dirs.pop_front();
142 		AAssetDir *dir = AAssetManager_openDir(_am, currentDir.c_str());
143 		const char *file = AAssetDir_getNextFileName(dir);
144 
145 		while (file) {
146 			Common::String f(file);
147 			f = currentDir + f;
148 			member_list.push_back(getMember(f));
149 			++count;
150 			file = AAssetDir_getNextFileName(dir);
151 		}
152 		AAssetDir_close(dir);
153 	}
154 
155 	_cachedMembers = new Common::ArchiveMemberList(member_list);
156 
157 	return count;
158 }
159 
getMember(const Common::String & name) const160 const Common::ArchiveMemberPtr AndroidAssetArchive::getMember(const Common::String &name) const {
161 	return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this));
162 }
163 
createReadStreamForMember(const Common::String & path) const164 Common::SeekableReadStream *AndroidAssetArchive::createReadStreamForMember(const Common::String &path) const {
165 	if (!hasFile(path)) {
166 		return nullptr;
167 	}
168 	return new AssetInputStream(_am, path);
169 }
170 
171 #endif
172