Index: libucdf/tester.c =================================================================== --- libucdf/tester.c (revision 35429) +++ libucdf/tester.c (revision 35430) @@ -43,6 +43,21 @@ return 0; } +static int print_file_at(ucdf_ctx_t *ctx, ucdf_direntry_t *de, long offs, long len) +{ + ucdf_file_t fp; + char tmp[1024]; + + if (ucdf_fopen(ctx, &fp, de) != 0) + return -1; + + printf(" seek to %ld: %d\n", offs, ucdf_fseek(&fp, offs)); + printf(" read %ld: %ld\n", len, ucdf_fread(&fp, tmp, len)); + fwrite(tmp, len, 1, stdout); + printf("\n"); + return 0; +} + int main(int argc, char *argv[]) { char *fn = "A.PcbDoc"; @@ -68,6 +83,11 @@ print_dir(&ctx, de, 0); printf("==\n"); dump_file(&ctx, de); + printf("==\n"); + print_file_at(&ctx, de, 39384, 10); + print_file_at(&ctx, de, 39385, 10); + print_file_at(&ctx, de, 39386, 10); + print_file_at(&ctx, de, 39387, 10); } ucdf_close(&ctx); Index: libucdf/ucdf.c =================================================================== --- libucdf/ucdf.c (revision 35429) +++ libucdf/ucdf.c (revision 35430) @@ -480,3 +480,50 @@ return ucdf_fread_long(fp, dst, len); } + +int ucdf_fseek(ucdf_file_t *fp, long offs) +{ + ucdf_ctx_t *ctx = fp->ctx; + long sect_min, sect_max; + long sect_idx, sect_offs, sect_id, n; + + if (fp->de->is_short) + return -1; + + if (offs == fp->stream_offs) + return 0; /* no need to move */ + + if ((offs < 0) || (offs >= fp->de->size)) + return -1; /* do not seek out of the file */ + + /* fast lane: check if seek is within the current sector */ + sect_min = fp->stream_offs - fp->sect_offs; + sect_max = sect_min + ctx->sect_size; + if ((offs >= sect_min) && (offs < sect_max)) { + long delta = offs - fp->stream_offs; + fp->stream_offs += delta; + fp->sect_offs += delta; + return 0; + } + + /* seeking to another sector; since SAT is a singly linked list, we need + to recalculate this sector by sector */ + sect_idx = offs / ctx->sect_size; + sect_offs = offs % ctx->sect_size; + + sect_id = fp->de->first; + for(n = 0; n < sect_idx; n++) { + if (sect_id < 0) + return -1; + sect_id = ctx->sat[sect_id]; + } + + if (sect_id < 0) + return -1; + + fp->stream_offs += offs; + fp->sect_offs += sect_offs; + fp->sect_id = sect_id; + return 0; +} + Index: libucdf/ucdf.h =================================================================== --- libucdf/ucdf.h (revision 35429) +++ libucdf/ucdf.h (revision 35430) @@ -88,4 +88,9 @@ ends short, returns less than len. If stream is already at EOF, returns 0 */ long ucdf_fread(ucdf_file_t *fp, char *dst, long len); +/* Seek to a given byte offset from the beginning of the stream. Returns 0 + on success or -1 on error (in which case no seek is done). At the moment + only long files are supported. */ +int ucdf_fseek(ucdf_file_t *fp, long offs); +