rsFileA3D.cpp revision 77d9f4bd05b2d2a161f30c12a2248f9c97eaac42
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 25using namespace android; 26using namespace android::renderscript; 27 28FileA3D::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 40FileA3D::~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 61void 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 85bool FileA3D::load(Asset *asset) { 86 mAsset = asset; 87 return load(asset->getBuffer(false), asset->getLength()); 88} 89 90bool 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 144bool 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 203size_t FileA3D::getNumIndexEntries() const { 204 return mIndex.size(); 205} 206 207const FileA3D::A3DIndexEntry *FileA3D::getIndexEntry(size_t index) const { 208 if (index < mIndex.size()) { 209 return mIndex[index]; 210 } 211 return NULL; 212} 213 214ObjectBase *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 279bool 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 345void 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 364RsObjectBase 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 378void 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 388void 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 409RsFile 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 423RsFile 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 433RsFile 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