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