ext/libmspack/mspack/chmd.c in libmspack-0.0.5 vs ext/libmspack/mspack/chmd.c in libmspack-0.1.0

- old
+ new

@@ -252,11 +252,11 @@ /* reads an encoded integer into a variable; 7 bits of data per byte, * the high bit is used to indicate that there is another byte */ #define READ_ENCINT(var) do { \ (var) = 0; \ do { \ - if (p > end) goto chunk_end; \ + if (p >= end) goto chunk_end; \ (var) = ((var) << 7) | (*p & 0x7F); \ } while (*p++ & 0x80); \ } while (0) static int chmd_read_headers(struct mspack_system *sys, struct mspack_file *fh, @@ -443,11 +443,13 @@ p = &chunk[pmgl_Entries]; end = &chunk[chm->chunk_size - 2]; num_entries = EndGetI16(end); while (num_entries--) { - READ_ENCINT(name_len); name = p; p += name_len; + READ_ENCINT(name_len); + if (name_len > (unsigned int) (end - p)) goto chunk_end; + name = p; p += name_len; READ_ENCINT(section); READ_ENCINT(offset); READ_ENCINT(length); /* empty files and directory names are stored as a file entry at @@ -744,11 +746,11 @@ M = (L + R) >> 1; /* compare filename with entry QR points to */ p = &chunk[entries_off + (M ? EndGetI16(start - (M << 1)) : 0)]; READ_ENCINT(name_len); - if (p + name_len > end) goto chunk_end; + if (name_len > (unsigned int) (end - p)) goto chunk_end; cmp = compare(filename, (char *)p, fname_len, name_len); if (cmp == 0) break; else if (cmp < 0) { if (M) R = M - 1; else return 0; } else if (cmp > 0) L = M + 1; @@ -781,11 +783,11 @@ * - */ *result = NULL; while (num_entries-- > 0) { READ_ENCINT(name_len); - if (p + name_len > end) goto chunk_end; + if (name_len > (unsigned int) (end - p)) goto chunk_end; cmp = compare(filename, (char *)p, fname_len, name_len); p += name_len; if (cmp == 0) { /* entry found */ @@ -848,39 +850,31 @@ 229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247, 248,249,250,251,252,253,254,255 }; #endif -/* decodes a UTF-8 character from s[] into c. Will not read past e. */ +/* decodes a UTF-8 character from s[] into c. Will not read past e. + * doesn't test that extension bytes are %10xxxxxx. + * allows some overlong encodings. + */ #define GET_UTF8_CHAR(s, e, c) do { \ unsigned char x = *s++; \ if (x < 0x80) c = x; \ - else if (x < 0xC0) c = -1; \ - else if (x < 0xE0) { \ - c = (s >= e) ? -1 : ((x & 0x1F) << 6) | (*s++ & 0x3F); \ + else if (x >= 0xC2 && x < 0xE0 && s < e) { \ + c = (x & 0x1F) << 6 | (*s++ & 0x3F); \ } \ - else if (x < 0xF0) { \ - c = (s+2 > e) ? -1 : ((x & 0x0F) << 12) | ((s[0] & 0x3F) << 6) \ - | (s[1] & 0x3F); \ + else if (x >= 0xE0 && x < 0xF0 && s+1 < e) { \ + c = (x & 0x0F) << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F); \ s += 2; \ } \ - else if (x < 0xF8) { \ - c = (s+3 > e) ? -1 : ((x & 0x07) << 18) | ((s[0] & 0x3F) << 12) \ - | ((s[1] & 0x3F) << 6) | (s[2] & 0x3F); \ + else if (x >= 0xF0 && x <= 0xF5 && s+2 < e) { \ + c = (x & 0x07) << 18 | (s[0] & 0x3F) << 12 | \ + (s[1] & 0x3F) << 6 | (s[2] & 0x3F); \ + if (c > 0x10FFFF) c = 0xFFFD; \ s += 3; \ } \ - else if (x < 0xFC) { \ - c = (s+4 > e) ? -1 : ((x & 0x03) << 24) | ((s[0] & 0x3F) << 18) \ - | ((s[1] & 0x3F) << 12)|((s[2] & 0x3F) << 6)|(s[3] & 0x3F); \ - s += 4; \ - } \ - else if (x < 0xFE) { \ - c = (s+5>e)?-1:((x&1)<<30)|((s[0]&0x3F)<<24)|((s[1]&0x3F)<<18)| \ - ((s[2] & 0x3F) << 12) | ((s[3] & 0x3F) << 6)|(s[4] & 0x3F); \ - s += 5; \ - } \ - else c = -1; \ + else c = 0xFFFD; \ } while (0) /* case-insensitively compares two UTF8 encoded strings. String length for * both strings must be provided, null bytes are not terminators */ static inline int compare(const char *s1, const char *s2, int l1, int l2) { @@ -1121,10 +1115,10 @@ D(("bad controldata window size")) return self->error = MSPACK_ERR_DATAFORMAT; } /* validate reset_interval */ - if (reset_interval % LZX_FRAME_SIZE) { + if (reset_interval == 0 || reset_interval % LZX_FRAME_SIZE) { D(("bad controldata reset interval")) return self->error = MSPACK_ERR_DATAFORMAT; } /* which reset table entry would we like? */