int stream_write_block(StreamWriter *sp, StreamBlock *blk, STREAM_CHECKSUM check) /*=============================================================================*/ { blk->error = 0 ; if (blk->type == '#') blk->error = STREAM_ERROR_HASHRESERVED ; else { int n ; char *json ; char lenbuf[32] ; md5_state_t md5, *md5p ; if (sp->checksum || check) { md5p = &md5 ; md5_init(md5p) ; } else md5p = NULL ; if (blk->header) { cJSON_DeleteItemFromObject(blk->header, "length") ; cJSON_AddNumberToObject(blk->header, "length", blk->length) ; json = cJSON_PrintUnformatted(blk->header) ; } else { json = calloc(32, 1) ; sprintf(json, "{\"length\":%d}", blk->length) ; } stream_write_data(sp->file, "#", 1, md5p) ; stream_write_data(sp->file, &blk->type, 1, md5p) ; sprintf(lenbuf, "%d", (int)strlen(json)) ; stream_write_data(sp->file, lenbuf, strlen(lenbuf), md5p) ; stream_write_data(sp->file, json, strlen(json), md5p) ; stream_write_data(sp->file, "\n", 1, md5p) ; free(json) ; n = 0 ; while (n < blk->length) { int w = min(blk->length - n, STREAM_BUFFER_SIZE) ; w = stream_write_data(sp->file, blk->content + n, w, md5p) ; if (w < 0) { blk->error = STREAM_ERROR_WRITEOF ; break ; } n += w ; } write(sp->file, "##", 2) ; if (md5p) { md5_byte_t digest[16] ; char hexdigest[33] ; int i ; md5_finish(md5p, digest) ; for (i = 0 ; i < 16 ; ++i) sprintf(hexdigest + 2*i, "%02x", digest[i]) ; write(sp->file, hexdigest, 32) ; } write(sp->file, "\n", 1) ; } return blk->error ; }
static int stdout_print(Value *vret, Value *v, RefNode *node) { int new_line = FUNC_INT(node); Value *varg = v + 1; if (fg->v_ctextio == VALUE_NULL) { v_ctextio_init(); } *v = Value_cp(fg->v_ctextio); while (varg < fg->stk_top) { if (!textio_print_sub(*v, NULL, *varg, NULL)) { return FALSE; } varg++; } if (new_line && !stream_write_data(fg->v_cio, "\n", 1)) { return FALSE; } return TRUE; }
static int textio_print(Value *vret, Value *v, RefNode *node) { Ref *ref = Value_ref(*v); Value *varg = v + 1; int new_line = FUNC_INT(node); Value stream = ref->v[INDEX_TEXTIO_STREAM]; RefNode *s_type = Value_type(stream); StrBuf *sb = NULL; if (s_type == fs->cls_bytesio) { sb = bytesio_get_strbuf(stream); } while (varg < fg->stk_top) { if (!textio_print_sub(*v, sb, *varg, NULL)) { return FALSE; } varg++; } if (new_line) { RefTextIO *tio = Value_vp(ref->v[INDEX_TEXTIO_TEXTIO]); if (tio == NULL || tio->cs->ascii) { if (sb != NULL) { if (!StrBuf_add_c(sb, '\n')) { return FALSE; } } else if (!stream_write_data(stream, "\n", 1)) { return FALSE; } } else { if (!stream_write_sub_s(stream, sb, "\n", 1, tio)) { return FALSE; } } } return TRUE; }
/** * 文字コードを変換しながらStreamに出力する * v : stream (optional,sb==NULLの場合必須) * sb : StrBuf : (optional) */ static int stream_write_sub_s(Value v, StrBuf *sb, const char *s_p, int s_size, RefTextIO *tio) { if (s_size < 0) { s_size = strlen(s_p); } // TODO:未検証 if (v != VALUE_NULL) { RefBytesIO *mb = Value_vp(v); if (mb->rh.type == fs->cls_bytesio) { sb = &mb->buf; } } if (sb != NULL) { // sprintfの場合tio==NULL if (tio == NULL || tio->cs->utf8) { if (!StrBuf_add(sb, s_p, s_size)) { return FALSE; } return TRUE; } else { if (tio->out.ic == (void*)-1) { if (!IconvIO_open(&tio->out, fs->cs_utf8, tio->cs, tio->trans ? "?" : NULL)) { return FALSE; } } if (!IconvIO_conv(&tio->out, sb, s_p, s_size, TRUE, TRUE)) { return FALSE; } return TRUE; } } else { if (tio == NULL || tio->cs->utf8) { return stream_write_data(v, s_p, s_size); } else { Ref *r = Value_ref(v); IconvIO *ic = &tio->out; Value *vmb = &r->v[INDEX_WRITE_MEMIO]; RefBytesIO *mb; int max = Value_integral(r->v[INDEX_WRITE_MAX]); if (max == -1) { throw_error_select(THROW_NOT_OPENED_FOR_WRITE); return FALSE; } if (tio->out.ic == (void*)-1) { if (!IconvIO_open(&tio->out, fs->cs_utf8, tio->cs, tio->trans ? "?" : NULL)) { return FALSE; } } if (*vmb == VALUE_NULL) { *vmb = vp_Value(bytesio_new_sub(NULL, BUFFER_SIZE)); max = BUFFER_SIZE; r->v[INDEX_WRITE_MAX] = int32_Value(max); // STDOUTだけ特別扱い if (fs->cgi_mode) { if (r == Value_vp(fg->v_cio)) { send_headers(); } } } mb = Value_vp(*vmb); ic->inbuf = s_p; ic->inbytesleft = s_size; ic->outbuf = mb->buf.p + mb->buf.size; ic->outbytesleft = max - mb->buf.size; for (;;) { switch (IconvIO_next(ic)) { case ICONV_OK: mb->buf.size = ic->outbuf - mb->buf.p; goto BREAK; case ICONV_OUTBUF: mb->buf.size = ic->outbuf - mb->buf.p; if (!stream_flush_sub(v)) { return FALSE; } ic->outbuf = mb->buf.p; ic->outbytesleft = max; break; case ICONV_INVALID: if (tio->trans) { const char *ptr; if (ic->outbytesleft == 0) { mb->buf.size = ic->outbuf - mb->buf.p; if (!stream_flush_sub(v)) { return FALSE; } ic->outbuf = mb->buf.p; ic->outbytesleft = max; } ptr = ic->inbuf; *ic->outbuf++ = '?'; ic->outbytesleft--; // 1文字進める utf8_next(&ptr, ptr + ic->inbytesleft); ic->inbytesleft -= ptr - ic->inbuf; ic->inbuf = ptr; } else { RefCharset *cs = tio->cs; throw_errorf(fs->mod_lang, "CharsetError", "Cannot convert %U to %S", utf8_codepoint_at(ic->inbuf), cs->name); return FALSE; } break; } } BREAK: return TRUE; } } }