<commit_before>// Package iso9660 implements ECMA-119 standard, also known as ISO 9660.
//
// References:
//
// * https://en.wikipedia.org/wiki/ISO_9660
//
// * http://alumnus.caltech.edu/~pje/iso9660.html
//
// * http://users.telenet.be/it3.consultants.bvba/handouts/ISO9960.html
//
// * http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
//
// * http://www.drdobbs.com/database/inside-the-iso-9660-filesystem-format/184408899
//
// * http://www.cdfs.com
//
// * http://wiki.osdev.org/ISO_9660
package iso9660

import (
	"bytes"
	"encoding/binary"
	"io"
	"os"
	"strings"
	"time"
)

// File represents a concrete implementation of os.FileInfo interface for
// accessing ISO 9660 file data
type File struct {
	DirectoryRecord
	fileID string
	// We have the raw image here only to be able to access file extents
	image io.ReadSeeker
}

// Name returns the file's name.
func (f *File) Name() string {
	name := strings.Split(f.fileID, ";")[0]
	return strings.ToLower(name)
}

// Size returns the file size in bytes
func (f *File) Size() int64 {
	return int64(f.ExtentLengthBE)
}

// Mode returns file's mode and permissions bits.
func (f *File) Mode() os.FileMode {
	return os.FileMode(0740)
}

// ModTime returns file's modification time.
func (f *File) ModTime() time.Time {
	return time.Now()
}

// IsDir tells whether the file is a directory or not.
func (f *File) IsDir() bool {
	if (f.FileFlags & 2) == 2 {
		return true
	}
	return false
}

// Sys returns io.Reader instance pointing to the file's content if it is not a directory, nil otherwise.
func (f *File) Sys() interface{} {
	if f.IsDir() {
		return nil
	}

	// if f.ExtentLengthBE <= 0 {
	// 	return bytes.NewReader([]byte(""))
	// }
	// Saves the current position within the ISO image. This is so we can
	// restore it once the file content is read. By doing this we allow
	// reader.Next() to keep working normally.
	// curOffset, err := f.image.Seek(0, os.SEEK_CUR)
	// fmt.Printf("Current offset within image: %d\n", curOffset)
	// if err != nil {
	// 	panic(err)
	// }

	_, err := f.image.Seek(int64(f.ExtentLocationBE*sectorSize), os.SEEK_SET)
	if err != nil {
		panic(err)
	}

	buffer := make([]byte, f.ExtentLengthBE)
	err = binary.Read(f.image, binary.BigEndian, buffer)
	if err != nil {
		panic(err)
	}

	// Restores original position within the ISO image after reading file's content.
	// _, err = f.image.Seek(curOffset, os.SEEK_SET)
	// if err != nil {
	// 	panic(err)
	// }

	return bytes.NewReader(buffer)
}

const (
	bootRecord       = 0
	primaryVol       = 1
	supplementaryVol = 2
	volPartition     = 3
	volSetTerminator = 255
	// System area goes from sectors 0x00 to 0x0F. Volume descriptors can be
	// found starting at sector 0x10
	dataAreaSector = 0x10
	sectorSize     = 2048
)

