<commit_before>// Copyright © 2015 <NAME> <<EMAIL>>. All rights reserved.
// Use of this source code is governed by the license that can be
// found in the LICENSE file.

package yara

/*
#ifdef _WIN32
#define fdopen _fdopen
#endif
#include <stdio.h>

#include <yara.h>

// This signature should be generated by cgo from the exported
// function below
void compilerCallback(int, char*, int, char*, void*);
*/
import "C"
import (
	"errors"
	"os"
	"runtime"
	"unsafe"
)

//export compilerCallback
func compilerCallback(errorLevel C.int, filename *C.char, linenumber C.int, message *C.char, ptr unsafe.Pointer) {
	if ptr == nil {
		return
	}
	compiler := (*Compiler)(ptr)
	msg := CompilerMessage{
		Filename: C.GoString(filename),
		Line:     int(linenumber),
		Text:     C.GoString(message),
	}
	switch errorLevel {
	case C.YARA_ERROR_LEVEL_ERROR:
		compiler.Errors = append(compiler.Errors, msg)
	case C.YARA_ERROR_LEVEL_WARNING:
		compiler.Warnings = append(compiler.Warnings, msg)
	}
}

// A Compiler encapsulates the YARA compiler that transforms rules
// into YARA's internal, binary form which in turn is used for
// scanning files or memory blocks.
type Compiler struct {
	*compiler
	Errors   []CompilerMessage
	Warnings []CompilerMessage
}

type compiler struct {
	cptr *C.YR_COMPILER
}

// A CompilerMessage contains an error or warning message produced
// while compiling sets of rules using AddString or AddFile.
type CompilerMessage struct {
	Filename string
	Line     int
	Text     string
}

// NewCompiler creates a YARA compiler.
func NewCompiler() (*Compiler, error) {
	var yrCompiler *C.YR_COMPILER
	if err := newError(C.yr_compiler_create(&yrCompiler)); err != nil {
		return nil, err
	}
	c := &Compiler{compiler: &compiler{cptr: yrCompiler}}
	C.yr_compiler_set_callback(yrCompiler, C.YR_COMPILER_CALLBACK_FUNC(C.compilerCallback), unsafe.Pointer(c))
	runtime.SetFinalizer(c.compiler, (*compiler).finalize)
	return c, nil
}

func (c *compiler) finalize() {
	C.yr_compiler_destroy(c.cptr)
	runtime.SetFinalizer(c, nil)
}

// Destroy destroys the YARA data structure representing a compiler.
// Since a Finalizer for the underlying YR_COMPILER structure is
// automatically set up on creation, it should not be necessary to
// explicitly call this method.
func (c *Compiler) Destroy() {
	if c.compiler != nil {
		c.compiler.finalize()
		c.compiler = nil
	}
}

// AddFile compiles rules from an os.File. Rules are added to the
// specified namespace.
func (c *Compiler) AddFile(file os.File, namespace string) (err error) {
	fh, err := C.fdopen(C.int(file.Fd()), C.CString("r"))
	if err != nil {
		return err
	}
	defer C.free(unsafe.Pointer(fh))
	var ns *C.char
	if namespace != "" {
		ns = C.CString(namespace)
		defer C.free(unsafe.Pointer(ns))
	}
	filename := C.CString(file.Name())
	defer C.free(unsafe.Pointer(filename))
	numErrors := int(C.yr_compiler_add_file(c.cptr, fh, ns, filename))
	if numErrors > 0 {
		var buf [1024]C.char
		msg := C.GoString(C.yr_compiler_get_error_message(
			c.cptr, (*C.char)(unsafe.Pointer(&buf[0])), 1024))
		err = errors.New(msg)
	}
	return
}<commit_msg>compiler.AddFile: Use fdopen on dup file descriptor and properly close it<commit_after>// Copyright © 2015 <NAME> <<EMAIL>>. All rights reserved.
// Use of this source code is governed by the license that can be
// found in the LICENSE file.

