static uint32_t Read4Skip(const char **in)
{
    const uint8_t *tmp = (const uint8_t*)*in;
    uint32_t res = Read4(tmp);
    *in = *in + 4;
    return res;
}
Esempio n. 2
0
bool RoboClaw::ReadMinMaxLogicVoltages(uint8_t address,uint16_t &min,uint16_t &max){
	bool valid;
	uint32_t value = Read4(address,GETMINMAXLOGICVOLTAGES,&valid);
	if(valid){
		min = value>>16;
		max = value&0xFFFF;
	}
	return valid;
}
Esempio n. 3
0
bool RoboClaw::ReadCurrents(uint8_t address, int16_t &current1, int16_t &current2){
	bool valid;
	uint32_t value = Read4(address,GETCURRENTS,&valid);
	if(valid){
		current1 = value>>16;
		current2 = value&0xFFFF;
	}
	return valid;
}
Esempio n. 4
0
bool RoboClaw::ReadPWMs(uint8_t address, int16_t &pwm1, int16_t &pwm2){
	bool valid;
	uint32_t value = Read4(address,GETPWMS,&valid);
	if(valid){
		pwm1 = value>>16;
		pwm2 = value&0xFFFF;
	}
	return valid;
}
Esempio n. 5
0
static int read_long(dest_t *dest, glui32 *val)
{
  unsigned char buf[4];
  int res = read_buffer(dest, buf, 4);
  if (res)
    return res;
  *val = Read4(buf);
  return 0;
}
Esempio n. 6
0
glui32 perform_verify()
{
  glui32 len, checksum, newlen;
  unsigned char buf[4];
  glui32 val, newsum, ix;

  len = gamefile_len;

  if (len < 256 || (len & 0xFF) != 0)
    return 1;

  glk_stream_set_position(gamefile, gamefile_start, seekmode_Start);
  newsum = 0;

  /* Read the header */
  for (ix=0; ix<9; ix++) {
    newlen = glk_get_buffer_stream(gamefile, (char *)buf, 4);
    if (newlen != 4)
      return 1;
    val = Read4(buf);
    if (ix == 3) {
      if (len != val)
        return 1;
    }
    if (ix == 8)
      checksum = val;
    else
      newsum += val;
  }

  /* Read everything else */
  for (; ix < len/4; ix++) {
    newlen = glk_get_buffer_stream(gamefile, (char *)buf, 4);
    if (newlen != 4)
      return 1;
    val = Read4(buf);
    newsum += val;
  }

  if (newsum != checksum)
    return 1;

  return 0;  
}
char* Decompress(const char *compressed, size_t compressedSize, size_t* uncompressedSizeOut, Allocator *allocator)
{
    ISzAllocatorAlloc lzmaAlloc;
    lzmaAlloc.Alloc = LzmaAllocatorAlloc;
    lzmaAlloc.Free = LzmaAllocatorFree;
    lzmaAlloc.allocator = allocator;

    if (compressedSize < LZMA86_HEADER_SIZE)
        return NULL;

    uint8_t usesX86Filter = (uint8_t)compressed[0];
    if (usesX86Filter > 1)
        return NULL;

    const uint8_t* compressed2 = (const uint8_t*)compressed;
    SizeT uncompressedSize = Read4(compressed2 + LZMA86_SIZE_OFFSET);
    uint8_t* uncompressed = (uint8_t*)Allocator::Alloc(allocator, uncompressedSize);
    if (!uncompressed)
        return NULL;

    SizeT compressedSizeTmp = compressedSize - LZMA86_HEADER_SIZE;
    SizeT uncompressedSizeTmp = uncompressedSize;

    ELzmaStatus status;
    // Note: would be nice to understand why status returns LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK and
    // not LZMA_STATUS_FINISHED_WITH_MARK. It seems to work, though.
    int res = LzmaDecode(uncompressed, &uncompressedSizeTmp,
        compressed2 + LZMA86_HEADER_SIZE, &compressedSizeTmp,
        compressed2 + 1, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status,
        &lzmaAlloc);

    if (SZ_OK != res) {
        Allocator::Free(allocator, uncompressed);
        return NULL;
    }

    if (usesX86Filter) {
        UInt32 x86State;
        x86_Convert_Init(x86State);
        x86_Convert(uncompressed, uncompressedSizeTmp, 0, &x86State, 0);
    }
    *uncompressedSizeOut = uncompressedSize;
    return (char*)uncompressed;
}
Esempio n. 8
0
/*
 * Read the given file and break it up into chunks, putting the number
 * of chunks and their info in *num_chunks and **chunks,
 * respectively.  Returns a malloc'd block of memory containing the
 * contents of the file; various pointers in the output chunk array
 * will point into this block of memory.  The caller should free the
 * return value when done with all the chunks.  Returns NULL on
 * failure.
 */
