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 #include <inttypes.h> 26 27 namespace android { 28 namespace renderscript { 29 30 FileA3D::FileA3D(Context *rsc) : ObjectBase(rsc) { 31 mAlloc = nullptr; 32 mData = nullptr; 33 mWriteStream = nullptr; 34 mReadStream = nullptr; 35 36 mMajorVersion = 0; 37 mMinorVersion = 1; 38 mDataSize = 0; 39 } 40 41 FileA3D::~FileA3D() { 42 for (size_t i = 0; i < mIndex.size(); i ++) { 43 delete mIndex[i]; 44 } 45 for (size_t i = 0; i < mWriteIndex.size(); i ++) { 46 delete mWriteIndex[i]; 47 } 48 if (mWriteStream) { 49 delete mWriteStream; 50 } 51 if (mReadStream) { 52 delete mReadStream; 53 } 54 if (mAlloc) { 55 free(mAlloc); 56 } 57 } 58 59 void FileA3D::parseHeader(IStream *headerStream) { 60 mMajorVersion = headerStream->loadU32(); 61 mMinorVersion = headerStream->loadU32(); 62 uint32_t flags = headerStream->loadU32(); 63 mUse64BitOffsets = (flags & 1) != 0; 64 65 uint32_t numIndexEntries = headerStream->loadU32(); 66 for (uint32_t i = 0; i < numIndexEntries; i ++) { 67 A3DIndexEntry *entry = new A3DIndexEntry(); 68 entry->mObjectName = headerStream->loadString(); 69 70 //ALOGV("Header data, entry name = %s", entry->mObjectName.string()); 71 entry->mType = (RsA3DClassID)headerStream->loadU32(); 72 if (mUse64BitOffsets){ 73 entry->mOffset = headerStream->loadOffset(); 74 entry->mLength = headerStream->loadOffset(); 75 } else { 76 entry->mOffset = headerStream->loadU32(); 77 entry->mLength = headerStream->loadU32(); 78 } 79 entry->mRsObj = nullptr; 80 mIndex.push_back(entry); 81 } 82 } 83 84 bool FileA3D::load(Asset *asset) { 85 return false; 86 } 87 88 bool FileA3D::load(const void *data, size_t length) { 89 const uint8_t *localData = (const uint8_t *)data; 90 91 size_t lengthRemaining = length; 92 size_t magicStrLen = 12; 93 if ((length < magicStrLen) || 94 memcmp(data, "Android3D_ff", magicStrLen)) { 95 return false; 96 } 97 98 localData += magicStrLen; 99 lengthRemaining -= magicStrLen; 100 101 // Next we get our header size 102 uint64_t headerSize = 0; 103 if (lengthRemaining < sizeof(headerSize)) { 104 return false; 105 } 106 107 memcpy(&headerSize, localData, sizeof(headerSize)); 108 localData += sizeof(headerSize); 109 lengthRemaining -= sizeof(headerSize); 110 111 if (lengthRemaining < headerSize) { 112 return false; 113 } 114 115 // Now open the stream to parse the header 116 IStream headerStream(localData, false); 117 parseHeader(&headerStream); 118 119 localData += headerSize; 120 lengthRemaining -= headerSize; 121 122 if (lengthRemaining < sizeof(mDataSize)) { 123 return false; 124 } 125 126 // Read the size of the data 127 memcpy(&mDataSize, localData, sizeof(mDataSize)); 128 localData += sizeof(mDataSize); 129 lengthRemaining -= sizeof(mDataSize); 130 131 if (lengthRemaining < mDataSize) { 132 return false; 133 } 134 135 // We should know enough to read the file in at this point. 136 mData = (uint8_t *)localData; 137 mReadStream = new IStream(mData, mUse64BitOffsets); 138 139 return true; 140 } 141 142 bool FileA3D::load(FILE *f) { 143 char magicString[12]; 144 size_t len; 145 146 ALOGV("file open 1"); 147 len = fread(magicString, 1, 12, f); 148 if ((len != 12) || 149 memcmp(magicString, "Android3D_ff", 12)) { 150 return false; 151 } 152 153 // Next thing is the size of the header 154 uint64_t headerSize = 0; 155 len = fread(&headerSize, 1, sizeof(headerSize), f); 156 if (len != sizeof(headerSize) || headerSize == 0) { 157 return false; 158 } 159 160 uint8_t *headerData = (uint8_t *)malloc(headerSize); 161 if (!headerData) { 162 return false; 163 } 164 165 len = fread(headerData, 1, headerSize, f); 166 if (len != headerSize) { 167 free(headerData); 168 return false; 169 } 170 171 // Now open the stream to parse the header 172 IStream headerStream(headerData, false); 173 parseHeader(&headerStream); 174 175 free(headerData); 176 177 // Next thing is the size of the header 178 len = fread(&mDataSize, 1, sizeof(mDataSize), f); 179 if (len != sizeof(mDataSize) || mDataSize == 0) { 180 return false; 181 } 182 183 ALOGV("file open size = %" PRIi64, mDataSize); 184 185 // We should know enough to read the file in at this point. 186 mAlloc = malloc(mDataSize); 187 if (!mAlloc) { 188 return false; 189 } 190 mData = (uint8_t *)mAlloc; 191 len = fread(mAlloc, 1, mDataSize, f); 192 if (len != mDataSize) { 193 return false; 194 } 195 196 mReadStream = new IStream(mData, mUse64BitOffsets); 197 198 ALOGV("Header is read an stream initialized"); 199 return true; 200 } 201 202 size_t FileA3D::getNumIndexEntries() const { 203 return mIndex.size(); 204 } 205 206 FileA3D::A3DIndexEntry::~A3DIndexEntry() { 207 delete[] mObjectName; 208 } 209 210 const FileA3D::A3DIndexEntry *FileA3D::getIndexEntry(size_t index) const { 211 if (index < mIndex.size()) { 212 return mIndex[index]; 213 } 214 return nullptr; 215 } 216 217 ObjectBase *FileA3D::initializeFromEntry(size_t index) { 218 if (index >= mIndex.size()) { 219 return nullptr; 220 } 221 222 FileA3D::A3DIndexEntry *entry = mIndex[index]; 223 if (!entry) { 224 return nullptr; 225 } 226 227 if (entry->mRsObj) { 228 entry->mRsObj->incUserRef(); 229 return entry->mRsObj; 230 } 231 232 // Seek to the beginning of object 233 mReadStream->reset(entry->mOffset); 234 switch (entry->mType) { 235 case RS_A3D_CLASS_ID_UNKNOWN: 236 return nullptr; 237 case RS_A3D_CLASS_ID_MESH: 238 entry->mRsObj = Mesh::createFromStream(mRSC, mReadStream); 239 break; 240 case RS_A3D_CLASS_ID_TYPE: 241 entry->mRsObj = Type::createFromStream(mRSC, mReadStream); 242 break; 243 case RS_A3D_CLASS_ID_ELEMENT: 244 entry->mRsObj = Element::createFromStream(mRSC, mReadStream); 245 break; 246 case RS_A3D_CLASS_ID_ALLOCATION: 247 entry->mRsObj = Allocation::createFromStream(mRSC, mReadStream); 248 break; 249 case RS_A3D_CLASS_ID_PROGRAM_VERTEX: 250 //entry->mRsObj = ProgramVertex::createFromStream(mRSC, mReadStream); 251 break; 252 case RS_A3D_CLASS_ID_PROGRAM_RASTER: 253 //entry->mRsObj = ProgramRaster::createFromStream(mRSC, mReadStream); 254 break; 255 case RS_A3D_CLASS_ID_PROGRAM_FRAGMENT: 256 //entry->mRsObj = ProgramFragment::createFromStream(mRSC, mReadStream); 257 break; 258 case RS_A3D_CLASS_ID_PROGRAM_STORE: 259 //entry->mRsObj = ProgramStore::createFromStream(mRSC, mReadStream); 260 break; 261 case RS_A3D_CLASS_ID_SAMPLER: 262 //entry->mRsObj = Sampler::createFromStream(mRSC, mReadStream); 263 break; 264 case RS_A3D_CLASS_ID_ANIMATION: 265 //entry->mRsObj = Animation::createFromStream(mRSC, mReadStream); 266 break; 267 case RS_A3D_CLASS_ID_ADAPTER_1D: 268 //entry->mRsObj = Adapter1D::createFromStream(mRSC, mReadStream); 269 break; 270 case RS_A3D_CLASS_ID_ADAPTER_2D: 271 //entry->mRsObj = Adapter2D::createFromStream(mRSC, mReadStream); 272 break; 273 case RS_A3D_CLASS_ID_SCRIPT_C: 274 break; 275 case RS_A3D_CLASS_ID_SCRIPT_KERNEL_ID: 276 break; 277 case RS_A3D_CLASS_ID_SCRIPT_INVOKE_ID: 278 break; 279 case RS_A3D_CLASS_ID_SCRIPT_FIELD_ID: 280 break; 281 case RS_A3D_CLASS_ID_SCRIPT_METHOD_ID: 282 break; 283 case RS_A3D_CLASS_ID_SCRIPT_GROUP: 284 break; 285 case RS_A3D_CLASS_ID_CLOSURE: 286 break; 287 case RS_A3D_CLASS_ID_SCRIPT_GROUP2: 288 break; 289 } 290 if (entry->mRsObj) { 291 entry->mRsObj->incUserRef(); 292 } 293 return entry->mRsObj; 294 } 295 296 bool FileA3D::writeFile(const char *filename) { 297 if (!mWriteStream) { 298 ALOGE("No objects to write\n"); 299 return false; 300 } 301 if (mWriteStream->getPos() == 0) { 302 ALOGE("No objects to write\n"); 303 return false; 304 } 305 306 FILE *writeHandle = fopen(filename, "wbe"); 307 if (!writeHandle) { 308 ALOGE("Couldn't open the file for writing\n"); 309 return false; 310 } 311 312 // Open a new stream to make writing the header easier 313 OStream headerStream(5*1024, false); 314 headerStream.addU32(mMajorVersion); 315 headerStream.addU32(mMinorVersion); 316 uint32_t is64Bit = 0; 317 headerStream.addU32(is64Bit); 318 319 uint32_t writeIndexSize = mWriteIndex.size(); 320 headerStream.addU32(writeIndexSize); 321 for (uint32_t i = 0; i < writeIndexSize; i ++) { 322 headerStream.addString(mWriteIndex[i]->mObjectName); 323 headerStream.addU32((uint32_t)mWriteIndex[i]->mType); 324 if (mUse64BitOffsets){ 325 headerStream.addOffset(mWriteIndex[i]->mOffset); 326 headerStream.addOffset(mWriteIndex[i]->mLength); 327 } else { 328 uint32_t offset = (uint32_t)mWriteIndex[i]->mOffset; 329 headerStream.addU32(offset); 330 offset = (uint32_t)mWriteIndex[i]->mLength; 331 headerStream.addU32(offset); 332 } 333 } 334 335 // Write our magic string so we know we are reading the right file 336 fwrite(A3D_MAGIC_KEY, sizeof(char), strlen(A3D_MAGIC_KEY), writeHandle); 337 338 // Store the size of the header to make it easier to parse when we read it 339 uint64_t headerSize = headerStream.getPos(); 340 fwrite(&headerSize, sizeof(headerSize), 1, writeHandle); 341 342 // Now write our header 343 fwrite(headerStream.getPtr(), sizeof(uint8_t), headerStream.getPos(), writeHandle); 344 345 // Now write the size of the data part of the file for easier parsing later 346 uint64_t fileDataSize = mWriteStream->getPos(); 347 fwrite(&fileDataSize, sizeof(fileDataSize), 1, writeHandle); 348 349 fwrite(mWriteStream->getPtr(), sizeof(uint8_t), mWriteStream->getPos(), writeHandle); 350 351 int status = fclose(writeHandle); 352 353 if (status != 0) { 354 ALOGE("Couldn't close file\n"); 355 return false; 356 } 357 358 return true; 359 } 360 361 void FileA3D::appendToFile(Context *con, ObjectBase *obj) { 362 if (!obj) { 363 return; 364 } 365 if (!mWriteStream) { 366 const uint64_t initialStreamSize = 256*1024; 367 mWriteStream = new OStream(initialStreamSize, false); 368 } 369 A3DIndexEntry *indexEntry = new A3DIndexEntry(); 370 indexEntry->mObjectName = rsuCopyString(obj->getName()); 371 indexEntry->mType = obj->getClassId(); 372 indexEntry->mOffset = mWriteStream->getPos(); 373 indexEntry->mRsObj = obj; 374 mWriteIndex.push_back(indexEntry); 375 obj->serialize(con, mWriteStream); 376 indexEntry->mLength = mWriteStream->getPos() - indexEntry->mOffset; 377 mWriteStream->align(4); 378 } 379 380 } // namespace renderscript 381 } // namespace android 382