#include <stdlib.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <time.h>

#include <dmg/dmg.h>

static char plstData[1032] = {
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
	0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};

const char* plistHeader = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n";
const char* plistFooter = "</dict>\n</plist>\n";

static void flipSizeResource(unsigned char* data, char out) {
  SizeResource* size;
  
  size = (SizeResource*) data;
  
  FLIPENDIANLE(size->version);
  FLIPENDIANLE(size->isHFS);
  FLIPENDIANLE(size->unknown2);
  FLIPENDIANLE(size->unknown3);
  FLIPENDIANLE(size->volumeModified);
  FLIPENDIANLE(size->unknown4);
  FLIPENDIANLE(size->volumeSignature);
  FLIPENDIANLE(size->sizePresent);
}

static void flipCSumResource(unsigned char* data, char out) {
  CSumResource* cSum;
  cSum = (CSumResource*) data;
  
  FLIPENDIANLE(cSum->version);
  FLIPENDIANLE(cSum->type);
  FLIPENDIANLE(cSum->checksum);
}


static void flipBLKXRun(BLKXRun* data) {
  BLKXRun* run;
  
  run = (BLKXRun*) data;
  
  FLIPENDIAN(run->type);
  FLIPENDIAN(run->reserved);
  FLIPENDIAN(run->sectorStart);
  FLIPENDIAN(run->sectorCount);
  FLIPENDIAN(run->compOffset);
  FLIPENDIAN(run->compLength);
}

static void flipBLKX(unsigned char* data, char out) {
  BLKXTable* blkx;
  uint32_t i;
  
  blkx = (BLKXTable*) data;
  
  FLIPENDIAN(blkx->fUDIFBlocksSignature);
  FLIPENDIAN(blkx->infoVersion);
  FLIPENDIAN(blkx->firstSectorNumber);
  FLIPENDIAN(blkx->sectorCount);
  
  FLIPENDIAN(blkx->dataStart);
  FLIPENDIAN(blkx->decompressBufferRequested);
  FLIPENDIAN(blkx->blocksDescriptor);
  
  FLIPENDIAN(blkx->reserved1);
  FLIPENDIAN(blkx->reserved2);
  FLIPENDIAN(blkx->reserved3);
  FLIPENDIAN(blkx->reserved4);
  FLIPENDIAN(blkx->reserved5);
  FLIPENDIAN(blkx->reserved6);
  
  flipUDIFChecksum(&(blkx->checksum), out);

  if(out) {
    for(i = 0; i < blkx->blocksRunCount; i++) {
      flipBLKXRun(&(blkx->runs[i]));     
    }
    FLIPENDIAN(blkx->blocksRunCount);
  } else {
    FLIPENDIAN(blkx->blocksRunCount);
    for(i = 0; i < blkx->blocksRunCount; i++) {
      flipBLKXRun(&(blkx->runs[i]));
    } 
  }
/*
    printf("fUDIFBlocksSignature: 0x%x\n", blkx->fUDIFBlocksSignature);
    printf("infoVersion: 0x%x\n", blkx->infoVersion);
    printf("firstSectorNumber: 0x%llx\n", blkx->firstSectorNumber);
    printf("sectorCount: 0x%llx\n", blkx->sectorCount);
    printf("dataStart: 0x%llx\n", blkx->dataStart);
    printf("decompressBufferRequested: 0x%x\n", blkx->decompressBufferRequested);
    printf("blocksDescriptor: 0x%x\n", blkx->blocksDescriptor);
    printf("blocksRunCount: 0x%x\n", blkx->blocksRunCount);

    for(i = 0; i < 0x20; i++)
    {
	    printf("checksum[%d]: %x\n", i, blkx->checksum.data[i]);
    }*/
}

