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