package yara

/*
#ifdef _WIN32
#define fdopen _fdopen
#endif
#include <stdio.h>
#include <unistd.h>

#include <yara.h>

// This signature should be generated by cgo from the exported
// function below
void compilerCallback(int, char*, int, char*, void*);
*/
import "C"
import (
	"errors"
	"os"
	"runtime"
	"unsafe"
)

//export compilerCallback
func compilerCallback(errorLevel C.int, filename *C.char, linenumber C.int, message *C.char, ptr unsafe.Pointer) {
	if ptr == nil {
		return
	}
	compiler := (*Compiler)(ptr)
	msg := CompilerMessage{
		Filename: C.GoString(filename),
		Line:     int(linenumber),
		Text:     C.GoString(message),
	}
	switch errorLevel {
	case C.YARA_ERROR_LEVEL_ERROR:
		compiler.Errors = append(compiler.Errors, msg)
	case C.YARA_ERROR_LEVEL_WARNING:
		compiler.Warnings = append(compiler.Warnings, msg)
	}
}

// A Compiler encapsulates the YARA compiler that transforms rules
// into YARA's internal, binary form which in turn is used for
// scanning files or memory blocks.
type Compiler struct {
	*compiler
	Errors   []CompilerMessage
	Warnings []CompilerMessage
}

type compiler struct {
	cptr *C.YR_COMPILER
}

// A CompilerMessage contains an error or warning message produced
// while compiling sets of rules using AddString or AddFile.
type CompilerMessage struct {
	Filename string
	Line     int
	Text     string
}

// NewCompiler creates a YARA compiler.
func NewCompiler() (*Compiler, error) {
	var yrCompiler *C.YR_COMPILER
	if err := newError(C.yr_compiler_create(&yrCompiler)); err != nil {
		return nil, err
	}
	c := &Compiler{compiler: &compiler{cptr: yrCompiler}}
	C.yr_compiler_set_callback(yrCompiler, C.YR_COMPILER_CALLBACK_FUNC(C.compilerCallback), unsafe.Pointer(c))
	runtime.SetFinalizer(c.compiler, (*compiler).finalize)
	return c, nil
}

func (c *compiler) finalize() {
	C.yr_compiler_destroy(c.cptr)
	runtime.SetFinalizer(c, nil)
}

// Destroy destroys the YARA data structure representing a compiler.
// Since a Finalizer for the underlying YR_COMPILER structure is
// automatically set up on creation, it should not be necessary to
// explicitly call this method.
func (c *Compiler) Destroy() {
	if c.compiler != nil {
		c.compiler.finalize()
		c.compiler = nil
	}
}

// AddFile compiles rules from an os.File. Rules are added to the
// specified namespace.
func (c *Compiler) AddFile(file os.File, namespace string) (err error) {
	fd := C.dup(C.int(file.Fd()))
	fh, err := C.fdopen(fd, C.CString("r"))
	if err != nil {
		return err
	}
	defer C.fclose(fh)
	var ns *C.char
	if namespace != "" {
		ns = C.CString(namespace)
		defer C.free(unsafe.Pointer(ns))
	}
	filename := C.CString(file.Name())
	defer C.free(unsafe.Pointer(filename))
	numErrors := int(C.yr_compiler_add_file(c.cptr, fh, ns, filename))
	if numErrors > 0 {
		var buf [1024]C.char
		msg := C.GoString(C.yr_compiler_get_error_message(
			c.cptr, (*C.char)(unsafe.Pointer(&buf[0])), 1024))
		err = errors.New(msg)
	}
	return
}
{'fraction_non_alphanumeric': 0.12076910853329095, 'fraction_numerical': 0.005085015096138567, 'mean_word_length': 4.1887881286067605, 'pattern_counts': {'":': 0, '<': 14, '<?xml version=': 0, '>': 16, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6758583', 'n_tokens_mistral': 2204, 'n_tokens_neox': 2095, 'n_words': 644}