// VolumeDescriptor identify the volume, the partitions recorded on the volume,
// the volume creator(s), certain attributes of the volume, the location of
// other recorded descriptors and the version of the standard which applies
// to the volume descriptor.
//
// When preparing to mount a CD, your first action will be reading the volume
// descriptors (specifically, you will be looking for the Primary Volume Descriptor).
// Since sectors 0x00-0x0F of the CD are reserved as System Area, the Volume
// Descriptors can be found starting at sector 0x10.
type VolumeDescriptor struct {
	// 0: BootRecord
	// 1: Primary Volume Descriptor
	// 2: Supplementary Volume Descriptor
	// 3: Volume Partition Descriptor<commit_msg>Makes sure to save and restore current image offset<commit_after>// Package iso9660 implements ECMA-119 standard, also known as ISO 9660.
//
// References:
//
// * https://en.wikipedia.org/wiki/ISO_9660
//
// * http://alumnus.caltech.edu/~pje/iso9660.html
//
// * http://users.telenet.be/it3.consultants.bvba/handouts/ISO9960.html
//
// * http://www.ecma-international.org/publications/files/ECMA-ST/Ecma-119.pdf
//
// * http://www.drdobbs.com/database/inside-the-iso-9660-filesystem-format/184408899
//
// * http://www.cdfs.com
//
// * http://wiki.osdev.org/ISO_9660
package iso9660

import (
	"bytes"
	"encoding/binary"
	"io"
	"os"
	"strings"
	"time"
)

// File represents a concrete implementation of os.FileInfo interface for
// accessing ISO 9660 file data
type File struct {
	DirectoryRecord
	fileID string
	// We have the raw image here only to be able to access file extents
	image io.ReadSeeker
}

// Name returns the file's name.
func (f *File) Name() string {
	name := strings.Split(f.fileID, ";")[0]
	return strings.ToLower(name)
}

// Size returns the file size in bytes
func (f *File) Size() int64 {
	return int64(f.ExtentLengthBE)
}

// Mode returns file's mode and permissions bits. Since we don't yet support
// Rock Ridge extensions we cannot extract POSIX permissions and the rest of the
// normal metadata. So, right we return 0740 for directories and 0640 for files.
func (f *File) Mode() os.FileMode {
	if f.IsDir() {
		return os.FileMode(0740)
	}
	return os.FileMode(0640)
}

// ModTime returns file's modification time.
func (f *File) ModTime() time.Time {
	return time.Now()
}

// IsDir tells whether the file is a directory or not.
func (f *File) IsDir() bool {
	if (f.FileFlags & 2) == 2 {
		return true
	}
	return false
}

// Sys returns io.Reader instance pointing to the file's content if it is not a directory, nil otherwise.
func (f *File) Sys() interface{} {
	if f.IsDir() {
		return nil
	}

	// if f.ExtentLengthBE <= 0 {
	// 	return bytes.NewReader([]byte(""))
	// }
	// Saves the current position within the ISO image. This is so we can
	// restore it once the file content is read. By doing this we allow
	// reader.Next() to keep working normally.
	curOffset, err := f.image.Seek(0, os.SEEK_CUR)
	if err != nil {
		panic(err)
	}

	_, err = f.image.Seek(int64(f.ExtentLocationBE*sectorSize), os.SEEK_SET)
	if err != nil {
		panic(err)
	}

	buffer := make([]byte, f.ExtentLengthBE)
	err = binary.Read(f.image, binary.BigEndian, buffer)
	if err != nil {
		panic(err)
	}

	// Restores original position within the ISO image after reading file's content.
	_, err = f.image.Seek(curOffset, os.SEEK_SET)
	if err != nil {
		panic(err)
	}

	return bytes.NewReader(buffer)
}

const (
	bootRecord       = 0
	primaryVol       = 1
	supplementaryVol = 2
	volPartition     = 3
	volSetTerminator = 255
	// System area goes from sectors 0x00 to 0x0F. Volume descriptors can be
	// found starting at sector 0x10
	dataAreaSector = 0x10
	sectorSize     = 2048
)

// VolumeDescriptor identify the volume, the partitions recorded on the volume,
// the volume creator(s), certain attributes of the volume, the location of
// other recorded descriptors and the version of the standard which applies
// to the volume descriptor.
//
// When preparing to mount a CD, your first action will be reading the volume
// descriptors (specifically, you will be looking for the Primary Volume Descriptor).
// Since sectors 0x00-0x0F of the CD are reserved as System Area, the Volume
// Descriptors can be found starting at sector 0x10.
type VolumeDescriptor struct {
	// 0: BootRecord
	// 1: Primary Volume Descriptor
	// 2: Supplementary Volume Descriptor
	// 3: Volume Partition Descriptor
{'fraction_non_alphanumeric': 0.12022768290989866, 'fraction_numerical': 0.029709843120921838, 'mean_word_length': 3.293206197854589, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 2, 'lorem ipsum': 0, 'www.': 6, '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': '3157190', 'n_tokens_mistral': 2567, 'n_tokens_neox': 2352, 'n_words': 811}