static char* getXMLString(char** location) {
  char* curLoc;
  char* tagEnd;
  char* toReturn;
  size_t strLen;
  
  curLoc = *location;
  
  curLoc = strstr(curLoc, "<string>");
  if(!curLoc)
    return NULL;
  curLoc += sizeof("<string>") - 1;
  
  tagEnd = strstr(curLoc, "</string>");
  
  strLen = (size_t)(tagEnd - curLoc);
  toReturn = (char*) malloc(strLen + 1);
  memcpy(toReturn, curLoc, strLen);
  toReturn[strLen] = '\0';
  
  curLoc = tagEnd + sizeof("</string>") - 1;
  
  *location = curLoc;
  
  return toReturn;
}

static uint32_t getXMLInteger(char** location) {
  char* curLoc;
  char* tagEnd;
  char* buffer;
  uint32_t toReturn;
  size_t strLen;
  
  curLoc = *location;
  
  curLoc = strstr(curLoc, "<integer>");
  if(!curLoc)
    return 0;
  curLoc += sizeof("<integer>") - 1;
  
  tagEnd = strstr(curLoc, "</integer>");
  
  strLen = (size_t)(tagEnd - curLoc);
  buffer = (char*) malloc(strLen + 1);
  memcpy(buffer, curLoc, strLen);
  buffer[strLen] = '\0';
  
  curLoc = tagEnd + sizeof("</integer>") - 1;
  
  sscanf(buffer, "%d", (int32_t*)(&toReturn));
  
  free(buffer);
  
  *location = curLoc;
  
  return toReturn;
}

static unsigned char* getXMLData(char** location, size_t *dataLength) {
  char* curLoc;
  char* tagEnd;
  char* encodedData;
  unsigned char* toReturn;
  size_t strLen;
  
  curLoc = *location;
  
  curLoc = strstr(curLoc, "<data>");
  if(!curLoc)
    return NULL;
  curLoc += sizeof("<data>") - 1;
  
  tagEnd = strstr(curLoc, "</data>");
  
  
  strLen = (size_t)(tagEnd - curLoc);
  
  encodedData = (char*) malloc(strLen + 1);
  memcpy(encodedData, curLoc, strLen);
  encodedData[strLen] = '\0';
  
  curLoc = tagEnd + sizeof("</data>") - 1;
  
  *location = curLoc;
  
  toReturn = decodeBase64(encodedData, dataLength);
  
  free(encodedData);
  
  return toReturn;
}

static void readResourceData(ResourceData* data, char** location, FlipDataFunc flipData) {
  char* curLoc;
  char* tagBegin;
  char* tagEnd;
  char* dictEnd;
  size_t strLen;
  char* buffer;
  
  curLoc = *location;
  
  data->name = NULL;
  data->attributes = 0;
  data->id = 0;
  data->data = NULL;
  
  curLoc = strstr(curLoc, "<dict>");
  dictEnd = strstr(curLoc, "</dict>"); /* hope there's not a dict type in this resource data! */
  while(curLoc != NULL && curLoc < dictEnd) {
    curLoc = strstr(curLoc, "<key>");
    if(!curLoc)
      break;
    curLoc += sizeof("<key>") - 1;
    
    tagEnd = strstr(curLoc, "</key>");
    
    strLen = (size_t)(tagEnd - curLoc);
    tagBegin = curLoc;
    curLoc = tagEnd + sizeof("</key>") - 1;
    
    if(strncmp(tagBegin, "Attributes", strLen) == 0) {
      buffer = getXMLString(&curLoc);
      sscanf(buffer, "0x%x", &(data->attributes));
      free(buffer);
    } else if(strncmp(tagBegin, "Data", strLen) == 0) {
      data->data = getXMLData(&curLoc, &(data->dataLength));
      if(flipData) {
        (*flipData)(data->data, 0);
      }
    } else if(strncmp(tagBegin, "ID", strLen) == 0) {
      buffer = getXMLString(&curLoc);
      sscanf(buffer, "%d", &(data->id));
      free(buffer);
    } else if(strncmp(tagBegin, "Name", strLen) == 0) {
      data->name = getXMLString(&curLoc);
    }
  }
  
  curLoc = dictEnd + sizeof("</dict>") - 1;
  
  *location = curLoc;
}

