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