/** \details creates a DATA_BLOB in uncompressed Rich Text Format (RTF) from the compressed format used in the PR_RTF_COMPRESSED property opened in the stream. \param obj_stream stream object with RTF stream content \param rtf the output blob with uncompressed content \return MAPI_E_SUCCESS on success, otherwise MAPI error. Possible MAPI error codes are: - MAPI_E_NOT_INITIALIZED: MAPI subsystem has not been initialized - MAPI_E_INVALID_PARAMETER: obj_stream is not a valid pointer - MAPI_E_CORRUPT_DATA: a problem was encountered while decompressing the RTF compressed data - MAPI_E_CALL_FAILED: A network problem was encountered during the transaction \note Developers may also call GetLastError() to retrieve the last MAPI error code. \note rtf->data needs to be freed with MAPIFreeBuffer \sa OpenStream */ _PUBLIC_ enum MAPISTATUS WrapCompressedRTFStream(mapi_object_t *obj_stream, DATA_BLOB *rtf) { enum MAPISTATUS retval; struct mapi_context *mapi_ctx; struct mapi_session *session; TALLOC_CTX *mem_ctx; uint32_t in_size; uint8_t *rtfcomp; uint16_t read_size; unsigned char buf[0x1000]; /* sanity check and init */ OPENCHANGE_RETVAL_IF(!obj_stream, MAPI_E_INVALID_PARAMETER, NULL); session = mapi_object_get_session(obj_stream); OPENCHANGE_RETVAL_IF(!session, MAPI_E_NOT_INITIALIZED, NULL); mapi_ctx = session->mapi_ctx; OPENCHANGE_RETVAL_IF(!mapi_ctx, MAPI_E_NOT_INITIALIZED, NULL); mem_ctx = mapi_ctx->mem_ctx; /* Read the stream pointed by obj_stream */ read_size = 0; in_size = 0; rtfcomp = talloc_zero(mem_ctx, uint8_t); do { retval = ReadStream(obj_stream, buf, 0x1000, &read_size); OPENCHANGE_RETVAL_IF(retval, GetLastError(), rtf->data); if (read_size) { rtfcomp = talloc_realloc(mem_ctx, rtfcomp, uint8_t, in_size + read_size); memcpy(&(rtfcomp[in_size]), buf, read_size); in_size += read_size; } } while (read_size); return uncompress_rtf(mem_ctx, rtfcomp, in_size, rtf); }
/** \details Test the Compressed RTF decompression routine. This function: -# Loads some test data and checks it -# Decompresses the test data -# Checks that the decompressed data matches the expected result \param mt pointer on the top-level mapitest structure \return true on success, otherwise false */ _PUBLIC_ bool mapitest_noserver_lzfu(struct mapitest *mt) { enum MAPISTATUS retval; DATA_BLOB uncompressed1; DATA_BLOB uncompressed2; uint8_t compressed_hex[1024]; uint8_t *compressed; uint32_t compressed_length; compressed = talloc_array(mt->mem_ctx, uint8_t, 1024); memcpy(compressed_hex, RTF_COMPRESSED1_HEX, 98); compressed_length = strhex_to_str((char*)compressed, 1024, (char*)compressed_hex, 98); if (compressed_length != 49) { mapitest_print(mt, "* %-40s: uncompress RTF - Bad length\n", "LZFU"); return false; } uint32_t crc = calculateCRC(compressed, 0x10, (49-0x10)); if (crc == 0xA7C7C5F1) { mapitest_print(mt, "* CRC pass\n"); } else { mapitest_print(mt, "* CRC failure, expected 0xA7C7C5F1, but got 0x%08X\n", crc); } retval = uncompress_rtf(mt->mem_ctx, compressed, compressed_length, &uncompressed1); if (retval != MAPI_E_SUCCESS) { mapitest_print_retval(mt, "uncompress_rtf - step 1 (bad retval)"); return false; } if (sizeof(RTF_UNCOMPRESSED1) != uncompressed1.length) { mapitest_print(mt, "* %-40s: FAILED (bad length: %i vs %i)\n", "uncompress_rtf - step 1", sizeof(RTF_UNCOMPRESSED1), uncompressed1.length); return false; } if (!strncmp((char*)uncompressed1.data, RTF_UNCOMPRESSED1, uncompressed1.length)) { mapitest_print(mt, "* %-40s: PASSED\n", "uncompress_rtf - step 1"); } else { mapitest_print(mt, "* %-40s: FAILED - %s\n", "uncompress_rtf - step 1", (char*)uncompressed1.data); return false; } memcpy(compressed_hex, RTF_COMPRESSED2_HEX, 60); compressed_length = strhex_to_str((char*)compressed, 1024, (char*)compressed_hex, 60); if (compressed_length != 30) { mapitest_print(mt, "* %-40s: uncompress RTF - Bad length\n", "LZFU"); return false; } retval = uncompress_rtf(mt->mem_ctx, compressed, compressed_length, &uncompressed2); if (retval != MAPI_E_SUCCESS) { mapitest_print_retval(mt, "uncompress_rtf - step 2 (bad retval)"); return false; } if (!strncmp((char*)uncompressed2.data, RTF_UNCOMPRESSED2, uncompressed2.length)) { mapitest_print(mt, "* %-40s: PASSED\n", "uncompress_rtf - step 2"); } else { mapitest_print(mt, "* %-40s: FAILED - %s\n", "uncompress_rtf - step 2", (char*)uncompressed2.data); return false; } /* TODO: add an uncompressed test here */ return true; }
/** \details Test the Compressed RTF compression / decompression routines on a larger file \param mt pointer to the top-level mapitest structure \return true on success, otherwise false */ _PUBLIC_ bool mapitest_noserver_rtfcp_large(struct mapitest *mt) { enum MAPISTATUS retval; char *filename = NULL; char *original_uncompressed_data; size_t original_uncompressed_length; char *original_uncompressed_hex; uint8_t *compressed; size_t compressed_length; DATA_BLOB decompressed; char *decompressed_hex; /* load the test file */ filename = talloc_asprintf(mt->mem_ctx, "%s/testcase.rtf", LZFU_DATADIR); original_uncompressed_data = file_load(filename, &original_uncompressed_length, 0, mt->mem_ctx); if (!original_uncompressed_data) { perror(filename); mapitest_print(mt, "%s: Error while loading %s\n", __FUNCTION__, filename); talloc_free(filename); return false; } talloc_free(filename); original_uncompressed_hex = hex_encode_talloc(mt->mem_ctx, (const unsigned char*)original_uncompressed_data, original_uncompressed_length); /* compress it */ retval = compress_rtf(mt->mem_ctx, original_uncompressed_data, original_uncompressed_length, &compressed, &compressed_length); if (retval != MAPI_E_SUCCESS) { mapitest_print_retval_clean(mt, "mapitest_noserver_rtfcp_large - step 1 (bad retval)", retval); return false; } /* decompress it */ retval = uncompress_rtf(mt->mem_ctx, compressed, compressed_length, &decompressed); if (retval != MAPI_E_SUCCESS) { mapitest_print_retval_clean(mt, "mapitest_noserver_rtfcp_large - step 2 (bad retval)", retval); return false; } mapitest_print(mt, "Original data size = 0x%zx\n", original_uncompressed_length); mapitest_print(mt, "Decompressed size = 0x%zx\n", decompressed.length); { int i; int min; min = (original_uncompressed_length >= decompressed.length) ? decompressed.length : original_uncompressed_length; mapitest_print(mt, "Comparing data over 0x%x bytes\n", min); for (i = 0; i < min; i++) { if (decompressed.data[i] != original_uncompressed_data[i]) { mapitest_print(mt, "Bytes differ at offset 0x%x: original (0x%.2x) decompressed (0x%.2x)\n", i, original_uncompressed_data[i], decompressed.data[i]); } } } /* check the uncompressed version (less trailing null) matches the original test file contents */ decompressed_hex = hex_encode_talloc(mt->mem_ctx, decompressed.data, decompressed.length -1); if (strncasecmp(original_uncompressed_hex, decompressed_hex, original_uncompressed_length) != 0) { mapitest_print(mt, "* %-40s: compare results - mismatch\n", "RTFCP_LARGE"); return false; } else { mapitest_print(mt, "* %-40s: compare results - match\n", "RTFCP_LARGE"); // mapitest_print(mt, "- %s\n", original_uncompressed_hex); // mapitest_print(mt, "- %s\n", decompressed_hex); } /* clean up */ talloc_free(decompressed_hex); talloc_free(compressed); talloc_free(original_uncompressed_hex); return true; }