static void readNSizResource(NSizResource* data, char** location) {
  char* curLoc;
  char* tagBegin;
  char* tagEnd;
  char* dictEnd;
  size_t strLen;
  size_t dummy;
  
  curLoc = *location;
  
  data->isVolume = FALSE;
  data->sha1Digest = NULL;
  data->blockChecksum2 = 0;
  data->bytes = 0;
  data->modifyDate = 0;
  data->partitionNumber = 0;
  data->version = 0;
  data->volumeSignature = 0;
  
  curLoc = strstr(curLoc, "<dict>");
  dictEnd = strstr(curLoc, "</dict>"); /* hope there's not a dict type in this resource data! */
  while(curLoc != NULL && curLoc < dictEnd) {
    curLoc = strstr(curLoc, "<key>");
    if(!curLoc)
      break;
    curLoc += sizeof("<key>") - 1;
    
    tagEnd = strstr(curLoc, "</key>");
    
    strLen = (size_t)(tagEnd - curLoc);
    tagBegin = curLoc;
    curLoc = tagEnd + sizeof("</key>") - 1;
    
    if(strncmp(tagBegin, "SHA-1-digest", strLen) == 0) {
      data->sha1Digest = getXMLData(&curLoc, &dummy);;
      /*flipEndian(data->sha1Digest, 4);*/
    } else if(strncmp(tagBegin, "block-checksum-2", strLen) == 0) {
      data->blockChecksum2 = getXMLInteger(&curLoc);
    } else if(strncmp(tagBegin, "bytes", strLen) == 0) {
      data->bytes = getXMLInteger(&curLoc);
    } else if(strncmp(tagBegin, "date", strLen) == 0) {
      data->modifyDate = getXMLInteger(&curLoc);
    } else if(strncmp(tagBegin, "part-num", strLen) == 0) {
      data->partitionNumber = getXMLInteger(&curLoc);
    } else if(strncmp(tagBegin, "version", strLen) == 0) {
      data->version = getXMLInteger(&curLoc);
    } else if(strncmp(tagBegin, "volume-signature", strLen) == 0) {
      data->volumeSignature = getXMLInteger(&curLoc);
      data->isVolume = TRUE;
    }
  }
  
  curLoc = dictEnd + sizeof("</dict>") - 1;
  
  *location = curLoc;
}

static void writeNSizResource(NSizResource* data, char* buffer) {
  char itemBuffer[1024];
  char* sha1Buffer;
  
  (*buffer) = '\0';
  itemBuffer[0] = '\0';
  
  strcat(buffer, plistHeader);
  if(data->sha1Digest != NULL) {
    sha1Buffer = convertBase64(data->sha1Digest, 20, 1, 42);
    sprintf(itemBuffer, "\t<key>SHA-1-digest</key>\n\t<data>\n%s\t</data>\n", sha1Buffer);
    free(sha1Buffer);
    strcat(buffer, itemBuffer);
  }
  sprintf(itemBuffer, "\t<key>block-checksum-2</key>\n\t<integer>%d</integer>\n", (int32_t)(data->blockChecksum2));
  strcat(buffer, itemBuffer);
  if(data->isVolume) {
    sprintf(itemBuffer, "\t<key>bytes</key>\n\t<integer>%d</integer>\n", (int32_t)(data->bytes));
    strcat(buffer, itemBuffer);
    sprintf(itemBuffer, "\t<key>date</key>\n\t<integer>%d</integer>\n", (int32_t)(data->modifyDate));
    strcat(buffer, itemBuffer);
  }
  sprintf(itemBuffer, "\t<key>part-num</key>\n\t<integer>%d</integer>\n", (int32_t)(data->partitionNumber));
  strcat(buffer, itemBuffer);
  sprintf(itemBuffer, "\t<key>version</key>\n\t<integer>%d</integer>\n", (int32_t)(data->version));
  strcat(buffer, itemBuffer);
  if(data->isVolume) {
    sprintf(itemBuffer, "\t<key>volume-signature</key>\n\t<integer>%d</integer>\n", (int32_t)(data->volumeSignature));
    strcat(buffer, itemBuffer);
  }
  strcat(buffer, plistFooter);
}


