1
2 /*
3 * Copyright (C) 2009 The Android Open Source Project
4 *
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17
18 #include "rsContext.h"
19 #include "rsFileA3D.h"
20
21 #include "rsMesh.h"
22 #include "rsAnimation.h"
23
24
25 using namespace android;
26 using namespace android::renderscript;
27
FileA3D(Context * rsc)28 FileA3D::FileA3D(Context *rsc) : ObjectBase(rsc) {
29 mAlloc = NULL;
30 mData = NULL;
31 mWriteStream = NULL;
32 mReadStream = NULL;
33 mAsset = NULL;
34
35 mMajorVersion = 0;
36 mMinorVersion = 1;
37 mDataSize = 0;
38 }
39
~FileA3D()40 FileA3D::~FileA3D() {
41 for (size_t i = 0; i < mIndex.size(); i ++) {
42 delete mIndex[i];
43 }
44 for (size_t i = 0; i < mWriteIndex.size(); i ++) {
45 delete mWriteIndex[i];
46 }
47 if (mWriteStream) {
48 delete mWriteStream;
49 }
50 if (mReadStream) {
51 delete mWriteStream;
52 }
53 if (mAlloc) {
54 free(mAlloc);
55 }
56 if (mAsset) {
57 delete mAsset;
58 }
59 }
60
parseHeader(IStream * headerStream)61 void FileA3D::parseHeader(IStream *headerStream) {
62 mMajorVersion = headerStream->loadU32();
63 mMinorVersion = headerStream->loadU32();
64 uint32_t flags = headerStream->loadU32();
65 mUse64BitOffsets = (flags & 1) != 0;
66
67 uint32_t numIndexEntries = headerStream->loadU32();
68 for (uint32_t i = 0; i < numIndexEntries; i ++) {
69 A3DIndexEntry *entry = new A3DIndexEntry();
70 headerStream->loadString(&entry->mObjectName);
71 //LOGV("Header data, entry name = %s", entry->mObjectName.string());
72 entry->mType = (RsA3DClassID)headerStream->loadU32();
73 if (mUse64BitOffsets){
74 entry->mOffset = headerStream->loadOffset();
75 entry->mLength = headerStream->loadOffset();
76 } else {
77 entry->mOffset = headerStream->loadU32();
78 entry->mLength = headerStream->loadU32();
79 }
80 entry->mRsObj = NULL;
81 mIndex.push(entry);
82 }
83 }
84
load(Asset * asset)85 bool FileA3D::load(Asset *asset) {
86 mAsset = asset;
87 return load(asset->getBuffer(false), asset->getLength());
88 }
89
load(const void * data,size_t length)90 bool FileA3D::load(const void *data, size_t length) {
91 const uint8_t *localData = (const uint8_t *)data;
92
93 size_t lengthRemaining = length;
94 size_t magicStrLen = 12;
95 if ((length < magicStrLen) ||
96 memcmp(data, "Android3D_ff", magicStrLen)) {
97 return false;
98 }
99
100 localData += magicStrLen;
101 lengthRemaining -= magicStrLen;
102
103 // Next we get our header size
104 uint64_t headerSize = 0;
105 if (lengthRemaining < sizeof(headerSize)) {
106 return false;
107 }
108
109 memcpy(&headerSize, localData, sizeof(headerSize));
110 localData += sizeof(headerSize);
111 lengthRemaining -= sizeof(headerSize);
112
113 if (lengthRemaining < headerSize) {
114 return false;
115 }
116
117 // Now open the stream to parse the header
118 IStream headerStream(localData, false);
119 parseHeader(&headerStream);
120
121 localData += headerSize;
122 lengthRemaining -= headerSize;
123
124 if (lengthRemaining < sizeof(mDataSize)) {
125 return false;
126 }
127
128 // Read the size of the data
129 memcpy(&mDataSize, localData, sizeof(mDataSize));
130 localData += sizeof(mDataSize);
131 lengthRemaining -= sizeof(mDataSize);
132
133 if (lengthRemaining < mDataSize) {
134 return false;
135 }
136
137 // We should know enough to read the file in at this point.
138 mData = (uint8_t *)localData;
139 mReadStream = new IStream(mData, mUse64BitOffsets);
140
141 return true;
142 }
143
load(FILE * f)144 bool FileA3D::load(FILE *f) {
145 char magicString[12];
146 size_t len;
147
148 LOGV("file open 1");
149 len = fread(magicString, 1, 12, f);
150 if ((len != 12) ||
151 memcmp(magicString, "Android3D_ff", 12)) {
152 return false;
153 }
154
155 // Next thing is the size of the header
156 uint64_t headerSize = 0;
157 len = fread(&headerSize, 1, sizeof(headerSize), f);
158 if (len != sizeof(headerSize) || headerSize == 0) {
159 return false;
160 }
161
162 uint8_t *headerData = (uint8_t *)malloc(headerSize);
163 if (!headerData) {
164 return false;
165 }
166
167 len = fread(headerData, 1, headerSize, f);
168 if (len != headerSize) {
169 return false;
170 }
171
172 // Now open the stream to parse the header
173 IStream headerStream(headerData, false);
174 parseHeader(&headerStream);
175
176 free(headerData);
177
178 // Next thing is the size of the header
179 len = fread(&mDataSize, 1, sizeof(mDataSize), f);
180 if (len != sizeof(mDataSize) || mDataSize == 0) {
181 return false;
182 }
183
184 LOGV("file open size = %lli", mDataSize);
185
186 // We should know enough to read the file in at this point.
187 mAlloc = malloc(mDataSize);
188 if (!mAlloc) {
189 return false;
190 }
191 mData = (uint8_t *)mAlloc;
192 len = fread(mAlloc, 1, mDataSize, f);
193 if (len != mDataSize) {
194 return false;
195 }
196
197 mReadStream = new IStream(mData, mUse64BitOffsets);
198
199 LOGV("Header is read an stream initialized");
200 return true;
201 }
202
getNumIndexEntries() const203 size_t FileA3D::getNumIndexEntries() const {
204 return mIndex.size();
205 }
206
getIndexEntry(size_t index) const207 const FileA3D::A3DIndexEntry *FileA3D::getIndexEntry(size_t index) const {
208 if (index < mIndex.size()) {
209 return mIndex[index];
210 }
211 return NULL;
212 }
213
initializeFromEntry(size_t index)214 ObjectBase *FileA3D::initializeFromEntry(size_t index) {
215 if (index >= mIndex.size()) {
216 return NULL;
217 }
218
219 FileA3D::A3DIndexEntry *entry = mIndex[index];
220 if (!entry) {
221 return NULL;
222 }
223
224 if (entry->mRsObj) {
225 entry->mRsObj->incUserRef();
226 return entry->mRsObj;
227 }
228
229 // Seek to the beginning of object
230 mReadStream->reset(entry->mOffset);
231 switch (entry->mType) {
232 case RS_A3D_CLASS_ID_UNKNOWN:
233 return NULL;
234 case RS_A3D_CLASS_ID_MESH:
235 entry->mRsObj = Mesh::createFromStream(mRSC, mReadStream);
236 break;
237 case RS_A3D_CLASS_ID_TYPE:
238 entry->mRsObj = Type::createFromStream(mRSC, mReadStream);
239 break;
240 case RS_A3D_CLASS_ID_ELEMENT:
241 entry->mRsObj = Element::createFromStream(mRSC, mReadStream);
242 break;
243 case RS_A3D_CLASS_ID_ALLOCATION:
244 entry->mRsObj = Allocation::createFromStream(mRSC, mReadStream);
245 break;
246 case RS_A3D_CLASS_ID_PROGRAM_VERTEX:
247 //entry->mRsObj = ProgramVertex::createFromStream(mRSC, mReadStream);
248 break;
249 case RS_A3D_CLASS_ID_PROGRAM_RASTER:
250 //entry->mRsObj = ProgramRaster::createFromStream(mRSC, mReadStream);
251 break;
252 case RS_A3D_CLASS_ID_PROGRAM_FRAGMENT:
253 //entry->mRsObj = ProgramFragment::createFromStream(mRSC, mReadStream);
254 break;
255 case RS_A3D_CLASS_ID_PROGRAM_STORE:
256 //entry->mRsObj = ProgramStore::createFromStream(mRSC, mReadStream);
257 break;
258 case RS_A3D_CLASS_ID_SAMPLER:
259 //entry->mRsObj = Sampler::createFromStream(mRSC, mReadStream);
260 break;
261 case RS_A3D_CLASS_ID_ANIMATION:
262 //entry->mRsObj = Animation::createFromStream(mRSC, mReadStream);
263 break;
264 case RS_A3D_CLASS_ID_ADAPTER_1D:
265 //entry->mRsObj = Adapter1D::createFromStream(mRSC, mReadStream);
266 break;
267 case RS_A3D_CLASS_ID_ADAPTER_2D:
268 //entry->mRsObj = Adapter2D::createFromStream(mRSC, mReadStream);
269 break;
270 case RS_A3D_CLASS_ID_SCRIPT_C:
271 break;
272 }
273 if (entry->mRsObj) {
274 entry->mRsObj->incUserRef();
275 }
276 return entry->mRsObj;
277 }
278
writeFile(const char * filename)279 bool FileA3D::writeFile(const char *filename) {
280 if (!mWriteStream) {
281 LOGE("No objects to write\n");
282 return false;
283 }
284 if (mWriteStream->getPos() == 0) {
285 LOGE("No objects to write\n");
286 return false;
287 }
288
289 FILE *writeHandle = fopen(filename, "wb");
290 if (!writeHandle) {
291 LOGE("Couldn't open the file for writing\n");
292 return false;
293 }
294
295 // Open a new stream to make writing the header easier
296 OStream headerStream(5*1024, false);
297 headerStream.addU32(mMajorVersion);
298 headerStream.addU32(mMinorVersion);
299 uint32_t is64Bit = 0;
300 headerStream.addU32(is64Bit);
301
302 uint32_t writeIndexSize = mWriteIndex.size();
303 headerStream.addU32(writeIndexSize);
304 for (uint32_t i = 0; i < writeIndexSize; i ++) {
305 headerStream.addString(&mWriteIndex[i]->mObjectName);
306 headerStream.addU32((uint32_t)mWriteIndex[i]->mType);
307 if (mUse64BitOffsets){
308 headerStream.addOffset(mWriteIndex[i]->mOffset);
309 headerStream.addOffset(mWriteIndex[i]->mLength);
310 } else {
311 uint32_t offset = (uint32_t)mWriteIndex[i]->mOffset;
312 headerStream.addU32(offset);
313 offset = (uint32_t)mWriteIndex[i]->mLength;
314 headerStream.addU32(offset);
315 }
316 }
317
318 // Write our magic string so we know we are reading the right file
319 String8 magicString(A3D_MAGIC_KEY);
320 fwrite(magicString.string(), sizeof(char), magicString.size(), writeHandle);
321
322 // Store the size of the header to make it easier to parse when we read it
323 uint64_t headerSize = headerStream.getPos();
324 fwrite(&headerSize, sizeof(headerSize), 1, writeHandle);
325
326 // Now write our header
327 fwrite(headerStream.getPtr(), sizeof(uint8_t), headerStream.getPos(), writeHandle);
328
329 // Now write the size of the data part of the file for easier parsing later
330 uint64_t fileDataSize = mWriteStream->getPos();
331 fwrite(&fileDataSize, sizeof(fileDataSize), 1, writeHandle);
332
333 fwrite(mWriteStream->getPtr(), sizeof(uint8_t), mWriteStream->getPos(), writeHandle);
334
335 int status = fclose(writeHandle);
336
337 if (status != 0) {
338 LOGE("Couldn't close file\n");
339 return false;
340 }
341
342 return true;
343 }
344
appendToFile(ObjectBase * obj)345 void FileA3D::appendToFile(ObjectBase *obj) {
346 if (!obj) {
347 return;
348 }
349 if (!mWriteStream) {
350 const uint64_t initialStreamSize = 256*1024;
351 mWriteStream = new OStream(initialStreamSize, false);
352 }
353 A3DIndexEntry *indexEntry = new A3DIndexEntry();
354 indexEntry->mObjectName.setTo(obj->getName());
355 indexEntry->mType = obj->getClassId();
356 indexEntry->mOffset = mWriteStream->getPos();
357 indexEntry->mRsObj = obj;
358 mWriteIndex.push(indexEntry);
359 obj->serialize(mWriteStream);
360 indexEntry->mLength = mWriteStream->getPos() - indexEntry->mOffset;
361 mWriteStream->align(4);
362 }
363
rsaFileA3DGetEntryByIndex(RsContext con,uint32_t index,RsFile file)364 RsObjectBase rsaFileA3DGetEntryByIndex(RsContext con, uint32_t index, RsFile file) {
365 FileA3D *fa3d = static_cast<FileA3D *>(file);
366 if (!fa3d) {
367 LOGE("Can't load entry. No valid file");
368 return NULL;
369 }
370
371 ObjectBase *obj = fa3d->initializeFromEntry(index);
372 //LOGV("Returning object with name %s", obj->getName());
373
374 return obj;
375 }
376
377
rsaFileA3DGetNumIndexEntries(RsContext con,int32_t * numEntries,RsFile file)378 void rsaFileA3DGetNumIndexEntries(RsContext con, int32_t *numEntries, RsFile file) {
379 FileA3D *fa3d = static_cast<FileA3D *>(file);
380
381 if (fa3d) {
382 *numEntries = fa3d->getNumIndexEntries();
383 } else {
384 *numEntries = 0;
385 }
386 }
387
rsaFileA3DGetIndexEntries(RsContext con,RsFileIndexEntry * fileEntries,uint32_t numEntries,RsFile file)388 void rsaFileA3DGetIndexEntries(RsContext con, RsFileIndexEntry *fileEntries, uint32_t numEntries, RsFile file) {
389 FileA3D *fa3d = static_cast<FileA3D *>(file);
390
391 if (!fa3d) {
392 LOGE("Can't load index entries. No valid file");
393 return;
394 }
395
396 uint32_t numFileEntries = fa3d->getNumIndexEntries();
397 if (numFileEntries != numEntries || numEntries == 0 || fileEntries == NULL) {
398 LOGE("Can't load index entries. Invalid number requested");
399 return;
400 }
401
402 for (uint32_t i = 0; i < numFileEntries; i ++) {
403 const FileA3D::A3DIndexEntry *entry = fa3d->getIndexEntry(i);
404 fileEntries[i].classID = entry->getType();
405 fileEntries[i].objectName = entry->getObjectName().string();
406 }
407 }
408
rsaFileA3DCreateFromMemory(RsContext con,const void * data,uint32_t len)409 RsFile rsaFileA3DCreateFromMemory(RsContext con, const void *data, uint32_t len) {
410 if (data == NULL) {
411 LOGE("File load failed. Asset stream is NULL");
412 return NULL;
413 }
414
415 Context *rsc = static_cast<Context *>(con);
416 FileA3D *fa3d = new FileA3D(rsc);
417 fa3d->incUserRef();
418
419 fa3d->load(data, len);
420 return fa3d;
421 }
422
rsaFileA3DCreateFromAsset(RsContext con,void * _asset)423 RsFile rsaFileA3DCreateFromAsset(RsContext con, void *_asset) {
424 Context *rsc = static_cast<Context *>(con);
425 Asset *asset = static_cast<Asset *>(_asset);
426 FileA3D *fa3d = new FileA3D(rsc);
427 fa3d->incUserRef();
428
429 fa3d->load(asset);
430 return fa3d;
431 }
432
rsaFileA3DCreateFromFile(RsContext con,const char * path)433 RsFile rsaFileA3DCreateFromFile(RsContext con, const char *path) {
434 if (path == NULL) {
435 LOGE("File load failed. Path is NULL");
436 return NULL;
437 }
438
439 Context *rsc = static_cast<Context *>(con);
440 FileA3D *fa3d = NULL;
441
442 FILE *f = fopen(path, "rb");
443 if (f) {
444 fa3d = new FileA3D(rsc);
445 fa3d->incUserRef();
446 fa3d->load(f);
447 fclose(f);
448 } else {
449 LOGE("Could not open file %s", path);
450 }
451
452 return fa3d;
453 }
454