Upload Apkdiff Module Source Code
This commit is contained in:
127
apkdiff/common/patch_format.h
Normal file
127
apkdiff/common/patch_format.h
Normal file
@@ -0,0 +1,127 @@
|
||||
/*
|
||||
* patch_format.h - APK diff patch file format definitions
|
||||
*
|
||||
* Patch file layout:
|
||||
* [16 bytes] Magic "APKDIFF/1.0\0\0\0"
|
||||
* [4 bytes] uint32_t entry_count
|
||||
* [entries...]
|
||||
*
|
||||
* Each entry:
|
||||
* [2 bytes] uint16_t path_len
|
||||
* [N bytes] path (no null terminator)
|
||||
* [1 byte] type (0=patch, 1=new_file, 2=copy)
|
||||
* [8 bytes] int64_t old_size (0 for new_file and copy)
|
||||
* [8 bytes] int64_t new_size (0 for copy)
|
||||
* [4 bytes] uint32_t compressed_size (0 for copy)
|
||||
* [N bytes] compressed_data (only for patch and new_file)
|
||||
*
|
||||
* Entry types:
|
||||
* PATCH (0): bsdiff patch data compressed with zlib
|
||||
* NEW (1): full new file content compressed with zlib
|
||||
* COPY (2): unchanged file, copy from old APK (no data follows)
|
||||
*/
|
||||
|
||||
#ifndef PATCH_FORMAT_H
|
||||
#define PATCH_FORMAT_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define APKDIFF_MAGIC "APKDIFF/1.0\0\0\0"
|
||||
#define APKDIFF_MAGIC_SIZE 16
|
||||
#define APKDIFF_VERSION 1
|
||||
|
||||
#define ENTRY_TYPE_PATCH 0
|
||||
#define ENTRY_TYPE_NEW 1
|
||||
#define ENTRY_TYPE_COPY 2
|
||||
|
||||
#pragma pack(push, 1)
|
||||
|
||||
typedef struct {
|
||||
char magic[APKDIFF_MAGIC_SIZE];
|
||||
uint32_t entry_count;
|
||||
} patch_header_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t path_len;
|
||||
uint8_t type;
|
||||
int64_t old_size;
|
||||
int64_t new_size;
|
||||
uint32_t compressed_size;
|
||||
} patch_entry_header_t;
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
/* Write the patch file header */
|
||||
static inline int patch_write_header(FILE* fp, uint32_t entry_count)
|
||||
{
|
||||
patch_header_t hdr;
|
||||
memcpy(hdr.magic, APKDIFF_MAGIC, APKDIFF_MAGIC_SIZE);
|
||||
hdr.entry_count = entry_count;
|
||||
return (fwrite(&hdr, sizeof(hdr), 1, fp) == 1) ? 0 : -1;
|
||||
}
|
||||
|
||||
/* Read and validate patch file header */
|
||||
static inline int patch_read_header(FILE* fp, uint32_t* entry_count)
|
||||
{
|
||||
patch_header_t hdr;
|
||||
if (fread(&hdr, sizeof(hdr), 1, fp) != 1)
|
||||
return -1;
|
||||
if (memcmp(hdr.magic, APKDIFF_MAGIC, APKDIFF_MAGIC_SIZE) != 0)
|
||||
return -1;
|
||||
*entry_count = hdr.entry_count;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Write a single entry header (call before writing compressed data) */
|
||||
static inline int patch_write_entry_header(FILE* fp, const char* path,
|
||||
uint8_t type, int64_t old_size, int64_t new_size, uint32_t compressed_size)
|
||||
{
|
||||
patch_entry_header_t eh;
|
||||
uint16_t path_len = (uint16_t)strlen(path);
|
||||
|
||||
eh.path_len = path_len;
|
||||
eh.type = type;
|
||||
eh.old_size = old_size;
|
||||
eh.new_size = new_size;
|
||||
eh.compressed_size = compressed_size;
|
||||
|
||||
if (fwrite(&eh, sizeof(eh), 1, fp) != 1) return -1;
|
||||
if (path_len > 0) {
|
||||
if (fwrite(path, 1, path_len, fp) != path_len) return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Read a single entry header. Caller must free *out_path. */
|
||||
static inline int patch_read_entry_header(FILE* fp, char** out_path,
|
||||
uint8_t* type, int64_t* old_size, int64_t* new_size, uint32_t* compressed_size)
|
||||
{
|
||||
patch_entry_header_t eh;
|
||||
char* path;
|
||||
|
||||
if (fread(&eh, sizeof(eh), 1, fp) != 1)
|
||||
return -1;
|
||||
|
||||
path = (char*)malloc(eh.path_len + 1);
|
||||
if (!path) return -1;
|
||||
|
||||
if (eh.path_len > 0) {
|
||||
if (fread(path, 1, eh.path_len, fp) != eh.path_len) {
|
||||
free(path);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
path[eh.path_len] = '\0';
|
||||
|
||||
*out_path = path;
|
||||
*type = eh.type;
|
||||
*old_size = eh.old_size;
|
||||
*new_size = eh.new_size;
|
||||
*compressed_size = eh.compressed_size;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* PATCH_FORMAT_H */
|
||||
162
apkdiff/common/zlib_stream.c
Normal file
162
apkdiff/common/zlib_stream.c
Normal file
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* zlib_stream.c - zlib compression callbacks for bsdiff/bspatch streams
|
||||
*/
|
||||
|
||||
#include "zlib_stream.h"
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
/* ============ Write (deflate) ============ */
|
||||
|
||||
static int zlib_flush_output(zlib_write_ctx* ctx)
|
||||
{
|
||||
int ret;
|
||||
do {
|
||||
ctx->zs.next_out = ctx->out_buf;
|
||||
ctx->zs.avail_out = ZLIB_STREAM_BUF_SIZE;
|
||||
ret = deflate(&ctx->zs, Z_NO_FLUSH);
|
||||
if (ret == Z_STREAM_ERROR)
|
||||
return -1;
|
||||
|
||||
size_t have = ZLIB_STREAM_BUF_SIZE - ctx->zs.avail_out;
|
||||
if (have > 0) {
|
||||
if (fwrite(ctx->out_buf, 1, have, ctx->fp) != have)
|
||||
return -1;
|
||||
}
|
||||
} while (ctx->zs.avail_out == 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zlib_write_init(zlib_write_ctx* ctx, FILE* fp)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->fp = fp;
|
||||
|
||||
ctx->zs.zalloc = Z_NULL;
|
||||
ctx->zs.zfree = Z_NULL;
|
||||
ctx->zs.opaque = Z_NULL;
|
||||
|
||||
if (deflateInit(&ctx->zs, Z_BEST_COMPRESSION) != Z_OK)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zlib_write_cb(struct bsdiff_stream* stream, const void* buffer, int size)
|
||||
{
|
||||
zlib_write_ctx* ctx = (zlib_write_ctx*)stream->opaque;
|
||||
|
||||
ctx->zs.next_in = (Bytef*)(uintptr_t)buffer;
|
||||
ctx->zs.avail_in = (uInt)size;
|
||||
|
||||
while (ctx->zs.avail_in > 0) {
|
||||
ctx->zs.next_out = ctx->out_buf;
|
||||
ctx->zs.avail_out = ZLIB_STREAM_BUF_SIZE;
|
||||
|
||||
int ret = deflate(&ctx->zs, Z_NO_FLUSH);
|
||||
if (ret == Z_STREAM_ERROR)
|
||||
return -1;
|
||||
|
||||
size_t have = ZLIB_STREAM_BUF_SIZE - ctx->zs.avail_out;
|
||||
if (have > 0) {
|
||||
if (fwrite(ctx->out_buf, 1, have, ctx->fp) != have)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int zlib_write_finish(zlib_write_ctx* ctx)
|
||||
{
|
||||
int ret;
|
||||
do {
|
||||
ctx->zs.next_out = ctx->out_buf;
|
||||
ctx->zs.avail_out = ZLIB_STREAM_BUF_SIZE;
|
||||
ret = deflate(&ctx->zs, Z_FINISH);
|
||||
if (ret == Z_STREAM_ERROR)
|
||||
return -1;
|
||||
|
||||
size_t have = ZLIB_STREAM_BUF_SIZE - ctx->zs.avail_out;
|
||||
if (have > 0) {
|
||||
if (fwrite(ctx->out_buf, 1, have, ctx->fp) != have)
|
||||
return -1;
|
||||
}
|
||||
} while (ret != Z_STREAM_END);
|
||||
|
||||
deflateEnd(&ctx->zs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ============ Read (inflate) ============ */
|
||||
|
||||
int zlib_read_init(zlib_read_ctx* ctx, const uint8_t* data, size_t len)
|
||||
{
|
||||
memset(ctx, 0, sizeof(*ctx));
|
||||
ctx->data = data;
|
||||
ctx->data_len = len;
|
||||
|
||||
ctx->zs.zalloc = Z_NULL;
|
||||
ctx->zs.zfree = Z_NULL;
|
||||
ctx->zs.opaque = Z_NULL;
|
||||
ctx->zs.next_in = (Bytef*)(uintptr_t)data;
|
||||
ctx->zs.avail_in = (uInt)len;
|
||||
|
||||
if (inflateInit(&ctx->zs) != Z_OK)
|
||||
return -1;
|
||||
|
||||
ctx->inited = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void zlib_read_cleanup(zlib_read_ctx* ctx)
|
||||
{
|
||||
if (ctx->inited) {
|
||||
inflateEnd(&ctx->zs);
|
||||
ctx->inited = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int zlib_read_cb(const struct bspatch_stream* stream, void* buffer, int length)
|
||||
{
|
||||
zlib_read_ctx* ctx = (zlib_read_ctx*)stream->opaque;
|
||||
|
||||
ctx->zs.next_out = (Bytef*)buffer;
|
||||
ctx->zs.avail_out = (uInt)length;
|
||||
|
||||
while (ctx->zs.avail_out > 0) {
|
||||
if (ctx->zs.avail_in == 0)
|
||||
return -1; /* ran out of compressed data */
|
||||
|
||||
int ret = inflate(&ctx->zs, Z_NO_FLUSH);
|
||||
if (ret == Z_STREAM_END) {
|
||||
if (ctx->zs.avail_out > 0)
|
||||
return -1; /* needed more data but stream ended */
|
||||
break;
|
||||
}
|
||||
if (ret != Z_OK)
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ============ Convenience setup ============ */
|
||||
|
||||
void zlib_setup_bsdiff_stream(struct bsdiff_stream* stream, zlib_write_ctx* ctx, FILE* fp)
|
||||
{
|
||||
zlib_write_init(ctx, fp);
|
||||
stream->opaque = ctx;
|
||||
stream->malloc = malloc;
|
||||
stream->free = free;
|
||||
stream->write = zlib_write_cb;
|
||||
}
|
||||
|
||||
void zlib_setup_bspatch_stream(struct bspatch_stream* stream, zlib_read_ctx* ctx,
|
||||
const uint8_t* data, size_t len)
|
||||
{
|
||||
zlib_read_init(ctx, data, len);
|
||||
stream->opaque = ctx;
|
||||
stream->read = zlib_read_cb;
|
||||
}
|
||||
62
apkdiff/common/zlib_stream.h
Normal file
62
apkdiff/common/zlib_stream.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* zlib_stream.h - zlib compression callbacks for bsdiff/bspatch streams
|
||||
*/
|
||||
|
||||
#ifndef ZLIB_STREAM_H
|
||||
#define ZLIB_STREAM_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <zlib.h>
|
||||
#include "bsdiff.h"
|
||||
#include "bspatch.h"
|
||||
|
||||
#define ZLIB_STREAM_BUF_SIZE 8192
|
||||
|
||||
/* ---- Write context (used by bsdiff in gen.exe) ---- */
|
||||
|
||||
typedef struct {
|
||||
FILE* fp;
|
||||
z_stream zs;
|
||||
uint8_t out_buf[ZLIB_STREAM_BUF_SIZE];
|
||||
} zlib_write_ctx;
|
||||
|
||||
/* Initialize zlib deflate write context. Must be called before bsdiff(). */
|
||||
int zlib_write_init(zlib_write_ctx* ctx, FILE* fp);
|
||||
|
||||
/* Flush and clean up. Must be called after bsdiff() completes. */
|
||||
int zlib_write_finish(zlib_write_ctx* ctx);
|
||||
|
||||
/* bsdiff_stream.write callback */
|
||||
int zlib_write_cb(struct bsdiff_stream* stream, const void* buffer, int size);
|
||||
|
||||
/* ---- Read context (used by bspatch in JNI) ---- */
|
||||
|
||||
typedef struct {
|
||||
const uint8_t* data;
|
||||
size_t data_len;
|
||||
z_stream zs;
|
||||
int inited;
|
||||
} zlib_read_ctx;
|
||||
|
||||
/* Initialize zlib inflate read context from compressed data buffer. */
|
||||
int zlib_read_init(zlib_read_ctx* ctx, const uint8_t* data, size_t len);
|
||||
|
||||
/* Clean up zlib read context. */
|
||||
void zlib_read_cleanup(zlib_read_ctx* ctx);
|
||||
|
||||
/* bspatch_stream.read callback */
|
||||
int zlib_read_cb(const struct bspatch_stream* stream, void* buffer, int length);
|
||||
|
||||
/* ---- Convenience setup functions ---- */
|
||||
|
||||
/* Fill a bsdiff_stream struct for zlib-compressed output to fp.
|
||||
* Caller must call zlib_write_finish() on ctx after bsdiff() completes. */
|
||||
void zlib_setup_bsdiff_stream(struct bsdiff_stream* stream, zlib_write_ctx* ctx, FILE* fp);
|
||||
|
||||
/* Fill a bspatch_stream struct for zlib-decompressed input from data buffer.
|
||||
* Caller must call zlib_read_cleanup() on ctx when done. */
|
||||
void zlib_setup_bspatch_stream(struct bspatch_stream* stream, zlib_read_ctx* ctx,
|
||||
const uint8_t* data, size_t len);
|
||||
|
||||
#endif /* ZLIB_STREAM_H */
|
||||
Reference in New Issue
Block a user