unsigned char* ReadImage(const char* filename,
                         int* num_chunks, ImageChunk** chunks) {
  struct stat st;
  if (stat(filename, &st) != 0) {
    printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
    return NULL;
  }

  unsigned char* img = malloc(st.st_size + 4);
  FILE* f = fopen(filename, "rb");
  if (fread(img, 1, st.st_size, f) != st.st_size) {
    printf("failed to read \"%s\" %s\n", filename, strerror(errno));
    fclose(f);
    return NULL;
  }
  fclose(f);

  // append 4 zero bytes to the data so we can always search for the
  // four-byte string 1f8b0800 starting at any point in the actual
  // file data, without special-casing the end of the data.
  memset(img+st.st_size, 0, 4);

  size_t pos = 0;

  *num_chunks = 0;
  *chunks = NULL;

  while (pos < st.st_size) {
    unsigned char* p = img+pos;

    if (st.st_size - pos >= 4 &&
        p[0] == 0x1f && p[1] == 0x8b &&
        p[2] == 0x08 &&    // deflate compression
        p[3] == 0x00) {    // no header flags
      // 'pos' is the offset of the start of a gzip chunk.

      *num_chunks += 3;
      *chunks = realloc(*chunks, *num_chunks * sizeof(ImageChunk));
      ImageChunk* curr = *chunks + (*num_chunks-3);

      // create a normal chunk for the header.
      curr->start = pos;
      curr->type = CHUNK_NORMAL;
      curr->len = GZIP_HEADER_LEN;
      curr->data = p;
      curr->I = NULL;

      pos += curr->len;
      p += curr->len;
      ++curr;

      curr->type = CHUNK_DEFLATE;
      curr->filename = NULL;
      curr->I = NULL;

      // We must decompress this chunk in order to discover where it
      // ends, and so we can put the uncompressed data and its length
      // into curr->data and curr->len.

      size_t allocated = 32768;
      curr->len = 0;
      curr->data = malloc(allocated);
      curr->start = pos;
      curr->deflate_data = p;

      z_stream strm;
      strm.zalloc = Z_NULL;
      strm.zfree = Z_NULL;
      strm.opaque = Z_NULL;
      strm.avail_in = st.st_size - pos;
      strm.next_in = p;

      // -15 means we are decoding a 'raw' deflate stream; zlib will
      // not expect zlib headers.
      int ret = inflateInit2(&strm, -15);

      do {
        strm.avail_out = allocated - curr->len;
        strm.next_out = curr->data + curr->len;
        ret = inflate(&strm, Z_NO_FLUSH);
        curr->len = allocated - strm.avail_out;
        if (strm.avail_out == 0) {
          allocated *= 2;
          curr->data = realloc(curr->data, allocated);
        }
      } while (ret != Z_STREAM_END);

      curr->deflate_len = st.st_size - strm.avail_in - pos;
      inflateEnd(&strm);
      pos += curr->deflate_len;
      p += curr->deflate_len;
      ++curr;

      // create a normal chunk for the footer

      curr->type = CHUNK_NORMAL;
      curr->start = pos;
      curr->len = GZIP_FOOTER_LEN;
      curr->data = img+pos;
      curr->I = NULL;

      pos += curr->len;
      p += curr->len;
      ++curr;

      // The footer (that we just skipped over) contains the size of
      // the uncompressed data.  Double-check to make sure that it
      // matches the size of the data we got when we actually did
      // the decompression.
      size_t footer_size = Read4(p-4);
      if (footer_size != curr[-2].len) {
        printf("Error: footer size %zd != decompressed size %zd\n",
                footer_size, curr[-2].len);
        free(img);
        return NULL;
      }
    } else {
      // Reallocate the list for every chunk; we expect the number of
      // chunks to be small (5 for typical boot and recovery images).
      ++*num_chunks;
      *chunks = realloc(*chunks, *num_chunks * sizeof(ImageChunk));
      ImageChunk* curr = *chunks + (*num_chunks-1);
      curr->start = pos;
      curr->I = NULL;

      // 'pos' is not the offset of the start of a gzip chunk, so scan
      // forward until we find a gzip header.
      curr->type = CHUNK_NORMAL;
      curr->data = p;

      for (curr->len = 0; curr->len < (st.st_size - pos); ++curr->len) {
        if (p[curr->len] == 0x1f &&
            p[curr->len+1] == 0x8b &&
            p[curr->len+2] == 0x08 &&
            p[curr->len+3] == 0x00) {
          break;
        }
      }
      pos += curr->len;
    }
  }

  return img;
}
Esempio n. 9
0
unsigned char* ReadZip(const char* filename,
                       int* num_chunks, ImageChunk** chunks,
                       int include_pseudo_chunk) {
  struct stat st;
  if (stat(filename, &st) != 0) {
    printf("failed to stat \"%s\": %s\n", filename, strerror(errno));
    return NULL;
  }

  unsigned char* img = malloc(st.st_size);
  FILE* f = fopen(filename, "rb");
  if (fread(img, 1, st.st_size, f) != st.st_size) {
    printf("failed to read \"%s\" %s\n", filename, strerror(errno));
    fclose(f);
    return NULL;
  }
  fclose(f);

  // look for the end-of-central-directory record.

  int i;
  for (i = st.st_size-20; i >= 0 && i > st.st_size - 65600; --i) {
    if (img[i] == 0x50 && img[i+1] == 0x4b &&
        img[i+2] == 0x05 && img[i+3] == 0x06) {
      break;
    }
  }
  // double-check: this archive consists of a single "disk"
  if (!(img[i+4] == 0 && img[i+5] == 0 && img[i+6] == 0 && img[i+7] == 0)) {
    printf("can't process multi-disk archive\n");
    return NULL;
  }

  int cdcount = Read2(img+i+8);
  int cdoffset = Read4(img+i+16);

  ZipFileEntry* temp_entries = malloc(cdcount * sizeof(ZipFileEntry));
  int entrycount = 0;

  unsigned char* cd = img+cdoffset;
  for (i = 0; i < cdcount; ++i) {
    if (!(cd[0] == 0x50 && cd[1] == 0x4b && cd[2] == 0x01 && cd[3] == 0x02)) {
      printf("bad central directory entry %d\n", i);
      return NULL;
    }

    int clen = Read4(cd+20);   // compressed len
    int ulen = Read4(cd+24);   // uncompressed len
    int nlen = Read2(cd+28);   // filename len
    int xlen = Read2(cd+30);   // extra field len
    int mlen = Read2(cd+32);   // file comment len
    int hoffset = Read4(cd+42);   // local header offset

    char* filename = malloc(nlen+1);
    memcpy(filename, cd+46, nlen);
    filename[nlen] = '\0';

    int method = Read2(cd+10);

    cd += 46 + nlen + xlen + mlen;

    if (method != 8) {  // 8 == deflate
      free(filename);
      continue;
    }

    unsigned char* lh = img + hoffset;

    if (!(lh[0] == 0x50 && lh[1] == 0x4b && lh[2] == 0x03 && lh[3] == 0x04)) {
      printf("bad local file header entry %d\n", i);
      return NULL;
    }

    if (Read2(lh+26) != nlen || memcmp(lh+30, filename, nlen) != 0) {
      printf("central dir filename doesn't match local header\n");
      return NULL;
    }

    xlen = Read2(lh+28);   // extra field len; might be different from CD entry?

    temp_entries[entrycount].data_offset = hoffset+30+nlen+xlen;
    temp_entries[entrycount].deflate_len = clen;
    temp_entries[entrycount].uncomp_len = ulen;
    temp_entries[entrycount].filename = filename;
    ++entrycount;
  }

  qsort(temp_entries, entrycount, sizeof(ZipFileEntry), fileentry_compare);

#if 1
  printf("found %d deflated entries\n", entrycount);
  for (i = 0; i < entrycount; ++i) {
    printf("off %10zd  len %10zd unlen %10zd   %p %s\n",
           temp_entries[i].data_offset,
           temp_entries[i].deflate_len,
           temp_entries[i].uncomp_len,
           temp_entries[i].filename,
           temp_entries[i].filename);
  }
#endif

  *num_chunks = 0;
  *chunks = malloc((entrycount*2+2) * sizeof(ImageChunk));
  ImageChunk* curr = *chunks;

  if (include_pseudo_chunk) {
    curr->type = CHUNK_NORMAL;
    curr->start = 0;
    curr->len = st.st_size;
    curr->data = img;
    curr->filename = NULL;
    curr->I = NULL;
    ++curr;
    ++*num_chunks;
  }

  int pos = 0;
  int nextentry = 0;

  while (pos < st.st_size) {
    if (nextentry < entrycount && pos == temp_entries[nextentry].data_offset) {
      curr->type = CHUNK_DEFLATE;
      curr->start = pos;
      curr->deflate_len = temp_entries[nextentry].deflate_len;
      curr->deflate_data = img + pos;
      curr->filename = temp_entries[nextentry].filename;
      curr->I = NULL;

      curr->len = temp_entries[nextentry].uncomp_len;
      curr->data = malloc(curr->len);

      z_stream strm;
      strm.zalloc = Z_NULL;
      strm.zfree = Z_NULL;
      strm.opaque = Z_NULL;
      strm.avail_in = curr->deflate_len;
      strm.next_in = curr->deflate_data;

      // -15 means we are decoding a 'raw' deflate stream; zlib will
      // not expect zlib headers.
      int ret = inflateInit2(&strm, -15);

      strm.avail_out = curr->len;
      strm.next_out = curr->data;
      ret = inflate(&strm, Z_NO_FLUSH);
      if (ret != Z_STREAM_END) {
        printf("failed to inflate \"%s\"; %d\n", curr->filename, ret);
        return NULL;
      }

      inflateEnd(&strm);

      pos += curr->deflate_len;
      ++nextentry;
      ++*num_chunks;
      ++curr;
      continue;
    }

    // use a normal chunk to take all the data up to the start of the
    // next deflate section.

    curr->type = CHUNK_NORMAL;
    curr->start = pos;
    if (nextentry < entrycount) {
      curr->len = temp_entries[nextentry].data_offset - pos;
    } else {
      curr->len = st.st_size - pos;
    }
    curr->data = img + pos;
    curr->filename = NULL;
    curr->I = NULL;
    pos += curr->len;

    ++*num_chunks;
    ++curr;
  }

  free(temp_entries);
  return img;
}
Esempio n. 10
0
/*
 * Apply the patch given in 'patch_filename' to the source data given
 * by (old_data, old_size).  Write the patched output to the 'output'
 * file, and update the SHA context with the output data as well.
 * Return 0 on success.
 */
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
                    const char* patch_filename,
                    SinkFn sink, void* token, SHA_CTX* ctx) {
  FILE* f;
  if ((f = fopen(patch_filename, "rb")) == NULL) {
    printf("failed to open patch file\n");
    return -1;
  }

  unsigned char header[12];
  if (fread(header, 1, 12, f) != 12) {
    printf("failed to read patch file header\n");
    return -1;
  }

  // IMGDIFF1 uses CHUNK_NORMAL and CHUNK_GZIP.
  // IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW.
  if (memcmp(header, "IMGDIFF", 7) != 0 ||
      (header[7] != '1' && header[7] != '2')) {
    printf("corrupt patch file header (magic number)\n");
    return -1;
  }

  int num_chunks = Read4(header+8);

  int i;
  for (i = 0; i < num_chunks; ++i) {
    // each chunk's header record starts with 4 bytes.
    unsigned char chunk[4];
    if (fread(chunk, 1, 4, f) != 4) {
      printf("failed to read chunk %d record\n", i);
      return -1;
    }

    int type = Read4(chunk);

    if (type == CHUNK_NORMAL) {
      unsigned char normal_header[24];
      if (fread(normal_header, 1, 24, f) != 24) {
        printf("failed to read chunk %d normal header data\n", i);
        return -1;
      }

      size_t src_start = Read8(normal_header);
      size_t src_len = Read8(normal_header+8);
      size_t patch_offset = Read8(normal_header+16);

      printf("CHUNK %d:  normal   patch offset %d\n", i, patch_offset);

      ApplyBSDiffPatch(old_data + src_start, src_len,
                       patch_filename, patch_offset,
                       sink, token, ctx);
    } else if (type == CHUNK_GZIP) {
      // This branch is basically a duplicate of the CHUNK_DEFLATE
      // branch, with a bit of extra processing for the gzip header
      // and footer.  I've avoided factoring the common code out since
      // this branch will just be deleted when we drop support for
      // IMGDIFF1.

      // gzip chunks have an additional 64 + gzip_header_len + 8 bytes
      // in their chunk header.
      unsigned char* gzip = malloc(64);
      if (fread(gzip, 1, 64, f) != 64) {
        printf("failed to read chunk %d initial gzip header data\n",
                i);
        return -1;
      }
      size_t gzip_header_len = Read4(gzip+60);
      gzip = realloc(gzip, 64 + gzip_header_len + 8);
      if (fread(gzip+64, 1, gzip_header_len+8, f) != gzip_header_len+8) {
        printf("failed to read chunk %d remaining gzip header data\n",
                i);
        return -1;
      }

      size_t src_start = Read8(gzip);
      size_t src_len = Read8(gzip+8);
      size_t patch_offset = Read8(gzip+16);

      size_t expanded_len = Read8(gzip+24);
      size_t target_len = Read8(gzip+32);
      int gz_level = Read4(gzip+40);
      int gz_method = Read4(gzip+44);
      int gz_windowBits = Read4(gzip+48);
      int gz_memLevel = Read4(gzip+52);
      int gz_strategy = Read4(gzip+56);

      printf("CHUNK %d:  gzip     patch offset %d\n", i, patch_offset);

      // Decompress the source data; the chunk header tells us exactly
      // how big we expect it to be when decompressed.

      unsigned char* expanded_source = malloc(expanded_len);
      if (expanded_source == NULL) {
        printf("failed to allocate %d bytes for expanded_source\n",
                expanded_len);
        return -1;
      }

      z_stream strm;
      strm.zalloc = Z_NULL;
      strm.zfree = Z_NULL;
      strm.opaque = Z_NULL;
      strm.avail_in = src_len - (gzip_header_len + 8);
      strm.next_in = (unsigned char*)(old_data + src_start + gzip_header_len);
      strm.avail_out = expanded_len;
      strm.next_out = expanded_source;

      int ret;
      ret = inflateInit2(&strm, -15);
      if (ret != Z_OK) {
        printf("failed to init source inflation: %d\n", ret);
        return -1;
      }

      // Because we've provided enough room to accommodate the output
      // data, we expect one call to inflate() to suffice.
      ret = inflate(&strm, Z_SYNC_FLUSH);
      if (ret != Z_STREAM_END) {
        printf("source inflation returned %d\n", ret);
        return -1;
      }
      // We should have filled the output buffer exactly.
      if (strm.avail_out != 0) {
        printf("source inflation short by %d bytes\n", strm.avail_out);
        return -1;
      }
      inflateEnd(&strm);

      // Next, apply the bsdiff patch (in memory) to the uncompressed
      // data.
      unsigned char* uncompressed_target_data;
      ssize_t uncompressed_target_size;
      if (ApplyBSDiffPatchMem(expanded_source, expanded_len,
                              patch_filename, patch_offset,
                              &uncompressed_target_data,
                              &uncompressed_target_size) != 0) {
        return -1;
      }

      // Now compress the target data and append it to the output.

      // start with the gzip header.
      sink(gzip+64, gzip_header_len, token);
      SHA_update(ctx, gzip+64, gzip_header_len);

      // we're done with the expanded_source data buffer, so we'll
      // reuse that memory to receive the output of deflate.
      unsigned char* temp_data = expanded_source;
      ssize_t temp_size = expanded_len;
      if (temp_size < 32768) {
        // ... unless the buffer is too small, in which case we'll
        // allocate a fresh one.
        free(temp_data);
        temp_data = malloc(32768);
        temp_size = 32768;
      }

      // now the deflate stream
      strm.zalloc = Z_NULL;
      strm.zfree = Z_NULL;
      strm.opaque = Z_NULL;
      strm.avail_in = uncompressed_target_size;
      strm.next_in = uncompressed_target_data;
      ret = deflateInit2(&strm, gz_level, gz_method, gz_windowBits,
                         gz_memLevel, gz_strategy);
      do {
        strm.avail_out = temp_size;
        strm.next_out = temp_data;
        ret = deflate(&strm, Z_FINISH);
        size_t have = temp_size - strm.avail_out;

        if (sink(temp_data, have, token) != have) {
          printf("failed to write %d compressed bytes to output\n",
                  have);
          return -1;
        }
        SHA_update(ctx, temp_data, have);
      } while (ret != Z_STREAM_END);
      deflateEnd(&strm);

      // lastly, the gzip footer.
      sink(gzip+64+gzip_header_len, 8, token);
      SHA_update(ctx, gzip+64+gzip_header_len, 8);

      free(temp_data);
      free(uncompressed_target_data);
      free(gzip);
    } else if (type == CHUNK_RAW) {
      unsigned char raw_header[4];
      if (fread(raw_header, 1, 4, f) != 4) {
        printf("failed to read chunk %d raw header data\n", i);
        return -1;
      }

      size_t data_len = Read4(raw_header);

      printf("CHUNK %d:  raw      data %d\n", i, data_len);

      unsigned char* temp = malloc(data_len);
      if (fread(temp, 1, data_len, f) != data_len) {
          printf("failed to read chunk %d raw data\n", i);
          return -1;
      }
      SHA_update(ctx, temp, data_len);
      if (sink(temp, data_len, token) != data_len) {
          printf("failed to write chunk %d raw data\n", i);
          return -1;
      }
    } else if (type == CHUNK_DEFLATE) {
      // deflate chunks have an additional 60 bytes in their chunk header.
      unsigned char deflate_header[60];
      if (fread(deflate_header, 1, 60, f) != 60) {
        printf("failed to read chunk %d deflate header data\n", i);
        return -1;
      }

      size_t src_start = Read8(deflate_header);
      size_t src_len = Read8(deflate_header+8);
      size_t patch_offset = Read8(deflate_header+16);
      size_t expanded_len = Read8(deflate_header+24);
      size_t target_len = Read8(deflate_header+32);
      int level = Read4(deflate_header+40);
      int method = Read4(deflate_header+44);
      int windowBits = Read4(deflate_header+48);
      int memLevel = Read4(deflate_header+52);
      int strategy = Read4(deflate_header+56);

      printf("CHUNK %d:  deflate  patch offset %d\n", i, patch_offset);

      // Decompress the source data; the chunk header tells us exactly
      // how big we expect it to be when decompressed.

      unsigned char* expanded_source = malloc(expanded_len);
      if (expanded_source == NULL) {
        printf("failed to allocate %d bytes for expanded_source\n",
                expanded_len);
        return -1;
      }

      z_stream strm;
      strm.zalloc = Z_NULL;
      strm.zfree = Z_NULL;
      strm.opaque = Z_NULL;
      strm.avail_in = src_len;
      strm.next_in = (unsigned char*)(old_data + src_start);
      strm.avail_out = expanded_len;
      strm.next_out = expanded_source;

      int ret;
      ret = inflateInit2(&strm, -15);
      if (ret != Z_OK) {
        printf("failed to init source inflation: %d\n", ret);
        return -1;
      }

      // Because we've provided enough room to accommodate the output
      // data, we expect one call to inflate() to suffice.
      ret = inflate(&strm, Z_SYNC_FLUSH);
      if (ret != Z_STREAM_END) {
        printf("source inflation returned %d\n", ret);
        return -1;
      }
      // We should have filled the output buffer exactly.
      if (strm.avail_out != 0) {
        printf("source inflation short by %d bytes\n", strm.avail_out);
        return -1;
      }
      inflateEnd(&strm);

      // Next, apply the bsdiff patch (in memory) to the uncompressed
      // data.
      unsigned char* uncompressed_target_data;
      ssize_t uncompressed_target_size;
      if (ApplyBSDiffPatchMem(expanded_source, expanded_len,
                              patch_filename, patch_offset,
                              &uncompressed_target_data,
                              &uncompressed_target_size) != 0) {
        return -1;
      }

      // Now compress the target data and append it to the output.

      // we're done with the expanded_source data buffer, so we'll
      // reuse that memory to receive the output of deflate.
      unsigned char* temp_data = expanded_source;
      ssize_t temp_size = expanded_len;
      if (temp_size < 32768) {
        // ... unless the buffer is too small, in which case we'll
        // allocate a fresh one.
        free(temp_data);
        temp_data = malloc(32768);
        temp_size = 32768;
      }

      // now the deflate stream
      strm.zalloc = Z_NULL;
      strm.zfree = Z_NULL;
      strm.opaque = Z_NULL;
      strm.avail_in = uncompressed_target_size;
      strm.next_in = uncompressed_target_data;
      ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy);
      do {
        strm.avail_out = temp_size;
        strm.next_out = temp_data;
        ret = deflate(&strm, Z_FINISH);
        size_t have = temp_size - strm.avail_out;

        if (sink(temp_data, have, token) != have) {
          printf("failed to write %d compressed bytes to output\n",
                  have);
          return -1;
        }
        SHA_update(ctx, temp_data, have);
      } while (ret != Z_STREAM_END);
      deflateEnd(&strm);

      free(temp_data);
      free(uncompressed_target_data);
    } else {
      printf("patch chunk %d is unknown type %d\n", i, type);
      return -1;
    }
  }

  return 0;
}
Esempio n. 11
0
/*
 * Apply the patch given in 'patch_filename' to the source data given
 * by (old_data, old_size).  Write the patched output to the 'output'
 * file, and update the SHA context with the output data as well.
 * Return 0 on success.
 */
