HIDE void deserializeSEXP(SEXP o) { _dbg(rjprintf("attempt to deserialize %p (clCL=%p, oCL=%p)\n", o, clClassLoader, oClassLoader)); SEXP s = EXTPTR_PROT(o); if (TYPEOF(s) == RAWSXP && EXTPTR_PTR(o) == NULL) { JNIEnv *env = getJNIEnv(); if (env && clClassLoader && oClassLoader) { jbyteArray ser = newByteArray(env, RAW(s), LENGTH(s)); if (ser) { jmethodID mid = (*env)->GetMethodID(env, clClassLoader, "toObject", "([B)Ljava/lang/Object;"); if (mid) { jobject res = (*env)->CallObjectMethod(env, oClassLoader, mid, ser); if (res) { jobject go = makeGlobal(env, res); _mp(MEM_PROF_OUT("R %08x RNEW %08x\n", (int) go, (int) res)) if (go) { _dbg(rjprintf(" - succeeded: %p\n", go)); /* set the deserialized object */ EXTPTR_PTR(o) = (SEXP) go; /* Note: currently we don't remove the serialized content, because it was created explicitly using .jcache to allow repeated saving. Once this is handled by a hook, we shall remove it. However, to assure compatibility TAG is always NULL for now, so we do clear the cache if TAG is non-null for future use. */ if (EXTPTR_TAG(o) != R_NilValue) { /* remove the serialized raw vector */ SETCDR(o, R_NilValue); /* Note: this is abuse of the API since it uses the fact that PROT is stored in CDR */ } } } } releaseObject(env, ser); } }
static bool decodeIndex(NexasPackage* package) { fseek(package->file, -4, SEEK_END); u32 encodedLen; if (fread(&encodedLen, sizeof(u32), 1, package->file) != 1) { writeLog(LOG_QUIET, L"ERROR: Unable to read the length of the encoded index!"); return false; } writeLog(LOG_VERBOSE, L"The length of the compressed index is %d.", encodedLen); if (fseek(package->file, -4-encodedLen, SEEK_END) != 0) { writeLog(LOG_QUIET, L"ERROR: Unable to locate the compressed index!"); return false; } ByteArray* encodedData = newByteArray(encodedLen); byte* data = baData(encodedData); if (fread(data, sizeof(byte), encodedLen, package->file) != encodedLen) { writeLog(LOG_QUIET, L"ERROR: Unable to read the compressed index!"); deleteByteArray(encodedData); return false; } for (u32 i = 0; i < encodedLen; ++i) { data[i] ^= 0xFF; } u32 decodedLen = sizeof(IndexEntry) * package->header->entryCount; ByteArray* originalIndexes = huffmanDecode(L"Entry Indexes", data, encodedLen, decodedLen); deleteByteArray(encodedData); package->indexes = originalIndexes; return (package->indexes != NULL); }
static ByteArray* decodeWithTree(const wchar_t* treeName, TreeNode tree[], BitStream* data, u32 originalLen) { u16 treeIndex = 0; u32 resIndex = 0; byte rbyte = 0; ByteArray* result = newByteArray(originalLen); while (true) { if (!bsNextBit(data, &rbyte)) { writeLog(LOG_QUIET, L"ERROR: Cannot decode the huffman code for %s: encoded data exhausted!", treeName); return false; } if (rbyte) { treeIndex = tree[treeIndex].rchild; } else { treeIndex = tree[treeIndex].lchild; } if (treeIndex >= 1024) { /// Byte value baData(result)[resIndex++] = treeIndex - 1024; treeIndex = 0; /** * The encoded data may not take up whole bytes, so there would be * some unused bits in the source array. To determine whether we have * decoded all the data we needed, we just do the following: */ if (resIndex == originalLen) { return result; } } } return NULL; }
static bool readIndex(NexasPackage* package) { /// First, try to read plain text index (used in Baldr Force EXE, PAC variant 2). writeLog(LOG_VERBOSE, L"Trying to read the index as plain text."); u32 indexesLen = package->header->entryCount * sizeof(IndexEntry); fseek(package->file, 12, SEEK_SET); package->indexes = newByteArray(indexesLen); if (fread(baData(package->indexes), sizeof(byte), indexesLen, package->file) != indexesLen) { writeLog(LOG_QUIET, L"ERROR: Unable to read the 'plain text' index!"); deleteByteArray(package->indexes); return false; } /** * If the index data is valid, the packed file contents should be immediately following, * or we can conclude that the real index data is at the end of the file and encoded. */ IndexEntry* indexes = (IndexEntry*)(baData(package->indexes)); if (indexes[0].offset != 12 + indexesLen) { writeLog(LOG_VERBOSE, L"The index is invalid, trying to read encoded index."); return decodeIndex(package); } return true; }
QScriptValue FilePrototype::readAll() { return newByteArray(thisFile()->readAll()); }
QScriptValue FilePrototype::readLine(qint64 maxSize) { return newByteArray(thisFile()->readLine(maxSize)); }
QScriptValue FilePrototype::peek(qint64 maxSize) { return newByteArray(thisFile()->peek(maxSize)); }
static bool recordAndWriteEntries(NexasPackage* package, bool isBfeFormat) { package->indexes = newByteArray(package->header->entryCount * sizeof(IndexEntry)); IndexEntry* indexes = (IndexEntry*)baData(package->indexes); u32 i = 0; u32 offset = 12; if (isBfeFormat) { /// This PAC Variant puts index first, but now we do not know /// the index, so we reserve the space. u32 len = baLength(package->indexes); for (u32 i = 0; i < len; ++i) { if (fputc('\0', package->file) == EOF) { writeLog(LOG_QUIET, L"ERROR: Unable to reserve space for the index!"); return false; } } offset += len; } struct _wfinddata_t foundFile; intptr_t handle = _wfindfirst(L"*", &foundFile); int status = 0; while (status == 0) { if ((foundFile.attrib & _A_SUBDIR) == 0) { char* fname = toMBString(foundFile.name, L"japanese"); if (strlen(fname) >= 64) { writeLog(LOG_QUIET, L"ERROR: Entry %u: %s, The file name is too long!", i, foundFile.name); free(fname); return false; } strncpy(indexes[i].name, fname, 64); free(fname); indexes[i].encodedLen = foundFile.size; indexes[i].decodedLen = foundFile.size; indexes[i].offset = offset; writeLog(LOG_VERBOSE, L"Entry %u: %s, Offset: %u, OLen: %u", i, foundFile.name, indexes[i].offset, indexes[i].decodedLen); FILE* infile = _wfopen(foundFile.name, L"rb"); byte* decodedData = malloc(indexes[i].decodedLen); if (fread(decodedData, 1, indexes[i].decodedLen, infile) != indexes[i].decodedLen) { writeLog(LOG_QUIET, L"ERROR: Entry %u: %s, Unable to read the file!", i, foundFile.name); free(decodedData); fclose(infile); return false; } fclose(infile); byte* encodedData = NULL; ByteArray* encodedArray = NULL; if (isBfeFormat) { encodedArray = lzssEncode(decodedData, indexes[i].decodedLen); encodedData = baData(encodedArray); indexes[i].encodedLen = baLength(encodedArray); } else if (shouldZip(foundFile.name)) { encodedData = malloc(indexes[i].decodedLen); unsigned long len = indexes[i].encodedLen; if (compress(encodedData, &len, decodedData, indexes[i].decodedLen) != Z_OK) { free(encodedData); free(decodedData); return false; } indexes[i].encodedLen = len; writeLog(LOG_VERBOSE, L"Entry %u is compressed: ELen: %u", i, len); } else { encodedData = decodedData; } offset += indexes[i].encodedLen; writeLog(LOG_VERBOSE, L"Entry %u: ELen: %u", i, indexes[i].encodedLen); if (fwrite(encodedData, 1, indexes[i].encodedLen, package->file) != indexes[i].encodedLen) { writeLog(LOG_QUIET, L"ERROR: Entry %u: %s, Unable to write to the package!", i, foundFile.name); if (encodedArray != NULL) { deleteByteArray(encodedArray); } else if (encodedData != decodedData) { free(encodedData); } free(decodedData); return false; } if (encodedArray != NULL) { deleteByteArray(encodedArray); } else if (encodedData != decodedData) { free(encodedData); } free(decodedData); writeLog(LOG_NORMAL, L"Packed: Entry %u: %s.", i, foundFile.name); ++i; } status = _wfindnext(handle, &foundFile); } _findclose(handle); return true; }
static bool extractFiles(NexasPackage* package, const wchar_t* targetDir) { IndexEntry* indexes = (IndexEntry*)baData(package->indexes); u32 count = package->header->entryCount; for (u32 i = 0; i < count; ++i) { wchar_t* wName = toWCString(indexes[i].name, L"japanese"); writeLog(LOG_VERBOSE, L"Entry %u: %s, Offset: %u, ELen: %u, DLen: %u", i, wName, indexes[i].offset, indexes[i].encodedLen, indexes[i].decodedLen); if (fseek(package->file, indexes[i].offset, SEEK_SET) != 0) { writeLog(LOG_QUIET, L"ERROR: Entry %u: %s, Unable to locate data!", i, wName); cleanupForEntry(wName, NULL, NULL, NULL, false); return false; } ByteArray* encodedData = newByteArray(indexes[i].encodedLen); ByteArray* decodedData = encodedData; if (fread(baData(encodedData), 1, indexes[i].encodedLen, package->file) != indexes[i].encodedLen) { writeLog(LOG_QUIET, L"ERROR: Entry %u: %s, Unable to read data from package!", i, wName); cleanupForEntry(wName, NULL, encodedData, NULL, false); return false; } /** * Now we support two PAC variants. * The first is Variant 4, where contents are either uncompressed (like ogg files), * or compressed using zlib (the deflate algorithm). * We should do a test to determine if the particular file is compressed or not. */ if (package->header->variantTag == CONTENT_MAYBE_DEFLATE) { unsigned long decodedLen = indexes[i].decodedLen; if (decodedLen > indexes[i].encodedLen) { decodedData = newByteArray(decodedLen); if (uncompress(baData(decodedData), &decodedLen, baData(encodedData), indexes[i].encodedLen) != Z_OK) { writeLog(LOG_QUIET, L"ERROR: Entry %u: %s, Unable to extract data!", i, wName); cleanupForEntry(wName, NULL, encodedData, decodedData, false); return false; } } } else if (package->header->variantTag == CONTENT_LZSS) { decodedData = lzssDecode(baData(encodedData), indexes[i].encodedLen, indexes[i].decodedLen); if (decodedData == NULL) { writeLog(LOG_QUIET, L"ERROR: Entry %u: %s, Unable to extract data!", i, wName); cleanupForEntry(wName, NULL, encodedData, decodedData, false); return false; } } wchar_t* wPath = fsCombinePath(targetDir, wName); FILE* outFile = _wfopen(wPath, L"wb"); if (outFile == NULL) { writeLog(LOG_QUIET, L"ERROR: Entry %u: %s, Unable to open output file!", i, wName); cleanupForEntry(wName, wPath, encodedData, decodedData, false); return false; } if (fwrite(baData(decodedData), 1, indexes[i].decodedLen, outFile) != indexes[i].decodedLen) { writeLog(LOG_QUIET, L"ERROR: Entry %u: %s, Unable to write file content!", i, wName); cleanupForEntry(wName, wPath, encodedData, decodedData, false); fclose(outFile); return false; } fclose(outFile); writeLog(LOG_NORMAL, L"Unpacked: Entry %u: %s", i, wName); cleanupForEntry(wName, wPath, encodedData, decodedData, true); } return true; }