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 case RS_A3D_CLASS_ID_SCRIPT_KERNEL_ID: 283 break; 284 case RS_A3D_CLASS_ID_SCRIPT_FIELD_ID: 285 break; 286 case RS_A3D_CLASS_ID_SCRIPT_METHOD_ID: 287 break; 288 case RS_A3D_CLASS_ID_SCRIPT_GROUP: 289 break; 290 } 291 if (entry->mRsObj) { 292 entry->mRsObj->incUserRef(); 293 } 294 return entry->mRsObj; 295 } 296 297 bool FileA3D::writeFile(const char *filename) { 298 if (!mWriteStream) { 299 ALOGE("No objects to write\n"); 300 return false; 301 } 302 if (mWriteStream->getPos() == 0) { 303 ALOGE("No objects to write\n"); 304 return false; 305 } 306 307 FILE *writeHandle = fopen(filename, "wb"); 308 if (!writeHandle) { 309 ALOGE("Couldn't open the file for writing\n"); 310 return false; 311 } 312 313 // Open a new stream to make writing the header easier 314 OStream headerStream(5*1024, false); 315 headerStream.addU32(mMajorVersion); 316 headerStream.addU32(mMinorVersion); 317 uint32_t is64Bit = 0; 318 headerStream.addU32(is64Bit); 319 320 uint32_t writeIndexSize = mWriteIndex.size(); 321 headerStream.addU32(writeIndexSize); 322 for (uint32_t i = 0; i < writeIndexSize; i ++) { 323 headerStream.addString(&mWriteIndex[i]->mObjectName); 324 headerStream.addU32((uint32_t)mWriteIndex[i]->mType); 325 if (mUse64BitOffsets){ 326 headerStream.addOffset(mWriteIndex[i]->mOffset); 327 headerStream.addOffset(mWriteIndex[i]->mLength); 328 } else { 329 uint32_t offset = (uint32_t)mWriteIndex[i]->mOffset; 330 headerStream.addU32(offset); 331 offset = (uint32_t)mWriteIndex[i]->mLength; 332 headerStream.addU32(offset); 333 } 334 } 335 336 // Write our magic string so we know we are reading the right file 337 String8 magicString(A3D_MAGIC_KEY); 338 fwrite(magicString.string(), sizeof(char), magicString.size(), writeHandle); 339 340 // Store the size of the header to make it easier to parse when we read it 341 uint64_t headerSize = headerStream.getPos(); 342 fwrite(&headerSize, sizeof(headerSize), 1, writeHandle); 343 344 // Now write our header 345 fwrite(headerStream.getPtr(), sizeof(uint8_t), headerStream.getPos(), writeHandle); 346 347 // Now write the size of the data part of the file for easier parsing later 348 uint64_t fileDataSize = mWriteStream->getPos(); 349 fwrite(&fileDataSize, sizeof(fileDataSize), 1, writeHandle); 350 351 fwrite(mWriteStream->getPtr(), sizeof(uint8_t), mWriteStream->getPos(), writeHandle); 352 353 int status = fclose(writeHandle); 354 355 if (status != 0) { 356 ALOGE("Couldn't close file\n"); 357 return false; 358 } 359 360 return true; 361 } 362 363 void FileA3D::appendToFile(Context *con, ObjectBase *obj) { 364 if (!obj) { 365 return; 366 } 367 if (!mWriteStream) { 368 const uint64_t initialStreamSize = 256*1024; 369 mWriteStream = new OStream(initialStreamSize, false); 370 } 371 A3DIndexEntry *indexEntry = new A3DIndexEntry(); 372 indexEntry->mObjectName.setTo(obj->getName()); 373 indexEntry->mType = obj->getClassId(); 374 indexEntry->mOffset = mWriteStream->getPos(); 375 indexEntry->mRsObj = obj; 376 mWriteIndex.push(indexEntry); 377 obj->serialize(con, mWriteStream); 378 indexEntry->mLength = mWriteStream->getPos() - indexEntry->mOffset; 379 mWriteStream->align(4); 380 } 381 382 RsObjectBase rsaFileA3DGetEntryByIndex(RsContext con, uint32_t index, RsFile file) { 383 FileA3D *fa3d = static_cast<FileA3D *>(file); 384 if (!fa3d) { 385 ALOGE("Can't load entry. No valid file"); 386 return NULL; 387 } 388 389 ObjectBase *obj = fa3d->initializeFromEntry(index); 390 //ALOGV("Returning object with name %s", obj->getName()); 391 392 return obj; 393 } 394 395 396 void rsaFileA3DGetNumIndexEntries(RsContext con, int32_t *numEntries, RsFile file) { 397 FileA3D *fa3d = static_cast<FileA3D *>(file); 398 399 if (fa3d) { 400 *numEntries = fa3d->getNumIndexEntries(); 401 } else { 402 *numEntries = 0; 403 } 404 } 405 406 void rsaFileA3DGetIndexEntries(RsContext con, RsFileIndexEntry *fileEntries, uint32_t numEntries, RsFile file) { 407 FileA3D *fa3d = static_cast<FileA3D *>(file); 408 409 if (!fa3d) { 410 ALOGE("Can't load index entries. No valid file"); 411 return; 412 } 413 414 uint32_t numFileEntries = fa3d->getNumIndexEntries(); 415 if (numFileEntries != numEntries || numEntries == 0 || fileEntries == NULL) { 416 ALOGE("Can't load index entries. Invalid number requested"); 417 return; 418 } 419 420 for (uint32_t i = 0; i < numFileEntries; i ++) { 421 const FileA3D::A3DIndexEntry *entry = fa3d->getIndexEntry(i); 422 fileEntries[i].classID = entry->getType(); 423 fileEntries[i].objectName = entry->getObjectName().string(); 424 } 425 } 426 427 RsFile rsaFileA3DCreateFromMemory(RsContext con, const void *data, uint32_t len) { 428 if (data == NULL) { 429 ALOGE("File load failed. Asset stream is NULL"); 430 return NULL; 431 } 432 433 Context *rsc = static_cast<Context *>(con); 434 FileA3D *fa3d = new FileA3D(rsc); 435 fa3d->incUserRef(); 436 437 fa3d->load(data, len); 438 return fa3d; 439 } 440 441 RsFile rsaFileA3DCreateFromAsset(RsContext con, void *_asset) { 442 #if !defined(__RS_PDK__) 443 Context *rsc = static_cast<Context *>(con); 444 Asset *asset = static_cast<Asset *>(_asset); 445 FileA3D *fa3d = new FileA3D(rsc); 446 fa3d->incUserRef(); 447 448 fa3d->load(asset); 449 return fa3d; 450 #else 451 return NULL; 452 #endif 453 } 454 455 RsFile rsaFileA3DCreateFromFile(RsContext con, const char *path) { 456 if (path == NULL) { 457 ALOGE("File load failed. Path is NULL"); 458 return NULL; 459 } 460 461 Context *rsc = static_cast<Context *>(con); 462 FileA3D *fa3d = NULL; 463 464 FILE *f = fopen(path, "rb"); 465 if (f) { 466 fa3d = new FileA3D(rsc); 467 fa3d->incUserRef(); 468 fa3d->load(f); 469 fclose(f); 470 } else { 471 ALOGE("Could not open file %s", path); 472 } 473 474 return fa3d; 475 } 476