From d4a253cae40fb4b38377273eb1f89f21c4cb224a Mon Sep 17 00:00:00 2001 From: Derrick Brashear Date: Sun, 7 Mar 2010 08:47:13 -0500 Subject: [PATCH] ADC support for libdmg-hfsplus adds decompression support only. code is from dmg2img (http://vu1tur.eu.org/tools/) and is available under the GPL --- dmg/CMakeLists.txt | 2 +- dmg/adc.c | 116 +++++++++++++++++++++++++++++++++++++++++++++ dmg/dmgfile.c | 8 ++++ dmg/io.c | 8 ++++ includes/dmg/adc.h | 15 ++++++ includes/dmg/dmg.h | 1 + 6 files changed, 149 insertions(+), 1 deletion(-) create mode 100644 dmg/adc.c create mode 100644 includes/dmg/adc.h diff --git a/dmg/CMakeLists.txt b/dmg/CMakeLists.txt index 055319f..c30507b 100644 --- a/dmg/CMakeLists.txt +++ b/dmg/CMakeLists.txt @@ -16,7 +16,7 @@ link_directories(${ZLIB_LIBRARIES}) link_directories(${PROJECT_BINARY_DIR}/common ${PROJECT_BINARY_DIR}/hfs) -add_library(dmg base64.c checksum.c dmgfile.c dmglib.c filevault.c io.c partition.c resources.c udif.c) +add_library(dmg adc.c base64.c checksum.c dmgfile.c dmglib.c filevault.c io.c partition.c resources.c udif.c) IF(OPENSSL_FOUND) add_definitions(-DHAVE_CRYPT) diff --git a/dmg/adc.c b/dmg/adc.c new file mode 100644 index 0000000..d54ba35 --- /dev/null +++ b/dmg/adc.c @@ -0,0 +1,116 @@ +#include +#include +#include +#include + +#include +#include + +int adc_decompress(int in_size, unsigned char *input, int avail_size, unsigned char *output, int *bytes_written) +{ + if (in_size == 0) + return 0; + bool output_full = false; + unsigned char *inp = input; + unsigned char *outp = output; + int chunk_type; + int chunk_size; + int offset; + int i; + + while (inp - input < in_size) { + chunk_type = adc_chunk_type(*inp); + switch (chunk_type) { + case ADC_PLAIN: + chunk_size = adc_chunk_size(*inp); + if (outp + chunk_size - output > avail_size) { + output_full = true; + break; + } + memcpy(outp, inp + 1, chunk_size); + inp += chunk_size + 1; + outp += chunk_size; + break; + + case ADC_2BYTE: + chunk_size = adc_chunk_size(*inp); + offset = adc_chunk_offset(inp); + if (outp + chunk_size - output > avail_size) { + output_full = true; + break; + } + if (offset == 0) { + memset(outp, *(outp - offset - 1), chunk_size); + outp += chunk_size; + inp += 2; + } else { + for (i = 0; i < chunk_size; i++) { + memcpy(outp, outp - offset - 1, 1); + outp++; + } + inp += 2; + } + break; + + case ADC_3BYTE: + chunk_size = adc_chunk_size(*inp); + offset = adc_chunk_offset(inp); + if (outp + chunk_size - output > avail_size) { + output_full = true; + break; + } + if (offset == 0) { + memset(outp, *(outp - offset - 1), chunk_size); + outp += chunk_size; + inp += 3; + } else { + for (i = 0; i < chunk_size; i++) { + memcpy(outp, outp - offset - 1, 1); + outp++; + } + inp += 3; + } + break; + } + if (output_full) + break; + } + *bytes_written = outp - output; + return inp - input; +} + +int adc_chunk_type(char _byte) +{ + if (_byte & 0x80) + return ADC_PLAIN; + if (_byte & 0x40) + return ADC_3BYTE; + return ADC_2BYTE; +} + +int adc_chunk_size(char _byte) +{ + switch (adc_chunk_type(_byte)) { + case ADC_PLAIN: + return (_byte & 0x7F) + 1; + case ADC_2BYTE: + return ((_byte & 0x3F) >> 2) + 3; + case ADC_3BYTE: + return (_byte & 0x3F) + 4; + } + return -1; +} + +int adc_chunk_offset(unsigned char *chunk_start) +{ + unsigned char *c = chunk_start; + switch (adc_chunk_type(*c)) { + case ADC_PLAIN: + return 0; + case ADC_2BYTE: + return ((((unsigned char)*c & 0x03)) << 8) + (unsigned char)*(c + 1); + case ADC_3BYTE: + return (((unsigned char)*(c + 1)) << 8) + (unsigned char)*(c + 2); + } + return -1; +} diff --git a/dmg/dmgfile.c b/dmg/dmgfile.c index 67172fb..df96620 100644 --- a/dmg/dmgfile.c +++ b/dmg/dmgfile.c @@ -30,6 +30,14 @@ static void cacheRun(DMG* dmg, BLKXTable* blkx, int run) { ASSERT(dmg->dmg->seek(dmg->dmg, blkx->dataStart + blkx->runs[run].compOffset) == 0, "fseeko"); switch(blkx->runs[run].type) { + case BLOCK_ADC: + bufferRead = 0; + do { + strm.avail_in = dmg->dmg->read(dmg->dmg, inBuffer, blkx->runs[run].compLength); + strm.avail_out = adc_decompress(strm.avail_in, inBuffer, bufferSize, dmg->runData, &have); + bufferRead+=strm.avail_out; + } while (bufferRead < blkx->runs[run].compLength); + break; case BLOCK_ZLIB: strm.zalloc = Z_NULL; strm.zfree = Z_NULL; diff --git a/dmg/io.c b/dmg/io.c index d0d5595..989b169 100644 --- a/dmg/io.c +++ b/dmg/io.c @@ -182,6 +182,14 @@ void extractBLKX(AbstractFile* in, AbstractFile* out, BLKXTable* blkx) { printf("run %d: start=%" PRId64 " sectors=%" PRId64 ", length=%" PRId64 ", fileOffset=0x%" PRIx64 "\n", i, initialOffset + (blkx->runs[i].sectorStart * SECTOR_SIZE), blkx->runs[i].sectorCount, blkx->runs[i].compLength, blkx->runs[i].compOffset); switch(blkx->runs[i].type) { + case BLOCK_ADC: + do { + ASSERT((strm.avail_in = in->read(in, inBuffer, blkx->runs[i].compLength)) == blkx->runs[i].compLength, "fread"); + strm.avail_out = adc_decompress(strm.avail_in, inBuffer, bufferSize, outBuffer, &have); + ASSERT(out->write(out, outBuffer, have) == have, "mWrite"); + bufferRead+=strm.avail_out; + } while (bufferRead < blkx->runs[i].compLength); + break; case BLOCK_ZLIB: strm.zalloc = Z_NULL; strm.zfree = Z_NULL; diff --git a/includes/dmg/adc.h b/includes/dmg/adc.h new file mode 100644 index 0000000..e3910f1 --- /dev/null +++ b/includes/dmg/adc.h @@ -0,0 +1,15 @@ +#include +#include + +#define ADC_PLAIN 0x01 +#define ADC_2BYTE 0x02 +#define ADC_3BYTE 0x03 + +#define bool short +#define true 1 +#define false 0 + +int adc_decompress(int in_size, unsigned char *input, int avail_size, unsigned char *output, int *bytes_written); +int adc_chunk_type(char _byte); +int adc_chunk_size(char _byte); +int adc_chunk_offset(unsigned char *chunk_start); diff --git a/includes/dmg/dmg.h b/includes/dmg/dmg.h index b4e78bb..2142075 100644 --- a/includes/dmg/dmg.h +++ b/includes/dmg/dmg.h @@ -13,6 +13,7 @@ #define CHECKSUM_NONE 0x0000 #define BLOCK_ZLIB 0x80000005 +#define BLOCK_ADC 0x80000004 #define BLOCK_RAW 0x00000001 #define BLOCK_IGNORE 0x00000002 #define BLOCK_COMMENT 0x7FFFFFFE