mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 06:15:21 +00:00
c-to-zig: return statement
This commit is contained in:
parent
848504117f
commit
ee9d1d0414
@ -833,7 +833,6 @@ struct AstNode {
|
||||
enum NodeType type;
|
||||
size_t line;
|
||||
size_t column;
|
||||
uint32_t create_index; // for determinism purposes
|
||||
ImportTableEntry *owner;
|
||||
union {
|
||||
AstNodeRoot root;
|
||||
@ -1523,7 +1522,6 @@ struct CodeGen {
|
||||
LLVMValueRef return_address_fn_val;
|
||||
LLVMValueRef frame_address_fn_val;
|
||||
bool error_during_imports;
|
||||
uint32_t next_node_index;
|
||||
TypeTableEntry *err_tag_type;
|
||||
|
||||
const char **clang_argv;
|
||||
|
||||
@ -3163,8 +3163,7 @@ ImportTableEntry *add_source_file(CodeGen *g, PackageTableEntry *package, Buf *a
|
||||
import_entry->line_offsets = tokenization.line_offsets;
|
||||
import_entry->path = abs_full_path;
|
||||
|
||||
import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color,
|
||||
&g->next_node_index);
|
||||
import_entry->root = ast_parse(source_code, tokenization.tokens, import_entry, g->err_color);
|
||||
assert(import_entry->root);
|
||||
if (g->verbose) {
|
||||
ast_print(stderr, import_entry->root, 0);
|
||||
|
||||
510
src/parseh.cpp
510
src/parseh.cpp
@ -17,6 +17,7 @@
|
||||
|
||||
#include <clang/Frontend/ASTUnit.h>
|
||||
#include <clang/Frontend/CompilerInstance.h>
|
||||
#include <clang/AST/Expr.h>
|
||||
|
||||
#include <string.h>
|
||||
|
||||
@ -54,6 +55,7 @@ struct Context {
|
||||
uint32_t next_anon_index;
|
||||
|
||||
CodeGen *codegen;
|
||||
ASTContext *ctx;
|
||||
};
|
||||
|
||||
static TypeTableEntry *resolve_qual_type_with_table(Context *c, QualType qt, const Decl *decl,
|
||||
@ -602,9 +604,477 @@ static TypeTableEntry *resolve_qual_type(Context *c, QualType qt, const Decl *de
|
||||
return resolve_qual_type_with_table(c, qt, decl, &c->global_type_table);
|
||||
}
|
||||
|
||||
#include "ast_render.hpp"
|
||||
|
||||
static AstNode * ast_trans_stmt(Context *c, Stmt *stmt);
|
||||
|
||||
static AstNode * ast_trans_expr(Context *c, Expr *expr) {
|
||||
return ast_trans_stmt(c, expr);
|
||||
}
|
||||
|
||||
static AstNode * ast_create_node(Context *c, const SourceRange &range, NodeType id) {
|
||||
AstNode *node = allocate<AstNode>(1);
|
||||
node->type = id;
|
||||
node->owner = c->import;
|
||||
// TODO line/column. mapping to C file??
|
||||
return node;
|
||||
}
|
||||
|
||||
static AstNode * ast_trans_compound_stmt(Context *c, CompoundStmt *stmt) {
|
||||
AstNode *block_node = ast_create_node(c, stmt->getSourceRange(), NodeTypeBlock);
|
||||
for (CompoundStmt::body_iterator it = stmt->body_begin(), end_it = stmt->body_end(); it != end_it; ++it) {
|
||||
AstNode *child_node = ast_trans_stmt(c, *it);
|
||||
block_node->data.block.statements.append(child_node);
|
||||
}
|
||||
return block_node;
|
||||
}
|
||||
|
||||
static AstNode *ast_trans_return_stmt(Context *c, ReturnStmt *stmt) {
|
||||
Expr *value_expr = stmt->getRetValue();
|
||||
if (value_expr == nullptr) {
|
||||
zig_panic("TODO handle C return void");
|
||||
} else {
|
||||
AstNode *return_node = ast_create_node(c, stmt->getSourceRange(), NodeTypeReturnExpr);
|
||||
return_node->data.return_expr.expr = ast_trans_expr(c, value_expr);
|
||||
return return_node;
|
||||
}
|
||||
}
|
||||
|
||||
static void aps_int_to_bigint(Context *c, const llvm::APSInt &aps_int, BigInt *bigint) {
|
||||
// TODO respect actually big integers
|
||||
if (aps_int.isSigned()) {
|
||||
if (aps_int > INT64_MAX || aps_int < INT64_MIN) {
|
||||
zig_panic("TODO actually bigint in C");
|
||||
} else {
|
||||
bigint_init_signed(bigint, aps_int.getExtValue());
|
||||
}
|
||||
} else {
|
||||
if (aps_int > INT64_MAX) {
|
||||
zig_panic("TODO actually bigint in C");
|
||||
} else {
|
||||
bigint_init_unsigned(bigint, aps_int.getExtValue());
|
||||
}
|
||||
}
|
||||
}
|
||||
static AstNode * ast_trans_integer_literal(Context *c, IntegerLiteral *stmt) {
|
||||
AstNode *node = ast_create_node(c, stmt->getSourceRange(), NodeTypeIntLiteral);
|
||||
llvm::APSInt result;
|
||||
if (!stmt->EvaluateAsInt(result, *c->ctx)) {
|
||||
fprintf(stderr, "TODO unable to convert integer literal to zig\n");
|
||||
}
|
||||
node->data.int_literal.bigint = allocate<BigInt>(1);
|
||||
aps_int_to_bigint(c, result, node->data.int_literal.bigint);
|
||||
return node;
|
||||
}
|
||||
|
||||
static AstNode *ast_trans_stmt(Context *c, Stmt *stmt) {
|
||||
Stmt::StmtClass sc = stmt->getStmtClass();
|
||||
switch (sc) {
|
||||
case Stmt::ReturnStmtClass:
|
||||
return ast_trans_return_stmt(c, (ReturnStmt *)stmt);
|
||||
case Stmt::CompoundStmtClass:
|
||||
return ast_trans_compound_stmt(c, (CompoundStmt *)stmt);
|
||||
case Stmt::IntegerLiteralClass:
|
||||
return ast_trans_integer_literal(c, (IntegerLiteral *)stmt);
|
||||
case Stmt::CaseStmtClass:
|
||||
zig_panic("TODO handle C CaseStmtClass");
|
||||
case Stmt::DefaultStmtClass:
|
||||
zig_panic("TODO handle C DefaultStmtClass");
|
||||
case Stmt::SwitchStmtClass:
|
||||
zig_panic("TODO handle C SwitchStmtClass");
|
||||
case Stmt::WhileStmtClass:
|
||||
zig_panic("TODO handle C WhileStmtClass");
|
||||
case Stmt::NoStmtClass:
|
||||
zig_panic("TODO handle C NoStmtClass");
|
||||
case Stmt::GCCAsmStmtClass:
|
||||
zig_panic("TODO handle C GCCAsmStmtClass");
|
||||
case Stmt::MSAsmStmtClass:
|
||||
zig_panic("TODO handle C MSAsmStmtClass");
|
||||
case Stmt::AttributedStmtClass:
|
||||
zig_panic("TODO handle C AttributedStmtClass");
|
||||
case Stmt::BreakStmtClass:
|
||||
zig_panic("TODO handle C BreakStmtClass");
|
||||
case Stmt::CXXCatchStmtClass:
|
||||
zig_panic("TODO handle C CXXCatchStmtClass");
|
||||
case Stmt::CXXForRangeStmtClass:
|
||||
zig_panic("TODO handle C CXXForRangeStmtClass");
|
||||
case Stmt::CXXTryStmtClass:
|
||||
zig_panic("TODO handle C CXXTryStmtClass");
|
||||
case Stmt::CapturedStmtClass:
|
||||
zig_panic("TODO handle C CapturedStmtClass");
|
||||
case Stmt::ContinueStmtClass:
|
||||
zig_panic("TODO handle C ContinueStmtClass");
|
||||
case Stmt::CoreturnStmtClass:
|
||||
zig_panic("TODO handle C CoreturnStmtClass");
|
||||
case Stmt::CoroutineBodyStmtClass:
|
||||
zig_panic("TODO handle C CoroutineBodyStmtClass");
|
||||
case Stmt::DeclStmtClass:
|
||||
zig_panic("TODO handle C DeclStmtClass");
|
||||
case Stmt::DoStmtClass:
|
||||
zig_panic("TODO handle C DoStmtClass");
|
||||
case Stmt::BinaryConditionalOperatorClass:
|
||||
zig_panic("TODO handle C BinaryConditionalOperatorClass");
|
||||
case Stmt::ConditionalOperatorClass:
|
||||
zig_panic("TODO handle C ConditionalOperatorClass");
|
||||
case Stmt::AddrLabelExprClass:
|
||||
zig_panic("TODO handle C AddrLabelExprClass");
|
||||
case Stmt::ArrayInitIndexExprClass:
|
||||
zig_panic("TODO handle C ArrayInitIndexExprClass");
|
||||
case Stmt::ArrayInitLoopExprClass:
|
||||
zig_panic("TODO handle C ArrayInitLoopExprClass");
|
||||
case Stmt::ArraySubscriptExprClass:
|
||||
zig_panic("TODO handle C ArraySubscriptExprClass");
|
||||
case Stmt::ArrayTypeTraitExprClass:
|
||||
zig_panic("TODO handle C ArrayTypeTraitExprClass");
|
||||
case Stmt::AsTypeExprClass:
|
||||
zig_panic("TODO handle C AsTypeExprClass");
|
||||
case Stmt::AtomicExprClass:
|
||||
zig_panic("TODO handle C AtomicExprClass");
|
||||
case Stmt::BinaryOperatorClass:
|
||||
zig_panic("TODO handle C BinaryOperatorClass");
|
||||
case Stmt::CompoundAssignOperatorClass:
|
||||
zig_panic("TODO handle C CompoundAssignOperatorClass");
|
||||
case Stmt::BlockExprClass:
|
||||
zig_panic("TODO handle C BlockExprClass");
|
||||
case Stmt::CXXBindTemporaryExprClass:
|
||||
zig_panic("TODO handle C CXXBindTemporaryExprClass");
|
||||
case Stmt::CXXBoolLiteralExprClass:
|
||||
zig_panic("TODO handle C CXXBoolLiteralExprClass");
|
||||
case Stmt::CXXConstructExprClass:
|
||||
zig_panic("TODO handle C CXXConstructExprClass");
|
||||
case Stmt::CXXTemporaryObjectExprClass:
|
||||
zig_panic("TODO handle C CXXTemporaryObjectExprClass");
|
||||
case Stmt::CXXDefaultArgExprClass:
|
||||
zig_panic("TODO handle C CXXDefaultArgExprClass");
|
||||
case Stmt::CXXDefaultInitExprClass:
|
||||
zig_panic("TODO handle C CXXDefaultInitExprClass");
|
||||
case Stmt::CXXDeleteExprClass:
|
||||
zig_panic("TODO handle C CXXDeleteExprClass");
|
||||
case Stmt::CXXDependentScopeMemberExprClass:
|
||||
zig_panic("TODO handle C CXXDependentScopeMemberExprClass");
|
||||
case Stmt::CXXFoldExprClass:
|
||||
zig_panic("TODO handle C CXXFoldExprClass");
|
||||
case Stmt::CXXInheritedCtorInitExprClass:
|
||||
zig_panic("TODO handle C CXXInheritedCtorInitExprClass");
|
||||
case Stmt::CXXNewExprClass:
|
||||
zig_panic("TODO handle C CXXNewExprClass");
|
||||
case Stmt::CXXNoexceptExprClass:
|
||||
zig_panic("TODO handle C CXXNoexceptExprClass");
|
||||
case Stmt::CXXNullPtrLiteralExprClass:
|
||||
zig_panic("TODO handle C CXXNullPtrLiteralExprClass");
|
||||
case Stmt::CXXPseudoDestructorExprClass:
|
||||
zig_panic("TODO handle C CXXPseudoDestructorExprClass");
|
||||
case Stmt::CXXScalarValueInitExprClass:
|
||||
zig_panic("TODO handle C CXXScalarValueInitExprClass");
|
||||
case Stmt::CXXStdInitializerListExprClass:
|
||||
zig_panic("TODO handle C CXXStdInitializerListExprClass");
|
||||
case Stmt::CXXThisExprClass:
|
||||
zig_panic("TODO handle C CXXThisExprClass");
|
||||
case Stmt::CXXThrowExprClass:
|
||||
zig_panic("TODO handle C CXXThrowExprClass");
|
||||
case Stmt::CXXTypeidExprClass:
|
||||
zig_panic("TODO handle C CXXTypeidExprClass");
|
||||
case Stmt::CXXUnresolvedConstructExprClass:
|
||||
zig_panic("TODO handle C CXXUnresolvedConstructExprClass");
|
||||
case Stmt::CXXUuidofExprClass:
|
||||
zig_panic("TODO handle C CXXUuidofExprClass");
|
||||
case Stmt::CallExprClass:
|
||||
zig_panic("TODO handle C CallExprClass");
|
||||
case Stmt::CUDAKernelCallExprClass:
|
||||
zig_panic("TODO handle C CUDAKernelCallExprClass");
|
||||
case Stmt::CXXMemberCallExprClass:
|
||||
zig_panic("TODO handle C CXXMemberCallExprClass");
|
||||
case Stmt::CXXOperatorCallExprClass:
|
||||
zig_panic("TODO handle C CXXOperatorCallExprClass");
|
||||
case Stmt::UserDefinedLiteralClass:
|
||||
zig_panic("TODO handle C UserDefinedLiteralClass");
|
||||
case Stmt::CStyleCastExprClass:
|
||||
zig_panic("TODO handle C CStyleCastExprClass");
|
||||
case Stmt::CXXFunctionalCastExprClass:
|
||||
zig_panic("TODO handle C CXXFunctionalCastExprClass");
|
||||
case Stmt::CXXConstCastExprClass:
|
||||
zig_panic("TODO handle C CXXConstCastExprClass");
|
||||
case Stmt::CXXDynamicCastExprClass:
|
||||
zig_panic("TODO handle C CXXDynamicCastExprClass");
|
||||
case Stmt::CXXReinterpretCastExprClass:
|
||||
zig_panic("TODO handle C CXXReinterpretCastExprClass");
|
||||
case Stmt::CXXStaticCastExprClass:
|
||||
zig_panic("TODO handle C CXXStaticCastExprClass");
|
||||
case Stmt::ObjCBridgedCastExprClass:
|
||||
zig_panic("TODO handle C ObjCBridgedCastExprClass");
|
||||
case Stmt::ImplicitCastExprClass:
|
||||
zig_panic("TODO handle C ImplicitCastExprClass");
|
||||
case Stmt::CharacterLiteralClass:
|
||||
zig_panic("TODO handle C CharacterLiteralClass");
|
||||
case Stmt::ChooseExprClass:
|
||||
zig_panic("TODO handle C ChooseExprClass");
|
||||
case Stmt::CompoundLiteralExprClass:
|
||||
zig_panic("TODO handle C CompoundLiteralExprClass");
|
||||
case Stmt::ConvertVectorExprClass:
|
||||
zig_panic("TODO handle C ConvertVectorExprClass");
|
||||
case Stmt::CoawaitExprClass:
|
||||
zig_panic("TODO handle C CoawaitExprClass");
|
||||
case Stmt::CoyieldExprClass:
|
||||
zig_panic("TODO handle C CoyieldExprClass");
|
||||
case Stmt::DeclRefExprClass:
|
||||
zig_panic("TODO handle C DeclRefExprClass");
|
||||
case Stmt::DependentCoawaitExprClass:
|
||||
zig_panic("TODO handle C DependentCoawaitExprClass");
|
||||
case Stmt::DependentScopeDeclRefExprClass:
|
||||
zig_panic("TODO handle C DependentScopeDeclRefExprClass");
|
||||
case Stmt::DesignatedInitExprClass:
|
||||
zig_panic("TODO handle C DesignatedInitExprClass");
|
||||
case Stmt::DesignatedInitUpdateExprClass:
|
||||
zig_panic("TODO handle C DesignatedInitUpdateExprClass");
|
||||
case Stmt::ExprWithCleanupsClass:
|
||||
zig_panic("TODO handle C ExprWithCleanupsClass");
|
||||
case Stmt::ExpressionTraitExprClass:
|
||||
zig_panic("TODO handle C ExpressionTraitExprClass");
|
||||
case Stmt::ExtVectorElementExprClass:
|
||||
zig_panic("TODO handle C ExtVectorElementExprClass");
|
||||
case Stmt::FloatingLiteralClass:
|
||||
zig_panic("TODO handle C FloatingLiteralClass");
|
||||
case Stmt::FunctionParmPackExprClass:
|
||||
zig_panic("TODO handle C FunctionParmPackExprClass");
|
||||
case Stmt::GNUNullExprClass:
|
||||
zig_panic("TODO handle C GNUNullExprClass");
|
||||
case Stmt::GenericSelectionExprClass:
|
||||
zig_panic("TODO handle C GenericSelectionExprClass");
|
||||
case Stmt::ImaginaryLiteralClass:
|
||||
zig_panic("TODO handle C ImaginaryLiteralClass");
|
||||
case Stmt::ImplicitValueInitExprClass:
|
||||
zig_panic("TODO handle C ImplicitValueInitExprClass");
|
||||
case Stmt::InitListExprClass:
|
||||
zig_panic("TODO handle C InitListExprClass");
|
||||
case Stmt::LambdaExprClass:
|
||||
zig_panic("TODO handle C LambdaExprClass");
|
||||
case Stmt::MSPropertyRefExprClass:
|
||||
zig_panic("TODO handle C MSPropertyRefExprClass");
|
||||
case Stmt::MSPropertySubscriptExprClass:
|
||||
zig_panic("TODO handle C MSPropertySubscriptExprClass");
|
||||
case Stmt::MaterializeTemporaryExprClass:
|
||||
zig_panic("TODO handle C MaterializeTemporaryExprClass");
|
||||
case Stmt::MemberExprClass:
|
||||
zig_panic("TODO handle C MemberExprClass");
|
||||
case Stmt::NoInitExprClass:
|
||||
zig_panic("TODO handle C NoInitExprClass");
|
||||
case Stmt::OMPArraySectionExprClass:
|
||||
zig_panic("TODO handle C OMPArraySectionExprClass");
|
||||
case Stmt::ObjCArrayLiteralClass:
|
||||
zig_panic("TODO handle C ObjCArrayLiteralClass");
|
||||
case Stmt::ObjCAvailabilityCheckExprClass:
|
||||
zig_panic("TODO handle C ObjCAvailabilityCheckExprClass");
|
||||
case Stmt::ObjCBoolLiteralExprClass:
|
||||
zig_panic("TODO handle C ObjCBoolLiteralExprClass");
|
||||
case Stmt::ObjCBoxedExprClass:
|
||||
zig_panic("TODO handle C ObjCBoxedExprClass");
|
||||
case Stmt::ObjCDictionaryLiteralClass:
|
||||
zig_panic("TODO handle C ObjCDictionaryLiteralClass");
|
||||
case Stmt::ObjCEncodeExprClass:
|
||||
zig_panic("TODO handle C ObjCEncodeExprClass");
|
||||
case Stmt::ObjCIndirectCopyRestoreExprClass:
|
||||
zig_panic("TODO handle C ObjCIndirectCopyRestoreExprClass");
|
||||
case Stmt::ObjCIsaExprClass:
|
||||
zig_panic("TODO handle C ObjCIsaExprClass");
|
||||
case Stmt::ObjCIvarRefExprClass:
|
||||
zig_panic("TODO handle C ObjCIvarRefExprClass");
|
||||
case Stmt::ObjCMessageExprClass:
|
||||
zig_panic("TODO handle C ObjCMessageExprClass");
|
||||
case Stmt::ObjCPropertyRefExprClass:
|
||||
zig_panic("TODO handle C ObjCPropertyRefExprClass");
|
||||
case Stmt::ObjCProtocolExprClass:
|
||||
zig_panic("TODO handle C ObjCProtocolExprClass");
|
||||
case Stmt::ObjCSelectorExprClass:
|
||||
zig_panic("TODO handle C ObjCSelectorExprClass");
|
||||
case Stmt::ObjCStringLiteralClass:
|
||||
zig_panic("TODO handle C ObjCStringLiteralClass");
|
||||
case Stmt::ObjCSubscriptRefExprClass:
|
||||
zig_panic("TODO handle C ObjCSubscriptRefExprClass");
|
||||
case Stmt::OffsetOfExprClass:
|
||||
zig_panic("TODO handle C OffsetOfExprClass");
|
||||
case Stmt::OpaqueValueExprClass:
|
||||
zig_panic("TODO handle C OpaqueValueExprClass");
|
||||
case Stmt::UnresolvedLookupExprClass:
|
||||
zig_panic("TODO handle C UnresolvedLookupExprClass");
|
||||
case Stmt::UnresolvedMemberExprClass:
|
||||
zig_panic("TODO handle C UnresolvedMemberExprClass");
|
||||
case Stmt::PackExpansionExprClass:
|
||||
zig_panic("TODO handle C PackExpansionExprClass");
|
||||
case Stmt::ParenExprClass:
|
||||
zig_panic("TODO handle C ParenExprClass");
|
||||
case Stmt::ParenListExprClass:
|
||||
zig_panic("TODO handle C ParenListExprClass");
|
||||
case Stmt::PredefinedExprClass:
|
||||
zig_panic("TODO handle C PredefinedExprClass");
|
||||
case Stmt::PseudoObjectExprClass:
|
||||
zig_panic("TODO handle C PseudoObjectExprClass");
|
||||
case Stmt::ShuffleVectorExprClass:
|
||||
zig_panic("TODO handle C ShuffleVectorExprClass");
|
||||
case Stmt::SizeOfPackExprClass:
|
||||
zig_panic("TODO handle C SizeOfPackExprClass");
|
||||
case Stmt::StmtExprClass:
|
||||
zig_panic("TODO handle C StmtExprClass");
|
||||
case Stmt::StringLiteralClass:
|
||||
zig_panic("TODO handle C StringLiteralClass");
|
||||
case Stmt::SubstNonTypeTemplateParmExprClass:
|
||||
zig_panic("TODO handle C SubstNonTypeTemplateParmExprClass");
|
||||
case Stmt::SubstNonTypeTemplateParmPackExprClass:
|
||||
zig_panic("TODO handle C SubstNonTypeTemplateParmPackExprClass");
|
||||
case Stmt::TypeTraitExprClass:
|
||||
zig_panic("TODO handle C TypeTraitExprClass");
|
||||
case Stmt::TypoExprClass:
|
||||
zig_panic("TODO handle C TypoExprClass");
|
||||
case Stmt::UnaryExprOrTypeTraitExprClass:
|
||||
zig_panic("TODO handle C UnaryExprOrTypeTraitExprClass");
|
||||
case Stmt::UnaryOperatorClass:
|
||||
zig_panic("TODO handle C UnaryOperatorClass");
|
||||
case Stmt::VAArgExprClass:
|
||||
zig_panic("TODO handle C VAArgExprClass");
|
||||
case Stmt::ForStmtClass:
|
||||
zig_panic("TODO handle C ForStmtClass");
|
||||
case Stmt::GotoStmtClass:
|
||||
zig_panic("TODO handle C GotoStmtClass");
|
||||
case Stmt::IfStmtClass:
|
||||
zig_panic("TODO handle C IfStmtClass");
|
||||
case Stmt::IndirectGotoStmtClass:
|
||||
zig_panic("TODO handle C IndirectGotoStmtClass");
|
||||
case Stmt::LabelStmtClass:
|
||||
zig_panic("TODO handle C LabelStmtClass");
|
||||
case Stmt::MSDependentExistsStmtClass:
|
||||
zig_panic("TODO handle C MSDependentExistsStmtClass");
|
||||
case Stmt::NullStmtClass:
|
||||
zig_panic("TODO handle C NullStmtClass");
|
||||
case Stmt::OMPAtomicDirectiveClass:
|
||||
zig_panic("TODO handle C OMPAtomicDirectiveClass");
|
||||
case Stmt::OMPBarrierDirectiveClass:
|
||||
zig_panic("TODO handle C OMPBarrierDirectiveClass");
|
||||
case Stmt::OMPCancelDirectiveClass:
|
||||
zig_panic("TODO handle C OMPCancelDirectiveClass");
|
||||
case Stmt::OMPCancellationPointDirectiveClass:
|
||||
zig_panic("TODO handle C OMPCancellationPointDirectiveClass");
|
||||
case Stmt::OMPCriticalDirectiveClass:
|
||||
zig_panic("TODO handle C OMPCriticalDirectiveClass");
|
||||
case Stmt::OMPFlushDirectiveClass:
|
||||
zig_panic("TODO handle C OMPFlushDirectiveClass");
|
||||
case Stmt::OMPDistributeDirectiveClass:
|
||||
zig_panic("TODO handle C OMPDistributeDirectiveClass");
|
||||
case Stmt::OMPDistributeParallelForDirectiveClass:
|
||||
zig_panic("TODO handle C OMPDistributeParallelForDirectiveClass");
|
||||
case Stmt::OMPDistributeParallelForSimdDirectiveClass:
|
||||
zig_panic("TODO handle C OMPDistributeParallelForSimdDirectiveClass");
|
||||
case Stmt::OMPDistributeSimdDirectiveClass:
|
||||
zig_panic("TODO handle C OMPDistributeSimdDirectiveClass");
|
||||
case Stmt::OMPForDirectiveClass:
|
||||
zig_panic("TODO handle C OMPForDirectiveClass");
|
||||
case Stmt::OMPForSimdDirectiveClass:
|
||||
zig_panic("TODO handle C OMPForSimdDirectiveClass");
|
||||
case Stmt::OMPParallelForDirectiveClass:
|
||||
zig_panic("TODO handle C OMPParallelForDirectiveClass");
|
||||
case Stmt::OMPParallelForSimdDirectiveClass:
|
||||
zig_panic("TODO handle C OMPParallelForSimdDirectiveClass");
|
||||
case Stmt::OMPSimdDirectiveClass:
|
||||
zig_panic("TODO handle C OMPSimdDirectiveClass");
|
||||
case Stmt::OMPTargetParallelForSimdDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetParallelForSimdDirectiveClass");
|
||||
case Stmt::OMPTargetSimdDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetSimdDirectiveClass");
|
||||
case Stmt::OMPTargetTeamsDistributeDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetTeamsDistributeDirectiveClass");
|
||||
case Stmt::OMPTargetTeamsDistributeParallelForDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetTeamsDistributeParallelForDirectiveClass");
|
||||
case Stmt::OMPTargetTeamsDistributeParallelForSimdDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetTeamsDistributeParallelForSimdDirectiveClass");
|
||||
case Stmt::OMPTargetTeamsDistributeSimdDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetTeamsDistributeSimdDirectiveClass");
|
||||
case Stmt::OMPTaskLoopDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTaskLoopDirectiveClass");
|
||||
case Stmt::OMPTaskLoopSimdDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTaskLoopSimdDirectiveClass");
|
||||
case Stmt::OMPTeamsDistributeDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTeamsDistributeDirectiveClass");
|
||||
case Stmt::OMPTeamsDistributeParallelForDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTeamsDistributeParallelForDirectiveClass");
|
||||
case Stmt::OMPTeamsDistributeParallelForSimdDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTeamsDistributeParallelForSimdDirectiveClass");
|
||||
case Stmt::OMPTeamsDistributeSimdDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTeamsDistributeSimdDirectiveClass");
|
||||
case Stmt::OMPMasterDirectiveClass:
|
||||
zig_panic("TODO handle C OMPMasterDirectiveClass");
|
||||
case Stmt::OMPOrderedDirectiveClass:
|
||||
zig_panic("TODO handle C OMPOrderedDirectiveClass");
|
||||
case Stmt::OMPParallelDirectiveClass:
|
||||
zig_panic("TODO handle C OMPParallelDirectiveClass");
|
||||
case Stmt::OMPParallelSectionsDirectiveClass:
|
||||
zig_panic("TODO handle C OMPParallelSectionsDirectiveClass");
|
||||
case Stmt::OMPSectionDirectiveClass:
|
||||
zig_panic("TODO handle C OMPSectionDirectiveClass");
|
||||
case Stmt::OMPSectionsDirectiveClass:
|
||||
zig_panic("TODO handle C OMPSectionsDirectiveClass");
|
||||
case Stmt::OMPSingleDirectiveClass:
|
||||
zig_panic("TODO handle C OMPSingleDirectiveClass");
|
||||
case Stmt::OMPTargetDataDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetDataDirectiveClass");
|
||||
case Stmt::OMPTargetDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetDirectiveClass");
|
||||
case Stmt::OMPTargetEnterDataDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetEnterDataDirectiveClass");
|
||||
case Stmt::OMPTargetExitDataDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetExitDataDirectiveClass");
|
||||
case Stmt::OMPTargetParallelDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetParallelDirectiveClass");
|
||||
case Stmt::OMPTargetParallelForDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetParallelForDirectiveClass");
|
||||
case Stmt::OMPTargetTeamsDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetTeamsDirectiveClass");
|
||||
case Stmt::OMPTargetUpdateDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTargetUpdateDirectiveClass");
|
||||
case Stmt::OMPTaskDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTaskDirectiveClass");
|
||||
case Stmt::OMPTaskgroupDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTaskgroupDirectiveClass");
|
||||
case Stmt::OMPTaskwaitDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTaskwaitDirectiveClass");
|
||||
case Stmt::OMPTaskyieldDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTaskyieldDirectiveClass");
|
||||
case Stmt::OMPTeamsDirectiveClass:
|
||||
zig_panic("TODO handle C OMPTeamsDirectiveClass");
|
||||
case Stmt::ObjCAtCatchStmtClass:
|
||||
zig_panic("TODO handle C ObjCAtCatchStmtClass");
|
||||
case Stmt::ObjCAtFinallyStmtClass:
|
||||
zig_panic("TODO handle C ObjCAtFinallyStmtClass");
|
||||
case Stmt::ObjCAtSynchronizedStmtClass:
|
||||
zig_panic("TODO handle C ObjCAtSynchronizedStmtClass");
|
||||
case Stmt::ObjCAtThrowStmtClass:
|
||||
zig_panic("TODO handle C ObjCAtThrowStmtClass");
|
||||
case Stmt::ObjCAtTryStmtClass:
|
||||
zig_panic("TODO handle C ObjCAtTryStmtClass");
|
||||
case Stmt::ObjCAutoreleasePoolStmtClass:
|
||||
zig_panic("TODO handle C ObjCAutoreleasePoolStmtClass");
|
||||
case Stmt::ObjCForCollectionStmtClass:
|
||||
zig_panic("TODO handle C ObjCForCollectionStmtClass");
|
||||
case Stmt::SEHExceptStmtClass:
|
||||
zig_panic("TODO handle C SEHExceptStmtClass");
|
||||
case Stmt::SEHFinallyStmtClass:
|
||||
zig_panic("TODO handle C SEHFinallyStmtClass");
|
||||
case Stmt::SEHLeaveStmtClass:
|
||||
zig_panic("TODO handle C SEHLeaveStmtClass");
|
||||
case Stmt::SEHTryStmtClass:
|
||||
zig_panic("TODO handle C SEHTryStmtClass");
|
||||
}
|
||||
zig_unreachable();
|
||||
}
|
||||
|
||||
static void visit_fn_decl(Context *c, const FunctionDecl *fn_decl) {
|
||||
Buf *fn_name = buf_create_from_str(decl_name(fn_decl));
|
||||
|
||||
if (fn_decl->hasBody()) {
|
||||
fprintf(stderr, "fn %s\n", buf_ptr(fn_name));
|
||||
Stmt *body = fn_decl->getBody();
|
||||
AstNode *body_node = ast_trans_stmt(c, body);
|
||||
ast_render(c->codegen, stderr, body_node, 4);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
|
||||
if (get_global(c, fn_name)) {
|
||||
// we already saw this function
|
||||
return;
|
||||
@ -1373,7 +1843,7 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
|
||||
|
||||
std::shared_ptr<PCHContainerOperations> pch_container_ops = std::make_shared<PCHContainerOperations>();
|
||||
|
||||
bool skip_function_bodies = true;
|
||||
bool skip_function_bodies = false;
|
||||
bool only_local_decls = true;
|
||||
bool capture_diagnostics = true;
|
||||
bool user_files_are_volatile = true;
|
||||
@ -1390,7 +1860,6 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
|
||||
single_file_parse, user_files_are_volatile, for_serialization, None, &err_unit,
|
||||
nullptr));
|
||||
|
||||
|
||||
// Early failures in LoadFromCommandLine may return with ErrUnit unset.
|
||||
if (!ast_unit && !err_unit) {
|
||||
return ErrorFileSystem;
|
||||
@ -1416,29 +1885,36 @@ int parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const ch
|
||||
break;
|
||||
}
|
||||
StringRef msg_str_ref = it->getMessage();
|
||||
FullSourceLoc fsl = it->getLocation();
|
||||
FileID file_id = fsl.getFileID();
|
||||
StringRef filename = fsl.getManager().getFilename(fsl);
|
||||
unsigned line = fsl.getSpellingLineNumber() - 1;
|
||||
unsigned column = fsl.getSpellingColumnNumber() - 1;
|
||||
unsigned offset = fsl.getManager().getFileOffset(fsl);
|
||||
const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin();
|
||||
Buf *msg = buf_create_from_str((const char *)msg_str_ref.bytes_begin());
|
||||
Buf *path;
|
||||
if (filename.empty()) {
|
||||
path = buf_alloc();
|
||||
FullSourceLoc fsl = it->getLocation();
|
||||
if (fsl.hasManager()) {
|
||||
FileID file_id = fsl.getFileID();
|
||||
StringRef filename = fsl.getManager().getFilename(fsl);
|
||||
unsigned line = fsl.getSpellingLineNumber() - 1;
|
||||
unsigned column = fsl.getSpellingColumnNumber() - 1;
|
||||
unsigned offset = fsl.getManager().getFileOffset(fsl);
|
||||
const char *source = (const char *)fsl.getManager().getBufferData(file_id).bytes_begin();
|
||||
Buf *path;
|
||||
if (filename.empty()) {
|
||||
path = buf_alloc();
|
||||
} else {
|
||||
path = buf_create_from_mem((const char *)filename.bytes_begin(), filename.size());
|
||||
}
|
||||
|
||||
ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg);
|
||||
|
||||
c->errors->append(err_msg);
|
||||
} else {
|
||||
path = buf_create_from_mem((const char *)filename.bytes_begin(), filename.size());
|
||||
// NOTE the only known way this gets triggered right now is if you have a lot of errors
|
||||
// clang emits "too many errors emitted, stopping now"
|
||||
fprintf(stderr, "unexpected error from clang: %s\n", buf_ptr(msg));
|
||||
}
|
||||
|
||||
ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg);
|
||||
|
||||
c->errors->append(err_msg);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
c->ctx = &ast_unit->getASTContext();
|
||||
c->source_manager = &ast_unit->getSourceManager();
|
||||
|
||||
ast_unit->visitLocalTopLevelDecls(c, decl_visitor);
|
||||
|
||||
@ -20,7 +20,6 @@ struct ParseContext {
|
||||
ZigList<Token> *tokens;
|
||||
ImportTableEntry *owner;
|
||||
ErrColor err_color;
|
||||
uint32_t *next_node_index;
|
||||
// These buffers are used freqently so we preallocate them once here.
|
||||
Buf *void_buf;
|
||||
Buf *empty_buf;
|
||||
@ -70,8 +69,6 @@ static AstNode *ast_create_node_no_line_info(ParseContext *pc, NodeType type) {
|
||||
AstNode *node = allocate<AstNode>(1);
|
||||
node->type = type;
|
||||
node->owner = pc->owner;
|
||||
node->create_index = *pc->next_node_index;
|
||||
*pc->next_node_index += 1;
|
||||
return node;
|
||||
}
|
||||
|
||||
@ -2611,7 +2608,7 @@ static AstNode *ast_parse_root(ParseContext *pc, size_t *token_index) {
|
||||
}
|
||||
|
||||
AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner,
|
||||
ErrColor err_color, uint32_t *next_node_index)
|
||||
ErrColor err_color)
|
||||
{
|
||||
ParseContext pc = {0};
|
||||
pc.void_buf = buf_create_from_str("void");
|
||||
@ -2620,7 +2617,6 @@ AstNode *ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner,
|
||||
pc.owner = owner;
|
||||
pc.buf = buf;
|
||||
pc.tokens = tokens;
|
||||
pc.next_node_index = next_node_index;
|
||||
size_t token_index = 0;
|
||||
pc.root = ast_parse_root(&pc, &token_index);
|
||||
return pc.root;
|
||||
|
||||
@ -17,8 +17,7 @@ void ast_token_error(Token *token, const char *format, ...);
|
||||
|
||||
|
||||
// This function is provided by generated code, generated by parsergen.cpp
|
||||
AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color,
|
||||
uint32_t *next_node_index);
|
||||
AstNode * ast_parse(Buf *buf, ZigList<Token> *tokens, ImportTableEntry *owner, ErrColor err_color);
|
||||
|
||||
void ast_print(AstNode *node, int indent);
|
||||
|
||||
|
||||
522
std/zlib/deflate.zig
Normal file
522
std/zlib/deflate.zig
Normal file
@ -0,0 +1,522 @@
|
||||
const z_stream = struct {
|
||||
/// next input byte */
|
||||
next_in: &const u8,
|
||||
|
||||
/// number of bytes available at next_in
|
||||
avail_in: u16,
|
||||
/// total number of input bytes read so far
|
||||
total_in: u32,
|
||||
|
||||
/// next output byte will go here
|
||||
next_out: u8,
|
||||
/// remaining free space at next_out
|
||||
avail_out: u16,
|
||||
/// total number of bytes output so far
|
||||
total_out: u32,
|
||||
|
||||
/// last error message, NULL if no error
|
||||
msg: ?&const u8,
|
||||
/// not visible by applications
|
||||
state:
|
||||
struct internal_state FAR *state; // not visible by applications */
|
||||
|
||||
alloc_func zalloc; // used to allocate the internal state */
|
||||
free_func zfree; // used to free the internal state */
|
||||
voidpf opaque; // private data object passed to zalloc and zfree */
|
||||
|
||||
int data_type; // best guess about the data type: binary or text
|
||||
// for deflate, or the decoding state for inflate */
|
||||
uint32_t adler; // Adler-32 or CRC-32 value of the uncompressed data */
|
||||
uint32_t reserved; // reserved for future use */
|
||||
};
|
||||
|
||||
typedef struct internal_state {
|
||||
z_stream * strm; /* pointer back to this zlib stream */
|
||||
int status; /* as the name implies */
|
||||
uint8_t *pending_buf; /* output still pending */
|
||||
ulg pending_buf_size; /* size of pending_buf */
|
||||
uint8_t *pending_out; /* next pending byte to output to the stream */
|
||||
ulg pending; /* nb of bytes in the pending buffer */
|
||||
int wrap; /* bit 0 true for zlib, bit 1 true for gzip */
|
||||
gz_headerp gzhead; /* gzip header information to write */
|
||||
ulg gzindex; /* where in extra, name, or comment */
|
||||
uint8_t method; /* can only be DEFLATED */
|
||||
int last_flush; /* value of flush param for previous deflate call */
|
||||
|
||||
/* used by deflate.c: */
|
||||
|
||||
uint16_t w_size; /* LZ77 window size (32K by default) */
|
||||
uint16_t w_bits; /* log2(w_size) (8..16) */
|
||||
uint16_t w_mask; /* w_size - 1 */
|
||||
|
||||
uint8_t *window;
|
||||
/* Sliding window. Input bytes are read into the second half of the window,
|
||||
* and move to the first half later to keep a dictionary of at least wSize
|
||||
* bytes. With this organization, matches are limited to a distance of
|
||||
* wSize-MAX_MATCH bytes, but this ensures that IO is always
|
||||
* performed with a length multiple of the block size. Also, it limits
|
||||
* the window size to 64K, which is quite useful on MSDOS.
|
||||
* To do: use the user input buffer as sliding window.
|
||||
*/
|
||||
|
||||
ulg window_size;
|
||||
/* Actual size of window: 2*wSize, except when the user input buffer
|
||||
* is directly used as sliding window.
|
||||
*/
|
||||
|
||||
Posf *prev;
|
||||
/* Link to older string with same hash index. To limit the size of this
|
||||
* array to 64K, this link is maintained only for the last 32K strings.
|
||||
* An index in this array is thus a window index modulo 32K.
|
||||
*/
|
||||
|
||||
Posf *head; /* Heads of the hash chains or NIL. */
|
||||
|
||||
uint16_t ins_h; /* hash index of string to be inserted */
|
||||
uint16_t hash_size; /* number of elements in hash table */
|
||||
uint16_t hash_bits; /* log2(hash_size) */
|
||||
uint16_t hash_mask; /* hash_size-1 */
|
||||
|
||||
uint16_t hash_shift;
|
||||
/* Number of bits by which ins_h must be shifted at each input
|
||||
* step. It must be such that after MIN_MATCH steps, the oldest
|
||||
* byte no longer takes part in the hash key, that is:
|
||||
* hash_shift * MIN_MATCH >= hash_bits
|
||||
*/
|
||||
|
||||
long block_start;
|
||||
/* Window position at the beginning of the current output block. Gets
|
||||
* negative when the window is moved backwards.
|
||||
*/
|
||||
|
||||
uint16_t match_length; /* length of best match */
|
||||
IPos prev_match; /* previous match */
|
||||
int match_available; /* set if previous match exists */
|
||||
uint16_t strstart; /* start of string to insert */
|
||||
uint16_t match_start; /* start of matching string */
|
||||
uint16_t lookahead; /* number of valid bytes ahead in window */
|
||||
|
||||
uint16_t prev_length;
|
||||
/* Length of the best match at previous step. Matches not greater than this
|
||||
* are discarded. This is used in the lazy match evaluation.
|
||||
*/
|
||||
|
||||
uint16_t max_chain_length;
|
||||
/* To speed up deflation, hash chains are never searched beyond this
|
||||
* length. A higher limit improves compression ratio but degrades the
|
||||
* speed.
|
||||
*/
|
||||
|
||||
uint16_t max_lazy_match;
|
||||
/* Attempt to find a better match only when the current match is strictly
|
||||
* smaller than this value. This mechanism is used only for compression
|
||||
* levels >= 4.
|
||||
*/
|
||||
# define max_insert_length max_lazy_match
|
||||
/* Insert new strings in the hash table only if the match length is not
|
||||
* greater than this length. This saves time but degrades compression.
|
||||
* max_insert_length is used only for compression levels <= 3.
|
||||
*/
|
||||
|
||||
int level; /* compression level (1..9) */
|
||||
int strategy; /* favor or force Huffman coding*/
|
||||
|
||||
uint16_t good_match;
|
||||
/* Use a faster search when the previous match is longer than this */
|
||||
|
||||
int nice_match; /* Stop searching when current match exceeds this */
|
||||
|
||||
/* used by trees.c: */
|
||||
/* Didn't use ct_data typedef below to suppress compiler warning */
|
||||
struct ct_data_s dyn_ltree[HEAP_SIZE]; /* literal and length tree */
|
||||
struct ct_data_s dyn_dtree[2*D_CODES+1]; /* distance tree */
|
||||
struct ct_data_s bl_tree[2*BL_CODES+1]; /* Huffman tree for bit lengths */
|
||||
|
||||
struct tree_desc_s l_desc; /* desc. for literal tree */
|
||||
struct tree_desc_s d_desc; /* desc. for distance tree */
|
||||
struct tree_desc_s bl_desc; /* desc. for bit length tree */
|
||||
|
||||
ush bl_count[MAX_BITS+1];
|
||||
/* number of codes at each bit length for an optimal tree */
|
||||
|
||||
int heap[2*L_CODES+1]; /* heap used to build the Huffman trees */
|
||||
int heap_len; /* number of elements in the heap */
|
||||
int heap_max; /* element of largest frequency */
|
||||
/* The sons of heap[n] are heap[2*n] and heap[2*n+1]. heap[0] is not used.
|
||||
* The same heap array is used to build all trees.
|
||||
*/
|
||||
|
||||
uch depth[2*L_CODES+1];
|
||||
/* Depth of each subtree used as tie breaker for trees of equal frequency
|
||||
*/
|
||||
|
||||
uchf *l_buf; /* buffer for literals or lengths */
|
||||
|
||||
uint16_t lit_bufsize;
|
||||
/* Size of match buffer for literals/lengths. There are 4 reasons for
|
||||
* limiting lit_bufsize to 64K:
|
||||
* - frequencies can be kept in 16 bit counters
|
||||
* - if compression is not successful for the first block, all input
|
||||
* data is still in the window so we can still emit a stored block even
|
||||
* when input comes from standard input. (This can also be done for
|
||||
* all blocks if lit_bufsize is not greater than 32K.)
|
||||
* - if compression is not successful for a file smaller than 64K, we can
|
||||
* even emit a stored file instead of a stored block (saving 5 bytes).
|
||||
* This is applicable only for zip (not gzip or zlib).
|
||||
* - creating new Huffman trees less frequently may not provide fast
|
||||
* adaptation to changes in the input data statistics. (Take for
|
||||
* example a binary file with poorly compressible code followed by
|
||||
* a highly compressible string table.) Smaller buffer sizes give
|
||||
* fast adaptation but have of course the overhead of transmitting
|
||||
* trees more frequently.
|
||||
* - I can't count above 4
|
||||
*/
|
||||
|
||||
uint16_t last_lit; /* running index in l_buf */
|
||||
|
||||
ushf *d_buf;
|
||||
/* Buffer for distances. To simplify the code, d_buf and l_buf have
|
||||
* the same number of elements. To use different lengths, an extra flag
|
||||
* array would be necessary.
|
||||
*/
|
||||
|
||||
ulg opt_len; /* bit length of current block with optimal trees */
|
||||
ulg static_len; /* bit length of current block with static trees */
|
||||
uint16_t matches; /* number of string matches in current block */
|
||||
uint16_t insert; /* bytes at end of window left to insert */
|
||||
|
||||
#ifdef ZLIB_DEBUG
|
||||
ulg compressed_len; /* total bit length of compressed file mod 2^32 */
|
||||
ulg bits_sent; /* bit length of compressed data sent mod 2^32 */
|
||||
#endif
|
||||
|
||||
ush bi_buf;
|
||||
/* Output buffer. bits are inserted starting at the bottom (least
|
||||
* significant bits).
|
||||
*/
|
||||
int bi_valid;
|
||||
/* Number of valid bits in bi_buf. All bits above the last valid bit
|
||||
* are always zero.
|
||||
*/
|
||||
|
||||
ulg high_water;
|
||||
/* High water mark offset in window for initialized bytes -- bytes above
|
||||
* this are set to zero in order to avoid memory check warnings when
|
||||
* longest match routines access bytes past the input. This is then
|
||||
* updated to the new high water mark.
|
||||
*/
|
||||
|
||||
} FAR deflate_state;
|
||||
|
||||
fn deflate(strm: &z_stream, flush: int) -> %void {
|
||||
|
||||
}
|
||||
|
||||
int deflate (z_stream * strm, int flush) {
|
||||
int old_flush; /* value of flush param for previous deflate call */
|
||||
deflate_state *s;
|
||||
|
||||
if (deflateStateCheck(strm) || flush > Z_BLOCK || flush < 0) {
|
||||
return Z_STREAM_ERROR;
|
||||
}
|
||||
s = strm->state;
|
||||
|
||||
if (strm->next_out == Z_NULL ||
|
||||
(strm->avail_in != 0 && strm->next_in == Z_NULL) ||
|
||||
(s->status == FINISH_STATE && flush != Z_FINISH)) {
|
||||
ERR_RETURN(strm, Z_STREAM_ERROR);
|
||||
}
|
||||
if (strm->avail_out == 0) ERR_RETURN(strm, Z_BUF_ERROR);
|
||||
|
||||
old_flush = s->last_flush;
|
||||
s->last_flush = flush;
|
||||
|
||||
/* Flush as much pending output as possible */
|
||||
if (s->pending != 0) {
|
||||
flush_pending(strm);
|
||||
if (strm->avail_out == 0) {
|
||||
/* Since avail_out is 0, deflate will be called again with
|
||||
* more output space, but possibly with both pending and
|
||||
* avail_in equal to zero. There won't be anything to do,
|
||||
* but this is not an error situation so make sure we
|
||||
* return OK instead of BUF_ERROR at next call of deflate:
|
||||
*/
|
||||
s->last_flush = -1;
|
||||
return Z_OK;
|
||||
}
|
||||
|
||||
/* Make sure there is something to do and avoid duplicate consecutive
|
||||
* flushes. For repeated and useless calls with Z_FINISH, we keep
|
||||
* returning Z_STREAM_END instead of Z_BUF_ERROR.
|
||||
*/
|
||||
} else if (strm->avail_in == 0 && RANK(flush) <= RANK(old_flush) &&
|
||||
flush != Z_FINISH) {
|
||||
ERR_RETURN(strm, Z_BUF_ERROR);
|
||||
}
|
||||
|
||||
/* User must not provide more input after the first FINISH: */
|
||||
if (s->status == FINISH_STATE && strm->avail_in != 0) {
|
||||
ERR_RETURN(strm, Z_BUF_ERROR);
|
||||
}
|
||||
|
||||
/* Write the header */
|
||||
if (s->status == INIT_STATE) {
|
||||
/* zlib header */
|
||||
uint16_t header = (Z_DEFLATED + ((s->w_bits-8)<<4)) << 8;
|
||||
uint16_t level_flags;
|
||||
|
||||
if (s->strategy >= Z_HUFFMAN_ONLY || s->level < 2)
|
||||
level_flags = 0;
|
||||
else if (s->level < 6)
|
||||
level_flags = 1;
|
||||
else if (s->level == 6)
|
||||
level_flags = 2;
|
||||
else
|
||||
level_flags = 3;
|
||||
header |= (level_flags << 6);
|
||||
if (s->strstart != 0) header |= PRESET_DICT;
|
||||
header += 31 - (header % 31);
|
||||
|
||||
putShortMSB(s, header);
|
||||
|
||||
/* Save the adler32 of the preset dictionary: */
|
||||
if (s->strstart != 0) {
|
||||
putShortMSB(s, (uint16_t)(strm->adler >> 16));
|
||||
putShortMSB(s, (uint16_t)(strm->adler & 0xffff));
|
||||
}
|
||||
strm->adler = adler32(0L, Z_NULL, 0);
|
||||
s->status = BUSY_STATE;
|
||||
|
||||
/* Compression must start with an empty pending buffer */
|
||||
flush_pending(strm);
|
||||
if (s->pending != 0) {
|
||||
s->last_flush = -1;
|
||||
return Z_OK;
|
||||
}
|
||||
}
|
||||
#ifdef GZIP
|
||||
if (s->status == GZIP_STATE) {
|
||||
/* gzip header */
|
||||
strm->adler = crc32(0L, Z_NULL, 0);
|
||||
put_byte(s, 31);
|
||||
put_byte(s, 139);
|
||||
put_byte(s, 8);
|
||||
if (s->gzhead == Z_NULL) {
|
||||
put_byte(s, 0);
|
||||
put_byte(s, 0);
|
||||
put_byte(s, 0);
|
||||
put_byte(s, 0);
|
||||
put_byte(s, 0);
|
||||
put_byte(s, s->level == 9 ? 2 :
|
||||
(s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
|
||||
4 : 0));
|
||||
put_byte(s, OS_CODE);
|
||||
s->status = BUSY_STATE;
|
||||
|
||||
/* Compression must start with an empty pending buffer */
|
||||
flush_pending(strm);
|
||||
if (s->pending != 0) {
|
||||
s->last_flush = -1;
|
||||
return Z_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
put_byte(s, (s->gzhead->text ? 1 : 0) +
|
||||
(s->gzhead->hcrc ? 2 : 0) +
|
||||
(s->gzhead->extra == Z_NULL ? 0 : 4) +
|
||||
(s->gzhead->name == Z_NULL ? 0 : 8) +
|
||||
(s->gzhead->comment == Z_NULL ? 0 : 16)
|
||||
);
|
||||
put_byte(s, (uint8_t)(s->gzhead->time & 0xff));
|
||||
put_byte(s, (uint8_t)((s->gzhead->time >> 8) & 0xff));
|
||||
put_byte(s, (uint8_t)((s->gzhead->time >> 16) & 0xff));
|
||||
put_byte(s, (uint8_t)((s->gzhead->time >> 24) & 0xff));
|
||||
put_byte(s, s->level == 9 ? 2 :
|
||||
(s->strategy >= Z_HUFFMAN_ONLY || s->level < 2 ?
|
||||
4 : 0));
|
||||
put_byte(s, s->gzhead->os & 0xff);
|
||||
if (s->gzhead->extra != Z_NULL) {
|
||||
put_byte(s, s->gzhead->extra_len & 0xff);
|
||||
put_byte(s, (s->gzhead->extra_len >> 8) & 0xff);
|
||||
}
|
||||
if (s->gzhead->hcrc)
|
||||
strm->adler = crc32(strm->adler, s->pending_buf,
|
||||
s->pending);
|
||||
s->gzindex = 0;
|
||||
s->status = EXTRA_STATE;
|
||||
}
|
||||
}
|
||||
if (s->status == EXTRA_STATE) {
|
||||
if (s->gzhead->extra != Z_NULL) {
|
||||
ulg beg = s->pending; /* start of bytes to update crc */
|
||||
uint16_t left = (s->gzhead->extra_len & 0xffff) - s->gzindex;
|
||||
while (s->pending + left > s->pending_buf_size) {
|
||||
uint16_t copy = s->pending_buf_size - s->pending;
|
||||
zmemcpy(s->pending_buf + s->pending,
|
||||
s->gzhead->extra + s->gzindex, copy);
|
||||
s->pending = s->pending_buf_size;
|
||||
HCRC_UPDATE(beg);
|
||||
s->gzindex += copy;
|
||||
flush_pending(strm);
|
||||
if (s->pending != 0) {
|
||||
s->last_flush = -1;
|
||||
return Z_OK;
|
||||
}
|
||||
beg = 0;
|
||||
left -= copy;
|
||||
}
|
||||
zmemcpy(s->pending_buf + s->pending,
|
||||
s->gzhead->extra + s->gzindex, left);
|
||||
s->pending += left;
|
||||
HCRC_UPDATE(beg);
|
||||
s->gzindex = 0;
|
||||
}
|
||||
s->status = NAME_STATE;
|
||||
}
|
||||
if (s->status == NAME_STATE) {
|
||||
if (s->gzhead->name != Z_NULL) {
|
||||
ulg beg = s->pending; /* start of bytes to update crc */
|
||||
int val;
|
||||
do {
|
||||
if (s->pending == s->pending_buf_size) {
|
||||
HCRC_UPDATE(beg);
|
||||
flush_pending(strm);
|
||||
if (s->pending != 0) {
|
||||
s->last_flush = -1;
|
||||
return Z_OK;
|
||||
}
|
||||
beg = 0;
|
||||
}
|
||||
val = s->gzhead->name[s->gzindex++];
|
||||
put_byte(s, val);
|
||||
} while (val != 0);
|
||||
HCRC_UPDATE(beg);
|
||||
s->gzindex = 0;
|
||||
}
|
||||
s->status = COMMENT_STATE;
|
||||
}
|
||||
if (s->status == COMMENT_STATE) {
|
||||
if (s->gzhead->comment != Z_NULL) {
|
||||
ulg beg = s->pending; /* start of bytes to update crc */
|
||||
int val;
|
||||
do {
|
||||
if (s->pending == s->pending_buf_size) {
|
||||
HCRC_UPDATE(beg);
|
||||
flush_pending(strm);
|
||||
if (s->pending != 0) {
|
||||
s->last_flush = -1;
|
||||
return Z_OK;
|
||||
}
|
||||
beg = 0;
|
||||
}
|
||||
val = s->gzhead->comment[s->gzindex++];
|
||||
put_byte(s, val);
|
||||
} while (val != 0);
|
||||
HCRC_UPDATE(beg);
|
||||
}
|
||||
s->status = HCRC_STATE;
|
||||
}
|
||||
if (s->status == HCRC_STATE) {
|
||||
if (s->gzhead->hcrc) {
|
||||
if (s->pending + 2 > s->pending_buf_size) {
|
||||
flush_pending(strm);
|
||||
if (s->pending != 0) {
|
||||
s->last_flush = -1;
|
||||
return Z_OK;
|
||||
}
|
||||
}
|
||||
put_byte(s, (uint8_t)(strm->adler & 0xff));
|
||||
put_byte(s, (uint8_t)((strm->adler >> 8) & 0xff));
|
||||
strm->adler = crc32(0L, Z_NULL, 0);
|
||||
}
|
||||
s->status = BUSY_STATE;
|
||||
|
||||
/* Compression must start with an empty pending buffer */
|
||||
flush_pending(strm);
|
||||
if (s->pending != 0) {
|
||||
s->last_flush = -1;
|
||||
return Z_OK;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Start a new block or continue the current one.
|
||||
*/
|
||||
if (strm->avail_in != 0 || s->lookahead != 0 ||
|
||||
(flush != Z_NO_FLUSH && s->status != FINISH_STATE)) {
|
||||
block_state bstate;
|
||||
|
||||
bstate = s->level == 0 ? deflate_stored(s, flush) :
|
||||
s->strategy == Z_HUFFMAN_ONLY ? deflate_huff(s, flush) :
|
||||
s->strategy == Z_RLE ? deflate_rle(s, flush) :
|
||||
(*(configuration_table[s->level].func))(s, flush);
|
||||
|
||||
if (bstate == finish_started || bstate == finish_done) {
|
||||
s->status = FINISH_STATE;
|
||||
}
|
||||
if (bstate == need_more || bstate == finish_started) {
|
||||
if (strm->avail_out == 0) {
|
||||
s->last_flush = -1; /* avoid BUF_ERROR next call, see above */
|
||||
}
|
||||
return Z_OK;
|
||||
/* If flush != Z_NO_FLUSH && avail_out == 0, the next call
|
||||
* of deflate should use the same flush parameter to make sure
|
||||
* that the flush is complete. So we don't have to output an
|
||||
* empty block here, this will be done at next call. This also
|
||||
* ensures that for a very small output buffer, we emit at most
|
||||
* one empty block.
|
||||
*/
|
||||
}
|
||||
if (bstate == block_done) {
|
||||
if (flush == Z_PARTIAL_FLUSH) {
|
||||
_tr_align(s);
|
||||
} else if (flush != Z_BLOCK) { /* FULL_FLUSH or SYNC_FLUSH */
|
||||
_tr_stored_block(s, (char*)0, 0L, 0);
|
||||
/* For a full flush, this empty block will be recognized
|
||||
* as a special marker by inflate_sync().
|
||||
*/
|
||||
if (flush == Z_FULL_FLUSH) {
|
||||
CLEAR_HASH(s); /* forget history */
|
||||
if (s->lookahead == 0) {
|
||||
s->strstart = 0;
|
||||
s->block_start = 0L;
|
||||
s->insert = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
flush_pending(strm);
|
||||
if (strm->avail_out == 0) {
|
||||
s->last_flush = -1; /* avoid BUF_ERROR at next call, see above */
|
||||
return Z_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (flush != Z_FINISH) return Z_OK;
|
||||
if (s->wrap <= 0) return Z_STREAM_END;
|
||||
|
||||
/* Write the trailer */
|
||||
#ifdef GZIP
|
||||
if (s->wrap == 2) {
|
||||
put_byte(s, (uint8_t)(strm->adler & 0xff));
|
||||
put_byte(s, (uint8_t)((strm->adler >> 8) & 0xff));
|
||||
put_byte(s, (uint8_t)((strm->adler >> 16) & 0xff));
|
||||
put_byte(s, (uint8_t)((strm->adler >> 24) & 0xff));
|
||||
put_byte(s, (uint8_t)(strm->total_in & 0xff));
|
||||
put_byte(s, (uint8_t)((strm->total_in >> 8) & 0xff));
|
||||
put_byte(s, (uint8_t)((strm->total_in >> 16) & 0xff));
|
||||
put_byte(s, (uint8_t)((strm->total_in >> 24) & 0xff));
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
putShortMSB(s, (uint16_t)(strm->adler >> 16));
|
||||
putShortMSB(s, (uint16_t)(strm->adler & 0xffff));
|
||||
}
|
||||
flush_pending(strm);
|
||||
/* If avail_out is zero, the application will call deflate again
|
||||
* to flush the rest.
|
||||
*/
|
||||
if (s->wrap > 0) s->wrap = -s->wrap; /* write the trailer only once! */
|
||||
return s->pending != 0 ? Z_OK : Z_STREAM_END;
|
||||
}
|
||||
969
std/zlib/inflate.zig
Normal file
969
std/zlib/inflate.zig
Normal file
@ -0,0 +1,969 @@
|
||||
|
||||
error Z_STREAM_ERROR;
|
||||
error Z_STREAM_END;
|
||||
error Z_NEED_DICT;
|
||||
error Z_ERRNO;
|
||||
error Z_STREAM_ERROR;
|
||||
error Z_DATA_ERROR;
|
||||
error Z_MEM_ERROR;
|
||||
error Z_BUF_ERROR;
|
||||
error Z_VERSION_ERROR;
|
||||
|
||||
pub Flush = enum {
|
||||
NO_FLUSH,
|
||||
PARTIAL_FLUSH,
|
||||
SYNC_FLUSH,
|
||||
FULL_FLUSH,
|
||||
FINISH,
|
||||
BLOCK,
|
||||
TREES,
|
||||
};
|
||||
|
||||
const code = struct {
|
||||
/// operation, extra bits, table bits
|
||||
op: u8,
|
||||
/// bits in this part of the code
|
||||
bits: u8,
|
||||
/// offset in table or code value
|
||||
val: u16,
|
||||
};
|
||||
|
||||
/// State maintained between inflate() calls -- approximately 7K bytes, not
|
||||
/// including the allocated sliding window, which is up to 32K bytes.
|
||||
const inflate_state = struct {
|
||||
z_stream * strm; /* pointer back to this zlib stream */
|
||||
inflate_mode mode; /* current inflate mode */
|
||||
int last; /* true if processing last block */
|
||||
int wrap; /* bit 0 true for zlib, bit 1 true for gzip,
|
||||
bit 2 true to validate check value */
|
||||
int havedict; /* true if dictionary provided */
|
||||
int flags; /* gzip header method and flags (0 if zlib) */
|
||||
unsigned dmax; /* zlib header max distance (INFLATE_STRICT) */
|
||||
unsigned long check; /* protected copy of check value */
|
||||
unsigned long total; /* protected copy of output count */
|
||||
gz_headerp head; /* where to save gzip header information */
|
||||
/* sliding window */
|
||||
unsigned wbits; /* log base 2 of requested window size */
|
||||
unsigned wsize; /* window size or zero if not using window */
|
||||
unsigned whave; /* valid bytes in the window */
|
||||
unsigned wnext; /* window write index */
|
||||
u8 FAR *window; /* allocated sliding window, if needed */
|
||||
/* bit accumulator */
|
||||
unsigned long hold; /* input bit accumulator */
|
||||
unsigned bits; /* number of bits in "in" */
|
||||
/* for string and stored block copying */
|
||||
unsigned length; /* literal or length of data to copy */
|
||||
unsigned offset; /* distance back to copy string from */
|
||||
/* for table and code decoding */
|
||||
unsigned extra; /* extra bits needed */
|
||||
/* fixed and dynamic code tables */
|
||||
code const FAR *lencode; /* starting table for length/literal codes */
|
||||
code const FAR *distcode; /* starting table for distance codes */
|
||||
unsigned lenbits; /* index bits for lencode */
|
||||
unsigned distbits; /* index bits for distcode */
|
||||
/* dynamic table building */
|
||||
unsigned ncode; /* number of code length code lengths */
|
||||
unsigned nlen; /* number of length code lengths */
|
||||
unsigned ndist; /* number of distance code lengths */
|
||||
unsigned have; /* number of code lengths in lens[] */
|
||||
code FAR *next; /* next available space in codes[] */
|
||||
unsigned short lens[320]; /* temporary storage for code lengths */
|
||||
unsigned short work[288]; /* work area for code table building */
|
||||
code codes[ENOUGH]; /* space for code tables */
|
||||
int sane; /* if false, allow invalid distance too far */
|
||||
int back; /* bits back of last unprocessed length/lit */
|
||||
unsigned was; /* initial length of match */
|
||||
};
|
||||
|
||||
const alloc_func = fn(opaque: &c_void, items: u16, size: u16);
|
||||
const free_func = fn(opaque: &c_void, address: &c_void);
|
||||
|
||||
const z_stream = struct {
|
||||
/// next input byte
|
||||
next_in: &u8,
|
||||
/// number of bytes available at next_in
|
||||
avail_in: u16,
|
||||
/// total number of input bytes read so far
|
||||
total_in: u32,
|
||||
|
||||
/// next output byte will go here
|
||||
next_out: &u8,
|
||||
/// remaining free space at next_out
|
||||
avail_out: u16,
|
||||
/// total number of bytes output so far */
|
||||
total_out: u32,
|
||||
|
||||
/// last error message, NULL if no error
|
||||
msg: &const u8,
|
||||
/// not visible by applications
|
||||
state: &inflate_state,
|
||||
|
||||
/// used to allocate the internal state
|
||||
zalloc: alloc_func,
|
||||
/// used to free the internal state
|
||||
zfree: free_func,
|
||||
/// private data object passed to zalloc and zfree
|
||||
opaque: &c_void,
|
||||
|
||||
/// best guess about the data type: binary or text
|
||||
/// for deflate, or the decoding state for inflate
|
||||
data_type: i32,
|
||||
|
||||
/// Adler-32 or CRC-32 value of the uncompressed data
|
||||
adler: u32,
|
||||
};
|
||||
|
||||
// Possible inflate modes between inflate() calls
|
||||
/// i: waiting for magic header
|
||||
pub const HEAD = 16180;
|
||||
/// i: waiting for method and flags (gzip)
|
||||
pub const FLAGS = 16181;
|
||||
/// i: waiting for modification time (gzip)
|
||||
pub const TIME = 16182;
|
||||
/// i: waiting for extra flags and operating system (gzip)
|
||||
pub const OS = 16183;
|
||||
/// i: waiting for extra length (gzip)
|
||||
pub const EXLEN = 16184;
|
||||
/// i: waiting for extra bytes (gzip)
|
||||
pub const EXTRA = 16185;
|
||||
/// i: waiting for end of file name (gzip)
|
||||
pub const NAME = 16186;
|
||||
/// i: waiting for end of comment (gzip)
|
||||
pub const COMMENT = 16187;
|
||||
/// i: waiting for header crc (gzip)
|
||||
pub const HCRC = 16188;
|
||||
/// i: waiting for dictionary check value
|
||||
pub const DICTID = 16189;
|
||||
/// waiting for inflateSetDictionary() call
|
||||
pub const DICT = 16190;
|
||||
/// i: waiting for type bits, including last-flag bit
|
||||
pub const TYPE = 16191;
|
||||
/// i: same, but skip check to exit inflate on new block
|
||||
pub const TYPEDO = 16192;
|
||||
/// i: waiting for stored size (length and complement)
|
||||
pub const STORED = 16193;
|
||||
/// i/o: same as COPY below, but only first time in
|
||||
pub const COPY_ = 16194;
|
||||
/// i/o: waiting for input or output to copy stored block
|
||||
pub const COPY = 16195;
|
||||
/// i: waiting for dynamic block table lengths
|
||||
pub const TABLE = 16196;
|
||||
/// i: waiting for code length code lengths
|
||||
pub const LENLENS = 16197;
|
||||
/// i: waiting for length/lit and distance code lengths
|
||||
pub const CODELENS = 16198;
|
||||
/// i: same as LEN below, but only first time in
|
||||
pub const LEN_ = 16199;
|
||||
/// i: waiting for length/lit/eob code
|
||||
pub const LEN = 16200;
|
||||
/// i: waiting for length extra bits
|
||||
pub const LENEXT = 16201;
|
||||
/// i: waiting for distance code
|
||||
pub const DIST = 16202;
|
||||
/// i: waiting for distance extra bits
|
||||
pub const DISTEXT = 16203;
|
||||
/// o: waiting for output space to copy string
|
||||
pub const MATCH = 16204;
|
||||
/// o: waiting for output space to write literal
|
||||
pub const LIT = 16205;
|
||||
/// i: waiting for 32-bit check value
|
||||
pub const CHECK = 16206;
|
||||
/// i: waiting for 32-bit length (gzip)
|
||||
pub const LENGTH = 16207;
|
||||
/// finished check, done -- remain here until reset
|
||||
pub const DONE = 16208;
|
||||
/// got a data error -- remain here until reset
|
||||
pub const BAD = 16209;
|
||||
/// got an inflate() memory error -- remain here until reset
|
||||
pub const MEM = 16210;
|
||||
/// looking for synchronization bytes to restart inflate() */
|
||||
pub const SYNC = 16211;
|
||||
|
||||
/// inflate() uses a state machine to process as much input data and generate as
|
||||
/// much output data as possible before returning. The state machine is
|
||||
/// structured roughly as follows:
|
||||
///
|
||||
/// for (;;) switch (state) {
|
||||
/// ...
|
||||
/// case STATEn:
|
||||
/// if (not enough input data or output space to make progress)
|
||||
/// return;
|
||||
/// ... make progress ...
|
||||
/// state = STATEm;
|
||||
/// break;
|
||||
/// ...
|
||||
/// }
|
||||
///
|
||||
/// so when inflate() is called again, the same case is attempted again, and
|
||||
/// if the appropriate resources are provided, the machine proceeds to the
|
||||
/// next state. The NEEDBITS() macro is usually the way the state evaluates
|
||||
/// whether it can proceed or should return. NEEDBITS() does the return if
|
||||
/// the requested bits are not available. The typical use of the BITS macros
|
||||
/// is:
|
||||
///
|
||||
/// NEEDBITS(n);
|
||||
/// ... do something with BITS(n) ...
|
||||
/// DROPBITS(n);
|
||||
///
|
||||
/// where NEEDBITS(n) either returns from inflate() if there isn't enough
|
||||
/// input left to load n bits into the accumulator, or it continues. BITS(n)
|
||||
/// gives the low n bits in the accumulator. When done, DROPBITS(n) drops
|
||||
/// the low n bits off the accumulator. INITBITS() clears the accumulator
|
||||
/// and sets the number of available bits to zero. BYTEBITS() discards just
|
||||
/// enough bits to put the accumulator on a byte boundary. After BYTEBITS()
|
||||
/// and a NEEDBITS(8), then BITS(8) would return the next byte in the stream.
|
||||
///
|
||||
/// NEEDBITS(n) uses PULLBYTE() to get an available byte of input, or to return
|
||||
/// if there is no input available. The decoding of variable length codes uses
|
||||
/// PULLBYTE() directly in order to pull just enough bytes to decode the next
|
||||
/// code, and no more.
|
||||
///
|
||||
/// Some states loop until they get enough input, making sure that enough
|
||||
/// state information is maintained to continue the loop where it left off
|
||||
/// if NEEDBITS() returns in the loop. For example, want, need, and keep
|
||||
/// would all have to actually be part of the saved state in case NEEDBITS()
|
||||
/// returns:
|
||||
///
|
||||
/// case STATEw:
|
||||
/// while (want < need) {
|
||||
/// NEEDBITS(n);
|
||||
/// keep[want++] = BITS(n);
|
||||
/// DROPBITS(n);
|
||||
/// }
|
||||
/// state = STATEx;
|
||||
/// case STATEx:
|
||||
///
|
||||
/// As shown above, if the next state is also the next case, then the break
|
||||
/// is omitted.
|
||||
///
|
||||
/// A state may also return if there is not enough output space available to
|
||||
/// complete that state. Those states are copying stored data, writing a
|
||||
/// literal byte, and copying a matching string.
|
||||
///
|
||||
/// When returning, a "goto inf_leave" is used to update the total counters,
|
||||
/// update the check value, and determine whether any progress has been made
|
||||
/// during that inflate() call in order to return the proper return code.
|
||||
/// Progress is defined as a change in either strm->avail_in or strm->avail_out.
|
||||
/// When there is a window, goto inf_leave will update the window with the last
|
||||
/// output written. If a goto inf_leave occurs in the middle of decompression
|
||||
/// and there is no window currently, goto inf_leave will create one and copy
|
||||
/// output to the window for the next call of inflate().
|
||||
///
|
||||
/// In this implementation, the flush parameter of inflate() only affects the
|
||||
/// return code (per zlib.h). inflate() always writes as much as possible to
|
||||
/// strm->next_out, given the space available and the provided input--the effect
|
||||
/// documented in zlib.h of Z_SYNC_FLUSH. Furthermore, inflate() always defers
|
||||
/// the allocation of and copying into a sliding window until necessary, which
|
||||
/// provides the effect documented in zlib.h for Z_FINISH when the entire input
|
||||
/// stream available. So the only thing the flush parameter actually does is:
|
||||
/// when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
|
||||
/// will return Z_BUF_ERROR if it has not reached the end of the stream.
|
||||
pub fn inflate(strm: &z_stream, flush: Flush, gunzip: bool) -> %void {
|
||||
// next input
|
||||
var next: &const u8 = undefined;
|
||||
// next output
|
||||
var put: &u8 = undefined;
|
||||
|
||||
// available input and output
|
||||
var have: u16 = undefined;
|
||||
var left: u16 = undefined;
|
||||
|
||||
// bit buffer
|
||||
var hold: u32 = undefined;
|
||||
// bits in bit buffer
|
||||
var bits: u16 = undefined;
|
||||
// save starting available input and output
|
||||
var in: u16 = undefined;
|
||||
var out: u16 = undefined;
|
||||
// number of stored or match bytes to copy
|
||||
var copy: u16 = undefined;
|
||||
// where to copy match bytes from
|
||||
var from: &u8 = undefined;
|
||||
// current decoding table entry
|
||||
var here: code = undefined;
|
||||
// parent table entry
|
||||
var last: code = undefined;
|
||||
// length to copy for repeats, bits to drop
|
||||
var len: u16 = undefined;
|
||||
|
||||
// return code
|
||||
var ret: error = undefined;
|
||||
|
||||
// buffer for gzip header crc calculation
|
||||
var hbuf: [4]u8 = undefined;
|
||||
|
||||
// permutation of code lengths
|
||||
const short_order = []u16 = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
|
||||
|
||||
if (inflateStateCheck(strm) or strm.next_out == Z_NULL or (strm.next_in == Z_NULL and strm.avail_in != 0)) {
|
||||
return error.Z_STREAM_ERROR;
|
||||
}
|
||||
|
||||
var state: &inflate_state = strm.state;
|
||||
if (state.mode == TYPE) {
|
||||
state.mode = TYPEDO; // skip check
|
||||
}
|
||||
put = strm.next_out; \
|
||||
left = strm.avail_out; \
|
||||
next = strm.next_in; \
|
||||
have = strm.avail_in; \
|
||||
hold = state.hold; \
|
||||
bits = state.bits; \
|
||||
in = have;
|
||||
out = left;
|
||||
ret = Z_OK;
|
||||
for (;;)
|
||||
switch (state.mode) {
|
||||
case HEAD:
|
||||
if (state.wrap == 0) {
|
||||
state.mode = TYPEDO;
|
||||
break;
|
||||
}
|
||||
NEEDBITS(16);
|
||||
#ifdef GUNZIP
|
||||
if ((state.wrap & 2) && hold == 0x8b1f) { /* gzip header */
|
||||
if (state.wbits == 0)
|
||||
state.wbits = 15;
|
||||
state.check = crc32(0L, Z_NULL, 0);
|
||||
CRC2(state.check, hold);
|
||||
INITBITS();
|
||||
state.mode = FLAGS;
|
||||
break;
|
||||
}
|
||||
state.flags = 0; /* expect zlib header */
|
||||
if (state.head != Z_NULL)
|
||||
state.head.done = -1;
|
||||
if (!(state.wrap & 1) || /* check if zlib header allowed */
|
||||
#else
|
||||
if (
|
||||
#endif
|
||||
((BITS(8) << 8) + (hold >> 8)) % 31) {
|
||||
strm.msg = (char *)"incorrect header check";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
if (BITS(4) != Z_DEFLATED) {
|
||||
strm.msg = (char *)"unknown compression method";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
DROPBITS(4);
|
||||
len = BITS(4) + 8;
|
||||
if (state.wbits == 0)
|
||||
state.wbits = len;
|
||||
if (len > 15 || len > state.wbits) {
|
||||
strm.msg = (char *)"invalid window size";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
state.dmax = 1U << len;
|
||||
Tracev((stderr, "inflate: zlib header ok\n"));
|
||||
strm.adler = state.check = adler32(0L, Z_NULL, 0);
|
||||
state.mode = hold & 0x200 ? DICTID : TYPE;
|
||||
INITBITS();
|
||||
break;
|
||||
#ifdef GUNZIP
|
||||
case FLAGS:
|
||||
NEEDBITS(16);
|
||||
state.flags = (int)(hold);
|
||||
if ((state.flags & 0xff) != Z_DEFLATED) {
|
||||
strm.msg = (char *)"unknown compression method";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
if (state.flags & 0xe000) {
|
||||
strm.msg = (char *)"unknown header flags set";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
if (state.head != Z_NULL)
|
||||
state.head.text = (int)((hold >> 8) & 1);
|
||||
if ((state.flags & 0x0200) && (state.wrap & 4))
|
||||
CRC2(state.check, hold);
|
||||
INITBITS();
|
||||
state.mode = TIME;
|
||||
case TIME:
|
||||
NEEDBITS(32);
|
||||
if (state.head != Z_NULL)
|
||||
state.head.time = hold;
|
||||
if ((state.flags & 0x0200) && (state.wrap & 4))
|
||||
CRC4(state.check, hold);
|
||||
INITBITS();
|
||||
state.mode = OS;
|
||||
case OS:
|
||||
NEEDBITS(16);
|
||||
if (state.head != Z_NULL) {
|
||||
state.head.xflags = (int)(hold & 0xff);
|
||||
state.head.os = (int)(hold >> 8);
|
||||
}
|
||||
if ((state.flags & 0x0200) && (state.wrap & 4))
|
||||
CRC2(state.check, hold);
|
||||
INITBITS();
|
||||
state.mode = EXLEN;
|
||||
case EXLEN:
|
||||
if (state.flags & 0x0400) {
|
||||
NEEDBITS(16);
|
||||
state.length = (unsigned)(hold);
|
||||
if (state.head != Z_NULL)
|
||||
state.head.extra_len = (unsigned)hold;
|
||||
if ((state.flags & 0x0200) && (state.wrap & 4))
|
||||
CRC2(state.check, hold);
|
||||
INITBITS();
|
||||
}
|
||||
else if (state.head != Z_NULL)
|
||||
state.head.extra = Z_NULL;
|
||||
state.mode = EXTRA;
|
||||
case EXTRA:
|
||||
if (state.flags & 0x0400) {
|
||||
copy = state.length;
|
||||
if (copy > have) copy = have;
|
||||
if (copy) {
|
||||
if (state.head != Z_NULL &&
|
||||
state.head.extra != Z_NULL) {
|
||||
len = state.head.extra_len - state.length;
|
||||
zmemcpy(state.head.extra + len, next,
|
||||
len + copy > state.head.extra_max ?
|
||||
state.head.extra_max - len : copy);
|
||||
}
|
||||
if ((state.flags & 0x0200) && (state.wrap & 4))
|
||||
state.check = crc32(state.check, next, copy);
|
||||
have -= copy;
|
||||
next += copy;
|
||||
state.length -= copy;
|
||||
}
|
||||
if (state.length) goto inf_leave;
|
||||
}
|
||||
state.length = 0;
|
||||
state.mode = NAME;
|
||||
case NAME:
|
||||
if (state.flags & 0x0800) {
|
||||
if (have == 0) goto inf_leave;
|
||||
copy = 0;
|
||||
do {
|
||||
len = (unsigned)(next[copy++]);
|
||||
if (state.head != Z_NULL &&
|
||||
state.head.name != Z_NULL &&
|
||||
state.length < state.head.name_max)
|
||||
state.head.name[state.length++] = (Bytef)len;
|
||||
} while (len && copy < have);
|
||||
if ((state.flags & 0x0200) && (state.wrap & 4))
|
||||
state.check = crc32(state.check, next, copy);
|
||||
have -= copy;
|
||||
next += copy;
|
||||
if (len) goto inf_leave;
|
||||
}
|
||||
else if (state.head != Z_NULL)
|
||||
state.head.name = Z_NULL;
|
||||
state.length = 0;
|
||||
state.mode = COMMENT;
|
||||
case COMMENT:
|
||||
if (state.flags & 0x1000) {
|
||||
if (have == 0) goto inf_leave;
|
||||
copy = 0;
|
||||
do {
|
||||
len = (unsigned)(next[copy++]);
|
||||
if (state.head != Z_NULL &&
|
||||
state.head.comment != Z_NULL &&
|
||||
state.length < state.head.comm_max)
|
||||
state.head.comment[state.length++] = (Bytef)len;
|
||||
} while (len && copy < have);
|
||||
if ((state.flags & 0x0200) && (state.wrap & 4))
|
||||
state.check = crc32(state.check, next, copy);
|
||||
have -= copy;
|
||||
next += copy;
|
||||
if (len) goto inf_leave;
|
||||
}
|
||||
else if (state.head != Z_NULL)
|
||||
state.head.comment = Z_NULL;
|
||||
state.mode = HCRC;
|
||||
case HCRC:
|
||||
if (state.flags & 0x0200) {
|
||||
NEEDBITS(16);
|
||||
if ((state.wrap & 4) && hold != (state.check & 0xffff)) {
|
||||
strm.msg = (char *)"header crc mismatch";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
INITBITS();
|
||||
}
|
||||
if (state.head != Z_NULL) {
|
||||
state.head.hcrc = (int)((state.flags >> 9) & 1);
|
||||
state.head.done = 1;
|
||||
}
|
||||
strm.adler = state.check = crc32(0L, Z_NULL, 0);
|
||||
state.mode = TYPE;
|
||||
break;
|
||||
#endif
|
||||
case DICTID:
|
||||
NEEDBITS(32);
|
||||
strm.adler = state.check = ZSWAP32(hold);
|
||||
INITBITS();
|
||||
state.mode = DICT;
|
||||
case DICT:
|
||||
if (state.havedict == 0) {
|
||||
strm.next_out = put; \
|
||||
strm.avail_out = left; \
|
||||
strm.next_in = next; \
|
||||
strm.avail_in = have; \
|
||||
state.hold = hold; \
|
||||
state.bits = bits; \
|
||||
return Z_NEED_DICT;
|
||||
}
|
||||
strm.adler = state.check = adler32(0L, Z_NULL, 0);
|
||||
state.mode = TYPE;
|
||||
case TYPE:
|
||||
if (flush == Z_BLOCK || flush == Z_TREES) goto inf_leave;
|
||||
case TYPEDO:
|
||||
if (state.last) {
|
||||
BYTEBITS();
|
||||
state.mode = CHECK;
|
||||
break;
|
||||
}
|
||||
NEEDBITS(3);
|
||||
state.last = BITS(1);
|
||||
DROPBITS(1);
|
||||
switch (BITS(2)) {
|
||||
case 0: /* stored block */
|
||||
Tracev((stderr, "inflate: stored block%s\n",
|
||||
state.last ? " (last)" : ""));
|
||||
state.mode = STORED;
|
||||
break;
|
||||
case 1: /* fixed block */
|
||||
fixedtables(state);
|
||||
Tracev((stderr, "inflate: fixed codes block%s\n",
|
||||
state.last ? " (last)" : ""));
|
||||
state.mode = LEN_; /* decode codes */
|
||||
if (flush == Z_TREES) {
|
||||
DROPBITS(2);
|
||||
goto inf_leave;
|
||||
}
|
||||
break;
|
||||
case 2: /* dynamic block */
|
||||
Tracev((stderr, "inflate: dynamic codes block%s\n",
|
||||
state.last ? " (last)" : ""));
|
||||
state.mode = TABLE;
|
||||
break;
|
||||
case 3:
|
||||
strm.msg = (char *)"invalid block type";
|
||||
state.mode = BAD;
|
||||
}
|
||||
DROPBITS(2);
|
||||
break;
|
||||
case STORED:
|
||||
BYTEBITS(); /* go to byte boundary */
|
||||
NEEDBITS(32);
|
||||
if ((hold & 0xffff) != ((hold >> 16) ^ 0xffff)) {
|
||||
strm.msg = (char *)"invalid stored block lengths";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
state.length = (unsigned)hold & 0xffff;
|
||||
Tracev((stderr, "inflate: stored length %u\n",
|
||||
state.length));
|
||||
INITBITS();
|
||||
state.mode = COPY_;
|
||||
if (flush == Z_TREES) goto inf_leave;
|
||||
case COPY_:
|
||||
state.mode = COPY;
|
||||
case COPY:
|
||||
copy = state.length;
|
||||
if (copy) {
|
||||
if (copy > have) copy = have;
|
||||
if (copy > left) copy = left;
|
||||
if (copy == 0) goto inf_leave;
|
||||
zmemcpy(put, next, copy);
|
||||
have -= copy;
|
||||
next += copy;
|
||||
left -= copy;
|
||||
put += copy;
|
||||
state.length -= copy;
|
||||
break;
|
||||
}
|
||||
Tracev((stderr, "inflate: stored end\n"));
|
||||
state.mode = TYPE;
|
||||
break;
|
||||
case TABLE:
|
||||
NEEDBITS(14);
|
||||
state.nlen = BITS(5) + 257;
|
||||
DROPBITS(5);
|
||||
state.ndist = BITS(5) + 1;
|
||||
DROPBITS(5);
|
||||
state.ncode = BITS(4) + 4;
|
||||
DROPBITS(4);
|
||||
#ifndef PKZIP_BUG_WORKAROUND
|
||||
if (state.nlen > 286 || state.ndist > 30) {
|
||||
strm.msg = (char *)"too many length or distance symbols";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
Tracev((stderr, "inflate: table sizes ok\n"));
|
||||
state.have = 0;
|
||||
state.mode = LENLENS;
|
||||
case LENLENS:
|
||||
while (state.have < state.ncode) {
|
||||
NEEDBITS(3);
|
||||
state.lens[order[state.have++]] = (unsigned short)BITS(3);
|
||||
DROPBITS(3);
|
||||
}
|
||||
while (state.have < 19)
|
||||
state.lens[order[state.have++]] = 0;
|
||||
state.next = state.codes;
|
||||
state.lencode = (const code FAR *)(state.next);
|
||||
state.lenbits = 7;
|
||||
ret = inflate_table(CODES, state.lens, 19, &(state.next),
|
||||
&(state.lenbits), state.work);
|
||||
if (ret) {
|
||||
strm.msg = (char *)"invalid code lengths set";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
Tracev((stderr, "inflate: code lengths ok\n"));
|
||||
state.have = 0;
|
||||
state.mode = CODELENS;
|
||||
case CODELENS:
|
||||
while (state.have < state.nlen + state.ndist) {
|
||||
for (;;) {
|
||||
here = state.lencode[BITS(state.lenbits)];
|
||||
if ((unsigned)(here.bits) <= bits) break;
|
||||
PULLBYTE();
|
||||
}
|
||||
if (here.val < 16) {
|
||||
DROPBITS(here.bits);
|
||||
state.lens[state.have++] = here.val;
|
||||
}
|
||||
else {
|
||||
if (here.val == 16) {
|
||||
NEEDBITS(here.bits + 2);
|
||||
DROPBITS(here.bits);
|
||||
if (state.have == 0) {
|
||||
strm.msg = (char *)"invalid bit length repeat";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
len = state.lens[state.have - 1];
|
||||
copy = 3 + BITS(2);
|
||||
DROPBITS(2);
|
||||
}
|
||||
else if (here.val == 17) {
|
||||
NEEDBITS(here.bits + 3);
|
||||
DROPBITS(here.bits);
|
||||
len = 0;
|
||||
copy = 3 + BITS(3);
|
||||
DROPBITS(3);
|
||||
}
|
||||
else {
|
||||
NEEDBITS(here.bits + 7);
|
||||
DROPBITS(here.bits);
|
||||
len = 0;
|
||||
copy = 11 + BITS(7);
|
||||
DROPBITS(7);
|
||||
}
|
||||
if (state.have + copy > state.nlen + state.ndist) {
|
||||
strm.msg = (char *)"invalid bit length repeat";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
while (copy--)
|
||||
state.lens[state.have++] = (unsigned short)len;
|
||||
}
|
||||
}
|
||||
|
||||
/* handle error breaks in while */
|
||||
if (state.mode == BAD) break;
|
||||
|
||||
/* check for end-of-block code (better have one) */
|
||||
if (state.lens[256] == 0) {
|
||||
strm.msg = (char *)"invalid code -- missing end-of-block";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
|
||||
/* build code tables -- note: do not change the lenbits or distbits
|
||||
values here (9 and 6) without reading the comments in inftrees.h
|
||||
concerning the ENOUGH constants, which depend on those values */
|
||||
state.next = state.codes;
|
||||
state.lencode = (const code FAR *)(state.next);
|
||||
state.lenbits = 9;
|
||||
ret = inflate_table(LENS, state.lens, state.nlen, &(state.next),
|
||||
&(state.lenbits), state.work);
|
||||
if (ret) {
|
||||
strm.msg = (char *)"invalid literal/lengths set";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
state.distcode = (const code FAR *)(state.next);
|
||||
state.distbits = 6;
|
||||
ret = inflate_table(DISTS, state.lens + state.nlen, state.ndist,
|
||||
&(state.next), &(state.distbits), state.work);
|
||||
if (ret) {
|
||||
strm.msg = (char *)"invalid distances set";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
Tracev((stderr, "inflate: codes ok\n"));
|
||||
state.mode = LEN_;
|
||||
if (flush == Z_TREES) goto inf_leave;
|
||||
case LEN_:
|
||||
state.mode = LEN;
|
||||
case LEN:
|
||||
if (have >= 6 && left >= 258) {
|
||||
strm.next_out = put; \
|
||||
strm.avail_out = left; \
|
||||
strm.next_in = next; \
|
||||
strm.avail_in = have; \
|
||||
state.hold = hold; \
|
||||
state.bits = bits; \
|
||||
|
||||
inflate_fast(strm, out);
|
||||
|
||||
put = strm.next_out; \
|
||||
left = strm.avail_out; \
|
||||
next = strm.next_in; \
|
||||
have = strm.avail_in; \
|
||||
hold = state.hold; \
|
||||
bits = state.bits; \
|
||||
if (state.mode == TYPE)
|
||||
state.back = -1;
|
||||
break;
|
||||
}
|
||||
state.back = 0;
|
||||
for (;;) {
|
||||
here = state.lencode[BITS(state.lenbits)];
|
||||
if ((unsigned)(here.bits) <= bits) break;
|
||||
PULLBYTE();
|
||||
}
|
||||
if (here.op && (here.op & 0xf0) == 0) {
|
||||
last = here;
|
||||
for (;;) {
|
||||
here = state.lencode[last.val +
|
||||
(BITS(last.bits + last.op) >> last.bits)];
|
||||
if ((unsigned)(last.bits + here.bits) <= bits) break;
|
||||
PULLBYTE();
|
||||
}
|
||||
DROPBITS(last.bits);
|
||||
state.back += last.bits;
|
||||
}
|
||||
DROPBITS(here.bits);
|
||||
state.back += here.bits;
|
||||
state.length = (unsigned)here.val;
|
||||
if ((int)(here.op) == 0) {
|
||||
Tracevv((stderr, here.val >= 0x20 && here.val < 0x7f ?
|
||||
"inflate: literal '%c'\n" :
|
||||
"inflate: literal 0x%02x\n", here.val));
|
||||
state.mode = LIT;
|
||||
break;
|
||||
}
|
||||
if (here.op & 32) {
|
||||
Tracevv((stderr, "inflate: end of block\n"));
|
||||
state.back = -1;
|
||||
state.mode = TYPE;
|
||||
break;
|
||||
}
|
||||
if (here.op & 64) {
|
||||
strm.msg = (char *)"invalid literal/length code";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
state.extra = (unsigned)(here.op) & 15;
|
||||
state.mode = LENEXT;
|
||||
case LENEXT:
|
||||
if (state.extra) {
|
||||
NEEDBITS(state.extra);
|
||||
state.length += BITS(state.extra);
|
||||
DROPBITS(state.extra);
|
||||
state.back += state.extra;
|
||||
}
|
||||
Tracevv((stderr, "inflate: length %u\n", state.length));
|
||||
state.was = state.length;
|
||||
state.mode = DIST;
|
||||
case DIST:
|
||||
for (;;) {
|
||||
here = state.distcode[BITS(state.distbits)];
|
||||
if ((unsigned)(here.bits) <= bits) break;
|
||||
PULLBYTE();
|
||||
}
|
||||
if ((here.op & 0xf0) == 0) {
|
||||
last = here;
|
||||
for (;;) {
|
||||
here = state.distcode[last.val +
|
||||
(BITS(last.bits + last.op) >> last.bits)];
|
||||
if ((unsigned)(last.bits + here.bits) <= bits) break;
|
||||
PULLBYTE();
|
||||
}
|
||||
DROPBITS(last.bits);
|
||||
state.back += last.bits;
|
||||
}
|
||||
DROPBITS(here.bits);
|
||||
state.back += here.bits;
|
||||
if (here.op & 64) {
|
||||
strm.msg = (char *)"invalid distance code";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
state.offset = (unsigned)here.val;
|
||||
state.extra = (unsigned)(here.op) & 15;
|
||||
state.mode = DISTEXT;
|
||||
case DISTEXT:
|
||||
if (state.extra) {
|
||||
NEEDBITS(state.extra);
|
||||
state.offset += BITS(state.extra);
|
||||
DROPBITS(state.extra);
|
||||
state.back += state.extra;
|
||||
}
|
||||
#ifdef INFLATE_STRICT
|
||||
if (state.offset > state.dmax) {
|
||||
strm.msg = (char *)"invalid distance too far back";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
Tracevv((stderr, "inflate: distance %u\n", state.offset));
|
||||
state.mode = MATCH;
|
||||
case MATCH:
|
||||
if (left == 0) goto inf_leave;
|
||||
copy = out - left;
|
||||
if (state.offset > copy) { /* copy from window */
|
||||
copy = state.offset - copy;
|
||||
if (copy > state.whave) {
|
||||
if (state.sane) {
|
||||
strm.msg = (char *)"invalid distance too far back";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
#ifdef INFLATE_ALLOW_INVALID_DISTANCE_TOOFAR_ARRR
|
||||
Trace((stderr, "inflate.c too far\n"));
|
||||
copy -= state.whave;
|
||||
if (copy > state.length) copy = state.length;
|
||||
if (copy > left) copy = left;
|
||||
left -= copy;
|
||||
state.length -= copy;
|
||||
do {
|
||||
*put++ = 0;
|
||||
} while (--copy);
|
||||
if (state.length == 0) state.mode = LEN;
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (copy > state.wnext) {
|
||||
copy -= state.wnext;
|
||||
from = state.window + (state.wsize - copy);
|
||||
}
|
||||
else
|
||||
from = state.window + (state.wnext - copy);
|
||||
if (copy > state.length) copy = state.length;
|
||||
}
|
||||
else { /* copy from output */
|
||||
from = put - state.offset;
|
||||
copy = state.length;
|
||||
}
|
||||
if (copy > left) copy = left;
|
||||
left -= copy;
|
||||
state.length -= copy;
|
||||
do {
|
||||
*put++ = *from++;
|
||||
} while (--copy);
|
||||
if (state.length == 0) state.mode = LEN;
|
||||
break;
|
||||
case LIT:
|
||||
if (left == 0) goto inf_leave;
|
||||
*put++ = (u8)(state.length);
|
||||
left--;
|
||||
state.mode = LEN;
|
||||
break;
|
||||
case CHECK:
|
||||
if (state.wrap) {
|
||||
NEEDBITS(32);
|
||||
out -= left;
|
||||
strm.total_out += out;
|
||||
state.total += out;
|
||||
if ((state.wrap & 4) && out)
|
||||
strm.adler = state.check =
|
||||
UPDATE(state.check, put - out, out);
|
||||
out = left;
|
||||
if ((state.wrap & 4) && (
|
||||
#ifdef GUNZIP
|
||||
state.flags ? hold :
|
||||
#endif
|
||||
ZSWAP32(hold)) != state.check) {
|
||||
strm.msg = (char *)"incorrect data check";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
INITBITS();
|
||||
Tracev((stderr, "inflate: check matches trailer\n"));
|
||||
}
|
||||
#ifdef GUNZIP
|
||||
state.mode = LENGTH;
|
||||
case LENGTH:
|
||||
if (state.wrap && state.flags) {
|
||||
NEEDBITS(32);
|
||||
if (hold != (state.total & 0xffffffffUL)) {
|
||||
strm.msg = (char *)"incorrect length check";
|
||||
state.mode = BAD;
|
||||
break;
|
||||
}
|
||||
INITBITS();
|
||||
Tracev((stderr, "inflate: length matches trailer\n"));
|
||||
}
|
||||
#endif
|
||||
state.mode = DONE;
|
||||
case DONE:
|
||||
ret = Z_STREAM_END;
|
||||
goto inf_leave;
|
||||
case BAD:
|
||||
ret = Z_DATA_ERROR;
|
||||
goto inf_leave;
|
||||
case MEM:
|
||||
return Z_MEM_ERROR;
|
||||
case SYNC:
|
||||
default:
|
||||
return Z_STREAM_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
Return from inflate(), updating the total counts and the check value.
|
||||
If there was no progress during the inflate() call, return a buffer
|
||||
error. Call updatewindow() to create and/or update the window state.
|
||||
Note: a memory error from inflate() is non-recoverable.
|
||||
*/
|
||||
inf_leave:
|
||||
strm.next_out = put; \
|
||||
strm.avail_out = left; \
|
||||
strm.next_in = next; \
|
||||
strm.avail_in = have; \
|
||||
state.hold = hold; \
|
||||
state.bits = bits; \
|
||||
if (state.wsize || (out != strm.avail_out && state.mode < BAD &&
|
||||
(state.mode < CHECK || flush != Z_FINISH)))
|
||||
if (updatewindow(strm, strm.next_out, out - strm.avail_out)) {
|
||||
state.mode = MEM;
|
||||
return Z_MEM_ERROR;
|
||||
}
|
||||
in -= strm.avail_in;
|
||||
out -= strm.avail_out;
|
||||
strm.total_in += in;
|
||||
strm.total_out += out;
|
||||
state.total += out;
|
||||
if ((state.wrap & 4) && out)
|
||||
strm.adler = state.check =
|
||||
UPDATE(state.check, strm.next_out - out, out);
|
||||
strm.data_type = (int)state.bits + (state.last ? 64 : 0) +
|
||||
(state.mode == TYPE ? 128 : 0) +
|
||||
(state.mode == LEN_ || state.mode == COPY_ ? 256 : 0);
|
||||
if (((in == 0 && out == 0) || flush == Z_FINISH) && ret == Z_OK)
|
||||
ret = Z_BUF_ERROR;
|
||||
return ret;
|
||||
}
|
||||
|
||||
local int inflateStateCheck(z_stream * strm) {
|
||||
struct inflate_state FAR *state;
|
||||
if (strm == Z_NULL ||
|
||||
strm.zalloc == (alloc_func)0 || strm.zfree == (free_func)0)
|
||||
return 1;
|
||||
state = (struct inflate_state FAR *)strm.state;
|
||||
if (state == Z_NULL || state.strm != strm ||
|
||||
state.mode < HEAD || state.mode > SYNC)
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user