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