/* Implements svn_stream_seek_fn_t */ static svn_error_t * seek_handler_lazyopen(void *baton, const svn_stream_mark_t *mark) { lazyopen_baton_t *b = baton; SVN_ERR(lazyopen_if_unopened(b)); SVN_ERR(svn_stream_seek(b->real_stream, mark)); return SVN_NO_ERROR; }
static svn_error_t * test_stream_seek_stringbuf(apr_pool_t *pool) { svn_stream_t *stream; svn_stringbuf_t *stringbuf; char buf[4]; apr_size_t len; svn_stream_mark_t *mark; stringbuf = svn_stringbuf_create("OneTwo", pool); stream = svn_stream_from_stringbuf(stringbuf, pool); len = 3; SVN_ERR(svn_stream_read_full(stream, buf, &len)); buf[3] = '\0'; SVN_TEST_STRING_ASSERT(buf, "One"); SVN_ERR(svn_stream_mark(stream, &mark, pool)); len = 3; SVN_ERR(svn_stream_read_full(stream, buf, &len)); buf[3] = '\0'; SVN_TEST_STRING_ASSERT(buf, "Two"); SVN_ERR(svn_stream_seek(stream, mark)); len = 3; SVN_ERR(svn_stream_read_full(stream, buf, &len)); buf[3] = '\0'; SVN_TEST_STRING_ASSERT(buf, "Two"); /* Go back to the begin of last word and try to skip some of it */ SVN_ERR(svn_stream_seek(stream, mark)); SVN_ERR(svn_stream_skip(stream, 2)); /* The remaining line should be empty */ len = 3; SVN_ERR(svn_stream_read_full(stream, buf, &len)); buf[len] = '\0'; SVN_TEST_ASSERT(len == 1); SVN_TEST_STRING_ASSERT(buf, "o"); SVN_ERR(svn_stream_close(stream)); return SVN_NO_ERROR; }
static svn_error_t * test_stream_seek_translated(apr_pool_t *pool) { svn_stream_t *stream, *translated_stream; svn_stringbuf_t *stringbuf; char buf[44]; /* strlen("One$MyKeyword: my keyword was expanded $Two") + \0 */ apr_size_t len; svn_stream_mark_t *mark; apr_hash_t *keywords; svn_string_t *keyword_val; keywords = apr_hash_make(pool); keyword_val = svn_string_create("my keyword was expanded", pool); apr_hash_set(keywords, "MyKeyword", APR_HASH_KEY_STRING, keyword_val); stringbuf = svn_stringbuf_create("One$MyKeyword$Two", pool); stream = svn_stream_from_stringbuf(stringbuf, pool); translated_stream = svn_subst_stream_translated(stream, APR_EOL_STR, FALSE, keywords, TRUE, pool); /* Seek from outside of keyword to inside of keyword. */ len = 25; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 25); buf[25] = '\0'; SVN_TEST_STRING_ASSERT(buf, "One$MyKeyword: my keyword"); SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); SVN_ERR(svn_stream_reset(translated_stream)); SVN_ERR(svn_stream_seek(translated_stream, mark)); len = 4; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 4); buf[4] = '\0'; SVN_TEST_STRING_ASSERT(buf, " was"); SVN_ERR(svn_stream_seek(translated_stream, mark)); SVN_ERR(svn_stream_skip(translated_stream, 2)); len = 2; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 2); buf[len] = '\0'; SVN_TEST_STRING_ASSERT(buf, "as"); /* Seek from inside of keyword to inside of keyword. */ SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); len = 9; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 9); buf[9] = '\0'; SVN_TEST_STRING_ASSERT(buf, " expanded"); SVN_ERR(svn_stream_seek(translated_stream, mark)); len = 9; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 9); buf[9] = '\0'; SVN_TEST_STRING_ASSERT(buf, " expanded"); SVN_ERR(svn_stream_seek(translated_stream, mark)); SVN_ERR(svn_stream_skip(translated_stream, 6)); len = 3; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 3); buf[len] = '\0'; SVN_TEST_STRING_ASSERT(buf, "ded"); /* Seek from inside of keyword to outside of keyword. */ SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); len = 4; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 4); buf[4] = '\0'; SVN_TEST_STRING_ASSERT(buf, " $Tw"); SVN_ERR(svn_stream_seek(translated_stream, mark)); len = 4; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 4); buf[4] = '\0'; SVN_TEST_STRING_ASSERT(buf, " $Tw"); SVN_ERR(svn_stream_seek(translated_stream, mark)); SVN_ERR(svn_stream_skip(translated_stream, 2)); len = 2; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 2); buf[len] = '\0'; SVN_TEST_STRING_ASSERT(buf, "Tw"); /* Seek from outside of keyword to outside of keyword. */ SVN_ERR(svn_stream_mark(translated_stream, &mark, pool)); len = 1; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 1); buf[1] = '\0'; SVN_TEST_STRING_ASSERT(buf, "o"); SVN_ERR(svn_stream_seek(translated_stream, mark)); len = 1; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 1); buf[1] = '\0'; SVN_TEST_STRING_ASSERT(buf, "o"); SVN_ERR(svn_stream_seek(translated_stream, mark)); SVN_ERR(svn_stream_skip(translated_stream, 2)); len = 1; SVN_ERR(svn_stream_read_full(translated_stream, buf, &len)); SVN_TEST_ASSERT(len == 0); buf[len] = '\0'; SVN_TEST_STRING_ASSERT(buf, ""); SVN_ERR(svn_stream_close(stream)); return SVN_NO_ERROR; }
static svn_error_t * test_stream_seek_file(apr_pool_t *pool) { static const char *file_data[2] = {"One", "Two"}; svn_stream_t *stream; svn_stringbuf_t *line; svn_boolean_t eof; apr_file_t *f; static const char *fname = "test_stream_seek.txt"; int j; apr_status_t status; static const char *NL = APR_EOL_STR; svn_stream_mark_t *mark; status = apr_file_open(&f, fname, (APR_READ | APR_WRITE | APR_CREATE | APR_TRUNCATE | APR_DELONCLOSE), APR_OS_DEFAULT, pool); if (status != APR_SUCCESS) return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, "Cannot open '%s'", fname); /* Create the file. */ for (j = 0; j < 2; j++) { apr_size_t len; len = strlen(file_data[j]); status = apr_file_write(f, file_data[j], &len); if (status || len != strlen(file_data[j])) return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, "Cannot write to '%s'", fname); len = strlen(NL); status = apr_file_write(f, NL, &len); if (status || len != strlen(NL)) return svn_error_createf(SVN_ERR_TEST_FAILED, NULL, "Cannot write to '%s'", fname); } /* Create a stream to read from the file. */ stream = svn_stream_from_aprfile2(f, FALSE, pool); SVN_ERR(svn_stream_reset(stream)); SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool)); SVN_TEST_ASSERT(! eof && strcmp(line->data, file_data[0]) == 0); /* Set a mark at the beginning of the second line of the file. */ SVN_ERR(svn_stream_mark(stream, &mark, pool)); /* Read the second line and then seek back to the mark. */ SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool)); SVN_TEST_ASSERT(! eof && strcmp(line->data, file_data[1]) == 0); SVN_ERR(svn_stream_seek(stream, mark)); /* The next read should return the second line again. */ SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool)); SVN_TEST_ASSERT(! eof && strcmp(line->data, file_data[1]) == 0); /* The next read should return EOF. */ SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool)); SVN_TEST_ASSERT(eof); /* Go back to the beginning of the last line and try to skip it * NOT including the EOL. */ SVN_ERR(svn_stream_seek(stream, mark)); SVN_ERR(svn_stream_skip(stream, strlen(file_data[1]))); /* The remaining line should be empty */ SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool)); SVN_TEST_ASSERT(! eof && strcmp(line->data, "") == 0); /* The next read should return EOF. */ SVN_ERR(svn_stream_readline(stream, &line, NL, &eof, pool)); SVN_TEST_ASSERT(eof); SVN_ERR(svn_stream_close(stream)); return SVN_NO_ERROR; }
/* Writes out a git-like literal output of the compressed data in COMPRESSED_DATA to OUTPUT_STREAM, describing that its normal length is UNCOMPRESSED_SIZE. */ static svn_error_t * write_literal(svn_filesize_t uncompressed_size, svn_stream_t *compressed_data, svn_stream_t *output_stream, svn_cancel_func_t cancel_func, void *cancel_baton, apr_pool_t *scratch_pool) { apr_size_t rd; SVN_ERR(svn_stream_seek(compressed_data, NULL)); /* Seek to start */ SVN_ERR(svn_stream_printf(output_stream, scratch_pool, "literal %" SVN_FILESIZE_T_FMT APR_EOL_STR, uncompressed_size)); do { char chunk[GIT_BASE85_CHUNKSIZE]; const unsigned char *next; apr_size_t left; rd = sizeof(chunk); if (cancel_func) SVN_ERR(cancel_func(cancel_baton)); SVN_ERR(svn_stream_read_full(compressed_data, chunk, &rd)); { apr_size_t one = 1; SVN_ERR(svn_stream_write(output_stream, &b85lenstr[rd-1], &one)); } left = rd; next = (void*)chunk; while (left) { char five[5]; unsigned info = 0; int n; apr_size_t five_sz; /* Push 4 bytes into the 32 bit info, when available */ for (n = 24; n >= 0 && left; n -= 8, next++, left--) { info |= (*next) << n; } /* Write out info as base85 */ for (n = 4; n >= 0; n--) { five[n] = b85str[info % 85]; info /= 85; } five_sz = 5; SVN_ERR(svn_stream_write(output_stream, five, &five_sz)); } SVN_ERR(svn_stream_puts(output_stream, APR_EOL_STR)); } while (rd == GIT_BASE85_CHUNKSIZE); return SVN_NO_ERROR; }
static svn_error_t * seek_handler_disown(void *baton, const svn_stream_mark_t *mark) { return svn_error_trace(svn_stream_seek(baton, mark)); }
static svn_error_t * stream_readline_chunky(svn_stringbuf_t **stringbuf, svn_boolean_t *eof, const char *eol, svn_stream_t *stream, apr_pool_t *pool) { /* Read larger chunks of data at once into this buffer and scan * that for EOL. A good chunk size should be about 80 chars since * most text lines will be shorter. However, don't use a much * larger value because filling the buffer from the stream takes * time as well. */ char buffer[LINE_CHUNK_SIZE+1]; /* variables */ svn_stream_mark_t *mark; apr_size_t numbytes; const char *eol_pos; apr_size_t total_parsed = 0; /* invariant for this call */ const size_t eol_len = strlen(eol); /* Remember the line start so this plus the line length will be * the position to move to at the end of this function. */ SVN_ERR(svn_stream_mark(stream, &mark, pool)); /* Read the first chunk. */ numbytes = LINE_CHUNK_SIZE; SVN_ERR(svn_stream_read(stream, buffer, &numbytes)); buffer[numbytes] = '\0'; /* Look for the EOL in this first chunk. If we find it, we are done here. */ eol_pos = strstr(buffer, eol); if (eol_pos != NULL) { *stringbuf = svn_stringbuf_ncreate(buffer, eol_pos - buffer, pool); total_parsed = eol_pos - buffer + eol_len; } else if (numbytes < LINE_CHUNK_SIZE) { /* We hit EOF but not EOL. */ *stringbuf = svn_stringbuf_ncreate(buffer, numbytes, pool); *eof = TRUE; return SVN_NO_ERROR; } else { /* A larger buffer for the string is needed. */ svn_stringbuf_t *str; str = svn_stringbuf_create_ensure(2*LINE_CHUNK_SIZE, pool); svn_stringbuf_appendbytes(str, buffer, numbytes); *stringbuf = str; /* Loop reading chunks until an EOL was found. If we hit EOF, fall * back to the standard implementation. */ do { /* Append the next chunk to the string read so far. */ svn_stringbuf_ensure(str, str->len + LINE_CHUNK_SIZE); numbytes = LINE_CHUNK_SIZE; SVN_ERR(svn_stream_read(stream, str->data + str->len, &numbytes)); str->len += numbytes; str->data[str->len] = '\0'; /* Look for the EOL in the new data plus the last part of the * previous chunk because the EOL may span over the boundary * between both chunks. */ eol_pos = strstr(str->data + str->len - numbytes - (eol_len-1), eol); if ((numbytes < LINE_CHUNK_SIZE) && (eol_pos == NULL)) { /* We hit EOF instead of EOL. */ *eof = TRUE; return SVN_NO_ERROR; } } while (eol_pos == NULL); /* Number of bytes we actually consumed (i.e. line + EOF). * We need to "return" the rest to the stream by moving its * read pointer. */ total_parsed = eol_pos - str->data + eol_len; /* Terminate the string at the EOL postion and return it. */ str->len = eol_pos - str->data; str->data[str->len] = 0; } /* Move the stream read pointer to the first position behind the EOL. */ SVN_ERR(svn_stream_seek(stream, mark)); return svn_error_trace(svn_stream_skip(stream, total_parsed)); }
svn_error_t * svn_stream_reset(svn_stream_t *stream) { return svn_error_trace( svn_stream_seek(stream, NULL)); }