NSizResource* readNSiz(ResourceKey* resources) {
  ResourceData* curData;
  NSizResource* toReturn;
  NSizResource* curNSiz;
  char* curLoc;
  uint32_t modifyDate;
  
  curData = getResourceByKey(resources, "nsiz")->data;
  toReturn = NULL;
   
  while(curData != NULL) {
    curLoc = (char*) curData->data;
    
    if(toReturn == NULL) {
      toReturn = (NSizResource*) malloc(sizeof(NSizResource));
      curNSiz = toReturn;
    } else {
      curNSiz->next = (NSizResource*) malloc(sizeof(NSizResource));
      curNSiz = curNSiz->next;
    }
    
    curNSiz->next = NULL;
    
    readNSizResource(curNSiz, &curLoc);
    
    
    printf("block-checksum-2:\t0x%x\n", curNSiz->blockChecksum2);
    printf("part-num:\t\t0x%x\n", curNSiz->partitionNumber);
    printf("version:\t\t0x%x\n", curNSiz->version);
    
    if(curNSiz->isVolume) {
      printf("has SHA1:\t\t%d\n", curNSiz->sha1Digest != NULL);
      printf("bytes:\t\t\t0x%x\n", curNSiz->bytes);
      modifyDate = APPLE_TO_UNIX_TIME(curNSiz->modifyDate);
      printf("date:\t\t\t%s", ctime((time_t*)(&modifyDate)));
      printf("volume-signature:\t0x%x\n", curNSiz->volumeSignature);
    }
    
    printf("\n");
    
    curData = curData->next;
  }
  
  return toReturn;
}

ResourceKey* writeNSiz(NSizResource* nSiz) {
  NSizResource* curNSiz;
  ResourceKey* key;
  ResourceData* curData;
  char buffer[1024];
  
  curNSiz = nSiz;
  
  key = (ResourceKey*) malloc(sizeof(ResourceKey));
  key->key = (unsigned char*) malloc(sizeof("nsiz") + 1);
  strcpy((char*) key->key, "nsiz");
  key->next = NULL;
  key->flipData = NULL;
  key->data = NULL;
  
  while(curNSiz != NULL) {
    writeNSizResource(curNSiz, buffer);
    if(key->data == NULL) {
      key->data = (ResourceData*) malloc(sizeof(ResourceData));
      curData = key->data;
    } else {
      curData->next = (ResourceData*) malloc(sizeof(ResourceData));
      curData = curData->next;
    }
    
    curData->attributes = 0;
    curData->id = curNSiz->partitionNumber;
    curData->name = (char*) malloc(sizeof(char));
    curData->name[0] = '\0';
    curData->next = NULL;
    curData->dataLength = sizeof(char) * strlen(buffer);
    curData->data = (unsigned char*) malloc(curData->dataLength);
    memcpy(curData->data, buffer, curData->dataLength);
    
    curNSiz = curNSiz->next;
  }
  
  return key;
}

void releaseNSiz(NSizResource* nSiz) {
  NSizResource* curNSiz;
  NSizResource* toRemove;
  
  curNSiz = nSiz;

  while(curNSiz != NULL) {
    if(curNSiz->sha1Digest != NULL)
      free(curNSiz->sha1Digest);
    
    toRemove = curNSiz;
    curNSiz = curNSiz->next;
    free(toRemove);
  }
}

