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