diff options
| -rw-r--r-- | src/all_types.hpp | 2 | ||||
| -rw-r--r-- | src/analyze.cpp | 3 | ||||
| -rw-r--r-- | src/parseh.cpp | 510 | ||||
| -rw-r--r-- | src/parser.cpp | 6 | ||||
| -rw-r--r-- | src/parser.hpp | 3 | ||||
| -rw-r--r-- | std/zlib/deflate.zig | 522 | ||||
| -rw-r--r-- | std/zlib/inflate.zig | 969 |
7 files changed, 1987 insertions, 28 deletions
diff --git a/src/all_types.hpp b/src/all_types.hpp index 39e6033988..e785e61c1b 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -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; diff --git a/src/analyze.cpp b/src/analyze.cpp index 041d4eea70..b3e9601102 100644 --- a/src/analyze.cpp +++ b/src/analyze.cpp @@ -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); diff --git a/src/parseh.cpp b/src/parseh.cpp index 9acbc7c57c..0d8bfd9dfe 100644 --- a/src/parseh.cpp +++ b/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(); - } else { - path = buf_create_from_mem((const char *)filename.bytes_begin(), filename.size()); - } + 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); + ErrorMsg *err_msg = err_msg_create_with_offset(path, line, column, offset, source, msg); - c->errors->append(err_msg); + c->errors->append(err_msg); + } else { + // 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)); + } } return 0; } + c->ctx = &ast_unit->getASTContext(); c->source_manager = &ast_unit->getSourceManager(); ast_unit->visitLocalTopLevelDecls(c, decl_visitor); diff --git a/src/parser.cpp b/src/parser.cpp index 7961953aff..75d4dd309c 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -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; diff --git a/src/parser.hpp b/src/parser.hpp index 2fe30ec4b4..c95413309f 100644 --- a/src/parser.hpp +++ b/src/parser.hpp @@ -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); diff --git a/std/zlib/deflate.zig b/std/zlib/deflate.zig new file mode 100644 index 0000000000..7374d33cf1 --- /dev/null +++ b/std/zlib/deflate.zig @@ -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; +} diff --git a/std/zlib/inflate.zig b/std/zlib/inflate.zig new file mode 100644 index 0000000000..1bb3f858ac --- /dev/null +++ b/std/zlib/inflate.zig @@ -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; +} |