void outResources(AbstractFile* file, AbstractFile* out)
{
	char* xml;
	UDIFResourceFile resourceFile;
	off_t fileLength;

	fileLength = file->getLength(file);
	file->seek(file, fileLength - sizeof(UDIFResourceFile));
	readUDIFResourceFile(file, &resourceFile);
	xml = (char*) malloc((size_t)resourceFile.fUDIFXMLLength);
	file->seek(file, (off_t)(resourceFile.fUDIFXMLOffset));
	ASSERT(file->read(file, xml, (size_t)resourceFile.fUDIFXMLLength) == (size_t)resourceFile.fUDIFXMLLength, "fread");
	ASSERT(out->write(out, xml, (size_t)resourceFile.fUDIFXMLLength) == (size_t)resourceFile.fUDIFXMLLength, "fwrite");

	file->close(file);
	out->close(out);
}

ResourceKey* readResources(AbstractFile* file, UDIFResourceFile* resourceFile) {
  char* xml;
  char* curLoc;
  char* tagEnd;
  size_t strLen;
  
  ResourceKey* toReturn;
  ResourceKey* curResource;
  ResourceData* curData;
  
  xml = (char*) malloc((size_t)resourceFile->fUDIFXMLLength + 1); /* we're not going to handle over 32-bit resource files, that'd be insane */
  xml[(size_t)resourceFile->fUDIFXMLLength] = '\0';

  if(!xml)
    return NULL;

  toReturn = NULL;
  curResource = NULL;
  curData = NULL;
  
  file->seek(file, (off_t)(resourceFile->fUDIFXMLOffset));
  ASSERT(file->read(file, xml, (size_t)resourceFile->fUDIFXMLLength) == (size_t)resourceFile->fUDIFXMLLength, "fread");

  curLoc = strstr(xml, "<key>resource-fork</key>");
  if(!curLoc)
    return NULL;
  curLoc += sizeof("<key>resource-fork</key>") - 1;
  
  curLoc = strstr(curLoc, "<dict>");
  if(!curLoc)
    return NULL;
  curLoc += sizeof("<dict>") - 1;
  
  while(TRUE) {
    curLoc = strstr(curLoc, "<key>");
    if(!curLoc)
      break;
    curLoc += sizeof("<key>") - 1;
    
    tagEnd = strstr(curLoc, "</key>");
    if(!tagEnd)
      break;
    
    if(toReturn == NULL) {    
      toReturn = (ResourceKey*) malloc(sizeof(ResourceKey));
      curResource = toReturn;
    } else {
      curResource->next = (ResourceKey*) malloc(sizeof(ResourceKey));
      curResource = curResource->next;
    }
    
    curResource->data = NULL;
    curResource->next = NULL;
    curResource->flipData = NULL;
    
    strLen = (size_t)(tagEnd - curLoc);
    curResource->key = (unsigned char*) malloc(strLen + 1);
    memcpy(curResource->key, curLoc, strLen);
    curResource->key[strLen] = '\0';
    
    curLoc = tagEnd + sizeof("</key>") - 1;
    
    curLoc = strstr(curLoc, "<array>");
    if(!curLoc)
      return NULL;
    curLoc += sizeof("<array>") - 1;
    
    tagEnd = strstr(curLoc, "</array>");
    if(!tagEnd)
      break;
      
    if(strcmp((char*) curResource->key, "blkx") == 0) {
      curResource->flipData = &flipBLKX;
    } else if(strcmp((char*) curResource->key, "size") == 0) {
      curResource->flipData = &flipSizeResource;
    } else if(strcmp((char*) curResource->key, "cSum") == 0) {
      curResource->flipData = &flipCSumResource;
    }
    
    curLoc = strstr(curLoc, "<dict>");
    while(curLoc != NULL && curLoc < tagEnd) {
      if(curResource->data == NULL) {
        curResource->data = (ResourceData*) malloc(sizeof(ResourceData));
        curData = curResource->data;
      } else {
        curData->next = (ResourceData*) malloc(sizeof(ResourceData));
        curData = curData->next;
      }
      
      curData->next = NULL;
      
      readResourceData(curData, &curLoc, curResource->flipData);
      curLoc = strstr(curLoc, "<dict>");
    }
       
    curLoc = tagEnd + sizeof("</array>") - 1;
  }
  
  free(xml);
  
  return toReturn;
}

