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