int ApplyImagePatch(const unsigned char* old_data, ssize_t old_size,
                    const Value* patch,
                    SinkFn sink, void* token, SHA_CTX* ctx,
                    const Value* bonus_data) {
    ssize_t pos = 12;
    char* header = patch->data;
    if (patch->size < 12) {
        printf("patch too short to contain header\n");
        return -1;
    }

    // IMGDIFF2 uses CHUNK_NORMAL, CHUNK_DEFLATE, and CHUNK_RAW.
    // (IMGDIFF1, which is no longer supported, used CHUNK_NORMAL and
    // CHUNK_GZIP.)
    if (memcmp(header, "IMGDIFF2", 8) != 0) {
        printf("corrupt patch file header (magic number)\n");
        return -1;
    }

    int num_chunks = Read4(header+8);

    int i;
    for (i = 0; i < num_chunks; ++i) {
        // each chunk's header record starts with 4 bytes.
        if (pos + 4 > patch->size) {
            printf("failed to read chunk %d record\n", i);
            return -1;
        }
        int type = Read4(patch->data + pos);
        pos += 4;

        if (type == CHUNK_NORMAL) {
            char* normal_header = patch->data + pos;
            pos += 24;
            if (pos > patch->size) {
                printf("failed to read chunk %d normal header data\n", i);
                return -1;
            }

            size_t src_start = Read8(normal_header);
            size_t src_len = Read8(normal_header+8);
            size_t patch_offset = Read8(normal_header+16);

            ApplyBSDiffPatch(old_data + src_start, src_len,
                             patch, patch_offset, sink, token, ctx);
        } else if (type == CHUNK_RAW) {
            char* raw_header = patch->data + pos;
            pos += 4;
            if (pos > patch->size) {
                printf("failed to read chunk %d raw header data\n", i);
                return -1;
            }

            ssize_t data_len = Read4(raw_header);

            if (pos + data_len > patch->size) {
                printf("failed to read chunk %d raw data\n", i);
                return -1;
            }
            SHA_update(ctx, patch->data + pos, data_len);
            if (sink((unsigned char*)patch->data + pos,
                     data_len, token) != data_len) {
                printf("failed to write chunk %d raw data\n", i);
                return -1;
            }
            pos += data_len;
        } else if (type == CHUNK_DEFLATE) {
            // deflate chunks have an additional 60 bytes in their chunk header.
            char* deflate_header = patch->data + pos;
            pos += 60;
            if (pos > patch->size) {
                printf("failed to read chunk %d deflate header data\n", i);
                return -1;
            }

            size_t src_start = Read8(deflate_header);
            size_t src_len = Read8(deflate_header+8);
            size_t patch_offset = Read8(deflate_header+16);
            size_t expanded_len = Read8(deflate_header+24);
            size_t target_len = Read8(deflate_header+32);
            int level = Read4(deflate_header+40);
            int method = Read4(deflate_header+44);
            int windowBits = Read4(deflate_header+48);
            int memLevel = Read4(deflate_header+52);
            int strategy = Read4(deflate_header+56);

            // Decompress the source data; the chunk header tells us exactly
            // how big we expect it to be when decompressed.

            // Note: expanded_len will include the bonus data size if
            // the patch was constructed with bonus data.  The
            // deflation will come up 'bonus_size' bytes short; these
            // must be appended from the bonus_data value.
            size_t bonus_size = (i == 1 && bonus_data != NULL) ? bonus_data->size : 0;

            unsigned char* expanded_source = malloc(expanded_len);
            if (expanded_source == NULL) {
                printf("failed to allocate %d bytes for expanded_source\n",
                       expanded_len);
                return -1;
            }

            z_stream strm;
            strm.zalloc = Z_NULL;
            strm.zfree = Z_NULL;
            strm.opaque = Z_NULL;
            strm.avail_in = src_len;
            strm.next_in = (unsigned char*)(old_data + src_start);
            strm.avail_out = expanded_len;
            strm.next_out = expanded_source;

            int ret;
            ret = inflateInit2(&strm, -15);
            if (ret != Z_OK) {
                printf("failed to init source inflation: %d\n", ret);
                return -1;
            }

            // Because we've provided enough room to accommodate the output
            // data, we expect one call to inflate() to suffice.
            ret = inflate(&strm, Z_SYNC_FLUSH);
            if (ret != Z_STREAM_END) {
                printf("source inflation returned %d\n", ret);
                return -1;
            }
            // We should have filled the output buffer exactly, except
            // for the bonus_size.
            if (strm.avail_out != bonus_size) {
                printf("source inflation short by %zu bytes\n", strm.avail_out-bonus_size);
                return -1;
            }
            inflateEnd(&strm);

            if (bonus_size) {
                memcpy(expanded_source + (expanded_len - bonus_size),
                       bonus_data->data, bonus_size);
            }

            // Next, apply the bsdiff patch (in memory) to the uncompressed
            // data.
            unsigned char* uncompressed_target_data;
            ssize_t uncompressed_target_size;
            if (ApplyBSDiffPatchMem(expanded_source, expanded_len,
                                    patch, patch_offset,
                                    &uncompressed_target_data,
                                    &uncompressed_target_size) != 0) {
                return -1;
            }

            // Now compress the target data and append it to the output.

            // we're done with the expanded_source data buffer, so we'll
            // reuse that memory to receive the output of deflate.
            unsigned char* temp_data = expanded_source;
            ssize_t temp_size = expanded_len;
            if (temp_size < 32768) {
                // ... unless the buffer is too small, in which case we'll
                // allocate a fresh one.
                free(temp_data);
                temp_data = malloc(32768);
                temp_size = 32768;
            }

            // now the deflate stream
            strm.zalloc = Z_NULL;
            strm.zfree = Z_NULL;
            strm.opaque = Z_NULL;
            strm.avail_in = uncompressed_target_size;
            strm.next_in = uncompressed_target_data;
            ret = deflateInit2(&strm, level, method, windowBits, memLevel, strategy);
            do {
                strm.avail_out = temp_size;
                strm.next_out = temp_data;
                ret = deflate(&strm, Z_FINISH);
                ssize_t have = temp_size - strm.avail_out;

                if (sink(temp_data, have, token) != have) {
                    printf("failed to write %ld compressed bytes to output\n",
                           (long)have);
                    return -1;
                }
                SHA_update(ctx, temp_data, have);
            } while (ret != Z_STREAM_END);
            deflateEnd(&strm);

            free(temp_data);
            free(uncompressed_target_data);
        } else {
            printf("patch chunk %d is unknown type %d\n", i, type);
            return -1;
        }
    }

    return 0;
}
Esempio n. 12
0
static glui32 read_stackstate(dest_t *dest, glui32 chunklen, int portable)
{
  glui32 res;
  glui32 frameend, frm, frm2, frm3, locpos, frlen, numlocals;

  if (chunklen > stacksize)
    return 1;

  stackptr = chunklen;
  frameptr = 0;
  valstackbase = 0;
  localsbase = 0;

  if (!portable) {
    res = read_buffer(dest, stack, stackptr);
    if (res)
      return res;
    return 0;
  }

  /* This isn't going to be pleasant; we're going to read the data in
     as a block, and then convert it in-place. */
  res = read_buffer(dest, stack, stackptr);
  if (res)
    return res;

  frameend = stackptr;
  while (frameend != 0) {
    /* Read the beginning-of-frame pointer. Remember, right now, the
       whole frame is stored big-endian. So we have to read with the
       Read*() macros, and then write with the StkW*() macros. */
    frm = Read4(stack+(frameend-4));

    frm2 = frm;

    frlen = Read4(stack+frm2);
    StkW4(frm2, frlen);
    frm2 += 4;
    locpos = Read4(stack+frm2);
    StkW4(frm2, locpos);
    frm2 += 4;

    /* The locals-format list is in bytes, so we don't have to convert it. */
    frm3 = frm2;
    frm2 = frm+locpos;

    numlocals = 0;

    while (1) {
      unsigned char loctype, loccount;
      loctype = Read1(stack+frm3);
      frm3 += 1;
      loccount = Read1(stack+frm3);
      frm3 += 1;

      if (loctype == 0 && loccount == 0)
        break;

      /* Skip up to 0, 1, or 3 bytes of padding, depending on loctype. */
      while (frm2 & (loctype-1)) {
        StkW1(frm2, 0);
        frm2++;
      }
      
      /* Convert this set of locals. */
      switch (loctype) {
        
      case 1:
        do {
          /* Don't need to convert bytes. */
          frm2 += 1;
          loccount--;
        } while (loccount);
        break;

      case 2:
        do {
          glui16 loc = Read2(stack+frm2);
          StkW2(frm2, loc);
          frm2 += 2;
          loccount--;
        } while (loccount);
        break;

      case 4:
        do {
          glui32 loc = Read4(stack+frm2);
          StkW4(frm2, loc);
          frm2 += 4;
          loccount--;
        } while (loccount);
        break;

      }

      numlocals++;
    }

    if ((numlocals & 1) == 0) {
      StkW1(frm3, 0);
      frm3++;
      StkW1(frm3, 0);
      frm3++;
    }

    if (frm3 != frm+locpos) {
      return 1;
    }

    while (frm2 & 3) {
      StkW1(frm2, 0);
      frm2++;
    }

    if (frm2 != frm+frlen) {
      return 1;
    }

    /* Now, the values pushed on the stack after the call frame itself.
       This includes the stub. */
    while (frm2 < frameend) {
      glui32 loc = Read4(stack+frm2);
      StkW4(frm2, loc);
      frm2 += 4;
    }

    frameend = frm;
  }

  return 0;
}