static void writeResourceData(AbstractFile* file, ResourceData* data, ResourceKey* curResource, FlipDataFunc flipData, int tabLength) {
  unsigned char* dataBuf;
  char* tabs;
  int i;
  
  tabs = (char*) malloc(sizeof(char) * (tabLength + 1));
  for(i = 0; i < tabLength; i++) {
    tabs[i] = '\t';
  }
  tabs[tabLength] = '\0';
  
  abstractFilePrint(file, "%s<dict>\n", tabs);
  abstractFilePrint(file, "%s\t<key>Attributes</key>\n%s\t<string>0x%04x</string>\n", tabs, tabs, data->attributes);

  if(strcmp((char*) curResource->key, "blkx") == 0)
    abstractFilePrint(file, "%s\t<key>CFName</key>\n%s\t<string>%s</string>\n", tabs, tabs, data->name);

  abstractFilePrint(file, "%s\t<key>Data</key>\n%s\t<data>\n", tabs, tabs);
  
  if(flipData) {
    dataBuf = (unsigned char*) malloc(data->dataLength);
    memcpy(dataBuf, data->data, data->dataLength);
    (*flipData)(dataBuf, 1);
    writeBase64(file, dataBuf, data->dataLength, tabLength + 1, 43);
    free(dataBuf);
  } else {
    writeBase64(file, data->data, data->dataLength, tabLength + 1, 43);
  }
  
  abstractFilePrint(file, "%s\t</data>\n", tabs);
  abstractFilePrint(file, "%s\t<key>ID</key>\n%s\t<string>%d</string>\n", tabs, tabs, data->id);
  abstractFilePrint(file, "%s\t<key>Name</key>\n%s\t<string>%s</string>\n", tabs, tabs, data->name);
  abstractFilePrint(file, "%s</dict>\n", tabs);
  
  free(tabs);
}

void writeResources(AbstractFile* file, ResourceKey* resources) {
  ResourceKey* curResource;
  ResourceData* curData;
  
  abstractFilePrint(file, plistHeader);
  abstractFilePrint(file, "\t<key>resource-fork</key>\n\t<dict>\n");
  
  curResource = resources;
  while(curResource != NULL) {
    abstractFilePrint(file, "\t\t<key>%s</key>\n\t\t<array>\n", curResource->key);
    curData = curResource->data;
    while(curData != NULL) {
	    writeResourceData(file, curData, curResource, curResource->flipData, 3);
	    curData = curData->next;
    }
    abstractFilePrint(file, "\t\t</array>\n", curResource->key);
    curResource = curResource->next;
  }  

  abstractFilePrint(file, "\t</dict>\n");
  abstractFilePrint(file, plistFooter);
   
}

static void releaseResourceData(ResourceData* data) {
  ResourceData* curData;
  ResourceData* nextData;
  
  nextData = data;
  while(nextData != NULL) {
    curData = nextData;
    
    if(curData->name)
      free(curData->name);
    
    if(curData->data)
      free(curData->data);
      
    nextData = nextData->next;
    free(curData);
  }
}

void releaseResources(ResourceKey* resources) {
  ResourceKey* curResource;
  ResourceKey* nextResource;
  
  nextResource = resources;
  while(nextResource != NULL) {
    curResource = nextResource;
    free(curResource->key);
    releaseResourceData(curResource->data);
    nextResource = nextResource->next;
    free(curResource);
  }
}

