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