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