ResourceKey* getResourceByKey(ResourceKey* resources, const char* key) {
  ResourceKey* curResource;
  
  curResource = resources;
  while(curResource != NULL) {
    if(strcmp((char*) curResource->key, key) == 0) {
      return curResource;
    }
    curResource = curResource->next;
  }
  
  return NULL;
}

ResourceData* getDataByID(ResourceKey* resource, int id) {
  ResourceData* curData;
  
  curData = resource->data;
  
  while(curData != NULL) {
    if(curData->id == id) {
      return curData;
    }
    curData = curData->next;
  }
  
  return NULL;
}

ResourceKey* insertData(ResourceKey* resources, const char* key, int id, const char* name, const char* data, size_t dataLength, uint32_t attributes) {
  ResourceKey* curResource;
  ResourceKey* lastResource;
  ResourceData* curData;
  
  lastResource = resources;
  curResource = resources;
  while(curResource != NULL) {
    if(strcmp((char*) curResource->key, key) == 0) {
      break;
    }
    lastResource = curResource;
    curResource = curResource->next;
  }
  
  if(curResource == NULL) {
    if(lastResource == NULL) {
      curResource = (ResourceKey*) malloc(sizeof(ResourceKey));
    } else {
      lastResource->next = (ResourceKey*) malloc(sizeof(ResourceKey));
      curResource = lastResource->next;
    }
    
    curResource->key = (unsigned char*) malloc(strlen(key) + 1);
    strcpy((char*) curResource->key, key);
    curResource->next = NULL;
    
    if(strcmp((char*) curResource->key, "blkx") == 0) {
      curResource->flipData = &flipBLKX;
    } else if(strcmp((char*) curResource->key, "size") == 0) {
	  printf("we know to flip this size resource\n");
      curResource->flipData = &flipSizeResource;
    } else if(strcmp((char*) curResource->key, "cSum") == 0) {
      curResource->flipData = &flipCSumResource;
    } else {
      curResource->flipData = NULL;
    }
    
    curResource->data = NULL;
  }
  
  if(curResource->data == NULL) {
    curData = (ResourceData*) malloc(sizeof(ResourceData));
    curResource->data = curData;
    curData->next = NULL;
  } else {
    curData = curResource->data;
    while(curData->next != NULL) {
      if(curData->id == id) {
        break;
      }
      curData = curData->next;
    }
    
    if(curData->id != id) {
      curData->next = (ResourceData*) malloc(sizeof(ResourceData));
      curData = curData->next;
      curData->next = NULL;
    } else {
      free(curData->data);
      free(curData->name);
    }
  }
  
  curData->attributes = attributes;
  curData->dataLength = dataLength;
  curData->id = id;
  curData->name = (char*) malloc(strlen(name) + 1);
  strcpy((char*) curData->name, name);
  curData->data = (unsigned char*) malloc(dataLength);
  memcpy(curData->data, data, dataLength);
  
  int i = 0;
  if(resources) {
    curResource = resources;
    while(curResource) {
      curResource = curResource->next;
      i++;
    }
    return resources;
  } else {
    return curResource;
  }
}

ResourceKey* makePlst() {
  return insertData(NULL, "plst", 0, "", plstData, sizeof(plstData), ATTRIBUTE_HDIUTIL); 
}

ResourceKey* makeSize(HFSPlusVolumeHeader* volumeHeader) {
  SizeResource size;
  memset(&size, 0, sizeof(SizeResource));
  size.version = 5;
  size.isHFS = 1;
  size.unknown1 = 0;
  size.unknown2 = 0;
  size.unknown3 = 0;
  size.volumeModified = volumeHeader->modifyDate;
  size.unknown4 = 0;
  size.volumeSignature = volumeHeader->signature;
  size.sizePresent = 1;

  printf("making size data\n");  
  return insertData(NULL, "size", 2, "", (const char*)(&size), sizeof(SizeResource), 0); 
}

