• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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